summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/ABI/testing/sysfs-block14
-rw-r--r--Documentation/DocBook/mtdnand.tmpl2
-rw-r--r--Documentation/block/biodoc.txt5
-rw-r--r--Documentation/devicetree/bindings/arm/davinci/nand.txt51
-rw-r--r--Documentation/devicetree/bindings/i2c/atmel-i2c.txt30
-rw-r--r--Documentation/devicetree/bindings/i2c/davinci.txt28
-rw-r--r--Documentation/devicetree/bindings/i2c/i2c-mxs.txt2
-rw-r--r--Documentation/devicetree/bindings/i2c/nomadik.txt23
-rw-r--r--Documentation/devicetree/bindings/interrupt-controller/brcm,bcm2835-armctrl-ic.txt2
-rw-r--r--Documentation/devicetree/bindings/mmc/atmel-hsmci.txt68
-rw-r--r--Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt87
-rw-r--r--Documentation/devicetree/bindings/mmc/mmc.txt9
-rw-r--r--Documentation/devicetree/bindings/mmc/pxa-mmc.txt25
-rw-r--r--Documentation/devicetree/bindings/mmc/samsung-sdhci.txt53
-rw-r--r--Documentation/devicetree/bindings/mmc/sdhci-dove.txt14
-rw-r--r--Documentation/devicetree/bindings/mmc/sdhci-spear.txt18
-rw-r--r--Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt79
-rw-r--r--Documentation/devicetree/bindings/mtd/atmel-nand.txt40
-rw-r--r--Documentation/devicetree/bindings/mtd/gpmi-nand.txt4
-rw-r--r--Documentation/devicetree/bindings/mtd/lpc32xx-mlc.txt50
-rw-r--r--Documentation/devicetree/bindings/mtd/lpc32xx-slc.txt52
-rw-r--r--Documentation/devicetree/bindings/mtd/mtd-physmap.txt7
-rw-r--r--Documentation/devicetree/bindings/pwm/imx-pwm.txt17
-rw-r--r--Documentation/devicetree/bindings/pwm/mxs-pwm.txt2
-rw-r--r--Documentation/devicetree/bindings/pwm/nvidia,tegra20-pwm.txt2
-rw-r--r--Documentation/devicetree/bindings/timer/brcm,bcm2835-system-timer.txt2
-rw-r--r--Documentation/driver-model/devres.txt4
-rw-r--r--Documentation/filesystems/nfs/nfs.txt44
-rw-r--r--Documentation/hwmon/da90522
-rw-r--r--Documentation/hwmon/max16192
-rw-r--r--Documentation/hwmon/twl4030-madc-hwmon2
-rw-r--r--Documentation/kernel-parameters.txt5
-rw-r--r--Documentation/leds/leds-lp5523.txt21
-rw-r--r--Documentation/percpu-rw-semaphore.txt27
-rw-r--r--Documentation/pwm.txt3
-rwxr-xr-xDocumentation/target/tcm_mod_builder.py16
-rw-r--r--Documentation/virtual/uml/UserModeLinux-HOWTO.txt2
-rw-r--r--MAINTAINERS17
-rw-r--r--Makefile19
-rw-r--r--arch/Kconfig3
-rw-r--r--arch/alpha/Kconfig1
-rw-r--r--arch/alpha/include/asm/Kbuild1
-rw-r--r--arch/alpha/include/asm/exec.h6
-rw-r--r--arch/alpha/include/asm/processor.h3
-rw-r--r--arch/alpha/include/asm/thread_info.h3
-rw-r--r--arch/alpha/include/asm/unistd.h2
-rw-r--r--arch/alpha/kernel/alpha_ksyms.c3
-rw-r--r--arch/alpha/kernel/entry.S82
-rw-r--r--arch/alpha/kernel/process.c79
-rw-r--r--arch/alpha/kernel/ptrace.c32
-rw-r--r--arch/arm/Kconfig4
-rw-r--r--arch/arm/boot/dts/Makefile15
-rw-r--r--arch/arm/boot/dts/at91sam9260.dtsi10
-rw-r--r--arch/arm/boot/dts/at91sam9263.dtsi10
-rw-r--r--arch/arm/boot/dts/at91sam9g20.dtsi4
-rw-r--r--arch/arm/boot/dts/at91sam9g25ek.dts12
-rw-r--r--arch/arm/boot/dts/at91sam9g45.dtsi20
-rw-r--r--arch/arm/boot/dts/at91sam9m10g45ek.dts8
-rw-r--r--arch/arm/boot/dts/at91sam9n12.dtsi20
-rw-r--r--arch/arm/boot/dts/at91sam9n12ek.dts8
-rw-r--r--arch/arm/boot/dts/at91sam9x5.dtsi30
-rw-r--r--arch/arm/boot/dts/imx28.dtsi2
-rw-r--r--arch/arm/boot/dts/imx51.dtsi7
-rw-r--r--arch/arm/boot/dts/imx53.dtsi7
-rw-r--r--arch/arm/boot/dts/omap4-panda.dts47
-rw-r--r--arch/arm/boot/dts/omap4-sdp.dts57
-rw-r--r--arch/arm/boot/dts/omap5-evm.dts58
-rw-r--r--arch/arm/boot/dts/omap5.dtsi17
-rw-r--r--arch/arm/boot/dts/spear300-evb.dts3
-rw-r--r--arch/arm/boot/dts/spear320-evb.dts2
-rw-r--r--arch/arm/boot/dts/tegra20-seaboard.dts2
-rw-r--r--arch/arm/boot/dts/tegra20.dtsi4
-rw-r--r--arch/arm/common/it8152.c12
-rw-r--r--arch/arm/configs/cam60_defconfig1
-rw-r--r--arch/arm/configs/corgi_defconfig1
-rw-r--r--arch/arm/configs/ep93xx_defconfig1
-rw-r--r--arch/arm/configs/mini2440_defconfig1
-rw-r--r--arch/arm/configs/mv78xx0_defconfig1
-rw-r--r--arch/arm/configs/nhk8815_defconfig1
-rw-r--r--arch/arm/configs/orion5x_defconfig1
-rw-r--r--arch/arm/configs/pxa3xx_defconfig1
-rw-r--r--arch/arm/configs/spitz_defconfig1
-rw-r--r--arch/arm/include/asm/processor.h5
-rw-r--r--arch/arm/include/asm/ptrace.h5
-rw-r--r--arch/arm/include/asm/system.h1
-rw-r--r--arch/arm/include/asm/thread_info.h2
-rw-r--r--arch/arm/include/asm/unistd.h2
-rw-r--r--arch/arm/kernel/calls.S2
-rw-r--r--arch/arm/kernel/entry-common.S29
-rw-r--r--arch/arm/kernel/process.c75
-rw-r--r--arch/arm/kernel/signal.c1
-rw-r--r--arch/arm/kernel/sys_arm.c63
-rw-r--r--arch/arm/mach-at91/at91rm9200.c1
-rw-r--r--arch/arm/mach-at91/at91rm9200_devices.c2
-rw-r--r--arch/arm/mach-at91/at91sam9260.c3
-rw-r--r--arch/arm/mach-at91/at91sam9260_devices.c8
-rw-r--r--arch/arm/mach-at91/at91sam9261.c2
-rw-r--r--arch/arm/mach-at91/at91sam9261_devices.c14
-rw-r--r--arch/arm/mach-at91/at91sam9263.c2
-rw-r--r--arch/arm/mach-at91/at91sam9263_devices.c2
-rw-r--r--arch/arm/mach-at91/at91sam9g45.c4
-rw-r--r--arch/arm/mach-at91/at91sam9g45_devices.c10
-rw-r--r--arch/arm/mach-at91/at91sam9n12.c2
-rw-r--r--arch/arm/mach-at91/at91sam9rl.c2
-rw-r--r--arch/arm/mach-at91/at91sam9rl_devices.c2
-rw-r--r--arch/arm/mach-at91/at91sam9x5.c3
-rw-r--r--arch/arm/mach-at91/include/mach/at91_twi.h68
-rw-r--r--arch/arm/mach-at91/pm.c5
-rw-r--r--arch/arm/mach-at91/setup.c2
-rw-r--r--arch/arm/mach-clps711x/autcpu12.c19
-rw-r--r--arch/arm/mach-davinci/da850.c2
-rw-r--r--arch/arm/mach-exynos/dma.c2
-rw-r--r--arch/arm/mach-exynos/mach-nuri.c2
-rw-r--r--arch/arm/mach-exynos/mach-origen.c2
-rw-r--r--arch/arm/mach-exynos/mach-smdk4x12.c2
-rw-r--r--arch/arm/mach-exynos/mach-smdkv310.c2
-rw-r--r--arch/arm/mach-exynos/mach-universal_c210.c2
-rw-r--r--arch/arm/mach-exynos/setup-fimd0.c2
-rw-r--r--arch/arm/mach-footbridge/include/mach/irqs.h2
-rw-r--r--arch/arm/mach-imx/clk-imx51-imx53.c2
-rw-r--r--arch/arm/mach-integrator/include/mach/cm.h2
-rw-r--r--arch/arm/mach-integrator/include/mach/platform.h6
-rw-r--r--arch/arm/mach-integrator/integrator_ap.c2
-rw-r--r--arch/arm/mach-integrator/integrator_cp.c4
-rw-r--r--arch/arm/mach-iop13xx/iq81340sc.c2
-rw-r--r--arch/arm/mach-iop13xx/pci.c2
-rw-r--r--arch/arm/mach-ks8695/include/mach/memory.h3
-rw-r--r--arch/arm/mach-mv78xx0/addr-map.c2
-rw-r--r--arch/arm/mach-mv78xx0/common.c2
-rw-r--r--arch/arm/mach-omap1/devices.c2
-rw-r--r--arch/arm/mach-omap2/board-4430sdp.c99
-rw-r--r--arch/arm/mach-omap2/board-flash.c2
-rw-r--r--arch/arm/mach-omap2/board-omap3beagle.c2
-rw-r--r--arch/arm/mach-omap2/board-omap3evm.c3
-rw-r--r--arch/arm/mach-omap2/board-omap3stalker.c5
-rw-r--r--arch/arm/mach-omap2/board-omap4panda.c45
-rw-r--r--arch/arm/mach-omap2/board-rx51-peripherals.c2
-rw-r--r--arch/arm/mach-omap2/board-zoom-peripherals.c3
-rw-r--r--arch/arm/mach-omap2/clkt_clksel.c2
-rw-r--r--arch/arm/mach-omap2/clock33xx_data.c2
-rw-r--r--arch/arm/mach-omap2/clockdomain2xxx_3xxx.c44
-rw-r--r--arch/arm/mach-omap2/display.c3
-rw-r--r--arch/arm/mach-omap2/gpmc.c4
-rw-r--r--arch/arm/mach-omap2/hsmmc.c2
-rw-r--r--arch/arm/mach-omap2/mux.c2
-rw-r--r--arch/arm/mach-omap2/omap-secure.c4
-rw-r--r--arch/arm/mach-omap2/omap_hwmod.c31
-rw-r--r--arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c2
-rw-r--r--arch/arm/mach-omap2/omap_hwmod_3xxx_data.c9
-rw-r--r--arch/arm/mach-omap2/opp.c23
-rw-r--r--arch/arm/mach-omap2/pm-debug.c2
-rw-r--r--arch/arm/mach-omap2/pm.c13
-rw-r--r--arch/arm/mach-omap2/sr_device.c2
-rw-r--r--arch/arm/mach-omap2/timer.c2
-rw-r--r--arch/arm/mach-omap2/twl-common.c8
-rw-r--r--arch/arm/mach-pxa/cm-x2xx.c1
-rw-r--r--arch/arm/mach-pxa/palmte2.c2
-rw-r--r--arch/arm/mach-pxa/sharpsl_pm.c48
-rw-r--r--arch/arm/mach-pxa/viper.c3
-rw-r--r--arch/arm/mach-rpc/ecard.c4
-rw-r--r--arch/arm/mach-s3c24xx/irq-s3c2416.c6
-rw-r--r--arch/arm/mach-s3c24xx/irq-s3c2443.c4
-rw-r--r--arch/arm/mach-s3c24xx/mach-smdk2416.c2
-rw-r--r--arch/arm/mach-s3c24xx/simtec-usb.c2
-rw-r--r--arch/arm/mach-s3c64xx/mach-anw6410.c2
-rw-r--r--arch/arm/mach-s3c64xx/mach-crag6410.c2
-rw-r--r--arch/arm/mach-s3c64xx/mach-hmt.c2
-rw-r--r--arch/arm/mach-s3c64xx/mach-mini6410.c2
-rw-r--r--arch/arm/mach-s3c64xx/mach-ncp.c2
-rw-r--r--arch/arm/mach-s3c64xx/mach-real6410.c2
-rw-r--r--arch/arm/mach-s3c64xx/mach-smartq5.c2
-rw-r--r--arch/arm/mach-s3c64xx/mach-smartq7.c2
-rw-r--r--arch/arm/mach-s3c64xx/mach-smdk6410.c2
-rw-r--r--arch/arm/mach-s5p64x0/mach-smdk6440.c2
-rw-r--r--arch/arm/mach-s5p64x0/mach-smdk6450.c2
-rw-r--r--arch/arm/mach-s5pc100/mach-smdkc100.c2
-rw-r--r--arch/arm/mach-s5pv210/mach-aquila.c2
-rw-r--r--arch/arm/mach-s5pv210/mach-goni.c2
-rw-r--r--arch/arm/mach-s5pv210/mach-smdkv210.c2
-rw-r--r--arch/arm/mach-sa1100/assabet.c2
-rw-r--r--arch/arm/mach-shark/pci.c2
-rw-r--r--arch/arm/mach-shmobile/include/mach/common.h2
-rw-r--r--arch/arm/mach-spear13xx/spear13xx.c3
-rw-r--r--arch/arm/mach-tegra/Kconfig6
-rw-r--r--arch/arm/mach-ux500/Kconfig4
-rw-r--r--arch/arm/mach-vt8500/include/mach/uncompress.h8
-rw-r--r--arch/arm/mach-vt8500/vt8500.c5
-rw-r--r--arch/arm/plat-mxc/devices/platform-mxc_nand.c11
-rw-r--r--arch/arm/plat-omap/Kconfig2
-rw-r--r--arch/arm/plat-omap/counter_32k.c21
-rw-r--r--arch/arm/plat-omap/i2c.c21
-rw-r--r--arch/arm/plat-omap/omap-pm-noop.c8
-rw-r--r--arch/arm/plat-omap/omap_device.c2
-rw-r--r--arch/arm/plat-samsung/include/plat/regs-fb-v4.h159
-rw-r--r--arch/avr32/include/asm/Kbuild1
-rw-r--r--arch/avr32/include/asm/exec.h13
-rw-r--r--arch/avr32/include/asm/thread_info.h18
-rw-r--r--arch/avr32/kernel/signal.c1
-rw-r--r--arch/avr32/mach-at32ap/at32ap700x.c3
-rw-r--r--arch/blackfin/configs/BF561-ACVILON_defconfig1
-rw-r--r--arch/blackfin/include/asm/thread_info.h4
-rw-r--r--arch/blackfin/kernel/signal.c1
-rw-r--r--arch/c6x/Kconfig1
-rw-r--r--arch/c6x/include/asm/Kbuild1
-rw-r--r--arch/c6x/include/asm/exec.h6
-rw-r--r--arch/c6x/include/asm/processor.h2
-rw-r--r--arch/c6x/include/asm/syscalls.h5
-rw-r--r--arch/c6x/include/asm/thread_info.h1
-rw-r--r--arch/c6x/include/asm/unistd.h3
-rw-r--r--arch/c6x/kernel/asm-offsets.c1
-rw-r--r--arch/c6x/kernel/entry.S56
-rw-r--r--arch/c6x/kernel/process.c72
-rw-r--r--arch/cris/include/asm/Kbuild1
-rw-r--r--arch/cris/include/asm/exec.h6
-rw-r--r--arch/cris/include/asm/thread_info.h3
-rw-r--r--arch/frv/Kconfig1
-rw-r--r--arch/frv/include/asm/Kbuild1
-rw-r--r--arch/frv/include/asm/exec.h17
-rw-r--r--arch/frv/include/asm/processor.h9
-rw-r--r--arch/frv/include/asm/ptrace.h1
-rw-r--r--arch/frv/include/asm/thread_info.h3
-rw-r--r--arch/frv/include/asm/unistd.h2
-rw-r--r--arch/frv/kernel/Makefile4
-rw-r--r--arch/frv/kernel/entry.S13
-rw-r--r--arch/frv/kernel/frv_ksyms.c1
-rw-r--r--arch/frv/kernel/kernel_execve.S33
-rw-r--r--arch/frv/kernel/kernel_thread.S77
-rw-r--r--arch/frv/kernel/process.c66
-rw-r--r--arch/frv/kernel/signal.c9
-rw-r--r--arch/h8300/include/asm/Kbuild3
-rw-r--r--arch/h8300/include/asm/exec.h6
-rw-r--r--arch/h8300/include/asm/thread_info.h7
-rw-r--r--arch/h8300/kernel/signal.c1
-rw-r--r--arch/hexagon/include/asm/thread_info.h5
-rw-r--r--arch/hexagon/kernel/signal.c1
-rw-r--r--arch/hexagon/kernel/syscall.c1
-rw-r--r--arch/ia64/include/asm/Kbuild1
-rw-r--r--arch/ia64/include/asm/exec.h14
-rw-r--r--arch/ia64/include/asm/thread_info.h2
-rw-r--r--arch/ia64/kernel/signal.c8
-rw-r--r--arch/m32r/include/asm/Kbuild3
-rw-r--r--arch/m32r/include/asm/exec.h14
-rw-r--r--arch/m32r/include/asm/thread_info.h9
-rw-r--r--arch/m32r/kernel/signal.c3
-rw-r--r--arch/m68k/Kconfig1
-rw-r--r--arch/m68k/include/asm/Kbuild1
-rw-r--r--arch/m68k/include/asm/exec.h6
-rw-r--r--arch/m68k/include/asm/processor.h25
-rw-r--r--arch/m68k/include/asm/ptrace.h2
-rw-r--r--arch/m68k/include/asm/unistd.h2
-rw-r--r--arch/m68k/kernel/entry.S16
-rw-r--r--arch/m68k/kernel/process.c104
-rw-r--r--arch/m68k/kernel/sys_m68k.c17
-rw-r--r--arch/microblaze/include/asm/Kbuild1
-rw-r--r--arch/microblaze/include/asm/exec.h14
-rw-r--r--arch/microblaze/include/asm/thread_info.h3
-rw-r--r--arch/microblaze/kernel/signal.c7
-rw-r--r--arch/mips/configs/rb532_defconfig1
-rw-r--r--arch/mips/include/asm/mach-jz4740/platform.h1
-rw-r--r--arch/mips/include/asm/mach-jz4740/timer.h113
-rw-r--r--arch/mips/include/asm/thread_info.h3
-rw-r--r--arch/mips/jz4740/Kconfig3
-rw-r--r--arch/mips/jz4740/Makefile2
-rw-r--r--arch/mips/jz4740/board-qi_lb60.c1
-rw-r--r--arch/mips/jz4740/platform.c6
-rw-r--r--arch/mips/jz4740/pwm.c177
-rw-r--r--arch/mips/jz4740/time.c2
-rw-r--r--arch/mips/jz4740/timer.c4
-rw-r--r--arch/mips/jz4740/timer.h136
-rw-r--r--arch/mn10300/Kconfig1
-rw-r--r--arch/mn10300/include/asm/Kbuild1
-rw-r--r--arch/mn10300/include/asm/exec.h16
-rw-r--r--arch/mn10300/include/asm/frame.inc2
-rw-r--r--arch/mn10300/include/asm/processor.h18
-rw-r--r--arch/mn10300/include/asm/ptrace.h1
-rw-r--r--arch/mn10300/include/asm/thread_info.h3
-rw-r--r--arch/mn10300/include/asm/unistd.h2
-rw-r--r--arch/mn10300/kernel/Makefile4
-rw-r--r--arch/mn10300/kernel/entry.S18
-rw-r--r--arch/mn10300/kernel/internal.h6
-rw-r--r--arch/mn10300/kernel/kernel_execve.S37
-rw-r--r--arch/mn10300/kernel/kthread.S31
-rw-r--r--arch/mn10300/kernel/process.c91
-rw-r--r--arch/mn10300/kernel/signal.c13
-rw-r--r--arch/openrisc/include/asm/thread_info.h3
-rw-r--r--arch/parisc/hpux/gate.S2
-rw-r--r--arch/parisc/include/asm/Kbuild1
-rw-r--r--arch/parisc/include/asm/exec.h6
-rw-r--r--arch/parisc/include/asm/thread_info.h5
-rw-r--r--arch/parisc/kernel/signal.c45
-rw-r--r--arch/parisc/kernel/syscall.S9
-rw-r--r--arch/powerpc/Kconfig1
-rw-r--r--arch/powerpc/configs/83xx/mpc8313_rdb_defconfig1
-rw-r--r--arch/powerpc/configs/83xx/mpc8315_rdb_defconfig1
-rw-r--r--arch/powerpc/configs/mpc83xx_defconfig1
-rw-r--r--arch/powerpc/include/asm/processor.h3
-rw-r--r--arch/powerpc/include/asm/ptrace.h2
-rw-r--r--arch/powerpc/include/asm/syscalls.h3
-rw-r--r--arch/powerpc/include/asm/thread_info.h2
-rw-r--r--arch/powerpc/include/asm/unistd.h2
-rw-r--r--arch/powerpc/kernel/entry_32.S16
-rw-r--r--arch/powerpc/kernel/entry_64.S16
-rw-r--r--arch/powerpc/kernel/misc.S7
-rw-r--r--arch/powerpc/kernel/misc_32.S33
-rw-r--r--arch/powerpc/kernel/misc_64.S34
-rw-r--r--arch/powerpc/kernel/ppc_ksyms.c1
-rw-r--r--arch/powerpc/kernel/process.c59
-rw-r--r--arch/powerpc/kernel/signal_32.c1
-rw-r--r--arch/powerpc/kernel/sys_ppc32.c22
-rw-r--r--arch/powerpc/platforms/pseries/hotplug-memory.c11
-rw-r--r--arch/s390/Kconfig1
-rw-r--r--arch/s390/Kconfig.debug12
-rw-r--r--arch/s390/include/asm/Kbuild14
-rw-r--r--arch/s390/include/asm/chpid.h19
-rw-r--r--arch/s390/include/asm/cmb.h51
-rw-r--r--arch/s390/include/asm/css_chars.h3
-rw-r--r--arch/s390/include/asm/debug.h28
-rw-r--r--arch/s390/include/asm/kvm_para.h14
-rw-r--r--arch/s390/include/asm/mman.h6
-rw-r--r--arch/s390/include/asm/page.h14
-rw-r--r--arch/s390/include/asm/pgtable.h30
-rw-r--r--arch/s390/include/asm/processor.h4
-rw-r--r--arch/s390/include/asm/ptrace.h462
-rw-r--r--arch/s390/include/asm/schid.h15
-rw-r--r--arch/s390/include/asm/setup.h21
-rw-r--r--arch/s390/include/asm/signal.h128
-rw-r--r--arch/s390/include/asm/termios.h42
-rw-r--r--arch/s390/include/asm/thread_info.h4
-rw-r--r--arch/s390/include/asm/types.h15
-rw-r--r--arch/s390/include/asm/unistd.h369
-rw-r--r--arch/s390/include/uapi/asm/Kbuild45
-rw-r--r--arch/s390/include/uapi/asm/auxvec.h (renamed from arch/s390/include/asm/auxvec.h)0
-rw-r--r--arch/s390/include/uapi/asm/bitsperlong.h (renamed from arch/s390/include/asm/bitsperlong.h)0
-rw-r--r--arch/s390/include/uapi/asm/byteorder.h (renamed from arch/s390/include/asm/byteorder.h)0
-rw-r--r--arch/s390/include/uapi/asm/chpid.h22
-rw-r--r--arch/s390/include/uapi/asm/chsc.h (renamed from arch/s390/include/asm/chsc.h)10
-rw-r--r--arch/s390/include/uapi/asm/cmb.h53
-rw-r--r--arch/s390/include/uapi/asm/dasd.h (renamed from arch/s390/include/asm/dasd.h)0
-rw-r--r--arch/s390/include/uapi/asm/debug.h34
-rw-r--r--arch/s390/include/uapi/asm/errno.h (renamed from arch/s390/include/asm/errno.h)0
-rw-r--r--arch/s390/include/uapi/asm/fcntl.h (renamed from arch/s390/include/asm/fcntl.h)0
-rw-r--r--arch/s390/include/uapi/asm/ioctl.h (renamed from arch/s390/include/asm/ioctl.h)0
-rw-r--r--arch/s390/include/uapi/asm/ioctls.h (renamed from arch/s390/include/asm/ioctls.h)0
-rw-r--r--arch/s390/include/uapi/asm/ipcbuf.h (renamed from arch/s390/include/asm/ipcbuf.h)0
-rw-r--r--arch/s390/include/uapi/asm/kvm.h (renamed from arch/s390/include/asm/kvm.h)0
-rw-r--r--arch/s390/include/uapi/asm/kvm_para.h0
-rw-r--r--arch/s390/include/uapi/asm/kvm_virtio.h (renamed from arch/s390/include/asm/kvm_virtio.h)0
-rw-r--r--arch/s390/include/uapi/asm/mman.h6
-rw-r--r--arch/s390/include/uapi/asm/monwriter.h (renamed from arch/s390/include/asm/monwriter.h)0
-rw-r--r--arch/s390/include/uapi/asm/msgbuf.h (renamed from arch/s390/include/asm/msgbuf.h)0
-rw-r--r--arch/s390/include/uapi/asm/param.h (renamed from arch/s390/include/asm/param.h)0
-rw-r--r--arch/s390/include/uapi/asm/poll.h (renamed from arch/s390/include/asm/poll.h)0
-rw-r--r--arch/s390/include/uapi/asm/posix_types.h (renamed from arch/s390/include/asm/posix_types.h)0
-rw-r--r--arch/s390/include/uapi/asm/ptrace.h472
-rw-r--r--arch/s390/include/uapi/asm/qeth.h (renamed from arch/s390/include/asm/qeth.h)0
-rw-r--r--arch/s390/include/uapi/asm/resource.h (renamed from arch/s390/include/asm/resource.h)0
-rw-r--r--arch/s390/include/uapi/asm/schid.h16
-rw-r--r--arch/s390/include/uapi/asm/sembuf.h (renamed from arch/s390/include/asm/sembuf.h)0
-rw-r--r--arch/s390/include/uapi/asm/setup.h13
-rw-r--r--arch/s390/include/uapi/asm/shmbuf.h (renamed from arch/s390/include/asm/shmbuf.h)0
-rw-r--r--arch/s390/include/uapi/asm/sigcontext.h (renamed from arch/s390/include/asm/sigcontext.h)0
-rw-r--r--arch/s390/include/uapi/asm/siginfo.h (renamed from arch/s390/include/asm/siginfo.h)0
-rw-r--r--arch/s390/include/uapi/asm/signal.h135
-rw-r--r--arch/s390/include/uapi/asm/socket.h (renamed from arch/s390/include/asm/socket.h)0
-rw-r--r--arch/s390/include/uapi/asm/sockios.h (renamed from arch/s390/include/asm/sockios.h)0
-rw-r--r--arch/s390/include/uapi/asm/stat.h (renamed from arch/s390/include/asm/stat.h)0
-rw-r--r--arch/s390/include/uapi/asm/statfs.h (renamed from arch/s390/include/asm/statfs.h)0
-rw-r--r--arch/s390/include/uapi/asm/swab.h (renamed from arch/s390/include/asm/swab.h)0
-rw-r--r--arch/s390/include/uapi/asm/tape390.h (renamed from arch/s390/include/asm/tape390.h)0
-rw-r--r--arch/s390/include/uapi/asm/termbits.h (renamed from arch/s390/include/asm/termbits.h)0
-rw-r--r--arch/s390/include/uapi/asm/termios.h49
-rw-r--r--arch/s390/include/uapi/asm/types.h22
-rw-r--r--arch/s390/include/uapi/asm/ucontext.h (renamed from arch/s390/include/asm/ucontext.h)0
-rw-r--r--arch/s390/include/uapi/asm/unistd.h374
-rw-r--r--arch/s390/include/uapi/asm/vtoc.h (renamed from arch/s390/include/asm/vtoc.h)0
-rw-r--r--arch/s390/include/uapi/asm/zcrypt.h (renamed from arch/s390/include/asm/zcrypt.h)0
-rw-r--r--arch/s390/kernel/compat_linux.c26
-rw-r--r--arch/s390/kernel/compat_linux.h2
-rw-r--r--arch/s390/kernel/compat_wrapper.S2
-rw-r--r--arch/s390/kernel/early.c17
-rw-r--r--arch/s390/kernel/entry.S51
-rw-r--r--arch/s390/kernel/entry.h3
-rw-r--r--arch/s390/kernel/entry64.S52
-rw-r--r--arch/s390/kernel/head.S101
-rw-r--r--arch/s390/kernel/head31.S3
-rw-r--r--arch/s390/kernel/head64.S3
-rw-r--r--arch/s390/kernel/module.c11
-rw-r--r--arch/s390/kernel/process.c107
-rw-r--r--arch/s390/kernel/setup.c51
-rw-r--r--arch/s390/mm/Makefile1
-rw-r--r--arch/s390/mm/dump_pagetables.c226
-rw-r--r--arch/s390/mm/pageattr.c40
-rw-r--r--arch/s390/mm/vmem.c45
-rw-r--r--arch/score/include/asm/thread_info.h4
-rw-r--r--arch/score/kernel/signal.c1
-rw-r--r--arch/sh/include/asm/Kbuild1
-rw-r--r--arch/sh/include/asm/exec.h10
-rw-r--r--arch/sh/include/asm/thread_info.h3
-rw-r--r--arch/sh/kernel/signal_32.c1
-rw-r--r--arch/sh/kernel/signal_64.c1
-rw-r--r--arch/sparc/include/asm/Kbuild17
-rw-r--r--arch/sparc/include/asm/exec.h6
-rw-r--r--arch/sparc/include/asm/fbio.h260
-rw-r--r--arch/sparc/include/asm/ioctls.h129
-rw-r--r--arch/sparc/include/asm/mman.h25
-rw-r--r--arch/sparc/include/asm/psr.h36
-rw-r--r--arch/sparc/include/asm/ptrace.h347
-rw-r--r--arch/sparc/include/asm/setup.h10
-rw-r--r--arch/sparc/include/asm/sigcontext.h4
-rw-r--r--arch/sparc/include/asm/siginfo.h23
-rw-r--r--arch/sparc/include/asm/signal.h185
-rw-r--r--arch/sparc/include/asm/termbits.h260
-rw-r--r--arch/sparc/include/asm/termios.h41
-rw-r--r--arch/sparc/include/asm/thread_info_32.h3
-rw-r--r--arch/sparc/include/asm/thread_info_64.h3
-rw-r--r--arch/sparc/include/asm/traps.h111
-rw-r--r--arch/sparc/include/asm/unistd.h412
-rw-r--r--arch/sparc/include/uapi/asm/Kbuild46
-rw-r--r--arch/sparc/include/uapi/asm/apc.h (renamed from arch/sparc/include/asm/apc.h)0
-rw-r--r--arch/sparc/include/uapi/asm/asi.h (renamed from arch/sparc/include/asm/asi.h)0
-rw-r--r--arch/sparc/include/uapi/asm/auxvec.h (renamed from arch/sparc/include/asm/auxvec.h)0
-rw-r--r--arch/sparc/include/uapi/asm/bitsperlong.h (renamed from arch/sparc/include/asm/bitsperlong.h)0
-rw-r--r--arch/sparc/include/uapi/asm/byteorder.h (renamed from arch/sparc/include/asm/byteorder.h)0
-rw-r--r--arch/sparc/include/uapi/asm/display7seg.h (renamed from arch/sparc/include/asm/display7seg.h)0
-rw-r--r--arch/sparc/include/uapi/asm/envctrl.h (renamed from arch/sparc/include/asm/envctrl.h)0
-rw-r--r--arch/sparc/include/uapi/asm/errno.h (renamed from arch/sparc/include/asm/errno.h)0
-rw-r--r--arch/sparc/include/uapi/asm/fbio.h259
-rw-r--r--arch/sparc/include/uapi/asm/fcntl.h (renamed from arch/sparc/include/asm/fcntl.h)0
-rw-r--r--arch/sparc/include/uapi/asm/ioctl.h (renamed from arch/sparc/include/asm/ioctl.h)0
-rw-r--r--arch/sparc/include/uapi/asm/ioctls.h131
-rw-r--r--arch/sparc/include/uapi/asm/ipcbuf.h (renamed from arch/sparc/include/asm/ipcbuf.h)0
-rw-r--r--arch/sparc/include/uapi/asm/jsflash.h (renamed from arch/sparc/include/asm/jsflash.h)0
-rw-r--r--arch/sparc/include/uapi/asm/kvm_para.h (renamed from arch/sparc/include/asm/kvm_para.h)0
-rw-r--r--arch/sparc/include/uapi/asm/mman.h27
-rw-r--r--arch/sparc/include/uapi/asm/msgbuf.h (renamed from arch/sparc/include/asm/msgbuf.h)0
-rw-r--r--arch/sparc/include/uapi/asm/openpromio.h (renamed from arch/sparc/include/asm/openpromio.h)0
-rw-r--r--arch/sparc/include/uapi/asm/param.h (renamed from arch/sparc/include/asm/param.h)0
-rw-r--r--arch/sparc/include/uapi/asm/perfctr.h (renamed from arch/sparc/include/asm/perfctr.h)0
-rw-r--r--arch/sparc/include/uapi/asm/poll.h (renamed from arch/sparc/include/asm/poll.h)0
-rw-r--r--arch/sparc/include/uapi/asm/posix_types.h (renamed from arch/sparc/include/asm/posix_types.h)0
-rw-r--r--arch/sparc/include/uapi/asm/psr.h47
-rw-r--r--arch/sparc/include/uapi/asm/psrcompat.h (renamed from arch/sparc/include/asm/psrcompat.h)0
-rw-r--r--arch/sparc/include/uapi/asm/pstate.h (renamed from arch/sparc/include/asm/pstate.h)0
-rw-r--r--arch/sparc/include/uapi/asm/ptrace.h352
-rw-r--r--arch/sparc/include/uapi/asm/resource.h (renamed from arch/sparc/include/asm/resource.h)0
-rw-r--r--arch/sparc/include/uapi/asm/sembuf.h (renamed from arch/sparc/include/asm/sembuf.h)0
-rw-r--r--arch/sparc/include/uapi/asm/setup.h15
-rw-r--r--arch/sparc/include/uapi/asm/shmbuf.h (renamed from arch/sparc/include/asm/shmbuf.h)0
-rw-r--r--arch/sparc/include/uapi/asm/sigcontext.h0
-rw-r--r--arch/sparc/include/uapi/asm/siginfo.h25
-rw-r--r--arch/sparc/include/uapi/asm/signal.h185
-rw-r--r--arch/sparc/include/uapi/asm/socket.h (renamed from arch/sparc/include/asm/socket.h)0
-rw-r--r--arch/sparc/include/uapi/asm/sockios.h (renamed from arch/sparc/include/asm/sockios.h)0
-rw-r--r--arch/sparc/include/uapi/asm/stat.h (renamed from arch/sparc/include/asm/stat.h)0
-rw-r--r--arch/sparc/include/uapi/asm/statfs.h (renamed from arch/sparc/include/asm/statfs.h)0
-rw-r--r--arch/sparc/include/uapi/asm/swab.h (renamed from arch/sparc/include/asm/swab.h)0
-rw-r--r--arch/sparc/include/uapi/asm/termbits.h263
-rw-r--r--arch/sparc/include/uapi/asm/termios.h43
-rw-r--r--arch/sparc/include/uapi/asm/traps.h120
-rw-r--r--arch/sparc/include/uapi/asm/types.h (renamed from arch/sparc/include/asm/types.h)0
-rw-r--r--arch/sparc/include/uapi/asm/uctx.h (renamed from arch/sparc/include/asm/uctx.h)0
-rw-r--r--arch/sparc/include/uapi/asm/unistd.h422
-rw-r--r--arch/sparc/include/uapi/asm/utrap.h (renamed from arch/sparc/include/asm/utrap.h)0
-rw-r--r--arch/sparc/include/uapi/asm/watchdog.h (renamed from arch/sparc/include/asm/watchdog.h)0
-rw-r--r--arch/tile/include/asm/Kbuild1
-rw-r--r--arch/tile/include/asm/exec.h20
-rw-r--r--arch/tile/kernel/compat_signal.c9
-rw-r--r--arch/tile/kernel/signal.c12
-rw-r--r--arch/um/drivers/chan_kern.c4
-rw-r--r--arch/um/drivers/chan_user.c4
-rw-r--r--arch/um/drivers/chan_user.h2
-rw-r--r--arch/um/drivers/cow_sys.h6
-rw-r--r--arch/um/drivers/daemon.h2
-rw-r--r--arch/um/drivers/daemon_kern.c4
-rw-r--r--arch/um/drivers/daemon_user.c6
-rw-r--r--arch/um/drivers/fd.c4
-rw-r--r--arch/um/drivers/harddog_user.c2
-rw-r--r--arch/um/drivers/hostaudio_kern.c18
-rw-r--r--arch/um/drivers/line.c16
-rw-r--r--arch/um/drivers/line.h12
-rw-r--r--arch/um/drivers/mconsole.h2
-rw-r--r--arch/um/drivers/mconsole_kern.c10
-rw-r--r--arch/um/drivers/mconsole_kern.h2
-rw-r--r--arch/um/drivers/mmapper_kern.c2
-rw-r--r--arch/um/drivers/net_kern.c10
-rw-r--r--arch/um/drivers/net_user.c6
-rw-r--r--arch/um/drivers/null.c2
-rw-r--r--arch/um/drivers/pcap_kern.c4
-rw-r--r--arch/um/drivers/pcap_user.c4
-rw-r--r--arch/um/drivers/pcap_user.h2
-rw-r--r--arch/um/drivers/port_kern.c20
-rw-r--r--arch/um/drivers/port_user.c4
-rw-r--r--arch/um/drivers/pty.c4
-rw-r--r--arch/um/drivers/random.c4
-rw-r--r--arch/um/drivers/slip_common.c2
-rw-r--r--arch/um/drivers/slip_kern.c2
-rw-r--r--arch/um/drivers/slip_user.c6
-rw-r--r--arch/um/drivers/slirp_kern.c6
-rw-r--r--arch/um/drivers/slirp_user.c4
-rw-r--r--arch/um/drivers/ssl.c22
-rw-r--r--arch/um/drivers/stdio_console.c36
-rw-r--r--arch/um/drivers/tty.c4
-rw-r--r--arch/um/drivers/ubd_kern.c8
-rw-r--r--arch/um/drivers/ubd_user.c2
-rw-r--r--arch/um/drivers/umcast.h2
-rw-r--r--arch/um/drivers/umcast_kern.c4
-rw-r--r--arch/um/drivers/umcast_user.c4
-rw-r--r--arch/um/drivers/vde_kern.c6
-rw-r--r--arch/um/drivers/vde_user.c4
-rw-r--r--arch/um/drivers/xterm.c4
-rw-r--r--arch/um/drivers/xterm_kern.c4
-rw-r--r--arch/um/include/asm/dma.h2
-rw-r--r--arch/um/include/asm/mmu.h2
-rw-r--r--arch/um/include/asm/page.h2
-rw-r--r--arch/um/include/asm/pgtable.h4
-rw-r--r--arch/um/include/asm/processor-generic.h8
-rw-r--r--arch/um/include/asm/ptrace-generic.h2
-rw-r--r--arch/um/include/asm/smp.h6
-rw-r--r--arch/um/include/asm/sysrq.h (renamed from arch/um/include/shared/sysrq.h)0
-rw-r--r--arch/um/include/asm/thread_info.h3
-rw-r--r--arch/um/include/shared/arch.h2
-rw-r--r--arch/um/include/shared/as-layout.h2
-rw-r--r--arch/um/include/shared/irq_kern.h4
-rw-r--r--arch/um/include/shared/irq_user.h2
-rw-r--r--arch/um/include/shared/kern_util.h4
-rw-r--r--arch/um/include/shared/longjmp.h4
-rw-r--r--arch/um/include/shared/os.h6
-rw-r--r--arch/um/include/shared/registers.h4
-rw-r--r--arch/um/include/shared/skas/skas.h2
-rw-r--r--arch/um/include/shared/skas_ptrace.h2
-rw-r--r--arch/um/kernel/asm-offsets.c2
-rw-r--r--arch/um/kernel/config.c.in2
-rw-r--r--arch/um/kernel/dyn.lds.S2
-rw-r--r--arch/um/kernel/early_printk.c2
-rw-r--r--arch/um/kernel/exec.c33
-rw-r--r--arch/um/kernel/gmon_syms.c2
-rw-r--r--arch/um/kernel/gprof_syms.c2
-rw-r--r--arch/um/kernel/initrd.c12
-rw-r--r--arch/um/kernel/internal.h1
-rw-r--r--arch/um/kernel/irq.c22
-rw-r--r--arch/um/kernel/ksyms.c2
-rw-r--r--arch/um/kernel/mem.c12
-rw-r--r--arch/um/kernel/process.c25
-rw-r--r--arch/um/kernel/reboot.c14
-rw-r--r--arch/um/kernel/sigio.c6
-rw-r--r--arch/um/kernel/signal.c4
-rw-r--r--arch/um/kernel/skas/clone.c8
-rw-r--r--arch/um/kernel/skas/mmu.c16
-rw-r--r--arch/um/kernel/skas/process.c12
-rw-r--r--arch/um/kernel/skas/syscall.c10
-rw-r--r--arch/um/kernel/skas/uaccess.c4
-rw-r--r--arch/um/kernel/smp.c30
-rw-r--r--arch/um/kernel/syscall.c37
-rw-r--r--arch/um/kernel/sysrq.c2
-rw-r--r--arch/um/kernel/time.c4
-rw-r--r--arch/um/kernel/tlb.c8
-rw-r--r--arch/um/kernel/trap.c10
-rw-r--r--arch/um/kernel/um_arch.c14
-rw-r--r--arch/um/kernel/umid.c6
-rw-r--r--arch/um/kernel/uml.lds.S2
-rw-r--r--arch/um/os-Linux/aio.c8
-rw-r--r--arch/um/os-Linux/drivers/etap.h2
-rw-r--r--arch/um/os-Linux/drivers/ethertap_kern.c2
-rw-r--r--arch/um/os-Linux/drivers/ethertap_user.c6
-rw-r--r--arch/um/os-Linux/drivers/tuntap.h2
-rw-r--r--arch/um/os-Linux/drivers/tuntap_kern.c2
-rw-r--r--arch/um/os-Linux/drivers/tuntap_user.c4
-rw-r--r--arch/um/os-Linux/elf_aux.c6
-rw-r--r--arch/um/os-Linux/execvp.c4
-rw-r--r--arch/um/os-Linux/file.c2
-rw-r--r--arch/um/os-Linux/helper.c6
-rw-r--r--arch/um/os-Linux/irq.c6
-rw-r--r--arch/um/os-Linux/main.c10
-rw-r--r--arch/um/os-Linux/mem.c4
-rw-r--r--arch/um/os-Linux/process.c8
-rw-r--r--arch/um/os-Linux/registers.c6
-rw-r--r--arch/um/os-Linux/sigio.c10
-rw-r--r--arch/um/os-Linux/signal.c8
-rw-r--r--arch/um/os-Linux/skas/mem.c20
-rw-r--r--arch/um/os-Linux/skas/process.c22
-rw-r--r--arch/um/os-Linux/start_up.c14
-rw-r--r--arch/um/os-Linux/time.c4
-rw-r--r--arch/um/os-Linux/tty.c4
-rw-r--r--arch/um/os-Linux/umid.c4
-rw-r--r--arch/um/os-Linux/user_syms.c4
-rw-r--r--arch/um/os-Linux/util.c2
-rw-r--r--arch/um/sys-ppc/miscthings.c6
-rw-r--r--arch/um/sys-ppc/ptrace.c2
-rw-r--r--arch/um/sys-ppc/ptrace_user.c2
-rw-r--r--arch/um/sys-ppc/shared/sysdep/ptrace.h2
-rw-r--r--arch/um/sys-ppc/sigcontext.c2
-rw-r--r--arch/um/sys-ppc/sysrq.c4
-rw-r--r--arch/unicore32/Kconfig12
-rw-r--r--arch/unicore32/include/asm/Kbuild1
-rw-r--r--arch/unicore32/include/asm/exec.h15
-rw-r--r--arch/unicore32/include/asm/thread_info.h4
-rw-r--r--arch/unicore32/include/mach/regs-ost.h18
-rw-r--r--arch/unicore32/kernel/Makefile1
-rw-r--r--arch/unicore32/kernel/entry.S2
-rw-r--r--arch/unicore32/kernel/pwm.c263
-rw-r--r--arch/unicore32/kernel/signal.c1
-rw-r--r--arch/unicore32/kernel/sys.c1
-rw-r--r--arch/x86/Kconfig1
-rw-r--r--arch/x86/ia32/ia32entry.S2
-rw-r--r--arch/x86/ia32/sys_ia32.c15
-rw-r--r--arch/x86/include/asm/processor.h5
-rw-r--r--arch/x86/include/asm/sys_ia32.h2
-rw-r--r--arch/x86/include/asm/syscalls.h2
-rw-r--r--arch/x86/include/asm/thread_info.h2
-rw-r--r--arch/x86/include/asm/unistd.h2
-rw-r--r--arch/x86/kernel/Makefile2
-rw-r--r--arch/x86/kernel/asm-offsets.c3
-rw-r--r--arch/x86/kernel/entry_32.S43
-rw-r--r--arch/x86/kernel/entry_64.S74
-rw-r--r--arch/x86/kernel/process.c65
-rw-r--r--arch/x86/kernel/process_32.c37
-rw-r--r--arch/x86/kernel/process_64.c35
-rw-r--r--arch/x86/kernel/signal.c4
-rw-r--r--arch/x86/kernel/sys_i386_32.c40
-rw-r--r--arch/x86/kernel/vm86_32.c6
-rw-r--r--arch/x86/syscalls/syscall_32.tbl2
-rw-r--r--arch/x86/um/Kconfig1
-rw-r--r--arch/x86/um/asm/checksum.h144
-rw-r--r--arch/x86/um/asm/checksum_32.h140
-rw-r--r--arch/x86/um/asm/checksum_64.h125
-rw-r--r--arch/x86/um/asm/elf.h2
-rw-r--r--arch/x86/um/asm/ptrace.h58
-rw-r--r--arch/x86/um/asm/ptrace_32.h28
-rw-r--r--arch/x86/um/asm/ptrace_64.h46
-rw-r--r--arch/x86/um/bugs_32.c6
-rw-r--r--arch/x86/um/bugs_64.c2
-rw-r--r--arch/x86/um/fault.c2
-rw-r--r--arch/x86/um/ldt.c10
-rw-r--r--arch/x86/um/mem_64.c6
-rw-r--r--arch/x86/um/os-Linux/registers.c4
-rw-r--r--arch/x86/um/os-Linux/task_size.c2
-rw-r--r--arch/x86/um/os-Linux/tls.c2
-rw-r--r--arch/x86/um/ptrace_32.c8
-rw-r--r--arch/x86/um/ptrace_user.c2
-rw-r--r--arch/x86/um/shared/sysdep/ptrace.h2
-rw-r--r--arch/x86/um/shared/sysdep/stub.h4
-rw-r--r--arch/x86/um/shared/sysdep/syscalls_32.h4
-rw-r--r--arch/x86/um/signal.c4
-rw-r--r--arch/x86/um/stub_32.S2
-rw-r--r--arch/x86/um/stub_64.S2
-rw-r--r--arch/x86/um/stub_segv.c6
-rw-r--r--arch/x86/um/sys_call_table_32.c1
-rw-r--r--arch/x86/um/sysrq_32.c12
-rw-r--r--arch/x86/um/sysrq_64.c2
-rw-r--r--arch/x86/um/tls_32.c12
-rw-r--r--arch/x86/um/tls_64.c2
-rw-r--r--arch/xtensa/include/asm/Kbuild1
-rw-r--r--arch/xtensa/include/asm/exec.h14
-rw-r--r--arch/xtensa/include/asm/thread_info.h5
-rw-r--r--arch/xtensa/kernel/signal.c4
-rw-r--r--block/blk-core.c51
-rw-r--r--block/blk-lib.c104
-rw-r--r--block/blk-merge.c53
-rw-r--r--block/blk-settings.c16
-rw-r--r--block/blk-sysfs.c44
-rw-r--r--block/blk-tag.c6
-rw-r--r--block/blk.h5
-rw-r--r--block/elevator.c6
-rw-r--r--block/ioctl.c27
-rw-r--r--drivers/block/drbd/drbd_main.c13
-rw-r--r--drivers/block/osdblk.c3
-rw-r--r--drivers/block/pktcdvd.c52
-rw-r--r--drivers/char/ds1620.c8
-rw-r--r--drivers/char/nwflash.c4
-rw-r--r--drivers/char/raw.c2
-rw-r--r--drivers/cpufreq/omap-cpufreq.c36
-rw-r--r--drivers/dma/Kconfig17
-rw-r--r--drivers/dma/Makefile2
-rw-r--r--drivers/dma/amba-pl08x.c2
-rw-r--r--drivers/dma/dw_dmac.c258
-rw-r--r--drivers/dma/dw_dmac_regs.h48
-rw-r--r--drivers/dma/edma.c671
-rw-r--r--drivers/dma/ioat/dma_v2.c3
-rw-r--r--drivers/dma/ioat/pci.c22
-rw-r--r--drivers/dma/mmp_pdma.c875
-rw-r--r--drivers/dma/mmp_tdma.c51
-rw-r--r--drivers/dma/mxs-dma.c14
-rw-r--r--drivers/dma/pl330.c78
-rw-r--r--drivers/dma/sirf-dma.c23
-rw-r--r--drivers/dma/ste_dma40.c14
-rw-r--r--drivers/dma/tegra20-apb-dma.c12
-rw-r--r--drivers/firewire/core-cdev.c4
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_fimd.c2
-rw-r--r--drivers/gpu/drm/nouveau/core/core/parent.c17
-rw-r--r--drivers/gpu/drm/nouveau/core/include/core/parent.h3
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/timer.h2
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/bios/base.c21
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/clock/nv50.c1
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/therm/nv50.c2
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/timer/nv04.c2
-rw-r--r--drivers/hwmon/acpi_power_meter.c1
-rw-r--r--drivers/hwmon/adm9240.c1
-rw-r--r--drivers/hwmon/adt7411.c1
-rw-r--r--drivers/hwmon/adt7462.c1
-rw-r--r--drivers/hwmon/adt7475.c1
-rw-r--r--drivers/hwmon/applesmc.c1
-rw-r--r--drivers/hwmon/asus_atk0110.c2
-rw-r--r--drivers/hwmon/da9052-hwmon.c1
-rw-r--r--drivers/hwmon/emc1403.c1
-rw-r--r--drivers/hwmon/emc6w201.c1
-rw-r--r--drivers/hwmon/hih6130.c1
-rw-r--r--drivers/hwmon/i5k_amb.c2
-rw-r--r--drivers/hwmon/ibmaem.c1
-rw-r--r--drivers/hwmon/ibmpex.c1
-rw-r--r--drivers/hwmon/ina2xx.c1
-rw-r--r--drivers/hwmon/k8temp.c1
-rw-r--r--drivers/hwmon/lineage-pem.c1
-rw-r--r--drivers/hwmon/lm92.c1
-rw-r--r--drivers/hwmon/lm93.c1
-rw-r--r--drivers/hwmon/ltc4151.c1
-rw-r--r--drivers/hwmon/ltc4215.c1
-rw-r--r--drivers/hwmon/ltc4245.c1
-rw-r--r--drivers/hwmon/ltc4261.c1
-rw-r--r--drivers/hwmon/max16065.c1
-rw-r--r--drivers/hwmon/max1619.c4
-rw-r--r--drivers/hwmon/max6642.c2
-rw-r--r--drivers/hwmon/pmbus/pmbus_core.c2
-rw-r--r--drivers/hwmon/s3c-hwmon.c1
-rw-r--r--drivers/hwmon/sht21.c1
-rw-r--r--drivers/hwmon/smm665.c1
-rw-r--r--drivers/hwmon/thmc50.c1
-rw-r--r--drivers/hwmon/tmp102.c1
-rw-r--r--drivers/hwmon/ultra45_env.c1
-rw-r--r--drivers/hwmon/w83791d.c1
-rw-r--r--drivers/hwmon/w83792d.c1
-rw-r--r--drivers/hwmon/w83793.c1
-rw-r--r--drivers/hwmon/w83795.c2
-rw-r--r--drivers/hwmon/w83l786ng.c1
-rw-r--r--drivers/i2c/algos/i2c-algo-pca.c27
-rw-r--r--drivers/i2c/busses/Kconfig27
-rw-r--r--drivers/i2c/busses/Makefile1
-rw-r--r--drivers/i2c/busses/i2c-at91.c667
-rw-r--r--drivers/i2c/busses/i2c-davinci.c58
-rw-r--r--drivers/i2c/busses/i2c-imx.c6
-rw-r--r--drivers/i2c/busses/i2c-mpc.c18
-rw-r--r--drivers/i2c/busses/i2c-mxs.c269
-rw-r--r--drivers/i2c/busses/i2c-nomadik.c52
-rw-r--r--drivers/i2c/busses/i2c-omap.c474
-rw-r--r--drivers/i2c/busses/i2c-rcar.c709
-rw-r--r--drivers/i2c/busses/i2c-s3c2410.c18
-rw-r--r--drivers/infiniband/core/cma.c3
-rw-r--r--drivers/infiniband/core/netlink.c1
-rw-r--r--drivers/infiniband/ulp/srpt/ib_srpt.c12
-rw-r--r--drivers/leds/Kconfig26
-rw-r--r--drivers/leds/Makefile3
-rw-r--r--drivers/leds/led-class.c15
-rw-r--r--drivers/leds/led-core.c16
-rw-r--r--drivers/leds/led-triggers.c17
-rw-r--r--drivers/leds/leds-clevo-mail.c10
-rw-r--r--drivers/leds/leds-gpio.c19
-rw-r--r--drivers/leds/leds-lm3530.c16
-rw-r--r--drivers/leds/leds-lm3556.c512
-rw-r--r--drivers/leds/leds-lm355x.c572
-rw-r--r--drivers/leds/leds-lm3642.c462
-rw-r--r--drivers/leds/leds-lp5523.c75
-rw-r--r--drivers/leds/leds-pca9633.c19
-rw-r--r--drivers/leds/leds-wm8350.c29
-rw-r--r--drivers/leds/leds.h2
-rw-r--r--drivers/md/dm-crypt.c16
-rw-r--r--drivers/md/dm-io.c11
-rw-r--r--drivers/md/dm.c74
-rw-r--r--drivers/md/md.c44
-rw-r--r--drivers/md/raid0.c1
-rw-r--r--drivers/media/platform/omap/omap_vout.c75
-rw-r--r--drivers/misc/Kconfig10
-rw-r--r--drivers/misc/Makefile1
-rw-r--r--drivers/mmc/core/core.c240
-rw-r--r--drivers/mmc/core/debugfs.c2
-rw-r--r--drivers/mmc/core/mmc.c57
-rw-r--r--drivers/mmc/core/mmc_ops.c84
-rw-r--r--drivers/mmc/core/sdio_bus.c7
-rw-r--r--drivers/mmc/core/slot-gpio.c8
-rw-r--r--drivers/mmc/host/Kconfig9
-rw-r--r--drivers/mmc/host/Makefile1
-rw-r--r--drivers/mmc/host/atmel-mci-regs.h7
-rw-r--r--drivers/mmc/host/atmel-mci.c113
-rw-r--r--drivers/mmc/host/bfin_sdh.c210
-rw-r--r--drivers/mmc/host/davinci_mmc.c271
-rw-r--r--drivers/mmc/host/dw_mmc-exynos.c253
-rw-r--r--drivers/mmc/host/dw_mmc-pci.c15
-rw-r--r--drivers/mmc/host/dw_mmc-pltfm.c62
-rw-r--r--drivers/mmc/host/dw_mmc-pltfm.h20
-rw-r--r--drivers/mmc/host/dw_mmc.c326
-rw-r--r--drivers/mmc/host/dw_mmc.h24
-rw-r--r--drivers/mmc/host/mmc_spi.c15
-rw-r--r--drivers/mmc/host/mmci.c13
-rw-r--r--drivers/mmc/host/mxcmmc.c76
-rw-r--r--drivers/mmc/host/omap.c37
-rw-r--r--drivers/mmc/host/omap_hsmmc.c125
-rw-r--r--drivers/mmc/host/pxamci.c52
-rw-r--r--drivers/mmc/host/sdhci-dove.c8
-rw-r--r--drivers/mmc/host/sdhci-of-esdhc.c36
-rw-r--r--drivers/mmc/host/sdhci-pci.c19
-rw-r--r--drivers/mmc/host/sdhci-pltfm.c3
-rw-r--r--drivers/mmc/host/sdhci-pxav2.c6
-rw-r--r--drivers/mmc/host/sdhci-pxav3.c35
-rw-r--r--drivers/mmc/host/sdhci-s3c.c216
-rw-r--r--drivers/mmc/host/sdhci-spear.c67
-rw-r--r--drivers/mmc/host/sdhci-tegra.c8
-rw-r--r--drivers/mmc/host/sdhci.c205
-rw-r--r--drivers/mmc/host/sh_mmcif.c8
-rw-r--r--drivers/mmc/host/via-sdmmc.c16
-rw-r--r--drivers/mmc/host/vub300.c4
-rw-r--r--drivers/mtd/Kconfig7
-rw-r--r--drivers/mtd/Makefile1
-rw-r--r--drivers/mtd/bcm47xxpart.c202
-rw-r--r--drivers/mtd/chips/Kconfig11
-rw-r--r--drivers/mtd/chips/cfi_cmdset_0001.c14
-rw-r--r--drivers/mtd/chips/cfi_cmdset_0002.c67
-rw-r--r--drivers/mtd/cmdlinepart.c183
-rw-r--r--drivers/mtd/devices/Kconfig10
-rw-r--r--drivers/mtd/devices/Makefile1
-rw-r--r--drivers/mtd/devices/bcm47xxsflash.c105
-rw-r--r--drivers/mtd/devices/doc2001plus.c14
-rw-r--r--drivers/mtd/devices/docg3.c12
-rw-r--r--drivers/mtd/devices/m25p80.c24
-rw-r--r--drivers/mtd/devices/spear_smi.c141
-rw-r--r--drivers/mtd/maps/Kconfig16
-rw-r--r--drivers/mtd/maps/Makefile1
-rw-r--r--drivers/mtd/maps/autcpu12-nvram.c153
-rw-r--r--drivers/mtd/maps/pci.c23
-rw-r--r--drivers/mtd/maps/physmap_of.c14
-rw-r--r--drivers/mtd/maps/rbtx4939-flash.c2
-rw-r--r--drivers/mtd/maps/uclinux.c15
-rw-r--r--drivers/mtd/maps/wr_sbc82xx_flash.c174
-rw-r--r--drivers/mtd/mtdchar.c6
-rw-r--r--drivers/mtd/mtdcore.c21
-rw-r--r--drivers/mtd/mtdoops.c14
-rw-r--r--drivers/mtd/mtdpart.c5
-rw-r--r--drivers/mtd/nand/Kconfig63
-rw-r--r--drivers/mtd/nand/Makefile4
-rw-r--r--drivers/mtd/nand/ams-delta.c13
-rw-r--r--drivers/mtd/nand/atmel_nand.c987
-rw-r--r--drivers/mtd/nand/atmel_nand_ecc.h114
-rw-r--r--drivers/mtd/nand/au1550nd.c46
-rw-r--r--drivers/mtd/nand/bcm_umi_bch.c217
-rw-r--r--drivers/mtd/nand/bcm_umi_nand.c555
-rw-r--r--drivers/mtd/nand/bf5xx_nand.c6
-rw-r--r--drivers/mtd/nand/cafe_nand.c20
-rw-r--r--drivers/mtd/nand/cmx270_nand.c13
-rw-r--r--drivers/mtd/nand/davinci_nand.c78
-rw-r--r--drivers/mtd/nand/denali.c12
-rw-r--r--drivers/mtd/nand/diskonchip.c63
-rw-r--r--drivers/mtd/nand/docg4.c43
-rw-r--r--drivers/mtd/nand/fsl_elbc_nand.c51
-rw-r--r--drivers/mtd/nand/fsl_ifc_nand.c52
-rw-r--r--drivers/mtd/nand/gpio.c54
-rw-r--r--drivers/mtd/nand/gpmi-nand/gpmi-lib.c322
-rw-r--r--drivers/mtd/nand/gpmi-nand/gpmi-nand.c152
-rw-r--r--drivers/mtd/nand/gpmi-nand/gpmi-nand.h26
-rw-r--r--drivers/mtd/nand/gpmi-nand/gpmi-regs.h12
-rw-r--r--drivers/mtd/nand/lpc32xx_mlc.c924
-rw-r--r--drivers/mtd/nand/lpc32xx_slc.c1039
-rw-r--r--drivers/mtd/nand/mpc5121_nfc.c22
-rw-r--r--drivers/mtd/nand/mxc_nand.c168
-rw-r--r--drivers/mtd/nand/nand_base.c529
-rw-r--r--drivers/mtd/nand/nand_bbt.c148
-rw-r--r--drivers/mtd/nand/nand_bcm_umi.c149
-rw-r--r--drivers/mtd/nand/nand_bcm_umi.h336
-rw-r--r--drivers/mtd/nand/nand_ids.c7
-rw-r--r--drivers/mtd/nand/nandsim.c17
-rw-r--r--drivers/mtd/nand/ndfc.c13
-rw-r--r--drivers/mtd/nand/nuc900_nand.c17
-rw-r--r--drivers/mtd/nand/omap2.c36
-rw-r--r--drivers/mtd/nand/orion_nand.c1
-rw-r--r--drivers/mtd/nand/plat_nand.c5
-rw-r--r--drivers/mtd/nand/pxa3xx_nand.c12
-rw-r--r--drivers/mtd/nand/r852.c22
-rw-r--r--drivers/mtd/nand/s3c2410.c191
-rw-r--r--drivers/mtd/nand/sh_flctl.c327
-rw-r--r--drivers/mtd/nand/socrates_nand.c19
-rw-r--r--drivers/mtd/nand/tmio_nand.c13
-rw-r--r--drivers/mtd/nand/txx9ndfmc.c13
-rw-r--r--drivers/mtd/nand/xway_nand.c201
-rw-r--r--drivers/mtd/sm_ftl.c1
-rw-r--r--drivers/mtd/tests/Makefile1
-rw-r--r--drivers/mtd/tests/mtd_nandbiterrs.c460
-rw-r--r--drivers/mtd/tests/mtd_nandecctest.c294
-rw-r--r--drivers/mtd/tests/mtd_speedtest.c16
-rw-r--r--drivers/mtd/tests/mtd_stresstest.c39
-rw-r--r--drivers/net/ethernet/amd/amd8111e.c2
-rw-r--r--drivers/net/ethernet/amd/au1000_eth.c10
-rw-r--r--drivers/net/ethernet/calxeda/xgmac.c19
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/cxgb4.h1
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c54
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/t4_hw.c15
-rw-r--r--drivers/net/ethernet/dec/tulip/dmfe.c12
-rw-r--r--drivers/net/ethernet/emulex/benet/be_main.c7
-rw-r--r--drivers/net/ethernet/freescale/gianfar.c27
-rw-r--r--drivers/net/ethernet/freescale/gianfar.h2
-rw-r--r--drivers/net/ethernet/freescale/ucc_geth.c29
-rw-r--r--drivers/net/ethernet/freescale/ucc_geth.h2
-rw-r--r--drivers/net/ethernet/intel/e1000e/hw.h2
-rw-r--r--drivers/net/ethernet/intel/e1000e/netdev.c2
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe.h2
-rw-r--r--drivers/net/ethernet/intel/ixgbevf/ixgbevf.h2
-rw-r--r--drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c7
-rw-r--r--drivers/net/ethernet/marvell/mv643xx_eth.c18
-rw-r--r--drivers/net/ethernet/marvell/skge.c13
-rw-r--r--drivers/net/ethernet/marvell/sky2.c5
-rw-r--r--drivers/net/ethernet/natsemi/natsemi.c4
-rw-r--r--drivers/net/ethernet/natsemi/xtsonic.c1
-rw-r--r--drivers/net/ethernet/oki-semi/pch_gbe/Kconfig3
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c3
-rw-r--r--drivers/net/ethernet/realtek/8139cp.c2
-rw-r--r--drivers/net/ethernet/renesas/sh_eth.c1
-rw-r--r--drivers/net/ethernet/sfc/ptp.c9
-rw-r--r--drivers/net/ethernet/sis/sis900.c4
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac.h1
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_main.c20
-rw-r--r--drivers/net/ethernet/sun/niu.c1
-rw-r--r--drivers/net/ethernet/sun/sungem.c3
-rw-r--r--drivers/net/irda/irtty-sir.c4
-rw-r--r--drivers/net/irda/mcs7780.c4
-rw-r--r--drivers/net/irda/pxaficp_ir.c4
-rw-r--r--drivers/net/irda/sa1100_ir.c4
-rw-r--r--drivers/net/irda/sh_irda.c4
-rw-r--r--drivers/net/irda/sh_sir.c5
-rw-r--r--drivers/net/phy/mdio_bus.c1
-rw-r--r--drivers/net/vxlan.c5
-rw-r--r--drivers/net/wan/farsync.c2
-rw-r--r--drivers/power/avs/smartreflex.c8
-rw-r--r--drivers/pwm/Kconfig29
-rw-r--r--drivers/pwm/Makefile3
-rw-r--r--drivers/pwm/core.c82
-rw-r--r--drivers/pwm/pwm-ab8500.c (renamed from drivers/misc/ab8500-pwm.c)116
-rw-r--r--drivers/pwm/pwm-bfin.c3
-rw-r--r--drivers/pwm/pwm-imx.c278
-rw-r--r--drivers/pwm/pwm-jz4740.c221
-rw-r--r--drivers/pwm/pwm-puv3.c161
-rw-r--r--drivers/pwm/pwm-pxa.c3
-rw-r--r--drivers/pwm/pwm-samsung.c3
-rw-r--r--drivers/pwm/pwm-tiecap.c24
-rw-r--r--drivers/pwm/pwm-tiehrpwm.c75
-rw-r--r--drivers/rapidio/rio-scan.c40
-rw-r--r--drivers/rapidio/rio.c75
-rw-r--r--drivers/rtc/Kconfig3
-rw-r--r--drivers/s390/block/dcssblk.c52
-rw-r--r--drivers/s390/crypto/zcrypt_pcixcc.c1
-rw-r--r--drivers/scsi/qla2xxx/qla_target.c2
-rw-r--r--drivers/scsi/qla2xxx/tcm_qla2xxx.c15
-rw-r--r--drivers/spi/Kconfig1
-rw-r--r--drivers/spi/spi-davinci.c292
-rw-r--r--drivers/staging/omapdrm/omap_drv.c5
-rw-r--r--drivers/target/iscsi/iscsi_target.c196
-rw-r--r--drivers/target/iscsi/iscsi_target.h5
-rw-r--r--drivers/target/iscsi/iscsi_target_configfs.c42
-rw-r--r--drivers/target/iscsi/iscsi_target_core.h15
-rw-r--r--drivers/target/iscsi/iscsi_target_erl0.c94
-rw-r--r--drivers/target/iscsi/iscsi_target_erl1.c4
-rw-r--r--drivers/target/iscsi/iscsi_target_erl1.h4
-rw-r--r--drivers/target/iscsi/iscsi_target_erl2.c9
-rw-r--r--drivers/target/iscsi/iscsi_target_erl2.h2
-rw-r--r--drivers/target/iscsi/iscsi_target_login.c20
-rw-r--r--drivers/target/iscsi/iscsi_target_nego.c31
-rw-r--r--drivers/target/iscsi/iscsi_target_parameters.c71
-rw-r--r--drivers/target/iscsi/iscsi_target_parameters.h7
-rw-r--r--drivers/target/iscsi/iscsi_target_seq_pdu_list.c61
-rw-r--r--drivers/target/iscsi/iscsi_target_tmr.c31
-rw-r--r--drivers/target/iscsi/iscsi_target_tpg.c12
-rw-r--r--drivers/target/iscsi/iscsi_target_tq.c6
-rw-r--r--drivers/target/iscsi/iscsi_target_tq.h1
-rw-r--r--drivers/target/iscsi/iscsi_target_util.c16
-rw-r--r--drivers/target/iscsi/iscsi_target_util.h8
-rw-r--r--drivers/target/loopback/tcm_loop.c74
-rw-r--r--drivers/target/sbp/sbp_target.c27
-rw-r--r--drivers/target/target_core_alua.c2
-rw-r--r--drivers/target/target_core_configfs.c18
-rw-r--r--drivers/target/target_core_device.c16
-rw-r--r--drivers/target/target_core_fabric_configfs.c1
-rw-r--r--drivers/target/target_core_fabric_lib.c8
-rw-r--r--drivers/target/target_core_file.c43
-rw-r--r--drivers/target/target_core_file.h1
-rw-r--r--drivers/target/target_core_iblock.c26
-rw-r--r--drivers/target/target_core_pr.c14
-rw-r--r--drivers/target/target_core_pscsi.c2
-rw-r--r--drivers/target/target_core_sbc.c23
-rw-r--r--drivers/target/target_core_spc.c48
-rw-r--r--drivers/target/target_core_stat.c1
-rw-r--r--drivers/target/target_core_tpg.c2
-rw-r--r--drivers/target/target_core_transport.c268
-rw-r--r--drivers/target/tcm_fc/tfc_cmd.c1
-rw-r--r--drivers/target/tcm_fc/tfc_conf.c12
-rw-r--r--drivers/target/tcm_fc/tfc_io.c4
-rw-r--r--drivers/target/tcm_fc/tfc_sess.c1
-rw-r--r--drivers/usb/gadget/tcm_usb_gadget.c15
-rw-r--r--drivers/vfio/pci/vfio_pci.c7
-rw-r--r--drivers/vfio/pci/vfio_pci_intrs.c18
-rw-r--r--drivers/vhost/tcm_vhost.c81
-rw-r--r--drivers/vhost/tcm_vhost.h8
-rw-r--r--drivers/video/Kconfig15
-rw-r--r--drivers/video/Makefile2
-rw-r--r--drivers/video/amifb.c2
-rw-r--r--drivers/video/arcfb.c1
-rw-r--r--drivers/video/atmel_lcdfb.c5
-rw-r--r--drivers/video/backlight/pwm_bl.c7
-rw-r--r--drivers/video/bf537-lq035.c12
-rw-r--r--drivers/video/bf54x-lq043fb.c9
-rw-r--r--drivers/video/bfin-lq035q1-fb.c13
-rw-r--r--drivers/video/bfin-t350mcqb-fb.c1
-rw-r--r--drivers/video/bw2.c4
-rw-r--r--drivers/video/cg3.c3
-rw-r--r--drivers/video/cobalt_lcdfb.c5
-rw-r--r--drivers/video/console/font_mini_4x6.c2
-rw-r--r--drivers/video/console/font_sun8x16.c2
-rw-r--r--drivers/video/cyber2000fb.c4
-rw-r--r--drivers/video/da8xx-fb.c283
-rw-r--r--drivers/video/ep93xx-fb.c17
-rw-r--r--drivers/video/exynos/exynos_dp_core.c322
-rw-r--r--drivers/video/exynos/exynos_dp_core.h6
-rw-r--r--drivers/video/exynos/exynos_dp_reg.c58
-rw-r--r--drivers/video/exynos/exynos_dp_reg.h3
-rw-r--r--drivers/video/exynos/exynos_mipi_dsi.c9
-rw-r--r--drivers/video/exynos/exynos_mipi_dsi_common.c8
-rw-r--r--drivers/video/fsl-diu-fb.c10
-rw-r--r--drivers/video/gbefb.c17
-rw-r--r--drivers/video/hpfb.c28
-rw-r--r--drivers/video/imxfb.c1
-rw-r--r--drivers/video/jz4740_fb.c44
-rw-r--r--drivers/video/mb862xx/mb862xxfbdrv.c10
-rw-r--r--drivers/video/mbx/mbxfb.c25
-rw-r--r--drivers/video/msm/mddi.c3
-rw-r--r--drivers/video/msm/mddi_client_nt35399.c6
-rw-r--r--drivers/video/msm/mdp.c1
-rw-r--r--drivers/video/msm/mdp_hw.h1
-rw-r--r--drivers/video/mx3fb.c3
-rw-r--r--drivers/video/nuc900fb.c2
-rw-r--r--drivers/video/omap/hwa742.c1
-rw-r--r--drivers/video/omap/lcd_palmte.c1
-rw-r--r--drivers/video/omap/omapfb_main.c9
-rw-r--r--drivers/video/omap2/displays/panel-acx565akm.c14
-rw-r--r--drivers/video/omap2/displays/panel-generic-dpi.c76
-rw-r--r--drivers/video/omap2/displays/panel-lgphilips-lb035q02.c3
-rw-r--r--drivers/video/omap2/displays/panel-n8x0.c31
-rw-r--r--drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c3
-rw-r--r--drivers/video/omap2/displays/panel-picodlp.c4
-rw-r--r--drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c3
-rw-r--r--drivers/video/omap2/displays/panel-taal.c239
-rw-r--r--drivers/video/omap2/displays/panel-tfp410.c20
-rw-r--r--drivers/video/omap2/displays/panel-tpo-td043mtea1.c7
-rw-r--r--drivers/video/omap2/dss/Kconfig2
-rw-r--r--drivers/video/omap2/dss/Makefile4
-rw-r--r--drivers/video/omap2/dss/apply.c330
-rw-r--r--drivers/video/omap2/dss/core.c91
-rw-r--r--drivers/video/omap2/dss/dispc.c1018
-rw-r--r--drivers/video/omap2/dss/dispc.h37
-rw-r--r--drivers/video/omap2/dss/display.c108
-rw-r--r--drivers/video/omap2/dss/dpi.c181
-rw-r--r--drivers/video/omap2/dss/dsi.c675
-rw-r--r--drivers/video/omap2/dss/dss.c257
-rw-r--r--drivers/video/omap2/dss/dss.h79
-rw-r--r--drivers/video/omap2/dss/dss_features.c278
-rw-r--r--drivers/video/omap2/dss/dss_features.h7
-rw-r--r--drivers/video/omap2/dss/hdmi.c247
-rw-r--r--drivers/video/omap2/dss/hdmi_panel.c31
-rw-r--r--drivers/video/omap2/dss/manager-sysfs.c512
-rw-r--r--drivers/video/omap2/dss/manager.c473
-rw-r--r--drivers/video/omap2/dss/output.c148
-rw-r--r--drivers/video/omap2/dss/overlay-sysfs.c456
-rw-r--r--drivers/video/omap2/dss/overlay.c492
-rw-r--r--drivers/video/omap2/dss/rfbi.c222
-rw-r--r--drivers/video/omap2/dss/sdi.c126
-rw-r--r--drivers/video/omap2/dss/venc.c337
-rw-r--r--drivers/video/omap2/dss/venc_panel.c251
-rw-r--r--drivers/video/omap2/omapfb/omapfb-ioctl.c7
-rw-r--r--drivers/video/omap2/omapfb/omapfb-main.c32
-rw-r--r--drivers/video/omap2/omapfb/omapfb.h5
-rw-r--r--drivers/video/omap2/vram.c56
-rw-r--r--drivers/video/pnx4008/Makefile7
-rw-r--r--drivers/video/pnx4008/dum.h211
-rw-r--r--drivers/video/pnx4008/fbcommon.h43
-rw-r--r--drivers/video/pnx4008/pnxrgbfb.c198
-rw-r--r--drivers/video/pnx4008/sdum.c861
-rw-r--r--drivers/video/pnx4008/sdum.h136
-rw-r--r--drivers/video/ps3fb.c7
-rw-r--r--drivers/video/s3c-fb.c54
-rw-r--r--drivers/video/s3c2410fb.c34
-rw-r--r--drivers/video/savage/savagefb_driver.c4
-rw-r--r--drivers/video/sis/initextlfb.c2
-rw-r--r--drivers/video/sunxvr1000.c4
-rw-r--r--drivers/video/sunxvr2500.c4
-rw-r--r--drivers/video/sunxvr500.c8
-rw-r--r--drivers/video/udlfb.c2
-rw-r--r--drivers/video/uvesafb.c2
-rw-r--r--drivers/video/vermilion/vermilion.c3
-rw-r--r--drivers/video/via/via_clock.c19
-rw-r--r--fs/9p/v9fs.c30
-rw-r--r--fs/9p/vfs_inode.c8
-rw-r--r--fs/autofs4/root.c6
-rw-r--r--fs/binfmt_elf.c1
-rw-r--r--fs/binfmt_elf_fdpic.c1
-rw-r--r--fs/bio-integrity.c44
-rw-r--r--fs/bio.c231
-rw-r--r--fs/block_dev.c68
-rw-r--r--fs/btrfs/backref.c299
-rw-r--r--fs/btrfs/backref.h10
-rw-r--r--fs/btrfs/btrfs_inode.h15
-rw-r--r--fs/btrfs/check-integrity.c16
-rw-r--r--fs/btrfs/compression.c13
-rw-r--r--fs/btrfs/ctree.c148
-rw-r--r--fs/btrfs/ctree.h109
-rw-r--r--fs/btrfs/delayed-inode.c6
-rw-r--r--fs/btrfs/disk-io.c230
-rw-r--r--fs/btrfs/disk-io.h2
-rw-r--r--fs/btrfs/extent-tree.c376
-rw-r--r--fs/btrfs/extent_io.c128
-rw-r--r--fs/btrfs/extent_io.h23
-rw-r--r--fs/btrfs/extent_map.c55
-rw-r--r--fs/btrfs/extent_map.h8
-rw-r--r--fs/btrfs/file-item.c5
-rw-r--r--fs/btrfs/file.c447
-rw-r--r--fs/btrfs/free-space-cache.c10
-rw-r--r--fs/btrfs/hash.h10
-rw-r--r--fs/btrfs/inode-item.c285
-rw-r--r--fs/btrfs/inode.c386
-rw-r--r--fs/btrfs/ioctl.c100
-rw-r--r--fs/btrfs/ordered-data.c97
-rw-r--r--fs/btrfs/ordered-data.h12
-rw-r--r--fs/btrfs/qgroup.c40
-rw-r--r--fs/btrfs/relocation.c11
-rw-r--r--fs/btrfs/root-tree.c29
-rw-r--r--fs/btrfs/scrub.c30
-rw-r--r--fs/btrfs/send.c915
-rw-r--r--fs/btrfs/send.h1
-rw-r--r--fs/btrfs/super.c74
-rw-r--r--fs/btrfs/transaction.c283
-rw-r--r--fs/btrfs/transaction.h20
-rw-r--r--fs/btrfs/tree-log.c889
-rw-r--r--fs/btrfs/ulist.c7
-rw-r--r--fs/btrfs/ulist.h9
-rw-r--r--fs/btrfs/volumes.c73
-rw-r--r--fs/btrfs/zlib.c8
-rw-r--r--fs/cifs/cifs_unicode.c22
-rw-r--r--fs/cifs/connect.c9
-rw-r--r--fs/cifs/transport.c6
-rw-r--r--fs/exec.c61
-rw-r--r--fs/exofs/ore.c5
-rw-r--r--fs/fs-writeback.c2
-rw-r--r--fs/hostfs/hostfs.h2
-rw-r--r--fs/hostfs/hostfs_kern.c12
-rw-r--r--fs/hostfs/hostfs_user.c1
-rw-r--r--fs/hppfs/hppfs.c4
-rw-r--r--fs/jffs2/super.c4
-rw-r--r--fs/jffs2/wbuf.c8
-rw-r--r--fs/lockd/mon.c86
-rw-r--r--fs/lockd/netns.h4
-rw-r--r--fs/lockd/svc.c1
-rw-r--r--fs/nfs/Kconfig4
-rw-r--r--fs/nfs/blocklayout/blocklayout.c306
-rw-r--r--fs/nfs/blocklayout/blocklayout.h2
-rw-r--r--fs/nfs/blocklayout/blocklayoutdev.c25
-rw-r--r--fs/nfs/blocklayout/extents.c3
-rw-r--r--fs/nfs/callback.c321
-rw-r--r--fs/nfs/callback.h3
-rw-r--r--fs/nfs/callback_proc.c31
-rw-r--r--fs/nfs/client.c23
-rw-r--r--fs/nfs/dir.c16
-rw-r--r--fs/nfs/direct.c32
-rw-r--r--fs/nfs/file.c41
-rw-r--r--fs/nfs/getroot.c2
-rw-r--r--fs/nfs/idmap.c114
-rw-r--r--fs/nfs/inode.c10
-rw-r--r--fs/nfs/internal.h15
-rw-r--r--fs/nfs/netns.h4
-rw-r--r--fs/nfs/nfs4_fs.h19
-rw-r--r--fs/nfs/nfs4client.c256
-rw-r--r--fs/nfs/nfs4file.c29
-rw-r--r--fs/nfs/nfs4filelayout.c41
-rw-r--r--fs/nfs/nfs4filelayout.h16
-rw-r--r--fs/nfs/nfs4filelayoutdev.c17
-rw-r--r--fs/nfs/nfs4namespace.c16
-rw-r--r--fs/nfs/nfs4proc.c342
-rw-r--r--fs/nfs/nfs4state.c228
-rw-r--r--fs/nfs/nfs4sysctl.c1
-rw-r--r--fs/nfs/nfs4xdr.c31
-rw-r--r--fs/nfs/objlayout/objio_osd.c9
-rw-r--r--fs/nfs/pagelist.c12
-rw-r--r--fs/nfs/pnfs.c417
-rw-r--r--fs/nfs/pnfs.h57
-rw-r--r--fs/nfs/pnfs_dev.c27
-rw-r--r--fs/nfs/super.c31
-rw-r--r--fs/nfs/write.c11
-rw-r--r--include/linux/bcma/bcma_driver_chipcommon.h2
-rw-r--r--include/linux/binfmts.h6
-rw-r--r--include/linux/bio.h70
-rw-r--r--include/linux/blk_types.h36
-rw-r--r--include/linux/blkdev.h82
-rw-r--r--include/linux/caif/Kbuild2
-rw-r--r--include/linux/compat.h8
-rw-r--r--include/linux/compiler-gcc4.h2
-rw-r--r--include/linux/dw_dmac.h7
-rw-r--r--include/linux/edma.h29
-rw-r--r--include/linux/fs.h6
-rw-r--r--include/linux/i2c-algo-pca.h1
-rw-r--r--include/linux/i2c-omap.h1
-rw-r--r--include/linux/i2c/i2c-rcar.h10
-rw-r--r--include/linux/if_vlan.h8
-rw-r--r--include/linux/isdn/Kbuild1
-rw-r--r--include/linux/leds-lp5523.h1
-rw-r--r--include/linux/leds.h4
-rw-r--r--include/linux/memcontrol.h4
-rw-r--r--include/linux/mmc/card.h18
-rw-r--r--include/linux/mmc/core.h4
-rw-r--r--include/linux/mmc/dw_mmc.h15
-rw-r--r--include/linux/mmc/host.h5
-rw-r--r--include/linux/mmc/mmc.h19
-rw-r--r--include/linux/mmc/sdhci.h3
-rw-r--r--include/linux/mtd/bbm.h7
-rw-r--r--include/linux/mtd/lpc32xx_mlc.h20
-rw-r--r--include/linux/mtd/lpc32xx_slc.h20
-rw-r--r--include/linux/mtd/mtd.h9
-rw-r--r--include/linux/mtd/nand.h72
-rw-r--r--include/linux/mtd/sh_flctl.h23
-rw-r--r--include/linux/netdevice.h19
-rw-r--r--include/linux/netfilter/Kbuild77
-rw-r--r--include/linux/netfilter/ipset/Kbuild4
-rw-r--r--include/linux/netfilter/ipset/ip_set.h225
-rw-r--r--include/linux/netfilter/ipset/ip_set_bitmap.h11
-rw-r--r--include/linux/netfilter/ipset/ip_set_hash.h19
-rw-r--r--include/linux/netfilter/ipset/ip_set_list.h19
-rw-r--r--include/linux/netfilter/nf_conntrack_common.h115
-rw-r--r--include/linux/netfilter/nf_conntrack_ftp.h16
-rw-r--r--include/linux/netfilter/nf_conntrack_tcp.h49
-rw-r--r--include/linux/netfilter/nfnetlink.h55
-rw-r--r--include/linux/netfilter/nfnetlink_acct.h25
-rw-r--r--include/linux/netfilter/x_tables.h186
-rw-r--r--include/linux/netfilter/xt_hashlimit.h71
-rw-r--r--include/linux/netfilter/xt_physdev.h21
-rw-r--r--include/linux/netfilter_arp/Kbuild2
-rw-r--r--include/linux/netfilter_arp/arp_tables.h200
-rw-r--r--include/linux/netfilter_bridge/Kbuild18
-rw-r--r--include/linux/netfilter_bridge/ebt_802_3.h61
-rw-r--r--include/linux/netfilter_bridge/ebtables.h255
-rw-r--r--include/linux/netfilter_ipv4/Kbuild10
-rw-r--r--include/linux/netfilter_ipv4/ip_tables.h218
-rw-r--r--include/linux/netfilter_ipv6/Kbuild12
-rw-r--r--include/linux/netfilter_ipv6/ip6_tables.h256
-rw-r--r--include/linux/netlink.h20
-rw-r--r--include/linux/nfs_fs.h11
-rw-r--r--include/linux/nfs_fs_sb.h3
-rw-r--r--include/linux/nfs_xdr.h5
-rw-r--r--include/linux/pageblock-flags.h6
-rw-r--r--include/linux/percpu-rwsem.h89
-rw-r--r--include/linux/platform_data/i2c-nomadik.h2
-rw-r--r--include/linux/platform_data/leds-lm3556.h50
-rw-r--r--include/linux/platform_data/leds-lm355x.h66
-rw-r--r--include/linux/platform_data/leds-lm3642.h38
-rw-r--r--include/linux/platform_data/leds-pca9633.h35
-rw-r--r--include/linux/platform_data/mmp_dma.h19
-rw-r--r--include/linux/platform_data/pxa_sdhci.h1
-rw-r--r--include/linux/ptrace.h4
-rw-r--r--include/linux/pwm.h108
-rw-r--r--include/linux/rio.h3
-rw-r--r--include/linux/scatterlist.h1
-rw-r--r--include/linux/sched.h3
-rw-r--r--include/linux/skbuff.h24
-rw-r--r--include/linux/sunrpc/clnt.h2
-rw-r--r--include/linux/sunrpc/xprt.h3
-rw-r--r--include/linux/tc_act/Kbuild7
-rw-r--r--include/linux/tc_ematch/Kbuild4
-rw-r--r--include/mtd/Kbuild5
-rw-r--r--include/net/flow.h1
-rw-r--r--include/net/route.h3
-rw-r--r--include/rdma/rdma_netlink.h1
-rw-r--r--include/target/target_core_backend.h3
-rw-r--r--include/target/target_core_fabric.h5
-rw-r--r--include/trace/events/btrfs.h14
-rw-r--r--include/uapi/linux/caif/Kbuild2
-rw-r--r--include/uapi/linux/caif/caif_socket.h (renamed from include/linux/caif/caif_socket.h)0
-rw-r--r--include/uapi/linux/caif/if_caif.h (renamed from include/linux/caif/if_caif.h)0
-rw-r--r--include/uapi/linux/isdn/Kbuild1
-rw-r--r--include/uapi/linux/isdn/capicmd.h (renamed from include/linux/isdn/capicmd.h)0
-rw-r--r--include/uapi/linux/netfilter/Kbuild76
-rw-r--r--include/uapi/linux/netfilter/ipset/Kbuild4
-rw-r--r--include/uapi/linux/netfilter/ipset/ip_set.h231
-rw-r--r--include/uapi/linux/netfilter/ipset/ip_set_bitmap.h13
-rw-r--r--include/uapi/linux/netfilter/ipset/ip_set_hash.h21
-rw-r--r--include/uapi/linux/netfilter/ipset/ip_set_list.h21
-rw-r--r--include/uapi/linux/netfilter/nf_conntrack_common.h117
-rw-r--r--include/uapi/linux/netfilter/nf_conntrack_ftp.h18
-rw-r--r--include/uapi/linux/netfilter/nf_conntrack_sctp.h (renamed from include/linux/netfilter/nf_conntrack_sctp.h)0
-rw-r--r--include/uapi/linux/netfilter/nf_conntrack_tcp.h51
-rw-r--r--include/uapi/linux/netfilter/nf_conntrack_tuple_common.h (renamed from include/linux/netfilter/nf_conntrack_tuple_common.h)0
-rw-r--r--include/uapi/linux/netfilter/nf_nat.h (renamed from include/linux/netfilter/nf_nat.h)0
-rw-r--r--include/uapi/linux/netfilter/nfnetlink.h56
-rw-r--r--include/uapi/linux/netfilter/nfnetlink_acct.h27
-rw-r--r--include/uapi/linux/netfilter/nfnetlink_compat.h (renamed from include/linux/netfilter/nfnetlink_compat.h)0
-rw-r--r--include/uapi/linux/netfilter/nfnetlink_conntrack.h (renamed from include/linux/netfilter/nfnetlink_conntrack.h)0
-rw-r--r--include/uapi/linux/netfilter/nfnetlink_cthelper.h (renamed from include/linux/netfilter/nfnetlink_cthelper.h)0
-rw-r--r--include/uapi/linux/netfilter/nfnetlink_cttimeout.h (renamed from include/linux/netfilter/nfnetlink_cttimeout.h)0
-rw-r--r--include/uapi/linux/netfilter/nfnetlink_log.h (renamed from include/linux/netfilter/nfnetlink_log.h)0
-rw-r--r--include/uapi/linux/netfilter/nfnetlink_queue.h (renamed from include/linux/netfilter/nfnetlink_queue.h)0
-rw-r--r--include/uapi/linux/netfilter/x_tables.h187
-rw-r--r--include/uapi/linux/netfilter/xt_AUDIT.h (renamed from include/linux/netfilter/xt_AUDIT.h)0
-rw-r--r--include/uapi/linux/netfilter/xt_CHECKSUM.h (renamed from include/linux/netfilter/xt_CHECKSUM.h)0
-rw-r--r--include/uapi/linux/netfilter/xt_CLASSIFY.h (renamed from include/linux/netfilter/xt_CLASSIFY.h)0
-rw-r--r--include/uapi/linux/netfilter/xt_CONNMARK.h (renamed from include/linux/netfilter/xt_CONNMARK.h)0
-rw-r--r--include/uapi/linux/netfilter/xt_CONNSECMARK.h (renamed from include/linux/netfilter/xt_CONNSECMARK.h)0
-rw-r--r--include/uapi/linux/netfilter/xt_CT.h (renamed from include/linux/netfilter/xt_CT.h)0
-rw-r--r--include/uapi/linux/netfilter/xt_DSCP.h (renamed from include/linux/netfilter/xt_DSCP.h)0
-rw-r--r--include/uapi/linux/netfilter/xt_IDLETIMER.h (renamed from include/linux/netfilter/xt_IDLETIMER.h)0
-rw-r--r--include/uapi/linux/netfilter/xt_LED.h (renamed from include/linux/netfilter/xt_LED.h)0
-rw-r--r--include/uapi/linux/netfilter/xt_LOG.h (renamed from include/linux/netfilter/xt_LOG.h)0
-rw-r--r--include/uapi/linux/netfilter/xt_MARK.h (renamed from include/linux/netfilter/xt_MARK.h)0
-rw-r--r--include/uapi/linux/netfilter/xt_NFLOG.h (renamed from include/linux/netfilter/xt_NFLOG.h)0
-rw-r--r--include/uapi/linux/netfilter/xt_NFQUEUE.h (renamed from include/linux/netfilter/xt_NFQUEUE.h)0
-rw-r--r--include/uapi/linux/netfilter/xt_RATEEST.h (renamed from include/linux/netfilter/xt_RATEEST.h)0
-rw-r--r--include/uapi/linux/netfilter/xt_SECMARK.h (renamed from include/linux/netfilter/xt_SECMARK.h)0
-rw-r--r--include/uapi/linux/netfilter/xt_TCPMSS.h (renamed from include/linux/netfilter/xt_TCPMSS.h)0
-rw-r--r--include/uapi/linux/netfilter/xt_TCPOPTSTRIP.h (renamed from include/linux/netfilter/xt_TCPOPTSTRIP.h)0
-rw-r--r--include/uapi/linux/netfilter/xt_TEE.h (renamed from include/linux/netfilter/xt_TEE.h)0
-rw-r--r--include/uapi/linux/netfilter/xt_TPROXY.h (renamed from include/linux/netfilter/xt_TPROXY.h)0
-rw-r--r--include/uapi/linux/netfilter/xt_addrtype.h (renamed from include/linux/netfilter/xt_addrtype.h)0
-rw-r--r--include/uapi/linux/netfilter/xt_cluster.h (renamed from include/linux/netfilter/xt_cluster.h)0
-rw-r--r--include/uapi/linux/netfilter/xt_comment.h (renamed from include/linux/netfilter/xt_comment.h)0
-rw-r--r--include/uapi/linux/netfilter/xt_connbytes.h (renamed from include/linux/netfilter/xt_connbytes.h)0
-rw-r--r--include/uapi/linux/netfilter/xt_connlimit.h (renamed from include/linux/netfilter/xt_connlimit.h)0
-rw-r--r--include/uapi/linux/netfilter/xt_connmark.h (renamed from include/linux/netfilter/xt_connmark.h)0
-rw-r--r--include/uapi/linux/netfilter/xt_conntrack.h (renamed from include/linux/netfilter/xt_conntrack.h)0
-rw-r--r--include/uapi/linux/netfilter/xt_cpu.h (renamed from include/linux/netfilter/xt_cpu.h)0
-rw-r--r--include/uapi/linux/netfilter/xt_dccp.h (renamed from include/linux/netfilter/xt_dccp.h)0
-rw-r--r--include/uapi/linux/netfilter/xt_devgroup.h (renamed from include/linux/netfilter/xt_devgroup.h)0
-rw-r--r--include/uapi/linux/netfilter/xt_dscp.h (renamed from include/linux/netfilter/xt_dscp.h)0
-rw-r--r--include/uapi/linux/netfilter/xt_ecn.h (renamed from include/linux/netfilter/xt_ecn.h)0
-rw-r--r--include/uapi/linux/netfilter/xt_esp.h (renamed from include/linux/netfilter/xt_esp.h)0
-rw-r--r--include/uapi/linux/netfilter/xt_hashlimit.h73
-rw-r--r--include/uapi/linux/netfilter/xt_helper.h (renamed from include/linux/netfilter/xt_helper.h)0
-rw-r--r--include/uapi/linux/netfilter/xt_iprange.h (renamed from include/linux/netfilter/xt_iprange.h)0
-rw-r--r--include/uapi/linux/netfilter/xt_ipvs.h (renamed from include/linux/netfilter/xt_ipvs.h)0
-rw-r--r--include/uapi/linux/netfilter/xt_length.h (renamed from include/linux/netfilter/xt_length.h)0
-rw-r--r--include/uapi/linux/netfilter/xt_limit.h (renamed from include/linux/netfilter/xt_limit.h)0
-rw-r--r--include/uapi/linux/netfilter/xt_mac.h (renamed from include/linux/netfilter/xt_mac.h)0
-rw-r--r--include/uapi/linux/netfilter/xt_mark.h (renamed from include/linux/netfilter/xt_mark.h)0
-rw-r--r--include/uapi/linux/netfilter/xt_multiport.h (renamed from include/linux/netfilter/xt_multiport.h)0
-rw-r--r--include/uapi/linux/netfilter/xt_nfacct.h (renamed from include/linux/netfilter/xt_nfacct.h)0
-rw-r--r--include/uapi/linux/netfilter/xt_osf.h (renamed from include/linux/netfilter/xt_osf.h)0
-rw-r--r--include/uapi/linux/netfilter/xt_owner.h (renamed from include/linux/netfilter/xt_owner.h)0
-rw-r--r--include/uapi/linux/netfilter/xt_physdev.h23
-rw-r--r--include/uapi/linux/netfilter/xt_pkttype.h (renamed from include/linux/netfilter/xt_pkttype.h)0
-rw-r--r--include/uapi/linux/netfilter/xt_policy.h (renamed from include/linux/netfilter/xt_policy.h)0
-rw-r--r--include/uapi/linux/netfilter/xt_quota.h (renamed from include/linux/netfilter/xt_quota.h)0
-rw-r--r--include/uapi/linux/netfilter/xt_rateest.h (renamed from include/linux/netfilter/xt_rateest.h)0
-rw-r--r--include/uapi/linux/netfilter/xt_realm.h (renamed from include/linux/netfilter/xt_realm.h)0
-rw-r--r--include/uapi/linux/netfilter/xt_recent.h (renamed from include/linux/netfilter/xt_recent.h)0
-rw-r--r--include/uapi/linux/netfilter/xt_sctp.h (renamed from include/linux/netfilter/xt_sctp.h)0
-rw-r--r--include/uapi/linux/netfilter/xt_set.h (renamed from include/linux/netfilter/xt_set.h)0
-rw-r--r--include/uapi/linux/netfilter/xt_socket.h (renamed from include/linux/netfilter/xt_socket.h)0
-rw-r--r--include/uapi/linux/netfilter/xt_state.h (renamed from include/linux/netfilter/xt_state.h)0
-rw-r--r--include/uapi/linux/netfilter/xt_statistic.h (renamed from include/linux/netfilter/xt_statistic.h)0
-rw-r--r--include/uapi/linux/netfilter/xt_string.h (renamed from include/linux/netfilter/xt_string.h)0
-rw-r--r--include/uapi/linux/netfilter/xt_tcpmss.h (renamed from include/linux/netfilter/xt_tcpmss.h)0
-rw-r--r--include/uapi/linux/netfilter/xt_tcpudp.h (renamed from include/linux/netfilter/xt_tcpudp.h)0
-rw-r--r--include/uapi/linux/netfilter/xt_time.h (renamed from include/linux/netfilter/xt_time.h)0
-rw-r--r--include/uapi/linux/netfilter/xt_u32.h (renamed from include/linux/netfilter/xt_u32.h)0
-rw-r--r--include/uapi/linux/netfilter_arp/Kbuild2
-rw-r--r--include/uapi/linux/netfilter_arp/arp_tables.h206
-rw-r--r--include/uapi/linux/netfilter_arp/arpt_mangle.h (renamed from include/linux/netfilter_arp/arpt_mangle.h)0
-rw-r--r--include/uapi/linux/netfilter_bridge/Kbuild18
-rw-r--r--include/uapi/linux/netfilter_bridge/ebt_802_3.h62
-rw-r--r--include/uapi/linux/netfilter_bridge/ebt_among.h (renamed from include/linux/netfilter_bridge/ebt_among.h)0
-rw-r--r--include/uapi/linux/netfilter_bridge/ebt_arp.h (renamed from include/linux/netfilter_bridge/ebt_arp.h)0
-rw-r--r--include/uapi/linux/netfilter_bridge/ebt_arpreply.h (renamed from include/linux/netfilter_bridge/ebt_arpreply.h)0
-rw-r--r--include/uapi/linux/netfilter_bridge/ebt_ip.h (renamed from include/linux/netfilter_bridge/ebt_ip.h)0
-rw-r--r--include/uapi/linux/netfilter_bridge/ebt_ip6.h (renamed from include/linux/netfilter_bridge/ebt_ip6.h)0
-rw-r--r--include/uapi/linux/netfilter_bridge/ebt_limit.h (renamed from include/linux/netfilter_bridge/ebt_limit.h)0
-rw-r--r--include/uapi/linux/netfilter_bridge/ebt_log.h (renamed from include/linux/netfilter_bridge/ebt_log.h)0
-rw-r--r--include/uapi/linux/netfilter_bridge/ebt_mark_m.h (renamed from include/linux/netfilter_bridge/ebt_mark_m.h)0
-rw-r--r--include/uapi/linux/netfilter_bridge/ebt_mark_t.h (renamed from include/linux/netfilter_bridge/ebt_mark_t.h)0
-rw-r--r--include/uapi/linux/netfilter_bridge/ebt_nat.h (renamed from include/linux/netfilter_bridge/ebt_nat.h)0
-rw-r--r--include/uapi/linux/netfilter_bridge/ebt_nflog.h (renamed from include/linux/netfilter_bridge/ebt_nflog.h)0
-rw-r--r--include/uapi/linux/netfilter_bridge/ebt_pkttype.h (renamed from include/linux/netfilter_bridge/ebt_pkttype.h)0
-rw-r--r--include/uapi/linux/netfilter_bridge/ebt_redirect.h (renamed from include/linux/netfilter_bridge/ebt_redirect.h)0
-rw-r--r--include/uapi/linux/netfilter_bridge/ebt_stp.h (renamed from include/linux/netfilter_bridge/ebt_stp.h)0
-rw-r--r--include/uapi/linux/netfilter_bridge/ebt_ulog.h (renamed from include/linux/netfilter_bridge/ebt_ulog.h)0
-rw-r--r--include/uapi/linux/netfilter_bridge/ebt_vlan.h (renamed from include/linux/netfilter_bridge/ebt_vlan.h)0
-rw-r--r--include/uapi/linux/netfilter_bridge/ebtables.h268
-rw-r--r--include/uapi/linux/netfilter_ipv4/Kbuild10
-rw-r--r--include/uapi/linux/netfilter_ipv4/ip_tables.h229
-rw-r--r--include/uapi/linux/netfilter_ipv4/ipt_CLUSTERIP.h (renamed from include/linux/netfilter_ipv4/ipt_CLUSTERIP.h)0
-rw-r--r--include/uapi/linux/netfilter_ipv4/ipt_ECN.h (renamed from include/linux/netfilter_ipv4/ipt_ECN.h)0
-rw-r--r--include/uapi/linux/netfilter_ipv4/ipt_LOG.h (renamed from include/linux/netfilter_ipv4/ipt_LOG.h)0
-rw-r--r--include/uapi/linux/netfilter_ipv4/ipt_REJECT.h (renamed from include/linux/netfilter_ipv4/ipt_REJECT.h)0
-rw-r--r--include/uapi/linux/netfilter_ipv4/ipt_TTL.h (renamed from include/linux/netfilter_ipv4/ipt_TTL.h)0
-rw-r--r--include/uapi/linux/netfilter_ipv4/ipt_ULOG.h (renamed from include/linux/netfilter_ipv4/ipt_ULOG.h)0
-rw-r--r--include/uapi/linux/netfilter_ipv4/ipt_ah.h (renamed from include/linux/netfilter_ipv4/ipt_ah.h)0
-rw-r--r--include/uapi/linux/netfilter_ipv4/ipt_ecn.h (renamed from include/linux/netfilter_ipv4/ipt_ecn.h)0
-rw-r--r--include/uapi/linux/netfilter_ipv4/ipt_ttl.h (renamed from include/linux/netfilter_ipv4/ipt_ttl.h)0
-rw-r--r--include/uapi/linux/netfilter_ipv6/Kbuild12
-rw-r--r--include/uapi/linux/netfilter_ipv6/ip6_tables.h267
-rw-r--r--include/uapi/linux/netfilter_ipv6/ip6t_HL.h (renamed from include/linux/netfilter_ipv6/ip6t_HL.h)0
-rw-r--r--include/uapi/linux/netfilter_ipv6/ip6t_LOG.h (renamed from include/linux/netfilter_ipv6/ip6t_LOG.h)0
-rw-r--r--include/uapi/linux/netfilter_ipv6/ip6t_NPT.h (renamed from include/linux/netfilter_ipv6/ip6t_NPT.h)0
-rw-r--r--include/uapi/linux/netfilter_ipv6/ip6t_REJECT.h (renamed from include/linux/netfilter_ipv6/ip6t_REJECT.h)0
-rw-r--r--include/uapi/linux/netfilter_ipv6/ip6t_ah.h (renamed from include/linux/netfilter_ipv6/ip6t_ah.h)0
-rw-r--r--include/uapi/linux/netfilter_ipv6/ip6t_frag.h (renamed from include/linux/netfilter_ipv6/ip6t_frag.h)0
-rw-r--r--include/uapi/linux/netfilter_ipv6/ip6t_hl.h (renamed from include/linux/netfilter_ipv6/ip6t_hl.h)0
-rw-r--r--include/uapi/linux/netfilter_ipv6/ip6t_ipv6header.h (renamed from include/linux/netfilter_ipv6/ip6t_ipv6header.h)0
-rw-r--r--include/uapi/linux/netfilter_ipv6/ip6t_mh.h (renamed from include/linux/netfilter_ipv6/ip6t_mh.h)0
-rw-r--r--include/uapi/linux/netfilter_ipv6/ip6t_opts.h (renamed from include/linux/netfilter_ipv6/ip6t_opts.h)0
-rw-r--r--include/uapi/linux/netfilter_ipv6/ip6t_rt.h (renamed from include/linux/netfilter_ipv6/ip6t_rt.h)0
-rw-r--r--include/uapi/linux/tc_act/Kbuild7
-rw-r--r--include/uapi/linux/tc_act/tc_csum.h (renamed from include/linux/tc_act/tc_csum.h)0
-rw-r--r--include/uapi/linux/tc_act/tc_gact.h (renamed from include/linux/tc_act/tc_gact.h)0
-rw-r--r--include/uapi/linux/tc_act/tc_ipt.h (renamed from include/linux/tc_act/tc_ipt.h)0
-rw-r--r--include/uapi/linux/tc_act/tc_mirred.h (renamed from include/linux/tc_act/tc_mirred.h)0
-rw-r--r--include/uapi/linux/tc_act/tc_nat.h (renamed from include/linux/tc_act/tc_nat.h)0
-rw-r--r--include/uapi/linux/tc_act/tc_pedit.h (renamed from include/linux/tc_act/tc_pedit.h)0
-rw-r--r--include/uapi/linux/tc_act/tc_skbedit.h (renamed from include/linux/tc_act/tc_skbedit.h)0
-rw-r--r--include/uapi/linux/tc_ematch/Kbuild4
-rw-r--r--include/uapi/linux/tc_ematch/tc_em_cmp.h (renamed from include/linux/tc_ematch/tc_em_cmp.h)0
-rw-r--r--include/uapi/linux/tc_ematch/tc_em_meta.h (renamed from include/linux/tc_ematch/tc_em_meta.h)0
-rw-r--r--include/uapi/linux/tc_ematch/tc_em_nbyte.h (renamed from include/linux/tc_ematch/tc_em_nbyte.h)0
-rw-r--r--include/uapi/linux/tc_ematch/tc_em_text.h (renamed from include/linux/tc_ematch/tc_em_text.h)0
-rw-r--r--include/uapi/mtd/Kbuild5
-rw-r--r--include/uapi/mtd/inftl-user.h (renamed from include/mtd/inftl-user.h)0
-rw-r--r--include/uapi/mtd/mtd-abi.h (renamed from include/mtd/mtd-abi.h)0
-rw-r--r--include/uapi/mtd/mtd-user.h (renamed from include/mtd/mtd-user.h)0
-rw-r--r--include/uapi/mtd/nftl-user.h (renamed from include/mtd/nftl-user.h)0
-rw-r--r--include/uapi/mtd/ubi-user.h (renamed from include/mtd/ubi-user.h)0
-rw-r--r--include/video/omapdss.h112
-rw-r--r--include/video/samsung_fimd.h (renamed from arch/arm/plat-samsung/include/plat/regs-fb.h)152
-rw-r--r--kernel/fork.c13
-rw-r--r--kernel/sched/core.c2
-rw-r--r--lib/kasprintf.c2
-rw-r--r--lib/scatterlist.c19
-rw-r--r--mm/backing-dev.c50
-rw-r--r--mm/page-writeback.c14
-rw-r--r--net/8021q/vlan_core.c10
-rw-r--r--net/9p/client.c18
-rw-r--r--net/9p/trans_fd.c38
-rw-r--r--net/core/dev.c59
-rw-r--r--net/core/neighbour.c6
-rw-r--r--net/core/skbuff.c47
-rw-r--r--net/ipv4/fib_frontend.c3
-rw-r--r--net/ipv4/fib_semantics.c2
-rw-r--r--net/ipv4/inet_connection_sock.c4
-rw-r--r--net/ipv4/ip_forward.c2
-rw-r--r--net/ipv4/ip_output.c4
-rw-r--r--net/ipv4/route.c146
-rw-r--r--net/ipv4/xfrm4_policy.c1
-rw-r--r--net/ipv6/af_inet6.c22
-rw-r--r--net/netfilter/ipvs/ip_vs_xmit.c6
-rw-r--r--net/netlink/af_netlink.c29
-rw-r--r--net/rds/send.c2
-rw-r--r--net/sunrpc/auth_gss/auth_gss.c58
-rw-r--r--net/sunrpc/clnt.c105
-rw-r--r--net/sunrpc/rpc_pipe.c8
-rw-r--r--net/sunrpc/sched.c2
-rw-r--r--net/sunrpc/xdr.c21
-rw-r--r--net/sunrpc/xprt.c8
-rw-r--r--net/sunrpc/xprtrdma/transport.c22
-rw-r--r--net/sunrpc/xprtsock.c40
-rw-r--r--scripts/Makefile.modinst2
-rw-r--r--scripts/Makefile.modpost2
-rwxr-xr-xscripts/coccicheck3
-rw-r--r--scripts/coccinelle/api/ptr_ret.cocci26
-rw-r--r--scripts/coccinelle/tests/odd_ptr_err.cocci65
-rw-r--r--scripts/kconfig/Makefile12
-rw-r--r--scripts/kconfig/conf.c25
-rw-r--r--scripts/kconfig/expr.h11
-rw-r--r--scripts/kconfig/lkc_proto.h6
-rw-r--r--scripts/kconfig/lxdialog/dialog.h9
-rw-r--r--scripts/kconfig/lxdialog/textbox.c171
-rw-r--r--scripts/kconfig/lxdialog/util.c7
-rw-r--r--scripts/kconfig/mconf.c123
-rw-r--r--scripts/kconfig/menu.c53
-rw-r--r--scripts/kconfig/nconf.c2
-rwxr-xr-xscripts/kernel-doc273
-rw-r--r--scripts/mod/modpost.c1
-rw-r--r--scripts/package/buildtar6
-rwxr-xr-xscripts/tags.sh8
-rw-r--r--sound/oss/waveartist.c4
-rw-r--r--tools/perf/util/include/linux/rbtree.h1
-rwxr-xr-xtools/testing/ktest/ktest.pl15
1479 files changed, 36566 insertions, 23417 deletions
diff --git a/Documentation/ABI/testing/sysfs-block b/Documentation/ABI/testing/sysfs-block
index c1eb41c..279da08 100644
--- a/Documentation/ABI/testing/sysfs-block
+++ b/Documentation/ABI/testing/sysfs-block
@@ -206,3 +206,17 @@ Description:
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.
+
+What: /sys/block/<disk>/queue/write_same_max_bytes
+Date: January 2012
+Contact: Martin K. Petersen <martin.petersen@oracle.com>
+Description:
+ Some devices support a write same operation in which a
+ single data block can be written to a range of several
+ contiguous blocks on storage. This can be used to wipe
+ areas on disk or to initialize drives in a RAID
+ configuration. write_same_max_bytes indicates how many
+ bytes can be written in a single write same command. If
+ write_same_max_bytes is 0, write same is not supported
+ by the device.
+
diff --git a/Documentation/DocBook/mtdnand.tmpl b/Documentation/DocBook/mtdnand.tmpl
index e0aedb7..fe122d6 100644
--- a/Documentation/DocBook/mtdnand.tmpl
+++ b/Documentation/DocBook/mtdnand.tmpl
@@ -1216,8 +1216,6 @@ in this page</entry>
#define NAND_BBT_LASTBLOCK 0x00000010
/* The bbt is at the given page, else we must scan for the bbt */
#define NAND_BBT_ABSPAGE 0x00000020
-/* The bbt is at the given page, else we must scan for the bbt */
-#define NAND_BBT_SEARCH 0x00000040
/* bbt is stored per chip on multichip devices */
#define NAND_BBT_PERCHIP 0x00000080
/* bbt has a version counter at offset veroffs */
diff --git a/Documentation/block/biodoc.txt b/Documentation/block/biodoc.txt
index e418dc0..8df5e8e 100644
--- a/Documentation/block/biodoc.txt
+++ b/Documentation/block/biodoc.txt
@@ -465,7 +465,6 @@ struct bio {
bio_end_io_t *bi_end_io; /* bi_end_io (bio) */
atomic_t bi_cnt; /* pin count: free when it hits zero */
void *bi_private;
- bio_destructor_t *bi_destructor; /* bi_destructor (bio) */
};
With this multipage bio design:
@@ -647,10 +646,6 @@ for a non-clone bio. There are the 6 pools setup for different size biovecs,
so bio_alloc(gfp_mask, nr_iovecs) will allocate a vec_list of the
given size from these slabs.
-The bi_destructor() routine takes into account the possibility of the bio
-having originated from a different source (see later discussions on
-n/w to block transfers and kvec_cb)
-
The bio_get() routine may be used to hold an extra reference on a bio prior
to i/o submission, if the bio fields are likely to be accessed after the
i/o is issued (since the bio may otherwise get freed in case i/o completion
diff --git a/Documentation/devicetree/bindings/arm/davinci/nand.txt b/Documentation/devicetree/bindings/arm/davinci/nand.txt
new file mode 100644
index 0000000..e37241f
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/davinci/nand.txt
@@ -0,0 +1,51 @@
+* Texas Instruments Davinci NAND
+
+This file provides information, what the device node for the
+davinci nand interface contain.
+
+Required properties:
+- compatible: "ti,davinci-nand";
+- reg : contain 2 offset/length values:
+ - offset and length for the access window
+ - offset and length for accessing the aemif control registers
+- ti,davinci-chipselect: Indicates on the davinci_nand driver which
+ chipselect is used for accessing the nand.
+
+Recommended properties :
+- ti,davinci-mask-ale: mask for ale
+- ti,davinci-mask-cle: mask for cle
+- ti,davinci-mask-chipsel: mask for chipselect
+- ti,davinci-ecc-mode: ECC mode valid values for davinci driver:
+ - "none"
+ - "soft"
+ - "hw"
+- ti,davinci-ecc-bits: used ECC bits, currently supported 1 or 4.
+- ti,davinci-nand-buswidth: buswidth 8 or 16
+- ti,davinci-nand-use-bbt: use flash based bad block table support.
+
+Example (enbw_cmc board):
+aemif@60000000 {
+ compatible = "ti,davinci-aemif";
+ #address-cells = <2>;
+ #size-cells = <1>;
+ reg = <0x68000000 0x80000>;
+ ranges = <2 0 0x60000000 0x02000000
+ 3 0 0x62000000 0x02000000
+ 4 0 0x64000000 0x02000000
+ 5 0 0x66000000 0x02000000
+ 6 0 0x68000000 0x02000000>;
+ nand@3,0 {
+ compatible = "ti,davinci-nand";
+ reg = <3 0x0 0x807ff
+ 6 0x0 0x8000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ti,davinci-chipselect = <1>;
+ ti,davinci-mask-ale = <0>;
+ ti,davinci-mask-cle = <0>;
+ ti,davinci-mask-chipsel = <0>;
+ ti,davinci-ecc-mode = "hw";
+ ti,davinci-ecc-bits = <4>;
+ ti,davinci-nand-use-bbt;
+ };
+};
diff --git a/Documentation/devicetree/bindings/i2c/atmel-i2c.txt b/Documentation/devicetree/bindings/i2c/atmel-i2c.txt
new file mode 100644
index 0000000..b689a0d
--- /dev/null
+++ b/Documentation/devicetree/bindings/i2c/atmel-i2c.txt
@@ -0,0 +1,30 @@
+I2C for Atmel platforms
+
+Required properties :
+- compatible : Must be "atmel,at91rm9200-i2c", "atmel,at91sam9261-i2c",
+ "atmel,at91sam9260-i2c", "atmel,at91sam9g20-i2c", "atmel,at91sam9g10-i2c"
+ or "atmel,at91sam9x5-i2c"
+- reg: physical base address of the controller and length of memory mapped
+ region.
+- interrupts: interrupt number to the cpu.
+- #address-cells = <1>;
+- #size-cells = <0>;
+
+Optional properties:
+- Child nodes conforming to i2c bus binding
+
+Examples :
+
+i2c0: i2c@fff84000 {
+ compatible = "atmel,at91sam9g20-i2c";
+ reg = <0xfff84000 0x100>;
+ interrupts = <12 4 6>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ 24c512@50 {
+ compatible = "24c512";
+ reg = <0x50>;
+ pagesize = <128>;
+ }
+}
diff --git a/Documentation/devicetree/bindings/i2c/davinci.txt b/Documentation/devicetree/bindings/i2c/davinci.txt
new file mode 100644
index 0000000..2dc935b
--- /dev/null
+++ b/Documentation/devicetree/bindings/i2c/davinci.txt
@@ -0,0 +1,28 @@
+* Texas Instruments Davinci I2C
+
+This file provides information, what the device node for the
+davinci i2c interface contain.
+
+Required properties:
+- compatible: "ti,davinci-i2c";
+- reg : Offset and length of the register set for the device
+
+Recommended properties :
+- interrupts : standard interrupt property.
+- clock-frequency : desired I2C bus clock frequency in Hz.
+
+Example (enbw_cmc board):
+ i2c@1c22000 {
+ compatible = "ti,davinci-i2c";
+ reg = <0x22000 0x1000>;
+ clock-frequency = <100000>;
+ interrupts = <15>;
+ interrupt-parent = <&intc>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ dtt@48 {
+ compatible = "national,lm75";
+ reg = <0x48>;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/i2c/i2c-mxs.txt b/Documentation/devicetree/bindings/i2c/i2c-mxs.txt
index 30ac3a0..7a3fe9e 100644
--- a/Documentation/devicetree/bindings/i2c/i2c-mxs.txt
+++ b/Documentation/devicetree/bindings/i2c/i2c-mxs.txt
@@ -6,6 +6,7 @@ Required properties:
- interrupts: Should contain ERROR and DMA interrupts
- clock-frequency: Desired I2C bus clock frequency in Hz.
Only 100000Hz and 400000Hz modes are supported.
+- fsl,i2c-dma-channel: APBX DMA channel for the I2C
Examples:
@@ -16,4 +17,5 @@ i2c0: i2c@80058000 {
reg = <0x80058000 2000>;
interrupts = <111 68>;
clock-frequency = <100000>;
+ fsl,i2c-dma-channel = <6>;
};
diff --git a/Documentation/devicetree/bindings/i2c/nomadik.txt b/Documentation/devicetree/bindings/i2c/nomadik.txt
new file mode 100644
index 0000000..72065b0
--- /dev/null
+++ b/Documentation/devicetree/bindings/i2c/nomadik.txt
@@ -0,0 +1,23 @@
+I2C for Nomadik based systems
+
+Required (non-standard) properties:
+ - Nil
+
+Recommended (non-standard) properties:
+ - clock-frequency : Maximum bus clock frequency for the device
+
+Optional (non-standard) properties:
+ - Nil
+
+Example :
+
+i2c@80004000 {
+ compatible = "stericsson,db8500-i2c", "st,nomadik-i2c";
+ reg = <0x80004000 0x1000>;
+ interrupts = <0 21 0x4>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ v-i2c-supply = <&db8500_vape_reg>;
+
+ clock-frequency = <400000>;
+};
diff --git a/Documentation/devicetree/bindings/interrupt-controller/brcm,bcm2835-armctrl-ic.txt b/Documentation/devicetree/bindings/interrupt-controller/brcm,bcm2835-armctrl-ic.txt
index 548892c..7da578d 100644
--- a/Documentation/devicetree/bindings/interrupt-controller/brcm,bcm2835-armctrl-ic.txt
+++ b/Documentation/devicetree/bindings/interrupt-controller/brcm,bcm2835-armctrl-ic.txt
@@ -7,7 +7,7 @@ as "armctrl" in the SoC documentation, hence naming of this binding.
Required properties:
-- compatible : should be "brcm,bcm2835-armctrl-ic.txt"
+- compatible : should be "brcm,bcm2835-armctrl-ic"
- reg : Specifies base physical address and size of the registers.
- interrupt-controller : Identifies the node as an interrupt controller
- #interrupt-cells : Specifies the number of cells needed to encode an
diff --git a/Documentation/devicetree/bindings/mmc/atmel-hsmci.txt b/Documentation/devicetree/bindings/mmc/atmel-hsmci.txt
new file mode 100644
index 0000000..0a85c70
--- /dev/null
+++ b/Documentation/devicetree/bindings/mmc/atmel-hsmci.txt
@@ -0,0 +1,68 @@
+* Atmel High Speed MultiMedia Card Interface
+
+This controller on atmel products provides an interface for MMC, SD and SDIO
+types of memory cards.
+
+This file documents differences between the core properties described
+by mmc.txt and the properties used by the atmel-mci driver.
+
+1) MCI node
+
+Required properties:
+- compatible: should be "atmel,hsmci"
+- #address-cells: should be one. The cell is the slot id.
+- #size-cells: should be zero.
+- at least one slot node
+
+The node contains child nodes for each slot that the platform uses
+
+Example MCI node:
+
+mmc0: mmc@f0008000 {
+ compatible = "atmel,hsmci";
+ reg = <0xf0008000 0x600>;
+ interrupts = <12 4>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ [ child node definitions...]
+};
+
+2) slot nodes
+
+Required properties:
+- reg: should contain the slot id.
+- bus-width: number of data lines connected to the controller
+
+Optional properties:
+- cd-gpios: specify GPIOs for card detection
+- cd-inverted: invert the value of external card detect gpio line
+- wp-gpios: specify GPIOs for write protection
+
+Example slot node:
+
+slot@0 {
+ reg = <0>;
+ bus-width = <4>;
+ cd-gpios = <&pioD 15 0>
+ cd-inverted;
+};
+
+Example full MCI node:
+mmc0: mmc@f0008000 {
+ compatible = "atmel,hsmci";
+ reg = <0xf0008000 0x600>;
+ interrupts = <12 4>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ slot@0 {
+ reg = <0>;
+ bus-width = <4>;
+ cd-gpios = <&pioD 15 0>
+ cd-inverted;
+ };
+ slot@1 {
+ reg = <1>;
+ bus-width = <4>;
+ };
+};
diff --git a/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt b/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt
new file mode 100644
index 0000000..7927689
--- /dev/null
+++ b/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt
@@ -0,0 +1,87 @@
+* Samsung Exynos specific extensions to the Synopsis Designware Mobile
+ Storage Host Controller
+
+The Synopsis designware mobile storage host controller is used to interface
+a SoC with storage medium such as eMMC or SD/MMC cards. This file documents
+differences between the core Synopsis dw mshc controller properties described
+by synposis-dw-mshc.txt and the properties used by the Samsung Exynos specific
+extensions to the Synopsis Designware Mobile Storage Host Controller.
+
+Required Properties:
+
+* compatible: should be
+ - "samsung,exynos4210-dw-mshc": for controllers with Samsung Exynos4210
+ specific extentions.
+ - "samsung,exynos4412-dw-mshc": for controllers with Samsung Exynos4412
+ specific extentions.
+ - "samsung,exynos5250-dw-mshc": for controllers with Samsung Exynos5250
+ specific extentions.
+
+* samsung,dw-mshc-ciu-div: Specifies the divider value for the card interface
+ unit (ciu) clock. This property is applicable only for Exynos5 SoC's and
+ ignored for Exynos4 SoC's. The valid range of divider value is 0 to 7.
+
+* samsung,dw-mshc-sdr-timing: Specifies the value of CIU clock phase shift value
+ in transmit mode and CIU clock phase shift value in receive mode for single
+ data rate mode operation. Refer notes below for the order of the cells and the
+ valid values.
+
+* samsung,dw-mshc-ddr-timing: Specifies the value of CUI clock phase shift value
+ in transmit mode and CIU clock phase shift value in receive mode for double
+ data rate mode operation. Refer notes below for the order of the cells and the
+ valid values.
+
+ Notes for the sdr-timing and ddr-timing values:
+
+ The order of the cells should be
+ - First Cell: CIU clock phase shift value for tx mode.
+ - Second Cell: CIU clock phase shift value for rx mode.
+
+ Valid values for SDR and DDR CIU clock timing for Exynos5250:
+ - valid value for tx phase shift and rx phase shift is 0 to 7.
+ - when CIU clock divider value is set to 3, all possible 8 phase shift
+ values can be used.
+ - if CIU clock divider value is 0 (that is divide by 1), both tx and rx
+ phase shift clocks should be 0.
+
+Required properties for a slot:
+
+* gpios: specifies a list of gpios used for command, clock and data bus. The
+ first gpio is the command line and the second gpio is the clock line. The
+ rest of the gpios (depending on the bus-width property) are the data lines in
+ no particular order. The format of the gpio specifier depends on the gpio
+ controller.
+
+Example:
+
+ The MSHC controller node can be split into two portions, SoC specific and
+ board specific portions as listed below.
+
+ dwmmc0@12200000 {
+ compatible = "samsung,exynos5250-dw-mshc";
+ reg = <0x12200000 0x1000>;
+ interrupts = <0 75 0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
+ dwmmc0@12200000 {
+ num-slots = <1>;
+ supports-highspeed;
+ broken-cd;
+ fifo-depth = <0x80>;
+ card-detect-delay = <200>;
+ samsung,dw-mshc-ciu-div = <3>;
+ samsung,dw-mshc-sdr-timing = <2 3>;
+ samsung,dw-mshc-ddr-timing = <1 2>;
+
+ slot@0 {
+ reg = <0>;
+ bus-width = <8>;
+ gpios = <&gpc0 0 2 0 3>, <&gpc0 1 2 0 3>,
+ <&gpc1 0 2 3 3>, <&gpc1 1 2 3 3>,
+ <&gpc1 2 2 3 3>, <&gpc1 3 2 3 3>,
+ <&gpc0 3 2 3 3>, <&gpc0 4 2 3 3>,
+ <&gpc0 5 2 3 3>, <&gpc0 6 2 3 3>;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/mmc/mmc.txt b/Documentation/devicetree/bindings/mmc/mmc.txt
index 8a6811f..8e2e0ba 100644
--- a/Documentation/devicetree/bindings/mmc/mmc.txt
+++ b/Documentation/devicetree/bindings/mmc/mmc.txt
@@ -9,12 +9,17 @@ Interpreted by the OF core:
Required properties:
- bus-width: Number of data lines, can be <1>, <4>, or <8>
+Card detection:
+If no property below is supplied, standard SDHCI card detect is used.
+Only one of the properties in this section should be supplied:
+ - broken-cd: There is no card detection available; polling must be used.
+ - cd-gpios: Specify GPIOs for card detection, see gpio binding
+ - non-removable: non-removable slot (like eMMC); assume always present.
+
Optional properties:
-- cd-gpios: Specify GPIOs for card detection, see gpio binding
- wp-gpios: Specify GPIOs for write protection, see gpio binding
- cd-inverted: when present, polarity on the cd gpio line is inverted
- wp-inverted: when present, polarity on the wp gpio line is inverted
-- non-removable: non-removable slot (like eMMC)
- max-frequency: maximum operating clock frequency
Example:
diff --git a/Documentation/devicetree/bindings/mmc/pxa-mmc.txt b/Documentation/devicetree/bindings/mmc/pxa-mmc.txt
new file mode 100644
index 0000000..b7025de
--- /dev/null
+++ b/Documentation/devicetree/bindings/mmc/pxa-mmc.txt
@@ -0,0 +1,25 @@
+* PXA MMC drivers
+
+Driver bindings for the PXA MCI (MMC/SDIO) interfaces
+
+Required properties:
+- compatible: Should be "marvell,pxa-mmc".
+- vmmc-supply: A regulator for VMMC
+
+Optional properties:
+- marvell,detect-delay-ms: sets the detection delay timeout in ms.
+- marvell,gpio-power: GPIO spec for the card power enable pin
+
+This file documents differences between the core properties in mmc.txt
+and the properties used by the pxa-mmc driver.
+
+Examples:
+
+mmc0: mmc@41100000 {
+ compatible = "marvell,pxa-mmc";
+ reg = <0x41100000 0x1000>;
+ interrupts = <23>;
+ cd-gpios = <&gpio 23 0>;
+ wp-gpios = <&gpio 24 0>;
+};
+
diff --git a/Documentation/devicetree/bindings/mmc/samsung-sdhci.txt b/Documentation/devicetree/bindings/mmc/samsung-sdhci.txt
new file mode 100644
index 0000000..630a7d7
--- /dev/null
+++ b/Documentation/devicetree/bindings/mmc/samsung-sdhci.txt
@@ -0,0 +1,53 @@
+* Samsung's SDHCI Controller device tree bindings
+
+Samsung's SDHCI controller is used as a connectivity interface with external
+MMC, SD and eMMC storage mediums. This file documents differences between the
+core mmc properties described by mmc.txt and the properties used by the
+Samsung implmentation of the SDHCI controller.
+
+Note: The mmc core bindings documentation states that if none of the core
+card-detect bindings are used, then the standard sdhci card detect mechanism
+is used. The Samsung's SDHCI controller bindings extends this as listed below.
+
+[A] The property "samsung,cd-pinmux-gpio" can be used as stated in the
+ "Optional Board Specific Properties" section below.
+
+[B] If core card-detect bindings and "samsung,cd-pinmux-gpio" property
+ is not specified, it is assumed that there is no card detection
+ mechanism used.
+
+Required SoC Specific Properties:
+- compatible: should be one of the following
+ - "samsung,s3c6410-sdhci": For controllers compatible with s3c6410 sdhci
+ controller.
+ - "samsung,exynos4210-sdhci": For controllers compatible with Exynos4 sdhci
+ controller.
+
+Required Board Specific Properties:
+- gpios: Should specify the gpios used for clock, command and data lines. The
+ gpio specifier format depends on the gpio controller.
+
+Optional Board Specific Properties:
+- samsung,cd-pinmux-gpio: Specifies the card detect line that is routed
+ through a pinmux to the card-detect pin of the card slot. This property
+ should be used only if none of the mmc core card-detect properties are
+ used.
+
+Example:
+ sdhci@12530000 {
+ compatible = "samsung,exynos4210-sdhci";
+ reg = <0x12530000 0x100>;
+ interrupts = <0 75 0>;
+ bus-width = <4>;
+ cd-gpios = <&gpk2 2 2 3 3>;
+ gpios = <&gpk2 0 2 0 3>, /* clock line */
+ <&gpk2 1 2 0 3>, /* command line */
+ <&gpk2 3 2 3 3>, /* data line 0 */
+ <&gpk2 4 2 3 3>, /* data line 1 */
+ <&gpk2 5 2 3 3>, /* data line 2 */
+ <&gpk2 6 2 3 3>; /* data line 3 */
+ };
+
+ Note: This example shows both SoC specific and board specific properties
+ in a single device node. The properties can be actually be seperated
+ into SoC specific node and board specific node.
diff --git a/Documentation/devicetree/bindings/mmc/sdhci-dove.txt b/Documentation/devicetree/bindings/mmc/sdhci-dove.txt
new file mode 100644
index 0000000..ae9aab9
--- /dev/null
+++ b/Documentation/devicetree/bindings/mmc/sdhci-dove.txt
@@ -0,0 +1,14 @@
+* Marvell sdhci-dove controller
+
+This file documents differences between the core properties in mmc.txt
+and the properties used by the sdhci-pxav2 and sdhci-pxav3 drivers.
+
+- compatible: Should be "marvell,dove-sdhci".
+
+Example:
+
+sdio0: sdio@92000 {
+ compatible = "marvell,dove-sdhci";
+ reg = <0x92000 0x100>;
+ interrupts = <35>;
+};
diff --git a/Documentation/devicetree/bindings/mmc/sdhci-spear.txt b/Documentation/devicetree/bindings/mmc/sdhci-spear.txt
new file mode 100644
index 0000000..fd3643e
--- /dev/null
+++ b/Documentation/devicetree/bindings/mmc/sdhci-spear.txt
@@ -0,0 +1,18 @@
+* SPEAr SDHCI Controller
+
+This file documents differences between the core properties in mmc.txt
+and the properties used by the sdhci-spear driver.
+
+Required properties:
+- compatible: "st,spear300-sdhci"
+
+Optional properties:
+- cd-gpios: card detect gpio, with zero flags.
+
+Example:
+
+ sdhci@fc000000 {
+ compatible = "st,spear300-sdhci";
+ reg = <0xfc000000 0x1000>;
+ cd-gpios = <&gpio0 6 0>;
+ };
diff --git a/Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt b/Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt
new file mode 100644
index 0000000..06cd32d08
--- /dev/null
+++ b/Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt
@@ -0,0 +1,79 @@
+* Synopsis Designware Mobile Storage Host Controller
+
+The Synopsis designware mobile storage host controller is used to interface
+a SoC with storage medium such as eMMC or SD/MMC cards. This file documents
+differences between the core mmc properties described by mmc.txt and the
+properties used by the Synopsis Designware Mobile Storage Host Controller.
+
+Required Properties:
+
+* compatible: should be
+ - snps,dw-mshc: for controllers compliant with synopsis dw-mshc.
+* #address-cells: should be 1.
+* #size-cells: should be 0.
+
+# Slots: The slot specific information are contained within child-nodes with
+ each child-node representing a supported slot. There should be atleast one
+ child node representing a card slot. The name of the child node representing
+ the slot is recommended to be slot@n where n is the unique number of the slot
+ connnected to the controller. The following are optional properties which
+ can be included in the slot child node.
+
+ * reg: specifies the physical slot number. The valid values of this
+ property is 0 to (num-slots -1), where num-slots is the value
+ specified by the num-slots property.
+
+ * bus-width: as documented in mmc core bindings.
+
+ * wp-gpios: specifies the write protect gpio line. The format of the
+ gpio specifier depends on the gpio controller. If the write-protect
+ line is not available, this property is optional.
+
+Optional properties:
+
+* num-slots: specifies the number of slots supported by the controller.
+ The number of physical slots actually used could be equal or less than the
+ value specified by num-slots. If this property is not specified, the value
+ of num-slot property is assumed to be 1.
+
+* fifo-depth: The maximum size of the tx/rx fifo's. If this property is not
+ specified, the default value of the fifo size is determined from the
+ controller registers.
+
+* card-detect-delay: Delay in milli-seconds before detecting card after card
+ insert event. The default value is 0.
+
+* supports-highspeed: Enables support for high speed cards (upto 50MHz)
+
+* broken-cd: as documented in mmc core bindings.
+
+Aliases:
+
+- All the MSHC controller nodes should be represented in the aliases node using
+ the following format 'mshc{n}' where n is a unique number for the alias.
+
+Example:
+
+The MSHC controller node can be split into two portions, SoC specific and
+board specific portions as listed below.
+
+ dwmmc0@12200000 {
+ compatible = "snps,dw-mshc";
+ reg = <0x12200000 0x1000>;
+ interrupts = <0 75 0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
+ dwmmc0@12200000 {
+ num-slots = <1>;
+ supports-highspeed;
+ broken-cd;
+ fifo-depth = <0x80>;
+ card-detect-delay = <200>;
+
+ slot@0 {
+ reg = <0>;
+ bus-width = <8>;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/mtd/atmel-nand.txt b/Documentation/devicetree/bindings/mtd/atmel-nand.txt
index a200695..d555421 100644
--- a/Documentation/devicetree/bindings/mtd/atmel-nand.txt
+++ b/Documentation/devicetree/bindings/mtd/atmel-nand.txt
@@ -3,7 +3,9 @@ Atmel NAND flash
Required properties:
- compatible : "atmel,at91rm9200-nand".
- reg : should specify localbus address and size used for the chip,
- and if availlable the ECC.
+ and hardware ECC controller if available.
+ If the hardware ECC is PMECC, it should contain address and size for
+ PMECC, PMECC Error Location controller and ROM which has lookup tables.
- atmel,nand-addr-offset : offset for the address latch.
- atmel,nand-cmd-offset : offset for the command latch.
- #address-cells, #size-cells : Must be present if the device has sub-nodes
@@ -16,6 +18,15 @@ Optional properties:
- nand-ecc-mode : String, operation mode of the NAND ecc mode, soft by default.
Supported values are: "none", "soft", "hw", "hw_syndrome", "hw_oob_first",
"soft_bch".
+- atmel,has-pmecc : boolean to enable Programmable Multibit ECC hardware.
+ Only supported by at91sam9x5 or later sam9 product.
+- atmel,pmecc-cap : error correct capability for Programmable Multibit ECC
+ Controller. Supported values are: 2, 4, 8, 12, 24.
+- atmel,pmecc-sector-size : sector size for ECC computation. Supported values
+ are: 512, 1024.
+- atmel,pmecc-lookup-table-offset : includes two offsets of lookup table in ROM
+ for different sector size. First one is for sector size 512, the next is for
+ sector size 1024.
- nand-bus-width : 8 or 16 bus width if not present 8
- nand-on-flash-bbt: boolean to enable on flash bbt option if not present false
@@ -39,3 +50,30 @@ nand0: nand@40000000,0 {
...
};
};
+
+/* for PMECC supported chips */
+nand0: nand@40000000 {
+ compatible = "atmel,at91rm9200-nand";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = < 0x40000000 0x10000000 /* bus addr & size */
+ 0xffffe000 0x00000600 /* PMECC addr & size */
+ 0xffffe600 0x00000200 /* PMECC ERRLOC addr & size */
+ 0x00100000 0x00100000 /* ROM addr & size */
+ >;
+ atmel,nand-addr-offset = <21>; /* ale */
+ atmel,nand-cmd-offset = <22>; /* cle */
+ nand-on-flash-bbt;
+ nand-ecc-mode = "hw";
+ atmel,has-pmecc; /* enable PMECC */
+ atmel,pmecc-cap = <2>;
+ atmel,pmecc-sector-size = <512>;
+ atmel,pmecc-lookup-table-offset = <0x8000 0x10000>;
+ gpios = <&pioD 5 0 /* rdy */
+ &pioD 4 0 /* nce */
+ 0 /* cd */
+ >;
+ partition@0 {
+ ...
+ };
+};
diff --git a/Documentation/devicetree/bindings/mtd/gpmi-nand.txt b/Documentation/devicetree/bindings/mtd/gpmi-nand.txt
index 1a5bbd3..3fb3f901 100644
--- a/Documentation/devicetree/bindings/mtd/gpmi-nand.txt
+++ b/Documentation/devicetree/bindings/mtd/gpmi-nand.txt
@@ -12,6 +12,10 @@ Required properties:
- interrupt-names : The interrupt names "gpmi-dma", "bch";
- fsl,gpmi-dma-channel : Should contain the dma channel it uses.
+Optional properties:
+ - nand-on-flash-bbt: boolean to enable on flash bbt option if not
+ present false
+
The device tree may optionally contain sub-nodes describing partitions of the
address space. See partition.txt for more detail.
diff --git a/Documentation/devicetree/bindings/mtd/lpc32xx-mlc.txt b/Documentation/devicetree/bindings/mtd/lpc32xx-mlc.txt
new file mode 100644
index 0000000..d0a3725
--- /dev/null
+++ b/Documentation/devicetree/bindings/mtd/lpc32xx-mlc.txt
@@ -0,0 +1,50 @@
+NXP LPC32xx SoC NAND MLC controller
+
+Required properties:
+- compatible: "nxp,lpc3220-mlc"
+- reg: Address and size of the controller
+- interrupts: The NAND interrupt specification
+- gpios: GPIO specification for NAND write protect
+
+The following required properties are very controller specific. See the LPC32xx
+User Manual 7.5.14 MLC NAND Timing Register (the values here are specified in
+Hz, to make them independent of actual clock speed and to provide for good
+accuracy:)
+- nxp,tcea_delay: TCEA_DELAY
+- nxp,busy_delay: BUSY_DELAY
+- nxp,nand_ta: NAND_TA
+- nxp,rd_high: RD_HIGH
+- nxp,rd_low: RD_LOW
+- nxp,wr_high: WR_HIGH
+- nxp,wr_low: WR_LOW
+
+Optional subnodes:
+- Partitions, see Documentation/devicetree/bindings/mtd/partition.txt
+
+Example:
+
+ mlc: flash@200A8000 {
+ compatible = "nxp,lpc3220-mlc";
+ reg = <0x200A8000 0x11000>;
+ interrupts = <11 0>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ nxp,tcea-delay = <333333333>;
+ nxp,busy-delay = <10000000>;
+ nxp,nand-ta = <18181818>;
+ nxp,rd-high = <31250000>;
+ nxp,rd-low = <45454545>;
+ nxp,wr-high = <40000000>;
+ nxp,wr-low = <83333333>;
+ gpios = <&gpio 5 19 1>; /* GPO_P3 19, active low */
+
+ mtd0@00000000 {
+ label = "boot";
+ reg = <0x00000000 0x00064000>;
+ read-only;
+ };
+
+ ...
+
+ };
diff --git a/Documentation/devicetree/bindings/mtd/lpc32xx-slc.txt b/Documentation/devicetree/bindings/mtd/lpc32xx-slc.txt
new file mode 100644
index 0000000..d94edc0
--- /dev/null
+++ b/Documentation/devicetree/bindings/mtd/lpc32xx-slc.txt
@@ -0,0 +1,52 @@
+NXP LPC32xx SoC NAND SLC controller
+
+Required properties:
+- compatible: "nxp,lpc3220-slc"
+- reg: Address and size of the controller
+- nand-on-flash-bbt: Use bad block table on flash
+- gpios: GPIO specification for NAND write protect
+
+The following required properties are very controller specific. See the LPC32xx
+User Manual:
+- nxp,wdr-clks: Delay before Ready signal is tested on write (W_RDY)
+- nxp,rdr-clks: Delay before Ready signal is tested on read (R_RDY)
+(The following values are specified in Hz, to make them independent of actual
+clock speed:)
+- nxp,wwidth: Write pulse width (W_WIDTH)
+- nxp,whold: Write hold time (W_HOLD)
+- nxp,wsetup: Write setup time (W_SETUP)
+- nxp,rwidth: Read pulse width (R_WIDTH)
+- nxp,rhold: Read hold time (R_HOLD)
+- nxp,rsetup: Read setup time (R_SETUP)
+
+Optional subnodes:
+- Partitions, see Documentation/devicetree/bindings/mtd/partition.txt
+
+Example:
+
+ slc: flash@20020000 {
+ compatible = "nxp,lpc3220-slc";
+ reg = <0x20020000 0x1000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ nxp,wdr-clks = <14>;
+ nxp,wwidth = <40000000>;
+ nxp,whold = <100000000>;
+ nxp,wsetup = <100000000>;
+ nxp,rdr-clks = <14>;
+ nxp,rwidth = <40000000>;
+ nxp,rhold = <66666666>;
+ nxp,rsetup = <100000000>;
+ nand-on-flash-bbt;
+ gpios = <&gpio 5 19 1>; /* GPO_P3 19, active low */
+
+ mtd0@00000000 {
+ label = "phy3250-boot";
+ reg = <0x00000000 0x00064000>;
+ read-only;
+ };
+
+ ...
+
+ };
diff --git a/Documentation/devicetree/bindings/mtd/mtd-physmap.txt b/Documentation/devicetree/bindings/mtd/mtd-physmap.txt
index a63c2bd7..94de19b 100644
--- a/Documentation/devicetree/bindings/mtd/mtd-physmap.txt
+++ b/Documentation/devicetree/bindings/mtd/mtd-physmap.txt
@@ -16,6 +16,13 @@ file systems on embedded devices.
- #address-cells, #size-cells : Must be present if the device has
sub-nodes representing partitions (see below). In this case
both #address-cells and #size-cells must be equal to 1.
+ - no-unaligned-direct-access: boolean to disable the default direct
+ mapping of the flash.
+ On some platforms (e.g. MPC5200) a direct 1:1 mapping may cause
+ problems with JFFS2 usage, as the local bus (LPB) doesn't support
+ unaligned accesses as implemented in the JFFS2 code via memcpy().
+ By defining "no-unaligned-direct-access", the flash will not be
+ exposed directly to the MTD users (e.g. JFFS2) any more.
For JEDEC compatible devices, the following additional properties
are defined:
diff --git a/Documentation/devicetree/bindings/pwm/imx-pwm.txt b/Documentation/devicetree/bindings/pwm/imx-pwm.txt
new file mode 100644
index 0000000..8522bfb
--- /dev/null
+++ b/Documentation/devicetree/bindings/pwm/imx-pwm.txt
@@ -0,0 +1,17 @@
+Freescale i.MX PWM controller
+
+Required properties:
+- compatible: should be "fsl,<soc>-pwm"
+- reg: physical base address and length of the controller's registers
+- #pwm-cells: should be 2. The first cell specifies the per-chip index
+ of the PWM to use and the second cell is the period in nanoseconds.
+- interrupts: The interrupt for the pwm controller
+
+Example:
+
+pwm1: pwm@53fb4000 {
+ #pwm-cells = <2>;
+ compatible = "fsl,imx53-pwm", "fsl,imx27-pwm";
+ reg = <0x53fb4000 0x4000>;
+ interrupts = <61>;
+};
diff --git a/Documentation/devicetree/bindings/pwm/mxs-pwm.txt b/Documentation/devicetree/bindings/pwm/mxs-pwm.txt
index 11963e4..9e3f8f1 100644
--- a/Documentation/devicetree/bindings/pwm/mxs-pwm.txt
+++ b/Documentation/devicetree/bindings/pwm/mxs-pwm.txt
@@ -4,7 +4,7 @@ Required properties:
- compatible: should be "fsl,imx23-pwm"
- reg: physical base address and length of the controller's registers
- #pwm-cells: should be 2. The first cell specifies the per-chip index
- of the PWM to use and the second cell is the duty cycle in nanoseconds.
+ of the PWM to use and the second cell is the period in nanoseconds.
- fsl,pwm-number: the number of PWM devices
Example:
diff --git a/Documentation/devicetree/bindings/pwm/nvidia,tegra20-pwm.txt b/Documentation/devicetree/bindings/pwm/nvidia,tegra20-pwm.txt
index bbbeedb..01438ec 100644
--- a/Documentation/devicetree/bindings/pwm/nvidia,tegra20-pwm.txt
+++ b/Documentation/devicetree/bindings/pwm/nvidia,tegra20-pwm.txt
@@ -7,7 +7,7 @@ Required properties:
- reg: physical base address and length of the controller's registers
- #pwm-cells: On Tegra the number of cells used to specify a PWM is 2. The
first cell specifies the per-chip index of the PWM to use and the second
- cell is the duty cycle in nanoseconds.
+ cell is the period in nanoseconds.
Example:
diff --git a/Documentation/devicetree/bindings/timer/brcm,bcm2835-system-timer.txt b/Documentation/devicetree/bindings/timer/brcm,bcm2835-system-timer.txt
index 2de21c2..844bd5f 100644
--- a/Documentation/devicetree/bindings/timer/brcm,bcm2835-system-timer.txt
+++ b/Documentation/devicetree/bindings/timer/brcm,bcm2835-system-timer.txt
@@ -7,7 +7,7 @@ free running counter values, and generates an interrupt.
Required properties:
-- compatible : should be "brcm,bcm2835-system-timer.txt"
+- compatible : should be "brcm,bcm2835-system-timer"
- reg : Specifies base physical address and size of the registers.
- interrupts : A list of 4 interrupt sinks; one per timer channel.
- clock-frequency : The frequency of the clock that drives the counter, in Hz.
diff --git a/Documentation/driver-model/devres.txt b/Documentation/driver-model/devres.txt
index 950856b..43cff70 100644
--- a/Documentation/driver-model/devres.txt
+++ b/Documentation/driver-model/devres.txt
@@ -284,3 +284,7 @@ CLOCK
PINCTRL
devm_pinctrl_get()
devm_pinctrl_put()
+
+PWM
+ devm_pwm_get()
+ devm_pwm_put()
diff --git a/Documentation/filesystems/nfs/nfs.txt b/Documentation/filesystems/nfs/nfs.txt
index f50f26c..f2571c8 100644
--- a/Documentation/filesystems/nfs/nfs.txt
+++ b/Documentation/filesystems/nfs/nfs.txt
@@ -12,9 +12,47 @@ and work is in progress on adding support for minor version 1 of the NFSv4
protocol.
The purpose of this document is to provide information on some of the
-upcall interfaces that are used in order to provide the NFS client with
-some of the information that it requires in order to fully comply with
-the NFS spec.
+special features of the NFS client that can be configured by system
+administrators.
+
+
+The nfs4_unique_id parameter
+============================
+
+NFSv4 requires clients to identify themselves to servers with a unique
+string. File open and lock state shared between one client and one server
+is associated with this identity. To support robust NFSv4 state recovery
+and transparent state migration, this identity string must not change
+across client reboots.
+
+Without any other intervention, the Linux client uses a string that contains
+the local system's node name. System administrators, however, often do not
+take care to ensure that node names are fully qualified and do not change
+over the lifetime of a client system. Node names can have other
+administrative requirements that require particular behavior that does not
+work well as part of an nfs_client_id4 string.
+
+The nfs.nfs4_unique_id boot parameter specifies a unique string that can be
+used instead of a system's node name when an NFS client identifies itself to
+a server. Thus, if the system's node name is not unique, or it changes, its
+nfs.nfs4_unique_id stays the same, preventing collision with other clients
+or loss of state during NFS reboot recovery or transparent state migration.
+
+The nfs.nfs4_unique_id string is typically a UUID, though it can contain
+anything that is believed to be unique across all NFS clients. An
+nfs4_unique_id string should be chosen when a client system is installed,
+just as a system's root file system gets a fresh UUID in its label at
+install time.
+
+The string should remain fixed for the lifetime of the client. It can be
+changed safely if care is taken that the client shuts down cleanly and all
+outstanding NFSv4 state has expired, to prevent loss of NFSv4 state.
+
+This string can be stored in an NFS client's grub.conf, or it can be provided
+via a net boot facility such as PXE. It may also be specified as an nfs.ko
+module parameter. Specifying a uniquifier string is not support for NFS
+clients running in containers.
+
The DNS resolver
================
diff --git a/Documentation/hwmon/da9052 b/Documentation/hwmon/da9052
index ef89855..5bc5134 100644
--- a/Documentation/hwmon/da9052
+++ b/Documentation/hwmon/da9052
@@ -56,6 +56,6 @@ The junction temperature is calculated:
The junction temperature attribute is supported by the driver.
The battery temperature is calculated:
- Degree Celcius = 1 / (t1 + 1/298)- 273
+ Degree Celsius = 1 / (t1 + 1/298)- 273
where t1 = (1/B)* ln(( ADCval * 2.5)/(R25*ITBAT*255))
Default values of R25, B, ITBAT are 10e3, 3380 and 50e-6 respectively.
diff --git a/Documentation/hwmon/max1619 b/Documentation/hwmon/max1619
index d6f8d9c..e6d8739 100644
--- a/Documentation/hwmon/max1619
+++ b/Documentation/hwmon/max1619
@@ -9,7 +9,7 @@ Supported chips:
http://pdfserv.maxim-ic.com/en/ds/MAX1619.pdf
Authors:
- Alexey Fisher <fishor@mail.ru>,
+ Oleksij Rempel <bug-track@fisher-privat.net>,
Jean Delvare <khali@linux-fr.org>
Description
diff --git a/Documentation/hwmon/twl4030-madc-hwmon b/Documentation/hwmon/twl4030-madc-hwmon
index ef79843..c3a3a5b 100644
--- a/Documentation/hwmon/twl4030-madc-hwmon
+++ b/Documentation/hwmon/twl4030-madc-hwmon
@@ -41,5 +41,5 @@ Channel Signal
The Sysfs nodes will represent the voltage in the units of mV,
the temperature channel shows the converted temperature in
-degree celcius. The Battery charging current channel represents
+degree Celsius. The Battery charging current channel represents
battery charging current in mA.
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index f777fa9..e2ed336 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -1730,6 +1730,11 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
will be autodetected by the client, and it will fall
back to using the idmapper.
To turn off this behaviour, set the value to '0'.
+ nfs.nfs4_unique_id=
+ [NFS4] Specify an additional fixed unique ident-
+ ification string that NFSv4 clients can insert into
+ their nfs_client_id4 string. This is typically a
+ UUID that is generated at system install time.
nfs.send_implementation_id =
[NFSv4.1] Send client implementation identification
diff --git a/Documentation/leds/leds-lp5523.txt b/Documentation/leds/leds-lp5523.txt
index fad2feb..c2743f5 100644
--- a/Documentation/leds/leds-lp5523.txt
+++ b/Documentation/leds/leds-lp5523.txt
@@ -10,8 +10,22 @@ Contact: Samu Onkalo (samu.p.onkalo-at-nokia.com)
Description
-----------
LP5523 can drive up to 9 channels. Leds can be controlled directly via
-the led class control interface. Channels have generic names:
-lp5523:channelx where x is 0...8
+the led class control interface.
+The name of each channel is configurable in the platform data - name and label.
+There are three options to make the channel name.
+
+a) Define the 'name' in the platform data
+To make specific channel name, then use 'name' platform data.
+/sys/class/leds/R1 (name: 'R1')
+/sys/class/leds/B1 (name: 'B1')
+
+b) Use the 'label' with no 'name' field
+For one device name with channel number, then use 'label'.
+/sys/class/leds/RGB:channelN (label: 'RGB', N: 0 ~ 8)
+
+c) Default
+If both fields are NULL, 'lp5523' is used by default.
+/sys/class/leds/lp5523:channelN (N: 0 ~ 8)
The chip provides 3 engines. Each engine can control channels without
interaction from the main CPU. Details of the micro engine code can be found
@@ -46,12 +60,13 @@ Note - chan_nr can have values between 0 and 8.
static struct lp5523_led_config lp5523_led_config[] = {
{
+ .name = "D1",
.chan_nr = 0,
.led_current = 50,
.max_current = 130,
},
...
- }, {
+ {
.chan_nr = 8,
.led_current = 50,
.max_current = 130,
diff --git a/Documentation/percpu-rw-semaphore.txt b/Documentation/percpu-rw-semaphore.txt
new file mode 100644
index 0000000..7d3c824
--- /dev/null
+++ b/Documentation/percpu-rw-semaphore.txt
@@ -0,0 +1,27 @@
+Percpu rw semaphores
+--------------------
+
+Percpu rw semaphores is a new read-write semaphore design that is
+optimized for locking for reading.
+
+The problem with traditional read-write semaphores is that when multiple
+cores take the lock for reading, the cache line containing the semaphore
+is bouncing between L1 caches of the cores, causing performance
+degradation.
+
+Locking for reading is very fast, it uses RCU and it avoids any atomic
+instruction in the lock and unlock path. On the other hand, locking for
+writing is very expensive, it calls synchronize_rcu() that can take
+hundreds of milliseconds.
+
+The lock is declared with "struct percpu_rw_semaphore" type.
+The lock is initialized percpu_init_rwsem, it returns 0 on success and
+-ENOMEM on allocation failure.
+The lock must be freed with percpu_free_rwsem to avoid memory leak.
+
+The lock is locked for read with percpu_down_read, percpu_up_read and
+for write with percpu_down_write, percpu_up_write.
+
+The idea of using RCU for optimized rw-lock was introduced by
+Eric Dumazet <eric.dumazet@gmail.com>.
+The code was written by Mikulas Patocka <mpatocka@redhat.com>
diff --git a/Documentation/pwm.txt b/Documentation/pwm.txt
index 554290e..7d2b4c9 100644
--- a/Documentation/pwm.txt
+++ b/Documentation/pwm.txt
@@ -36,7 +36,8 @@ Legacy users can request a PWM device using pwm_request() and free it
after usage with pwm_free().
New users should use the pwm_get() function and pass to it the consumer
-device or a consumer name. pwm_put() is used to free the PWM device.
+device or a consumer name. pwm_put() is used to free the PWM device. Managed
+variants of these functions, devm_pwm_get() and devm_pwm_put(), also exist.
After being requested a PWM has to be configured using:
diff --git a/Documentation/target/tcm_mod_builder.py b/Documentation/target/tcm_mod_builder.py
index a78879b..3fe0d81 100755
--- a/Documentation/target/tcm_mod_builder.py
+++ b/Documentation/target/tcm_mod_builder.py
@@ -402,8 +402,6 @@ def tcm_mod_build_configfs(proto_ident, fabric_mod_dir_var, fabric_mod_name):
buf += " .queue_data_in = " + fabric_mod_name + "_queue_data_in,\n"
buf += " .queue_status = " + fabric_mod_name + "_queue_status,\n"
buf += " .queue_tm_rsp = " + fabric_mod_name + "_queue_tm_rsp,\n"
- buf += " .get_fabric_sense_len = " + fabric_mod_name + "_get_fabric_sense_len,\n"
- buf += " .set_fabric_sense_len = " + fabric_mod_name + "_set_fabric_sense_len,\n"
buf += " .is_state_remove = " + fabric_mod_name + "_is_state_remove,\n"
buf += " /*\n"
buf += " * Setup function pointers for generic logic in target_core_fabric_configfs.c\n"
@@ -906,20 +904,6 @@ def tcm_mod_dump_fabric_ops(proto_ident, fabric_mod_dir_var, fabric_mod_name):
buf += "}\n\n"
bufi += "int " + fabric_mod_name + "_queue_tm_rsp(struct se_cmd *);\n"
- if re.search('get_fabric_sense_len\)\(', fo):
- buf += "u16 " + fabric_mod_name + "_get_fabric_sense_len(void)\n"
- buf += "{\n"
- buf += " return 0;\n"
- buf += "}\n\n"
- bufi += "u16 " + fabric_mod_name + "_get_fabric_sense_len(void);\n"
-
- if re.search('set_fabric_sense_len\)\(', fo):
- buf += "u16 " + fabric_mod_name + "_set_fabric_sense_len(struct se_cmd *se_cmd, u32 sense_length)\n"
- buf += "{\n"
- buf += " return 0;\n"
- buf += "}\n\n"
- bufi += "u16 " + fabric_mod_name + "_set_fabric_sense_len(struct se_cmd *, u32);\n"
-
if re.search('is_state_remove\)\(', fo):
buf += "int " + fabric_mod_name + "_is_state_remove(struct se_cmd *se_cmd)\n"
buf += "{\n"
diff --git a/Documentation/virtual/uml/UserModeLinux-HOWTO.txt b/Documentation/virtual/uml/UserModeLinux-HOWTO.txt
index 77dfecf..a5f8436 100644
--- a/Documentation/virtual/uml/UserModeLinux-HOWTO.txt
+++ b/Documentation/virtual/uml/UserModeLinux-HOWTO.txt
@@ -3591,7 +3591,7 @@
Looking at the source shows that the fault happened during a call to
- copy_to_user to copy the data into the kernel:
+ copy_from_user to copy the data into the kernel:
107 count -= chars;
diff --git a/MAINTAINERS b/MAINTAINERS
index eae3cd8..e73060f 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1544,7 +1544,7 @@ S: Supported
F: drivers/rtc/rtc-bfin.c
BLACKFIN SDH DRIVER
-M: Cliff Cai <cliff.cai@analog.com>
+M: Sonic Zhang <sonic.zhang@analog.com>
L: uclinux-dist-devel@blackfin.uclinux.org
W: http://blackfin.uclinux.org
S: Supported
@@ -1958,10 +1958,10 @@ S: Supported
F: drivers/platform/x86/classmate-laptop.c
COCCINELLE/Semantic Patches (SmPL)
-M: Julia Lawall <julia@diku.dk>
+M: Julia Lawall <Julia.Lawall@lip6.fr>
M: Gilles Muller <Gilles.Muller@lip6.fr>
-M: Nicolas Palix <npalix.work@gmail.com>
-L: cocci@diku.dk (moderated for non-subscribers)
+M: Nicolas Palix <nicolas.palix@imag.fr>
+L: cocci@systeme.lip6.fr (moderated for non-subscribers)
W: http://coccinelle.lip6.fr/
S: Supported
F: scripts/coccinelle/
@@ -2423,11 +2423,6 @@ S: Maintained
F: Documentation/hwmon/dme1737
F: drivers/hwmon/dme1737.c
-DOCBOOK FOR DOCUMENTATION
-M: Randy Dunlap <rdunlap@xenotime.net>
-S: Maintained
-F: scripts/kernel-doc
-
DOCKING STATION DRIVER
M: Shaohua Li <shaohua.li@intel.com>
L: linux-acpi@vger.kernel.org
@@ -5207,8 +5202,10 @@ S: Maintained
F: drivers/mmc/host/omap.c
OMAP HS MMC SUPPORT
+M: Venkatraman S <svenkatr@ti.com>
+L: linux-mmc@vger.kernel.org
L: linux-omap@vger.kernel.org
-S: Orphan
+S: Maintained
F: drivers/mmc/host/omap_hsmmc.c
OMAP RANDOM NUMBER GENERATOR SUPPORT
diff --git a/Makefile b/Makefile
index 86eb6ac..5d8e7f2 100644
--- a/Makefile
+++ b/Makefile
@@ -664,22 +664,9 @@ ifeq ($(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-goto.sh $(CC)), y)
endif
# Add user supplied CPPFLAGS, AFLAGS and CFLAGS as the last assignments
-# But warn user when we do so
-warn-assign = \
-$(warning "WARNING: Appending $$K$(1) ($(K$(1))) from $(origin K$(1)) to kernel $$$(1)")
-
-ifneq ($(KCPPFLAGS),)
- $(call warn-assign,CPPFLAGS)
- KBUILD_CPPFLAGS += $(KCPPFLAGS)
-endif
-ifneq ($(KAFLAGS),)
- $(call warn-assign,AFLAGS)
- KBUILD_AFLAGS += $(KAFLAGS)
-endif
-ifneq ($(KCFLAGS),)
- $(call warn-assign,CFLAGS)
- KBUILD_CFLAGS += $(KCFLAGS)
-endif
+KBUILD_CPPFLAGS += $(KCPPFLAGS)
+KBUILD_AFLAGS += $(KAFLAGS)
+KBUILD_CFLAGS += $(KCFLAGS)
# Use --build-id when available.
LDFLAGS_BUILD_ID = $(patsubst -Wl$(comma)%,%,\
diff --git a/arch/Kconfig b/arch/Kconfig
index 550cce4..26a2841 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -271,6 +271,9 @@ config ARCH_WANT_OLD_COMPAT_IPC
select ARCH_WANT_COMPAT_IPC_PARSE_VERSION
bool
+config GENERIC_KERNEL_THREAD
+ bool
+
config HAVE_ARCH_SECCOMP_FILTER
bool
help
diff --git a/arch/alpha/Kconfig b/arch/alpha/Kconfig
index 9944ded..7da9124 100644
--- a/arch/alpha/Kconfig
+++ b/arch/alpha/Kconfig
@@ -20,6 +20,7 @@ config ALPHA
select GENERIC_CMOS_UPDATE
select GENERIC_STRNCPY_FROM_USER
select GENERIC_STRNLEN_USER
+ select GENERIC_KERNEL_THREAD
help
The Alpha is a 64-bit general-purpose processor designed and
marketed by the Digital Equipment Corporation of blessed memory,
diff --git a/arch/alpha/include/asm/Kbuild b/arch/alpha/include/asm/Kbuild
index d97d663..64ffc9e 100644
--- a/arch/alpha/include/asm/Kbuild
+++ b/arch/alpha/include/asm/Kbuild
@@ -10,3 +10,4 @@ header-y += pal.h
header-y += reg.h
header-y += regdef.h
header-y += sysinfo.h
+generic-y += exec.h
diff --git a/arch/alpha/include/asm/exec.h b/arch/alpha/include/asm/exec.h
deleted file mode 100644
index 4a5a41f..0000000
--- a/arch/alpha/include/asm/exec.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __ALPHA_EXEC_H
-#define __ALPHA_EXEC_H
-
-#define arch_align_stack(x) (x)
-
-#endif /* __ALPHA_EXEC_H */
diff --git a/arch/alpha/include/asm/processor.h b/arch/alpha/include/asm/processor.h
index e37b887..6cb7fe8 100644
--- a/arch/alpha/include/asm/processor.h
+++ b/arch/alpha/include/asm/processor.h
@@ -49,9 +49,6 @@ extern void start_thread(struct pt_regs *, unsigned long, unsigned long);
/* Free all resources held by a thread. */
extern void release_thread(struct task_struct *);
-/* Create a kernel thread without removing it from tasklists. */
-extern long kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
-
unsigned long get_wchan(struct task_struct *p);
#define KSTK_EIP(tsk) (task_pt_regs(tsk)->pc)
diff --git a/arch/alpha/include/asm/thread_info.h b/arch/alpha/include/asm/thread_info.h
index 28335bd..4554ecb 100644
--- a/arch/alpha/include/asm/thread_info.h
+++ b/arch/alpha/include/asm/thread_info.h
@@ -84,7 +84,6 @@ register struct thread_info *__current_thread_info __asm__("$8");
#define _TIF_SIGPENDING (1<<TIF_SIGPENDING)
#define _TIF_NEED_RESCHED (1<<TIF_NEED_RESCHED)
#define _TIF_POLLING_NRFLAG (1<<TIF_POLLING_NRFLAG)
-#define _TIF_RESTORE_SIGMASK (1<<TIF_RESTORE_SIGMASK)
#define _TIF_NOTIFY_RESUME (1<<TIF_NOTIFY_RESUME)
/* Work to do on interrupt/exception return. */
@@ -117,5 +116,7 @@ register struct thread_info *__current_thread_info __asm__("$8");
(int __user *)(value)); \
})
+#define tsk_is_polling(t) test_tsk_thread_flag(t, TIF_POLLING_NRFLAG)
+
#endif /* __KERNEL__ */
#endif /* _ALPHA_THREAD_INFO_H */
diff --git a/arch/alpha/include/asm/unistd.h b/arch/alpha/include/asm/unistd.h
index a31a78e..3cb6c11 100644
--- a/arch/alpha/include/asm/unistd.h
+++ b/arch/alpha/include/asm/unistd.h
@@ -481,6 +481,8 @@
#define __ARCH_WANT_SYS_OLDUMOUNT
#define __ARCH_WANT_SYS_SIGPENDING
#define __ARCH_WANT_SYS_RT_SIGSUSPEND
+#define __ARCH_WANT_SYS_EXECVE
+#define __ARCH_WANT_KERNEL_EXECVE
/* "Conditional" syscalls. What we want is
diff --git a/arch/alpha/kernel/alpha_ksyms.c b/arch/alpha/kernel/alpha_ksyms.c
index 15fa821..89566b3 100644
--- a/arch/alpha/kernel/alpha_ksyms.c
+++ b/arch/alpha/kernel/alpha_ksyms.c
@@ -50,9 +50,6 @@ EXPORT_SYMBOL(alpha_read_fp_reg_s);
EXPORT_SYMBOL(alpha_write_fp_reg);
EXPORT_SYMBOL(alpha_write_fp_reg_s);
-/* entry.S */
-EXPORT_SYMBOL(kernel_thread);
-
/* Networking helper routines. */
EXPORT_SYMBOL(csum_tcpudp_magic);
EXPORT_SYMBOL(ip_compute_csum);
diff --git a/arch/alpha/kernel/entry.S b/arch/alpha/kernel/entry.S
index ec0da05..2a359c9 100644
--- a/arch/alpha/kernel/entry.S
+++ b/arch/alpha/kernel/entry.S
@@ -418,11 +418,10 @@ $work_notifysig:
strace:
/* set up signal stack, call syscall_trace */
bsr $1, do_switch_stack
- jsr $26, syscall_trace
+ jsr $26, syscall_trace_enter /* returns the syscall number */
bsr $1, undo_switch_stack
- /* get the system call number and the arguments back.. */
- ldq $0, 0($sp)
+ /* get the arguments back.. */
ldq $16, SP_OFF+24($sp)
ldq $17, SP_OFF+32($sp)
ldq $18, SP_OFF+40($sp)
@@ -449,7 +448,7 @@ $strace_success:
stq $0, 0($sp) /* save return value */
bsr $1, do_switch_stack
- jsr $26, syscall_trace
+ jsr $26, syscall_trace_leave
bsr $1, undo_switch_stack
br $31, ret_from_sys_call
@@ -467,7 +466,7 @@ $strace_error:
bsr $1, do_switch_stack
mov $19, $9 /* save old syscall number */
mov $20, $10 /* save old a3 */
- jsr $26, syscall_trace
+ jsr $26, syscall_trace_leave
mov $9, $19
mov $10, $20
bsr $1, undo_switch_stack
@@ -609,59 +608,35 @@ ret_from_fork:
.end ret_from_fork
/*
- * kernel_thread(fn, arg, clone_flags)
+ * ... and new kernel threads - here
*/
.align 4
- .globl kernel_thread
- .ent kernel_thread
-kernel_thread:
- /* We can be called from a module. */
- ldgp $gp, 0($27)
- .prologue 1
- subq $sp, SP_OFF+6*8, $sp
- br $1, 2f /* load start address */
-
- /* We've now "returned" from a fake system call. */
- unop
- blt $0, 1f /* error? */
- ldi $1, 0x3fff
- beq $20, 1f /* parent or child? */
-
- bic $sp, $1, $8 /* in child. */
- jsr $26, ($27)
+ .globl ret_from_kernel_thread
+ .ent ret_from_kernel_thread
+ret_from_kernel_thread:
+ mov $17, $16
+ jsr $26, schedule_tail
+ mov $9, $27
+ mov $10, $16
+ jsr $26, ($9)
ldgp $gp, 0($26)
mov $0, $16
mov $31, $26
jmp $31, sys_exit
+.end ret_from_kernel_thread
-1: ret /* in parent. */
-
- .align 4
-2: /* Fake a system call stack frame, as we can't do system calls
- from kernel space. Note that we store FN and ARG as they
- need to be set up in the child for the call. Also store $8
- and $26 for use in the parent. */
- stq $31, SP_OFF($sp) /* ps */
- stq $1, SP_OFF+8($sp) /* pc */
- stq $gp, SP_OFF+16($sp) /* gp */
- stq $16, 136($sp) /* $27; FN for child */
- stq $17, SP_OFF+24($sp) /* $16; ARG for child */
- stq $8, 64($sp) /* $8 */
- stq $26, 128($sp) /* $26 */
+ .globl ret_from_kernel_execve
+ .align 4
+ .ent ret_from_kernel_execve
+ret_from_kernel_execve:
+ mov $16, $sp
/* Avoid the HAE being gratuitously wrong, to avoid restoring it. */
ldq $2, alpha_mv+HAE_CACHE
stq $2, 152($sp) /* HAE */
+ mov $31, $19 /* to disable syscall restarts */
+ br $31, ret_to_user
- /* Shuffle FLAGS to the front; add CLONE_VM. */
- ldi $1, CLONE_VM|CLONE_UNTRACED
- or $18, $1, $16
- bsr $26, sys_clone
-
- /* We don't actually care for a3 success widgetry in the kernel.
- Not for positive errno values. */
- stq $0, 0($sp) /* $0 */
- br ret_to_kernel
-.end kernel_thread
+.end ret_from_kernel_execve
/*
@@ -722,7 +697,7 @@ sys_sigreturn:
lda $sp, -SWITCH_STACK_SIZE($sp)
jsr $26, do_sigreturn
bne $9, 1f
- jsr $26, syscall_trace
+ jsr $26, syscall_trace_leave
1: br $1, undo_switch_stack
br ret_from_sys_call
.end sys_sigreturn
@@ -739,21 +714,12 @@ sys_rt_sigreturn:
lda $sp, -SWITCH_STACK_SIZE($sp)
jsr $26, do_rt_sigreturn
bne $9, 1f
- jsr $26, syscall_trace
+ jsr $26, syscall_trace_leave
1: br $1, undo_switch_stack
br ret_from_sys_call
.end sys_rt_sigreturn
.align 4
- .globl sys_execve
- .ent sys_execve
-sys_execve:
- .prologue 0
- mov $sp, $19
- jmp $31, do_sys_execve
-.end sys_execve
-
- .align 4
.globl alpha_ni_syscall
.ent alpha_ni_syscall
alpha_ni_syscall:
diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c
index 83638aa..4054e0f 100644
--- a/arch/alpha/kernel/process.c
+++ b/arch/alpha/kernel/process.c
@@ -263,33 +263,35 @@ alpha_vfork(struct pt_regs *regs)
/*
* Copy an alpha thread..
- *
- * Note the "stack_offset" stuff: when returning to kernel mode, we need
- * to have some extra stack-space for the kernel stack that still exists
- * after the "ret_from_fork". When returning to user mode, we only want
- * the space needed by the syscall stack frame (ie "struct pt_regs").
- * Use the passed "regs" pointer to determine how much space we need
- * for a kernel fork().
*/
int
copy_thread(unsigned long clone_flags, unsigned long usp,
- unsigned long unused,
+ unsigned long arg,
struct task_struct * p, struct pt_regs * regs)
{
extern void ret_from_fork(void);
+ extern void ret_from_kernel_thread(void);
struct thread_info *childti = task_thread_info(p);
- struct pt_regs * childregs;
- struct switch_stack * childstack, *stack;
- unsigned long stack_offset, settls;
-
- stack_offset = PAGE_SIZE - sizeof(struct pt_regs);
- if (!(regs->ps & 8))
- stack_offset = (PAGE_SIZE-1) & (unsigned long) regs;
- childregs = (struct pt_regs *)
- (stack_offset + PAGE_SIZE + task_stack_page(p));
-
+ struct pt_regs *childregs = task_pt_regs(p);
+ struct switch_stack *childstack, *stack;
+ unsigned long settls;
+
+ childstack = ((struct switch_stack *) childregs) - 1;
+ if (unlikely(!regs)) {
+ /* kernel thread */
+ memset(childstack, 0,
+ sizeof(struct switch_stack) + sizeof(struct pt_regs));
+ childstack->r26 = (unsigned long) ret_from_kernel_thread;
+ childstack->r9 = usp; /* function */
+ childstack->r10 = arg;
+ childregs->hae = alpha_mv.hae_cache,
+ childti->pcb.usp = 0;
+ childti->pcb.ksp = (unsigned long) childstack;
+ childti->pcb.flags = 1; /* set FEN, clear everything else */
+ return 0;
+ }
*childregs = *regs;
settls = regs->r20;
childregs->r0 = 0;
@@ -297,7 +299,6 @@ copy_thread(unsigned long clone_flags, unsigned long usp,
childregs->r20 = 1; /* OSF/1 has some strange fork() semantics. */
regs->r20 = 0;
stack = ((struct switch_stack *) regs) - 1;
- childstack = ((struct switch_stack *) childregs) - 1;
*childstack = *stack;
childstack->r26 = (unsigned long) ret_from_fork;
childti->pcb.usp = usp;
@@ -386,27 +387,6 @@ dump_elf_task_fp(elf_fpreg_t *dest, struct task_struct *task)
EXPORT_SYMBOL(dump_elf_task_fp);
/*
- * sys_execve() executes a new program.
- */
-asmlinkage int
-do_sys_execve(const char __user *ufilename,
- const char __user *const __user *argv,
- const char __user *const __user *envp, struct pt_regs *regs)
-{
- int error;
- char *filename;
-
- filename = getname(ufilename);
- error = PTR_ERR(filename);
- if (IS_ERR(filename))
- goto out;
- error = do_execve(filename, argv, envp, regs);
- putname(filename);
-out:
- return error;
-}
-
-/*
* Return saved PC of a blocked thread. This assumes the frame
* pointer is the 6th saved long on the kernel stack and that the
* saved return address is the first long in the frame. This all
@@ -459,22 +439,3 @@ get_wchan(struct task_struct *p)
}
return pc;
}
-
-int kernel_execve(const char *path, const char *const argv[], const char *const envp[])
-{
- /* Avoid the HAE being gratuitously wrong, which would cause us
- to do the whole turn off interrupts thing and restore it. */
- struct pt_regs regs = {.hae = alpha_mv.hae_cache};
- int err = do_execve(path, argv, envp, &regs);
- if (!err) {
- struct pt_regs *p = current_pt_regs();
- /* copy regs to normal position and off to userland we go... */
- *p = regs;
- __asm__ __volatile__ (
- "mov %0, $sp;"
- "br $31, ret_from_sys_call"
- : : "r"(p));
- }
- return err;
-}
-EXPORT_SYMBOL(kernel_execve);
diff --git a/arch/alpha/kernel/ptrace.c b/arch/alpha/kernel/ptrace.c
index 54616f4..2a4a80f 100644
--- a/arch/alpha/kernel/ptrace.c
+++ b/arch/alpha/kernel/ptrace.c
@@ -13,6 +13,7 @@
#include <linux/user.h>
#include <linux/security.h>
#include <linux/signal.h>
+#include <linux/tracehook.h>
#include <asm/uaccess.h>
#include <asm/pgtable.h>
@@ -312,25 +313,18 @@ long arch_ptrace(struct task_struct *child, long request,
return ret;
}
+asmlinkage unsigned long syscall_trace_enter(void)
+{
+ unsigned long ret = 0;
+ if (test_thread_flag(TIF_SYSCALL_TRACE) &&
+ tracehook_report_syscall_entry(current_pt_regs()))
+ ret = -1UL;
+ return ret ?: current_pt_regs()->r0;
+}
+
asmlinkage void
-syscall_trace(void)
+syscall_trace_leave(void)
{
- if (!test_thread_flag(TIF_SYSCALL_TRACE))
- return;
- if (!(current->ptrace & PT_PTRACED))
- return;
- /* The 0x80 provides a way for the tracing parent to distinguish
- between a syscall stop and SIGTRAP delivery */
- ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
- ? 0x80 : 0));
-
- /*
- * This isn't the same as continuing with a signal, but it will do
- * for normal use. strace only continues with a signal if the
- * stopping signal is not SIGTRAP. -brl
- */
- if (current->exit_code) {
- send_sig(current->exit_code, current, 1);
- current->exit_code = 0;
- }
+ if (test_thread_flag(TIF_SYSCALL_TRACE))
+ tracehook_report_syscall_exit(current_pt_regs(), 0);
}
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 2867a77..767aae8 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -52,6 +52,7 @@ config ARM
select GENERIC_STRNCPY_FROM_USER
select GENERIC_STRNLEN_USER
select DCACHE_WORD_ACCESS if (CPU_V6 || CPU_V6K || CPU_V7) && !CPU_BIG_ENDIAN
+ select GENERIC_KERNEL_THREAD
help
The ARM series is a line of low-power-consumption RISC chip designs
licensed by ARM Ltd and targeted at embedded applications and
@@ -493,7 +494,6 @@ config ARCH_IOP32X
depends on MMU
select CPU_XSCALE
select NEED_MACH_GPIO_H
- select NEED_MACH_IO_H
select NEED_RET_TO_USER
select PLAT_IOP
select PCI
@@ -507,7 +507,6 @@ config ARCH_IOP33X
depends on MMU
select CPU_XSCALE
select NEED_MACH_GPIO_H
- select NEED_MACH_IO_H
select NEED_RET_TO_USER
select PLAT_IOP
select PCI
@@ -1771,6 +1770,7 @@ source "mm/Kconfig"
config FORCE_MAX_ZONEORDER
int "Maximum zone order" if ARCH_SHMOBILE
range 11 64 if ARCH_SHMOBILE
+ default "12" if SOC_AM33XX
default "9" if SA1111
default "11"
help
diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
index 29f541f0..c1ce813 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -25,14 +25,6 @@ dtb-$(CONFIG_ARCH_EXYNOS) += exynos4210-origen.dtb \
exynos4210-trats.dtb \
exynos5250-smdk5250.dtb
dtb-$(CONFIG_ARCH_HIGHBANK) += highbank.dtb
-dtb-$(CONFIG_ARCH_IMX5) += imx51-babbage.dtb \
- imx53-ard.dtb \
- imx53-evk.dtb \
- imx53-qsb.dtb \
- imx53-smd.dtb
-dtb-$(CONFIG_SOC_IMX6Q) += imx6q-arm2.dtb \
- imx6q-sabrelite.dtb \
- imx6q-sabresd.dtb
dtb-$(CONFIG_ARCH_LPC32XX) += ea3250.dtb phy3250.dtb
dtb-$(CONFIG_ARCH_KIRKWOOD) += kirkwood-dns320.dtb \
kirkwood-dns325.dtb \
@@ -76,7 +68,9 @@ dtb-$(CONFIG_ARCH_OMAP2PLUS) += omap2420-h4.dtb \
omap4-pandaES.dtb \
omap4-var_som.dtb \
omap4-sdp.dtb \
- omap5-evm.dtb
+ omap5-evm.dtb \
+ am335x-evm.dtb \
+ am335x-bone.dtb
dtb-$(CONFIG_ARCH_PRIMA2) += prima2-evb.dtb
dtb-$(CONFIG_ARCH_U8500) += snowball.dtb
dtb-$(CONFIG_ARCH_SHMOBILE) += emev2-kzm9d.dtb \
@@ -104,5 +98,8 @@ dtb-$(CONFIG_ARCH_VEXPRESS) += vexpress-v2p-ca5s.dtb \
vexpress-v2p-ca15-tc1.dtb \
vexpress-v2p-ca15_a7.dtb \
xenvm-4.2.dtb
+dtb-$(CONFIG_ARCH_VT8500) += vt8500-bv07.dtb \
+ wm8505-ref.dtb \
+ wm8650-mid.dtb
endif
diff --git a/arch/arm/boot/dts/at91sam9260.dtsi b/arch/arm/boot/dts/at91sam9260.dtsi
index 7c95f76..d410581 100644
--- a/arch/arm/boot/dts/at91sam9260.dtsi
+++ b/arch/arm/boot/dts/at91sam9260.dtsi
@@ -28,6 +28,7 @@
gpio2 = &pioC;
tcb0 = &tcb0;
tcb1 = &tcb1;
+ i2c0 = &i2c0;
};
cpus {
cpu@0 {
@@ -202,6 +203,15 @@
status = "disabled";
};
+ i2c0: i2c@fffac000 {
+ compatible = "atmel,at91sam9260-i2c";
+ reg = <0xfffac000 0x100>;
+ interrupts = <11 4 6>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
adc0: adc@fffe0000 {
compatible = "atmel,at91sam9260-adc";
reg = <0xfffe0000 0x100>;
diff --git a/arch/arm/boot/dts/at91sam9263.dtsi b/arch/arm/boot/dts/at91sam9263.dtsi
index 195019b..3e6e5c1 100644
--- a/arch/arm/boot/dts/at91sam9263.dtsi
+++ b/arch/arm/boot/dts/at91sam9263.dtsi
@@ -24,6 +24,7 @@
gpio3 = &pioD;
gpio4 = &pioE;
tcb0 = &tcb0;
+ i2c0 = &i2c0;
};
cpus {
cpu@0 {
@@ -185,6 +186,15 @@
interrupts = <24 4 2>;
status = "disabled";
};
+
+ i2c0: i2c@fff88000 {
+ compatible = "atmel,at91sam9263-i2c";
+ reg = <0xfff88000 0x100>;
+ interrupts = <13 4 6>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
};
nand0: nand@40000000 {
diff --git a/arch/arm/boot/dts/at91sam9g20.dtsi b/arch/arm/boot/dts/at91sam9g20.dtsi
index 2a1d1ca..75ce6e7 100644
--- a/arch/arm/boot/dts/at91sam9g20.dtsi
+++ b/arch/arm/boot/dts/at91sam9g20.dtsi
@@ -18,6 +18,10 @@
ahb {
apb {
+ i2c0: i2c@fffac000 {
+ compatible = "atmel,at91sam9g20-i2c";
+ };
+
adc0: adc@fffe0000 {
atmel,adc-startup-time = <40>;
};
diff --git a/arch/arm/boot/dts/at91sam9g25ek.dts b/arch/arm/boot/dts/at91sam9g25ek.dts
index 96514c1..877c08f 100644
--- a/arch/arm/boot/dts/at91sam9g25ek.dts
+++ b/arch/arm/boot/dts/at91sam9g25ek.dts
@@ -32,6 +32,18 @@
phy-mode = "rmii";
status = "okay";
};
+
+ i2c0: i2c@f8010000 {
+ status = "okay";
+ };
+
+ i2c1: i2c@f8014000 {
+ status = "okay";
+ };
+
+ i2c2: i2c@f8018000 {
+ status = "okay";
+ };
};
usb0: ohci@00600000 {
diff --git a/arch/arm/boot/dts/at91sam9g45.dtsi b/arch/arm/boot/dts/at91sam9g45.dtsi
index 63751b1..3add030 100644
--- a/arch/arm/boot/dts/at91sam9g45.dtsi
+++ b/arch/arm/boot/dts/at91sam9g45.dtsi
@@ -29,6 +29,8 @@
gpio4 = &pioE;
tcb0 = &tcb0;
tcb1 = &tcb1;
+ i2c0 = &i2c0;
+ i2c1 = &i2c1;
};
cpus {
cpu@0 {
@@ -206,6 +208,24 @@
status = "disabled";
};
+ i2c0: i2c@fff84000 {
+ compatible = "atmel,at91sam9g10-i2c";
+ reg = <0xfff84000 0x100>;
+ interrupts = <12 4 6>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ i2c1: i2c@fff88000 {
+ compatible = "atmel,at91sam9g10-i2c";
+ reg = <0xfff88000 0x100>;
+ interrupts = <13 4 6>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
adc0: adc@fffb0000 {
compatible = "atmel,at91sam9260-adc";
reg = <0xfffb0000 0x100>;
diff --git a/arch/arm/boot/dts/at91sam9m10g45ek.dts b/arch/arm/boot/dts/at91sam9m10g45ek.dts
index a3633bd..15e1dd4 100644
--- a/arch/arm/boot/dts/at91sam9m10g45ek.dts
+++ b/arch/arm/boot/dts/at91sam9m10g45ek.dts
@@ -46,6 +46,14 @@
phy-mode = "rmii";
status = "okay";
};
+
+ i2c0: i2c@fff84000 {
+ status = "okay";
+ };
+
+ i2c1: i2c@fff88000 {
+ status = "okay";
+ };
};
nand0: nand@40000000 {
diff --git a/arch/arm/boot/dts/at91sam9n12.dtsi b/arch/arm/boot/dts/at91sam9n12.dtsi
index ef9336a..82508d6 100644
--- a/arch/arm/boot/dts/at91sam9n12.dtsi
+++ b/arch/arm/boot/dts/at91sam9n12.dtsi
@@ -26,6 +26,8 @@
gpio3 = &pioD;
tcb0 = &tcb0;
tcb1 = &tcb1;
+ i2c0 = &i2c0;
+ i2c1 = &i2c1;
};
cpus {
cpu@0 {
@@ -182,6 +184,24 @@
atmel,use-dma-tx;
status = "disabled";
};
+
+ i2c0: i2c@f8010000 {
+ compatible = "atmel,at91sam9x5-i2c";
+ reg = <0xf8010000 0x100>;
+ interrupts = <9 4 6>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ i2c1: i2c@f8014000 {
+ compatible = "atmel,at91sam9x5-i2c";
+ reg = <0xf8014000 0x100>;
+ interrupts = <10 4 6>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
};
nand0: nand@40000000 {
diff --git a/arch/arm/boot/dts/at91sam9n12ek.dts b/arch/arm/boot/dts/at91sam9n12ek.dts
index f4e43e3..912b2c2 100644
--- a/arch/arm/boot/dts/at91sam9n12ek.dts
+++ b/arch/arm/boot/dts/at91sam9n12ek.dts
@@ -37,6 +37,14 @@
dbgu: serial@fffff200 {
status = "okay";
};
+
+ i2c0: i2c@f8010000 {
+ status = "okay";
+ };
+
+ i2c1: i2c@f8014000 {
+ status = "okay";
+ };
};
nand0: nand@40000000 {
diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi b/arch/arm/boot/dts/at91sam9x5.dtsi
index 8a387a8..03fc136 100644
--- a/arch/arm/boot/dts/at91sam9x5.dtsi
+++ b/arch/arm/boot/dts/at91sam9x5.dtsi
@@ -27,6 +27,9 @@
gpio3 = &pioD;
tcb0 = &tcb0;
tcb1 = &tcb1;
+ i2c0 = &i2c0;
+ i2c1 = &i2c1;
+ i2c2 = &i2c2;
};
cpus {
cpu@0 {
@@ -196,6 +199,33 @@
status = "disabled";
};
+ i2c0: i2c@f8010000 {
+ compatible = "atmel,at91sam9x5-i2c";
+ reg = <0xf8010000 0x100>;
+ interrupts = <9 4 6>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ i2c1: i2c@f8014000 {
+ compatible = "atmel,at91sam9x5-i2c";
+ reg = <0xf8014000 0x100>;
+ interrupts = <10 4 6>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ i2c2: i2c@f8018000 {
+ compatible = "atmel,at91sam9x5-i2c";
+ reg = <0xf8018000 0x100>;
+ interrupts = <11 4 6>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
adc0: adc@f804c000 {
compatible = "atmel,at91sam9260-adc";
reg = <0xf804c000 0x100>;
diff --git a/arch/arm/boot/dts/imx28.dtsi b/arch/arm/boot/dts/imx28.dtsi
index 59fbfba..e16d631 100644
--- a/arch/arm/boot/dts/imx28.dtsi
+++ b/arch/arm/boot/dts/imx28.dtsi
@@ -764,6 +764,7 @@
reg = <0x80058000 0x2000>;
interrupts = <111 68>;
clock-frequency = <100000>;
+ fsl,i2c-dma-channel = <6>;
status = "disabled";
};
@@ -774,6 +775,7 @@
reg = <0x8005a000 0x2000>;
interrupts = <110 69>;
clock-frequency = <100000>;
+ fsl,i2c-dma-channel = <7>;
status = "disabled";
};
diff --git a/arch/arm/boot/dts/imx51.dtsi b/arch/arm/boot/dts/imx51.dtsi
index 2f71a91..75d069f 100644
--- a/arch/arm/boot/dts/imx51.dtsi
+++ b/arch/arm/boot/dts/imx51.dtsi
@@ -407,6 +407,13 @@
status = "disabled";
};
+ nand@83fdb000 {
+ compatible = "fsl,imx51-nand";
+ reg = <0x83fdb000 0x1000 0xcfff0000 0x10000>;
+ interrupts = <8>;
+ status = "disabled";
+ };
+
ssi3: ssi@83fe8000 {
compatible = "fsl,imx51-ssi", "fsl,imx21-ssi";
reg = <0x83fe8000 0x4000>;
diff --git a/arch/arm/boot/dts/imx53.dtsi b/arch/arm/boot/dts/imx53.dtsi
index 221cf33..76ebb1a 100644
--- a/arch/arm/boot/dts/imx53.dtsi
+++ b/arch/arm/boot/dts/imx53.dtsi
@@ -518,6 +518,13 @@
status = "disabled";
};
+ nand@63fdb000 {
+ compatible = "fsl,imx53-nand";
+ reg = <0x63fdb000 0x1000 0xf7ff0000 0x10000>;
+ interrupts = <8>;
+ status = "disabled";
+ };
+
ssi3: ssi@63fe8000 {
compatible = "fsl,imx53-ssi", "fsl,imx21-ssi";
reg = <0x63fe8000 0x4000>;
diff --git a/arch/arm/boot/dts/omap4-panda.dts b/arch/arm/boot/dts/omap4-panda.dts
index 20b966e..e8f927c 100644
--- a/arch/arm/boot/dts/omap4-panda.dts
+++ b/arch/arm/boot/dts/omap4-panda.dts
@@ -59,6 +59,41 @@
};
};
+&omap4_pmx_core {
+ pinctrl-names = "default";
+ pinctrl-0 = <
+ &twl6040_pins
+ &mcpdm_pins
+ &mcbsp1_pins
+ >;
+
+ twl6040_pins: pinmux_twl6040_pins {
+ pinctrl-single,pins = <
+ 0xe0 0x3 /* hdq_sio.gpio_127 OUTPUT | MODE3 */
+ 0x160 0x100 /* sys_nirq2.sys_nirq2 INPUT | MODE0 */
+ >;
+ };
+
+ mcpdm_pins: pinmux_mcpdm_pins {
+ pinctrl-single,pins = <
+ 0xc6 0x108 /* abe_pdm_ul_data.abe_pdm_ul_data INPUT PULLDOWN | MODE0 */
+ 0xc8 0x108 /* abe_pdm_dl_data.abe_pdm_dl_data INPUT PULLDOWN | MODE0 */
+ 0xca 0x118 /* abe_pdm_frame.abe_pdm_frame INPUT PULLUP | MODE0 */
+ 0xcc 0x108 /* abe_pdm_lb_clk.abe_pdm_lb_clk INPUT PULLDOWN | MODE0 */
+ 0xce 0x108 /* abe_clks.abe_clks INPUT PULLDOWN | MODE0 */
+ >;
+ };
+
+ mcbsp1_pins: pinmux_mcbsp1_pins {
+ pinctrl-single,pins = <
+ 0xbe 0x100 /* abe_mcbsp1_clkx.abe_mcbsp1_clkx INPUT | MODE0 */
+ 0xc0 0x108 /* abe_mcbsp1_dr.abe_mcbsp1_dr INPUT PULLDOWN | MODE0 */
+ 0xc2 0x8 /* abe_mcbsp1_dx.abe_mcbsp1_dx OUTPUT PULLDOWN | MODE0 */
+ 0xc4 0x100 /* abe_mcbsp1_fsx.abe_mcbsp1_fsx INPUT | MODE0 */
+ >;
+ };
+};
+
&i2c1 {
clock-frequency = <400000>;
@@ -137,3 +172,15 @@
cs1-used;
device-handle = <&elpida_ECB240ABACN>;
};
+
+&mcbsp2 {
+ status = "disabled";
+};
+
+&mcbsp3 {
+ status = "disabled";
+};
+
+&dmic {
+ status = "disabled";
+};
diff --git a/arch/arm/boot/dts/omap4-sdp.dts b/arch/arm/boot/dts/omap4-sdp.dts
index 94a23b3..5b7e04f 100644
--- a/arch/arm/boot/dts/omap4-sdp.dts
+++ b/arch/arm/boot/dts/omap4-sdp.dts
@@ -117,6 +117,15 @@
};
&omap4_pmx_core {
+ pinctrl-names = "default";
+ pinctrl-0 = <
+ &twl6040_pins
+ &mcpdm_pins
+ &dmic_pins
+ &mcbsp1_pins
+ &mcbsp2_pins
+ >;
+
uart2_pins: pinmux_uart2_pins {
pinctrl-single,pins = <
0xd8 0x118 /* uart2_cts.uart2_cts INPUT_PULLUP | MODE0 */
@@ -141,6 +150,50 @@
0x11e 0 /* uart4_tx.uart4_tx OUTPUT | MODE0 */
>;
};
+
+ twl6040_pins: pinmux_twl6040_pins {
+ pinctrl-single,pins = <
+ 0xe0 0x3 /* hdq_sio.gpio_127 OUTPUT | MODE3 */
+ 0x160 0x100 /* sys_nirq2.sys_nirq2 INPUT | MODE0 */
+ >;
+ };
+
+ mcpdm_pins: pinmux_mcpdm_pins {
+ pinctrl-single,pins = <
+ 0xc6 0x108 /* abe_pdm_ul_data.abe_pdm_ul_data INPUT PULLDOWN | MODE0 */
+ 0xc8 0x108 /* abe_pdm_dl_data.abe_pdm_dl_data INPUT PULLDOWN | MODE0 */
+ 0xca 0x118 /* abe_pdm_frame.abe_pdm_frame INPUT PULLUP | MODE0 */
+ 0xcc 0x108 /* abe_pdm_lb_clk.abe_pdm_lb_clk INPUT PULLDOWN | MODE0 */
+ 0xce 0x108 /* abe_clks.abe_clks INPUT PULLDOWN | MODE0 */
+ >;
+ };
+
+ dmic_pins: pinmux_dmic_pins {
+ pinctrl-single,pins = <
+ 0xd0 0 /* abe_dmic_clk1.abe_dmic_clk1 OUTPUT | MODE0 */
+ 0xd2 0x100 /* abe_dmic_din1.abe_dmic_din1 INPUT | MODE0 */
+ 0xd4 0x100 /* abe_dmic_din2.abe_dmic_din2 INPUT | MODE0 */
+ 0xd6 0x100 /* abe_dmic_din3.abe_dmic_din3 INPUT | MODE0 */
+ >;
+ };
+
+ mcbsp1_pins: pinmux_mcbsp1_pins {
+ pinctrl-single,pins = <
+ 0xbe 0x100 /* abe_mcbsp1_clkx.abe_mcbsp1_clkx INPUT | MODE0 */
+ 0xc0 0x108 /* abe_mcbsp1_dr.abe_mcbsp1_dr INPUT PULLDOWN | MODE0 */
+ 0xc2 0x8 /* abe_mcbsp1_dx.abe_mcbsp1_dx OUTPUT PULLDOWN | MODE0 */
+ 0xc4 0x100 /* abe_mcbsp1_fsx.abe_mcbsp1_fsx INPUT | MODE0 */
+ >;
+ };
+
+ mcbsp2_pins: pinmux_mcbsp2_pins {
+ pinctrl-single,pins = <
+ 0xb6 0x100 /* abe_mcbsp2_clkx.abe_mcbsp2_clkx INPUT | MODE0 */
+ 0xb8 0x108 /* abe_mcbsp2_dr.abe_mcbsp2_dr INPUT PULLDOWN | MODE0 */
+ 0xba 0x8 /* abe_mcbsp2_dx.abe_mcbsp2_dx OUTPUT PULLDOWN | MODE0 */
+ 0xbc 0x100 /* abe_mcbsp2_fsx.abe_mcbsp2_fsx INPUT | MODE0 */
+ >;
+ };
};
&i2c1 {
@@ -349,3 +402,7 @@
pinctrl-names = "default";
pinctrl-0 = <&uart4_pins>;
};
+
+&mcbsp3 {
+ status = "disabled";
+};
diff --git a/arch/arm/boot/dts/omap5-evm.dts b/arch/arm/boot/dts/omap5-evm.dts
index 9c41a3f..c663eba 100644
--- a/arch/arm/boot/dts/omap5-evm.dts
+++ b/arch/arm/boot/dts/omap5-evm.dts
@@ -27,6 +27,60 @@
};
+&omap5_pmx_core {
+ pinctrl-names = "default";
+ pinctrl-0 = <
+ &twl6040_pins
+ &mcpdm_pins
+ &dmic_pins
+ &mcbsp1_pins
+ &mcbsp2_pins
+ >;
+
+ twl6040_pins: pinmux_twl6040_pins {
+ pinctrl-single,pins = <
+ 0x18a 0x6 /* perslimbus2_clock.gpio5_145 OUTPUT | MODE6 */
+ >;
+ };
+
+ mcpdm_pins: pinmux_mcpdm_pins {
+ pinctrl-single,pins = <
+ 0x142 0x108 /* abe_clks.abe_clks INPUT PULLDOWN | MODE0 */
+ 0x15c 0x108 /* abemcpdm_ul_data.abemcpdm_ul_data INPUT PULLDOWN | MODE0 */
+ 0x15e 0x108 /* abemcpdm_dl_data.abemcpdm_dl_data INPUT PULLDOWN | MODE0 */
+ 0x160 0x118 /* abemcpdm_frame.abemcpdm_frame INPUT PULLUP | MODE0 */
+ 0x162 0x108 /* abemcpdm_lb_clk.abemcpdm_lb_clk INPUT PULLDOWN | MODE0 */
+ >;
+ };
+
+ dmic_pins: pinmux_dmic_pins {
+ pinctrl-single,pins = <
+ 0x144 0x100 /* abedmic_din1.abedmic_din1 INPUT | MODE0 */
+ 0x146 0x100 /* abedmic_din2.abedmic_din2 INPUT | MODE0 */
+ 0x148 0x100 /* abedmic_din3.abedmic_din3 INPUT | MODE0 */
+ 0x14a 0 /* abedmic_clk1.abedmic_clk1 OUTPUT | MODE0 */
+ >;
+ };
+
+ mcbsp1_pins: pinmux_mcbsp1_pins {
+ pinctrl-single,pins = <
+ 0x14c 0x101 /* abedmic_clk2.abemcbsp1_fsx INPUT | MODE1 */
+ 0x14e 0x9 /* abedmic_clk3.abemcbsp1_dx OUTPUT PULLDOWN | MODE1 */
+ 0x150 0x101 /* abeslimbus1_clock.abemcbsp1_clkx INPUT | MODE0 */
+ 0x152 0x109 /* abeslimbus1_data.abemcbsp1_dr INPUT PULLDOWN | MODE1 */
+ >;
+ };
+
+ mcbsp2_pins: pinmux_mcbsp2_pins {
+ pinctrl-single,pins = <
+ 0x154 0x108 /* abemcbsp2_dr.abemcbsp2_dr INPUT PULLDOWN | MODE0 */
+ 0x156 0x8 /* abemcbsp2_dx.abemcbsp2_dx OUTPUT PULLDOWN | MODE0 */
+ 0x158 0x100 /* abemcbsp2_fsx.abemcbsp2_fsx INPUT | MODE0 */
+ 0x15a 0x100 /* abemcbsp2_clkx.abemcbsp2_clkx INPUT | MODE0 */
+ >;
+ };
+};
+
&mmc1 {
vmmc-supply = <&vmmcsd_fixed>;
bus-width = <4>;
@@ -82,3 +136,7 @@
0x020700d9>; /* SEARCH */
linux,input-no-autorepeat;
};
+
+&mcbsp3 {
+ status = "disabled";
+};
diff --git a/arch/arm/boot/dts/omap5.dtsi b/arch/arm/boot/dts/omap5.dtsi
index 5db33f4..42c78be 100644
--- a/arch/arm/boot/dts/omap5.dtsi
+++ b/arch/arm/boot/dts/omap5.dtsi
@@ -77,6 +77,23 @@
ranges;
ti,hwmods = "l3_main_1", "l3_main_2", "l3_main_3";
+ omap5_pmx_core: pinmux@4a002840 {
+ compatible = "ti,omap4-padconf", "pinctrl-single";
+ reg = <0x4a002840 0x01b6>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ pinctrl-single,register-width = <16>;
+ pinctrl-single,function-mask = <0x7fff>;
+ };
+ omap5_pmx_wkup: pinmux@4ae0c840 {
+ compatible = "ti,omap4-padconf", "pinctrl-single";
+ reg = <0x4ae0c840 0x0038>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ pinctrl-single,register-width = <16>;
+ pinctrl-single,function-mask = <0x7fff>;
+ };
+
gic: interrupt-controller@48211000 {
compatible = "arm,cortex-a15-gic";
interrupt-controller;
diff --git a/arch/arm/boot/dts/spear300-evb.dts b/arch/arm/boot/dts/spear300-evb.dts
index d71b8d5..1e7c7a8 100644
--- a/arch/arm/boot/dts/spear300-evb.dts
+++ b/arch/arm/boot/dts/spear300-evb.dts
@@ -80,8 +80,7 @@
};
sdhci@70000000 {
- int-gpio = <&gpio1 0 0>;
- power-gpio = <&gpio1 2 1>;
+ cd-gpios = <&gpio1 0 0>;
status = "okay";
};
diff --git a/arch/arm/boot/dts/spear320-evb.dts b/arch/arm/boot/dts/spear320-evb.dts
index e4e912f..082328b 100644
--- a/arch/arm/boot/dts/spear320-evb.dts
+++ b/arch/arm/boot/dts/spear320-evb.dts
@@ -103,8 +103,6 @@
};
sdhci@70000000 {
- power-gpio = <&gpio0 2 1>;
- power_always_enb;
status = "okay";
};
diff --git a/arch/arm/boot/dts/tegra20-seaboard.dts b/arch/arm/boot/dts/tegra20-seaboard.dts
index e60dc71..f0ba901 100644
--- a/arch/arm/boot/dts/tegra20-seaboard.dts
+++ b/arch/arm/boot/dts/tegra20-seaboard.dts
@@ -539,7 +539,7 @@
nvidia,invert-interrupt;
};
- memory-controller@0x7000f400 {
+ memory-controller@7000f400 {
emc-table@190000 {
reg = <190000>;
compatible = "nvidia,tegra20-emc-table";
diff --git a/arch/arm/boot/dts/tegra20.dtsi b/arch/arm/boot/dts/tegra20.dtsi
index 67a6cd9..f3a09d0 100644
--- a/arch/arm/boot/dts/tegra20.dtsi
+++ b/arch/arm/boot/dts/tegra20.dtsi
@@ -170,7 +170,7 @@
reg = <0x7000e400 0x400>;
};
- memory-controller@0x7000f000 {
+ memory-controller@7000f000 {
compatible = "nvidia,tegra20-mc";
reg = <0x7000f000 0x024
0x7000f03c 0x3c4>;
@@ -183,7 +183,7 @@
0x58000000 0x02000000>; /* GART aperture */
};
- memory-controller@0x7000f400 {
+ memory-controller@7000f400 {
compatible = "nvidia,tegra20-emc";
reg = <0x7000f400 0x200>;
#address-cells = <1>;
diff --git a/arch/arm/common/it8152.c b/arch/arm/common/it8152.c
index c4110d1..001f491 100644
--- a/arch/arm/common/it8152.c
+++ b/arch/arm/common/it8152.c
@@ -284,11 +284,17 @@ int dma_set_coherent_mask(struct device *dev, u64 mask)
int __init it8152_pci_setup(int nr, struct pci_sys_data *sys)
{
- it8152_io.start = IT8152_IO_BASE + 0x12000;
- it8152_io.end = IT8152_IO_BASE + 0x12000 + 0x100000;
+ /*
+ * FIXME: use pci_ioremap_io to remap the IO space here and
+ * move over to the generic io.h implementation.
+ * This requires solving the same problem for PXA PCMCIA
+ * support.
+ */
+ it8152_io.start = (unsigned long)IT8152_IO_BASE + 0x12000;
+ it8152_io.end = (unsigned long)IT8152_IO_BASE + 0x12000 + 0x100000;
sys->mem_offset = 0x10000000;
- sys->io_offset = IT8152_IO_BASE;
+ sys->io_offset = (unsigned long)IT8152_IO_BASE;
if (request_resource(&ioport_resource, &it8152_io)) {
printk(KERN_ERR "PCI: unable to allocate IO region\n");
diff --git a/arch/arm/configs/cam60_defconfig b/arch/arm/configs/cam60_defconfig
index cedc92e..1457971 100644
--- a/arch/arm/configs/cam60_defconfig
+++ b/arch/arm/configs/cam60_defconfig
@@ -49,7 +49,6 @@ CONFIG_MTD_COMPLEX_MAPPINGS=y
CONFIG_MTD_PLATRAM=m
CONFIG_MTD_DATAFLASH=y
CONFIG_MTD_NAND=y
-CONFIG_MTD_NAND_VERIFY_WRITE=y
CONFIG_MTD_NAND_ATMEL=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_RAM=y
diff --git a/arch/arm/configs/corgi_defconfig b/arch/arm/configs/corgi_defconfig
index e53c475..4b8a25d 100644
--- a/arch/arm/configs/corgi_defconfig
+++ b/arch/arm/configs/corgi_defconfig
@@ -97,7 +97,6 @@ CONFIG_MTD_BLOCK=y
CONFIG_MTD_ROM=y
CONFIG_MTD_COMPLEX_MAPPINGS=y
CONFIG_MTD_NAND=y
-CONFIG_MTD_NAND_VERIFY_WRITE=y
CONFIG_MTD_NAND_SHARPSL=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_IDE=y
diff --git a/arch/arm/configs/ep93xx_defconfig b/arch/arm/configs/ep93xx_defconfig
index 8e97b2f..806005a 100644
--- a/arch/arm/configs/ep93xx_defconfig
+++ b/arch/arm/configs/ep93xx_defconfig
@@ -61,7 +61,6 @@ CONFIG_MTD_CFI_STAA=y
CONFIG_MTD_ROM=y
CONFIG_MTD_PHYSMAP=y
CONFIG_MTD_NAND=y
-CONFIG_MTD_NAND_VERIFY_WRITE=y
CONFIG_BLK_DEV_NBD=y
CONFIG_EEPROM_LEGACY=y
CONFIG_SCSI=y
diff --git a/arch/arm/configs/mini2440_defconfig b/arch/arm/configs/mini2440_defconfig
index 082175c..00630e6 100644
--- a/arch/arm/configs/mini2440_defconfig
+++ b/arch/arm/configs/mini2440_defconfig
@@ -102,7 +102,6 @@ CONFIG_MTD_CFI_STAA=y
CONFIG_MTD_RAM=y
CONFIG_MTD_ROM=y
CONFIG_MTD_NAND=y
-CONFIG_MTD_NAND_VERIFY_WRITE=y
CONFIG_MTD_NAND_S3C2410=y
CONFIG_MTD_NAND_PLATFORM=y
CONFIG_MTD_LPDDR=y
diff --git a/arch/arm/configs/mv78xx0_defconfig b/arch/arm/configs/mv78xx0_defconfig
index 7305ebd..1f08219 100644
--- a/arch/arm/configs/mv78xx0_defconfig
+++ b/arch/arm/configs/mv78xx0_defconfig
@@ -49,7 +49,6 @@ CONFIG_MTD_CFI_INTELEXT=y
CONFIG_MTD_CFI_AMDSTD=y
CONFIG_MTD_PHYSMAP=y
CONFIG_MTD_NAND=y
-CONFIG_MTD_NAND_VERIFY_WRITE=y
CONFIG_MTD_NAND_ORION=y
CONFIG_BLK_DEV_LOOP=y
# CONFIG_SCSI_PROC_FS is not set
diff --git a/arch/arm/configs/nhk8815_defconfig b/arch/arm/configs/nhk8815_defconfig
index bf123c5..240b25e 100644
--- a/arch/arm/configs/nhk8815_defconfig
+++ b/arch/arm/configs/nhk8815_defconfig
@@ -57,7 +57,6 @@ CONFIG_MTD_CHAR=y
CONFIG_MTD_BLOCK=y
CONFIG_MTD_NAND=y
CONFIG_MTD_NAND_ECC_SMC=y
-CONFIG_MTD_NAND_VERIFY_WRITE=y
CONFIG_MTD_NAND_NOMADIK=y
CONFIG_MTD_ONENAND=y
CONFIG_MTD_ONENAND_VERIFY_WRITE=y
diff --git a/arch/arm/configs/orion5x_defconfig b/arch/arm/configs/orion5x_defconfig
index a288d70..cd5e6ba 100644
--- a/arch/arm/configs/orion5x_defconfig
+++ b/arch/arm/configs/orion5x_defconfig
@@ -72,7 +72,6 @@ CONFIG_MTD_CFI_INTELEXT=y
CONFIG_MTD_CFI_AMDSTD=y
CONFIG_MTD_PHYSMAP=y
CONFIG_MTD_NAND=y
-CONFIG_MTD_NAND_VERIFY_WRITE=y
CONFIG_MTD_NAND_PLATFORM=y
CONFIG_MTD_NAND_ORION=y
CONFIG_BLK_DEV_LOOP=y
diff --git a/arch/arm/configs/pxa3xx_defconfig b/arch/arm/configs/pxa3xx_defconfig
index 1677a06..60e3138 100644
--- a/arch/arm/configs/pxa3xx_defconfig
+++ b/arch/arm/configs/pxa3xx_defconfig
@@ -36,7 +36,6 @@ CONFIG_MTD_CONCAT=y
CONFIG_MTD_CHAR=y
CONFIG_MTD_BLOCK=y
CONFIG_MTD_NAND=y
-CONFIG_MTD_NAND_VERIFY_WRITE=y
CONFIG_MTD_NAND_PXA3xx=y
CONFIG_MTD_NAND_PXA3xx_BUILTIN=y
CONFIG_MTD_ONENAND=y
diff --git a/arch/arm/configs/spitz_defconfig b/arch/arm/configs/spitz_defconfig
index 7015827..df77931 100644
--- a/arch/arm/configs/spitz_defconfig
+++ b/arch/arm/configs/spitz_defconfig
@@ -94,7 +94,6 @@ CONFIG_MTD_BLOCK=y
CONFIG_MTD_ROM=y
CONFIG_MTD_COMPLEX_MAPPINGS=y
CONFIG_MTD_NAND=y
-CONFIG_MTD_NAND_VERIFY_WRITE=y
CONFIG_MTD_NAND_SHARPSL=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_IDE=y
diff --git a/arch/arm/include/asm/processor.h b/arch/arm/include/asm/processor.h
index 99afa74..06e7d50 100644
--- a/arch/arm/include/asm/processor.h
+++ b/arch/arm/include/asm/processor.h
@@ -85,11 +85,6 @@ unsigned long get_wchan(struct task_struct *p);
#define cpu_relax() barrier()
#endif
-/*
- * Create a new kernel thread
- */
-extern int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
-
#define task_pt_regs(p) \
((struct pt_regs *)(THREAD_START_SP + task_stack_page(p)) - 1)
diff --git a/arch/arm/include/asm/ptrace.h b/arch/arm/include/asm/ptrace.h
index 355ece5..44fe998 100644
--- a/arch/arm/include/asm/ptrace.h
+++ b/arch/arm/include/asm/ptrace.h
@@ -254,6 +254,11 @@ static inline unsigned long user_stack_pointer(struct pt_regs *regs)
return regs->ARM_sp;
}
+#define current_pt_regs(void) ({ \
+ register unsigned long sp asm ("sp"); \
+ (struct pt_regs *)((sp | (THREAD_SIZE - 1)) - 7) - 1; \
+})
+
#endif /* __KERNEL__ */
#endif /* __ASSEMBLY__ */
diff --git a/arch/arm/include/asm/system.h b/arch/arm/include/asm/system.h
index 74542c5..368165e 100644
--- a/arch/arm/include/asm/system.h
+++ b/arch/arm/include/asm/system.h
@@ -2,7 +2,6 @@
#include <asm/barrier.h>
#include <asm/compiler.h>
#include <asm/cmpxchg.h>
-#include <asm/exec.h>
#include <asm/switch_to.h>
#include <asm/system_info.h>
#include <asm/system_misc.h>
diff --git a/arch/arm/include/asm/thread_info.h b/arch/arm/include/asm/thread_info.h
index f71cdab..8477b4c 100644
--- a/arch/arm/include/asm/thread_info.h
+++ b/arch/arm/include/asm/thread_info.h
@@ -151,7 +151,6 @@ extern int vfp_restore_user_hwstate(struct user_vfp __user *,
#define TIF_SYSCALL_TRACE 8
#define TIF_SYSCALL_AUDIT 9
#define TIF_SYSCALL_TRACEPOINT 10
-#define TIF_POLLING_NRFLAG 16
#define TIF_USING_IWMMXT 17
#define TIF_MEMDIE 18 /* is terminating due to OOM killer */
#define TIF_RESTORE_SIGMASK 20
@@ -164,7 +163,6 @@ extern int vfp_restore_user_hwstate(struct user_vfp __user *,
#define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE)
#define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT)
#define _TIF_SYSCALL_TRACEPOINT (1 << TIF_SYSCALL_TRACEPOINT)
-#define _TIF_POLLING_NRFLAG (1 << TIF_POLLING_NRFLAG)
#define _TIF_USING_IWMMXT (1 << TIF_USING_IWMMXT)
#define _TIF_SECCOMP (1 << TIF_SECCOMP)
diff --git a/arch/arm/include/asm/unistd.h b/arch/arm/include/asm/unistd.h
index d9ff5cc..f259921 100644
--- a/arch/arm/include/asm/unistd.h
+++ b/arch/arm/include/asm/unistd.h
@@ -478,6 +478,8 @@
#define __ARCH_WANT_OLD_READDIR
#define __ARCH_WANT_SYS_SOCKETCALL
#endif
+#define __ARCH_WANT_SYS_EXECVE
+#define __ARCH_WANT_KERNEL_EXECVE
/*
* "Conditional" syscalls
diff --git a/arch/arm/kernel/calls.S b/arch/arm/kernel/calls.S
index e337879..831cd38 100644
--- a/arch/arm/kernel/calls.S
+++ b/arch/arm/kernel/calls.S
@@ -20,7 +20,7 @@
CALL(sys_creat)
CALL(sys_link)
/* 10 */ CALL(sys_unlink)
- CALL(sys_execve_wrapper)
+ CALL(sys_execve)
CALL(sys_chdir)
CALL(OBSOLETE(sys_time)) /* used by libc4 */
CALL(sys_mknod)
diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S
index f459870..e340fa1 100644
--- a/arch/arm/kernel/entry-common.S
+++ b/arch/arm/kernel/entry-common.S
@@ -91,6 +91,30 @@ ENTRY(ret_from_fork)
b ret_slow_syscall
ENDPROC(ret_from_fork)
+ENTRY(ret_from_kernel_thread)
+ UNWIND(.fnstart)
+ UNWIND(.cantunwind)
+ bl schedule_tail
+ mov r0, r4
+ adr lr, BSYM(1f) @ kernel threads should not exit
+ mov pc, r5
+1: bl do_exit
+ nop
+ UNWIND(.fnend)
+ENDPROC(ret_from_kernel_thread)
+
+/*
+ * turn a kernel thread into userland process
+ * use: ret_from_kernel_execve(struct pt_regs *normal)
+ */
+ENTRY(ret_from_kernel_execve)
+ mov why, #0 @ not a syscall
+ str why, [r0, #S_R0] @ ... and we want 0 in ->ARM_r0 as well
+ get_thread_info tsk @ thread structure
+ mov sp, r0 @ stack pointer just under pt_regs
+ b ret_slow_syscall
+ENDPROC(ret_from_kernel_execve)
+
.equ NR_syscalls,0
#define CALL(x) .equ NR_syscalls,NR_syscalls+1
#include "calls.S"
@@ -517,11 +541,6 @@ sys_vfork_wrapper:
b sys_vfork
ENDPROC(sys_vfork_wrapper)
-sys_execve_wrapper:
- add r3, sp, #S_OFF
- b sys_execve
-ENDPROC(sys_execve_wrapper)
-
sys_clone_wrapper:
add ip, sp, #S_OFF
str ip, [sp, #4]
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
index 04eea22..f98c17f 100644
--- a/arch/arm/kernel/process.c
+++ b/arch/arm/kernel/process.c
@@ -373,6 +373,7 @@ void release_thread(struct task_struct *dead_task)
}
asmlinkage void ret_from_fork(void) __asm__("ret_from_fork");
+asmlinkage void ret_from_kernel_thread(void) __asm__("ret_from_kernel_thread");
int
copy_thread(unsigned long clone_flags, unsigned long stack_start,
@@ -381,13 +382,20 @@ copy_thread(unsigned long clone_flags, unsigned long stack_start,
struct thread_info *thread = task_thread_info(p);
struct pt_regs *childregs = task_pt_regs(p);
- *childregs = *regs;
- childregs->ARM_r0 = 0;
- childregs->ARM_sp = stack_start;
-
memset(&thread->cpu_context, 0, sizeof(struct cpu_context_save));
+
+ if (likely(regs)) {
+ *childregs = *regs;
+ childregs->ARM_r0 = 0;
+ childregs->ARM_sp = stack_start;
+ thread->cpu_context.pc = (unsigned long)ret_from_fork;
+ } else {
+ thread->cpu_context.r4 = stk_sz;
+ thread->cpu_context.r5 = stack_start;
+ thread->cpu_context.pc = (unsigned long)ret_from_kernel_thread;
+ childregs->ARM_cpsr = SVC_MODE;
+ }
thread->cpu_context.sp = (unsigned long)childregs;
- thread->cpu_context.pc = (unsigned long)ret_from_fork;
clear_ptrace_hw_breakpoint(p);
@@ -423,63 +431,6 @@ int dump_fpu (struct pt_regs *regs, struct user_fp *fp)
}
EXPORT_SYMBOL(dump_fpu);
-/*
- * Shuffle the argument into the correct register before calling the
- * thread function. r4 is the thread argument, r5 is the pointer to
- * the thread function, and r6 points to the exit function.
- */
-extern void kernel_thread_helper(void);
-asm( ".pushsection .text\n"
-" .align\n"
-" .type kernel_thread_helper, #function\n"
-"kernel_thread_helper:\n"
-#ifdef CONFIG_TRACE_IRQFLAGS
-" bl trace_hardirqs_on\n"
-#endif
-" msr cpsr_c, r7\n"
-" mov r0, r4\n"
-" mov lr, r6\n"
-" mov pc, r5\n"
-" .size kernel_thread_helper, . - kernel_thread_helper\n"
-" .popsection");
-
-#ifdef CONFIG_ARM_UNWIND
-extern void kernel_thread_exit(long code);
-asm( ".pushsection .text\n"
-" .align\n"
-" .type kernel_thread_exit, #function\n"
-"kernel_thread_exit:\n"
-" .fnstart\n"
-" .cantunwind\n"
-" bl do_exit\n"
-" nop\n"
-" .fnend\n"
-" .size kernel_thread_exit, . - kernel_thread_exit\n"
-" .popsection");
-#else
-#define kernel_thread_exit do_exit
-#endif
-
-/*
- * Create a kernel thread.
- */
-pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
-{
- struct pt_regs regs;
-
- memset(&regs, 0, sizeof(regs));
-
- regs.ARM_r4 = (unsigned long)arg;
- regs.ARM_r5 = (unsigned long)fn;
- regs.ARM_r6 = (unsigned long)kernel_thread_exit;
- regs.ARM_r7 = SVC_MODE | PSR_ENDSTATE | PSR_ISETSTATE;
- regs.ARM_pc = (unsigned long)kernel_thread_helper;
- regs.ARM_cpsr = regs.ARM_r7 | PSR_I_BIT;
-
- return do_fork(flags|CLONE_VM|CLONE_UNTRACED, 0, &regs, 0, NULL, NULL);
-}
-EXPORT_SYMBOL(kernel_thread);
-
unsigned long get_wchan(struct task_struct *p)
{
struct stackframe frame;
diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c
index f27789e..56f72d2 100644
--- a/arch/arm/kernel/signal.c
+++ b/arch/arm/kernel/signal.c
@@ -10,7 +10,6 @@
#include <linux/errno.h>
#include <linux/signal.h>
#include <linux/personality.h>
-#include <linux/freezer.h>
#include <linux/uaccess.h>
#include <linux/tracehook.h>
diff --git a/arch/arm/kernel/sys_arm.c b/arch/arm/kernel/sys_arm.c
index 76cbb05..c2a898a 100644
--- a/arch/arm/kernel/sys_arm.c
+++ b/arch/arm/kernel/sys_arm.c
@@ -59,69 +59,6 @@ asmlinkage int sys_vfork(struct pt_regs *regs)
return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->ARM_sp, regs, 0, NULL, NULL);
}
-/* sys_execve() executes a new program.
- * This is called indirectly via a small wrapper
- */
-asmlinkage int sys_execve(const char __user *filenamei,
- const char __user *const __user *argv,
- const char __user *const __user *envp, struct pt_regs *regs)
-{
- int error;
- char * filename;
-
- filename = getname(filenamei);
- error = PTR_ERR(filename);
- if (IS_ERR(filename))
- goto out;
- error = do_execve(filename, argv, envp, regs);
- putname(filename);
-out:
- return error;
-}
-
-int kernel_execve(const char *filename,
- const char *const argv[],
- const char *const envp[])
-{
- struct pt_regs regs;
- int ret;
-
- memset(&regs, 0, sizeof(struct pt_regs));
- ret = do_execve(filename,
- (const char __user *const __user *)argv,
- (const char __user *const __user *)envp, &regs);
- if (ret < 0)
- goto out;
-
- /*
- * Save argc to the register structure for userspace.
- */
- regs.ARM_r0 = ret;
-
- /*
- * We were successful. We won't be returning to our caller, but
- * instead to user space by manipulating the kernel stack.
- */
- asm( "add r0, %0, %1\n\t"
- "mov r1, %2\n\t"
- "mov r2, %3\n\t"
- "bl memmove\n\t" /* copy regs to top of stack */
- "mov r8, #0\n\t" /* not a syscall */
- "mov r9, %0\n\t" /* thread structure */
- "mov sp, r0\n\t" /* reposition stack pointer */
- "b ret_to_user"
- :
- : "r" (current_thread_info()),
- "Ir" (THREAD_START_SP - sizeof(regs)),
- "r" (&regs),
- "Ir" (sizeof(regs))
- : "r0", "r1", "r2", "r3", "r8", "r9", "ip", "lr", "memory");
-
- out:
- return ret;
-}
-EXPORT_SYMBOL(kernel_execve);
-
/*
* Since loff_t is a 64 bit type we avoid a lot of ABI hassle
* with a different argument ordering.
diff --git a/arch/arm/mach-at91/at91rm9200.c b/arch/arm/mach-at91/at91rm9200.c
index 6f50c67..b4f0565 100644
--- a/arch/arm/mach-at91/at91rm9200.c
+++ b/arch/arm/mach-at91/at91rm9200.c
@@ -187,6 +187,7 @@ 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("pclk", "ssc.2", &ssc2_clk),
+ CLKDEV_CON_DEV_ID(NULL, "i2c-at91rm9200", &twi_clk),
/* fake hclk clock */
CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &ohci_clk),
CLKDEV_CON_ID("pioA", &pioA_clk),
diff --git a/arch/arm/mach-at91/at91rm9200_devices.c b/arch/arm/mach-at91/at91rm9200_devices.c
index 9ac427a..a563189 100644
--- a/arch/arm/mach-at91/at91rm9200_devices.c
+++ b/arch/arm/mach-at91/at91rm9200_devices.c
@@ -511,7 +511,7 @@ static struct resource twi_resources[] = {
};
static struct platform_device at91rm9200_twi_device = {
- .name = "at91_i2c",
+ .name = "i2c-at91rm9200",
.id = -1,
.resource = twi_resources,
.num_resources = ARRAY_SIZE(twi_resources),
diff --git a/arch/arm/mach-at91/at91sam9260.c b/arch/arm/mach-at91/at91sam9260.c
index 30c7f26..ad29f93 100644
--- a/arch/arm/mach-at91/at91sam9260.c
+++ b/arch/arm/mach-at91/at91sam9260.c
@@ -211,6 +211,8 @@ static struct clk_lookup periph_clocks_lookups[] = {
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("pclk", "ssc.0", &ssc_clk),
+ CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9260", &twi_clk),
+ CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g20", &twi_clk),
/* more usart lookup table for DT entries */
CLKDEV_CON_DEV_ID("usart", "fffff200.serial", &mck),
CLKDEV_CON_DEV_ID("usart", "fffb0000.serial", &usart0_clk),
@@ -219,6 +221,7 @@ static struct clk_lookup periph_clocks_lookups[] = {
CLKDEV_CON_DEV_ID("usart", "fffd0000.serial", &usart3_clk),
CLKDEV_CON_DEV_ID("usart", "fffd4000.serial", &usart4_clk),
CLKDEV_CON_DEV_ID("usart", "fffd8000.serial", &usart5_clk),
+ CLKDEV_CON_DEV_ID(NULL, "fffac000.i2c", &twi_clk),
/* more tc lookup table for DT entries */
CLKDEV_CON_DEV_ID("t0_clk", "fffa0000.timer", &tc0_clk),
CLKDEV_CON_DEV_ID("t1_clk", "fffa0000.timer", &tc1_clk),
diff --git a/arch/arm/mach-at91/at91sam9260_devices.c b/arch/arm/mach-at91/at91sam9260_devices.c
index af50ff3..a76b868 100644
--- a/arch/arm/mach-at91/at91sam9260_devices.c
+++ b/arch/arm/mach-at91/at91sam9260_devices.c
@@ -421,7 +421,6 @@ static struct resource twi_resources[] = {
};
static struct platform_device at91sam9260_twi_device = {
- .name = "at91_i2c",
.id = -1,
.resource = twi_resources,
.num_resources = ARRAY_SIZE(twi_resources),
@@ -429,6 +428,13 @@ static struct platform_device at91sam9260_twi_device = {
void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices)
{
+ /* IP version is not the same on 9260 and g20 */
+ if (cpu_is_at91sam9g20()) {
+ at91sam9260_twi_device.name = "i2c-at91sam9g20";
+ } else {
+ at91sam9260_twi_device.name = "i2c-at91sam9260";
+ }
+
/* pins used for TWI interface */
at91_set_A_periph(AT91_PIN_PA23, 0); /* TWD */
at91_set_multi_drive(AT91_PIN_PA23, 1);
diff --git a/arch/arm/mach-at91/at91sam9261.c b/arch/arm/mach-at91/at91sam9261.c
index f40762c..8d999eb 100644
--- a/arch/arm/mach-at91/at91sam9261.c
+++ b/arch/arm/mach-at91/at91sam9261.c
@@ -178,6 +178,8 @@ static struct clk_lookup periph_clocks_lookups[] = {
CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk),
CLKDEV_CON_DEV_ID("pclk", "ssc.2", &ssc2_clk),
CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &hck0),
+ CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9261", &twi_clk),
+ CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g10", &twi_clk),
CLKDEV_CON_ID("pioA", &pioA_clk),
CLKDEV_CON_ID("pioB", &pioB_clk),
CLKDEV_CON_ID("pioC", &pioC_clk),
diff --git a/arch/arm/mach-at91/at91sam9261_devices.c b/arch/arm/mach-at91/at91sam9261_devices.c
index 11e9fa8..9752f17 100644
--- a/arch/arm/mach-at91/at91sam9261_devices.c
+++ b/arch/arm/mach-at91/at91sam9261_devices.c
@@ -317,7 +317,6 @@ static struct resource twi_resources[] = {
};
static struct platform_device at91sam9261_twi_device = {
- .name = "at91_i2c",
.id = -1,
.resource = twi_resources,
.num_resources = ARRAY_SIZE(twi_resources),
@@ -325,12 +324,19 @@ static struct platform_device at91sam9261_twi_device = {
void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices)
{
+ /* IP version is not the same on 9261 and g10 */
+ if (cpu_is_at91sam9g10()) {
+ at91sam9261_twi_device.name = "i2c-at91sam9g10";
+ /* I2C PIO must not be configured as open-drain on this chip */
+ } else {
+ at91sam9261_twi_device.name = "i2c-at91sam9261";
+ at91_set_multi_drive(AT91_PIN_PA7, 1);
+ at91_set_multi_drive(AT91_PIN_PA8, 1);
+ }
+
/* pins used for TWI interface */
at91_set_A_periph(AT91_PIN_PA7, 0); /* TWD */
- at91_set_multi_drive(AT91_PIN_PA7, 1);
-
at91_set_A_periph(AT91_PIN_PA8, 0); /* TWCK */
- at91_set_multi_drive(AT91_PIN_PA8, 1);
i2c_register_board_info(0, devices, nr_devices);
platform_device_register(&at91sam9261_twi_device);
diff --git a/arch/arm/mach-at91/at91sam9263.c b/arch/arm/mach-at91/at91sam9263.c
index 144ef5d..6a01d03 100644
--- a/arch/arm/mach-at91/at91sam9263.c
+++ b/arch/arm/mach-at91/at91sam9263.c
@@ -193,6 +193,7 @@ 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", &tcb_clk),
+ CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9260", &twi_clk),
/* fake hclk clock */
CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &ohci_clk),
CLKDEV_CON_ID("pioA", &pioA_clk),
@@ -210,6 +211,7 @@ static struct clk_lookup periph_clocks_lookups[] = {
CLKDEV_CON_DEV_ID("hclk", "a00000.ohci", &ohci_clk),
CLKDEV_CON_DEV_ID("spi_clk", "fffa4000.spi", &spi0_clk),
CLKDEV_CON_DEV_ID("spi_clk", "fffa8000.spi", &spi1_clk),
+ CLKDEV_CON_DEV_ID(NULL, "fff88000.i2c", &twi_clk),
};
static struct clk_lookup usart_clocks_lookups[] = {
diff --git a/arch/arm/mach-at91/at91sam9263_devices.c b/arch/arm/mach-at91/at91sam9263_devices.c
index 7c0898f..8dde220 100644
--- a/arch/arm/mach-at91/at91sam9263_devices.c
+++ b/arch/arm/mach-at91/at91sam9263_devices.c
@@ -599,7 +599,7 @@ static struct resource twi_resources[] = {
};
static struct platform_device at91sam9263_twi_device = {
- .name = "at91_i2c",
+ .name = "i2c-at91sam9260",
.id = -1,
.resource = twi_resources,
.num_resources = ARRAY_SIZE(twi_resources),
diff --git a/arch/arm/mach-at91/at91sam9g45.c b/arch/arm/mach-at91/at91sam9g45.c
index ef6cedd..84af1b5 100644
--- a/arch/arm/mach-at91/at91sam9g45.c
+++ b/arch/arm/mach-at91/at91sam9g45.c
@@ -237,6 +237,8 @@ static struct clk_lookup periph_clocks_lookups[] = {
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(NULL, "i2c-at91sam9g10.0", &twi0_clk),
+ CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g10.1", &twi1_clk),
CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc0_clk),
CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk),
CLKDEV_CON_DEV_ID(NULL, "atmel-trng", &trng_clk),
@@ -254,6 +256,8 @@ static struct clk_lookup periph_clocks_lookups[] = {
CLKDEV_CON_DEV_ID("t0_clk", "fffd4000.timer", &tcb0_clk),
CLKDEV_CON_DEV_ID("hclk", "700000.ohci", &uhphs_clk),
CLKDEV_CON_DEV_ID("ehci_clk", "800000.ehci", &uhphs_clk),
+ CLKDEV_CON_DEV_ID(NULL, "fff84000.i2c", &twi0_clk),
+ CLKDEV_CON_DEV_ID(NULL, "fff88000.i2c", &twi1_clk),
/* fake hclk clock */
CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &uhphs_clk),
CLKDEV_CON_ID("pioA", &pioA_clk),
diff --git a/arch/arm/mach-at91/at91sam9g45_devices.c b/arch/arm/mach-at91/at91sam9g45_devices.c
index e4c3b37..b159607 100644
--- a/arch/arm/mach-at91/at91sam9g45_devices.c
+++ b/arch/arm/mach-at91/at91sam9g45_devices.c
@@ -653,7 +653,7 @@ static struct resource twi0_resources[] = {
};
static struct platform_device at91sam9g45_twi0_device = {
- .name = "at91_i2c",
+ .name = "i2c-at91sam9g10",
.id = 0,
.resource = twi0_resources,
.num_resources = ARRAY_SIZE(twi0_resources),
@@ -673,7 +673,7 @@ static struct resource twi1_resources[] = {
};
static struct platform_device at91sam9g45_twi1_device = {
- .name = "at91_i2c",
+ .name = "i2c-at91sam9g10",
.id = 1,
.resource = twi1_resources,
.num_resources = ARRAY_SIZE(twi1_resources),
@@ -686,18 +686,12 @@ void __init at91_add_device_i2c(short i2c_id, struct i2c_board_info *devices, in
/* pins used for TWI interface */
if (i2c_id == 0) {
at91_set_A_periph(AT91_PIN_PA20, 0); /* TWD */
- at91_set_multi_drive(AT91_PIN_PA20, 1);
-
at91_set_A_periph(AT91_PIN_PA21, 0); /* TWCK */
- at91_set_multi_drive(AT91_PIN_PA21, 1);
platform_device_register(&at91sam9g45_twi0_device);
} else {
at91_set_A_periph(AT91_PIN_PB10, 0); /* TWD */
- at91_set_multi_drive(AT91_PIN_PB10, 1);
-
at91_set_A_periph(AT91_PIN_PB11, 0); /* TWCK */
- at91_set_multi_drive(AT91_PIN_PB11, 1);
platform_device_register(&at91sam9g45_twi1_device);
}
diff --git a/arch/arm/mach-at91/at91sam9n12.c b/arch/arm/mach-at91/at91sam9n12.c
index 0849466..732d3d3 100644
--- a/arch/arm/mach-at91/at91sam9n12.c
+++ b/arch/arm/mach-at91/at91sam9n12.c
@@ -169,6 +169,8 @@ static struct clk_lookup periph_clocks_lookups[] = {
CLKDEV_CON_DEV_ID("t0_clk", "f8008000.timer", &tcb_clk),
CLKDEV_CON_DEV_ID("t0_clk", "f800c000.timer", &tcb_clk),
CLKDEV_CON_DEV_ID("dma_clk", "ffffec00.dma-controller", &dma_clk),
+ CLKDEV_CON_DEV_ID(NULL, "f8010000.i2c", &twi0_clk),
+ CLKDEV_CON_DEV_ID(NULL, "f8014000.i2c", &twi1_clk),
CLKDEV_CON_ID("pioA", &pioAB_clk),
CLKDEV_CON_ID("pioB", &pioAB_clk),
CLKDEV_CON_ID("pioC", &pioCD_clk),
diff --git a/arch/arm/mach-at91/at91sam9rl.c b/arch/arm/mach-at91/at91sam9rl.c
index 72ce50a..72e9084 100644
--- a/arch/arm/mach-at91/at91sam9rl.c
+++ b/arch/arm/mach-at91/at91sam9rl.c
@@ -186,6 +186,8 @@ static struct clk_lookup periph_clocks_lookups[] = {
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),
+ CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g20.0", &twi0_clk),
+ CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g20.1", &twi1_clk),
CLKDEV_CON_ID("pioA", &pioA_clk),
CLKDEV_CON_ID("pioB", &pioB_clk),
CLKDEV_CON_ID("pioC", &pioC_clk),
diff --git a/arch/arm/mach-at91/at91sam9rl_devices.c b/arch/arm/mach-at91/at91sam9rl_devices.c
index deafea0..d6ca054 100644
--- a/arch/arm/mach-at91/at91sam9rl_devices.c
+++ b/arch/arm/mach-at91/at91sam9rl_devices.c
@@ -346,7 +346,7 @@ static struct resource twi_resources[] = {
};
static struct platform_device at91sam9rl_twi_device = {
- .name = "at91_i2c",
+ .name = "i2c-at91sam9g20",
.id = -1,
.resource = twi_resources,
.num_resources = ARRAY_SIZE(twi_resources),
diff --git a/arch/arm/mach-at91/at91sam9x5.c b/arch/arm/mach-at91/at91sam9x5.c
index 477cf9d..e503538 100644
--- a/arch/arm/mach-at91/at91sam9x5.c
+++ b/arch/arm/mach-at91/at91sam9x5.c
@@ -231,6 +231,9 @@ static struct clk_lookup periph_clocks_lookups[] = {
CLKDEV_CON_DEV_ID("t0_clk", "f800c000.timer", &tcb0_clk),
CLKDEV_CON_DEV_ID("dma_clk", "ffffec00.dma-controller", &dma0_clk),
CLKDEV_CON_DEV_ID("dma_clk", "ffffee00.dma-controller", &dma1_clk),
+ CLKDEV_CON_DEV_ID(NULL, "f8010000.i2c", &twi0_clk),
+ CLKDEV_CON_DEV_ID(NULL, "f8014000.i2c", &twi1_clk),
+ CLKDEV_CON_DEV_ID(NULL, "f8018000.i2c", &twi2_clk),
CLKDEV_CON_ID("pioA", &pioAB_clk),
CLKDEV_CON_ID("pioB", &pioAB_clk),
CLKDEV_CON_ID("pioC", &pioCD_clk),
diff --git a/arch/arm/mach-at91/include/mach/at91_twi.h b/arch/arm/mach-at91/include/mach/at91_twi.h
deleted file mode 100644
index bb2880f..0000000
--- a/arch/arm/mach-at91/include/mach/at91_twi.h
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * arch/arm/mach-at91/include/mach/at91_twi.h
- *
- * Copyright (C) 2005 Ivan Kokshaysky
- * Copyright (C) SAN People
- *
- * Two-wire Interface (TWI) registers.
- * Based on AT91RM9200 datasheet revision E.
- *
- * 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 AT91_TWI_H
-#define AT91_TWI_H
-
-#define AT91_TWI_CR 0x00 /* Control Register */
-#define AT91_TWI_START (1 << 0) /* Send a Start Condition */
-#define AT91_TWI_STOP (1 << 1) /* Send a Stop Condition */
-#define AT91_TWI_MSEN (1 << 2) /* Master Transfer Enable */
-#define AT91_TWI_MSDIS (1 << 3) /* Master Transfer Disable */
-#define AT91_TWI_SVEN (1 << 4) /* Slave Transfer Enable [SAM9260 only] */
-#define AT91_TWI_SVDIS (1 << 5) /* Slave Transfer Disable [SAM9260 only] */
-#define AT91_TWI_SWRST (1 << 7) /* Software Reset */
-
-#define AT91_TWI_MMR 0x04 /* Master Mode Register */
-#define AT91_TWI_IADRSZ (3 << 8) /* Internal Device Address Size */
-#define AT91_TWI_IADRSZ_NO (0 << 8)
-#define AT91_TWI_IADRSZ_1 (1 << 8)
-#define AT91_TWI_IADRSZ_2 (2 << 8)
-#define AT91_TWI_IADRSZ_3 (3 << 8)
-#define AT91_TWI_MREAD (1 << 12) /* Master Read Direction */
-#define AT91_TWI_DADR (0x7f << 16) /* Device Address */
-
-#define AT91_TWI_SMR 0x08 /* Slave Mode Register [SAM9260 only] */
-#define AT91_TWI_SADR (0x7f << 16) /* Slave Address */
-
-#define AT91_TWI_IADR 0x0c /* Internal Address Register */
-
-#define AT91_TWI_CWGR 0x10 /* Clock Waveform Generator Register */
-#define AT91_TWI_CLDIV (0xff << 0) /* Clock Low Divisor */
-#define AT91_TWI_CHDIV (0xff << 8) /* Clock High Divisor */
-#define AT91_TWI_CKDIV (7 << 16) /* Clock Divider */
-
-#define AT91_TWI_SR 0x20 /* Status Register */
-#define AT91_TWI_TXCOMP (1 << 0) /* Transmission Complete */
-#define AT91_TWI_RXRDY (1 << 1) /* Receive Holding Register Ready */
-#define AT91_TWI_TXRDY (1 << 2) /* Transmit Holding Register Ready */
-#define AT91_TWI_SVREAD (1 << 3) /* Slave Read [SAM9260 only] */
-#define AT91_TWI_SVACC (1 << 4) /* Slave Access [SAM9260 only] */
-#define AT91_TWI_GACC (1 << 5) /* General Call Access [SAM9260 only] */
-#define AT91_TWI_OVRE (1 << 6) /* Overrun Error [AT91RM9200 only] */
-#define AT91_TWI_UNRE (1 << 7) /* Underrun Error [AT91RM9200 only] */
-#define AT91_TWI_NACK (1 << 8) /* Not Acknowledged */
-#define AT91_TWI_ARBLST (1 << 9) /* Arbitration Lost [SAM9260 only] */
-#define AT91_TWI_SCLWS (1 << 10) /* Clock Wait State [SAM9260 only] */
-#define AT91_TWI_EOSACC (1 << 11) /* End of Slave Address [SAM9260 only] */
-
-#define AT91_TWI_IER 0x24 /* Interrupt Enable Register */
-#define AT91_TWI_IDR 0x28 /* Interrupt Disable Register */
-#define AT91_TWI_IMR 0x2c /* Interrupt Mask Register */
-#define AT91_TWI_RHR 0x30 /* Receive Holding Register */
-#define AT91_TWI_THR 0x34 /* Transmit Holding Register */
-
-#endif
-
diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c
index 2c2d865..5315f05 100644
--- a/arch/arm/mach-at91/pm.c
+++ b/arch/arm/mach-at91/pm.c
@@ -153,7 +153,9 @@ static int at91_pm_verify_clocks(void)
}
}
-#ifdef CONFIG_AT91_PROGRAMMABLE_CLOCKS
+ if (!IS_ENABLED(CONFIG_AT91_PROGRAMMABLE_CLOCKS))
+ return 1;
+
/* PCK0..PCK3 must be disabled, or configured to use clk32k */
for (i = 0; i < 4; i++) {
u32 css;
@@ -167,7 +169,6 @@ static int at91_pm_verify_clocks(void)
return 0;
}
}
-#endif
return 1;
}
diff --git a/arch/arm/mach-at91/setup.c b/arch/arm/mach-at91/setup.c
index e6f52de..da9881b 100644
--- a/arch/arm/mach-at91/setup.c
+++ b/arch/arm/mach-at91/setup.c
@@ -87,7 +87,7 @@ void __init at91_init_sram(int bank, unsigned long base, unsigned int length)
iotable_init(desc, 1);
}
-static struct map_desc at91_io_desc __initdata = {
+static struct map_desc at91_io_desc __initdata __maybe_unused = {
.virtual = (unsigned long)AT91_VA_BASE_SYS,
.pfn = __phys_to_pfn(AT91_BASE_SYS),
.length = SZ_16K,
diff --git a/arch/arm/mach-clps711x/autcpu12.c b/arch/arm/mach-clps711x/autcpu12.c
index 3fb79a1..3287191 100644
--- a/arch/arm/mach-clps711x/autcpu12.c
+++ b/arch/arm/mach-clps711x/autcpu12.c
@@ -23,6 +23,8 @@
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/platform_device.h>
#include <mach/hardware.h>
#include <asm/sizes.h>
@@ -62,9 +64,26 @@ void __init autcpu12_map_io(void)
iotable_init(autcpu12_io_desc, ARRAY_SIZE(autcpu12_io_desc));
}
+static struct resource autcpu12_nvram_resource[] __initdata = {
+ DEFINE_RES_MEM_NAMED(AUTCPU12_PHYS_NVRAM, SZ_128K, "SRAM"),
+};
+
+static struct platform_device autcpu12_nvram_pdev __initdata = {
+ .name = "autcpu12_nvram",
+ .id = -1,
+ .resource = autcpu12_nvram_resource,
+ .num_resources = ARRAY_SIZE(autcpu12_nvram_resource),
+};
+
+static void __init autcpu12_init(void)
+{
+ platform_device_register(&autcpu12_nvram_pdev);
+}
+
MACHINE_START(AUTCPU12, "autronix autcpu12")
/* Maintainer: Thomas Gleixner */
.atag_offset = 0x20000,
+ .init_machine = autcpu12_init,
.map_io = autcpu12_map_io,
.init_irq = clps711x_init_irq,
.timer = &clps711x_timer,
diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c
index 6676dee..e517e10 100644
--- a/arch/arm/mach-davinci/da850.c
+++ b/arch/arm/mach-davinci/da850.c
@@ -939,7 +939,7 @@ static struct platform_device da850_cpufreq_device = {
unsigned int da850_max_speed = 300000;
-int __init da850_register_cpufreq(char *async_clk)
+int da850_register_cpufreq(char *async_clk)
{
int i;
diff --git a/arch/arm/mach-exynos/dma.c b/arch/arm/mach-exynos/dma.c
index f60b66d..21d568b 100644
--- a/arch/arm/mach-exynos/dma.c
+++ b/arch/arm/mach-exynos/dma.c
@@ -303,10 +303,12 @@ static int __init exynos_dma_init(void)
dma_cap_set(DMA_SLAVE, exynos_pdma0_pdata.cap_mask);
dma_cap_set(DMA_CYCLIC, exynos_pdma0_pdata.cap_mask);
+ dma_cap_set(DMA_PRIVATE, exynos_pdma0_pdata.cap_mask);
amba_device_register(&exynos_pdma0_device, &iomem_resource);
dma_cap_set(DMA_SLAVE, exynos_pdma1_pdata.cap_mask);
dma_cap_set(DMA_CYCLIC, exynos_pdma1_pdata.cap_mask);
+ dma_cap_set(DMA_PRIVATE, exynos_pdma1_pdata.cap_mask);
amba_device_register(&exynos_pdma1_device, &iomem_resource);
dma_cap_set(DMA_MEMCPY, exynos_mdma1_pdata.cap_mask);
diff --git a/arch/arm/mach-exynos/mach-nuri.c b/arch/arm/mach-exynos/mach-nuri.c
index 480cd78..85fc2fe 100644
--- a/arch/arm/mach-exynos/mach-nuri.c
+++ b/arch/arm/mach-exynos/mach-nuri.c
@@ -29,6 +29,7 @@
#include <drm/exynos_drm.h>
#include <video/platform_lcd.h>
+#include <video/samsung_fimd.h>
#include <media/m5mols.h>
#include <media/s5k6aa.h>
#include <media/s5p_fimc.h>
@@ -39,7 +40,6 @@
#include <asm/mach-types.h>
#include <plat/adc.h>
-#include <plat/regs-fb-v4.h>
#include <plat/regs-serial.h>
#include <plat/cpu.h>
#include <plat/devs.h>
diff --git a/arch/arm/mach-exynos/mach-origen.c b/arch/arm/mach-exynos/mach-origen.c
index 67b50bb..c11a62e 100644
--- a/arch/arm/mach-exynos/mach-origen.c
+++ b/arch/arm/mach-exynos/mach-origen.c
@@ -30,9 +30,9 @@
#include <asm/mach-types.h>
#include <video/platform_lcd.h>
+#include <video/samsung_fimd.h>
#include <plat/regs-serial.h>
-#include <plat/regs-fb-v4.h>
#include <plat/cpu.h>
#include <plat/devs.h>
#include <plat/sdhci.h>
diff --git a/arch/arm/mach-exynos/mach-smdk4x12.c b/arch/arm/mach-exynos/mach-smdk4x12.c
index 7a265d1..730f1ac 100644
--- a/arch/arm/mach-exynos/mach-smdk4x12.c
+++ b/arch/arm/mach-exynos/mach-smdk4x12.c
@@ -27,6 +27,7 @@
#include <asm/hardware/gic.h>
#include <asm/mach-types.h>
+#include <video/samsung_fimd.h>
#include <plat/backlight.h>
#include <plat/clock.h>
#include <plat/cpu.h>
@@ -36,7 +37,6 @@
#include <linux/platform_data/i2c-s3c2410.h>
#include <plat/keypad.h>
#include <plat/mfc.h>
-#include <plat/regs-fb.h>
#include <plat/regs-serial.h>
#include <plat/sdhci.h>
diff --git a/arch/arm/mach-exynos/mach-smdkv310.c b/arch/arm/mach-exynos/mach-smdkv310.c
index c15d223..ee4fb1a 100644
--- a/arch/arm/mach-exynos/mach-smdkv310.c
+++ b/arch/arm/mach-exynos/mach-smdkv310.c
@@ -27,9 +27,9 @@
#include <asm/mach-types.h>
#include <video/platform_lcd.h>
+#include <video/samsung_fimd.h>
#include <plat/regs-serial.h>
#include <plat/regs-srom.h>
-#include <plat/regs-fb-v4.h>
#include <plat/cpu.h>
#include <plat/devs.h>
#include <plat/fb.h>
diff --git a/arch/arm/mach-exynos/mach-universal_c210.c b/arch/arm/mach-exynos/mach-universal_c210.c
index 98d3ace..08b81fd 100644
--- a/arch/arm/mach-exynos/mach-universal_c210.c
+++ b/arch/arm/mach-exynos/mach-universal_c210.c
@@ -30,6 +30,7 @@
#include <asm/hardware/gic.h>
#include <asm/mach-types.h>
+#include <video/samsung_fimd.h>
#include <plat/regs-serial.h>
#include <plat/clock.h>
#include <plat/cpu.h>
@@ -39,7 +40,6 @@
#include <plat/fb.h>
#include <plat/mfc.h>
#include <plat/sdhci.h>
-#include <plat/regs-fb-v4.h>
#include <plat/fimc-core.h>
#include <plat/s5p-time.h>
#include <plat/camport.h>
diff --git a/arch/arm/mach-exynos/setup-fimd0.c b/arch/arm/mach-exynos/setup-fimd0.c
index 07a6dbe..5665bb4 100644
--- a/arch/arm/mach-exynos/setup-fimd0.c
+++ b/arch/arm/mach-exynos/setup-fimd0.c
@@ -13,8 +13,8 @@
#include <linux/fb.h>
#include <linux/gpio.h>
+#include <video/samsung_fimd.h>
#include <plat/gpio-cfg.h>
-#include <plat/regs-fb-v4.h>
#include <mach/map.h>
diff --git a/arch/arm/mach-footbridge/include/mach/irqs.h b/arch/arm/mach-footbridge/include/mach/irqs.h
index 400551e..61c714c 100644
--- a/arch/arm/mach-footbridge/include/mach/irqs.h
+++ b/arch/arm/mach-footbridge/include/mach/irqs.h
@@ -89,8 +89,6 @@
#define IRQ_NETWINDER_VGA _ISA_IRQ(11)
#define IRQ_NETWINDER_SOUND _ISA_IRQ(12)
-#undef RTC_IRQ
-#define RTC_IRQ IRQ_ISA_RTC_ALARM
#define I8042_KBD_IRQ IRQ_ISA_KEYBOARD
#define I8042_AUX_IRQ (machine_is_netwinder() ? IRQ_NETWINDER_PS2MOUSE : IRQ_ISA_PS2MOUSE)
#define IRQ_FLOPPYDISK IRQ_ISA_FLOPPY
diff --git a/arch/arm/mach-imx/clk-imx51-imx53.c b/arch/arm/mach-imx/clk-imx51-imx53.c
index e5165a8..a0bf848 100644
--- a/arch/arm/mach-imx/clk-imx51-imx53.c
+++ b/arch/arm/mach-imx/clk-imx51-imx53.c
@@ -369,6 +369,7 @@ int __init mx51_clocks_init(unsigned long rate_ckil, unsigned long rate_osc,
clk_register_clkdev(clk[ssi1_ipg_gate], NULL, "83fcc000.ssi");
clk_register_clkdev(clk[ssi2_ipg_gate], NULL, "70014000.ssi");
clk_register_clkdev(clk[ssi3_ipg_gate], NULL, "83fe8000.ssi");
+ clk_register_clkdev(clk[nfc_gate], NULL, "83fdb000.nand");
/* set the usboh3 parent to pll2_sw */
clk_set_parent(clk[usboh3_sel], clk[pll2_sw]);
@@ -461,6 +462,7 @@ int __init mx53_clocks_init(unsigned long rate_ckil, unsigned long rate_osc,
clk_register_clkdev(clk[ssi1_ipg_gate], NULL, "63fcc000.ssi");
clk_register_clkdev(clk[ssi2_ipg_gate], NULL, "50014000.ssi");
clk_register_clkdev(clk[ssi3_ipg_gate], NULL, "63fd0000.ssi");
+ clk_register_clkdev(clk[nfc_gate], NULL, "63fdb000.nand");
clk_register_clkdev(clk[can1_ipg_gate], "ipg", "53fc8000.can");
clk_register_clkdev(clk[can1_serial_gate], "per", "53fc8000.can");
clk_register_clkdev(clk[can2_ipg_gate], "ipg", "53fcc000.can");
diff --git a/arch/arm/mach-integrator/include/mach/cm.h b/arch/arm/mach-integrator/include/mach/cm.h
index 1a78692e..202e6a5 100644
--- a/arch/arm/mach-integrator/include/mach/cm.h
+++ b/arch/arm/mach-integrator/include/mach/cm.h
@@ -3,7 +3,7 @@
*/
void cm_control(u32, u32);
-#define CM_CTRL IO_ADDRESS(INTEGRATOR_HDR_CTRL)
+#define CM_CTRL __io_address(INTEGRATOR_HDR_CTRL)
#define CM_CTRL_LED (1 << 0)
#define CM_CTRL_nMBDET (1 << 1)
diff --git a/arch/arm/mach-integrator/include/mach/platform.h b/arch/arm/mach-integrator/include/mach/platform.h
index 4c03475..efeac5d 100644
--- a/arch/arm/mach-integrator/include/mach/platform.h
+++ b/arch/arm/mach-integrator/include/mach/platform.h
@@ -324,9 +324,9 @@
*/
#define PHYS_PCI_V3_BASE 0x62000000
-#define PCI_MEMORY_VADDR 0xe8000000
-#define PCI_CONFIG_VADDR 0xec000000
-#define PCI_V3_VADDR 0xed000000
+#define PCI_MEMORY_VADDR IOMEM(0xe8000000)
+#define PCI_CONFIG_VADDR IOMEM(0xec000000)
+#define PCI_V3_VADDR IOMEM(0xed000000)
/* ------------------------------------------------------------------------
* Integrator Interrupt Controllers
diff --git a/arch/arm/mach-integrator/integrator_ap.c b/arch/arm/mach-integrator/integrator_ap.c
index d5b5435a..e6617c1 100644
--- a/arch/arm/mach-integrator/integrator_ap.c
+++ b/arch/arm/mach-integrator/integrator_ap.c
@@ -157,7 +157,7 @@ static struct map_desc ap_io_desc[] __initdata = {
static void __init ap_map_io(void)
{
iotable_init(ap_io_desc, ARRAY_SIZE(ap_io_desc));
- vga_base = PCI_MEMORY_VADDR;
+ vga_base = (unsigned long)PCI_MEMORY_VADDR;
pci_map_io_early(__phys_to_pfn(PHYS_PCI_IO_BASE));
}
diff --git a/arch/arm/mach-integrator/integrator_cp.c b/arch/arm/mach-integrator/integrator_cp.c
index 6870a1f..5b08e8e 100644
--- a/arch/arm/mach-integrator/integrator_cp.c
+++ b/arch/arm/mach-integrator/integrator_cp.c
@@ -261,6 +261,8 @@ static void __init intcp_init_early(void)
#endif
}
+#ifdef CONFIG_OF
+
static void __init intcp_timer_init_of(void)
{
struct device_node *node;
@@ -297,8 +299,6 @@ static struct sys_timer cp_of_timer = {
.init = intcp_timer_init_of,
};
-#ifdef CONFIG_OF
-
static const struct of_device_id fpga_irq_of_match[] __initconst = {
{ .compatible = "arm,versatile-fpga-irq", .data = fpga_irq_of_init, },
{ /* Sentinel */ }
diff --git a/arch/arm/mach-iop13xx/iq81340sc.c b/arch/arm/mach-iop13xx/iq81340sc.c
index 060cddd..e947441 100644
--- a/arch/arm/mach-iop13xx/iq81340sc.c
+++ b/arch/arm/mach-iop13xx/iq81340sc.c
@@ -30,7 +30,7 @@
extern int init_atu;
static int __init
-iq81340sc_atux_map_irq(struct pci_dev *dev, u8 idsel, u8 pin)
+iq81340sc_atux_map_irq(const struct pci_dev *dev, u8 idsel, u8 pin)
{
WARN_ON(idsel < 1 || idsel > 2);
diff --git a/arch/arm/mach-iop13xx/pci.c b/arch/arm/mach-iop13xx/pci.c
index 9082b84..2f28018 100644
--- a/arch/arm/mach-iop13xx/pci.c
+++ b/arch/arm/mach-iop13xx/pci.c
@@ -504,7 +504,7 @@ iop13xx_pci_abort(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
/* Scan an IOP13XX PCI bus. nr selects which ATU we use.
*/
-struct pci_bus *iop13xx_scan_bus(int nr, struct pci_sys_data *sys)
+struct pci_bus * __devinit iop13xx_scan_bus(int nr, struct pci_sys_data *sys)
{
int which_atu;
struct pci_bus *bus = NULL;
diff --git a/arch/arm/mach-ks8695/include/mach/memory.h b/arch/arm/mach-ks8695/include/mach/memory.h
index f7e1b9b..95e731a 100644
--- a/arch/arm/mach-ks8695/include/mach/memory.h
+++ b/arch/arm/mach-ks8695/include/mach/memory.h
@@ -34,7 +34,8 @@ extern struct bus_type platform_bus_type;
#define __arch_dma_to_virt(dev, x) ({ (void *) (is_lbus_device(dev) ? \
__phys_to_virt(x) : __bus_to_virt(x)); })
#define __arch_virt_to_dma(dev, x) ({ is_lbus_device(dev) ? \
- (dma_addr_t)__virt_to_phys(x) : (dma_addr_t)__virt_to_bus(x); })
+ (dma_addr_t)__virt_to_phys((unsigned long)x) \
+ : (dma_addr_t)__virt_to_bus(x); })
#define __arch_pfn_to_dma(dev, pfn) \
({ dma_addr_t __dma = __pfn_to_phys(pfn); \
if (!is_lbus_device(dev)) \
diff --git a/arch/arm/mach-mv78xx0/addr-map.c b/arch/arm/mach-mv78xx0/addr-map.c
index 343c435..26e9876 100644
--- a/arch/arm/mach-mv78xx0/addr-map.c
+++ b/arch/arm/mach-mv78xx0/addr-map.c
@@ -54,7 +54,7 @@ static void __init __iomem *win_cfg_base(const struct orion_addr_map_cfg *cfg, i
/*
* Description of the windows needed by the platform code
*/
-static struct __initdata orion_addr_map_cfg addr_map_cfg = {
+static struct orion_addr_map_cfg addr_map_cfg __initdata = {
.num_wins = 14,
.remappable_wins = 8,
.win_cfg_base = win_cfg_base,
diff --git a/arch/arm/mach-mv78xx0/common.c b/arch/arm/mach-mv78xx0/common.c
index 131cd48..d0cb485 100644
--- a/arch/arm/mach-mv78xx0/common.c
+++ b/arch/arm/mach-mv78xx0/common.c
@@ -336,7 +336,7 @@ void __init mv78xx0_init_early(void)
orion_time_set_base(TIMER_VIRT_BASE);
}
-static void mv78xx0_timer_init(void)
+static void __init_refok mv78xx0_timer_init(void)
{
orion_time_init(BRIDGE_VIRT_BASE, BRIDGE_INT_TIMER1_CLR,
IRQ_MV78XX0_TIMER_1, get_tclk());
diff --git a/arch/arm/mach-omap1/devices.c b/arch/arm/mach-omap1/devices.c
index 726c02c..d3fec92 100644
--- a/arch/arm/mach-omap1/devices.c
+++ b/arch/arm/mach-omap1/devices.c
@@ -231,7 +231,7 @@ void __init omap1_init_mmc(struct omap_mmc_platform_data **mmc_data,
omap_mmc_add("mmci-omap", i, base, size, irq,
rx_req, tx_req, mmc_data[i]);
- };
+ }
}
#endif
diff --git a/arch/arm/mach-omap2/board-4430sdp.c b/arch/arm/mach-omap2/board-4430sdp.c
index a88809a..3669c12 100644
--- a/arch/arm/mach-omap2/board-4430sdp.c
+++ b/arch/arm/mach-omap2/board-4430sdp.c
@@ -607,29 +607,6 @@ static void __init omap_sfh7741prox_init(void)
__func__, OMAP4_SFH7741_ENABLE_GPIO, error);
}
-static struct gpio sdp4430_hdmi_gpios[] = {
- { HDMI_GPIO_CT_CP_HPD, GPIOF_OUT_INIT_HIGH, "hdmi_gpio_ct_cp_hpd" },
- { HDMI_GPIO_LS_OE, GPIOF_OUT_INIT_HIGH, "hdmi_gpio_ls_oe" },
- { HDMI_GPIO_HPD, GPIOF_DIR_IN, "hdmi_gpio_hpd" },
-};
-
-static int sdp4430_panel_enable_hdmi(struct omap_dss_device *dssdev)
-{
- int status;
-
- 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;
-}
-
-static void sdp4430_panel_disable_hdmi(struct omap_dss_device *dssdev)
-{
- gpio_free_array(sdp4430_hdmi_gpios, ARRAY_SIZE(sdp4430_hdmi_gpios));
-}
-
static struct nokia_dsi_panel_data dsi1_panel = {
.name = "taal",
.reset_gpio = 102,
@@ -650,29 +627,6 @@ static struct omap_dss_device sdp4430_lcd_device = {
.phy.dsi = {
.module = 0,
},
-
- .clocks = {
- .dispc = {
- .channel = {
- /* Logic Clock = 172.8 MHz */
- .lck_div = 1,
- /* Pixel Clock = 34.56 MHz */
- .pck_div = 5,
- .lcd_clk_src = OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC,
- },
- .dispc_fclk_src = OMAP_DSS_CLK_SRC_FCK,
- },
-
- .dsi = {
- .regn = 16, /* Fint = 2.4 MHz */
- .regm = 180, /* DDR Clock = 216 MHz */
- .regm_dispc = 5, /* PLL1_CLK1 = 172.8 MHz */
- .regm_dsi = 5, /* PLL1_CLK2 = 172.8 MHz */
-
- .lp_clk_div = 10, /* LP Clock = 8.64 MHz */
- .dsi_fclk_src = OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI,
- },
- },
.channel = OMAP_DSS_CHANNEL_LCD,
};
@@ -697,33 +651,12 @@ static struct omap_dss_device sdp4430_lcd2_device = {
.module = 1,
},
-
- .clocks = {
- .dispc = {
- .channel = {
- /* Logic Clock = 172.8 MHz */
- .lck_div = 1,
- /* Pixel Clock = 34.56 MHz */
- .pck_div = 5,
- .lcd_clk_src = OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC,
- },
- .dispc_fclk_src = OMAP_DSS_CLK_SRC_FCK,
- },
-
- .dsi = {
- .regn = 16, /* Fint = 2.4 MHz */
- .regm = 180, /* DDR Clock = 216 MHz */
- .regm_dispc = 5, /* PLL1_CLK1 = 172.8 MHz */
- .regm_dsi = 5, /* PLL1_CLK2 = 172.8 MHz */
-
- .lp_clk_div = 10, /* LP Clock = 8.64 MHz */
- .dsi_fclk_src = OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI,
- },
- },
.channel = OMAP_DSS_CHANNEL_LCD2,
};
static struct omap_dss_hdmi_data sdp4430_hdmi_data = {
+ .ct_cp_hpd_gpio = HDMI_GPIO_CT_CP_HPD,
+ .ls_oe_gpio = HDMI_GPIO_LS_OE,
.hpd_gpio = HDMI_GPIO_HPD,
};
@@ -731,8 +664,6 @@ static struct omap_dss_device sdp4430_hdmi_device = {
.name = "hdmi",
.driver_name = "hdmi_panel",
.type = OMAP_DISPLAY_TYPE_HDMI,
- .platform_enable = sdp4430_panel_enable_hdmi,
- .platform_disable = sdp4430_panel_disable_hdmi,
.channel = OMAP_DSS_CHANNEL_DIGIT,
.data = &sdp4430_hdmi_data,
};
@@ -830,6 +761,32 @@ static struct omap_board_mux board_mux[] __initdata = {
/* NIRQ2 for twl6040 */
OMAP4_MUX(SYS_NIRQ2, OMAP_MUX_MODE0 |
OMAP_PIN_INPUT_PULLUP | OMAP_PIN_OFF_WAKEUPENABLE),
+ /* GPIO_127 for twl6040 */
+ OMAP4_MUX(HDQ_SIO, OMAP_MUX_MODE3 | OMAP_PIN_OUTPUT),
+ /* McPDM */
+ OMAP4_MUX(ABE_PDM_UL_DATA, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLDOWN),
+ OMAP4_MUX(ABE_PDM_DL_DATA, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLDOWN),
+ OMAP4_MUX(ABE_PDM_FRAME, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP),
+ OMAP4_MUX(ABE_PDM_LB_CLK, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLDOWN),
+ OMAP4_MUX(ABE_CLKS, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLDOWN),
+ /* DMIC */
+ OMAP4_MUX(ABE_DMIC_CLK1, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
+ OMAP4_MUX(ABE_DMIC_DIN1, OMAP_MUX_MODE0 | OMAP_PIN_INPUT),
+ OMAP4_MUX(ABE_DMIC_DIN2, OMAP_MUX_MODE0 | OMAP_PIN_INPUT),
+ OMAP4_MUX(ABE_DMIC_DIN3, OMAP_MUX_MODE0 | OMAP_PIN_INPUT),
+ /* McBSP1 */
+ OMAP4_MUX(ABE_MCBSP1_CLKX, OMAP_MUX_MODE0 | OMAP_PIN_INPUT),
+ OMAP4_MUX(ABE_MCBSP1_DR, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLDOWN),
+ OMAP4_MUX(ABE_MCBSP1_DX, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT |
+ OMAP_PULL_ENA),
+ OMAP4_MUX(ABE_MCBSP1_FSX, OMAP_MUX_MODE0 | OMAP_PIN_INPUT),
+ /* McBSP2 */
+ OMAP4_MUX(ABE_MCBSP2_CLKX, OMAP_MUX_MODE0 | OMAP_PIN_INPUT),
+ OMAP4_MUX(ABE_MCBSP2_DR, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLDOWN),
+ OMAP4_MUX(ABE_MCBSP2_DX, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT |
+ OMAP_PULL_ENA),
+ OMAP4_MUX(ABE_MCBSP2_FSX, OMAP_MUX_MODE0 | OMAP_PIN_INPUT),
+
{ .reg_offset = OMAP_MUX_TERMINATOR },
};
diff --git a/arch/arm/mach-omap2/board-flash.c b/arch/arm/mach-omap2/board-flash.c
index 0cabe61..e642acf 100644
--- a/arch/arm/mach-omap2/board-flash.c
+++ b/arch/arm/mach-omap2/board-flash.c
@@ -218,7 +218,7 @@ void __init board_flash_init(struct flash_partitions partition_info[],
if (onenandcs > GPMC_CS_NUM)
onenandcs = cs;
break;
- };
+ }
cs++;
}
diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c
index a08bebc..388c431 100644
--- a/arch/arm/mach-omap2/board-omap3beagle.c
+++ b/arch/arm/mach-omap2/board-omap3beagle.c
@@ -461,7 +461,7 @@ static void __init beagle_opp_init(void)
mpu_dev = omap_device_get_by_hwmod_name("mpu");
iva_dev = omap_device_get_by_hwmod_name("iva");
- if (!mpu_dev || !iva_dev) {
+ if (IS_ERR(mpu_dev) || IS_ERR(iva_dev)) {
pr_err("%s: Aiee.. no mpu/dsp devices? %p %p\n",
__func__, mpu_dev, iva_dev);
return;
diff --git a/arch/arm/mach-omap2/board-omap3evm.c b/arch/arm/mach-omap2/board-omap3evm.c
index a3959de..b9b776b 100644
--- a/arch/arm/mach-omap2/board-omap3evm.c
+++ b/arch/arm/mach-omap2/board-omap3evm.c
@@ -88,11 +88,10 @@ enum {
static u8 omap3_evm_version;
-u8 get_omap3_evm_rev(void)
+static u8 get_omap3_evm_rev(void)
{
return omap3_evm_version;
}
-EXPORT_SYMBOL(get_omap3_evm_rev);
static void __init omap3_evm_get_revision(void)
{
diff --git a/arch/arm/mach-omap2/board-omap3stalker.c b/arch/arm/mach-omap2/board-omap3stalker.c
index c7f3d02..731235e 100644
--- a/arch/arm/mach-omap2/board-omap3stalker.c
+++ b/arch/arm/mach-omap2/board-omap3stalker.c
@@ -48,11 +48,6 @@
#include <video/omap-panel-tfp410.h>
#include <linux/platform_data/spi-omap2-mcspi.h>
-#include <linux/input/matrix_keypad.h>
-#include <linux/spi/spi.h>
-#include <linux/interrupt.h>
-#include <linux/smsc911x.h>
-#include <linux/i2c/at24.h>
#include "sdram-micron-mt46h32m32lf-6.h"
#include "mux.h"
diff --git a/arch/arm/mach-omap2/board-omap4panda.c b/arch/arm/mach-omap2/board-omap4panda.c
index 2b012f9..bfcd397 100644
--- a/arch/arm/mach-omap2/board-omap4panda.c
+++ b/arch/arm/mach-omap2/board-omap4panda.c
@@ -247,8 +247,7 @@ static struct platform_device omap_vwlan_device = {
};
static struct wl12xx_platform_data omap_panda_wlan_data __initdata = {
- /* PANDA ref clock is 38.4 MHz */
- .board_ref_clock = 2,
+ .board_ref_clock = WL12XX_REFCLOCK_38, /* 38.4 MHz */
};
static struct twl6040_codec_data twl6040_codec = {
@@ -388,6 +387,21 @@ static struct omap_board_mux board_mux[] __initdata = {
/* NIRQ2 for twl6040 */
OMAP4_MUX(SYS_NIRQ2, OMAP_MUX_MODE0 |
OMAP_PIN_INPUT_PULLUP | OMAP_PIN_OFF_WAKEUPENABLE),
+ /* GPIO_127 for twl6040 */
+ OMAP4_MUX(HDQ_SIO, OMAP_MUX_MODE3 | OMAP_PIN_OUTPUT),
+ /* McPDM */
+ OMAP4_MUX(ABE_PDM_UL_DATA, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLDOWN),
+ OMAP4_MUX(ABE_PDM_DL_DATA, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLDOWN),
+ OMAP4_MUX(ABE_PDM_FRAME, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP),
+ OMAP4_MUX(ABE_PDM_LB_CLK, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLDOWN),
+ OMAP4_MUX(ABE_CLKS, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLDOWN),
+ /* McBSP1 */
+ OMAP4_MUX(ABE_MCBSP1_CLKX, OMAP_MUX_MODE0 | OMAP_PIN_INPUT),
+ OMAP4_MUX(ABE_MCBSP1_DR, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLDOWN),
+ OMAP4_MUX(ABE_MCBSP1_DX, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT |
+ OMAP_PULL_ENA),
+ OMAP4_MUX(ABE_MCBSP1_FSX, OMAP_MUX_MODE0 | OMAP_PIN_INPUT),
+
{ .reg_offset = OMAP_MUX_TERMINATOR },
};
@@ -414,30 +428,9 @@ static struct omap_dss_device omap4_panda_dvi_device = {
.channel = OMAP_DSS_CHANNEL_LCD2,
};
-static struct gpio panda_hdmi_gpios[] = {
- { HDMI_GPIO_CT_CP_HPD, GPIOF_OUT_INIT_HIGH, "hdmi_gpio_ct_cp_hpd" },
- { HDMI_GPIO_LS_OE, GPIOF_OUT_INIT_HIGH, "hdmi_gpio_ls_oe" },
- { HDMI_GPIO_HPD, GPIOF_DIR_IN, "hdmi_gpio_hpd" },
-};
-
-static int omap4_panda_panel_enable_hdmi(struct omap_dss_device *dssdev)
-{
- int status;
-
- status = gpio_request_array(panda_hdmi_gpios,
- ARRAY_SIZE(panda_hdmi_gpios));
- if (status)
- pr_err("Cannot request HDMI GPIOs\n");
-
- return status;
-}
-
-static void omap4_panda_panel_disable_hdmi(struct omap_dss_device *dssdev)
-{
- gpio_free_array(panda_hdmi_gpios, ARRAY_SIZE(panda_hdmi_gpios));
-}
-
static struct omap_dss_hdmi_data omap4_panda_hdmi_data = {
+ .ct_cp_hpd_gpio = HDMI_GPIO_CT_CP_HPD,
+ .ls_oe_gpio = HDMI_GPIO_LS_OE,
.hpd_gpio = HDMI_GPIO_HPD,
};
@@ -445,8 +438,6 @@ static struct omap_dss_device omap4_panda_hdmi_device = {
.name = "hdmi",
.driver_name = "hdmi_panel",
.type = OMAP_DISPLAY_TYPE_HDMI,
- .platform_enable = omap4_panda_panel_enable_hdmi,
- .platform_disable = omap4_panda_panel_disable_hdmi,
.channel = OMAP_DSS_CHANNEL_DIGIT,
.data = &omap4_panda_hdmi_data,
};
diff --git a/arch/arm/mach-omap2/board-rx51-peripherals.c b/arch/arm/mach-omap2/board-rx51-peripherals.c
index ed85fb8..020e03c 100644
--- a/arch/arm/mach-omap2/board-rx51-peripherals.c
+++ b/arch/arm/mach-omap2/board-rx51-peripherals.c
@@ -748,7 +748,7 @@ static struct radio_si4713_platform_data rx51_si4713_data __initdata_or_module =
.subdev_board_info = &rx51_si4713_board_info,
};
-static struct platform_device rx51_si4713_dev = {
+static struct platform_device rx51_si4713_dev __initdata_or_module = {
.name = "radio-si4713",
.id = -1,
.dev = {
diff --git a/arch/arm/mach-omap2/board-zoom-peripherals.c b/arch/arm/mach-omap2/board-zoom-peripherals.c
index 67f8540..c166fe1 100644
--- a/arch/arm/mach-omap2/board-zoom-peripherals.c
+++ b/arch/arm/mach-omap2/board-zoom-peripherals.c
@@ -195,8 +195,7 @@ static struct platform_device omap_vwlan_device = {
};
static struct wl12xx_platform_data omap_zoom_wlan_data __initdata = {
- /* ZOOM ref clock is 26 MHz */
- .board_ref_clock = 1,
+ .board_ref_clock = WL12XX_REFCLOCK_26, /* 26 MHz */
};
static struct omap2_hsmmc_info mmc[] = {
diff --git a/arch/arm/mach-omap2/clkt_clksel.c b/arch/arm/mach-omap2/clkt_clksel.c
index eaed390..3ff2211 100644
--- a/arch/arm/mach-omap2/clkt_clksel.c
+++ b/arch/arm/mach-omap2/clkt_clksel.c
@@ -382,7 +382,7 @@ void omap2_init_clksel_parent(struct clk *clk)
__clk_get_name(parent) :
"NULL"));
clk_reparent(clk, clks->parent);
- };
+ }
found = 1;
}
}
diff --git a/arch/arm/mach-omap2/clock33xx_data.c b/arch/arm/mach-omap2/clock33xx_data.c
index b87b88c..114ab4b 100644
--- a/arch/arm/mach-omap2/clock33xx_data.c
+++ b/arch/arm/mach-omap2/clock33xx_data.c
@@ -1035,6 +1035,8 @@ static struct omap_clk am33xx_clks[] = {
CLK(NULL, "pruss_ocp_gclk", &pruss_ocp_gclk, CK_AM33XX),
CLK("davinci-mcasp.0", NULL, &mcasp0_fck, CK_AM33XX),
CLK("davinci-mcasp.1", NULL, &mcasp1_fck, CK_AM33XX),
+ CLK(NULL, "mcasp0_fck", &mcasp0_fck, CK_AM33XX),
+ CLK(NULL, "mcasp1_fck", &mcasp1_fck, CK_AM33XX),
CLK("NULL", "mmc2_fck", &mmc2_fck, CK_AM33XX),
CLK(NULL, "mmu_fck", &mmu_fck, CK_AM33XX),
CLK(NULL, "smartreflex0_fck", &smartreflex0_fck, CK_AM33XX),
diff --git a/arch/arm/mach-omap2/clockdomain2xxx_3xxx.c b/arch/arm/mach-omap2/clockdomain2xxx_3xxx.c
index 9a7792a..70294f5 100644
--- a/arch/arm/mach-omap2/clockdomain2xxx_3xxx.c
+++ b/arch/arm/mach-omap2/clockdomain2xxx_3xxx.c
@@ -183,17 +183,6 @@ static int omap2_clkdm_clk_enable(struct clockdomain *clkdm)
if (!clkdm->clktrctrl_mask)
return 0;
- /*
- * The CLKDM_MISSING_IDLE_REPORTING flag documentation has
- * more details on the unpleasant problem this is working
- * around
- */
- if (clkdm->flags & CLKDM_MISSING_IDLE_REPORTING &&
- !(clkdm->flags & CLKDM_CAN_FORCE_SLEEP)) {
- _enable_hwsup(clkdm);
- return 0;
- }
-
hwsup = omap2_cm_is_clkdm_in_hwsup(clkdm->pwrdm.ptr->prcm_offs,
clkdm->clktrctrl_mask);
@@ -217,17 +206,6 @@ static int omap2_clkdm_clk_disable(struct clockdomain *clkdm)
if (!clkdm->clktrctrl_mask)
return 0;
- /*
- * The CLKDM_MISSING_IDLE_REPORTING flag documentation has
- * more details on the unpleasant problem this is working
- * around
- */
- if ((clkdm->flags & CLKDM_MISSING_IDLE_REPORTING) &&
- (clkdm->flags & CLKDM_CAN_FORCE_WAKEUP)) {
- omap3_clkdm_wakeup(clkdm);
- return 0;
- }
-
hwsup = omap2_cm_is_clkdm_in_hwsup(clkdm->pwrdm.ptr->prcm_offs,
clkdm->clktrctrl_mask);
@@ -269,6 +247,17 @@ static int omap3xxx_clkdm_clk_enable(struct clockdomain *clkdm)
if (!clkdm->clktrctrl_mask)
return 0;
+ /*
+ * The CLKDM_MISSING_IDLE_REPORTING flag documentation has
+ * more details on the unpleasant problem this is working
+ * around
+ */
+ if ((clkdm->flags & CLKDM_MISSING_IDLE_REPORTING) &&
+ (clkdm->flags & CLKDM_CAN_FORCE_WAKEUP)) {
+ omap3_clkdm_wakeup(clkdm);
+ return 0;
+ }
+
hwsup = omap2_cm_is_clkdm_in_hwsup(clkdm->pwrdm.ptr->prcm_offs,
clkdm->clktrctrl_mask);
@@ -292,6 +281,17 @@ static int omap3xxx_clkdm_clk_disable(struct clockdomain *clkdm)
if (!clkdm->clktrctrl_mask)
return 0;
+ /*
+ * The CLKDM_MISSING_IDLE_REPORTING flag documentation has
+ * more details on the unpleasant problem this is working
+ * around
+ */
+ if (clkdm->flags & CLKDM_MISSING_IDLE_REPORTING &&
+ !(clkdm->flags & CLKDM_CAN_FORCE_SLEEP)) {
+ _enable_hwsup(clkdm);
+ return 0;
+ }
+
hwsup = omap2_cm_is_clkdm_in_hwsup(clkdm->pwrdm.ptr->prcm_offs,
clkdm->clktrctrl_mask);
diff --git a/arch/arm/mach-omap2/display.c b/arch/arm/mach-omap2/display.c
index 7012068..1011995 100644
--- a/arch/arm/mach-omap2/display.c
+++ b/arch/arm/mach-omap2/display.c
@@ -95,7 +95,6 @@ static const struct omap_dss_hwmod_data omap4_dss_hwmod_data[] __initconst = {
{ "dss_core", "omapdss_dss", -1 },
{ "dss_dispc", "omapdss_dispc", -1 },
{ "dss_rfbi", "omapdss_rfbi", -1 },
- { "dss_venc", "omapdss_venc", -1 },
{ "dss_dsi1", "omapdss_dsi", 0 },
{ "dss_dsi2", "omapdss_dsi", 1 },
{ "dss_hdmi", "omapdss_hdmi", -1 },
@@ -221,7 +220,7 @@ static struct platform_device *create_dss_pdev(const char *pdev_name,
ohs[0] = oh;
od = omap_device_alloc(pdev, ohs, 1, NULL, 0);
- if (!od) {
+ if (IS_ERR(od)) {
pr_err("Could not alloc omap_device for %s\n", pdev_name);
r = -ENOMEM;
goto err;
diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index 8ab1e1b..5ac5cf3 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -838,7 +838,7 @@ static int gpmc_setup_irq(void)
return request_irq(gpmc_irq, gpmc_handle_irq, 0, "gpmc", NULL);
}
-static __exit int gpmc_free_irq(void)
+static __devexit int gpmc_free_irq(void)
{
int i;
@@ -944,7 +944,7 @@ static __devinit int gpmc_probe(struct platform_device *pdev)
return 0;
}
-static __exit int gpmc_remove(struct platform_device *pdev)
+static __devexit int gpmc_remove(struct platform_device *pdev)
{
gpmc_free_irq();
gpmc_mem_exit();
diff --git a/arch/arm/mach-omap2/hsmmc.c b/arch/arm/mach-omap2/hsmmc.c
index 03ebf47..4d3a632 100644
--- a/arch/arm/mach-omap2/hsmmc.c
+++ b/arch/arm/mach-omap2/hsmmc.c
@@ -523,7 +523,7 @@ static void __init omap_hsmmc_init_one(struct omap2_hsmmc_info *hsmmcinfo,
dev_set_name(&pdev->dev, "%s.%d", pdev->name, pdev->id);
od = omap_device_alloc(pdev, ohs, 1, NULL, 0);
- if (!od) {
+ if (IS_ERR(od)) {
pr_err("Could not allocate od for %s\n", name);
goto put_pdev;
}
diff --git a/arch/arm/mach-omap2/mux.c b/arch/arm/mach-omap2/mux.c
index 9fe6829..701e17c 100644
--- a/arch/arm/mach-omap2/mux.c
+++ b/arch/arm/mach-omap2/mux.c
@@ -486,7 +486,7 @@ void omap_hwmod_mux(struct omap_hwmod_mux_info *hmux, u8 state)
default:
/* Nothing to be done */
break;
- };
+ }
if (val >= 0) {
omap_mux_write(pad->partition, val,
diff --git a/arch/arm/mach-omap2/omap-secure.c b/arch/arm/mach-omap2/omap-secure.c
index a004cb9..e089e4d 100644
--- a/arch/arm/mach-omap2/omap-secure.c
+++ b/arch/arm/mach-omap2/omap-secure.c
@@ -61,8 +61,8 @@ int __init omap_secure_ram_reserve_memblock(void)
{
u32 size = OMAP_SECURE_RAM_STORAGE;
- size = ALIGN(size, SZ_1M);
- omap_secure_memblock_base = arm_memblock_steal(size, SZ_1M);
+ size = ALIGN(size, SECTION_SIZE);
+ omap_secure_memblock_base = arm_memblock_steal(size, SECTION_SIZE);
return 0;
}
diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c
index 299ca28..b969ab1 100644
--- a/arch/arm/mach-omap2/omap_hwmod.c
+++ b/arch/arm/mach-omap2/omap_hwmod.c
@@ -1698,6 +1698,29 @@ static bool _are_all_hardreset_lines_asserted(struct omap_hwmod *oh)
}
/**
+ * _are_any_hardreset_lines_asserted - return true if any part of @oh is
+ * hard-reset
+ * @oh: struct omap_hwmod *
+ *
+ * If any hardreset lines associated with @oh are asserted, then
+ * return true. Otherwise, if no hardreset lines associated with @oh
+ * are asserted, or if @oh has no hardreset lines, then return false.
+ * This function is used to avoid executing some parts of the IP block
+ * enable/disable sequence if any hardreset line is set.
+ */
+static bool _are_any_hardreset_lines_asserted(struct omap_hwmod *oh)
+{
+ int rst_cnt = 0;
+ int i;
+
+ for (i = 0; i < oh->rst_lines_cnt && rst_cnt == 0; i++)
+ if (_read_hardreset(oh, oh->rst_lines[i].name) > 0)
+ rst_cnt++;
+
+ return (rst_cnt) ? true : false;
+}
+
+/**
* _omap4_disable_module - enable CLKCTRL modulemode on OMAP4
* @oh: struct omap_hwmod *
*
@@ -1715,7 +1738,7 @@ static int _omap4_disable_module(struct omap_hwmod *oh)
* Since integration code might still be doing something, only
* disable if all lines are under hardreset.
*/
- if (!_are_all_hardreset_lines_asserted(oh))
+ if (_are_any_hardreset_lines_asserted(oh))
return 0;
pr_debug("omap_hwmod: %s: %s\n", oh->name, __func__);
@@ -1749,12 +1772,12 @@ static int _am33xx_disable_module(struct omap_hwmod *oh)
pr_debug("omap_hwmod: %s: %s\n", oh->name, __func__);
+ if (_are_any_hardreset_lines_asserted(oh))
+ return 0;
+
am33xx_cm_module_disable(oh->clkdm->cm_inst, oh->clkdm->clkdm_offs,
oh->prcm.omap4.clkctrl_offs);
- if (_are_all_hardreset_lines_asserted(oh))
- return 0;
-
v = _am33xx_wait_target_disable(oh);
if (v)
pr_warn("omap_hwmod: %s: _wait_target_disable failed\n",
diff --git a/arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c b/arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c
index 35dcdb6..bd9220e 100644
--- a/arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c
@@ -219,7 +219,7 @@ struct omap_hwmod omap2xxx_l4_wkup_hwmod = {
/* MPU */
static struct omap_hwmod_irq_info omap2xxx_mpu_irqs[] = {
- { .name = "pmu", .irq = 3 },
+ { .name = "pmu", .irq = 3 + OMAP_INTC_START },
{ .irq = -1 }
};
diff --git a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
index 2857772..f67b7ee 100644
--- a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
@@ -94,7 +94,7 @@ static struct omap_hwmod omap3xxx_l4_sec_hwmod = {
/* MPU */
static struct omap_hwmod_irq_info omap3xxx_mpu_irqs[] = {
- { .name = "pmu", .irq = 3 },
+ { .name = "pmu", .irq = 3 + OMAP_INTC_START },
{ .irq = -1 }
};
@@ -3683,6 +3683,7 @@ static struct omap_hwmod_ocp_if *am35xx_hwmod_ocp_ifs[] __initdata = {
&omap3xxx_l4_core__usb_tll_hs,
&omap3xxx_l4_core__es3plus_mmc1,
&omap3xxx_l4_core__es3plus_mmc2,
+ &omap3xxx_l4_core__hdq1w,
&am35xx_mdio__l3,
&am35xx_l4_core__mdio,
&am35xx_emac__l3,
@@ -3737,7 +3738,7 @@ int __init omap3xxx_hwmod_init(void)
} else {
WARN(1, "OMAP3 hwmod family init: unknown chip type\n");
return -EINVAL;
- };
+ }
r = omap_hwmod_register_links(h);
if (r < 0)
@@ -3754,7 +3755,7 @@ int __init omap3xxx_hwmod_init(void)
rev == OMAP3430_REV_ES3_0 || rev == OMAP3430_REV_ES3_1 ||
rev == OMAP3430_REV_ES3_1_2) {
h = omap3430es2plus_hwmod_ocp_ifs;
- };
+ }
if (h) {
r = omap_hwmod_register_links(h);
@@ -3769,7 +3770,7 @@ int __init omap3xxx_hwmod_init(void)
} else if (rev == OMAP3430_REV_ES3_0 || rev == OMAP3430_REV_ES3_1 ||
rev == OMAP3430_REV_ES3_1_2) {
h = omap3430_es3plus_hwmod_ocp_ifs;
- };
+ }
if (h)
r = omap_hwmod_register_links(h);
diff --git a/arch/arm/mach-omap2/opp.c b/arch/arm/mach-omap2/opp.c
index 45ad7f7..58e16ae 100644
--- a/arch/arm/mach-omap2/opp.c
+++ b/arch/arm/mach-omap2/opp.c
@@ -18,6 +18,7 @@
*/
#include <linux/module.h>
#include <linux/opp.h>
+#include <linux/cpu.h>
#include <plat/omap_device.h>
@@ -62,13 +63,23 @@ int __init omap_init_opp_table(struct omap_opp_def *opp_def,
__func__, i);
return -EINVAL;
}
- oh = omap_hwmod_lookup(opp_def->hwmod_name);
- if (!oh || !oh->od) {
- pr_debug("%s: no hwmod or odev for %s, [%d] cannot add OPPs.\n",
- __func__, opp_def->hwmod_name, i);
- continue;
+
+ if (!strncmp(opp_def->hwmod_name, "mpu", 3)) {
+ /*
+ * All current OMAPs share voltage rail and
+ * clock source, so CPU0 is used to represent
+ * the MPU-SS.
+ */
+ dev = get_cpu_device(0);
+ } else {
+ oh = omap_hwmod_lookup(opp_def->hwmod_name);
+ if (!oh || !oh->od) {
+ pr_debug("%s: no hwmod or odev for %s, [%d] cannot add OPPs.\n",
+ __func__, opp_def->hwmod_name, i);
+ continue;
+ }
+ dev = &oh->od->pdev->dev;
}
- dev = &oh->od->pdev->dev;
r = opp_add(dev, opp_def->freq, opp_def->u_volt);
if (r) {
diff --git a/arch/arm/mach-omap2/pm-debug.c b/arch/arm/mach-omap2/pm-debug.c
index 3e1345f..46092cd 100644
--- a/arch/arm/mach-omap2/pm-debug.c
+++ b/arch/arm/mach-omap2/pm-debug.c
@@ -168,7 +168,7 @@ static int pm_dbg_open(struct inode *inode, struct file *file)
default:
return single_open(file, pm_dbg_show_timers,
&inode->i_private);
- };
+ }
}
static const struct file_operations debug_fops = {
diff --git a/arch/arm/mach-omap2/pm.c b/arch/arm/mach-omap2/pm.c
index abefbc4..ea61c329 100644
--- a/arch/arm/mach-omap2/pm.c
+++ b/arch/arm/mach-omap2/pm.c
@@ -16,6 +16,7 @@
#include <linux/opp.h>
#include <linux/export.h>
#include <linux/suspend.h>
+#include <linux/cpu.h>
#include <asm/system_misc.h>
@@ -169,7 +170,15 @@ static int __init omap2_set_init_voltage(char *vdd_name, char *clk_name,
goto exit;
}
- dev = omap_device_get_by_hwmod_name(oh_name);
+ if (!strncmp(oh_name, "mpu", 3))
+ /*
+ * All current OMAPs share voltage rail and clock
+ * source, so CPU0 is used to represent the MPU-SS.
+ */
+ dev = get_cpu_device(0);
+ else
+ dev = omap_device_get_by_hwmod_name(oh_name);
+
if (IS_ERR(dev)) {
pr_err("%s: Unable to get dev pointer for hwmod %s\n",
__func__, oh_name);
@@ -177,7 +186,7 @@ static int __init omap2_set_init_voltage(char *vdd_name, char *clk_name,
}
voltdm = voltdm_lookup(vdd_name);
- if (IS_ERR(voltdm)) {
+ if (!voltdm) {
pr_err("%s: unable to get vdd pointer for vdd_%s\n",
__func__, vdd_name);
goto exit;
diff --git a/arch/arm/mach-omap2/sr_device.c b/arch/arm/mach-omap2/sr_device.c
index cbeae56..f8217a5 100644
--- a/arch/arm/mach-omap2/sr_device.c
+++ b/arch/arm/mach-omap2/sr_device.c
@@ -122,7 +122,7 @@ static int __init sr_dev_init(struct omap_hwmod *oh, void *user)
sr_data->senp_mod = 0x1;
sr_data->voltdm = voltdm_lookup(sr_dev_attr->sensor_voltdm_name);
- if (IS_ERR(sr_data->voltdm)) {
+ if (!sr_data->voltdm) {
pr_err("%s: Unable to get voltage domain pointer for VDD %s\n",
__func__, sr_dev_attr->sensor_voltdm_name);
goto exit;
diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c
index 8847d6e..44f9aa7 100644
--- a/arch/arm/mach-omap2/timer.c
+++ b/arch/arm/mach-omap2/timer.c
@@ -378,7 +378,7 @@ static void __init realtime_counter_init(void)
return;
}
sys_clk = clk_get(NULL, "sys_clkin_ck");
- if (!sys_clk) {
+ if (IS_ERR(sys_clk)) {
pr_err("%s: failed to get system clock handle\n", __func__);
iounmap(base);
return;
diff --git a/arch/arm/mach-omap2/twl-common.c b/arch/arm/mach-omap2/twl-common.c
index 18a8519..635e109 100644
--- a/arch/arm/mach-omap2/twl-common.c
+++ b/arch/arm/mach-omap2/twl-common.c
@@ -158,7 +158,7 @@ static struct regulator_init_data omap3_vpll2_idata = {
};
static struct regulator_consumer_supply omap3_vdd1_supply[] = {
- REGULATOR_SUPPLY("vcc", "mpu.0"),
+ REGULATOR_SUPPLY("vcc", "cpu0"),
};
static struct regulator_consumer_supply omap3_vdd2_supply[] = {
@@ -239,6 +239,10 @@ void __init omap3_pmic_get_config(struct twl4030_platform_data *pmic_data,
static struct twl4030_usb_data omap4_usb_pdata = {
};
+static struct regulator_consumer_supply omap4_vdda_hdmi_dac_supplies[] = {
+ REGULATOR_SUPPLY("vdda_hdmi_dac", "omapdss_hdmi"),
+};
+
static struct regulator_init_data omap4_vdac_idata = {
.constraints = {
.min_uV = 1800000,
@@ -248,6 +252,8 @@ static struct regulator_init_data omap4_vdac_idata = {
.valid_ops_mask = REGULATOR_CHANGE_MODE
| REGULATOR_CHANGE_STATUS,
},
+ .num_consumer_supplies = ARRAY_SIZE(omap4_vdda_hdmi_dac_supplies),
+ .consumer_supplies = omap4_vdda_hdmi_dac_supplies,
.supply_regulator = "V2V1",
};
diff --git a/arch/arm/mach-pxa/cm-x2xx.c b/arch/arm/mach-pxa/cm-x2xx.c
index fc3afc7..a103c8f 100644
--- a/arch/arm/mach-pxa/cm-x2xx.c
+++ b/arch/arm/mach-pxa/cm-x2xx.c
@@ -22,6 +22,7 @@
#include <asm/mach/map.h>
#include <mach/pxa25x.h>
+#undef GPIO24_SSP1_SFRM
#include <mach/pxa27x.h>
#include <mach/audio.h>
#include <linux/platform_data/video-pxafb.h>
diff --git a/arch/arm/mach-pxa/palmte2.c b/arch/arm/mach-pxa/palmte2.c
index 997e6da..32e0d79 100644
--- a/arch/arm/mach-pxa/palmte2.c
+++ b/arch/arm/mach-pxa/palmte2.c
@@ -105,6 +105,7 @@ static struct pxamci_platform_data palmte2_mci_platform_data = {
.gpio_power = GPIO_NR_PALMTE2_SD_POWER,
};
+#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
/******************************************************************************
* GPIO keys
******************************************************************************/
@@ -132,6 +133,7 @@ static struct platform_device palmte2_pxa_keys = {
.platform_data = &palmte2_pxa_keys_data,
},
};
+#endif
/******************************************************************************
* Backlight
diff --git a/arch/arm/mach-pxa/sharpsl_pm.c b/arch/arm/mach-pxa/sharpsl_pm.c
index 5a406f7..ec55c57 100644
--- a/arch/arm/mach-pxa/sharpsl_pm.c
+++ b/arch/arm/mach-pxa/sharpsl_pm.c
@@ -55,7 +55,6 @@
#ifdef CONFIG_PM
static int sharpsl_off_charge_battery(void);
static int sharpsl_check_battery_voltage(void);
-static int sharpsl_fatal_check(void);
#endif
static int sharpsl_check_battery_temp(void);
static int sharpsl_ac_check(void);
@@ -686,53 +685,6 @@ static int corgi_pxa_pm_enter(suspend_state_t state)
return 0;
}
-/*
- * Check for fatal battery errors
- * Fatal returns -1
- */
-static int sharpsl_fatal_check(void)
-{
- int buff[5], temp, i, acin;
-
- dev_dbg(sharpsl_pm.dev, "sharpsl_fatal_check entered\n");
-
- /* Check AC-Adapter */
- acin = sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_ACIN);
-
- if (acin && (sharpsl_pm.charge_mode == CHRG_ON)) {
- sharpsl_pm.machinfo->charge(0);
- udelay(100);
- sharpsl_pm.machinfo->discharge(1); /* enable discharge */
- mdelay(SHARPSL_WAIT_DISCHARGE_ON);
- }
-
- if (sharpsl_pm.machinfo->discharge1)
- sharpsl_pm.machinfo->discharge1(1);
-
- /* Check battery : check inserting battery ? */
- for (i = 0; i < 5; i++) {
- buff[i] = sharpsl_pm.machinfo->read_devdata(SHARPSL_BATT_VOLT);
- mdelay(SHARPSL_CHECK_BATTERY_WAIT_TIME_VOLT);
- }
-
- if (sharpsl_pm.machinfo->discharge1)
- sharpsl_pm.machinfo->discharge1(0);
-
- if (acin && (sharpsl_pm.charge_mode == CHRG_ON)) {
- udelay(100);
- sharpsl_pm.machinfo->charge(1);
- sharpsl_pm.machinfo->discharge(0);
- }
-
- temp = get_select_val(buff);
- dev_dbg(sharpsl_pm.dev, "sharpsl_fatal_check: acin: %d, discharge voltage: %d, no discharge: %ld\n", acin, temp, sharpsl_pm.machinfo->read_devdata(SHARPSL_BATT_VOLT));
-
- if ((acin && (temp < sharpsl_pm.machinfo->fatal_acin_volt)) ||
- (!acin && (temp < sharpsl_pm.machinfo->fatal_noacin_volt)))
- return -1;
- return 0;
-}
-
static int sharpsl_off_charge_error(void)
{
dev_err(sharpsl_pm.dev, "Offline Charger: Error occurred.\n");
diff --git a/arch/arm/mach-pxa/viper.c b/arch/arm/mach-pxa/viper.c
index 392412c..c773e4d 100644
--- a/arch/arm/mach-pxa/viper.c
+++ b/arch/arm/mach-pxa/viper.c
@@ -768,8 +768,7 @@ static unsigned long viper_tpm;
static int __init viper_tpm_setup(char *str)
{
- strict_strtoul(str, 10, &viper_tpm);
- return 1;
+ return strict_strtoul(str, 10, &viper_tpm) >= 0;
}
__setup("tpm=", viper_tpm_setup);
diff --git a/arch/arm/mach-rpc/ecard.c b/arch/arm/mach-rpc/ecard.c
index b91bc87..fcb1d59 100644
--- a/arch/arm/mach-rpc/ecard.c
+++ b/arch/arm/mach-rpc/ecard.c
@@ -960,7 +960,9 @@ static int __init ecard_probe(int slot, unsigned irq, card_type_t type)
*ecp = ec;
slot_to_expcard[slot] = ec;
- device_register(&ec->dev);
+ rc = device_register(&ec->dev);
+ if (rc)
+ goto nodev;
return 0;
diff --git a/arch/arm/mach-s3c24xx/irq-s3c2416.c b/arch/arm/mach-s3c24xx/irq-s3c2416.c
index 23ec973..ff141b0 100644
--- a/arch/arm/mach-s3c24xx/irq-s3c2416.c
+++ b/arch/arm/mach-s3c24xx/irq-s3c2416.c
@@ -232,7 +232,7 @@ struct irq_chip s3c2416_irq_second = {
/* IRQ initialisation code */
-static int __init s3c2416_add_sub(unsigned int base,
+static int s3c2416_add_sub(unsigned int base,
void (*demux)(unsigned int,
struct irq_desc *),
struct irq_chip *chip,
@@ -251,7 +251,7 @@ static int __init s3c2416_add_sub(unsigned int base,
return 0;
}
-static void __init s3c2416_irq_add_second(void)
+static void s3c2416_irq_add_second(void)
{
unsigned long pend;
unsigned long last;
@@ -287,7 +287,7 @@ static void __init s3c2416_irq_add_second(void)
}
}
-static int __init s3c2416_irq_add(struct device *dev,
+static int s3c2416_irq_add(struct device *dev,
struct subsys_interface *sif)
{
printk(KERN_INFO "S3C2416: IRQ Support\n");
diff --git a/arch/arm/mach-s3c24xx/irq-s3c2443.c b/arch/arm/mach-s3c24xx/irq-s3c2443.c
index ac2829f..5e69109 100644
--- a/arch/arm/mach-s3c24xx/irq-s3c2443.c
+++ b/arch/arm/mach-s3c24xx/irq-s3c2443.c
@@ -222,7 +222,7 @@ static struct irq_chip s3c2443_irq_cam = {
/* IRQ initialisation code */
-static int __init s3c2443_add_sub(unsigned int base,
+static int s3c2443_add_sub(unsigned int base,
void (*demux)(unsigned int,
struct irq_desc *),
struct irq_chip *chip,
@@ -241,7 +241,7 @@ static int __init s3c2443_add_sub(unsigned int base,
return 0;
}
-static int __init s3c2443_irq_add(struct device *dev,
+static int s3c2443_irq_add(struct device *dev,
struct subsys_interface *sif)
{
printk("S3C2443: IRQ Support\n");
diff --git a/arch/arm/mach-s3c24xx/mach-smdk2416.c b/arch/arm/mach-s3c24xx/mach-smdk2416.c
index db2787a..f30d7fc 100644
--- a/arch/arm/mach-s3c24xx/mach-smdk2416.c
+++ b/arch/arm/mach-s3c24xx/mach-smdk2416.c
@@ -29,6 +29,7 @@
#include <asm/mach/map.h>
#include <asm/mach/irq.h>
+#include <video/samsung_fimd.h>
#include <mach/hardware.h>
#include <asm/irq.h>
#include <asm/mach-types.h>
@@ -52,7 +53,6 @@
#include <linux/platform_data/usb-s3c2410_udc.h>
#include <linux/platform_data/s3c-hsudc.h>
-#include <plat/regs-fb-v4.h>
#include <plat/fb.h>
#include <plat/common-smdk.h>
diff --git a/arch/arm/mach-s3c24xx/simtec-usb.c b/arch/arm/mach-s3c24xx/simtec-usb.c
index 17f8356..ddf7a3c 100644
--- a/arch/arm/mach-s3c24xx/simtec-usb.c
+++ b/arch/arm/mach-s3c24xx/simtec-usb.c
@@ -104,7 +104,7 @@ static struct s3c2410_hcd_info usb_simtec_info __initdata = {
};
-int usb_simtec_init(void)
+int __init usb_simtec_init(void)
{
int ret;
diff --git a/arch/arm/mach-s3c64xx/mach-anw6410.c b/arch/arm/mach-s3c64xx/mach-anw6410.c
index 15c58df..99e82ac 100644
--- a/arch/arm/mach-s3c64xx/mach-anw6410.c
+++ b/arch/arm/mach-s3c64xx/mach-anw6410.c
@@ -29,6 +29,7 @@
#include <linux/dm9000.h>
#include <video/platform_lcd.h>
+#include <video/samsung_fimd.h>
#include <asm/hardware/vic.h>
#include <asm/mach/arch.h>
@@ -44,7 +45,6 @@
#include <plat/regs-serial.h>
#include <linux/platform_data/i2c-s3c2410.h>
#include <plat/fb.h>
-#include <plat/regs-fb-v4.h>
#include <plat/clock.h>
#include <plat/devs.h>
diff --git a/arch/arm/mach-s3c64xx/mach-crag6410.c b/arch/arm/mach-s3c64xx/mach-crag6410.c
index 8b4d467..13b7eaa 100644
--- a/arch/arm/mach-s3c64xx/mach-crag6410.c
+++ b/arch/arm/mach-s3c64xx/mach-crag6410.c
@@ -46,6 +46,7 @@
#include <asm/mach/arch.h>
#include <asm/mach-types.h>
+#include <video/samsung_fimd.h>
#include <mach/hardware.h>
#include <mach/map.h>
@@ -57,7 +58,6 @@
#include <mach/regs-gpio-memport.h>
#include <plat/regs-serial.h>
-#include <plat/regs-fb-v4.h>
#include <plat/fb.h>
#include <plat/sdhci.h>
#include <plat/gpio-cfg.h>
diff --git a/arch/arm/mach-s3c64xx/mach-hmt.c b/arch/arm/mach-s3c64xx/mach-hmt.c
index 02222b3..2b14489 100644
--- a/arch/arm/mach-s3c64xx/mach-hmt.c
+++ b/arch/arm/mach-s3c64xx/mach-hmt.c
@@ -26,6 +26,7 @@
#include <asm/mach/map.h>
#include <asm/mach/irq.h>
+#include <video/samsung_fimd.h>
#include <mach/hardware.h>
#include <mach/map.h>
@@ -41,7 +42,6 @@
#include <plat/clock.h>
#include <plat/devs.h>
#include <plat/cpu.h>
-#include <plat/regs-fb-v4.h>
#include "common.h"
diff --git a/arch/arm/mach-s3c64xx/mach-mini6410.c b/arch/arm/mach-s3c64xx/mach-mini6410.c
index 09311cc..07c349c 100644
--- a/arch/arm/mach-s3c64xx/mach-mini6410.c
+++ b/arch/arm/mach-s3c64xx/mach-mini6410.c
@@ -41,9 +41,9 @@
#include <linux/platform_data/mtd-nand-s3c2410.h>
#include <plat/regs-serial.h>
#include <linux/platform_data/touchscreen-s3c2410.h>
-#include <plat/regs-fb-v4.h>
#include <video/platform_lcd.h>
+#include <video/samsung_fimd.h>
#include "common.h"
diff --git a/arch/arm/mach-s3c64xx/mach-ncp.c b/arch/arm/mach-s3c64xx/mach-ncp.c
index 46ee88d..e5f9a79 100644
--- a/arch/arm/mach-s3c64xx/mach-ncp.c
+++ b/arch/arm/mach-s3c64xx/mach-ncp.c
@@ -24,6 +24,7 @@
#include <linux/delay.h>
#include <video/platform_lcd.h>
+#include <video/samsung_fimd.h>
#include <asm/hardware/vic.h>
#include <asm/mach/arch.h>
@@ -43,7 +44,6 @@
#include <plat/clock.h>
#include <plat/devs.h>
#include <plat/cpu.h>
-#include <plat/regs-fb-v4.h>
#include "common.h"
diff --git a/arch/arm/mach-s3c64xx/mach-real6410.c b/arch/arm/mach-s3c64xx/mach-real6410.c
index 6daca20..7476f7c 100644
--- a/arch/arm/mach-s3c64xx/mach-real6410.c
+++ b/arch/arm/mach-s3c64xx/mach-real6410.c
@@ -42,9 +42,9 @@
#include <linux/platform_data/mtd-nand-s3c2410.h>
#include <plat/regs-serial.h>
#include <linux/platform_data/touchscreen-s3c2410.h>
-#include <plat/regs-fb-v4.h>
#include <video/platform_lcd.h>
+#include <video/samsung_fimd.h>
#include "common.h"
diff --git a/arch/arm/mach-s3c64xx/mach-smartq5.c b/arch/arm/mach-s3c64xx/mach-smartq5.c
index d6266d8..96d6da2 100644
--- a/arch/arm/mach-s3c64xx/mach-smartq5.c
+++ b/arch/arm/mach-s3c64xx/mach-smartq5.c
@@ -21,6 +21,7 @@
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
+#include <video/samsung_fimd.h>
#include <mach/map.h>
#include <mach/regs-gpio.h>
@@ -28,7 +29,6 @@
#include <plat/devs.h>
#include <plat/fb.h>
#include <plat/gpio-cfg.h>
-#include <plat/regs-fb-v4.h>
#include "common.h"
#include "mach-smartq.h"
diff --git a/arch/arm/mach-s3c64xx/mach-smartq7.c b/arch/arm/mach-s3c64xx/mach-smartq7.c
index 0957d2a..7d1167b 100644
--- a/arch/arm/mach-s3c64xx/mach-smartq7.c
+++ b/arch/arm/mach-s3c64xx/mach-smartq7.c
@@ -21,6 +21,7 @@
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
+#include <video/samsung_fimd.h>
#include <mach/map.h>
#include <mach/regs-gpio.h>
@@ -28,7 +29,6 @@
#include <plat/devs.h>
#include <plat/fb.h>
#include <plat/gpio-cfg.h>
-#include <plat/regs-fb-v4.h>
#include "common.h"
#include "mach-smartq.h"
diff --git a/arch/arm/mach-s3c64xx/mach-smdk6410.c b/arch/arm/mach-s3c64xx/mach-smdk6410.c
index 2547a88..da1a771 100644
--- a/arch/arm/mach-s3c64xx/mach-smdk6410.c
+++ b/arch/arm/mach-s3c64xx/mach-smdk6410.c
@@ -43,6 +43,7 @@
#endif
#include <video/platform_lcd.h>
+#include <video/samsung_fimd.h>
#include <asm/hardware/vic.h>
#include <asm/mach/arch.h>
@@ -72,7 +73,6 @@
#include <linux/platform_data/touchscreen-s3c2410.h>
#include <plat/keypad.h>
#include <plat/backlight.h>
-#include <plat/regs-fb-v4.h>
#include "common.h"
diff --git a/arch/arm/mach-s5p64x0/mach-smdk6440.c b/arch/arm/mach-s5p64x0/mach-smdk6440.c
index dea78a8..96ea1fe 100644
--- a/arch/arm/mach-s5p64x0/mach-smdk6440.c
+++ b/arch/arm/mach-s5p64x0/mach-smdk6440.c
@@ -27,6 +27,7 @@
#include <linux/mmc/host.h>
#include <video/platform_lcd.h>
+#include <video/samsung_fimd.h>
#include <asm/hardware/vic.h>
#include <asm/mach/arch.h>
@@ -52,7 +53,6 @@
#include <plat/s5p-time.h>
#include <plat/backlight.h>
#include <plat/fb.h>
-#include <plat/regs-fb.h>
#include <plat/sdhci.h>
#include "common.h"
diff --git a/arch/arm/mach-s5p64x0/mach-smdk6450.c b/arch/arm/mach-s5p64x0/mach-smdk6450.c
index 6f14fc7..12748b6 100644
--- a/arch/arm/mach-s5p64x0/mach-smdk6450.c
+++ b/arch/arm/mach-s5p64x0/mach-smdk6450.c
@@ -27,6 +27,7 @@
#include <linux/mmc/host.h>
#include <video/platform_lcd.h>
+#include <video/samsung_fimd.h>
#include <asm/hardware/vic.h>
#include <asm/mach/arch.h>
@@ -52,7 +53,6 @@
#include <plat/s5p-time.h>
#include <plat/backlight.h>
#include <plat/fb.h>
-#include <plat/regs-fb.h>
#include <plat/sdhci.h>
#include "common.h"
diff --git a/arch/arm/mach-s5pc100/mach-smdkc100.c b/arch/arm/mach-s5pc100/mach-smdkc100.c
index 5d2c093..dba7384 100644
--- a/arch/arm/mach-s5pc100/mach-smdkc100.c
+++ b/arch/arm/mach-s5pc100/mach-smdkc100.c
@@ -33,6 +33,7 @@
#include <mach/regs-gpio.h>
#include <video/platform_lcd.h>
+#include <video/samsung_fimd.h>
#include <asm/irq.h>
#include <asm/mach-types.h>
@@ -51,7 +52,6 @@
#include <linux/platform_data/touchscreen-s3c2410.h>
#include <linux/platform_data/asoc-s3c.h>
#include <plat/backlight.h>
-#include <plat/regs-fb-v4.h>
#include "common.h"
diff --git a/arch/arm/mach-s5pv210/mach-aquila.c b/arch/arm/mach-s5pv210/mach-aquila.c
index 78028df..ee9fa5c 100644
--- a/arch/arm/mach-s5pv210/mach-aquila.c
+++ b/arch/arm/mach-s5pv210/mach-aquila.c
@@ -28,6 +28,7 @@
#include <asm/setup.h>
#include <asm/mach-types.h>
+#include <video/samsung_fimd.h>
#include <mach/map.h>
#include <mach/regs-clock.h>
@@ -39,7 +40,6 @@
#include <plat/fimc-core.h>
#include <plat/sdhci.h>
#include <plat/s5p-time.h>
-#include <plat/regs-fb-v4.h>
#include "common.h"
diff --git a/arch/arm/mach-s5pv210/mach-goni.c b/arch/arm/mach-s5pv210/mach-goni.c
index 00f1e47..55e1dba 100644
--- a/arch/arm/mach-s5pv210/mach-goni.c
+++ b/arch/arm/mach-s5pv210/mach-goni.c
@@ -35,6 +35,7 @@
#include <asm/setup.h>
#include <asm/mach-types.h>
+#include <video/samsung_fimd.h>
#include <mach/map.h>
#include <mach/regs-clock.h>
@@ -49,7 +50,6 @@
#include <plat/clock.h>
#include <plat/s5p-time.h>
#include <plat/mfc.h>
-#include <plat/regs-fb-v4.h>
#include <plat/camport.h>
#include <media/v4l2-mediabus.h>
diff --git a/arch/arm/mach-s5pv210/mach-smdkv210.c b/arch/arm/mach-s5pv210/mach-smdkv210.c
index 7d6fab4..4cdb5bb 100644
--- a/arch/arm/mach-s5pv210/mach-smdkv210.c
+++ b/arch/arm/mach-s5pv210/mach-smdkv210.c
@@ -28,6 +28,7 @@
#include <asm/mach-types.h>
#include <video/platform_lcd.h>
+#include <video/samsung_fimd.h>
#include <mach/map.h>
#include <mach/regs-clock.h>
@@ -46,7 +47,6 @@
#include <plat/fb.h>
#include <plat/s5p-time.h>
#include <plat/backlight.h>
-#include <plat/regs-fb-v4.h>
#include <plat/mfc.h>
#include <plat/clock.h>
diff --git a/arch/arm/mach-sa1100/assabet.c b/arch/arm/mach-sa1100/assabet.c
index e1ccda6..6a7ad3c 100644
--- a/arch/arm/mach-sa1100/assabet.c
+++ b/arch/arm/mach-sa1100/assabet.c
@@ -388,7 +388,7 @@ static void __init map_sa1100_gpio_regs( void )
*/
static void __init get_assabet_scr(void)
{
- unsigned long scr, i;
+ unsigned long uninitialized_var(scr), i;
GPDR |= 0x3fc; /* Configure GPIO 9:2 as outputs */
GPSR = 0x3fc; /* Write 0xFF to GPIO 9:2 */
diff --git a/arch/arm/mach-shark/pci.c b/arch/arm/mach-shark/pci.c
index b8b4ab3..6d91a91 100644
--- a/arch/arm/mach-shark/pci.c
+++ b/arch/arm/mach-shark/pci.c
@@ -41,7 +41,7 @@ static struct hw_pci shark_pci __initdata = {
static int __init shark_pci_init(void)
{
if (!machine_is_shark())
- return;
+ return -ENODEV;
pcibios_min_io = 0x6000;
pcibios_min_mem = 0x50000000;
diff --git a/arch/arm/mach-shmobile/include/mach/common.h b/arch/arm/mach-shmobile/include/mach/common.h
index ed77ab8..d47e215 100644
--- a/arch/arm/mach-shmobile/include/mach/common.h
+++ b/arch/arm/mach-shmobile/include/mach/common.h
@@ -100,7 +100,7 @@ static inline int shmobile_cpu_is_dead(unsigned int cpu) { return 1; }
extern void shmobile_smp_init_cpus(unsigned int ncores);
-static inline void shmobile_init_late(void)
+static inline void __init shmobile_init_late(void)
{
shmobile_suspend_init();
shmobile_cpuidle_init();
diff --git a/arch/arm/mach-spear13xx/spear13xx.c b/arch/arm/mach-spear13xx/spear13xx.c
index e106488..5633d69 100644
--- a/arch/arm/mach-spear13xx/spear13xx.c
+++ b/arch/arm/mach-spear13xx/spear13xx.c
@@ -78,6 +78,9 @@ struct dw_dma_platform_data dmac_plat_data = {
.nr_channels = 8,
.chan_allocation_order = CHAN_ALLOCATION_DESCENDING,
.chan_priority = CHAN_PRIORITY_DESCENDING,
+ .block_size = 4095U,
+ .nr_masters = 2,
+ .data_width = { 3, 3, 0, 0 },
};
void __init spear13xx_l2x0_init(void)
diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig
index 5f3c03b..11680c5 100644
--- a/arch/arm/mach-tegra/Kconfig
+++ b/arch/arm/mach-tegra/Kconfig
@@ -16,7 +16,7 @@ config ARCH_TEGRA_2x_SOC
select ARM_ERRATA_742230
select ARM_ERRATA_751472
select ARM_ERRATA_754327
- select ARM_ERRATA_764369
+ select ARM_ERRATA_764369 if SMP
select PL310_ERRATA_727915 if CACHE_L2X0
select PL310_ERRATA_769419 if CACHE_L2X0
select CPU_FREQ_TABLE if CPU_FREQ
@@ -37,7 +37,7 @@ config ARCH_TEGRA_3x_SOC
select ARM_ERRATA_743622
select ARM_ERRATA_751472
select ARM_ERRATA_754322
- select ARM_ERRATA_764369
+ select ARM_ERRATA_764369 if SMP
select PL310_ERRATA_769419 if CACHE_L2X0
select CPU_FREQ_TABLE if CPU_FREQ
help
@@ -57,8 +57,6 @@ config TEGRA_AHB
which controls AHB bus master arbitration and some
perfomance parameters(priority, prefech size).
-comment "Tegra board type"
-
choice
prompt "Default low-level debug console UART"
default TEGRA_DEBUG_UART_NONE
diff --git a/arch/arm/mach-ux500/Kconfig b/arch/arm/mach-ux500/Kconfig
index c77c86c4..5848206 100644
--- a/arch/arm/mach-ux500/Kconfig
+++ b/arch/arm/mach-ux500/Kconfig
@@ -5,9 +5,9 @@ config UX500_SOC_COMMON
default y
select ARM_GIC
select HAS_MTU
- select PL310_ERRATA_753970
+ select PL310_ERRATA_753970 if CACHE_PL310
select ARM_ERRATA_754322
- select ARM_ERRATA_764369
+ select ARM_ERRATA_764369 if SMP
select CACHE_L2X0
select PINCTRL
select PINCTRL_NOMADIK
diff --git a/arch/arm/mach-vt8500/include/mach/uncompress.h b/arch/arm/mach-vt8500/include/mach/uncompress.h
index bb9e2d2..e6e81fd 100644
--- a/arch/arm/mach-vt8500/include/mach/uncompress.h
+++ b/arch/arm/mach-vt8500/include/mach/uncompress.h
@@ -15,15 +15,15 @@
*
*/
-#define UART0_PHYS 0xd8200000
-#include <asm/io.h>
+#define UART0_PHYS 0xd8200000
+#define UART0_ADDR(x) *(volatile unsigned char *)(UART0_PHYS + x)
static void putc(const char c)
{
- while (readb(UART0_PHYS + 0x1c) & 0x2)
+ while (UART0_ADDR(0x1c) & 0x2)
/* Tx busy, wait and poll */;
- writeb(c, UART0_PHYS);
+ UART0_ADDR(0) = c;
}
static void flush(void)
diff --git a/arch/arm/mach-vt8500/vt8500.c b/arch/arm/mach-vt8500/vt8500.c
index 587ea95..8d3871f 100644
--- a/arch/arm/mach-vt8500/vt8500.c
+++ b/arch/arm/mach-vt8500/vt8500.c
@@ -77,8 +77,11 @@ static void vt8500_power_off(void)
void __init vt8500_init(void)
{
- struct device_node *np, *fb;
+ struct device_node *np;
+#if defined(CONFIG_FB_VT8500) || defined(CONFIG_FB_WM8505)
+ struct device_node *fb;
void __iomem *gpio_base;
+#endif
#ifdef CONFIG_FB_VT8500
fb = of_find_compatible_node(NULL, NULL, "via,vt8500-fb");
diff --git a/arch/arm/plat-mxc/devices/platform-mxc_nand.c b/arch/arm/plat-mxc/devices/platform-mxc_nand.c
index 1568f39..95b75cc 100644
--- a/arch/arm/plat-mxc/devices/platform-mxc_nand.c
+++ b/arch/arm/plat-mxc/devices/platform-mxc_nand.c
@@ -63,10 +63,6 @@ struct platform_device *__init imx_add_mxc_nand(
/* AXI has to come first, that's how the mxc_nand driver expect it */
struct resource res[] = {
{
- .start = data->axibase,
- .end = data->axibase + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- }, {
.start = data->iobase,
.end = data->iobase + data->iosize - 1,
.flags = IORESOURCE_MEM,
@@ -74,10 +70,13 @@ struct platform_device *__init imx_add_mxc_nand(
.start = data->irq,
.end = data->irq,
.flags = IORESOURCE_IRQ,
+ }, {
+ .start = data->axibase,
+ .end = data->axibase + SZ_16K - 1,
+ .flags = IORESOURCE_MEM,
},
};
return imx_add_platform_device("mxc_nand", data->id,
- res + !data->axibase,
- ARRAY_SIZE(res) - !data->axibase,
+ res, ARRAY_SIZE(res) - !data->axibase,
pdata, sizeof(*pdata));
}
diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig
index ca83a76..c9d1c36 100644
--- a/arch/arm/plat-omap/Kconfig
+++ b/arch/arm/plat-omap/Kconfig
@@ -43,11 +43,13 @@ config OMAP_DEBUG_DEVICES
config OMAP_DEBUG_LEDS
def_bool y if NEW_LEDS
+ select LEDS_CLASS
depends on OMAP_DEBUG_DEVICES
config POWER_AVS_OMAP
bool "AVS(Adaptive Voltage Scaling) support for OMAP IP versions 1&2"
depends on POWER_AVS && (ARCH_OMAP3 || ARCH_OMAP4) && PM
+ select POWER_SUPPLY
help
Say Y to enable AVS(Adaptive Voltage Scaling)
support on OMAP containing the version 1 or
diff --git a/arch/arm/plat-omap/counter_32k.c b/arch/arm/plat-omap/counter_32k.c
index 2e826f1..87ba8dd 100644
--- a/arch/arm/plat-omap/counter_32k.c
+++ b/arch/arm/plat-omap/counter_32k.c
@@ -52,22 +52,29 @@ static u32 notrace omap_32k_read_sched_clock(void)
* nsecs and adds to a monotonically increasing timespec.
*/
static struct timespec persistent_ts;
-static cycles_t cycles, last_cycles;
+static cycles_t cycles;
static unsigned int persistent_mult, persistent_shift;
+static DEFINE_SPINLOCK(read_persistent_clock_lock);
+
static void omap_read_persistent_clock(struct timespec *ts)
{
unsigned long long nsecs;
- cycles_t delta;
- struct timespec *tsp = &persistent_ts;
+ cycles_t last_cycles;
+ unsigned long flags;
+
+ spin_lock_irqsave(&read_persistent_clock_lock, flags);
last_cycles = cycles;
cycles = sync32k_cnt_reg ? __raw_readl(sync32k_cnt_reg) : 0;
- delta = cycles - last_cycles;
- nsecs = clocksource_cyc2ns(delta, persistent_mult, persistent_shift);
+ nsecs = clocksource_cyc2ns(cycles - last_cycles,
+ persistent_mult, persistent_shift);
+
+ timespec_add_ns(&persistent_ts, nsecs);
+
+ *ts = persistent_ts;
- timespec_add_ns(tsp, nsecs);
- *ts = *tsp;
+ spin_unlock_irqrestore(&read_persistent_clock_lock, flags);
}
/**
diff --git a/arch/arm/plat-omap/i2c.c b/arch/arm/plat-omap/i2c.c
index 6013831..a5683a8 100644
--- a/arch/arm/plat-omap/i2c.c
+++ b/arch/arm/plat-omap/i2c.c
@@ -26,14 +26,12 @@
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/i2c.h>
-#include <linux/i2c-omap.h>
#include <linux/slab.h>
#include <linux/err.h>
#include <linux/clk.h>
#include <mach/irqs.h>
#include <plat/i2c.h>
-#include <plat/omap-pm.h>
#include <plat/omap_device.h>
#define OMAP_I2C_SIZE 0x3f
@@ -129,16 +127,6 @@ static inline int omap1_i2c_add_bus(int bus_id)
#ifdef CONFIG_ARCH_OMAP2PLUS
-/*
- * XXX This function is a temporary compatibility wrapper - only
- * needed until the I2C driver can be converted to call
- * omap_pm_set_max_dev_wakeup_lat() and handle a return code.
- */
-static void omap_pm_set_max_mpu_wakeup_lat_compat(struct device *dev, long t)
-{
- omap_pm_set_max_mpu_wakeup_lat(dev, t);
-}
-
static inline int omap2_i2c_add_bus(int bus_id)
{
int l;
@@ -170,15 +158,6 @@ static inline int omap2_i2c_add_bus(int bus_id)
dev_attr = (struct omap_i2c_dev_attr *)oh->dev_attr;
pdata->flags = dev_attr->flags;
- /*
- * When waiting for completion of a i2c transfer, we need to
- * set a wake up latency constraint for the MPU. This is to
- * ensure quick enough wakeup from idle, when transfer
- * completes.
- * Only omap3 has support for constraints
- */
- if (cpu_is_omap34xx())
- pdata->set_mpu_wkup_lat = omap_pm_set_max_mpu_wakeup_lat_compat;
pdev = omap_device_build(name, bus_id, oh, pdata,
sizeof(struct omap_i2c_bus_platform_data),
NULL, 0, 0);
diff --git a/arch/arm/plat-omap/omap-pm-noop.c b/arch/arm/plat-omap/omap-pm-noop.c
index 9f64133..9722f41 100644
--- a/arch/arm/plat-omap/omap-pm-noop.c
+++ b/arch/arm/plat-omap/omap-pm-noop.c
@@ -38,7 +38,7 @@ int omap_pm_set_max_mpu_wakeup_lat(struct device *dev, long t)
if (!dev || t < -1) {
WARN(1, "OMAP PM: %s: invalid parameter(s)", __func__);
return -EINVAL;
- };
+ }
if (t == -1)
pr_debug("OMAP PM: remove max MPU wakeup latency constraint: dev %s\n",
@@ -67,7 +67,7 @@ int omap_pm_set_min_bus_tput(struct device *dev, u8 agent_id, unsigned long r)
agent_id != OCP_TARGET_AGENT)) {
WARN(1, "OMAP PM: %s: invalid parameter(s)", __func__);
return -EINVAL;
- };
+ }
if (r == 0)
pr_debug("OMAP PM: remove min bus tput constraint: dev %s for agent_id %d\n",
@@ -93,7 +93,7 @@ int omap_pm_set_max_dev_wakeup_lat(struct device *req_dev, struct device *dev,
if (!req_dev || !dev || t < -1) {
WARN(1, "OMAP PM: %s: invalid parameter(s)", __func__);
return -EINVAL;
- };
+ }
if (t == -1)
pr_debug("OMAP PM: remove max device latency constraint: dev %s\n",
@@ -123,7 +123,7 @@ int omap_pm_set_max_sdma_lat(struct device *dev, long t)
if (!dev || t < -1) {
WARN(1, "OMAP PM: %s: invalid parameter(s)", __func__);
return -EINVAL;
- };
+ }
if (t == -1)
pr_debug("OMAP PM: remove max DMA latency constraint: dev %s\n",
diff --git a/arch/arm/plat-omap/omap_device.c b/arch/arm/plat-omap/omap_device.c
index cee85a5..7a7d1f2 100644
--- a/arch/arm/plat-omap/omap_device.c
+++ b/arch/arm/plat-omap/omap_device.c
@@ -725,7 +725,7 @@ struct platform_device __init *omap_device_build_ss(const char *pdev_name, int p
dev_set_name(&pdev->dev, "%s", pdev->name);
od = omap_device_alloc(pdev, ohs, oh_cnt, pm_lats, pm_lats_cnt);
- if (!od)
+ if (IS_ERR(od))
goto odbs_exit1;
ret = platform_device_add_data(pdev, pdata, pdata_len);
diff --git a/arch/arm/plat-samsung/include/plat/regs-fb-v4.h b/arch/arm/plat-samsung/include/plat/regs-fb-v4.h
deleted file mode 100644
index 4c3647f..0000000
--- a/arch/arm/plat-samsung/include/plat/regs-fb-v4.h
+++ /dev/null
@@ -1,159 +0,0 @@
-/* arch/arm/plat-samsung/include/plat/regs-fb-v4.h
- *
- * Copyright 2008 Openmoko, Inc.
- * Copyright 2008 Simtec Electronics
- * http://armlinux.simtec.co.uk/
- * Ben Dooks <ben@simtec.co.uk>
- *
- * S3C64XX - new-style framebuffer register definitions
- *
- * This is the register set for the new style framebuffer interface
- * found from the S3C2443 onwards and specifically the S3C64XX series
- * S3C6400 and S3C6410.
- *
- * The file contains the cpu specific items which change between whichever
- * architecture is selected. See <plat/regs-fb.h> for the core definitions
- * that are the same.
- *
- * 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 the core definitions here, in case we really do need to
- * override them at a later date.
-*/
-
-#include <plat/regs-fb.h>
-
-#define S3C_FB_MAX_WIN (5) /* number of hardware windows available. */
-#define VIDCON1_FSTATUS_EVEN (1 << 15)
-
-/* Video timing controls */
-#define VIDTCON0 (0x10)
-#define VIDTCON1 (0x14)
-#define VIDTCON2 (0x18)
-
-/* Window position controls */
-
-#define WINCON(_win) (0x20 + ((_win) * 4))
-
-/* OSD1 and OSD4 do not have register D */
-
-#define VIDOSD_BASE (0x40)
-
-#define VIDINTCON0 (0x130)
-
-/* WINCONx */
-
-#define WINCONx_CSCWIDTH_MASK (0x3 << 26)
-#define WINCONx_CSCWIDTH_SHIFT (26)
-#define WINCONx_CSCWIDTH_WIDE (0x0 << 26)
-#define WINCONx_CSCWIDTH_NARROW (0x3 << 26)
-
-#define WINCONx_ENLOCAL (1 << 22)
-#define WINCONx_BUFSTATUS (1 << 21)
-#define WINCONx_BUFSEL (1 << 20)
-#define WINCONx_BUFAUTOEN (1 << 19)
-#define WINCONx_YCbCr (1 << 13)
-
-#define WINCON1_LOCALSEL_CAMIF (1 << 23)
-
-#define WINCON2_LOCALSEL_CAMIF (1 << 23)
-#define WINCON2_BLD_PIX (1 << 6)
-
-#define WINCON2_ALPHA_SEL (1 << 1)
-#define WINCON2_BPPMODE_MASK (0xf << 2)
-#define WINCON2_BPPMODE_SHIFT (2)
-#define WINCON2_BPPMODE_1BPP (0x0 << 2)
-#define WINCON2_BPPMODE_2BPP (0x1 << 2)
-#define WINCON2_BPPMODE_4BPP (0x2 << 2)
-#define WINCON2_BPPMODE_8BPP_1232 (0x4 << 2)
-#define WINCON2_BPPMODE_16BPP_565 (0x5 << 2)
-#define WINCON2_BPPMODE_16BPP_A1555 (0x6 << 2)
-#define WINCON2_BPPMODE_16BPP_I1555 (0x7 << 2)
-#define WINCON2_BPPMODE_18BPP_666 (0x8 << 2)
-#define WINCON2_BPPMODE_18BPP_A1665 (0x9 << 2)
-#define WINCON2_BPPMODE_19BPP_A1666 (0xa << 2)
-#define WINCON2_BPPMODE_24BPP_888 (0xb << 2)
-#define WINCON2_BPPMODE_24BPP_A1887 (0xc << 2)
-#define WINCON2_BPPMODE_25BPP_A1888 (0xd << 2)
-#define WINCON2_BPPMODE_28BPP_A4888 (0xd << 2)
-
-#define WINCON3_BLD_PIX (1 << 6)
-
-#define WINCON3_ALPHA_SEL (1 << 1)
-#define WINCON3_BPPMODE_MASK (0xf << 2)
-#define WINCON3_BPPMODE_SHIFT (2)
-#define WINCON3_BPPMODE_1BPP (0x0 << 2)
-#define WINCON3_BPPMODE_2BPP (0x1 << 2)
-#define WINCON3_BPPMODE_4BPP (0x2 << 2)
-#define WINCON3_BPPMODE_16BPP_565 (0x5 << 2)
-#define WINCON3_BPPMODE_16BPP_A1555 (0x6 << 2)
-#define WINCON3_BPPMODE_16BPP_I1555 (0x7 << 2)
-#define WINCON3_BPPMODE_18BPP_666 (0x8 << 2)
-#define WINCON3_BPPMODE_18BPP_A1665 (0x9 << 2)
-#define WINCON3_BPPMODE_19BPP_A1666 (0xa << 2)
-#define WINCON3_BPPMODE_24BPP_888 (0xb << 2)
-#define WINCON3_BPPMODE_24BPP_A1887 (0xc << 2)
-#define WINCON3_BPPMODE_25BPP_A1888 (0xd << 2)
-#define WINCON3_BPPMODE_28BPP_A4888 (0xd << 2)
-
-#define VIDINTCON0_FIFIOSEL_WINDOW2 (0x10 << 5)
-#define VIDINTCON0_FIFIOSEL_WINDOW3 (0x20 << 5)
-#define VIDINTCON0_FIFIOSEL_WINDOW4 (0x40 << 5)
-
-#define DITHMODE (0x170)
-#define WINxMAP(_win) (0x180 + ((_win) * 4))
-
-
-#define DITHMODE_R_POS_MASK (0x3 << 5)
-#define DITHMODE_R_POS_SHIFT (5)
-#define DITHMODE_R_POS_8BIT (0x0 << 5)
-#define DITHMODE_R_POS_6BIT (0x1 << 5)
-#define DITHMODE_R_POS_5BIT (0x2 << 5)
-
-#define DITHMODE_G_POS_MASK (0x3 << 3)
-#define DITHMODE_G_POS_SHIFT (3)
-#define DITHMODE_G_POS_8BIT (0x0 << 3)
-#define DITHMODE_G_POS_6BIT (0x1 << 3)
-#define DITHMODE_G_POS_5BIT (0x2 << 3)
-
-#define DITHMODE_B_POS_MASK (0x3 << 1)
-#define DITHMODE_B_POS_SHIFT (1)
-#define DITHMODE_B_POS_8BIT (0x0 << 1)
-#define DITHMODE_B_POS_6BIT (0x1 << 1)
-#define DITHMODE_B_POS_5BIT (0x2 << 1)
-
-#define DITHMODE_DITH_EN (1 << 0)
-
-#define WPALCON (0x1A0)
-
-/* Palette control */
-/* Note for S5PC100: you can still use those macros on WPALCON (aka WPALCON_L),
- * but make sure that WPALCON_H W2PAL-W4PAL entries are zeroed out */
-#define WPALCON_W4PAL_16BPP_A555 (1 << 8)
-#define WPALCON_W3PAL_16BPP_A555 (1 << 7)
-#define WPALCON_W2PAL_16BPP_A555 (1 << 6)
-
-
-/* Notes on per-window bpp settings
- *
- * Value Win0 Win1 Win2 Win3 Win 4
- * 0000 1(P) 1(P) 1(P) 1(P) 1(P)
- * 0001 2(P) 2(P) 2(P) 2(P) 2(P)
- * 0010 4(P) 4(P) 4(P) 4(P) -none-
- * 0011 8(P) 8(P) -none- -none- -none-
- * 0100 -none- 8(A232) 8(A232) -none- -none-
- * 0101 16(565) 16(565) 16(565) 16(565) 16(565)
- * 0110 -none- 16(A555) 16(A555) 16(A555) 16(A555)
- * 0111 16(I555) 16(I565) 16(I555) 16(I555) 16(I555)
- * 1000 18(666) 18(666) 18(666) 18(666) 18(666)
- * 1001 -none- 18(A665) 18(A665) 18(A665) 16(A665)
- * 1010 -none- 19(A666) 19(A666) 19(A666) 19(A666)
- * 1011 24(888) 24(888) 24(888) 24(888) 24(888)
- * 1100 -none- 24(A887) 24(A887) 24(A887) 24(A887)
- * 1101 -none- 25(A888) 25(A888) 25(A888) 25(A888)
- * 1110 -none- -none- -none- -none- -none-
- * 1111 -none- -none- -none- -none- -none-
-*/
diff --git a/arch/avr32/include/asm/Kbuild b/arch/avr32/include/asm/Kbuild
index e3ba7bc..be0433e 100644
--- a/arch/avr32/include/asm/Kbuild
+++ b/arch/avr32/include/asm/Kbuild
@@ -1,5 +1,6 @@
include include/asm-generic/Kbuild.asm
generic-y += clkdev.h
+generic-y += exec.h
header-y += cachectl.h
diff --git a/arch/avr32/include/asm/exec.h b/arch/avr32/include/asm/exec.h
deleted file mode 100644
index f467be8..0000000
--- a/arch/avr32/include/asm/exec.h
+++ /dev/null
@@ -1,13 +0,0 @@
-/*
- * Copyright (C) 2004-2006 Atmel Corporation
- *
- * 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_AVR32_EXEC_H
-#define __ASM_AVR32_EXEC_H
-
-#define arch_align_stack(x) (x)
-
-#endif /* __ASM_AVR32_EXEC_H */
diff --git a/arch/avr32/include/asm/thread_info.h b/arch/avr32/include/asm/thread_info.h
index e5deda4..6dc62e1 100644
--- a/arch/avr32/include/asm/thread_info.h
+++ b/arch/avr32/include/asm/thread_info.h
@@ -77,8 +77,6 @@ static inline struct thread_info *current_thread_info(void)
#define TIF_SYSCALL_TRACE 0 /* syscall trace active */
#define TIF_SIGPENDING 1 /* signal pending */
#define TIF_NEED_RESCHED 2 /* rescheduling necessary */
-#define TIF_POLLING_NRFLAG 3 /* true if poll_idle() is polling
- TIF_NEED_RESCHED */
#define TIF_BREAKPOINT 4 /* enter monitor mode on return */
#define TIF_SINGLE_STEP 5 /* single step in progress */
#define TIF_MEMDIE 6 /* is terminating due to OOM killer */
@@ -91,10 +89,9 @@ static inline struct thread_info *current_thread_info(void)
#define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE)
#define _TIF_SIGPENDING (1 << TIF_SIGPENDING)
#define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED)
-#define _TIF_POLLING_NRFLAG (1 << TIF_POLLING_NRFLAG)
+#define _TIF_BREAKPOINT (1 << TIF_BREAKPOINT)
#define _TIF_SINGLE_STEP (1 << TIF_SINGLE_STEP)
#define _TIF_MEMDIE (1 << TIF_MEMDIE)
-#define _TIF_RESTORE_SIGMASK (1 << TIF_RESTORE_SIGMASK)
#define _TIF_CPU_GOING_TO_SLEEP (1 << TIF_CPU_GOING_TO_SLEEP)
#define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME)
@@ -102,17 +99,14 @@ static inline struct thread_info *current_thread_info(void)
/* work to do on interrupt/exception return */
#define _TIF_WORK_MASK \
- ((1 << TIF_SIGPENDING) \
+ (_TIF_SIGPENDING \
| _TIF_NOTIFY_RESUME \
- | (1 << TIF_NEED_RESCHED) \
- | (1 << TIF_POLLING_NRFLAG) \
- | (1 << TIF_BREAKPOINT) \
- | (1 << TIF_RESTORE_SIGMASK))
+ | _TIF_NEED_RESCHED \
+ | _TIF_BREAKPOINT)
/* work to do on any return to userspace */
-#define _TIF_ALLWORK_MASK (_TIF_WORK_MASK | (1 << TIF_SYSCALL_TRACE) | \
- _TIF_NOTIFY_RESUME)
+#define _TIF_ALLWORK_MASK (_TIF_WORK_MASK | _TIF_SYSCALL_TRACE)
/* work to do on return from debug mode */
-#define _TIF_DBGWORK_MASK (_TIF_WORK_MASK & ~(1 << TIF_BREAKPOINT))
+#define _TIF_DBGWORK_MASK (_TIF_WORK_MASK & ~_TIF_BREAKPOINT)
#endif /* __ASM_AVR32_THREAD_INFO_H */
diff --git a/arch/avr32/kernel/signal.c b/arch/avr32/kernel/signal.c
index d552a85..5e01c3a 100644
--- a/arch/avr32/kernel/signal.c
+++ b/arch/avr32/kernel/signal.c
@@ -15,7 +15,6 @@
#include <linux/errno.h>
#include <linux/ptrace.h>
#include <linux/unistd.h>
-#include <linux/freezer.h>
#include <linux/tracehook.h>
#include <asm/uaccess.h>
diff --git a/arch/avr32/mach-at32ap/at32ap700x.c b/arch/avr32/mach-at32ap/at32ap700x.c
index 0445c4f..b323d8d 100644
--- a/arch/avr32/mach-at32ap/at32ap700x.c
+++ b/arch/avr32/mach-at32ap/at32ap700x.c
@@ -605,6 +605,9 @@ static void __init genclk_init_parent(struct clk *clk)
static struct dw_dma_platform_data dw_dmac0_data = {
.nr_channels = 3,
+ .block_size = 4095U,
+ .nr_masters = 2,
+ .data_width = { 2, 2, 0, 0 },
};
static struct resource dw_dmac0_resource[] = {
diff --git a/arch/blackfin/configs/BF561-ACVILON_defconfig b/arch/blackfin/configs/BF561-ACVILON_defconfig
index 0fdc4ec..9198837 100644
--- a/arch/blackfin/configs/BF561-ACVILON_defconfig
+++ b/arch/blackfin/configs/BF561-ACVILON_defconfig
@@ -57,7 +57,6 @@ CONFIG_MTD_PLATRAM=y
CONFIG_MTD_PHRAM=y
CONFIG_MTD_BLOCK2MTD=y
CONFIG_MTD_NAND=y
-CONFIG_MTD_NAND_VERIFY_WRITE=y
CONFIG_MTD_NAND_PLATFORM=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_RAM=y
diff --git a/arch/blackfin/include/asm/thread_info.h b/arch/blackfin/include/asm/thread_info.h
index 53ad100..3894005 100644
--- a/arch/blackfin/include/asm/thread_info.h
+++ b/arch/blackfin/include/asm/thread_info.h
@@ -96,8 +96,6 @@ static inline struct thread_info *current_thread_info(void)
#define TIF_SYSCALL_TRACE 0 /* syscall trace active */
#define TIF_SIGPENDING 1 /* signal pending */
#define TIF_NEED_RESCHED 2 /* rescheduling necessary */
-#define TIF_POLLING_NRFLAG 3 /* true if poll_idle() is polling
- TIF_NEED_RESCHED */
#define TIF_MEMDIE 4 /* is terminating due to OOM killer */
#define TIF_RESTORE_SIGMASK 5 /* restore signal mask in do_signal() */
#define TIF_IRQ_SYNC 7 /* sync pipeline stage */
@@ -108,8 +106,6 @@ static inline struct thread_info *current_thread_info(void)
#define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE)
#define _TIF_SIGPENDING (1<<TIF_SIGPENDING)
#define _TIF_NEED_RESCHED (1<<TIF_NEED_RESCHED)
-#define _TIF_POLLING_NRFLAG (1<<TIF_POLLING_NRFLAG)
-#define _TIF_RESTORE_SIGMASK (1<<TIF_RESTORE_SIGMASK)
#define _TIF_IRQ_SYNC (1<<TIF_IRQ_SYNC)
#define _TIF_NOTIFY_RESUME (1<<TIF_NOTIFY_RESUME)
#define _TIF_SINGLESTEP (1<<TIF_SINGLESTEP)
diff --git a/arch/blackfin/kernel/signal.c b/arch/blackfin/kernel/signal.c
index 6682b73..6ed20a1 100644
--- a/arch/blackfin/kernel/signal.c
+++ b/arch/blackfin/kernel/signal.c
@@ -10,7 +10,6 @@
#include <linux/tty.h>
#include <linux/personality.h>
#include <linux/binfmts.h>
-#include <linux/freezer.h>
#include <linux/uaccess.h>
#include <linux/tracehook.h>
diff --git a/arch/c6x/Kconfig b/arch/c6x/Kconfig
index 983c859..45268b5 100644
--- a/arch/c6x/Kconfig
+++ b/arch/c6x/Kconfig
@@ -17,6 +17,7 @@ config C6X
select OF
select OF_EARLY_FLATTREE
select GENERIC_CLOCKEVENTS
+ select GENERIC_KERNEL_THREAD
config MMU
def_bool n
diff --git a/arch/c6x/include/asm/Kbuild b/arch/c6x/include/asm/Kbuild
index 277f1a4..4e4e98d 100644
--- a/arch/c6x/include/asm/Kbuild
+++ b/arch/c6x/include/asm/Kbuild
@@ -12,6 +12,7 @@ generic-y += div64.h
generic-y += dma.h
generic-y += emergency-restart.h
generic-y += errno.h
+generic-y += exec.h
generic-y += fb.h
generic-y += fcntl.h
generic-y += futex.h
diff --git a/arch/c6x/include/asm/exec.h b/arch/c6x/include/asm/exec.h
deleted file mode 100644
index 0fea482..0000000
--- a/arch/c6x/include/asm/exec.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _ASM_C6X_EXEC_H
-#define _ASM_C6X_EXEC_H
-
-#define arch_align_stack(x) (x)
-
-#endif /* _ASM_C6X_EXEC_H */
diff --git a/arch/c6x/include/asm/processor.h b/arch/c6x/include/asm/processor.h
index c50af7e..b9eb3da 100644
--- a/arch/c6x/include/asm/processor.h
+++ b/arch/c6x/include/asm/processor.h
@@ -92,8 +92,6 @@ static inline void release_thread(struct task_struct *dead_task)
{
}
-extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
-
#define copy_segments(tsk, mm) do { } while (0)
#define release_segments(mm) do { } while (0)
diff --git a/arch/c6x/include/asm/syscalls.h b/arch/c6x/include/asm/syscalls.h
index aed53da..e7b8991 100644
--- a/arch/c6x/include/asm/syscalls.h
+++ b/arch/c6x/include/asm/syscalls.h
@@ -44,11 +44,6 @@ extern int sys_cache_sync(unsigned long s, unsigned long e);
struct pt_regs;
extern asmlinkage long sys_c6x_clone(struct pt_regs *regs);
-extern asmlinkage long sys_c6x_execve(const char __user *name,
- const char __user *const __user *argv,
- const char __user *const __user *envp,
- struct pt_regs *regs);
-
#include <asm-generic/syscalls.h>
diff --git a/arch/c6x/include/asm/thread_info.h b/arch/c6x/include/asm/thread_info.h
index 1710bcb..4c8dc56 100644
--- a/arch/c6x/include/asm/thread_info.h
+++ b/arch/c6x/include/asm/thread_info.h
@@ -97,7 +97,6 @@ struct thread_info *current_thread_info(void)
#define TIF_NEED_RESCHED 3 /* rescheduling necessary */
#define TIF_RESTORE_SIGMASK 4 /* restore signal mask in do_signal() */
-#define TIF_POLLING_NRFLAG 16 /* true if polling TIF_NEED_RESCHED */
#define TIF_MEMDIE 17 /* OOM killer killed process */
#define TIF_WORK_MASK 0x00007FFE /* work on irq/exception return */
diff --git a/arch/c6x/include/asm/unistd.h b/arch/c6x/include/asm/unistd.h
index ed22590..4ff747d 100644
--- a/arch/c6x/include/asm/unistd.h
+++ b/arch/c6x/include/asm/unistd.h
@@ -14,6 +14,9 @@
* more details.
*/
+#define __ARCH_WANT_KERNEL_EXECVE
+#define __ARCH_WANT_SYS_EXECVE
+
/* Use the standard ABI for syscalls. */
#include <asm-generic/unistd.h>
diff --git a/arch/c6x/kernel/asm-offsets.c b/arch/c6x/kernel/asm-offsets.c
index 759ad6d..60f1e43 100644
--- a/arch/c6x/kernel/asm-offsets.c
+++ b/arch/c6x/kernel/asm-offsets.c
@@ -116,7 +116,6 @@ void foo(void)
DEFINE(_TIF_NOTIFY_RESUME, (1<<TIF_NOTIFY_RESUME));
DEFINE(_TIF_SIGPENDING, (1<<TIF_SIGPENDING));
DEFINE(_TIF_NEED_RESCHED, (1<<TIF_NEED_RESCHED));
- DEFINE(_TIF_POLLING_NRFLAG, (1<<TIF_POLLING_NRFLAG));
DEFINE(_TIF_ALLWORK_MASK, TIF_ALLWORK_MASK);
DEFINE(_TIF_WORK_MASK, TIF_WORK_MASK);
diff --git a/arch/c6x/kernel/entry.S b/arch/c6x/kernel/entry.S
index 30b37e5..5449c36 100644
--- a/arch/c6x/kernel/entry.S
+++ b/arch/c6x/kernel/entry.S
@@ -400,6 +400,32 @@ ret_from_fork_2:
STW .D2T2 B0,*+SP(REGS_A4+8)
ENDPROC(ret_from_fork)
+ENTRY(ret_from_kernel_thread)
+#ifdef CONFIG_C6X_BIG_KERNEL
+ MVKL .S1 schedule_tail,A0
+ MVKH .S1 schedule_tail,A0
+ B .S2X A0
+#else
+ B .S2 schedule_tail
+#endif
+ LDW .D2T2 *+SP(REGS_A0+8),B10 /* get fn */
+ ADDKPC .S2 0f,B3,3
+0:
+ B .S2 B10 /* call fn */
+ LDW .D2T1 *+SP(REGS_A1+8),A4 /* get arg */
+ MVKL .S2 sys_exit,B11
+ MVKH .S2 sys_exit,B11
+ ADDKPC .S2 0f,B3,1
+0:
+ BNOP .S2 B11,5 /* jump to sys_exit */
+ENDPROC(ret_from_kernel_thread)
+
+ENTRY(ret_from_kernel_execve)
+ GET_THREAD_INFO A12
+ BNOP .S2 syscall_exit,4
+ ADD .D2X A4,-8,SP
+ENDPROC(ret_from_kernel_execve)
+
;;
;; These are the interrupt handlers, responsible for calling __do_IRQ()
;; int6 is used for syscalls (see _system_call entry)
@@ -593,13 +619,6 @@ ENTRY(sys_sigaltstack)
NOP 4
ENDPROC(sys_sigaltstack)
- ;; kernel_execve
-ENTRY(kernel_execve)
- MVK .S2 __NR_execve,B0
- SWE
- BNOP .S2 B3,5
-ENDPROC(kernel_execve)
-
;;
;; Special system calls
;; return address is in B3
@@ -628,29 +647,6 @@ ENTRY(sys_rt_sigreturn)
#endif
ENDPROC(sys_rt_sigreturn)
-ENTRY(sys_execve)
- ADDAW .D2 SP,2,B6 ; put regs addr in 4th parameter
- ; & adjust regs stack addr
- LDW .D2T2 *+SP(REGS_B4+8),B4
-
- ;; c6x_execve(char *name, char **argv,
- ;; char **envp, struct pt_regs *regs)
-#ifdef CONFIG_C6X_BIG_KERNEL
- || MVKL .S1 sys_c6x_execve,A0
- MVKH .S1 sys_c6x_execve,A0
- B .S2X A0
-#else
- || B .S2 sys_c6x_execve
-#endif
- STW .D2T2 B3,*SP--[2]
- ADDKPC .S2 ret_from_c6x_execve,B3,3
-
-ret_from_c6x_execve:
- LDW .D2T2 *++SP[2],B3
- NOP 4
- BNOP .S2 B3,5
-ENDPROC(sys_execve)
-
ENTRY(sys_pread_c6x)
MV .D2X A8,B7
#ifdef CONFIG_C6X_BIG_KERNEL
diff --git a/arch/c6x/kernel/process.c b/arch/c6x/kernel/process.c
index 45e924a..2770d9a 100644
--- a/arch/c6x/kernel/process.c
+++ b/arch/c6x/kernel/process.c
@@ -25,6 +25,7 @@ void (*c6x_restart)(void);
void (*c6x_halt)(void);
extern asmlinkage void ret_from_fork(void);
+extern asmlinkage void ret_from_kernel_thread(void);
/*
* power off function, if any
@@ -103,37 +104,6 @@ void machine_power_off(void)
halt_loop();
}
-static void kernel_thread_helper(int dummy, void *arg, int (*fn)(void *))
-{
- do_exit(fn(arg));
-}
-
-/*
- * Create a kernel thread
- */
-int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
-{
- struct pt_regs regs;
-
- /*
- * copy_thread sets a4 to zero (child return from fork)
- * so we can't just set things up to directly return to
- * fn.
- */
- memset(&regs, 0, sizeof(regs));
- regs.b4 = (unsigned long) arg;
- regs.a6 = (unsigned long) fn;
- regs.pc = (unsigned long) kernel_thread_helper;
- local_save_flags(regs.csr);
- regs.csr |= 1;
- regs.tsr = 5; /* Set GEE and GIE in TSR */
-
- /* Ok, create the new process.. */
- return do_fork(flags | CLONE_VM | CLONE_UNTRACED, -1, &regs,
- 0, NULL, NULL);
-}
-EXPORT_SYMBOL(kernel_thread);
-
void flush_thread(void)
{
}
@@ -191,22 +161,24 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
childregs = task_pt_regs(p);
- *childregs = *regs;
- childregs->a4 = 0;
-
- if (usp == -1)
+ if (!regs) {
/* case of __kernel_thread: we return to supervisor space */
+ memset(childregs, 0, sizeof(struct pt_regs));
childregs->sp = (unsigned long)(childregs + 1);
- else
+ p->thread.pc = (unsigned long) ret_from_kernel_thread;
+ childregs->a0 = usp; /* function */
+ childregs->a1 = ustk_size; /* argument */
+ } else {
/* Otherwise use the given stack */
+ *childregs = *regs;
childregs->sp = usp;
+ p->thread.pc = (unsigned long) ret_from_fork;
+ }
/* Set usp/ksp */
p->thread.usp = childregs->sp;
- /* switch_to uses stack to save/restore 14 callee-saved regs */
thread_saved_ksp(p) = (unsigned long)childregs - 8;
- p->thread.pc = (unsigned int) ret_from_fork;
- p->thread.wchan = (unsigned long) ret_from_fork;
+ p->thread.wchan = p->thread.pc;
#ifdef __DSBT__
{
unsigned long dp;
@@ -221,28 +193,6 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
return 0;
}
-/*
- * c6x_execve() executes a new program.
- */
-SYSCALL_DEFINE4(c6x_execve, const char __user *, name,
- const char __user *const __user *, argv,
- const char __user *const __user *, envp,
- struct pt_regs *, regs)
-{
- int error;
- char *filename;
-
- filename = getname(name);
- error = PTR_ERR(filename);
- if (IS_ERR(filename))
- goto out;
-
- error = do_execve(filename, argv, envp, regs);
- putname(filename);
-out:
- return error;
-}
-
unsigned long get_wchan(struct task_struct *p)
{
return p->thread.wchan;
diff --git a/arch/cris/include/asm/Kbuild b/arch/cris/include/asm/Kbuild
index a8eab26..ff1bf7f 100644
--- a/arch/cris/include/asm/Kbuild
+++ b/arch/cris/include/asm/Kbuild
@@ -9,3 +9,4 @@ header-y += rs485.h
header-y += sync_serial.h
generic-y += clkdev.h
+generic-y += exec.h
diff --git a/arch/cris/include/asm/exec.h b/arch/cris/include/asm/exec.h
deleted file mode 100644
index 9665dab..0000000
--- a/arch/cris/include/asm/exec.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __ASM_CRIS_EXEC_H
-#define __ASM_CRIS_EXEC_H
-
-#define arch_align_stack(x) (x)
-
-#endif /* __ASM_CRIS_EXEC_H */
diff --git a/arch/cris/include/asm/thread_info.h b/arch/cris/include/asm/thread_info.h
index 5b1c448..07c8c40 100644
--- a/arch/cris/include/asm/thread_info.h
+++ b/arch/cris/include/asm/thread_info.h
@@ -78,15 +78,12 @@ struct thread_info {
#define TIF_SIGPENDING 2 /* signal pending */
#define TIF_NEED_RESCHED 3 /* rescheduling necessary */
#define TIF_RESTORE_SIGMASK 9 /* restore signal mask in do_signal() */
-#define TIF_POLLING_NRFLAG 16 /* true if poll_idle() is polling TIF_NEED_RESCHED */
#define TIF_MEMDIE 17 /* is terminating due to OOM killer */
#define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE)
#define _TIF_NOTIFY_RESUME (1<<TIF_NOTIFY_RESUME)
#define _TIF_SIGPENDING (1<<TIF_SIGPENDING)
#define _TIF_NEED_RESCHED (1<<TIF_NEED_RESCHED)
-#define _TIF_RESTORE_SIGMASK (1<<TIF_RESTORE_SIGMASK)
-#define _TIF_POLLING_NRFLAG (1<<TIF_POLLING_NRFLAG)
#define _TIF_WORK_MASK 0x0000FFFE /* work to do on interrupt/exception return */
#define _TIF_ALLWORK_MASK 0x0000FFFF /* work to do on any return to u-space */
diff --git a/arch/frv/Kconfig b/arch/frv/Kconfig
index 9d26264..b741250 100644
--- a/arch/frv/Kconfig
+++ b/arch/frv/Kconfig
@@ -12,6 +12,7 @@ config FRV
select ARCH_HAVE_NMI_SAFE_CMPXCHG
select GENERIC_CPU_DEVICES
select ARCH_WANT_IPC_PARSE_VERSION
+ select GENERIC_KERNEL_THREAD
config ZONE_DMA
bool
diff --git a/arch/frv/include/asm/Kbuild b/arch/frv/include/asm/Kbuild
index 13cd044..251bd71 100644
--- a/arch/frv/include/asm/Kbuild
+++ b/arch/frv/include/asm/Kbuild
@@ -3,3 +3,4 @@ include include/asm-generic/Kbuild.asm
header-y += registers.h
header-y += termios.h
generic-y += clkdev.h
+generic-y += exec.h
diff --git a/arch/frv/include/asm/exec.h b/arch/frv/include/asm/exec.h
deleted file mode 100644
index 65c9130..0000000
--- a/arch/frv/include/asm/exec.h
+++ /dev/null
@@ -1,17 +0,0 @@
-/* FR-V CPU executable handling
- *
- * Copyright (C) 2003 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_EXEC_H
-#define _ASM_EXEC_H
-
-#define arch_align_stack(x) (x)
-
-#endif /* _ASM_EXEC_H */
diff --git a/arch/frv/include/asm/processor.h b/arch/frv/include/asm/processor.h
index dccb9d1..a34f309 100644
--- a/arch/frv/include/asm/processor.h
+++ b/arch/frv/include/asm/processor.h
@@ -92,14 +92,12 @@ extern struct task_struct *__kernel_current_task;
/*
* do necessary setup to start up a newly executed thread.
- * - need to discard the frame stacked by init() invoking the execve syscall
*/
#define start_thread(_regs, _pc, _usp) \
do { \
- __frame = __kernel_frame0_ptr; \
- __frame->pc = (_pc); \
- __frame->psr &= ~PSR_S; \
- __frame->sp = (_usp); \
+ _regs->pc = (_pc); \
+ _regs->psr &= ~PSR_S; \
+ _regs->sp = (_usp); \
} while(0)
/* Free all resources held by a thread. */
@@ -107,7 +105,6 @@ static inline void release_thread(struct task_struct *dead_task)
{
}
-extern asmlinkage int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
extern asmlinkage void save_user_regs(struct user_context *target);
extern asmlinkage void *restore_user_regs(const struct user_context *target, ...);
diff --git a/arch/frv/include/asm/ptrace.h b/arch/frv/include/asm/ptrace.h
index ef6635c..bd534b2 100644
--- a/arch/frv/include/asm/ptrace.h
+++ b/arch/frv/include/asm/ptrace.h
@@ -76,6 +76,7 @@ register struct pt_regs *__frame asm("gr28");
#define user_mode(regs) (!((regs)->psr & PSR_S))
#define instruction_pointer(regs) ((regs)->pc)
#define user_stack_pointer(regs) ((regs)->sp)
+#define current_pt_regs() (__frame)
extern unsigned long user_stack(const struct pt_regs *);
#define profile_pc(regs) ((regs)->pc)
diff --git a/arch/frv/include/asm/thread_info.h b/arch/frv/include/asm/thread_info.h
index 0ff03a3..bebd7ea 100644
--- a/arch/frv/include/asm/thread_info.h
+++ b/arch/frv/include/asm/thread_info.h
@@ -94,7 +94,6 @@ register struct thread_info *__current_thread_info asm("gr15");
#define TIF_NEED_RESCHED 3 /* rescheduling necessary */
#define TIF_SINGLESTEP 4 /* restore singlestep on return to user mode */
#define TIF_RESTORE_SIGMASK 5 /* restore signal mask in do_signal() */
-#define TIF_POLLING_NRFLAG 6 /* true if poll_idle() is polling TIF_NEED_RESCHED */
#define TIF_MEMDIE 7 /* is terminating due to OOM killer */
#define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE)
@@ -102,8 +101,6 @@ register struct thread_info *__current_thread_info asm("gr15");
#define _TIF_SIGPENDING (1 << TIF_SIGPENDING)
#define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED)
#define _TIF_SINGLESTEP (1 << TIF_SINGLESTEP)
-#define _TIF_RESTORE_SIGMASK (1 << TIF_RESTORE_SIGMASK)
-#define _TIF_POLLING_NRFLAG (1 << TIF_POLLING_NRFLAG)
/* work to do on interrupt/exception return */
#define _TIF_WORK_MASK \
diff --git a/arch/frv/include/asm/unistd.h b/arch/frv/include/asm/unistd.h
index 67f23a3..b6b07e5 100644
--- a/arch/frv/include/asm/unistd.h
+++ b/arch/frv/include/asm/unistd.h
@@ -372,6 +372,8 @@
#define __ARCH_WANT_SYS_SIGPROCMASK
#define __ARCH_WANT_SYS_RT_SIGACTION
#define __ARCH_WANT_SYS_RT_SIGSUSPEND
+#define __ARCH_WANT_SYS_EXECVE
+#define __ARCH_WANT_KERNEL_EXECVE
/*
* "Conditional" syscalls
diff --git a/arch/frv/kernel/Makefile b/arch/frv/kernel/Makefile
index ad4087b..3cbb329 100644
--- a/arch/frv/kernel/Makefile
+++ b/arch/frv/kernel/Makefile
@@ -7,8 +7,8 @@ heads-$(CONFIG_MMU) := head-mmu-fr451.o
extra-y:= head.o vmlinux.lds
-obj-y := $(heads-y) entry.o entry-table.o break.o switch_to.o kernel_thread.o \
- kernel_execve.o process.o traps.o ptrace.o signal.o dma.o \
+obj-y := $(heads-y) entry.o entry-table.o break.o switch_to.o \
+ process.o traps.o ptrace.o signal.o dma.o \
sys_frv.o time.o setup.o frv_ksyms.o \
debug-stub.o irq.o sleep.o uaccess.o
diff --git a/arch/frv/kernel/entry.S b/arch/frv/kernel/entry.S
index 7d5e000..0027329 100644
--- a/arch/frv/kernel/entry.S
+++ b/arch/frv/kernel/entry.S
@@ -863,6 +863,19 @@ ret_from_fork:
setlos.p #0,gr8
bra __syscall_exit
+ .globl ret_from_kernel_thread
+ret_from_kernel_thread:
+ lddi.p @(gr28,#REG_GR(8)),gr20
+ call schedule_tail
+ or.p gr20,gr20,gr8
+ calll @(gr21,gr0)
+ bra sys_exit
+
+ .globl ret_from_kernel_execve
+ret_from_kernel_execve:
+ ori gr28,0,sp
+ bra __syscall_exit
+
###################################################################################################
#
# Return to user mode is not as complex as all this looks,
diff --git a/arch/frv/kernel/frv_ksyms.c b/arch/frv/kernel/frv_ksyms.c
index a89803b..86c516d 100644
--- a/arch/frv/kernel/frv_ksyms.c
+++ b/arch/frv/kernel/frv_ksyms.c
@@ -30,7 +30,6 @@ EXPORT_SYMBOL(ip_fast_csum);
EXPORT_SYMBOL(local_irq_count);
EXPORT_SYMBOL(local_bh_count);
#endif
-EXPORT_SYMBOL(kernel_thread);
EXPORT_SYMBOL(__res_bus_clock_speed_HZ);
EXPORT_SYMBOL(__page_offset);
diff --git a/arch/frv/kernel/kernel_execve.S b/arch/frv/kernel/kernel_execve.S
deleted file mode 100644
index 9b074a1..0000000
--- a/arch/frv/kernel/kernel_execve.S
+++ /dev/null
@@ -1,33 +0,0 @@
-/* in-kernel program execution
- *
- * Copyright (C) 2006 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.
- */
-
-#include <linux/linkage.h>
-#include <asm/unistd.h>
-
-###############################################################################
-#
-# 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, char *const argv[], char *const envp[])
-#
-# On entry: GR8/GR9/GR10: arguments to function
-# On return: GR8: syscall return.
-#
-###############################################################################
- .globl kernel_execve
- .type kernel_execve,@function
-kernel_execve:
- setlos __NR_execve,gr7
- tira gr0,#0
- bralr
-
- .size kernel_execve,.-kernel_execve
diff --git a/arch/frv/kernel/kernel_thread.S b/arch/frv/kernel/kernel_thread.S
deleted file mode 100644
index f0e5294..0000000
--- a/arch/frv/kernel/kernel_thread.S
+++ /dev/null
@@ -1,77 +0,0 @@
-/* kernel_thread.S: kernel thread creation
- *
- * Copyright (C) 2003 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.
- */
-
-#include <linux/linkage.h>
-#include <linux/kern_levels.h>
-#include <asm/unistd.h>
-
-#define CLONE_VM 0x00000100 /* set if VM shared between processes */
-
- .section .rodata
-kernel_thread_emsg:
- .asciz KERN_ERR "failed to create kernel thread: error=%d\n"
-
- .text
- .balign 4
-
-###############################################################################
-#
-# Create a kernel thread
-#
-# int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
-#
-###############################################################################
- .globl kernel_thread
- .type kernel_thread,@function
-kernel_thread:
- or.p gr8,gr0,gr4
- or gr9,gr0,gr5
-
- # start by forking the current process, but with shared VM
- setlos.p #__NR_clone,gr7 ; syscall number
- ori gr10,#CLONE_VM,gr8 ; first syscall arg [clone_flags]
- sethi.p #0xe4e4,gr9 ; second syscall arg [newsp]
- setlo #0xe4e4,gr9
- setlos.p #0,gr10 ; third syscall arg [parent_tidptr]
- setlos #0,gr11 ; fourth syscall arg [child_tidptr]
- tira gr0,#0
- setlos.p #4095,gr7
- andcc gr8,gr8,gr0,icc0
- addcc.p gr8,gr7,gr0,icc1
- bnelr icc0,#2
- bc icc1,#0,kernel_thread_error
-
- # now invoke the work function
- or gr5,gr0,gr8
- calll @(gr4,gr0)
-
- # and finally exit the thread
- setlos #__NR_exit,gr7 ; syscall number
- tira gr0,#0
-
-kernel_thread_error:
- subi sp,#8,sp
- movsg lr,gr4
- sti gr8,@(sp,#0)
- sti.p gr4,@(sp,#4)
-
- or gr8,gr0,gr9
- sethi.p %hi(kernel_thread_emsg),gr8
- setlo %lo(kernel_thread_emsg),gr8
-
- call printk
-
- ldi @(sp,#4),gr4
- ldi @(sp,#0),gr8
- subi sp,#8,sp
- jmpl @(gr4,gr0)
-
- .size kernel_thread,.-kernel_thread
diff --git a/arch/frv/kernel/process.c b/arch/frv/kernel/process.c
index 2eb7fa5..655d90d 100644
--- a/arch/frv/kernel/process.c
+++ b/arch/frv/kernel/process.c
@@ -38,6 +38,7 @@
#include "local.h"
asmlinkage void ret_from_fork(void);
+asmlinkage void ret_from_kernel_thread(void);
#include <asm/pgalloc.h>
@@ -172,32 +173,13 @@ asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp,
* set up the kernel stack and exception frames for a new process
*/
int copy_thread(unsigned long clone_flags,
- unsigned long usp, unsigned long topstk,
+ unsigned long usp, unsigned long arg,
struct task_struct *p, struct pt_regs *regs)
{
- struct pt_regs *childregs0, *childregs, *regs0;
+ struct pt_regs *childregs;
- regs0 = __kernel_frame0_ptr;
- childregs0 = (struct pt_regs *)
+ childregs = (struct pt_regs *)
(task_stack_page(p) + THREAD_SIZE - FRV_FRAME0_SIZE);
- childregs = childregs0;
-
- /* set up the userspace frame (the only place that the USP is stored) */
- *childregs0 = *regs0;
-
- childregs0->gr8 = 0;
- childregs0->sp = usp;
- childregs0->next_frame = NULL;
-
- /* set up the return kernel frame if called from kernel_thread() */
- if (regs != regs0) {
- childregs--;
- *childregs = *regs;
- childregs->sp = (unsigned long) childregs0;
- childregs->next_frame = childregs0;
- childregs->gr15 = (unsigned long) task_thread_info(p);
- childregs->gr29 = (unsigned long) p;
- }
p->set_child_tid = p->clear_child_tid = NULL;
@@ -206,8 +188,25 @@ int copy_thread(unsigned long clone_flags,
p->thread.sp = (unsigned long) childregs;
p->thread.fp = 0;
p->thread.lr = 0;
- p->thread.pc = (unsigned long) ret_from_fork;
- p->thread.frame0 = childregs0;
+ p->thread.frame0 = childregs;
+
+ if (unlikely(!regs)) {
+ memset(childregs, 0, sizeof(struct pt_regs));
+ childregs->gr9 = usp; /* function */
+ childregs->gr8 = arg;
+ chilregs->psr = PSR_S;
+ p->thread.pc = (unsigned long) ret_from_kernel_thread;
+ save_user_regs(p->thread.user);
+ return 0;
+ }
+
+ /* set up the userspace frame (the only place that the USP is stored) */
+ *childregs = *regs;
+
+ childregs->sp = usp;
+ childregs->next_frame = NULL;
+
+ p->thread.pc = (unsigned long) ret_from_fork;
/* the new TLS pointer is passed in as arg #5 to sys_clone() */
if (clone_flags & CLONE_SETTLS)
@@ -218,25 +217,6 @@ int copy_thread(unsigned long clone_flags,
return 0;
} /* end copy_thread() */
-/*
- * sys_execve() executes a new program.
- */
-asmlinkage int sys_execve(const char __user *name,
- const char __user *const __user *argv,
- const char __user *const __user *envp)
-{
- int error;
- char * filename;
-
- filename = getname(name);
- error = PTR_ERR(filename);
- if (IS_ERR(filename))
- return error;
- error = do_execve(filename, argv, envp, __frame);
- putname(filename);
- return error;
-}
-
unsigned long get_wchan(struct task_struct *p)
{
struct pt_regs *regs0;
diff --git a/arch/frv/kernel/signal.c b/arch/frv/kernel/signal.c
index 864c2f0..535810a 100644
--- a/arch/frv/kernel/signal.c
+++ b/arch/frv/kernel/signal.c
@@ -20,7 +20,6 @@
#include <linux/ptrace.h>
#include <linux/unistd.h>
#include <linux/personality.h>
-#include <linux/freezer.h>
#include <linux/tracehook.h>
#include <asm/ucontext.h>
#include <asm/uaccess.h>
@@ -298,10 +297,6 @@ static int setup_frame(int sig, struct k_sigaction *ka, sigset_t *set)
__frame->lr = (unsigned long) &frame->retcode;
__frame->gr8 = sig;
- /* the tracer may want to single-step inside the handler */
- if (test_thread_flag(TIF_SINGLESTEP))
- ptrace_notify(SIGTRAP);
-
#if DEBUG_SIG
printk("SIG deliver %d (%s:%d): sp=%p pc=%lx ra=%p\n",
sig, current->comm, current->pid, frame, __frame->pc,
@@ -400,10 +395,6 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
__frame->gr8 = sig;
__frame->gr9 = (unsigned long) &frame->info;
- /* the tracer may want to single-step inside the handler */
- if (test_thread_flag(TIF_SINGLESTEP))
- ptrace_notify(SIGTRAP);
-
#if DEBUG_SIG
printk("SIG deliver %d (%s:%d): sp=%p pc=%lx ra=%p\n",
sig, current->comm, current->pid, frame, __frame->pc,
diff --git a/arch/h8300/include/asm/Kbuild b/arch/h8300/include/asm/Kbuild
index 0e152a9..fccd81e 100644
--- a/arch/h8300/include/asm/Kbuild
+++ b/arch/h8300/include/asm/Kbuild
@@ -1,3 +1,4 @@
include include/asm-generic/Kbuild.asm
-generic-y += clkdev.h
+generic-y += clkdev.h
+generic-y += exec.h
diff --git a/arch/h8300/include/asm/exec.h b/arch/h8300/include/asm/exec.h
deleted file mode 100644
index c01c45c..0000000
--- a/arch/h8300/include/asm/exec.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _H8300_EXEC_H
-#define _H8300_EXEC_H
-
-#define arch_align_stack(x) (x)
-
-#endif /* _H8300_EXEC_H */
diff --git a/arch/h8300/include/asm/thread_info.h b/arch/h8300/include/asm/thread_info.h
index 9c126e0..ec2f777 100644
--- a/arch/h8300/include/asm/thread_info.h
+++ b/arch/h8300/include/asm/thread_info.h
@@ -85,8 +85,6 @@ static inline struct thread_info *current_thread_info(void)
#define TIF_SYSCALL_TRACE 0 /* syscall trace active */
#define TIF_SIGPENDING 1 /* signal pending */
#define TIF_NEED_RESCHED 2 /* rescheduling necessary */
-#define TIF_POLLING_NRFLAG 3 /* true if poll_idle() is polling
- TIF_NEED_RESCHED */
#define TIF_MEMDIE 4 /* is terminating due to OOM killer */
#define TIF_RESTORE_SIGMASK 5 /* restore signal mask in do_signal() */
#define TIF_NOTIFY_RESUME 6 /* callback before returning to user */
@@ -95,11 +93,10 @@ static inline struct thread_info *current_thread_info(void)
#define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE)
#define _TIF_SIGPENDING (1<<TIF_SIGPENDING)
#define _TIF_NEED_RESCHED (1<<TIF_NEED_RESCHED)
-#define _TIF_POLLING_NRFLAG (1<<TIF_POLLING_NRFLAG)
-#define _TIF_RESTORE_SIGMASK (1<<TIF_RESTORE_SIGMASK)
#define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME)
-#define _TIF_WORK_MASK 0x0000FFFE /* work to do on interrupt/exception return */
+#define _TIF_WORK_MASK (_TIF_SIGPENDING | _TIF_NEED_RESCHED | \
+ _TIF_NOTIFY_RESUME)
#endif /* __KERNEL__ */
diff --git a/arch/h8300/kernel/signal.c b/arch/h8300/kernel/signal.c
index 5adaada..0e81b96 100644
--- a/arch/h8300/kernel/signal.c
+++ b/arch/h8300/kernel/signal.c
@@ -38,7 +38,6 @@
#include <linux/personality.h>
#include <linux/tty.h>
#include <linux/binfmts.h>
-#include <linux/freezer.h>
#include <linux/tracehook.h>
#include <asm/setup.h>
diff --git a/arch/hexagon/include/asm/thread_info.h b/arch/hexagon/include/asm/thread_info.h
index 4f936a7..e4a0aad 100644
--- a/arch/hexagon/include/asm/thread_info.h
+++ b/arch/hexagon/include/asm/thread_info.h
@@ -120,10 +120,8 @@ register struct thread_info *__current_thread_info asm(QUOTED_THREADINFO_REG);
#define TIF_SIGPENDING 2 /* signal pending */
#define TIF_NEED_RESCHED 3 /* rescheduling necessary */
#define TIF_SINGLESTEP 4 /* restore ss @ return to usr mode */
-#define TIF_IRET 5 /* return with iret */
#define TIF_RESTORE_SIGMASK 6 /* restore sig mask in do_signal() */
/* true if poll_idle() is polling TIF_NEED_RESCHED */
-#define TIF_POLLING_NRFLAG 16
#define TIF_MEMDIE 17 /* OOM killer killed process */
#define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE)
@@ -131,9 +129,6 @@ register struct thread_info *__current_thread_info asm(QUOTED_THREADINFO_REG);
#define _TIF_SIGPENDING (1 << TIF_SIGPENDING)
#define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED)
#define _TIF_SINGLESTEP (1 << TIF_SINGLESTEP)
-#define _TIF_IRET (1 << TIF_IRET)
-#define _TIF_RESTORE_SIGMASK (1 << TIF_RESTORE_SIGMASK)
-#define _TIF_POLLING_NRFLAG (1 << TIF_POLLING_NRFLAG)
/* work to do on interrupt/exception return - All but TIF_SYSCALL_TRACE */
#define _TIF_WORK_MASK (0x0000FFFF & ~_TIF_SYSCALL_TRACE)
diff --git a/arch/hexagon/kernel/signal.c b/arch/hexagon/kernel/signal.c
index 304b0808..1ea16be 100644
--- a/arch/hexagon/kernel/signal.c
+++ b/arch/hexagon/kernel/signal.c
@@ -20,7 +20,6 @@
#include <linux/linkage.h>
#include <linux/syscalls.h>
-#include <linux/freezer.h>
#include <linux/tracehook.h>
#include <asm/registers.h>
#include <asm/thread_info.h>
diff --git a/arch/hexagon/kernel/syscall.c b/arch/hexagon/kernel/syscall.c
index 620dd18..553cd60 100644
--- a/arch/hexagon/kernel/syscall.c
+++ b/arch/hexagon/kernel/syscall.c
@@ -87,4 +87,3 @@ int kernel_execve(const char *filename,
return retval;
}
-EXPORT_SYMBOL(kernel_execve);
diff --git a/arch/ia64/include/asm/Kbuild b/arch/ia64/include/asm/Kbuild
index 58f3d14..562f593 100644
--- a/arch/ia64/include/asm/Kbuild
+++ b/arch/ia64/include/asm/Kbuild
@@ -14,3 +14,4 @@ header-y += rse.h
header-y += ucontext.h
header-y += ustack.h
generic-y += clkdev.h
+generic-y += exec.h
diff --git a/arch/ia64/include/asm/exec.h b/arch/ia64/include/asm/exec.h
deleted file mode 100644
index b262424..0000000
--- a/arch/ia64/include/asm/exec.h
+++ /dev/null
@@ -1,14 +0,0 @@
-/*
- * Process execution defines.
- *
- * Copyright (C) 1998-2003 Hewlett-Packard Co
- * David Mosberger-Tang <davidm@hpl.hp.com>
- * Copyright (C) 1999 Asit Mallick <asit.k.mallick@intel.com>
- * Copyright (C) 1999 Don Dugger <don.dugger@intel.com>
- */
-#ifndef _ASM_IA64_EXEC_H
-#define _ASM_IA64_EXEC_H
-
-#define arch_align_stack(x) (x)
-
-#endif /* _ASM_IA64_EXEC_H */
diff --git a/arch/ia64/include/asm/thread_info.h b/arch/ia64/include/asm/thread_info.h
index f7ee853..ff2ae41 100644
--- a/arch/ia64/include/asm/thread_info.h
+++ b/arch/ia64/include/asm/thread_info.h
@@ -106,7 +106,6 @@ struct thread_info {
#define TIF_SYSCALL_AUDIT 3 /* syscall auditing active */
#define TIF_SINGLESTEP 4 /* restore singlestep on return to user mode */
#define TIF_NOTIFY_RESUME 6 /* resumption notification requested */
-#define TIF_POLLING_NRFLAG 16 /* true if poll_idle() is polling TIF_NEED_RESCHED */
#define TIF_MEMDIE 17 /* is terminating due to OOM killer */
#define TIF_MCA_INIT 18 /* this task is processing MCA or INIT */
#define TIF_DB_DISABLED 19 /* debug trap disabled for fsyscall */
@@ -119,7 +118,6 @@ struct thread_info {
#define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME)
#define _TIF_SIGPENDING (1 << TIF_SIGPENDING)
#define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED)
-#define _TIF_POLLING_NRFLAG (1 << TIF_POLLING_NRFLAG)
#define _TIF_MCA_INIT (1 << TIF_MCA_INIT)
#define _TIF_DB_DISABLED (1 << TIF_DB_DISABLED)
#define _TIF_RESTORE_RSE (1 << TIF_RESTORE_RSE)
diff --git a/arch/ia64/kernel/signal.c b/arch/ia64/kernel/signal.c
index 37dd795..680b737 100644
--- a/arch/ia64/kernel/signal.c
+++ b/arch/ia64/kernel/signal.c
@@ -438,14 +438,6 @@ ia64_do_signal (struct sigscratch *scr, long in_syscall)
long errno = scr->pt.r8;
/*
- * In the ia64_leave_kernel code path, we want the common case to go fast, which
- * is why we may in certain cases get here from kernel mode. Just return without
- * doing anything if so.
- */
- if (!user_mode(&scr->pt))
- return;
-
- /*
* This only loops in the rare cases of handle_signal() failing, in which case we
* need to push through a forced SIGSEGV.
*/
diff --git a/arch/m32r/include/asm/Kbuild b/arch/m32r/include/asm/Kbuild
index 0e152a9..fccd81e 100644
--- a/arch/m32r/include/asm/Kbuild
+++ b/arch/m32r/include/asm/Kbuild
@@ -1,3 +1,4 @@
include include/asm-generic/Kbuild.asm
-generic-y += clkdev.h
+generic-y += clkdev.h
+generic-y += exec.h
diff --git a/arch/m32r/include/asm/exec.h b/arch/m32r/include/asm/exec.h
deleted file mode 100644
index c805dbd..0000000
--- a/arch/m32r/include/asm/exec.h
+++ /dev/null
@@ -1,14 +0,0 @@
-/*
- * 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 Hiroyuki Kondo, Hirokazu Takata, and Hitoshi Yamamoto
- * Copyright (C) 2004, 2006 Hirokazu Takata <takata at linux-m32r.org>
- */
-#ifndef _ASM_M32R_EXEC_H
-#define _ASM_M32R_EXEC_H
-
-#define arch_align_stack(x) (x)
-
-#endif /* _ASM_M32R_EXEC_H */
diff --git a/arch/m32r/include/asm/thread_info.h b/arch/m32r/include/asm/thread_info.h
index c083f60..c074f4c 100644
--- a/arch/m32r/include/asm/thread_info.h
+++ b/arch/m32r/include/asm/thread_info.h
@@ -119,25 +119,20 @@ static inline unsigned int get_thread_fault_code(void)
#define TIF_SIGPENDING 1 /* signal pending */
#define TIF_NEED_RESCHED 2 /* rescheduling necessary */
#define TIF_SINGLESTEP 3 /* restore singlestep on return to user mode */
-#define TIF_IRET 4 /* return with iret */
#define TIF_NOTIFY_RESUME 5 /* callback before returning to user */
#define TIF_RESTORE_SIGMASK 8 /* restore signal mask in do_signal() */
#define TIF_USEDFPU 16 /* FPU was used by this task this quantum (SMP) */
-#define TIF_POLLING_NRFLAG 17 /* true if poll_idle() is polling TIF_NEED_RESCHED */
#define TIF_MEMDIE 18 /* is terminating due to OOM killer */
#define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE)
#define _TIF_SIGPENDING (1<<TIF_SIGPENDING)
#define _TIF_NEED_RESCHED (1<<TIF_NEED_RESCHED)
#define _TIF_SINGLESTEP (1<<TIF_SINGLESTEP)
-#define _TIF_IRET (1<<TIF_IRET)
#define _TIF_NOTIFY_RESUME (1<<TIF_NOTIFY_RESUME)
-#define _TIF_RESTORE_SIGMASK (1<<TIF_RESTORE_SIGMASK)
#define _TIF_USEDFPU (1<<TIF_USEDFPU)
-#define _TIF_POLLING_NRFLAG (1<<TIF_POLLING_NRFLAG)
-#define _TIF_WORK_MASK 0x0000FFFE /* work to do on interrupt/exception return */
-#define _TIF_ALLWORK_MASK 0x0000FFFF /* work to do on any return to u-space */
+#define _TIF_WORK_MASK (_TIF_SIGPENDING | _TIF_NEED_RESCHED | _TIF_NOTIFY_RESUME)
+#define _TIF_ALLWORK_MASK (_TIF_WORK_MASK | _TIF_SYSCALL_TRACE)
/*
* Thread-synchronous status.
diff --git a/arch/m32r/kernel/signal.c b/arch/m32r/kernel/signal.c
index d0f60b9..6e3c26a 100644
--- a/arch/m32r/kernel/signal.c
+++ b/arch/m32r/kernel/signal.c
@@ -20,7 +20,6 @@
#include <linux/unistd.h>
#include <linux/stddef.h>
#include <linux/personality.h>
-#include <linux/freezer.h>
#include <linux/tracehook.h>
#include <asm/cacheflush.h>
#include <asm/ucontext.h>
@@ -366,6 +365,4 @@ void do_notify_resume(struct pt_regs *regs, __u32 thread_info_flags)
clear_thread_flag(TIF_NOTIFY_RESUME);
tracehook_notify_resume(regs);
}
-
- clear_thread_flag(TIF_IRET);
}
diff --git a/arch/m68k/Kconfig b/arch/m68k/Kconfig
index dae1e7e..76fd6e2 100644
--- a/arch/m68k/Kconfig
+++ b/arch/m68k/Kconfig
@@ -15,6 +15,7 @@ config M68K
select FPU if MMU
select ARCH_WANT_IPC_PARSE_VERSION
select ARCH_USES_GETTIMEOFFSET if MMU && !COLDFIRE
+ select GENERIC_KERNEL_THREAD
config RWSEM_GENERIC_SPINLOCK
bool
diff --git a/arch/m68k/include/asm/Kbuild b/arch/m68k/include/asm/Kbuild
index bfe675f..ecb5408 100644
--- a/arch/m68k/include/asm/Kbuild
+++ b/arch/m68k/include/asm/Kbuild
@@ -7,6 +7,7 @@ generic-y += cputime.h
generic-y += device.h
generic-y += emergency-restart.h
generic-y += errno.h
+generic-y += exec.h
generic-y += futex.h
generic-y += ioctl.h
generic-y += ipcbuf.h
diff --git a/arch/m68k/include/asm/exec.h b/arch/m68k/include/asm/exec.h
deleted file mode 100644
index 0499adf..0000000
--- a/arch/m68k/include/asm/exec.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _M68K_EXEC_H
-#define _M68K_EXEC_H
-
-#define arch_align_stack(x) (x)
-
-#endif /* _M68K_EXEC_H */
diff --git a/arch/m68k/include/asm/processor.h b/arch/m68k/include/asm/processor.h
index f17c42a..ae700f4 100644
--- a/arch/m68k/include/asm/processor.h
+++ b/arch/m68k/include/asm/processor.h
@@ -100,6 +100,16 @@ struct thread_struct {
.fs = __KERNEL_DS, \
}
+/*
+ * ColdFire stack format sbould be 0x4 for an aligned usp (will always be
+ * true on thread creation). We need to set this explicitly.
+ */
+#ifdef CONFIG_COLDFIRE
+#define setframeformat(_regs) do { (_regs)->format = 0x4; } while(0)
+#else
+#define setframeformat(_regs) do { } while (0)
+#endif
+
#ifdef CONFIG_MMU
/*
* Do necessary setup to start up a newly executed thread.
@@ -109,6 +119,7 @@ static inline void start_thread(struct pt_regs * regs, unsigned long pc,
{
regs->pc = pc;
regs->sr &= ~0x2000;
+ setframeformat(regs);
wrusp(usp);
}
@@ -116,21 +127,11 @@ extern int handle_kernel_fault(struct pt_regs *regs);
#else
-/*
- * Coldfire stacks need to be re-aligned on trap exit, conventional
- * 68k can handle this case cleanly.
- */
-#ifdef CONFIG_COLDFIRE
-#define reformat(_regs) do { (_regs)->format = 0x4; } while(0)
-#else
-#define reformat(_regs) do { } while (0)
-#endif
-
#define start_thread(_regs, _pc, _usp) \
do { \
(_regs)->pc = (_pc); \
((struct switch_stack *)(_regs))[-1].a6 = 0; \
- reformat(_regs); \
+ setframeformat(_regs); \
if (current->mm) \
(_regs)->d5 = current->mm->start_data; \
(_regs)->sr &= ~0x2000; \
@@ -153,8 +154,6 @@ static inline void release_thread(struct task_struct *dead_task)
{
}
-extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
-
/*
* Free current thread data structures etc..
*/
diff --git a/arch/m68k/include/asm/ptrace.h b/arch/m68k/include/asm/ptrace.h
index 65322b17..5e08b59 100644
--- a/arch/m68k/include/asm/ptrace.h
+++ b/arch/m68k/include/asm/ptrace.h
@@ -85,6 +85,8 @@ struct switch_stack {
#define user_mode(regs) (!((regs)->sr & PS_S))
#define instruction_pointer(regs) ((regs)->pc)
#define profile_pc(regs) instruction_pointer(regs)
+#define current_pt_regs() \
+ (struct pt_regs *)((char *)current_thread_info() + THREAD_SIZE) - 1
#define arch_has_single_step() (1)
diff --git a/arch/m68k/include/asm/unistd.h b/arch/m68k/include/asm/unistd.h
index 045cfd6..c702ad7 100644
--- a/arch/m68k/include/asm/unistd.h
+++ b/arch/m68k/include/asm/unistd.h
@@ -382,6 +382,8 @@
#define __ARCH_WANT_SYS_SIGPROCMASK
#define __ARCH_WANT_SYS_RT_SIGACTION
#define __ARCH_WANT_SYS_RT_SIGSUSPEND
+#define __ARCH_WANT_SYS_EXECVE
+#define __ARCH_WANT_KERNEL_EXECVE
/*
* "Conditional" syscalls
diff --git a/arch/m68k/kernel/entry.S b/arch/m68k/kernel/entry.S
index 165ee9f..946cb01 100644
--- a/arch/m68k/kernel/entry.S
+++ b/arch/m68k/kernel/entry.S
@@ -111,6 +111,22 @@ ENTRY(ret_from_fork)
addql #4,%sp
jra ret_from_exception
+ENTRY(ret_from_kernel_thread)
+ | a3 contains the kernel thread payload, d7 - its argument
+ movel %d1,%sp@-
+ jsr schedule_tail
+ GET_CURRENT(%d0)
+ movel %d7,(%sp)
+ jsr %a3@
+ addql #4,%sp
+ movel %d0,(%sp)
+ jra sys_exit
+
+ENTRY(ret_from_kernel_execve)
+ movel 4(%sp), %sp
+ GET_CURRENT(%d0)
+ jra ret_from_exception
+
#if defined(CONFIG_COLDFIRE) || !defined(CONFIG_MMU)
#ifdef TRAP_DBG_INTERRUPT
diff --git a/arch/m68k/kernel/process.c b/arch/m68k/kernel/process.c
index ac2892e..c51bb17 100644
--- a/arch/m68k/kernel/process.c
+++ b/arch/m68k/kernel/process.c
@@ -35,6 +35,7 @@
asmlinkage void ret_from_fork(void);
+asmlinkage void ret_from_kernel_thread(void);
/*
@@ -123,51 +124,6 @@ void show_regs(struct pt_regs * regs)
printk("USP: %08lx\n", rdusp());
}
-/*
- * Create a kernel thread
- */
-int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
-{
- int pid;
- mm_segment_t fs;
-
- fs = get_fs();
- set_fs (KERNEL_DS);
-
- {
- register long retval __asm__ ("d0");
- register long clone_arg __asm__ ("d1") = flags | CLONE_VM | CLONE_UNTRACED;
-
- retval = __NR_clone;
- __asm__ __volatile__
- ("clrl %%d2\n\t"
- "trap #0\n\t" /* Linux/m68k system call */
- "tstl %0\n\t" /* child or parent */
- "jne 1f\n\t" /* parent - jump */
-#ifdef CONFIG_MMU
- "lea %%sp@(%c7),%6\n\t" /* reload current */
- "movel %6@,%6\n\t"
-#endif
- "movel %3,%%sp@-\n\t" /* push argument */
- "jsr %4@\n\t" /* call fn */
- "movel %0,%%d1\n\t" /* pass exit value */
- "movel %2,%%d0\n\t" /* exit */
- "trap #0\n"
- "1:"
- : "+d" (retval)
- : "i" (__NR_clone), "i" (__NR_exit),
- "r" (arg), "a" (fn), "d" (clone_arg), "r" (current),
- "i" (-THREAD_SIZE)
- : "d2");
-
- pid = retval;
- }
-
- set_fs (fs);
- return pid;
-}
-EXPORT_SYMBOL(kernel_thread);
-
void flush_thread(void)
{
current->thread.fs = __USER_DS;
@@ -219,30 +175,18 @@ asmlinkage int m68k_clone(struct pt_regs *regs)
}
int copy_thread(unsigned long clone_flags, unsigned long usp,
- unsigned long unused,
+ unsigned long arg,
struct task_struct * p, struct pt_regs * regs)
{
struct pt_regs * childregs;
- struct switch_stack * childstack, *stack;
- unsigned long *retp;
+ struct switch_stack *childstack;
childregs = (struct pt_regs *) (task_stack_page(p) + THREAD_SIZE) - 1;
-
- *childregs = *regs;
- childregs->d0 = 0;
-
- retp = ((unsigned long *) regs);
- stack = ((struct switch_stack *) retp) - 1;
-
childstack = ((struct switch_stack *) childregs) - 1;
- *childstack = *stack;
- childstack->retpc = (unsigned long)ret_from_fork;
p->thread.usp = usp;
p->thread.ksp = (unsigned long)childstack;
-
- if (clone_flags & CLONE_SETTLS)
- task_thread_info(p)->tp_value = regs->d5;
+ p->thread.esp0 = (unsigned long)childregs;
/*
* Must save the current SFC/DFC value, NOT the value when
@@ -250,6 +194,26 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
*/
p->thread.fs = get_fs().seg;
+ if (unlikely(!regs)) {
+ /* kernel thread */
+ memset(childstack, 0,
+ sizeof(struct switch_stack) + sizeof(struct pt_regs));
+ childregs->sr = PS_S;
+ childstack->a3 = usp; /* function */
+ childstack->d7 = arg;
+ childstack->retpc = (unsigned long)ret_from_kernel_thread;
+ p->thread.usp = 0;
+ return 0;
+ }
+ *childregs = *regs;
+ childregs->d0 = 0;
+
+ *childstack = ((struct switch_stack *) regs)[-1];
+ childstack->retpc = (unsigned long)ret_from_fork;
+
+ if (clone_flags & CLONE_SETTLS)
+ task_thread_info(p)->tp_value = regs->d5;
+
#ifdef CONFIG_FPU
if (!FPU_IS_EMU) {
/* Copy the current fpu state */
@@ -337,26 +301,6 @@ int dump_fpu (struct pt_regs *regs, struct user_m68kfp_struct *fpu)
EXPORT_SYMBOL(dump_fpu);
#endif /* CONFIG_FPU */
-/*
- * sys_execve() executes a new program.
- */
-asmlinkage int sys_execve(const char __user *name,
- const char __user *const __user *argv,
- const char __user *const __user *envp)
-{
- int error;
- char * filename;
- struct pt_regs *regs = (struct pt_regs *) &name;
-
- filename = getname(name);
- error = PTR_ERR(filename);
- if (IS_ERR(filename))
- return error;
- error = do_execve(filename, argv, envp, regs);
- putname(filename);
- return error;
-}
-
unsigned long get_wchan(struct task_struct *p)
{
unsigned long fp, pc;
diff --git a/arch/m68k/kernel/sys_m68k.c b/arch/m68k/kernel/sys_m68k.c
index 9a5932e..3a480b3 100644
--- a/arch/m68k/kernel/sys_m68k.c
+++ b/arch/m68k/kernel/sys_m68k.c
@@ -549,23 +549,6 @@ 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;
diff --git a/arch/microblaze/include/asm/Kbuild b/arch/microblaze/include/asm/Kbuild
index 48510f6..8653072 100644
--- a/arch/microblaze/include/asm/Kbuild
+++ b/arch/microblaze/include/asm/Kbuild
@@ -2,3 +2,4 @@ include include/asm-generic/Kbuild.asm
header-y += elf.h
generic-y += clkdev.h
+generic-y += exec.h
diff --git a/arch/microblaze/include/asm/exec.h b/arch/microblaze/include/asm/exec.h
deleted file mode 100644
index e750de1..0000000
--- a/arch/microblaze/include/asm/exec.h
+++ /dev/null
@@ -1,14 +0,0 @@
-/*
- * Copyright (C) 2006 Atmark Techno, Inc.
- *
- * 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.
- */
-
-#ifndef _ASM_MICROBLAZE_EXEC_H
-#define _ASM_MICROBLAZE_EXEC_H
-
-#define arch_align_stack(x) (x)
-
-#endif /* _ASM_MICROBLAZE_EXEC_H */
diff --git a/arch/microblaze/include/asm/thread_info.h b/arch/microblaze/include/asm/thread_info.h
index 6c610234..008f304 100644
--- a/arch/microblaze/include/asm/thread_info.h
+++ b/arch/microblaze/include/asm/thread_info.h
@@ -121,7 +121,6 @@ static inline struct thread_info *current_thread_info(void)
#define TIF_NEED_RESCHED 3 /* rescheduling necessary */
/* restore singlestep on return to user mode */
#define TIF_SINGLESTEP 4
-#define TIF_IRET 5 /* return with iret */
#define TIF_MEMDIE 6 /* is terminating due to OOM killer */
#define TIF_SYSCALL_AUDIT 9 /* syscall auditing active */
#define TIF_SECCOMP 10 /* secure computing */
@@ -134,7 +133,6 @@ static inline struct thread_info *current_thread_info(void)
#define _TIF_SIGPENDING (1 << TIF_SIGPENDING)
#define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED)
#define _TIF_SINGLESTEP (1 << TIF_SINGLESTEP)
-#define _TIF_IRET (1 << TIF_IRET)
#define _TIF_POLLING_NRFLAG (1 << TIF_POLLING_NRFLAG)
#define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT)
#define _TIF_SECCOMP (1 << TIF_SECCOMP)
@@ -184,6 +182,7 @@ static inline bool test_and_clear_restore_sigmask(void)
ti->status &= ~TS_RESTORE_SIGMASK;
return true;
}
+#define tsk_is_polling(t) test_tsk_thread_flag(t, TIF_POLLING_NRFLAG)
#endif
#endif /* __KERNEL__ */
diff --git a/arch/microblaze/kernel/signal.c b/arch/microblaze/kernel/signal.c
index c1220db..3847e5b 100644
--- a/arch/microblaze/kernel/signal.c
+++ b/arch/microblaze/kernel/signal.c
@@ -254,10 +254,6 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
set_fs(USER_DS);
- /* the tracer may want to single-step inside the handler */
- if (test_thread_flag(TIF_SINGLESTEP))
- ptrace_notify(SIGTRAP);
-
#ifdef DEBUG_SIG
printk(KERN_INFO "SIG deliver (%s:%d): sp=%p pc=%08lx\n",
current->comm, current->pid, frame, regs->pc);
@@ -315,7 +311,8 @@ handle_signal(unsigned long sig, struct k_sigaction *ka,
if (ret)
return;
- signal_delivered(sig, info, ka, regs, 0);
+ signal_delivered(sig, info, ka, regs,
+ test_thread_flag(TIF_SINGLESTEP));
}
/*
diff --git a/arch/mips/configs/rb532_defconfig b/arch/mips/configs/rb532_defconfig
index 55902d9..b85b121 100644
--- a/arch/mips/configs/rb532_defconfig
+++ b/arch/mips/configs/rb532_defconfig
@@ -119,7 +119,6 @@ CONFIG_MTD_CHAR=y
CONFIG_MTD_BLOCK=y
CONFIG_MTD_BLOCK2MTD=y
CONFIG_MTD_NAND=y
-CONFIG_MTD_NAND_VERIFY_WRITE=y
CONFIG_MTD_NAND_PLATFORM=y
CONFIG_ATA=y
# CONFIG_ATA_VERBOSE_ERROR is not set
diff --git a/arch/mips/include/asm/mach-jz4740/platform.h b/arch/mips/include/asm/mach-jz4740/platform.h
index 564ab81..163e81d 100644
--- a/arch/mips/include/asm/mach-jz4740/platform.h
+++ b/arch/mips/include/asm/mach-jz4740/platform.h
@@ -31,6 +31,7 @@ extern struct platform_device jz4740_pcm_device;
extern struct platform_device jz4740_codec_device;
extern struct platform_device jz4740_adc_device;
extern struct platform_device jz4740_wdt_device;
+extern struct platform_device jz4740_pwm_device;
void jz4740_serial_device_register(void);
diff --git a/arch/mips/include/asm/mach-jz4740/timer.h b/arch/mips/include/asm/mach-jz4740/timer.h
index 9baa03c..a7759fb 100644
--- a/arch/mips/include/asm/mach-jz4740/timer.h
+++ b/arch/mips/include/asm/mach-jz4740/timer.h
@@ -16,7 +16,120 @@
#ifndef __ASM_MACH_JZ4740_TIMER
#define __ASM_MACH_JZ4740_TIMER
+#define JZ_REG_TIMER_STOP 0x0C
+#define JZ_REG_TIMER_STOP_SET 0x1C
+#define JZ_REG_TIMER_STOP_CLEAR 0x2C
+#define JZ_REG_TIMER_ENABLE 0x00
+#define JZ_REG_TIMER_ENABLE_SET 0x04
+#define JZ_REG_TIMER_ENABLE_CLEAR 0x08
+#define JZ_REG_TIMER_FLAG 0x10
+#define JZ_REG_TIMER_FLAG_SET 0x14
+#define JZ_REG_TIMER_FLAG_CLEAR 0x18
+#define JZ_REG_TIMER_MASK 0x20
+#define JZ_REG_TIMER_MASK_SET 0x24
+#define JZ_REG_TIMER_MASK_CLEAR 0x28
+
+#define JZ_REG_TIMER_DFR(x) (((x) * 0x10) + 0x30)
+#define JZ_REG_TIMER_DHR(x) (((x) * 0x10) + 0x34)
+#define JZ_REG_TIMER_CNT(x) (((x) * 0x10) + 0x38)
+#define JZ_REG_TIMER_CTRL(x) (((x) * 0x10) + 0x3C)
+
+#define JZ_TIMER_IRQ_HALF(x) BIT((x) + 0x10)
+#define JZ_TIMER_IRQ_FULL(x) BIT(x)
+
+#define JZ_TIMER_CTRL_PWM_ABBRUPT_SHUTDOWN BIT(9)
+#define JZ_TIMER_CTRL_PWM_ACTIVE_LOW BIT(8)
+#define JZ_TIMER_CTRL_PWM_ENABLE BIT(7)
+#define JZ_TIMER_CTRL_PRESCALE_MASK 0x1c
+#define JZ_TIMER_CTRL_PRESCALE_OFFSET 0x3
+#define JZ_TIMER_CTRL_PRESCALE_1 (0 << 3)
+#define JZ_TIMER_CTRL_PRESCALE_4 (1 << 3)
+#define JZ_TIMER_CTRL_PRESCALE_16 (2 << 3)
+#define JZ_TIMER_CTRL_PRESCALE_64 (3 << 3)
+#define JZ_TIMER_CTRL_PRESCALE_256 (4 << 3)
+#define JZ_TIMER_CTRL_PRESCALE_1024 (5 << 3)
+
+#define JZ_TIMER_CTRL_PRESCALER(x) ((x) << JZ_TIMER_CTRL_PRESCALE_OFFSET)
+
+#define JZ_TIMER_CTRL_SRC_EXT BIT(2)
+#define JZ_TIMER_CTRL_SRC_RTC BIT(1)
+#define JZ_TIMER_CTRL_SRC_PCLK BIT(0)
+
+extern void __iomem *jz4740_timer_base;
+void __init jz4740_timer_init(void);
+
void jz4740_timer_enable_watchdog(void);
void jz4740_timer_disable_watchdog(void);
+static inline void jz4740_timer_stop(unsigned int timer)
+{
+ writel(BIT(timer), jz4740_timer_base + JZ_REG_TIMER_STOP_SET);
+}
+
+static inline void jz4740_timer_start(unsigned int timer)
+{
+ writel(BIT(timer), jz4740_timer_base + JZ_REG_TIMER_STOP_CLEAR);
+}
+
+static inline bool jz4740_timer_is_enabled(unsigned int timer)
+{
+ return readb(jz4740_timer_base + JZ_REG_TIMER_ENABLE) & BIT(timer);
+}
+
+static inline void jz4740_timer_enable(unsigned int timer)
+{
+ writeb(BIT(timer), jz4740_timer_base + JZ_REG_TIMER_ENABLE_SET);
+}
+
+static inline void jz4740_timer_disable(unsigned int timer)
+{
+ writeb(BIT(timer), jz4740_timer_base + JZ_REG_TIMER_ENABLE_CLEAR);
+}
+
+static inline void jz4740_timer_set_period(unsigned int timer, uint16_t period)
+{
+ writew(period, jz4740_timer_base + JZ_REG_TIMER_DFR(timer));
+}
+
+static inline void jz4740_timer_set_duty(unsigned int timer, uint16_t duty)
+{
+ writew(duty, jz4740_timer_base + JZ_REG_TIMER_DHR(timer));
+}
+
+static inline void jz4740_timer_set_count(unsigned int timer, uint16_t count)
+{
+ writew(count, jz4740_timer_base + JZ_REG_TIMER_CNT(timer));
+}
+
+static inline uint16_t jz4740_timer_get_count(unsigned int timer)
+{
+ return readw(jz4740_timer_base + JZ_REG_TIMER_CNT(timer));
+}
+
+static inline void jz4740_timer_ack_full(unsigned int timer)
+{
+ writel(JZ_TIMER_IRQ_FULL(timer), jz4740_timer_base + JZ_REG_TIMER_FLAG_CLEAR);
+}
+
+static inline void jz4740_timer_irq_full_enable(unsigned int timer)
+{
+ writel(JZ_TIMER_IRQ_FULL(timer), jz4740_timer_base + JZ_REG_TIMER_FLAG_CLEAR);
+ writel(JZ_TIMER_IRQ_FULL(timer), jz4740_timer_base + JZ_REG_TIMER_MASK_CLEAR);
+}
+
+static inline void jz4740_timer_irq_full_disable(unsigned int timer)
+{
+ writel(JZ_TIMER_IRQ_FULL(timer), jz4740_timer_base + JZ_REG_TIMER_MASK_SET);
+}
+
+static inline void jz4740_timer_set_ctrl(unsigned int timer, uint16_t ctrl)
+{
+ writew(ctrl, jz4740_timer_base + JZ_REG_TIMER_CTRL(timer));
+}
+
+static inline uint16_t jz4740_timer_get_ctrl(unsigned int timer)
+{
+ return readw(jz4740_timer_base + JZ_REG_TIMER_CTRL(timer));
+}
+
#endif
diff --git a/arch/mips/include/asm/thread_info.h b/arch/mips/include/asm/thread_info.h
index 946e010..8debe9e 100644
--- a/arch/mips/include/asm/thread_info.h
+++ b/arch/mips/include/asm/thread_info.h
@@ -103,7 +103,6 @@ register struct thread_info *__current_thread_info __asm__("$28");
#define TIF_NOTIFY_RESUME 5 /* callback before returning to user */
#define TIF_RESTORE_SIGMASK 9 /* restore signal mask in do_signal() */
#define TIF_USEDFPU 16 /* FPU was used by this task this quantum (SMP) */
-#define TIF_POLLING_NRFLAG 17 /* true if poll_idle() is polling TIF_NEED_RESCHED */
#define TIF_MEMDIE 18 /* is terminating due to OOM killer */
#define TIF_FIXADE 20 /* Fix address errors in software */
#define TIF_LOGADE 21 /* Log address errors to syslog */
@@ -125,9 +124,7 @@ register struct thread_info *__current_thread_info __asm__("$28");
#define _TIF_SYSCALL_AUDIT (1<<TIF_SYSCALL_AUDIT)
#define _TIF_SECCOMP (1<<TIF_SECCOMP)
#define _TIF_NOTIFY_RESUME (1<<TIF_NOTIFY_RESUME)
-#define _TIF_RESTORE_SIGMASK (1<<TIF_RESTORE_SIGMASK)
#define _TIF_USEDFPU (1<<TIF_USEDFPU)
-#define _TIF_POLLING_NRFLAG (1<<TIF_POLLING_NRFLAG)
#define _TIF_FIXADE (1<<TIF_FIXADE)
#define _TIF_LOGADE (1<<TIF_LOGADE)
#define _TIF_32BIT_REGS (1<<TIF_32BIT_REGS)
diff --git a/arch/mips/jz4740/Kconfig b/arch/mips/jz4740/Kconfig
index 3e7141f..4689030 100644
--- a/arch/mips/jz4740/Kconfig
+++ b/arch/mips/jz4740/Kconfig
@@ -7,6 +7,3 @@ config JZ4740_QI_LB60
bool "Qi Hardware Ben NanoNote"
endchoice
-
-config HAVE_PWM
- bool
diff --git a/arch/mips/jz4740/Makefile b/arch/mips/jz4740/Makefile
index e44abea..63bad0e 100644
--- a/arch/mips/jz4740/Makefile
+++ b/arch/mips/jz4740/Makefile
@@ -5,7 +5,7 @@
# Object file lists.
obj-y += prom.o irq.o time.o reset.o setup.o dma.o \
- gpio.o clock.o platform.o timer.o pwm.o serial.o
+ gpio.o clock.o platform.o timer.o serial.o
obj-$(CONFIG_DEBUG_FS) += clock-debugfs.o
diff --git a/arch/mips/jz4740/board-qi_lb60.c b/arch/mips/jz4740/board-qi_lb60.c
index 9a3d9de..43d964d 100644
--- a/arch/mips/jz4740/board-qi_lb60.c
+++ b/arch/mips/jz4740/board-qi_lb60.c
@@ -437,6 +437,7 @@ static struct platform_device *jz_platform_devices[] __initdata = {
&jz4740_codec_device,
&jz4740_rtc_device,
&jz4740_adc_device,
+ &jz4740_pwm_device,
&qi_lb60_gpio_keys,
&qi_lb60_pwm_beeper,
&qi_lb60_charger_device,
diff --git a/arch/mips/jz4740/platform.c b/arch/mips/jz4740/platform.c
index e342ed4..6d14dcd 100644
--- a/arch/mips/jz4740/platform.c
+++ b/arch/mips/jz4740/platform.c
@@ -323,3 +323,9 @@ struct platform_device jz4740_wdt_device = {
.num_resources = ARRAY_SIZE(jz4740_wdt_resources),
.resource = jz4740_wdt_resources,
};
+
+/* PWM */
+struct platform_device jz4740_pwm_device = {
+ .name = "jz4740-pwm",
+ .id = -1,
+};
diff --git a/arch/mips/jz4740/pwm.c b/arch/mips/jz4740/pwm.c
deleted file mode 100644
index a26a6fa..0000000
--- a/arch/mips/jz4740/pwm.c
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
- * JZ4740 platform PWM support
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * 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/kernel.h>
-
-#include <linux/clk.h>
-#include <linux/err.h>
-#include <linux/pwm.h>
-#include <linux/gpio.h>
-
-#include <asm/mach-jz4740/gpio.h>
-#include "timer.h"
-
-static struct clk *jz4740_pwm_clk;
-
-DEFINE_MUTEX(jz4740_pwm_mutex);
-
-struct pwm_device {
- unsigned int id;
- unsigned int gpio;
- bool used;
-};
-
-static struct pwm_device jz4740_pwm_list[] = {
- { 2, JZ_GPIO_PWM2, false },
- { 3, JZ_GPIO_PWM3, false },
- { 4, JZ_GPIO_PWM4, false },
- { 5, JZ_GPIO_PWM5, false },
- { 6, JZ_GPIO_PWM6, false },
- { 7, JZ_GPIO_PWM7, false },
-};
-
-struct pwm_device *pwm_request(int id, const char *label)
-{
- int ret = 0;
- struct pwm_device *pwm;
-
- if (id < 2 || id > 7 || !jz4740_pwm_clk)
- return ERR_PTR(-ENODEV);
-
- mutex_lock(&jz4740_pwm_mutex);
-
- pwm = &jz4740_pwm_list[id - 2];
- if (pwm->used)
- ret = -EBUSY;
- else
- pwm->used = true;
-
- mutex_unlock(&jz4740_pwm_mutex);
-
- if (ret)
- return ERR_PTR(ret);
-
- ret = gpio_request(pwm->gpio, label);
-
- if (ret) {
- printk(KERN_ERR "Failed to request pwm gpio: %d\n", ret);
- pwm->used = false;
- return ERR_PTR(ret);
- }
-
- jz_gpio_set_function(pwm->gpio, JZ_GPIO_FUNC_PWM);
-
- jz4740_timer_start(id);
-
- return pwm;
-}
-
-void pwm_free(struct pwm_device *pwm)
-{
- pwm_disable(pwm);
- jz4740_timer_set_ctrl(pwm->id, 0);
-
- jz_gpio_set_function(pwm->gpio, JZ_GPIO_FUNC_NONE);
- gpio_free(pwm->gpio);
-
- jz4740_timer_stop(pwm->id);
-
- pwm->used = false;
-}
-
-int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
-{
- unsigned long long tmp;
- unsigned long period, duty;
- unsigned int prescaler = 0;
- unsigned int id = pwm->id;
- uint16_t ctrl;
- bool is_enabled;
-
- if (duty_ns < 0 || duty_ns > period_ns)
- return -EINVAL;
-
- tmp = (unsigned long long)clk_get_rate(jz4740_pwm_clk) * period_ns;
- do_div(tmp, 1000000000);
- period = tmp;
-
- while (period > 0xffff && prescaler < 6) {
- period >>= 2;
- ++prescaler;
- }
-
- if (prescaler == 6)
- return -EINVAL;
-
- tmp = (unsigned long long)period * duty_ns;
- do_div(tmp, period_ns);
- duty = period - tmp;
-
- if (duty >= period)
- duty = period - 1;
-
- is_enabled = jz4740_timer_is_enabled(id);
- if (is_enabled)
- pwm_disable(pwm);
-
- jz4740_timer_set_count(id, 0);
- jz4740_timer_set_duty(id, duty);
- jz4740_timer_set_period(id, period);
-
- ctrl = JZ_TIMER_CTRL_PRESCALER(prescaler) | JZ_TIMER_CTRL_SRC_EXT |
- JZ_TIMER_CTRL_PWM_ABBRUPT_SHUTDOWN;
-
- jz4740_timer_set_ctrl(id, ctrl);
-
- if (is_enabled)
- pwm_enable(pwm);
-
- return 0;
-}
-
-int pwm_enable(struct pwm_device *pwm)
-{
- uint32_t ctrl = jz4740_timer_get_ctrl(pwm->id);
-
- ctrl |= JZ_TIMER_CTRL_PWM_ENABLE;
- jz4740_timer_set_ctrl(pwm->id, ctrl);
- jz4740_timer_enable(pwm->id);
-
- return 0;
-}
-
-void pwm_disable(struct pwm_device *pwm)
-{
- uint32_t ctrl = jz4740_timer_get_ctrl(pwm->id);
-
- ctrl &= ~JZ_TIMER_CTRL_PWM_ENABLE;
- jz4740_timer_disable(pwm->id);
- jz4740_timer_set_ctrl(pwm->id, ctrl);
-}
-
-static int __init jz4740_pwm_init(void)
-{
- int ret = 0;
-
- jz4740_pwm_clk = clk_get(NULL, "ext");
-
- if (IS_ERR(jz4740_pwm_clk)) {
- ret = PTR_ERR(jz4740_pwm_clk);
- jz4740_pwm_clk = NULL;
- }
-
- return ret;
-}
-subsys_initcall(jz4740_pwm_init);
diff --git a/arch/mips/jz4740/time.c b/arch/mips/jz4740/time.c
index f83c2dd..39bb4bb 100644
--- a/arch/mips/jz4740/time.c
+++ b/arch/mips/jz4740/time.c
@@ -20,10 +20,10 @@
#include <linux/clockchips.h>
#include <asm/mach-jz4740/irq.h>
+#include <asm/mach-jz4740/timer.h>
#include <asm/time.h>
#include "clock.h"
-#include "timer.h"
#define TIMER_CLOCKEVENT 0
#define TIMER_CLOCKSOURCE 1
diff --git a/arch/mips/jz4740/timer.c b/arch/mips/jz4740/timer.c
index 654d5c3..22f11d7 100644
--- a/arch/mips/jz4740/timer.c
+++ b/arch/mips/jz4740/timer.c
@@ -17,11 +17,11 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include "timer.h"
-
#include <asm/mach-jz4740/base.h>
+#include <asm/mach-jz4740/timer.h>
void __iomem *jz4740_timer_base;
+EXPORT_SYMBOL_GPL(jz4740_timer_base);
void jz4740_timer_enable_watchdog(void)
{
diff --git a/arch/mips/jz4740/timer.h b/arch/mips/jz4740/timer.h
deleted file mode 100644
index fca3994..0000000
--- a/arch/mips/jz4740/timer.h
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
- * JZ4740 platform timer support
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * 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 __MIPS_JZ4740_TIMER_H__
-#define __MIPS_JZ4740_TIMER_H__
-
-#include <linux/module.h>
-#include <linux/io.h>
-
-#define JZ_REG_TIMER_STOP 0x0C
-#define JZ_REG_TIMER_STOP_SET 0x1C
-#define JZ_REG_TIMER_STOP_CLEAR 0x2C
-#define JZ_REG_TIMER_ENABLE 0x00
-#define JZ_REG_TIMER_ENABLE_SET 0x04
-#define JZ_REG_TIMER_ENABLE_CLEAR 0x08
-#define JZ_REG_TIMER_FLAG 0x10
-#define JZ_REG_TIMER_FLAG_SET 0x14
-#define JZ_REG_TIMER_FLAG_CLEAR 0x18
-#define JZ_REG_TIMER_MASK 0x20
-#define JZ_REG_TIMER_MASK_SET 0x24
-#define JZ_REG_TIMER_MASK_CLEAR 0x28
-
-#define JZ_REG_TIMER_DFR(x) (((x) * 0x10) + 0x30)
-#define JZ_REG_TIMER_DHR(x) (((x) * 0x10) + 0x34)
-#define JZ_REG_TIMER_CNT(x) (((x) * 0x10) + 0x38)
-#define JZ_REG_TIMER_CTRL(x) (((x) * 0x10) + 0x3C)
-
-#define JZ_TIMER_IRQ_HALF(x) BIT((x) + 0x10)
-#define JZ_TIMER_IRQ_FULL(x) BIT(x)
-
-#define JZ_TIMER_CTRL_PWM_ABBRUPT_SHUTDOWN BIT(9)
-#define JZ_TIMER_CTRL_PWM_ACTIVE_LOW BIT(8)
-#define JZ_TIMER_CTRL_PWM_ENABLE BIT(7)
-#define JZ_TIMER_CTRL_PRESCALE_MASK 0x1c
-#define JZ_TIMER_CTRL_PRESCALE_OFFSET 0x3
-#define JZ_TIMER_CTRL_PRESCALE_1 (0 << 3)
-#define JZ_TIMER_CTRL_PRESCALE_4 (1 << 3)
-#define JZ_TIMER_CTRL_PRESCALE_16 (2 << 3)
-#define JZ_TIMER_CTRL_PRESCALE_64 (3 << 3)
-#define JZ_TIMER_CTRL_PRESCALE_256 (4 << 3)
-#define JZ_TIMER_CTRL_PRESCALE_1024 (5 << 3)
-
-#define JZ_TIMER_CTRL_PRESCALER(x) ((x) << JZ_TIMER_CTRL_PRESCALE_OFFSET)
-
-#define JZ_TIMER_CTRL_SRC_EXT BIT(2)
-#define JZ_TIMER_CTRL_SRC_RTC BIT(1)
-#define JZ_TIMER_CTRL_SRC_PCLK BIT(0)
-
-extern void __iomem *jz4740_timer_base;
-void __init jz4740_timer_init(void);
-
-static inline void jz4740_timer_stop(unsigned int timer)
-{
- writel(BIT(timer), jz4740_timer_base + JZ_REG_TIMER_STOP_SET);
-}
-
-static inline void jz4740_timer_start(unsigned int timer)
-{
- writel(BIT(timer), jz4740_timer_base + JZ_REG_TIMER_STOP_CLEAR);
-}
-
-static inline bool jz4740_timer_is_enabled(unsigned int timer)
-{
- return readb(jz4740_timer_base + JZ_REG_TIMER_ENABLE) & BIT(timer);
-}
-
-static inline void jz4740_timer_enable(unsigned int timer)
-{
- writeb(BIT(timer), jz4740_timer_base + JZ_REG_TIMER_ENABLE_SET);
-}
-
-static inline void jz4740_timer_disable(unsigned int timer)
-{
- writeb(BIT(timer), jz4740_timer_base + JZ_REG_TIMER_ENABLE_CLEAR);
-}
-
-
-static inline void jz4740_timer_set_period(unsigned int timer, uint16_t period)
-{
- writew(period, jz4740_timer_base + JZ_REG_TIMER_DFR(timer));
-}
-
-static inline void jz4740_timer_set_duty(unsigned int timer, uint16_t duty)
-{
- writew(duty, jz4740_timer_base + JZ_REG_TIMER_DHR(timer));
-}
-
-static inline void jz4740_timer_set_count(unsigned int timer, uint16_t count)
-{
- writew(count, jz4740_timer_base + JZ_REG_TIMER_CNT(timer));
-}
-
-static inline uint16_t jz4740_timer_get_count(unsigned int timer)
-{
- return readw(jz4740_timer_base + JZ_REG_TIMER_CNT(timer));
-}
-
-static inline void jz4740_timer_ack_full(unsigned int timer)
-{
- writel(JZ_TIMER_IRQ_FULL(timer), jz4740_timer_base + JZ_REG_TIMER_FLAG_CLEAR);
-}
-
-static inline void jz4740_timer_irq_full_enable(unsigned int timer)
-{
- writel(JZ_TIMER_IRQ_FULL(timer), jz4740_timer_base + JZ_REG_TIMER_FLAG_CLEAR);
- writel(JZ_TIMER_IRQ_FULL(timer), jz4740_timer_base + JZ_REG_TIMER_MASK_CLEAR);
-}
-
-static inline void jz4740_timer_irq_full_disable(unsigned int timer)
-{
- writel(JZ_TIMER_IRQ_FULL(timer), jz4740_timer_base + JZ_REG_TIMER_MASK_SET);
-}
-
-static inline void jz4740_timer_set_ctrl(unsigned int timer, uint16_t ctrl)
-{
- writew(ctrl, jz4740_timer_base + JZ_REG_TIMER_CTRL(timer));
-}
-
-static inline uint16_t jz4740_timer_get_ctrl(unsigned int timer)
-{
- return readw(jz4740_timer_base + JZ_REG_TIMER_CTRL(timer));
-}
-
-#endif
diff --git a/arch/mn10300/Kconfig b/arch/mn10300/Kconfig
index 5cfb086..ddbdc33 100644
--- a/arch/mn10300/Kconfig
+++ b/arch/mn10300/Kconfig
@@ -8,6 +8,7 @@ config MN10300
select HAVE_ARCH_KGDB
select HAVE_NMI_WATCHDOG if MN10300_WD_TIMER
select GENERIC_CLOCKEVENTS
+ select GENERIC_KERNEL_THREAD
config AM33_2
def_bool n
diff --git a/arch/mn10300/include/asm/Kbuild b/arch/mn10300/include/asm/Kbuild
index 0d20f55..fccd81e 100644
--- a/arch/mn10300/include/asm/Kbuild
+++ b/arch/mn10300/include/asm/Kbuild
@@ -1,3 +1,4 @@
include include/asm-generic/Kbuild.asm
generic-y += clkdev.h
+generic-y += exec.h
diff --git a/arch/mn10300/include/asm/exec.h b/arch/mn10300/include/asm/exec.h
deleted file mode 100644
index c74e367..0000000
--- a/arch/mn10300/include/asm/exec.h
+++ /dev/null
@@ -1,16 +0,0 @@
-/* MN10300 process execution definitions
- *
- * Copyright (C) 2007 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 Licence
- * as published by the Free Software Foundation; either version
- * 2 of the Licence, or (at your option) any later version.
- */
-#ifndef _ASM_EXEC_H
-#define _ASM_EXEC_H
-
-#define arch_align_stack(x) (x)
-
-#endif /* _ASM_EXEC_H */
diff --git a/arch/mn10300/include/asm/frame.inc b/arch/mn10300/include/asm/frame.inc
index 2ee58e3..1c3eb4f 100644
--- a/arch/mn10300/include/asm/frame.inc
+++ b/arch/mn10300/include/asm/frame.inc
@@ -61,7 +61,7 @@
###############################################################################
.macro RESTORE_ALL
# peel back the stack to the calling frame
- # - this permits execve() to discard extra frames due to kernel syscalls
+ # - we need that when returning from interrupts to kernel mode
GET_THREAD_INFO a0
mov (TI_frame,a0),fp
mov fp,sp
diff --git a/arch/mn10300/include/asm/processor.h b/arch/mn10300/include/asm/processor.h
index 247928c..8b80b19 100644
--- a/arch/mn10300/include/asm/processor.h
+++ b/arch/mn10300/include/asm/processor.h
@@ -119,20 +119,13 @@ struct thread_struct {
/*
* do necessary setup to start up a newly executed thread
- * - need to discard the frame stacked by the kernel thread invoking the execve
- * syscall (see RESTORE_ALL macro)
*/
static inline void start_thread(struct pt_regs *regs,
unsigned long new_pc, unsigned long new_sp)
{
- struct thread_info *ti = current_thread_info();
- struct pt_regs *frame0;
-
- frame0 = thread_info_to_uregs(ti);
- frame0->epsw = EPSW_nSL | EPSW_IE | EPSW_IM;
- frame0->pc = new_pc;
- frame0->sp = new_sp;
- ti->frame = frame0;
+ regs->epsw = EPSW_nSL | EPSW_IE | EPSW_IM;
+ regs->pc = new_pc;
+ regs->sp = new_sp;
}
@@ -140,11 +133,6 @@ static inline void start_thread(struct pt_regs *regs,
extern void release_thread(struct task_struct *);
/*
- * create a kernel thread without removing it from tasklists
- */
-extern int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
-
-/*
* Return saved PC of a blocked thread.
*/
extern unsigned long thread_saved_pc(struct task_struct *tsk);
diff --git a/arch/mn10300/include/asm/ptrace.h b/arch/mn10300/include/asm/ptrace.h
index 44251b9..08ac856 100644
--- a/arch/mn10300/include/asm/ptrace.h
+++ b/arch/mn10300/include/asm/ptrace.h
@@ -86,6 +86,7 @@ struct pt_regs {
#define user_mode(regs) (((regs)->epsw & EPSW_nSL) == EPSW_nSL)
#define instruction_pointer(regs) ((regs)->pc)
#define user_stack_pointer(regs) ((regs)->sp)
+#define current_pt_regs() current_frame()
#define arch_has_single_step() (1)
diff --git a/arch/mn10300/include/asm/thread_info.h b/arch/mn10300/include/asm/thread_info.h
index ac519bb..f90062b 100644
--- a/arch/mn10300/include/asm/thread_info.h
+++ b/arch/mn10300/include/asm/thread_info.h
@@ -160,12 +160,13 @@ void arch_release_thread_info(struct thread_info *ti);
#define _TIF_SIGPENDING +(1 << TIF_SIGPENDING)
#define _TIF_NEED_RESCHED +(1 << TIF_NEED_RESCHED)
#define _TIF_SINGLESTEP +(1 << TIF_SINGLESTEP)
-#define _TIF_RESTORE_SIGMASK +(1 << TIF_RESTORE_SIGMASK)
#define _TIF_POLLING_NRFLAG +(1 << TIF_POLLING_NRFLAG)
#define _TIF_WORK_MASK 0x0000FFFE /* work to do on interrupt/exception return */
#define _TIF_ALLWORK_MASK 0x0000FFFF /* work to do on any return to u-space */
+#define tsk_is_polling(t) test_tsk_thread_flag(t, TIF_POLLING_NRFLAG)
+
#endif /* __KERNEL__ */
#endif /* _ASM_THREAD_INFO_H */
diff --git a/arch/mn10300/include/asm/unistd.h b/arch/mn10300/include/asm/unistd.h
index 866eb14..044c770 100644
--- a/arch/mn10300/include/asm/unistd.h
+++ b/arch/mn10300/include/asm/unistd.h
@@ -382,6 +382,8 @@
#define __ARCH_WANT_SYS_SIGPROCMASK
#define __ARCH_WANT_SYS_RT_SIGACTION
#define __ARCH_WANT_SYS_RT_SIGSUSPEND
+#define __ARCH_WANT_SYS_EXECVE
+#define __ARCH_WANT_KERNEL_EXECVE
/*
* "Conditional" syscalls
diff --git a/arch/mn10300/kernel/Makefile b/arch/mn10300/kernel/Makefile
index d067491..561029f 100644
--- a/arch/mn10300/kernel/Makefile
+++ b/arch/mn10300/kernel/Makefile
@@ -7,8 +7,8 @@ fpu-obj-y := fpu-nofpu.o fpu-nofpu-low.o
fpu-obj-$(CONFIG_FPU) := fpu.o fpu-low.o
obj-y := process.o signal.o entry.o traps.o irq.o \
- ptrace.o setup.o time.o sys_mn10300.o io.o kthread.o \
- switch_to.o mn10300_ksyms.o kernel_execve.o $(fpu-obj-y) \
+ ptrace.o setup.o time.o sys_mn10300.o io.o \
+ switch_to.o mn10300_ksyms.o $(fpu-obj-y) \
csrc-mn10300.o cevt-mn10300.o
obj-$(CONFIG_SMP) += smp.o smp-low.o
diff --git a/arch/mn10300/kernel/entry.S b/arch/mn10300/kernel/entry.S
index 8e11f9f..0c631d3 100644
--- a/arch/mn10300/kernel/entry.S
+++ b/arch/mn10300/kernel/entry.S
@@ -55,6 +55,20 @@ ENTRY(ret_from_fork)
mov d0,(REG_D0,fp)
jmp syscall_exit
+ENTRY(ret_from_kernel_thread)
+ call schedule_tail[],0
+ mov (REG_D0,fp),d0
+ mov (REG_A0,fp),a0
+ calls (a0)
+ jmp sys_exit
+
+ENTRY(ret_from_kernel_execve)
+ add -12,d0 /* pt_regs -> frame */
+ mov d0,sp
+ GET_THREAD_INFO a2
+ clr d0
+ jmp syscall_exit
+
###############################################################################
#
# system call handler
@@ -94,6 +108,10 @@ restore_all:
###############################################################################
ALIGN
syscall_exit_work:
+ mov (REG_EPSW,fp),d0
+ and EPSW_nSL,d0
+ beq resume_kernel # returning to supervisor mode
+
btst _TIF_SYSCALL_TRACE,d2
beq work_pending
LOCAL_IRQ_ENABLE # could let syscall_trace_exit() call
diff --git a/arch/mn10300/kernel/internal.h b/arch/mn10300/kernel/internal.h
index 2df4401..5617855 100644
--- a/arch/mn10300/kernel/internal.h
+++ b/arch/mn10300/kernel/internal.h
@@ -15,14 +15,10 @@ struct clocksource;
struct clock_event_device;
/*
- * kthread.S
- */
-extern int kernel_thread_helper(int);
-
-/*
* entry.S
*/
extern void ret_from_fork(struct task_struct *) __attribute__((noreturn));
+extern void ret_from_kernel_thread(struct task_struct *) __attribute__((noreturn));
/*
* smp-low.S
diff --git a/arch/mn10300/kernel/kernel_execve.S b/arch/mn10300/kernel/kernel_execve.S
deleted file mode 100644
index 86039f1..0000000
--- a/arch/mn10300/kernel/kernel_execve.S
+++ /dev/null
@@ -1,37 +0,0 @@
-/* MN10300 In-kernel program execution
- *
- * Copyright (C) 2007 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 Licence
- * as published by the Free Software Foundation; either version
- * 2 of the Licence, or (at your option) any later version.
- */
-#include <linux/linkage.h>
-#include <asm/unistd.h>
-
-###############################################################################
-#
-# 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, char *const argv[],
-# char *const envp[])
-#
-# On entry: D0/D1/8(SP): arguments to function
-# On return: D0: syscall return.
-#
-###############################################################################
- .globl kernel_execve
- .type kernel_execve,@function
-kernel_execve:
- mov a3,a1
- mov d0,a0
- mov (12,sp),a3
- mov +__NR_execve,d0
- syscall 0
- mov a1,a3
- rets
-
- .size kernel_execve,.-kernel_execve
diff --git a/arch/mn10300/kernel/kthread.S b/arch/mn10300/kernel/kthread.S
deleted file mode 100644
index b5ae467..0000000
--- a/arch/mn10300/kernel/kthread.S
+++ /dev/null
@@ -1,31 +0,0 @@
-/* MN10300 Kernel thread trampoline function
- *
- * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
- * Written by Mark Salter (msalter@redhat.com)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public Licence
- * as published by the Free Software Foundation; either version
- * 2 of the Licence, or (at your option) any later version.
- */
- .text
-
-###############################################################################
-#
-# kernel_thread_helper - trampoline for kernel_thread()
-#
-# On entry:
-# A2 = address of function to call
-# D2 = function argument
-#
-###############################################################################
- .globl kernel_thread_helper
- .type kernel_thread_helper,@function
-kernel_thread_helper:
- mov do_exit,d1
- mov d1,(sp)
- mov d1,mdr
- mov d2,d0
- jmp (a2)
-
- .size kernel_thread_helper,.-kernel_thread_helper
diff --git a/arch/mn10300/kernel/process.c b/arch/mn10300/kernel/process.c
index e9cceba..d0c671b 100644
--- a/arch/mn10300/kernel/process.c
+++ b/arch/mn10300/kernel/process.c
@@ -165,27 +165,6 @@ void show_regs(struct pt_regs *regs)
}
/*
- * create a kernel thread
- */
-int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
-{
- struct pt_regs regs;
-
- memset(&regs, 0, sizeof(regs));
-
- regs.a2 = (unsigned long) fn;
- regs.d2 = (unsigned long) arg;
- regs.pc = (unsigned long) kernel_thread_helper;
- local_save_flags(regs.epsw);
- regs.epsw |= EPSW_IE | EPSW_IM_7;
-
- /* Ok, create the new process.. */
- return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, &regs, 0,
- NULL, NULL);
-}
-EXPORT_SYMBOL(kernel_thread);
-
-/*
* free current thread data structures etc..
*/
void exit_thread(void)
@@ -230,50 +209,42 @@ int copy_thread(unsigned long clone_flags,
struct task_struct *p, struct pt_regs *kregs)
{
struct thread_info *ti = task_thread_info(p);
- struct pt_regs *c_uregs, *c_kregs, *uregs;
+ struct pt_regs *c_regs;
unsigned long c_ksp;
- uregs = current->thread.uregs;
-
c_ksp = (unsigned long) task_stack_page(p) + THREAD_SIZE;
/* allocate the userspace exception frame and set it up */
c_ksp -= sizeof(struct pt_regs);
- c_uregs = (struct pt_regs *) c_ksp;
+ c_regs = (struct pt_regs *) c_ksp;
+ c_ksp -= 12; /* allocate function call ABI slack */
- p->thread.uregs = c_uregs;
- *c_uregs = *uregs;
- c_uregs->sp = c_usp;
- c_uregs->epsw &= ~EPSW_FE; /* my FPU */
+ /* set up things up so the scheduler can start the new task */
+ p->thread.uregs = c_regs;
+ ti->frame = c_regs;
+ p->thread.a3 = (unsigned long) c_regs;
+ p->thread.sp = c_ksp;
+ p->thread.wchan = p->thread.pc;
+ p->thread.usp = c_usp;
- c_ksp -= 12; /* allocate function call ABI slack */
+ if (unlikely(!kregs)) {
+ memset(c_regs, 0, sizeof(struct pt_regs));
+ c_regs->a0 = c_usp; /* function */
+ c_regs->d0 = ustk_size; /* argument */
+ local_save_flags(c_regs->epsw);
+ c_regs->epsw |= EPSW_IE | EPSW_IM_7;
+ p->thread.pc = (unsigned long) ret_from_kernel_thread;
+ return 0;
+ }
+ *c_regs = *kregs;
+ c_regs->sp = c_usp;
+ c_regs->epsw &= ~EPSW_FE; /* my FPU */
/* the new TLS pointer is passed in as arg #5 to sys_clone() */
if (clone_flags & CLONE_SETTLS)
- c_uregs->e2 = current_frame()->d3;
-
- /* set up the return kernel frame if called from kernel_thread() */
- c_kregs = c_uregs;
- if (kregs != uregs) {
- c_ksp -= sizeof(struct pt_regs);
- c_kregs = (struct pt_regs *) c_ksp;
- *c_kregs = *kregs;
- c_kregs->sp = c_usp;
- c_kregs->next = c_uregs;
-#ifdef CONFIG_MN10300_CURRENT_IN_E2
- c_kregs->e2 = (unsigned long) p; /* current */
-#endif
-
- c_ksp -= 12; /* allocate function call ABI slack */
- }
+ c_regs->e2 = current_frame()->d3;
- /* set up things up so the scheduler can start the new task */
- ti->frame = c_kregs;
- p->thread.a3 = (unsigned long) c_kregs;
- p->thread.sp = c_ksp;
p->thread.pc = (unsigned long) ret_from_fork;
- p->thread.wchan = (unsigned long) ret_from_fork;
- p->thread.usp = c_usp;
return 0;
}
@@ -302,22 +273,6 @@ asmlinkage long sys_vfork(void)
current_frame(), 0, NULL, NULL);
}
-asmlinkage long sys_execve(const char __user *name,
- const char __user *const __user *argv,
- const char __user *const __user *envp)
-{
- char *filename;
- int error;
-
- filename = getname(name);
- error = PTR_ERR(filename);
- if (IS_ERR(filename))
- return error;
- error = do_execve(filename, argv, envp, current_frame());
- putname(filename);
- return error;
-}
-
unsigned long get_wchan(struct task_struct *p)
{
return p->thread.wchan;
diff --git a/arch/mn10300/kernel/signal.c b/arch/mn10300/kernel/signal.c
index 4d584ae..f570b30 100644
--- a/arch/mn10300/kernel/signal.c
+++ b/arch/mn10300/kernel/signal.c
@@ -317,10 +317,6 @@ static int setup_frame(int sig, struct k_sigaction *ka, sigset_t *set,
regs->d0 = sig;
regs->d1 = (unsigned long) &frame->sc;
- /* the tracer may want to single-step inside the handler */
- if (test_thread_flag(TIF_SINGLESTEP))
- ptrace_notify(SIGTRAP);
-
#if DEBUG_SIG
printk(KERN_DEBUG "SIG deliver %d (%s:%d): sp=%p pc=%lx ra=%p\n",
sig, current->comm, current->pid, frame, regs->pc,
@@ -398,10 +394,6 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
regs->d0 = sig;
regs->d1 = (long) &frame->info;
- /* the tracer may want to single-step inside the handler */
- if (test_thread_flag(TIF_SINGLESTEP))
- ptrace_notify(SIGTRAP);
-
#if DEBUG_SIG
printk(KERN_DEBUG "SIG deliver %d (%s:%d): sp=%p pc=%lx ra=%p\n",
sig, current->comm, current->pid, frame, regs->pc,
@@ -475,11 +467,6 @@ static void do_signal(struct pt_regs *regs)
siginfo_t info;
int signr;
- /* we want the common case to go fast, which is why we may in certain
- * cases get here from kernel mode */
- if (!user_mode(regs))
- return;
-
signr = get_signal_to_deliver(&info, &ka, regs, NULL);
if (signr > 0) {
if (handle_signal(signr, &info, &ka, regs) == 0) {
diff --git a/arch/openrisc/include/asm/thread_info.h b/arch/openrisc/include/asm/thread_info.h
index 07a8bc0..07f3212 100644
--- a/arch/openrisc/include/asm/thread_info.h
+++ b/arch/openrisc/include/asm/thread_info.h
@@ -121,7 +121,6 @@ register struct thread_info *current_thread_info_reg asm("r10");
#define _TIF_SIGPENDING (1<<TIF_SIGPENDING)
#define _TIF_NEED_RESCHED (1<<TIF_NEED_RESCHED)
#define _TIF_SINGLESTEP (1<<TIF_SINGLESTEP)
-#define _TIF_RESTORE_SIGMASK (1<<TIF_RESTORE_SIGMASK)
#define _TIF_POLLING_NRFLAG (1<<TIF_POLLING_NRFLAG)
@@ -129,6 +128,8 @@ register struct thread_info *current_thread_info_reg asm("r10");
/* For OpenRISC, this is anything in the LSW other than syscall trace */
#define _TIF_WORK_MASK (0xff & ~(_TIF_SYSCALL_TRACE|_TIF_SINGLESTEP))
+#define tsk_is_polling(t) test_tsk_thread_flag(t, TIF_POLLING_NRFLAG)
+
#endif /* __KERNEL__ */
#endif /* _ASM_THREAD_INFO_H */
diff --git a/arch/parisc/hpux/gate.S b/arch/parisc/hpux/gate.S
index 38a1c1b..0114688 100644
--- a/arch/parisc/hpux/gate.S
+++ b/arch/parisc/hpux/gate.S
@@ -71,7 +71,7 @@ ENTRY(hpux_gateway_page)
STREG %r26, TASK_PT_GR26(%r1) /* 1st argument */
STREG %r27, TASK_PT_GR27(%r1) /* user dp */
STREG %r28, TASK_PT_GR28(%r1) /* return value 0 */
- STREG %r28, TASK_PT_ORIG_R28(%r1) /* return value 0 (saved for signals) */
+ STREG %r0, TASK_PT_ORIG_R28(%r1) /* don't prohibit restarts */
STREG %r29, TASK_PT_GR29(%r1) /* 8th argument */
STREG %r31, TASK_PT_GR31(%r1) /* preserve syscall return ptr */
diff --git a/arch/parisc/include/asm/Kbuild b/arch/parisc/include/asm/Kbuild
index 0587f62..458371a 100644
--- a/arch/parisc/include/asm/Kbuild
+++ b/arch/parisc/include/asm/Kbuild
@@ -3,3 +3,4 @@ include include/asm-generic/Kbuild.asm
header-y += pdc.h
generic-y += clkdev.h
generic-y += word-at-a-time.h
+generic-y += exec.h
diff --git a/arch/parisc/include/asm/exec.h b/arch/parisc/include/asm/exec.h
deleted file mode 100644
index 6bb5af7..0000000
--- a/arch/parisc/include/asm/exec.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __PARISC_EXEC_H
-#define __PARISC_EXEC_H
-
-#define arch_align_stack(x) (x)
-
-#endif /* __PARISC_EXEC_H */
diff --git a/arch/parisc/include/asm/thread_info.h b/arch/parisc/include/asm/thread_info.h
index 22b4726..d1fb79a 100644
--- a/arch/parisc/include/asm/thread_info.h
+++ b/arch/parisc/include/asm/thread_info.h
@@ -68,13 +68,16 @@ struct thread_info {
#define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED)
#define _TIF_POLLING_NRFLAG (1 << TIF_POLLING_NRFLAG)
#define _TIF_32BIT (1 << TIF_32BIT)
-#define _TIF_RESTORE_SIGMASK (1 << TIF_RESTORE_SIGMASK)
#define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME)
#define _TIF_SINGLESTEP (1 << TIF_SINGLESTEP)
#define _TIF_BLOCKSTEP (1 << TIF_BLOCKSTEP)
#define _TIF_USER_WORK_MASK (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | \
_TIF_NEED_RESCHED)
+#define _TIF_SYSCALL_TRACE_MASK (_TIF_SYSCALL_TRACE | _TIF_SINGLESTEP | \
+ _TIF_BLOCKSTEP)
+
+#define tsk_is_polling(t) test_tsk_thread_flag(t, TIF_POLLING_NRFLAG)
#endif /* __KERNEL__ */
diff --git a/arch/parisc/kernel/signal.c b/arch/parisc/kernel/signal.c
index 594459b..5379969 100644
--- a/arch/parisc/kernel/signal.c
+++ b/arch/parisc/kernel/signal.c
@@ -113,6 +113,8 @@ sys_rt_sigreturn(struct pt_regs *regs, int in_syscall)
(usp - sigframe_size);
DBG(2,"sys_rt_sigreturn: frame is %p\n", frame);
+ regs->orig_r28 = 1; /* no restarts for sigreturn */
+
#ifdef CONFIG_64BIT
compat_frame = (struct compat_rt_sigframe __user *)frame;
@@ -437,7 +439,7 @@ give_sigsegv:
* OK, we're invoking a handler.
*/
-static long
+static void
handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
struct pt_regs *regs, int in_syscall)
{
@@ -447,7 +449,7 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
/* Set up the stack frame */
if (!setup_rt_frame(sig, ka, info, oldset, regs, in_syscall))
- return 0;
+ return;
signal_delivered(sig, info, ka, regs,
test_thread_flag(TIF_SINGLESTEP) ||
@@ -455,13 +457,14 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
DBG(1,KERN_DEBUG "do_signal: Exit (success), regs->gr[28] = %ld\n",
regs->gr[28]);
-
- return 1;
}
static inline void
syscall_restart(struct pt_regs *regs, struct k_sigaction *ka)
{
+ if (regs->orig_r28)
+ return;
+ regs->orig_r28 = 1; /* no more restarts */
/* Check the return code */
switch (regs->gr[28]) {
case -ERESTART_RESTARTBLOCK:
@@ -482,8 +485,6 @@ syscall_restart(struct pt_regs *regs, struct k_sigaction *ka)
* we have to do is fiddle the return pointer.
*/
regs->gr[31] -= 8; /* delayed branching */
- /* Preserve original r28. */
- regs->gr[28] = regs->orig_r28;
break;
}
}
@@ -491,6 +492,9 @@ syscall_restart(struct pt_regs *regs, struct k_sigaction *ka)
static inline void
insert_restart_trampoline(struct pt_regs *regs)
{
+ if (regs->orig_r28)
+ return;
+ regs->orig_r28 = 1; /* no more restarts */
switch(regs->gr[28]) {
case -ERESTART_RESTARTBLOCK: {
/* Restart the system call - no handlers present */
@@ -525,9 +529,6 @@ insert_restart_trampoline(struct pt_regs *regs)
flush_user_icache_range(regs->gr[30], regs->gr[30] + 4);
regs->gr[31] = regs->gr[30] + 8;
- /* Preserve original r28. */
- regs->gr[28] = regs->orig_r28;
-
return;
}
case -ERESTARTNOHAND:
@@ -539,9 +540,6 @@ insert_restart_trampoline(struct pt_regs *regs)
* slot of the branch external instruction.
*/
regs->gr[31] -= 8;
- /* Preserve original r28. */
- regs->gr[28] = regs->orig_r28;
-
return;
}
default:
@@ -570,30 +568,17 @@ do_signal(struct pt_regs *regs, long in_syscall)
DBG(1,"\ndo_signal: regs=0x%p, sr7 %#lx, in_syscall=%d\n",
regs, regs->sr[7], in_syscall);
- /* Everyone else checks to see if they are in kernel mode at
- this point and exits if that's the case. I'm not sure why
- we would be called in that case, but for some reason we
- are. */
-
- /* May need to force signal if handle_signal failed to deliver */
- while (1) {
- signr = get_signal_to_deliver(&info, &ka, regs, NULL);
- DBG(3,"do_signal: signr = %d, regs->gr[28] = %ld\n", signr, regs->gr[28]);
+ signr = get_signal_to_deliver(&info, &ka, regs, NULL);
+ DBG(3,"do_signal: signr = %d, regs->gr[28] = %ld\n", signr, regs->gr[28]);
- if (signr <= 0)
- break;
-
+ if (signr > 0) {
/* Restart a system call if necessary. */
if (in_syscall)
syscall_restart(regs, &ka);
- /* Whee! Actually deliver the signal. If the
- delivery failed, we need to continue to iterate in
- this loop so we can deliver the SIGSEGV... */
- if (handle_signal(signr, &info, &ka, regs, in_syscall))
- return;
+ handle_signal(signr, &info, &ka, regs, in_syscall);
+ return;
}
- /* end of while(1) looping forever if we can't force a signal */
/* Did we come from a system call? */
if (in_syscall)
diff --git a/arch/parisc/kernel/syscall.S b/arch/parisc/kernel/syscall.S
index 82a52b2..86742df 100644
--- a/arch/parisc/kernel/syscall.S
+++ b/arch/parisc/kernel/syscall.S
@@ -156,7 +156,7 @@ linux_gateway_entry:
STREG %r26, TASK_PT_GR26(%r1) /* 1st argument */
STREG %r27, TASK_PT_GR27(%r1) /* user dp */
STREG %r28, TASK_PT_GR28(%r1) /* return value 0 */
- STREG %r28, TASK_PT_ORIG_R28(%r1) /* return value 0 (saved for signals) */
+ STREG %r0, TASK_PT_ORIG_R28(%r1) /* don't prohibit restarts */
STREG %r29, TASK_PT_GR29(%r1) /* return value 1 */
STREG %r31, TASK_PT_GR31(%r1) /* preserve syscall return ptr */
@@ -180,9 +180,10 @@ linux_gateway_entry:
/* Are we being ptraced? */
mfctl %cr30, %r1
- LDREG TI_TASK(%r1),%r1
- ldw TASK_PTRACE(%r1), %r1
- bb,<,n %r1,31,.Ltracesys
+ LDREG TI_FLAGS(%r1),%r1
+ ldi _TIF_SYSCALL_TRACE_MASK, %r19
+ and,COND(=) %r1, %r19, %r0
+ b,n .Ltracesys
/* Note! We cannot use the syscall table that is mapped
nearby since the gateway page is mapped execute-only. */
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index df7edb8..78d6588 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -141,6 +141,7 @@ config PPC
select GENERIC_CLOCKEVENTS
select GENERIC_STRNCPY_FROM_USER
select GENERIC_STRNLEN_USER
+ select GENERIC_KERNEL_THREAD
config EARLY_PRINTK
bool
diff --git a/arch/powerpc/configs/83xx/mpc8313_rdb_defconfig b/arch/powerpc/configs/83xx/mpc8313_rdb_defconfig
index 126ef1b0..e4ad2e2 100644
--- a/arch/powerpc/configs/83xx/mpc8313_rdb_defconfig
+++ b/arch/powerpc/configs/83xx/mpc8313_rdb_defconfig
@@ -38,7 +38,6 @@ CONFIG_MTD_CFI=y
CONFIG_MTD_CFI_AMDSTD=y
CONFIG_MTD_PHYSMAP_OF=y
CONFIG_MTD_NAND=y
-CONFIG_MTD_NAND_VERIFY_WRITE=y
CONFIG_MTD_NAND_FSL_ELBC=y
CONFIG_PROC_DEVICETREE=y
CONFIG_BLK_DEV_LOOP=y
diff --git a/arch/powerpc/configs/83xx/mpc8315_rdb_defconfig b/arch/powerpc/configs/83xx/mpc8315_rdb_defconfig
index abcf00a..34ff568 100644
--- a/arch/powerpc/configs/83xx/mpc8315_rdb_defconfig
+++ b/arch/powerpc/configs/83xx/mpc8315_rdb_defconfig
@@ -37,7 +37,6 @@ CONFIG_MTD_CFI=y
CONFIG_MTD_CFI_AMDSTD=y
CONFIG_MTD_PHYSMAP_OF=y
CONFIG_MTD_NAND=y
-CONFIG_MTD_NAND_VERIFY_WRITE=y
CONFIG_PROC_DEVICETREE=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_RAM=y
diff --git a/arch/powerpc/configs/mpc83xx_defconfig b/arch/powerpc/configs/mpc83xx_defconfig
index 9352e44..09116c6 100644
--- a/arch/powerpc/configs/mpc83xx_defconfig
+++ b/arch/powerpc/configs/mpc83xx_defconfig
@@ -50,7 +50,6 @@ CONFIG_MTD_CFI=y
CONFIG_MTD_CFI_AMDSTD=y
CONFIG_MTD_PHYSMAP_OF=y
CONFIG_MTD_NAND=y
-CONFIG_MTD_NAND_VERIFY_WRITE=y
CONFIG_MTD_NAND_FSL_ELBC=y
CONFIG_PROC_DEVICETREE=y
CONFIG_BLK_DEV_LOOP=y
diff --git a/arch/powerpc/include/asm/processor.h b/arch/powerpc/include/asm/processor.h
index 9dc5cd1..8734b38 100644
--- a/arch/powerpc/include/asm/processor.h
+++ b/arch/powerpc/include/asm/processor.h
@@ -74,9 +74,6 @@ struct task_struct;
void start_thread(struct pt_regs *regs, unsigned long fdptr, unsigned long sp);
void release_thread(struct task_struct *);
-/* Create a new kernel thread. */
-extern long kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
-
/* Lazy FPU handling on uni-processor */
extern struct task_struct *last_task_used_math;
extern struct task_struct *last_task_used_altivec;
diff --git a/arch/powerpc/include/asm/ptrace.h b/arch/powerpc/include/asm/ptrace.h
index 9c21ed4..f76b88c 100644
--- a/arch/powerpc/include/asm/ptrace.h
+++ b/arch/powerpc/include/asm/ptrace.h
@@ -125,6 +125,8 @@ extern unsigned long ptrace_get_reg(struct task_struct *task, int regno);
extern int ptrace_put_reg(struct task_struct *task, int regno,
unsigned long data);
+#define current_pt_regs() \
+ ((struct pt_regs *)((unsigned long)current_thread_info() + THREAD_SIZE) - 1)
/*
* We use the least-significant bit of the trap field to indicate
* whether we have saved the full set of registers, or only a
diff --git a/arch/powerpc/include/asm/syscalls.h b/arch/powerpc/include/asm/syscalls.h
index 4084e56..329db4e 100644
--- a/arch/powerpc/include/asm/syscalls.h
+++ b/arch/powerpc/include/asm/syscalls.h
@@ -17,9 +17,6 @@ asmlinkage unsigned long sys_mmap(unsigned long addr, size_t len,
asmlinkage unsigned long sys_mmap2(unsigned long addr, size_t len,
unsigned long prot, unsigned long flags,
unsigned long fd, unsigned long pgoff);
-asmlinkage int sys_execve(unsigned long a0, unsigned long a1,
- unsigned long a2, unsigned long a3, unsigned long a4,
- unsigned long a5, struct pt_regs *regs);
asmlinkage int sys_clone(unsigned long clone_flags, unsigned long usp,
int __user *parent_tidp, void __user *child_threadptr,
int __user *child_tidp, int p6, struct pt_regs *regs);
diff --git a/arch/powerpc/include/asm/thread_info.h b/arch/powerpc/include/asm/thread_info.h
index 8ceea14..406b7b9 100644
--- a/arch/powerpc/include/asm/thread_info.h
+++ b/arch/powerpc/include/asm/thread_info.h
@@ -182,6 +182,8 @@ static inline bool test_thread_local_flags(unsigned int flags)
#define is_32bit_task() (1)
#endif
+#define tsk_is_polling(t) test_tsk_thread_flag(t, TIF_POLLING_NRFLAG)
+
#endif /* !__ASSEMBLY__ */
#endif /* __KERNEL__ */
diff --git a/arch/powerpc/include/asm/unistd.h b/arch/powerpc/include/asm/unistd.h
index c683fa3..2533752 100644
--- a/arch/powerpc/include/asm/unistd.h
+++ b/arch/powerpc/include/asm/unistd.h
@@ -421,6 +421,8 @@
#define __ARCH_WANT_SYS_NEWFSTATAT
#define __ARCH_WANT_COMPAT_SYS_SENDFILE
#endif
+#define __ARCH_WANT_SYS_EXECVE
+#define __ARCH_WANT_KERNEL_EXECVE
/*
* "Conditional" syscalls
diff --git a/arch/powerpc/kernel/entry_32.S b/arch/powerpc/kernel/entry_32.S
index af37528..9499385 100644
--- a/arch/powerpc/kernel/entry_32.S
+++ b/arch/powerpc/kernel/entry_32.S
@@ -435,6 +435,22 @@ ret_from_fork:
li r3,0
b ret_from_syscall
+ .globl ret_from_kernel_thread
+ret_from_kernel_thread:
+ REST_NVGPRS(r1)
+ bl schedule_tail
+ mtlr r14
+ mr r3,r15
+ PPC440EP_ERR42
+ blrl
+ li r3,0
+ b do_exit # no return
+
+ .globl __ret_from_kernel_execve
+__ret_from_kernel_execve:
+ addi r1,r3,-STACK_FRAME_OVERHEAD
+ b ret_from_syscall
+
/* Traced system call support */
syscall_dotrace:
SAVE_NVGPRS(r1)
diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S
index 0e931aa..56e0ff0 100644
--- a/arch/powerpc/kernel/entry_64.S
+++ b/arch/powerpc/kernel/entry_64.S
@@ -370,6 +370,22 @@ _GLOBAL(ret_from_fork)
li r3,0
b syscall_exit
+_GLOBAL(ret_from_kernel_thread)
+ bl .schedule_tail
+ REST_NVGPRS(r1)
+ REST_GPR(2,r1)
+ mtlr r14
+ mr r3,r15
+ blrl
+ li r3,0
+ b .do_exit # no return
+
+_GLOBAL(__ret_from_kernel_execve)
+ addi r1,r3,-STACK_FRAME_OVERHEAD
+ li r10,1
+ std r10,SOFTE(r1)
+ b syscall_exit
+
.section ".toc","aw"
DSCR_DEFAULT:
.tc dscr_default[TC],dscr_default
diff --git a/arch/powerpc/kernel/misc.S b/arch/powerpc/kernel/misc.S
index ba16874..7ce26d4 100644
--- a/arch/powerpc/kernel/misc.S
+++ b/arch/powerpc/kernel/misc.S
@@ -54,13 +54,6 @@ _GLOBAL(add_reloc_offset)
.align 3
2: PPC_LONG 1b
-_GLOBAL(kernel_execve)
- li r0,__NR_execve
- sc
- bnslr
- neg r3,r3
- blr
-
_GLOBAL(setjmp)
mflr r0
PPC_STL r0,0(r3)
diff --git a/arch/powerpc/kernel/misc_32.S b/arch/powerpc/kernel/misc_32.S
index 407e293..19e096b 100644
--- a/arch/powerpc/kernel/misc_32.S
+++ b/arch/powerpc/kernel/misc_32.S
@@ -663,39 +663,6 @@ _GLOBAL(abs)
sub r3,r3,r4
blr
-/*
- * Create a kernel thread
- * kernel_thread(fn, arg, flags)
- */
-_GLOBAL(kernel_thread)
- stwu r1,-16(r1)
- stw r30,8(r1)
- stw r31,12(r1)
- mr r30,r3 /* function */
- mr r31,r4 /* argument */
- ori r3,r5,CLONE_VM /* flags */
- oris r3,r3,CLONE_UNTRACED>>16
- li r4,0 /* new sp (unused) */
- li r0,__NR_clone
- sc
- bns+ 1f /* did system call indicate error? */
- neg r3,r3 /* if so, make return code negative */
-1: cmpwi 0,r3,0 /* parent or child? */
- bne 2f /* return if parent */
- li r0,0 /* make top-level stack frame */
- stwu r0,-16(r1)
- mtlr r30 /* fn addr in lr */
- mr r3,r31 /* load arg and call fn */
- PPC440EP_ERR42
- blrl
- li r0,__NR_exit /* exit if function returns */
- li r3,0
- sc
-2: lwz r30,8(r1)
- lwz r31,12(r1)
- addi r1,r1,16
- blr
-
#ifdef CONFIG_SMP
_GLOBAL(start_secondary_resume)
/* Reset stack */
diff --git a/arch/powerpc/kernel/misc_64.S b/arch/powerpc/kernel/misc_64.S
index 565b786..5cfa800 100644
--- a/arch/powerpc/kernel/misc_64.S
+++ b/arch/powerpc/kernel/misc_64.S
@@ -407,40 +407,6 @@ _GLOBAL(scom970_write)
/*
- * Create a kernel thread
- * kernel_thread(fn, arg, flags)
- */
-_GLOBAL(kernel_thread)
- std r29,-24(r1)
- std r30,-16(r1)
- stdu r1,-STACK_FRAME_OVERHEAD(r1)
- mr r29,r3
- mr r30,r4
- ori r3,r5,CLONE_VM /* flags */
- oris r3,r3,(CLONE_UNTRACED>>16)
- li r4,0 /* new sp (unused) */
- li r0,__NR_clone
- sc
- bns+ 1f /* did system call indicate error? */
- neg r3,r3 /* if so, make return code negative */
-1: cmpdi 0,r3,0 /* parent or child? */
- bne 2f /* return if parent */
- li r0,0
- stdu r0,-STACK_FRAME_OVERHEAD(r1)
- ld r2,8(r29)
- ld r29,0(r29)
- mtlr r29 /* fn addr in lr */
- mr r3,r30 /* load arg and call fn */
- blrl
- li r0,__NR_exit /* exit after child exits */
- li r3,0
- sc
-2: addi r1,r1,STACK_FRAME_OVERHEAD
- ld r29,-24(r1)
- ld r30,-16(r1)
- blr
-
-/*
* disable_kernel_fp()
* Disable the FPU.
*/
diff --git a/arch/powerpc/kernel/ppc_ksyms.c b/arch/powerpc/kernel/ppc_ksyms.c
index 3e40315..19e4288 100644
--- a/arch/powerpc/kernel/ppc_ksyms.c
+++ b/arch/powerpc/kernel/ppc_ksyms.c
@@ -94,7 +94,6 @@ EXPORT_SYMBOL(pci_dram_offset);
#endif /* CONFIG_PCI */
EXPORT_SYMBOL(start_thread);
-EXPORT_SYMBOL(kernel_thread);
EXPORT_SYMBOL(giveup_fpu);
#ifdef CONFIG_ALTIVEC
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index d5ad666..ba48233 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -733,30 +733,39 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
extern unsigned long dscr_default; /* defined in arch/powerpc/kernel/sysfs.c */
int copy_thread(unsigned long clone_flags, unsigned long usp,
- unsigned long unused, struct task_struct *p,
+ unsigned long arg, struct task_struct *p,
struct pt_regs *regs)
{
struct pt_regs *childregs, *kregs;
extern void ret_from_fork(void);
+ extern void ret_from_kernel_thread(void);
+ void (*f)(void);
unsigned long sp = (unsigned long)task_stack_page(p) + THREAD_SIZE;
- CHECK_FULL_REGS(regs);
/* Copy registers */
sp -= sizeof(struct pt_regs);
childregs = (struct pt_regs *) sp;
- *childregs = *regs;
- if ((childregs->msr & MSR_PR) == 0) {
+ if (!regs) {
/* for kernel thread, set `current' and stackptr in new task */
+ memset(childregs, 0, sizeof(struct pt_regs));
childregs->gpr[1] = sp + sizeof(struct pt_regs);
-#ifdef CONFIG_PPC32
- childregs->gpr[2] = (unsigned long) p;
-#else
+#ifdef CONFIG_PPC64
+ childregs->gpr[14] = *(unsigned long *)usp;
+ childregs->gpr[2] = ((unsigned long *)usp)[1],
clear_tsk_thread_flag(p, TIF_32BIT);
+#else
+ childregs->gpr[14] = usp; /* function */
+ childregs->gpr[2] = (unsigned long) p;
#endif
+ childregs->gpr[15] = arg;
p->thread.regs = NULL; /* no user register state */
+ f = ret_from_kernel_thread;
} else {
+ CHECK_FULL_REGS(regs);
+ *childregs = *regs;
childregs->gpr[1] = usp;
p->thread.regs = childregs;
+ childregs->gpr[3] = 0; /* Result from fork() */
if (clone_flags & CLONE_SETTLS) {
#ifdef CONFIG_PPC64
if (!is_32bit_task())
@@ -765,8 +774,9 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
#endif
childregs->gpr[2] = childregs->gpr[6];
}
+
+ f = ret_from_fork;
}
- childregs->gpr[3] = 0; /* Result from fork() */
sp -= STACK_FRAME_OVERHEAD;
/*
@@ -805,19 +815,17 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
p->thread.dscr = current->thread.dscr;
}
#endif
-
/*
* The PPC64 ABI makes use of a TOC to contain function
* pointers. The function (ret_from_except) is actually a pointer
* to the TOC entry. The first entry is a pointer to the actual
* function.
- */
+ */
#ifdef CONFIG_PPC64
- kregs->nip = *((unsigned long *)ret_from_fork);
+ kregs->nip = *((unsigned long *)f);
#else
- kregs->nip = (unsigned long)ret_from_fork;
+ kregs->nip = (unsigned long)f;
#endif
-
return 0;
}
@@ -1055,26 +1063,13 @@ int sys_vfork(unsigned long p1, unsigned long p2, unsigned long p3,
regs, 0, NULL, NULL);
}
-int sys_execve(unsigned long a0, unsigned long a1, unsigned long a2,
- unsigned long a3, unsigned long a4, unsigned long a5,
- struct pt_regs *regs)
+void __ret_from_kernel_execve(struct pt_regs *normal)
+__noreturn;
+
+void ret_from_kernel_execve(struct pt_regs *normal)
{
- int error;
- char *filename;
-
- filename = getname((const char __user *) a0);
- error = PTR_ERR(filename);
- if (IS_ERR(filename))
- goto out;
- flush_fp_to_thread(current);
- flush_altivec_to_thread(current);
- flush_spe_to_thread(current);
- error = do_execve(filename,
- (const char __user *const __user *) a1,
- (const char __user *const __user *) a2, regs);
- putname(filename);
-out:
- return error;
+ set_thread_flag(TIF_RESTOREALL);
+ __ret_from_kernel_execve(normal);
}
static inline int valid_irq_stack(unsigned long sp, struct task_struct *p,
diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c
index 8b4c049..804e323 100644
--- a/arch/powerpc/kernel/signal_32.c
+++ b/arch/powerpc/kernel/signal_32.c
@@ -35,7 +35,6 @@
#include <linux/stddef.h>
#include <linux/tty.h>
#include <linux/binfmts.h>
-#include <linux/freezer.h>
#endif
#include <asm/uaccess.h>
diff --git a/arch/powerpc/kernel/sys_ppc32.c b/arch/powerpc/kernel/sys_ppc32.c
index abd1112..9c2ed90 100644
--- a/arch/powerpc/kernel/sys_ppc32.c
+++ b/arch/powerpc/kernel/sys_ppc32.c
@@ -156,28 +156,6 @@ asmlinkage long compat_sys_sendfile64_wrapper(u32 out_fd, u32 in_fd,
(off_t __user *)offset, count);
}
-long compat_sys_execve(unsigned long a0, unsigned long a1, unsigned long a2,
- unsigned long a3, unsigned long a4, unsigned long a5,
- struct pt_regs *regs)
-{
- int error;
- char * filename;
-
- filename = getname((char __user *) a0);
- error = PTR_ERR(filename);
- if (IS_ERR(filename))
- goto out;
- flush_fp_to_thread(current);
- flush_altivec_to_thread(current);
-
- error = compat_do_execve(filename, compat_ptr(a1), compat_ptr(a2), regs);
-
- putname(filename);
-
-out:
- return error;
-}
-
/* Note: it is necessary to treat option as an unsigned int,
* with the corresponding cast to a signed int to insure that the
* proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
diff --git a/arch/powerpc/platforms/pseries/hotplug-memory.c b/arch/powerpc/platforms/pseries/hotplug-memory.c
index dc0a035..ecdb0a6 100644
--- a/arch/powerpc/platforms/pseries/hotplug-memory.c
+++ b/arch/powerpc/platforms/pseries/hotplug-memory.c
@@ -77,8 +77,9 @@ static int pseries_remove_memblock(unsigned long base, unsigned int memblock_siz
{
unsigned long start, start_pfn;
struct zone *zone;
- int i, ret;
- int sections_to_remove;
+ int ret;
+ unsigned long section;
+ unsigned long sections_to_remove;
start_pfn = base >> PAGE_SHIFT;
@@ -99,9 +100,9 @@ static int pseries_remove_memblock(unsigned long base, unsigned int memblock_siz
* while writing to it. So we have to defer it to here.
*/
sections_to_remove = (memblock_size >> PAGE_SHIFT) / PAGES_PER_SECTION;
- for (i = 0; i < sections_to_remove; i++) {
- unsigned long pfn = start_pfn + i * PAGES_PER_SECTION;
- ret = __remove_pages(zone, start_pfn, PAGES_PER_SECTION);
+ for (section = 0; section < sections_to_remove; section++) {
+ unsigned long pfn = start_pfn + section * PAGES_PER_SECTION;
+ ret = __remove_pages(zone, pfn, PAGES_PER_SECTION);
if (ret)
return ret;
}
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig
index ceff7ae..99d2d79 100644
--- a/arch/s390/Kconfig
+++ b/arch/s390/Kconfig
@@ -135,6 +135,7 @@ config S390
select GENERIC_CLOCKEVENTS
select KTIME_SCALAR if 32BIT
select HAVE_ARCH_SECCOMP_FILTER
+ select GENERIC_KERNEL_THREAD
config SCHED_OMIT_FRAME_POINTER
def_bool y
diff --git a/arch/s390/Kconfig.debug b/arch/s390/Kconfig.debug
index d76cef3..fc32a2d 100644
--- a/arch/s390/Kconfig.debug
+++ b/arch/s390/Kconfig.debug
@@ -31,6 +31,18 @@ config DEBUG_STRICT_USER_COPY_CHECKS
If unsure, or if you run an older (pre 4.4) gcc, say N.
+config S390_PTDUMP
+ bool "Export kernel pagetable layout to userspace via debugfs"
+ depends on DEBUG_KERNEL
+ select DEBUG_FS
+ ---help---
+ Say Y here if you want to show the kernel pagetable layout in a
+ debugfs file. This information is only useful for kernel developers
+ who are working in architecture specific areas of the kernel.
+ It is probably not a good idea to enable this feature in a production
+ kernel.
+ If in doubt, say "N"
+
config DEBUG_SET_MODULE_RONX
def_bool y
depends on MODULES
diff --git a/arch/s390/include/asm/Kbuild b/arch/s390/include/asm/Kbuild
index f18fc79..0633dc6 100644
--- a/arch/s390/include/asm/Kbuild
+++ b/arch/s390/include/asm/Kbuild
@@ -1,17 +1,3 @@
-include include/asm-generic/Kbuild.asm
-header-y += chpid.h
-header-y += chsc.h
-header-y += cmb.h
-header-y += dasd.h
-header-y += debug.h
-header-y += kvm_virtio.h
-header-y += monwriter.h
-header-y += qeth.h
-header-y += schid.h
-header-y += tape390.h
-header-y += ucontext.h
-header-y += vtoc.h
-header-y += zcrypt.h
generic-y += clkdev.h
diff --git a/arch/s390/include/asm/chpid.h b/arch/s390/include/asm/chpid.h
index e5bde9f..38c405e 100644
--- a/arch/s390/include/asm/chpid.h
+++ b/arch/s390/include/asm/chpid.h
@@ -1,24 +1,11 @@
/*
- * Copyright IBM Corp. 2007
+ * Copyright IBM Corp. 2007, 2012
* Author(s): Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
*/
-
#ifndef _ASM_S390_CHPID_H
#define _ASM_S390_CHPID_H
-#include <linux/string.h>
-#include <linux/types.h>
-
-#define __MAX_CHPID 255
-
-struct chp_id {
- u8 reserved1;
- u8 cssid;
- u8 reserved2;
- u8 id;
-} __attribute__((packed));
-
-#ifdef __KERNEL__
+#include <uapi/asm/chpid.h>
#include <asm/cio.h>
static inline void chp_id_init(struct chp_id *chpid)
@@ -49,6 +36,4 @@ static inline int chp_id_is_valid(struct chp_id *chpid)
#define chp_id_for_each(c) \
for (chp_id_init(c); chp_id_is_valid(c); chp_id_next(c))
-#endif /* __KERNEL */
-
#endif /* _ASM_S390_CHPID_H */
diff --git a/arch/s390/include/asm/cmb.h b/arch/s390/include/asm/cmb.h
index 39ae032..806eac1 100644
--- a/arch/s390/include/asm/cmb.h
+++ b/arch/s390/include/asm/cmb.h
@@ -1,61 +1,12 @@
#ifndef S390_CMB_H
#define S390_CMB_H
-#include <linux/types.h>
+#include <uapi/asm/cmb.h>
-/**
- * struct cmbdata - channel measurement block data for user space
- * @size: size of the stored data
- * @elapsed_time: time since last sampling
- * @ssch_rsch_count: number of ssch and rsch
- * @sample_count: number of samples
- * @device_connect_time: time of device connect
- * @function_pending_time: time of function pending
- * @device_disconnect_time: time of device disconnect
- * @control_unit_queuing_time: time of control unit queuing
- * @device_active_only_time: time of device active only
- * @device_busy_time: time of device busy (ext. format)
- * @initial_command_response_time: initial command response time (ext. format)
- *
- * All values are stored as 64 bit for simplicity, especially
- * in 32 bit emulation mode. All time values are normalized to
- * nanoseconds.
- * Currently, two formats are known, which differ by the size of
- * this structure, i.e. the last two members are only set when
- * the extended channel measurement facility (first shipped in
- * z990 machines) is activated.
- * Potentially, more fields could be added, which would result in a
- * new ioctl number.
- */
-struct cmbdata {
- __u64 size;
- __u64 elapsed_time;
- /* basic and exended format: */
- __u64 ssch_rsch_count;
- __u64 sample_count;
- __u64 device_connect_time;
- __u64 function_pending_time;
- __u64 device_disconnect_time;
- __u64 control_unit_queuing_time;
- __u64 device_active_only_time;
- /* extended format only: */
- __u64 device_busy_time;
- __u64 initial_command_response_time;
-};
-
-/* enable channel measurement */
-#define BIODASDCMFENABLE _IO(DASD_IOCTL_LETTER, 32)
-/* enable channel measurement */
-#define BIODASDCMFDISABLE _IO(DASD_IOCTL_LETTER, 33)
-/* read channel measurement data */
-#define BIODASDREADALLCMB _IOWR(DASD_IOCTL_LETTER, 33, struct cmbdata)
-
-#ifdef __KERNEL__
struct ccw_device;
extern int enable_cmf(struct ccw_device *cdev);
extern int disable_cmf(struct ccw_device *cdev);
extern u64 cmf_read(struct ccw_device *cdev, int index);
extern int cmf_readall(struct ccw_device *cdev, struct cmbdata *data);
-#endif /* __KERNEL__ */
#endif /* S390_CMB_H */
diff --git a/arch/s390/include/asm/css_chars.h b/arch/s390/include/asm/css_chars.h
index a06ebc2..7e1c917 100644
--- a/arch/s390/include/asm/css_chars.h
+++ b/arch/s390/include/asm/css_chars.h
@@ -3,8 +3,6 @@
#include <linux/types.h>
-#ifdef __KERNEL__
-
struct css_general_char {
u64 : 12;
u32 dynio : 1; /* bit 12 */
@@ -35,5 +33,4 @@ struct css_general_char {
extern struct css_general_char css_general_characteristics;
-#endif /* __KERNEL__ */
#endif
diff --git a/arch/s390/include/asm/debug.h b/arch/s390/include/asm/debug.h
index f39677e..188c505 100644
--- a/arch/s390/include/asm/debug.h
+++ b/arch/s390/include/asm/debug.h
@@ -3,39 +3,14 @@
*
* Copyright IBM Corp. 1999, 2000
*/
-
#ifndef DEBUG_H
#define DEBUG_H
-#include <linux/fs.h>
-
-/* Note:
- * struct __debug_entry must be defined outside of #ifdef __KERNEL__
- * in order to allow a user program to analyze the 'raw'-view.
- */
-
-struct __debug_entry{
- union {
- struct {
- unsigned long long clock:52;
- unsigned long long exception:1;
- unsigned long long level:3;
- unsigned long long cpuid:8;
- } fields;
-
- unsigned long long stck;
- } id;
- void* caller;
-} __attribute__((packed));
-
-
-#define __DEBUG_FEATURE_VERSION 2 /* version of debug feature */
-
-#ifdef __KERNEL__
#include <linux/string.h>
#include <linux/spinlock.h>
#include <linux/kernel.h>
#include <linux/time.h>
+#include <uapi/asm/debug.h>
#define DEBUG_MAX_LEVEL 6 /* debug levels range from 0 to 6 */
#define DEBUG_OFF_LEVEL -1 /* level where debug is switched off */
@@ -254,5 +229,4 @@ int debug_unregister_view(debug_info_t* id, struct debug_view* view);
#define PRINT_FATAL(x...) printk ( KERN_DEBUG PRINTK_HEADER x )
#endif /* DASD_DEBUG */
-#endif /* __KERNEL__ */
#endif /* DEBUG_H */
diff --git a/arch/s390/include/asm/kvm_para.h b/arch/s390/include/asm/kvm_para.h
index da44867..e0f8423 100644
--- a/arch/s390/include/asm/kvm_para.h
+++ b/arch/s390/include/asm/kvm_para.h
@@ -9,12 +9,6 @@
*
* Author(s): Christian Borntraeger <borntraeger@de.ibm.com>
*/
-
-#ifndef __S390_KVM_PARA_H
-#define __S390_KVM_PARA_H
-
-#ifdef __KERNEL__
-
/*
* Hypercalls for KVM on s390. The calling convention is similar to the
* s390 ABI, so we use R2-R6 for parameters 1-5. In addition we use R1
@@ -29,6 +23,12 @@
*
* This work is licensed under the terms of the GNU GPL, version 2.
*/
+#ifndef __S390_KVM_PARA_H
+#define __S390_KVM_PARA_H
+
+#include <uapi/asm/kvm_para.h>
+
+
static inline long kvm_hypercall0(unsigned long nr)
{
@@ -154,6 +154,4 @@ static inline bool kvm_check_and_clear_guest_paused(void)
return false;
}
-#endif
-
#endif /* __S390_KVM_PARA_H */
diff --git a/arch/s390/include/asm/mman.h b/arch/s390/include/asm/mman.h
index abc1932..0e47a57 100644
--- a/arch/s390/include/asm/mman.h
+++ b/arch/s390/include/asm/mman.h
@@ -3,17 +3,13 @@
*
* Derived from "include/asm-i386/mman.h"
*/
-
#ifndef __S390_MMAN_H__
#define __S390_MMAN_H__
-#include <asm-generic/mman.h>
+#include <uapi/asm/mman.h>
-#if defined(__KERNEL__)
#if !defined(__ASSEMBLY__) && defined(CONFIG_64BIT)
int s390_mmap_check(unsigned long addr, unsigned long len);
#define arch_mmap_check(addr,len,flags) s390_mmap_check(addr,len)
#endif
-#endif
-
#endif /* __S390_MMAN_H__ */
diff --git a/arch/s390/include/asm/page.h b/arch/s390/include/asm/page.h
index 27ab3c7..6d53670 100644
--- a/arch/s390/include/asm/page.h
+++ b/arch/s390/include/asm/page.h
@@ -30,12 +30,20 @@
#include <asm/setup.h>
#ifndef __ASSEMBLY__
+static unsigned long pfmf(unsigned long function, unsigned long address)
+{
+ asm volatile(
+ " .insn rre,0xb9af0000,%[function],%[address]"
+ : [address] "+a" (address)
+ : [function] "d" (function)
+ : "memory");
+ return address;
+}
+
static inline void clear_page(void *page)
{
if (MACHINE_HAS_PFMF) {
- asm volatile(
- " .insn rre,0xb9af0000,%0,%1"
- : : "d" (0x10000), "a" (page) : "memory", "cc");
+ pfmf(0x10000, (unsigned long)page);
} else {
register unsigned long reg1 asm ("1") = 0;
register void *reg2 asm ("2") = page;
diff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h
index 979fe3d..dd647c9 100644
--- a/arch/s390/include/asm/pgtable.h
+++ b/arch/s390/include/asm/pgtable.h
@@ -119,13 +119,12 @@ static inline int is_zero_pfn(unsigned long pfn)
#ifndef __ASSEMBLY__
/*
- * The vmalloc area will always be on the topmost area of the kernel
- * mapping. We reserve 96MB (31bit) / 128GB (64bit) for vmalloc,
- * which should be enough for any sane case.
- * By putting vmalloc at the top, we maximise the gap between physical
- * memory and vmalloc to catch misplaced memory accesses. As a side
- * effect, this also makes sure that 64 bit module code cannot be used
- * as system call address.
+ * The vmalloc and module area will always be on the topmost area of the kernel
+ * mapping. We reserve 96MB (31bit) / 128GB (64bit) for vmalloc and modules.
+ * On 64 bit kernels we have a 2GB area at the top of the vmalloc area where
+ * modules will reside. That makes sure that inter module branches always
+ * happen without trampolines and in addition the placement within a 2GB frame
+ * is branch prediction unit friendly.
*/
extern unsigned long VMALLOC_START;
extern unsigned long VMALLOC_END;
@@ -133,6 +132,14 @@ extern struct page *vmemmap;
#define VMEM_MAX_PHYS ((unsigned long) vmemmap)
+#ifdef CONFIG_64BIT
+extern unsigned long MODULES_VADDR;
+extern unsigned long MODULES_END;
+#define MODULES_VADDR MODULES_VADDR
+#define MODULES_END MODULES_END
+#define MODULES_LEN (1UL << 31)
+#endif
+
/*
* A 31 bit pagetable entry of S390 has following format:
* | PFRA | | OS |
@@ -507,6 +514,15 @@ static inline int pmd_none(pmd_t pmd)
return (pmd_val(pmd) & _SEGMENT_ENTRY_INV) != 0UL;
}
+static inline int pmd_large(pmd_t pmd)
+{
+#ifdef CONFIG_64BIT
+ return !!(pmd_val(pmd) & _SEGMENT_ENTRY_LARGE);
+#else
+ return 0;
+#endif
+}
+
static inline int pmd_bad(pmd_t pmd)
{
unsigned long mask = ~_SEGMENT_ENTRY_ORIGIN & ~_SEGMENT_ENTRY_INV;
diff --git a/arch/s390/include/asm/processor.h b/arch/s390/include/asm/processor.h
index 56831df..94e749c 100644
--- a/arch/s390/include/asm/processor.h
+++ b/arch/s390/include/asm/processor.h
@@ -35,6 +35,7 @@ static inline void get_cpu_id(struct cpuid *ptr)
extern void s390_adjust_jiffies(void);
extern const struct seq_operations cpuinfo_op;
extern int sysctl_ieee_emulation_warnings;
+extern void execve_tail(void);
/*
* User space process size: 2GB for 31 bit, 4TB or 8PT for 64 bit.
@@ -126,6 +127,7 @@ struct stack_frame {
regs->psw.mask = psw_user_bits | PSW_MASK_EA | PSW_MASK_BA; \
regs->psw.addr = new_psw | PSW_ADDR_AMODE; \
regs->gprs[15] = new_stackp; \
+ execve_tail(); \
} while (0)
#define start_thread31(regs, new_psw, new_stackp) do { \
@@ -135,6 +137,7 @@ struct stack_frame {
__tlb_flush_mm(current->mm); \
crst_table_downgrade(current->mm, 1UL << 31); \
update_mm(current->mm, current); \
+ execve_tail(); \
} while (0)
/* Forward declaration, a strange C thing */
@@ -150,7 +153,6 @@ static inline void show_cacheinfo(struct seq_file *m) { }
/* Free all resources held by a thread. */
extern void release_thread(struct task_struct *);
-extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
/*
* Return saved PC of a blocked thread.
diff --git a/arch/s390/include/asm/ptrace.h b/arch/s390/include/asm/ptrace.h
index ce20a53..3ee5da3 100644
--- a/arch/s390/include/asm/ptrace.h
+++ b/arch/s390/include/asm/ptrace.h
@@ -3,316 +3,17 @@
* Copyright IBM Corp. 1999, 2000
* Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
*/
-
#ifndef _S390_PTRACE_H
#define _S390_PTRACE_H
-/*
- * Offsets in the user_regs_struct. They are used for the ptrace
- * system call and in entry.S
- */
-#ifndef __s390x__
-
-#define PT_PSWMASK 0x00
-#define PT_PSWADDR 0x04
-#define PT_GPR0 0x08
-#define PT_GPR1 0x0C
-#define PT_GPR2 0x10
-#define PT_GPR3 0x14
-#define PT_GPR4 0x18
-#define PT_GPR5 0x1C
-#define PT_GPR6 0x20
-#define PT_GPR7 0x24
-#define PT_GPR8 0x28
-#define PT_GPR9 0x2C
-#define PT_GPR10 0x30
-#define PT_GPR11 0x34
-#define PT_GPR12 0x38
-#define PT_GPR13 0x3C
-#define PT_GPR14 0x40
-#define PT_GPR15 0x44
-#define PT_ACR0 0x48
-#define PT_ACR1 0x4C
-#define PT_ACR2 0x50
-#define PT_ACR3 0x54
-#define PT_ACR4 0x58
-#define PT_ACR5 0x5C
-#define PT_ACR6 0x60
-#define PT_ACR7 0x64
-#define PT_ACR8 0x68
-#define PT_ACR9 0x6C
-#define PT_ACR10 0x70
-#define PT_ACR11 0x74
-#define PT_ACR12 0x78
-#define PT_ACR13 0x7C
-#define PT_ACR14 0x80
-#define PT_ACR15 0x84
-#define PT_ORIGGPR2 0x88
-#define PT_FPC 0x90
-/*
- * A nasty fact of life that the ptrace api
- * only supports passing of longs.
- */
-#define PT_FPR0_HI 0x98
-#define PT_FPR0_LO 0x9C
-#define PT_FPR1_HI 0xA0
-#define PT_FPR1_LO 0xA4
-#define PT_FPR2_HI 0xA8
-#define PT_FPR2_LO 0xAC
-#define PT_FPR3_HI 0xB0
-#define PT_FPR3_LO 0xB4
-#define PT_FPR4_HI 0xB8
-#define PT_FPR4_LO 0xBC
-#define PT_FPR5_HI 0xC0
-#define PT_FPR5_LO 0xC4
-#define PT_FPR6_HI 0xC8
-#define PT_FPR6_LO 0xCC
-#define PT_FPR7_HI 0xD0
-#define PT_FPR7_LO 0xD4
-#define PT_FPR8_HI 0xD8
-#define PT_FPR8_LO 0XDC
-#define PT_FPR9_HI 0xE0
-#define PT_FPR9_LO 0xE4
-#define PT_FPR10_HI 0xE8
-#define PT_FPR10_LO 0xEC
-#define PT_FPR11_HI 0xF0
-#define PT_FPR11_LO 0xF4
-#define PT_FPR12_HI 0xF8
-#define PT_FPR12_LO 0xFC
-#define PT_FPR13_HI 0x100
-#define PT_FPR13_LO 0x104
-#define PT_FPR14_HI 0x108
-#define PT_FPR14_LO 0x10C
-#define PT_FPR15_HI 0x110
-#define PT_FPR15_LO 0x114
-#define PT_CR_9 0x118
-#define PT_CR_10 0x11C
-#define PT_CR_11 0x120
-#define PT_IEEE_IP 0x13C
-#define PT_LASTOFF PT_IEEE_IP
-#define PT_ENDREGS 0x140-1
-
-#define GPR_SIZE 4
-#define CR_SIZE 4
-
-#define STACK_FRAME_OVERHEAD 96 /* size of minimum stack frame */
-
-#else /* __s390x__ */
-
-#define PT_PSWMASK 0x00
-#define PT_PSWADDR 0x08
-#define PT_GPR0 0x10
-#define PT_GPR1 0x18
-#define PT_GPR2 0x20
-#define PT_GPR3 0x28
-#define PT_GPR4 0x30
-#define PT_GPR5 0x38
-#define PT_GPR6 0x40
-#define PT_GPR7 0x48
-#define PT_GPR8 0x50
-#define PT_GPR9 0x58
-#define PT_GPR10 0x60
-#define PT_GPR11 0x68
-#define PT_GPR12 0x70
-#define PT_GPR13 0x78
-#define PT_GPR14 0x80
-#define PT_GPR15 0x88
-#define PT_ACR0 0x90
-#define PT_ACR1 0x94
-#define PT_ACR2 0x98
-#define PT_ACR3 0x9C
-#define PT_ACR4 0xA0
-#define PT_ACR5 0xA4
-#define PT_ACR6 0xA8
-#define PT_ACR7 0xAC
-#define PT_ACR8 0xB0
-#define PT_ACR9 0xB4
-#define PT_ACR10 0xB8
-#define PT_ACR11 0xBC
-#define PT_ACR12 0xC0
-#define PT_ACR13 0xC4
-#define PT_ACR14 0xC8
-#define PT_ACR15 0xCC
-#define PT_ORIGGPR2 0xD0
-#define PT_FPC 0xD8
-#define PT_FPR0 0xE0
-#define PT_FPR1 0xE8
-#define PT_FPR2 0xF0
-#define PT_FPR3 0xF8
-#define PT_FPR4 0x100
-#define PT_FPR5 0x108
-#define PT_FPR6 0x110
-#define PT_FPR7 0x118
-#define PT_FPR8 0x120
-#define PT_FPR9 0x128
-#define PT_FPR10 0x130
-#define PT_FPR11 0x138
-#define PT_FPR12 0x140
-#define PT_FPR13 0x148
-#define PT_FPR14 0x150
-#define PT_FPR15 0x158
-#define PT_CR_9 0x160
-#define PT_CR_10 0x168
-#define PT_CR_11 0x170
-#define PT_IEEE_IP 0x1A8
-#define PT_LASTOFF PT_IEEE_IP
-#define PT_ENDREGS 0x1B0-1
-
-#define GPR_SIZE 8
-#define CR_SIZE 8
-
-#define STACK_FRAME_OVERHEAD 160 /* size of minimum stack frame */
-
-#endif /* __s390x__ */
-
-#define NUM_GPRS 16
-#define NUM_FPRS 16
-#define NUM_CRS 16
-#define NUM_ACRS 16
-
-#define NUM_CR_WORDS 3
-
-#define FPR_SIZE 8
-#define FPC_SIZE 4
-#define FPC_PAD_SIZE 4 /* gcc insists on aligning the fpregs */
-#define ACR_SIZE 4
-
-
-#define PTRACE_OLDSETOPTIONS 21
+#include <uapi/asm/ptrace.h>
#ifndef __ASSEMBLY__
-#include <linux/stddef.h>
-#include <linux/types.h>
-
-typedef union
-{
- float f;
- double d;
- __u64 ui;
- struct
- {
- __u32 hi;
- __u32 lo;
- } fp;
-} freg_t;
-
-typedef struct
-{
- __u32 fpc;
- freg_t fprs[NUM_FPRS];
-} s390_fp_regs;
-
-#define FPC_EXCEPTION_MASK 0xF8000000
-#define FPC_FLAGS_MASK 0x00F80000
-#define FPC_DXC_MASK 0x0000FF00
-#define FPC_RM_MASK 0x00000003
-#define FPC_VALID_MASK 0xF8F8FF03
-
-/* this typedef defines how a Program Status Word looks like */
-typedef struct
-{
- unsigned long mask;
- unsigned long addr;
-} __attribute__ ((aligned(8))) psw_t;
-
-typedef struct
-{
- __u32 mask;
- __u32 addr;
-} __attribute__ ((aligned(8))) psw_compat_t;
-
#ifndef __s390x__
-
-#define PSW_MASK_PER 0x40000000UL
-#define PSW_MASK_DAT 0x04000000UL
-#define PSW_MASK_IO 0x02000000UL
-#define PSW_MASK_EXT 0x01000000UL
-#define PSW_MASK_KEY 0x00F00000UL
-#define PSW_MASK_BASE 0x00080000UL /* always one */
-#define PSW_MASK_MCHECK 0x00040000UL
-#define PSW_MASK_WAIT 0x00020000UL
-#define PSW_MASK_PSTATE 0x00010000UL
-#define PSW_MASK_ASC 0x0000C000UL
-#define PSW_MASK_CC 0x00003000UL
-#define PSW_MASK_PM 0x00000F00UL
-#define PSW_MASK_RI 0x00000000UL
-#define PSW_MASK_EA 0x00000000UL
-#define PSW_MASK_BA 0x00000000UL
-
-#define PSW_MASK_USER 0x00003F00UL
-
-#define PSW_ADDR_AMODE 0x80000000UL
-#define PSW_ADDR_INSN 0x7FFFFFFFUL
-
-#define PSW_DEFAULT_KEY (((unsigned long) PAGE_DEFAULT_ACC) << 20)
-
-#define PSW_ASC_PRIMARY 0x00000000UL
-#define PSW_ASC_ACCREG 0x00004000UL
-#define PSW_ASC_SECONDARY 0x00008000UL
-#define PSW_ASC_HOME 0x0000C000UL
-
#else /* __s390x__ */
-
-#define PSW_MASK_PER 0x4000000000000000UL
-#define PSW_MASK_DAT 0x0400000000000000UL
-#define PSW_MASK_IO 0x0200000000000000UL
-#define PSW_MASK_EXT 0x0100000000000000UL
-#define PSW_MASK_BASE 0x0000000000000000UL
-#define PSW_MASK_KEY 0x00F0000000000000UL
-#define PSW_MASK_MCHECK 0x0004000000000000UL
-#define PSW_MASK_WAIT 0x0002000000000000UL
-#define PSW_MASK_PSTATE 0x0001000000000000UL
-#define PSW_MASK_ASC 0x0000C00000000000UL
-#define PSW_MASK_CC 0x0000300000000000UL
-#define PSW_MASK_PM 0x00000F0000000000UL
-#define PSW_MASK_RI 0x0000008000000000UL
-#define PSW_MASK_EA 0x0000000100000000UL
-#define PSW_MASK_BA 0x0000000080000000UL
-
-#define PSW_MASK_USER 0x00003F8180000000UL
-
-#define PSW_ADDR_AMODE 0x0000000000000000UL
-#define PSW_ADDR_INSN 0xFFFFFFFFFFFFFFFFUL
-
-#define PSW_DEFAULT_KEY (((unsigned long) PAGE_DEFAULT_ACC) << 52)
-
-#define PSW_ASC_PRIMARY 0x0000000000000000UL
-#define PSW_ASC_ACCREG 0x0000400000000000UL
-#define PSW_ASC_SECONDARY 0x0000800000000000UL
-#define PSW_ASC_HOME 0x0000C00000000000UL
-
#endif /* __s390x__ */
-
-#ifdef __KERNEL__
extern long psw_kernel_bits;
extern long psw_user_bits;
-#endif
-
-/*
- * The s390_regs structure is used to define the elf_gregset_t.
- */
-typedef struct
-{
- psw_t psw;
- unsigned long gprs[NUM_GPRS];
- unsigned int acrs[NUM_ACRS];
- unsigned long orig_gpr2;
-} s390_regs;
-
-typedef struct
-{
- psw_compat_t psw;
- __u32 gprs[NUM_GPRS];
- __u32 acrs[NUM_ACRS];
- __u32 orig_gpr2;
-} s390_compat_regs;
-
-typedef struct
-{
- __u32 gprs_high[NUM_GPRS];
-} s390_compat_regs_high;
-
-#ifdef __KERNEL__
/*
* The pt_regs struct defines the way the registers are stored on
@@ -376,167 +77,8 @@ struct per_struct_kernel {
#define PER_CONTROL_SUSPENSION 0x00400000UL
#define PER_CONTROL_ALTERATION 0x00200000UL
-#endif
-
-/*
- * Now for the user space program event recording (trace) definitions.
- * The following structures are used only for the ptrace interface, don't
- * touch or even look at it if you don't want to modify the user-space
- * ptrace interface. In particular stay away from it for in-kernel PER.
- */
-typedef struct
-{
- unsigned long cr[NUM_CR_WORDS];
-} per_cr_words;
-
-#define PER_EM_MASK 0xE8000000UL
-
-typedef struct
-{
#ifdef __s390x__
- unsigned : 32;
#endif /* __s390x__ */
- unsigned em_branching : 1;
- unsigned em_instruction_fetch : 1;
- /*
- * Switching on storage alteration automatically fixes
- * the storage alteration event bit in the users std.
- */
- unsigned em_storage_alteration : 1;
- unsigned em_gpr_alt_unused : 1;
- unsigned em_store_real_address : 1;
- unsigned : 3;
- unsigned branch_addr_ctl : 1;
- unsigned : 1;
- unsigned storage_alt_space_ctl : 1;
- unsigned : 21;
- unsigned long starting_addr;
- unsigned long ending_addr;
-} per_cr_bits;
-
-typedef struct
-{
- unsigned short perc_atmid;
- unsigned long address;
- unsigned char access_id;
-} per_lowcore_words;
-
-typedef struct
-{
- unsigned perc_branching : 1;
- unsigned perc_instruction_fetch : 1;
- unsigned perc_storage_alteration : 1;
- unsigned perc_gpr_alt_unused : 1;
- unsigned perc_store_real_address : 1;
- unsigned : 3;
- unsigned atmid_psw_bit_31 : 1;
- unsigned atmid_validity_bit : 1;
- unsigned atmid_psw_bit_32 : 1;
- unsigned atmid_psw_bit_5 : 1;
- unsigned atmid_psw_bit_16 : 1;
- unsigned atmid_psw_bit_17 : 1;
- unsigned si : 2;
- unsigned long address;
- unsigned : 4;
- unsigned access_id : 4;
-} per_lowcore_bits;
-
-typedef struct
-{
- union {
- per_cr_words words;
- per_cr_bits bits;
- } control_regs;
- /*
- * Use these flags instead of setting em_instruction_fetch
- * directly they are used so that single stepping can be
- * switched on & off while not affecting other tracing
- */
- unsigned single_step : 1;
- unsigned instruction_fetch : 1;
- unsigned : 30;
- /*
- * These addresses are copied into cr10 & cr11 if single
- * stepping is switched off
- */
- unsigned long starting_addr;
- unsigned long ending_addr;
- union {
- per_lowcore_words words;
- per_lowcore_bits bits;
- } lowcore;
-} per_struct;
-
-typedef struct
-{
- unsigned int len;
- unsigned long kernel_addr;
- unsigned long process_addr;
-} ptrace_area;
-
-/*
- * S/390 specific non posix ptrace requests. I chose unusual values so
- * they are unlikely to clash with future ptrace definitions.
- */
-#define PTRACE_PEEKUSR_AREA 0x5000
-#define PTRACE_POKEUSR_AREA 0x5001
-#define PTRACE_PEEKTEXT_AREA 0x5002
-#define PTRACE_PEEKDATA_AREA 0x5003
-#define PTRACE_POKETEXT_AREA 0x5004
-#define PTRACE_POKEDATA_AREA 0x5005
-#define PTRACE_GET_LAST_BREAK 0x5006
-#define PTRACE_PEEK_SYSTEM_CALL 0x5007
-#define PTRACE_POKE_SYSTEM_CALL 0x5008
-#define PTRACE_ENABLE_TE 0x5009
-#define PTRACE_DISABLE_TE 0x5010
-
-/*
- * PT_PROT definition is loosely based on hppa bsd definition in
- * gdb/hppab-nat.c
- */
-#define PTRACE_PROT 21
-
-typedef enum
-{
- ptprot_set_access_watchpoint,
- ptprot_set_write_watchpoint,
- ptprot_disable_watchpoint
-} ptprot_flags;
-
-typedef struct
-{
- unsigned long lowaddr;
- unsigned long hiaddr;
- ptprot_flags prot;
-} ptprot_area;
-
-/* Sequence of bytes for breakpoint illegal instruction. */
-#define S390_BREAKPOINT {0x0,0x1}
-#define S390_BREAKPOINT_U16 ((__u16)0x0001)
-#define S390_SYSCALL_OPCODE ((__u16)0x0a00)
-#define S390_SYSCALL_SIZE 2
-
-/*
- * The user_regs_struct defines the way the user registers are
- * store on the stack for signal handling.
- */
-struct user_regs_struct
-{
- psw_t psw;
- unsigned long gprs[NUM_GPRS];
- unsigned int acrs[NUM_ACRS];
- unsigned long orig_gpr2;
- s390_fp_regs fp_regs;
- /*
- * These per registers are in here so that gdb can modify them
- * itself as there is no "official" ptrace interface for hardware
- * watchpoints. This is the way intel does it.
- */
- per_struct per_info;
- unsigned long ieee_instruction_pointer; /* obsolete, always 0 */
-};
-
-#ifdef __KERNEL__
/*
* These are defined as per linux/ptrace.h, which see.
*/
@@ -562,7 +104,5 @@ static inline unsigned long kernel_stack_pointer(struct pt_regs *regs)
return regs->gprs[15] & PSW_ADDR_INSN;
}
-#endif /* __KERNEL__ */
#endif /* __ASSEMBLY__ */
-
#endif /* _S390_PTRACE_H */
diff --git a/arch/s390/include/asm/schid.h b/arch/s390/include/asm/schid.h
index 3e4d401..40b47df 100644
--- a/arch/s390/include/asm/schid.h
+++ b/arch/s390/include/asm/schid.h
@@ -1,19 +1,8 @@
#ifndef ASM_SCHID_H
#define ASM_SCHID_H
-#include <linux/types.h>
-
-struct subchannel_id {
- __u32 cssid : 8;
- __u32 : 4;
- __u32 m : 1;
- __u32 ssid : 2;
- __u32 one : 1;
- __u32 sch_no : 16;
-} __attribute__ ((packed, aligned(4)));
-
-#ifdef __KERNEL__
#include <linux/string.h>
+#include <uapi/asm/schid.h>
/* Helper function for sane state of pre-allocated subchannel_id. */
static inline void
@@ -29,6 +18,4 @@ schid_equal(struct subchannel_id *schid1, struct subchannel_id *schid2)
return !memcmp(schid1, schid2, sizeof(struct subchannel_id));
}
-#endif /* __KERNEL__ */
-
#endif /* ASM_SCHID_H */
diff --git a/arch/s390/include/asm/setup.h b/arch/s390/include/asm/setup.h
index 8cfd731..f69f76b 100644
--- a/arch/s390/include/asm/setup.h
+++ b/arch/s390/include/asm/setup.h
@@ -2,15 +2,11 @@
* S390 version
* Copyright IBM Corp. 1999, 2010
*/
-
#ifndef _ASM_S390_SETUP_H
#define _ASM_S390_SETUP_H
-#define COMMAND_LINE_SIZE 4096
-
-#define ARCH_COMMAND_LINE_SIZE 896
+#include <uapi/asm/setup.h>
-#ifdef __KERNEL__
#define PARMAREA 0x10400
#define MEMORY_CHUNKS 256
@@ -75,8 +71,8 @@ extern unsigned int s390_user_mode;
#define MACHINE_FLAG_DIAG9C (1UL << 7)
#define MACHINE_FLAG_MVCOS (1UL << 8)
#define MACHINE_FLAG_KVM (1UL << 9)
-#define MACHINE_FLAG_HPAGE (1UL << 10)
-#define MACHINE_FLAG_PFMF (1UL << 11)
+#define MACHINE_FLAG_EDAT1 (1UL << 10)
+#define MACHINE_FLAG_EDAT2 (1UL << 11)
#define MACHINE_FLAG_LPAR (1UL << 12)
#define MACHINE_FLAG_SPP (1UL << 13)
#define MACHINE_FLAG_TOPOLOGY (1UL << 14)
@@ -88,6 +84,8 @@ extern unsigned int s390_user_mode;
#define MACHINE_IS_LPAR (S390_lowcore.machine_flags & MACHINE_FLAG_LPAR)
#define MACHINE_HAS_DIAG9C (S390_lowcore.machine_flags & MACHINE_FLAG_DIAG9C)
+#define MACHINE_HAS_PFMF MACHINE_HAS_EDAT1
+#define MACHINE_HAS_HPAGE MACHINE_HAS_EDAT1
#ifndef CONFIG_64BIT
#define MACHINE_HAS_IEEE (S390_lowcore.machine_flags & MACHINE_FLAG_IEEE)
@@ -96,8 +94,8 @@ extern unsigned int s390_user_mode;
#define MACHINE_HAS_DIAG44 (1)
#define MACHINE_HAS_MVPG (S390_lowcore.machine_flags & MACHINE_FLAG_MVPG)
#define MACHINE_HAS_MVCOS (0)
-#define MACHINE_HAS_HPAGE (0)
-#define MACHINE_HAS_PFMF (0)
+#define MACHINE_HAS_EDAT1 (0)
+#define MACHINE_HAS_EDAT2 (0)
#define MACHINE_HAS_SPP (0)
#define MACHINE_HAS_TOPOLOGY (0)
#define MACHINE_HAS_TE (0)
@@ -109,8 +107,8 @@ extern unsigned int s390_user_mode;
#define MACHINE_HAS_DIAG44 (S390_lowcore.machine_flags & MACHINE_FLAG_DIAG44)
#define MACHINE_HAS_MVPG (1)
#define MACHINE_HAS_MVCOS (S390_lowcore.machine_flags & MACHINE_FLAG_MVCOS)
-#define MACHINE_HAS_HPAGE (S390_lowcore.machine_flags & MACHINE_FLAG_HPAGE)
-#define MACHINE_HAS_PFMF (S390_lowcore.machine_flags & MACHINE_FLAG_PFMF)
+#define MACHINE_HAS_EDAT1 (S390_lowcore.machine_flags & MACHINE_FLAG_EDAT1)
+#define MACHINE_HAS_EDAT2 (S390_lowcore.machine_flags & MACHINE_FLAG_EDAT2)
#define MACHINE_HAS_SPP (S390_lowcore.machine_flags & MACHINE_FLAG_SPP)
#define MACHINE_HAS_TOPOLOGY (S390_lowcore.machine_flags & MACHINE_FLAG_TOPOLOGY)
#define MACHINE_HAS_TE (S390_lowcore.machine_flags & MACHINE_FLAG_TE)
@@ -173,5 +171,4 @@ extern void (*_machine_power_off)(void);
#define COMMAND_LINE 0x10480
#endif /* __ASSEMBLY__ */
-#endif /* __KERNEL__ */
#endif /* _ASM_S390_SETUP_H */
diff --git a/arch/s390/include/asm/signal.h b/arch/s390/include/asm/signal.h
index 6d4d9d1..bffdbdd 100644
--- a/arch/s390/include/asm/signal.h
+++ b/arch/s390/include/asm/signal.h
@@ -3,18 +3,11 @@
*
* Derived from "include/asm-i386/signal.h"
*/
-
#ifndef _ASMS390_SIGNAL_H
#define _ASMS390_SIGNAL_H
-#include <linux/types.h>
-#include <linux/time.h>
-
-/* Avoid too many header ordering problems. */
-struct siginfo;
-struct pt_regs;
+#include <uapi/asm/signal.h>
-#ifdef __KERNEL__
/* Most things should be clean enough to redefine this at will, if care
is taken to make libc match. */
#include <asm/sigcontext.h>
@@ -28,94 +21,6 @@ typedef struct {
unsigned long sig[_NSIG_WORDS];
} sigset_t;
-#else
-/* Here we must cater to libcs that poke about in kernel headers. */
-
-#define NSIG 32
-typedef unsigned long sigset_t;
-
-#endif /* __KERNEL__ */
-
-#define SIGHUP 1
-#define SIGINT 2
-#define SIGQUIT 3
-#define SIGILL 4
-#define SIGTRAP 5
-#define SIGABRT 6
-#define SIGIOT 6
-#define SIGBUS 7
-#define SIGFPE 8
-#define SIGKILL 9
-#define SIGUSR1 10
-#define SIGSEGV 11
-#define SIGUSR2 12
-#define SIGPIPE 13
-#define SIGALRM 14
-#define SIGTERM 15
-#define SIGSTKFLT 16
-#define SIGCHLD 17
-#define SIGCONT 18
-#define SIGSTOP 19
-#define SIGTSTP 20
-#define SIGTTIN 21
-#define SIGTTOU 22
-#define SIGURG 23
-#define SIGXCPU 24
-#define SIGXFSZ 25
-#define SIGVTALRM 26
-#define SIGPROF 27
-#define SIGWINCH 28
-#define SIGIO 29
-#define SIGPOLL SIGIO
-/*
-#define SIGLOST 29
-*/
-#define SIGPWR 30
-#define SIGSYS 31
-#define SIGUNUSED 31
-
-/* These should not be considered constants from userland. */
-#define SIGRTMIN 32
-#define SIGRTMAX _NSIG
-
-/*
- * SA_FLAGS values:
- *
- * SA_ONSTACK indicates that a registered stack_t will be used.
- * SA_RESTART flag to get restarting signals (which were the default long ago)
- * SA_NOCLDSTOP flag to turn off SIGCHLD when children stop.
- * SA_RESETHAND clears the handler when the signal is delivered.
- * SA_NOCLDWAIT flag on SIGCHLD to inhibit zombies.
- * SA_NODEFER prevents the current signal from being masked in the handler.
- *
- * SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single
- * Unix names RESETHAND and NODEFER respectively.
- */
-#define SA_NOCLDSTOP 0x00000001
-#define SA_NOCLDWAIT 0x00000002
-#define SA_SIGINFO 0x00000004
-#define SA_ONSTACK 0x08000000
-#define SA_RESTART 0x10000000
-#define SA_NODEFER 0x40000000
-#define SA_RESETHAND 0x80000000
-
-#define SA_NOMASK SA_NODEFER
-#define SA_ONESHOT SA_RESETHAND
-
-#define SA_RESTORER 0x04000000
-
-/*
- * sigaltstack controls
- */
-#define SS_ONSTACK 1
-#define SS_DISABLE 2
-
-#define MINSIGSTKSZ 2048
-#define SIGSTKSZ 8192
-
-#include <asm-generic/signal-defs.h>
-
-#ifdef __KERNEL__
struct old_sigaction {
__sighandler_t sa_handler;
old_sigset_t sa_mask;
@@ -136,35 +41,4 @@ struct k_sigaction {
#define ptrace_signal_deliver(regs, cookie) do { } while (0)
-#else
-/* Here we must cater to libcs that poke about in kernel headers. */
-
-struct sigaction {
- union {
- __sighandler_t _sa_handler;
- void (*_sa_sigaction)(int, struct siginfo *, void *);
- } _u;
-#ifndef __s390x__ /* lovely */
- sigset_t sa_mask;
- unsigned long sa_flags;
- void (*sa_restorer)(void);
-#else /* __s390x__ */
- unsigned long sa_flags;
- void (*sa_restorer)(void);
- sigset_t sa_mask;
-#endif /* __s390x__ */
-};
-
-#define sa_handler _u._sa_handler
-#define sa_sigaction _u._sa_sigaction
-
-#endif /* __KERNEL__ */
-
-typedef struct sigaltstack {
- void __user *ss_sp;
- int ss_flags;
- size_t ss_size;
-} stack_t;
-
-
#endif
diff --git a/arch/s390/include/asm/termios.h b/arch/s390/include/asm/termios.h
index cb9fe27..db028d1 100644
--- a/arch/s390/include/asm/termios.h
+++ b/arch/s390/include/asm/termios.h
@@ -3,49 +3,11 @@
*
* Derived from "include/asm-i386/termios.h"
*/
-
#ifndef _S390_TERMIOS_H
#define _S390_TERMIOS_H
-#include <asm/termbits.h>
-#include <asm/ioctls.h>
-
-struct winsize {
- unsigned short ws_row;
- unsigned short ws_col;
- unsigned short ws_xpixel;
- unsigned short ws_ypixel;
-};
-
-#define NCC 8
-struct termio {
- unsigned short c_iflag; /* input mode flags */
- unsigned short c_oflag; /* output mode flags */
- unsigned short c_cflag; /* control mode flags */
- unsigned short c_lflag; /* local mode flags */
- unsigned char c_line; /* line discipline */
- unsigned char c_cc[NCC]; /* control characters */
-};
+#include <uapi/asm/termios.h>
-/* modem lines */
-#define TIOCM_LE 0x001
-#define TIOCM_DTR 0x002
-#define TIOCM_RTS 0x004
-#define TIOCM_ST 0x008
-#define TIOCM_SR 0x010
-#define TIOCM_CTS 0x020
-#define TIOCM_CAR 0x040
-#define TIOCM_RNG 0x080
-#define TIOCM_DSR 0x100
-#define TIOCM_CD TIOCM_CAR
-#define TIOCM_RI TIOCM_RNG
-#define TIOCM_OUT1 0x2000
-#define TIOCM_OUT2 0x4000
-#define TIOCM_LOOP 0x8000
-
-/* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
-
-#ifdef __KERNEL__
/* intr=^C quit=^\ erase=del kill=^U
eof=^D vtime=\0 vmin=\1 sxtc=\0
@@ -60,6 +22,4 @@ struct termio {
#include <asm-generic/termios-base.h>
-#endif /* __KERNEL__ */
-
#endif /* _S390_TERMIOS_H */
diff --git a/arch/s390/include/asm/thread_info.h b/arch/s390/include/asm/thread_info.h
index bb08e2a..9e2cfe0 100644
--- a/arch/s390/include/asm/thread_info.h
+++ b/arch/s390/include/asm/thread_info.h
@@ -91,8 +91,6 @@ static inline struct thread_info *current_thread_info(void)
#define TIF_SYSCALL_AUDIT 9 /* syscall auditing active */
#define TIF_SECCOMP 10 /* secure computing */
#define TIF_SYSCALL_TRACEPOINT 11 /* syscall tracepoint instrumentation */
-#define TIF_POLLING_NRFLAG 16 /* true if poll_idle() is polling
- TIF_NEED_RESCHED */
#define TIF_31BIT 17 /* 32bit process */
#define TIF_MEMDIE 18 /* is terminating due to OOM killer */
#define TIF_RESTORE_SIGMASK 19 /* restore signal mask in do_signal() */
@@ -100,7 +98,6 @@ static inline struct thread_info *current_thread_info(void)
#define _TIF_SYSCALL (1<<TIF_SYSCALL)
#define _TIF_NOTIFY_RESUME (1<<TIF_NOTIFY_RESUME)
-#define _TIF_RESTORE_SIGMASK (1<<TIF_RESTORE_SIGMASK)
#define _TIF_SIGPENDING (1<<TIF_SIGPENDING)
#define _TIF_NEED_RESCHED (1<<TIF_NEED_RESCHED)
#define _TIF_PER_TRAP (1<<TIF_PER_TRAP)
@@ -109,7 +106,6 @@ static inline struct thread_info *current_thread_info(void)
#define _TIF_SYSCALL_AUDIT (1<<TIF_SYSCALL_AUDIT)
#define _TIF_SECCOMP (1<<TIF_SECCOMP)
#define _TIF_SYSCALL_TRACEPOINT (1<<TIF_SYSCALL_TRACEPOINT)
-#define _TIF_POLLING_NRFLAG (1<<TIF_POLLING_NRFLAG)
#define _TIF_31BIT (1<<TIF_31BIT)
#define _TIF_SINGLE_STEP (1<<TIF_SINGLE_STEP)
diff --git a/arch/s390/include/asm/types.h b/arch/s390/include/asm/types.h
index 6ba7c2c..dccef3c 100644
--- a/arch/s390/include/asm/types.h
+++ b/arch/s390/include/asm/types.h
@@ -3,26 +3,14 @@
*
* Derived from "include/asm-i386/types.h"
*/
-
#ifndef _S390_TYPES_H
#define _S390_TYPES_H
-#include <asm-generic/int-ll64.h>
-
-#ifndef __ASSEMBLY__
-
-/* A address type so that arithmetic can be done on it & it can be upgraded to
- 64 bit when necessary
-*/
-typedef unsigned long addr_t;
-typedef __signed__ long saddr_t;
-
-#endif /* __ASSEMBLY__ */
+#include <uapi/asm/types.h>
/*
* These aren't exported outside the kernel to avoid name space clashes
*/
-#ifdef __KERNEL__
#ifndef __ASSEMBLY__
@@ -37,5 +25,4 @@ typedef union {
#endif /* ! CONFIG_64BIT */
#endif /* __ASSEMBLY__ */
-#endif /* __KERNEL__ */
#endif /* _S390_TYPES_H */
diff --git a/arch/s390/include/asm/unistd.h b/arch/s390/include/asm/unistd.h
index 4e64b5c..bbbae41 100644
--- a/arch/s390/include/asm/unistd.h
+++ b/arch/s390/include/asm/unistd.h
@@ -3,375 +3,11 @@
*
* Derived from "include/asm-i386/unistd.h"
*/
-
#ifndef _ASM_S390_UNISTD_H_
#define _ASM_S390_UNISTD_H_
-/*
- * This file contains the system call numbers.
- */
-
-#define __NR_exit 1
-#define __NR_fork 2
-#define __NR_read 3
-#define __NR_write 4
-#define __NR_open 5
-#define __NR_close 6
-#define __NR_restart_syscall 7
-#define __NR_creat 8
-#define __NR_link 9
-#define __NR_unlink 10
-#define __NR_execve 11
-#define __NR_chdir 12
-#define __NR_mknod 14
-#define __NR_chmod 15
-#define __NR_lseek 19
-#define __NR_getpid 20
-#define __NR_mount 21
-#define __NR_umount 22
-#define __NR_ptrace 26
-#define __NR_alarm 27
-#define __NR_pause 29
-#define __NR_utime 30
-#define __NR_access 33
-#define __NR_nice 34
-#define __NR_sync 36
-#define __NR_kill 37
-#define __NR_rename 38
-#define __NR_mkdir 39
-#define __NR_rmdir 40
-#define __NR_dup 41
-#define __NR_pipe 42
-#define __NR_times 43
-#define __NR_brk 45
-#define __NR_signal 48
-#define __NR_acct 51
-#define __NR_umount2 52
-#define __NR_ioctl 54
-#define __NR_fcntl 55
-#define __NR_setpgid 57
-#define __NR_umask 60
-#define __NR_chroot 61
-#define __NR_ustat 62
-#define __NR_dup2 63
-#define __NR_getppid 64
-#define __NR_getpgrp 65
-#define __NR_setsid 66
-#define __NR_sigaction 67
-#define __NR_sigsuspend 72
-#define __NR_sigpending 73
-#define __NR_sethostname 74
-#define __NR_setrlimit 75
-#define __NR_getrusage 77
-#define __NR_gettimeofday 78
-#define __NR_settimeofday 79
-#define __NR_symlink 83
-#define __NR_readlink 85
-#define __NR_uselib 86
-#define __NR_swapon 87
-#define __NR_reboot 88
-#define __NR_readdir 89
-#define __NR_mmap 90
-#define __NR_munmap 91
-#define __NR_truncate 92
-#define __NR_ftruncate 93
-#define __NR_fchmod 94
-#define __NR_getpriority 96
-#define __NR_setpriority 97
-#define __NR_statfs 99
-#define __NR_fstatfs 100
-#define __NR_socketcall 102
-#define __NR_syslog 103
-#define __NR_setitimer 104
-#define __NR_getitimer 105
-#define __NR_stat 106
-#define __NR_lstat 107
-#define __NR_fstat 108
-#define __NR_lookup_dcookie 110
-#define __NR_vhangup 111
-#define __NR_idle 112
-#define __NR_wait4 114
-#define __NR_swapoff 115
-#define __NR_sysinfo 116
-#define __NR_ipc 117
-#define __NR_fsync 118
-#define __NR_sigreturn 119
-#define __NR_clone 120
-#define __NR_setdomainname 121
-#define __NR_uname 122
-#define __NR_adjtimex 124
-#define __NR_mprotect 125
-#define __NR_sigprocmask 126
-#define __NR_create_module 127
-#define __NR_init_module 128
-#define __NR_delete_module 129
-#define __NR_get_kernel_syms 130
-#define __NR_quotactl 131
-#define __NR_getpgid 132
-#define __NR_fchdir 133
-#define __NR_bdflush 134
-#define __NR_sysfs 135
-#define __NR_personality 136
-#define __NR_afs_syscall 137 /* Syscall for Andrew File System */
-#define __NR_getdents 141
-#define __NR_flock 143
-#define __NR_msync 144
-#define __NR_readv 145
-#define __NR_writev 146
-#define __NR_getsid 147
-#define __NR_fdatasync 148
-#define __NR__sysctl 149
-#define __NR_mlock 150
-#define __NR_munlock 151
-#define __NR_mlockall 152
-#define __NR_munlockall 153
-#define __NR_sched_setparam 154
-#define __NR_sched_getparam 155
-#define __NR_sched_setscheduler 156
-#define __NR_sched_getscheduler 157
-#define __NR_sched_yield 158
-#define __NR_sched_get_priority_max 159
-#define __NR_sched_get_priority_min 160
-#define __NR_sched_rr_get_interval 161
-#define __NR_nanosleep 162
-#define __NR_mremap 163
-#define __NR_query_module 167
-#define __NR_poll 168
-#define __NR_nfsservctl 169
-#define __NR_prctl 172
-#define __NR_rt_sigreturn 173
-#define __NR_rt_sigaction 174
-#define __NR_rt_sigprocmask 175
-#define __NR_rt_sigpending 176
-#define __NR_rt_sigtimedwait 177
-#define __NR_rt_sigqueueinfo 178
-#define __NR_rt_sigsuspend 179
-#define __NR_pread64 180
-#define __NR_pwrite64 181
-#define __NR_getcwd 183
-#define __NR_capget 184
-#define __NR_capset 185
-#define __NR_sigaltstack 186
-#define __NR_sendfile 187
-#define __NR_getpmsg 188
-#define __NR_putpmsg 189
-#define __NR_vfork 190
-#define __NR_pivot_root 217
-#define __NR_mincore 218
-#define __NR_madvise 219
-#define __NR_getdents64 220
-#define __NR_readahead 222
-#define __NR_setxattr 224
-#define __NR_lsetxattr 225
-#define __NR_fsetxattr 226
-#define __NR_getxattr 227
-#define __NR_lgetxattr 228
-#define __NR_fgetxattr 229
-#define __NR_listxattr 230
-#define __NR_llistxattr 231
-#define __NR_flistxattr 232
-#define __NR_removexattr 233
-#define __NR_lremovexattr 234
-#define __NR_fremovexattr 235
-#define __NR_gettid 236
-#define __NR_tkill 237
-#define __NR_futex 238
-#define __NR_sched_setaffinity 239
-#define __NR_sched_getaffinity 240
-#define __NR_tgkill 241
-/* Number 242 is reserved for tux */
-#define __NR_io_setup 243
-#define __NR_io_destroy 244
-#define __NR_io_getevents 245
-#define __NR_io_submit 246
-#define __NR_io_cancel 247
-#define __NR_exit_group 248
-#define __NR_epoll_create 249
-#define __NR_epoll_ctl 250
-#define __NR_epoll_wait 251
-#define __NR_set_tid_address 252
-#define __NR_fadvise64 253
-#define __NR_timer_create 254
-#define __NR_timer_settime (__NR_timer_create+1)
-#define __NR_timer_gettime (__NR_timer_create+2)
-#define __NR_timer_getoverrun (__NR_timer_create+3)
-#define __NR_timer_delete (__NR_timer_create+4)
-#define __NR_clock_settime (__NR_timer_create+5)
-#define __NR_clock_gettime (__NR_timer_create+6)
-#define __NR_clock_getres (__NR_timer_create+7)
-#define __NR_clock_nanosleep (__NR_timer_create+8)
-/* Number 263 is reserved for vserver */
-#define __NR_statfs64 265
-#define __NR_fstatfs64 266
-#define __NR_remap_file_pages 267
-/* Number 268 is reserved for new sys_mbind */
-/* Number 269 is reserved for new sys_get_mempolicy */
-/* Number 270 is reserved for new sys_set_mempolicy */
-#define __NR_mq_open 271
-#define __NR_mq_unlink 272
-#define __NR_mq_timedsend 273
-#define __NR_mq_timedreceive 274
-#define __NR_mq_notify 275
-#define __NR_mq_getsetattr 276
-#define __NR_kexec_load 277
-#define __NR_add_key 278
-#define __NR_request_key 279
-#define __NR_keyctl 280
-#define __NR_waitid 281
-#define __NR_ioprio_set 282
-#define __NR_ioprio_get 283
-#define __NR_inotify_init 284
-#define __NR_inotify_add_watch 285
-#define __NR_inotify_rm_watch 286
-/* Number 287 is reserved for new sys_migrate_pages */
-#define __NR_openat 288
-#define __NR_mkdirat 289
-#define __NR_mknodat 290
-#define __NR_fchownat 291
-#define __NR_futimesat 292
-#define __NR_unlinkat 294
-#define __NR_renameat 295
-#define __NR_linkat 296
-#define __NR_symlinkat 297
-#define __NR_readlinkat 298
-#define __NR_fchmodat 299
-#define __NR_faccessat 300
-#define __NR_pselect6 301
-#define __NR_ppoll 302
-#define __NR_unshare 303
-#define __NR_set_robust_list 304
-#define __NR_get_robust_list 305
-#define __NR_splice 306
-#define __NR_sync_file_range 307
-#define __NR_tee 308
-#define __NR_vmsplice 309
-/* Number 310 is reserved for new sys_move_pages */
-#define __NR_getcpu 311
-#define __NR_epoll_pwait 312
-#define __NR_utimes 313
-#define __NR_fallocate 314
-#define __NR_utimensat 315
-#define __NR_signalfd 316
-#define __NR_timerfd 317
-#define __NR_eventfd 318
-#define __NR_timerfd_create 319
-#define __NR_timerfd_settime 320
-#define __NR_timerfd_gettime 321
-#define __NR_signalfd4 322
-#define __NR_eventfd2 323
-#define __NR_inotify_init1 324
-#define __NR_pipe2 325
-#define __NR_dup3 326
-#define __NR_epoll_create1 327
-#define __NR_preadv 328
-#define __NR_pwritev 329
-#define __NR_rt_tgsigqueueinfo 330
-#define __NR_perf_event_open 331
-#define __NR_fanotify_init 332
-#define __NR_fanotify_mark 333
-#define __NR_prlimit64 334
-#define __NR_name_to_handle_at 335
-#define __NR_open_by_handle_at 336
-#define __NR_clock_adjtime 337
-#define __NR_syncfs 338
-#define __NR_setns 339
-#define __NR_process_vm_readv 340
-#define __NR_process_vm_writev 341
-#define __NR_s390_runtime_instr 342
-#define __NR_kcmp 343
-#define NR_syscalls 344
-
-/*
- * There are some system calls that are not present on 64 bit, some
- * have a different name although they do the same (e.g. __NR_chown32
- * is __NR_chown on 64 bit).
- */
-#ifndef __s390x__
-
-#define __NR_time 13
-#define __NR_lchown 16
-#define __NR_setuid 23
-#define __NR_getuid 24
-#define __NR_stime 25
-#define __NR_setgid 46
-#define __NR_getgid 47
-#define __NR_geteuid 49
-#define __NR_getegid 50
-#define __NR_setreuid 70
-#define __NR_setregid 71
-#define __NR_getrlimit 76
-#define __NR_getgroups 80
-#define __NR_setgroups 81
-#define __NR_fchown 95
-#define __NR_ioperm 101
-#define __NR_setfsuid 138
-#define __NR_setfsgid 139
-#define __NR__llseek 140
-#define __NR__newselect 142
-#define __NR_setresuid 164
-#define __NR_getresuid 165
-#define __NR_setresgid 170
-#define __NR_getresgid 171
-#define __NR_chown 182
-#define __NR_ugetrlimit 191 /* SuS compliant getrlimit */
-#define __NR_mmap2 192
-#define __NR_truncate64 193
-#define __NR_ftruncate64 194
-#define __NR_stat64 195
-#define __NR_lstat64 196
-#define __NR_fstat64 197
-#define __NR_lchown32 198
-#define __NR_getuid32 199
-#define __NR_getgid32 200
-#define __NR_geteuid32 201
-#define __NR_getegid32 202
-#define __NR_setreuid32 203
-#define __NR_setregid32 204
-#define __NR_getgroups32 205
-#define __NR_setgroups32 206
-#define __NR_fchown32 207
-#define __NR_setresuid32 208
-#define __NR_getresuid32 209
-#define __NR_setresgid32 210
-#define __NR_getresgid32 211
-#define __NR_chown32 212
-#define __NR_setuid32 213
-#define __NR_setgid32 214
-#define __NR_setfsuid32 215
-#define __NR_setfsgid32 216
-#define __NR_fcntl64 221
-#define __NR_sendfile64 223
-#define __NR_fadvise64_64 264
-#define __NR_fstatat64 293
-
-#else
-
-#define __NR_select 142
-#define __NR_getrlimit 191 /* SuS compliant getrlimit */
-#define __NR_lchown 198
-#define __NR_getuid 199
-#define __NR_getgid 200
-#define __NR_geteuid 201
-#define __NR_getegid 202
-#define __NR_setreuid 203
-#define __NR_setregid 204
-#define __NR_getgroups 205
-#define __NR_setgroups 206
-#define __NR_fchown 207
-#define __NR_setresuid 208
-#define __NR_getresuid 209
-#define __NR_setresgid 210
-#define __NR_getresgid 211
-#define __NR_chown 212
-#define __NR_setuid 213
-#define __NR_setgid 214
-#define __NR_setfsuid 215
-#define __NR_setfsgid 216
-#define __NR_newfstatat 293
-
-#endif
+#include <uapi/asm/unistd.h>
-#ifdef __KERNEL__
#ifndef CONFIG_64BIT
#define __IGNORE_select
@@ -417,6 +53,8 @@
# define __ARCH_WANT_COMPAT_SYS_TIME
# define __ARCH_WANT_COMPAT_SYS_RT_SIGSUSPEND
# endif
+#define __ARCH_WANT_SYS_EXECVE
+#define __ARCH_WANT_KERNEL_EXECVE
/*
* "Conditional" syscalls
@@ -426,5 +64,4 @@
*/
#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall")
-#endif /* __KERNEL__ */
#endif /* _ASM_S390_UNISTD_H_ */
diff --git a/arch/s390/include/uapi/asm/Kbuild b/arch/s390/include/uapi/asm/Kbuild
index baebb3d..7bf68ff 100644
--- a/arch/s390/include/uapi/asm/Kbuild
+++ b/arch/s390/include/uapi/asm/Kbuild
@@ -1,3 +1,48 @@
# UAPI Header export list
include include/uapi/asm-generic/Kbuild.asm
+header-y += auxvec.h
+header-y += bitsperlong.h
+header-y += byteorder.h
+header-y += chpid.h
+header-y += chsc.h
+header-y += cmb.h
+header-y += dasd.h
+header-y += debug.h
+header-y += errno.h
+header-y += fcntl.h
+header-y += ioctl.h
+header-y += ioctls.h
+header-y += ipcbuf.h
+header-y += kvm.h
+header-y += kvm_para.h
+header-y += kvm_virtio.h
+header-y += mman.h
+header-y += monwriter.h
+header-y += msgbuf.h
+header-y += param.h
+header-y += poll.h
+header-y += posix_types.h
+header-y += ptrace.h
+header-y += qeth.h
+header-y += resource.h
+header-y += schid.h
+header-y += sembuf.h
+header-y += setup.h
+header-y += shmbuf.h
+header-y += sigcontext.h
+header-y += siginfo.h
+header-y += signal.h
+header-y += socket.h
+header-y += sockios.h
+header-y += stat.h
+header-y += statfs.h
+header-y += swab.h
+header-y += tape390.h
+header-y += termbits.h
+header-y += termios.h
+header-y += types.h
+header-y += ucontext.h
+header-y += unistd.h
+header-y += vtoc.h
+header-y += zcrypt.h
diff --git a/arch/s390/include/asm/auxvec.h b/arch/s390/include/uapi/asm/auxvec.h
index a1f153e..a1f153e 100644
--- a/arch/s390/include/asm/auxvec.h
+++ b/arch/s390/include/uapi/asm/auxvec.h
diff --git a/arch/s390/include/asm/bitsperlong.h b/arch/s390/include/uapi/asm/bitsperlong.h
index 6b235ae..6b235ae 100644
--- a/arch/s390/include/asm/bitsperlong.h
+++ b/arch/s390/include/uapi/asm/bitsperlong.h
diff --git a/arch/s390/include/asm/byteorder.h b/arch/s390/include/uapi/asm/byteorder.h
index a332e59..a332e59 100644
--- a/arch/s390/include/asm/byteorder.h
+++ b/arch/s390/include/uapi/asm/byteorder.h
diff --git a/arch/s390/include/uapi/asm/chpid.h b/arch/s390/include/uapi/asm/chpid.h
new file mode 100644
index 0000000..581992d
--- /dev/null
+++ b/arch/s390/include/uapi/asm/chpid.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright IBM Corp. 2007
+ * Author(s): Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
+ */
+
+#ifndef _UAPI_ASM_S390_CHPID_H
+#define _UAPI_ASM_S390_CHPID_H
+
+#include <linux/string.h>
+#include <linux/types.h>
+
+#define __MAX_CHPID 255
+
+struct chp_id {
+ u8 reserved1;
+ u8 cssid;
+ u8 reserved2;
+ u8 id;
+} __attribute__((packed));
+
+
+#endif /* _UAPI_ASM_S390_CHPID_H */
diff --git a/arch/s390/include/asm/chsc.h b/arch/s390/include/uapi/asm/chsc.h
index aea451f..1c6a7f8 100644
--- a/arch/s390/include/asm/chsc.h
+++ b/arch/s390/include/uapi/asm/chsc.h
@@ -1,7 +1,7 @@
/*
* ioctl interface for /dev/chsc
*
- * Copyright IBM Corp. 2008
+ * Copyright IBM Corp. 2008, 2012
* Author(s): Cornelia Huck <cornelia.huck@de.ibm.com>
*/
@@ -9,9 +9,12 @@
#define _ASM_CHSC_H
#include <linux/types.h>
+#include <linux/ioctl.h>
#include <asm/chpid.h>
#include <asm/schid.h>
+#define CHSC_SIZE 0x1000
+
struct chsc_async_header {
__u16 length;
__u16 code;
@@ -23,15 +26,14 @@ struct chsc_async_header {
struct chsc_async_area {
struct chsc_async_header header;
- __u8 data[PAGE_SIZE - 16 /* size of chsc_async_header */];
+ __u8 data[CHSC_SIZE - sizeof(struct chsc_async_header)];
} __attribute__ ((packed));
-
struct chsc_response_struct {
__u16 length;
__u16 code;
__u32 parms;
- __u8 data[PAGE_SIZE - 8];
+ __u8 data[CHSC_SIZE - 2 * sizeof(__u16) - sizeof(__u32)];
} __attribute__ ((packed));
struct chsc_chp_cd {
diff --git a/arch/s390/include/uapi/asm/cmb.h b/arch/s390/include/uapi/asm/cmb.h
new file mode 100644
index 0000000..0c086d0
--- /dev/null
+++ b/arch/s390/include/uapi/asm/cmb.h
@@ -0,0 +1,53 @@
+#ifndef _UAPIS390_CMB_H
+#define _UAPIS390_CMB_H
+
+#include <linux/types.h>
+
+/**
+ * struct cmbdata - channel measurement block data for user space
+ * @size: size of the stored data
+ * @elapsed_time: time since last sampling
+ * @ssch_rsch_count: number of ssch and rsch
+ * @sample_count: number of samples
+ * @device_connect_time: time of device connect
+ * @function_pending_time: time of function pending
+ * @device_disconnect_time: time of device disconnect
+ * @control_unit_queuing_time: time of control unit queuing
+ * @device_active_only_time: time of device active only
+ * @device_busy_time: time of device busy (ext. format)
+ * @initial_command_response_time: initial command response time (ext. format)
+ *
+ * All values are stored as 64 bit for simplicity, especially
+ * in 32 bit emulation mode. All time values are normalized to
+ * nanoseconds.
+ * Currently, two formats are known, which differ by the size of
+ * this structure, i.e. the last two members are only set when
+ * the extended channel measurement facility (first shipped in
+ * z990 machines) is activated.
+ * Potentially, more fields could be added, which would result in a
+ * new ioctl number.
+ */
+struct cmbdata {
+ __u64 size;
+ __u64 elapsed_time;
+ /* basic and exended format: */
+ __u64 ssch_rsch_count;
+ __u64 sample_count;
+ __u64 device_connect_time;
+ __u64 function_pending_time;
+ __u64 device_disconnect_time;
+ __u64 control_unit_queuing_time;
+ __u64 device_active_only_time;
+ /* extended format only: */
+ __u64 device_busy_time;
+ __u64 initial_command_response_time;
+};
+
+/* enable channel measurement */
+#define BIODASDCMFENABLE _IO(DASD_IOCTL_LETTER, 32)
+/* enable channel measurement */
+#define BIODASDCMFDISABLE _IO(DASD_IOCTL_LETTER, 33)
+/* read channel measurement data */
+#define BIODASDREADALLCMB _IOWR(DASD_IOCTL_LETTER, 33, struct cmbdata)
+
+#endif /* _UAPIS390_CMB_H */
diff --git a/arch/s390/include/asm/dasd.h b/arch/s390/include/uapi/asm/dasd.h
index 38eca3b..38eca3b 100644
--- a/arch/s390/include/asm/dasd.h
+++ b/arch/s390/include/uapi/asm/dasd.h
diff --git a/arch/s390/include/uapi/asm/debug.h b/arch/s390/include/uapi/asm/debug.h
new file mode 100644
index 0000000..c59fc79
--- /dev/null
+++ b/arch/s390/include/uapi/asm/debug.h
@@ -0,0 +1,34 @@
+/*
+ * S/390 debug facility
+ *
+ * Copyright IBM Corp. 1999, 2000
+ */
+
+#ifndef _UAPIDEBUG_H
+#define _UAPIDEBUG_H
+
+#include <linux/fs.h>
+
+/* Note:
+ * struct __debug_entry must be defined outside of #ifdef __KERNEL__
+ * in order to allow a user program to analyze the 'raw'-view.
+ */
+
+struct __debug_entry{
+ union {
+ struct {
+ unsigned long long clock:52;
+ unsigned long long exception:1;
+ unsigned long long level:3;
+ unsigned long long cpuid:8;
+ } fields;
+
+ unsigned long long stck;
+ } id;
+ void* caller;
+} __attribute__((packed));
+
+
+#define __DEBUG_FEATURE_VERSION 2 /* version of debug feature */
+
+#endif /* _UAPIDEBUG_H */
diff --git a/arch/s390/include/asm/errno.h b/arch/s390/include/uapi/asm/errno.h
index 395e97d..395e97d 100644
--- a/arch/s390/include/asm/errno.h
+++ b/arch/s390/include/uapi/asm/errno.h
diff --git a/arch/s390/include/asm/fcntl.h b/arch/s390/include/uapi/asm/fcntl.h
index 46ab12d..46ab12d 100644
--- a/arch/s390/include/asm/fcntl.h
+++ b/arch/s390/include/uapi/asm/fcntl.h
diff --git a/arch/s390/include/asm/ioctl.h b/arch/s390/include/uapi/asm/ioctl.h
index b279fe0..b279fe0 100644
--- a/arch/s390/include/asm/ioctl.h
+++ b/arch/s390/include/uapi/asm/ioctl.h
diff --git a/arch/s390/include/asm/ioctls.h b/arch/s390/include/uapi/asm/ioctls.h
index 960a4c1..960a4c1 100644
--- a/arch/s390/include/asm/ioctls.h
+++ b/arch/s390/include/uapi/asm/ioctls.h
diff --git a/arch/s390/include/asm/ipcbuf.h b/arch/s390/include/uapi/asm/ipcbuf.h
index 37f293d..37f293d 100644
--- a/arch/s390/include/asm/ipcbuf.h
+++ b/arch/s390/include/uapi/asm/ipcbuf.h
diff --git a/arch/s390/include/asm/kvm.h b/arch/s390/include/uapi/asm/kvm.h
index d25da59..d25da59 100644
--- a/arch/s390/include/asm/kvm.h
+++ b/arch/s390/include/uapi/asm/kvm.h
diff --git a/arch/s390/include/uapi/asm/kvm_para.h b/arch/s390/include/uapi/asm/kvm_para.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/arch/s390/include/uapi/asm/kvm_para.h
diff --git a/arch/s390/include/asm/kvm_virtio.h b/arch/s390/include/uapi/asm/kvm_virtio.h
index 44a438c..44a438c 100644
--- a/arch/s390/include/asm/kvm_virtio.h
+++ b/arch/s390/include/uapi/asm/kvm_virtio.h
diff --git a/arch/s390/include/uapi/asm/mman.h b/arch/s390/include/uapi/asm/mman.h
new file mode 100644
index 0000000..de23da1
--- /dev/null
+++ b/arch/s390/include/uapi/asm/mman.h
@@ -0,0 +1,6 @@
+/*
+ * S390 version
+ *
+ * Derived from "include/asm-i386/mman.h"
+ */
+#include <asm-generic/mman.h>
diff --git a/arch/s390/include/asm/monwriter.h b/arch/s390/include/uapi/asm/monwriter.h
index f845c8e..f845c8e 100644
--- a/arch/s390/include/asm/monwriter.h
+++ b/arch/s390/include/uapi/asm/monwriter.h
diff --git a/arch/s390/include/asm/msgbuf.h b/arch/s390/include/uapi/asm/msgbuf.h
index 1bbdee9..1bbdee9 100644
--- a/arch/s390/include/asm/msgbuf.h
+++ b/arch/s390/include/uapi/asm/msgbuf.h
diff --git a/arch/s390/include/asm/param.h b/arch/s390/include/uapi/asm/param.h
index c616821..c616821 100644
--- a/arch/s390/include/asm/param.h
+++ b/arch/s390/include/uapi/asm/param.h
diff --git a/arch/s390/include/asm/poll.h b/arch/s390/include/uapi/asm/poll.h
index c98509d..c98509d 100644
--- a/arch/s390/include/asm/poll.h
+++ b/arch/s390/include/uapi/asm/poll.h
diff --git a/arch/s390/include/asm/posix_types.h b/arch/s390/include/uapi/asm/posix_types.h
index bf2a2ad..bf2a2ad 100644
--- a/arch/s390/include/asm/posix_types.h
+++ b/arch/s390/include/uapi/asm/posix_types.h
diff --git a/arch/s390/include/uapi/asm/ptrace.h b/arch/s390/include/uapi/asm/ptrace.h
new file mode 100644
index 0000000..705588a
--- /dev/null
+++ b/arch/s390/include/uapi/asm/ptrace.h
@@ -0,0 +1,472 @@
+/*
+ * S390 version
+ * Copyright IBM Corp. 1999, 2000
+ * Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
+ */
+
+#ifndef _UAPI_S390_PTRACE_H
+#define _UAPI_S390_PTRACE_H
+
+/*
+ * Offsets in the user_regs_struct. They are used for the ptrace
+ * system call and in entry.S
+ */
+#ifndef __s390x__
+
+#define PT_PSWMASK 0x00
+#define PT_PSWADDR 0x04
+#define PT_GPR0 0x08
+#define PT_GPR1 0x0C
+#define PT_GPR2 0x10
+#define PT_GPR3 0x14
+#define PT_GPR4 0x18
+#define PT_GPR5 0x1C
+#define PT_GPR6 0x20
+#define PT_GPR7 0x24
+#define PT_GPR8 0x28
+#define PT_GPR9 0x2C
+#define PT_GPR10 0x30
+#define PT_GPR11 0x34
+#define PT_GPR12 0x38
+#define PT_GPR13 0x3C
+#define PT_GPR14 0x40
+#define PT_GPR15 0x44
+#define PT_ACR0 0x48
+#define PT_ACR1 0x4C
+#define PT_ACR2 0x50
+#define PT_ACR3 0x54
+#define PT_ACR4 0x58
+#define PT_ACR5 0x5C
+#define PT_ACR6 0x60
+#define PT_ACR7 0x64
+#define PT_ACR8 0x68
+#define PT_ACR9 0x6C
+#define PT_ACR10 0x70
+#define PT_ACR11 0x74
+#define PT_ACR12 0x78
+#define PT_ACR13 0x7C
+#define PT_ACR14 0x80
+#define PT_ACR15 0x84
+#define PT_ORIGGPR2 0x88
+#define PT_FPC 0x90
+/*
+ * A nasty fact of life that the ptrace api
+ * only supports passing of longs.
+ */
+#define PT_FPR0_HI 0x98
+#define PT_FPR0_LO 0x9C
+#define PT_FPR1_HI 0xA0
+#define PT_FPR1_LO 0xA4
+#define PT_FPR2_HI 0xA8
+#define PT_FPR2_LO 0xAC
+#define PT_FPR3_HI 0xB0
+#define PT_FPR3_LO 0xB4
+#define PT_FPR4_HI 0xB8
+#define PT_FPR4_LO 0xBC
+#define PT_FPR5_HI 0xC0
+#define PT_FPR5_LO 0xC4
+#define PT_FPR6_HI 0xC8
+#define PT_FPR6_LO 0xCC
+#define PT_FPR7_HI 0xD0
+#define PT_FPR7_LO 0xD4
+#define PT_FPR8_HI 0xD8
+#define PT_FPR8_LO 0XDC
+#define PT_FPR9_HI 0xE0
+#define PT_FPR9_LO 0xE4
+#define PT_FPR10_HI 0xE8
+#define PT_FPR10_LO 0xEC
+#define PT_FPR11_HI 0xF0
+#define PT_FPR11_LO 0xF4
+#define PT_FPR12_HI 0xF8
+#define PT_FPR12_LO 0xFC
+#define PT_FPR13_HI 0x100
+#define PT_FPR13_LO 0x104
+#define PT_FPR14_HI 0x108
+#define PT_FPR14_LO 0x10C
+#define PT_FPR15_HI 0x110
+#define PT_FPR15_LO 0x114
+#define PT_CR_9 0x118
+#define PT_CR_10 0x11C
+#define PT_CR_11 0x120
+#define PT_IEEE_IP 0x13C
+#define PT_LASTOFF PT_IEEE_IP
+#define PT_ENDREGS 0x140-1
+
+#define GPR_SIZE 4
+#define CR_SIZE 4
+
+#define STACK_FRAME_OVERHEAD 96 /* size of minimum stack frame */
+
+#else /* __s390x__ */
+
+#define PT_PSWMASK 0x00
+#define PT_PSWADDR 0x08
+#define PT_GPR0 0x10
+#define PT_GPR1 0x18
+#define PT_GPR2 0x20
+#define PT_GPR3 0x28
+#define PT_GPR4 0x30
+#define PT_GPR5 0x38
+#define PT_GPR6 0x40
+#define PT_GPR7 0x48
+#define PT_GPR8 0x50
+#define PT_GPR9 0x58
+#define PT_GPR10 0x60
+#define PT_GPR11 0x68
+#define PT_GPR12 0x70
+#define PT_GPR13 0x78
+#define PT_GPR14 0x80
+#define PT_GPR15 0x88
+#define PT_ACR0 0x90
+#define PT_ACR1 0x94
+#define PT_ACR2 0x98
+#define PT_ACR3 0x9C
+#define PT_ACR4 0xA0
+#define PT_ACR5 0xA4
+#define PT_ACR6 0xA8
+#define PT_ACR7 0xAC
+#define PT_ACR8 0xB0
+#define PT_ACR9 0xB4
+#define PT_ACR10 0xB8
+#define PT_ACR11 0xBC
+#define PT_ACR12 0xC0
+#define PT_ACR13 0xC4
+#define PT_ACR14 0xC8
+#define PT_ACR15 0xCC
+#define PT_ORIGGPR2 0xD0
+#define PT_FPC 0xD8
+#define PT_FPR0 0xE0
+#define PT_FPR1 0xE8
+#define PT_FPR2 0xF0
+#define PT_FPR3 0xF8
+#define PT_FPR4 0x100
+#define PT_FPR5 0x108
+#define PT_FPR6 0x110
+#define PT_FPR7 0x118
+#define PT_FPR8 0x120
+#define PT_FPR9 0x128
+#define PT_FPR10 0x130
+#define PT_FPR11 0x138
+#define PT_FPR12 0x140
+#define PT_FPR13 0x148
+#define PT_FPR14 0x150
+#define PT_FPR15 0x158
+#define PT_CR_9 0x160
+#define PT_CR_10 0x168
+#define PT_CR_11 0x170
+#define PT_IEEE_IP 0x1A8
+#define PT_LASTOFF PT_IEEE_IP
+#define PT_ENDREGS 0x1B0-1
+
+#define GPR_SIZE 8
+#define CR_SIZE 8
+
+#define STACK_FRAME_OVERHEAD 160 /* size of minimum stack frame */
+
+#endif /* __s390x__ */
+
+#define NUM_GPRS 16
+#define NUM_FPRS 16
+#define NUM_CRS 16
+#define NUM_ACRS 16
+
+#define NUM_CR_WORDS 3
+
+#define FPR_SIZE 8
+#define FPC_SIZE 4
+#define FPC_PAD_SIZE 4 /* gcc insists on aligning the fpregs */
+#define ACR_SIZE 4
+
+
+#define PTRACE_OLDSETOPTIONS 21
+
+#ifndef __ASSEMBLY__
+#include <linux/stddef.h>
+#include <linux/types.h>
+
+typedef union
+{
+ float f;
+ double d;
+ __u64 ui;
+ struct
+ {
+ __u32 hi;
+ __u32 lo;
+ } fp;
+} freg_t;
+
+typedef struct
+{
+ __u32 fpc;
+ freg_t fprs[NUM_FPRS];
+} s390_fp_regs;
+
+#define FPC_EXCEPTION_MASK 0xF8000000
+#define FPC_FLAGS_MASK 0x00F80000
+#define FPC_DXC_MASK 0x0000FF00
+#define FPC_RM_MASK 0x00000003
+#define FPC_VALID_MASK 0xF8F8FF03
+
+/* this typedef defines how a Program Status Word looks like */
+typedef struct
+{
+ unsigned long mask;
+ unsigned long addr;
+} __attribute__ ((aligned(8))) psw_t;
+
+typedef struct
+{
+ __u32 mask;
+ __u32 addr;
+} __attribute__ ((aligned(8))) psw_compat_t;
+
+#ifndef __s390x__
+
+#define PSW_MASK_PER 0x40000000UL
+#define PSW_MASK_DAT 0x04000000UL
+#define PSW_MASK_IO 0x02000000UL
+#define PSW_MASK_EXT 0x01000000UL
+#define PSW_MASK_KEY 0x00F00000UL
+#define PSW_MASK_BASE 0x00080000UL /* always one */
+#define PSW_MASK_MCHECK 0x00040000UL
+#define PSW_MASK_WAIT 0x00020000UL
+#define PSW_MASK_PSTATE 0x00010000UL
+#define PSW_MASK_ASC 0x0000C000UL
+#define PSW_MASK_CC 0x00003000UL
+#define PSW_MASK_PM 0x00000F00UL
+#define PSW_MASK_RI 0x00000000UL
+#define PSW_MASK_EA 0x00000000UL
+#define PSW_MASK_BA 0x00000000UL
+
+#define PSW_MASK_USER 0x00003F00UL
+
+#define PSW_ADDR_AMODE 0x80000000UL
+#define PSW_ADDR_INSN 0x7FFFFFFFUL
+
+#define PSW_DEFAULT_KEY (((unsigned long) PAGE_DEFAULT_ACC) << 20)
+
+#define PSW_ASC_PRIMARY 0x00000000UL
+#define PSW_ASC_ACCREG 0x00004000UL
+#define PSW_ASC_SECONDARY 0x00008000UL
+#define PSW_ASC_HOME 0x0000C000UL
+
+#else /* __s390x__ */
+
+#define PSW_MASK_PER 0x4000000000000000UL
+#define PSW_MASK_DAT 0x0400000000000000UL
+#define PSW_MASK_IO 0x0200000000000000UL
+#define PSW_MASK_EXT 0x0100000000000000UL
+#define PSW_MASK_BASE 0x0000000000000000UL
+#define PSW_MASK_KEY 0x00F0000000000000UL
+#define PSW_MASK_MCHECK 0x0004000000000000UL
+#define PSW_MASK_WAIT 0x0002000000000000UL
+#define PSW_MASK_PSTATE 0x0001000000000000UL
+#define PSW_MASK_ASC 0x0000C00000000000UL
+#define PSW_MASK_CC 0x0000300000000000UL
+#define PSW_MASK_PM 0x00000F0000000000UL
+#define PSW_MASK_RI 0x0000008000000000UL
+#define PSW_MASK_EA 0x0000000100000000UL
+#define PSW_MASK_BA 0x0000000080000000UL
+
+#define PSW_MASK_USER 0x00003F8180000000UL
+
+#define PSW_ADDR_AMODE 0x0000000000000000UL
+#define PSW_ADDR_INSN 0xFFFFFFFFFFFFFFFFUL
+
+#define PSW_DEFAULT_KEY (((unsigned long) PAGE_DEFAULT_ACC) << 52)
+
+#define PSW_ASC_PRIMARY 0x0000000000000000UL
+#define PSW_ASC_ACCREG 0x0000400000000000UL
+#define PSW_ASC_SECONDARY 0x0000800000000000UL
+#define PSW_ASC_HOME 0x0000C00000000000UL
+
+#endif /* __s390x__ */
+
+
+/*
+ * The s390_regs structure is used to define the elf_gregset_t.
+ */
+typedef struct
+{
+ psw_t psw;
+ unsigned long gprs[NUM_GPRS];
+ unsigned int acrs[NUM_ACRS];
+ unsigned long orig_gpr2;
+} s390_regs;
+
+typedef struct
+{
+ psw_compat_t psw;
+ __u32 gprs[NUM_GPRS];
+ __u32 acrs[NUM_ACRS];
+ __u32 orig_gpr2;
+} s390_compat_regs;
+
+typedef struct
+{
+ __u32 gprs_high[NUM_GPRS];
+} s390_compat_regs_high;
+
+
+/*
+ * Now for the user space program event recording (trace) definitions.
+ * The following structures are used only for the ptrace interface, don't
+ * touch or even look at it if you don't want to modify the user-space
+ * ptrace interface. In particular stay away from it for in-kernel PER.
+ */
+typedef struct
+{
+ unsigned long cr[NUM_CR_WORDS];
+} per_cr_words;
+
+#define PER_EM_MASK 0xE8000000UL
+
+typedef struct
+{
+#ifdef __s390x__
+ unsigned : 32;
+#endif /* __s390x__ */
+ unsigned em_branching : 1;
+ unsigned em_instruction_fetch : 1;
+ /*
+ * Switching on storage alteration automatically fixes
+ * the storage alteration event bit in the users std.
+ */
+ unsigned em_storage_alteration : 1;
+ unsigned em_gpr_alt_unused : 1;
+ unsigned em_store_real_address : 1;
+ unsigned : 3;
+ unsigned branch_addr_ctl : 1;
+ unsigned : 1;
+ unsigned storage_alt_space_ctl : 1;
+ unsigned : 21;
+ unsigned long starting_addr;
+ unsigned long ending_addr;
+} per_cr_bits;
+
+typedef struct
+{
+ unsigned short perc_atmid;
+ unsigned long address;
+ unsigned char access_id;
+} per_lowcore_words;
+
+typedef struct
+{
+ unsigned perc_branching : 1;
+ unsigned perc_instruction_fetch : 1;
+ unsigned perc_storage_alteration : 1;
+ unsigned perc_gpr_alt_unused : 1;
+ unsigned perc_store_real_address : 1;
+ unsigned : 3;
+ unsigned atmid_psw_bit_31 : 1;
+ unsigned atmid_validity_bit : 1;
+ unsigned atmid_psw_bit_32 : 1;
+ unsigned atmid_psw_bit_5 : 1;
+ unsigned atmid_psw_bit_16 : 1;
+ unsigned atmid_psw_bit_17 : 1;
+ unsigned si : 2;
+ unsigned long address;
+ unsigned : 4;
+ unsigned access_id : 4;
+} per_lowcore_bits;
+
+typedef struct
+{
+ union {
+ per_cr_words words;
+ per_cr_bits bits;
+ } control_regs;
+ /*
+ * Use these flags instead of setting em_instruction_fetch
+ * directly they are used so that single stepping can be
+ * switched on & off while not affecting other tracing
+ */
+ unsigned single_step : 1;
+ unsigned instruction_fetch : 1;
+ unsigned : 30;
+ /*
+ * These addresses are copied into cr10 & cr11 if single
+ * stepping is switched off
+ */
+ unsigned long starting_addr;
+ unsigned long ending_addr;
+ union {
+ per_lowcore_words words;
+ per_lowcore_bits bits;
+ } lowcore;
+} per_struct;
+
+typedef struct
+{
+ unsigned int len;
+ unsigned long kernel_addr;
+ unsigned long process_addr;
+} ptrace_area;
+
+/*
+ * S/390 specific non posix ptrace requests. I chose unusual values so
+ * they are unlikely to clash with future ptrace definitions.
+ */
+#define PTRACE_PEEKUSR_AREA 0x5000
+#define PTRACE_POKEUSR_AREA 0x5001
+#define PTRACE_PEEKTEXT_AREA 0x5002
+#define PTRACE_PEEKDATA_AREA 0x5003
+#define PTRACE_POKETEXT_AREA 0x5004
+#define PTRACE_POKEDATA_AREA 0x5005
+#define PTRACE_GET_LAST_BREAK 0x5006
+#define PTRACE_PEEK_SYSTEM_CALL 0x5007
+#define PTRACE_POKE_SYSTEM_CALL 0x5008
+#define PTRACE_ENABLE_TE 0x5009
+#define PTRACE_DISABLE_TE 0x5010
+
+/*
+ * PT_PROT definition is loosely based on hppa bsd definition in
+ * gdb/hppab-nat.c
+ */
+#define PTRACE_PROT 21
+
+typedef enum
+{
+ ptprot_set_access_watchpoint,
+ ptprot_set_write_watchpoint,
+ ptprot_disable_watchpoint
+} ptprot_flags;
+
+typedef struct
+{
+ unsigned long lowaddr;
+ unsigned long hiaddr;
+ ptprot_flags prot;
+} ptprot_area;
+
+/* Sequence of bytes for breakpoint illegal instruction. */
+#define S390_BREAKPOINT {0x0,0x1}
+#define S390_BREAKPOINT_U16 ((__u16)0x0001)
+#define S390_SYSCALL_OPCODE ((__u16)0x0a00)
+#define S390_SYSCALL_SIZE 2
+
+/*
+ * The user_regs_struct defines the way the user registers are
+ * store on the stack for signal handling.
+ */
+struct user_regs_struct
+{
+ psw_t psw;
+ unsigned long gprs[NUM_GPRS];
+ unsigned int acrs[NUM_ACRS];
+ unsigned long orig_gpr2;
+ s390_fp_regs fp_regs;
+ /*
+ * These per registers are in here so that gdb can modify them
+ * itself as there is no "official" ptrace interface for hardware
+ * watchpoints. This is the way intel does it.
+ */
+ per_struct per_info;
+ unsigned long ieee_instruction_pointer; /* obsolete, always 0 */
+};
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* _UAPI_S390_PTRACE_H */
diff --git a/arch/s390/include/asm/qeth.h b/arch/s390/include/uapi/asm/qeth.h
index 3a896cf..3a896cf 100644
--- a/arch/s390/include/asm/qeth.h
+++ b/arch/s390/include/uapi/asm/qeth.h
diff --git a/arch/s390/include/asm/resource.h b/arch/s390/include/uapi/asm/resource.h
index ec23d1c..ec23d1c 100644
--- a/arch/s390/include/asm/resource.h
+++ b/arch/s390/include/uapi/asm/resource.h
diff --git a/arch/s390/include/uapi/asm/schid.h b/arch/s390/include/uapi/asm/schid.h
new file mode 100644
index 0000000..32f3ab2
--- /dev/null
+++ b/arch/s390/include/uapi/asm/schid.h
@@ -0,0 +1,16 @@
+#ifndef _UAPIASM_SCHID_H
+#define _UAPIASM_SCHID_H
+
+#include <linux/types.h>
+
+struct subchannel_id {
+ __u32 cssid : 8;
+ __u32 : 4;
+ __u32 m : 1;
+ __u32 ssid : 2;
+ __u32 one : 1;
+ __u32 sch_no : 16;
+} __attribute__ ((packed, aligned(4)));
+
+
+#endif /* _UAPIASM_SCHID_H */
diff --git a/arch/s390/include/asm/sembuf.h b/arch/s390/include/uapi/asm/sembuf.h
index 32626b0..32626b0 100644
--- a/arch/s390/include/asm/sembuf.h
+++ b/arch/s390/include/uapi/asm/sembuf.h
diff --git a/arch/s390/include/uapi/asm/setup.h b/arch/s390/include/uapi/asm/setup.h
new file mode 100644
index 0000000..5a637e3
--- /dev/null
+++ b/arch/s390/include/uapi/asm/setup.h
@@ -0,0 +1,13 @@
+/*
+ * S390 version
+ * Copyright IBM Corp. 1999, 2010
+ */
+
+#ifndef _UAPI_ASM_S390_SETUP_H
+#define _UAPI_ASM_S390_SETUP_H
+
+#define COMMAND_LINE_SIZE 4096
+
+#define ARCH_COMMAND_LINE_SIZE 896
+
+#endif /* _UAPI_ASM_S390_SETUP_H */
diff --git a/arch/s390/include/asm/shmbuf.h b/arch/s390/include/uapi/asm/shmbuf.h
index eed2e28..eed2e28 100644
--- a/arch/s390/include/asm/shmbuf.h
+++ b/arch/s390/include/uapi/asm/shmbuf.h
diff --git a/arch/s390/include/asm/sigcontext.h b/arch/s390/include/uapi/asm/sigcontext.h
index 584787f..584787f 100644
--- a/arch/s390/include/asm/sigcontext.h
+++ b/arch/s390/include/uapi/asm/sigcontext.h
diff --git a/arch/s390/include/asm/siginfo.h b/arch/s390/include/uapi/asm/siginfo.h
index 91fd3e4..91fd3e4 100644
--- a/arch/s390/include/asm/siginfo.h
+++ b/arch/s390/include/uapi/asm/siginfo.h
diff --git a/arch/s390/include/uapi/asm/signal.h b/arch/s390/include/uapi/asm/signal.h
new file mode 100644
index 0000000..8c6a49e
--- /dev/null
+++ b/arch/s390/include/uapi/asm/signal.h
@@ -0,0 +1,135 @@
+/*
+ * S390 version
+ *
+ * Derived from "include/asm-i386/signal.h"
+ */
+
+#ifndef _UAPI_ASMS390_SIGNAL_H
+#define _UAPI_ASMS390_SIGNAL_H
+
+#include <linux/types.h>
+#include <linux/time.h>
+
+/* Avoid too many header ordering problems. */
+struct siginfo;
+struct pt_regs;
+
+#ifndef __KERNEL__
+/* Here we must cater to libcs that poke about in kernel headers. */
+
+#define NSIG 32
+typedef unsigned long sigset_t;
+
+#endif /* __KERNEL__ */
+
+#define SIGHUP 1
+#define SIGINT 2
+#define SIGQUIT 3
+#define SIGILL 4
+#define SIGTRAP 5
+#define SIGABRT 6
+#define SIGIOT 6
+#define SIGBUS 7
+#define SIGFPE 8
+#define SIGKILL 9
+#define SIGUSR1 10
+#define SIGSEGV 11
+#define SIGUSR2 12
+#define SIGPIPE 13
+#define SIGALRM 14
+#define SIGTERM 15
+#define SIGSTKFLT 16
+#define SIGCHLD 17
+#define SIGCONT 18
+#define SIGSTOP 19
+#define SIGTSTP 20
+#define SIGTTIN 21
+#define SIGTTOU 22
+#define SIGURG 23
+#define SIGXCPU 24
+#define SIGXFSZ 25
+#define SIGVTALRM 26
+#define SIGPROF 27
+#define SIGWINCH 28
+#define SIGIO 29
+#define SIGPOLL SIGIO
+/*
+#define SIGLOST 29
+*/
+#define SIGPWR 30
+#define SIGSYS 31
+#define SIGUNUSED 31
+
+/* These should not be considered constants from userland. */
+#define SIGRTMIN 32
+#define SIGRTMAX _NSIG
+
+/*
+ * SA_FLAGS values:
+ *
+ * SA_ONSTACK indicates that a registered stack_t will be used.
+ * SA_RESTART flag to get restarting signals (which were the default long ago)
+ * SA_NOCLDSTOP flag to turn off SIGCHLD when children stop.
+ * SA_RESETHAND clears the handler when the signal is delivered.
+ * SA_NOCLDWAIT flag on SIGCHLD to inhibit zombies.
+ * SA_NODEFER prevents the current signal from being masked in the handler.
+ *
+ * SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single
+ * Unix names RESETHAND and NODEFER respectively.
+ */
+#define SA_NOCLDSTOP 0x00000001
+#define SA_NOCLDWAIT 0x00000002
+#define SA_SIGINFO 0x00000004
+#define SA_ONSTACK 0x08000000
+#define SA_RESTART 0x10000000
+#define SA_NODEFER 0x40000000
+#define SA_RESETHAND 0x80000000
+
+#define SA_NOMASK SA_NODEFER
+#define SA_ONESHOT SA_RESETHAND
+
+#define SA_RESTORER 0x04000000
+
+/*
+ * sigaltstack controls
+ */
+#define SS_ONSTACK 1
+#define SS_DISABLE 2
+
+#define MINSIGSTKSZ 2048
+#define SIGSTKSZ 8192
+
+#include <asm-generic/signal-defs.h>
+
+#ifndef __KERNEL__
+/* Here we must cater to libcs that poke about in kernel headers. */
+
+struct sigaction {
+ union {
+ __sighandler_t _sa_handler;
+ void (*_sa_sigaction)(int, struct siginfo *, void *);
+ } _u;
+#ifndef __s390x__ /* lovely */
+ sigset_t sa_mask;
+ unsigned long sa_flags;
+ void (*sa_restorer)(void);
+#else /* __s390x__ */
+ unsigned long sa_flags;
+ void (*sa_restorer)(void);
+ sigset_t sa_mask;
+#endif /* __s390x__ */
+};
+
+#define sa_handler _u._sa_handler
+#define sa_sigaction _u._sa_sigaction
+
+#endif /* __KERNEL__ */
+
+typedef struct sigaltstack {
+ void __user *ss_sp;
+ int ss_flags;
+ size_t ss_size;
+} stack_t;
+
+
+#endif /* _UAPI_ASMS390_SIGNAL_H */
diff --git a/arch/s390/include/asm/socket.h b/arch/s390/include/uapi/asm/socket.h
index 69718cd..69718cd 100644
--- a/arch/s390/include/asm/socket.h
+++ b/arch/s390/include/uapi/asm/socket.h
diff --git a/arch/s390/include/asm/sockios.h b/arch/s390/include/uapi/asm/sockios.h
index 6f60eee..6f60eee 100644
--- a/arch/s390/include/asm/sockios.h
+++ b/arch/s390/include/uapi/asm/sockios.h
diff --git a/arch/s390/include/asm/stat.h b/arch/s390/include/uapi/asm/stat.h
index b4ca97d..b4ca97d 100644
--- a/arch/s390/include/asm/stat.h
+++ b/arch/s390/include/uapi/asm/stat.h
diff --git a/arch/s390/include/asm/statfs.h b/arch/s390/include/uapi/asm/statfs.h
index 5acca0a..5acca0a 100644
--- a/arch/s390/include/asm/statfs.h
+++ b/arch/s390/include/uapi/asm/statfs.h
diff --git a/arch/s390/include/asm/swab.h b/arch/s390/include/uapi/asm/swab.h
index da3bfe5..da3bfe5 100644
--- a/arch/s390/include/asm/swab.h
+++ b/arch/s390/include/uapi/asm/swab.h
diff --git a/arch/s390/include/asm/tape390.h b/arch/s390/include/uapi/asm/tape390.h
index b2bc4ba..b2bc4ba 100644
--- a/arch/s390/include/asm/tape390.h
+++ b/arch/s390/include/uapi/asm/tape390.h
diff --git a/arch/s390/include/asm/termbits.h b/arch/s390/include/uapi/asm/termbits.h
index 71bf6ac..71bf6ac 100644
--- a/arch/s390/include/asm/termbits.h
+++ b/arch/s390/include/uapi/asm/termbits.h
diff --git a/arch/s390/include/uapi/asm/termios.h b/arch/s390/include/uapi/asm/termios.h
new file mode 100644
index 0000000..554f973
--- /dev/null
+++ b/arch/s390/include/uapi/asm/termios.h
@@ -0,0 +1,49 @@
+/*
+ * S390 version
+ *
+ * Derived from "include/asm-i386/termios.h"
+ */
+
+#ifndef _UAPI_S390_TERMIOS_H
+#define _UAPI_S390_TERMIOS_H
+
+#include <asm/termbits.h>
+#include <asm/ioctls.h>
+
+struct winsize {
+ unsigned short ws_row;
+ unsigned short ws_col;
+ unsigned short ws_xpixel;
+ unsigned short ws_ypixel;
+};
+
+#define NCC 8
+struct termio {
+ unsigned short c_iflag; /* input mode flags */
+ unsigned short c_oflag; /* output mode flags */
+ unsigned short c_cflag; /* control mode flags */
+ unsigned short c_lflag; /* local mode flags */
+ unsigned char c_line; /* line discipline */
+ unsigned char c_cc[NCC]; /* control characters */
+};
+
+/* modem lines */
+#define TIOCM_LE 0x001
+#define TIOCM_DTR 0x002
+#define TIOCM_RTS 0x004
+#define TIOCM_ST 0x008
+#define TIOCM_SR 0x010
+#define TIOCM_CTS 0x020
+#define TIOCM_CAR 0x040
+#define TIOCM_RNG 0x080
+#define TIOCM_DSR 0x100
+#define TIOCM_CD TIOCM_CAR
+#define TIOCM_RI TIOCM_RNG
+#define TIOCM_OUT1 0x2000
+#define TIOCM_OUT2 0x4000
+#define TIOCM_LOOP 0x8000
+
+/* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
+
+
+#endif /* _UAPI_S390_TERMIOS_H */
diff --git a/arch/s390/include/uapi/asm/types.h b/arch/s390/include/uapi/asm/types.h
new file mode 100644
index 0000000..038f2b9
--- /dev/null
+++ b/arch/s390/include/uapi/asm/types.h
@@ -0,0 +1,22 @@
+/*
+ * S390 version
+ *
+ * Derived from "include/asm-i386/types.h"
+ */
+
+#ifndef _UAPI_S390_TYPES_H
+#define _UAPI_S390_TYPES_H
+
+#include <asm-generic/int-ll64.h>
+
+#ifndef __ASSEMBLY__
+
+/* A address type so that arithmetic can be done on it & it can be upgraded to
+ 64 bit when necessary
+*/
+typedef unsigned long addr_t;
+typedef __signed__ long saddr_t;
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* _UAPI_S390_TYPES_H */
diff --git a/arch/s390/include/asm/ucontext.h b/arch/s390/include/uapi/asm/ucontext.h
index 200e063..200e063 100644
--- a/arch/s390/include/asm/ucontext.h
+++ b/arch/s390/include/uapi/asm/ucontext.h
diff --git a/arch/s390/include/uapi/asm/unistd.h b/arch/s390/include/uapi/asm/unistd.h
new file mode 100644
index 0000000..63e6078
--- /dev/null
+++ b/arch/s390/include/uapi/asm/unistd.h
@@ -0,0 +1,374 @@
+/*
+ * S390 version
+ *
+ * Derived from "include/asm-i386/unistd.h"
+ */
+
+#ifndef _UAPI_ASM_S390_UNISTD_H_
+#define _UAPI_ASM_S390_UNISTD_H_
+
+/*
+ * This file contains the system call numbers.
+ */
+
+#define __NR_exit 1
+#define __NR_fork 2
+#define __NR_read 3
+#define __NR_write 4
+#define __NR_open 5
+#define __NR_close 6
+#define __NR_restart_syscall 7
+#define __NR_creat 8
+#define __NR_link 9
+#define __NR_unlink 10
+#define __NR_execve 11
+#define __NR_chdir 12
+#define __NR_mknod 14
+#define __NR_chmod 15
+#define __NR_lseek 19
+#define __NR_getpid 20
+#define __NR_mount 21
+#define __NR_umount 22
+#define __NR_ptrace 26
+#define __NR_alarm 27
+#define __NR_pause 29
+#define __NR_utime 30
+#define __NR_access 33
+#define __NR_nice 34
+#define __NR_sync 36
+#define __NR_kill 37
+#define __NR_rename 38
+#define __NR_mkdir 39
+#define __NR_rmdir 40
+#define __NR_dup 41
+#define __NR_pipe 42
+#define __NR_times 43
+#define __NR_brk 45
+#define __NR_signal 48
+#define __NR_acct 51
+#define __NR_umount2 52
+#define __NR_ioctl 54
+#define __NR_fcntl 55
+#define __NR_setpgid 57
+#define __NR_umask 60
+#define __NR_chroot 61
+#define __NR_ustat 62
+#define __NR_dup2 63
+#define __NR_getppid 64
+#define __NR_getpgrp 65
+#define __NR_setsid 66
+#define __NR_sigaction 67
+#define __NR_sigsuspend 72
+#define __NR_sigpending 73
+#define __NR_sethostname 74
+#define __NR_setrlimit 75
+#define __NR_getrusage 77
+#define __NR_gettimeofday 78
+#define __NR_settimeofday 79
+#define __NR_symlink 83
+#define __NR_readlink 85
+#define __NR_uselib 86
+#define __NR_swapon 87
+#define __NR_reboot 88
+#define __NR_readdir 89
+#define __NR_mmap 90
+#define __NR_munmap 91
+#define __NR_truncate 92
+#define __NR_ftruncate 93
+#define __NR_fchmod 94
+#define __NR_getpriority 96
+#define __NR_setpriority 97
+#define __NR_statfs 99
+#define __NR_fstatfs 100
+#define __NR_socketcall 102
+#define __NR_syslog 103
+#define __NR_setitimer 104
+#define __NR_getitimer 105
+#define __NR_stat 106
+#define __NR_lstat 107
+#define __NR_fstat 108
+#define __NR_lookup_dcookie 110
+#define __NR_vhangup 111
+#define __NR_idle 112
+#define __NR_wait4 114
+#define __NR_swapoff 115
+#define __NR_sysinfo 116
+#define __NR_ipc 117
+#define __NR_fsync 118
+#define __NR_sigreturn 119
+#define __NR_clone 120
+#define __NR_setdomainname 121
+#define __NR_uname 122
+#define __NR_adjtimex 124
+#define __NR_mprotect 125
+#define __NR_sigprocmask 126
+#define __NR_create_module 127
+#define __NR_init_module 128
+#define __NR_delete_module 129
+#define __NR_get_kernel_syms 130
+#define __NR_quotactl 131
+#define __NR_getpgid 132
+#define __NR_fchdir 133
+#define __NR_bdflush 134
+#define __NR_sysfs 135
+#define __NR_personality 136
+#define __NR_afs_syscall 137 /* Syscall for Andrew File System */
+#define __NR_getdents 141
+#define __NR_flock 143
+#define __NR_msync 144
+#define __NR_readv 145
+#define __NR_writev 146
+#define __NR_getsid 147
+#define __NR_fdatasync 148
+#define __NR__sysctl 149
+#define __NR_mlock 150
+#define __NR_munlock 151
+#define __NR_mlockall 152
+#define __NR_munlockall 153
+#define __NR_sched_setparam 154
+#define __NR_sched_getparam 155
+#define __NR_sched_setscheduler 156
+#define __NR_sched_getscheduler 157
+#define __NR_sched_yield 158
+#define __NR_sched_get_priority_max 159
+#define __NR_sched_get_priority_min 160
+#define __NR_sched_rr_get_interval 161
+#define __NR_nanosleep 162
+#define __NR_mremap 163
+#define __NR_query_module 167
+#define __NR_poll 168
+#define __NR_nfsservctl 169
+#define __NR_prctl 172
+#define __NR_rt_sigreturn 173
+#define __NR_rt_sigaction 174
+#define __NR_rt_sigprocmask 175
+#define __NR_rt_sigpending 176
+#define __NR_rt_sigtimedwait 177
+#define __NR_rt_sigqueueinfo 178
+#define __NR_rt_sigsuspend 179
+#define __NR_pread64 180
+#define __NR_pwrite64 181
+#define __NR_getcwd 183
+#define __NR_capget 184
+#define __NR_capset 185
+#define __NR_sigaltstack 186
+#define __NR_sendfile 187
+#define __NR_getpmsg 188
+#define __NR_putpmsg 189
+#define __NR_vfork 190
+#define __NR_pivot_root 217
+#define __NR_mincore 218
+#define __NR_madvise 219
+#define __NR_getdents64 220
+#define __NR_readahead 222
+#define __NR_setxattr 224
+#define __NR_lsetxattr 225
+#define __NR_fsetxattr 226
+#define __NR_getxattr 227
+#define __NR_lgetxattr 228
+#define __NR_fgetxattr 229
+#define __NR_listxattr 230
+#define __NR_llistxattr 231
+#define __NR_flistxattr 232
+#define __NR_removexattr 233
+#define __NR_lremovexattr 234
+#define __NR_fremovexattr 235
+#define __NR_gettid 236
+#define __NR_tkill 237
+#define __NR_futex 238
+#define __NR_sched_setaffinity 239
+#define __NR_sched_getaffinity 240
+#define __NR_tgkill 241
+/* Number 242 is reserved for tux */
+#define __NR_io_setup 243
+#define __NR_io_destroy 244
+#define __NR_io_getevents 245
+#define __NR_io_submit 246
+#define __NR_io_cancel 247
+#define __NR_exit_group 248
+#define __NR_epoll_create 249
+#define __NR_epoll_ctl 250
+#define __NR_epoll_wait 251
+#define __NR_set_tid_address 252
+#define __NR_fadvise64 253
+#define __NR_timer_create 254
+#define __NR_timer_settime (__NR_timer_create+1)
+#define __NR_timer_gettime (__NR_timer_create+2)
+#define __NR_timer_getoverrun (__NR_timer_create+3)
+#define __NR_timer_delete (__NR_timer_create+4)
+#define __NR_clock_settime (__NR_timer_create+5)
+#define __NR_clock_gettime (__NR_timer_create+6)
+#define __NR_clock_getres (__NR_timer_create+7)
+#define __NR_clock_nanosleep (__NR_timer_create+8)
+/* Number 263 is reserved for vserver */
+#define __NR_statfs64 265
+#define __NR_fstatfs64 266
+#define __NR_remap_file_pages 267
+/* Number 268 is reserved for new sys_mbind */
+/* Number 269 is reserved for new sys_get_mempolicy */
+/* Number 270 is reserved for new sys_set_mempolicy */
+#define __NR_mq_open 271
+#define __NR_mq_unlink 272
+#define __NR_mq_timedsend 273
+#define __NR_mq_timedreceive 274
+#define __NR_mq_notify 275
+#define __NR_mq_getsetattr 276
+#define __NR_kexec_load 277
+#define __NR_add_key 278
+#define __NR_request_key 279
+#define __NR_keyctl 280
+#define __NR_waitid 281
+#define __NR_ioprio_set 282
+#define __NR_ioprio_get 283
+#define __NR_inotify_init 284
+#define __NR_inotify_add_watch 285
+#define __NR_inotify_rm_watch 286
+/* Number 287 is reserved for new sys_migrate_pages */
+#define __NR_openat 288
+#define __NR_mkdirat 289
+#define __NR_mknodat 290
+#define __NR_fchownat 291
+#define __NR_futimesat 292
+#define __NR_unlinkat 294
+#define __NR_renameat 295
+#define __NR_linkat 296
+#define __NR_symlinkat 297
+#define __NR_readlinkat 298
+#define __NR_fchmodat 299
+#define __NR_faccessat 300
+#define __NR_pselect6 301
+#define __NR_ppoll 302
+#define __NR_unshare 303
+#define __NR_set_robust_list 304
+#define __NR_get_robust_list 305
+#define __NR_splice 306
+#define __NR_sync_file_range 307
+#define __NR_tee 308
+#define __NR_vmsplice 309
+/* Number 310 is reserved for new sys_move_pages */
+#define __NR_getcpu 311
+#define __NR_epoll_pwait 312
+#define __NR_utimes 313
+#define __NR_fallocate 314
+#define __NR_utimensat 315
+#define __NR_signalfd 316
+#define __NR_timerfd 317
+#define __NR_eventfd 318
+#define __NR_timerfd_create 319
+#define __NR_timerfd_settime 320
+#define __NR_timerfd_gettime 321
+#define __NR_signalfd4 322
+#define __NR_eventfd2 323
+#define __NR_inotify_init1 324
+#define __NR_pipe2 325
+#define __NR_dup3 326
+#define __NR_epoll_create1 327
+#define __NR_preadv 328
+#define __NR_pwritev 329
+#define __NR_rt_tgsigqueueinfo 330
+#define __NR_perf_event_open 331
+#define __NR_fanotify_init 332
+#define __NR_fanotify_mark 333
+#define __NR_prlimit64 334
+#define __NR_name_to_handle_at 335
+#define __NR_open_by_handle_at 336
+#define __NR_clock_adjtime 337
+#define __NR_syncfs 338
+#define __NR_setns 339
+#define __NR_process_vm_readv 340
+#define __NR_process_vm_writev 341
+#define __NR_s390_runtime_instr 342
+#define __NR_kcmp 343
+#define NR_syscalls 344
+
+/*
+ * There are some system calls that are not present on 64 bit, some
+ * have a different name although they do the same (e.g. __NR_chown32
+ * is __NR_chown on 64 bit).
+ */
+#ifndef __s390x__
+
+#define __NR_time 13
+#define __NR_lchown 16
+#define __NR_setuid 23
+#define __NR_getuid 24
+#define __NR_stime 25
+#define __NR_setgid 46
+#define __NR_getgid 47
+#define __NR_geteuid 49
+#define __NR_getegid 50
+#define __NR_setreuid 70
+#define __NR_setregid 71
+#define __NR_getrlimit 76
+#define __NR_getgroups 80
+#define __NR_setgroups 81
+#define __NR_fchown 95
+#define __NR_ioperm 101
+#define __NR_setfsuid 138
+#define __NR_setfsgid 139
+#define __NR__llseek 140
+#define __NR__newselect 142
+#define __NR_setresuid 164
+#define __NR_getresuid 165
+#define __NR_setresgid 170
+#define __NR_getresgid 171
+#define __NR_chown 182
+#define __NR_ugetrlimit 191 /* SuS compliant getrlimit */
+#define __NR_mmap2 192
+#define __NR_truncate64 193
+#define __NR_ftruncate64 194
+#define __NR_stat64 195
+#define __NR_lstat64 196
+#define __NR_fstat64 197
+#define __NR_lchown32 198
+#define __NR_getuid32 199
+#define __NR_getgid32 200
+#define __NR_geteuid32 201
+#define __NR_getegid32 202
+#define __NR_setreuid32 203
+#define __NR_setregid32 204
+#define __NR_getgroups32 205
+#define __NR_setgroups32 206
+#define __NR_fchown32 207
+#define __NR_setresuid32 208
+#define __NR_getresuid32 209
+#define __NR_setresgid32 210
+#define __NR_getresgid32 211
+#define __NR_chown32 212
+#define __NR_setuid32 213
+#define __NR_setgid32 214
+#define __NR_setfsuid32 215
+#define __NR_setfsgid32 216
+#define __NR_fcntl64 221
+#define __NR_sendfile64 223
+#define __NR_fadvise64_64 264
+#define __NR_fstatat64 293
+
+#else
+
+#define __NR_select 142
+#define __NR_getrlimit 191 /* SuS compliant getrlimit */
+#define __NR_lchown 198
+#define __NR_getuid 199
+#define __NR_getgid 200
+#define __NR_geteuid 201
+#define __NR_getegid 202
+#define __NR_setreuid 203
+#define __NR_setregid 204
+#define __NR_getgroups 205
+#define __NR_setgroups 206
+#define __NR_fchown 207
+#define __NR_setresuid 208
+#define __NR_getresuid 209
+#define __NR_setresgid 210
+#define __NR_getresgid 211
+#define __NR_chown 212
+#define __NR_setuid 213
+#define __NR_setgid 214
+#define __NR_setfsuid 215
+#define __NR_setfsgid 216
+#define __NR_newfstatat 293
+
+#endif
+
+#endif /* _UAPI_ASM_S390_UNISTD_H_ */
diff --git a/arch/s390/include/asm/vtoc.h b/arch/s390/include/uapi/asm/vtoc.h
index 221419d..221419d 100644
--- a/arch/s390/include/asm/vtoc.h
+++ b/arch/s390/include/uapi/asm/vtoc.h
diff --git a/arch/s390/include/asm/zcrypt.h b/arch/s390/include/uapi/asm/zcrypt.h
index e83fc11..e83fc11 100644
--- a/arch/s390/include/asm/zcrypt.h
+++ b/arch/s390/include/uapi/asm/zcrypt.h
diff --git a/arch/s390/kernel/compat_linux.c b/arch/s390/kernel/compat_linux.c
index 189963c..65cca95 100644
--- a/arch/s390/kernel/compat_linux.c
+++ b/arch/s390/kernel/compat_linux.c
@@ -432,32 +432,6 @@ sys32_rt_sigqueueinfo(int pid, int sig, compat_siginfo_t __user *uinfo)
return ret;
}
-/*
- * sys32_execve() executes a new program after the asm stub has set
- * things up for us. This should basically do what I want it to.
- */
-asmlinkage long sys32_execve(const char __user *name, compat_uptr_t __user *argv,
- compat_uptr_t __user *envp)
-{
- struct pt_regs *regs = task_pt_regs(current);
- char *filename;
- long rc;
-
- filename = getname(name);
- rc = PTR_ERR(filename);
- if (IS_ERR(filename))
- return rc;
- rc = compat_do_execve(filename, argv, envp, regs);
- if (rc)
- goto out;
- current->thread.fp_regs.fpc=0;
- asm volatile("sfpc %0,0" : : "d" (0));
- rc = regs->gprs[2];
-out:
- putname(filename);
- return rc;
-}
-
asmlinkage long sys32_pread64(unsigned int fd, char __user *ubuf,
size_t count, u32 poshi, u32 poslo)
{
diff --git a/arch/s390/kernel/compat_linux.h b/arch/s390/kernel/compat_linux.h
index 90887bd..d4d0239 100644
--- a/arch/s390/kernel/compat_linux.h
+++ b/arch/s390/kernel/compat_linux.h
@@ -125,8 +125,6 @@ long sys32_rt_sigprocmask(int how, compat_sigset_t __user *set,
compat_sigset_t __user *oset, size_t sigsetsize);
long sys32_rt_sigpending(compat_sigset_t __user *set, size_t sigsetsize);
long sys32_rt_sigqueueinfo(int pid, int sig, compat_siginfo_t __user *uinfo);
-long sys32_execve(const char __user *name, compat_uptr_t __user *argv,
- compat_uptr_t __user *envp);
long sys32_init_module(void __user *umod, unsigned long len,
const char __user *uargs);
long sys32_delete_module(const char __user *name_user, unsigned int flags);
diff --git a/arch/s390/kernel/compat_wrapper.S b/arch/s390/kernel/compat_wrapper.S
index 3afba80..ad79b84 100644
--- a/arch/s390/kernel/compat_wrapper.S
+++ b/arch/s390/kernel/compat_wrapper.S
@@ -1576,7 +1576,7 @@ ENTRY(sys32_execve_wrapper)
llgtr %r2,%r2 # char *
llgtr %r3,%r3 # compat_uptr_t *
llgtr %r4,%r4 # compat_uptr_t *
- jg sys32_execve # branch to system call
+ jg compat_sys_execve # branch to system call
ENTRY(sys_fanotify_init_wrapper)
llgfr %r2,%r2 # unsigned int
diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c
index 00d1144..1f0eee9 100644
--- a/arch/s390/kernel/early.c
+++ b/arch/s390/kernel/early.c
@@ -283,14 +283,6 @@ static noinline __init void setup_facility_list(void)
ARRAY_SIZE(S390_lowcore.stfle_fac_list));
}
-static noinline __init void setup_hpage(void)
-{
- if (!test_facility(2) || !test_facility(8))
- return;
- S390_lowcore.machine_flags |= MACHINE_FLAG_HPAGE;
- __ctl_set_bit(0, 23);
-}
-
static __init void detect_mvpg(void)
{
#ifndef CONFIG_64BIT
@@ -378,10 +370,14 @@ static __init void detect_diag44(void)
static __init void detect_machine_facilities(void)
{
#ifdef CONFIG_64BIT
+ if (test_facility(8)) {
+ S390_lowcore.machine_flags |= MACHINE_FLAG_EDAT1;
+ __ctl_set_bit(0, 23);
+ }
+ if (test_facility(78))
+ S390_lowcore.machine_flags |= MACHINE_FLAG_EDAT2;
if (test_facility(3))
S390_lowcore.machine_flags |= MACHINE_FLAG_IDTE;
- if (test_facility(8))
- S390_lowcore.machine_flags |= MACHINE_FLAG_PFMF;
if (test_facility(27))
S390_lowcore.machine_flags |= MACHINE_FLAG_MVCOS;
if (test_facility(40))
@@ -484,7 +480,6 @@ void __init startup_init(void)
detect_diag9c();
detect_diag44();
detect_machine_facilities();
- setup_hpage();
setup_topology();
sclp_facilities_detect();
detect_memory_layout(memory_chunk);
diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S
index 870bad6..ef46f66 100644
--- a/arch/s390/kernel/entry.S
+++ b/arch/s390/kernel/entry.S
@@ -331,45 +331,38 @@ ENTRY(ret_from_fork)
l %r12,__LC_THREAD_INFO
l %r13,__LC_SVC_NEW_PSW+4
tm __PT_PSW+1(%r11),0x01 # forking a kernel thread ?
- jo 0f
- st %r15,__PT_R15(%r11) # store stack pointer for new kthread
-0: l %r1,BASED(.Lschedule_tail)
+ je 1f
+ l %r1,BASED(.Lschedule_tail)
basr %r14,%r1 # call schedule_tail
TRACE_IRQS_ON
ssm __LC_SVC_NEW_PSW # reenable interrupts
j sysc_tracenogo
+1: # it's a kernel thread
+ st %r15,__PT_R15(%r11) # store stack pointer for new kthread
+ l %r1,BASED(.Lschedule_tail)
+ basr %r14,%r1 # call schedule_tail
+ TRACE_IRQS_ON
+ ssm __LC_SVC_NEW_PSW # reenable interrupts
+ lm %r9,%r11,__PT_R9(%r11) # load gprs
+ENTRY(kernel_thread_starter)
+ la %r2,0(%r10)
+ basr %r14,%r9
+ la %r2,0
+ br %r11 # do_exit
+
#
# kernel_execve function needs to deal with pt_regs that is not
# at the usual place
#
-ENTRY(kernel_execve)
- stm %r12,%r15,48(%r15)
- lr %r14,%r15
- l %r13,__LC_SVC_NEW_PSW+4
- ahi %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE)
- st %r14,__SF_BACKCHAIN(%r15)
- la %r12,STACK_FRAME_OVERHEAD(%r15)
- xc 0(__PT_SIZE,%r12),0(%r12)
- l %r1,BASED(.Ldo_execve)
- lr %r5,%r12
- basr %r14,%r1 # call do_execve
- ltr %r2,%r2
- je 0f
- ahi %r15,(STACK_FRAME_OVERHEAD + __PT_SIZE)
- lm %r12,%r15,48(%r15)
- br %r14
- # execve succeeded.
-0: ssm __LC_PGM_NEW_PSW # disable I/O and ext. interrupts
- l %r15,__LC_KERNEL_STACK # load ksp
- ahi %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE)
- la %r11,STACK_FRAME_OVERHEAD(%r15)
- mvc 0(__PT_SIZE,%r11),0(%r12) # copy pt_regs
- l %r12,__LC_THREAD_INFO
+ENTRY(ret_from_kernel_execve)
+ ssm __LC_PGM_NEW_PSW # disable I/O and ext. interrupts
+ lr %r15,%r2
+ lr %r11,%r2
+ ahi %r15,-STACK_FRAME_OVERHEAD
xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15)
+ l %r12,__LC_THREAD_INFO
ssm __LC_SVC_NEW_PSW # reenable interrupts
- l %r1,BASED(.Lexecve_tail)
- basr %r14,%r1 # call execve_tail
j sysc_return
/*
@@ -931,8 +924,6 @@ cleanup_idle_wait:
.Ldo_signal: .long do_signal
.Ldo_notify_resume: .long do_notify_resume
.Ldo_per_trap: .long do_per_trap
-.Ldo_execve: .long do_execve
-.Lexecve_tail: .long execve_tail
.Ljump_table: .long pgm_check_table
.Lschedule: .long schedule
#ifdef CONFIG_PREEMPT
diff --git a/arch/s390/kernel/entry.h b/arch/s390/kernel/entry.h
index a5f4dc4..d0d3f69 100644
--- a/arch/s390/kernel/entry.h
+++ b/arch/s390/kernel/entry.h
@@ -58,9 +58,6 @@ long sys_fork(void);
long sys_clone(unsigned long newsp, unsigned long clone_flags,
int __user *parent_tidptr, int __user *child_tidptr);
long sys_vfork(void);
-void execve_tail(void);
-long sys_execve(const char __user *name, const char __user *const __user *argv,
- const char __user *const __user *envp);
long sys_sigsuspend(int history0, int history1, old_sigset_t mask);
long sys_sigaction(int sig, const struct old_sigaction __user *act,
struct old_sigaction __user *oact);
diff --git a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S
index 7549985..07d8de3 100644
--- a/arch/s390/kernel/entry64.S
+++ b/arch/s390/kernel/entry64.S
@@ -295,7 +295,7 @@ sysc_sigpending:
jno sysc_return
lmg %r2,%r7,__PT_R2(%r11) # load svc arguments
lghi %r8,0 # svc 0 returns -ENOSYS
- lh %r1,__PT_INT_CODE+2(%r11) # load new svc number
+ llgh %r1,__PT_INT_CODE+2(%r11) # load new svc number
cghi %r1,NR_syscalls
jnl sysc_nr_ok # invalid svc number -> do svc 0
slag %r8,%r1,2
@@ -353,41 +353,31 @@ ENTRY(ret_from_fork)
la %r11,STACK_FRAME_OVERHEAD(%r15)
lg %r12,__LC_THREAD_INFO
tm __PT_PSW+1(%r11),0x01 # forking a kernel thread ?
- jo 0f
- stg %r15,__PT_R15(%r11) # store stack pointer for new kthread
-0: brasl %r14,schedule_tail
+ je 1f
+ brasl %r14,schedule_tail
TRACE_IRQS_ON
ssm __LC_SVC_NEW_PSW # reenable interrupts
j sysc_tracenogo
-
-#
-# kernel_execve function needs to deal with pt_regs that is not
-# at the usual place
-#
-ENTRY(kernel_execve)
- stmg %r12,%r15,96(%r15)
- lgr %r14,%r15
- aghi %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE)
- stg %r14,__SF_BACKCHAIN(%r15)
- la %r12,STACK_FRAME_OVERHEAD(%r15)
- xc 0(__PT_SIZE,%r12),0(%r12)
- lgr %r5,%r12
- brasl %r14,do_execve
- ltgfr %r2,%r2
- je 0f
- aghi %r15,(STACK_FRAME_OVERHEAD + __PT_SIZE)
- lmg %r12,%r15,96(%r15)
- br %r14
- # execve succeeded.
-0: ssm __LC_PGM_NEW_PSW # disable I/O and ext. interrupts
- lg %r15,__LC_KERNEL_STACK # load ksp
- aghi %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE)
- la %r11,STACK_FRAME_OVERHEAD(%r15)
- mvc 0(__PT_SIZE,%r11),0(%r12) # copy pt_regs
- lg %r12,__LC_THREAD_INFO
+1: # it's a kernel thread
+ stg %r15,__PT_R15(%r11) # store stack pointer for new kthread
+ brasl %r14,schedule_tail
+ TRACE_IRQS_ON
+ ssm __LC_SVC_NEW_PSW # reenable interrupts
+ lmg %r9,%r11,__PT_R9(%r11) # load gprs
+ENTRY(kernel_thread_starter)
+ la %r2,0(%r10)
+ basr %r14,%r9
+ la %r2,0
+ br %r11 # do_exit
+
+ENTRY(ret_from_kernel_execve)
+ ssm __LC_PGM_NEW_PSW # disable I/O and ext. interrupts
+ lgr %r15,%r2
+ lgr %r11,%r2
+ aghi %r15,-STACK_FRAME_OVERHEAD
xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15)
+ lg %r12,__LC_THREAD_INFO
ssm __LC_SVC_NEW_PSW # reenable interrupts
- brasl %r14,execve_tail
j sysc_return
/*
diff --git a/arch/s390/kernel/head.S b/arch/s390/kernel/head.S
index 805b668..984726c 100644
--- a/arch/s390/kernel/head.S
+++ b/arch/s390/kernel/head.S
@@ -52,7 +52,7 @@ __HEAD
.long 0x02000370,0x60000050 # the channel program the PSW
.long 0x020003c0,0x60000050 # at location 0 is loaded.
.long 0x02000410,0x60000050 # Initial processing starts
- .long 0x02000460,0x60000050 # at 0xf0 = iplstart.
+ .long 0x02000460,0x60000050 # at 0x200 = iplstart.
.long 0x020004b0,0x60000050
.long 0x02000500,0x60000050
.long 0x02000550,0x60000050
@@ -62,11 +62,54 @@ __HEAD
.long 0x02000690,0x60000050
.long 0x020006e0,0x20000050
- .org 0xf0
+ .org 0x200
+#
+# subroutine to set architecture mode
+#
+.Lsetmode:
+#ifdef CONFIG_64BIT
+ mvi __LC_AR_MODE_ID,1 # set esame flag
+ slr %r0,%r0 # set cpuid to zero
+ lhi %r1,2 # mode 2 = esame (dump)
+ sigp %r1,%r0,0x12 # switch to esame mode
+ bras %r13,0f
+ .fill 16,4,0x0
+0: lmh %r0,%r15,0(%r13) # clear high-order half of gprs
+ sam31 # switch to 31 bit addressing mode
+#else
+ mvi __LC_AR_MODE_ID,0 # set ESA flag (mode 0)
+#endif
+ br %r14
+
+#
+# subroutine to wait for end I/O
+#
+.Lirqwait:
+#ifdef CONFIG_64BIT
+ mvc 0x1f0(16),.Lnewpsw # set up IO interrupt psw
+ lpsw .Lwaitpsw
+.Lioint:
+ br %r14
+ .align 8
+.Lnewpsw:
+ .quad 0x0000000080000000,.Lioint
+#else
+ mvc 0x78(8),.Lnewpsw # set up IO interrupt psw
+ lpsw .Lwaitpsw
+.Lioint:
+ br %r14
+ .align 8
+.Lnewpsw:
+ .long 0x00080000,0x80000000+.Lioint
+#endif
+.Lwaitpsw:
+ .long 0x020a0000,0x80000000+.Lioint
+
#
# subroutine for loading cards from the reader
#
.Lloader:
+ la %r4,0(%r14)
la %r3,.Lorb # r2 = address of orb into r2
la %r5,.Lirb # r4 = address of irb
la %r6,.Lccws
@@ -83,9 +126,7 @@ __HEAD
ssch 0(%r3) # load chunk of 1600 bytes
bnz .Llderr
.Lwait4irq:
- mvc 0x78(8),.Lnewpsw # set up IO interrupt psw
- lpsw .Lwaitpsw
-.Lioint:
+ bas %r14,.Lirqwait
c %r1,0xb8 # compare subchannel number
bne .Lwait4irq
tsch 0(%r5)
@@ -104,7 +145,7 @@ __HEAD
sr %r0,%r3 # #ccws*80-residual=#bytes read
ar %r2,%r0
- br %r14 # r2 contains the total size
+ br %r4 # r2 contains the total size
.Lcont:
ahi %r2,0x640 # add 0x640 to total size
@@ -128,10 +169,6 @@ __HEAD
.Lloadp:.long 0,0
.align 8
.Lcrash:.long 0x000a0000,0x00000000
-.Lnewpsw:
- .long 0x00080000,0x80000000+.Lioint
-.Lwaitpsw:
- .long 0x020a0000,0x80000000+.Lioint
.align 8
.Lccws: .rept 19
@@ -140,6 +177,7 @@ __HEAD
.long 0x02200050,0x00000000
iplstart:
+ bas %r14,.Lsetmode # Immediately switch to 64 bit mode
lh %r1,0xb8 # test if subchannel number
bct %r1,.Lnoload # is valid
l %r1,0xb8 # load ipl subchannel number
@@ -209,8 +247,8 @@ iplstart:
#
# reset files in VM reader
#
- stidp __LC_SAVE_AREA_SYNC # store cpuid
- tm __LC_SAVE_AREA_SYNC,0xff# running VM ?
+ stidp .Lcpuid # store cpuid
+ tm .Lcpuid,0xff # running VM ?
bno .Lnoreset
la %r2,.Lreset
lhi %r3,26
@@ -222,23 +260,14 @@ iplstart:
tm 31(%r5),0xff # bits is set in the schib
bz .Lnoreset
.Lwaitforirq:
- mvc 0x78(8),.Lrdrnewpsw # set up IO interrupt psw
-.Lwaitrdrirq:
- lpsw .Lrdrwaitpsw
-.Lrdrint:
+ bas %r14,.Lirqwait # wait for IO interrupt
c %r1,0xb8 # compare subchannel number
- bne .Lwaitrdrirq
+ bne .Lwaitforirq
la %r5,.Lirb
tsch 0(%r5)
.Lnoreset:
b .Lnoload
- .align 8
-.Lrdrnewpsw:
- .long 0x00080000,0x80000000+.Lrdrint
-.Lrdrwaitpsw:
- .long 0x020a0000,0x80000000+.Lrdrint
-
#
# everything loaded, go for it
#
@@ -254,6 +283,8 @@ iplstart:
.byte 0xc8,0xd6,0xd3,0xc4 # "change rdr all keep nohold"
.L_eof: .long 0xc5d6c600 /* C'EOF' */
.L_hdr: .long 0xc8c4d900 /* C'HDR' */
+ .align 8
+.Lcpuid:.fill 8,1,0
#
# SALIPL loader support. Based on a patch by Rob van der Heij.
@@ -263,6 +294,7 @@ iplstart:
.org 0x800
ENTRY(start)
stm %r0,%r15,0x07b0 # store registers
+ bas %r14,.Lsetmode # Immediately switch to 64 bit mode
basr %r12,%r0
.base:
l %r11,.parm
@@ -343,6 +375,18 @@ ENTRY(startup)
ENTRY(startup_kdump)
j .Lep_startup_kdump
.Lep_startup_normal:
+#ifdef CONFIG_64BIT
+ mvi __LC_AR_MODE_ID,1 # set esame flag
+ slr %r0,%r0 # set cpuid to zero
+ lhi %r1,2 # mode 2 = esame (dump)
+ sigp %r1,%r0,0x12 # switch to esame mode
+ bras %r13,0f
+ .fill 16,4,0x0
+0: lmh %r0,%r15,0(%r13) # clear high-order half of gprs
+ sam31 # switch to 31 bit addressing mode
+#else
+ mvi __LC_AR_MODE_ID,0 # set ESA flag (mode 0)
+#endif
basr %r13,0 # get base
.LPG0:
xc 0x200(256),0x200 # partially clear lowcore
@@ -410,22 +454,17 @@ ENTRY(startup_kdump)
#endif
#ifdef CONFIG_64BIT
- mvi __LC_AR_MODE_ID,1 # set esame flag
- slr %r0,%r0 # set cpuid to zero
- lhi %r1,2 # mode 2 = esame (dump)
- sigp %r1,%r0,0x12 # switch to esame mode
+ /* Continue with 64bit startup code in head64.S */
sam64 # switch to 64 bit mode
- larl %r13,4f
- lmh %r0,%r15,0(%r13) # clear high-order half
jg startup_continue
-4: .fill 16,4,0x0
#else
- mvi __LC_AR_MODE_ID,0 # set ESA flag (mode 0)
+ /* Continue with 31bit startup code in head31.S */
l %r13,4f-.LPG0(%r13)
b 0(%r13)
.align 8
4: .long startup_continue
#endif
+
.align 8
5: .long 0x7fffffff,0xffffffff
diff --git a/arch/s390/kernel/head31.S b/arch/s390/kernel/head31.S
index a1372ae..9a99856 100644
--- a/arch/s390/kernel/head31.S
+++ b/arch/s390/kernel/head31.S
@@ -78,10 +78,7 @@ ENTRY(startup_continue)
ENTRY(_ehead)
-#ifdef CONFIG_SHARED_KERNEL
.org 0x100000 - 0x11000 # head.o ends at 0x11000
-#endif
-
#
# startup-code, running in absolute addressing mode
#
diff --git a/arch/s390/kernel/head64.S b/arch/s390/kernel/head64.S
index c108af2..b9e25ae 100644
--- a/arch/s390/kernel/head64.S
+++ b/arch/s390/kernel/head64.S
@@ -76,10 +76,7 @@ ENTRY(startup_continue)
ENTRY(_ehead)
-#ifdef CONFIG_SHARED_KERNEL
.org 0x100000 - 0x11000 # head.o ends at 0x11000
-#endif
-
#
# startup-code, running in absolute addressing mode
#
diff --git a/arch/s390/kernel/module.c b/arch/s390/kernel/module.c
index 46412b1..4610dea 100644
--- a/arch/s390/kernel/module.c
+++ b/arch/s390/kernel/module.c
@@ -44,6 +44,17 @@
#define PLT_ENTRY_SIZE 20
#endif /* CONFIG_64BIT */
+#ifdef CONFIG_64BIT
+void *module_alloc(unsigned long size)
+{
+ if (PAGE_ALIGN(size) > MODULES_LEN)
+ return NULL;
+ return __vmalloc_node_range(size, 1, MODULES_VADDR, MODULES_END,
+ GFP_KERNEL, PAGE_KERNEL, -1,
+ __builtin_return_address(0));
+}
+#endif
+
/* Free memory returned from module_alloc */
void module_free(struct module *mod, void *module_region)
{
diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c
index 5024be2..cd31ad4 100644
--- a/arch/s390/kernel/process.c
+++ b/arch/s390/kernel/process.c
@@ -100,35 +100,6 @@ void cpu_idle(void)
extern void __kprobes kernel_thread_starter(void);
-asm(
- ".section .kprobes.text, \"ax\"\n"
- ".global kernel_thread_starter\n"
- "kernel_thread_starter:\n"
- " la 2,0(10)\n"
- " basr 14,9\n"
- " la 2,0\n"
- " br 11\n"
- ".previous\n");
-
-int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
-{
- struct pt_regs regs;
-
- memset(&regs, 0, sizeof(regs));
- regs.psw.mask = psw_kernel_bits |
- PSW_MASK_DAT | PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK;
- regs.psw.addr = (unsigned long) kernel_thread_starter | PSW_ADDR_AMODE;
- regs.gprs[9] = (unsigned long) fn;
- regs.gprs[10] = (unsigned long) arg;
- regs.gprs[11] = (unsigned long) do_exit;
- regs.orig_gpr2 = -1;
-
- /* Ok, create the new process.. */
- return do_fork(flags | CLONE_VM | CLONE_UNTRACED,
- 0, &regs, 0, NULL, NULL);
-}
-EXPORT_SYMBOL(kernel_thread);
-
/*
* Free current thread data structures etc..
*/
@@ -146,7 +117,7 @@ void release_thread(struct task_struct *dead_task)
}
int copy_thread(unsigned long clone_flags, unsigned long new_stackp,
- unsigned long unused,
+ unsigned long arg,
struct task_struct *p, struct pt_regs *regs)
{
struct thread_info *ti;
@@ -158,20 +129,44 @@ int copy_thread(unsigned long clone_flags, unsigned long new_stackp,
frame = container_of(task_pt_regs(p), struct fake_frame, childregs);
p->thread.ksp = (unsigned long) frame;
- /* Store access registers to kernel stack of new process. */
- frame->childregs = *regs;
- frame->childregs.gprs[2] = 0; /* child returns 0 on fork. */
- frame->childregs.gprs[15] = new_stackp;
- frame->sf.back_chain = 0;
+ /* Save access registers to new thread structure. */
+ save_access_regs(&p->thread.acrs[0]);
+ /* start new process with ar4 pointing to the correct address space */
+ p->thread.mm_segment = get_fs();
+ /* Don't copy debug registers */
+ memset(&p->thread.per_user, 0, sizeof(p->thread.per_user));
+ memset(&p->thread.per_event, 0, sizeof(p->thread.per_event));
+ clear_tsk_thread_flag(p, TIF_SINGLE_STEP);
+ clear_tsk_thread_flag(p, TIF_PER_TRAP);
+ /* Initialize per thread user and system timer values */
+ ti = task_thread_info(p);
+ ti->user_timer = 0;
+ ti->system_timer = 0;
+ frame->sf.back_chain = 0;
/* new return point is ret_from_fork */
frame->sf.gprs[8] = (unsigned long) ret_from_fork;
-
/* fake return stack for resume(), don't go back to schedule */
frame->sf.gprs[9] = (unsigned long) frame;
- /* Save access registers to new thread structure. */
- save_access_regs(&p->thread.acrs[0]);
+ /* Store access registers to kernel stack of new process. */
+ if (unlikely(!regs)) {
+ /* kernel thread */
+ memset(&frame->childregs, 0, sizeof(struct pt_regs));
+ frame->childregs.psw.mask = psw_kernel_bits | PSW_MASK_DAT |
+ PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK;
+ frame->childregs.psw.addr = PSW_ADDR_AMODE |
+ (unsigned long) kernel_thread_starter;
+ frame->childregs.gprs[9] = new_stackp; /* function */
+ frame->childregs.gprs[10] = arg;
+ frame->childregs.gprs[11] = (unsigned long) do_exit;
+ frame->childregs.orig_gpr2 = -1;
+
+ return 0;
+ }
+ frame->childregs = *regs;
+ frame->childregs.gprs[2] = 0; /* child returns 0 on fork. */
+ frame->childregs.gprs[15] = new_stackp;
/* Don't copy runtime instrumentation info */
p->thread.ri_cb = NULL;
@@ -202,17 +197,6 @@ int copy_thread(unsigned long clone_flags, unsigned long new_stackp,
}
}
#endif /* CONFIG_64BIT */
- /* start new process with ar4 pointing to the correct address space */
- p->thread.mm_segment = get_fs();
- /* Don't copy debug registers */
- memset(&p->thread.per_user, 0, sizeof(p->thread.per_user));
- memset(&p->thread.per_event, 0, sizeof(p->thread.per_event));
- clear_tsk_thread_flag(p, TIF_SINGLE_STEP);
- clear_tsk_thread_flag(p, TIF_PER_TRAP);
- /* Initialize per thread user and system timer values */
- ti = task_thread_info(p);
- ti->user_timer = 0;
- ti->system_timer = 0;
return 0;
}
@@ -258,31 +242,6 @@ asmlinkage void execve_tail(void)
}
/*
- * sys_execve() executes a new program.
- */
-SYSCALL_DEFINE3(execve, const char __user *, name,
- const char __user *const __user *, argv,
- const char __user *const __user *, envp)
-{
- struct pt_regs *regs = task_pt_regs(current);
- char *filename;
- long rc;
-
- filename = getname(name);
- rc = PTR_ERR(filename);
- if (IS_ERR(filename))
- return rc;
- rc = do_execve(filename, argv, envp, regs);
- if (rc)
- goto out;
- execve_tail();
- rc = regs->gprs[2];
-out:
- putname(filename);
- return rc;
-}
-
-/*
* fill in the FPU structure for a core dump.
*/
int dump_fpu (struct pt_regs * regs, s390_fp_regs *fpregs)
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c
index afa9fdb..b1f2be9 100644
--- a/arch/s390/kernel/setup.c
+++ b/arch/s390/kernel/setup.c
@@ -105,6 +105,11 @@ EXPORT_SYMBOL(VMALLOC_END);
struct page *vmemmap;
EXPORT_SYMBOL(vmemmap);
+#ifdef CONFIG_64BIT
+unsigned long MODULES_VADDR;
+unsigned long MODULES_END;
+#endif
+
/* An array with a pointer to the lowcore of every CPU. */
struct _lowcore *lowcore_ptr[NR_CPUS];
EXPORT_SYMBOL(lowcore_ptr);
@@ -544,19 +549,23 @@ static void __init setup_memory_end(void)
/* Choose kernel address space layout: 2, 3, or 4 levels. */
#ifdef CONFIG_64BIT
- vmalloc_size = VMALLOC_END ?: 128UL << 30;
+ vmalloc_size = VMALLOC_END ?: (128UL << 30) - MODULES_LEN;
tmp = (memory_end ?: real_memory_size) / PAGE_SIZE;
tmp = tmp * (sizeof(struct page) + PAGE_SIZE) + vmalloc_size;
if (tmp <= (1UL << 42))
vmax = 1UL << 42; /* 3-level kernel page table */
else
vmax = 1UL << 53; /* 4-level kernel page table */
+ /* module area is at the end of the kernel address space. */
+ MODULES_END = vmax;
+ MODULES_VADDR = MODULES_END - MODULES_LEN;
+ VMALLOC_END = MODULES_VADDR;
#else
vmalloc_size = VMALLOC_END ?: 96UL << 20;
vmax = 1UL << 31; /* 2-level kernel page table */
-#endif
/* vmalloc area is at the end of the kernel address space. */
VMALLOC_END = vmax;
+#endif
VMALLOC_START = vmax - vmalloc_size;
/* Split remaining virtual space between 1:1 mapping & vmemmap array */
@@ -768,6 +777,40 @@ static void __init reserve_crashkernel(void)
#endif
}
+static void __init init_storage_keys(unsigned long start, unsigned long end)
+{
+ unsigned long boundary, function, size;
+
+ while (start < end) {
+ if (MACHINE_HAS_EDAT2) {
+ /* set storage keys for a 2GB frame */
+ function = 0x22000 | PAGE_DEFAULT_KEY;
+ size = 1UL << 31;
+ boundary = (start + size) & ~(size - 1);
+ if (boundary <= end) {
+ do {
+ start = pfmf(function, start);
+ } while (start < boundary);
+ continue;
+ }
+ }
+ if (MACHINE_HAS_EDAT1) {
+ /* set storage keys for a 1MB frame */
+ function = 0x21000 | PAGE_DEFAULT_KEY;
+ size = 1UL << 20;
+ boundary = (start + size) & ~(size - 1);
+ if (boundary <= end) {
+ do {
+ start = pfmf(function, start);
+ } while (start < boundary);
+ continue;
+ }
+ }
+ page_set_storage_key(start, PAGE_DEFAULT_KEY, 0);
+ start += PAGE_SIZE;
+ }
+}
+
static void __init setup_memory(void)
{
unsigned long bootmap_size;
@@ -846,9 +889,7 @@ static void __init setup_memory(void)
memblock_add_node(PFN_PHYS(start_chunk),
PFN_PHYS(end_chunk - start_chunk), 0);
pfn = max(start_chunk, start_pfn);
- for (; pfn < end_chunk; pfn++)
- page_set_storage_key(PFN_PHYS(pfn),
- PAGE_DEFAULT_KEY, 0);
+ init_storage_keys(PFN_PHYS(pfn), PFN_PHYS(end_chunk));
}
psw_set_key(PAGE_DEFAULT_KEY);
diff --git a/arch/s390/mm/Makefile b/arch/s390/mm/Makefile
index 0f5536b..1bea6d1 100644
--- a/arch/s390/mm/Makefile
+++ b/arch/s390/mm/Makefile
@@ -7,3 +7,4 @@ obj-y := init.o fault.o extmem.o mmap.o vmem.o pgtable.o maccess.o \
obj-$(CONFIG_CMM) += cmm.o
obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o
obj-$(CONFIG_DEBUG_SET_MODULE_RONX) += pageattr.o
+obj-$(CONFIG_S390_PTDUMP) += dump_pagetables.o
diff --git a/arch/s390/mm/dump_pagetables.c b/arch/s390/mm/dump_pagetables.c
new file mode 100644
index 0000000..cbc6668
--- /dev/null
+++ b/arch/s390/mm/dump_pagetables.c
@@ -0,0 +1,226 @@
+#include <linux/seq_file.h>
+#include <linux/debugfs.h>
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <asm/sections.h>
+#include <asm/pgtable.h>
+
+static unsigned long max_addr;
+
+struct addr_marker {
+ unsigned long start_address;
+ const char *name;
+};
+
+enum address_markers_idx {
+ IDENTITY_NR = 0,
+ KERNEL_START_NR,
+ KERNEL_END_NR,
+ VMEMMAP_NR,
+ VMALLOC_NR,
+#ifdef CONFIG_64BIT
+ MODULES_NR,
+#endif
+};
+
+static struct addr_marker address_markers[] = {
+ [IDENTITY_NR] = {0, "Identity Mapping"},
+ [KERNEL_START_NR] = {(unsigned long)&_stext, "Kernel Image Start"},
+ [KERNEL_END_NR] = {(unsigned long)&_end, "Kernel Image End"},
+ [VMEMMAP_NR] = {0, "vmemmap Area"},
+ [VMALLOC_NR] = {0, "vmalloc Area"},
+#ifdef CONFIG_64BIT
+ [MODULES_NR] = {0, "Modules Area"},
+#endif
+ { -1, NULL }
+};
+
+struct pg_state {
+ int level;
+ unsigned int current_prot;
+ unsigned long start_address;
+ unsigned long current_address;
+ const struct addr_marker *marker;
+};
+
+static void print_prot(struct seq_file *m, unsigned int pr, int level)
+{
+ static const char * const level_name[] =
+ { "ASCE", "PGD", "PUD", "PMD", "PTE" };
+
+ seq_printf(m, "%s ", level_name[level]);
+ if (pr & _PAGE_INVALID)
+ seq_printf(m, "I\n");
+ else
+ seq_printf(m, "%s\n", pr & _PAGE_RO ? "RO" : "RW");
+}
+
+static void note_page(struct seq_file *m, struct pg_state *st,
+ unsigned int new_prot, int level)
+{
+ static const char units[] = "KMGTPE";
+ int width = sizeof(unsigned long) * 2;
+ const char *unit = units;
+ unsigned int prot, cur;
+ unsigned long delta;
+
+ /*
+ * If we have a "break" in the series, we need to flush the state
+ * that we have now. "break" is either changing perms, levels or
+ * address space marker.
+ */
+ prot = new_prot;
+ cur = st->current_prot;
+
+ if (!st->level) {
+ /* First entry */
+ st->current_prot = new_prot;
+ st->level = level;
+ st->marker = address_markers;
+ seq_printf(m, "---[ %s ]---\n", st->marker->name);
+ } else if (prot != cur || level != st->level ||
+ st->current_address >= st->marker[1].start_address) {
+ /* Print the actual finished series */
+ seq_printf(m, "0x%0*lx-0x%0*lx",
+ width, st->start_address,
+ width, st->current_address);
+ delta = (st->current_address - st->start_address) >> 10;
+ while (!(delta & 0x3ff) && unit[1]) {
+ delta >>= 10;
+ unit++;
+ }
+ seq_printf(m, "%9lu%c ", delta, *unit);
+ print_prot(m, st->current_prot, st->level);
+ if (st->current_address >= st->marker[1].start_address) {
+ st->marker++;
+ seq_printf(m, "---[ %s ]---\n", st->marker->name);
+ }
+ st->start_address = st->current_address;
+ st->current_prot = new_prot;
+ st->level = level;
+ }
+}
+
+/*
+ * The actual page table walker functions. In order to keep the implementation
+ * of print_prot() short, we only check and pass _PAGE_INVALID and _PAGE_RO
+ * flags to note_page() if a region, segment or page table entry is invalid or
+ * read-only.
+ * After all it's just a hint that the current level being walked contains an
+ * invalid or read-only entry.
+ */
+static void walk_pte_level(struct seq_file *m, struct pg_state *st,
+ pmd_t *pmd, unsigned long addr)
+{
+ unsigned int prot;
+ pte_t *pte;
+ int i;
+
+ for (i = 0; i < PTRS_PER_PTE && addr < max_addr; i++) {
+ st->current_address = addr;
+ pte = pte_offset_kernel(pmd, addr);
+ prot = pte_val(*pte) & (_PAGE_RO | _PAGE_INVALID);
+ note_page(m, st, prot, 4);
+ addr += PAGE_SIZE;
+ }
+}
+
+static void walk_pmd_level(struct seq_file *m, struct pg_state *st,
+ pud_t *pud, unsigned long addr)
+{
+ unsigned int prot;
+ pmd_t *pmd;
+ int i;
+
+ for (i = 0; i < PTRS_PER_PMD && addr < max_addr; i++) {
+ st->current_address = addr;
+ pmd = pmd_offset(pud, addr);
+ if (!pmd_none(*pmd)) {
+ if (pmd_large(*pmd)) {
+ prot = pmd_val(*pmd) & _SEGMENT_ENTRY_RO;
+ note_page(m, st, prot, 3);
+ } else
+ walk_pte_level(m, st, pmd, addr);
+ } else
+ note_page(m, st, _PAGE_INVALID, 3);
+ addr += PMD_SIZE;
+ }
+}
+
+static void walk_pud_level(struct seq_file *m, struct pg_state *st,
+ pgd_t *pgd, unsigned long addr)
+{
+ pud_t *pud;
+ int i;
+
+ for (i = 0; i < PTRS_PER_PUD && addr < max_addr; i++) {
+ st->current_address = addr;
+ pud = pud_offset(pgd, addr);
+ if (!pud_none(*pud))
+ walk_pmd_level(m, st, pud, addr);
+ else
+ note_page(m, st, _PAGE_INVALID, 2);
+ addr += PUD_SIZE;
+ }
+}
+
+static void walk_pgd_level(struct seq_file *m)
+{
+ unsigned long addr = 0;
+ struct pg_state st;
+ pgd_t *pgd;
+ int i;
+
+ memset(&st, 0, sizeof(st));
+ for (i = 0; i < PTRS_PER_PGD && addr < max_addr; i++) {
+ st.current_address = addr;
+ pgd = pgd_offset_k(addr);
+ if (!pgd_none(*pgd))
+ walk_pud_level(m, &st, pgd, addr);
+ else
+ note_page(m, &st, _PAGE_INVALID, 1);
+ addr += PGDIR_SIZE;
+ }
+ /* Flush out the last page */
+ st.current_address = max_addr;
+ note_page(m, &st, 0, 0);
+}
+
+static int ptdump_show(struct seq_file *m, void *v)
+{
+ walk_pgd_level(m);
+ return 0;
+}
+
+static int ptdump_open(struct inode *inode, struct file *filp)
+{
+ return single_open(filp, ptdump_show, NULL);
+}
+
+static const struct file_operations ptdump_fops = {
+ .open = ptdump_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int pt_dump_init(void)
+{
+ /*
+ * Figure out the maximum virtual address being accessible with the
+ * kernel ASCE. We need this to keep the page table walker functions
+ * from accessing non-existent entries.
+ */
+#ifdef CONFIG_32BIT
+ max_addr = 1UL << 31;
+#else
+ max_addr = (S390_lowcore.kernel_asce & _REGION_ENTRY_TYPE_MASK) >> 2;
+ max_addr = 1UL << (max_addr * 11 + 31);
+ address_markers[MODULES_NR].start_address = MODULES_VADDR;
+#endif
+ address_markers[VMEMMAP_NR].start_address = (unsigned long) vmemmap;
+ address_markers[VMALLOC_NR].start_address = VMALLOC_START;
+ debugfs_create_file("kernel_page_tables", 0400, NULL, NULL, &ptdump_fops);
+ return 0;
+}
+device_initcall(pt_dump_init);
diff --git a/arch/s390/mm/pageattr.c b/arch/s390/mm/pageattr.c
index b36537a..00be01c 100644
--- a/arch/s390/mm/pageattr.c
+++ b/arch/s390/mm/pageattr.c
@@ -8,25 +8,38 @@
#include <asm/cacheflush.h>
#include <asm/pgtable.h>
+static pte_t *walk_page_table(unsigned long addr)
+{
+ pgd_t *pgdp;
+ pud_t *pudp;
+ pmd_t *pmdp;
+ pte_t *ptep;
+
+ pgdp = pgd_offset_k(addr);
+ if (pgd_none(*pgdp))
+ return NULL;
+ pudp = pud_offset(pgdp, addr);
+ if (pud_none(*pudp))
+ return NULL;
+ pmdp = pmd_offset(pudp, addr);
+ if (pmd_none(*pmdp) || pmd_large(*pmdp))
+ return NULL;
+ ptep = pte_offset_kernel(pmdp, addr);
+ if (pte_none(*ptep))
+ return NULL;
+ return ptep;
+}
+
static void change_page_attr(unsigned long addr, int numpages,
pte_t (*set) (pte_t))
{
pte_t *ptep, pte;
- pmd_t *pmdp;
- pud_t *pudp;
- pgd_t *pgdp;
int i;
for (i = 0; i < numpages; i++) {
- pgdp = pgd_offset(&init_mm, addr);
- pudp = pud_offset(pgdp, addr);
- pmdp = pmd_offset(pudp, addr);
- if (pmd_huge(*pmdp)) {
- WARN_ON_ONCE(1);
- continue;
- }
- ptep = pte_offset_kernel(pmdp, addr);
-
+ ptep = walk_page_table(addr);
+ if (WARN_ON_ONCE(!ptep))
+ break;
pte = *ptep;
pte = set(pte);
__ptep_ipte(addr, ptep);
@@ -40,21 +53,18 @@ int set_memory_ro(unsigned long addr, int numpages)
change_page_attr(addr, numpages, pte_wrprotect);
return 0;
}
-EXPORT_SYMBOL_GPL(set_memory_ro);
int set_memory_rw(unsigned long addr, int numpages)
{
change_page_attr(addr, numpages, pte_mkwrite);
return 0;
}
-EXPORT_SYMBOL_GPL(set_memory_rw);
/* not possible */
int set_memory_nx(unsigned long addr, int numpages)
{
return 0;
}
-EXPORT_SYMBOL_GPL(set_memory_nx);
int set_memory_x(unsigned long addr, int numpages)
{
diff --git a/arch/s390/mm/vmem.c b/arch/s390/mm/vmem.c
index c22abf9..387c7c6 100644
--- a/arch/s390/mm/vmem.c
+++ b/arch/s390/mm/vmem.c
@@ -79,7 +79,8 @@ static pte_t __ref *vmem_pte_alloc(unsigned long address)
*/
static int vmem_add_mem(unsigned long start, unsigned long size, int ro)
{
- unsigned long address;
+ unsigned long end = start + size;
+ unsigned long address = start;
pgd_t *pg_dir;
pud_t *pu_dir;
pmd_t *pm_dir;
@@ -87,7 +88,7 @@ static int vmem_add_mem(unsigned long start, unsigned long size, int ro)
pte_t pte;
int ret = -ENOMEM;
- for (address = start; address < start + size; address += PAGE_SIZE) {
+ while (address < end) {
pg_dir = pgd_offset_k(address);
if (pgd_none(*pg_dir)) {
pu_dir = vmem_pud_alloc();
@@ -108,12 +109,11 @@ static int vmem_add_mem(unsigned long start, unsigned long size, int ro)
pm_dir = pmd_offset(pu_dir, address);
#if defined(CONFIG_64BIT) && !defined(CONFIG_DEBUG_PAGEALLOC)
- if (MACHINE_HAS_HPAGE && !(address & ~HPAGE_MASK) &&
- (address + HPAGE_SIZE <= start + size) &&
- (address >= HPAGE_SIZE)) {
+ if (MACHINE_HAS_EDAT1 && pmd_none(*pm_dir) && address &&
+ !(address & ~PMD_MASK) && (address + PMD_SIZE <= end)) {
pte_val(pte) |= _SEGMENT_ENTRY_LARGE;
pmd_val(*pm_dir) = pte_val(pte);
- address += HPAGE_SIZE - PAGE_SIZE;
+ address += PMD_SIZE;
continue;
}
#endif
@@ -126,10 +126,11 @@ static int vmem_add_mem(unsigned long start, unsigned long size, int ro)
pt_dir = pte_offset_kernel(pm_dir, address);
*pt_dir = pte;
+ address += PAGE_SIZE;
}
ret = 0;
out:
- flush_tlb_kernel_range(start, start + size);
+ flush_tlb_kernel_range(start, end);
return ret;
}
@@ -139,7 +140,8 @@ out:
*/
static void vmem_remove_range(unsigned long start, unsigned long size)
{
- unsigned long address;
+ unsigned long end = start + size;
+ unsigned long address = start;
pgd_t *pg_dir;
pud_t *pu_dir;
pmd_t *pm_dir;
@@ -147,25 +149,32 @@ static void vmem_remove_range(unsigned long start, unsigned long size)
pte_t pte;
pte_val(pte) = _PAGE_TYPE_EMPTY;
- for (address = start; address < start + size; address += PAGE_SIZE) {
+ while (address < end) {
pg_dir = pgd_offset_k(address);
+ if (pgd_none(*pg_dir)) {
+ address += PGDIR_SIZE;
+ continue;
+ }
pu_dir = pud_offset(pg_dir, address);
- if (pud_none(*pu_dir))
+ if (pud_none(*pu_dir)) {
+ address += PUD_SIZE;
continue;
+ }
pm_dir = pmd_offset(pu_dir, address);
- if (pmd_none(*pm_dir))
+ if (pmd_none(*pm_dir)) {
+ address += PMD_SIZE;
continue;
-
- if (pmd_huge(*pm_dir)) {
+ }
+ if (pmd_large(*pm_dir)) {
pmd_clear(pm_dir);
- address += HPAGE_SIZE - PAGE_SIZE;
+ address += PMD_SIZE;
continue;
}
-
pt_dir = pte_offset_kernel(pm_dir, address);
*pt_dir = pte;
+ address += PAGE_SIZE;
}
- flush_tlb_kernel_range(start, start + size);
+ flush_tlb_kernel_range(start, end);
}
/*
@@ -330,8 +339,8 @@ void __init vmem_map_init(void)
unsigned long start, end;
int i;
- ro_start = ((unsigned long)&_stext) & PAGE_MASK;
- ro_end = PFN_ALIGN((unsigned long)&_eshared);
+ ro_start = PFN_ALIGN((unsigned long)&_stext);
+ ro_end = (unsigned long)&_eshared & PAGE_MASK;
for (i = 0; i < MEMORY_CHUNKS && memory_chunk[i].size > 0; i++) {
if (memory_chunk[i].type == CHUNK_CRASHK ||
memory_chunk[i].type == CHUNK_OLDMEM)
diff --git a/arch/score/include/asm/thread_info.h b/arch/score/include/asm/thread_info.h
index a18006e9..1425cc0 100644
--- a/arch/score/include/asm/thread_info.h
+++ b/arch/score/include/asm/thread_info.h
@@ -86,16 +86,12 @@ register struct thread_info *__current_thread_info __asm__("r28");
#define TIF_NEED_RESCHED 2 /* rescheduling necessary */
#define TIF_NOTIFY_RESUME 5 /* callback before returning to user */
#define TIF_RESTORE_SIGMASK 9 /* restore signal mask in do_signal() */
-#define TIF_POLLING_NRFLAG 17 /* true if poll_idle() is polling
- TIF_NEED_RESCHED */
#define TIF_MEMDIE 18 /* is terminating due to OOM killer */
#define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE)
#define _TIF_SIGPENDING (1<<TIF_SIGPENDING)
#define _TIF_NEED_RESCHED (1<<TIF_NEED_RESCHED)
#define _TIF_NOTIFY_RESUME (1<<TIF_NOTIFY_RESUME)
-#define _TIF_RESTORE_SIGMASK (1<<TIF_RESTORE_SIGMASK)
-#define _TIF_POLLING_NRFLAG (1<<TIF_POLLING_NRFLAG)
#define _TIF_WORK_MASK (0x0000ffff)
diff --git a/arch/score/kernel/signal.c b/arch/score/kernel/signal.c
index e382c52..c268bbf 100644
--- a/arch/score/kernel/signal.c
+++ b/arch/score/kernel/signal.c
@@ -174,6 +174,7 @@ score_rt_sigreturn(struct pt_regs *regs)
/* It is more difficult to avoid calling this function than to
call it and ignore errors. */
do_sigaltstack((stack_t __user *)&st, NULL, regs->regs[0]);
+ regs->is_syscall = 0;
__asm__ __volatile__(
"mv\tr0, %0\n\t"
diff --git a/arch/sh/include/asm/Kbuild b/arch/sh/include/asm/Kbuild
index 7b673dd..86eadce 100644
--- a/arch/sh/include/asm/Kbuild
+++ b/arch/sh/include/asm/Kbuild
@@ -7,6 +7,7 @@ generic-y += delay.h
generic-y += div64.h
generic-y += emergency-restart.h
generic-y += errno.h
+generic-y += exec.h
generic-y += fcntl.h
generic-y += ioctl.h
generic-y += ipcbuf.h
diff --git a/arch/sh/include/asm/exec.h b/arch/sh/include/asm/exec.h
deleted file mode 100644
index 69486a9..0000000
--- a/arch/sh/include/asm/exec.h
+++ /dev/null
@@ -1,10 +0,0 @@
-/*
- * Copyright (C) 1999, 2000 Niibe Yutaka & Kaz Kojima
- * Copyright (C) 2002 Paul Mundt
- */
-#ifndef __ASM_SH_EXEC_H
-#define __ASM_SH_EXEC_H
-
-#define arch_align_stack(x) (x)
-
-#endif /* __ASM_SH_EXEC_H */
diff --git a/arch/sh/include/asm/thread_info.h b/arch/sh/include/asm/thread_info.h
index bc13b57..7d5ac4e 100644
--- a/arch/sh/include/asm/thread_info.h
+++ b/arch/sh/include/asm/thread_info.h
@@ -206,6 +206,9 @@ static inline bool test_and_clear_restore_sigmask(void)
ti->status &= ~TS_RESTORE_SIGMASK;
return true;
}
+
+#define tsk_is_polling(t) test_tsk_thread_flag(t, TIF_POLLING_NRFLAG)
+
#endif /* !__ASSEMBLY__ */
#endif /* __KERNEL__ */
diff --git a/arch/sh/kernel/signal_32.c b/arch/sh/kernel/signal_32.c
index d6b7b61..2f1f653 100644
--- a/arch/sh/kernel/signal_32.c
+++ b/arch/sh/kernel/signal_32.c
@@ -22,7 +22,6 @@
#include <linux/elf.h>
#include <linux/personality.h>
#include <linux/binfmts.h>
-#include <linux/freezer.h>
#include <linux/io.h>
#include <linux/tracehook.h>
#include <asm/ucontext.h>
diff --git a/arch/sh/kernel/signal_64.c b/arch/sh/kernel/signal_64.c
index 6b5b3df..2385381 100644
--- a/arch/sh/kernel/signal_64.c
+++ b/arch/sh/kernel/signal_64.c
@@ -18,7 +18,6 @@
#include <linux/errno.h>
#include <linux/wait.h>
#include <linux/personality.h>
-#include <linux/freezer.h>
#include <linux/ptrace.h>
#include <linux/unistd.h>
#include <linux/stddef.h>
diff --git a/arch/sparc/include/asm/Kbuild b/arch/sparc/include/asm/Kbuild
index f80ff93..10d54e5 100644
--- a/arch/sparc/include/asm/Kbuild
+++ b/arch/sparc/include/asm/Kbuild
@@ -1,24 +1,9 @@
# User exported sparc header files
-include include/asm-generic/Kbuild.asm
-header-y += apc.h
-header-y += asi.h
-header-y += display7seg.h
-header-y += envctrl.h
-header-y += fbio.h
-header-y += jsflash.h
-header-y += openpromio.h
-header-y += perfctr.h
-header-y += psrcompat.h
-header-y += psr.h
-header-y += pstate.h
-header-y += traps.h
-header-y += uctx.h
-header-y += utrap.h
-header-y += watchdog.h
generic-y += clkdev.h
generic-y += div64.h
+generic-y += exec.h
generic-y += local64.h
generic-y += irq_regs.h
generic-y += local.h
diff --git a/arch/sparc/include/asm/exec.h b/arch/sparc/include/asm/exec.h
deleted file mode 100644
index 2e08588..0000000
--- a/arch/sparc/include/asm/exec.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __SPARC_EXEC_H
-#define __SPARC_EXEC_H
-
-#define arch_align_stack(x) (x)
-
-#endif /* __SPARC_EXEC_H */
diff --git a/arch/sparc/include/asm/fbio.h b/arch/sparc/include/asm/fbio.h
index 0a21da8..1d9afe2 100644
--- a/arch/sparc/include/asm/fbio.h
+++ b/arch/sparc/include/asm/fbio.h
@@ -1,225 +1,10 @@
#ifndef __LINUX_FBIO_H
#define __LINUX_FBIO_H
-#include <linux/compiler.h>
-#include <linux/types.h>
+#include <uapi/asm/fbio.h>
-/* Constants used for fbio SunOS compatibility */
-/* (C) 1996 Miguel de Icaza */
-
-/* Frame buffer types */
-#define FBTYPE_NOTYPE -1
-#define FBTYPE_SUN1BW 0 /* mono */
-#define FBTYPE_SUN1COLOR 1
-#define FBTYPE_SUN2BW 2
-#define FBTYPE_SUN2COLOR 3
-#define FBTYPE_SUN2GP 4
-#define FBTYPE_SUN5COLOR 5
-#define FBTYPE_SUN3COLOR 6
-#define FBTYPE_MEMCOLOR 7
-#define FBTYPE_SUN4COLOR 8
-
-#define FBTYPE_NOTSUN1 9
-#define FBTYPE_NOTSUN2 10
-#define FBTYPE_NOTSUN3 11
-
-#define FBTYPE_SUNFAST_COLOR 12 /* cg6 */
-#define FBTYPE_SUNROP_COLOR 13
-#define FBTYPE_SUNFB_VIDEO 14
-#define FBTYPE_SUNGIFB 15
-#define FBTYPE_SUNGPLAS 16
-#define FBTYPE_SUNGP3 17
-#define FBTYPE_SUNGT 18
-#define FBTYPE_SUNLEO 19 /* zx Leo card */
-#define FBTYPE_MDICOLOR 20 /* cg14 */
-#define FBTYPE_TCXCOLOR 21 /* SUNW,tcx card */
-
-#define FBTYPE_LASTPLUSONE 21 /* This is not last + 1 in fact... */
-
-/* Does not seem to be listed in the Sun file either */
-#define FBTYPE_CREATOR 22
-#define FBTYPE_PCI_IGA1682 23
-#define FBTYPE_P9100COLOR 24
-
-#define FBTYPE_PCI_GENERIC 1000
-#define FBTYPE_PCI_MACH64 1001
-
-/* fbio ioctls */
-/* Returned by FBIOGTYPE */
-struct fbtype {
- int fb_type; /* fb type, see above */
- int fb_height; /* pixels */
- int fb_width; /* pixels */
- int fb_depth;
- int fb_cmsize; /* color map entries */
- int fb_size; /* fb size in bytes */
-};
-#define FBIOGTYPE _IOR('F', 0, struct fbtype)
-
-struct fbcmap {
- int index; /* first element (0 origin) */
- int count;
- unsigned char __user *red;
- unsigned char __user *green;
- unsigned char __user *blue;
-};
-
-#ifdef __KERNEL__
#define FBIOPUTCMAP_SPARC _IOW('F', 3, struct fbcmap)
#define FBIOGETCMAP_SPARC _IOW('F', 4, struct fbcmap)
-#else
-#define FBIOPUTCMAP _IOW('F', 3, struct fbcmap)
-#define FBIOGETCMAP _IOW('F', 4, struct fbcmap)
-#endif
-
-/* # of device specific values */
-#define FB_ATTR_NDEVSPECIFIC 8
-/* # of possible emulations */
-#define FB_ATTR_NEMUTYPES 4
-
-struct fbsattr {
- int flags;
- int emu_type; /* -1 if none */
- int dev_specific[FB_ATTR_NDEVSPECIFIC];
-};
-
-struct fbgattr {
- int real_type; /* real frame buffer type */
- int owner; /* unknown */
- struct fbtype fbtype; /* real frame buffer fbtype */
- struct fbsattr sattr;
- int emu_types[FB_ATTR_NEMUTYPES]; /* supported emulations */
-};
-#define FBIOSATTR _IOW('F', 5, struct fbgattr) /* Unsupported: */
-#define FBIOGATTR _IOR('F', 6, struct fbgattr) /* supported */
-
-#define FBIOSVIDEO _IOW('F', 7, int)
-#define FBIOGVIDEO _IOR('F', 8, int)
-
-struct fbcursor {
- short set; /* what to set, choose from the list above */
- short enable; /* cursor on/off */
- struct fbcurpos pos; /* cursor position */
- struct fbcurpos hot; /* cursor hot spot */
- struct fbcmap cmap; /* color map info */
- struct fbcurpos size; /* cursor bit map size */
- char __user *image; /* cursor image bits */
- char __user *mask; /* cursor mask bits */
-};
-
-/* set/get cursor attributes/shape */
-#define FBIOSCURSOR _IOW('F', 24, struct fbcursor)
-#define FBIOGCURSOR _IOWR('F', 25, struct fbcursor)
-
-/* set/get cursor position */
-#define FBIOSCURPOS _IOW('F', 26, struct fbcurpos)
-#define FBIOGCURPOS _IOW('F', 27, struct fbcurpos)
-
-/* get max cursor size */
-#define FBIOGCURMAX _IOR('F', 28, struct fbcurpos)
-
-/* wid manipulation */
-struct fb_wid_alloc {
-#define FB_WID_SHARED_8 0
-#define FB_WID_SHARED_24 1
-#define FB_WID_DBL_8 2
-#define FB_WID_DBL_24 3
- __u32 wa_type;
- __s32 wa_index; /* Set on return */
- __u32 wa_count;
-};
-struct fb_wid_item {
- __u32 wi_type;
- __s32 wi_index;
- __u32 wi_attrs;
- __u32 wi_values[32];
-};
-struct fb_wid_list {
- __u32 wl_flags;
- __u32 wl_count;
- struct fb_wid_item *wl_list;
-};
-
-#define FBIO_WID_ALLOC _IOWR('F', 30, struct fb_wid_alloc)
-#define FBIO_WID_FREE _IOW('F', 31, struct fb_wid_alloc)
-#define FBIO_WID_PUT _IOW('F', 32, struct fb_wid_list)
-#define FBIO_WID_GET _IOWR('F', 33, struct fb_wid_list)
-
-/* Creator ioctls */
-#define FFB_IOCTL ('F'<<8)
-#define FFB_SYS_INFO (FFB_IOCTL|80)
-#define FFB_CLUTREAD (FFB_IOCTL|81)
-#define FFB_CLUTPOST (FFB_IOCTL|82)
-#define FFB_SETDIAGMODE (FFB_IOCTL|83)
-#define FFB_GETMONITORID (FFB_IOCTL|84)
-#define FFB_GETVIDEOMODE (FFB_IOCTL|85)
-#define FFB_SETVIDEOMODE (FFB_IOCTL|86)
-#define FFB_SETSERVER (FFB_IOCTL|87)
-#define FFB_SETOVCTL (FFB_IOCTL|88)
-#define FFB_GETOVCTL (FFB_IOCTL|89)
-#define FFB_GETSAXNUM (FFB_IOCTL|90)
-#define FFB_FBDEBUG (FFB_IOCTL|91)
-
-/* Cg14 ioctls */
-#define MDI_IOCTL ('M'<<8)
-#define MDI_RESET (MDI_IOCTL|1)
-#define MDI_GET_CFGINFO (MDI_IOCTL|2)
-#define MDI_SET_PIXELMODE (MDI_IOCTL|3)
-# define MDI_32_PIX 32
-# define MDI_16_PIX 16
-# define MDI_8_PIX 8
-
-struct mdi_cfginfo {
- int mdi_ncluts; /* Number of implemented CLUTs in this MDI */
- int mdi_type; /* FBTYPE name */
- int mdi_height; /* height */
- int mdi_width; /* width */
- int mdi_size; /* available ram */
- int mdi_mode; /* 8bpp, 16bpp or 32bpp */
- int mdi_pixfreq; /* pixel clock (from PROM) */
-};
-
-/* SparcLinux specific ioctl for the MDI, should be replaced for
- * the SET_XLUT/SET_CLUTn ioctls instead
- */
-#define MDI_CLEAR_XLUT (MDI_IOCTL|9)
-
-/* leo & ffb ioctls */
-struct fb_clut_alloc {
- __u32 clutid; /* Set on return */
- __u32 flag;
- __u32 index;
-};
-
-struct fb_clut {
-#define FB_CLUT_WAIT 0x00000001 /* Not yet implemented */
- __u32 flag;
- __u32 clutid;
- __u32 offset;
- __u32 count;
- char * red;
- char * green;
- char * blue;
-};
-
-struct fb_clut32 {
- __u32 flag;
- __u32 clutid;
- __u32 offset;
- __u32 count;
- __u32 red;
- __u32 green;
- __u32 blue;
-};
-
-#define LEO_CLUTALLOC _IOWR('L', 53, struct fb_clut_alloc)
-#define LEO_CLUTFREE _IOW('L', 54, struct fb_clut_alloc)
-#define LEO_CLUTREAD _IOW('L', 55, struct fb_clut)
-#define LEO_CLUTPOST _IOW('L', 56, struct fb_clut)
-#define LEO_SETGAMMA _IOW('L', 68, int) /* Not yet implemented */
-#define LEO_GETGAMMA _IOR('L', 69, int) /* Not yet implemented */
-
-#ifdef __KERNEL__
/* Addresses on the fd of a cgsix that are mappable */
#define CG6_FBC 0x70000000
#define CG6_TEC 0x70001000
@@ -260,47 +45,6 @@ struct fb_clut32 {
#define CG14_CLUT3 0x6000 /* Color Look Up Table */
#define CG14_AUTO 0xf000
-#endif /* KERNEL */
-
-/* These are exported to userland for applications to use */
-/* Mappable offsets for the cg14: control registers */
-#define MDI_DIRECT_MAP 0x10000000
-#define MDI_CTLREG_MAP 0x20000000
-#define MDI_CURSOR_MAP 0x30000000
-#define MDI_SHDW_VRT_MAP 0x40000000
-
-/* Mappable offsets for the cg14: frame buffer resolutions */
-/* 32 bits */
-#define MDI_CHUNKY_XBGR_MAP 0x50000000
-#define MDI_CHUNKY_BGR_MAP 0x60000000
-
-/* 16 bits */
-#define MDI_PLANAR_X16_MAP 0x70000000
-#define MDI_PLANAR_C16_MAP 0x80000000
-
-/* 8 bit is done as CG3 MMAP offset */
-/* 32 bits, planar */
-#define MDI_PLANAR_X32_MAP 0x90000000
-#define MDI_PLANAR_B32_MAP 0xa0000000
-#define MDI_PLANAR_G32_MAP 0xb0000000
-#define MDI_PLANAR_R32_MAP 0xc0000000
-
-/* Mappable offsets on leo */
-#define LEO_SS0_MAP 0x00000000
-#define LEO_LC_SS0_USR_MAP 0x00800000
-#define LEO_LD_SS0_MAP 0x00801000
-#define LEO_LX_CURSOR_MAP 0x00802000
-#define LEO_SS1_MAP 0x00803000
-#define LEO_LC_SS1_USR_MAP 0x01003000
-#define LEO_LD_SS1_MAP 0x01004000
-#define LEO_UNK_MAP 0x01005000
-#define LEO_LX_KRN_MAP 0x01006000
-#define LEO_LC_SS0_KRN_MAP 0x01007000
-#define LEO_LC_SS1_KRN_MAP 0x01008000
-#define LEO_LD_GBL_MAP 0x01009000
-#define LEO_UNK2_MAP 0x0100a000
-
-#ifdef __KERNEL__
struct fbcmap32 {
int index; /* first element (0 origin) */
int count;
@@ -325,6 +69,4 @@ struct fbcursor32 {
#define FBIOSCURSOR32 _IOW('F', 24, struct fbcursor32)
#define FBIOGCURSOR32 _IOW('F', 25, struct fbcursor32)
-#endif
-
#endif /* __LINUX_FBIO_H */
diff --git a/arch/sparc/include/asm/ioctls.h b/arch/sparc/include/asm/ioctls.h
index 28d0c8b..77413b7 100644
--- a/arch/sparc/include/asm/ioctls.h
+++ b/arch/sparc/include/asm/ioctls.h
@@ -1,123 +1,8 @@
#ifndef _ASM_SPARC_IOCTLS_H
#define _ASM_SPARC_IOCTLS_H
-#include <asm/ioctl.h>
+#include <uapi/asm/ioctls.h>
-/* Big T */
-#define TCGETA _IOR('T', 1, struct termio)
-#define TCSETA _IOW('T', 2, struct termio)
-#define TCSETAW _IOW('T', 3, struct termio)
-#define TCSETAF _IOW('T', 4, struct termio)
-#define TCSBRK _IO('T', 5)
-#define TCXONC _IO('T', 6)
-#define TCFLSH _IO('T', 7)
-#define TCGETS _IOR('T', 8, struct termios)
-#define TCSETS _IOW('T', 9, struct termios)
-#define TCSETSW _IOW('T', 10, struct termios)
-#define TCSETSF _IOW('T', 11, struct termios)
-#define TCGETS2 _IOR('T', 12, struct termios2)
-#define TCSETS2 _IOW('T', 13, struct termios2)
-#define TCSETSW2 _IOW('T', 14, struct termios2)
-#define TCSETSF2 _IOW('T', 15, struct termios2)
-#define TIOCGDEV _IOR('T',0x32, unsigned int) /* Get primary device node of /dev/console */
-#define TIOCVHANGUP _IO('T', 0x37)
-
-/* Note that all the ioctls that are not available in Linux have a
- * double underscore on the front to: a) avoid some programs to
- * think we support some ioctls under Linux (autoconfiguration stuff)
- */
-/* Little t */
-#define TIOCGETD _IOR('t', 0, int)
-#define TIOCSETD _IOW('t', 1, int)
-#define __TIOCHPCL _IO('t', 2) /* SunOS Specific */
-#define __TIOCMODG _IOR('t', 3, int) /* SunOS Specific */
-#define __TIOCMODS _IOW('t', 4, int) /* SunOS Specific */
-#define __TIOCGETP _IOR('t', 8, struct sgttyb) /* SunOS Specific */
-#define __TIOCSETP _IOW('t', 9, struct sgttyb) /* SunOS Specific */
-#define __TIOCSETN _IOW('t', 10, struct sgttyb) /* SunOS Specific */
-#define TIOCEXCL _IO('t', 13)
-#define TIOCNXCL _IO('t', 14)
-#define __TIOCFLUSH _IOW('t', 16, int) /* SunOS Specific */
-#define __TIOCSETC _IOW('t', 17, struct tchars) /* SunOS Specific */
-#define __TIOCGETC _IOR('t', 18, struct tchars) /* SunOS Specific */
-#define __TIOCTCNTL _IOW('t', 32, int) /* SunOS Specific */
-#define __TIOCSIGNAL _IOW('t', 33, int) /* SunOS Specific */
-#define __TIOCSETX _IOW('t', 34, int) /* SunOS Specific */
-#define __TIOCGETX _IOR('t', 35, int) /* SunOS Specific */
-#define TIOCCONS _IO('t', 36)
-#define TIOCGSOFTCAR _IOR('t', 100, int)
-#define TIOCSSOFTCAR _IOW('t', 101, int)
-#define __TIOCUCNTL _IOW('t', 102, int) /* SunOS Specific */
-#define TIOCSWINSZ _IOW('t', 103, struct winsize)
-#define TIOCGWINSZ _IOR('t', 104, struct winsize)
-#define __TIOCREMOTE _IOW('t', 105, int) /* SunOS Specific */
-#define TIOCMGET _IOR('t', 106, int)
-#define TIOCMBIC _IOW('t', 107, int)
-#define TIOCMBIS _IOW('t', 108, int)
-#define TIOCMSET _IOW('t', 109, int)
-#define TIOCSTART _IO('t', 110)
-#define TIOCSTOP _IO('t', 111)
-#define TIOCPKT _IOW('t', 112, int)
-#define TIOCNOTTY _IO('t', 113)
-#define TIOCSTI _IOW('t', 114, char)
-#define TIOCOUTQ _IOR('t', 115, int)
-#define __TIOCGLTC _IOR('t', 116, struct ltchars) /* SunOS Specific */
-#define __TIOCSLTC _IOW('t', 117, struct ltchars) /* SunOS Specific */
-/* 118 is the non-posix setpgrp tty ioctl */
-/* 119 is the non-posix getpgrp tty ioctl */
-#define __TIOCCDTR _IO('t', 120) /* SunOS Specific */
-#define __TIOCSDTR _IO('t', 121) /* SunOS Specific */
-#define TIOCCBRK _IO('t', 122)
-#define TIOCSBRK _IO('t', 123)
-#define __TIOCLGET _IOW('t', 124, int) /* SunOS Specific */
-#define __TIOCLSET _IOW('t', 125, int) /* SunOS Specific */
-#define __TIOCLBIC _IOW('t', 126, int) /* SunOS Specific */
-#define __TIOCLBIS _IOW('t', 127, int) /* SunOS Specific */
-#define __TIOCISPACE _IOR('t', 128, int) /* SunOS Specific */
-#define __TIOCISIZE _IOR('t', 129, int) /* SunOS Specific */
-#define TIOCSPGRP _IOW('t', 130, int)
-#define TIOCGPGRP _IOR('t', 131, int)
-#define TIOCSCTTY _IO('t', 132)
-#define TIOCGSID _IOR('t', 133, int)
-/* Get minor device of a pty master's FD -- Solaris equiv is ISPTM */
-#define TIOCGPTN _IOR('t', 134, unsigned int) /* Get Pty Number */
-#define TIOCSPTLCK _IOW('t', 135, int) /* Lock/unlock PTY */
-#define TIOCSIG _IOW('t', 136, int) /* Generate signal on Pty slave */
-
-/* Little f */
-#define FIOCLEX _IO('f', 1)
-#define FIONCLEX _IO('f', 2)
-#define FIOASYNC _IOW('f', 125, int)
-#define FIONBIO _IOW('f', 126, int)
-#define FIONREAD _IOR('f', 127, int)
-#define TIOCINQ FIONREAD
-#define FIOQSIZE _IOR('f', 128, loff_t)
-
-/* SCARY Rutgers local SunOS kernel hackery, perhaps I will support it
- * someday. This is completely bogus, I know...
- */
-#define __TCGETSTAT _IO('T', 200) /* Rutgers specific */
-#define __TCSETSTAT _IO('T', 201) /* Rutgers specific */
-
-/* Linux specific, no SunOS equivalent. */
-#define TIOCLINUX 0x541C
-#define TIOCGSERIAL 0x541E
-#define TIOCSSERIAL 0x541F
-#define TCSBRKP 0x5425
-#define TIOCSERCONFIG 0x5453
-#define TIOCSERGWILD 0x5454
-#define TIOCSERSWILD 0x5455
-#define TIOCGLCKTRMIOS 0x5456
-#define TIOCSLCKTRMIOS 0x5457
-#define TIOCSERGSTRUCT 0x5458 /* For debugging only */
-#define TIOCSERGETLSR 0x5459 /* Get line status register */
-#define TIOCSERGETMULTI 0x545A /* Get multiport config */
-#define TIOCSERSETMULTI 0x545B /* Set multiport config */
-#define TIOCMIWAIT 0x545C /* Wait for change on serial input line(s) */
-#define TIOCGICOUNT 0x545D /* Read serial port inline interrupt counts */
-
-/* Kernel definitions */
-#ifdef __KERNEL__
#define TIOCGETC __TIOCGETC
#define TIOCGETP __TIOCGETP
#define TIOCGLTC __TIOCGLTC
@@ -125,16 +10,4 @@
#define TIOCSETP __TIOCSETP
#define TIOCSETN __TIOCSETN
#define TIOCSETC __TIOCSETC
-#endif
-
-/* Used for packet mode */
-#define TIOCPKT_DATA 0
-#define TIOCPKT_FLUSHREAD 1
-#define TIOCPKT_FLUSHWRITE 2
-#define TIOCPKT_STOP 4
-#define TIOCPKT_START 8
-#define TIOCPKT_NOSTOP 16
-#define TIOCPKT_DOSTOP 32
-#define TIOCPKT_IOCTL 64
-
#endif /* !(_ASM_SPARC_IOCTLS_H) */
diff --git a/arch/sparc/include/asm/mman.h b/arch/sparc/include/asm/mman.h
index c3029ad..59bb593 100644
--- a/arch/sparc/include/asm/mman.h
+++ b/arch/sparc/include/asm/mman.h
@@ -1,33 +1,10 @@
#ifndef __SPARC_MMAN_H__
#define __SPARC_MMAN_H__
-#include <asm-generic/mman-common.h>
+#include <uapi/asm/mman.h>
-/* SunOS'ified... */
-
-#define MAP_RENAME MAP_ANONYMOUS /* In SunOS terminology */
-#define MAP_NORESERVE 0x40 /* don't reserve swap pages */
-#define MAP_INHERIT 0x80 /* SunOS doesn't do this, but... */
-#define MAP_LOCKED 0x100 /* lock the mapping */
-#define _MAP_NEW 0x80000000 /* Binary compatibility is fun... */
-
-#define MAP_GROWSDOWN 0x0200 /* stack-like segment */
-#define MAP_DENYWRITE 0x0800 /* ETXTBSY */
-#define MAP_EXECUTABLE 0x1000 /* mark it as an executable */
-
-#define MCL_CURRENT 0x2000 /* lock all currently mapped pages */
-#define MCL_FUTURE 0x4000 /* lock all additions to address space */
-
-#define MAP_POPULATE 0x8000 /* populate (prefault) pagetables */
-#define MAP_NONBLOCK 0x10000 /* do not block on IO */
-#define MAP_STACK 0x20000 /* give out an address that is best suited for process/thread stacks */
-#define MAP_HUGETLB 0x40000 /* create a huge page mapping */
-
-#ifdef __KERNEL__
#ifndef __ASSEMBLY__
#define arch_mmap_check(addr,len,flags) sparc_mmap_check(addr,len)
int sparc_mmap_check(unsigned long addr, unsigned long len);
#endif
-#endif
-
#endif /* __SPARC_MMAN_H__ */
diff --git a/arch/sparc/include/asm/psr.h b/arch/sparc/include/asm/psr.h
index cee7ed9..e71eb57 100644
--- a/arch/sparc/include/asm/psr.h
+++ b/arch/sparc/include/asm/psr.h
@@ -7,43 +7,11 @@
*
* Copyright (C) 1994 David S. Miller (davem@caip.rutgers.edu)
*/
-
#ifndef __LINUX_SPARC_PSR_H
#define __LINUX_SPARC_PSR_H
-/* The Sparc PSR fields are laid out as the following:
- *
- * ------------------------------------------------------------------------
- * | impl | vers | icc | resv | EC | EF | PIL | S | PS | ET | CWP |
- * | 31-28 | 27-24 | 23-20 | 19-14 | 13 | 12 | 11-8 | 7 | 6 | 5 | 4-0 |
- * ------------------------------------------------------------------------
- */
-#define PSR_CWP 0x0000001f /* current window pointer */
-#define PSR_ET 0x00000020 /* enable traps field */
-#define PSR_PS 0x00000040 /* previous privilege level */
-#define PSR_S 0x00000080 /* current privilege level */
-#define PSR_PIL 0x00000f00 /* processor interrupt level */
-#define PSR_EF 0x00001000 /* enable floating point */
-#define PSR_EC 0x00002000 /* enable co-processor */
-#define PSR_SYSCALL 0x00004000 /* inside of a syscall */
-#define PSR_LE 0x00008000 /* SuperSparcII little-endian */
-#define PSR_ICC 0x00f00000 /* integer condition codes */
-#define PSR_C 0x00100000 /* carry bit */
-#define PSR_V 0x00200000 /* overflow bit */
-#define PSR_Z 0x00400000 /* zero bit */
-#define PSR_N 0x00800000 /* negative bit */
-#define PSR_VERS 0x0f000000 /* cpu-version field */
-#define PSR_IMPL 0xf0000000 /* cpu-implementation field */
-
-#define PSR_VERS_SHIFT 24
-#define PSR_IMPL_SHIFT 28
-#define PSR_VERS_SHIFTED_MASK 0xf
-#define PSR_IMPL_SHIFTED_MASK 0xf
-
-#define PSR_IMPL_TI 0x4
-#define PSR_IMPL_LEON 0xf
+#include <uapi/asm/psr.h>
-#ifdef __KERNEL__
#ifndef __ASSEMBLY__
/* Get the %psr register. */
@@ -96,6 +64,4 @@ static inline unsigned int get_fsr(void)
#endif /* !(__ASSEMBLY__) */
-#endif /* (__KERNEL__) */
-
#endif /* !(__LINUX_SPARC_PSR_H) */
diff --git a/arch/sparc/include/asm/ptrace.h b/arch/sparc/include/asm/ptrace.h
index fd9c3f2..0c6f6b0 100644
--- a/arch/sparc/include/asm/ptrace.h
+++ b/arch/sparc/include/asm/ptrace.h
@@ -1,169 +1,11 @@
#ifndef __SPARC_PTRACE_H
#define __SPARC_PTRACE_H
-#if defined(__sparc__) && defined(__arch64__)
-/* 64 bit sparc */
-#include <asm/pstate.h>
-
-/* This struct defines the way the registers are stored on the
- * stack during a system call and basically all traps.
- */
-
-/* This magic value must have the low 9 bits clear,
- * as that is where we encode the %tt value, see below.
- */
-#define PT_REGS_MAGIC 0x57ac6c00
-
-#ifndef __ASSEMBLY__
-
-#include <linux/types.h>
-
-struct pt_regs {
- unsigned long u_regs[16]; /* globals and ins */
- unsigned long tstate;
- unsigned long tpc;
- unsigned long tnpc;
- unsigned int y;
-
- /* We encode a magic number, PT_REGS_MAGIC, along
- * with the %tt (trap type) register value at trap
- * entry time. The magic number allows us to identify
- * accurately a trap stack frame in the stack
- * unwinder, and the %tt value allows us to test
- * things like "in a system call" etc. for an arbitray
- * process.
- *
- * The PT_REGS_MAGIC is chosen such that it can be
- * loaded completely using just a sethi instruction.
- */
- unsigned int magic;
-};
-
-struct pt_regs32 {
- unsigned int psr;
- unsigned int pc;
- unsigned int npc;
- unsigned int y;
- unsigned int u_regs[16]; /* globals and ins */
-};
-
-/* A V9 register window */
-struct reg_window {
- unsigned long locals[8];
- unsigned long ins[8];
-};
-
-/* A 32-bit register window. */
-struct reg_window32 {
- unsigned int locals[8];
- unsigned int ins[8];
-};
-
-/* A V9 Sparc stack frame */
-struct sparc_stackf {
- unsigned long locals[8];
- unsigned long ins[6];
- struct sparc_stackf *fp;
- unsigned long callers_pc;
- char *structptr;
- unsigned long xargs[6];
- unsigned long xxargs[1];
-};
-
-/* A 32-bit Sparc stack frame */
-struct sparc_stackf32 {
- unsigned int locals[8];
- unsigned int ins[6];
- unsigned int fp;
- unsigned int callers_pc;
- unsigned int structptr;
- unsigned int xargs[6];
- unsigned int xxargs[1];
-};
-
-struct sparc_trapf {
- unsigned long locals[8];
- unsigned long ins[8];
- unsigned long _unused;
- struct pt_regs *regs;
-};
-#endif /* (!__ASSEMBLY__) */
-#else
-/* 32 bit sparc */
-
-#include <asm/psr.h>
-
-/* This struct defines the way the registers are stored on the
- * stack during a system call and basically all traps.
- */
-#ifndef __ASSEMBLY__
-
-#include <linux/types.h>
-
-struct pt_regs {
- unsigned long psr;
- unsigned long pc;
- unsigned long npc;
- unsigned long y;
- unsigned long u_regs[16]; /* globals and ins */
-};
-
-/* A 32-bit register window. */
-struct reg_window32 {
- unsigned long locals[8];
- unsigned long ins[8];
-};
-
-/* A Sparc stack frame */
-struct sparc_stackf {
- unsigned long locals[8];
- unsigned long ins[6];
- struct sparc_stackf *fp;
- unsigned long callers_pc;
- char *structptr;
- unsigned long xargs[6];
- unsigned long xxargs[1];
-};
-#endif /* (!__ASSEMBLY__) */
-
-#endif /* (defined(__sparc__) && defined(__arch64__))*/
-
-#ifndef __ASSEMBLY__
-
-#define TRACEREG_SZ sizeof(struct pt_regs)
-#define STACKFRAME_SZ sizeof(struct sparc_stackf)
-
-#define TRACEREG32_SZ sizeof(struct pt_regs32)
-#define STACKFRAME32_SZ sizeof(struct sparc_stackf32)
-
-#endif /* (!__ASSEMBLY__) */
-
-#define UREG_G0 0
-#define UREG_G1 1
-#define UREG_G2 2
-#define UREG_G3 3
-#define UREG_G4 4
-#define UREG_G5 5
-#define UREG_G6 6
-#define UREG_G7 7
-#define UREG_I0 8
-#define UREG_I1 9
-#define UREG_I2 10
-#define UREG_I3 11
-#define UREG_I4 12
-#define UREG_I5 13
-#define UREG_I6 14
-#define UREG_I7 15
-#define UREG_FP UREG_I6
-#define UREG_RETPC UREG_I7
+#include <uapi/asm/ptrace.h>
#if defined(__sparc__) && defined(__arch64__)
-/* 64 bit sparc */
-
#ifndef __ASSEMBLY__
-#ifdef __KERNEL__
-
#include <linux/threads.h>
#include <asm/switch_to.h>
@@ -223,24 +65,10 @@ extern unsigned long profile_pc(struct pt_regs *);
#else
#define profile_pc(regs) instruction_pointer(regs)
#endif
-#endif /* (__KERNEL__) */
-
#else /* __ASSEMBLY__ */
-/* For assembly code. */
-#define TRACEREG_SZ 0xa0
-#define STACKFRAME_SZ 0xc0
-
-#define TRACEREG32_SZ 0x50
-#define STACKFRAME32_SZ 0x60
#endif /* __ASSEMBLY__ */
-
#else /* (defined(__sparc__) && defined(__arch64__)) */
-
-/* 32 bit sparc */
-
#ifndef __ASSEMBLY__
-
-#ifdef __KERNEL__
#include <asm/switch_to.h>
static inline bool pt_regs_is_syscall(struct pt_regs *regs)
@@ -265,158 +93,10 @@ static inline bool pt_regs_clear_syscall(struct pt_regs *regs)
#define instruction_pointer(regs) ((regs)->pc)
#define user_stack_pointer(regs) ((regs)->u_regs[UREG_FP])
unsigned long profile_pc(struct pt_regs *);
-#endif /* (__KERNEL__) */
-
#else /* (!__ASSEMBLY__) */
-/* For assembly code. */
-#define TRACEREG_SZ 0x50
-#define STACKFRAME_SZ 0x60
#endif /* (!__ASSEMBLY__) */
-
#endif /* (defined(__sparc__) && defined(__arch64__)) */
-
-#ifdef __KERNEL__
#define STACK_BIAS 2047
-#endif
-
-/* These are for pt_regs. */
-#define PT_V9_G0 0x00
-#define PT_V9_G1 0x08
-#define PT_V9_G2 0x10
-#define PT_V9_G3 0x18
-#define PT_V9_G4 0x20
-#define PT_V9_G5 0x28
-#define PT_V9_G6 0x30
-#define PT_V9_G7 0x38
-#define PT_V9_I0 0x40
-#define PT_V9_I1 0x48
-#define PT_V9_I2 0x50
-#define PT_V9_I3 0x58
-#define PT_V9_I4 0x60
-#define PT_V9_I5 0x68
-#define PT_V9_I6 0x70
-#define PT_V9_FP PT_V9_I6
-#define PT_V9_I7 0x78
-#define PT_V9_TSTATE 0x80
-#define PT_V9_TPC 0x88
-#define PT_V9_TNPC 0x90
-#define PT_V9_Y 0x98
-#define PT_V9_MAGIC 0x9c
-#define PT_TSTATE PT_V9_TSTATE
-#define PT_TPC PT_V9_TPC
-#define PT_TNPC PT_V9_TNPC
-
-/* These for pt_regs32. */
-#define PT_PSR 0x0
-#define PT_PC 0x4
-#define PT_NPC 0x8
-#define PT_Y 0xc
-#define PT_G0 0x10
-#define PT_WIM PT_G0
-#define PT_G1 0x14
-#define PT_G2 0x18
-#define PT_G3 0x1c
-#define PT_G4 0x20
-#define PT_G5 0x24
-#define PT_G6 0x28
-#define PT_G7 0x2c
-#define PT_I0 0x30
-#define PT_I1 0x34
-#define PT_I2 0x38
-#define PT_I3 0x3c
-#define PT_I4 0x40
-#define PT_I5 0x44
-#define PT_I6 0x48
-#define PT_FP PT_I6
-#define PT_I7 0x4c
-
-/* Reg_window offsets */
-#define RW_V9_L0 0x00
-#define RW_V9_L1 0x08
-#define RW_V9_L2 0x10
-#define RW_V9_L3 0x18
-#define RW_V9_L4 0x20
-#define RW_V9_L5 0x28
-#define RW_V9_L6 0x30
-#define RW_V9_L7 0x38
-#define RW_V9_I0 0x40
-#define RW_V9_I1 0x48
-#define RW_V9_I2 0x50
-#define RW_V9_I3 0x58
-#define RW_V9_I4 0x60
-#define RW_V9_I5 0x68
-#define RW_V9_I6 0x70
-#define RW_V9_I7 0x78
-
-#define RW_L0 0x00
-#define RW_L1 0x04
-#define RW_L2 0x08
-#define RW_L3 0x0c
-#define RW_L4 0x10
-#define RW_L5 0x14
-#define RW_L6 0x18
-#define RW_L7 0x1c
-#define RW_I0 0x20
-#define RW_I1 0x24
-#define RW_I2 0x28
-#define RW_I3 0x2c
-#define RW_I4 0x30
-#define RW_I5 0x34
-#define RW_I6 0x38
-#define RW_I7 0x3c
-
-/* Stack_frame offsets */
-#define SF_V9_L0 0x00
-#define SF_V9_L1 0x08
-#define SF_V9_L2 0x10
-#define SF_V9_L3 0x18
-#define SF_V9_L4 0x20
-#define SF_V9_L5 0x28
-#define SF_V9_L6 0x30
-#define SF_V9_L7 0x38
-#define SF_V9_I0 0x40
-#define SF_V9_I1 0x48
-#define SF_V9_I2 0x50
-#define SF_V9_I3 0x58
-#define SF_V9_I4 0x60
-#define SF_V9_I5 0x68
-#define SF_V9_FP 0x70
-#define SF_V9_PC 0x78
-#define SF_V9_RETP 0x80
-#define SF_V9_XARG0 0x88
-#define SF_V9_XARG1 0x90
-#define SF_V9_XARG2 0x98
-#define SF_V9_XARG3 0xa0
-#define SF_V9_XARG4 0xa8
-#define SF_V9_XARG5 0xb0
-#define SF_V9_XXARG 0xb8
-
-#define SF_L0 0x00
-#define SF_L1 0x04
-#define SF_L2 0x08
-#define SF_L3 0x0c
-#define SF_L4 0x10
-#define SF_L5 0x14
-#define SF_L6 0x18
-#define SF_L7 0x1c
-#define SF_I0 0x20
-#define SF_I1 0x24
-#define SF_I2 0x28
-#define SF_I3 0x2c
-#define SF_I4 0x30
-#define SF_I5 0x34
-#define SF_FP 0x38
-#define SF_PC 0x3c
-#define SF_RETP 0x40
-#define SF_XARG0 0x44
-#define SF_XARG1 0x48
-#define SF_XARG2 0x4c
-#define SF_XARG3 0x50
-#define SF_XARG4 0x54
-#define SF_XARG5 0x58
-#define SF_XXARG 0x5c
-
-#ifdef __KERNEL__
/* global_reg_snapshot offsets */
#define GR_SNAP_TSTATE 0x00
@@ -428,29 +108,4 @@ unsigned long profile_pc(struct pt_regs *);
#define GR_SNAP_THREAD 0x30
#define GR_SNAP_PAD1 0x38
-#endif /* __KERNEL__ */
-
-/* Stuff for the ptrace system call */
-#define PTRACE_SPARC_DETACH 11
-#define PTRACE_GETREGS 12
-#define PTRACE_SETREGS 13
-#define PTRACE_GETFPREGS 14
-#define PTRACE_SETFPREGS 15
-#define PTRACE_READDATA 16
-#define PTRACE_WRITEDATA 17
-#define PTRACE_READTEXT 18
-#define PTRACE_WRITETEXT 19
-#define PTRACE_GETFPAREGS 20
-#define PTRACE_SETFPAREGS 21
-
-/* There are for debugging 64-bit processes, either from a 32 or 64 bit
- * parent. Thus their complements are for debugging 32-bit processes only.
- */
-
-#define PTRACE_GETREGS64 22
-#define PTRACE_SETREGS64 23
-/* PTRACE_SYSCALL is 24 */
-#define PTRACE_GETFPREGS64 25
-#define PTRACE_SETFPREGS64 26
-
#endif /* !(__SPARC_PTRACE_H) */
diff --git a/arch/sparc/include/asm/setup.h b/arch/sparc/include/asm/setup.h
index 8a83699..5e35e05 100644
--- a/arch/sparc/include/asm/setup.h
+++ b/arch/sparc/include/asm/setup.h
@@ -1,17 +1,11 @@
/*
* Just a place holder.
*/
-
#ifndef _SPARC_SETUP_H
#define _SPARC_SETUP_H
-#if defined(__sparc__) && defined(__arch64__)
-# define COMMAND_LINE_SIZE 2048
-#else
-# define COMMAND_LINE_SIZE 256
-#endif
+#include <uapi/asm/setup.h>
-#ifdef __KERNEL__
extern char reboot_command[];
@@ -34,6 +28,4 @@ extern void sun_do_break(void);
extern int stop_a_enabled;
extern int scons_pwroff;
-#endif /* __KERNEL__ */
-
#endif /* _SPARC_SETUP_H */
diff --git a/arch/sparc/include/asm/sigcontext.h b/arch/sparc/include/asm/sigcontext.h
index 69914d7..fc2df1e 100644
--- a/arch/sparc/include/asm/sigcontext.h
+++ b/arch/sparc/include/asm/sigcontext.h
@@ -1,8 +1,8 @@
#ifndef __SPARC_SIGCONTEXT_H
#define __SPARC_SIGCONTEXT_H
-#ifdef __KERNEL__
#include <asm/ptrace.h>
+#include <uapi/asm/sigcontext.h>
#ifndef __ASSEMBLY__
@@ -105,6 +105,4 @@ typedef struct {
#endif /* !(__ASSEMBLY__) */
-#endif /* (__KERNEL__) */
-
#endif /* !(__SPARC_SIGCONTEXT_H) */
diff --git a/arch/sparc/include/asm/siginfo.h b/arch/sparc/include/asm/siginfo.h
index dbc182c..48c34c1 100644
--- a/arch/sparc/include/asm/siginfo.h
+++ b/arch/sparc/include/asm/siginfo.h
@@ -1,19 +1,8 @@
#ifndef __SPARC_SIGINFO_H
#define __SPARC_SIGINFO_H
-#if defined(__sparc__) && defined(__arch64__)
+#include <uapi/asm/siginfo.h>
-#define __ARCH_SI_PREAMBLE_SIZE (4 * sizeof(int))
-#define __ARCH_SI_BAND_T int
-
-#endif /* defined(__sparc__) && defined(__arch64__) */
-
-
-#define __ARCH_SI_TRAPNO
-
-#include <asm-generic/siginfo.h>
-
-#ifdef __KERNEL__
#ifdef CONFIG_COMPAT
@@ -21,14 +10,4 @@ struct compat_siginfo;
#endif /* CONFIG_COMPAT */
-#endif /* __KERNEL__ */
-
-#define SI_NOINFO 32767 /* no information in siginfo_t */
-
-/*
- * SIGEMT si_codes
- */
-#define EMT_TAGOVF (__SI_FAULT|1) /* tag overflow */
-#define NSIGEMT 1
-
#endif /* !(__SPARC_SIGINFO_H) */
diff --git a/arch/sparc/include/asm/signal.h b/arch/sparc/include/asm/signal.h
index aa42fe3..d243c2a 100644
--- a/arch/sparc/include/asm/signal.h
+++ b/arch/sparc/include/asm/signal.h
@@ -1,168 +1,13 @@
#ifndef __SPARC_SIGNAL_H
#define __SPARC_SIGNAL_H
-#include <asm/sigcontext.h>
-#include <linux/compiler.h>
-
-#ifdef __KERNEL__
#ifndef __ASSEMBLY__
#include <linux/personality.h>
#include <linux/types.h>
#endif
-#endif
-
-/* On the Sparc the signal handlers get passed a 'sub-signal' code
- * for certain signal types, which we document here.
- */
-#define SIGHUP 1
-#define SIGINT 2
-#define SIGQUIT 3
-#define SIGILL 4
-#define SUBSIG_STACK 0
-#define SUBSIG_ILLINST 2
-#define SUBSIG_PRIVINST 3
-#define SUBSIG_BADTRAP(t) (0x80 + (t))
-
-#define SIGTRAP 5
-#define SIGABRT 6
-#define SIGIOT 6
-
-#define SIGEMT 7
-#define SUBSIG_TAG 10
-
-#define SIGFPE 8
-#define SUBSIG_FPDISABLED 0x400
-#define SUBSIG_FPERROR 0x404
-#define SUBSIG_FPINTOVFL 0x001
-#define SUBSIG_FPSTSIG 0x002
-#define SUBSIG_IDIVZERO 0x014
-#define SUBSIG_FPINEXACT 0x0c4
-#define SUBSIG_FPDIVZERO 0x0c8
-#define SUBSIG_FPUNFLOW 0x0cc
-#define SUBSIG_FPOPERROR 0x0d0
-#define SUBSIG_FPOVFLOW 0x0d4
-
-#define SIGKILL 9
-#define SIGBUS 10
-#define SUBSIG_BUSTIMEOUT 1
-#define SUBSIG_ALIGNMENT 2
-#define SUBSIG_MISCERROR 5
-
-#define SIGSEGV 11
-#define SUBSIG_NOMAPPING 3
-#define SUBSIG_PROTECTION 4
-#define SUBSIG_SEGERROR 5
-
-#define SIGSYS 12
-
-#define SIGPIPE 13
-#define SIGALRM 14
-#define SIGTERM 15
-#define SIGURG 16
-
-/* SunOS values which deviate from the Linux/i386 ones */
-#define SIGSTOP 17
-#define SIGTSTP 18
-#define SIGCONT 19
-#define SIGCHLD 20
-#define SIGTTIN 21
-#define SIGTTOU 22
-#define SIGIO 23
-#define SIGPOLL SIGIO /* SysV name for SIGIO */
-#define SIGXCPU 24
-#define SIGXFSZ 25
-#define SIGVTALRM 26
-#define SIGPROF 27
-#define SIGWINCH 28
-#define SIGLOST 29
-#define SIGPWR SIGLOST
-#define SIGUSR1 30
-#define SIGUSR2 31
-
-/* Most things should be clean enough to redefine this at will, if care
- is taken to make libc match. */
-
-#define __OLD_NSIG 32
-#define __NEW_NSIG 64
-#ifdef __arch64__
-#define _NSIG_BPW 64
-#else
-#define _NSIG_BPW 32
-#endif
-#define _NSIG_WORDS (__NEW_NSIG / _NSIG_BPW)
-
-#define SIGRTMIN 32
-#define SIGRTMAX __NEW_NSIG
-
-#if defined(__KERNEL__) || defined(__WANT_POSIX1B_SIGNALS__)
-#define _NSIG __NEW_NSIG
-#define __new_sigset_t sigset_t
-#define __new_sigaction sigaction
-#define __new_sigaction32 sigaction32
-#define __old_sigset_t old_sigset_t
-#define __old_sigaction old_sigaction
-#define __old_sigaction32 old_sigaction32
-#else
-#define _NSIG __OLD_NSIG
-#define NSIG _NSIG
-#define __old_sigset_t sigset_t
-#define __old_sigaction sigaction
-#define __old_sigaction32 sigaction32
-#endif
+#include <uapi/asm/signal.h>
#ifndef __ASSEMBLY__
-
-typedef unsigned long __old_sigset_t; /* at least 32 bits */
-
-typedef struct {
- unsigned long sig[_NSIG_WORDS];
-} __new_sigset_t;
-
-/* A SunOS sigstack */
-struct sigstack {
- /* XXX 32-bit pointers pinhead XXX */
- char *the_stack;
- int cur_status;
-};
-
-/* Sigvec flags */
-#define _SV_SSTACK 1u /* This signal handler should use sig-stack */
-#define _SV_INTR 2u /* Sig return should not restart system call */
-#define _SV_RESET 4u /* Set handler to SIG_DFL upon taken signal */
-#define _SV_IGNCHILD 8u /* Do not send SIGCHLD */
-
-/*
- * sa_flags values: SA_STACK is not currently supported, but will allow the
- * usage of signal stacks by using the (now obsolete) sa_restorer field in
- * the sigaction structure as a stack pointer. This is now possible due to
- * the changes in signal handling. LBT 010493.
- * SA_RESTART flag to get restarting signals (which were the default long ago)
- */
-#define SA_NOCLDSTOP _SV_IGNCHILD
-#define SA_STACK _SV_SSTACK
-#define SA_ONSTACK _SV_SSTACK
-#define SA_RESTART _SV_INTR
-#define SA_ONESHOT _SV_RESET
-#define SA_NODEFER 0x20u
-#define SA_NOCLDWAIT 0x100u
-#define SA_SIGINFO 0x200u
-
-#define SA_NOMASK SA_NODEFER
-
-#define SIG_BLOCK 0x01 /* for blocking signals */
-#define SIG_UNBLOCK 0x02 /* for unblocking signals */
-#define SIG_SETMASK 0x04 /* for setting the signal mask */
-
-/*
- * sigaltstack controls
- */
-#define SS_ONSTACK 1
-#define SS_DISABLE 2
-
-#define MINSIGSTKSZ 4096
-#define SIGSTKSZ 16384
-
-#ifdef __KERNEL__
/*
* DJHR
* SA_STATIC_ALLOC is used for the sparc32 system to indicate that this
@@ -175,31 +20,6 @@ struct sigstack {
*
*/
#define SA_STATIC_ALLOC 0x8000
-#endif
-
-#include <asm-generic/signal-defs.h>
-
-struct __new_sigaction {
- __sighandler_t sa_handler;
- unsigned long sa_flags;
- __sigrestore_t sa_restorer; /* not used by Linux/SPARC yet */
- __new_sigset_t sa_mask;
-};
-
-struct __old_sigaction {
- __sighandler_t sa_handler;
- __old_sigset_t sa_mask;
- unsigned long sa_flags;
- void (*sa_restorer)(void); /* not used by Linux/SPARC yet */
-};
-
-typedef struct sigaltstack {
- void __user *ss_sp;
- int ss_flags;
- size_t ss_size;
-} stack_t;
-
-#ifdef __KERNEL__
struct k_sigaction {
struct __new_sigaction sa;
@@ -208,8 +28,5 @@ struct k_sigaction {
#define ptrace_signal_deliver(regs, cookie) do { } while (0)
-#endif /* !(__KERNEL__) */
-
#endif /* !(__ASSEMBLY__) */
-
#endif /* !(__SPARC_SIGNAL_H) */
diff --git a/arch/sparc/include/asm/termbits.h b/arch/sparc/include/asm/termbits.h
index 23b10ff..9480670 100644
--- a/arch/sparc/include/asm/termbits.h
+++ b/arch/sparc/include/asm/termbits.h
@@ -1,266 +1,8 @@
#ifndef _SPARC_TERMBITS_H
#define _SPARC_TERMBITS_H
-#include <linux/posix_types.h>
+#include <uapi/asm/termbits.h>
-typedef unsigned char cc_t;
-typedef unsigned int speed_t;
-
-#if defined(__sparc__) && defined(__arch64__)
-typedef unsigned int tcflag_t;
-#else
-typedef unsigned long tcflag_t;
-#endif
-
-#define NCC 8
-struct termio {
- unsigned short c_iflag; /* input mode flags */
- unsigned short c_oflag; /* output mode flags */
- unsigned short c_cflag; /* control mode flags */
- unsigned short c_lflag; /* local mode flags */
- unsigned char c_line; /* line discipline */
- unsigned char c_cc[NCC]; /* control characters */
-};
-
-#define NCCS 17
-struct termios {
- tcflag_t c_iflag; /* input mode flags */
- tcflag_t c_oflag; /* output mode flags */
- tcflag_t c_cflag; /* control mode flags */
- tcflag_t c_lflag; /* local mode flags */
- cc_t c_line; /* line discipline */
-#ifndef __KERNEL__
- cc_t c_cc[NCCS]; /* control characters */
-#else
- cc_t c_cc[NCCS+2]; /* kernel needs 2 more to hold vmin/vtime */
-#define SIZEOF_USER_TERMIOS sizeof (struct termios) - (2*sizeof (cc_t))
-#endif
-};
-
-struct termios2 {
- tcflag_t c_iflag; /* input mode flags */
- tcflag_t c_oflag; /* output mode flags */
- tcflag_t c_cflag; /* control mode flags */
- tcflag_t c_lflag; /* local mode flags */
- cc_t c_line; /* line discipline */
- cc_t c_cc[NCCS+2]; /* control characters */
- speed_t c_ispeed; /* input speed */
- speed_t c_ospeed; /* output speed */
-};
-
-struct ktermios {
- tcflag_t c_iflag; /* input mode flags */
- tcflag_t c_oflag; /* output mode flags */
- tcflag_t c_cflag; /* control mode flags */
- tcflag_t c_lflag; /* local mode flags */
- cc_t c_line; /* line discipline */
- cc_t c_cc[NCCS+2]; /* control characters */
- speed_t c_ispeed; /* input speed */
- speed_t c_ospeed; /* output speed */
-};
-
-/* c_cc characters */
-#define VINTR 0
-#define VQUIT 1
-#define VERASE 2
-#define VKILL 3
-#define VEOF 4
-#define VEOL 5
-#define VEOL2 6
-#define VSWTC 7
-#define VSTART 8
-#define VSTOP 9
-
-
-
-#define VSUSP 10
-#define VDSUSP 11 /* SunOS POSIX nicety I do believe... */
-#define VREPRINT 12
-#define VDISCARD 13
-#define VWERASE 14
-#define VLNEXT 15
-
-/* Kernel keeps vmin/vtime separated, user apps assume vmin/vtime is
- * shared with eof/eol
- */
-#ifdef __KERNEL__
#define VMIN 16
#define VTIME 17
-#else
-#define VMIN VEOF
-#define VTIME VEOL
-#endif
-
-/* c_iflag bits */
-#define IGNBRK 0x00000001
-#define BRKINT 0x00000002
-#define IGNPAR 0x00000004
-#define PARMRK 0x00000008
-#define INPCK 0x00000010
-#define ISTRIP 0x00000020
-#define INLCR 0x00000040
-#define IGNCR 0x00000080
-#define ICRNL 0x00000100
-#define IUCLC 0x00000200
-#define IXON 0x00000400
-#define IXANY 0x00000800
-#define IXOFF 0x00001000
-#define IMAXBEL 0x00002000
-#define IUTF8 0x00004000
-
-/* c_oflag bits */
-#define OPOST 0x00000001
-#define OLCUC 0x00000002
-#define ONLCR 0x00000004
-#define OCRNL 0x00000008
-#define ONOCR 0x00000010
-#define ONLRET 0x00000020
-#define OFILL 0x00000040
-#define OFDEL 0x00000080
-#define NLDLY 0x00000100
-#define NL0 0x00000000
-#define NL1 0x00000100
-#define CRDLY 0x00000600
-#define CR0 0x00000000
-#define CR1 0x00000200
-#define CR2 0x00000400
-#define CR3 0x00000600
-#define TABDLY 0x00001800
-#define TAB0 0x00000000
-#define TAB1 0x00000800
-#define TAB2 0x00001000
-#define TAB3 0x00001800
-#define XTABS 0x00001800
-#define BSDLY 0x00002000
-#define BS0 0x00000000
-#define BS1 0x00002000
-#define VTDLY 0x00004000
-#define VT0 0x00000000
-#define VT1 0x00004000
-#define FFDLY 0x00008000
-#define FF0 0x00000000
-#define FF1 0x00008000
-#define PAGEOUT 0x00010000 /* SUNOS specific */
-#define WRAP 0x00020000 /* SUNOS specific */
-
-/* c_cflag bit meaning */
-#define CBAUD 0x0000100f
-#define B0 0x00000000 /* hang up */
-#define B50 0x00000001
-#define B75 0x00000002
-#define B110 0x00000003
-#define B134 0x00000004
-#define B150 0x00000005
-#define B200 0x00000006
-#define B300 0x00000007
-#define B600 0x00000008
-#define B1200 0x00000009
-#define B1800 0x0000000a
-#define B2400 0x0000000b
-#define B4800 0x0000000c
-#define B9600 0x0000000d
-#define B19200 0x0000000e
-#define B38400 0x0000000f
-#define EXTA B19200
-#define EXTB B38400
-#define CSIZE 0x00000030
-#define CS5 0x00000000
-#define CS6 0x00000010
-#define CS7 0x00000020
-#define CS8 0x00000030
-#define CSTOPB 0x00000040
-#define CREAD 0x00000080
-#define PARENB 0x00000100
-#define PARODD 0x00000200
-#define HUPCL 0x00000400
-#define CLOCAL 0x00000800
-#define CBAUDEX 0x00001000
-/* We'll never see these speeds with the Zilogs, but for completeness... */
-#define BOTHER 0x00001000
-#define B57600 0x00001001
-#define B115200 0x00001002
-#define B230400 0x00001003
-#define B460800 0x00001004
-/* This is what we can do with the Zilogs. */
-#define B76800 0x00001005
-/* This is what we can do with the SAB82532. */
-#define B153600 0x00001006
-#define B307200 0x00001007
-#define B614400 0x00001008
-#define B921600 0x00001009
-/* And these are the rest... */
-#define B500000 0x0000100a
-#define B576000 0x0000100b
-#define B1000000 0x0000100c
-#define B1152000 0x0000100d
-#define B1500000 0x0000100e
-#define B2000000 0x0000100f
-/* These have totally bogus values and nobody uses them
- so far. Later on we'd have to use say 0x10000x and
- adjust CBAUD constant and drivers accordingly.
-#define B2500000 0x00001010
-#define B3000000 0x00001011
-#define B3500000 0x00001012
-#define B4000000 0x00001013 */
-#define CIBAUD 0x100f0000 /* input baud rate (not used) */
-#define CMSPAR 0x40000000 /* mark or space (stick) parity */
-#define CRTSCTS 0x80000000 /* flow control */
-
-#define IBSHIFT 16 /* Shift from CBAUD to CIBAUD */
-
-/* c_lflag bits */
-#define ISIG 0x00000001
-#define ICANON 0x00000002
-#define XCASE 0x00000004
-#define ECHO 0x00000008
-#define ECHOE 0x00000010
-#define ECHOK 0x00000020
-#define ECHONL 0x00000040
-#define NOFLSH 0x00000080
-#define TOSTOP 0x00000100
-#define ECHOCTL 0x00000200
-#define ECHOPRT 0x00000400
-#define ECHOKE 0x00000800
-#define DEFECHO 0x00001000 /* SUNOS thing, what is it? */
-#define FLUSHO 0x00002000
-#define PENDIN 0x00004000
-#define IEXTEN 0x00008000
-#define EXTPROC 0x00010000
-
-/* modem lines */
-#define TIOCM_LE 0x001
-#define TIOCM_DTR 0x002
-#define TIOCM_RTS 0x004
-#define TIOCM_ST 0x008
-#define TIOCM_SR 0x010
-#define TIOCM_CTS 0x020
-#define TIOCM_CAR 0x040
-#define TIOCM_RNG 0x080
-#define TIOCM_DSR 0x100
-#define TIOCM_CD TIOCM_CAR
-#define TIOCM_RI TIOCM_RNG
-#define TIOCM_OUT1 0x2000
-#define TIOCM_OUT2 0x4000
-#define TIOCM_LOOP 0x8000
-
-/* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
-#define TIOCSER_TEMT 0x01 /* Transmitter physically empty */
-
-
-/* tcflow() and TCXONC use these */
-#define TCOOFF 0
-#define TCOON 1
-#define TCIOFF 2
-#define TCION 3
-
-/* tcflush() and TCFLSH use these */
-#define TCIFLUSH 0
-#define TCOFLUSH 1
-#define TCIOFLUSH 2
-
-/* tcsetattr uses these */
-#define TCSANOW 0
-#define TCSADRAIN 1
-#define TCSAFLUSH 2
-
#endif /* !(_SPARC_TERMBITS_H) */
diff --git a/arch/sparc/include/asm/termios.h b/arch/sparc/include/asm/termios.h
index e2f4670..0c2414d 100644
--- a/arch/sparc/include/asm/termios.h
+++ b/arch/sparc/include/asm/termios.h
@@ -1,45 +1,8 @@
#ifndef _SPARC_TERMIOS_H
#define _SPARC_TERMIOS_H
-#include <asm/ioctls.h>
-#include <asm/termbits.h>
+#include <uapi/asm/termios.h>
-#if defined(__KERNEL__) || defined(__DEFINE_BSD_TERMIOS)
-struct sgttyb {
- char sg_ispeed;
- char sg_ospeed;
- char sg_erase;
- char sg_kill;
- short sg_flags;
-};
-
-struct tchars {
- char t_intrc;
- char t_quitc;
- char t_startc;
- char t_stopc;
- char t_eofc;
- char t_brkc;
-};
-
-struct ltchars {
- char t_suspc;
- char t_dsuspc;
- char t_rprntc;
- char t_flushc;
- char t_werasc;
- char t_lnextc;
-};
-#endif /* __KERNEL__ */
-
-struct winsize {
- unsigned short ws_row;
- unsigned short ws_col;
- unsigned short ws_xpixel;
- unsigned short ws_ypixel;
-};
-
-#ifdef __KERNEL__
/*
* c_cc characters in the termio structure. Oh, how I love being
@@ -180,6 +143,4 @@ struct winsize {
err; \
})
-#endif /* __KERNEL__ */
-
#endif /* _SPARC_TERMIOS_H */
diff --git a/arch/sparc/include/asm/thread_info_32.h b/arch/sparc/include/asm/thread_info_32.h
index e6cd224..25849ae 100644
--- a/arch/sparc/include/asm/thread_info_32.h
+++ b/arch/sparc/include/asm/thread_info_32.h
@@ -126,13 +126,14 @@ register struct thread_info *current_thread_info_reg asm("g6");
#define _TIF_NOTIFY_RESUME (1<<TIF_NOTIFY_RESUME)
#define _TIF_SIGPENDING (1<<TIF_SIGPENDING)
#define _TIF_NEED_RESCHED (1<<TIF_NEED_RESCHED)
-#define _TIF_RESTORE_SIGMASK (1<<TIF_RESTORE_SIGMASK)
#define _TIF_USEDFPU (1<<TIF_USEDFPU)
#define _TIF_POLLING_NRFLAG (1<<TIF_POLLING_NRFLAG)
#define _TIF_DO_NOTIFY_RESUME_MASK (_TIF_NOTIFY_RESUME | \
_TIF_SIGPENDING)
+#define tsk_is_polling(t) test_tsk_thread_flag(t, TIF_POLLING_NRFLAG)
+
#endif /* __KERNEL__ */
#endif /* _ASM_THREAD_INFO_H */
diff --git a/arch/sparc/include/asm/thread_info_64.h b/arch/sparc/include/asm/thread_info_64.h
index cfa8c38..4e227663 100644
--- a/arch/sparc/include/asm/thread_info_64.h
+++ b/arch/sparc/include/asm/thread_info_64.h
@@ -256,6 +256,9 @@ static inline bool test_and_clear_restore_sigmask(void)
ti->status &= ~TS_RESTORE_SIGMASK;
return true;
}
+
+#define tsk_is_polling(t) test_tsk_thread_flag(t, TIF_POLLING_NRFLAG)
+
#endif /* !__ASSEMBLY__ */
#endif /* __KERNEL__ */
diff --git a/arch/sparc/include/asm/traps.h b/arch/sparc/include/asm/traps.h
index 3aa62dd..51abcb1 100644
--- a/arch/sparc/include/asm/traps.h
+++ b/arch/sparc/include/asm/traps.h
@@ -3,14 +3,12 @@
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
*/
-
#ifndef _SPARC_TRAPS_H
#define _SPARC_TRAPS_H
-#define NUM_SPARC_TRAPS 255
+#include <uapi/asm/traps.h>
#ifndef __ASSEMBLY__
-#ifdef __KERNEL__
/* This is for V8 compliant Sparc CPUS */
struct tt_entry {
unsigned long inst_one;
@@ -22,112 +20,5 @@ struct tt_entry {
/* We set this to _start in system setup. */
extern struct tt_entry *sparc_ttable;
-#endif /* (__KERNEL__) */
#endif /* !(__ASSEMBLY__) */
-
-/* For patching the trap table at boot time, we need to know how to
- * form various common Sparc instructions. Thus these macros...
- */
-
-#define SPARC_MOV_CONST_L3(const) (0xa6102000 | (const&0xfff))
-
-/* The following assumes that the branch lies before the place we
- * are branching to. This is the case for a trap vector...
- * You have been warned.
- */
-#define SPARC_BRANCH(dest_addr, inst_addr) \
- (0x10800000 | (((dest_addr-inst_addr)>>2)&0x3fffff))
-
-#define SPARC_RD_PSR_L0 (0xa1480000)
-#define SPARC_RD_WIM_L3 (0xa7500000)
-#define SPARC_NOP (0x01000000)
-
-/* Various interesting trap levels. */
-/* First, hardware traps. */
-#define SP_TRAP_TFLT 0x1 /* Text fault */
-#define SP_TRAP_II 0x2 /* Illegal Instruction */
-#define SP_TRAP_PI 0x3 /* Privileged Instruction */
-#define SP_TRAP_FPD 0x4 /* Floating Point Disabled */
-#define SP_TRAP_WOVF 0x5 /* Window Overflow */
-#define SP_TRAP_WUNF 0x6 /* Window Underflow */
-#define SP_TRAP_MNA 0x7 /* Memory Address Unaligned */
-#define SP_TRAP_FPE 0x8 /* Floating Point Exception */
-#define SP_TRAP_DFLT 0x9 /* Data Fault */
-#define SP_TRAP_TOF 0xa /* Tag Overflow */
-#define SP_TRAP_WDOG 0xb /* Watchpoint Detected */
-#define SP_TRAP_IRQ1 0x11 /* IRQ level 1 */
-#define SP_TRAP_IRQ2 0x12 /* IRQ level 2 */
-#define SP_TRAP_IRQ3 0x13 /* IRQ level 3 */
-#define SP_TRAP_IRQ4 0x14 /* IRQ level 4 */
-#define SP_TRAP_IRQ5 0x15 /* IRQ level 5 */
-#define SP_TRAP_IRQ6 0x16 /* IRQ level 6 */
-#define SP_TRAP_IRQ7 0x17 /* IRQ level 7 */
-#define SP_TRAP_IRQ8 0x18 /* IRQ level 8 */
-#define SP_TRAP_IRQ9 0x19 /* IRQ level 9 */
-#define SP_TRAP_IRQ10 0x1a /* IRQ level 10 */
-#define SP_TRAP_IRQ11 0x1b /* IRQ level 11 */
-#define SP_TRAP_IRQ12 0x1c /* IRQ level 12 */
-#define SP_TRAP_IRQ13 0x1d /* IRQ level 13 */
-#define SP_TRAP_IRQ14 0x1e /* IRQ level 14 */
-#define SP_TRAP_IRQ15 0x1f /* IRQ level 15 Non-maskable */
-#define SP_TRAP_RACC 0x20 /* Register Access Error ??? */
-#define SP_TRAP_IACC 0x21 /* Instruction Access Error */
-#define SP_TRAP_CPDIS 0x24 /* Co-Processor Disabled */
-#define SP_TRAP_BADFL 0x25 /* Unimplemented Flush Instruction */
-#define SP_TRAP_CPEXP 0x28 /* Co-Processor Exception */
-#define SP_TRAP_DACC 0x29 /* Data Access Error */
-#define SP_TRAP_DIVZ 0x2a /* Divide By Zero */
-#define SP_TRAP_DSTORE 0x2b /* Data Store Error ??? */
-#define SP_TRAP_DMM 0x2c /* Data Access MMU Miss ??? */
-#define SP_TRAP_IMM 0x3c /* Instruction Access MMU Miss ??? */
-
-/* Now the Software Traps... */
-#define SP_TRAP_SUNOS 0x80 /* SunOS System Call */
-#define SP_TRAP_SBPT 0x81 /* Software Breakpoint */
-#define SP_TRAP_SDIVZ 0x82 /* Software Divide-by-Zero trap */
-#define SP_TRAP_FWIN 0x83 /* Flush Windows */
-#define SP_TRAP_CWIN 0x84 /* Clean Windows */
-#define SP_TRAP_RCHK 0x85 /* Range Check */
-#define SP_TRAP_FUNA 0x86 /* Fix Unaligned Access */
-#define SP_TRAP_IOWFL 0x87 /* Integer Overflow */
-#define SP_TRAP_SOLARIS 0x88 /* Solaris System Call */
-#define SP_TRAP_NETBSD 0x89 /* NetBSD System Call */
-#define SP_TRAP_LINUX 0x90 /* Linux System Call */
-
-/* Names used for compatibility with SunOS */
-#define ST_SYSCALL 0x00
-#define ST_BREAKPOINT 0x01
-#define ST_DIV0 0x02
-#define ST_FLUSH_WINDOWS 0x03
-#define ST_CLEAN_WINDOWS 0x04
-#define ST_RANGE_CHECK 0x05
-#define ST_FIX_ALIGN 0x06
-#define ST_INT_OVERFLOW 0x07
-
-/* Special traps... */
-#define SP_TRAP_KBPT1 0xfe /* KADB/PROM Breakpoint one */
-#define SP_TRAP_KBPT2 0xff /* KADB/PROM Breakpoint two */
-
-/* Handy Macros */
-/* Is this a trap we never expect to get? */
-#define BAD_TRAP_P(level) \
- ((level > SP_TRAP_WDOG && level < SP_TRAP_IRQ1) || \
- (level > SP_TRAP_IACC && level < SP_TRAP_CPDIS) || \
- (level > SP_TRAP_BADFL && level < SP_TRAP_CPEXP) || \
- (level > SP_TRAP_DMM && level < SP_TRAP_IMM) || \
- (level > SP_TRAP_IMM && level < SP_TRAP_SUNOS) || \
- (level > SP_TRAP_LINUX && level < SP_TRAP_KBPT1))
-
-/* Is this a Hardware trap? */
-#define HW_TRAP_P(level) ((level > 0) && (level < SP_TRAP_SUNOS))
-
-/* Is this a Software trap? */
-#define SW_TRAP_P(level) ((level >= SP_TRAP_SUNOS) && (level <= SP_TRAP_KBPT2))
-
-/* Is this a system call for some OS we know about? */
-#define SCALL_TRAP_P(level) ((level == SP_TRAP_SUNOS) || \
- (level == SP_TRAP_SOLARIS) || \
- (level == SP_TRAP_NETBSD) || \
- (level == SP_TRAP_LINUX))
-
#endif /* !(_SPARC_TRAPS_H) */
diff --git a/arch/sparc/include/asm/unistd.h b/arch/sparc/include/asm/unistd.h
index d9a677c..0ecea6e 100644
--- a/arch/sparc/include/asm/unistd.h
+++ b/arch/sparc/include/asm/unistd.h
@@ -1,6 +1,3 @@
-#ifndef _SPARC_UNISTD_H
-#define _SPARC_UNISTD_H
-
/*
* System calls under the Sparc.
*
@@ -14,415 +11,15 @@
*
* Copyright (C) 1995 Adrian M. Rodriguez (adrian@remus.rutgers.edu)
*/
-#ifndef __32bit_syscall_numbers__
-#ifndef __arch64__
-#define __32bit_syscall_numbers__
-#endif
-#endif
+#ifndef _SPARC_UNISTD_H
+#define _SPARC_UNISTD_H
+
+#include <uapi/asm/unistd.h>
-#define __NR_restart_syscall 0 /* Linux Specific */
-#define __NR_exit 1 /* Common */
-#define __NR_fork 2 /* Common */
-#define __NR_read 3 /* Common */
-#define __NR_write 4 /* Common */
-#define __NR_open 5 /* Common */
-#define __NR_close 6 /* Common */
-#define __NR_wait4 7 /* Common */
-#define __NR_creat 8 /* Common */
-#define __NR_link 9 /* Common */
-#define __NR_unlink 10 /* Common */
-#define __NR_execv 11 /* SunOS Specific */
-#define __NR_chdir 12 /* Common */
-#define __NR_chown 13 /* Common */
-#define __NR_mknod 14 /* Common */
-#define __NR_chmod 15 /* Common */
-#define __NR_lchown 16 /* Common */
-#define __NR_brk 17 /* Common */
-#define __NR_perfctr 18 /* Performance counter operations */
-#define __NR_lseek 19 /* Common */
-#define __NR_getpid 20 /* Common */
-#define __NR_capget 21 /* Linux Specific */
-#define __NR_capset 22 /* Linux Specific */
-#define __NR_setuid 23 /* Implemented via setreuid in SunOS */
-#define __NR_getuid 24 /* Common */
-#define __NR_vmsplice 25 /* ENOSYS under SunOS */
-#define __NR_ptrace 26 /* Common */
-#define __NR_alarm 27 /* Implemented via setitimer in SunOS */
-#define __NR_sigaltstack 28 /* Common */
-#define __NR_pause 29 /* Is sigblock(0)->sigpause() in SunOS */
-#define __NR_utime 30 /* Implemented via utimes() under SunOS */
-#ifdef __32bit_syscall_numbers__
-#define __NR_lchown32 31 /* Linux sparc32 specific */
-#define __NR_fchown32 32 /* Linux sparc32 specific */
-#endif
-#define __NR_access 33 /* Common */
-#define __NR_nice 34 /* Implemented via get/setpriority() in SunOS */
-#ifdef __32bit_syscall_numbers__
-#define __NR_chown32 35 /* Linux sparc32 specific */
-#endif
-#define __NR_sync 36 /* Common */
-#define __NR_kill 37 /* Common */
-#define __NR_stat 38 /* Common */
-#define __NR_sendfile 39 /* Linux Specific */
-#define __NR_lstat 40 /* Common */
-#define __NR_dup 41 /* Common */
-#define __NR_pipe 42 /* Common */
-#define __NR_times 43 /* Implemented via getrusage() in SunOS */
-#ifdef __32bit_syscall_numbers__
-#define __NR_getuid32 44 /* Linux sparc32 specific */
-#endif
-#define __NR_umount2 45 /* Linux Specific */
-#define __NR_setgid 46 /* Implemented via setregid() in SunOS */
-#define __NR_getgid 47 /* Common */
-#define __NR_signal 48 /* Implemented via sigvec() in SunOS */
-#define __NR_geteuid 49 /* SunOS calls getuid() */
-#define __NR_getegid 50 /* SunOS calls getgid() */
-#define __NR_acct 51 /* Common */
-#ifdef __32bit_syscall_numbers__
-#define __NR_getgid32 53 /* Linux sparc32 specific */
-#else
-#define __NR_memory_ordering 52 /* Linux Specific */
-#endif
-#define __NR_ioctl 54 /* Common */
-#define __NR_reboot 55 /* Common */
-#ifdef __32bit_syscall_numbers__
-#define __NR_mmap2 56 /* Linux sparc32 Specific */
-#endif
-#define __NR_symlink 57 /* Common */
-#define __NR_readlink 58 /* Common */
-#define __NR_execve 59 /* Common */
-#define __NR_umask 60 /* Common */
-#define __NR_chroot 61 /* Common */
-#define __NR_fstat 62 /* Common */
-#define __NR_fstat64 63 /* Linux Specific */
-#define __NR_getpagesize 64 /* Common */
-#define __NR_msync 65 /* Common in newer 1.3.x revs... */
-#define __NR_vfork 66 /* Common */
-#define __NR_pread64 67 /* Linux Specific */
-#define __NR_pwrite64 68 /* Linux Specific */
-#ifdef __32bit_syscall_numbers__
-#define __NR_geteuid32 69 /* Linux sparc32, sbrk under SunOS */
-#define __NR_getegid32 70 /* Linux sparc32, sstk under SunOS */
-#endif
-#define __NR_mmap 71 /* Common */
-#ifdef __32bit_syscall_numbers__
-#define __NR_setreuid32 72 /* Linux sparc32, vadvise under SunOS */
-#endif
-#define __NR_munmap 73 /* Common */
-#define __NR_mprotect 74 /* Common */
-#define __NR_madvise 75 /* Common */
-#define __NR_vhangup 76 /* Common */
-#ifdef __32bit_syscall_numbers__
-#define __NR_truncate64 77 /* Linux sparc32 Specific */
-#endif
-#define __NR_mincore 78 /* Common */
-#define __NR_getgroups 79 /* Common */
-#define __NR_setgroups 80 /* Common */
-#define __NR_getpgrp 81 /* Common */
-#ifdef __32bit_syscall_numbers__
-#define __NR_setgroups32 82 /* Linux sparc32, setpgrp under SunOS */
-#endif
-#define __NR_setitimer 83 /* Common */
-#ifdef __32bit_syscall_numbers__
-#define __NR_ftruncate64 84 /* Linux sparc32 Specific */
-#endif
-#define __NR_swapon 85 /* Common */
-#define __NR_getitimer 86 /* Common */
-#ifdef __32bit_syscall_numbers__
-#define __NR_setuid32 87 /* Linux sparc32, gethostname under SunOS */
-#endif
-#define __NR_sethostname 88 /* Common */
-#ifdef __32bit_syscall_numbers__
-#define __NR_setgid32 89 /* Linux sparc32, getdtablesize under SunOS */
-#endif
-#define __NR_dup2 90 /* Common */
-#ifdef __32bit_syscall_numbers__
-#define __NR_setfsuid32 91 /* Linux sparc32, getdopt under SunOS */
-#endif
-#define __NR_fcntl 92 /* Common */
-#define __NR_select 93 /* Common */
-#ifdef __32bit_syscall_numbers__
-#define __NR_setfsgid32 94 /* Linux sparc32, setdopt under SunOS */
-#endif
-#define __NR_fsync 95 /* Common */
-#define __NR_setpriority 96 /* Common */
-#define __NR_socket 97 /* Common */
-#define __NR_connect 98 /* Common */
-#define __NR_accept 99 /* Common */
-#define __NR_getpriority 100 /* Common */
-#define __NR_rt_sigreturn 101 /* Linux Specific */
-#define __NR_rt_sigaction 102 /* Linux Specific */
-#define __NR_rt_sigprocmask 103 /* Linux Specific */
-#define __NR_rt_sigpending 104 /* Linux Specific */
-#define __NR_rt_sigtimedwait 105 /* Linux Specific */
-#define __NR_rt_sigqueueinfo 106 /* Linux Specific */
-#define __NR_rt_sigsuspend 107 /* Linux Specific */
-#ifdef __32bit_syscall_numbers__
-#define __NR_setresuid32 108 /* Linux Specific, sigvec under SunOS */
-#define __NR_getresuid32 109 /* Linux Specific, sigblock under SunOS */
-#define __NR_setresgid32 110 /* Linux Specific, sigsetmask under SunOS */
-#define __NR_getresgid32 111 /* Linux Specific, sigpause under SunOS */
-#define __NR_setregid32 112 /* Linux sparc32, sigstack under SunOS */
-#else
-#define __NR_setresuid 108 /* Linux Specific, sigvec under SunOS */
-#define __NR_getresuid 109 /* Linux Specific, sigblock under SunOS */
-#define __NR_setresgid 110 /* Linux Specific, sigsetmask under SunOS */
-#define __NR_getresgid 111 /* Linux Specific, sigpause under SunOS */
-#endif
-#define __NR_recvmsg 113 /* Common */
-#define __NR_sendmsg 114 /* Common */
-#ifdef __32bit_syscall_numbers__
-#define __NR_getgroups32 115 /* Linux sparc32, vtrace under SunOS */
-#endif
-#define __NR_gettimeofday 116 /* Common */
-#define __NR_getrusage 117 /* Common */
-#define __NR_getsockopt 118 /* Common */
-#define __NR_getcwd 119 /* Linux Specific */
-#define __NR_readv 120 /* Common */
-#define __NR_writev 121 /* Common */
-#define __NR_settimeofday 122 /* Common */
-#define __NR_fchown 123 /* Common */
-#define __NR_fchmod 124 /* Common */
-#define __NR_recvfrom 125 /* Common */
-#define __NR_setreuid 126 /* Common */
-#define __NR_setregid 127 /* Common */
-#define __NR_rename 128 /* Common */
-#define __NR_truncate 129 /* Common */
-#define __NR_ftruncate 130 /* Common */
-#define __NR_flock 131 /* Common */
-#define __NR_lstat64 132 /* Linux Specific */
-#define __NR_sendto 133 /* Common */
-#define __NR_shutdown 134 /* Common */
-#define __NR_socketpair 135 /* Common */
-#define __NR_mkdir 136 /* Common */
-#define __NR_rmdir 137 /* Common */
-#define __NR_utimes 138 /* SunOS Specific */
-#define __NR_stat64 139 /* Linux Specific */
-#define __NR_sendfile64 140 /* adjtime under SunOS */
-#define __NR_getpeername 141 /* Common */
-#define __NR_futex 142 /* gethostid under SunOS */
-#define __NR_gettid 143 /* ENOSYS under SunOS */
-#define __NR_getrlimit 144 /* Common */
-#define __NR_setrlimit 145 /* Common */
-#define __NR_pivot_root 146 /* Linux Specific, killpg under SunOS */
-#define __NR_prctl 147 /* ENOSYS under SunOS */
-#define __NR_pciconfig_read 148 /* ENOSYS under SunOS */
-#define __NR_pciconfig_write 149 /* ENOSYS under SunOS */
-#define __NR_getsockname 150 /* Common */
-#define __NR_inotify_init 151 /* Linux specific */
-#define __NR_inotify_add_watch 152 /* Linux specific */
-#define __NR_poll 153 /* Common */
-#define __NR_getdents64 154 /* Linux specific */
-#ifdef __32bit_syscall_numbers__
-#define __NR_fcntl64 155 /* Linux sparc32 Specific */
-#endif
-#define __NR_inotify_rm_watch 156 /* Linux specific */
-#define __NR_statfs 157 /* Common */
-#define __NR_fstatfs 158 /* Common */
-#define __NR_umount 159 /* Common */
-#define __NR_sched_set_affinity 160 /* Linux specific, async_daemon under SunOS */
-#define __NR_sched_get_affinity 161 /* Linux specific, getfh under SunOS */
-#define __NR_getdomainname 162 /* SunOS Specific */
-#define __NR_setdomainname 163 /* Common */
-#ifndef __32bit_syscall_numbers__
-#define __NR_utrap_install 164 /* SYSV ABI/v9 required */
-#endif
-#define __NR_quotactl 165 /* Common */
-#define __NR_set_tid_address 166 /* Linux specific, exportfs under SunOS */
-#define __NR_mount 167 /* Common */
-#define __NR_ustat 168 /* Common */
-#define __NR_setxattr 169 /* SunOS: semsys */
-#define __NR_lsetxattr 170 /* SunOS: msgsys */
-#define __NR_fsetxattr 171 /* SunOS: shmsys */
-#define __NR_getxattr 172 /* SunOS: auditsys */
-#define __NR_lgetxattr 173 /* SunOS: rfssys */
-#define __NR_getdents 174 /* Common */
-#define __NR_setsid 175 /* Common */
-#define __NR_fchdir 176 /* Common */
-#define __NR_fgetxattr 177 /* SunOS: fchroot */
-#define __NR_listxattr 178 /* SunOS: vpixsys */
-#define __NR_llistxattr 179 /* SunOS: aioread */
-#define __NR_flistxattr 180 /* SunOS: aiowrite */
-#define __NR_removexattr 181 /* SunOS: aiowait */
-#define __NR_lremovexattr 182 /* SunOS: aiocancel */
-#define __NR_sigpending 183 /* Common */
-#define __NR_query_module 184 /* Linux Specific */
-#define __NR_setpgid 185 /* Common */
-#define __NR_fremovexattr 186 /* SunOS: pathconf */
-#define __NR_tkill 187 /* SunOS: fpathconf */
-#define __NR_exit_group 188 /* Linux specific, sysconf undef SunOS */
-#define __NR_uname 189 /* Linux Specific */
-#define __NR_init_module 190 /* Linux Specific */
-#define __NR_personality 191 /* Linux Specific */
-#define __NR_remap_file_pages 192 /* Linux Specific */
-#define __NR_epoll_create 193 /* Linux Specific */
-#define __NR_epoll_ctl 194 /* Linux Specific */
-#define __NR_epoll_wait 195 /* Linux Specific */
-#define __NR_ioprio_set 196 /* Linux Specific */
-#define __NR_getppid 197 /* Linux Specific */
-#define __NR_sigaction 198 /* Linux Specific */
-#define __NR_sgetmask 199 /* Linux Specific */
-#define __NR_ssetmask 200 /* Linux Specific */
-#define __NR_sigsuspend 201 /* Linux Specific */
-#define __NR_oldlstat 202 /* Linux Specific */
-#define __NR_uselib 203 /* Linux Specific */
-#define __NR_readdir 204 /* Linux Specific */
-#define __NR_readahead 205 /* Linux Specific */
-#define __NR_socketcall 206 /* Linux Specific */
-#define __NR_syslog 207 /* Linux Specific */
-#define __NR_lookup_dcookie 208 /* Linux Specific */
-#define __NR_fadvise64 209 /* Linux Specific */
-#define __NR_fadvise64_64 210 /* Linux Specific */
-#define __NR_tgkill 211 /* Linux Specific */
-#define __NR_waitpid 212 /* Linux Specific */
-#define __NR_swapoff 213 /* Linux Specific */
-#define __NR_sysinfo 214 /* Linux Specific */
-#define __NR_ipc 215 /* Linux Specific */
-#define __NR_sigreturn 216 /* Linux Specific */
-#define __NR_clone 217 /* Linux Specific */
-#define __NR_ioprio_get 218 /* Linux Specific */
-#define __NR_adjtimex 219 /* Linux Specific */
-#define __NR_sigprocmask 220 /* Linux Specific */
-#define __NR_create_module 221 /* Linux Specific */
-#define __NR_delete_module 222 /* Linux Specific */
-#define __NR_get_kernel_syms 223 /* Linux Specific */
-#define __NR_getpgid 224 /* Linux Specific */
-#define __NR_bdflush 225 /* Linux Specific */
-#define __NR_sysfs 226 /* Linux Specific */
-#define __NR_afs_syscall 227 /* Linux Specific */
-#define __NR_setfsuid 228 /* Linux Specific */
-#define __NR_setfsgid 229 /* Linux Specific */
-#define __NR__newselect 230 /* Linux Specific */
#ifdef __32bit_syscall_numbers__
-#define __NR_time 231 /* Linux Specific */
#else
-#ifdef __KERNEL__
#define __NR_time 231 /* Linux sparc32 */
#endif
-#endif
-#define __NR_splice 232 /* Linux Specific */
-#define __NR_stime 233 /* Linux Specific */
-#define __NR_statfs64 234 /* Linux Specific */
-#define __NR_fstatfs64 235 /* Linux Specific */
-#define __NR__llseek 236 /* Linux Specific */
-#define __NR_mlock 237
-#define __NR_munlock 238
-#define __NR_mlockall 239
-#define __NR_munlockall 240
-#define __NR_sched_setparam 241
-#define __NR_sched_getparam 242
-#define __NR_sched_setscheduler 243
-#define __NR_sched_getscheduler 244
-#define __NR_sched_yield 245
-#define __NR_sched_get_priority_max 246
-#define __NR_sched_get_priority_min 247
-#define __NR_sched_rr_get_interval 248
-#define __NR_nanosleep 249
-#define __NR_mremap 250
-#define __NR__sysctl 251
-#define __NR_getsid 252
-#define __NR_fdatasync 253
-#define __NR_nfsservctl 254
-#define __NR_sync_file_range 255
-#define __NR_clock_settime 256
-#define __NR_clock_gettime 257
-#define __NR_clock_getres 258
-#define __NR_clock_nanosleep 259
-#define __NR_sched_getaffinity 260
-#define __NR_sched_setaffinity 261
-#define __NR_timer_settime 262
-#define __NR_timer_gettime 263
-#define __NR_timer_getoverrun 264
-#define __NR_timer_delete 265
-#define __NR_timer_create 266
-/* #define __NR_vserver 267 Reserved for VSERVER */
-#define __NR_io_setup 268
-#define __NR_io_destroy 269
-#define __NR_io_submit 270
-#define __NR_io_cancel 271
-#define __NR_io_getevents 272
-#define __NR_mq_open 273
-#define __NR_mq_unlink 274
-#define __NR_mq_timedsend 275
-#define __NR_mq_timedreceive 276
-#define __NR_mq_notify 277
-#define __NR_mq_getsetattr 278
-#define __NR_waitid 279
-#define __NR_tee 280
-#define __NR_add_key 281
-#define __NR_request_key 282
-#define __NR_keyctl 283
-#define __NR_openat 284
-#define __NR_mkdirat 285
-#define __NR_mknodat 286
-#define __NR_fchownat 287
-#define __NR_futimesat 288
-#define __NR_fstatat64 289
-#define __NR_unlinkat 290
-#define __NR_renameat 291
-#define __NR_linkat 292
-#define __NR_symlinkat 293
-#define __NR_readlinkat 294
-#define __NR_fchmodat 295
-#define __NR_faccessat 296
-#define __NR_pselect6 297
-#define __NR_ppoll 298
-#define __NR_unshare 299
-#define __NR_set_robust_list 300
-#define __NR_get_robust_list 301
-#define __NR_migrate_pages 302
-#define __NR_mbind 303
-#define __NR_get_mempolicy 304
-#define __NR_set_mempolicy 305
-#define __NR_kexec_load 306
-#define __NR_move_pages 307
-#define __NR_getcpu 308
-#define __NR_epoll_pwait 309
-#define __NR_utimensat 310
-#define __NR_signalfd 311
-#define __NR_timerfd_create 312
-#define __NR_eventfd 313
-#define __NR_fallocate 314
-#define __NR_timerfd_settime 315
-#define __NR_timerfd_gettime 316
-#define __NR_signalfd4 317
-#define __NR_eventfd2 318
-#define __NR_epoll_create1 319
-#define __NR_dup3 320
-#define __NR_pipe2 321
-#define __NR_inotify_init1 322
-#define __NR_accept4 323
-#define __NR_preadv 324
-#define __NR_pwritev 325
-#define __NR_rt_tgsigqueueinfo 326
-#define __NR_perf_event_open 327
-#define __NR_recvmmsg 328
-#define __NR_fanotify_init 329
-#define __NR_fanotify_mark 330
-#define __NR_prlimit64 331
-#define __NR_name_to_handle_at 332
-#define __NR_open_by_handle_at 333
-#define __NR_clock_adjtime 334
-#define __NR_syncfs 335
-#define __NR_sendmmsg 336
-#define __NR_setns 337
-#define __NR_process_vm_readv 338
-#define __NR_process_vm_writev 339
-
-#define NR_syscalls 340
-
-#ifdef __32bit_syscall_numbers__
-/* Sparc 32-bit only has the "setresuid32", "getresuid32" variants,
- * it never had the plain ones and there is no value to adding those
- * old versions into the syscall table.
- */
-#define __IGNORE_setresuid
-#define __IGNORE_getresuid
-#define __IGNORE_setresgid
-#define __IGNORE_getresgid
-#endif
-
-#ifdef __KERNEL__
#define __ARCH_WANT_OLD_READDIR
#define __ARCH_WANT_STAT64
#define __ARCH_WANT_SYS_ALARM
@@ -458,5 +55,4 @@
*/
#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall")
-#endif /* __KERNEL__ */
#endif /* _SPARC_UNISTD_H */
diff --git a/arch/sparc/include/uapi/asm/Kbuild b/arch/sparc/include/uapi/asm/Kbuild
index 7518ad2..ce175af 100644
--- a/arch/sparc/include/uapi/asm/Kbuild
+++ b/arch/sparc/include/uapi/asm/Kbuild
@@ -3,3 +3,49 @@
include include/uapi/asm-generic/Kbuild.asm
+header-y += apc.h
+header-y += asi.h
+header-y += auxvec.h
+header-y += bitsperlong.h
+header-y += byteorder.h
+header-y += display7seg.h
+header-y += envctrl.h
+header-y += errno.h
+header-y += fbio.h
+header-y += fcntl.h
+header-y += ioctl.h
+header-y += ioctls.h
+header-y += ipcbuf.h
+header-y += jsflash.h
+header-y += kvm_para.h
+header-y += mman.h
+header-y += msgbuf.h
+header-y += openpromio.h
+header-y += param.h
+header-y += perfctr.h
+header-y += poll.h
+header-y += posix_types.h
+header-y += psr.h
+header-y += psrcompat.h
+header-y += pstate.h
+header-y += ptrace.h
+header-y += resource.h
+header-y += sembuf.h
+header-y += setup.h
+header-y += shmbuf.h
+header-y += sigcontext.h
+header-y += siginfo.h
+header-y += signal.h
+header-y += socket.h
+header-y += sockios.h
+header-y += stat.h
+header-y += statfs.h
+header-y += swab.h
+header-y += termbits.h
+header-y += termios.h
+header-y += traps.h
+header-y += types.h
+header-y += uctx.h
+header-y += unistd.h
+header-y += utrap.h
+header-y += watchdog.h
diff --git a/arch/sparc/include/asm/apc.h b/arch/sparc/include/uapi/asm/apc.h
index 24e9a7d..24e9a7d 100644
--- a/arch/sparc/include/asm/apc.h
+++ b/arch/sparc/include/uapi/asm/apc.h
diff --git a/arch/sparc/include/asm/asi.h b/arch/sparc/include/uapi/asm/asi.h
index aace6f3..aace6f3 100644
--- a/arch/sparc/include/asm/asi.h
+++ b/arch/sparc/include/uapi/asm/asi.h
diff --git a/arch/sparc/include/asm/auxvec.h b/arch/sparc/include/uapi/asm/auxvec.h
index ad6f360..ad6f360 100644
--- a/arch/sparc/include/asm/auxvec.h
+++ b/arch/sparc/include/uapi/asm/auxvec.h
diff --git a/arch/sparc/include/asm/bitsperlong.h b/arch/sparc/include/uapi/asm/bitsperlong.h
index 40dcaa3..40dcaa3 100644
--- a/arch/sparc/include/asm/bitsperlong.h
+++ b/arch/sparc/include/uapi/asm/bitsperlong.h
diff --git a/arch/sparc/include/asm/byteorder.h b/arch/sparc/include/uapi/asm/byteorder.h
index ccc1b6b..ccc1b6b 100644
--- a/arch/sparc/include/asm/byteorder.h
+++ b/arch/sparc/include/uapi/asm/byteorder.h
diff --git a/arch/sparc/include/asm/display7seg.h b/arch/sparc/include/uapi/asm/display7seg.h
index 86d4a90..86d4a90 100644
--- a/arch/sparc/include/asm/display7seg.h
+++ b/arch/sparc/include/uapi/asm/display7seg.h
diff --git a/arch/sparc/include/asm/envctrl.h b/arch/sparc/include/uapi/asm/envctrl.h
index 624fa7e..624fa7e 100644
--- a/arch/sparc/include/asm/envctrl.h
+++ b/arch/sparc/include/uapi/asm/envctrl.h
diff --git a/arch/sparc/include/asm/errno.h b/arch/sparc/include/uapi/asm/errno.h
index c351aba..c351aba 100644
--- a/arch/sparc/include/asm/errno.h
+++ b/arch/sparc/include/uapi/asm/errno.h
diff --git a/arch/sparc/include/uapi/asm/fbio.h b/arch/sparc/include/uapi/asm/fbio.h
new file mode 100644
index 0000000..d6cea07
--- /dev/null
+++ b/arch/sparc/include/uapi/asm/fbio.h
@@ -0,0 +1,259 @@
+#ifndef _UAPI__LINUX_FBIO_H
+#define _UAPI__LINUX_FBIO_H
+
+#include <linux/compiler.h>
+#include <linux/types.h>
+
+/* Constants used for fbio SunOS compatibility */
+/* (C) 1996 Miguel de Icaza */
+
+/* Frame buffer types */
+#define FBTYPE_NOTYPE -1
+#define FBTYPE_SUN1BW 0 /* mono */
+#define FBTYPE_SUN1COLOR 1
+#define FBTYPE_SUN2BW 2
+#define FBTYPE_SUN2COLOR 3
+#define FBTYPE_SUN2GP 4
+#define FBTYPE_SUN5COLOR 5
+#define FBTYPE_SUN3COLOR 6
+#define FBTYPE_MEMCOLOR 7
+#define FBTYPE_SUN4COLOR 8
+
+#define FBTYPE_NOTSUN1 9
+#define FBTYPE_NOTSUN2 10
+#define FBTYPE_NOTSUN3 11
+
+#define FBTYPE_SUNFAST_COLOR 12 /* cg6 */
+#define FBTYPE_SUNROP_COLOR 13
+#define FBTYPE_SUNFB_VIDEO 14
+#define FBTYPE_SUNGIFB 15
+#define FBTYPE_SUNGPLAS 16
+#define FBTYPE_SUNGP3 17
+#define FBTYPE_SUNGT 18
+#define FBTYPE_SUNLEO 19 /* zx Leo card */
+#define FBTYPE_MDICOLOR 20 /* cg14 */
+#define FBTYPE_TCXCOLOR 21 /* SUNW,tcx card */
+
+#define FBTYPE_LASTPLUSONE 21 /* This is not last + 1 in fact... */
+
+/* Does not seem to be listed in the Sun file either */
+#define FBTYPE_CREATOR 22
+#define FBTYPE_PCI_IGA1682 23
+#define FBTYPE_P9100COLOR 24
+
+#define FBTYPE_PCI_GENERIC 1000
+#define FBTYPE_PCI_MACH64 1001
+
+/* fbio ioctls */
+/* Returned by FBIOGTYPE */
+struct fbtype {
+ int fb_type; /* fb type, see above */
+ int fb_height; /* pixels */
+ int fb_width; /* pixels */
+ int fb_depth;
+ int fb_cmsize; /* color map entries */
+ int fb_size; /* fb size in bytes */
+};
+#define FBIOGTYPE _IOR('F', 0, struct fbtype)
+
+struct fbcmap {
+ int index; /* first element (0 origin) */
+ int count;
+ unsigned char __user *red;
+ unsigned char __user *green;
+ unsigned char __user *blue;
+};
+
+#ifndef __KERNEL__
+#define FBIOPUTCMAP _IOW('F', 3, struct fbcmap)
+#define FBIOGETCMAP _IOW('F', 4, struct fbcmap)
+#endif
+
+/* # of device specific values */
+#define FB_ATTR_NDEVSPECIFIC 8
+/* # of possible emulations */
+#define FB_ATTR_NEMUTYPES 4
+
+struct fbsattr {
+ int flags;
+ int emu_type; /* -1 if none */
+ int dev_specific[FB_ATTR_NDEVSPECIFIC];
+};
+
+struct fbgattr {
+ int real_type; /* real frame buffer type */
+ int owner; /* unknown */
+ struct fbtype fbtype; /* real frame buffer fbtype */
+ struct fbsattr sattr;
+ int emu_types[FB_ATTR_NEMUTYPES]; /* supported emulations */
+};
+#define FBIOSATTR _IOW('F', 5, struct fbgattr) /* Unsupported: */
+#define FBIOGATTR _IOR('F', 6, struct fbgattr) /* supported */
+
+#define FBIOSVIDEO _IOW('F', 7, int)
+#define FBIOGVIDEO _IOR('F', 8, int)
+
+struct fbcursor {
+ short set; /* what to set, choose from the list above */
+ short enable; /* cursor on/off */
+ struct fbcurpos pos; /* cursor position */
+ struct fbcurpos hot; /* cursor hot spot */
+ struct fbcmap cmap; /* color map info */
+ struct fbcurpos size; /* cursor bit map size */
+ char __user *image; /* cursor image bits */
+ char __user *mask; /* cursor mask bits */
+};
+
+/* set/get cursor attributes/shape */
+#define FBIOSCURSOR _IOW('F', 24, struct fbcursor)
+#define FBIOGCURSOR _IOWR('F', 25, struct fbcursor)
+
+/* set/get cursor position */
+#define FBIOSCURPOS _IOW('F', 26, struct fbcurpos)
+#define FBIOGCURPOS _IOW('F', 27, struct fbcurpos)
+
+/* get max cursor size */
+#define FBIOGCURMAX _IOR('F', 28, struct fbcurpos)
+
+/* wid manipulation */
+struct fb_wid_alloc {
+#define FB_WID_SHARED_8 0
+#define FB_WID_SHARED_24 1
+#define FB_WID_DBL_8 2
+#define FB_WID_DBL_24 3
+ __u32 wa_type;
+ __s32 wa_index; /* Set on return */
+ __u32 wa_count;
+};
+struct fb_wid_item {
+ __u32 wi_type;
+ __s32 wi_index;
+ __u32 wi_attrs;
+ __u32 wi_values[32];
+};
+struct fb_wid_list {
+ __u32 wl_flags;
+ __u32 wl_count;
+ struct fb_wid_item *wl_list;
+};
+
+#define FBIO_WID_ALLOC _IOWR('F', 30, struct fb_wid_alloc)
+#define FBIO_WID_FREE _IOW('F', 31, struct fb_wid_alloc)
+#define FBIO_WID_PUT _IOW('F', 32, struct fb_wid_list)
+#define FBIO_WID_GET _IOWR('F', 33, struct fb_wid_list)
+
+/* Creator ioctls */
+#define FFB_IOCTL ('F'<<8)
+#define FFB_SYS_INFO (FFB_IOCTL|80)
+#define FFB_CLUTREAD (FFB_IOCTL|81)
+#define FFB_CLUTPOST (FFB_IOCTL|82)
+#define FFB_SETDIAGMODE (FFB_IOCTL|83)
+#define FFB_GETMONITORID (FFB_IOCTL|84)
+#define FFB_GETVIDEOMODE (FFB_IOCTL|85)
+#define FFB_SETVIDEOMODE (FFB_IOCTL|86)
+#define FFB_SETSERVER (FFB_IOCTL|87)
+#define FFB_SETOVCTL (FFB_IOCTL|88)
+#define FFB_GETOVCTL (FFB_IOCTL|89)
+#define FFB_GETSAXNUM (FFB_IOCTL|90)
+#define FFB_FBDEBUG (FFB_IOCTL|91)
+
+/* Cg14 ioctls */
+#define MDI_IOCTL ('M'<<8)
+#define MDI_RESET (MDI_IOCTL|1)
+#define MDI_GET_CFGINFO (MDI_IOCTL|2)
+#define MDI_SET_PIXELMODE (MDI_IOCTL|3)
+# define MDI_32_PIX 32
+# define MDI_16_PIX 16
+# define MDI_8_PIX 8
+
+struct mdi_cfginfo {
+ int mdi_ncluts; /* Number of implemented CLUTs in this MDI */
+ int mdi_type; /* FBTYPE name */
+ int mdi_height; /* height */
+ int mdi_width; /* width */
+ int mdi_size; /* available ram */
+ int mdi_mode; /* 8bpp, 16bpp or 32bpp */
+ int mdi_pixfreq; /* pixel clock (from PROM) */
+};
+
+/* SparcLinux specific ioctl for the MDI, should be replaced for
+ * the SET_XLUT/SET_CLUTn ioctls instead
+ */
+#define MDI_CLEAR_XLUT (MDI_IOCTL|9)
+
+/* leo & ffb ioctls */
+struct fb_clut_alloc {
+ __u32 clutid; /* Set on return */
+ __u32 flag;
+ __u32 index;
+};
+
+struct fb_clut {
+#define FB_CLUT_WAIT 0x00000001 /* Not yet implemented */
+ __u32 flag;
+ __u32 clutid;
+ __u32 offset;
+ __u32 count;
+ char * red;
+ char * green;
+ char * blue;
+};
+
+struct fb_clut32 {
+ __u32 flag;
+ __u32 clutid;
+ __u32 offset;
+ __u32 count;
+ __u32 red;
+ __u32 green;
+ __u32 blue;
+};
+
+#define LEO_CLUTALLOC _IOWR('L', 53, struct fb_clut_alloc)
+#define LEO_CLUTFREE _IOW('L', 54, struct fb_clut_alloc)
+#define LEO_CLUTREAD _IOW('L', 55, struct fb_clut)
+#define LEO_CLUTPOST _IOW('L', 56, struct fb_clut)
+#define LEO_SETGAMMA _IOW('L', 68, int) /* Not yet implemented */
+#define LEO_GETGAMMA _IOR('L', 69, int) /* Not yet implemented */
+
+
+/* These are exported to userland for applications to use */
+/* Mappable offsets for the cg14: control registers */
+#define MDI_DIRECT_MAP 0x10000000
+#define MDI_CTLREG_MAP 0x20000000
+#define MDI_CURSOR_MAP 0x30000000
+#define MDI_SHDW_VRT_MAP 0x40000000
+
+/* Mappable offsets for the cg14: frame buffer resolutions */
+/* 32 bits */
+#define MDI_CHUNKY_XBGR_MAP 0x50000000
+#define MDI_CHUNKY_BGR_MAP 0x60000000
+
+/* 16 bits */
+#define MDI_PLANAR_X16_MAP 0x70000000
+#define MDI_PLANAR_C16_MAP 0x80000000
+
+/* 8 bit is done as CG3 MMAP offset */
+/* 32 bits, planar */
+#define MDI_PLANAR_X32_MAP 0x90000000
+#define MDI_PLANAR_B32_MAP 0xa0000000
+#define MDI_PLANAR_G32_MAP 0xb0000000
+#define MDI_PLANAR_R32_MAP 0xc0000000
+
+/* Mappable offsets on leo */
+#define LEO_SS0_MAP 0x00000000
+#define LEO_LC_SS0_USR_MAP 0x00800000
+#define LEO_LD_SS0_MAP 0x00801000
+#define LEO_LX_CURSOR_MAP 0x00802000
+#define LEO_SS1_MAP 0x00803000
+#define LEO_LC_SS1_USR_MAP 0x01003000
+#define LEO_LD_SS1_MAP 0x01004000
+#define LEO_UNK_MAP 0x01005000
+#define LEO_LX_KRN_MAP 0x01006000
+#define LEO_LC_SS0_KRN_MAP 0x01007000
+#define LEO_LC_SS1_KRN_MAP 0x01008000
+#define LEO_LD_GBL_MAP 0x01009000
+#define LEO_UNK2_MAP 0x0100a000
+
+
+#endif /* _UAPI__LINUX_FBIO_H */
diff --git a/arch/sparc/include/asm/fcntl.h b/arch/sparc/include/uapi/asm/fcntl.h
index d0b83f6..d0b83f6 100644
--- a/arch/sparc/include/asm/fcntl.h
+++ b/arch/sparc/include/uapi/asm/fcntl.h
diff --git a/arch/sparc/include/asm/ioctl.h b/arch/sparc/include/uapi/asm/ioctl.h
index 7d6bd51..7d6bd51 100644
--- a/arch/sparc/include/asm/ioctl.h
+++ b/arch/sparc/include/uapi/asm/ioctl.h
diff --git a/arch/sparc/include/uapi/asm/ioctls.h b/arch/sparc/include/uapi/asm/ioctls.h
new file mode 100644
index 0000000..9155f70
--- /dev/null
+++ b/arch/sparc/include/uapi/asm/ioctls.h
@@ -0,0 +1,131 @@
+#ifndef _UAPI_ASM_SPARC_IOCTLS_H
+#define _UAPI_ASM_SPARC_IOCTLS_H
+
+#include <asm/ioctl.h>
+
+/* Big T */
+#define TCGETA _IOR('T', 1, struct termio)
+#define TCSETA _IOW('T', 2, struct termio)
+#define TCSETAW _IOW('T', 3, struct termio)
+#define TCSETAF _IOW('T', 4, struct termio)
+#define TCSBRK _IO('T', 5)
+#define TCXONC _IO('T', 6)
+#define TCFLSH _IO('T', 7)
+#define TCGETS _IOR('T', 8, struct termios)
+#define TCSETS _IOW('T', 9, struct termios)
+#define TCSETSW _IOW('T', 10, struct termios)
+#define TCSETSF _IOW('T', 11, struct termios)
+#define TCGETS2 _IOR('T', 12, struct termios2)
+#define TCSETS2 _IOW('T', 13, struct termios2)
+#define TCSETSW2 _IOW('T', 14, struct termios2)
+#define TCSETSF2 _IOW('T', 15, struct termios2)
+#define TIOCGDEV _IOR('T',0x32, unsigned int) /* Get primary device node of /dev/console */
+#define TIOCVHANGUP _IO('T', 0x37)
+
+/* Note that all the ioctls that are not available in Linux have a
+ * double underscore on the front to: a) avoid some programs to
+ * think we support some ioctls under Linux (autoconfiguration stuff)
+ */
+/* Little t */
+#define TIOCGETD _IOR('t', 0, int)
+#define TIOCSETD _IOW('t', 1, int)
+#define __TIOCHPCL _IO('t', 2) /* SunOS Specific */
+#define __TIOCMODG _IOR('t', 3, int) /* SunOS Specific */
+#define __TIOCMODS _IOW('t', 4, int) /* SunOS Specific */
+#define __TIOCGETP _IOR('t', 8, struct sgttyb) /* SunOS Specific */
+#define __TIOCSETP _IOW('t', 9, struct sgttyb) /* SunOS Specific */
+#define __TIOCSETN _IOW('t', 10, struct sgttyb) /* SunOS Specific */
+#define TIOCEXCL _IO('t', 13)
+#define TIOCNXCL _IO('t', 14)
+#define __TIOCFLUSH _IOW('t', 16, int) /* SunOS Specific */
+#define __TIOCSETC _IOW('t', 17, struct tchars) /* SunOS Specific */
+#define __TIOCGETC _IOR('t', 18, struct tchars) /* SunOS Specific */
+#define __TIOCTCNTL _IOW('t', 32, int) /* SunOS Specific */
+#define __TIOCSIGNAL _IOW('t', 33, int) /* SunOS Specific */
+#define __TIOCSETX _IOW('t', 34, int) /* SunOS Specific */
+#define __TIOCGETX _IOR('t', 35, int) /* SunOS Specific */
+#define TIOCCONS _IO('t', 36)
+#define TIOCGSOFTCAR _IOR('t', 100, int)
+#define TIOCSSOFTCAR _IOW('t', 101, int)
+#define __TIOCUCNTL _IOW('t', 102, int) /* SunOS Specific */
+#define TIOCSWINSZ _IOW('t', 103, struct winsize)
+#define TIOCGWINSZ _IOR('t', 104, struct winsize)
+#define __TIOCREMOTE _IOW('t', 105, int) /* SunOS Specific */
+#define TIOCMGET _IOR('t', 106, int)
+#define TIOCMBIC _IOW('t', 107, int)
+#define TIOCMBIS _IOW('t', 108, int)
+#define TIOCMSET _IOW('t', 109, int)
+#define TIOCSTART _IO('t', 110)
+#define TIOCSTOP _IO('t', 111)
+#define TIOCPKT _IOW('t', 112, int)
+#define TIOCNOTTY _IO('t', 113)
+#define TIOCSTI _IOW('t', 114, char)
+#define TIOCOUTQ _IOR('t', 115, int)
+#define __TIOCGLTC _IOR('t', 116, struct ltchars) /* SunOS Specific */
+#define __TIOCSLTC _IOW('t', 117, struct ltchars) /* SunOS Specific */
+/* 118 is the non-posix setpgrp tty ioctl */
+/* 119 is the non-posix getpgrp tty ioctl */
+#define __TIOCCDTR _IO('t', 120) /* SunOS Specific */
+#define __TIOCSDTR _IO('t', 121) /* SunOS Specific */
+#define TIOCCBRK _IO('t', 122)
+#define TIOCSBRK _IO('t', 123)
+#define __TIOCLGET _IOW('t', 124, int) /* SunOS Specific */
+#define __TIOCLSET _IOW('t', 125, int) /* SunOS Specific */
+#define __TIOCLBIC _IOW('t', 126, int) /* SunOS Specific */
+#define __TIOCLBIS _IOW('t', 127, int) /* SunOS Specific */
+#define __TIOCISPACE _IOR('t', 128, int) /* SunOS Specific */
+#define __TIOCISIZE _IOR('t', 129, int) /* SunOS Specific */
+#define TIOCSPGRP _IOW('t', 130, int)
+#define TIOCGPGRP _IOR('t', 131, int)
+#define TIOCSCTTY _IO('t', 132)
+#define TIOCGSID _IOR('t', 133, int)
+/* Get minor device of a pty master's FD -- Solaris equiv is ISPTM */
+#define TIOCGPTN _IOR('t', 134, unsigned int) /* Get Pty Number */
+#define TIOCSPTLCK _IOW('t', 135, int) /* Lock/unlock PTY */
+#define TIOCSIG _IOW('t', 136, int) /* Generate signal on Pty slave */
+
+/* Little f */
+#define FIOCLEX _IO('f', 1)
+#define FIONCLEX _IO('f', 2)
+#define FIOASYNC _IOW('f', 125, int)
+#define FIONBIO _IOW('f', 126, int)
+#define FIONREAD _IOR('f', 127, int)
+#define TIOCINQ FIONREAD
+#define FIOQSIZE _IOR('f', 128, loff_t)
+
+/* SCARY Rutgers local SunOS kernel hackery, perhaps I will support it
+ * someday. This is completely bogus, I know...
+ */
+#define __TCGETSTAT _IO('T', 200) /* Rutgers specific */
+#define __TCSETSTAT _IO('T', 201) /* Rutgers specific */
+
+/* Linux specific, no SunOS equivalent. */
+#define TIOCLINUX 0x541C
+#define TIOCGSERIAL 0x541E
+#define TIOCSSERIAL 0x541F
+#define TCSBRKP 0x5425
+#define TIOCSERCONFIG 0x5453
+#define TIOCSERGWILD 0x5454
+#define TIOCSERSWILD 0x5455
+#define TIOCGLCKTRMIOS 0x5456
+#define TIOCSLCKTRMIOS 0x5457
+#define TIOCSERGSTRUCT 0x5458 /* For debugging only */
+#define TIOCSERGETLSR 0x5459 /* Get line status register */
+#define TIOCSERGETMULTI 0x545A /* Get multiport config */
+#define TIOCSERSETMULTI 0x545B /* Set multiport config */
+#define TIOCMIWAIT 0x545C /* Wait for change on serial input line(s) */
+#define TIOCGICOUNT 0x545D /* Read serial port inline interrupt counts */
+
+/* Kernel definitions */
+
+/* Used for packet mode */
+#define TIOCPKT_DATA 0
+#define TIOCPKT_FLUSHREAD 1
+#define TIOCPKT_FLUSHWRITE 2
+#define TIOCPKT_STOP 4
+#define TIOCPKT_START 8
+#define TIOCPKT_NOSTOP 16
+#define TIOCPKT_DOSTOP 32
+#define TIOCPKT_IOCTL 64
+
+#endif /* _UAPI_ASM_SPARC_IOCTLS_H */
diff --git a/arch/sparc/include/asm/ipcbuf.h b/arch/sparc/include/uapi/asm/ipcbuf.h
index 66013b4..66013b4 100644
--- a/arch/sparc/include/asm/ipcbuf.h
+++ b/arch/sparc/include/uapi/asm/ipcbuf.h
diff --git a/arch/sparc/include/asm/jsflash.h b/arch/sparc/include/uapi/asm/jsflash.h
index 0717d9e..0717d9e 100644
--- a/arch/sparc/include/asm/jsflash.h
+++ b/arch/sparc/include/uapi/asm/jsflash.h
diff --git a/arch/sparc/include/asm/kvm_para.h b/arch/sparc/include/uapi/asm/kvm_para.h
index 14fab8f..14fab8f 100644
--- a/arch/sparc/include/asm/kvm_para.h
+++ b/arch/sparc/include/uapi/asm/kvm_para.h
diff --git a/arch/sparc/include/uapi/asm/mman.h b/arch/sparc/include/uapi/asm/mman.h
new file mode 100644
index 0000000..0b14df3
--- /dev/null
+++ b/arch/sparc/include/uapi/asm/mman.h
@@ -0,0 +1,27 @@
+#ifndef _UAPI__SPARC_MMAN_H__
+#define _UAPI__SPARC_MMAN_H__
+
+#include <asm-generic/mman-common.h>
+
+/* SunOS'ified... */
+
+#define MAP_RENAME MAP_ANONYMOUS /* In SunOS terminology */
+#define MAP_NORESERVE 0x40 /* don't reserve swap pages */
+#define MAP_INHERIT 0x80 /* SunOS doesn't do this, but... */
+#define MAP_LOCKED 0x100 /* lock the mapping */
+#define _MAP_NEW 0x80000000 /* Binary compatibility is fun... */
+
+#define MAP_GROWSDOWN 0x0200 /* stack-like segment */
+#define MAP_DENYWRITE 0x0800 /* ETXTBSY */
+#define MAP_EXECUTABLE 0x1000 /* mark it as an executable */
+
+#define MCL_CURRENT 0x2000 /* lock all currently mapped pages */
+#define MCL_FUTURE 0x4000 /* lock all additions to address space */
+
+#define MAP_POPULATE 0x8000 /* populate (prefault) pagetables */
+#define MAP_NONBLOCK 0x10000 /* do not block on IO */
+#define MAP_STACK 0x20000 /* give out an address that is best suited for process/thread stacks */
+#define MAP_HUGETLB 0x40000 /* create a huge page mapping */
+
+
+#endif /* _UAPI__SPARC_MMAN_H__ */
diff --git a/arch/sparc/include/asm/msgbuf.h b/arch/sparc/include/uapi/asm/msgbuf.h
index efc7cbe9..efc7cbe9 100644
--- a/arch/sparc/include/asm/msgbuf.h
+++ b/arch/sparc/include/uapi/asm/msgbuf.h
diff --git a/arch/sparc/include/asm/openpromio.h b/arch/sparc/include/uapi/asm/openpromio.h
index 917fb8e..917fb8e 100644
--- a/arch/sparc/include/asm/openpromio.h
+++ b/arch/sparc/include/uapi/asm/openpromio.h
diff --git a/arch/sparc/include/asm/param.h b/arch/sparc/include/uapi/asm/param.h
index 0bc356b..0bc356b 100644
--- a/arch/sparc/include/asm/param.h
+++ b/arch/sparc/include/uapi/asm/param.h
diff --git a/arch/sparc/include/asm/perfctr.h b/arch/sparc/include/uapi/asm/perfctr.h
index 214feef..214feef 100644
--- a/arch/sparc/include/asm/perfctr.h
+++ b/arch/sparc/include/uapi/asm/perfctr.h
diff --git a/arch/sparc/include/asm/poll.h b/arch/sparc/include/uapi/asm/poll.h
index 091d3ad..091d3ad 100644
--- a/arch/sparc/include/asm/poll.h
+++ b/arch/sparc/include/uapi/asm/poll.h
diff --git a/arch/sparc/include/asm/posix_types.h b/arch/sparc/include/uapi/asm/posix_types.h
index 156220e..156220e 100644
--- a/arch/sparc/include/asm/posix_types.h
+++ b/arch/sparc/include/uapi/asm/posix_types.h
diff --git a/arch/sparc/include/uapi/asm/psr.h b/arch/sparc/include/uapi/asm/psr.h
new file mode 100644
index 0000000..2f0ed85
--- /dev/null
+++ b/arch/sparc/include/uapi/asm/psr.h
@@ -0,0 +1,47 @@
+/*
+ * psr.h: This file holds the macros for masking off various parts of
+ * the processor status register on the Sparc. This is valid
+ * for Version 8. On the V9 this is renamed to the PSTATE
+ * register and its members are accessed as fields like
+ * PSTATE.PRIV for the current CPU privilege level.
+ *
+ * Copyright (C) 1994 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#ifndef _UAPI__LINUX_SPARC_PSR_H
+#define _UAPI__LINUX_SPARC_PSR_H
+
+/* The Sparc PSR fields are laid out as the following:
+ *
+ * ------------------------------------------------------------------------
+ * | impl | vers | icc | resv | EC | EF | PIL | S | PS | ET | CWP |
+ * | 31-28 | 27-24 | 23-20 | 19-14 | 13 | 12 | 11-8 | 7 | 6 | 5 | 4-0 |
+ * ------------------------------------------------------------------------
+ */
+#define PSR_CWP 0x0000001f /* current window pointer */
+#define PSR_ET 0x00000020 /* enable traps field */
+#define PSR_PS 0x00000040 /* previous privilege level */
+#define PSR_S 0x00000080 /* current privilege level */
+#define PSR_PIL 0x00000f00 /* processor interrupt level */
+#define PSR_EF 0x00001000 /* enable floating point */
+#define PSR_EC 0x00002000 /* enable co-processor */
+#define PSR_SYSCALL 0x00004000 /* inside of a syscall */
+#define PSR_LE 0x00008000 /* SuperSparcII little-endian */
+#define PSR_ICC 0x00f00000 /* integer condition codes */
+#define PSR_C 0x00100000 /* carry bit */
+#define PSR_V 0x00200000 /* overflow bit */
+#define PSR_Z 0x00400000 /* zero bit */
+#define PSR_N 0x00800000 /* negative bit */
+#define PSR_VERS 0x0f000000 /* cpu-version field */
+#define PSR_IMPL 0xf0000000 /* cpu-implementation field */
+
+#define PSR_VERS_SHIFT 24
+#define PSR_IMPL_SHIFT 28
+#define PSR_VERS_SHIFTED_MASK 0xf
+#define PSR_IMPL_SHIFTED_MASK 0xf
+
+#define PSR_IMPL_TI 0x4
+#define PSR_IMPL_LEON 0xf
+
+
+#endif /* _UAPI__LINUX_SPARC_PSR_H */
diff --git a/arch/sparc/include/asm/psrcompat.h b/arch/sparc/include/uapi/asm/psrcompat.h
index 44b6327..44b6327 100644
--- a/arch/sparc/include/asm/psrcompat.h
+++ b/arch/sparc/include/uapi/asm/psrcompat.h
diff --git a/arch/sparc/include/asm/pstate.h b/arch/sparc/include/uapi/asm/pstate.h
index 4b6b998..4b6b998 100644
--- a/arch/sparc/include/asm/pstate.h
+++ b/arch/sparc/include/uapi/asm/pstate.h
diff --git a/arch/sparc/include/uapi/asm/ptrace.h b/arch/sparc/include/uapi/asm/ptrace.h
new file mode 100644
index 0000000..56fe4ea
--- /dev/null
+++ b/arch/sparc/include/uapi/asm/ptrace.h
@@ -0,0 +1,352 @@
+#ifndef _UAPI__SPARC_PTRACE_H
+#define _UAPI__SPARC_PTRACE_H
+
+#if defined(__sparc__) && defined(__arch64__)
+/* 64 bit sparc */
+#include <asm/pstate.h>
+
+/* This struct defines the way the registers are stored on the
+ * stack during a system call and basically all traps.
+ */
+
+/* This magic value must have the low 9 bits clear,
+ * as that is where we encode the %tt value, see below.
+ */
+#define PT_REGS_MAGIC 0x57ac6c00
+
+#ifndef __ASSEMBLY__
+
+#include <linux/types.h>
+
+struct pt_regs {
+ unsigned long u_regs[16]; /* globals and ins */
+ unsigned long tstate;
+ unsigned long tpc;
+ unsigned long tnpc;
+ unsigned int y;
+
+ /* We encode a magic number, PT_REGS_MAGIC, along
+ * with the %tt (trap type) register value at trap
+ * entry time. The magic number allows us to identify
+ * accurately a trap stack frame in the stack
+ * unwinder, and the %tt value allows us to test
+ * things like "in a system call" etc. for an arbitray
+ * process.
+ *
+ * The PT_REGS_MAGIC is chosen such that it can be
+ * loaded completely using just a sethi instruction.
+ */
+ unsigned int magic;
+};
+
+struct pt_regs32 {
+ unsigned int psr;
+ unsigned int pc;
+ unsigned int npc;
+ unsigned int y;
+ unsigned int u_regs[16]; /* globals and ins */
+};
+
+/* A V9 register window */
+struct reg_window {
+ unsigned long locals[8];
+ unsigned long ins[8];
+};
+
+/* A 32-bit register window. */
+struct reg_window32 {
+ unsigned int locals[8];
+ unsigned int ins[8];
+};
+
+/* A V9 Sparc stack frame */
+struct sparc_stackf {
+ unsigned long locals[8];
+ unsigned long ins[6];
+ struct sparc_stackf *fp;
+ unsigned long callers_pc;
+ char *structptr;
+ unsigned long xargs[6];
+ unsigned long xxargs[1];
+};
+
+/* A 32-bit Sparc stack frame */
+struct sparc_stackf32 {
+ unsigned int locals[8];
+ unsigned int ins[6];
+ unsigned int fp;
+ unsigned int callers_pc;
+ unsigned int structptr;
+ unsigned int xargs[6];
+ unsigned int xxargs[1];
+};
+
+struct sparc_trapf {
+ unsigned long locals[8];
+ unsigned long ins[8];
+ unsigned long _unused;
+ struct pt_regs *regs;
+};
+#endif /* (!__ASSEMBLY__) */
+#else
+/* 32 bit sparc */
+
+#include <asm/psr.h>
+
+/* This struct defines the way the registers are stored on the
+ * stack during a system call and basically all traps.
+ */
+#ifndef __ASSEMBLY__
+
+#include <linux/types.h>
+
+struct pt_regs {
+ unsigned long psr;
+ unsigned long pc;
+ unsigned long npc;
+ unsigned long y;
+ unsigned long u_regs[16]; /* globals and ins */
+};
+
+/* A 32-bit register window. */
+struct reg_window32 {
+ unsigned long locals[8];
+ unsigned long ins[8];
+};
+
+/* A Sparc stack frame */
+struct sparc_stackf {
+ unsigned long locals[8];
+ unsigned long ins[6];
+ struct sparc_stackf *fp;
+ unsigned long callers_pc;
+ char *structptr;
+ unsigned long xargs[6];
+ unsigned long xxargs[1];
+};
+#endif /* (!__ASSEMBLY__) */
+
+#endif /* (defined(__sparc__) && defined(__arch64__))*/
+
+#ifndef __ASSEMBLY__
+
+#define TRACEREG_SZ sizeof(struct pt_regs)
+#define STACKFRAME_SZ sizeof(struct sparc_stackf)
+
+#define TRACEREG32_SZ sizeof(struct pt_regs32)
+#define STACKFRAME32_SZ sizeof(struct sparc_stackf32)
+
+#endif /* (!__ASSEMBLY__) */
+
+#define UREG_G0 0
+#define UREG_G1 1
+#define UREG_G2 2
+#define UREG_G3 3
+#define UREG_G4 4
+#define UREG_G5 5
+#define UREG_G6 6
+#define UREG_G7 7
+#define UREG_I0 8
+#define UREG_I1 9
+#define UREG_I2 10
+#define UREG_I3 11
+#define UREG_I4 12
+#define UREG_I5 13
+#define UREG_I6 14
+#define UREG_I7 15
+#define UREG_FP UREG_I6
+#define UREG_RETPC UREG_I7
+
+#if defined(__sparc__) && defined(__arch64__)
+/* 64 bit sparc */
+
+#ifndef __ASSEMBLY__
+
+
+#else /* __ASSEMBLY__ */
+/* For assembly code. */
+#define TRACEREG_SZ 0xa0
+#define STACKFRAME_SZ 0xc0
+
+#define TRACEREG32_SZ 0x50
+#define STACKFRAME32_SZ 0x60
+#endif /* __ASSEMBLY__ */
+
+#else /* (defined(__sparc__) && defined(__arch64__)) */
+
+/* 32 bit sparc */
+
+#ifndef __ASSEMBLY__
+
+
+#else /* (!__ASSEMBLY__) */
+/* For assembly code. */
+#define TRACEREG_SZ 0x50
+#define STACKFRAME_SZ 0x60
+#endif /* (!__ASSEMBLY__) */
+
+#endif /* (defined(__sparc__) && defined(__arch64__)) */
+
+
+/* These are for pt_regs. */
+#define PT_V9_G0 0x00
+#define PT_V9_G1 0x08
+#define PT_V9_G2 0x10
+#define PT_V9_G3 0x18
+#define PT_V9_G4 0x20
+#define PT_V9_G5 0x28
+#define PT_V9_G6 0x30
+#define PT_V9_G7 0x38
+#define PT_V9_I0 0x40
+#define PT_V9_I1 0x48
+#define PT_V9_I2 0x50
+#define PT_V9_I3 0x58
+#define PT_V9_I4 0x60
+#define PT_V9_I5 0x68
+#define PT_V9_I6 0x70
+#define PT_V9_FP PT_V9_I6
+#define PT_V9_I7 0x78
+#define PT_V9_TSTATE 0x80
+#define PT_V9_TPC 0x88
+#define PT_V9_TNPC 0x90
+#define PT_V9_Y 0x98
+#define PT_V9_MAGIC 0x9c
+#define PT_TSTATE PT_V9_TSTATE
+#define PT_TPC PT_V9_TPC
+#define PT_TNPC PT_V9_TNPC
+
+/* These for pt_regs32. */
+#define PT_PSR 0x0
+#define PT_PC 0x4
+#define PT_NPC 0x8
+#define PT_Y 0xc
+#define PT_G0 0x10
+#define PT_WIM PT_G0
+#define PT_G1 0x14
+#define PT_G2 0x18
+#define PT_G3 0x1c
+#define PT_G4 0x20
+#define PT_G5 0x24
+#define PT_G6 0x28
+#define PT_G7 0x2c
+#define PT_I0 0x30
+#define PT_I1 0x34
+#define PT_I2 0x38
+#define PT_I3 0x3c
+#define PT_I4 0x40
+#define PT_I5 0x44
+#define PT_I6 0x48
+#define PT_FP PT_I6
+#define PT_I7 0x4c
+
+/* Reg_window offsets */
+#define RW_V9_L0 0x00
+#define RW_V9_L1 0x08
+#define RW_V9_L2 0x10
+#define RW_V9_L3 0x18
+#define RW_V9_L4 0x20
+#define RW_V9_L5 0x28
+#define RW_V9_L6 0x30
+#define RW_V9_L7 0x38
+#define RW_V9_I0 0x40
+#define RW_V9_I1 0x48
+#define RW_V9_I2 0x50
+#define RW_V9_I3 0x58
+#define RW_V9_I4 0x60
+#define RW_V9_I5 0x68
+#define RW_V9_I6 0x70
+#define RW_V9_I7 0x78
+
+#define RW_L0 0x00
+#define RW_L1 0x04
+#define RW_L2 0x08
+#define RW_L3 0x0c
+#define RW_L4 0x10
+#define RW_L5 0x14
+#define RW_L6 0x18
+#define RW_L7 0x1c
+#define RW_I0 0x20
+#define RW_I1 0x24
+#define RW_I2 0x28
+#define RW_I3 0x2c
+#define RW_I4 0x30
+#define RW_I5 0x34
+#define RW_I6 0x38
+#define RW_I7 0x3c
+
+/* Stack_frame offsets */
+#define SF_V9_L0 0x00
+#define SF_V9_L1 0x08
+#define SF_V9_L2 0x10
+#define SF_V9_L3 0x18
+#define SF_V9_L4 0x20
+#define SF_V9_L5 0x28
+#define SF_V9_L6 0x30
+#define SF_V9_L7 0x38
+#define SF_V9_I0 0x40
+#define SF_V9_I1 0x48
+#define SF_V9_I2 0x50
+#define SF_V9_I3 0x58
+#define SF_V9_I4 0x60
+#define SF_V9_I5 0x68
+#define SF_V9_FP 0x70
+#define SF_V9_PC 0x78
+#define SF_V9_RETP 0x80
+#define SF_V9_XARG0 0x88
+#define SF_V9_XARG1 0x90
+#define SF_V9_XARG2 0x98
+#define SF_V9_XARG3 0xa0
+#define SF_V9_XARG4 0xa8
+#define SF_V9_XARG5 0xb0
+#define SF_V9_XXARG 0xb8
+
+#define SF_L0 0x00
+#define SF_L1 0x04
+#define SF_L2 0x08
+#define SF_L3 0x0c
+#define SF_L4 0x10
+#define SF_L5 0x14
+#define SF_L6 0x18
+#define SF_L7 0x1c
+#define SF_I0 0x20
+#define SF_I1 0x24
+#define SF_I2 0x28
+#define SF_I3 0x2c
+#define SF_I4 0x30
+#define SF_I5 0x34
+#define SF_FP 0x38
+#define SF_PC 0x3c
+#define SF_RETP 0x40
+#define SF_XARG0 0x44
+#define SF_XARG1 0x48
+#define SF_XARG2 0x4c
+#define SF_XARG3 0x50
+#define SF_XARG4 0x54
+#define SF_XARG5 0x58
+#define SF_XXARG 0x5c
+
+
+/* Stuff for the ptrace system call */
+#define PTRACE_SPARC_DETACH 11
+#define PTRACE_GETREGS 12
+#define PTRACE_SETREGS 13
+#define PTRACE_GETFPREGS 14
+#define PTRACE_SETFPREGS 15
+#define PTRACE_READDATA 16
+#define PTRACE_WRITEDATA 17
+#define PTRACE_READTEXT 18
+#define PTRACE_WRITETEXT 19
+#define PTRACE_GETFPAREGS 20
+#define PTRACE_SETFPAREGS 21
+
+/* There are for debugging 64-bit processes, either from a 32 or 64 bit
+ * parent. Thus their complements are for debugging 32-bit processes only.
+ */
+
+#define PTRACE_GETREGS64 22
+#define PTRACE_SETREGS64 23
+/* PTRACE_SYSCALL is 24 */
+#define PTRACE_GETFPREGS64 25
+#define PTRACE_SETFPREGS64 26
+
+#endif /* _UAPI__SPARC_PTRACE_H */
diff --git a/arch/sparc/include/asm/resource.h b/arch/sparc/include/uapi/asm/resource.h
index fe163ca..fe163ca 100644
--- a/arch/sparc/include/asm/resource.h
+++ b/arch/sparc/include/uapi/asm/resource.h
diff --git a/arch/sparc/include/asm/sembuf.h b/arch/sparc/include/uapi/asm/sembuf.h
index faee1be..faee1be 100644
--- a/arch/sparc/include/asm/sembuf.h
+++ b/arch/sparc/include/uapi/asm/sembuf.h
diff --git a/arch/sparc/include/uapi/asm/setup.h b/arch/sparc/include/uapi/asm/setup.h
new file mode 100644
index 0000000..5337684
--- /dev/null
+++ b/arch/sparc/include/uapi/asm/setup.h
@@ -0,0 +1,15 @@
+/*
+ * Just a place holder.
+ */
+
+#ifndef _UAPI_SPARC_SETUP_H
+#define _UAPI_SPARC_SETUP_H
+
+#if defined(__sparc__) && defined(__arch64__)
+# define COMMAND_LINE_SIZE 2048
+#else
+# define COMMAND_LINE_SIZE 256
+#endif
+
+
+#endif /* _UAPI_SPARC_SETUP_H */
diff --git a/arch/sparc/include/asm/shmbuf.h b/arch/sparc/include/uapi/asm/shmbuf.h
index 83a1605..83a1605 100644
--- a/arch/sparc/include/asm/shmbuf.h
+++ b/arch/sparc/include/uapi/asm/shmbuf.h
diff --git a/arch/sparc/include/uapi/asm/sigcontext.h b/arch/sparc/include/uapi/asm/sigcontext.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/arch/sparc/include/uapi/asm/sigcontext.h
diff --git a/arch/sparc/include/uapi/asm/siginfo.h b/arch/sparc/include/uapi/asm/siginfo.h
new file mode 100644
index 0000000..2d9b79cc
--- /dev/null
+++ b/arch/sparc/include/uapi/asm/siginfo.h
@@ -0,0 +1,25 @@
+#ifndef _UAPI__SPARC_SIGINFO_H
+#define _UAPI__SPARC_SIGINFO_H
+
+#if defined(__sparc__) && defined(__arch64__)
+
+#define __ARCH_SI_PREAMBLE_SIZE (4 * sizeof(int))
+#define __ARCH_SI_BAND_T int
+
+#endif /* defined(__sparc__) && defined(__arch64__) */
+
+
+#define __ARCH_SI_TRAPNO
+
+#include <asm-generic/siginfo.h>
+
+
+#define SI_NOINFO 32767 /* no information in siginfo_t */
+
+/*
+ * SIGEMT si_codes
+ */
+#define EMT_TAGOVF (__SI_FAULT|1) /* tag overflow */
+#define NSIGEMT 1
+
+#endif /* _UAPI__SPARC_SIGINFO_H */
diff --git a/arch/sparc/include/uapi/asm/signal.h b/arch/sparc/include/uapi/asm/signal.h
new file mode 100644
index 0000000..1a04189
--- /dev/null
+++ b/arch/sparc/include/uapi/asm/signal.h
@@ -0,0 +1,185 @@
+#ifndef _UAPI__SPARC_SIGNAL_H
+#define _UAPI__SPARC_SIGNAL_H
+
+#include <asm/sigcontext.h>
+#include <linux/compiler.h>
+
+
+/* On the Sparc the signal handlers get passed a 'sub-signal' code
+ * for certain signal types, which we document here.
+ */
+#define SIGHUP 1
+#define SIGINT 2
+#define SIGQUIT 3
+#define SIGILL 4
+#define SUBSIG_STACK 0
+#define SUBSIG_ILLINST 2
+#define SUBSIG_PRIVINST 3
+#define SUBSIG_BADTRAP(t) (0x80 + (t))
+
+#define SIGTRAP 5
+#define SIGABRT 6
+#define SIGIOT 6
+
+#define SIGEMT 7
+#define SUBSIG_TAG 10
+
+#define SIGFPE 8
+#define SUBSIG_FPDISABLED 0x400
+#define SUBSIG_FPERROR 0x404
+#define SUBSIG_FPINTOVFL 0x001
+#define SUBSIG_FPSTSIG 0x002
+#define SUBSIG_IDIVZERO 0x014
+#define SUBSIG_FPINEXACT 0x0c4
+#define SUBSIG_FPDIVZERO 0x0c8
+#define SUBSIG_FPUNFLOW 0x0cc
+#define SUBSIG_FPOPERROR 0x0d0
+#define SUBSIG_FPOVFLOW 0x0d4
+
+#define SIGKILL 9
+#define SIGBUS 10
+#define SUBSIG_BUSTIMEOUT 1
+#define SUBSIG_ALIGNMENT 2
+#define SUBSIG_MISCERROR 5
+
+#define SIGSEGV 11
+#define SUBSIG_NOMAPPING 3
+#define SUBSIG_PROTECTION 4
+#define SUBSIG_SEGERROR 5
+
+#define SIGSYS 12
+
+#define SIGPIPE 13
+#define SIGALRM 14
+#define SIGTERM 15
+#define SIGURG 16
+
+/* SunOS values which deviate from the Linux/i386 ones */
+#define SIGSTOP 17
+#define SIGTSTP 18
+#define SIGCONT 19
+#define SIGCHLD 20
+#define SIGTTIN 21
+#define SIGTTOU 22
+#define SIGIO 23
+#define SIGPOLL SIGIO /* SysV name for SIGIO */
+#define SIGXCPU 24
+#define SIGXFSZ 25
+#define SIGVTALRM 26
+#define SIGPROF 27
+#define SIGWINCH 28
+#define SIGLOST 29
+#define SIGPWR SIGLOST
+#define SIGUSR1 30
+#define SIGUSR2 31
+
+/* Most things should be clean enough to redefine this at will, if care
+ is taken to make libc match. */
+
+#define __OLD_NSIG 32
+#define __NEW_NSIG 64
+#ifdef __arch64__
+#define _NSIG_BPW 64
+#else
+#define _NSIG_BPW 32
+#endif
+#define _NSIG_WORDS (__NEW_NSIG / _NSIG_BPW)
+
+#define SIGRTMIN 32
+#define SIGRTMAX __NEW_NSIG
+
+#if defined(__KERNEL__) || defined(__WANT_POSIX1B_SIGNALS__)
+#define _NSIG __NEW_NSIG
+#define __new_sigset_t sigset_t
+#define __new_sigaction sigaction
+#define __new_sigaction32 sigaction32
+#define __old_sigset_t old_sigset_t
+#define __old_sigaction old_sigaction
+#define __old_sigaction32 old_sigaction32
+#else
+#define _NSIG __OLD_NSIG
+#define NSIG _NSIG
+#define __old_sigset_t sigset_t
+#define __old_sigaction sigaction
+#define __old_sigaction32 sigaction32
+#endif
+
+#ifndef __ASSEMBLY__
+
+typedef unsigned long __old_sigset_t; /* at least 32 bits */
+
+typedef struct {
+ unsigned long sig[_NSIG_WORDS];
+} __new_sigset_t;
+
+/* A SunOS sigstack */
+struct sigstack {
+ /* XXX 32-bit pointers pinhead XXX */
+ char *the_stack;
+ int cur_status;
+};
+
+/* Sigvec flags */
+#define _SV_SSTACK 1u /* This signal handler should use sig-stack */
+#define _SV_INTR 2u /* Sig return should not restart system call */
+#define _SV_RESET 4u /* Set handler to SIG_DFL upon taken signal */
+#define _SV_IGNCHILD 8u /* Do not send SIGCHLD */
+
+/*
+ * sa_flags values: SA_STACK is not currently supported, but will allow the
+ * usage of signal stacks by using the (now obsolete) sa_restorer field in
+ * the sigaction structure as a stack pointer. This is now possible due to
+ * the changes in signal handling. LBT 010493.
+ * SA_RESTART flag to get restarting signals (which were the default long ago)
+ */
+#define SA_NOCLDSTOP _SV_IGNCHILD
+#define SA_STACK _SV_SSTACK
+#define SA_ONSTACK _SV_SSTACK
+#define SA_RESTART _SV_INTR
+#define SA_ONESHOT _SV_RESET
+#define SA_NODEFER 0x20u
+#define SA_NOCLDWAIT 0x100u
+#define SA_SIGINFO 0x200u
+
+#define SA_NOMASK SA_NODEFER
+
+#define SIG_BLOCK 0x01 /* for blocking signals */
+#define SIG_UNBLOCK 0x02 /* for unblocking signals */
+#define SIG_SETMASK 0x04 /* for setting the signal mask */
+
+/*
+ * sigaltstack controls
+ */
+#define SS_ONSTACK 1
+#define SS_DISABLE 2
+
+#define MINSIGSTKSZ 4096
+#define SIGSTKSZ 16384
+
+
+#include <asm-generic/signal-defs.h>
+
+struct __new_sigaction {
+ __sighandler_t sa_handler;
+ unsigned long sa_flags;
+ __sigrestore_t sa_restorer; /* not used by Linux/SPARC yet */
+ __new_sigset_t sa_mask;
+};
+
+struct __old_sigaction {
+ __sighandler_t sa_handler;
+ __old_sigset_t sa_mask;
+ unsigned long sa_flags;
+ void (*sa_restorer)(void); /* not used by Linux/SPARC yet */
+};
+
+typedef struct sigaltstack {
+ void __user *ss_sp;
+ int ss_flags;
+ size_t ss_size;
+} stack_t;
+
+
+#endif /* !(__ASSEMBLY__) */
+
+#endif /* _UAPI__SPARC_SIGNAL_H */
diff --git a/arch/sparc/include/asm/socket.h b/arch/sparc/include/uapi/asm/socket.h
index bea1568..bea1568 100644
--- a/arch/sparc/include/asm/socket.h
+++ b/arch/sparc/include/uapi/asm/socket.h
diff --git a/arch/sparc/include/asm/sockios.h b/arch/sparc/include/uapi/asm/sockios.h
index 990ea74..990ea74 100644
--- a/arch/sparc/include/asm/sockios.h
+++ b/arch/sparc/include/uapi/asm/sockios.h
diff --git a/arch/sparc/include/asm/stat.h b/arch/sparc/include/uapi/asm/stat.h
index a232e9e..a232e9e 100644
--- a/arch/sparc/include/asm/stat.h
+++ b/arch/sparc/include/uapi/asm/stat.h
diff --git a/arch/sparc/include/asm/statfs.h b/arch/sparc/include/uapi/asm/statfs.h
index 55e607a..55e607a 100644
--- a/arch/sparc/include/asm/statfs.h
+++ b/arch/sparc/include/uapi/asm/statfs.h
diff --git a/arch/sparc/include/asm/swab.h b/arch/sparc/include/uapi/asm/swab.h
index a34ad07..a34ad07 100644
--- a/arch/sparc/include/asm/swab.h
+++ b/arch/sparc/include/uapi/asm/swab.h
diff --git a/arch/sparc/include/uapi/asm/termbits.h b/arch/sparc/include/uapi/asm/termbits.h
new file mode 100644
index 0000000..dd91642
--- /dev/null
+++ b/arch/sparc/include/uapi/asm/termbits.h
@@ -0,0 +1,263 @@
+#ifndef _UAPI_SPARC_TERMBITS_H
+#define _UAPI_SPARC_TERMBITS_H
+
+#include <linux/posix_types.h>
+
+typedef unsigned char cc_t;
+typedef unsigned int speed_t;
+
+#if defined(__sparc__) && defined(__arch64__)
+typedef unsigned int tcflag_t;
+#else
+typedef unsigned long tcflag_t;
+#endif
+
+#define NCC 8
+struct termio {
+ unsigned short c_iflag; /* input mode flags */
+ unsigned short c_oflag; /* output mode flags */
+ unsigned short c_cflag; /* control mode flags */
+ unsigned short c_lflag; /* local mode flags */
+ unsigned char c_line; /* line discipline */
+ unsigned char c_cc[NCC]; /* control characters */
+};
+
+#define NCCS 17
+struct termios {
+ tcflag_t c_iflag; /* input mode flags */
+ tcflag_t c_oflag; /* output mode flags */
+ tcflag_t c_cflag; /* control mode flags */
+ tcflag_t c_lflag; /* local mode flags */
+ cc_t c_line; /* line discipline */
+#ifndef __KERNEL__
+ cc_t c_cc[NCCS]; /* control characters */
+#else
+ cc_t c_cc[NCCS+2]; /* kernel needs 2 more to hold vmin/vtime */
+#define SIZEOF_USER_TERMIOS sizeof (struct termios) - (2*sizeof (cc_t))
+#endif
+};
+
+struct termios2 {
+ tcflag_t c_iflag; /* input mode flags */
+ tcflag_t c_oflag; /* output mode flags */
+ tcflag_t c_cflag; /* control mode flags */
+ tcflag_t c_lflag; /* local mode flags */
+ cc_t c_line; /* line discipline */
+ cc_t c_cc[NCCS+2]; /* control characters */
+ speed_t c_ispeed; /* input speed */
+ speed_t c_ospeed; /* output speed */
+};
+
+struct ktermios {
+ tcflag_t c_iflag; /* input mode flags */
+ tcflag_t c_oflag; /* output mode flags */
+ tcflag_t c_cflag; /* control mode flags */
+ tcflag_t c_lflag; /* local mode flags */
+ cc_t c_line; /* line discipline */
+ cc_t c_cc[NCCS+2]; /* control characters */
+ speed_t c_ispeed; /* input speed */
+ speed_t c_ospeed; /* output speed */
+};
+
+/* c_cc characters */
+#define VINTR 0
+#define VQUIT 1
+#define VERASE 2
+#define VKILL 3
+#define VEOF 4
+#define VEOL 5
+#define VEOL2 6
+#define VSWTC 7
+#define VSTART 8
+#define VSTOP 9
+
+
+
+#define VSUSP 10
+#define VDSUSP 11 /* SunOS POSIX nicety I do believe... */
+#define VREPRINT 12
+#define VDISCARD 13
+#define VWERASE 14
+#define VLNEXT 15
+
+/* Kernel keeps vmin/vtime separated, user apps assume vmin/vtime is
+ * shared with eof/eol
+ */
+#ifndef __KERNEL__
+#define VMIN VEOF
+#define VTIME VEOL
+#endif
+
+/* c_iflag bits */
+#define IGNBRK 0x00000001
+#define BRKINT 0x00000002
+#define IGNPAR 0x00000004
+#define PARMRK 0x00000008
+#define INPCK 0x00000010
+#define ISTRIP 0x00000020
+#define INLCR 0x00000040
+#define IGNCR 0x00000080
+#define ICRNL 0x00000100
+#define IUCLC 0x00000200
+#define IXON 0x00000400
+#define IXANY 0x00000800
+#define IXOFF 0x00001000
+#define IMAXBEL 0x00002000
+#define IUTF8 0x00004000
+
+/* c_oflag bits */
+#define OPOST 0x00000001
+#define OLCUC 0x00000002
+#define ONLCR 0x00000004
+#define OCRNL 0x00000008
+#define ONOCR 0x00000010
+#define ONLRET 0x00000020
+#define OFILL 0x00000040
+#define OFDEL 0x00000080
+#define NLDLY 0x00000100
+#define NL0 0x00000000
+#define NL1 0x00000100
+#define CRDLY 0x00000600
+#define CR0 0x00000000
+#define CR1 0x00000200
+#define CR2 0x00000400
+#define CR3 0x00000600
+#define TABDLY 0x00001800
+#define TAB0 0x00000000
+#define TAB1 0x00000800
+#define TAB2 0x00001000
+#define TAB3 0x00001800
+#define XTABS 0x00001800
+#define BSDLY 0x00002000
+#define BS0 0x00000000
+#define BS1 0x00002000
+#define VTDLY 0x00004000
+#define VT0 0x00000000
+#define VT1 0x00004000
+#define FFDLY 0x00008000
+#define FF0 0x00000000
+#define FF1 0x00008000
+#define PAGEOUT 0x00010000 /* SUNOS specific */
+#define WRAP 0x00020000 /* SUNOS specific */
+
+/* c_cflag bit meaning */
+#define CBAUD 0x0000100f
+#define B0 0x00000000 /* hang up */
+#define B50 0x00000001
+#define B75 0x00000002
+#define B110 0x00000003
+#define B134 0x00000004
+#define B150 0x00000005
+#define B200 0x00000006
+#define B300 0x00000007
+#define B600 0x00000008
+#define B1200 0x00000009
+#define B1800 0x0000000a
+#define B2400 0x0000000b
+#define B4800 0x0000000c
+#define B9600 0x0000000d
+#define B19200 0x0000000e
+#define B38400 0x0000000f
+#define EXTA B19200
+#define EXTB B38400
+#define CSIZE 0x00000030
+#define CS5 0x00000000
+#define CS6 0x00000010
+#define CS7 0x00000020
+#define CS8 0x00000030
+#define CSTOPB 0x00000040
+#define CREAD 0x00000080
+#define PARENB 0x00000100
+#define PARODD 0x00000200
+#define HUPCL 0x00000400
+#define CLOCAL 0x00000800
+#define CBAUDEX 0x00001000
+/* We'll never see these speeds with the Zilogs, but for completeness... */
+#define BOTHER 0x00001000
+#define B57600 0x00001001
+#define B115200 0x00001002
+#define B230400 0x00001003
+#define B460800 0x00001004
+/* This is what we can do with the Zilogs. */
+#define B76800 0x00001005
+/* This is what we can do with the SAB82532. */
+#define B153600 0x00001006
+#define B307200 0x00001007
+#define B614400 0x00001008
+#define B921600 0x00001009
+/* And these are the rest... */
+#define B500000 0x0000100a
+#define B576000 0x0000100b
+#define B1000000 0x0000100c
+#define B1152000 0x0000100d
+#define B1500000 0x0000100e
+#define B2000000 0x0000100f
+/* These have totally bogus values and nobody uses them
+ so far. Later on we'd have to use say 0x10000x and
+ adjust CBAUD constant and drivers accordingly.
+#define B2500000 0x00001010
+#define B3000000 0x00001011
+#define B3500000 0x00001012
+#define B4000000 0x00001013 */
+#define CIBAUD 0x100f0000 /* input baud rate (not used) */
+#define CMSPAR 0x40000000 /* mark or space (stick) parity */
+#define CRTSCTS 0x80000000 /* flow control */
+
+#define IBSHIFT 16 /* Shift from CBAUD to CIBAUD */
+
+/* c_lflag bits */
+#define ISIG 0x00000001
+#define ICANON 0x00000002
+#define XCASE 0x00000004
+#define ECHO 0x00000008
+#define ECHOE 0x00000010
+#define ECHOK 0x00000020
+#define ECHONL 0x00000040
+#define NOFLSH 0x00000080
+#define TOSTOP 0x00000100
+#define ECHOCTL 0x00000200
+#define ECHOPRT 0x00000400
+#define ECHOKE 0x00000800
+#define DEFECHO 0x00001000 /* SUNOS thing, what is it? */
+#define FLUSHO 0x00002000
+#define PENDIN 0x00004000
+#define IEXTEN 0x00008000
+#define EXTPROC 0x00010000
+
+/* modem lines */
+#define TIOCM_LE 0x001
+#define TIOCM_DTR 0x002
+#define TIOCM_RTS 0x004
+#define TIOCM_ST 0x008
+#define TIOCM_SR 0x010
+#define TIOCM_CTS 0x020
+#define TIOCM_CAR 0x040
+#define TIOCM_RNG 0x080
+#define TIOCM_DSR 0x100
+#define TIOCM_CD TIOCM_CAR
+#define TIOCM_RI TIOCM_RNG
+#define TIOCM_OUT1 0x2000
+#define TIOCM_OUT2 0x4000
+#define TIOCM_LOOP 0x8000
+
+/* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
+#define TIOCSER_TEMT 0x01 /* Transmitter physically empty */
+
+
+/* tcflow() and TCXONC use these */
+#define TCOOFF 0
+#define TCOON 1
+#define TCIOFF 2
+#define TCION 3
+
+/* tcflush() and TCFLSH use these */
+#define TCIFLUSH 0
+#define TCOFLUSH 1
+#define TCIOFLUSH 2
+
+/* tcsetattr uses these */
+#define TCSANOW 0
+#define TCSADRAIN 1
+#define TCSAFLUSH 2
+
+#endif /* _UAPI_SPARC_TERMBITS_H */
diff --git a/arch/sparc/include/uapi/asm/termios.h b/arch/sparc/include/uapi/asm/termios.h
new file mode 100644
index 0000000..ea6f09e5
--- /dev/null
+++ b/arch/sparc/include/uapi/asm/termios.h
@@ -0,0 +1,43 @@
+#ifndef _UAPI_SPARC_TERMIOS_H
+#define _UAPI_SPARC_TERMIOS_H
+
+#include <asm/ioctls.h>
+#include <asm/termbits.h>
+
+#if defined(__KERNEL__) || defined(__DEFINE_BSD_TERMIOS)
+struct sgttyb {
+ char sg_ispeed;
+ char sg_ospeed;
+ char sg_erase;
+ char sg_kill;
+ short sg_flags;
+};
+
+struct tchars {
+ char t_intrc;
+ char t_quitc;
+ char t_startc;
+ char t_stopc;
+ char t_eofc;
+ char t_brkc;
+};
+
+struct ltchars {
+ char t_suspc;
+ char t_dsuspc;
+ char t_rprntc;
+ char t_flushc;
+ char t_werasc;
+ char t_lnextc;
+};
+#endif /* __KERNEL__ */
+
+struct winsize {
+ unsigned short ws_row;
+ unsigned short ws_col;
+ unsigned short ws_xpixel;
+ unsigned short ws_ypixel;
+};
+
+
+#endif /* _UAPI_SPARC_TERMIOS_H */
diff --git a/arch/sparc/include/uapi/asm/traps.h b/arch/sparc/include/uapi/asm/traps.h
new file mode 100644
index 0000000..a4eceac
--- /dev/null
+++ b/arch/sparc/include/uapi/asm/traps.h
@@ -0,0 +1,120 @@
+/*
+ * traps.h: Format of entries for the Sparc trap table.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#ifndef _UAPI_SPARC_TRAPS_H
+#define _UAPI_SPARC_TRAPS_H
+
+#define NUM_SPARC_TRAPS 255
+
+#ifndef __ASSEMBLY__
+#endif /* !(__ASSEMBLY__) */
+
+/* For patching the trap table at boot time, we need to know how to
+ * form various common Sparc instructions. Thus these macros...
+ */
+
+#define SPARC_MOV_CONST_L3(const) (0xa6102000 | (const&0xfff))
+
+/* The following assumes that the branch lies before the place we
+ * are branching to. This is the case for a trap vector...
+ * You have been warned.
+ */
+#define SPARC_BRANCH(dest_addr, inst_addr) \
+ (0x10800000 | (((dest_addr-inst_addr)>>2)&0x3fffff))
+
+#define SPARC_RD_PSR_L0 (0xa1480000)
+#define SPARC_RD_WIM_L3 (0xa7500000)
+#define SPARC_NOP (0x01000000)
+
+/* Various interesting trap levels. */
+/* First, hardware traps. */
+#define SP_TRAP_TFLT 0x1 /* Text fault */
+#define SP_TRAP_II 0x2 /* Illegal Instruction */
+#define SP_TRAP_PI 0x3 /* Privileged Instruction */
+#define SP_TRAP_FPD 0x4 /* Floating Point Disabled */
+#define SP_TRAP_WOVF 0x5 /* Window Overflow */
+#define SP_TRAP_WUNF 0x6 /* Window Underflow */
+#define SP_TRAP_MNA 0x7 /* Memory Address Unaligned */
+#define SP_TRAP_FPE 0x8 /* Floating Point Exception */
+#define SP_TRAP_DFLT 0x9 /* Data Fault */
+#define SP_TRAP_TOF 0xa /* Tag Overflow */
+#define SP_TRAP_WDOG 0xb /* Watchpoint Detected */
+#define SP_TRAP_IRQ1 0x11 /* IRQ level 1 */
+#define SP_TRAP_IRQ2 0x12 /* IRQ level 2 */
+#define SP_TRAP_IRQ3 0x13 /* IRQ level 3 */
+#define SP_TRAP_IRQ4 0x14 /* IRQ level 4 */
+#define SP_TRAP_IRQ5 0x15 /* IRQ level 5 */
+#define SP_TRAP_IRQ6 0x16 /* IRQ level 6 */
+#define SP_TRAP_IRQ7 0x17 /* IRQ level 7 */
+#define SP_TRAP_IRQ8 0x18 /* IRQ level 8 */
+#define SP_TRAP_IRQ9 0x19 /* IRQ level 9 */
+#define SP_TRAP_IRQ10 0x1a /* IRQ level 10 */
+#define SP_TRAP_IRQ11 0x1b /* IRQ level 11 */
+#define SP_TRAP_IRQ12 0x1c /* IRQ level 12 */
+#define SP_TRAP_IRQ13 0x1d /* IRQ level 13 */
+#define SP_TRAP_IRQ14 0x1e /* IRQ level 14 */
+#define SP_TRAP_IRQ15 0x1f /* IRQ level 15 Non-maskable */
+#define SP_TRAP_RACC 0x20 /* Register Access Error ??? */
+#define SP_TRAP_IACC 0x21 /* Instruction Access Error */
+#define SP_TRAP_CPDIS 0x24 /* Co-Processor Disabled */
+#define SP_TRAP_BADFL 0x25 /* Unimplemented Flush Instruction */
+#define SP_TRAP_CPEXP 0x28 /* Co-Processor Exception */
+#define SP_TRAP_DACC 0x29 /* Data Access Error */
+#define SP_TRAP_DIVZ 0x2a /* Divide By Zero */
+#define SP_TRAP_DSTORE 0x2b /* Data Store Error ??? */
+#define SP_TRAP_DMM 0x2c /* Data Access MMU Miss ??? */
+#define SP_TRAP_IMM 0x3c /* Instruction Access MMU Miss ??? */
+
+/* Now the Software Traps... */
+#define SP_TRAP_SUNOS 0x80 /* SunOS System Call */
+#define SP_TRAP_SBPT 0x81 /* Software Breakpoint */
+#define SP_TRAP_SDIVZ 0x82 /* Software Divide-by-Zero trap */
+#define SP_TRAP_FWIN 0x83 /* Flush Windows */
+#define SP_TRAP_CWIN 0x84 /* Clean Windows */
+#define SP_TRAP_RCHK 0x85 /* Range Check */
+#define SP_TRAP_FUNA 0x86 /* Fix Unaligned Access */
+#define SP_TRAP_IOWFL 0x87 /* Integer Overflow */
+#define SP_TRAP_SOLARIS 0x88 /* Solaris System Call */
+#define SP_TRAP_NETBSD 0x89 /* NetBSD System Call */
+#define SP_TRAP_LINUX 0x90 /* Linux System Call */
+
+/* Names used for compatibility with SunOS */
+#define ST_SYSCALL 0x00
+#define ST_BREAKPOINT 0x01
+#define ST_DIV0 0x02
+#define ST_FLUSH_WINDOWS 0x03
+#define ST_CLEAN_WINDOWS 0x04
+#define ST_RANGE_CHECK 0x05
+#define ST_FIX_ALIGN 0x06
+#define ST_INT_OVERFLOW 0x07
+
+/* Special traps... */
+#define SP_TRAP_KBPT1 0xfe /* KADB/PROM Breakpoint one */
+#define SP_TRAP_KBPT2 0xff /* KADB/PROM Breakpoint two */
+
+/* Handy Macros */
+/* Is this a trap we never expect to get? */
+#define BAD_TRAP_P(level) \
+ ((level > SP_TRAP_WDOG && level < SP_TRAP_IRQ1) || \
+ (level > SP_TRAP_IACC && level < SP_TRAP_CPDIS) || \
+ (level > SP_TRAP_BADFL && level < SP_TRAP_CPEXP) || \
+ (level > SP_TRAP_DMM && level < SP_TRAP_IMM) || \
+ (level > SP_TRAP_IMM && level < SP_TRAP_SUNOS) || \
+ (level > SP_TRAP_LINUX && level < SP_TRAP_KBPT1))
+
+/* Is this a Hardware trap? */
+#define HW_TRAP_P(level) ((level > 0) && (level < SP_TRAP_SUNOS))
+
+/* Is this a Software trap? */
+#define SW_TRAP_P(level) ((level >= SP_TRAP_SUNOS) && (level <= SP_TRAP_KBPT2))
+
+/* Is this a system call for some OS we know about? */
+#define SCALL_TRAP_P(level) ((level == SP_TRAP_SUNOS) || \
+ (level == SP_TRAP_SOLARIS) || \
+ (level == SP_TRAP_NETBSD) || \
+ (level == SP_TRAP_LINUX))
+
+#endif /* _UAPI_SPARC_TRAPS_H */
diff --git a/arch/sparc/include/asm/types.h b/arch/sparc/include/uapi/asm/types.h
index 383d156..383d156 100644
--- a/arch/sparc/include/asm/types.h
+++ b/arch/sparc/include/uapi/asm/types.h
diff --git a/arch/sparc/include/asm/uctx.h b/arch/sparc/include/uapi/asm/uctx.h
index dc937c7..dc937c7 100644
--- a/arch/sparc/include/asm/uctx.h
+++ b/arch/sparc/include/uapi/asm/uctx.h
diff --git a/arch/sparc/include/uapi/asm/unistd.h b/arch/sparc/include/uapi/asm/unistd.h
new file mode 100644
index 0000000..8974ef7
--- /dev/null
+++ b/arch/sparc/include/uapi/asm/unistd.h
@@ -0,0 +1,422 @@
+/*
+ * System calls under the Sparc.
+ *
+ * Don't be scared by the ugly clobbers, it is the only way I can
+ * think of right now to force the arguments into fixed registers
+ * before the trap into the system call with gcc 'asm' statements.
+ *
+ * Copyright (C) 1995, 2007 David S. Miller (davem@davemloft.net)
+ *
+ * SunOS compatibility based upon preliminary work which is:
+ *
+ * Copyright (C) 1995 Adrian M. Rodriguez (adrian@remus.rutgers.edu)
+ */
+#ifndef _UAPI_SPARC_UNISTD_H
+#define _UAPI_SPARC_UNISTD_H
+
+#ifndef __32bit_syscall_numbers__
+#ifndef __arch64__
+#define __32bit_syscall_numbers__
+#endif
+#endif
+
+#define __NR_restart_syscall 0 /* Linux Specific */
+#define __NR_exit 1 /* Common */
+#define __NR_fork 2 /* Common */
+#define __NR_read 3 /* Common */
+#define __NR_write 4 /* Common */
+#define __NR_open 5 /* Common */
+#define __NR_close 6 /* Common */
+#define __NR_wait4 7 /* Common */
+#define __NR_creat 8 /* Common */
+#define __NR_link 9 /* Common */
+#define __NR_unlink 10 /* Common */
+#define __NR_execv 11 /* SunOS Specific */
+#define __NR_chdir 12 /* Common */
+#define __NR_chown 13 /* Common */
+#define __NR_mknod 14 /* Common */
+#define __NR_chmod 15 /* Common */
+#define __NR_lchown 16 /* Common */
+#define __NR_brk 17 /* Common */
+#define __NR_perfctr 18 /* Performance counter operations */
+#define __NR_lseek 19 /* Common */
+#define __NR_getpid 20 /* Common */
+#define __NR_capget 21 /* Linux Specific */
+#define __NR_capset 22 /* Linux Specific */
+#define __NR_setuid 23 /* Implemented via setreuid in SunOS */
+#define __NR_getuid 24 /* Common */
+#define __NR_vmsplice 25 /* ENOSYS under SunOS */
+#define __NR_ptrace 26 /* Common */
+#define __NR_alarm 27 /* Implemented via setitimer in SunOS */
+#define __NR_sigaltstack 28 /* Common */
+#define __NR_pause 29 /* Is sigblock(0)->sigpause() in SunOS */
+#define __NR_utime 30 /* Implemented via utimes() under SunOS */
+#ifdef __32bit_syscall_numbers__
+#define __NR_lchown32 31 /* Linux sparc32 specific */
+#define __NR_fchown32 32 /* Linux sparc32 specific */
+#endif
+#define __NR_access 33 /* Common */
+#define __NR_nice 34 /* Implemented via get/setpriority() in SunOS */
+#ifdef __32bit_syscall_numbers__
+#define __NR_chown32 35 /* Linux sparc32 specific */
+#endif
+#define __NR_sync 36 /* Common */
+#define __NR_kill 37 /* Common */
+#define __NR_stat 38 /* Common */
+#define __NR_sendfile 39 /* Linux Specific */
+#define __NR_lstat 40 /* Common */
+#define __NR_dup 41 /* Common */
+#define __NR_pipe 42 /* Common */
+#define __NR_times 43 /* Implemented via getrusage() in SunOS */
+#ifdef __32bit_syscall_numbers__
+#define __NR_getuid32 44 /* Linux sparc32 specific */
+#endif
+#define __NR_umount2 45 /* Linux Specific */
+#define __NR_setgid 46 /* Implemented via setregid() in SunOS */
+#define __NR_getgid 47 /* Common */
+#define __NR_signal 48 /* Implemented via sigvec() in SunOS */
+#define __NR_geteuid 49 /* SunOS calls getuid() */
+#define __NR_getegid 50 /* SunOS calls getgid() */
+#define __NR_acct 51 /* Common */
+#ifdef __32bit_syscall_numbers__
+#define __NR_getgid32 53 /* Linux sparc32 specific */
+#else
+#define __NR_memory_ordering 52 /* Linux Specific */
+#endif
+#define __NR_ioctl 54 /* Common */
+#define __NR_reboot 55 /* Common */
+#ifdef __32bit_syscall_numbers__
+#define __NR_mmap2 56 /* Linux sparc32 Specific */
+#endif
+#define __NR_symlink 57 /* Common */
+#define __NR_readlink 58 /* Common */
+#define __NR_execve 59 /* Common */
+#define __NR_umask 60 /* Common */
+#define __NR_chroot 61 /* Common */
+#define __NR_fstat 62 /* Common */
+#define __NR_fstat64 63 /* Linux Specific */
+#define __NR_getpagesize 64 /* Common */
+#define __NR_msync 65 /* Common in newer 1.3.x revs... */
+#define __NR_vfork 66 /* Common */
+#define __NR_pread64 67 /* Linux Specific */
+#define __NR_pwrite64 68 /* Linux Specific */
+#ifdef __32bit_syscall_numbers__
+#define __NR_geteuid32 69 /* Linux sparc32, sbrk under SunOS */
+#define __NR_getegid32 70 /* Linux sparc32, sstk under SunOS */
+#endif
+#define __NR_mmap 71 /* Common */
+#ifdef __32bit_syscall_numbers__
+#define __NR_setreuid32 72 /* Linux sparc32, vadvise under SunOS */
+#endif
+#define __NR_munmap 73 /* Common */
+#define __NR_mprotect 74 /* Common */
+#define __NR_madvise 75 /* Common */
+#define __NR_vhangup 76 /* Common */
+#ifdef __32bit_syscall_numbers__
+#define __NR_truncate64 77 /* Linux sparc32 Specific */
+#endif
+#define __NR_mincore 78 /* Common */
+#define __NR_getgroups 79 /* Common */
+#define __NR_setgroups 80 /* Common */
+#define __NR_getpgrp 81 /* Common */
+#ifdef __32bit_syscall_numbers__
+#define __NR_setgroups32 82 /* Linux sparc32, setpgrp under SunOS */
+#endif
+#define __NR_setitimer 83 /* Common */
+#ifdef __32bit_syscall_numbers__
+#define __NR_ftruncate64 84 /* Linux sparc32 Specific */
+#endif
+#define __NR_swapon 85 /* Common */
+#define __NR_getitimer 86 /* Common */
+#ifdef __32bit_syscall_numbers__
+#define __NR_setuid32 87 /* Linux sparc32, gethostname under SunOS */
+#endif
+#define __NR_sethostname 88 /* Common */
+#ifdef __32bit_syscall_numbers__
+#define __NR_setgid32 89 /* Linux sparc32, getdtablesize under SunOS */
+#endif
+#define __NR_dup2 90 /* Common */
+#ifdef __32bit_syscall_numbers__
+#define __NR_setfsuid32 91 /* Linux sparc32, getdopt under SunOS */
+#endif
+#define __NR_fcntl 92 /* Common */
+#define __NR_select 93 /* Common */
+#ifdef __32bit_syscall_numbers__
+#define __NR_setfsgid32 94 /* Linux sparc32, setdopt under SunOS */
+#endif
+#define __NR_fsync 95 /* Common */
+#define __NR_setpriority 96 /* Common */
+#define __NR_socket 97 /* Common */
+#define __NR_connect 98 /* Common */
+#define __NR_accept 99 /* Common */
+#define __NR_getpriority 100 /* Common */
+#define __NR_rt_sigreturn 101 /* Linux Specific */
+#define __NR_rt_sigaction 102 /* Linux Specific */
+#define __NR_rt_sigprocmask 103 /* Linux Specific */
+#define __NR_rt_sigpending 104 /* Linux Specific */
+#define __NR_rt_sigtimedwait 105 /* Linux Specific */
+#define __NR_rt_sigqueueinfo 106 /* Linux Specific */
+#define __NR_rt_sigsuspend 107 /* Linux Specific */
+#ifdef __32bit_syscall_numbers__
+#define __NR_setresuid32 108 /* Linux Specific, sigvec under SunOS */
+#define __NR_getresuid32 109 /* Linux Specific, sigblock under SunOS */
+#define __NR_setresgid32 110 /* Linux Specific, sigsetmask under SunOS */
+#define __NR_getresgid32 111 /* Linux Specific, sigpause under SunOS */
+#define __NR_setregid32 112 /* Linux sparc32, sigstack under SunOS */
+#else
+#define __NR_setresuid 108 /* Linux Specific, sigvec under SunOS */
+#define __NR_getresuid 109 /* Linux Specific, sigblock under SunOS */
+#define __NR_setresgid 110 /* Linux Specific, sigsetmask under SunOS */
+#define __NR_getresgid 111 /* Linux Specific, sigpause under SunOS */
+#endif
+#define __NR_recvmsg 113 /* Common */
+#define __NR_sendmsg 114 /* Common */
+#ifdef __32bit_syscall_numbers__
+#define __NR_getgroups32 115 /* Linux sparc32, vtrace under SunOS */
+#endif
+#define __NR_gettimeofday 116 /* Common */
+#define __NR_getrusage 117 /* Common */
+#define __NR_getsockopt 118 /* Common */
+#define __NR_getcwd 119 /* Linux Specific */
+#define __NR_readv 120 /* Common */
+#define __NR_writev 121 /* Common */
+#define __NR_settimeofday 122 /* Common */
+#define __NR_fchown 123 /* Common */
+#define __NR_fchmod 124 /* Common */
+#define __NR_recvfrom 125 /* Common */
+#define __NR_setreuid 126 /* Common */
+#define __NR_setregid 127 /* Common */
+#define __NR_rename 128 /* Common */
+#define __NR_truncate 129 /* Common */
+#define __NR_ftruncate 130 /* Common */
+#define __NR_flock 131 /* Common */
+#define __NR_lstat64 132 /* Linux Specific */
+#define __NR_sendto 133 /* Common */
+#define __NR_shutdown 134 /* Common */
+#define __NR_socketpair 135 /* Common */
+#define __NR_mkdir 136 /* Common */
+#define __NR_rmdir 137 /* Common */
+#define __NR_utimes 138 /* SunOS Specific */
+#define __NR_stat64 139 /* Linux Specific */
+#define __NR_sendfile64 140 /* adjtime under SunOS */
+#define __NR_getpeername 141 /* Common */
+#define __NR_futex 142 /* gethostid under SunOS */
+#define __NR_gettid 143 /* ENOSYS under SunOS */
+#define __NR_getrlimit 144 /* Common */
+#define __NR_setrlimit 145 /* Common */
+#define __NR_pivot_root 146 /* Linux Specific, killpg under SunOS */
+#define __NR_prctl 147 /* ENOSYS under SunOS */
+#define __NR_pciconfig_read 148 /* ENOSYS under SunOS */
+#define __NR_pciconfig_write 149 /* ENOSYS under SunOS */
+#define __NR_getsockname 150 /* Common */
+#define __NR_inotify_init 151 /* Linux specific */
+#define __NR_inotify_add_watch 152 /* Linux specific */
+#define __NR_poll 153 /* Common */
+#define __NR_getdents64 154 /* Linux specific */
+#ifdef __32bit_syscall_numbers__
+#define __NR_fcntl64 155 /* Linux sparc32 Specific */
+#endif
+#define __NR_inotify_rm_watch 156 /* Linux specific */
+#define __NR_statfs 157 /* Common */
+#define __NR_fstatfs 158 /* Common */
+#define __NR_umount 159 /* Common */
+#define __NR_sched_set_affinity 160 /* Linux specific, async_daemon under SunOS */
+#define __NR_sched_get_affinity 161 /* Linux specific, getfh under SunOS */
+#define __NR_getdomainname 162 /* SunOS Specific */
+#define __NR_setdomainname 163 /* Common */
+#ifndef __32bit_syscall_numbers__
+#define __NR_utrap_install 164 /* SYSV ABI/v9 required */
+#endif
+#define __NR_quotactl 165 /* Common */
+#define __NR_set_tid_address 166 /* Linux specific, exportfs under SunOS */
+#define __NR_mount 167 /* Common */
+#define __NR_ustat 168 /* Common */
+#define __NR_setxattr 169 /* SunOS: semsys */
+#define __NR_lsetxattr 170 /* SunOS: msgsys */
+#define __NR_fsetxattr 171 /* SunOS: shmsys */
+#define __NR_getxattr 172 /* SunOS: auditsys */
+#define __NR_lgetxattr 173 /* SunOS: rfssys */
+#define __NR_getdents 174 /* Common */
+#define __NR_setsid 175 /* Common */
+#define __NR_fchdir 176 /* Common */
+#define __NR_fgetxattr 177 /* SunOS: fchroot */
+#define __NR_listxattr 178 /* SunOS: vpixsys */
+#define __NR_llistxattr 179 /* SunOS: aioread */
+#define __NR_flistxattr 180 /* SunOS: aiowrite */
+#define __NR_removexattr 181 /* SunOS: aiowait */
+#define __NR_lremovexattr 182 /* SunOS: aiocancel */
+#define __NR_sigpending 183 /* Common */
+#define __NR_query_module 184 /* Linux Specific */
+#define __NR_setpgid 185 /* Common */
+#define __NR_fremovexattr 186 /* SunOS: pathconf */
+#define __NR_tkill 187 /* SunOS: fpathconf */
+#define __NR_exit_group 188 /* Linux specific, sysconf undef SunOS */
+#define __NR_uname 189 /* Linux Specific */
+#define __NR_init_module 190 /* Linux Specific */
+#define __NR_personality 191 /* Linux Specific */
+#define __NR_remap_file_pages 192 /* Linux Specific */
+#define __NR_epoll_create 193 /* Linux Specific */
+#define __NR_epoll_ctl 194 /* Linux Specific */
+#define __NR_epoll_wait 195 /* Linux Specific */
+#define __NR_ioprio_set 196 /* Linux Specific */
+#define __NR_getppid 197 /* Linux Specific */
+#define __NR_sigaction 198 /* Linux Specific */
+#define __NR_sgetmask 199 /* Linux Specific */
+#define __NR_ssetmask 200 /* Linux Specific */
+#define __NR_sigsuspend 201 /* Linux Specific */
+#define __NR_oldlstat 202 /* Linux Specific */
+#define __NR_uselib 203 /* Linux Specific */
+#define __NR_readdir 204 /* Linux Specific */
+#define __NR_readahead 205 /* Linux Specific */
+#define __NR_socketcall 206 /* Linux Specific */
+#define __NR_syslog 207 /* Linux Specific */
+#define __NR_lookup_dcookie 208 /* Linux Specific */
+#define __NR_fadvise64 209 /* Linux Specific */
+#define __NR_fadvise64_64 210 /* Linux Specific */
+#define __NR_tgkill 211 /* Linux Specific */
+#define __NR_waitpid 212 /* Linux Specific */
+#define __NR_swapoff 213 /* Linux Specific */
+#define __NR_sysinfo 214 /* Linux Specific */
+#define __NR_ipc 215 /* Linux Specific */
+#define __NR_sigreturn 216 /* Linux Specific */
+#define __NR_clone 217 /* Linux Specific */
+#define __NR_ioprio_get 218 /* Linux Specific */
+#define __NR_adjtimex 219 /* Linux Specific */
+#define __NR_sigprocmask 220 /* Linux Specific */
+#define __NR_create_module 221 /* Linux Specific */
+#define __NR_delete_module 222 /* Linux Specific */
+#define __NR_get_kernel_syms 223 /* Linux Specific */
+#define __NR_getpgid 224 /* Linux Specific */
+#define __NR_bdflush 225 /* Linux Specific */
+#define __NR_sysfs 226 /* Linux Specific */
+#define __NR_afs_syscall 227 /* Linux Specific */
+#define __NR_setfsuid 228 /* Linux Specific */
+#define __NR_setfsgid 229 /* Linux Specific */
+#define __NR__newselect 230 /* Linux Specific */
+#ifdef __32bit_syscall_numbers__
+#define __NR_time 231 /* Linux Specific */
+#else
+#endif
+#define __NR_splice 232 /* Linux Specific */
+#define __NR_stime 233 /* Linux Specific */
+#define __NR_statfs64 234 /* Linux Specific */
+#define __NR_fstatfs64 235 /* Linux Specific */
+#define __NR__llseek 236 /* Linux Specific */
+#define __NR_mlock 237
+#define __NR_munlock 238
+#define __NR_mlockall 239
+#define __NR_munlockall 240
+#define __NR_sched_setparam 241
+#define __NR_sched_getparam 242
+#define __NR_sched_setscheduler 243
+#define __NR_sched_getscheduler 244
+#define __NR_sched_yield 245
+#define __NR_sched_get_priority_max 246
+#define __NR_sched_get_priority_min 247
+#define __NR_sched_rr_get_interval 248
+#define __NR_nanosleep 249
+#define __NR_mremap 250
+#define __NR__sysctl 251
+#define __NR_getsid 252
+#define __NR_fdatasync 253
+#define __NR_nfsservctl 254
+#define __NR_sync_file_range 255
+#define __NR_clock_settime 256
+#define __NR_clock_gettime 257
+#define __NR_clock_getres 258
+#define __NR_clock_nanosleep 259
+#define __NR_sched_getaffinity 260
+#define __NR_sched_setaffinity 261
+#define __NR_timer_settime 262
+#define __NR_timer_gettime 263
+#define __NR_timer_getoverrun 264
+#define __NR_timer_delete 265
+#define __NR_timer_create 266
+/* #define __NR_vserver 267 Reserved for VSERVER */
+#define __NR_io_setup 268
+#define __NR_io_destroy 269
+#define __NR_io_submit 270
+#define __NR_io_cancel 271
+#define __NR_io_getevents 272
+#define __NR_mq_open 273
+#define __NR_mq_unlink 274
+#define __NR_mq_timedsend 275
+#define __NR_mq_timedreceive 276
+#define __NR_mq_notify 277
+#define __NR_mq_getsetattr 278
+#define __NR_waitid 279
+#define __NR_tee 280
+#define __NR_add_key 281
+#define __NR_request_key 282
+#define __NR_keyctl 283
+#define __NR_openat 284
+#define __NR_mkdirat 285
+#define __NR_mknodat 286
+#define __NR_fchownat 287
+#define __NR_futimesat 288
+#define __NR_fstatat64 289
+#define __NR_unlinkat 290
+#define __NR_renameat 291
+#define __NR_linkat 292
+#define __NR_symlinkat 293
+#define __NR_readlinkat 294
+#define __NR_fchmodat 295
+#define __NR_faccessat 296
+#define __NR_pselect6 297
+#define __NR_ppoll 298
+#define __NR_unshare 299
+#define __NR_set_robust_list 300
+#define __NR_get_robust_list 301
+#define __NR_migrate_pages 302
+#define __NR_mbind 303
+#define __NR_get_mempolicy 304
+#define __NR_set_mempolicy 305
+#define __NR_kexec_load 306
+#define __NR_move_pages 307
+#define __NR_getcpu 308
+#define __NR_epoll_pwait 309
+#define __NR_utimensat 310
+#define __NR_signalfd 311
+#define __NR_timerfd_create 312
+#define __NR_eventfd 313
+#define __NR_fallocate 314
+#define __NR_timerfd_settime 315
+#define __NR_timerfd_gettime 316
+#define __NR_signalfd4 317
+#define __NR_eventfd2 318
+#define __NR_epoll_create1 319
+#define __NR_dup3 320
+#define __NR_pipe2 321
+#define __NR_inotify_init1 322
+#define __NR_accept4 323
+#define __NR_preadv 324
+#define __NR_pwritev 325
+#define __NR_rt_tgsigqueueinfo 326
+#define __NR_perf_event_open 327
+#define __NR_recvmmsg 328
+#define __NR_fanotify_init 329
+#define __NR_fanotify_mark 330
+#define __NR_prlimit64 331
+#define __NR_name_to_handle_at 332
+#define __NR_open_by_handle_at 333
+#define __NR_clock_adjtime 334
+#define __NR_syncfs 335
+#define __NR_sendmmsg 336
+#define __NR_setns 337
+#define __NR_process_vm_readv 338
+#define __NR_process_vm_writev 339
+
+#define NR_syscalls 340
+
+#ifdef __32bit_syscall_numbers__
+/* Sparc 32-bit only has the "setresuid32", "getresuid32" variants,
+ * it never had the plain ones and there is no value to adding those
+ * old versions into the syscall table.
+ */
+#define __IGNORE_setresuid
+#define __IGNORE_getresuid
+#define __IGNORE_setresgid
+#define __IGNORE_getresgid
+#endif
+
+#endif /* _UAPI_SPARC_UNISTD_H */
diff --git a/arch/sparc/include/asm/utrap.h b/arch/sparc/include/uapi/asm/utrap.h
index b10e527..b10e527 100644
--- a/arch/sparc/include/asm/utrap.h
+++ b/arch/sparc/include/uapi/asm/utrap.h
diff --git a/arch/sparc/include/asm/watchdog.h b/arch/sparc/include/uapi/asm/watchdog.h
index 5baf2d3..5baf2d3 100644
--- a/arch/sparc/include/asm/watchdog.h
+++ b/arch/sparc/include/uapi/asm/watchdog.h
diff --git a/arch/tile/include/asm/Kbuild b/arch/tile/include/asm/Kbuild
index ea2e8ea..5cd98fa 100644
--- a/arch/tile/include/asm/Kbuild
+++ b/arch/tile/include/asm/Kbuild
@@ -13,6 +13,7 @@ generic-y += cputime.h
generic-y += div64.h
generic-y += emergency-restart.h
generic-y += errno.h
+generic-y += exec.h
generic-y += fb.h
generic-y += fcntl.h
generic-y += ioctl.h
diff --git a/arch/tile/include/asm/exec.h b/arch/tile/include/asm/exec.h
deleted file mode 100644
index a714e19..0000000
--- a/arch/tile/include/asm/exec.h
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright 2010 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_EXEC_H
-#define _ASM_TILE_EXEC_H
-
-#define arch_align_stack(x) (x)
-
-#endif /* _ASM_TILE_EXEC_H */
diff --git a/arch/tile/kernel/compat_signal.c b/arch/tile/kernel/compat_signal.c
index 7bc0859..08b4fe1 100644
--- a/arch/tile/kernel/compat_signal.c
+++ b/arch/tile/kernel/compat_signal.c
@@ -354,15 +354,6 @@ int compat_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
regs->regs[1] = ptr_to_compat_reg(&frame->info);
regs->regs[2] = ptr_to_compat_reg(&frame->uc);
regs->flags |= PT_FLAGS_CALLER_SAVES;
-
- /*
- * Notify any tracer that was single-stepping it.
- * The tracer may want to single-step inside the
- * handler too.
- */
- if (test_thread_flag(TIF_SINGLESTEP))
- ptrace_notify(SIGTRAP);
-
return 0;
give_sigsegv:
diff --git a/arch/tile/kernel/signal.c b/arch/tile/kernel/signal.c
index e29b055..67efb65 100644
--- a/arch/tile/kernel/signal.c
+++ b/arch/tile/kernel/signal.c
@@ -219,15 +219,6 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
regs->regs[1] = (unsigned long) &frame->info;
regs->regs[2] = (unsigned long) &frame->uc;
regs->flags |= PT_FLAGS_CALLER_SAVES;
-
- /*
- * Notify any tracer that was single-stepping it.
- * The tracer may want to single-step inside the
- * handler too.
- */
- if (test_thread_flag(TIF_SINGLESTEP))
- ptrace_notify(SIGTRAP);
-
return 0;
give_sigsegv:
@@ -278,7 +269,8 @@ static void handle_signal(unsigned long sig, siginfo_t *info,
ret = setup_rt_frame(sig, ka, info, oldset, regs);
if (ret)
return;
- signal_delivered(sig, info, ka, regs, 0);
+ signal_delivered(sig, info, ka, regs,
+ test_thread_flag(TIF_SINGLESTEP));
}
/*
diff --git a/arch/um/drivers/chan_kern.c b/arch/um/drivers/chan_kern.c
index 87eebfe..c3bba73 100644
--- a/arch/um/drivers/chan_kern.c
+++ b/arch/um/drivers/chan_kern.c
@@ -7,8 +7,8 @@
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include "chan.h"
-#include "os.h"
-#include "irq_kern.h"
+#include <os.h>
+#include <irq_kern.h>
#ifdef CONFIG_NOCONFIG_CHAN
static void *not_configged_init(char *str, int device,
diff --git a/arch/um/drivers/chan_user.c b/arch/um/drivers/chan_user.c
index f180813..9be670a 100644
--- a/arch/um/drivers/chan_user.c
+++ b/arch/um/drivers/chan_user.c
@@ -11,8 +11,8 @@
#include <termios.h>
#include <sys/ioctl.h>
#include "chan_user.h"
-#include "os.h"
-#include "um_malloc.h"
+#include <os.h>
+#include <um_malloc.h>
void generic_close(int fd, void *unused)
{
diff --git a/arch/um/drivers/chan_user.h b/arch/um/drivers/chan_user.h
index 6257b7a..dc693298 100644
--- a/arch/um/drivers/chan_user.h
+++ b/arch/um/drivers/chan_user.h
@@ -6,7 +6,7 @@
#ifndef __CHAN_USER_H__
#define __CHAN_USER_H__
-#include "init.h"
+#include <init.h>
struct chan_opts {
void (*const announce)(char *dev_name, int dev);
diff --git a/arch/um/drivers/cow_sys.h b/arch/um/drivers/cow_sys.h
index 7f2ed0b..67cbee6 100644
--- a/arch/um/drivers/cow_sys.h
+++ b/arch/um/drivers/cow_sys.h
@@ -1,9 +1,9 @@
#ifndef __COW_SYS_H__
#define __COW_SYS_H__
-#include "kern_util.h"
-#include "os.h"
-#include "um_malloc.h"
+#include <kern_util.h>
+#include <os.h>
+#include <um_malloc.h>
static inline void *cow_malloc(int size)
{
diff --git a/arch/um/drivers/daemon.h b/arch/um/drivers/daemon.h
index 6e0e891..c2dd195 100644
--- a/arch/um/drivers/daemon.h
+++ b/arch/um/drivers/daemon.h
@@ -6,7 +6,7 @@
#ifndef __DAEMON_H__
#define __DAEMON_H__
-#include "net_user.h"
+#include <net_user.h>
#define SWITCH_VERSION 3
diff --git a/arch/um/drivers/daemon_kern.c b/arch/um/drivers/daemon_kern.c
index b4a1522..7568cc2 100644
--- a/arch/um/drivers/daemon_kern.c
+++ b/arch/um/drivers/daemon_kern.c
@@ -6,9 +6,9 @@
* Licensed under the GPL.
*/
-#include "linux/init.h"
+#include <linux/init.h>
#include <linux/netdevice.h>
-#include "net_kern.h"
+#include <net_kern.h>
#include "daemon.h"
struct daemon_init {
diff --git a/arch/um/drivers/daemon_user.c b/arch/um/drivers/daemon_user.c
index a4fd7bc..8813c10 100644
--- a/arch/um/drivers/daemon_user.c
+++ b/arch/um/drivers/daemon_user.c
@@ -14,9 +14,9 @@
#include <sys/time.h>
#include <sys/un.h>
#include "daemon.h"
-#include "net_user.h"
-#include "os.h"
-#include "um_malloc.h"
+#include <net_user.h>
+#include <os.h>
+#include <um_malloc.h>
enum request_type { REQ_NEW_CONTROL };
diff --git a/arch/um/drivers/fd.c b/arch/um/drivers/fd.c
index 5b81d25..a13a427 100644
--- a/arch/um/drivers/fd.c
+++ b/arch/um/drivers/fd.c
@@ -9,8 +9,8 @@
#include <errno.h>
#include <termios.h>
#include "chan_user.h"
-#include "os.h"
-#include "um_malloc.h"
+#include <os.h>
+#include <um_malloc.h>
struct fd_chan {
int fd;
diff --git a/arch/um/drivers/harddog_user.c b/arch/um/drivers/harddog_user.c
index 0345d62..f99b32a 100644
--- a/arch/um/drivers/harddog_user.c
+++ b/arch/um/drivers/harddog_user.c
@@ -6,7 +6,7 @@
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
-#include "os.h"
+#include <os.h>
struct dog_data {
int stdin;
diff --git a/arch/um/drivers/hostaudio_kern.c b/arch/um/drivers/hostaudio_kern.c
index f9f6a4e..9b90fdc 100644
--- a/arch/um/drivers/hostaudio_kern.c
+++ b/arch/um/drivers/hostaudio_kern.c
@@ -3,15 +3,15 @@
* Licensed under the GPL
*/
-#include "linux/fs.h"
-#include "linux/module.h"
-#include "linux/slab.h"
-#include "linux/sound.h"
-#include "linux/soundcard.h"
-#include "linux/mutex.h"
-#include "asm/uaccess.h"
-#include "init.h"
-#include "os.h"
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/sound.h>
+#include <linux/soundcard.h>
+#include <linux/mutex.h>
+#include <asm/uaccess.h>
+#include <init.h>
+#include <os.h>
struct hostaudio_state {
int fd;
diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c
index 457475f..fd9a15b 100644
--- a/arch/um/drivers/line.c
+++ b/arch/um/drivers/line.c
@@ -3,15 +3,15 @@
* Licensed under the GPL
*/
-#include "linux/irqreturn.h"
-#include "linux/kd.h"
-#include "linux/sched.h"
-#include "linux/slab.h"
+#include <linux/irqreturn.h>
+#include <linux/kd.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
#include "chan.h"
-#include "irq_kern.h"
-#include "irq_user.h"
-#include "kern_util.h"
-#include "os.h"
+#include <irq_kern.h>
+#include <irq_user.h>
+#include <kern_util.h>
+#include <os.h>
#define LINE_BUFSIZE 4096
diff --git a/arch/um/drivers/line.h b/arch/um/drivers/line.h
index bae9561..138a145 100644
--- a/arch/um/drivers/line.h
+++ b/arch/um/drivers/line.h
@@ -6,12 +6,12 @@
#ifndef __LINE_H__
#define __LINE_H__
-#include "linux/list.h"
-#include "linux/workqueue.h"
-#include "linux/tty.h"
-#include "linux/interrupt.h"
-#include "linux/spinlock.h"
-#include "linux/mutex.h"
+#include <linux/list.h>
+#include <linux/workqueue.h>
+#include <linux/tty.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/mutex.h>
#include "chan_user.h"
#include "mconsole_kern.h"
diff --git a/arch/um/drivers/mconsole.h b/arch/um/drivers/mconsole.h
index c139ae1..8b22535 100644
--- a/arch/um/drivers/mconsole.h
+++ b/arch/um/drivers/mconsole.h
@@ -12,7 +12,7 @@
#define u32 uint32_t
#endif
-#include "sysdep/ptrace.h"
+#include <sysdep/ptrace.h>
#define MCONSOLE_MAGIC (0xcafebabe)
#define MCONSOLE_MAX_DATA (512)
diff --git a/arch/um/drivers/mconsole_kern.c b/arch/um/drivers/mconsole_kern.c
index 9efeb6d..79ccfe6 100644
--- a/arch/um/drivers/mconsole_kern.c
+++ b/arch/um/drivers/mconsole_kern.c
@@ -27,13 +27,13 @@
#include <asm/uaccess.h>
#include <asm/switch_to.h>
-#include "init.h"
-#include "irq_kern.h"
-#include "irq_user.h"
-#include "kern_util.h"
+#include <init.h>
+#include <irq_kern.h>
+#include <irq_user.h>
+#include <kern_util.h>
#include "mconsole.h"
#include "mconsole_kern.h"
-#include "os.h"
+#include <os.h>
static int do_unlink_socket(struct notifier_block *notifier,
unsigned long what, void *data)
diff --git a/arch/um/drivers/mconsole_kern.h b/arch/um/drivers/mconsole_kern.h
index d2fe07e..7a0c6a1 100644
--- a/arch/um/drivers/mconsole_kern.h
+++ b/arch/um/drivers/mconsole_kern.h
@@ -6,7 +6,7 @@
#ifndef __MCONSOLE_KERN_H__
#define __MCONSOLE_KERN_H__
-#include "linux/list.h"
+#include <linux/list.h>
#include "mconsole.h"
struct mconsole_entry {
diff --git a/arch/um/drivers/mmapper_kern.c b/arch/um/drivers/mmapper_kern.c
index c0ef803..62145c2 100644
--- a/arch/um/drivers/mmapper_kern.c
+++ b/arch/um/drivers/mmapper_kern.c
@@ -18,7 +18,7 @@
#include <linux/mm.h>
#include <asm/uaccess.h>
-#include "mem_user.h"
+#include <mem_user.h>
/* These are set in mmapper_init, which is called at boot time */
static unsigned long mmapper_size;
diff --git a/arch/um/drivers/net_kern.c b/arch/um/drivers/net_kern.c
index 458d324..b1314eb 100644
--- a/arch/um/drivers/net_kern.c
+++ b/arch/um/drivers/net_kern.c
@@ -18,12 +18,12 @@
#include <linux/skbuff.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
-#include "init.h"
-#include "irq_kern.h"
-#include "irq_user.h"
+#include <init.h>
+#include <irq_kern.h>
+#include <irq_user.h>
#include "mconsole_kern.h"
-#include "net_kern.h"
-#include "net_user.h"
+#include <net_kern.h>
+#include <net_user.h>
#define DRIVER_NAME "uml-netdev"
diff --git a/arch/um/drivers/net_user.c b/arch/um/drivers/net_user.c
index 05090c3..cd14157 100644
--- a/arch/um/drivers/net_user.c
+++ b/arch/um/drivers/net_user.c
@@ -11,9 +11,9 @@
#include <string.h>
#include <sys/socket.h>
#include <sys/wait.h>
-#include "net_user.h"
-#include "os.h"
-#include "um_malloc.h"
+#include <net_user.h>
+#include <os.h>
+#include <um_malloc.h>
int tap_open_common(void *dev, char *gate_addr)
{
diff --git a/arch/um/drivers/null.c b/arch/um/drivers/null.c
index 2b45a14..1049574 100644
--- a/arch/um/drivers/null.c
+++ b/arch/um/drivers/null.c
@@ -7,7 +7,7 @@
#include <errno.h>
#include <fcntl.h>
#include "chan_user.h"
-#include "os.h"
+#include <os.h>
/* This address is used only as a unique identifier */
static int null_chan;
diff --git a/arch/um/drivers/pcap_kern.c b/arch/um/drivers/pcap_kern.c
index 2860525..be0fb57bd 100644
--- a/arch/um/drivers/pcap_kern.c
+++ b/arch/um/drivers/pcap_kern.c
@@ -3,9 +3,9 @@
* Licensed under the GPL.
*/
-#include "linux/init.h"
+#include <linux/init.h>
#include <linux/netdevice.h>
-#include "net_kern.h"
+#include <net_kern.h>
#include "pcap_user.h"
struct pcap_init {
diff --git a/arch/um/drivers/pcap_user.c b/arch/um/drivers/pcap_user.c
index 702a75b..c07b9c7 100644
--- a/arch/um/drivers/pcap_user.c
+++ b/arch/um/drivers/pcap_user.c
@@ -7,9 +7,9 @@
#include <pcap.h>
#include <string.h>
#include <asm/types.h>
-#include "net_user.h"
+#include <net_user.h>
#include "pcap_user.h"
-#include "um_malloc.h"
+#include <um_malloc.h>
#define PCAP_FD(p) (*(int *)(p))
diff --git a/arch/um/drivers/pcap_user.h b/arch/um/drivers/pcap_user.h
index d8ba615..1ca7c76 100644
--- a/arch/um/drivers/pcap_user.h
+++ b/arch/um/drivers/pcap_user.h
@@ -3,7 +3,7 @@
* Licensed under the GPL
*/
-#include "net_user.h"
+#include <net_user.h>
struct pcap_data {
char *host_if;
diff --git a/arch/um/drivers/port_kern.c b/arch/um/drivers/port_kern.c
index 1d83d50..40ca5cc 100644
--- a/arch/um/drivers/port_kern.c
+++ b/arch/um/drivers/port_kern.c
@@ -3,16 +3,16 @@
* Licensed under the GPL
*/
-#include "linux/completion.h"
-#include "linux/interrupt.h"
-#include "linux/list.h"
-#include "linux/mutex.h"
-#include "linux/slab.h"
-#include "linux/workqueue.h"
-#include "asm/atomic.h"
-#include "init.h"
-#include "irq_kern.h"
-#include "os.h"
+#include <linux/completion.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include <asm/atomic.h>
+#include <init.h>
+#include <irq_kern.h>
+#include <os.h>
#include "port.h"
struct port_list {
diff --git a/arch/um/drivers/port_user.c b/arch/um/drivers/port_user.c
index 7b010b7..9a8e1b6 100644
--- a/arch/um/drivers/port_user.c
+++ b/arch/um/drivers/port_user.c
@@ -10,9 +10,9 @@
#include <unistd.h>
#include <netinet/in.h>
#include "chan_user.h"
-#include "os.h"
+#include <os.h>
#include "port.h"
-#include "um_malloc.h"
+#include <um_malloc.h>
struct port_chan {
int raw;
diff --git a/arch/um/drivers/pty.c b/arch/um/drivers/pty.c
index cff2b75..f1fcc2c 100644
--- a/arch/um/drivers/pty.c
+++ b/arch/um/drivers/pty.c
@@ -12,8 +12,8 @@
#include <termios.h>
#include <sys/stat.h>
#include "chan_user.h"
-#include "os.h"
-#include "um_malloc.h"
+#include <os.h>
+#include <um_malloc.h>
struct pty_chan {
void (*announce)(char *dev_name, int dev);
diff --git a/arch/um/drivers/random.c b/arch/um/drivers/random.c
index e32c6aa..9e3a722 100644
--- a/arch/um/drivers/random.c
+++ b/arch/um/drivers/random.c
@@ -13,8 +13,8 @@
#include <linux/miscdevice.h>
#include <linux/delay.h>
#include <asm/uaccess.h>
-#include "irq_kern.h"
-#include "os.h"
+#include <irq_kern.h>
+#include <os.h>
/*
* core module and version information
diff --git a/arch/um/drivers/slip_common.c b/arch/um/drivers/slip_common.c
index e89cfc6..f597fa7 100644
--- a/arch/um/drivers/slip_common.c
+++ b/arch/um/drivers/slip_common.c
@@ -1,6 +1,6 @@
#include <string.h>
#include "slip_common.h"
-#include "net_user.h"
+#include <net_user.h>
int slip_proto_read(int fd, void *buf, int len, struct slip_proto *slip)
{
diff --git a/arch/um/drivers/slip_kern.c b/arch/um/drivers/slip_kern.c
index dd2aadc..ed5249f 100644
--- a/arch/um/drivers/slip_kern.c
+++ b/arch/um/drivers/slip_kern.c
@@ -6,7 +6,7 @@
#include <linux/if_arp.h>
#include <linux/init.h>
#include <linux/netdevice.h>
-#include "net_kern.h"
+#include <net_kern.h>
#include "slip.h"
struct slip_init {
diff --git a/arch/um/drivers/slip_user.c b/arch/um/drivers/slip_user.c
index 932b4d6..55c290d 100644
--- a/arch/um/drivers/slip_user.c
+++ b/arch/um/drivers/slip_user.c
@@ -11,10 +11,10 @@
#include <string.h>
#include <sys/termios.h>
#include <sys/wait.h>
-#include "net_user.h"
-#include "os.h"
+#include <net_user.h>
+#include <os.h>
#include "slip.h"
-#include "um_malloc.h"
+#include <um_malloc.h>
static int slip_user_init(void *data, void *dev)
{
diff --git a/arch/um/drivers/slirp_kern.c b/arch/um/drivers/slirp_kern.c
index e376284..4ef11ca 100644
--- a/arch/um/drivers/slirp_kern.c
+++ b/arch/um/drivers/slirp_kern.c
@@ -4,11 +4,11 @@
*/
#include <linux/if_arp.h>
-#include "linux/init.h"
+#include <linux/init.h>
#include <linux/netdevice.h>
#include <linux/string.h>
-#include "net_kern.h"
-#include "net_user.h"
+#include <net_kern.h>
+#include <net_user.h>
#include "slirp.h"
struct slirp_init {
diff --git a/arch/um/drivers/slirp_user.c b/arch/um/drivers/slirp_user.c
index db4adb6..c999d18 100644
--- a/arch/um/drivers/slirp_user.c
+++ b/arch/um/drivers/slirp_user.c
@@ -7,8 +7,8 @@
#include <errno.h>
#include <string.h>
#include <sys/wait.h>
-#include "net_user.h"
-#include "os.h"
+#include <net_user.h>
+#include <os.h>
#include "slirp.h"
static int slirp_user_init(void *data, void *dev)
diff --git a/arch/um/drivers/ssl.c b/arch/um/drivers/ssl.c
index 7e86f00..16fdd0a 100644
--- a/arch/um/drivers/ssl.c
+++ b/arch/um/drivers/ssl.c
@@ -3,19 +3,19 @@
* Licensed under the GPL
*/
-#include "linux/fs.h"
-#include "linux/tty.h"
-#include "linux/tty_driver.h"
-#include "linux/major.h"
-#include "linux/mm.h"
-#include "linux/init.h"
-#include "linux/console.h"
-#include "asm/termbits.h"
-#include "asm/irq.h"
+#include <linux/fs.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/major.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <asm/termbits.h>
+#include <asm/irq.h>
#include "ssl.h"
#include "chan.h"
-#include "init.h"
-#include "irq_user.h"
+#include <init.h>
+#include <irq_user.h>
#include "mconsole_kern.h"
static const int ssl_version = 1;
diff --git a/arch/um/drivers/stdio_console.c b/arch/um/drivers/stdio_console.c
index 929b99a..827777a 100644
--- a/arch/um/drivers/stdio_console.c
+++ b/arch/um/drivers/stdio_console.c
@@ -3,27 +3,27 @@
* Licensed under the GPL
*/
-#include "linux/posix_types.h"
-#include "linux/tty.h"
-#include "linux/tty_flip.h"
-#include "linux/types.h"
-#include "linux/major.h"
-#include "linux/kdev_t.h"
-#include "linux/console.h"
-#include "linux/string.h"
-#include "linux/sched.h"
-#include "linux/list.h"
-#include "linux/init.h"
-#include "linux/interrupt.h"
-#include "linux/slab.h"
-#include "linux/hardirq.h"
-#include "asm/current.h"
-#include "asm/irq.h"
+#include <linux/posix_types.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/types.h>
+#include <linux/major.h>
+#include <linux/kdev_t.h>
+#include <linux/console.h>
+#include <linux/string.h>
+#include <linux/sched.h>
+#include <linux/list.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/hardirq.h>
+#include <asm/current.h>
+#include <asm/irq.h>
#include "stdio_console.h"
#include "chan.h"
-#include "irq_user.h"
+#include <irq_user.h>
#include "mconsole_kern.h"
-#include "init.h"
+#include <init.h>
#define MAX_TTYS (16)
diff --git a/arch/um/drivers/tty.c b/arch/um/drivers/tty.c
index a97391f..eaa201b 100644
--- a/arch/um/drivers/tty.c
+++ b/arch/um/drivers/tty.c
@@ -7,8 +7,8 @@
#include <fcntl.h>
#include <termios.h>
#include "chan_user.h"
-#include "os.h"
-#include "um_malloc.h"
+#include <os.h>
+#include <um_malloc.h>
struct tty_chan {
char *dev;
diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c
index 0643e5b..41bf720 100644
--- a/arch/um/drivers/ubd_kern.c
+++ b/arch/um/drivers/ubd_kern.c
@@ -33,12 +33,12 @@
#include <linux/platform_device.h>
#include <linux/scatterlist.h>
#include <asm/tlbflush.h>
-#include "kern_util.h"
+#include <kern_util.h>
#include "mconsole_kern.h"
-#include "init.h"
-#include "irq_kern.h"
+#include <init.h>
+#include <irq_kern.h>
#include "ubd.h"
-#include "os.h"
+#include <os.h>
#include "cow.h"
enum ubd_req { UBD_READ, UBD_WRITE };
diff --git a/arch/um/drivers/ubd_user.c b/arch/um/drivers/ubd_user.c
index ffe02c4..a703e45 100644
--- a/arch/um/drivers/ubd_user.c
+++ b/arch/um/drivers/ubd_user.c
@@ -19,7 +19,7 @@
#include <byteswap.h>
#include "ubd.h"
-#include "os.h"
+#include <os.h>
void ignore_sigwinch_sig(void)
{
diff --git a/arch/um/drivers/umcast.h b/arch/um/drivers/umcast.h
index 6f8c0fe..c190c64 100644
--- a/arch/um/drivers/umcast.h
+++ b/arch/um/drivers/umcast.h
@@ -6,7 +6,7 @@
#ifndef __DRIVERS_UMCAST_H
#define __DRIVERS_UMCAST_H
-#include "net_user.h"
+#include <net_user.h>
struct umcast_data {
char *addr;
diff --git a/arch/um/drivers/umcast_kern.c b/arch/um/drivers/umcast_kern.c
index 42dab11..f5ba6e3 100644
--- a/arch/um/drivers/umcast_kern.c
+++ b/arch/um/drivers/umcast_kern.c
@@ -11,10 +11,10 @@
* Licensed under the GPL.
*/
-#include "linux/init.h"
+#include <linux/init.h>
#include <linux/netdevice.h>
#include "umcast.h"
-#include "net_kern.h"
+#include <net_kern.h>
struct umcast_init {
char *addr;
diff --git a/arch/um/drivers/umcast_user.c b/arch/um/drivers/umcast_user.c
index 010fa2d..6074184 100644
--- a/arch/um/drivers/umcast_user.c
+++ b/arch/um/drivers/umcast_user.c
@@ -16,8 +16,8 @@
#include <errno.h>
#include <netinet/in.h>
#include "umcast.h"
-#include "net_user.h"
-#include "um_malloc.h"
+#include <net_user.h>
+#include <um_malloc.h>
static struct sockaddr_in *new_addr(char *addr, unsigned short port)
{
diff --git a/arch/um/drivers/vde_kern.c b/arch/um/drivers/vde_kern.c
index 1b852bf..6a365fa 100644
--- a/arch/um/drivers/vde_kern.c
+++ b/arch/um/drivers/vde_kern.c
@@ -7,10 +7,10 @@
*
*/
-#include "linux/init.h"
+#include <linux/init.h>
#include <linux/netdevice.h>
-#include "net_kern.h"
-#include "net_user.h"
+#include <net_kern.h>
+#include <net_user.h>
#include "vde.h"
static void vde_init(struct net_device *dev, void *data)
diff --git a/arch/um/drivers/vde_user.c b/arch/um/drivers/vde_user.c
index b8c2867..64cb630 100644
--- a/arch/um/drivers/vde_user.c
+++ b/arch/um/drivers/vde_user.c
@@ -6,8 +6,8 @@
#include <stddef.h>
#include <errno.h>
#include <libvdeplug.h>
-#include "net_user.h"
-#include "um_malloc.h"
+#include <net_user.h>
+#include <um_malloc.h>
#include "vde.h"
static int vde_user_init(void *data, void *dev)
diff --git a/arch/um/drivers/xterm.c b/arch/um/drivers/xterm.c
index 969110e..20e30be 100644
--- a/arch/um/drivers/xterm.c
+++ b/arch/um/drivers/xterm.c
@@ -11,8 +11,8 @@
#include <string.h>
#include <termios.h>
#include "chan_user.h"
-#include "os.h"
-#include "um_malloc.h"
+#include <os.h>
+#include <um_malloc.h>
#include "xterm.h"
struct xterm_chan {
diff --git a/arch/um/drivers/xterm_kern.c b/arch/um/drivers/xterm_kern.c
index e3031e6..e8f9957 100644
--- a/arch/um/drivers/xterm_kern.c
+++ b/arch/um/drivers/xterm_kern.c
@@ -7,8 +7,8 @@
#include <linux/completion.h>
#include <linux/irqreturn.h>
#include <asm/irq.h>
-#include "irq_kern.h"
-#include "os.h"
+#include <irq_kern.h>
+#include <os.h>
struct xterm_wait {
struct completion ready;
diff --git a/arch/um/include/asm/dma.h b/arch/um/include/asm/dma.h
index 9f6139a..f88c586 100644
--- a/arch/um/include/asm/dma.h
+++ b/arch/um/include/asm/dma.h
@@ -1,7 +1,7 @@
#ifndef __UM_DMA_H
#define __UM_DMA_H
-#include "asm/io.h"
+#include <asm/io.h>
extern unsigned long uml_physmem;
diff --git a/arch/um/include/asm/mmu.h b/arch/um/include/asm/mmu.h
index 53e8b49..da70544 100644
--- a/arch/um/include/asm/mmu.h
+++ b/arch/um/include/asm/mmu.h
@@ -6,7 +6,7 @@
#ifndef __ARCH_UM_MMU_H
#define __ARCH_UM_MMU_H
-#include "mm_id.h"
+#include <mm_id.h>
#include <asm/mm_context.h>
typedef struct mm_context {
diff --git a/arch/um/include/asm/page.h b/arch/um/include/asm/page.h
index 7cfc3ce..5ff53d9 100644
--- a/arch/um/include/asm/page.h
+++ b/arch/um/include/asm/page.h
@@ -99,7 +99,7 @@ extern unsigned long uml_physmem;
#define __va_space (8*1024*1024)
-#include "mem.h"
+#include <mem.h>
/* Cast to unsigned long before casting to void * to avoid a warning from
* mmap_kmem about cutting a long long down to a void *. Not sure that
diff --git a/arch/um/include/asm/pgtable.h b/arch/um/include/asm/pgtable.h
index 5888f1b..ae02909 100644
--- a/arch/um/include/asm/pgtable.h
+++ b/arch/um/include/asm/pgtable.h
@@ -23,9 +23,9 @@
pte_present gives true */
#ifdef CONFIG_3_LEVEL_PGTABLES
-#include "asm/pgtable-3level.h"
+#include <asm/pgtable-3level.h>
#else
-#include "asm/pgtable-2level.h"
+#include <asm/pgtable-2level.h>
#endif
extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
diff --git a/arch/um/include/asm/processor-generic.h b/arch/um/include/asm/processor-generic.h
index 33a6a24..1e82e95 100644
--- a/arch/um/include/asm/processor-generic.h
+++ b/arch/um/include/asm/processor-generic.h
@@ -10,9 +10,9 @@ struct pt_regs;
struct task_struct;
-#include "asm/ptrace.h"
-#include "registers.h"
-#include "sysdep/archsetjmp.h"
+#include <asm/ptrace.h>
+#include <registers.h>
+#include <sysdep/archsetjmp.h>
#include <linux/prefetch.h>
@@ -63,8 +63,6 @@ static inline void release_thread(struct task_struct *task)
{
}
-extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
-
extern unsigned long thread_saved_pc(struct task_struct *t);
static inline void mm_copy_segments(struct mm_struct *from_mm,
diff --git a/arch/um/include/asm/ptrace-generic.h b/arch/um/include/asm/ptrace-generic.h
index 442f1d0..cb9b3c4 100644
--- a/arch/um/include/asm/ptrace-generic.h
+++ b/arch/um/include/asm/ptrace-generic.h
@@ -9,7 +9,7 @@
#ifndef __ASSEMBLY__
#include <asm/ptrace-abi.h>
-#include "sysdep/ptrace.h"
+#include <sysdep/ptrace.h>
struct pt_regs {
struct uml_pt_regs regs;
diff --git a/arch/um/include/asm/smp.h b/arch/um/include/asm/smp.h
index 4a4b09d..e450793 100644
--- a/arch/um/include/asm/smp.h
+++ b/arch/um/include/asm/smp.h
@@ -3,9 +3,9 @@
#ifdef CONFIG_SMP
-#include "linux/bitops.h"
-#include "asm/current.h"
-#include "linux/cpumask.h"
+#include <linux/bitops.h>
+#include <asm/current.h>
+#include <linux/cpumask.h>
#define raw_smp_processor_id() (current_thread->cpu)
diff --git a/arch/um/include/shared/sysrq.h b/arch/um/include/asm/sysrq.h
index c8d332b..c8d332b 100644
--- a/arch/um/include/shared/sysrq.h
+++ b/arch/um/include/asm/sysrq.h
diff --git a/arch/um/include/asm/thread_info.h b/arch/um/include/asm/thread_info.h
index c04e5ab..2c8eeb2 100644
--- a/arch/um/include/asm/thread_info.h
+++ b/arch/um/include/asm/thread_info.h
@@ -65,8 +65,6 @@ static inline struct thread_info *current_thread_info(void)
#define TIF_SYSCALL_TRACE 0 /* syscall trace active */
#define TIF_SIGPENDING 1 /* signal pending */
#define TIF_NEED_RESCHED 2 /* rescheduling necessary */
-#define TIF_POLLING_NRFLAG 3 /* true if poll_idle() is polling
- * TIF_NEED_RESCHED */
#define TIF_RESTART_BLOCK 4
#define TIF_MEMDIE 5 /* is terminating due to OOM killer */
#define TIF_SYSCALL_AUDIT 6
@@ -76,7 +74,6 @@ static inline struct thread_info *current_thread_info(void)
#define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE)
#define _TIF_SIGPENDING (1 << TIF_SIGPENDING)
#define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED)
-#define _TIF_POLLING_NRFLAG (1 << TIF_POLLING_NRFLAG)
#define _TIF_MEMDIE (1 << TIF_MEMDIE)
#define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT)
diff --git a/arch/um/include/shared/arch.h b/arch/um/include/shared/arch.h
index 2de92a0..4f46abd 100644
--- a/arch/um/include/shared/arch.h
+++ b/arch/um/include/shared/arch.h
@@ -6,7 +6,7 @@
#ifndef __ARCH_H__
#define __ARCH_H__
-#include "sysdep/ptrace.h"
+#include <sysdep/ptrace.h>
extern void arch_check_bugs(void);
extern int arch_fixup(unsigned long address, struct uml_pt_regs *regs);
diff --git a/arch/um/include/shared/as-layout.h b/arch/um/include/shared/as-layout.h
index 86daa54..694c792 100644
--- a/arch/um/include/shared/as-layout.h
+++ b/arch/um/include/shared/as-layout.h
@@ -35,7 +35,7 @@
#ifndef __ASSEMBLY__
-#include "sysdep/ptrace.h"
+#include <sysdep/ptrace.h>
struct cpu_task {
int pid;
diff --git a/arch/um/include/shared/irq_kern.h b/arch/um/include/shared/irq_kern.h
index 7a5bfa6..e05bd66 100644
--- a/arch/um/include/shared/irq_kern.h
+++ b/arch/um/include/shared/irq_kern.h
@@ -6,8 +6,8 @@
#ifndef __IRQ_KERN_H__
#define __IRQ_KERN_H__
-#include "linux/interrupt.h"
-#include "asm/ptrace.h"
+#include <linux/interrupt.h>
+#include <asm/ptrace.h>
extern int um_request_irq(unsigned int irq, int fd, int type,
irq_handler_t handler,
diff --git a/arch/um/include/shared/irq_user.h b/arch/um/include/shared/irq_user.h
index 2b6d703..df56330 100644
--- a/arch/um/include/shared/irq_user.h
+++ b/arch/um/include/shared/irq_user.h
@@ -6,7 +6,7 @@
#ifndef __IRQ_USER_H__
#define __IRQ_USER_H__
-#include "sysdep/ptrace.h"
+#include <sysdep/ptrace.h>
struct irq_fd {
struct irq_fd *next;
diff --git a/arch/um/include/shared/kern_util.h b/arch/um/include/shared/kern_util.h
index af6b6dc..83a91f9 100644
--- a/arch/um/include/shared/kern_util.h
+++ b/arch/um/include/shared/kern_util.h
@@ -6,8 +6,8 @@
#ifndef __KERN_UTIL_H__
#define __KERN_UTIL_H__
-#include "sysdep/ptrace.h"
-#include "sysdep/faultinfo.h"
+#include <sysdep/ptrace.h>
+#include <sysdep/faultinfo.h>
struct siginfo;
diff --git a/arch/um/include/shared/longjmp.h b/arch/um/include/shared/longjmp.h
index e860bc584..9bdddf4 100644
--- a/arch/um/include/shared/longjmp.h
+++ b/arch/um/include/shared/longjmp.h
@@ -1,8 +1,8 @@
#ifndef __UML_LONGJMP_H
#define __UML_LONGJMP_H
-#include "sysdep/archsetjmp.h"
-#include "os.h"
+#include <sysdep/archsetjmp.h>
+#include <os.h>
extern int setjmp(jmp_buf);
extern void longjmp(jmp_buf, int);
diff --git a/arch/um/include/shared/os.h b/arch/um/include/shared/os.h
index 89b686c1..4488304 100644
--- a/arch/um/include/shared/os.h
+++ b/arch/um/include/shared/os.h
@@ -7,9 +7,9 @@
#define __OS_H__
#include <stdarg.h>
-#include "irq_user.h"
-#include "longjmp.h"
-#include "mm_id.h"
+#include <irq_user.h>
+#include <longjmp.h>
+#include <mm_id.h>
#define CATCH_EINTR(expr) while ((errno = 0, ((expr) < 0)) && (errno == EINTR))
diff --git a/arch/um/include/shared/registers.h b/arch/um/include/shared/registers.h
index f1e0aa5..f5b7635 100644
--- a/arch/um/include/shared/registers.h
+++ b/arch/um/include/shared/registers.h
@@ -6,8 +6,8 @@
#ifndef __REGISTERS_H
#define __REGISTERS_H
-#include "sysdep/ptrace.h"
-#include "sysdep/archsetjmp.h"
+#include <sysdep/ptrace.h>
+#include <sysdep/archsetjmp.h>
extern int save_fp_registers(int pid, unsigned long *fp_regs);
extern int restore_fp_registers(int pid, unsigned long *fp_regs);
diff --git a/arch/um/include/shared/skas/skas.h b/arch/um/include/shared/skas/skas.h
index 64d2c74..c45df96 100644
--- a/arch/um/include/shared/skas/skas.h
+++ b/arch/um/include/shared/skas/skas.h
@@ -6,7 +6,7 @@
#ifndef __SKAS_H
#define __SKAS_H
-#include "sysdep/ptrace.h"
+#include <sysdep/ptrace.h>
extern int userspace_pid[];
extern int proc_mm, ptrace_faultinfo, ptrace_ldt;
diff --git a/arch/um/include/shared/skas_ptrace.h b/arch/um/include/shared/skas_ptrace.h
index 3d31bba..630a9c9 100644
--- a/arch/um/include/shared/skas_ptrace.h
+++ b/arch/um/include/shared/skas_ptrace.h
@@ -9,6 +9,6 @@
#define PTRACE_FAULTINFO 52
#define PTRACE_SWITCH_MM 55
-#include "sysdep/skas_ptrace.h"
+#include <sysdep/skas_ptrace.h>
#endif
diff --git a/arch/um/kernel/asm-offsets.c b/arch/um/kernel/asm-offsets.c
index 91ea538..1fb1223 100644
--- a/arch/um/kernel/asm-offsets.c
+++ b/arch/um/kernel/asm-offsets.c
@@ -1 +1 @@
-#include "sysdep/kernel-offsets.h"
+#include <sysdep/kernel-offsets.h>
diff --git a/arch/um/kernel/config.c.in b/arch/um/kernel/config.c.in
index b7a43fe..972bf16 100644
--- a/arch/um/kernel/config.c.in
+++ b/arch/um/kernel/config.c.in
@@ -5,7 +5,7 @@
#include <stdio.h>
#include <stdlib.h>
-#include "init.h"
+#include <init.h>
static __initdata const char *config[] = {
"CONFIG"
diff --git a/arch/um/kernel/dyn.lds.S b/arch/um/kernel/dyn.lds.S
index a3cab6d..fb8fd6f 100644
--- a/arch/um/kernel/dyn.lds.S
+++ b/arch/um/kernel/dyn.lds.S
@@ -89,7 +89,7 @@ SECTIONS
.kstrtab : { *(.kstrtab) }
- #include "asm/common.lds.S"
+ #include <asm/common.lds.S>
init.data : { INIT_DATA }
diff --git a/arch/um/kernel/early_printk.c b/arch/um/kernel/early_printk.c
index ec649bf..49480f0 100644
--- a/arch/um/kernel/early_printk.c
+++ b/arch/um/kernel/early_printk.c
@@ -9,7 +9,7 @@
#include <linux/kernel.h>
#include <linux/console.h>
#include <linux/init.h>
-#include "os.h"
+#include <os.h>
static void early_console_write(struct console *con, const char *s, unsigned int n)
{
diff --git a/arch/um/kernel/exec.c b/arch/um/kernel/exec.c
index 8c82786..ab019c7 100644
--- a/arch/um/kernel/exec.c
+++ b/arch/um/kernel/exec.c
@@ -12,11 +12,10 @@
#include <asm/current.h>
#include <asm/processor.h>
#include <asm/uaccess.h>
-#include "as-layout.h"
-#include "mem_user.h"
-#include "skas.h"
-#include "os.h"
-#include "internal.h"
+#include <as-layout.h>
+#include <mem_user.h>
+#include <skas.h>
+#include <os.h>
void flush_thread(void)
{
@@ -49,27 +48,7 @@ void start_thread(struct pt_regs *regs, unsigned long eip, unsigned long esp)
}
EXPORT_SYMBOL(start_thread);
-long um_execve(const char *file, const char __user *const __user *argv, const char __user *const __user *env)
+void __noreturn ret_from_kernel_execve(struct pt_regs *unused)
{
- long err;
-
- err = do_execve(file, argv, env, &current->thread.regs);
- if (!err)
- UML_LONGJMP(current->thread.exec_buf, 1);
- return err;
-}
-
-long sys_execve(const char __user *file, const char __user *const __user *argv,
- const char __user *const __user *env)
-{
- long error;
- char *filename;
-
- filename = getname(file);
- error = PTR_ERR(filename);
- if (IS_ERR(filename)) goto out;
- error = do_execve(filename, argv, env, &current->thread.regs);
- putname(filename);
- out:
- return error;
+ UML_LONGJMP(current->thread.exec_buf, 1);
}
diff --git a/arch/um/kernel/gmon_syms.c b/arch/um/kernel/gmon_syms.c
index e9bcf247..1bf6126 100644
--- a/arch/um/kernel/gmon_syms.c
+++ b/arch/um/kernel/gmon_syms.c
@@ -3,7 +3,7 @@
* Licensed under the GPL
*/
-#include "linux/module.h"
+#include <linux/module.h>
extern void __bb_init_func(void *) __attribute__((weak));
EXPORT_SYMBOL(__bb_init_func);
diff --git a/arch/um/kernel/gprof_syms.c b/arch/um/kernel/gprof_syms.c
index e2f043d..74ddb44 100644
--- a/arch/um/kernel/gprof_syms.c
+++ b/arch/um/kernel/gprof_syms.c
@@ -3,7 +3,7 @@
* Licensed under the GPL
*/
-#include "linux/module.h"
+#include <linux/module.h>
extern void mcount(void);
EXPORT_SYMBOL(mcount);
diff --git a/arch/um/kernel/initrd.c b/arch/um/kernel/initrd.c
index 10cc18f..55cead8 100644
--- a/arch/um/kernel/initrd.c
+++ b/arch/um/kernel/initrd.c
@@ -3,12 +3,12 @@
* Licensed under the GPL
*/
-#include "linux/init.h"
-#include "linux/bootmem.h"
-#include "linux/initrd.h"
-#include "asm/types.h"
-#include "init.h"
-#include "os.h"
+#include <linux/init.h>
+#include <linux/bootmem.h>
+#include <linux/initrd.h>
+#include <asm/types.h>
+#include <init.h>
+#include <os.h>
/* Changed by uml_initrd_setup, which is a setup */
static char *initrd __initdata = NULL;
diff --git a/arch/um/kernel/internal.h b/arch/um/kernel/internal.h
deleted file mode 100644
index 5bf97db..0000000
--- a/arch/um/kernel/internal.h
+++ /dev/null
@@ -1 +0,0 @@
-extern long um_execve(const char *file, const char __user *const __user *argv, const char __user *const __user *env);
diff --git a/arch/um/kernel/irq.c b/arch/um/kernel/irq.c
index 9883026..36e12f0 100644
--- a/arch/um/kernel/irq.c
+++ b/arch/um/kernel/irq.c
@@ -5,17 +5,17 @@
* Copyright (C) 1992, 1998 Linus Torvalds, Ingo Molnar
*/
-#include "linux/cpumask.h"
-#include "linux/hardirq.h"
-#include "linux/interrupt.h"
-#include "linux/kernel_stat.h"
-#include "linux/module.h"
-#include "linux/sched.h"
-#include "linux/seq_file.h"
-#include "linux/slab.h"
-#include "as-layout.h"
-#include "kern_util.h"
-#include "os.h"
+#include <linux/cpumask.h>
+#include <linux/hardirq.h>
+#include <linux/interrupt.h>
+#include <linux/kernel_stat.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/seq_file.h>
+#include <linux/slab.h>
+#include <as-layout.h>
+#include <kern_util.h>
+#include <os.h>
/*
* This list is accessed under irq_lock, except in sigio_handler,
diff --git a/arch/um/kernel/ksyms.c b/arch/um/kernel/ksyms.c
index e17bea0..543c047 100644
--- a/arch/um/kernel/ksyms.c
+++ b/arch/um/kernel/ksyms.c
@@ -4,7 +4,7 @@
*/
#include <linux/module.h>
-#include "os.h"
+#include <os.h>
EXPORT_SYMBOL(set_signals);
EXPORT_SYMBOL(get_signals);
diff --git a/arch/um/kernel/mem.c b/arch/um/kernel/mem.c
index ebb86b2..5abcbfb 100644
--- a/arch/um/kernel/mem.c
+++ b/arch/um/kernel/mem.c
@@ -12,12 +12,12 @@
#include <linux/slab.h>
#include <asm/fixmap.h>
#include <asm/page.h>
-#include "as-layout.h"
-#include "init.h"
-#include "kern.h"
-#include "kern_util.h"
-#include "mem_user.h"
-#include "os.h"
+#include <as-layout.h>
+#include <init.h>
+#include <kern.h>
+#include <kern_util.h>
+#include <mem_user.h>
+#include <os.h>
/* allocated in paging_init, zeroed in mem_init, and unchanged thereafter */
unsigned long *empty_zero_page = NULL;
diff --git a/arch/um/kernel/process.c b/arch/um/kernel/process.c
index c5f5afa..3062978 100644
--- a/arch/um/kernel/process.c
+++ b/arch/um/kernel/process.c
@@ -23,10 +23,10 @@
#include <asm/pgtable.h>
#include <asm/mmu_context.h>
#include <asm/uaccess.h>
-#include "as-layout.h"
-#include "kern_util.h"
-#include "os.h"
-#include "skas.h"
+#include <as-layout.h>
+#include <kern_util.h>
+#include <os.h>
+#include <skas.h>
/*
* This is a per-cpu array. A processor only modifies its entry and it only
@@ -69,18 +69,6 @@ unsigned long alloc_stack(int order, int atomic)
return page;
}
-int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
-{
- int pid;
-
- current->thread.request.u.thread.proc = fn;
- current->thread.request.u.thread.arg = arg;
- pid = do_fork(CLONE_VM | CLONE_UNTRACED | flags, 0,
- &current->thread.regs, 0, NULL, NULL);
- return pid;
-}
-EXPORT_SYMBOL(kernel_thread);
-
static inline void set_current(struct task_struct *task)
{
cpu_tasks[task_thread_info(task)->cpu] = ((struct cpu_task)
@@ -177,7 +165,7 @@ void fork_handler(void)
}
int copy_thread(unsigned long clone_flags, unsigned long sp,
- unsigned long stack_top, struct task_struct * p,
+ unsigned long arg, struct task_struct * p,
struct pt_regs *regs)
{
void (*handler)(void);
@@ -198,7 +186,8 @@ int copy_thread(unsigned long clone_flags, unsigned long sp,
arch_copy_thread(&current->thread.arch, &p->thread.arch);
} else {
get_safe_registers(p->thread.regs.regs.gp, p->thread.regs.regs.fp);
- p->thread.request.u.thread = current->thread.request.u.thread;
+ p->thread.request.u.thread.proc = (int (*)(void *))sp;
+ p->thread.request.u.thread.arg = (void *)arg;
handler = new_thread_handler;
}
diff --git a/arch/um/kernel/reboot.c b/arch/um/kernel/reboot.c
index 3d15243..ced8903 100644
--- a/arch/um/kernel/reboot.c
+++ b/arch/um/kernel/reboot.c
@@ -3,13 +3,13 @@
* Licensed under the GPL
*/
-#include "linux/sched.h"
-#include "linux/spinlock.h"
-#include "linux/slab.h"
-#include "linux/oom.h"
-#include "kern_util.h"
-#include "os.h"
-#include "skas.h"
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/oom.h>
+#include <kern_util.h>
+#include <os.h>
+#include <skas.h>
void (*pm_power_off)(void);
diff --git a/arch/um/kernel/sigio.c b/arch/um/kernel/sigio.c
index c882111..b5e0cbb 100644
--- a/arch/um/kernel/sigio.c
+++ b/arch/um/kernel/sigio.c
@@ -4,9 +4,9 @@
*/
#include <linux/interrupt.h>
-#include "irq_kern.h"
-#include "os.h"
-#include "sigio.h"
+#include <irq_kern.h>
+#include <os.h>
+#include <sigio.h>
/* Protected by sigio_lock() called from write_sigio_workaround */
static int sigio_irq_fd = -1;
diff --git a/arch/um/kernel/signal.c b/arch/um/kernel/signal.c
index cc9c235..db18eb6 100644
--- a/arch/um/kernel/signal.c
+++ b/arch/um/kernel/signal.c
@@ -9,8 +9,8 @@
#include <asm/siginfo.h>
#include <asm/signal.h>
#include <asm/unistd.h>
-#include "frame_kern.h"
-#include "kern_util.h"
+#include <frame_kern.h>
+#include <kern_util.h>
EXPORT_SYMBOL(block_signals);
EXPORT_SYMBOL(unblock_signals);
diff --git a/arch/um/kernel/skas/clone.c b/arch/um/kernel/skas/clone.c
index e1fd066..289771d 100644
--- a/arch/um/kernel/skas/clone.c
+++ b/arch/um/kernel/skas/clone.c
@@ -7,10 +7,10 @@
#include <sched.h>
#include <asm/unistd.h>
#include <sys/time.h>
-#include "as-layout.h"
-#include "ptrace_user.h"
-#include "stub-data.h"
-#include "sysdep/stub.h"
+#include <as-layout.h>
+#include <ptrace_user.h>
+#include <stub-data.h>
+#include <sysdep/stub.h>
/*
* This is in a separate file because it needs to be compiled with any
diff --git a/arch/um/kernel/skas/mmu.c b/arch/um/kernel/skas/mmu.c
index 0a49ef0..ff03067 100644
--- a/arch/um/kernel/skas/mmu.c
+++ b/arch/um/kernel/skas/mmu.c
@@ -3,14 +3,14 @@
* Licensed under the GPL
*/
-#include "linux/mm.h"
-#include "linux/sched.h"
-#include "linux/slab.h"
-#include "asm/pgalloc.h"
-#include "asm/pgtable.h"
-#include "as-layout.h"
-#include "os.h"
-#include "skas.h"
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <asm/pgalloc.h>
+#include <asm/pgtable.h>
+#include <as-layout.h>
+#include <os.h>
+#include <skas.h>
extern int __syscall_stub_start;
diff --git a/arch/um/kernel/skas/process.c b/arch/um/kernel/skas/process.c
index 0a9e57e..4da11b3 100644
--- a/arch/um/kernel/skas/process.c
+++ b/arch/um/kernel/skas/process.c
@@ -3,12 +3,12 @@
* Licensed under the GPL
*/
-#include "linux/init.h"
-#include "linux/sched.h"
-#include "as-layout.h"
-#include "kern.h"
-#include "os.h"
-#include "skas.h"
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <as-layout.h>
+#include <kern.h>
+#include <os.h>
+#include <skas.h>
int new_mm(unsigned long stack)
{
diff --git a/arch/um/kernel/skas/syscall.c b/arch/um/kernel/skas/syscall.c
index 86368a0..c0681e0 100644
--- a/arch/um/kernel/skas/syscall.c
+++ b/arch/um/kernel/skas/syscall.c
@@ -3,11 +3,11 @@
* Licensed under the GPL
*/
-#include "linux/kernel.h"
-#include "linux/ptrace.h"
-#include "kern_util.h"
-#include "sysdep/ptrace.h"
-#include "sysdep/syscalls.h"
+#include <linux/kernel.h>
+#include <linux/ptrace.h>
+#include <kern_util.h>
+#include <sysdep/ptrace.h>
+#include <sysdep/syscalls.h>
extern int syscall_table_size;
#define NR_SYSCALLS (syscall_table_size / sizeof(void *))
diff --git a/arch/um/kernel/skas/uaccess.c b/arch/um/kernel/skas/uaccess.c
index cd7df79..1d3e0c1 100644
--- a/arch/um/kernel/skas/uaccess.c
+++ b/arch/um/kernel/skas/uaccess.c
@@ -11,8 +11,8 @@
#include <asm/current.h>
#include <asm/page.h>
#include <asm/pgtable.h>
-#include "kern_util.h"
-#include "os.h"
+#include <kern_util.h>
+#include <os.h>
pte_t *virt_to_pte(struct mm_struct *mm, unsigned long addr)
{
diff --git a/arch/um/kernel/smp.c b/arch/um/kernel/smp.c
index a02b7e9..5c8c3ea 100644
--- a/arch/um/kernel/smp.c
+++ b/arch/um/kernel/smp.c
@@ -3,24 +3,24 @@
* Licensed under the GPL
*/
-#include "linux/percpu.h"
-#include "asm/pgalloc.h"
-#include "asm/tlb.h"
+#include <linux/percpu.h>
+#include <asm/pgalloc.h>
+#include <asm/tlb.h>
#ifdef CONFIG_SMP
-#include "linux/sched.h"
-#include "linux/module.h"
-#include "linux/threads.h"
-#include "linux/interrupt.h"
-#include "linux/err.h"
-#include "linux/hardirq.h"
-#include "asm/smp.h"
-#include "asm/processor.h"
-#include "asm/spinlock.h"
-#include "kern.h"
-#include "irq_user.h"
-#include "os.h"
+#include <linux/sched.h>
+#include <linux/module.h>
+#include <linux/threads.h>
+#include <linux/interrupt.h>
+#include <linux/err.h>
+#include <linux/hardirq.h>
+#include <asm/smp.h>
+#include <asm/processor.h>
+#include <asm/spinlock.h>
+#include <kern.h>
+#include <irq_user.h>
+#include <os.h>
/* Per CPU bogomips and other parameters
* The only piece used here is the ipi pipe, which is set before SMP is
diff --git a/arch/um/kernel/syscall.c b/arch/um/kernel/syscall.c
index a4c6d8e..a81f370 100644
--- a/arch/um/kernel/syscall.c
+++ b/arch/um/kernel/syscall.c
@@ -3,17 +3,16 @@
* Licensed under the GPL
*/
-#include "linux/file.h"
-#include "linux/fs.h"
-#include "linux/mm.h"
-#include "linux/sched.h"
-#include "linux/utsname.h"
-#include "linux/syscalls.h"
-#include "asm/current.h"
-#include "asm/mman.h"
-#include "asm/uaccess.h"
-#include "asm/unistd.h"
-#include "internal.h"
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/utsname.h>
+#include <linux/syscalls.h>
+#include <asm/current.h>
+#include <asm/mman.h>
+#include <asm/uaccess.h>
+#include <asm/unistd.h>
long sys_fork(void)
{
@@ -50,19 +49,3 @@ long old_mmap(unsigned long addr, unsigned long len,
out:
return err;
}
-
-int kernel_execve(const char *filename,
- const char *const argv[],
- const char *const envp[])
-{
- mm_segment_t fs;
- int ret;
-
- fs = get_fs();
- set_fs(KERNEL_DS);
- ret = um_execve(filename, (const char __user *const __user *)argv,
- (const char __user *const __user *) envp);
- set_fs(fs);
-
- return ret;
-}
diff --git a/arch/um/kernel/sysrq.c b/arch/um/kernel/sysrq.c
index 0960de5..e562ff8 100644
--- a/arch/um/kernel/sysrq.c
+++ b/arch/um/kernel/sysrq.c
@@ -7,7 +7,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/sched.h>
-#include "sysrq.h"
+#include <asm/sysrq.h>
/* Catch non-i386 SUBARCH's. */
#if !defined(CONFIG_UML_X86) || defined(CONFIG_64BIT)
diff --git a/arch/um/kernel/time.c b/arch/um/kernel/time.c
index 5f76d4b..117568d 100644
--- a/arch/um/kernel/time.c
+++ b/arch/um/kernel/time.c
@@ -10,8 +10,8 @@
#include <linux/threads.h>
#include <asm/irq.h>
#include <asm/param.h>
-#include "kern_util.h"
-#include "os.h"
+#include <kern_util.h>
+#include <os.h>
void timer_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs)
{
diff --git a/arch/um/kernel/tlb.c b/arch/um/kernel/tlb.c
index f819af9..9472079 100644
--- a/arch/um/kernel/tlb.c
+++ b/arch/um/kernel/tlb.c
@@ -8,10 +8,10 @@
#include <linux/sched.h>
#include <asm/pgtable.h>
#include <asm/tlbflush.h>
-#include "as-layout.h"
-#include "mem_user.h"
-#include "os.h"
-#include "skas.h"
+#include <as-layout.h>
+#include <mem_user.h>
+#include <os.h>
+#include <skas.h>
struct host_vm_change {
struct host_vm_op {
diff --git a/arch/um/kernel/trap.c b/arch/um/kernel/trap.c
index 0f00e9c..089f398 100644
--- a/arch/um/kernel/trap.c
+++ b/arch/um/kernel/trap.c
@@ -10,11 +10,11 @@
#include <asm/current.h>
#include <asm/pgtable.h>
#include <asm/tlbflush.h>
-#include "arch.h"
-#include "as-layout.h"
-#include "kern_util.h"
-#include "os.h"
-#include "skas.h"
+#include <arch.h>
+#include <as-layout.h>
+#include <kern_util.h>
+#include <os.h>
+#include <skas.h>
/*
* Note this is constrained to return 0, -EFAULT, -EACCESS, -ENOMEM by
diff --git a/arch/um/kernel/um_arch.c b/arch/um/kernel/um_arch.c
index 4db8770..87df5e3 100644
--- a/arch/um/kernel/um_arch.c
+++ b/arch/um/kernel/um_arch.c
@@ -14,13 +14,13 @@
#include <asm/pgtable.h>
#include <asm/processor.h>
#include <asm/setup.h>
-#include "as-layout.h"
-#include "arch.h"
-#include "init.h"
-#include "kern.h"
-#include "kern_util.h"
-#include "mem_user.h"
-#include "os.h"
+#include <as-layout.h>
+#include <arch.h>
+#include <init.h>
+#include <kern.h>
+#include <kern_util.h>
+#include <mem_user.h>
+#include <os.h>
#define DEFAULT_COMMAND_LINE "root=98:0"
diff --git a/arch/um/kernel/umid.c b/arch/um/kernel/umid.c
index 81e07e2b..f6cc3bd 100644
--- a/arch/um/kernel/umid.c
+++ b/arch/um/kernel/umid.c
@@ -4,9 +4,9 @@
*/
#include <asm/errno.h>
-#include "init.h"
-#include "kern.h"
-#include "os.h"
+#include <init.h>
+#include <kern.h>
+#include <os.h>
/* Changed by set_umid_arg */
static int umid_inited = 0;
diff --git a/arch/um/kernel/uml.lds.S b/arch/um/kernel/uml.lds.S
index fbd9940..ff65fb4 100644
--- a/arch/um/kernel/uml.lds.S
+++ b/arch/um/kernel/uml.lds.S
@@ -60,7 +60,7 @@ SECTIONS
PROVIDE_HIDDEN(__rela_iplt_end = .);
}
- #include "asm/common.lds.S"
+ #include <asm/common.lds.S>
init.data : { INIT_DATA }
.data :
diff --git a/arch/um/os-Linux/aio.c b/arch/um/os-Linux/aio.c
index c5d039e..3a6bc2a 100644
--- a/arch/um/os-Linux/aio.c
+++ b/arch/um/os-Linux/aio.c
@@ -9,10 +9,10 @@
#include <errno.h>
#include <sys/time.h>
#include <asm/unistd.h>
-#include "aio.h"
-#include "init.h"
-#include "kern_util.h"
-#include "os.h"
+#include <aio.h>
+#include <init.h>
+#include <kern_util.h>
+#include <os.h>
struct aio_thread_req {
enum aio_type type;
diff --git a/arch/um/os-Linux/drivers/etap.h b/arch/um/os-Linux/drivers/etap.h
index ddffd41..54183a6 100644
--- a/arch/um/os-Linux/drivers/etap.h
+++ b/arch/um/os-Linux/drivers/etap.h
@@ -6,7 +6,7 @@
#ifndef __DRIVERS_ETAP_H
#define __DRIVERS_ETAP_H
-#include "net_user.h"
+#include <net_user.h>
struct ethertap_data {
char *dev_name;
diff --git a/arch/um/os-Linux/drivers/ethertap_kern.c b/arch/um/os-Linux/drivers/ethertap_kern.c
index 7f6f9a71..f424600 100644
--- a/arch/um/os-Linux/drivers/ethertap_kern.c
+++ b/arch/um/os-Linux/drivers/ethertap_kern.c
@@ -9,7 +9,7 @@
#include <linux/init.h>
#include <linux/netdevice.h>
#include "etap.h"
-#include "net_kern.h"
+#include <net_kern.h>
struct ethertap_init {
char *dev_name;
diff --git a/arch/um/os-Linux/drivers/ethertap_user.c b/arch/um/os-Linux/drivers/ethertap_user.c
index db3d648..b39b669 100644
--- a/arch/um/os-Linux/drivers/ethertap_user.c
+++ b/arch/um/os-Linux/drivers/ethertap_user.c
@@ -13,9 +13,9 @@
#include <sys/socket.h>
#include <sys/wait.h>
#include "etap.h"
-#include "os.h"
-#include "net_user.h"
-#include "um_malloc.h"
+#include <os.h>
+#include <net_user.h>
+#include <um_malloc.h>
#define MAX_PACKET ETH_MAX_PACKET
diff --git a/arch/um/os-Linux/drivers/tuntap.h b/arch/um/os-Linux/drivers/tuntap.h
index f17c315..7367354 100644
--- a/arch/um/os-Linux/drivers/tuntap.h
+++ b/arch/um/os-Linux/drivers/tuntap.h
@@ -6,7 +6,7 @@
#ifndef __UM_TUNTAP_H
#define __UM_TUNTAP_H
-#include "net_user.h"
+#include <net_user.h>
struct tuntap_data {
char *dev_name;
diff --git a/arch/um/os-Linux/drivers/tuntap_kern.c b/arch/um/os-Linux/drivers/tuntap_kern.c
index 4048800..d9d56e5 100644
--- a/arch/um/os-Linux/drivers/tuntap_kern.c
+++ b/arch/um/os-Linux/drivers/tuntap_kern.c
@@ -7,7 +7,7 @@
#include <linux/init.h>
#include <linux/skbuff.h>
#include <asm/errno.h>
-#include "net_kern.h"
+#include <net_kern.h>
#include "tuntap.h"
struct tuntap_init {
diff --git a/arch/um/os-Linux/drivers/tuntap_user.c b/arch/um/os-Linux/drivers/tuntap_user.c
index a2aacff..14126d9 100644
--- a/arch/um/os-Linux/drivers/tuntap_user.c
+++ b/arch/um/os-Linux/drivers/tuntap_user.c
@@ -13,8 +13,8 @@
#include <sys/socket.h>
#include <sys/wait.h>
#include <sys/uio.h>
-#include "kern_util.h"
-#include "os.h"
+#include <kern_util.h>
+#include <os.h>
#include "tuntap.h"
static int tuntap_user_init(void *data, void *dev)
diff --git a/arch/um/os-Linux/elf_aux.c b/arch/um/os-Linux/elf_aux.c
index d895271..1a365dd 100644
--- a/arch/um/os-Linux/elf_aux.c
+++ b/arch/um/os-Linux/elf_aux.c
@@ -9,9 +9,9 @@
*/
#include <elf.h>
#include <stddef.h>
-#include "init.h"
-#include "elf_user.h"
-#include "mem_user.h"
+#include <init.h>
+#include <elf_user.h>
+#include <mem_user.h>
typedef Elf32_auxv_t elf_auxv_t;
diff --git a/arch/um/os-Linux/execvp.c b/arch/um/os-Linux/execvp.c
index 66e583a..8fb25ca 100644
--- a/arch/um/os-Linux/execvp.c
+++ b/arch/um/os-Linux/execvp.c
@@ -27,12 +27,12 @@
#include <limits.h>
#ifndef TEST
-#include "um_malloc.h"
+#include <um_malloc.h>
#else
#include <stdio.h>
#define um_kmalloc malloc
#endif
-#include "os.h"
+#include <os.h>
/* Execute FILE, searching in the `PATH' environment variable if it contains
no slashes, with arguments ARGV and environment from `environ'. */
diff --git a/arch/um/os-Linux/file.c b/arch/um/os-Linux/file.c
index b049a63..c17bd6f 100644
--- a/arch/um/os-Linux/file.c
+++ b/arch/um/os-Linux/file.c
@@ -13,7 +13,7 @@
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/un.h>
-#include "os.h"
+#include <os.h>
static void copy_stat(struct uml_stat *dst, const struct stat64 *src)
{
diff --git a/arch/um/os-Linux/helper.c b/arch/um/os-Linux/helper.c
index cf26c4a..e3ee4a5 100644
--- a/arch/um/os-Linux/helper.c
+++ b/arch/um/os-Linux/helper.c
@@ -10,9 +10,9 @@
#include <linux/limits.h>
#include <sys/socket.h>
#include <sys/wait.h>
-#include "kern_util.h"
-#include "os.h"
-#include "um_malloc.h"
+#include <kern_util.h>
+#include <os.h>
+#include <um_malloc.h>
struct helper_data {
void (*pre_exec)(void*);
diff --git a/arch/um/os-Linux/irq.c b/arch/um/os-Linux/irq.c
index 9a49908..b9afb74 100644
--- a/arch/um/os-Linux/irq.c
+++ b/arch/um/os-Linux/irq.c
@@ -8,9 +8,9 @@
#include <poll.h>
#include <signal.h>
#include <string.h>
-#include "irq_user.h"
-#include "os.h"
-#include "um_malloc.h"
+#include <irq_user.h>
+#include <os.h>
+#include <um_malloc.h>
/*
* Locked by irq_lock in arch/um/kernel/irq.c. Changed by os_create_pollfd
diff --git a/arch/um/os-Linux/main.c b/arch/um/os-Linux/main.c
index 7a86dd5..749c96d 100644
--- a/arch/um/os-Linux/main.c
+++ b/arch/um/os-Linux/main.c
@@ -10,11 +10,11 @@
#include <signal.h>
#include <string.h>
#include <sys/resource.h>
-#include "as-layout.h"
-#include "init.h"
-#include "kern_util.h"
-#include "os.h"
-#include "um_malloc.h"
+#include <as-layout.h>
+#include <init.h>
+#include <kern_util.h>
+#include <os.h>
+#include <um_malloc.h>
#define PGD_BOUND (4 * 1024 * 1024)
#define STACKSIZE (8 * 1024 * 1024)
diff --git a/arch/um/os-Linux/mem.c b/arch/um/os-Linux/mem.c
index 8e421e1..ba43980 100644
--- a/arch/um/os-Linux/mem.c
+++ b/arch/um/os-Linux/mem.c
@@ -13,8 +13,8 @@
#include <sys/stat.h>
#include <sys/mman.h>
#include <sys/param.h>
-#include "init.h"
-#include "os.h"
+#include <init.h>
+#include <os.h>
/* Modified by which_tmpdir, which is called during early boot */
static char *default_tmpdir = "/tmp";
diff --git a/arch/um/os-Linux/process.c b/arch/um/os-Linux/process.c
index 307f173..162bea3 100644
--- a/arch/um/os-Linux/process.c
+++ b/arch/um/os-Linux/process.c
@@ -12,10 +12,10 @@
#include <sys/ptrace.h>
#include <sys/wait.h>
#include <asm/unistd.h>
-#include "init.h"
-#include "longjmp.h"
-#include "os.h"
-#include "skas_ptrace.h"
+#include <init.h>
+#include <longjmp.h>
+#include <os.h>
+#include <skas_ptrace.h>
#define ARBITRARY_ADDR -1
#define FAILURE_PID -1
diff --git a/arch/um/os-Linux/registers.c b/arch/um/os-Linux/registers.c
index b866b9e..2ff8d4f 100644
--- a/arch/um/os-Linux/registers.c
+++ b/arch/um/os-Linux/registers.c
@@ -7,9 +7,9 @@
#include <errno.h>
#include <string.h>
#include <sys/ptrace.h>
-#include "sysdep/ptrace.h"
-#include "sysdep/ptrace_user.h"
-#include "registers.h"
+#include <sysdep/ptrace.h>
+#include <sysdep/ptrace_user.h>
+#include <registers.h>
int save_registers(int pid, struct uml_pt_regs *regs)
{
diff --git a/arch/um/os-Linux/sigio.c b/arch/um/os-Linux/sigio.c
index 3c16121..8b61cc0 100644
--- a/arch/um/os-Linux/sigio.c
+++ b/arch/um/os-Linux/sigio.c
@@ -11,11 +11,11 @@
#include <sched.h>
#include <signal.h>
#include <string.h>
-#include "kern_util.h"
-#include "init.h"
-#include "os.h"
-#include "sigio.h"
-#include "um_malloc.h"
+#include <kern_util.h>
+#include <init.h>
+#include <os.h>
+#include <sigio.h>
+#include <um_malloc.h>
/*
* Protected by sigio_lock(), also used by sigio_cleanup, which is an
diff --git a/arch/um/os-Linux/signal.c b/arch/um/os-Linux/signal.c
index 6366ce9..b1469fe 100644
--- a/arch/um/os-Linux/signal.c
+++ b/arch/um/os-Linux/signal.c
@@ -9,10 +9,10 @@
#include <errno.h>
#include <signal.h>
#include <strings.h>
-#include "as-layout.h"
-#include "kern_util.h"
-#include "os.h"
-#include "sysdep/mcontext.h"
+#include <as-layout.h>
+#include <kern_util.h>
+#include <os.h>
+#include <sysdep/mcontext.h>
#include "internal.h"
void (*sig_info[NSIG])(int, siginfo_t *, struct uml_pt_regs *) = {
diff --git a/arch/um/os-Linux/skas/mem.c b/arch/um/os-Linux/skas/mem.c
index 90b310d..689b18d 100644
--- a/arch/um/os-Linux/skas/mem.c
+++ b/arch/um/os-Linux/skas/mem.c
@@ -8,16 +8,16 @@
#include <errno.h>
#include <string.h>
#include <sys/mman.h>
-#include "init.h"
-#include "as-layout.h"
-#include "mm_id.h"
-#include "os.h"
-#include "proc_mm.h"
-#include "ptrace_user.h"
-#include "registers.h"
-#include "skas.h"
-#include "sysdep/ptrace.h"
-#include "sysdep/stub.h"
+#include <init.h>
+#include <as-layout.h>
+#include <mm_id.h>
+#include <os.h>
+#include <proc_mm.h>
+#include <ptrace_user.h>
+#include <registers.h>
+#include <skas.h>
+#include <sysdep/ptrace.h>
+#include <sysdep/stub.h>
extern unsigned long batch_syscall_stub, __syscall_stub_start;
diff --git a/arch/um/os-Linux/skas/process.c b/arch/um/os-Linux/skas/process.c
index d93bb40..4625949 100644
--- a/arch/um/os-Linux/skas/process.c
+++ b/arch/um/os-Linux/skas/process.c
@@ -11,17 +11,17 @@
#include <sys/mman.h>
#include <sys/wait.h>
#include <asm/unistd.h>
-#include "as-layout.h"
-#include "init.h"
-#include "kern_util.h"
-#include "mem.h"
-#include "os.h"
-#include "proc_mm.h"
-#include "ptrace_user.h"
-#include "registers.h"
-#include "skas.h"
-#include "skas_ptrace.h"
-#include "sysdep/stub.h"
+#include <as-layout.h>
+#include <init.h>
+#include <kern_util.h>
+#include <mem.h>
+#include <os.h>
+#include <proc_mm.h>
+#include <ptrace_user.h>
+#include <registers.h>
+#include <skas.h>
+#include <skas_ptrace.h>
+#include <sysdep/stub.h>
int is_skas_winch(int pid, int fd, void *data)
{
diff --git a/arch/um/os-Linux/start_up.c b/arch/um/os-Linux/start_up.c
index 425162e..da4b9e9 100644
--- a/arch/um/os-Linux/start_up.c
+++ b/arch/um/os-Linux/start_up.c
@@ -16,13 +16,13 @@
#include <sys/stat.h>
#include <sys/wait.h>
#include <asm/unistd.h>
-#include "init.h"
-#include "os.h"
-#include "mem_user.h"
-#include "ptrace_user.h"
-#include "registers.h"
-#include "skas.h"
-#include "skas_ptrace.h"
+#include <init.h>
+#include <os.h>
+#include <mem_user.h>
+#include <ptrace_user.h>
+#include <registers.h>
+#include <skas.h>
+#include <skas_ptrace.h>
static void ptrace_child(void)
{
diff --git a/arch/um/os-Linux/time.c b/arch/um/os-Linux/time.c
index 0748fe0..fac388c 100644
--- a/arch/um/os-Linux/time.c
+++ b/arch/um/os-Linux/time.c
@@ -8,8 +8,8 @@
#include <signal.h>
#include <time.h>
#include <sys/time.h>
-#include "kern_util.h"
-#include "os.h"
+#include <kern_util.h>
+#include <os.h>
#include "internal.h"
int set_interval(void)
diff --git a/arch/um/os-Linux/tty.c b/arch/um/os-Linux/tty.c
index dd12b99..721d8af 100644
--- a/arch/um/os-Linux/tty.c
+++ b/arch/um/os-Linux/tty.c
@@ -7,8 +7,8 @@
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
-#include "kern_util.h"
-#include "os.h"
+#include <kern_util.h>
+#include <os.h>
struct grantpt_info {
int fd;
diff --git a/arch/um/os-Linux/umid.c b/arch/um/os-Linux/umid.c
index 4832eb5..c1dc892 100644
--- a/arch/um/os-Linux/umid.c
+++ b/arch/um/os-Linux/umid.c
@@ -12,8 +12,8 @@
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
-#include "init.h"
-#include "os.h"
+#include <init.h>
+#include <os.h>
#define UML_DIR "~/.uml/"
diff --git a/arch/um/os-Linux/user_syms.c b/arch/um/os-Linux/user_syms.c
index 73926fa..db4a034 100644
--- a/arch/um/os-Linux/user_syms.c
+++ b/arch/um/os-Linux/user_syms.c
@@ -1,5 +1,5 @@
-#include "linux/types.h"
-#include "linux/module.h"
+#include <linux/types.h>
+#include <linux/module.h>
/* Some of this are builtin function (some are not but could in the future),
* so I *must* declare good prototypes for them and then EXPORT them.
diff --git a/arch/um/os-Linux/util.c b/arch/um/os-Linux/util.c
index 9e3b43b..492ef5e 100644
--- a/arch/um/os-Linux/util.c
+++ b/arch/um/os-Linux/util.c
@@ -13,7 +13,7 @@
#include <wait.h>
#include <sys/mman.h>
#include <sys/utsname.h>
-#include "os.h"
+#include <os.h>
void stack_protections(unsigned long address)
{
diff --git a/arch/um/sys-ppc/miscthings.c b/arch/um/sys-ppc/miscthings.c
index 1c11aed..25908d2 100644
--- a/arch/um/sys-ppc/miscthings.c
+++ b/arch/um/sys-ppc/miscthings.c
@@ -1,6 +1,6 @@
-#include "linux/threads.h"
-#include "linux/stddef.h" // for NULL
-#include "linux/elf.h" // for AT_NULL
+#include <linux/threads.h>
+#include <linux/stddef.h> // for NULL
+#include <linux/elf.h> // for AT_NULL
/* The following function nicked from arch/ppc/kernel/process.c and
* adapted slightly */
diff --git a/arch/um/sys-ppc/ptrace.c b/arch/um/sys-ppc/ptrace.c
index 66ef155..8245df4 100644
--- a/arch/um/sys-ppc/ptrace.c
+++ b/arch/um/sys-ppc/ptrace.c
@@ -1,4 +1,4 @@
-#include "linux/sched.h"
+#include <linux/sched.h>
#include "asm/ptrace.h"
int putreg(struct task_struct *child, unsigned long regno,
diff --git a/arch/um/sys-ppc/ptrace_user.c b/arch/um/sys-ppc/ptrace_user.c
index 224d240..4601b92 100644
--- a/arch/um/sys-ppc/ptrace_user.c
+++ b/arch/um/sys-ppc/ptrace_user.c
@@ -1,6 +1,6 @@
#include <errno.h>
#include <asm/ptrace.h>
-#include "sysdep/ptrace.h"
+#include <sysdep/ptrace.h>
int ptrace_getregs(long pid, unsigned long *regs_out)
{
diff --git a/arch/um/sys-ppc/shared/sysdep/ptrace.h b/arch/um/sys-ppc/shared/sysdep/ptrace.h
index 0e3230e..efe0c1a 100644
--- a/arch/um/sys-ppc/shared/sysdep/ptrace.h
+++ b/arch/um/sys-ppc/shared/sysdep/ptrace.h
@@ -5,7 +5,7 @@
#ifndef __SYS_PTRACE_PPC_H
#define __SYS_PTRACE_PPC_H
-#include "linux/types.h"
+#include <linux/types.h>
/* the following taken from <asm-ppc/ptrace.h> */
diff --git a/arch/um/sys-ppc/sigcontext.c b/arch/um/sys-ppc/sigcontext.c
index 40694d0..aac6c83 100644
--- a/arch/um/sys-ppc/sigcontext.c
+++ b/arch/um/sys-ppc/sigcontext.c
@@ -1,4 +1,4 @@
#include "asm/ptrace.h"
#include "asm/sigcontext.h"
-#include "sysdep/ptrace.h"
+#include <sysdep/ptrace.h>
diff --git a/arch/um/sys-ppc/sysrq.c b/arch/um/sys-ppc/sysrq.c
index 2f816f1..f889449 100644
--- a/arch/um/sys-ppc/sysrq.c
+++ b/arch/um/sys-ppc/sysrq.c
@@ -3,8 +3,8 @@
* Licensed under the GPL
*/
-#include "linux/kernel.h"
-#include "linux/smp.h"
+#include <linux/kernel.h>
+#include <linux/smp.h>
#include "asm/ptrace.h"
#include "sysrq.h"
diff --git a/arch/unicore32/Kconfig b/arch/unicore32/Kconfig
index 1e638e7..35ee2bf 100644
--- a/arch/unicore32/Kconfig
+++ b/arch/unicore32/Kconfig
@@ -21,9 +21,6 @@ config UNICORE32
designs licensed by PKUnity Ltd.
Please see web page at <http://www.pkunity.com/>.
-config HAVE_PWM
- bool
-
config GENERIC_GPIO
def_bool y
@@ -106,7 +103,8 @@ config PUV3_DB0913
config PUV3_NB0916
bool "NetBook board (0916)"
- select HAVE_PWM
+ select PWM
+ select PWM_PUV3
config PUV3_SMW0919
bool "Security Mini-Workstation board (0919)"
@@ -220,12 +218,6 @@ config PUV3_GPIO
select GPIO_SYSFS if EXPERIMENTAL
default y
-config PUV3_PWM
- tristate
- default BACKLIGHT_PWM
- help
- Enable support for NB0916 PWM controllers
-
if PUV3_NB0916
menu "PKUnity NetBook-0916 Features"
diff --git a/arch/unicore32/include/asm/Kbuild b/arch/unicore32/include/asm/Kbuild
index 123c59a..c910c98 100644
--- a/arch/unicore32/include/asm/Kbuild
+++ b/arch/unicore32/include/asm/Kbuild
@@ -11,6 +11,7 @@ generic-y += device.h
generic-y += div64.h
generic-y += emergency-restart.h
generic-y += errno.h
+generic-y += exec.h
generic-y += fb.h
generic-y += fcntl.h
generic-y += ftrace.h
diff --git a/arch/unicore32/include/asm/exec.h b/arch/unicore32/include/asm/exec.h
deleted file mode 100644
index 06d1f0f..0000000
--- a/arch/unicore32/include/asm/exec.h
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- * Process execution bits for PKUnity SoC and UniCore ISA
- *
- * Copyright (C) 2001-2012 GUAN Xue-tao
- *
- * 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 __UNICORE_EXEC_H__
-#define __UNICORE_EXEC_H__
-
-#define arch_align_stack(x) (x)
-
-#endif /* __UNICORE_EXEC_H__ */
diff --git a/arch/unicore32/include/asm/thread_info.h b/arch/unicore32/include/asm/thread_info.h
index 89f7557..818b4a1 100644
--- a/arch/unicore32/include/asm/thread_info.h
+++ b/arch/unicore32/include/asm/thread_info.h
@@ -141,12 +141,12 @@ static inline struct thread_info *current_thread_info(void)
#define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED)
#define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME)
#define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE)
-#define _TIF_RESTORE_SIGMASK (1 << TIF_RESTORE_SIGMASK)
/*
* Change these and you break ASM code in entry-common.S
*/
-#define _TIF_WORK_MASK 0x000000ff
+#define _TIF_WORK_MASK \
+ (_TIF_SIGPENDING | _TIF_NEED_RESCHED | _TIF_NOTIFY_RESUME)
#endif /* __KERNEL__ */
#endif /* __UNICORE_THREAD_INFO_H__ */
diff --git a/arch/unicore32/include/mach/regs-ost.h b/arch/unicore32/include/mach/regs-ost.h
index 7b91fe6..4a85fb4 100644
--- a/arch/unicore32/include/mach/regs-ost.h
+++ b/arch/unicore32/include/mach/regs-ost.h
@@ -33,18 +33,16 @@
* Interrupt Enable Reg OST_OIER
*/
#define OST_OIER (PKUNITY_OST_BASE + 0x001C)
+
/*
- * PWM Pulse Width Control Reg OST_PWMPWCR
- */
-#define OST_PWMPWCR (PKUNITY_OST_BASE + 0x0080)
-/*
- * PWM Duty Cycle Control Reg OST_PWMDCCR
- */
-#define OST_PWMDCCR (PKUNITY_OST_BASE + 0x0084)
-/*
- * PWM Period Control Reg OST_PWMPCR
+ * PWM Registers: IO base address: PKUNITY_OST_BASE + 0x80
+ * PWCR: Pulse Width Control Reg
+ * DCCR: Duty Cycle Control Reg
+ * PCR: Period Control Reg
*/
-#define OST_PWMPCR (PKUNITY_OST_BASE + 0x0088)
+#define OST_PWM_PWCR (0x00)
+#define OST_PWM_DCCR (0x04)
+#define OST_PWM_PCR (0x08)
/*
* Match detected 0 OST_OSSR_M0
diff --git a/arch/unicore32/kernel/Makefile b/arch/unicore32/kernel/Makefile
index 3240101..fa497e0 100644
--- a/arch/unicore32/kernel/Makefile
+++ b/arch/unicore32/kernel/Makefile
@@ -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_PWM) += pwm.o
obj-$(CONFIG_PUV3_PM) += pm.o sleep.o
obj-$(CONFIG_HIBERNATION) += hibernate.o hibernate_asm.o
diff --git a/arch/unicore32/kernel/entry.S b/arch/unicore32/kernel/entry.S
index 00a259f..dcb87ab 100644
--- a/arch/unicore32/kernel/entry.S
+++ b/arch/unicore32/kernel/entry.S
@@ -544,8 +544,6 @@ fast_work_pending:
work_pending:
cand.a r1, #_TIF_NEED_RESCHED
bne work_resched
- cand.a r1, #_TIF_SIGPENDING|_TIF_NOTIFY_RESUME
- beq no_work_pending
mov r0, sp @ 'regs'
mov r2, why @ 'syscall'
cand.a r1, #_TIF_SIGPENDING @ delivering a signal?
diff --git a/arch/unicore32/kernel/pwm.c b/arch/unicore32/kernel/pwm.c
deleted file mode 100644
index 4615d51..0000000
--- a/arch/unicore32/kernel/pwm.c
+++ /dev/null
@@ -1,263 +0,0 @@
-/*
- * linux/arch/unicore32/kernel/pwm.c
- *
- * Code specific to PKUnity SoC and UniCore ISA
- *
- * Maintained by GUAN Xue-tao <gxt@mprc.pku.edu.cn>
- * Copyright (C) 2001-2010 Guan Xuetao
- *
- * 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/kernel.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <linux/err.h>
-#include <linux/clk.h>
-#include <linux/io.h>
-#include <linux/pwm.h>
-
-#include <asm/div64.h>
-#include <mach/hardware.h>
-
-struct pwm_device {
- struct list_head node;
- struct platform_device *pdev;
-
- const char *label;
- struct clk *clk;
- int clk_enabled;
-
- unsigned int use_count;
- unsigned int pwm_id;
-};
-
-/*
- * period_ns = 10^9 * (PRESCALE + 1) * (PV + 1) / PWM_CLK_RATE
- * duty_ns = 10^9 * (PRESCALE + 1) * DC / PWM_CLK_RATE
- */
-int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
-{
- unsigned long long c;
- unsigned long period_cycles, prescale, pv, dc;
-
- if (pwm == NULL || period_ns == 0 || duty_ns > period_ns)
- return -EINVAL;
-
- c = clk_get_rate(pwm->clk);
- c = c * period_ns;
- do_div(c, 1000000000);
- period_cycles = c;
-
- if (period_cycles < 1)
- period_cycles = 1;
- prescale = (period_cycles - 1) / 1024;
- pv = period_cycles / (prescale + 1) - 1;
-
- if (prescale > 63)
- return -EINVAL;
-
- if (duty_ns == period_ns)
- dc = OST_PWMDCCR_FDCYCLE;
- else
- dc = (pv + 1) * duty_ns / period_ns;
-
- /* NOTE: the clock to PWM has to be enabled first
- * before writing to the registers
- */
- clk_enable(pwm->clk);
- OST_PWMPWCR = prescale;
- OST_PWMDCCR = pv - dc;
- OST_PWMPCR = pv;
- clk_disable(pwm->clk);
-
- return 0;
-}
-EXPORT_SYMBOL(pwm_config);
-
-int pwm_enable(struct pwm_device *pwm)
-{
- int rc = 0;
-
- if (!pwm->clk_enabled) {
- rc = clk_enable(pwm->clk);
- if (!rc)
- pwm->clk_enabled = 1;
- }
- return rc;
-}
-EXPORT_SYMBOL(pwm_enable);
-
-void pwm_disable(struct pwm_device *pwm)
-{
- if (pwm->clk_enabled) {
- clk_disable(pwm->clk);
- pwm->clk_enabled = 0;
- }
-}
-EXPORT_SYMBOL(pwm_disable);
-
-static DEFINE_MUTEX(pwm_lock);
-static LIST_HEAD(pwm_list);
-
-struct pwm_device *pwm_request(int pwm_id, const char *label)
-{
- struct pwm_device *pwm;
- int found = 0;
-
- mutex_lock(&pwm_lock);
-
- list_for_each_entry(pwm, &pwm_list, node) {
- if (pwm->pwm_id == pwm_id) {
- found = 1;
- break;
- }
- }
-
- if (found) {
- if (pwm->use_count == 0) {
- pwm->use_count++;
- pwm->label = label;
- } else
- pwm = ERR_PTR(-EBUSY);
- } else
- pwm = ERR_PTR(-ENOENT);
-
- mutex_unlock(&pwm_lock);
- return pwm;
-}
-EXPORT_SYMBOL(pwm_request);
-
-void pwm_free(struct pwm_device *pwm)
-{
- mutex_lock(&pwm_lock);
-
- if (pwm->use_count) {
- pwm->use_count--;
- pwm->label = NULL;
- } else
- pr_warning("PWM device already freed\n");
-
- mutex_unlock(&pwm_lock);
-}
-EXPORT_SYMBOL(pwm_free);
-
-static inline void __add_pwm(struct pwm_device *pwm)
-{
- mutex_lock(&pwm_lock);
- list_add_tail(&pwm->node, &pwm_list);
- mutex_unlock(&pwm_lock);
-}
-
-static struct pwm_device *pwm_probe(struct platform_device *pdev,
- unsigned int pwm_id, struct pwm_device *parent_pwm)
-{
- struct pwm_device *pwm;
- struct resource *r;
- int ret = 0;
-
- pwm = kzalloc(sizeof(struct pwm_device), GFP_KERNEL);
- if (pwm == NULL) {
- dev_err(&pdev->dev, "failed to allocate memory\n");
- return ERR_PTR(-ENOMEM);
- }
-
- pwm->clk = clk_get(NULL, "OST_CLK");
- if (IS_ERR(pwm->clk)) {
- ret = PTR_ERR(pwm->clk);
- goto err_free;
- }
- pwm->clk_enabled = 0;
-
- pwm->use_count = 0;
- pwm->pwm_id = pwm_id;
- pwm->pdev = pdev;
-
- r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (r == NULL) {
- dev_err(&pdev->dev, "no memory resource defined\n");
- ret = -ENODEV;
- goto err_free_clk;
- }
-
- r = request_mem_region(r->start, resource_size(r), pdev->name);
- if (r == NULL) {
- dev_err(&pdev->dev, "failed to request memory resource\n");
- ret = -EBUSY;
- goto err_free_clk;
- }
-
- __add_pwm(pwm);
- platform_set_drvdata(pdev, pwm);
- return pwm;
-
-err_free_clk:
- clk_put(pwm->clk);
-err_free:
- kfree(pwm);
- return ERR_PTR(ret);
-}
-
-static int __devinit puv3_pwm_probe(struct platform_device *pdev)
-{
- struct pwm_device *pwm = pwm_probe(pdev, pdev->id, NULL);
-
- if (IS_ERR(pwm))
- return PTR_ERR(pwm);
-
- return 0;
-}
-
-static int __devexit pwm_remove(struct platform_device *pdev)
-{
- struct pwm_device *pwm;
- struct resource *r;
-
- pwm = platform_get_drvdata(pdev);
- if (pwm == NULL)
- return -ENODEV;
-
- mutex_lock(&pwm_lock);
- list_del(&pwm->node);
- mutex_unlock(&pwm_lock);
-
- r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- release_mem_region(r->start, resource_size(r));
-
- clk_put(pwm->clk);
- kfree(pwm);
- return 0;
-}
-
-static struct platform_driver puv3_pwm_driver = {
- .driver = {
- .name = "PKUnity-v3-PWM",
- },
- .probe = puv3_pwm_probe,
- .remove = __devexit_p(pwm_remove),
-};
-
-static int __init pwm_init(void)
-{
- int ret = 0;
-
- ret = platform_driver_register(&puv3_pwm_driver);
- if (ret) {
- printk(KERN_ERR "failed to register puv3_pwm_driver\n");
- return ret;
- }
-
- return ret;
-}
-arch_initcall(pwm_init);
-
-static void __exit pwm_exit(void)
-{
- platform_driver_unregister(&puv3_pwm_driver);
-}
-module_exit(pwm_exit);
-
-MODULE_LICENSE("GPL v2");
diff --git a/arch/unicore32/kernel/signal.c b/arch/unicore32/kernel/signal.c
index 8adedb3..b8b2ffd 100644
--- a/arch/unicore32/kernel/signal.c
+++ b/arch/unicore32/kernel/signal.c
@@ -12,7 +12,6 @@
#include <linux/errno.h>
#include <linux/signal.h>
#include <linux/personality.h>
-#include <linux/freezer.h>
#include <linux/uaccess.h>
#include <linux/tracehook.h>
#include <linux/elf.h>
diff --git a/arch/unicore32/kernel/sys.c b/arch/unicore32/kernel/sys.c
index 3afe60a..5fd9af7 100644
--- a/arch/unicore32/kernel/sys.c
+++ b/arch/unicore32/kernel/sys.c
@@ -104,7 +104,6 @@ int kernel_execve(const char *filename,
out:
return ret;
}
-EXPORT_SYMBOL(kernel_execve);
/* Note: used by the compat code even in 64-bit Linux. */
SYSCALL_DEFINE6(mmap2, unsigned long, addr, unsigned long, len,
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 1ae94bc..42d2c35 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -108,6 +108,7 @@ config X86
select GENERIC_STRNLEN_USER
select HAVE_RCU_USER_QS if X86_64
select HAVE_IRQ_TIME_ACCOUNTING
+ select GENERIC_KERNEL_THREAD
config INSTRUCTION_DECODER
def_bool y
diff --git a/arch/x86/ia32/ia32entry.S b/arch/x86/ia32/ia32entry.S
index 9c28950..076745f 100644
--- a/arch/x86/ia32/ia32entry.S
+++ b/arch/x86/ia32/ia32entry.S
@@ -465,7 +465,7 @@ GLOBAL(\label)
PTREGSCALL stub32_rt_sigreturn, sys32_rt_sigreturn, %rdi
PTREGSCALL stub32_sigreturn, sys32_sigreturn, %rdi
PTREGSCALL stub32_sigaltstack, sys32_sigaltstack, %rdx
- PTREGSCALL stub32_execve, sys32_execve, %rcx
+ PTREGSCALL stub32_execve, compat_sys_execve, %rcx
PTREGSCALL stub32_fork, sys_fork, %rdi
PTREGSCALL stub32_clone, sys32_clone, %rdx
PTREGSCALL stub32_vfork, sys_vfork, %rdi
diff --git a/arch/x86/ia32/sys_ia32.c b/arch/x86/ia32/sys_ia32.c
index c5b938d..86d68d1 100644
--- a/arch/x86/ia32/sys_ia32.c
+++ b/arch/x86/ia32/sys_ia32.c
@@ -385,21 +385,6 @@ asmlinkage long sys32_sendfile(int out_fd, int in_fd,
return ret;
}
-asmlinkage long sys32_execve(const char __user *name, compat_uptr_t __user *argv,
- compat_uptr_t __user *envp, struct pt_regs *regs)
-{
- long error;
- char *filename;
-
- filename = getname(name);
- error = PTR_ERR(filename);
- if (IS_ERR(filename))
- return error;
- error = compat_do_execve(filename, argv, envp, regs);
- putname(filename);
- return error;
-}
-
asmlinkage long sys32_clone(unsigned int clone_flags, unsigned int newsp,
struct pt_regs *regs)
{
diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h
index b98c0d9..ad1fc85 100644
--- a/arch/x86/include/asm/processor.h
+++ b/arch/x86/include/asm/processor.h
@@ -588,11 +588,6 @@ typedef struct {
} mm_segment_t;
-/*
- * create a kernel thread without removing it from tasklists
- */
-extern int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
-
/* Free all resources held by a thread. */
extern void release_thread(struct task_struct *);
diff --git a/arch/x86/include/asm/sys_ia32.h b/arch/x86/include/asm/sys_ia32.h
index 4ca1c61..a9a8cf3 100644
--- a/arch/x86/include/asm/sys_ia32.h
+++ b/arch/x86/include/asm/sys_ia32.h
@@ -54,8 +54,6 @@ asmlinkage long sys32_pwrite(unsigned int, const char __user *, u32, u32, u32);
asmlinkage long sys32_personality(unsigned long);
asmlinkage long sys32_sendfile(int, int, compat_off_t __user *, s32);
-asmlinkage long sys32_execve(const char __user *, compat_uptr_t __user *,
- compat_uptr_t __user *, struct pt_regs *);
asmlinkage long sys32_clone(unsigned int, unsigned int, struct pt_regs *);
long sys32_lseek(unsigned int, int, unsigned int);
diff --git a/arch/x86/include/asm/syscalls.h b/arch/x86/include/asm/syscalls.h
index f1d8b44..2be0b88 100644
--- a/arch/x86/include/asm/syscalls.h
+++ b/arch/x86/include/asm/syscalls.h
@@ -25,7 +25,7 @@ int sys_fork(struct pt_regs *);
int sys_vfork(struct pt_regs *);
long sys_execve(const char __user *,
const char __user *const __user *,
- const char __user *const __user *, struct pt_regs *);
+ const char __user *const __user *);
long sys_clone(unsigned long, unsigned long, void __user *,
void __user *, struct pt_regs *);
diff --git a/arch/x86/include/asm/thread_info.h b/arch/x86/include/asm/thread_info.h
index c535d847..2d946e6 100644
--- a/arch/x86/include/asm/thread_info.h
+++ b/arch/x86/include/asm/thread_info.h
@@ -79,7 +79,6 @@ struct thread_info {
#define TIF_SIGPENDING 2 /* signal pending */
#define TIF_NEED_RESCHED 3 /* rescheduling necessary */
#define TIF_SINGLESTEP 4 /* reenable singlestep on user return*/
-#define TIF_IRET 5 /* force IRET */
#define TIF_SYSCALL_EMU 6 /* syscall emulation active */
#define TIF_SYSCALL_AUDIT 7 /* syscall auditing active */
#define TIF_SECCOMP 8 /* secure computing */
@@ -105,7 +104,6 @@ struct thread_info {
#define _TIF_SIGPENDING (1 << TIF_SIGPENDING)
#define _TIF_SINGLESTEP (1 << TIF_SINGLESTEP)
#define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED)
-#define _TIF_IRET (1 << TIF_IRET)
#define _TIF_SYSCALL_EMU (1 << TIF_SYSCALL_EMU)
#define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT)
#define _TIF_SECCOMP (1 << TIF_SECCOMP)
diff --git a/arch/x86/include/asm/unistd.h b/arch/x86/include/asm/unistd.h
index 0d9776e..55d1555 100644
--- a/arch/x86/include/asm/unistd.h
+++ b/arch/x86/include/asm/unistd.h
@@ -50,6 +50,8 @@
# define __ARCH_WANT_SYS_TIME
# define __ARCH_WANT_SYS_UTIME
# define __ARCH_WANT_SYS_WAITPID
+# define __ARCH_WANT_SYS_EXECVE
+# define __ARCH_WANT_KERNEL_EXECVE
/*
* "Conditional" syscalls
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
index a48ea05..91ce48f 100644
--- a/arch/x86/kernel/Makefile
+++ b/arch/x86/kernel/Makefile
@@ -23,7 +23,7 @@ obj-y += time.o ioport.o ldt.o dumpstack.o nmi.o
obj-y += setup.o x86_init.o i8259.o irqinit.o jump_label.o
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_32) += i386_ksyms_32.o
obj-$(CONFIG_X86_64) += sys_x86_64.o x8664_ksyms_64.o
obj-y += syscall_$(BITS).o
obj-$(CONFIG_X86_64) += vsyscall_64.o
diff --git a/arch/x86/kernel/asm-offsets.c b/arch/x86/kernel/asm-offsets.c
index 68de2dc..2861082 100644
--- a/arch/x86/kernel/asm-offsets.c
+++ b/arch/x86/kernel/asm-offsets.c
@@ -69,4 +69,7 @@ void common(void) {
OFFSET(BP_kernel_alignment, boot_params, hdr.kernel_alignment);
OFFSET(BP_pref_address, boot_params, hdr.pref_address);
OFFSET(BP_code32_start, boot_params, hdr.code32_start);
+
+ BLANK();
+ DEFINE(PTREGS_SIZE, sizeof(struct pt_regs));
}
diff --git a/arch/x86/kernel/entry_32.S b/arch/x86/kernel/entry_32.S
index 0750e3b..2c63407 100644
--- a/arch/x86/kernel/entry_32.S
+++ b/arch/x86/kernel/entry_32.S
@@ -299,6 +299,13 @@ ENTRY(ret_from_fork)
CFI_ENDPROC
END(ret_from_fork)
+ENTRY(ret_from_kernel_execve)
+ movl %eax, %esp
+ movl $0,PT_EAX(%esp)
+ GET_THREAD_INFO(%ebp)
+ jmp syscall_exit
+END(ret_from_kernel_execve)
+
/*
* Interrupt exit functions should be protected against kprobes
*/
@@ -323,8 +330,7 @@ ret_from_intr:
andl $(X86_EFLAGS_VM | SEGMENT_RPL_MASK), %eax
#else
/*
- * We can be coming here from a syscall done in the kernel space,
- * e.g. a failed kernel_execve().
+ * We can be coming here from child spawned by kernel_thread().
*/
movl PT_CS(%esp), %eax
andl $SEGMENT_RPL_MASK, %eax
@@ -616,6 +622,10 @@ work_notifysig: # deal with pending signals and
movl %esp, %eax
jne work_notifysig_v86 # returning to kernel-space or
# vm86-space
+1:
+#else
+ movl %esp, %eax
+#endif
TRACE_IRQS_ON
ENABLE_INTERRUPTS(CLBR_NONE)
movb PT_CS(%esp), %bl
@@ -626,24 +636,15 @@ work_notifysig: # deal with pending signals and
call do_notify_resume
jmp resume_userspace
+#ifdef CONFIG_VM86
ALIGN
work_notifysig_v86:
pushl_cfi %ecx # save ti_flags for do_notify_resume
call save_v86_state # %eax contains pt_regs pointer
popl_cfi %ecx
movl %eax, %esp
-#else
- movl %esp, %eax
+ jmp 1b
#endif
- TRACE_IRQS_ON
- ENABLE_INTERRUPTS(CLBR_NONE)
- movb PT_CS(%esp), %bl
- andb $SEGMENT_RPL_MASK, %bl
- cmpb $USER_RPL, %bl
- jb resume_kernel
- xorl %edx, %edx
- call do_notify_resume
- jmp resume_userspace
END(work_pending)
# perform syscall exit tracing
@@ -732,7 +733,6 @@ ENDPROC(ptregs_##name)
PTREGSCALL1(iopl)
PTREGSCALL0(fork)
PTREGSCALL0(vfork)
-PTREGSCALL3(execve)
PTREGSCALL2(sigaltstack)
PTREGSCALL0(sigreturn)
PTREGSCALL0(rt_sigreturn)
@@ -1015,15 +1015,20 @@ END(spurious_interrupt_bug)
*/
.popsection
-ENTRY(kernel_thread_helper)
- pushl $0 # fake return address for unwinder
+ENTRY(ret_from_kernel_thread)
CFI_STARTPROC
- movl %edi,%eax
- call *%esi
+ pushl_cfi %eax
+ call schedule_tail
+ GET_THREAD_INFO(%ebp)
+ popl_cfi %eax
+ pushl_cfi $0x0202 # Reset kernel eflags
+ popfl_cfi
+ movl PT_EBP(%esp),%eax
+ call *PT_EBX(%esp)
call do_exit
ud2 # padding for call trace
CFI_ENDPROC
-ENDPROC(kernel_thread_helper)
+ENDPROC(ret_from_kernel_thread)
#ifdef CONFIG_XEN
/* Xen doesn't set %esp to be precisely what the normal sysenter
diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S
index 44531ac..cdc790c 100644
--- a/arch/x86/kernel/entry_64.S
+++ b/arch/x86/kernel/entry_64.S
@@ -554,7 +554,7 @@ ENTRY(ret_from_fork)
RESTORE_REST
testl $3, CS-ARGOFFSET(%rsp) # from kernel_thread?
- jz retint_restore_args
+ jz 1f
testl $_TIF_IA32, TI_flags(%rcx) # 32-bit compat task needs IRET
jnz int_ret_from_sys_call
@@ -562,6 +562,16 @@ ENTRY(ret_from_fork)
RESTORE_TOP_OF_STACK %rdi, -ARGOFFSET
jmp ret_from_sys_call # go to the SYSRET fastpath
+1:
+ subq $REST_SKIP, %rsp # move the stack pointer back
+ CFI_ADJUST_CFA_OFFSET REST_SKIP
+ movq %rbp, %rdi
+ call *%rbx
+ # exit
+ mov %eax, %edi
+ call do_exit
+ ud2 # padding for call trace
+
CFI_ENDPROC
END(ret_from_fork)
@@ -862,7 +872,6 @@ ENTRY(stub_execve)
PARTIAL_FRAME 0
SAVE_REST
FIXUP_TOP_OF_STACK %r11
- movq %rsp, %rcx
call sys_execve
RESTORE_TOP_OF_STACK %r11
movq %rax,RAX(%rsp)
@@ -912,8 +921,7 @@ ENTRY(stub_x32_execve)
PARTIAL_FRAME 0
SAVE_REST
FIXUP_TOP_OF_STACK %r11
- movq %rsp, %rcx
- call sys32_execve
+ call compat_sys_execve
RESTORE_TOP_OF_STACK %r11
movq %rax,RAX(%rsp)
RESTORE_REST
@@ -1318,51 +1326,19 @@ bad_gs:
jmp 2b
.previous
-ENTRY(kernel_thread_helper)
- pushq $0 # fake return address
- CFI_STARTPROC
- /*
- * Here we are in the child and the registers are set as they were
- * at kernel_thread() invocation in the parent.
- */
- call *%rsi
- # exit
- mov %eax, %edi
- call do_exit
- ud2 # padding for call trace
- CFI_ENDPROC
-END(kernel_thread_helper)
-
-/*
- * execve(). This function needs to use IRET, not SYSRET, to set up all state properly.
- *
- * C extern interface:
- * extern long execve(const char *name, char **argv, char **envp)
- *
- * asm input arguments:
- * rdi: name, rsi: argv, rdx: envp
- *
- * We want to fallback into:
- * extern long sys_execve(const char *name, char **argv,char **envp, struct pt_regs *regs)
- *
- * do_sys_execve asm fallback arguments:
- * rdi: name, rsi: argv, rdx: envp, rcx: fake frame on the stack
- */
-ENTRY(kernel_execve)
- CFI_STARTPROC
- FAKE_STACK_FRAME $0
- SAVE_ALL
- movq %rsp,%rcx
- call sys_execve
- movq %rax, RAX(%rsp)
- RESTORE_REST
- testq %rax,%rax
- je int_ret_from_sys_call
- RESTORE_ARGS
- UNFAKE_STACK_FRAME
- ret
- CFI_ENDPROC
-END(kernel_execve)
+ENTRY(ret_from_kernel_execve)
+ movq %rdi, %rsp
+ movl $0, RAX(%rsp)
+ // RESTORE_REST
+ movq 0*8(%rsp), %r15
+ movq 1*8(%rsp), %r14
+ movq 2*8(%rsp), %r13
+ movq 3*8(%rsp), %r12
+ movq 4*8(%rsp), %rbp
+ movq 5*8(%rsp), %rbx
+ addq $(6*8), %rsp
+ jmp int_ret_from_sys_call
+END(ret_from_kernel_execve)
/* Call softirq on interrupt stack. Interrupts are off. */
ENTRY(call_softirq)
diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c
index dc3567e..b644e1c 100644
--- a/arch/x86/kernel/process.c
+++ b/arch/x86/kernel/process.c
@@ -293,71 +293,6 @@ sys_clone(unsigned long clone_flags, unsigned long newsp,
}
/*
- * This gets run with %si containing the
- * function to call, and %di containing
- * the "args".
- */
-extern void kernel_thread_helper(void);
-
-/*
- * Create a kernel thread
- */
-int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
-{
- struct pt_regs regs;
-
- memset(&regs, 0, sizeof(regs));
-
- regs.si = (unsigned long) fn;
- regs.di = (unsigned long) arg;
-
-#ifdef CONFIG_X86_32
- regs.ds = __USER_DS;
- regs.es = __USER_DS;
- regs.fs = __KERNEL_PERCPU;
- regs.gs = __KERNEL_STACK_CANARY;
-#else
- regs.ss = __KERNEL_DS;
-#endif
-
- regs.orig_ax = -1;
- regs.ip = (unsigned long) kernel_thread_helper;
- regs.cs = __KERNEL_CS | get_kernel_rpl();
- regs.flags = X86_EFLAGS_IF | X86_EFLAGS_BIT1;
-
- /* Ok, create the new process.. */
- return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, &regs, 0, NULL, NULL);
-}
-EXPORT_SYMBOL(kernel_thread);
-
-/*
- * sys_execve() executes a new program.
- */
-long sys_execve(const char __user *name,
- const char __user *const __user *argv,
- const char __user *const __user *envp, struct pt_regs *regs)
-{
- long error;
- char *filename;
-
- filename = getname(name);
- error = PTR_ERR(filename);
- if (IS_ERR(filename))
- return error;
- error = do_execve(filename, argv, envp, regs);
-
-#ifdef CONFIG_X86_32
- if (error == 0) {
- /* Make sure we don't return using sysenter.. */
- set_thread_flag(TIF_IRET);
- }
-#endif
-
- putname(filename);
- return error;
-}
-
-/*
* Idle related variables and functions
*/
unsigned long boot_option_idle_override = IDLE_NO_OVERRIDE;
diff --git a/arch/x86/kernel/process_32.c b/arch/x86/kernel/process_32.c
index b9ff83c..44e0bff 100644
--- a/arch/x86/kernel/process_32.c
+++ b/arch/x86/kernel/process_32.c
@@ -57,6 +57,7 @@
#include <asm/switch_to.h>
asmlinkage void ret_from_fork(void) __asm__("ret_from_fork");
+asmlinkage void ret_from_kernel_thread(void) __asm__("ret_from_kernel_thread");
/*
* Return saved PC of a blocked thread.
@@ -127,23 +128,39 @@ void release_thread(struct task_struct *dead_task)
}
int copy_thread(unsigned long clone_flags, unsigned long sp,
- unsigned long unused,
+ unsigned long arg,
struct task_struct *p, struct pt_regs *regs)
{
- struct pt_regs *childregs;
+ struct pt_regs *childregs = task_pt_regs(p);
struct task_struct *tsk;
int err;
- childregs = task_pt_regs(p);
+ p->thread.sp = (unsigned long) childregs;
+ p->thread.sp0 = (unsigned long) (childregs+1);
+
+ if (unlikely(!regs)) {
+ /* kernel thread */
+ memset(childregs, 0, sizeof(struct pt_regs));
+ p->thread.ip = (unsigned long) ret_from_kernel_thread;
+ task_user_gs(p) = __KERNEL_STACK_CANARY;
+ childregs->ds = __USER_DS;
+ childregs->es = __USER_DS;
+ childregs->fs = __KERNEL_PERCPU;
+ childregs->bx = sp; /* function */
+ childregs->bp = arg;
+ childregs->orig_ax = -1;
+ childregs->cs = __KERNEL_CS | get_kernel_rpl();
+ childregs->flags = X86_EFLAGS_IF | X86_EFLAGS_BIT1;
+ p->fpu_counter = 0;
+ p->thread.io_bitmap_ptr = NULL;
+ memset(p->thread.ptrace_bps, 0, sizeof(p->thread.ptrace_bps));
+ return 0;
+ }
*childregs = *regs;
childregs->ax = 0;
childregs->sp = sp;
- p->thread.sp = (unsigned long) childregs;
- p->thread.sp0 = (unsigned long) (childregs+1);
-
p->thread.ip = (unsigned long) ret_from_fork;
-
task_user_gs(p) = get_user_gs(regs);
p->fpu_counter = 0;
@@ -190,6 +207,12 @@ start_thread(struct pt_regs *regs, unsigned long new_ip, unsigned long new_sp)
regs->cs = __USER_CS;
regs->ip = new_ip;
regs->sp = new_sp;
+ regs->flags = X86_EFLAGS_IF;
+ /*
+ * force it to the iret return path by making it look as if there was
+ * some work pending.
+ */
+ set_thread_flag(TIF_NOTIFY_RESUME);
}
EXPORT_SYMBOL_GPL(start_thread);
diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c
index 8a6d20c..16c6365 100644
--- a/arch/x86/kernel/process_64.c
+++ b/arch/x86/kernel/process_64.c
@@ -146,29 +146,18 @@ static inline u32 read_32bit_tls(struct task_struct *t, int tls)
}
int copy_thread(unsigned long clone_flags, unsigned long sp,
- unsigned long unused,
+ unsigned long arg,
struct task_struct *p, struct pt_regs *regs)
{
int err;
struct pt_regs *childregs;
struct task_struct *me = current;
- childregs = ((struct pt_regs *)
- (THREAD_SIZE + task_stack_page(p))) - 1;
- *childregs = *regs;
-
- childregs->ax = 0;
- if (user_mode(regs))
- childregs->sp = sp;
- else
- childregs->sp = (unsigned long)childregs;
-
+ p->thread.sp0 = (unsigned long)task_stack_page(p) + THREAD_SIZE;
+ childregs = task_pt_regs(p);
p->thread.sp = (unsigned long) childregs;
- p->thread.sp0 = (unsigned long) (childregs+1);
p->thread.usersp = me->thread.usersp;
-
set_tsk_thread_flag(p, TIF_FORK);
-
p->fpu_counter = 0;
p->thread.io_bitmap_ptr = NULL;
@@ -178,6 +167,24 @@ int copy_thread(unsigned long clone_flags, unsigned long sp,
p->thread.fs = p->thread.fsindex ? 0 : me->thread.fs;
savesegment(es, p->thread.es);
savesegment(ds, p->thread.ds);
+ memset(p->thread.ptrace_bps, 0, sizeof(p->thread.ptrace_bps));
+
+ if (unlikely(!regs)) {
+ /* kernel thread */
+ memset(childregs, 0, sizeof(struct pt_regs));
+ childregs->sp = (unsigned long)childregs;
+ childregs->ss = __KERNEL_DS;
+ childregs->bx = sp; /* function */
+ childregs->bp = arg;
+ childregs->orig_ax = -1;
+ childregs->cs = __KERNEL_CS | get_kernel_rpl();
+ childregs->flags = X86_EFLAGS_IF | X86_EFLAGS_BIT1;
+ return 0;
+ }
+ *childregs = *regs;
+
+ childregs->ax = 0;
+ childregs->sp = sp;
err = -ENOMEM;
memset(p->thread.ptrace_bps, 0, sizeof(p->thread.ptrace_bps));
diff --git a/arch/x86/kernel/signal.c b/arch/x86/kernel/signal.c
index b33144c..29ad351 100644
--- a/arch/x86/kernel/signal.c
+++ b/arch/x86/kernel/signal.c
@@ -840,10 +840,6 @@ do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags)
if (thread_info_flags & _TIF_USER_RETURN_NOTIFY)
fire_user_return_notifiers();
-#ifdef CONFIG_X86_32
- clear_thread_flag(TIF_IRET);
-#endif /* CONFIG_X86_32 */
-
rcu_user_enter();
}
diff --git a/arch/x86/kernel/sys_i386_32.c b/arch/x86/kernel/sys_i386_32.c
deleted file mode 100644
index 0b0cb5f..0000000
--- a/arch/x86/kernel/sys_i386_32.c
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * This file contains various random system calls that
- * have a non-standard calling sequence on the Linux/i386
- * platform.
- */
-
-#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/utsname.h>
-#include <linux/ipc.h>
-
-#include <linux/uaccess.h>
-#include <linux/unistd.h>
-
-#include <asm/syscalls.h>
-
-/*
- * 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[])
-{
- long __res;
- asm volatile ("int $0x80"
- : "=a" (__res)
- : "0" (__NR_execve), "b" (filename), "c" (argv), "d" (envp) : "memory");
- return __res;
-}
diff --git a/arch/x86/kernel/vm86_32.c b/arch/x86/kernel/vm86_32.c
index 54abcc0..5c9687b 100644
--- a/arch/x86/kernel/vm86_32.c
+++ b/arch/x86/kernel/vm86_32.c
@@ -561,9 +561,9 @@ int handle_vm86_trap(struct kernel_vm86_regs *regs, long error_code, int trapno)
if ((trapno == 3) || (trapno == 1)) {
KVM86->regs32->ax = VM86_TRAP + (trapno << 8);
/* setting this flag forces the code in entry_32.S to
- call save_v86_state() and change the stack pointer
- to KVM86->regs32 */
- set_thread_flag(TIF_IRET);
+ the path where we call save_v86_state() and change
+ the stack pointer to KVM86->regs32 */
+ set_thread_flag(TIF_NOTIFY_RESUME);
return 0;
}
do_int(regs, trapno, (unsigned char __user *) (regs->pt.ss << 4), SP(regs));
diff --git a/arch/x86/syscalls/syscall_32.tbl b/arch/x86/syscalls/syscall_32.tbl
index 7a35a6e..a47103f 100644
--- a/arch/x86/syscalls/syscall_32.tbl
+++ b/arch/x86/syscalls/syscall_32.tbl
@@ -17,7 +17,7 @@
8 i386 creat sys_creat
9 i386 link sys_link
10 i386 unlink sys_unlink
-11 i386 execve ptregs_execve stub32_execve
+11 i386 execve sys_execve stub32_execve
12 i386 chdir sys_chdir
13 i386 time sys_time compat_sys_time
14 i386 mknod sys_mknod
diff --git a/arch/x86/um/Kconfig b/arch/x86/um/Kconfig
index aeaff8b..30c4eec 100644
--- a/arch/x86/um/Kconfig
+++ b/arch/x86/um/Kconfig
@@ -13,6 +13,7 @@ endmenu
config UML_X86
def_bool y
select GENERIC_FIND_FIRST_BIT
+ select GENERIC_KERNEL_THREAD
config 64BIT
bool "64-bit kernel" if SUBARCH = "x86"
diff --git a/arch/x86/um/asm/checksum.h b/arch/x86/um/asm/checksum.h
index b6efe23..4b181b7 100644
--- a/arch/x86/um/asm/checksum.h
+++ b/arch/x86/um/asm/checksum.h
@@ -1,6 +1,150 @@
#ifndef __UM_CHECKSUM_H
#define __UM_CHECKSUM_H
+#include <linux/string.h>
+#include <linux/in6.h>
+
+/*
+ * computes the checksum of a memory block at buff, length len,
+ * and adds in "sum" (32-bit)
+ *
+ * returns a 32-bit number suitable for feeding into itself
+ * or csum_tcpudp_magic
+ *
+ * this function must be called with even lengths, except
+ * for the last fragment, which may be odd
+ *
+ * it's best to have buff aligned on a 32-bit boundary
+ */
+extern __wsum csum_partial(const void *buff, int len, __wsum sum);
+
+/*
+ * Note: when you get a NULL pointer exception here this means someone
+ * passed in an incorrect kernel address to one of these functions.
+ *
+ * If you use these functions directly please don't forget the
+ * access_ok().
+ */
+
+static __inline__
+__wsum csum_partial_copy_nocheck(const void *src, void *dst,
+ int len, __wsum sum)
+{
+ memcpy(dst, src, len);
+ return csum_partial(dst, len, sum);
+}
+
+/*
+ * the same as csum_partial, but copies from src while it
+ * checksums, and handles user-space pointer exceptions correctly, when needed.
+ *
+ * here even more important to align src and dst on a 32-bit (or even
+ * better 64-bit) boundary
+ */
+
+static __inline__
+__wsum csum_partial_copy_from_user(const void __user *src, void *dst,
+ int len, __wsum sum, int *err_ptr)
+{
+ if (copy_from_user(dst, src, len)) {
+ *err_ptr = -EFAULT;
+ return (__force __wsum)-1;
+ }
+
+ return csum_partial(dst, len, sum);
+}
+
+/**
+ * csum_fold - Fold and invert a 32bit checksum.
+ * sum: 32bit unfolded sum
+ *
+ * Fold a 32bit running checksum to 16bit and invert it. This is usually
+ * the last step before putting a checksum into a packet.
+ * Make sure not to mix with 64bit checksums.
+ */
+static inline __sum16 csum_fold(__wsum sum)
+{
+ __asm__(
+ " addl %1,%0\n"
+ " adcl $0xffff,%0"
+ : "=r" (sum)
+ : "r" ((__force u32)sum << 16),
+ "0" ((__force u32)sum & 0xffff0000)
+ );
+ return (__force __sum16)(~(__force u32)sum >> 16);
+}
+
+/**
+ * csum_tcpup_nofold - Compute an IPv4 pseudo header checksum.
+ * @saddr: source address
+ * @daddr: destination address
+ * @len: length of packet
+ * @proto: ip protocol of packet
+ * @sum: initial sum to be added in (32bit unfolded)
+ *
+ * Returns the pseudo header checksum the input data. Result is
+ * 32bit unfolded.
+ */
+static inline __wsum
+csum_tcpudp_nofold(__be32 saddr, __be32 daddr, unsigned short len,
+ unsigned short proto, __wsum sum)
+{
+ asm(" addl %1, %0\n"
+ " adcl %2, %0\n"
+ " adcl %3, %0\n"
+ " adcl $0, %0\n"
+ : "=r" (sum)
+ : "g" (daddr), "g" (saddr), "g" ((len + proto) << 8), "0" (sum));
+ return sum;
+}
+
+/*
+ * computes the checksum of the TCP/UDP pseudo-header
+ * returns a 16-bit checksum, already complemented
+ */
+static inline __sum16 csum_tcpudp_magic(__be32 saddr, __be32 daddr,
+ unsigned short len,
+ unsigned short proto,
+ __wsum sum)
+{
+ return csum_fold(csum_tcpudp_nofold(saddr,daddr,len,proto,sum));
+}
+
+/**
+ * ip_fast_csum - Compute the IPv4 header checksum efficiently.
+ * iph: ipv4 header
+ * ihl: length of header / 4
+ */
+static inline __sum16 ip_fast_csum(const void *iph, unsigned int ihl)
+{
+ unsigned int sum;
+
+ asm( " movl (%1), %0\n"
+ " subl $4, %2\n"
+ " jbe 2f\n"
+ " addl 4(%1), %0\n"
+ " adcl 8(%1), %0\n"
+ " adcl 12(%1), %0\n"
+ "1: adcl 16(%1), %0\n"
+ " lea 4(%1), %1\n"
+ " decl %2\n"
+ " jne 1b\n"
+ " adcl $0, %0\n"
+ " movl %0, %2\n"
+ " shrl $16, %0\n"
+ " addw %w2, %w0\n"
+ " adcl $0, %0\n"
+ " notl %0\n"
+ "2:"
+ /* Since the input registers which are loaded with iph and ipl
+ are modified, we must also specify them as outputs, or gcc
+ will assume they contain their original values. */
+ : "=r" (sum), "=r" (iph), "=r" (ihl)
+ : "1" (iph), "2" (ihl)
+ : "memory");
+ return (__force __sum16)sum;
+}
+
#ifdef CONFIG_X86_32
# include "checksum_32.h"
#else
diff --git a/arch/x86/um/asm/checksum_32.h b/arch/x86/um/asm/checksum_32.h
index caab742..ab77b6f 100644
--- a/arch/x86/um/asm/checksum_32.h
+++ b/arch/x86/um/asm/checksum_32.h
@@ -5,145 +5,6 @@
#ifndef __UM_SYSDEP_CHECKSUM_H
#define __UM_SYSDEP_CHECKSUM_H
-#include "linux/in6.h"
-#include "linux/string.h"
-
-/*
- * computes the checksum of a memory block at buff, length len,
- * and adds in "sum" (32-bit)
- *
- * returns a 32-bit number suitable for feeding into itself
- * or csum_tcpudp_magic
- *
- * this function must be called with even lengths, except
- * for the last fragment, which may be odd
- *
- * it's best to have buff aligned on a 32-bit boundary
- */
-__wsum csum_partial(const void *buff, int len, __wsum sum);
-
-/*
- * Note: when you get a NULL pointer exception here this means someone
- * passed in an incorrect kernel address to one of these functions.
- *
- * If you use these functions directly please don't forget the
- * access_ok().
- */
-
-static __inline__
-__wsum csum_partial_copy_nocheck(const void *src, void *dst,
- int len, __wsum sum)
-{
- memcpy(dst, src, len);
- return csum_partial(dst, len, sum);
-}
-
-/*
- * the same as csum_partial, but copies from src while it
- * checksums, and handles user-space pointer exceptions correctly, when needed.
- *
- * here even more important to align src and dst on a 32-bit (or even
- * better 64-bit) boundary
- */
-
-static __inline__
-__wsum csum_partial_copy_from_user(const void __user *src, void *dst,
- int len, __wsum sum, int *err_ptr)
-{
- if (copy_from_user(dst, src, len)) {
- *err_ptr = -EFAULT;
- return (__force __wsum)-1;
- }
-
- return csum_partial(dst, len, sum);
-}
-
-/*
- * This is a version of ip_compute_csum() optimized for IP headers,
- * which always checksum on 4 octet boundaries.
- *
- * By Jorge Cwik <jorge@laser.satlink.net>, adapted for linux by
- * Arnt Gulbrandsen.
- */
-static inline __sum16 ip_fast_csum(const void *iph, unsigned int ihl)
-{
- unsigned int sum;
-
- __asm__ __volatile__(
- "movl (%1), %0 ;\n"
- "subl $4, %2 ;\n"
- "jbe 2f ;\n"
- "addl 4(%1), %0 ;\n"
- "adcl 8(%1), %0 ;\n"
- "adcl 12(%1), %0 ;\n"
-"1: adcl 16(%1), %0 ;\n"
- "lea 4(%1), %1 ;\n"
- "decl %2 ;\n"
- "jne 1b ;\n"
- "adcl $0, %0 ;\n"
- "movl %0, %2 ;\n"
- "shrl $16, %0 ;\n"
- "addw %w2, %w0 ;\n"
- "adcl $0, %0 ;\n"
- "notl %0 ;\n"
-"2: ;\n"
- /* Since the input registers which are loaded with iph and ipl
- are modified, we must also specify them as outputs, or gcc
- will assume they contain their original values. */
- : "=r" (sum), "=r" (iph), "=r" (ihl)
- : "1" (iph), "2" (ihl)
- : "memory");
- return (__force __sum16)sum;
-}
-
-/*
- * Fold a partial checksum
- */
-
-static inline __sum16 csum_fold(__wsum sum)
-{
- __asm__(
- "addl %1, %0 ;\n"
- "adcl $0xffff, %0 ;\n"
- : "=r" (sum)
- : "r" ((__force u32)sum << 16),
- "0" ((__force u32)sum & 0xffff0000)
- );
- return (__force __sum16)(~(__force u32)sum >> 16);
-}
-
-static inline __wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr,
- unsigned short len,
- unsigned short proto,
- __wsum sum)
-{
- __asm__(
- "addl %1, %0 ;\n"
- "adcl %2, %0 ;\n"
- "adcl %3, %0 ;\n"
- "adcl $0, %0 ;\n"
- : "=r" (sum)
- : "g" (daddr), "g"(saddr), "g"((len + proto) << 8), "0"(sum));
- return sum;
-}
-
-/*
- * computes the checksum of the TCP/UDP pseudo-header
- * returns a 16-bit checksum, already complemented
- */
-static inline __sum16 csum_tcpudp_magic(__be32 saddr, __be32 daddr,
- unsigned short len,
- unsigned short proto,
- __wsum sum)
-{
- return csum_fold(csum_tcpudp_nofold(saddr,daddr,len,proto,sum));
-}
-
-/*
- * this routine is used for miscellaneous IP-like checksums, mainly
- * in icmp.c
- */
-
static inline __sum16 ip_compute_csum(const void *buff, int len)
{
return csum_fold (csum_partial(buff, len, 0));
@@ -198,4 +59,3 @@ static __inline__ __wsum csum_and_copy_to_user(const void *src,
}
#endif
-
diff --git a/arch/x86/um/asm/checksum_64.h b/arch/x86/um/asm/checksum_64.h
index a5be903..7b6cd19 100644
--- a/arch/x86/um/asm/checksum_64.h
+++ b/arch/x86/um/asm/checksum_64.h
@@ -5,131 +5,6 @@
#ifndef __UM_SYSDEP_CHECKSUM_H
#define __UM_SYSDEP_CHECKSUM_H
-#include "linux/string.h"
-#include "linux/in6.h"
-#include "asm/uaccess.h"
-
-extern __wsum csum_partial(const void *buff, int len, __wsum sum);
-
-/*
- * Note: when you get a NULL pointer exception here this means someone
- * passed in an incorrect kernel address to one of these functions.
- *
- * If you use these functions directly please don't forget the
- * access_ok().
- */
-
-static __inline__
-__wsum csum_partial_copy_nocheck(const void *src, void *dst,
- int len, __wsum sum)
-{
- memcpy(dst, src, len);
- return(csum_partial(dst, len, sum));
-}
-
-static __inline__
-__wsum csum_partial_copy_from_user(const void __user *src,
- void *dst, int len, __wsum sum,
- int *err_ptr)
-{
- if (copy_from_user(dst, src, len)) {
- *err_ptr = -EFAULT;
- return (__force __wsum)-1;
- }
- return csum_partial(dst, len, sum);
-}
-
-/**
- * csum_fold - Fold and invert a 32bit checksum.
- * sum: 32bit unfolded sum
- *
- * Fold a 32bit running checksum to 16bit and invert it. This is usually
- * the last step before putting a checksum into a packet.
- * Make sure not to mix with 64bit checksums.
- */
-static inline __sum16 csum_fold(__wsum sum)
-{
- __asm__(
- " addl %1,%0\n"
- " adcl $0xffff,%0"
- : "=r" (sum)
- : "r" ((__force u32)sum << 16),
- "0" ((__force u32)sum & 0xffff0000)
- );
- return (__force __sum16)(~(__force u32)sum >> 16);
-}
-
-/**
- * csum_tcpup_nofold - Compute an IPv4 pseudo header checksum.
- * @saddr: source address
- * @daddr: destination address
- * @len: length of packet
- * @proto: ip protocol of packet
- * @sum: initial sum to be added in (32bit unfolded)
- *
- * Returns the pseudo header checksum the input data. Result is
- * 32bit unfolded.
- */
-static inline __wsum
-csum_tcpudp_nofold(__be32 saddr, __be32 daddr, unsigned short len,
- unsigned short proto, __wsum sum)
-{
- asm(" addl %1, %0\n"
- " adcl %2, %0\n"
- " adcl %3, %0\n"
- " adcl $0, %0\n"
- : "=r" (sum)
- : "g" (daddr), "g" (saddr), "g" ((len + proto) << 8), "0" (sum));
- return sum;
-}
-
-/*
- * computes the checksum of the TCP/UDP pseudo-header
- * returns a 16-bit checksum, already complemented
- */
-static inline __sum16 csum_tcpudp_magic(__be32 saddr, __be32 daddr,
- unsigned short len,
- unsigned short proto,
- __wsum sum)
-{
- return csum_fold(csum_tcpudp_nofold(saddr,daddr,len,proto,sum));
-}
-
-/**
- * ip_fast_csum - Compute the IPv4 header checksum efficiently.
- * iph: ipv4 header
- * ihl: length of header / 4
- */
-static inline __sum16 ip_fast_csum(const void *iph, unsigned int ihl)
-{
- unsigned int sum;
-
- asm( " movl (%1), %0\n"
- " subl $4, %2\n"
- " jbe 2f\n"
- " addl 4(%1), %0\n"
- " adcl 8(%1), %0\n"
- " adcl 12(%1), %0\n"
- "1: adcl 16(%1), %0\n"
- " lea 4(%1), %1\n"
- " decl %2\n"
- " jne 1b\n"
- " adcl $0, %0\n"
- " movl %0, %2\n"
- " shrl $16, %0\n"
- " addw %w2, %w0\n"
- " adcl $0, %0\n"
- " notl %0\n"
- "2:"
- /* Since the input registers which are loaded with iph and ipl
- are modified, we must also specify them as outputs, or gcc
- will assume they contain their original values. */
- : "=r" (sum), "=r" (iph), "=r" (ihl)
- : "1" (iph), "2" (ihl)
- : "memory");
- return (__force __sum16)sum;
-}
-
static inline unsigned add32_with_carry(unsigned a, unsigned b)
{
asm("addl %2,%0\n\t"
diff --git a/arch/x86/um/asm/elf.h b/arch/x86/um/asm/elf.h
index 0e07adc..0feee2f 100644
--- a/arch/x86/um/asm/elf.h
+++ b/arch/x86/um/asm/elf.h
@@ -6,7 +6,7 @@
#define __UM_ELF_X86_H
#include <asm/user.h>
-#include "skas.h"
+#include <skas.h>
#ifdef CONFIG_X86_32
diff --git a/arch/x86/um/asm/ptrace.h b/arch/x86/um/asm/ptrace.h
index e72cd0d..75513325 100644
--- a/arch/x86/um/asm/ptrace.h
+++ b/arch/x86/um/asm/ptrace.h
@@ -1,11 +1,13 @@
#ifndef __UM_X86_PTRACE_H
#define __UM_X86_PTRACE_H
-#ifdef CONFIG_X86_32
-# include "ptrace_32.h"
-#else
-# include "ptrace_64.h"
+#include <linux/compiler.h>
+#ifndef CONFIG_X86_32
+#define __FRAME_OFFSETS /* Needed to get the R* macros */
#endif
+#include <asm/ptrace-generic.h>
+
+#define user_mode(r) UPT_IS_USER(&(r)->regs)
#define PT_REGS_AX(r) UPT_AX(&(r)->regs)
#define PT_REGS_BX(r) UPT_BX(&(r)->regs)
@@ -36,4 +38,52 @@ static inline long regs_return_value(struct pt_regs *regs)
{
return PT_REGS_AX(regs);
}
+
+/*
+ * Forward declaration to avoid including sysdep/tls.h, which causes a
+ * circular include, and compilation failures.
+ */
+struct user_desc;
+
+#ifdef CONFIG_X86_32
+
+#define HOST_AUDIT_ARCH AUDIT_ARCH_I386
+
+extern int ptrace_get_thread_area(struct task_struct *child, int idx,
+ struct user_desc __user *user_desc);
+
+extern int ptrace_set_thread_area(struct task_struct *child, int idx,
+ struct user_desc __user *user_desc);
+
+#else
+
+#define HOST_AUDIT_ARCH AUDIT_ARCH_X86_64
+
+#define PT_REGS_R8(r) UPT_R8(&(r)->regs)
+#define PT_REGS_R9(r) UPT_R9(&(r)->regs)
+#define PT_REGS_R10(r) UPT_R10(&(r)->regs)
+#define PT_REGS_R11(r) UPT_R11(&(r)->regs)
+#define PT_REGS_R12(r) UPT_R12(&(r)->regs)
+#define PT_REGS_R13(r) UPT_R13(&(r)->regs)
+#define PT_REGS_R14(r) UPT_R14(&(r)->regs)
+#define PT_REGS_R15(r) UPT_R15(&(r)->regs)
+
+#include <asm/errno.h>
+
+static inline int ptrace_get_thread_area(struct task_struct *child, int idx,
+ struct user_desc __user *user_desc)
+{
+ return -ENOSYS;
+}
+
+static inline int ptrace_set_thread_area(struct task_struct *child, int idx,
+ struct user_desc __user *user_desc)
+{
+ return -ENOSYS;
+}
+
+extern long arch_prctl(struct task_struct *task, int code,
+ unsigned long __user *addr);
+
+#endif
#endif /* __UM_X86_PTRACE_H */
diff --git a/arch/x86/um/asm/ptrace_32.h b/arch/x86/um/asm/ptrace_32.h
deleted file mode 100644
index 2cf2253..0000000
--- a/arch/x86/um/asm/ptrace_32.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
- * Licensed under the GPL
- */
-
-#ifndef __UM_PTRACE_I386_H
-#define __UM_PTRACE_I386_H
-
-#define HOST_AUDIT_ARCH AUDIT_ARCH_I386
-
-#include "linux/compiler.h"
-#include "asm/ptrace-generic.h"
-
-#define user_mode(r) UPT_IS_USER(&(r)->regs)
-
-/*
- * Forward declaration to avoid including sysdep/tls.h, which causes a
- * circular include, and compilation failures.
- */
-struct user_desc;
-
-extern int ptrace_get_thread_area(struct task_struct *child, int idx,
- struct user_desc __user *user_desc);
-
-extern int ptrace_set_thread_area(struct task_struct *child, int idx,
- struct user_desc __user *user_desc);
-
-#endif
diff --git a/arch/x86/um/asm/ptrace_64.h b/arch/x86/um/asm/ptrace_64.h
deleted file mode 100644
index ea7bff3..0000000
--- a/arch/x86/um/asm/ptrace_64.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright 2003 PathScale, Inc.
- *
- * Licensed under the GPL
- */
-
-#ifndef __UM_PTRACE_X86_64_H
-#define __UM_PTRACE_X86_64_H
-
-#include "linux/compiler.h"
-#include "asm/errno.h"
-
-#define __FRAME_OFFSETS /* Needed to get the R* macros */
-#include "asm/ptrace-generic.h"
-
-#define HOST_AUDIT_ARCH AUDIT_ARCH_X86_64
-
-#define PT_REGS_R8(r) UPT_R8(&(r)->regs)
-#define PT_REGS_R9(r) UPT_R9(&(r)->regs)
-#define PT_REGS_R10(r) UPT_R10(&(r)->regs)
-#define PT_REGS_R11(r) UPT_R11(&(r)->regs)
-#define PT_REGS_R12(r) UPT_R12(&(r)->regs)
-#define PT_REGS_R13(r) UPT_R13(&(r)->regs)
-#define PT_REGS_R14(r) UPT_R14(&(r)->regs)
-#define PT_REGS_R15(r) UPT_R15(&(r)->regs)
-
-/* XXX */
-#define user_mode(r) UPT_IS_USER(&(r)->regs)
-
-struct user_desc;
-
-static inline int ptrace_get_thread_area(struct task_struct *child, int idx,
- struct user_desc __user *user_desc)
-{
- return -ENOSYS;
-}
-
-static inline int ptrace_set_thread_area(struct task_struct *child, int idx,
- struct user_desc __user *user_desc)
-{
- return -ENOSYS;
-}
-
-extern long arch_prctl(struct task_struct *task, int code,
- unsigned long __user *addr);
-#endif
diff --git a/arch/x86/um/bugs_32.c b/arch/x86/um/bugs_32.c
index 17d88cf..33daff4 100644
--- a/arch/x86/um/bugs_32.c
+++ b/arch/x86/um/bugs_32.c
@@ -4,9 +4,9 @@
*/
#include <signal.h>
-#include "kern_util.h"
-#include "longjmp.h"
-#include "sysdep/ptrace.h"
+#include <kern_util.h>
+#include <longjmp.h>
+#include <sysdep/ptrace.h>
#include <generated/asm-offsets.h>
/* Set during early boot */
diff --git a/arch/x86/um/bugs_64.c b/arch/x86/um/bugs_64.c
index 44e02ba..8cc8256 100644
--- a/arch/x86/um/bugs_64.c
+++ b/arch/x86/um/bugs_64.c
@@ -4,7 +4,7 @@
* Licensed under the GPL
*/
-#include "sysdep/ptrace.h"
+#include <sysdep/ptrace.h>
void arch_check_bugs(void)
{
diff --git a/arch/x86/um/fault.c b/arch/x86/um/fault.c
index d670f68..8784ab3 100644
--- a/arch/x86/um/fault.c
+++ b/arch/x86/um/fault.c
@@ -3,7 +3,7 @@
* Licensed under the GPL
*/
-#include "sysdep/ptrace.h"
+#include <sysdep/ptrace.h>
/* These two are from asm-um/uaccess.h and linux/module.h, check them. */
struct exception_table_entry
diff --git a/arch/x86/um/ldt.c b/arch/x86/um/ldt.c
index 26b0e39..8e08176 100644
--- a/arch/x86/um/ldt.c
+++ b/arch/x86/um/ldt.c
@@ -7,11 +7,11 @@
#include <linux/sched.h>
#include <linux/slab.h>
#include <asm/unistd.h>
-#include "os.h"
-#include "proc_mm.h"
-#include "skas.h"
-#include "skas_ptrace.h"
-#include "sysdep/tls.h"
+#include <os.h>
+#include <proc_mm.h>
+#include <skas.h>
+#include <skas_ptrace.h>
+#include <sysdep/tls.h>
extern int modify_ldt(int func, void *ptr, unsigned long bytecount);
diff --git a/arch/x86/um/mem_64.c b/arch/x86/um/mem_64.c
index 5465187..c6492e7 100644
--- a/arch/x86/um/mem_64.c
+++ b/arch/x86/um/mem_64.c
@@ -1,6 +1,6 @@
-#include "linux/mm.h"
-#include "asm/page.h"
-#include "asm/mman.h"
+#include <linux/mm.h>
+#include <asm/page.h>
+#include <asm/mman.h>
const char *arch_vma_name(struct vm_area_struct *vma)
{
diff --git a/arch/x86/um/os-Linux/registers.c b/arch/x86/um/os-Linux/registers.c
index 0cdbb86..41bfe84 100644
--- a/arch/x86/um/os-Linux/registers.c
+++ b/arch/x86/um/os-Linux/registers.c
@@ -9,8 +9,8 @@
#ifdef __i386__
#include <sys/user.h>
#endif
-#include "longjmp.h"
-#include "sysdep/ptrace_user.h"
+#include <longjmp.h>
+#include <sysdep/ptrace_user.h>
int save_fp_registers(int pid, unsigned long *fp_regs)
{
diff --git a/arch/x86/um/os-Linux/task_size.c b/arch/x86/um/os-Linux/task_size.c
index efb16c5..8502ad3 100644
--- a/arch/x86/um/os-Linux/task_size.c
+++ b/arch/x86/um/os-Linux/task_size.c
@@ -2,7 +2,7 @@
#include <stdlib.h>
#include <signal.h>
#include <sys/mman.h>
-#include "longjmp.h"
+#include <longjmp.h>
#ifdef __i386__
diff --git a/arch/x86/um/os-Linux/tls.c b/arch/x86/um/os-Linux/tls.c
index 82276b6..9d94b3b 100644
--- a/arch/x86/um/os-Linux/tls.c
+++ b/arch/x86/um/os-Linux/tls.c
@@ -5,7 +5,7 @@
#include <sys/syscall.h>
#include <unistd.h>
-#include "sysdep/tls.h"
+#include <sysdep/tls.h>
#ifndef PTRACE_GET_THREAD_AREA
#define PTRACE_GET_THREAD_AREA 25
diff --git a/arch/x86/um/ptrace_32.c b/arch/x86/um/ptrace_32.c
index 3b949daa..ce3dd4f 100644
--- a/arch/x86/um/ptrace_32.c
+++ b/arch/x86/um/ptrace_32.c
@@ -3,10 +3,10 @@
* Licensed under the GPL
*/
-#include "linux/mm.h"
-#include "linux/sched.h"
-#include "asm/uaccess.h"
-#include "skas.h"
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <asm/uaccess.h>
+#include <skas.h>
extern int arch_switch_tls(struct task_struct *to);
diff --git a/arch/x86/um/ptrace_user.c b/arch/x86/um/ptrace_user.c
index 3960ca1..617885b 100644
--- a/arch/x86/um/ptrace_user.c
+++ b/arch/x86/um/ptrace_user.c
@@ -4,7 +4,7 @@
*/
#include <errno.h>
-#include "ptrace_user.h"
+#include <ptrace_user.h>
int ptrace_getregs(long pid, unsigned long *regs_out)
{
diff --git a/arch/x86/um/shared/sysdep/ptrace.h b/arch/x86/um/shared/sysdep/ptrace.h
index 6ce2d76..eb93569 100644
--- a/arch/x86/um/shared/sysdep/ptrace.h
+++ b/arch/x86/um/shared/sysdep/ptrace.h
@@ -2,7 +2,7 @@
#define __SYSDEP_X86_PTRACE_H
#include <generated/user_constants.h>
-#include "sysdep/faultinfo.h"
+#include <sysdep/faultinfo.h>
#define MAX_REG_OFFSET (UM_FRAME_SIZE)
#define MAX_REG_NR ((MAX_REG_OFFSET) / sizeof(unsigned long))
diff --git a/arch/x86/um/shared/sysdep/stub.h b/arch/x86/um/shared/sysdep/stub.h
index bd161e3..3f55e5b 100644
--- a/arch/x86/um/shared/sysdep/stub.h
+++ b/arch/x86/um/shared/sysdep/stub.h
@@ -1,8 +1,8 @@
#include <asm/unistd.h>
#include <sys/mman.h>
#include <signal.h>
-#include "as-layout.h"
-#include "stub-data.h"
+#include <as-layout.h>
+#include <stub-data.h>
#ifdef __i386__
#include "stub_32.h"
diff --git a/arch/x86/um/shared/sysdep/syscalls_32.h b/arch/x86/um/shared/sysdep/syscalls_32.h
index 05cb796..8436079 100644
--- a/arch/x86/um/shared/sysdep/syscalls_32.h
+++ b/arch/x86/um/shared/sysdep/syscalls_32.h
@@ -3,8 +3,8 @@
* Licensed under the GPL
*/
-#include "asm/unistd.h"
-#include "sysdep/ptrace.h"
+#include <asm/unistd.h>
+#include <sysdep/ptrace.h>
typedef long syscall_handler_t(struct pt_regs);
diff --git a/arch/x86/um/signal.c b/arch/x86/um/signal.c
index ba7363e..bdaa08c 100644
--- a/arch/x86/um/signal.c
+++ b/arch/x86/um/signal.c
@@ -11,8 +11,8 @@
#include <asm/unistd.h>
#include <asm/uaccess.h>
#include <asm/ucontext.h>
-#include "frame_kern.h"
-#include "skas.h"
+#include <frame_kern.h>
+#include <skas.h>
#ifdef CONFIG_X86_32
diff --git a/arch/x86/um/stub_32.S b/arch/x86/um/stub_32.S
index 54a36ec..b972649 100644
--- a/arch/x86/um/stub_32.S
+++ b/arch/x86/um/stub_32.S
@@ -1,4 +1,4 @@
-#include "as-layout.h"
+#include <as-layout.h>
.globl syscall_stub
.section .__syscall_stub, "ax"
diff --git a/arch/x86/um/stub_64.S b/arch/x86/um/stub_64.S
index 20e4a96..7160b20 100644
--- a/arch/x86/um/stub_64.S
+++ b/arch/x86/um/stub_64.S
@@ -1,4 +1,4 @@
-#include "as-layout.h"
+#include <as-layout.h>
.globl syscall_stub
.section .__syscall_stub, "ax"
diff --git a/arch/x86/um/stub_segv.c b/arch/x86/um/stub_segv.c
index b7450bd..1518d28 100644
--- a/arch/x86/um/stub_segv.c
+++ b/arch/x86/um/stub_segv.c
@@ -3,9 +3,9 @@
* Licensed under the GPL
*/
-#include "sysdep/stub.h"
-#include "sysdep/faultinfo.h"
-#include "sysdep/mcontext.h"
+#include <sysdep/stub.h>
+#include <sysdep/faultinfo.h>
+#include <sysdep/mcontext.h>
void __attribute__ ((__section__ (".__syscall_stub")))
stub_segv_handler(int sig, siginfo_t *info, void *p)
diff --git a/arch/x86/um/sys_call_table_32.c b/arch/x86/um/sys_call_table_32.c
index b5408ce..232e605 100644
--- a/arch/x86/um/sys_call_table_32.c
+++ b/arch/x86/um/sys_call_table_32.c
@@ -25,7 +25,6 @@
#define old_mmap sys_old_mmap
#define ptregs_fork sys_fork
-#define ptregs_execve sys_execve
#define ptregs_iopl sys_iopl
#define ptregs_vm86old sys_vm86old
#define ptregs_clone i386_clone
diff --git a/arch/x86/um/sysrq_32.c b/arch/x86/um/sysrq_32.c
index 2d5cc51..c9bee5b 100644
--- a/arch/x86/um/sysrq_32.c
+++ b/arch/x86/um/sysrq_32.c
@@ -3,12 +3,12 @@
* Licensed under the GPL
*/
-#include "linux/kernel.h"
-#include "linux/smp.h"
-#include "linux/sched.h"
-#include "linux/kallsyms.h"
-#include "asm/ptrace.h"
-#include "sysrq.h"
+#include <linux/kernel.h>
+#include <linux/smp.h>
+#include <linux/sched.h>
+#include <linux/kallsyms.h>
+#include <asm/ptrace.h>
+#include <asm/sysrq.h>
/* This is declared by <linux/sched.h> */
void show_regs(struct pt_regs *regs)
diff --git a/arch/x86/um/sysrq_64.c b/arch/x86/um/sysrq_64.c
index 08258f1..a0e7fb1 100644
--- a/arch/x86/um/sysrq_64.c
+++ b/arch/x86/um/sysrq_64.c
@@ -10,7 +10,7 @@
#include <linux/utsname.h>
#include <asm/current.h>
#include <asm/ptrace.h>
-#include "sysrq.h"
+#include <asm/sysrq.h>
void __show_regs(struct pt_regs *regs)
{
diff --git a/arch/x86/um/tls_32.c b/arch/x86/um/tls_32.c
index baba84f..5f5feff 100644
--- a/arch/x86/um/tls_32.c
+++ b/arch/x86/um/tls_32.c
@@ -3,12 +3,12 @@
* Licensed under the GPL
*/
-#include "linux/percpu.h"
-#include "linux/sched.h"
-#include "asm/uaccess.h"
-#include "os.h"
-#include "skas.h"
-#include "sysdep/tls.h"
+#include <linux/percpu.h>
+#include <linux/sched.h>
+#include <asm/uaccess.h>
+#include <os.h>
+#include <skas.h>
+#include <sysdep/tls.h>
/*
* If needed we can detect when it's uninitialized.
diff --git a/arch/x86/um/tls_64.c b/arch/x86/um/tls_64.c
index f7ba462..d22363c 100644
--- a/arch/x86/um/tls_64.c
+++ b/arch/x86/um/tls_64.c
@@ -1,4 +1,4 @@
-#include "linux/sched.h"
+#include <linux/sched.h>
void clear_flushed_tls(struct task_struct *task)
{
diff --git a/arch/xtensa/include/asm/Kbuild b/arch/xtensa/include/asm/Kbuild
index 0d20f55..fccd81e 100644
--- a/arch/xtensa/include/asm/Kbuild
+++ b/arch/xtensa/include/asm/Kbuild
@@ -1,3 +1,4 @@
include include/asm-generic/Kbuild.asm
generic-y += clkdev.h
+generic-y += exec.h
diff --git a/arch/xtensa/include/asm/exec.h b/arch/xtensa/include/asm/exec.h
deleted file mode 100644
index af949e2..0000000
--- a/arch/xtensa/include/asm/exec.h
+++ /dev/null
@@ -1,14 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef _XTENSA_EXEC_H
-#define _XTENSA_EXEC_H
-
-#define arch_align_stack(x) (x)
-
-#endif /* _XTENSA_EXEC_H */
diff --git a/arch/xtensa/include/asm/thread_info.h b/arch/xtensa/include/asm/thread_info.h
index 81abfd5..9481004 100644
--- a/arch/xtensa/include/asm/thread_info.h
+++ b/arch/xtensa/include/asm/thread_info.h
@@ -128,19 +128,14 @@ static inline struct thread_info *current_thread_info(void)
#define TIF_SIGPENDING 1 /* signal pending */
#define TIF_NEED_RESCHED 2 /* rescheduling necessary */
#define TIF_SINGLESTEP 3 /* restore singlestep on return to user mode */
-#define TIF_IRET 4 /* return with iret */
#define TIF_MEMDIE 5 /* is terminating due to OOM killer */
#define TIF_RESTORE_SIGMASK 6 /* restore signal mask in do_signal() */
#define TIF_NOTIFY_RESUME 7 /* callback before returning to user */
-#define TIF_POLLING_NRFLAG 16 /* true if poll_idle() is polling TIF_NEED_RESCHED */
#define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE)
#define _TIF_SIGPENDING (1<<TIF_SIGPENDING)
#define _TIF_NEED_RESCHED (1<<TIF_NEED_RESCHED)
#define _TIF_SINGLESTEP (1<<TIF_SINGLESTEP)
-#define _TIF_IRET (1<<TIF_IRET)
-#define _TIF_POLLING_NRFLAG (1<<TIF_POLLING_NRFLAG)
-#define _TIF_RESTORE_SIGMASK (1<<TIF_RESTORE_SIGMASK)
#define _TIF_WORK_MASK 0x0000FFFE /* work to do on interrupt/exception return */
#define _TIF_ALLWORK_MASK 0x0000FFFF /* work to do on any return to u-space */
diff --git a/arch/xtensa/kernel/signal.c b/arch/xtensa/kernel/signal.c
index efe4e85..63c566f 100644
--- a/arch/xtensa/kernel/signal.c
+++ b/arch/xtensa/kernel/signal.c
@@ -19,7 +19,6 @@
#include <linux/errno.h>
#include <linux/ptrace.h>
#include <linux/personality.h>
-#include <linux/freezer.h>
#include <linux/tracehook.h>
#include <asm/ucontext.h>
@@ -527,9 +526,6 @@ static void do_signal(struct pt_regs *regs)
void do_notify_resume(struct pt_regs *regs)
{
- if (!user_mode(regs))
- return;
-
if (test_thread_flag(TIF_SIGPENDING))
do_signal(regs);
diff --git a/block/blk-core.c b/block/blk-core.c
index d2da641..a33870b 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -606,8 +606,8 @@ struct request_queue *blk_alloc_queue_node(gfp_t gfp_mask, int node_id)
/*
* A queue starts its life with bypass turned on to avoid
* unnecessary bypass on/off overhead and nasty surprises during
- * init. The initial bypass will be finished at the end of
- * blk_init_allocated_queue().
+ * init. The initial bypass will be finished when the queue is
+ * registered by blk_register_queue().
*/
q->bypass_depth = 1;
__set_bit(QUEUE_FLAG_BYPASS, &q->queue_flags);
@@ -694,7 +694,7 @@ blk_init_allocated_queue(struct request_queue *q, request_fn_proc *rfn,
q->request_fn = rfn;
q->prep_rq_fn = NULL;
q->unprep_rq_fn = NULL;
- q->queue_flags = QUEUE_FLAG_DEFAULT;
+ q->queue_flags |= QUEUE_FLAG_DEFAULT;
/* Override internal queue lock with supplied lock pointer */
if (lock)
@@ -710,11 +710,6 @@ blk_init_allocated_queue(struct request_queue *q, request_fn_proc *rfn,
/* init elevator */
if (elevator_init(q, NULL))
return NULL;
-
- blk_queue_congestion_threshold(q);
-
- /* all done, end the initial bypass */
- blk_queue_bypass_end(q);
return q;
}
EXPORT_SYMBOL(blk_init_allocated_queue);
@@ -1657,8 +1652,8 @@ generic_make_request_checks(struct bio *bio)
goto end_io;
}
- if (unlikely(!(bio->bi_rw & REQ_DISCARD) &&
- nr_sectors > queue_max_hw_sectors(q))) {
+ if (likely(bio_is_rw(bio) &&
+ nr_sectors > queue_max_hw_sectors(q))) {
printk(KERN_ERR "bio too big device %s (%u > %u)\n",
bdevname(bio->bi_bdev, b),
bio_sectors(bio),
@@ -1699,8 +1694,12 @@ generic_make_request_checks(struct bio *bio)
if ((bio->bi_rw & REQ_DISCARD) &&
(!blk_queue_discard(q) ||
- ((bio->bi_rw & REQ_SECURE) &&
- !blk_queue_secdiscard(q)))) {
+ ((bio->bi_rw & REQ_SECURE) && !blk_queue_secdiscard(q)))) {
+ err = -EOPNOTSUPP;
+ goto end_io;
+ }
+
+ if (bio->bi_rw & REQ_WRITE_SAME && !bdev_write_same(bio->bi_bdev)) {
err = -EOPNOTSUPP;
goto end_io;
}
@@ -1810,15 +1809,20 @@ EXPORT_SYMBOL(generic_make_request);
*/
void submit_bio(int rw, struct bio *bio)
{
- int count = bio_sectors(bio);
-
bio->bi_rw |= rw;
/*
* If it's a regular read/write or a barrier with data attached,
* go through the normal accounting stuff before submission.
*/
- if (bio_has_data(bio) && !(rw & REQ_DISCARD)) {
+ if (bio_has_data(bio)) {
+ unsigned int count;
+
+ if (unlikely(rw & REQ_WRITE_SAME))
+ count = bdev_logical_block_size(bio->bi_bdev) >> 9;
+ else
+ count = bio_sectors(bio);
+
if (rw & WRITE) {
count_vm_events(PGPGOUT, count);
} else {
@@ -1864,11 +1868,10 @@ EXPORT_SYMBOL(submit_bio);
*/
int blk_rq_check_limits(struct request_queue *q, struct request *rq)
{
- if (rq->cmd_flags & REQ_DISCARD)
+ if (!rq_mergeable(rq))
return 0;
- if (blk_rq_sectors(rq) > queue_max_sectors(q) ||
- blk_rq_bytes(rq) > queue_max_hw_sectors(q) << 9) {
+ if (blk_rq_sectors(rq) > blk_queue_get_max_sectors(q, rq->cmd_flags)) {
printk(KERN_ERR "%s: over max size limit.\n", __func__);
return -EIO;
}
@@ -2340,7 +2343,7 @@ bool blk_update_request(struct request *req, int error, unsigned int nr_bytes)
req->buffer = bio_data(req->bio);
/* update sector only for requests with clear definition of sector */
- if (req->cmd_type == REQ_TYPE_FS || (req->cmd_flags & REQ_DISCARD))
+ if (req->cmd_type == REQ_TYPE_FS)
req->__sector += total_bytes >> 9;
/* mixed attributes always follow the first bio */
@@ -2781,16 +2784,10 @@ int blk_rq_prep_clone(struct request *rq, struct request *rq_src,
blk_rq_init(NULL, rq);
__rq_for_each_bio(bio_src, rq_src) {
- bio = bio_alloc_bioset(gfp_mask, bio_src->bi_max_vecs, bs);
+ bio = bio_clone_bioset(bio_src, gfp_mask, bs);
if (!bio)
goto free_and_out;
- __bio_clone(bio, bio_src);
-
- if (bio_integrity(bio_src) &&
- bio_integrity_clone(bio, bio_src, gfp_mask, bs))
- goto free_and_out;
-
if (bio_ctr && bio_ctr(bio, bio_src, data))
goto free_and_out;
@@ -2807,7 +2804,7 @@ int blk_rq_prep_clone(struct request *rq, struct request *rq_src,
free_and_out:
if (bio)
- bio_free(bio, bs);
+ bio_put(bio);
blk_rq_unprep_clone(rq);
return -ENOMEM;
diff --git a/block/blk-lib.c b/block/blk-lib.c
index 19cc761..9373b58 100644
--- a/block/blk-lib.c
+++ b/block/blk-lib.c
@@ -130,6 +130,80 @@ int blkdev_issue_discard(struct block_device *bdev, sector_t sector,
EXPORT_SYMBOL(blkdev_issue_discard);
/**
+ * blkdev_issue_write_same - queue a write same operation
+ * @bdev: target blockdev
+ * @sector: start sector
+ * @nr_sects: number of sectors to write
+ * @gfp_mask: memory allocation flags (for bio_alloc)
+ * @page: page containing data to write
+ *
+ * Description:
+ * Issue a write same request for the sectors in question.
+ */
+int blkdev_issue_write_same(struct block_device *bdev, sector_t sector,
+ sector_t nr_sects, gfp_t gfp_mask,
+ struct page *page)
+{
+ DECLARE_COMPLETION_ONSTACK(wait);
+ struct request_queue *q = bdev_get_queue(bdev);
+ unsigned int max_write_same_sectors;
+ struct bio_batch bb;
+ struct bio *bio;
+ int ret = 0;
+
+ if (!q)
+ return -ENXIO;
+
+ max_write_same_sectors = q->limits.max_write_same_sectors;
+
+ if (max_write_same_sectors == 0)
+ return -EOPNOTSUPP;
+
+ 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;
+ break;
+ }
+
+ bio->bi_sector = sector;
+ bio->bi_end_io = bio_batch_end_io;
+ bio->bi_bdev = bdev;
+ bio->bi_private = &bb;
+ bio->bi_vcnt = 1;
+ bio->bi_io_vec->bv_page = page;
+ bio->bi_io_vec->bv_offset = 0;
+ bio->bi_io_vec->bv_len = bdev_logical_block_size(bdev);
+
+ if (nr_sects > max_write_same_sectors) {
+ bio->bi_size = max_write_same_sectors << 9;
+ nr_sects -= max_write_same_sectors;
+ sector += max_write_same_sectors;
+ } else {
+ bio->bi_size = nr_sects << 9;
+ nr_sects = 0;
+ }
+
+ atomic_inc(&bb.done);
+ submit_bio(REQ_WRITE | REQ_WRITE_SAME, bio);
+ }
+
+ /* Wait for bios in-flight */
+ if (!atomic_dec_and_test(&bb.done))
+ wait_for_completion(&wait);
+
+ if (!test_bit(BIO_UPTODATE, &bb.flags))
+ ret = -ENOTSUPP;
+
+ return ret;
+}
+EXPORT_SYMBOL(blkdev_issue_write_same);
+
+/**
* blkdev_issue_zeroout - generate number of zero filed write bios
* @bdev: blockdev to issue
* @sector: start sector
@@ -140,7 +214,7 @@ EXPORT_SYMBOL(blkdev_issue_discard);
* Generate and issue number of bios with zerofiled pages.
*/
-int blkdev_issue_zeroout(struct block_device *bdev, sector_t sector,
+int __blkdev_issue_zeroout(struct block_device *bdev, sector_t sector,
sector_t nr_sects, gfp_t gfp_mask)
{
int ret;
@@ -190,4 +264,32 @@ int blkdev_issue_zeroout(struct block_device *bdev, sector_t sector,
return ret;
}
+
+/**
+ * blkdev_issue_zeroout - zero-fill a block range
+ * @bdev: blockdev to write
+ * @sector: start sector
+ * @nr_sects: number of sectors to write
+ * @gfp_mask: memory allocation flags (for bio_alloc)
+ *
+ * Description:
+ * Generate and issue number of bios with zerofiled pages.
+ */
+
+int blkdev_issue_zeroout(struct block_device *bdev, sector_t sector,
+ sector_t nr_sects, gfp_t gfp_mask)
+{
+ if (bdev_write_same(bdev)) {
+ unsigned char bdn[BDEVNAME_SIZE];
+
+ if (!blkdev_issue_write_same(bdev, sector, nr_sects, gfp_mask,
+ ZERO_PAGE(0)))
+ return 0;
+
+ bdevname(bdev, bdn);
+ pr_err("%s: WRITE SAME failed. Manually zeroing.\n", bdn);
+ }
+
+ return __blkdev_issue_zeroout(bdev, sector, nr_sects, gfp_mask);
+}
EXPORT_SYMBOL(blkdev_issue_zeroout);
diff --git a/block/blk-merge.c b/block/blk-merge.c
index e76279e..936a110 100644
--- a/block/blk-merge.c
+++ b/block/blk-merge.c
@@ -275,14 +275,8 @@ no_merge:
int ll_back_merge_fn(struct request_queue *q, struct request *req,
struct bio *bio)
{
- unsigned short max_sectors;
-
- if (unlikely(req->cmd_type == REQ_TYPE_BLOCK_PC))
- max_sectors = queue_max_hw_sectors(q);
- else
- max_sectors = queue_max_sectors(q);
-
- if (blk_rq_sectors(req) + bio_sectors(bio) > max_sectors) {
+ if (blk_rq_sectors(req) + bio_sectors(bio) >
+ blk_rq_get_max_sectors(req)) {
req->cmd_flags |= REQ_NOMERGE;
if (req == q->last_merge)
q->last_merge = NULL;
@@ -299,15 +293,8 @@ int ll_back_merge_fn(struct request_queue *q, struct request *req,
int ll_front_merge_fn(struct request_queue *q, struct request *req,
struct bio *bio)
{
- unsigned short max_sectors;
-
- if (unlikely(req->cmd_type == REQ_TYPE_BLOCK_PC))
- max_sectors = queue_max_hw_sectors(q);
- else
- max_sectors = queue_max_sectors(q);
-
-
- if (blk_rq_sectors(req) + bio_sectors(bio) > max_sectors) {
+ if (blk_rq_sectors(req) + bio_sectors(bio) >
+ blk_rq_get_max_sectors(req)) {
req->cmd_flags |= REQ_NOMERGE;
if (req == q->last_merge)
q->last_merge = NULL;
@@ -338,7 +325,8 @@ static int ll_merge_requests_fn(struct request_queue *q, struct request *req,
/*
* Will it become too large?
*/
- if ((blk_rq_sectors(req) + blk_rq_sectors(next)) > queue_max_sectors(q))
+ if ((blk_rq_sectors(req) + blk_rq_sectors(next)) >
+ blk_rq_get_max_sectors(req))
return 0;
total_phys_segments = req->nr_phys_segments + next->nr_phys_segments;
@@ -417,16 +405,7 @@ static int attempt_merge(struct request_queue *q, struct request *req,
if (!rq_mergeable(req) || !rq_mergeable(next))
return 0;
- /*
- * Don't merge file system requests and discard requests
- */
- if ((req->cmd_flags & REQ_DISCARD) != (next->cmd_flags & REQ_DISCARD))
- return 0;
-
- /*
- * Don't merge discard requests and secure discard requests
- */
- if ((req->cmd_flags & REQ_SECURE) != (next->cmd_flags & REQ_SECURE))
+ if (!blk_check_merge_flags(req->cmd_flags, next->cmd_flags))
return 0;
/*
@@ -440,6 +419,10 @@ static int attempt_merge(struct request_queue *q, struct request *req,
|| next->special)
return 0;
+ if (req->cmd_flags & REQ_WRITE_SAME &&
+ !blk_write_same_mergeable(req->bio, next->bio))
+ return 0;
+
/*
* If we are allowed to merge, then append bio list
* from next to rq and release next. merge_requests_fn
@@ -521,15 +504,10 @@ int blk_attempt_req_merge(struct request_queue *q, struct request *rq,
bool blk_rq_merge_ok(struct request *rq, struct bio *bio)
{
- if (!rq_mergeable(rq))
+ if (!rq_mergeable(rq) || !bio_mergeable(bio))
return false;
- /* don't merge file system requests and discard requests */
- if ((bio->bi_rw & REQ_DISCARD) != (rq->bio->bi_rw & REQ_DISCARD))
- return false;
-
- /* don't merge discard requests and secure discard requests */
- if ((bio->bi_rw & REQ_SECURE) != (rq->bio->bi_rw & REQ_SECURE))
+ if (!blk_check_merge_flags(rq->cmd_flags, bio->bi_rw))
return false;
/* different data direction or already started, don't merge */
@@ -544,6 +522,11 @@ bool blk_rq_merge_ok(struct request *rq, struct bio *bio)
if (bio_integrity(bio) != blk_integrity_rq(rq))
return false;
+ /* must be using the same buffer */
+ if (rq->cmd_flags & REQ_WRITE_SAME &&
+ !blk_write_same_mergeable(rq->bio, bio))
+ return false;
+
return true;
}
diff --git a/block/blk-settings.c b/block/blk-settings.c
index 565a678..779bb76 100644
--- a/block/blk-settings.c
+++ b/block/blk-settings.c
@@ -113,6 +113,7 @@ void blk_set_default_limits(struct queue_limits *lim)
lim->seg_boundary_mask = BLK_SEG_BOUNDARY_MASK;
lim->max_segment_size = BLK_MAX_SEGMENT_SIZE;
lim->max_sectors = lim->max_hw_sectors = BLK_SAFE_MAX_SECTORS;
+ lim->max_write_same_sectors = 0;
lim->max_discard_sectors = 0;
lim->discard_granularity = 0;
lim->discard_alignment = 0;
@@ -144,6 +145,7 @@ void blk_set_stacking_limits(struct queue_limits *lim)
lim->max_segments = USHRT_MAX;
lim->max_hw_sectors = UINT_MAX;
lim->max_sectors = UINT_MAX;
+ lim->max_write_same_sectors = UINT_MAX;
}
EXPORT_SYMBOL(blk_set_stacking_limits);
@@ -286,6 +288,18 @@ void blk_queue_max_discard_sectors(struct request_queue *q,
EXPORT_SYMBOL(blk_queue_max_discard_sectors);
/**
+ * blk_queue_max_write_same_sectors - set max sectors for a single write same
+ * @q: the request queue for the device
+ * @max_write_same_sectors: maximum number of sectors to write per command
+ **/
+void blk_queue_max_write_same_sectors(struct request_queue *q,
+ unsigned int max_write_same_sectors)
+{
+ q->limits.max_write_same_sectors = max_write_same_sectors;
+}
+EXPORT_SYMBOL(blk_queue_max_write_same_sectors);
+
+/**
* blk_queue_max_segments - set max hw segments for a request for this queue
* @q: the request queue for the device
* @max_segments: max number of segments
@@ -510,6 +524,8 @@ int blk_stack_limits(struct queue_limits *t, struct queue_limits *b,
t->max_sectors = min_not_zero(t->max_sectors, b->max_sectors);
t->max_hw_sectors = min_not_zero(t->max_hw_sectors, b->max_hw_sectors);
+ t->max_write_same_sectors = min(t->max_write_same_sectors,
+ b->max_write_same_sectors);
t->bounce_pfn = min_not_zero(t->bounce_pfn, b->bounce_pfn);
t->seg_boundary_mask = min_not_zero(t->seg_boundary_mask,
diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c
index 9628b29..ce62046 100644
--- a/block/blk-sysfs.c
+++ b/block/blk-sysfs.c
@@ -26,9 +26,15 @@ queue_var_show(unsigned long var, char *page)
static ssize_t
queue_var_store(unsigned long *var, const char *page, size_t count)
{
- char *p = (char *) page;
+ int err;
+ unsigned long v;
+
+ err = strict_strtoul(page, 10, &v);
+ if (err || v > UINT_MAX)
+ return -EINVAL;
+
+ *var = v;
- *var = simple_strtoul(p, &p, 10);
return count;
}
@@ -48,6 +54,9 @@ queue_requests_store(struct request_queue *q, const char *page, size_t count)
return -EINVAL;
ret = queue_var_store(&nr, page, count);
+ if (ret < 0)
+ return ret;
+
if (nr < BLKDEV_MIN_RQ)
nr = BLKDEV_MIN_RQ;
@@ -102,6 +111,9 @@ queue_ra_store(struct request_queue *q, const char *page, size_t count)
unsigned long ra_kb;
ssize_t ret = queue_var_store(&ra_kb, page, count);
+ if (ret < 0)
+ return ret;
+
q->backing_dev_info.ra_pages = ra_kb >> (PAGE_CACHE_SHIFT - 10);
return ret;
@@ -168,6 +180,13 @@ static ssize_t queue_discard_zeroes_data_show(struct request_queue *q, char *pag
return queue_var_show(queue_discard_zeroes_data(q), page);
}
+static ssize_t queue_write_same_max_show(struct request_queue *q, char *page)
+{
+ return sprintf(page, "%llu\n",
+ (unsigned long long)q->limits.max_write_same_sectors << 9);
+}
+
+
static ssize_t
queue_max_sectors_store(struct request_queue *q, const char *page, size_t count)
{
@@ -176,6 +195,9 @@ queue_max_sectors_store(struct request_queue *q, const char *page, size_t count)
page_kb = 1 << (PAGE_CACHE_SHIFT - 10);
ssize_t ret = queue_var_store(&max_sectors_kb, page, count);
+ if (ret < 0)
+ return ret;
+
if (max_sectors_kb > max_hw_sectors_kb || max_sectors_kb < page_kb)
return -EINVAL;
@@ -236,6 +258,9 @@ static ssize_t queue_nomerges_store(struct request_queue *q, const char *page,
unsigned long nm;
ssize_t ret = queue_var_store(&nm, page, count);
+ if (ret < 0)
+ return ret;
+
spin_lock_irq(q->queue_lock);
queue_flag_clear(QUEUE_FLAG_NOMERGES, q);
queue_flag_clear(QUEUE_FLAG_NOXMERGES, q);
@@ -264,6 +289,9 @@ queue_rq_affinity_store(struct request_queue *q, const char *page, size_t count)
unsigned long val;
ret = queue_var_store(&val, page, count);
+ if (ret < 0)
+ return ret;
+
spin_lock_irq(q->queue_lock);
if (val == 2) {
queue_flag_set(QUEUE_FLAG_SAME_COMP, q);
@@ -364,6 +392,11 @@ static struct queue_sysfs_entry queue_discard_zeroes_data_entry = {
.show = queue_discard_zeroes_data_show,
};
+static struct queue_sysfs_entry queue_write_same_max_entry = {
+ .attr = {.name = "write_same_max_bytes", .mode = S_IRUGO },
+ .show = queue_write_same_max_show,
+};
+
static struct queue_sysfs_entry queue_nonrot_entry = {
.attr = {.name = "rotational", .mode = S_IRUGO | S_IWUSR },
.show = queue_show_nonrot,
@@ -411,6 +444,7 @@ static struct attribute *default_attrs[] = {
&queue_discard_granularity_entry.attr,
&queue_discard_max_entry.attr,
&queue_discard_zeroes_data_entry.attr,
+ &queue_write_same_max_entry.attr,
&queue_nonrot_entry.attr,
&queue_nomerges_entry.attr,
&queue_rq_affinity_entry.attr,
@@ -527,6 +561,12 @@ int blk_register_queue(struct gendisk *disk)
if (WARN_ON(!q))
return -ENXIO;
+ /*
+ * Initialization must be complete by now. Finish the initial
+ * bypass from queue allocation.
+ */
+ blk_queue_bypass_end(q);
+
ret = blk_trace_init_sysfs(dev);
if (ret)
return ret;
diff --git a/block/blk-tag.c b/block/blk-tag.c
index 4af6f5c..cc345e1 100644
--- a/block/blk-tag.c
+++ b/block/blk-tag.c
@@ -186,7 +186,8 @@ int blk_queue_init_tags(struct request_queue *q, int depth,
tags = __blk_queue_init_tags(q, depth);
if (!tags)
- goto fail;
+ return -ENOMEM;
+
} else if (q->queue_tags) {
rc = blk_queue_resize_tags(q, depth);
if (rc)
@@ -203,9 +204,6 @@ int blk_queue_init_tags(struct request_queue *q, int depth,
queue_flag_set_unlocked(QUEUE_FLAG_QUEUED, q);
INIT_LIST_HEAD(&q->tag_busy_list);
return 0;
-fail:
- kfree(tags);
- return -ENOMEM;
}
EXPORT_SYMBOL(blk_queue_init_tags);
diff --git a/block/blk.h b/block/blk.h
index 2a0ea32..ca51543 100644
--- a/block/blk.h
+++ b/block/blk.h
@@ -171,14 +171,13 @@ static inline int queue_congestion_off_threshold(struct request_queue *q)
*
* a) it's attached to a gendisk, and
* b) the queue had IO stats enabled when this request was started, and
- * c) it's a file system request or a discard request
+ * c) it's a file system request
*/
static inline int blk_do_io_stat(struct request *rq)
{
return rq->rq_disk &&
(rq->cmd_flags & REQ_IO_STAT) &&
- (rq->cmd_type == REQ_TYPE_FS ||
- (rq->cmd_flags & REQ_DISCARD));
+ (rq->cmd_type == REQ_TYPE_FS);
}
/*
diff --git a/block/elevator.c b/block/elevator.c
index 6a55d41..9b1d42b 100644
--- a/block/elevator.c
+++ b/block/elevator.c
@@ -562,8 +562,7 @@ void __elv_add_request(struct request_queue *q, struct request *rq, int where)
if (rq->cmd_flags & REQ_SOFTBARRIER) {
/* barriers are scheduling boundary, update end_sector */
- if (rq->cmd_type == REQ_TYPE_FS ||
- (rq->cmd_flags & REQ_DISCARD)) {
+ if (rq->cmd_type == REQ_TYPE_FS) {
q->end_sector = rq_end_sector(rq);
q->boundary_rq = rq;
}
@@ -605,8 +604,7 @@ void __elv_add_request(struct request_queue *q, struct request *rq, int where)
if (elv_attempt_insert_merge(q, rq))
break;
case ELEVATOR_INSERT_SORT:
- BUG_ON(rq->cmd_type != REQ_TYPE_FS &&
- !(rq->cmd_flags & REQ_DISCARD));
+ BUG_ON(rq->cmd_type != REQ_TYPE_FS);
rq->cmd_flags |= REQ_SORTED;
q->nr_sorted++;
if (rq_mergeable(rq)) {
diff --git a/block/ioctl.c b/block/ioctl.c
index 4a85096..a31d91d9b 100644
--- a/block/ioctl.c
+++ b/block/ioctl.c
@@ -185,6 +185,22 @@ static int blk_ioctl_discard(struct block_device *bdev, uint64_t start,
return blkdev_issue_discard(bdev, start, len, GFP_KERNEL, flags);
}
+static int blk_ioctl_zeroout(struct block_device *bdev, uint64_t start,
+ uint64_t len)
+{
+ if (start & 511)
+ return -EINVAL;
+ if (len & 511)
+ return -EINVAL;
+ start >>= 9;
+ len >>= 9;
+
+ if (start + len > (i_size_read(bdev->bd_inode) >> 9))
+ return -EINVAL;
+
+ return blkdev_issue_zeroout(bdev, start, len, GFP_KERNEL);
+}
+
static int put_ushort(unsigned long arg, unsigned short val)
{
return put_user(val, (unsigned short __user *)arg);
@@ -300,6 +316,17 @@ int blkdev_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd,
return blk_ioctl_discard(bdev, range[0], range[1],
cmd == BLKSECDISCARD);
}
+ case BLKZEROOUT: {
+ uint64_t range[2];
+
+ if (!(mode & FMODE_WRITE))
+ return -EBADF;
+
+ if (copy_from_user(range, (void __user *)arg, sizeof(range)))
+ return -EFAULT;
+
+ return blk_ioctl_zeroout(bdev, range[0], range[1]);
+ }
case HDIO_GETGEO: {
struct hd_geometry geo;
diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c
index f93a032..f55683a 100644
--- a/drivers/block/drbd/drbd_main.c
+++ b/drivers/block/drbd/drbd_main.c
@@ -162,23 +162,12 @@ static const struct block_device_operations drbd_ops = {
.release = drbd_release,
};
-static void bio_destructor_drbd(struct bio *bio)
-{
- bio_free(bio, drbd_md_io_bio_set);
-}
-
struct bio *bio_alloc_drbd(gfp_t gfp_mask)
{
- struct bio *bio;
-
if (!drbd_md_io_bio_set)
return bio_alloc(gfp_mask, 1);
- bio = bio_alloc_bioset(gfp_mask, 1, drbd_md_io_bio_set);
- if (!bio)
- return NULL;
- bio->bi_destructor = bio_destructor_drbd;
- return bio;
+ return bio_alloc_bioset(gfp_mask, 1, drbd_md_io_bio_set);
}
#ifdef __CHECKER__
diff --git a/drivers/block/osdblk.c b/drivers/block/osdblk.c
index 87311eb..1bbc681 100644
--- a/drivers/block/osdblk.c
+++ b/drivers/block/osdblk.c
@@ -266,11 +266,10 @@ static struct bio *bio_chain_clone(struct bio *old_chain, gfp_t gfpmask)
struct bio *tmp, *new_chain = NULL, *tail = NULL;
while (old_chain) {
- tmp = bio_kmalloc(gfpmask, old_chain->bi_max_vecs);
+ tmp = bio_clone_kmalloc(old_chain, gfpmask);
if (!tmp)
goto err_out;
- __bio_clone(tmp, old_chain);
tmp->bi_bdev = NULL;
gfpmask &= ~__GFP_WAIT;
tmp->bi_next = NULL;
diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c
index ba66e44..2e7de7a 100644
--- a/drivers/block/pktcdvd.c
+++ b/drivers/block/pktcdvd.c
@@ -522,38 +522,6 @@ static void pkt_bio_finished(struct pktcdvd_device *pd)
}
}
-static void pkt_bio_destructor(struct bio *bio)
-{
- kfree(bio->bi_io_vec);
- kfree(bio);
-}
-
-static struct bio *pkt_bio_alloc(int nr_iovecs)
-{
- struct bio_vec *bvl = NULL;
- struct bio *bio;
-
- bio = kmalloc(sizeof(struct bio), GFP_KERNEL);
- if (!bio)
- goto no_bio;
- bio_init(bio);
-
- bvl = kcalloc(nr_iovecs, sizeof(struct bio_vec), GFP_KERNEL);
- if (!bvl)
- goto no_bvl;
-
- bio->bi_max_vecs = nr_iovecs;
- bio->bi_io_vec = bvl;
- bio->bi_destructor = pkt_bio_destructor;
-
- return bio;
-
- no_bvl:
- kfree(bio);
- no_bio:
- return NULL;
-}
-
/*
* Allocate a packet_data struct
*/
@@ -567,7 +535,7 @@ static struct packet_data *pkt_alloc_packet_data(int frames)
goto no_pkt;
pkt->frames = frames;
- pkt->w_bio = pkt_bio_alloc(frames);
+ pkt->w_bio = bio_kmalloc(GFP_KERNEL, frames);
if (!pkt->w_bio)
goto no_bio;
@@ -581,9 +549,10 @@ static struct packet_data *pkt_alloc_packet_data(int frames)
bio_list_init(&pkt->orig_bios);
for (i = 0; i < frames; i++) {
- struct bio *bio = pkt_bio_alloc(1);
+ struct bio *bio = bio_kmalloc(GFP_KERNEL, 1);
if (!bio)
goto no_rd_bio;
+
pkt->r_bios[i] = bio;
}
@@ -1111,21 +1080,17 @@ static void pkt_gather_data(struct pktcdvd_device *pd, struct packet_data *pkt)
* Schedule reads for missing parts of the packet.
*/
for (f = 0; f < pkt->frames; f++) {
- struct bio_vec *vec;
-
int p, offset;
+
if (written[f])
continue;
+
bio = pkt->r_bios[f];
- vec = bio->bi_io_vec;
- bio_init(bio);
- bio->bi_max_vecs = 1;
+ bio_reset(bio);
bio->bi_sector = pkt->sector + f * (CD_FRAMESIZE >> 9);
bio->bi_bdev = pd->bdev;
bio->bi_end_io = pkt_end_io_read;
bio->bi_private = pkt;
- bio->bi_io_vec = vec;
- bio->bi_destructor = pkt_bio_destructor;
p = (f * CD_FRAMESIZE) / PAGE_SIZE;
offset = (f * CD_FRAMESIZE) % PAGE_SIZE;
@@ -1418,14 +1383,11 @@ static void pkt_start_write(struct pktcdvd_device *pd, struct packet_data *pkt)
}
/* Start the write request */
- bio_init(pkt->w_bio);
- pkt->w_bio->bi_max_vecs = PACKET_MAX_SIZE;
+ bio_reset(pkt->w_bio);
pkt->w_bio->bi_sector = pkt->sector;
pkt->w_bio->bi_bdev = pd->bdev;
pkt->w_bio->bi_end_io = pkt_end_io_packet_write;
pkt->w_bio->bi_private = pkt;
- pkt->w_bio->bi_io_vec = bvec;
- pkt->w_bio->bi_destructor = pkt_bio_destructor;
for (f = 0; f < pkt->frames; f++)
if (!bio_add_page(pkt->w_bio, bvec[f].bv_page, CD_FRAMESIZE, bvec[f].bv_offset))
BUG();
diff --git a/drivers/char/ds1620.c b/drivers/char/ds1620.c
index aab9605..24ffd8c 100644
--- a/drivers/char/ds1620.c
+++ b/drivers/char/ds1620.c
@@ -74,21 +74,21 @@ static inline void netwinder_ds1620_reset(void)
static inline void netwinder_lock(unsigned long *flags)
{
- spin_lock_irqsave(&nw_gpio_lock, *flags);
+ raw_spin_lock_irqsave(&nw_gpio_lock, *flags);
}
static inline void netwinder_unlock(unsigned long *flags)
{
- spin_unlock_irqrestore(&nw_gpio_lock, *flags);
+ raw_spin_unlock_irqrestore(&nw_gpio_lock, *flags);
}
static inline void netwinder_set_fan(int i)
{
unsigned long flags;
- spin_lock_irqsave(&nw_gpio_lock, flags);
+ raw_spin_lock_irqsave(&nw_gpio_lock, flags);
nw_gpio_modify_op(GPIO_FAN, i ? GPIO_FAN : 0);
- spin_unlock_irqrestore(&nw_gpio_lock, flags);
+ raw_spin_unlock_irqrestore(&nw_gpio_lock, flags);
}
static inline int netwinder_get_fan(void)
diff --git a/drivers/char/nwflash.c b/drivers/char/nwflash.c
index a0e2f7d..e371480 100644
--- a/drivers/char/nwflash.c
+++ b/drivers/char/nwflash.c
@@ -583,9 +583,9 @@ static void kick_open(void)
* we want to write a bit pattern XXX1 to Xilinx to enable
* the write gate, which will be open for about the next 2ms.
*/
- spin_lock_irqsave(&nw_gpio_lock, flags);
+ raw_spin_lock_irqsave(&nw_gpio_lock, flags);
nw_cpld_modify(CPLD_FLASH_WR_ENABLE, CPLD_FLASH_WR_ENABLE);
- spin_unlock_irqrestore(&nw_gpio_lock, flags);
+ raw_spin_unlock_irqrestore(&nw_gpio_lock, flags);
/*
* let the ISA bus to catch on...
diff --git a/drivers/char/raw.c b/drivers/char/raw.c
index 54a3a6d..0bb207e 100644
--- a/drivers/char/raw.c
+++ b/drivers/char/raw.c
@@ -285,7 +285,7 @@ static long raw_ctl_compat_ioctl(struct file *file, unsigned int cmd,
static const struct file_operations raw_fops = {
.read = do_sync_read,
- .aio_read = generic_file_aio_read,
+ .aio_read = blkdev_aio_read,
.write = do_sync_write,
.aio_write = blkdev_aio_write,
.fsync = blkdev_fsync,
diff --git a/drivers/cpufreq/omap-cpufreq.c b/drivers/cpufreq/omap-cpufreq.c
index 65f8e9a..1f3417a 100644
--- a/drivers/cpufreq/omap-cpufreq.c
+++ b/drivers/cpufreq/omap-cpufreq.c
@@ -30,20 +30,12 @@
#include <asm/smp_plat.h>
#include <asm/cpu.h>
-#include <plat/clock.h>
-#include <plat/omap-pm.h>
-#include <plat/common.h>
-#include <plat/omap_device.h>
-
-#include <mach/hardware.h>
-
/* OPP tolerance in percentage */
#define OPP_TOLERANCE 4
static struct cpufreq_frequency_table *freq_table;
static atomic_t freq_table_users = ATOMIC_INIT(0);
static struct clk *mpu_clk;
-static char *mpu_clk_name;
static struct device *mpu_dev;
static struct regulator *mpu_reg;
@@ -108,6 +100,14 @@ static int omap_target(struct cpufreq_policy *policy,
}
freq = freqs.new * 1000;
+ ret = clk_round_rate(mpu_clk, freq);
+ if (IS_ERR_VALUE(ret)) {
+ dev_warn(mpu_dev,
+ "CPUfreq: Cannot find matching frequency for %lu\n",
+ freq);
+ return ret;
+ }
+ freq = ret;
if (mpu_reg) {
opp = opp_find_freq_ceil(mpu_dev, &freq);
@@ -172,7 +172,7 @@ static int __cpuinit omap_cpu_init(struct cpufreq_policy *policy)
{
int result = 0;
- mpu_clk = clk_get(NULL, mpu_clk_name);
+ mpu_clk = clk_get(NULL, "cpufreq_ck");
if (IS_ERR(mpu_clk))
return PTR_ERR(mpu_clk);
@@ -253,22 +253,10 @@ static struct cpufreq_driver omap_driver = {
static int __init omap_cpufreq_init(void)
{
- if (cpu_is_omap24xx())
- mpu_clk_name = "virt_prcm_set";
- else if (cpu_is_omap34xx())
- mpu_clk_name = "dpll1_ck";
- else if (cpu_is_omap44xx())
- mpu_clk_name = "dpll_mpu_ck";
-
- if (!mpu_clk_name) {
- pr_err("%s: unsupported Silicon?\n", __func__);
- return -EINVAL;
- }
-
- mpu_dev = omap_device_get_by_hwmod_name("mpu");
- if (IS_ERR(mpu_dev)) {
+ mpu_dev = get_cpu_device(0);
+ if (!mpu_dev) {
pr_warning("%s: unable to get the mpu device\n", __func__);
- return PTR_ERR(mpu_dev);
+ return -EINVAL;
}
mpu_reg = regulator_get(mpu_dev, "vcc");
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index d06ea29..677cd6e 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -208,6 +208,16 @@ config SIRF_DMA
help
Enable support for the CSR SiRFprimaII DMA engine.
+config TI_EDMA
+ tristate "TI EDMA support"
+ depends on ARCH_DAVINCI
+ select DMA_ENGINE
+ select DMA_VIRTUAL_CHANNELS
+ default n
+ help
+ Enable support for the TI EDMA controller. This DMA
+ engine is found on TI DaVinci and AM33xx parts.
+
config ARCH_HAS_ASYNC_TX_FIND_CHANNEL
bool
@@ -292,6 +302,13 @@ config DMA_OMAP
select DMA_ENGINE
select DMA_VIRTUAL_CHANNELS
+config MMP_PDMA
+ bool "MMP PDMA support"
+ depends on (ARCH_MMP || ARCH_PXA)
+ select DMA_ENGINE
+ help
+ Support the MMP PDMA engine for PXA and MMP platfrom.
+
config DMA_ENGINE
bool
diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile
index 4cf6b12..7428fea 100644
--- a/drivers/dma/Makefile
+++ b/drivers/dma/Makefile
@@ -23,6 +23,7 @@ obj-$(CONFIG_IMX_DMA) += imx-dma.o
obj-$(CONFIG_MXS_DMA) += mxs-dma.o
obj-$(CONFIG_TIMB_DMA) += timb_dma.o
obj-$(CONFIG_SIRF_DMA) += sirf-dma.o
+obj-$(CONFIG_TI_EDMA) += edma.o
obj-$(CONFIG_STE_DMA40) += ste_dma40.o ste_dma40_ll.o
obj-$(CONFIG_TEGRA20_APB_DMA) += tegra20-apb-dma.o
obj-$(CONFIG_PL330_DMA) += pl330.o
@@ -32,3 +33,4 @@ obj-$(CONFIG_EP93XX_DMA) += ep93xx_dma.o
obj-$(CONFIG_DMA_SA11X0) += sa11x0-dma.o
obj-$(CONFIG_MMP_TDMA) += mmp_tdma.o
obj-$(CONFIG_DMA_OMAP) += omap-dma.o
+obj-$(CONFIG_MMP_PDMA) += mmp_pdma.o
diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c
index 6fbeebb..d1cc579 100644
--- a/drivers/dma/amba-pl08x.c
+++ b/drivers/dma/amba-pl08x.c
@@ -1892,6 +1892,7 @@ static int pl08x_probe(struct amba_device *adev, const struct amba_id *id)
pl08x->pd = dev_get_platdata(&adev->dev);
if (!pl08x->pd) {
dev_err(&adev->dev, "no platform data supplied\n");
+ ret = -EINVAL;
goto out_no_platdata;
}
@@ -1943,6 +1944,7 @@ static int pl08x_probe(struct amba_device *adev, const struct amba_id *id)
dev_err(&adev->dev, "%s failed to allocate "
"physical channel holders\n",
__func__);
+ ret = -ENOMEM;
goto out_no_phychans;
}
diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c
index d3c5a5a..c4b0eb3c 100644
--- a/drivers/dma/dw_dmac.c
+++ b/drivers/dma/dw_dmac.c
@@ -36,12 +36,22 @@
* which does not support descriptor writeback.
*/
+static inline unsigned int dwc_get_dms(struct dw_dma_slave *slave)
+{
+ return slave ? slave->dst_master : 0;
+}
+
+static inline unsigned int dwc_get_sms(struct dw_dma_slave *slave)
+{
+ return slave ? slave->src_master : 1;
+}
+
#define DWC_DEFAULT_CTLLO(_chan) ({ \
struct dw_dma_slave *__slave = (_chan->private); \
struct dw_dma_chan *_dwc = to_dw_dma_chan(_chan); \
struct dma_slave_config *_sconfig = &_dwc->dma_sconfig; \
- int _dms = __slave ? __slave->dst_master : 0; \
- int _sms = __slave ? __slave->src_master : 1; \
+ int _dms = dwc_get_dms(__slave); \
+ int _sms = dwc_get_sms(__slave); \
u8 _smsize = __slave ? _sconfig->src_maxburst : \
DW_DMA_MSIZE_16; \
u8 _dmsize = __slave ? _sconfig->dst_maxburst : \
@@ -56,16 +66,6 @@
})
/*
- * This is configuration-dependent and usually a funny size like 4095.
- *
- * Note that this is a transfer count, i.e. if we transfer 32-bit
- * words, we can do 16380 bytes per descriptor.
- *
- * This parameter is also system-specific.
- */
-#define DWC_MAX_COUNT 4095U
-
-/*
* Number of descriptors to allocate for each channel. This should be
* made configurable somehow; preferably, the clients (at least the
* ones using slave transfers) should be able to give us a hint.
@@ -177,6 +177,11 @@ static void dwc_initialize(struct dw_dma_chan *dwc)
cfghi = dws->cfg_hi;
cfglo |= dws->cfg_lo & ~DWC_CFGL_CH_PRIOR_MASK;
+ } else {
+ if (dwc->dma_sconfig.direction == DMA_MEM_TO_DEV)
+ cfghi = DWC_CFGH_DST_PER(dwc->dma_sconfig.slave_id);
+ else if (dwc->dma_sconfig.direction == DMA_DEV_TO_MEM)
+ cfghi = DWC_CFGH_SRC_PER(dwc->dma_sconfig.slave_id);
}
channel_writel(dwc, CFG_LO, cfglo);
@@ -206,7 +211,7 @@ static inline unsigned int dwc_fast_fls(unsigned long long v)
return 0;
}
-static void dwc_dump_chan_regs(struct dw_dma_chan *dwc)
+static inline void dwc_dump_chan_regs(struct dw_dma_chan *dwc)
{
dev_err(chan2dev(&dwc->chan),
" SAR: 0x%x DAR: 0x%x LLP: 0x%x CTL: 0x%x:%08x\n",
@@ -227,10 +232,29 @@ static inline void dwc_chan_disable(struct dw_dma *dw, struct dw_dma_chan *dwc)
/*----------------------------------------------------------------------*/
+/* Perform single block transfer */
+static inline void dwc_do_single_block(struct dw_dma_chan *dwc,
+ struct dw_desc *desc)
+{
+ struct dw_dma *dw = to_dw_dma(dwc->chan.device);
+ u32 ctllo;
+
+ /* Software emulation of LLP mode relies on interrupts to continue
+ * multi block transfer. */
+ ctllo = desc->lli.ctllo | DWC_CTLL_INT_EN;
+
+ channel_writel(dwc, SAR, desc->lli.sar);
+ channel_writel(dwc, DAR, desc->lli.dar);
+ channel_writel(dwc, CTL_LO, ctllo);
+ channel_writel(dwc, CTL_HI, desc->lli.ctlhi);
+ channel_set_bit(dw, CH_EN, dwc->mask);
+}
+
/* Called with dwc->lock held and bh disabled */
static void dwc_dostart(struct dw_dma_chan *dwc, struct dw_desc *first)
{
struct dw_dma *dw = to_dw_dma(dwc->chan.device);
+ unsigned long was_soft_llp;
/* ASSERT: channel is idle */
if (dma_readl(dw, CH_EN) & dwc->mask) {
@@ -242,6 +266,26 @@ static void dwc_dostart(struct dw_dma_chan *dwc, struct dw_desc *first)
return;
}
+ if (dwc->nollp) {
+ was_soft_llp = test_and_set_bit(DW_DMA_IS_SOFT_LLP,
+ &dwc->flags);
+ if (was_soft_llp) {
+ dev_err(chan2dev(&dwc->chan),
+ "BUG: Attempted to start new LLP transfer "
+ "inside ongoing one\n");
+ return;
+ }
+
+ dwc_initialize(dwc);
+
+ dwc->tx_list = &first->tx_list;
+ dwc->tx_node_active = first->tx_list.next;
+
+ dwc_do_single_block(dwc, first);
+
+ return;
+ }
+
dwc_initialize(dwc);
channel_writel(dwc, LLP, first->txd.phys);
@@ -553,8 +597,36 @@ static void dw_dma_tasklet(unsigned long data)
dwc_handle_cyclic(dw, dwc, status_err, status_xfer);
else if (status_err & (1 << i))
dwc_handle_error(dw, dwc);
- else if (status_xfer & (1 << i))
+ else if (status_xfer & (1 << i)) {
+ unsigned long flags;
+
+ spin_lock_irqsave(&dwc->lock, flags);
+ if (test_bit(DW_DMA_IS_SOFT_LLP, &dwc->flags)) {
+ if (dwc->tx_node_active != dwc->tx_list) {
+ struct dw_desc *desc =
+ list_entry(dwc->tx_node_active,
+ struct dw_desc,
+ desc_node);
+
+ dma_writel(dw, CLEAR.XFER, dwc->mask);
+
+ /* move pointer to next descriptor */
+ dwc->tx_node_active =
+ dwc->tx_node_active->next;
+
+ dwc_do_single_block(dwc, desc);
+
+ spin_unlock_irqrestore(&dwc->lock, flags);
+ continue;
+ } else {
+ /* we are done here */
+ clear_bit(DW_DMA_IS_SOFT_LLP, &dwc->flags);
+ }
+ }
+ spin_unlock_irqrestore(&dwc->lock, flags);
+
dwc_scan_descriptors(dw, dwc);
+ }
}
/*
@@ -636,6 +708,7 @@ dwc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
size_t len, unsigned long flags)
{
struct dw_dma_chan *dwc = to_dw_dma_chan(chan);
+ struct dw_dma_slave *dws = chan->private;
struct dw_desc *desc;
struct dw_desc *first;
struct dw_desc *prev;
@@ -643,6 +716,7 @@ dwc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
size_t offset;
unsigned int src_width;
unsigned int dst_width;
+ unsigned int data_width;
u32 ctllo;
dev_vdbg(chan2dev(chan),
@@ -655,7 +729,11 @@ dwc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
return NULL;
}
- src_width = dst_width = dwc_fast_fls(src | dest | len);
+ data_width = min_t(unsigned int, dwc->dw->data_width[dwc_get_sms(dws)],
+ dwc->dw->data_width[dwc_get_dms(dws)]);
+
+ src_width = dst_width = min_t(unsigned int, data_width,
+ dwc_fast_fls(src | dest | len));
ctllo = DWC_DEFAULT_CTLLO(chan)
| DWC_CTLL_DST_WIDTH(dst_width)
@@ -667,7 +745,7 @@ dwc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
for (offset = 0; offset < len; offset += xfer_count << src_width) {
xfer_count = min_t(size_t, (len - offset) >> src_width,
- DWC_MAX_COUNT);
+ dwc->block_size);
desc = dwc_desc_get(dwc);
if (!desc)
@@ -725,6 +803,7 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
dma_addr_t reg;
unsigned int reg_width;
unsigned int mem_width;
+ unsigned int data_width;
unsigned int i;
struct scatterlist *sg;
size_t total_len = 0;
@@ -748,6 +827,8 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
ctllo |= sconfig->device_fc ? DWC_CTLL_FC(DW_DMA_FC_P_M2P) :
DWC_CTLL_FC(DW_DMA_FC_D_M2P);
+ data_width = dwc->dw->data_width[dwc_get_sms(dws)];
+
for_each_sg(sgl, sg, sg_len, i) {
struct dw_desc *desc;
u32 len, dlen, mem;
@@ -755,7 +836,8 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
mem = sg_dma_address(sg);
len = sg_dma_len(sg);
- mem_width = dwc_fast_fls(mem | len);
+ mem_width = min_t(unsigned int,
+ data_width, dwc_fast_fls(mem | len));
slave_sg_todev_fill_desc:
desc = dwc_desc_get(dwc);
@@ -768,8 +850,8 @@ slave_sg_todev_fill_desc:
desc->lli.sar = mem;
desc->lli.dar = reg;
desc->lli.ctllo = ctllo | DWC_CTLL_SRC_WIDTH(mem_width);
- if ((len >> mem_width) > DWC_MAX_COUNT) {
- dlen = DWC_MAX_COUNT << mem_width;
+ if ((len >> mem_width) > dwc->block_size) {
+ dlen = dwc->block_size << mem_width;
mem += dlen;
len -= dlen;
} else {
@@ -808,6 +890,8 @@ slave_sg_todev_fill_desc:
ctllo |= sconfig->device_fc ? DWC_CTLL_FC(DW_DMA_FC_P_P2M) :
DWC_CTLL_FC(DW_DMA_FC_D_P2M);
+ data_width = dwc->dw->data_width[dwc_get_dms(dws)];
+
for_each_sg(sgl, sg, sg_len, i) {
struct dw_desc *desc;
u32 len, dlen, mem;
@@ -815,7 +899,8 @@ slave_sg_todev_fill_desc:
mem = sg_dma_address(sg);
len = sg_dma_len(sg);
- mem_width = dwc_fast_fls(mem | len);
+ mem_width = min_t(unsigned int,
+ data_width, dwc_fast_fls(mem | len));
slave_sg_fromdev_fill_desc:
desc = dwc_desc_get(dwc);
@@ -828,8 +913,8 @@ slave_sg_fromdev_fill_desc:
desc->lli.sar = reg;
desc->lli.dar = mem;
desc->lli.ctllo = ctllo | DWC_CTLL_DST_WIDTH(mem_width);
- if ((len >> reg_width) > DWC_MAX_COUNT) {
- dlen = DWC_MAX_COUNT << reg_width;
+ if ((len >> reg_width) > dwc->block_size) {
+ dlen = dwc->block_size << reg_width;
mem += dlen;
len -= dlen;
} else {
@@ -945,6 +1030,8 @@ static int dwc_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
} else if (cmd == DMA_TERMINATE_ALL) {
spin_lock_irqsave(&dwc->lock, flags);
+ clear_bit(DW_DMA_IS_SOFT_LLP, &dwc->flags);
+
dwc_chan_disable(dw, dwc);
dwc->paused = false;
@@ -1187,6 +1274,13 @@ struct dw_cyclic_desc *dw_dma_cyclic_prep(struct dma_chan *chan,
unsigned long flags;
spin_lock_irqsave(&dwc->lock, flags);
+ if (dwc->nollp) {
+ spin_unlock_irqrestore(&dwc->lock, flags);
+ dev_dbg(chan2dev(&dwc->chan),
+ "channel doesn't support LLP transfers\n");
+ return ERR_PTR(-EINVAL);
+ }
+
if (!list_empty(&dwc->queue) || !list_empty(&dwc->active_list)) {
spin_unlock_irqrestore(&dwc->lock, flags);
dev_dbg(chan2dev(&dwc->chan),
@@ -1212,7 +1306,7 @@ struct dw_cyclic_desc *dw_dma_cyclic_prep(struct dma_chan *chan,
periods = buf_len / period_len;
/* Check for too big/unaligned periods and unaligned DMA buffer. */
- if (period_len > (DWC_MAX_COUNT << reg_width))
+ if (period_len > (dwc->block_size << reg_width))
goto out_err;
if (unlikely(period_len & ((1 << reg_width) - 1)))
goto out_err;
@@ -1374,6 +1468,11 @@ static int __devinit dw_probe(struct platform_device *pdev)
struct resource *io;
struct dw_dma *dw;
size_t size;
+ void __iomem *regs;
+ bool autocfg;
+ unsigned int dw_params;
+ unsigned int nr_channels;
+ unsigned int max_blk_size = 0;
int irq;
int err;
int i;
@@ -1390,32 +1489,46 @@ static int __devinit dw_probe(struct platform_device *pdev)
if (irq < 0)
return irq;
- size = sizeof(struct dw_dma);
- size += pdata->nr_channels * sizeof(struct dw_dma_chan);
- dw = kzalloc(size, GFP_KERNEL);
+ regs = devm_request_and_ioremap(&pdev->dev, io);
+ if (!regs)
+ return -EBUSY;
+
+ dw_params = dma_read_byaddr(regs, DW_PARAMS);
+ autocfg = dw_params >> DW_PARAMS_EN & 0x1;
+
+ if (autocfg)
+ nr_channels = (dw_params >> DW_PARAMS_NR_CHAN & 0x7) + 1;
+ else
+ nr_channels = pdata->nr_channels;
+
+ size = sizeof(struct dw_dma) + nr_channels * sizeof(struct dw_dma_chan);
+ dw = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
if (!dw)
return -ENOMEM;
- if (!request_mem_region(io->start, DW_REGLEN, pdev->dev.driver->name)) {
- err = -EBUSY;
- goto err_kfree;
- }
+ dw->clk = devm_clk_get(&pdev->dev, "hclk");
+ if (IS_ERR(dw->clk))
+ return PTR_ERR(dw->clk);
+ clk_prepare_enable(dw->clk);
- dw->regs = ioremap(io->start, DW_REGLEN);
- if (!dw->regs) {
- err = -ENOMEM;
- goto err_release_r;
- }
+ dw->regs = regs;
+
+ /* get hardware configuration parameters */
+ if (autocfg) {
+ max_blk_size = dma_readl(dw, MAX_BLK_SIZE);
- dw->clk = clk_get(&pdev->dev, "hclk");
- if (IS_ERR(dw->clk)) {
- err = PTR_ERR(dw->clk);
- goto err_clk;
+ dw->nr_masters = (dw_params >> DW_PARAMS_NR_MASTER & 3) + 1;
+ for (i = 0; i < dw->nr_masters; i++) {
+ dw->data_width[i] =
+ (dw_params >> DW_PARAMS_DATA_WIDTH(i) & 3) + 2;
+ }
+ } else {
+ dw->nr_masters = pdata->nr_masters;
+ memcpy(dw->data_width, pdata->data_width, 4);
}
- clk_prepare_enable(dw->clk);
/* Calculate all channel mask before DMA setup */
- dw->all_chan_mask = (1 << pdata->nr_channels) - 1;
+ dw->all_chan_mask = (1 << nr_channels) - 1;
/* force dma off, just in case */
dw_dma_off(dw);
@@ -1423,17 +1536,19 @@ static int __devinit dw_probe(struct platform_device *pdev)
/* disable BLOCK interrupts as well */
channel_clear_bit(dw, MASK.BLOCK, dw->all_chan_mask);
- err = request_irq(irq, dw_dma_interrupt, 0, "dw_dmac", dw);
+ err = devm_request_irq(&pdev->dev, irq, dw_dma_interrupt, 0,
+ "dw_dmac", dw);
if (err)
- goto err_irq;
+ return err;
platform_set_drvdata(pdev, dw);
tasklet_init(&dw->tasklet, dw_dma_tasklet, (unsigned long)dw);
INIT_LIST_HEAD(&dw->dma.channels);
- for (i = 0; i < pdata->nr_channels; i++) {
+ for (i = 0; i < nr_channels; i++) {
struct dw_dma_chan *dwc = &dw->chan[i];
+ int r = nr_channels - i - 1;
dwc->chan.device = &dw->dma;
dma_cookie_init(&dwc->chan);
@@ -1445,7 +1560,7 @@ static int __devinit dw_probe(struct platform_device *pdev)
/* 7 is highest priority & 0 is lowest. */
if (pdata->chan_priority == CHAN_PRIORITY_ASCENDING)
- dwc->priority = pdata->nr_channels - i - 1;
+ dwc->priority = r;
else
dwc->priority = i;
@@ -1458,6 +1573,32 @@ static int __devinit dw_probe(struct platform_device *pdev)
INIT_LIST_HEAD(&dwc->free_list);
channel_clear_bit(dw, CH_EN, dwc->mask);
+
+ dwc->dw = dw;
+
+ /* hardware configuration */
+ if (autocfg) {
+ unsigned int dwc_params;
+
+ dwc_params = dma_read_byaddr(regs + r * sizeof(u32),
+ DWC_PARAMS);
+
+ /* Decode maximum block size for given channel. The
+ * stored 4 bit value represents blocks from 0x00 for 3
+ * up to 0x0a for 4095. */
+ dwc->block_size =
+ (4 << ((max_blk_size >> 4 * i) & 0xf)) - 1;
+ dwc->nollp =
+ (dwc_params >> DWC_PARAMS_MBLK_EN & 0x1) == 0;
+ } else {
+ dwc->block_size = pdata->block_size;
+
+ /* Check if channel supports multi block transfer */
+ channel_writel(dwc, LLP, 0xfffffffc);
+ dwc->nollp =
+ (channel_readl(dwc, LLP) & 0xfffffffc) == 0;
+ channel_writel(dwc, LLP, 0);
+ }
}
/* Clear all interrupts on all channels. */
@@ -1486,35 +1627,21 @@ static int __devinit dw_probe(struct platform_device *pdev)
dma_writel(dw, CFG, DW_CFG_DMA_EN);
printk(KERN_INFO "%s: DesignWare DMA Controller, %d channels\n",
- dev_name(&pdev->dev), pdata->nr_channels);
+ dev_name(&pdev->dev), nr_channels);
dma_async_device_register(&dw->dma);
return 0;
-
-err_irq:
- clk_disable_unprepare(dw->clk);
- clk_put(dw->clk);
-err_clk:
- iounmap(dw->regs);
- dw->regs = NULL;
-err_release_r:
- release_resource(io);
-err_kfree:
- kfree(dw);
- return err;
}
static int __devexit dw_remove(struct platform_device *pdev)
{
struct dw_dma *dw = platform_get_drvdata(pdev);
struct dw_dma_chan *dwc, *_dwc;
- struct resource *io;
dw_dma_off(dw);
dma_async_device_unregister(&dw->dma);
- free_irq(platform_get_irq(pdev, 0), dw);
tasklet_kill(&dw->tasklet);
list_for_each_entry_safe(dwc, _dwc, &dw->dma.channels,
@@ -1523,17 +1650,6 @@ static int __devexit dw_remove(struct platform_device *pdev)
channel_clear_bit(dw, CH_EN, dwc->mask);
}
- clk_disable_unprepare(dw->clk);
- clk_put(dw->clk);
-
- iounmap(dw->regs);
- dw->regs = NULL;
-
- io = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- release_mem_region(io->start, DW_REGLEN);
-
- kfree(dw);
-
return 0;
}
diff --git a/drivers/dma/dw_dmac_regs.h b/drivers/dma/dw_dmac_regs.h
index 50830be..ff39fa6 100644
--- a/drivers/dma/dw_dmac_regs.h
+++ b/drivers/dma/dw_dmac_regs.h
@@ -82,9 +82,39 @@ struct dw_dma_regs {
DW_REG(ID);
DW_REG(TEST);
+ /* reserved */
+ DW_REG(__reserved0);
+ DW_REG(__reserved1);
+
/* optional encoded params, 0x3c8..0x3f7 */
+ u32 __reserved;
+
+ /* per-channel configuration registers */
+ u32 DWC_PARAMS[DW_DMA_MAX_NR_CHANNELS];
+ u32 MULTI_BLK_TYPE;
+ u32 MAX_BLK_SIZE;
+
+ /* top-level parameters */
+ u32 DW_PARAMS;
};
+/* To access the registers in early stage of probe */
+#define dma_read_byaddr(addr, name) \
+ readl((addr) + offsetof(struct dw_dma_regs, name))
+
+/* Bitfields in DW_PARAMS */
+#define DW_PARAMS_NR_CHAN 8 /* number of channels */
+#define DW_PARAMS_NR_MASTER 11 /* number of AHB masters */
+#define DW_PARAMS_DATA_WIDTH(n) (15 + 2 * (n))
+#define DW_PARAMS_DATA_WIDTH1 15 /* master 1 data width */
+#define DW_PARAMS_DATA_WIDTH2 17 /* master 2 data width */
+#define DW_PARAMS_DATA_WIDTH3 19 /* master 3 data width */
+#define DW_PARAMS_DATA_WIDTH4 21 /* master 4 data width */
+#define DW_PARAMS_EN 28 /* encoded parameters */
+
+/* Bitfields in DWC_PARAMS */
+#define DWC_PARAMS_MBLK_EN 11 /* multi block transfer */
+
/* Bitfields in CTL_LO */
#define DWC_CTLL_INT_EN (1 << 0) /* irqs enabled? */
#define DWC_CTLL_DST_WIDTH(n) ((n)<<1) /* bytes per element */
@@ -140,10 +170,9 @@ struct dw_dma_regs {
/* Bitfields in CFG */
#define DW_CFG_DMA_EN (1 << 0)
-#define DW_REGLEN 0x400
-
enum dw_dmac_flags {
DW_DMA_IS_CYCLIC = 0,
+ DW_DMA_IS_SOFT_LLP = 1,
};
struct dw_dma_chan {
@@ -154,6 +183,10 @@ struct dw_dma_chan {
bool paused;
bool initialized;
+ /* software emulation of the LLP transfers */
+ struct list_head *tx_list;
+ struct list_head *tx_node_active;
+
spinlock_t lock;
/* these other elements are all protected by lock */
@@ -165,8 +198,15 @@ struct dw_dma_chan {
unsigned int descs_allocated;
+ /* hardware configuration */
+ unsigned int block_size;
+ bool nollp;
+
/* configuration passed via DMA_SLAVE_CONFIG */
struct dma_slave_config dma_sconfig;
+
+ /* backlink to dw_dma */
+ struct dw_dma *dw;
};
static inline struct dw_dma_chan_regs __iomem *
@@ -193,6 +233,10 @@ struct dw_dma {
u8 all_chan_mask;
+ /* hardware configuration */
+ unsigned char nr_masters;
+ unsigned char data_width[4];
+
struct dw_dma_chan chan[0];
};
diff --git a/drivers/dma/edma.c b/drivers/dma/edma.c
new file mode 100644
index 0000000..05aea3c
--- /dev/null
+++ b/drivers/dma/edma.c
@@ -0,0 +1,671 @@
+/*
+ * TI EDMA DMA engine driver
+ *
+ * Copyright 2012 Texas Instruments
+ *
+ * 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 "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+#include <mach/edma.h>
+
+#include "dmaengine.h"
+#include "virt-dma.h"
+
+/*
+ * This will go away when the private EDMA API is folded
+ * into this driver and the platform device(s) are
+ * instantiated in the arch code. We can only get away
+ * with this simplification because DA8XX may not be built
+ * in the same kernel image with other DaVinci parts. This
+ * avoids having to sprinkle dmaengine driver platform devices
+ * and data throughout all the existing board files.
+ */
+#ifdef CONFIG_ARCH_DAVINCI_DA8XX
+#define EDMA_CTLRS 2
+#define EDMA_CHANS 32
+#else
+#define EDMA_CTLRS 1
+#define EDMA_CHANS 64
+#endif /* CONFIG_ARCH_DAVINCI_DA8XX */
+
+/* Max of 16 segments per channel to conserve PaRAM slots */
+#define MAX_NR_SG 16
+#define EDMA_MAX_SLOTS MAX_NR_SG
+#define EDMA_DESCRIPTORS 16
+
+struct edma_desc {
+ struct virt_dma_desc vdesc;
+ struct list_head node;
+ int absync;
+ int pset_nr;
+ struct edmacc_param pset[0];
+};
+
+struct edma_cc;
+
+struct edma_chan {
+ struct virt_dma_chan vchan;
+ struct list_head node;
+ struct edma_desc *edesc;
+ struct edma_cc *ecc;
+ int ch_num;
+ bool alloced;
+ int slot[EDMA_MAX_SLOTS];
+ dma_addr_t addr;
+ int addr_width;
+ int maxburst;
+};
+
+struct edma_cc {
+ int ctlr;
+ struct dma_device dma_slave;
+ struct edma_chan slave_chans[EDMA_CHANS];
+ int num_slave_chans;
+ int dummy_slot;
+};
+
+static inline struct edma_cc *to_edma_cc(struct dma_device *d)
+{
+ return container_of(d, struct edma_cc, dma_slave);
+}
+
+static inline struct edma_chan *to_edma_chan(struct dma_chan *c)
+{
+ return container_of(c, struct edma_chan, vchan.chan);
+}
+
+static inline struct edma_desc
+*to_edma_desc(struct dma_async_tx_descriptor *tx)
+{
+ return container_of(tx, struct edma_desc, vdesc.tx);
+}
+
+static void edma_desc_free(struct virt_dma_desc *vdesc)
+{
+ kfree(container_of(vdesc, struct edma_desc, vdesc));
+}
+
+/* Dispatch a queued descriptor to the controller (caller holds lock) */
+static void edma_execute(struct edma_chan *echan)
+{
+ struct virt_dma_desc *vdesc = vchan_next_desc(&echan->vchan);
+ struct edma_desc *edesc;
+ int i;
+
+ if (!vdesc) {
+ echan->edesc = NULL;
+ return;
+ }
+
+ list_del(&vdesc->node);
+
+ echan->edesc = edesc = to_edma_desc(&vdesc->tx);
+
+ /* Write descriptor PaRAM set(s) */
+ for (i = 0; i < edesc->pset_nr; i++) {
+ edma_write_slot(echan->slot[i], &edesc->pset[i]);
+ dev_dbg(echan->vchan.chan.device->dev,
+ "\n pset[%d]:\n"
+ " chnum\t%d\n"
+ " slot\t%d\n"
+ " opt\t%08x\n"
+ " src\t%08x\n"
+ " dst\t%08x\n"
+ " abcnt\t%08x\n"
+ " ccnt\t%08x\n"
+ " bidx\t%08x\n"
+ " cidx\t%08x\n"
+ " lkrld\t%08x\n",
+ i, echan->ch_num, echan->slot[i],
+ edesc->pset[i].opt,
+ edesc->pset[i].src,
+ edesc->pset[i].dst,
+ edesc->pset[i].a_b_cnt,
+ edesc->pset[i].ccnt,
+ edesc->pset[i].src_dst_bidx,
+ edesc->pset[i].src_dst_cidx,
+ edesc->pset[i].link_bcntrld);
+ /* Link to the previous slot if not the last set */
+ if (i != (edesc->pset_nr - 1))
+ edma_link(echan->slot[i], echan->slot[i+1]);
+ /* Final pset links to the dummy pset */
+ else
+ edma_link(echan->slot[i], echan->ecc->dummy_slot);
+ }
+
+ edma_start(echan->ch_num);
+}
+
+static int edma_terminate_all(struct edma_chan *echan)
+{
+ unsigned long flags;
+ LIST_HEAD(head);
+
+ spin_lock_irqsave(&echan->vchan.lock, flags);
+
+ /*
+ * Stop DMA activity: we assume the callback will not be called
+ * after edma_dma() returns (even if it does, it will see
+ * echan->edesc is NULL and exit.)
+ */
+ if (echan->edesc) {
+ echan->edesc = NULL;
+ edma_stop(echan->ch_num);
+ }
+
+ vchan_get_all_descriptors(&echan->vchan, &head);
+ spin_unlock_irqrestore(&echan->vchan.lock, flags);
+ vchan_dma_desc_free_list(&echan->vchan, &head);
+
+ return 0;
+}
+
+
+static int edma_slave_config(struct edma_chan *echan,
+ struct dma_slave_config *config)
+{
+ if ((config->src_addr_width > DMA_SLAVE_BUSWIDTH_4_BYTES) ||
+ (config->dst_addr_width > DMA_SLAVE_BUSWIDTH_4_BYTES))
+ return -EINVAL;
+
+ if (config->direction == DMA_MEM_TO_DEV) {
+ if (config->dst_addr)
+ echan->addr = config->dst_addr;
+ if (config->dst_addr_width)
+ echan->addr_width = config->dst_addr_width;
+ if (config->dst_maxburst)
+ echan->maxburst = config->dst_maxburst;
+ } else if (config->direction == DMA_DEV_TO_MEM) {
+ if (config->src_addr)
+ echan->addr = config->src_addr;
+ if (config->src_addr_width)
+ echan->addr_width = config->src_addr_width;
+ if (config->src_maxburst)
+ echan->maxburst = config->src_maxburst;
+ }
+
+ return 0;
+}
+
+static int edma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
+ unsigned long arg)
+{
+ int ret = 0;
+ struct dma_slave_config *config;
+ struct edma_chan *echan = to_edma_chan(chan);
+
+ switch (cmd) {
+ case DMA_TERMINATE_ALL:
+ edma_terminate_all(echan);
+ break;
+ case DMA_SLAVE_CONFIG:
+ config = (struct dma_slave_config *)arg;
+ ret = edma_slave_config(echan, config);
+ break;
+ default:
+ ret = -ENOSYS;
+ }
+
+ return ret;
+}
+
+static struct dma_async_tx_descriptor *edma_prep_slave_sg(
+ struct dma_chan *chan, struct scatterlist *sgl,
+ unsigned int sg_len, enum dma_transfer_direction direction,
+ unsigned long tx_flags, void *context)
+{
+ struct edma_chan *echan = to_edma_chan(chan);
+ struct device *dev = chan->device->dev;
+ struct edma_desc *edesc;
+ struct scatterlist *sg;
+ int i;
+ int acnt, bcnt, ccnt, src, dst, cidx;
+ int src_bidx, dst_bidx, src_cidx, dst_cidx;
+
+ if (unlikely(!echan || !sgl || !sg_len))
+ return NULL;
+
+ if (echan->addr_width == DMA_SLAVE_BUSWIDTH_UNDEFINED) {
+ dev_err(dev, "Undefined slave buswidth\n");
+ return NULL;
+ }
+
+ if (sg_len > MAX_NR_SG) {
+ dev_err(dev, "Exceeded max SG segments %d > %d\n",
+ sg_len, MAX_NR_SG);
+ return NULL;
+ }
+
+ edesc = kzalloc(sizeof(*edesc) + sg_len *
+ sizeof(edesc->pset[0]), GFP_ATOMIC);
+ if (!edesc) {
+ dev_dbg(dev, "Failed to allocate a descriptor\n");
+ return NULL;
+ }
+
+ edesc->pset_nr = sg_len;
+
+ for_each_sg(sgl, sg, sg_len, i) {
+ /* Allocate a PaRAM slot, if needed */
+ if (echan->slot[i] < 0) {
+ echan->slot[i] =
+ edma_alloc_slot(EDMA_CTLR(echan->ch_num),
+ EDMA_SLOT_ANY);
+ if (echan->slot[i] < 0) {
+ dev_err(dev, "Failed to allocate slot\n");
+ return NULL;
+ }
+ }
+
+ acnt = echan->addr_width;
+
+ /*
+ * If the maxburst is equal to the fifo width, use
+ * A-synced transfers. This allows for large contiguous
+ * buffer transfers using only one PaRAM set.
+ */
+ if (echan->maxburst == 1) {
+ edesc->absync = false;
+ ccnt = sg_dma_len(sg) / acnt / (SZ_64K - 1);
+ bcnt = sg_dma_len(sg) / acnt - ccnt * (SZ_64K - 1);
+ if (bcnt)
+ ccnt++;
+ else
+ bcnt = SZ_64K - 1;
+ cidx = acnt;
+ /*
+ * If maxburst is greater than the fifo address_width,
+ * use AB-synced transfers where A count is the fifo
+ * address_width and B count is the maxburst. In this
+ * case, we are limited to transfers of C count frames
+ * of (address_width * maxburst) where C count is limited
+ * to SZ_64K-1. This places an upper bound on the length
+ * of an SG segment that can be handled.
+ */
+ } else {
+ edesc->absync = true;
+ bcnt = echan->maxburst;
+ ccnt = sg_dma_len(sg) / (acnt * bcnt);
+ if (ccnt > (SZ_64K - 1)) {
+ dev_err(dev, "Exceeded max SG segment size\n");
+ return NULL;
+ }
+ cidx = acnt * bcnt;
+ }
+
+ if (direction == DMA_MEM_TO_DEV) {
+ src = sg_dma_address(sg);
+ dst = echan->addr;
+ src_bidx = acnt;
+ src_cidx = cidx;
+ dst_bidx = 0;
+ dst_cidx = 0;
+ } else {
+ src = echan->addr;
+ dst = sg_dma_address(sg);
+ src_bidx = 0;
+ src_cidx = 0;
+ dst_bidx = acnt;
+ dst_cidx = cidx;
+ }
+
+ edesc->pset[i].opt = EDMA_TCC(EDMA_CHAN_SLOT(echan->ch_num));
+ /* Configure A or AB synchronized transfers */
+ if (edesc->absync)
+ edesc->pset[i].opt |= SYNCDIM;
+ /* If this is the last set, enable completion interrupt flag */
+ if (i == sg_len - 1)
+ edesc->pset[i].opt |= TCINTEN;
+
+ edesc->pset[i].src = src;
+ edesc->pset[i].dst = dst;
+
+ edesc->pset[i].src_dst_bidx = (dst_bidx << 16) | src_bidx;
+ edesc->pset[i].src_dst_cidx = (dst_cidx << 16) | src_cidx;
+
+ edesc->pset[i].a_b_cnt = bcnt << 16 | acnt;
+ edesc->pset[i].ccnt = ccnt;
+ edesc->pset[i].link_bcntrld = 0xffffffff;
+
+ }
+
+ return vchan_tx_prep(&echan->vchan, &edesc->vdesc, tx_flags);
+}
+
+static void edma_callback(unsigned ch_num, u16 ch_status, void *data)
+{
+ struct edma_chan *echan = data;
+ struct device *dev = echan->vchan.chan.device->dev;
+ struct edma_desc *edesc;
+ unsigned long flags;
+
+ /* Stop the channel */
+ edma_stop(echan->ch_num);
+
+ switch (ch_status) {
+ case DMA_COMPLETE:
+ dev_dbg(dev, "transfer complete on channel %d\n", ch_num);
+
+ spin_lock_irqsave(&echan->vchan.lock, flags);
+
+ edesc = echan->edesc;
+ if (edesc) {
+ edma_execute(echan);
+ vchan_cookie_complete(&edesc->vdesc);
+ }
+
+ spin_unlock_irqrestore(&echan->vchan.lock, flags);
+
+ break;
+ case DMA_CC_ERROR:
+ dev_dbg(dev, "transfer error on channel %d\n", ch_num);
+ break;
+ default:
+ break;
+ }
+}
+
+/* Alloc channel resources */
+static int edma_alloc_chan_resources(struct dma_chan *chan)
+{
+ struct edma_chan *echan = to_edma_chan(chan);
+ struct device *dev = chan->device->dev;
+ int ret;
+ int a_ch_num;
+ LIST_HEAD(descs);
+
+ a_ch_num = edma_alloc_channel(echan->ch_num, edma_callback,
+ chan, EVENTQ_DEFAULT);
+
+ if (a_ch_num < 0) {
+ ret = -ENODEV;
+ goto err_no_chan;
+ }
+
+ if (a_ch_num != echan->ch_num) {
+ dev_err(dev, "failed to allocate requested channel %u:%u\n",
+ EDMA_CTLR(echan->ch_num),
+ EDMA_CHAN_SLOT(echan->ch_num));
+ ret = -ENODEV;
+ goto err_wrong_chan;
+ }
+
+ echan->alloced = true;
+ echan->slot[0] = echan->ch_num;
+
+ dev_info(dev, "allocated channel for %u:%u\n",
+ EDMA_CTLR(echan->ch_num), EDMA_CHAN_SLOT(echan->ch_num));
+
+ return 0;
+
+err_wrong_chan:
+ edma_free_channel(a_ch_num);
+err_no_chan:
+ return ret;
+}
+
+/* Free channel resources */
+static void edma_free_chan_resources(struct dma_chan *chan)
+{
+ struct edma_chan *echan = to_edma_chan(chan);
+ struct device *dev = chan->device->dev;
+ int i;
+
+ /* Terminate transfers */
+ edma_stop(echan->ch_num);
+
+ vchan_free_chan_resources(&echan->vchan);
+
+ /* Free EDMA PaRAM slots */
+ for (i = 1; i < EDMA_MAX_SLOTS; i++) {
+ if (echan->slot[i] >= 0) {
+ edma_free_slot(echan->slot[i]);
+ echan->slot[i] = -1;
+ }
+ }
+
+ /* Free EDMA channel */
+ if (echan->alloced) {
+ edma_free_channel(echan->ch_num);
+ echan->alloced = false;
+ }
+
+ dev_info(dev, "freeing channel for %u\n", echan->ch_num);
+}
+
+/* Send pending descriptor to hardware */
+static void edma_issue_pending(struct dma_chan *chan)
+{
+ struct edma_chan *echan = to_edma_chan(chan);
+ unsigned long flags;
+
+ spin_lock_irqsave(&echan->vchan.lock, flags);
+ if (vchan_issue_pending(&echan->vchan) && !echan->edesc)
+ edma_execute(echan);
+ spin_unlock_irqrestore(&echan->vchan.lock, flags);
+}
+
+static size_t edma_desc_size(struct edma_desc *edesc)
+{
+ int i;
+ size_t size;
+
+ if (edesc->absync)
+ for (size = i = 0; i < edesc->pset_nr; i++)
+ size += (edesc->pset[i].a_b_cnt & 0xffff) *
+ (edesc->pset[i].a_b_cnt >> 16) *
+ edesc->pset[i].ccnt;
+ else
+ size = (edesc->pset[0].a_b_cnt & 0xffff) *
+ (edesc->pset[0].a_b_cnt >> 16) +
+ (edesc->pset[0].a_b_cnt & 0xffff) *
+ (SZ_64K - 1) * edesc->pset[0].ccnt;
+
+ return size;
+}
+
+/* Check request completion status */
+static enum dma_status edma_tx_status(struct dma_chan *chan,
+ dma_cookie_t cookie,
+ struct dma_tx_state *txstate)
+{
+ struct edma_chan *echan = to_edma_chan(chan);
+ struct virt_dma_desc *vdesc;
+ enum dma_status ret;
+ unsigned long flags;
+
+ ret = dma_cookie_status(chan, cookie, txstate);
+ if (ret == DMA_SUCCESS || !txstate)
+ return ret;
+
+ spin_lock_irqsave(&echan->vchan.lock, flags);
+ vdesc = vchan_find_desc(&echan->vchan, cookie);
+ if (vdesc) {
+ txstate->residue = edma_desc_size(to_edma_desc(&vdesc->tx));
+ } else if (echan->edesc && echan->edesc->vdesc.tx.cookie == cookie) {
+ struct edma_desc *edesc = echan->edesc;
+ txstate->residue = edma_desc_size(edesc);
+ } else {
+ txstate->residue = 0;
+ }
+ spin_unlock_irqrestore(&echan->vchan.lock, flags);
+
+ return ret;
+}
+
+static void __init edma_chan_init(struct edma_cc *ecc,
+ struct dma_device *dma,
+ struct edma_chan *echans)
+{
+ int i, j;
+
+ for (i = 0; i < EDMA_CHANS; i++) {
+ struct edma_chan *echan = &echans[i];
+ echan->ch_num = EDMA_CTLR_CHAN(ecc->ctlr, i);
+ echan->ecc = ecc;
+ echan->vchan.desc_free = edma_desc_free;
+
+ vchan_init(&echan->vchan, dma);
+
+ INIT_LIST_HEAD(&echan->node);
+ for (j = 0; j < EDMA_MAX_SLOTS; j++)
+ echan->slot[j] = -1;
+ }
+}
+
+static void edma_dma_init(struct edma_cc *ecc, struct dma_device *dma,
+ struct device *dev)
+{
+ dma->device_prep_slave_sg = edma_prep_slave_sg;
+ dma->device_alloc_chan_resources = edma_alloc_chan_resources;
+ dma->device_free_chan_resources = edma_free_chan_resources;
+ dma->device_issue_pending = edma_issue_pending;
+ dma->device_tx_status = edma_tx_status;
+ dma->device_control = edma_control;
+ dma->dev = dev;
+
+ INIT_LIST_HEAD(&dma->channels);
+}
+
+static int __devinit edma_probe(struct platform_device *pdev)
+{
+ struct edma_cc *ecc;
+ int ret;
+
+ ecc = devm_kzalloc(&pdev->dev, sizeof(*ecc), GFP_KERNEL);
+ if (!ecc) {
+ dev_err(&pdev->dev, "Can't allocate controller\n");
+ return -ENOMEM;
+ }
+
+ ecc->ctlr = pdev->id;
+ ecc->dummy_slot = edma_alloc_slot(ecc->ctlr, EDMA_SLOT_ANY);
+ if (ecc->dummy_slot < 0) {
+ dev_err(&pdev->dev, "Can't allocate PaRAM dummy slot\n");
+ return -EIO;
+ }
+
+ dma_cap_zero(ecc->dma_slave.cap_mask);
+ dma_cap_set(DMA_SLAVE, ecc->dma_slave.cap_mask);
+
+ edma_dma_init(ecc, &ecc->dma_slave, &pdev->dev);
+
+ edma_chan_init(ecc, &ecc->dma_slave, ecc->slave_chans);
+
+ ret = dma_async_device_register(&ecc->dma_slave);
+ if (ret)
+ goto err_reg1;
+
+ platform_set_drvdata(pdev, ecc);
+
+ dev_info(&pdev->dev, "TI EDMA DMA engine driver\n");
+
+ return 0;
+
+err_reg1:
+ edma_free_slot(ecc->dummy_slot);
+ return ret;
+}
+
+static int __devexit edma_remove(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct edma_cc *ecc = dev_get_drvdata(dev);
+
+ dma_async_device_unregister(&ecc->dma_slave);
+ edma_free_slot(ecc->dummy_slot);
+
+ return 0;
+}
+
+static struct platform_driver edma_driver = {
+ .probe = edma_probe,
+ .remove = __devexit_p(edma_remove),
+ .driver = {
+ .name = "edma-dma-engine",
+ .owner = THIS_MODULE,
+ },
+};
+
+bool edma_filter_fn(struct dma_chan *chan, void *param)
+{
+ if (chan->device->dev->driver == &edma_driver.driver) {
+ struct edma_chan *echan = to_edma_chan(chan);
+ unsigned ch_req = *(unsigned *)param;
+ return ch_req == echan->ch_num;
+ }
+ return false;
+}
+EXPORT_SYMBOL(edma_filter_fn);
+
+static struct platform_device *pdev0, *pdev1;
+
+static const struct platform_device_info edma_dev_info0 = {
+ .name = "edma-dma-engine",
+ .id = 0,
+ .dma_mask = DMA_BIT_MASK(32),
+};
+
+static const struct platform_device_info edma_dev_info1 = {
+ .name = "edma-dma-engine",
+ .id = 1,
+ .dma_mask = DMA_BIT_MASK(32),
+};
+
+static int edma_init(void)
+{
+ int ret = platform_driver_register(&edma_driver);
+
+ if (ret == 0) {
+ pdev0 = platform_device_register_full(&edma_dev_info0);
+ if (IS_ERR(pdev0)) {
+ platform_driver_unregister(&edma_driver);
+ ret = PTR_ERR(pdev0);
+ goto out;
+ }
+ }
+
+ if (EDMA_CTLRS == 2) {
+ pdev1 = platform_device_register_full(&edma_dev_info1);
+ if (IS_ERR(pdev1)) {
+ platform_driver_unregister(&edma_driver);
+ platform_device_unregister(pdev0);
+ ret = PTR_ERR(pdev1);
+ }
+ }
+
+out:
+ return ret;
+}
+subsys_initcall(edma_init);
+
+static void __exit edma_exit(void)
+{
+ platform_device_unregister(pdev0);
+ if (pdev1)
+ platform_device_unregister(pdev1);
+ platform_driver_unregister(&edma_driver);
+}
+module_exit(edma_exit);
+
+MODULE_AUTHOR("Matt Porter <mporter@ti.com>");
+MODULE_DESCRIPTION("TI EDMA DMA engine driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/dma/ioat/dma_v2.c b/drivers/dma/ioat/dma_v2.c
index 8689576..b9d6678 100644
--- a/drivers/dma/ioat/dma_v2.c
+++ b/drivers/dma/ioat/dma_v2.c
@@ -434,12 +434,11 @@ static struct ioat_ring_ent *ioat2_alloc_ring_ent(struct dma_chan *chan, gfp_t f
return NULL;
memset(hw, 0, sizeof(*hw));
- desc = kmem_cache_alloc(ioat2_cache, flags);
+ desc = kmem_cache_zalloc(ioat2_cache, flags);
if (!desc) {
pci_pool_free(dma->dma_pool, hw, phys);
return NULL;
}
- memset(desc, 0, sizeof(*desc));
dma_async_tx_descriptor_init(&desc->txd, chan);
desc->txd.tx_submit = ioat2_tx_submit_unlock;
diff --git a/drivers/dma/ioat/pci.c b/drivers/dma/ioat/pci.c
index 5e3a40f..c057306 100644
--- a/drivers/dma/ioat/pci.c
+++ b/drivers/dma/ioat/pci.c
@@ -40,6 +40,17 @@ MODULE_VERSION(IOAT_DMA_VERSION);
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("Intel Corporation");
+#define PCI_DEVICE_ID_INTEL_IOAT_IVB0 0x0e20
+#define PCI_DEVICE_ID_INTEL_IOAT_IVB1 0x0e21
+#define PCI_DEVICE_ID_INTEL_IOAT_IVB2 0x0e22
+#define PCI_DEVICE_ID_INTEL_IOAT_IVB3 0x0e23
+#define PCI_DEVICE_ID_INTEL_IOAT_IVB4 0x0e24
+#define PCI_DEVICE_ID_INTEL_IOAT_IVB5 0x0e25
+#define PCI_DEVICE_ID_INTEL_IOAT_IVB6 0x0e26
+#define PCI_DEVICE_ID_INTEL_IOAT_IVB7 0x0e27
+#define PCI_DEVICE_ID_INTEL_IOAT_IVB8 0x0e2e
+#define PCI_DEVICE_ID_INTEL_IOAT_IVB9 0x0e2f
+
static struct pci_device_id ioat_pci_tbl[] = {
/* I/OAT v1 platforms */
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT) },
@@ -83,6 +94,17 @@ static struct pci_device_id ioat_pci_tbl[] = {
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_SNB8) },
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_SNB9) },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_IVB0) },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_IVB1) },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_IVB2) },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_IVB3) },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_IVB4) },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_IVB5) },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_IVB6) },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_IVB7) },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_IVB8) },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_IVB9) },
+
{ 0, }
};
MODULE_DEVICE_TABLE(pci, ioat_pci_tbl);
diff --git a/drivers/dma/mmp_pdma.c b/drivers/dma/mmp_pdma.c
new file mode 100644
index 0000000..14da1f4
--- /dev/null
+++ b/drivers/dma/mmp_pdma.c
@@ -0,0 +1,875 @@
+/*
+ * Copyright 2012 Marvell International Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <linux/dmaengine.h>
+#include <linux/platform_device.h>
+#include <linux/device.h>
+#include <linux/platform_data/mmp_dma.h>
+#include <linux/dmapool.h>
+#include <linux/of_device.h>
+#include <linux/of.h>
+
+#include "dmaengine.h"
+
+#define DCSR 0x0000
+#define DALGN 0x00a0
+#define DINT 0x00f0
+#define DDADR 0x0200
+#define DSADR 0x0204
+#define DTADR 0x0208
+#define DCMD 0x020c
+
+#define DCSR_RUN (1 << 31) /* Run Bit (read / write) */
+#define DCSR_NODESC (1 << 30) /* No-Descriptor Fetch (read / write) */
+#define DCSR_STOPIRQEN (1 << 29) /* Stop Interrupt Enable (read / write) */
+#define DCSR_REQPEND (1 << 8) /* Request Pending (read-only) */
+#define DCSR_STOPSTATE (1 << 3) /* Stop State (read-only) */
+#define DCSR_ENDINTR (1 << 2) /* End Interrupt (read / write) */
+#define DCSR_STARTINTR (1 << 1) /* Start Interrupt (read / write) */
+#define DCSR_BUSERR (1 << 0) /* Bus Error Interrupt (read / write) */
+
+#define DCSR_EORIRQEN (1 << 28) /* End of Receive Interrupt Enable (R/W) */
+#define DCSR_EORJMPEN (1 << 27) /* Jump to next descriptor on EOR */
+#define DCSR_EORSTOPEN (1 << 26) /* STOP on an EOR */
+#define DCSR_SETCMPST (1 << 25) /* Set Descriptor Compare Status */
+#define DCSR_CLRCMPST (1 << 24) /* Clear Descriptor Compare Status */
+#define DCSR_CMPST (1 << 10) /* The Descriptor Compare Status */
+#define DCSR_EORINTR (1 << 9) /* The end of Receive */
+
+#define DRCMR_MAPVLD (1 << 7) /* Map Valid (read / write) */
+#define DRCMR_CHLNUM 0x1f /* mask for Channel Number (read / write) */
+
+#define DDADR_DESCADDR 0xfffffff0 /* Address of next descriptor (mask) */
+#define DDADR_STOP (1 << 0) /* Stop (read / write) */
+
+#define DCMD_INCSRCADDR (1 << 31) /* Source Address Increment Setting. */
+#define DCMD_INCTRGADDR (1 << 30) /* Target Address Increment Setting. */
+#define DCMD_FLOWSRC (1 << 29) /* Flow Control by the source. */
+#define DCMD_FLOWTRG (1 << 28) /* Flow Control by the target. */
+#define DCMD_STARTIRQEN (1 << 22) /* Start Interrupt Enable */
+#define DCMD_ENDIRQEN (1 << 21) /* End Interrupt Enable */
+#define DCMD_ENDIAN (1 << 18) /* Device Endian-ness. */
+#define DCMD_BURST8 (1 << 16) /* 8 byte burst */
+#define DCMD_BURST16 (2 << 16) /* 16 byte burst */
+#define DCMD_BURST32 (3 << 16) /* 32 byte burst */
+#define DCMD_WIDTH1 (1 << 14) /* 1 byte width */
+#define DCMD_WIDTH2 (2 << 14) /* 2 byte width (HalfWord) */
+#define DCMD_WIDTH4 (3 << 14) /* 4 byte width (Word) */
+#define DCMD_LENGTH 0x01fff /* length mask (max = 8K - 1) */
+
+#define PDMA_ALIGNMENT 3
+#define PDMA_MAX_DESC_BYTES 0x1000
+
+struct mmp_pdma_desc_hw {
+ u32 ddadr; /* Points to the next descriptor + flags */
+ u32 dsadr; /* DSADR value for the current transfer */
+ u32 dtadr; /* DTADR value for the current transfer */
+ u32 dcmd; /* DCMD value for the current transfer */
+} __aligned(32);
+
+struct mmp_pdma_desc_sw {
+ struct mmp_pdma_desc_hw desc;
+ struct list_head node;
+ struct list_head tx_list;
+ struct dma_async_tx_descriptor async_tx;
+};
+
+struct mmp_pdma_phy;
+
+struct mmp_pdma_chan {
+ struct device *dev;
+ struct dma_chan chan;
+ struct dma_async_tx_descriptor desc;
+ struct mmp_pdma_phy *phy;
+ enum dma_transfer_direction dir;
+
+ /* channel's basic info */
+ struct tasklet_struct tasklet;
+ u32 dcmd;
+ u32 drcmr;
+ u32 dev_addr;
+
+ /* list for desc */
+ spinlock_t desc_lock; /* Descriptor list lock */
+ struct list_head chain_pending; /* Link descriptors queue for pending */
+ struct list_head chain_running; /* Link descriptors queue for running */
+ bool idle; /* channel statue machine */
+
+ struct dma_pool *desc_pool; /* Descriptors pool */
+};
+
+struct mmp_pdma_phy {
+ int idx;
+ void __iomem *base;
+ struct mmp_pdma_chan *vchan;
+};
+
+struct mmp_pdma_device {
+ int dma_channels;
+ void __iomem *base;
+ struct device *dev;
+ struct dma_device device;
+ struct mmp_pdma_phy *phy;
+};
+
+#define tx_to_mmp_pdma_desc(tx) container_of(tx, struct mmp_pdma_desc_sw, async_tx)
+#define to_mmp_pdma_desc(lh) container_of(lh, struct mmp_pdma_desc_sw, node)
+#define to_mmp_pdma_chan(dchan) container_of(dchan, struct mmp_pdma_chan, chan)
+#define to_mmp_pdma_dev(dmadev) container_of(dmadev, struct mmp_pdma_device, device)
+
+static void set_desc(struct mmp_pdma_phy *phy, dma_addr_t addr)
+{
+ u32 reg = (phy->idx << 4) + DDADR;
+
+ writel(addr, phy->base + reg);
+}
+
+static void enable_chan(struct mmp_pdma_phy *phy)
+{
+ u32 reg;
+
+ if (!phy->vchan)
+ return;
+
+ reg = phy->vchan->drcmr;
+ reg = (((reg) < 64) ? 0x0100 : 0x1100) + (((reg) & 0x3f) << 2);
+ writel(DRCMR_MAPVLD | phy->idx, phy->base + reg);
+
+ reg = (phy->idx << 2) + DCSR;
+ writel(readl(phy->base + reg) | DCSR_RUN,
+ phy->base + reg);
+}
+
+static void disable_chan(struct mmp_pdma_phy *phy)
+{
+ u32 reg;
+
+ if (phy) {
+ reg = (phy->idx << 2) + DCSR;
+ writel(readl(phy->base + reg) & ~DCSR_RUN,
+ phy->base + reg);
+ }
+}
+
+static int clear_chan_irq(struct mmp_pdma_phy *phy)
+{
+ u32 dcsr;
+ u32 dint = readl(phy->base + DINT);
+ u32 reg = (phy->idx << 2) + DCSR;
+
+ if (dint & BIT(phy->idx)) {
+ /* clear irq */
+ dcsr = readl(phy->base + reg);
+ writel(dcsr, phy->base + reg);
+ if ((dcsr & DCSR_BUSERR) && (phy->vchan))
+ dev_warn(phy->vchan->dev, "DCSR_BUSERR\n");
+ return 0;
+ }
+ return -EAGAIN;
+}
+
+static irqreturn_t mmp_pdma_chan_handler(int irq, void *dev_id)
+{
+ struct mmp_pdma_phy *phy = dev_id;
+
+ if (clear_chan_irq(phy) == 0) {
+ tasklet_schedule(&phy->vchan->tasklet);
+ return IRQ_HANDLED;
+ } else
+ return IRQ_NONE;
+}
+
+static irqreturn_t mmp_pdma_int_handler(int irq, void *dev_id)
+{
+ struct mmp_pdma_device *pdev = dev_id;
+ struct mmp_pdma_phy *phy;
+ u32 dint = readl(pdev->base + DINT);
+ int i, ret;
+ int irq_num = 0;
+
+ while (dint) {
+ i = __ffs(dint);
+ dint &= (dint - 1);
+ phy = &pdev->phy[i];
+ ret = mmp_pdma_chan_handler(irq, phy);
+ if (ret == IRQ_HANDLED)
+ irq_num++;
+ }
+
+ if (irq_num)
+ return IRQ_HANDLED;
+ else
+ return IRQ_NONE;
+}
+
+/* lookup free phy channel as descending priority */
+static struct mmp_pdma_phy *lookup_phy(struct mmp_pdma_chan *pchan)
+{
+ int prio, i;
+ struct mmp_pdma_device *pdev = to_mmp_pdma_dev(pchan->chan.device);
+ struct mmp_pdma_phy *phy;
+
+ /*
+ * dma channel priorities
+ * ch 0 - 3, 16 - 19 <--> (0)
+ * ch 4 - 7, 20 - 23 <--> (1)
+ * ch 8 - 11, 24 - 27 <--> (2)
+ * ch 12 - 15, 28 - 31 <--> (3)
+ */
+ for (prio = 0; prio <= (((pdev->dma_channels - 1) & 0xf) >> 2); prio++) {
+ for (i = 0; i < pdev->dma_channels; i++) {
+ if (prio != ((i & 0xf) >> 2))
+ continue;
+ phy = &pdev->phy[i];
+ if (!phy->vchan) {
+ phy->vchan = pchan;
+ return phy;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+/* desc->tx_list ==> pending list */
+static void append_pending_queue(struct mmp_pdma_chan *chan,
+ struct mmp_pdma_desc_sw *desc)
+{
+ struct mmp_pdma_desc_sw *tail =
+ to_mmp_pdma_desc(chan->chain_pending.prev);
+
+ if (list_empty(&chan->chain_pending))
+ goto out_splice;
+
+ /* one irq per queue, even appended */
+ tail->desc.ddadr = desc->async_tx.phys;
+ tail->desc.dcmd &= ~DCMD_ENDIRQEN;
+
+ /* softly link to pending list */
+out_splice:
+ list_splice_tail_init(&desc->tx_list, &chan->chain_pending);
+}
+
+/**
+ * start_pending_queue - transfer any pending transactions
+ * pending list ==> running list
+ */
+static void start_pending_queue(struct mmp_pdma_chan *chan)
+{
+ struct mmp_pdma_desc_sw *desc;
+
+ /* still in running, irq will start the pending list */
+ if (!chan->idle) {
+ dev_dbg(chan->dev, "DMA controller still busy\n");
+ return;
+ }
+
+ if (list_empty(&chan->chain_pending)) {
+ /* chance to re-fetch phy channel with higher prio */
+ if (chan->phy) {
+ chan->phy->vchan = NULL;
+ chan->phy = NULL;
+ }
+ dev_dbg(chan->dev, "no pending list\n");
+ return;
+ }
+
+ if (!chan->phy) {
+ chan->phy = lookup_phy(chan);
+ if (!chan->phy) {
+ dev_dbg(chan->dev, "no free dma channel\n");
+ return;
+ }
+ }
+
+ /*
+ * pending -> running
+ * reintilize pending list
+ */
+ desc = list_first_entry(&chan->chain_pending,
+ struct mmp_pdma_desc_sw, node);
+ list_splice_tail_init(&chan->chain_pending, &chan->chain_running);
+
+ /*
+ * Program the descriptor's address into the DMA controller,
+ * then start the DMA transaction
+ */
+ set_desc(chan->phy, desc->async_tx.phys);
+ enable_chan(chan->phy);
+ chan->idle = false;
+}
+
+
+/* desc->tx_list ==> pending list */
+static dma_cookie_t mmp_pdma_tx_submit(struct dma_async_tx_descriptor *tx)
+{
+ struct mmp_pdma_chan *chan = to_mmp_pdma_chan(tx->chan);
+ struct mmp_pdma_desc_sw *desc = tx_to_mmp_pdma_desc(tx);
+ struct mmp_pdma_desc_sw *child;
+ unsigned long flags;
+ dma_cookie_t cookie = -EBUSY;
+
+ spin_lock_irqsave(&chan->desc_lock, flags);
+
+ list_for_each_entry(child, &desc->tx_list, node) {
+ cookie = dma_cookie_assign(&child->async_tx);
+ }
+
+ append_pending_queue(chan, desc);
+
+ spin_unlock_irqrestore(&chan->desc_lock, flags);
+
+ return cookie;
+}
+
+struct mmp_pdma_desc_sw *mmp_pdma_alloc_descriptor(struct mmp_pdma_chan *chan)
+{
+ struct mmp_pdma_desc_sw *desc;
+ dma_addr_t pdesc;
+
+ desc = dma_pool_alloc(chan->desc_pool, GFP_ATOMIC, &pdesc);
+ if (!desc) {
+ dev_err(chan->dev, "out of memory for link descriptor\n");
+ return NULL;
+ }
+
+ memset(desc, 0, sizeof(*desc));
+ INIT_LIST_HEAD(&desc->tx_list);
+ dma_async_tx_descriptor_init(&desc->async_tx, &chan->chan);
+ /* each desc has submit */
+ desc->async_tx.tx_submit = mmp_pdma_tx_submit;
+ desc->async_tx.phys = pdesc;
+
+ return desc;
+}
+
+/**
+ * mmp_pdma_alloc_chan_resources - Allocate resources for DMA channel.
+ *
+ * This function will create a dma pool for descriptor allocation.
+ * Request irq only when channel is requested
+ * Return - The number of allocated descriptors.
+ */
+
+static int mmp_pdma_alloc_chan_resources(struct dma_chan *dchan)
+{
+ struct mmp_pdma_chan *chan = to_mmp_pdma_chan(dchan);
+
+ if (chan->desc_pool)
+ return 1;
+
+ chan->desc_pool =
+ dma_pool_create(dev_name(&dchan->dev->device), chan->dev,
+ sizeof(struct mmp_pdma_desc_sw),
+ __alignof__(struct mmp_pdma_desc_sw), 0);
+ if (!chan->desc_pool) {
+ dev_err(chan->dev, "unable to allocate descriptor pool\n");
+ return -ENOMEM;
+ }
+ if (chan->phy) {
+ chan->phy->vchan = NULL;
+ chan->phy = NULL;
+ }
+ chan->idle = true;
+ chan->dev_addr = 0;
+ return 1;
+}
+
+static void mmp_pdma_free_desc_list(struct mmp_pdma_chan *chan,
+ struct list_head *list)
+{
+ struct mmp_pdma_desc_sw *desc, *_desc;
+
+ list_for_each_entry_safe(desc, _desc, list, node) {
+ list_del(&desc->node);
+ dma_pool_free(chan->desc_pool, desc, desc->async_tx.phys);
+ }
+}
+
+static void mmp_pdma_free_chan_resources(struct dma_chan *dchan)
+{
+ struct mmp_pdma_chan *chan = to_mmp_pdma_chan(dchan);
+ unsigned long flags;
+
+ spin_lock_irqsave(&chan->desc_lock, flags);
+ mmp_pdma_free_desc_list(chan, &chan->chain_pending);
+ mmp_pdma_free_desc_list(chan, &chan->chain_running);
+ spin_unlock_irqrestore(&chan->desc_lock, flags);
+
+ dma_pool_destroy(chan->desc_pool);
+ chan->desc_pool = NULL;
+ chan->idle = true;
+ chan->dev_addr = 0;
+ if (chan->phy) {
+ chan->phy->vchan = NULL;
+ chan->phy = NULL;
+ }
+ return;
+}
+
+static struct dma_async_tx_descriptor *
+mmp_pdma_prep_memcpy(struct dma_chan *dchan,
+ dma_addr_t dma_dst, dma_addr_t dma_src,
+ size_t len, unsigned long flags)
+{
+ struct mmp_pdma_chan *chan;
+ struct mmp_pdma_desc_sw *first = NULL, *prev = NULL, *new;
+ size_t copy = 0;
+
+ if (!dchan)
+ return NULL;
+
+ if (!len)
+ return NULL;
+
+ chan = to_mmp_pdma_chan(dchan);
+
+ if (!chan->dir) {
+ chan->dir = DMA_MEM_TO_MEM;
+ chan->dcmd = DCMD_INCTRGADDR | DCMD_INCSRCADDR;
+ chan->dcmd |= DCMD_BURST32;
+ }
+
+ do {
+ /* Allocate the link descriptor from DMA pool */
+ new = mmp_pdma_alloc_descriptor(chan);
+ if (!new) {
+ dev_err(chan->dev, "no memory for desc\n");
+ goto fail;
+ }
+
+ copy = min_t(size_t, len, PDMA_MAX_DESC_BYTES);
+
+ new->desc.dcmd = chan->dcmd | (DCMD_LENGTH & copy);
+ new->desc.dsadr = dma_src;
+ new->desc.dtadr = dma_dst;
+
+ if (!first)
+ first = new;
+ else
+ prev->desc.ddadr = new->async_tx.phys;
+
+ new->async_tx.cookie = 0;
+ async_tx_ack(&new->async_tx);
+
+ prev = new;
+ len -= copy;
+
+ if (chan->dir == DMA_MEM_TO_DEV) {
+ dma_src += copy;
+ } else if (chan->dir == DMA_DEV_TO_MEM) {
+ dma_dst += copy;
+ } else if (chan->dir == DMA_MEM_TO_MEM) {
+ dma_src += copy;
+ dma_dst += copy;
+ }
+
+ /* Insert the link descriptor to the LD ring */
+ list_add_tail(&new->node, &first->tx_list);
+ } while (len);
+
+ first->async_tx.flags = flags; /* client is in control of this ack */
+ first->async_tx.cookie = -EBUSY;
+
+ /* last desc and fire IRQ */
+ new->desc.ddadr = DDADR_STOP;
+ new->desc.dcmd |= DCMD_ENDIRQEN;
+
+ return &first->async_tx;
+
+fail:
+ if (first)
+ mmp_pdma_free_desc_list(chan, &first->tx_list);
+ return NULL;
+}
+
+static struct dma_async_tx_descriptor *
+mmp_pdma_prep_slave_sg(struct dma_chan *dchan, struct scatterlist *sgl,
+ unsigned int sg_len, enum dma_transfer_direction dir,
+ unsigned long flags, void *context)
+{
+ struct mmp_pdma_chan *chan = to_mmp_pdma_chan(dchan);
+ struct mmp_pdma_desc_sw *first = NULL, *prev = NULL, *new = NULL;
+ size_t len, avail;
+ struct scatterlist *sg;
+ dma_addr_t addr;
+ int i;
+
+ if ((sgl == NULL) || (sg_len == 0))
+ return NULL;
+
+ for_each_sg(sgl, sg, sg_len, i) {
+ addr = sg_dma_address(sg);
+ avail = sg_dma_len(sgl);
+
+ do {
+ len = min_t(size_t, avail, PDMA_MAX_DESC_BYTES);
+
+ /* allocate and populate the descriptor */
+ new = mmp_pdma_alloc_descriptor(chan);
+ if (!new) {
+ dev_err(chan->dev, "no memory for desc\n");
+ goto fail;
+ }
+
+ new->desc.dcmd = chan->dcmd | (DCMD_LENGTH & len);
+ if (dir == DMA_MEM_TO_DEV) {
+ new->desc.dsadr = addr;
+ new->desc.dtadr = chan->dev_addr;
+ } else {
+ new->desc.dsadr = chan->dev_addr;
+ new->desc.dtadr = addr;
+ }
+
+ if (!first)
+ first = new;
+ else
+ prev->desc.ddadr = new->async_tx.phys;
+
+ new->async_tx.cookie = 0;
+ async_tx_ack(&new->async_tx);
+ prev = new;
+
+ /* Insert the link descriptor to the LD ring */
+ list_add_tail(&new->node, &first->tx_list);
+
+ /* update metadata */
+ addr += len;
+ avail -= len;
+ } while (avail);
+ }
+
+ first->async_tx.cookie = -EBUSY;
+ first->async_tx.flags = flags;
+
+ /* last desc and fire IRQ */
+ new->desc.ddadr = DDADR_STOP;
+ new->desc.dcmd |= DCMD_ENDIRQEN;
+
+ return &first->async_tx;
+
+fail:
+ if (first)
+ mmp_pdma_free_desc_list(chan, &first->tx_list);
+ return NULL;
+}
+
+static int mmp_pdma_control(struct dma_chan *dchan, enum dma_ctrl_cmd cmd,
+ unsigned long arg)
+{
+ struct mmp_pdma_chan *chan = to_mmp_pdma_chan(dchan);
+ struct dma_slave_config *cfg = (void *)arg;
+ unsigned long flags;
+ int ret = 0;
+ u32 maxburst = 0, addr = 0;
+ enum dma_slave_buswidth width = DMA_SLAVE_BUSWIDTH_UNDEFINED;
+
+ if (!dchan)
+ return -EINVAL;
+
+ switch (cmd) {
+ case DMA_TERMINATE_ALL:
+ disable_chan(chan->phy);
+ if (chan->phy) {
+ chan->phy->vchan = NULL;
+ chan->phy = NULL;
+ }
+ spin_lock_irqsave(&chan->desc_lock, flags);
+ mmp_pdma_free_desc_list(chan, &chan->chain_pending);
+ mmp_pdma_free_desc_list(chan, &chan->chain_running);
+ spin_unlock_irqrestore(&chan->desc_lock, flags);
+ chan->idle = true;
+ break;
+ case DMA_SLAVE_CONFIG:
+ if (cfg->direction == DMA_DEV_TO_MEM) {
+ chan->dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC;
+ maxburst = cfg->src_maxburst;
+ width = cfg->src_addr_width;
+ addr = cfg->src_addr;
+ } else if (cfg->direction == DMA_MEM_TO_DEV) {
+ chan->dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG;
+ maxburst = cfg->dst_maxburst;
+ width = cfg->dst_addr_width;
+ addr = cfg->dst_addr;
+ }
+
+ if (width == DMA_SLAVE_BUSWIDTH_1_BYTE)
+ chan->dcmd |= DCMD_WIDTH1;
+ else if (width == DMA_SLAVE_BUSWIDTH_2_BYTES)
+ chan->dcmd |= DCMD_WIDTH2;
+ else if (width == DMA_SLAVE_BUSWIDTH_4_BYTES)
+ chan->dcmd |= DCMD_WIDTH4;
+
+ if (maxburst == 8)
+ chan->dcmd |= DCMD_BURST8;
+ else if (maxburst == 16)
+ chan->dcmd |= DCMD_BURST16;
+ else if (maxburst == 32)
+ chan->dcmd |= DCMD_BURST32;
+
+ if (cfg) {
+ chan->dir = cfg->direction;
+ chan->drcmr = cfg->slave_id;
+ }
+ chan->dev_addr = addr;
+ break;
+ default:
+ return -ENOSYS;
+ }
+
+ return ret;
+}
+
+static enum dma_status mmp_pdma_tx_status(struct dma_chan *dchan,
+ dma_cookie_t cookie, struct dma_tx_state *txstate)
+{
+ struct mmp_pdma_chan *chan = to_mmp_pdma_chan(dchan);
+ enum dma_status ret;
+ unsigned long flags;
+
+ spin_lock_irqsave(&chan->desc_lock, flags);
+ ret = dma_cookie_status(dchan, cookie, txstate);
+ spin_unlock_irqrestore(&chan->desc_lock, flags);
+
+ return ret;
+}
+
+/**
+ * mmp_pdma_issue_pending - Issue the DMA start command
+ * pending list ==> running list
+ */
+static void mmp_pdma_issue_pending(struct dma_chan *dchan)
+{
+ struct mmp_pdma_chan *chan = to_mmp_pdma_chan(dchan);
+ unsigned long flags;
+
+ spin_lock_irqsave(&chan->desc_lock, flags);
+ start_pending_queue(chan);
+ spin_unlock_irqrestore(&chan->desc_lock, flags);
+}
+
+/*
+ * dma_do_tasklet
+ * Do call back
+ * Start pending list
+ */
+static void dma_do_tasklet(unsigned long data)
+{
+ struct mmp_pdma_chan *chan = (struct mmp_pdma_chan *)data;
+ struct mmp_pdma_desc_sw *desc, *_desc;
+ LIST_HEAD(chain_cleanup);
+ unsigned long flags;
+
+ /* submit pending list; callback for each desc; free desc */
+
+ spin_lock_irqsave(&chan->desc_lock, flags);
+
+ /* update the cookie if we have some descriptors to cleanup */
+ if (!list_empty(&chan->chain_running)) {
+ dma_cookie_t cookie;
+
+ desc = to_mmp_pdma_desc(chan->chain_running.prev);
+ cookie = desc->async_tx.cookie;
+ dma_cookie_complete(&desc->async_tx);
+
+ dev_dbg(chan->dev, "completed_cookie=%d\n", cookie);
+ }
+
+ /*
+ * move the descriptors to a temporary list so we can drop the lock
+ * during the entire cleanup operation
+ */
+ list_splice_tail_init(&chan->chain_running, &chain_cleanup);
+
+ /* the hardware is now idle and ready for more */
+ chan->idle = true;
+
+ /* Start any pending transactions automatically */
+ start_pending_queue(chan);
+ spin_unlock_irqrestore(&chan->desc_lock, flags);
+
+ /* Run the callback for each descriptor, in order */
+ list_for_each_entry_safe(desc, _desc, &chain_cleanup, node) {
+ struct dma_async_tx_descriptor *txd = &desc->async_tx;
+
+ /* Remove from the list of transactions */
+ list_del(&desc->node);
+ /* Run the link descriptor callback function */
+ if (txd->callback)
+ txd->callback(txd->callback_param);
+
+ dma_pool_free(chan->desc_pool, desc, txd->phys);
+ }
+}
+
+static int __devexit mmp_pdma_remove(struct platform_device *op)
+{
+ struct mmp_pdma_device *pdev = platform_get_drvdata(op);
+
+ dma_async_device_unregister(&pdev->device);
+ return 0;
+}
+
+static int __devinit mmp_pdma_chan_init(struct mmp_pdma_device *pdev,
+ int idx, int irq)
+{
+ struct mmp_pdma_phy *phy = &pdev->phy[idx];
+ struct mmp_pdma_chan *chan;
+ int ret;
+
+ chan = devm_kzalloc(pdev->dev,
+ sizeof(struct mmp_pdma_chan), GFP_KERNEL);
+ if (chan == NULL)
+ return -ENOMEM;
+
+ phy->idx = idx;
+ phy->base = pdev->base;
+
+ if (irq) {
+ ret = devm_request_irq(pdev->dev, irq,
+ mmp_pdma_chan_handler, IRQF_DISABLED, "pdma", phy);
+ if (ret) {
+ dev_err(pdev->dev, "channel request irq fail!\n");
+ return ret;
+ }
+ }
+
+ spin_lock_init(&chan->desc_lock);
+ chan->dev = pdev->dev;
+ chan->chan.device = &pdev->device;
+ tasklet_init(&chan->tasklet, dma_do_tasklet, (unsigned long)chan);
+ INIT_LIST_HEAD(&chan->chain_pending);
+ INIT_LIST_HEAD(&chan->chain_running);
+
+ /* register virt channel to dma engine */
+ list_add_tail(&chan->chan.device_node,
+ &pdev->device.channels);
+
+ return 0;
+}
+
+static struct of_device_id mmp_pdma_dt_ids[] = {
+ { .compatible = "marvell,pdma-1.0", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, mmp_pdma_dt_ids);
+
+static int __devinit mmp_pdma_probe(struct platform_device *op)
+{
+ struct mmp_pdma_device *pdev;
+ const struct of_device_id *of_id;
+ struct mmp_dma_platdata *pdata = dev_get_platdata(&op->dev);
+ struct resource *iores;
+ int i, ret, irq = 0;
+ int dma_channels = 0, irq_num = 0;
+
+ pdev = devm_kzalloc(&op->dev, sizeof(*pdev), GFP_KERNEL);
+ if (!pdev)
+ return -ENOMEM;
+ pdev->dev = &op->dev;
+
+ iores = platform_get_resource(op, IORESOURCE_MEM, 0);
+ if (!iores)
+ return -EINVAL;
+
+ pdev->base = devm_request_and_ioremap(pdev->dev, iores);
+ if (!pdev->base)
+ return -EADDRNOTAVAIL;
+
+ of_id = of_match_device(mmp_pdma_dt_ids, pdev->dev);
+ if (of_id)
+ of_property_read_u32(pdev->dev->of_node,
+ "#dma-channels", &dma_channels);
+ else if (pdata && pdata->dma_channels)
+ dma_channels = pdata->dma_channels;
+ else
+ dma_channels = 32; /* default 32 channel */
+ pdev->dma_channels = dma_channels;
+
+ for (i = 0; i < dma_channels; i++) {
+ if (platform_get_irq(op, i) > 0)
+ irq_num++;
+ }
+
+ pdev->phy = devm_kzalloc(pdev->dev,
+ dma_channels * sizeof(struct mmp_pdma_chan), GFP_KERNEL);
+ if (pdev->phy == NULL)
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(&pdev->device.channels);
+
+ if (irq_num != dma_channels) {
+ /* all chan share one irq, demux inside */
+ irq = platform_get_irq(op, 0);
+ ret = devm_request_irq(pdev->dev, irq,
+ mmp_pdma_int_handler, IRQF_DISABLED, "pdma", pdev);
+ if (ret)
+ return ret;
+ }
+
+ for (i = 0; i < dma_channels; i++) {
+ irq = (irq_num != dma_channels) ? 0 : platform_get_irq(op, i);
+ ret = mmp_pdma_chan_init(pdev, i, irq);
+ if (ret)
+ return ret;
+ }
+
+ dma_cap_set(DMA_SLAVE, pdev->device.cap_mask);
+ dma_cap_set(DMA_MEMCPY, pdev->device.cap_mask);
+ dma_cap_set(DMA_SLAVE, pdev->device.cap_mask);
+ pdev->device.dev = &op->dev;
+ pdev->device.device_alloc_chan_resources = mmp_pdma_alloc_chan_resources;
+ pdev->device.device_free_chan_resources = mmp_pdma_free_chan_resources;
+ pdev->device.device_tx_status = mmp_pdma_tx_status;
+ pdev->device.device_prep_dma_memcpy = mmp_pdma_prep_memcpy;
+ pdev->device.device_prep_slave_sg = mmp_pdma_prep_slave_sg;
+ pdev->device.device_issue_pending = mmp_pdma_issue_pending;
+ pdev->device.device_control = mmp_pdma_control;
+ pdev->device.copy_align = PDMA_ALIGNMENT;
+
+ if (pdev->dev->coherent_dma_mask)
+ dma_set_mask(pdev->dev, pdev->dev->coherent_dma_mask);
+ else
+ dma_set_mask(pdev->dev, DMA_BIT_MASK(64));
+
+ ret = dma_async_device_register(&pdev->device);
+ if (ret) {
+ dev_err(pdev->device.dev, "unable to register\n");
+ return ret;
+ }
+
+ dev_info(pdev->device.dev, "initialized\n");
+ return 0;
+}
+
+static const struct platform_device_id mmp_pdma_id_table[] = {
+ { "mmp-pdma", },
+ { },
+};
+
+static struct platform_driver mmp_pdma_driver = {
+ .driver = {
+ .name = "mmp-pdma",
+ .owner = THIS_MODULE,
+ .of_match_table = mmp_pdma_dt_ids,
+ },
+ .id_table = mmp_pdma_id_table,
+ .probe = mmp_pdma_probe,
+ .remove = __devexit_p(mmp_pdma_remove),
+};
+
+module_platform_driver(mmp_pdma_driver);
+
+MODULE_DESCRIPTION("MARVELL MMP Periphera DMA Driver");
+MODULE_AUTHOR("Marvell International Ltd.");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/dma/mmp_tdma.c b/drivers/dma/mmp_tdma.c
index 6d9c82e..f3e8d71 100644
--- a/drivers/dma/mmp_tdma.c
+++ b/drivers/dma/mmp_tdma.c
@@ -20,6 +20,7 @@
#include <linux/device.h>
#include <mach/regs-icu.h>
#include <linux/platform_data/dma-mmp_tdma.h>
+#include <linux/of_device.h>
#include "dmaengine.h"
@@ -127,7 +128,6 @@ struct mmp_tdma_device {
void __iomem *base;
struct dma_device device;
struct mmp_tdma_chan *tdmac[TDMA_CHANNEL_NUM];
- int irq;
};
#define to_mmp_tdma_chan(dchan) container_of(dchan, struct mmp_tdma_chan, chan)
@@ -492,7 +492,7 @@ static int __devinit mmp_tdma_chan_init(struct mmp_tdma_device *tdev,
return -ENOMEM;
}
if (irq)
- tdmac->irq = irq + idx;
+ tdmac->irq = irq;
tdmac->dev = tdev->dev;
tdmac->chan.device = &tdev->device;
tdmac->idx = idx;
@@ -505,34 +505,43 @@ static int __devinit mmp_tdma_chan_init(struct mmp_tdma_device *tdev,
/* add the channel to tdma_chan list */
list_add_tail(&tdmac->chan.device_node,
&tdev->device.channels);
-
return 0;
}
+static struct of_device_id mmp_tdma_dt_ids[] = {
+ { .compatible = "marvell,adma-1.0", .data = (void *)MMP_AUD_TDMA},
+ { .compatible = "marvell,pxa910-squ", .data = (void *)PXA910_SQU},
+ {}
+};
+MODULE_DEVICE_TABLE(of, mmp_tdma_dt_ids);
+
static int __devinit mmp_tdma_probe(struct platform_device *pdev)
{
- const struct platform_device_id *id = platform_get_device_id(pdev);
- enum mmp_tdma_type type = id->driver_data;
+ enum mmp_tdma_type type;
+ const struct of_device_id *of_id;
struct mmp_tdma_device *tdev;
struct resource *iores;
int i, ret;
- int irq = 0;
+ int irq = 0, irq_num = 0;
int chan_num = TDMA_CHANNEL_NUM;
+ of_id = of_match_device(mmp_tdma_dt_ids, &pdev->dev);
+ if (of_id)
+ type = (enum mmp_tdma_type) of_id->data;
+ else
+ type = platform_get_device_id(pdev)->driver_data;
+
/* always have couple channels */
tdev = devm_kzalloc(&pdev->dev, sizeof(*tdev), GFP_KERNEL);
if (!tdev)
return -ENOMEM;
tdev->dev = &pdev->dev;
- iores = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
- if (!iores)
- return -EINVAL;
- if (resource_size(iores) != chan_num)
- tdev->irq = iores->start;
- else
- irq = iores->start;
+ for (i = 0; i < chan_num; i++) {
+ if (platform_get_irq(pdev, i) > 0)
+ irq_num++;
+ }
iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!iores)
@@ -542,25 +551,26 @@ static int __devinit mmp_tdma_probe(struct platform_device *pdev)
if (!tdev->base)
return -EADDRNOTAVAIL;
- if (tdev->irq) {
- ret = devm_request_irq(&pdev->dev, tdev->irq,
+ INIT_LIST_HEAD(&tdev->device.channels);
+
+ if (irq_num != chan_num) {
+ irq = platform_get_irq(pdev, 0);
+ ret = devm_request_irq(&pdev->dev, irq,
mmp_tdma_int_handler, IRQF_DISABLED, "tdma", tdev);
if (ret)
return ret;
}
- dma_cap_set(DMA_SLAVE, tdev->device.cap_mask);
- dma_cap_set(DMA_CYCLIC, tdev->device.cap_mask);
-
- INIT_LIST_HEAD(&tdev->device.channels);
-
/* initialize channel parameters */
for (i = 0; i < chan_num; i++) {
+ irq = (irq_num != chan_num) ? 0 : platform_get_irq(pdev, i);
ret = mmp_tdma_chan_init(tdev, i, irq, type);
if (ret)
return ret;
}
+ dma_cap_set(DMA_SLAVE, tdev->device.cap_mask);
+ dma_cap_set(DMA_CYCLIC, tdev->device.cap_mask);
tdev->device.dev = &pdev->dev;
tdev->device.device_alloc_chan_resources =
mmp_tdma_alloc_chan_resources;
@@ -595,6 +605,7 @@ static struct platform_driver mmp_tdma_driver = {
.driver = {
.name = "mmp-tdma",
.owner = THIS_MODULE,
+ .of_match_table = mmp_tdma_dt_ids,
},
.id_table = mmp_tdma_id_table,
.probe = mmp_tdma_probe,
diff --git a/drivers/dma/mxs-dma.c b/drivers/dma/mxs-dma.c
index 734a4eb..9f02e79 100644
--- a/drivers/dma/mxs-dma.c
+++ b/drivers/dma/mxs-dma.c
@@ -101,7 +101,8 @@ struct mxs_dma_ccw {
u32 pio_words[MXS_PIO_WORDS];
};
-#define NUM_CCW (int)(PAGE_SIZE / sizeof(struct mxs_dma_ccw))
+#define CCW_BLOCK_SIZE (4 * PAGE_SIZE)
+#define NUM_CCW (int)(CCW_BLOCK_SIZE / sizeof(struct mxs_dma_ccw))
struct mxs_dma_chan {
struct mxs_dma_engine *mxs_dma;
@@ -354,14 +355,15 @@ static int mxs_dma_alloc_chan_resources(struct dma_chan *chan)
mxs_chan->chan_irq = data->chan_irq;
- mxs_chan->ccw = dma_alloc_coherent(mxs_dma->dma_device.dev, PAGE_SIZE,
- &mxs_chan->ccw_phys, GFP_KERNEL);
+ mxs_chan->ccw = dma_alloc_coherent(mxs_dma->dma_device.dev,
+ CCW_BLOCK_SIZE, &mxs_chan->ccw_phys,
+ GFP_KERNEL);
if (!mxs_chan->ccw) {
ret = -ENOMEM;
goto err_alloc;
}
- memset(mxs_chan->ccw, 0, PAGE_SIZE);
+ memset(mxs_chan->ccw, 0, CCW_BLOCK_SIZE);
if (mxs_chan->chan_irq != NO_IRQ) {
ret = request_irq(mxs_chan->chan_irq, mxs_dma_int_handler,
@@ -387,7 +389,7 @@ static int mxs_dma_alloc_chan_resources(struct dma_chan *chan)
err_clk:
free_irq(mxs_chan->chan_irq, mxs_dma);
err_irq:
- dma_free_coherent(mxs_dma->dma_device.dev, PAGE_SIZE,
+ dma_free_coherent(mxs_dma->dma_device.dev, CCW_BLOCK_SIZE,
mxs_chan->ccw, mxs_chan->ccw_phys);
err_alloc:
return ret;
@@ -402,7 +404,7 @@ static void mxs_dma_free_chan_resources(struct dma_chan *chan)
free_irq(mxs_chan->chan_irq, mxs_dma);
- dma_free_coherent(mxs_dma->dma_device.dev, PAGE_SIZE,
+ dma_free_coherent(mxs_dma->dma_device.dev, CCW_BLOCK_SIZE,
mxs_chan->ccw, mxs_chan->ccw_phys);
clk_disable_unprepare(mxs_dma->clk);
diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c
index 169c0db..665668b 100644
--- a/drivers/dma/pl330.c
+++ b/drivers/dma/pl330.c
@@ -23,7 +23,6 @@
#include <linux/dmaengine.h>
#include <linux/amba/bus.h>
#include <linux/amba/pl330.h>
-#include <linux/pm_runtime.h>
#include <linux/scatterlist.h>
#include <linux/of.h>
@@ -586,8 +585,6 @@ struct dma_pl330_dmac {
/* Peripheral channels connected to this DMAC */
struct dma_pl330_chan *peripherals; /* keep at end */
-
- struct clk *clk;
};
struct dma_pl330_desc {
@@ -2395,7 +2392,7 @@ static int pl330_alloc_chan_resources(struct dma_chan *chan)
pch->pl330_chid = pl330_request_channel(&pdmac->pif);
if (!pch->pl330_chid) {
spin_unlock_irqrestore(&pch->lock, flags);
- return 0;
+ return -ENOMEM;
}
tasklet_init(&pch->task, pl330_tasklet, (unsigned long) pch);
@@ -2889,29 +2886,17 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id)
goto probe_err1;
}
- pdmac->clk = clk_get(&adev->dev, "dma");
- if (IS_ERR(pdmac->clk)) {
- dev_err(&adev->dev, "Cannot get operation clock.\n");
- ret = -EINVAL;
- goto probe_err2;
- }
-
amba_set_drvdata(adev, pdmac);
-#ifndef CONFIG_PM_RUNTIME
- /* enable dma clk */
- clk_enable(pdmac->clk);
-#endif
-
irq = adev->irq[0];
ret = request_irq(irq, pl330_irq_handler, 0,
dev_name(&adev->dev), pi);
if (ret)
- goto probe_err3;
+ goto probe_err2;
ret = pl330_add(pi);
if (ret)
- goto probe_err4;
+ goto probe_err3;
INIT_LIST_HEAD(&pdmac->desc_pool);
spin_lock_init(&pdmac->pool_lock);
@@ -2933,7 +2918,7 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id)
if (!pdmac->peripherals) {
ret = -ENOMEM;
dev_err(&adev->dev, "unable to allocate pdmac->peripherals\n");
- goto probe_err5;
+ goto probe_err4;
}
for (i = 0; i < num_chan; i++) {
@@ -2961,6 +2946,7 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id)
if (pi->pcfg.num_peri) {
dma_cap_set(DMA_SLAVE, pd->cap_mask);
dma_cap_set(DMA_CYCLIC, pd->cap_mask);
+ dma_cap_set(DMA_PRIVATE, pd->cap_mask);
}
}
@@ -2976,7 +2962,7 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id)
ret = dma_async_device_register(pd);
if (ret) {
dev_err(&adev->dev, "unable to register DMAC\n");
- goto probe_err5;
+ goto probe_err4;
}
dev_info(&adev->dev,
@@ -2989,15 +2975,10 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id)
return 0;
-probe_err5:
- pl330_del(pi);
probe_err4:
- free_irq(irq, pi);
+ pl330_del(pi);
probe_err3:
-#ifndef CONFIG_PM_RUNTIME
- clk_disable(pdmac->clk);
-#endif
- clk_put(pdmac->clk);
+ free_irq(irq, pi);
probe_err2:
iounmap(pi->base);
probe_err1:
@@ -3044,10 +3025,6 @@ static int __devexit pl330_remove(struct amba_device *adev)
res = &adev->res;
release_mem_region(res->start, resource_size(res));
-#ifndef CONFIG_PM_RUNTIME
- clk_disable(pdmac->clk);
-#endif
-
kfree(pdmac);
return 0;
@@ -3063,49 +3040,10 @@ static struct amba_id pl330_ids[] = {
MODULE_DEVICE_TABLE(amba, pl330_ids);
-#ifdef CONFIG_PM_RUNTIME
-static int pl330_runtime_suspend(struct device *dev)
-{
- struct dma_pl330_dmac *pdmac = dev_get_drvdata(dev);
-
- if (!pdmac) {
- dev_err(dev, "failed to get dmac\n");
- return -ENODEV;
- }
-
- clk_disable(pdmac->clk);
-
- return 0;
-}
-
-static int pl330_runtime_resume(struct device *dev)
-{
- struct dma_pl330_dmac *pdmac = dev_get_drvdata(dev);
-
- if (!pdmac) {
- dev_err(dev, "failed to get dmac\n");
- return -ENODEV;
- }
-
- clk_enable(pdmac->clk);
-
- return 0;
-}
-#else
-#define pl330_runtime_suspend NULL
-#define pl330_runtime_resume NULL
-#endif /* CONFIG_PM_RUNTIME */
-
-static const struct dev_pm_ops pl330_pm_ops = {
- .runtime_suspend = pl330_runtime_suspend,
- .runtime_resume = pl330_runtime_resume,
-};
-
static struct amba_driver pl330_driver = {
.drv = {
.owner = THIS_MODULE,
.name = "dma-pl330",
- .pm = &pl330_pm_ops,
},
.id_table = pl330_ids,
.probe = pl330_probe,
diff --git a/drivers/dma/sirf-dma.c b/drivers/dma/sirf-dma.c
index 3eed8b3..64385cd 100644
--- a/drivers/dma/sirf-dma.c
+++ b/drivers/dma/sirf-dma.c
@@ -570,21 +570,19 @@ static int __devinit sirfsoc_dma_probe(struct platform_device *op)
if (of_property_read_u32(dn, "cell-index", &id)) {
dev_err(dev, "Fail to get DMAC index\n");
- ret = -ENODEV;
- goto free_mem;
+ return -ENODEV;
}
sdma->irq = irq_of_parse_and_map(dn, 0);
if (sdma->irq == NO_IRQ) {
dev_err(dev, "Error mapping IRQ!\n");
- ret = -EINVAL;
- goto free_mem;
+ return -EINVAL;
}
ret = of_address_to_resource(dn, 0, &res);
if (ret) {
dev_err(dev, "Error parsing memory region!\n");
- goto free_mem;
+ goto irq_dispose;
}
regs_start = res.start;
@@ -597,12 +595,11 @@ static int __devinit sirfsoc_dma_probe(struct platform_device *op)
goto irq_dispose;
}
- ret = devm_request_irq(dev, sdma->irq, &sirfsoc_dma_irq, 0, DRV_NAME,
- sdma);
+ ret = request_irq(sdma->irq, &sirfsoc_dma_irq, 0, DRV_NAME, sdma);
if (ret) {
dev_err(dev, "Error requesting IRQ!\n");
ret = -EINVAL;
- goto unmap_mem;
+ goto irq_dispose;
}
dma = &sdma->dma;
@@ -652,13 +649,9 @@ static int __devinit sirfsoc_dma_probe(struct platform_device *op)
return 0;
free_irq:
- devm_free_irq(dev, sdma->irq, sdma);
+ free_irq(sdma->irq, sdma);
irq_dispose:
irq_dispose_mapping(sdma->irq);
-unmap_mem:
- iounmap(sdma->base);
-free_mem:
- devm_kfree(dev, sdma);
return ret;
}
@@ -668,10 +661,8 @@ static int __devexit sirfsoc_dma_remove(struct platform_device *op)
struct sirfsoc_dma *sdma = dev_get_drvdata(dev);
dma_async_device_unregister(&sdma->dma);
- devm_free_irq(dev, sdma->irq, sdma);
+ free_irq(sdma->irq, sdma);
irq_dispose_mapping(sdma->irq);
- iounmap(sdma->base);
- devm_kfree(dev, sdma);
return 0;
}
diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c
index eee8d9b..ae55091 100644
--- a/drivers/dma/ste_dma40.c
+++ b/drivers/dma/ste_dma40.c
@@ -2921,19 +2921,23 @@ static struct d40_base * __init d40_hw_detect_init(struct platform_device *pdev)
struct d40_base *base = NULL;
int num_log_chans = 0;
int num_phy_chans;
+ int clk_ret = -EINVAL;
int i;
u32 pid;
u32 cid;
u8 rev;
clk = clk_get(&pdev->dev, NULL);
-
if (IS_ERR(clk)) {
d40_err(&pdev->dev, "No matching clock found\n");
goto failure;
}
- clk_enable(clk);
+ clk_ret = clk_prepare_enable(clk);
+ if (clk_ret) {
+ d40_err(&pdev->dev, "Failed to prepare/enable clock\n");
+ goto failure;
+ }
/* Get IO for DMAC base address */
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "base");
@@ -3063,10 +3067,10 @@ static struct d40_base * __init d40_hw_detect_init(struct platform_device *pdev)
return base;
failure:
- if (!IS_ERR(clk)) {
- clk_disable(clk);
+ if (!clk_ret)
+ clk_disable_unprepare(clk);
+ if (!IS_ERR(clk))
clk_put(clk);
- }
if (virtbase)
iounmap(virtbase);
if (res)
diff --git a/drivers/dma/tegra20-apb-dma.c b/drivers/dma/tegra20-apb-dma.c
index 45fbeed..528c62d 100644
--- a/drivers/dma/tegra20-apb-dma.c
+++ b/drivers/dma/tegra20-apb-dma.c
@@ -169,6 +169,7 @@ typedef void (*dma_isr_handler)(struct tegra_dma_channel *tdc,
/* tegra_dma_channel: Channel specific information */
struct tegra_dma_channel {
struct dma_chan dma_chan;
+ char name[30];
bool config_init;
int id;
int irq;
@@ -475,8 +476,7 @@ static void tegra_dma_abort_all(struct tegra_dma_channel *tdc)
while (!list_empty(&tdc->pending_sg_req)) {
sgreq = list_first_entry(&tdc->pending_sg_req,
typeof(*sgreq), node);
- list_del(&sgreq->node);
- list_add_tail(&sgreq->node, &tdc->free_sg_req);
+ list_move_tail(&sgreq->node, &tdc->free_sg_req);
if (sgreq->last_sg) {
dma_desc = sgreq->dma_desc;
dma_desc->dma_status = DMA_ERROR;
@@ -570,8 +570,7 @@ static void handle_cont_sngl_cycle_dma_done(struct tegra_dma_channel *tdc,
/* If not last req then put at end of pending list */
if (!list_is_last(&sgreq->node, &tdc->pending_sg_req)) {
- list_del(&sgreq->node);
- list_add_tail(&sgreq->node, &tdc->pending_sg_req);
+ list_move_tail(&sgreq->node, &tdc->pending_sg_req);
sgreq->configured = false;
st = handle_continuous_head_request(tdc, sgreq, to_terminate);
if (!st)
@@ -1284,7 +1283,6 @@ static int __devinit tegra_dma_probe(struct platform_device *pdev)
INIT_LIST_HEAD(&tdma->dma_dev.channels);
for (i = 0; i < cdata->nr_channels; i++) {
struct tegra_dma_channel *tdc = &tdma->channels[i];
- char irq_name[30];
tdc->chan_base_offset = TEGRA_APBDMA_CHANNEL_BASE_ADD_OFFSET +
i * TEGRA_APBDMA_CHANNEL_REGISTER_SIZE;
@@ -1296,9 +1294,9 @@ static int __devinit tegra_dma_probe(struct platform_device *pdev)
goto err_irq;
}
tdc->irq = res->start;
- snprintf(irq_name, sizeof(irq_name), "apbdma.%d", i);
+ snprintf(tdc->name, sizeof(tdc->name), "apbdma.%d", i);
ret = devm_request_irq(&pdev->dev, tdc->irq,
- tegra_dma_isr, 0, irq_name, tdc);
+ tegra_dma_isr, 0, tdc->name, tdc);
if (ret) {
dev_err(&pdev->dev,
"request_irq failed with err %d channel %d\n",
diff --git a/drivers/firewire/core-cdev.c b/drivers/firewire/core-cdev.c
index 2783f69..f8d2287 100644
--- a/drivers/firewire/core-cdev.c
+++ b/drivers/firewire/core-cdev.c
@@ -473,8 +473,8 @@ static int ioctl_get_info(struct client *client, union ioctl_arg *arg)
client->bus_reset_closure = a->bus_reset_closure;
if (a->bus_reset != 0) {
fill_bus_reset_event(&bus_reset, client);
- ret = copy_to_user(u64_to_uptr(a->bus_reset),
- &bus_reset, sizeof(bus_reset));
+ /* unaligned size of bus_reset is 36 bytes */
+ ret = copy_to_user(u64_to_uptr(a->bus_reset), &bus_reset, 36);
}
if (ret == 0 && list_empty(&client->link))
list_add_tail(&client->link, &client->device->client_list);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
index a328379..130a2b5 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
@@ -19,8 +19,8 @@
#include <linux/clk.h>
#include <linux/pm_runtime.h>
+#include <video/samsung_fimd.h>
#include <drm/exynos_drm.h>
-#include <plat/regs-fb-v4.h>
#include "exynos_drm_drv.h"
#include "exynos_drm_fbdev.h"
diff --git a/drivers/gpu/drm/nouveau/core/core/parent.c b/drivers/gpu/drm/nouveau/core/core/parent.c
index a1ea034..db7c549 100644
--- a/drivers/gpu/drm/nouveau/core/core/parent.c
+++ b/drivers/gpu/drm/nouveau/core/core/parent.c
@@ -101,23 +101,6 @@ nouveau_parent_create_(struct nouveau_object *parent,
return 0;
}
-int
-_nouveau_parent_ctor(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nouveau_parent *object;
- int ret;
-
- ret = nouveau_parent_create(parent, engine, oclass, 0, NULL, 0, &object);
- *pobject = nv_object(object);
- if (ret)
- return ret;
-
- return 0;
-}
-
void
nouveau_parent_destroy(struct nouveau_parent *parent)
{
diff --git a/drivers/gpu/drm/nouveau/core/include/core/parent.h b/drivers/gpu/drm/nouveau/core/include/core/parent.h
index d3aa251..3c2e940 100644
--- a/drivers/gpu/drm/nouveau/core/include/core/parent.h
+++ b/drivers/gpu/drm/nouveau/core/include/core/parent.h
@@ -50,9 +50,6 @@ int nouveau_parent_create_(struct nouveau_object *, struct nouveau_object *,
int size, void **);
void nouveau_parent_destroy(struct nouveau_parent *);
-int _nouveau_parent_ctor(struct nouveau_object *, struct nouveau_object *,
- struct nouveau_oclass *, void *, u32,
- struct nouveau_object **);
void _nouveau_parent_dtor(struct nouveau_object *);
#define _nouveau_parent_init _nouveau_object_init
#define _nouveau_parent_fini _nouveau_object_fini
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/timer.h b/drivers/gpu/drm/nouveau/core/include/subdev/timer.h
index 49bff90..c24ec8a 100644
--- a/drivers/gpu/drm/nouveau/core/include/subdev/timer.h
+++ b/drivers/gpu/drm/nouveau/core/include/subdev/timer.h
@@ -26,7 +26,7 @@ void nouveau_timer_alarm(void *, u32 nsec, struct nouveau_alarm *);
struct nouveau_timer {
struct nouveau_subdev base;
u64 (*read)(struct nouveau_timer *);
- void (*alarm)(struct nouveau_timer *, u32 time, struct nouveau_alarm *);
+ void (*alarm)(struct nouveau_timer *, u64 time, struct nouveau_alarm *);
};
static inline struct nouveau_timer *
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/base.c b/drivers/gpu/drm/nouveau/core/subdev/bios/base.c
index 2fbb6df..dcb5c2b 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/bios/base.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/bios/base.c
@@ -185,23 +185,22 @@ static void
nouveau_bios_shadow_acpi(struct nouveau_bios *bios)
{
struct pci_dev *pdev = nv_device(bios)->pdev;
- int cnt = 65536 / 4096;
- int ret;
+ int ret, cnt, i;
+ u8 data[3];
if (!nouveau_acpi_rom_supported(pdev))
return;
- bios->data = kmalloc(65536, GFP_KERNEL);
bios->size = 0;
- if (!bios->data)
- return;
-
- while (cnt--) {
- ret = nouveau_acpi_get_bios_chunk(bios->data, bios->size, 4096);
- if (ret != 4096)
- return;
+ if (nouveau_acpi_get_bios_chunk(data, 0, 3) == 3)
+ bios->size = data[2] * 512;
- bios->size += 4096;
+ bios->data = kmalloc(bios->size, GFP_KERNEL);
+ for (i = 0; bios->data && i < bios->size; i += cnt) {
+ cnt = min((bios->size - i), (u32)4096);
+ ret = nouveau_acpi_get_bios_chunk(bios->data, i, cnt);
+ if (ret != cnt)
+ break;
}
}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/clock/nv50.c
index fd181fb..f4147f6 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/clock/nv50.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/clock/nv50.c
@@ -90,6 +90,7 @@ nv50_clock_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
return ret;
priv->base.pll_set = nv50_clock_pll_set;
+ priv->base.pll_calc = nv04_clock_pll_calc;
return 0;
}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/therm/nv50.c
index f87a7a3..9360ddd 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/therm/nv50.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/therm/nv50.c
@@ -92,7 +92,7 @@ nv50_fan_pwm_clock(struct nouveau_therm *therm)
if (nv_rd32(therm, 0xc040) & 0x800000) {
/* Use the HOST clock (100 MHz)
* Where does this constant(2.4) comes from? */
- pwm_clock = (100000000 >> pwm_div) / 10 / 24;
+ pwm_clock = (100000000 >> pwm_div) * 10 / 24;
} else {
/* Where does this constant(20) comes from? */
pwm_clock = (crystal * 1000) >> pwm_div;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/timer/nv04.c b/drivers/gpu/drm/nouveau/core/subdev/timer/nv04.c
index 49976be..c26ca9b 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/timer/nv04.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/timer/nv04.c
@@ -85,7 +85,7 @@ nv04_timer_alarm_trigger(struct nouveau_timer *ptimer)
}
static void
-nv04_timer_alarm(struct nouveau_timer *ptimer, u32 time,
+nv04_timer_alarm(struct nouveau_timer *ptimer, u64 time,
struct nouveau_alarm *alarm)
{
struct nv04_timer_priv *priv = (void *)ptimer;
diff --git a/drivers/hwmon/acpi_power_meter.c b/drivers/hwmon/acpi_power_meter.c
index 23ab3c4..1672e2a 100644
--- a/drivers/hwmon/acpi_power_meter.c
+++ b/drivers/hwmon/acpi_power_meter.c
@@ -29,6 +29,7 @@
#include <linux/kdev_t.h>
#include <linux/sched.h>
#include <linux/time.h>
+#include <linux/err.h>
#include <acpi/acpi_drivers.h>
#include <acpi/acpi_bus.h>
diff --git a/drivers/hwmon/adm9240.c b/drivers/hwmon/adm9240.c
index 8b24d1a..dafa477 100644
--- a/drivers/hwmon/adm9240.c
+++ b/drivers/hwmon/adm9240.c
@@ -50,6 +50,7 @@
#include <linux/hwmon-vid.h>
#include <linux/err.h>
#include <linux/mutex.h>
+#include <linux/jiffies.h>
/* Addresses to scan */
static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, 0x2f,
diff --git a/drivers/hwmon/adt7411.c b/drivers/hwmon/adt7411.c
index fe72c69..517f185 100644
--- a/drivers/hwmon/adt7411.c
+++ b/drivers/hwmon/adt7411.c
@@ -15,7 +15,6 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/err.h>
-#include <linux/delay.h>
#include <linux/mutex.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
diff --git a/drivers/hwmon/adt7462.c b/drivers/hwmon/adt7462.c
index baee482..98a7d81 100644
--- a/drivers/hwmon/adt7462.c
+++ b/drivers/hwmon/adt7462.c
@@ -26,7 +26,6 @@
#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
#include <linux/mutex.h>
-#include <linux/delay.h>
#include <linux/log2.h>
#include <linux/slab.h>
diff --git a/drivers/hwmon/adt7475.c b/drivers/hwmon/adt7475.c
index 861c756..989e54c 100644
--- a/drivers/hwmon/adt7475.c
+++ b/drivers/hwmon/adt7475.c
@@ -20,6 +20,7 @@
#include <linux/hwmon-sysfs.h>
#include <linux/hwmon-vid.h>
#include <linux/err.h>
+#include <linux/jiffies.h>
/* Indexes for the sysfs hooks */
diff --git a/drivers/hwmon/applesmc.c b/drivers/hwmon/applesmc.c
index 8f3f6f2..b41baff 100644
--- a/drivers/hwmon/applesmc.c
+++ b/drivers/hwmon/applesmc.c
@@ -43,6 +43,7 @@
#include <linux/leds.h>
#include <linux/hwmon.h>
#include <linux/workqueue.h>
+#include <linux/err.h>
/* data port used by Apple SMC */
#define APPLESMC_DATA_PORT 0x300
diff --git a/drivers/hwmon/asus_atk0110.c b/drivers/hwmon/asus_atk0110.c
index cccb0e9..56dbcfb 100644
--- a/drivers/hwmon/asus_atk0110.c
+++ b/drivers/hwmon/asus_atk0110.c
@@ -14,6 +14,8 @@
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/dmi.h>
+#include <linux/jiffies.h>
+#include <linux/err.h>
#include <acpi/acpi.h>
#include <acpi/acpixf.h>
diff --git a/drivers/hwmon/da9052-hwmon.c b/drivers/hwmon/da9052-hwmon.c
index fc65f2d..b8d01c5 100644
--- a/drivers/hwmon/da9052-hwmon.c
+++ b/drivers/hwmon/da9052-hwmon.c
@@ -12,7 +12,6 @@
*
*/
-#include <linux/delay.h>
#include <linux/err.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
diff --git a/drivers/hwmon/emc1403.c b/drivers/hwmon/emc1403.c
index 68ab94b..142e1cb 100644
--- a/drivers/hwmon/emc1403.c
+++ b/drivers/hwmon/emc1403.c
@@ -33,6 +33,7 @@
#include <linux/err.h>
#include <linux/sysfs.h>
#include <linux/mutex.h>
+#include <linux/jiffies.h>
#define THERMAL_PID_REG 0xfd
#define THERMAL_SMSC_ID_REG 0xfe
diff --git a/drivers/hwmon/emc6w201.c b/drivers/hwmon/emc6w201.c
index ada12a9..a98c917 100644
--- a/drivers/hwmon/emc6w201.c
+++ b/drivers/hwmon/emc6w201.c
@@ -18,7 +18,6 @@
*/
#include <linux/module.h>
-#include <linux/delay.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/jiffies.h>
diff --git a/drivers/hwmon/hih6130.c b/drivers/hwmon/hih6130.c
index e8ee75f..9a675ef 100644
--- a/drivers/hwmon/hih6130.c
+++ b/drivers/hwmon/hih6130.c
@@ -33,6 +33,7 @@
#include <linux/mutex.h>
#include <linux/device.h>
#include <linux/delay.h>
+#include <linux/jiffies.h>
/**
* struct hih6130 - HIH-6130 device specific data
diff --git a/drivers/hwmon/i5k_amb.c b/drivers/hwmon/i5k_amb.c
index a18882c..46141ab 100644
--- a/drivers/hwmon/i5k_amb.c
+++ b/drivers/hwmon/i5k_amb.c
@@ -21,12 +21,10 @@
*/
#include <linux/module.h>
-#include <linux/jiffies.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
#include <linux/mutex.h>
-#include <linux/delay.h>
#include <linux/log2.h>
#include <linux/pci.h>
#include <linux/platform_device.h>
diff --git a/drivers/hwmon/ibmaem.c b/drivers/hwmon/ibmaem.c
index 37f17e0..a14f634 100644
--- a/drivers/hwmon/ibmaem.c
+++ b/drivers/hwmon/ibmaem.c
@@ -36,6 +36,7 @@
#include <linux/platform_device.h>
#include <linux/math64.h>
#include <linux/time.h>
+#include <linux/err.h>
#define REFRESH_INTERVAL (HZ)
#define IPMI_TIMEOUT (30 * HZ)
diff --git a/drivers/hwmon/ibmpex.c b/drivers/hwmon/ibmpex.c
index 41dbf81..b622a93 100644
--- a/drivers/hwmon/ibmpex.c
+++ b/drivers/hwmon/ibmpex.c
@@ -26,6 +26,7 @@
#include <linux/jiffies.h>
#include <linux/mutex.h>
#include <linux/slab.h>
+#include <linux/err.h>
#define REFRESH_INTERVAL (2 * HZ)
#define DRVNAME "ibmpex"
diff --git a/drivers/hwmon/ina2xx.c b/drivers/hwmon/ina2xx.c
index 70717d4..2b72634 100644
--- a/drivers/hwmon/ina2xx.c
+++ b/drivers/hwmon/ina2xx.c
@@ -33,6 +33,7 @@
#include <linux/i2c.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
+#include <linux/jiffies.h>
#include <linux/platform_data/ina2xx.h>
diff --git a/drivers/hwmon/k8temp.c b/drivers/hwmon/k8temp.c
index 49a69c5..e8c7fb0 100644
--- a/drivers/hwmon/k8temp.c
+++ b/drivers/hwmon/k8temp.c
@@ -22,7 +22,6 @@
*/
#include <linux/module.h>
-#include <linux/delay.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/jiffies.h>
diff --git a/drivers/hwmon/lineage-pem.c b/drivers/hwmon/lineage-pem.c
index bd75d24..41df29f 100644
--- a/drivers/hwmon/lineage-pem.c
+++ b/drivers/hwmon/lineage-pem.c
@@ -29,6 +29,7 @@
#include <linux/i2c.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
+#include <linux/jiffies.h>
/*
* This driver supports various Lineage Compact Power Line DC/DC and AC/DC
diff --git a/drivers/hwmon/lm92.c b/drivers/hwmon/lm92.c
index 2282d77..71626f3 100644
--- a/drivers/hwmon/lm92.c
+++ b/drivers/hwmon/lm92.c
@@ -48,6 +48,7 @@
#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
#include <linux/mutex.h>
+#include <linux/jiffies.h>
/*
* The LM92 and MAX6635 have 2 two-state pins for address selection,
diff --git a/drivers/hwmon/lm93.c b/drivers/hwmon/lm93.c
index c3d4255..1a003f7 100644
--- a/drivers/hwmon/lm93.c
+++ b/drivers/hwmon/lm93.c
@@ -47,6 +47,7 @@
#include <linux/hwmon-vid.h>
#include <linux/err.h>
#include <linux/delay.h>
+#include <linux/jiffies.h>
/* LM93 REGISTER ADDRESSES */
diff --git a/drivers/hwmon/ltc4151.c b/drivers/hwmon/ltc4151.c
index 8496baa..4319a94 100644
--- a/drivers/hwmon/ltc4151.c
+++ b/drivers/hwmon/ltc4151.c
@@ -36,6 +36,7 @@
#include <linux/i2c.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
+#include <linux/jiffies.h>
/* chip registers */
#define LTC4151_SENSE_H 0x00
diff --git a/drivers/hwmon/ltc4215.c b/drivers/hwmon/ltc4215.c
index 98b3d04f..e887610 100644
--- a/drivers/hwmon/ltc4215.c
+++ b/drivers/hwmon/ltc4215.c
@@ -19,6 +19,7 @@
#include <linux/i2c.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
+#include <linux/jiffies.h>
/* Here are names of the chip's registers (a.k.a. commands) */
enum ltc4215_cmd {
diff --git a/drivers/hwmon/ltc4245.c b/drivers/hwmon/ltc4245.c
index 52075914..3653f79 100644
--- a/drivers/hwmon/ltc4245.c
+++ b/drivers/hwmon/ltc4245.c
@@ -21,6 +21,7 @@
#include <linux/i2c.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
+#include <linux/jiffies.h>
#include <linux/i2c/ltc4245.h>
/* Here are names of the chip's registers (a.k.a. commands) */
diff --git a/drivers/hwmon/ltc4261.c b/drivers/hwmon/ltc4261.c
index 77476a5..84a2d28 100644
--- a/drivers/hwmon/ltc4261.c
+++ b/drivers/hwmon/ltc4261.c
@@ -33,6 +33,7 @@
#include <linux/i2c.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
+#include <linux/jiffies.h>
/* chip registers */
#define LTC4261_STATUS 0x00 /* readonly */
diff --git a/drivers/hwmon/max16065.c b/drivers/hwmon/max16065.c
index 019427d..e0019c6 100644
--- a/drivers/hwmon/max16065.c
+++ b/drivers/hwmon/max16065.c
@@ -22,7 +22,6 @@
#include <linux/i2c.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
-#include <linux/delay.h>
#include <linux/jiffies.h>
enum chips { max16065, max16066, max16067, max16068, max16070, max16071 };
diff --git a/drivers/hwmon/max1619.c b/drivers/hwmon/max1619.c
index 6c11ec2..445e5d4 100644
--- a/drivers/hwmon/max1619.c
+++ b/drivers/hwmon/max1619.c
@@ -1,7 +1,7 @@
/*
* max1619.c - Part of lm_sensors, Linux kernel modules for hardware
* monitoring
- * Copyright (C) 2003-2004 Alexey Fisher <fishor@mail.ru>
+ * Copyright (C) 2003-2004 Oleksij Rempel <bug-track@fisher-privat.net>
* Jean Delvare <khali@linux-fr.org>
*
* Based on the lm90 driver. The MAX1619 is a sensor chip made by Maxim.
@@ -357,7 +357,7 @@ static struct max1619_data *max1619_update_device(struct device *dev)
module_i2c_driver(max1619_driver);
-MODULE_AUTHOR("Alexey Fisher <fishor@mail.ru> and "
+MODULE_AUTHOR("Oleksij Rempel <bug-track@fisher-privat.net> and "
"Jean Delvare <khali@linux-fr.org>");
MODULE_DESCRIPTION("MAX1619 sensor driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/max6642.c b/drivers/hwmon/max6642.c
index bf236c0..223461a 100644
--- a/drivers/hwmon/max6642.c
+++ b/drivers/hwmon/max6642.c
@@ -7,7 +7,7 @@
* Derived from:
*
* Based on the max1619 driver.
- * Copyright (C) 2003-2004 Alexey Fisher <fishor@mail.ru>
+ * Copyright (C) 2003-2004 Oleksij Rempel <bug-track@fisher-privat.net>
* Jean Delvare <khali@linux-fr.org>
*
* The MAX6642 is a sensor chip made by Maxim.
diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c
index 29b319d..7d19b1b 100644
--- a/drivers/hwmon/pmbus/pmbus_core.c
+++ b/drivers/hwmon/pmbus/pmbus_core.c
@@ -26,7 +26,7 @@
#include <linux/i2c.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
-#include <linux/delay.h>
+#include <linux/jiffies.h>
#include <linux/i2c/pmbus.h>
#include "pmbus.h"
diff --git a/drivers/hwmon/s3c-hwmon.c b/drivers/hwmon/s3c-hwmon.c
index fe11b95..bcecd02 100644
--- a/drivers/hwmon/s3c-hwmon.c
+++ b/drivers/hwmon/s3c-hwmon.c
@@ -22,7 +22,6 @@
#include <linux/module.h>
#include <linux/slab.h>
-#include <linux/delay.h>
#include <linux/io.h>
#include <linux/init.h>
#include <linux/err.h>
diff --git a/drivers/hwmon/sht21.c b/drivers/hwmon/sht21.c
index c2565d0..5f675469 100644
--- a/drivers/hwmon/sht21.c
+++ b/drivers/hwmon/sht21.c
@@ -29,6 +29,7 @@
#include <linux/err.h>
#include <linux/mutex.h>
#include <linux/device.h>
+#include <linux/jiffies.h>
/* I2C command bytes */
#define SHT21_TRIG_T_MEASUREMENT_HM 0xe3
diff --git a/drivers/hwmon/smm665.c b/drivers/hwmon/smm665.c
index cbc51fb..d9e1b7d 100644
--- a/drivers/hwmon/smm665.c
+++ b/drivers/hwmon/smm665.c
@@ -24,6 +24,7 @@
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/delay.h>
+#include <linux/jiffies.h>
/* Internal reference voltage (VREF, x 1000 */
#define SMM665_VREF_ADC_X1000 1250
diff --git a/drivers/hwmon/thmc50.c b/drivers/hwmon/thmc50.c
index 080c263..3c2c48d 100644
--- a/drivers/hwmon/thmc50.c
+++ b/drivers/hwmon/thmc50.c
@@ -28,6 +28,7 @@
#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
#include <linux/mutex.h>
+#include <linux/jiffies.h>
MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/tmp102.c b/drivers/hwmon/tmp102.c
index 4e1ff82..b8777e5 100644
--- a/drivers/hwmon/tmp102.c
+++ b/drivers/hwmon/tmp102.c
@@ -26,6 +26,7 @@
#include <linux/err.h>
#include <linux/mutex.h>
#include <linux/device.h>
+#include <linux/jiffies.h>
#define DRIVER_NAME "tmp102"
diff --git a/drivers/hwmon/ultra45_env.c b/drivers/hwmon/ultra45_env.c
index c315c59..44136bb 100644
--- a/drivers/hwmon/ultra45_env.c
+++ b/drivers/hwmon/ultra45_env.c
@@ -12,6 +12,7 @@
#include <linux/io.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
#define DRV_MODULE_VERSION "0.1"
diff --git a/drivers/hwmon/w83791d.c b/drivers/hwmon/w83791d.c
index 93ea81a..39ab7bc 100644
--- a/drivers/hwmon/w83791d.c
+++ b/drivers/hwmon/w83791d.c
@@ -41,6 +41,7 @@
#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
#include <linux/mutex.h>
+#include <linux/jiffies.h>
#define NUMBER_OF_VIN 10
#define NUMBER_OF_FANIN 5
diff --git a/drivers/hwmon/w83792d.c b/drivers/hwmon/w83792d.c
index 06d6f56..0536452 100644
--- a/drivers/hwmon/w83792d.c
+++ b/drivers/hwmon/w83792d.c
@@ -44,6 +44,7 @@
#include <linux/err.h>
#include <linux/mutex.h>
#include <linux/sysfs.h>
+#include <linux/jiffies.h>
/* Addresses to scan */
static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, 0x2f,
diff --git a/drivers/hwmon/w83793.c b/drivers/hwmon/w83793.c
index 4fc47e0..99799fd 100644
--- a/drivers/hwmon/w83793.c
+++ b/drivers/hwmon/w83793.c
@@ -46,6 +46,7 @@
#include <linux/kref.h>
#include <linux/notifier.h>
#include <linux/reboot.h>
+#include <linux/jiffies.h>
/* Default values */
#define WATCHDOG_TIMEOUT 2 /* 2 minute default timeout */
diff --git a/drivers/hwmon/w83795.c b/drivers/hwmon/w83795.c
index b813c64..55a4f48 100644
--- a/drivers/hwmon/w83795.c
+++ b/drivers/hwmon/w83795.c
@@ -34,7 +34,7 @@
#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
#include <linux/mutex.h>
-#include <linux/delay.h>
+#include <linux/jiffies.h>
/* Addresses to scan */
static const unsigned short normal_i2c[] = {
diff --git a/drivers/hwmon/w83l786ng.c b/drivers/hwmon/w83l786ng.c
index c99c8a0..f0e8286 100644
--- a/drivers/hwmon/w83l786ng.c
+++ b/drivers/hwmon/w83l786ng.c
@@ -33,6 +33,7 @@
#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
#include <linux/mutex.h>
+#include <linux/jiffies.h>
/* Addresses to scan */
static const unsigned short normal_i2c[] = { 0x2e, 0x2f, I2C_CLIENT_END };
diff --git a/drivers/i2c/algos/i2c-algo-pca.c b/drivers/i2c/algos/i2c-algo-pca.c
index 6f5f98d..f892a42 100644
--- a/drivers/i2c/algos/i2c-algo-pca.c
+++ b/drivers/i2c/algos/i2c-algo-pca.c
@@ -46,14 +46,19 @@ static int i2c_debug;
#define pca_set_con(adap, val) pca_outw(adap, I2C_PCA_CON, val)
#define pca_get_con(adap) pca_inw(adap, I2C_PCA_CON)
#define pca_wait(adap) adap->wait_for_completion(adap->data)
-#define pca_reset(adap) adap->reset_chip(adap->data)
-static void pca9665_reset(void *pd)
+static void pca_reset(struct i2c_algo_pca_data *adap)
{
- struct i2c_algo_pca_data *adap = pd;
- pca_outw(adap, I2C_PCA_INDPTR, I2C_PCA_IPRESET);
- pca_outw(adap, I2C_PCA_IND, 0xA5);
- pca_outw(adap, I2C_PCA_IND, 0x5A);
+ if (adap->chip == I2C_PCA_CHIP_9665) {
+ /* Ignore the reset function from the module,
+ * we can use the parallel bus reset.
+ */
+ pca_outw(adap, I2C_PCA_INDPTR, I2C_PCA_IPRESET);
+ pca_outw(adap, I2C_PCA_IND, 0xA5);
+ pca_outw(adap, I2C_PCA_IND, 0x5A);
+ } else {
+ adap->reset_chip(adap->data);
+ }
}
/*
@@ -378,11 +383,12 @@ static unsigned int pca_probe_chip(struct i2c_adapter *adap)
pca_outw(pca_data, I2C_PCA_INDPTR, I2C_PCA_IADR);
if (pca_inw(pca_data, I2C_PCA_IND) == 0xAA) {
printk(KERN_INFO "%s: PCA9665 detected.\n", adap->name);
- return I2C_PCA_CHIP_9665;
+ pca_data->chip = I2C_PCA_CHIP_9665;
} else {
printk(KERN_INFO "%s: PCA9564 detected.\n", adap->name);
- return I2C_PCA_CHIP_9564;
+ pca_data->chip = I2C_PCA_CHIP_9564;
}
+ return pca_data->chip;
}
static int pca_init(struct i2c_adapter *adap)
@@ -456,11 +462,6 @@ static int pca_init(struct i2c_adapter *adap)
*/
int raise_fall_time;
- /* Ignore the reset function from the module,
- * we can use the parallel bus reset
- */
- pca_data->reset_chip = pca9665_reset;
-
if (pca_data->i2c_clock > 1265800) {
printk(KERN_WARNING "%s: I2C clock speed too high."
" Using 1265.8kHz.\n", adap->name);
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index ff01c38..65dd599 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -294,18 +294,21 @@ comment "I2C system bus drivers (mostly embedded / system-on-chip)"
config I2C_AT91
tristate "Atmel AT91 I2C Two-Wire interface (TWI)"
- depends on ARCH_AT91 && EXPERIMENTAL && BROKEN
+ depends on ARCH_AT91 && EXPERIMENTAL
help
This supports the use of the I2C interface on Atmel AT91
processors.
- This driver is BROKEN because the controller which it uses
- will easily trigger RX overrun and TX underrun errors. Using
- low I2C clock rates may partially work around those issues
- on some systems. Another serious problem is that there is no
- documented way to issue repeated START conditions, as needed
+ A serious problem is that there is no documented way to issue
+ repeated START conditions for more than two messages, as needed
to support combined I2C messages. Use the i2c-gpio driver
- unless your system can cope with those limitations.
+ unless your system can cope with this limitation.
+
+ Caution! at91rm9200, at91sam9261, at91sam9260, at91sam9263 devices
+ don't have clock stretching in transmission mode. For that reason,
+ you can encounter underrun issues causing premature stop sendings if
+ the latency to fill the transmission register is too long. If you
+ are facing this situation, use the i2c-gpio driver.
config I2C_AU1550
tristate "Au1550/Au1200/Au1300 SMBus interface"
@@ -718,6 +721,16 @@ config I2C_XLR
This driver can also be built as a module. If so, the module
will be called i2c-xlr.
+config I2C_RCAR
+ tristate "Renesas R-Car I2C Controller"
+ depends on ARCH_SHMOBILE && I2C
+ help
+ If you say yes to this option, support will be included for the
+ R-Car I2C controller.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-rcar.
+
comment "External I2C/SMBus adapter drivers"
config I2C_DIOLAN_U2C
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 37c4182..2d33d62 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -71,6 +71,7 @@ obj-$(CONFIG_I2C_VERSATILE) += i2c-versatile.o
obj-$(CONFIG_I2C_OCTEON) += i2c-octeon.o
obj-$(CONFIG_I2C_XILINX) += i2c-xiic.o
obj-$(CONFIG_I2C_XLR) += i2c-xlr.o
+obj-$(CONFIG_I2C_RCAR) += i2c-rcar.o
# External I2C/SMBus adapter drivers
obj-$(CONFIG_I2C_DIOLAN_U2C) += i2c-diolan-u2c.o
diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c
index e24484b..aa59a25 100644
--- a/drivers/i2c/busses/i2c-at91.c
+++ b/drivers/i2c/busses/i2c-at91.c
@@ -1,315 +1,554 @@
/*
- i2c Support for Atmel's AT91 Two-Wire Interface (TWI)
-
- Copyright (C) 2004 Rick Bronson
- Converted to 2.6 by Andrew Victor <andrew@sanpeople.com>
-
- Borrowed heavily from original work by:
- Copyright (C) 2000 Philip Edelbrock <phil@stimpy.netroedge.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.
-*/
+ * i2c Support for Atmel's AT91 Two-Wire Interface (TWI)
+ *
+ * Copyright (C) 2011 Weinmann Medical GmbH
+ * Author: Nikolaus Voss <n.voss@weinmann.de>
+ *
+ * Evolved from original work by:
+ * Copyright (C) 2004 Rick Bronson
+ * Converted to 2.6 by Andrew Victor <andrew@sanpeople.com>
+ *
+ * Borrowed heavily from original work by:
+ * Copyright (C) 2000 Philip Edelbrock <phil@stimpy.netroedge.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/module.h>
-#include <linux/kernel.h>
+#include <linux/clk.h>
+#include <linux/completion.h>
#include <linux/err.h>
-#include <linux/slab.h>
-#include <linux/types.h>
-#include <linux/delay.h>
#include <linux/i2c.h>
-#include <linux/init.h>
-#include <linux/clk.h>
-#include <linux/platform_device.h>
+#include <linux/interrupt.h>
#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_i2c.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#define TWI_CLK_HZ 100000 /* max 400 Kbits/s */
+#define AT91_I2C_TIMEOUT msecs_to_jiffies(100) /* transfer timeout */
+
+/* AT91 TWI register definitions */
+#define AT91_TWI_CR 0x0000 /* Control Register */
+#define AT91_TWI_START 0x0001 /* Send a Start Condition */
+#define AT91_TWI_STOP 0x0002 /* Send a Stop Condition */
+#define AT91_TWI_MSEN 0x0004 /* Master Transfer Enable */
+#define AT91_TWI_SVDIS 0x0020 /* Slave Transfer Disable */
+#define AT91_TWI_SWRST 0x0080 /* Software Reset */
+
+#define AT91_TWI_MMR 0x0004 /* Master Mode Register */
+#define AT91_TWI_IADRSZ_1 0x0100 /* Internal Device Address Size */
+#define AT91_TWI_MREAD 0x1000 /* Master Read Direction */
+
+#define AT91_TWI_IADR 0x000c /* Internal Address Register */
+
+#define AT91_TWI_CWGR 0x0010 /* Clock Waveform Generator Reg */
+
+#define AT91_TWI_SR 0x0020 /* Status Register */
+#define AT91_TWI_TXCOMP 0x0001 /* Transmission Complete */
+#define AT91_TWI_RXRDY 0x0002 /* Receive Holding Register Ready */
+#define AT91_TWI_TXRDY 0x0004 /* Transmit Holding Register Ready */
-#include <mach/at91_twi.h>
-#include <mach/board.h>
-#include <mach/cpu.h>
+#define AT91_TWI_OVRE 0x0040 /* Overrun Error */
+#define AT91_TWI_UNRE 0x0080 /* Underrun Error */
+#define AT91_TWI_NACK 0x0100 /* Not Acknowledged */
-#define TWI_CLOCK 100000 /* Hz. max 400 Kbits/sec */
+#define AT91_TWI_IER 0x0024 /* Interrupt Enable Register */
+#define AT91_TWI_IDR 0x0028 /* Interrupt Disable Register */
+#define AT91_TWI_IMR 0x002c /* Interrupt Mask Register */
+#define AT91_TWI_RHR 0x0030 /* Receive Holding Register */
+#define AT91_TWI_THR 0x0034 /* Transmit Holding Register */
+struct at91_twi_pdata {
+ unsigned clk_max_div;
+ unsigned clk_offset;
+ bool has_unre_flag;
+};
+
+struct at91_twi_dev {
+ struct device *dev;
+ void __iomem *base;
+ struct completion cmd_complete;
+ struct clk *clk;
+ u8 *buf;
+ size_t buf_len;
+ struct i2c_msg *msg;
+ int irq;
+ unsigned transfer_status;
+ struct i2c_adapter adapter;
+ unsigned twi_cwgr_reg;
+ struct at91_twi_pdata *pdata;
+};
-static struct clk *twi_clk;
-static void __iomem *twi_base;
+static unsigned at91_twi_read(struct at91_twi_dev *dev, unsigned reg)
+{
+ return readl_relaxed(dev->base + reg);
+}
+
+static void at91_twi_write(struct at91_twi_dev *dev, unsigned reg, unsigned val)
+{
+ writel_relaxed(val, dev->base + reg);
+}
-#define at91_twi_read(reg) __raw_readl(twi_base + (reg))
-#define at91_twi_write(reg, val) __raw_writel((val), twi_base + (reg))
+static void at91_disable_twi_interrupts(struct at91_twi_dev *dev)
+{
+ at91_twi_write(dev, AT91_TWI_IDR,
+ AT91_TWI_TXCOMP | AT91_TWI_RXRDY | AT91_TWI_TXRDY);
+}
+static void at91_init_twi_bus(struct at91_twi_dev *dev)
+{
+ at91_disable_twi_interrupts(dev);
+ at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_SWRST);
+ at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_MSEN);
+ at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_SVDIS);
+ at91_twi_write(dev, AT91_TWI_CWGR, dev->twi_cwgr_reg);
+}
/*
- * Initialize the TWI hardware registers.
+ * Calculate symmetric clock as stated in datasheet:
+ * twi_clk = F_MAIN / (2 * (cdiv * (1 << ckdiv) + offset))
*/
-static void __devinit at91_twi_hwinit(void)
+static void __devinit at91_calc_twi_clock(struct at91_twi_dev *dev, int twi_clk)
{
- unsigned long cdiv, ckdiv;
-
- at91_twi_write(AT91_TWI_IDR, 0xffffffff); /* Disable all interrupts */
- at91_twi_write(AT91_TWI_CR, AT91_TWI_SWRST); /* Reset peripheral */
- at91_twi_write(AT91_TWI_CR, AT91_TWI_MSEN); /* Set Master mode */
-
- /* Calcuate clock dividers */
- cdiv = (clk_get_rate(twi_clk) / (2 * TWI_CLOCK)) - 3;
- cdiv = cdiv + 1; /* round up */
- ckdiv = 0;
- while (cdiv > 255) {
- ckdiv++;
- cdiv = cdiv >> 1;
+ int ckdiv, cdiv, div;
+ struct at91_twi_pdata *pdata = dev->pdata;
+ int offset = pdata->clk_offset;
+ int max_ckdiv = pdata->clk_max_div;
+
+ div = max(0, (int)DIV_ROUND_UP(clk_get_rate(dev->clk),
+ 2 * twi_clk) - offset);
+ ckdiv = fls(div >> 8);
+ cdiv = div >> ckdiv;
+
+ if (ckdiv > max_ckdiv) {
+ dev_warn(dev->dev, "%d exceeds ckdiv max value which is %d.\n",
+ ckdiv, max_ckdiv);
+ ckdiv = max_ckdiv;
+ cdiv = 255;
}
- if (cpu_is_at91rm9200()) { /* AT91RM9200 Errata #22 */
- if (ckdiv > 5) {
- printk(KERN_ERR "AT91 I2C: Invalid TWI_CLOCK value!\n");
- ckdiv = 5;
- }
- }
+ dev->twi_cwgr_reg = (ckdiv << 16) | (cdiv << 8) | cdiv;
+ dev_dbg(dev->dev, "cdiv %d ckdiv %d\n", cdiv, ckdiv);
+}
- at91_twi_write(AT91_TWI_CWGR, (ckdiv << 16) | (cdiv << 8) | cdiv);
+static void at91_twi_write_next_byte(struct at91_twi_dev *dev)
+{
+ if (dev->buf_len <= 0)
+ return;
+
+ at91_twi_write(dev, AT91_TWI_THR, *dev->buf);
+
+ /* send stop when last byte has been written */
+ if (--dev->buf_len == 0)
+ at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_STOP);
+
+ dev_dbg(dev->dev, "wrote 0x%x, to go %d\n", *dev->buf, dev->buf_len);
+
+ ++dev->buf;
}
-/*
- * Poll the i2c status register until the specified bit is set.
- * Returns 0 if timed out (100 msec).
- */
-static short at91_poll_status(unsigned long bit)
+static void at91_twi_read_next_byte(struct at91_twi_dev *dev)
{
- int loop_cntr = 10000;
+ if (dev->buf_len <= 0)
+ return;
+
+ *dev->buf = at91_twi_read(dev, AT91_TWI_RHR) & 0xff;
+ --dev->buf_len;
+
+ /* handle I2C_SMBUS_BLOCK_DATA */
+ if (unlikely(dev->msg->flags & I2C_M_RECV_LEN)) {
+ dev->msg->flags &= ~I2C_M_RECV_LEN;
+ dev->buf_len += *dev->buf;
+ dev->msg->len = dev->buf_len + 1;
+ dev_dbg(dev->dev, "received block length %d\n", dev->buf_len);
+ }
+
+ /* send stop if second but last byte has been read */
+ if (dev->buf_len == 1)
+ at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_STOP);
- do {
- udelay(10);
- } while (!(at91_twi_read(AT91_TWI_SR) & bit) && (--loop_cntr > 0));
+ dev_dbg(dev->dev, "read 0x%x, to go %d\n", *dev->buf, dev->buf_len);
- return (loop_cntr > 0);
+ ++dev->buf;
}
-static int xfer_read(struct i2c_adapter *adap, unsigned char *buf, int length)
+static irqreturn_t atmel_twi_interrupt(int irq, void *dev_id)
{
- /* Send Start */
- at91_twi_write(AT91_TWI_CR, AT91_TWI_START);
-
- /* Read data */
- while (length--) {
- if (!length) /* need to send Stop before reading last byte */
- at91_twi_write(AT91_TWI_CR, AT91_TWI_STOP);
- if (!at91_poll_status(AT91_TWI_RXRDY)) {
- dev_dbg(&adap->dev, "RXRDY timeout\n");
- return -ETIMEDOUT;
- }
- *buf++ = (at91_twi_read(AT91_TWI_RHR) & 0xff);
+ struct at91_twi_dev *dev = dev_id;
+ const unsigned status = at91_twi_read(dev, AT91_TWI_SR);
+ const unsigned irqstatus = status & at91_twi_read(dev, AT91_TWI_IMR);
+
+ if (!irqstatus)
+ return IRQ_NONE;
+ else if (irqstatus & AT91_TWI_RXRDY)
+ at91_twi_read_next_byte(dev);
+ else if (irqstatus & AT91_TWI_TXRDY)
+ at91_twi_write_next_byte(dev);
+
+ /* catch error flags */
+ dev->transfer_status |= status;
+
+ if (irqstatus & AT91_TWI_TXCOMP) {
+ at91_disable_twi_interrupts(dev);
+ complete(&dev->cmd_complete);
}
- return 0;
+ return IRQ_HANDLED;
}
-static int xfer_write(struct i2c_adapter *adap, unsigned char *buf, int length)
+static int at91_do_twi_transfer(struct at91_twi_dev *dev)
{
- /* Load first byte into transmitter */
- at91_twi_write(AT91_TWI_THR, *buf++);
+ int ret;
+ bool has_unre_flag = dev->pdata->has_unre_flag;
- /* Send Start */
- at91_twi_write(AT91_TWI_CR, AT91_TWI_START);
+ dev_dbg(dev->dev, "transfer: %s %d bytes.\n",
+ (dev->msg->flags & I2C_M_RD) ? "read" : "write", dev->buf_len);
- do {
- if (!at91_poll_status(AT91_TWI_TXRDY)) {
- dev_dbg(&adap->dev, "TXRDY timeout\n");
- return -ETIMEDOUT;
- }
+ INIT_COMPLETION(dev->cmd_complete);
+ dev->transfer_status = 0;
+ if (dev->msg->flags & I2C_M_RD) {
+ unsigned start_flags = AT91_TWI_START;
- length--; /* byte was transmitted */
+ if (at91_twi_read(dev, AT91_TWI_SR) & AT91_TWI_RXRDY) {
+ dev_err(dev->dev, "RXRDY still set!");
+ at91_twi_read(dev, AT91_TWI_RHR);
+ }
- if (length > 0) /* more data to send? */
- at91_twi_write(AT91_TWI_THR, *buf++);
- } while (length);
+ /* if only one byte is to be read, immediately stop transfer */
+ if (dev->buf_len <= 1 && !(dev->msg->flags & I2C_M_RECV_LEN))
+ start_flags |= AT91_TWI_STOP;
+ at91_twi_write(dev, AT91_TWI_CR, start_flags);
+ at91_twi_write(dev, AT91_TWI_IER,
+ AT91_TWI_TXCOMP | AT91_TWI_RXRDY);
+ } else {
+ at91_twi_write_next_byte(dev);
+ at91_twi_write(dev, AT91_TWI_IER,
+ AT91_TWI_TXCOMP | AT91_TWI_TXRDY);
+ }
- /* Send Stop */
- at91_twi_write(AT91_TWI_CR, AT91_TWI_STOP);
+ ret = wait_for_completion_interruptible_timeout(&dev->cmd_complete,
+ dev->adapter.timeout);
+ if (ret == 0) {
+ dev_err(dev->dev, "controller timed out\n");
+ at91_init_twi_bus(dev);
+ return -ETIMEDOUT;
+ }
+ if (dev->transfer_status & AT91_TWI_NACK) {
+ dev_dbg(dev->dev, "received nack\n");
+ return -EREMOTEIO;
+ }
+ if (dev->transfer_status & AT91_TWI_OVRE) {
+ dev_err(dev->dev, "overrun while reading\n");
+ return -EIO;
+ }
+ if (has_unre_flag && dev->transfer_status & AT91_TWI_UNRE) {
+ dev_err(dev->dev, "underrun while writing\n");
+ return -EIO;
+ }
+ dev_dbg(dev->dev, "transfer complete\n");
return 0;
}
-/*
- * Generic i2c master transfer entrypoint.
- *
- * Note: We do not use Atmel's feature of storing the "internal device address".
- * Instead the "internal device address" has to be written using a separate
- * i2c message.
- * http://lists.arm.linux.org.uk/pipermail/linux-arm-kernel/2004-September/024411.html
- */
-static int at91_xfer(struct i2c_adapter *adap, struct i2c_msg *pmsg, int num)
+static int at91_twi_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, int num)
{
- int i, ret;
+ struct at91_twi_dev *dev = i2c_get_adapdata(adap);
+ int ret;
+ unsigned int_addr_flag = 0;
+ struct i2c_msg *m_start = msg;
dev_dbg(&adap->dev, "at91_xfer: processing %d messages:\n", num);
- for (i = 0; i < num; i++) {
- dev_dbg(&adap->dev, " #%d: %sing %d byte%s %s 0x%02x\n", i,
- pmsg->flags & I2C_M_RD ? "read" : "writ",
- pmsg->len, pmsg->len > 1 ? "s" : "",
- pmsg->flags & I2C_M_RD ? "from" : "to", pmsg->addr);
-
- at91_twi_write(AT91_TWI_MMR, (pmsg->addr << 16)
- | ((pmsg->flags & I2C_M_RD) ? AT91_TWI_MREAD : 0));
-
- if (pmsg->len && pmsg->buf) { /* sanity check */
- if (pmsg->flags & I2C_M_RD)
- ret = xfer_read(adap, pmsg->buf, pmsg->len);
- else
- ret = xfer_write(adap, pmsg->buf, pmsg->len);
-
- if (ret)
- return ret;
-
- /* Wait until transfer is finished */
- if (!at91_poll_status(AT91_TWI_TXCOMP)) {
- dev_dbg(&adap->dev, "TXCOMP timeout\n");
- return -ETIMEDOUT;
- }
+ /*
+ * The hardware can handle at most two messages concatenated by a
+ * repeated start via it's internal address feature.
+ */
+ if (num > 2) {
+ dev_err(dev->dev,
+ "cannot handle more than two concatenated messages.\n");
+ return 0;
+ } else if (num == 2) {
+ int internal_address = 0;
+ int i;
+
+ if (msg->flags & I2C_M_RD) {
+ dev_err(dev->dev, "first transfer must be write.\n");
+ return -EINVAL;
}
- dev_dbg(&adap->dev, "transfer complete\n");
- pmsg++; /* next message */
+ if (msg->len > 3) {
+ dev_err(dev->dev, "first message size must be <= 3.\n");
+ return -EINVAL;
+ }
+
+ /* 1st msg is put into the internal address, start with 2nd */
+ m_start = &msg[1];
+ for (i = 0; i < msg->len; ++i) {
+ const unsigned addr = msg->buf[msg->len - 1 - i];
+
+ internal_address |= addr << (8 * i);
+ int_addr_flag += AT91_TWI_IADRSZ_1;
+ }
+ at91_twi_write(dev, AT91_TWI_IADR, internal_address);
}
- return i;
+
+ at91_twi_write(dev, AT91_TWI_MMR, (m_start->addr << 16) | int_addr_flag
+ | ((m_start->flags & I2C_M_RD) ? AT91_TWI_MREAD : 0));
+
+ dev->buf_len = m_start->len;
+ dev->buf = m_start->buf;
+ dev->msg = m_start;
+
+ ret = at91_do_twi_transfer(dev);
+
+ return (ret < 0) ? ret : num;
}
-/*
- * Return list of supported functionality.
- */
-static u32 at91_func(struct i2c_adapter *adapter)
+static u32 at91_twi_func(struct i2c_adapter *adapter)
{
- return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL
+ | I2C_FUNC_SMBUS_READ_BLOCK_DATA;
}
-static struct i2c_algorithm at91_algorithm = {
- .master_xfer = at91_xfer,
- .functionality = at91_func,
+static struct i2c_algorithm at91_twi_algorithm = {
+ .master_xfer = at91_twi_xfer,
+ .functionality = at91_twi_func,
};
-/*
- * Main initialization routine.
- */
-static int __devinit at91_i2c_probe(struct platform_device *pdev)
-{
- struct i2c_adapter *adapter;
- struct resource *res;
- int rc;
+static struct at91_twi_pdata at91rm9200_config = {
+ .clk_max_div = 5,
+ .clk_offset = 3,
+ .has_unre_flag = true,
+};
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res)
- return -ENXIO;
+static struct at91_twi_pdata at91sam9261_config = {
+ .clk_max_div = 5,
+ .clk_offset = 4,
+ .has_unre_flag = false,
+};
- if (!request_mem_region(res->start, resource_size(res), "at91_i2c"))
- return -EBUSY;
+static struct at91_twi_pdata at91sam9260_config = {
+ .clk_max_div = 7,
+ .clk_offset = 4,
+ .has_unre_flag = false,
+};
+
+static struct at91_twi_pdata at91sam9g20_config = {
+ .clk_max_div = 7,
+ .clk_offset = 4,
+ .has_unre_flag = false,
+};
+
+static struct at91_twi_pdata at91sam9g10_config = {
+ .clk_max_div = 7,
+ .clk_offset = 4,
+ .has_unre_flag = false,
+};
- twi_base = ioremap(res->start, resource_size(res));
- if (!twi_base) {
- rc = -ENOMEM;
- goto fail0;
+static struct at91_twi_pdata at91sam9x5_config = {
+ .clk_max_div = 7,
+ .clk_offset = 4,
+ .has_unre_flag = false,
+};
+
+static const struct platform_device_id at91_twi_devtypes[] = {
+ {
+ .name = "i2c-at91rm9200",
+ .driver_data = (unsigned long) &at91rm9200_config,
+ }, {
+ .name = "i2c-at91sam9261",
+ .driver_data = (unsigned long) &at91sam9261_config,
+ }, {
+ .name = "i2c-at91sam9260",
+ .driver_data = (unsigned long) &at91sam9260_config,
+ }, {
+ .name = "i2c-at91sam9g20",
+ .driver_data = (unsigned long) &at91sam9g20_config,
+ }, {
+ .name = "i2c-at91sam9g10",
+ .driver_data = (unsigned long) &at91sam9g10_config,
+ }, {
+ /* sentinel */
}
+};
- twi_clk = clk_get(NULL, "twi_clk");
- if (IS_ERR(twi_clk)) {
- dev_err(&pdev->dev, "no clock defined\n");
- rc = -ENODEV;
- goto fail1;
+#if defined(CONFIG_OF)
+static const struct of_device_id atmel_twi_dt_ids[] = {
+ {
+ .compatible = "atmel,at91sam9260-i2c",
+ .data = &at91sam9260_config,
+ } , {
+ .compatible = "atmel,at91sam9g20-i2c",
+ .data = &at91sam9g20_config,
+ } , {
+ .compatible = "atmel,at91sam9g10-i2c",
+ .data = &at91sam9g10_config,
+ }, {
+ .compatible = "atmel,at91sam9x5-i2c",
+ .data = &at91sam9x5_config,
+ }, {
+ /* sentinel */
}
+};
+MODULE_DEVICE_TABLE(of, atmel_twi_dt_ids);
+#else
+#define atmel_twi_dt_ids NULL
+#endif
- adapter = kzalloc(sizeof(struct i2c_adapter), GFP_KERNEL);
- if (adapter == NULL) {
- dev_err(&pdev->dev, "can't allocate inteface!\n");
- rc = -ENOMEM;
- goto fail2;
+static struct at91_twi_pdata * __devinit at91_twi_get_driver_data(
+ struct platform_device *pdev)
+{
+ if (pdev->dev.of_node) {
+ const struct of_device_id *match;
+ match = of_match_node(atmel_twi_dt_ids, pdev->dev.of_node);
+ if (!match)
+ return NULL;
+ return match->data;
}
- snprintf(adapter->name, sizeof(adapter->name), "AT91");
- adapter->algo = &at91_algorithm;
- adapter->class = I2C_CLASS_HWMON;
- adapter->dev.parent = &pdev->dev;
- /* adapter->id == 0 ... only one TWI controller for now */
+ return (struct at91_twi_pdata *) platform_get_device_id(pdev)->driver_data;
+}
+
+static int __devinit at91_twi_probe(struct platform_device *pdev)
+{
+ struct at91_twi_dev *dev;
+ struct resource *mem;
+ int rc;
+
+ dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
+ if (!dev)
+ return -ENOMEM;
+ init_completion(&dev->cmd_complete);
+ dev->dev = &pdev->dev;
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!mem)
+ return -ENODEV;
+
+ dev->pdata = at91_twi_get_driver_data(pdev);
+ if (!dev->pdata)
+ return -ENODEV;
- platform_set_drvdata(pdev, adapter);
+ dev->base = devm_request_and_ioremap(&pdev->dev, mem);
+ if (!dev->base)
+ return -EBUSY;
- clk_enable(twi_clk); /* enable peripheral clock */
- at91_twi_hwinit(); /* initialize TWI controller */
+ dev->irq = platform_get_irq(pdev, 0);
+ if (dev->irq < 0)
+ return dev->irq;
- rc = i2c_add_numbered_adapter(adapter);
+ rc = devm_request_irq(&pdev->dev, dev->irq, atmel_twi_interrupt, 0,
+ dev_name(dev->dev), dev);
if (rc) {
- dev_err(&pdev->dev, "Adapter %s registration failed\n",
- adapter->name);
- goto fail3;
+ dev_err(dev->dev, "Cannot get irq %d: %d\n", dev->irq, rc);
+ return rc;
}
- dev_info(&pdev->dev, "AT91 i2c bus driver.\n");
- return 0;
+ platform_set_drvdata(pdev, dev);
-fail3:
- platform_set_drvdata(pdev, NULL);
- kfree(adapter);
- clk_disable(twi_clk);
-fail2:
- clk_put(twi_clk);
-fail1:
- iounmap(twi_base);
-fail0:
- release_mem_region(res->start, resource_size(res));
+ dev->clk = devm_clk_get(dev->dev, NULL);
+ if (IS_ERR(dev->clk)) {
+ dev_err(dev->dev, "no clock defined\n");
+ return -ENODEV;
+ }
+ clk_prepare_enable(dev->clk);
+
+ at91_calc_twi_clock(dev, TWI_CLK_HZ);
+ at91_init_twi_bus(dev);
+
+ snprintf(dev->adapter.name, sizeof(dev->adapter.name), "AT91");
+ i2c_set_adapdata(&dev->adapter, dev);
+ dev->adapter.owner = THIS_MODULE;
+ dev->adapter.class = I2C_CLASS_HWMON;
+ dev->adapter.algo = &at91_twi_algorithm;
+ dev->adapter.dev.parent = dev->dev;
+ dev->adapter.nr = pdev->id;
+ dev->adapter.timeout = AT91_I2C_TIMEOUT;
+ dev->adapter.dev.of_node = pdev->dev.of_node;
+
+ rc = i2c_add_numbered_adapter(&dev->adapter);
+ if (rc) {
+ dev_err(dev->dev, "Adapter %s registration failed\n",
+ dev->adapter.name);
+ clk_disable_unprepare(dev->clk);
+ return rc;
+ }
- return rc;
+ of_i2c_register_devices(&dev->adapter);
+
+ dev_info(dev->dev, "AT91 i2c bus driver.\n");
+ return 0;
}
-static int __devexit at91_i2c_remove(struct platform_device *pdev)
+static int __devexit at91_twi_remove(struct platform_device *pdev)
{
- struct i2c_adapter *adapter = platform_get_drvdata(pdev);
- struct resource *res;
+ struct at91_twi_dev *dev = platform_get_drvdata(pdev);
int rc;
- rc = i2c_del_adapter(adapter);
- platform_set_drvdata(pdev, NULL);
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- iounmap(twi_base);
- release_mem_region(res->start, resource_size(res));
-
- clk_disable(twi_clk); /* disable peripheral clock */
- clk_put(twi_clk);
+ rc = i2c_del_adapter(&dev->adapter);
+ clk_disable_unprepare(dev->clk);
return rc;
}
#ifdef CONFIG_PM
-/* NOTE: could save a few mA by keeping clock off outside of at91_xfer... */
-
-static int at91_i2c_suspend(struct device *dev)
+static int at91_twi_runtime_suspend(struct device *dev)
{
- clk_disable(twi_clk);
+ struct at91_twi_dev *twi_dev = dev_get_drvdata(dev);
+
+ clk_disable(twi_dev->clk);
+
return 0;
}
-static int at91_i2c_resume(struct device *dev)
+static int at91_twi_runtime_resume(struct device *dev)
{
- return clk_enable(twi_clk);
+ struct at91_twi_dev *twi_dev = dev_get_drvdata(dev);
+
+ return clk_enable(twi_dev->clk);
}
-static SIMPLE_DEV_PM_OPS(at91_i2c_pm, at91_i2c_suspend, at91_i2c_resume);
-#define AT91_I2C_PM (&at91_i2c_pm)
+static const struct dev_pm_ops at91_twi_pm = {
+ .runtime_suspend = at91_twi_runtime_suspend,
+ .runtime_resume = at91_twi_runtime_resume,
+};
+#define at91_twi_pm_ops (&at91_twi_pm)
#else
-#define AT91_I2C_PM NULL
+#define at91_twi_pm_ops NULL
#endif
-static struct platform_driver at91_i2c_driver = {
- .probe = at91_i2c_probe,
- .remove = __devexit_p(at91_i2c_remove),
+static struct platform_driver at91_twi_driver = {
+ .probe = at91_twi_probe,
+ .remove = __devexit_p(at91_twi_remove),
+ .id_table = at91_twi_devtypes,
.driver = {
.name = "at91_i2c",
.owner = THIS_MODULE,
- .pm = AT91_I2C_PM,
+ .of_match_table = atmel_twi_dt_ids,
+ .pm = at91_twi_pm_ops,
},
};
-module_platform_driver(at91_i2c_driver);
+static int __init at91_twi_init(void)
+{
+ return platform_driver_register(&at91_twi_driver);
+}
+
+static void __exit at91_twi_exit(void)
+{
+ platform_driver_unregister(&at91_twi_driver);
+}
+
+subsys_initcall(at91_twi_init);
+module_exit(at91_twi_exit);
-MODULE_AUTHOR("Rick Bronson");
+MODULE_AUTHOR("Nikolaus Voss <n.voss@weinmann.de>");
MODULE_DESCRIPTION("I2C (TWI) driver for Atmel AT91");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:at91_i2c");
diff --git a/drivers/i2c/busses/i2c-davinci.c b/drivers/i2c/busses/i2c-davinci.c
index 79a2542..6a0a553 100644
--- a/drivers/i2c/busses/i2c-davinci.c
+++ b/drivers/i2c/busses/i2c-davinci.c
@@ -38,6 +38,8 @@
#include <linux/slab.h>
#include <linux/cpufreq.h>
#include <linux/gpio.h>
+#include <linux/of_i2c.h>
+#include <linux/of_device.h>
#include <mach/hardware.h>
#include <linux/platform_data/i2c-davinci.h>
@@ -114,6 +116,7 @@ struct davinci_i2c_dev {
struct completion xfr_complete;
struct notifier_block freq_transition;
#endif
+ struct davinci_i2c_platform_data *pdata;
};
/* default platform data to use if not supplied in the platform_device */
@@ -155,7 +158,7 @@ static void generic_i2c_clock_pulse(unsigned int scl_pin)
static void i2c_recover_bus(struct davinci_i2c_dev *dev)
{
u32 flag = 0;
- struct davinci_i2c_platform_data *pdata = dev->dev->platform_data;
+ struct davinci_i2c_platform_data *pdata = dev->pdata;
dev_err(dev->dev, "initiating i2c bus recovery\n");
/* Send NACK to the slave */
@@ -163,8 +166,7 @@ static void i2c_recover_bus(struct davinci_i2c_dev *dev)
flag |= DAVINCI_I2C_MDR_NACK;
/* write the data into mode register */
davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, flag);
- if (pdata)
- generic_i2c_clock_pulse(pdata->scl_pin);
+ generic_i2c_clock_pulse(pdata->scl_pin);
/* Send STOP */
flag = davinci_i2c_read_reg(dev, DAVINCI_I2C_MDR_REG);
flag |= DAVINCI_I2C_MDR_STP;
@@ -187,7 +189,7 @@ static inline void davinci_i2c_reset_ctrl(struct davinci_i2c_dev *i2c_dev,
static void i2c_davinci_calc_clk_dividers(struct davinci_i2c_dev *dev)
{
- struct davinci_i2c_platform_data *pdata = dev->dev->platform_data;
+ struct davinci_i2c_platform_data *pdata = dev->pdata;
u16 psc;
u32 clk;
u32 d;
@@ -235,10 +237,7 @@ static void i2c_davinci_calc_clk_dividers(struct davinci_i2c_dev *dev)
*/
static int i2c_davinci_init(struct davinci_i2c_dev *dev)
{
- struct davinci_i2c_platform_data *pdata = dev->dev->platform_data;
-
- if (!pdata)
- pdata = &davinci_i2c_platform_data_default;
+ struct davinci_i2c_platform_data *pdata = dev->pdata;
/* put I2C into reset */
davinci_i2c_reset_ctrl(dev, 0);
@@ -260,6 +259,7 @@ static int i2c_davinci_init(struct davinci_i2c_dev *dev)
dev_dbg(dev->dev, "bus_freq = %dkHz, bus_delay = %d\n",
pdata->bus_freq, pdata->bus_delay);
+
/* Take the I2C module out of reset: */
davinci_i2c_reset_ctrl(dev, 1);
@@ -308,13 +308,11 @@ static int
i2c_davinci_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, int stop)
{
struct davinci_i2c_dev *dev = i2c_get_adapdata(adap);
- struct davinci_i2c_platform_data *pdata = dev->dev->platform_data;
+ struct davinci_i2c_platform_data *pdata = dev->pdata;
u32 flag;
u16 w;
int r;
- if (!pdata)
- pdata = &davinci_i2c_platform_data_default;
/* Introduce a delay, required for some boards (e.g Davinci EVM) */
if (pdata->bus_delay)
udelay(pdata->bus_delay);
@@ -635,6 +633,12 @@ static struct i2c_algorithm i2c_davinci_algo = {
.functionality = i2c_davinci_func,
};
+static const struct of_device_id davinci_i2c_of_match[] = {
+ {.compatible = "ti,davinci-i2c", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, davinci_i2c_of_match);
+
static int davinci_i2c_probe(struct platform_device *pdev)
{
struct davinci_i2c_dev *dev;
@@ -674,14 +678,33 @@ static int davinci_i2c_probe(struct platform_device *pdev)
#endif
dev->dev = get_device(&pdev->dev);
dev->irq = irq->start;
+ dev->pdata = dev->dev->platform_data;
platform_set_drvdata(pdev, dev);
+ if (!dev->pdata && pdev->dev.of_node) {
+ u32 prop;
+
+ dev->pdata = devm_kzalloc(&pdev->dev,
+ sizeof(struct davinci_i2c_platform_data), GFP_KERNEL);
+ if (!dev->pdata) {
+ r = -ENOMEM;
+ goto err_free_mem;
+ }
+ memcpy(dev->pdata, &davinci_i2c_platform_data_default,
+ sizeof(struct davinci_i2c_platform_data));
+ if (!of_property_read_u32(pdev->dev.of_node, "clock-frequency",
+ &prop))
+ dev->pdata->bus_freq = prop / 1000;
+ } else if (!dev->pdata) {
+ dev->pdata = &davinci_i2c_platform_data_default;
+ }
+
dev->clk = clk_get(&pdev->dev, NULL);
if (IS_ERR(dev->clk)) {
r = -ENODEV;
goto err_free_mem;
}
- clk_enable(dev->clk);
+ clk_prepare_enable(dev->clk);
dev->base = ioremap(mem->start, resource_size(mem));
if (!dev->base) {
@@ -711,6 +734,7 @@ static int davinci_i2c_probe(struct platform_device *pdev)
adap->algo = &i2c_davinci_algo;
adap->dev.parent = &pdev->dev;
adap->timeout = DAVINCI_I2C_TIMEOUT;
+ adap->dev.of_node = pdev->dev.of_node;
adap->nr = pdev->id;
r = i2c_add_numbered_adapter(adap);
@@ -718,6 +742,7 @@ static int davinci_i2c_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "failure adding adapter\n");
goto err_free_irq;
}
+ of_i2c_register_devices(adap);
return 0;
@@ -726,7 +751,7 @@ err_free_irq:
err_unuse_clocks:
iounmap(dev->base);
err_mem_ioremap:
- clk_disable(dev->clk);
+ clk_disable_unprepare(dev->clk);
clk_put(dev->clk);
dev->clk = NULL;
err_free_mem:
@@ -750,7 +775,7 @@ static int davinci_i2c_remove(struct platform_device *pdev)
i2c_del_adapter(&dev->adapter);
put_device(&pdev->dev);
- clk_disable(dev->clk);
+ clk_disable_unprepare(dev->clk);
clk_put(dev->clk);
dev->clk = NULL;
@@ -772,7 +797,7 @@ static int davinci_i2c_suspend(struct device *dev)
/* put I2C into reset */
davinci_i2c_reset_ctrl(i2c_dev, 0);
- clk_disable(i2c_dev->clk);
+ clk_disable_unprepare(i2c_dev->clk);
return 0;
}
@@ -782,7 +807,7 @@ static int davinci_i2c_resume(struct device *dev)
struct platform_device *pdev = to_platform_device(dev);
struct davinci_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
- clk_enable(i2c_dev->clk);
+ clk_prepare_enable(i2c_dev->clk);
/* take I2C out of reset */
davinci_i2c_reset_ctrl(i2c_dev, 1);
@@ -809,6 +834,7 @@ static struct platform_driver davinci_i2c_driver = {
.name = "i2c_davinci",
.owner = THIS_MODULE,
.pm = davinci_i2c_pm_ops,
+ .of_match_table = of_match_ptr(davinci_i2c_of_match),
},
};
diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c
index b7907ba..2ef162d 100644
--- a/drivers/i2c/busses/i2c-imx.c
+++ b/drivers/i2c/busses/i2c-imx.c
@@ -272,9 +272,9 @@ static void __init i2c_imx_set_clk(struct imx_i2c_struct *i2c_imx,
/* dev_dbg() can't be used, because adapter is not yet registered */
#ifdef CONFIG_I2C_DEBUG_BUS
- printk(KERN_DEBUG "I2C: <%s> I2C_CLK=%d, REQ DIV=%d\n",
+ dev_dbg(&i2c_imx->adapter.dev, "<%s> I2C_CLK=%d, REQ DIV=%d\n",
__func__, i2c_clk_rate, div);
- printk(KERN_DEBUG "I2C: <%s> IFDR[IC]=0x%x, REAL DIV=%d\n",
+ dev_dbg(&i2c_imx->adapter.dev, "<%s> IFDR[IC]=0x%x, REAL DIV=%d\n",
__func__, i2c_clk_div[i][1], i2c_clk_div[i][0]);
#endif
}
@@ -564,7 +564,7 @@ static int __init i2c_imx_probe(struct platform_device *pdev)
resource_size(res), res->start);
dev_dbg(&i2c_imx->adapter.dev, "adapter name: \"%s\"\n",
i2c_imx->adapter.name);
- dev_dbg(&i2c_imx->adapter.dev, "IMX I2C adapter registered\n");
+ dev_info(&i2c_imx->adapter.dev, "IMX I2C adapter registered\n");
return 0; /* Return OK */
}
diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c
index 57f7703..ca86430 100644
--- a/drivers/i2c/busses/i2c-mpc.c
+++ b/drivers/i2c/busses/i2c-mpc.c
@@ -576,7 +576,23 @@ static int mpc_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
mpc_write(i2c, pmsg->addr, pmsg->buf, pmsg->len, i);
}
}
- mpc_i2c_stop(i2c);
+ mpc_i2c_stop(i2c); /* Initiate STOP */
+ orig_jiffies = jiffies;
+ /* Wait until STOP is seen, allow up to 1 s */
+ while (readb(i2c->base + MPC_I2C_SR) & CSR_MBB) {
+ if (time_after(jiffies, orig_jiffies + HZ)) {
+ u8 status = readb(i2c->base + MPC_I2C_SR);
+
+ dev_dbg(i2c->dev, "timeout\n");
+ if ((status & (CSR_MCF | CSR_MBB | CSR_RXAK)) != 0) {
+ writeb(status & ~CSR_MAL,
+ i2c->base + MPC_I2C_SR);
+ mpc_i2c_fixup(i2c);
+ }
+ return -EIO;
+ }
+ cond_resched();
+ }
return (ret < 0) ? ret : num;
}
diff --git a/drivers/i2c/busses/i2c-mxs.c b/drivers/i2c/busses/i2c-mxs.c
index 51f05b8..1f58197 100644
--- a/drivers/i2c/busses/i2c-mxs.c
+++ b/drivers/i2c/busses/i2c-mxs.c
@@ -7,8 +7,6 @@
*
* Copyright (C) 2009-2010 Freescale Semiconductor, Inc. All Rights Reserved.
*
- * TODO: add dma-support if platform-support for it is available
- *
* 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
@@ -31,9 +29,16 @@
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_i2c.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
+#include <linux/fsl/mxs-dma.h>
#define DRIVER_NAME "mxs-i2c"
+static bool use_pioqueue;
+module_param(use_pioqueue, bool, 0);
+MODULE_PARM_DESC(use_pioqueue, "Use PIOQUEUE mode for transfer instead of DMA");
+
#define MXS_I2C_CTRL0 (0x00)
#define MXS_I2C_CTRL0_SET (0x04)
@@ -146,6 +151,16 @@ struct mxs_i2c_dev {
u32 cmd_err;
struct i2c_adapter adapter;
const struct mxs_i2c_speed_config *speed;
+
+ /* DMA support components */
+ bool dma_mode;
+ int dma_channel;
+ struct dma_chan *dmach;
+ struct mxs_dma_data dma_data;
+ uint32_t pio_data[2];
+ uint32_t addr_data;
+ struct scatterlist sg_io[2];
+ bool dma_read;
};
static void mxs_i2c_reset(struct mxs_i2c_dev *i2c)
@@ -157,7 +172,11 @@ static void mxs_i2c_reset(struct mxs_i2c_dev *i2c)
writel(i2c->speed->timing2, i2c->regs + MXS_I2C_TIMING2);
writel(MXS_I2C_IRQ_MASK << 8, i2c->regs + MXS_I2C_CTRL1_SET);
- writel(MXS_I2C_QUEUECTRL_PIO_QUEUE_MODE,
+ if (i2c->dma_mode)
+ writel(MXS_I2C_QUEUECTRL_PIO_QUEUE_MODE,
+ i2c->regs + MXS_I2C_QUEUECTRL_CLR);
+ else
+ writel(MXS_I2C_QUEUECTRL_PIO_QUEUE_MODE,
i2c->regs + MXS_I2C_QUEUECTRL_SET);
}
@@ -248,6 +267,150 @@ static int mxs_i2c_finish_read(struct mxs_i2c_dev *i2c, u8 *buf, int len)
return 0;
}
+static void mxs_i2c_dma_finish(struct mxs_i2c_dev *i2c)
+{
+ if (i2c->dma_read) {
+ dma_unmap_sg(i2c->dev, &i2c->sg_io[0], 1, DMA_TO_DEVICE);
+ dma_unmap_sg(i2c->dev, &i2c->sg_io[1], 1, DMA_FROM_DEVICE);
+ } else {
+ dma_unmap_sg(i2c->dev, i2c->sg_io, 2, DMA_TO_DEVICE);
+ }
+}
+
+static void mxs_i2c_dma_irq_callback(void *param)
+{
+ struct mxs_i2c_dev *i2c = param;
+
+ complete(&i2c->cmd_complete);
+ mxs_i2c_dma_finish(i2c);
+}
+
+static int mxs_i2c_dma_setup_xfer(struct i2c_adapter *adap,
+ struct i2c_msg *msg, uint32_t flags)
+{
+ struct dma_async_tx_descriptor *desc;
+ struct mxs_i2c_dev *i2c = i2c_get_adapdata(adap);
+
+ if (msg->flags & I2C_M_RD) {
+ i2c->dma_read = 1;
+ i2c->addr_data = (msg->addr << 1) | I2C_SMBUS_READ;
+
+ /*
+ * SELECT command.
+ */
+
+ /* Queue the PIO register write transfer. */
+ i2c->pio_data[0] = MXS_CMD_I2C_SELECT;
+ desc = dmaengine_prep_slave_sg(i2c->dmach,
+ (struct scatterlist *)&i2c->pio_data[0],
+ 1, DMA_TRANS_NONE, 0);
+ if (!desc) {
+ dev_err(i2c->dev,
+ "Failed to get PIO reg. write descriptor.\n");
+ goto select_init_pio_fail;
+ }
+
+ /* Queue the DMA data transfer. */
+ sg_init_one(&i2c->sg_io[0], &i2c->addr_data, 1);
+ dma_map_sg(i2c->dev, &i2c->sg_io[0], 1, DMA_TO_DEVICE);
+ desc = dmaengine_prep_slave_sg(i2c->dmach, &i2c->sg_io[0], 1,
+ DMA_MEM_TO_DEV,
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ if (!desc) {
+ dev_err(i2c->dev,
+ "Failed to get DMA data write descriptor.\n");
+ goto select_init_dma_fail;
+ }
+
+ /*
+ * READ command.
+ */
+
+ /* Queue the PIO register write transfer. */
+ i2c->pio_data[1] = flags | MXS_CMD_I2C_READ |
+ MXS_I2C_CTRL0_XFER_COUNT(msg->len);
+ desc = dmaengine_prep_slave_sg(i2c->dmach,
+ (struct scatterlist *)&i2c->pio_data[1],
+ 1, DMA_TRANS_NONE, DMA_PREP_INTERRUPT);
+ if (!desc) {
+ dev_err(i2c->dev,
+ "Failed to get PIO reg. write descriptor.\n");
+ goto select_init_dma_fail;
+ }
+
+ /* Queue the DMA data transfer. */
+ sg_init_one(&i2c->sg_io[1], msg->buf, msg->len);
+ dma_map_sg(i2c->dev, &i2c->sg_io[1], 1, DMA_FROM_DEVICE);
+ desc = dmaengine_prep_slave_sg(i2c->dmach, &i2c->sg_io[1], 1,
+ DMA_DEV_TO_MEM,
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ if (!desc) {
+ dev_err(i2c->dev,
+ "Failed to get DMA data write descriptor.\n");
+ goto read_init_dma_fail;
+ }
+ } else {
+ i2c->dma_read = 0;
+ i2c->addr_data = (msg->addr << 1) | I2C_SMBUS_WRITE;
+
+ /*
+ * WRITE command.
+ */
+
+ /* Queue the PIO register write transfer. */
+ i2c->pio_data[0] = flags | MXS_CMD_I2C_WRITE |
+ MXS_I2C_CTRL0_XFER_COUNT(msg->len + 1);
+ desc = dmaengine_prep_slave_sg(i2c->dmach,
+ (struct scatterlist *)&i2c->pio_data[0],
+ 1, DMA_TRANS_NONE, 0);
+ if (!desc) {
+ dev_err(i2c->dev,
+ "Failed to get PIO reg. write descriptor.\n");
+ goto write_init_pio_fail;
+ }
+
+ /* Queue the DMA data transfer. */
+ sg_init_table(i2c->sg_io, 2);
+ sg_set_buf(&i2c->sg_io[0], &i2c->addr_data, 1);
+ sg_set_buf(&i2c->sg_io[1], msg->buf, msg->len);
+ dma_map_sg(i2c->dev, i2c->sg_io, 2, DMA_TO_DEVICE);
+ desc = dmaengine_prep_slave_sg(i2c->dmach, i2c->sg_io, 2,
+ DMA_MEM_TO_DEV,
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ if (!desc) {
+ dev_err(i2c->dev,
+ "Failed to get DMA data write descriptor.\n");
+ goto write_init_dma_fail;
+ }
+ }
+
+ /*
+ * The last descriptor must have this callback,
+ * to finish the DMA transaction.
+ */
+ desc->callback = mxs_i2c_dma_irq_callback;
+ desc->callback_param = i2c;
+
+ /* Start the transfer. */
+ dmaengine_submit(desc);
+ dma_async_issue_pending(i2c->dmach);
+ return 0;
+
+/* Read failpath. */
+read_init_dma_fail:
+ dma_unmap_sg(i2c->dev, &i2c->sg_io[1], 1, DMA_FROM_DEVICE);
+select_init_dma_fail:
+ dma_unmap_sg(i2c->dev, &i2c->sg_io[0], 1, DMA_TO_DEVICE);
+select_init_pio_fail:
+ return -EINVAL;
+
+/* Write failpath. */
+write_init_dma_fail:
+ dma_unmap_sg(i2c->dev, i2c->sg_io, 2, DMA_TO_DEVICE);
+write_init_pio_fail:
+ return -EINVAL;
+}
+
/*
* Low level master read/write transaction.
*/
@@ -258,6 +421,8 @@ static int mxs_i2c_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg,
int ret;
int flags;
+ flags = stop ? MXS_I2C_CTRL0_POST_SEND_STOP : 0;
+
dev_dbg(i2c->dev, "addr: 0x%04x, len: %d, flags: 0x%x, stop: %d\n",
msg->addr, msg->len, msg->flags, stop);
@@ -267,23 +432,29 @@ static int mxs_i2c_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg,
init_completion(&i2c->cmd_complete);
i2c->cmd_err = 0;
- flags = stop ? MXS_I2C_CTRL0_POST_SEND_STOP : 0;
-
- if (msg->flags & I2C_M_RD)
- mxs_i2c_pioq_setup_read(i2c, msg->addr, msg->len, flags);
- else
- mxs_i2c_pioq_setup_write(i2c, msg->addr, msg->buf, msg->len,
- flags);
+ if (i2c->dma_mode) {
+ ret = mxs_i2c_dma_setup_xfer(adap, msg, flags);
+ if (ret)
+ return ret;
+ } else {
+ if (msg->flags & I2C_M_RD) {
+ mxs_i2c_pioq_setup_read(i2c, msg->addr,
+ msg->len, flags);
+ } else {
+ mxs_i2c_pioq_setup_write(i2c, msg->addr, msg->buf,
+ msg->len, flags);
+ }
- writel(MXS_I2C_QUEUECTRL_QUEUE_RUN,
+ writel(MXS_I2C_QUEUECTRL_QUEUE_RUN,
i2c->regs + MXS_I2C_QUEUECTRL_SET);
+ }
ret = wait_for_completion_timeout(&i2c->cmd_complete,
msecs_to_jiffies(1000));
if (ret == 0)
goto timeout;
- if ((!i2c->cmd_err) && (msg->flags & I2C_M_RD)) {
+ if (!i2c->dma_mode && !i2c->cmd_err && (msg->flags & I2C_M_RD)) {
ret = mxs_i2c_finish_read(i2c, msg->buf, msg->len);
if (ret)
goto timeout;
@@ -301,6 +472,8 @@ static int mxs_i2c_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg,
timeout:
dev_dbg(i2c->dev, "Timeout!\n");
+ if (i2c->dma_mode)
+ mxs_i2c_dma_finish(i2c);
mxs_i2c_reset(i2c);
return -ETIMEDOUT;
}
@@ -342,11 +515,13 @@ static irqreturn_t mxs_i2c_isr(int this_irq, void *dev_id)
/* MXS_I2C_CTRL1_OVERSIZE_XFER_TERM_IRQ is only for slaves */
i2c->cmd_err = -EIO;
- is_last_cmd = (readl(i2c->regs + MXS_I2C_QUEUESTAT) &
- MXS_I2C_QUEUESTAT_WRITE_QUEUE_CNT_MASK) == 0;
+ if (!i2c->dma_mode) {
+ is_last_cmd = (readl(i2c->regs + MXS_I2C_QUEUESTAT) &
+ MXS_I2C_QUEUESTAT_WRITE_QUEUE_CNT_MASK) == 0;
- if (is_last_cmd || i2c->cmd_err)
- complete(&i2c->cmd_complete);
+ if (is_last_cmd || i2c->cmd_err)
+ complete(&i2c->cmd_complete);
+ }
writel(stat, i2c->regs + MXS_I2C_CTRL1_CLR);
@@ -358,6 +533,21 @@ static const struct i2c_algorithm mxs_i2c_algo = {
.functionality = mxs_i2c_func,
};
+static bool mxs_i2c_dma_filter(struct dma_chan *chan, void *param)
+{
+ struct mxs_i2c_dev *i2c = param;
+
+ if (!mxs_dma_is_apbx(chan))
+ return false;
+
+ if (chan->chan_id != i2c->dma_channel)
+ return false;
+
+ chan->private = &i2c->dma_data;
+
+ return true;
+}
+
static int mxs_i2c_get_ofdata(struct mxs_i2c_dev *i2c)
{
uint32_t speed;
@@ -365,6 +555,26 @@ static int mxs_i2c_get_ofdata(struct mxs_i2c_dev *i2c)
struct device_node *node = dev->of_node;
int ret;
+ /*
+ * The MXS I2C DMA mode is prefered and enabled by default.
+ * The PIO mode is still supported, but should be used only
+ * for debuging purposes etc.
+ */
+ i2c->dma_mode = !use_pioqueue;
+ if (!i2c->dma_mode)
+ dev_info(dev, "Using PIOQUEUE mode for I2C transfers!\n");
+
+ /*
+ * TODO: This is a temporary solution and should be changed
+ * to use generic DMA binding later when the helpers get in.
+ */
+ ret = of_property_read_u32(node, "fsl,i2c-dma-channel",
+ &i2c->dma_channel);
+ if (ret) {
+ dev_warn(dev, "Failed to get DMA channel, using PIOQUEUE!\n");
+ i2c->dma_mode = 0;
+ }
+
ret = of_property_read_u32(node, "clock-frequency", &speed);
if (ret)
dev_warn(dev, "No I2C speed selected, using 100kHz\n");
@@ -384,7 +594,8 @@ static int __devinit mxs_i2c_probe(struct platform_device *pdev)
struct pinctrl *pinctrl;
struct resource *res;
resource_size_t res_size;
- int err, irq;
+ int err, irq, dmairq;
+ dma_cap_mask_t mask;
pinctrl = devm_pinctrl_get_select_default(dev);
if (IS_ERR(pinctrl))
@@ -395,7 +606,10 @@ static int __devinit mxs_i2c_probe(struct platform_device *pdev)
return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res)
+ irq = platform_get_irq(pdev, 0);
+ dmairq = platform_get_irq(pdev, 1);
+
+ if (!res || irq < 0 || dmairq < 0)
return -ENOENT;
res_size = resource_size(res);
@@ -406,10 +620,6 @@ static int __devinit mxs_i2c_probe(struct platform_device *pdev)
if (!i2c->regs)
return -EBUSY;
- irq = platform_get_irq(pdev, 0);
- if (irq < 0)
- return irq;
-
err = devm_request_irq(dev, irq, mxs_i2c_isr, 0, dev_name(dev), i2c);
if (err)
return err;
@@ -423,6 +633,18 @@ static int __devinit mxs_i2c_probe(struct platform_device *pdev)
return err;
}
+ /* Setup the DMA */
+ if (i2c->dma_mode) {
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_SLAVE, mask);
+ i2c->dma_data.chan_irq = dmairq;
+ i2c->dmach = dma_request_channel(mask, mxs_i2c_dma_filter, i2c);
+ if (!i2c->dmach) {
+ dev_err(dev, "Failed to request dma\n");
+ return -ENODEV;
+ }
+ }
+
platform_set_drvdata(pdev, i2c);
/* Do reset to enforce correct startup after pinmuxing */
@@ -458,6 +680,9 @@ static int __devexit mxs_i2c_remove(struct platform_device *pdev)
if (ret)
return -EBUSY;
+ if (i2c->dmach)
+ dma_release_channel(i2c->dmach);
+
writel(MXS_I2C_CTRL0_SFTRST, i2c->regs + MXS_I2C_CTRL0_SET);
platform_set_drvdata(pdev, NULL);
diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c
index 61b00ed..698d7ac 100644
--- a/drivers/i2c/busses/i2c-nomadik.c
+++ b/drivers/i2c/busses/i2c-nomadik.c
@@ -22,9 +22,10 @@
#include <linux/err.h>
#include <linux/clk.h>
#include <linux/io.h>
-#include <linux/regulator/consumer.h>
#include <linux/pm_runtime.h>
#include <linux/platform_data/i2c-nomadik.h>
+#include <linux/of.h>
+#include <linux/of_i2c.h>
#define DRIVER_NAME "nmk-i2c"
@@ -146,7 +147,6 @@ struct i2c_nmk_client {
* @stop: stop condition.
* @xfer_complete: acknowledge completion for a I2C message.
* @result: controller propogated result.
- * @regulator: pointer to i2c regulator.
* @busy: Busy doing transfer.
*/
struct nmk_i2c_dev {
@@ -160,7 +160,6 @@ struct nmk_i2c_dev {
int stop;
struct completion xfer_complete;
int result;
- struct regulator *regulator;
bool busy;
};
@@ -643,8 +642,6 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap,
dev->busy = true;
- if (dev->regulator)
- regulator_enable(dev->regulator);
pm_runtime_get_sync(&dev->adev->dev);
clk_enable(dev->clk);
@@ -676,8 +673,6 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap,
out:
clk_disable(dev->clk);
pm_runtime_put_sync(&dev->adev->dev);
- if (dev->regulator)
- regulator_disable(dev->regulator);
dev->busy = false;
@@ -920,18 +915,42 @@ static struct nmk_i2c_controller u8500_i2c = {
.sm = I2C_FREQ_MODE_FAST,
};
+static void nmk_i2c_of_probe(struct device_node *np,
+ struct nmk_i2c_controller *pdata)
+{
+ of_property_read_u32(np, "clock-frequency", &pdata->clk_freq);
+
+ /* This driver only supports 'standard' and 'fast' modes of operation. */
+ if (pdata->clk_freq <= 100000)
+ pdata->sm = I2C_FREQ_MODE_STANDARD;
+ else
+ pdata->sm = I2C_FREQ_MODE_FAST;
+}
+
static atomic_t adapter_id = ATOMIC_INIT(0);
static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id)
{
int ret = 0;
struct nmk_i2c_controller *pdata = adev->dev.platform_data;
+ struct device_node *np = adev->dev.of_node;
struct nmk_i2c_dev *dev;
struct i2c_adapter *adap;
- if (!pdata)
- /* No i2c configuration found, using the default. */
- pdata = &u8500_i2c;
+ if (!pdata) {
+ if (np) {
+ pdata = devm_kzalloc(&adev->dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata) {
+ ret = -ENOMEM;
+ goto err_no_mem;
+ }
+ /* Provide the default configuration as a base. */
+ memcpy(pdata, &u8500_i2c, sizeof(struct nmk_i2c_controller));
+ nmk_i2c_of_probe(np, pdata);
+ } else
+ /* No i2c configuration found, using the default. */
+ pdata = &u8500_i2c;
+ }
dev = kzalloc(sizeof(struct nmk_i2c_dev), GFP_KERNEL);
if (!dev) {
@@ -957,12 +976,6 @@ static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id)
goto err_irq;
}
- dev->regulator = regulator_get(&adev->dev, "v-i2c");
- if (IS_ERR(dev->regulator)) {
- dev_warn(&adev->dev, "could not get i2c regulator\n");
- dev->regulator = NULL;
- }
-
pm_suspend_ignore_children(&adev->dev, true);
dev->clk = clk_get(&adev->dev, NULL);
@@ -973,6 +986,7 @@ static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id)
}
adap = &dev->adap;
+ adap->dev.of_node = np;
adap->dev.parent = &adev->dev;
adap->owner = THIS_MODULE;
adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
@@ -1002,6 +1016,8 @@ static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id)
goto err_add_adap;
}
+ of_i2c_register_devices(adap);
+
pm_runtime_put(&adev->dev);
return 0;
@@ -1009,8 +1025,6 @@ static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id)
err_add_adap:
clk_put(dev->clk);
err_no_clk:
- if (dev->regulator)
- regulator_put(dev->regulator);
free_irq(dev->irq, dev);
err_irq:
iounmap(dev->virtbase);
@@ -1038,8 +1052,6 @@ static int nmk_i2c_remove(struct amba_device *adev)
if (res)
release_mem_region(res->start, resource_size(res));
clk_put(dev->clk);
- if (dev->regulator)
- regulator_put(dev->regulator);
pm_runtime_disable(&adev->dev);
amba_set_drvdata(adev, NULL);
kfree(dev);
diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c
index a0e49f6..db31eae 100644
--- a/drivers/i2c/busses/i2c-omap.c
+++ b/drivers/i2c/busses/i2c-omap.c
@@ -43,6 +43,7 @@
#include <linux/slab.h>
#include <linux/i2c-omap.h>
#include <linux/pm_runtime.h>
+#include <linux/pm_qos.h>
/* I2C controller revisions */
#define OMAP_I2C_OMAP1_REV_2 0x20
@@ -55,6 +56,9 @@
/* timeout waiting for the controller to respond */
#define OMAP_I2C_TIMEOUT (msecs_to_jiffies(1000))
+/* timeout for pm runtime autosuspend */
+#define OMAP_I2C_PM_TIMEOUT 1000 /* ms */
+
/* For OMAP3 I2C_IV has changed to I2C_WE (wakeup enable) */
enum {
OMAP_I2C_REV_REG = 0,
@@ -176,15 +180,15 @@ enum {
#define I2C_OMAP_ERRATA_I462 (1 << 1)
struct omap_i2c_dev {
+ spinlock_t lock; /* IRQ synchronization */
struct device *dev;
void __iomem *base; /* virtual */
int irq;
int reg_shift; /* bit shift for I2C register addresses */
struct completion cmd_complete;
struct resource *ioarea;
- u32 latency; /* maximum mpu wkup latency */
- void (*set_mpu_wkup_lat)(struct device *dev,
- long latency);
+ u32 latency; /* maximum MPU wkup latency */
+ struct pm_qos_request pm_qos_request;
u32 speed; /* Speed of bus in kHz */
u32 dtrev; /* extra revision from DT */
u32 flags;
@@ -193,12 +197,14 @@ struct omap_i2c_dev {
u8 *regs;
size_t buf_len;
struct i2c_adapter adapter;
+ u8 threshold;
u8 fifo_size; /* use as flag and value
* fifo_size==0 implies no fifo
* if set, should be trsh+1
*/
u8 rev;
unsigned b_hw:1; /* bad h/w fixes */
+ unsigned receiver:1; /* true when we're in receiver mode */
u16 iestate; /* Saved interrupt register */
u16 pscstate;
u16 scllstate;
@@ -417,13 +423,6 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)
omap_i2c_write_reg(dev, OMAP_I2C_SCLL_REG, scll);
omap_i2c_write_reg(dev, OMAP_I2C_SCLH_REG, sclh);
- if (dev->fifo_size) {
- /* Note: setup required fifo size - 1. RTRSH and XTRSH */
- buf = (dev->fifo_size - 1) << 8 | OMAP_I2C_BUF_RXFIF_CLR |
- (dev->fifo_size - 1) | OMAP_I2C_BUF_TXFIF_CLR;
- omap_i2c_write_reg(dev, OMAP_I2C_BUF_REG, buf);
- }
-
/* Take the I2C module out of reset: */
omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN);
@@ -461,6 +460,43 @@ static int omap_i2c_wait_for_bb(struct omap_i2c_dev *dev)
return 0;
}
+static void omap_i2c_resize_fifo(struct omap_i2c_dev *dev, u8 size, bool is_rx)
+{
+ u16 buf;
+
+ if (dev->flags & OMAP_I2C_FLAG_NO_FIFO)
+ return;
+
+ /*
+ * Set up notification threshold based on message size. We're doing
+ * this to try and avoid draining feature as much as possible. Whenever
+ * we have big messages to transfer (bigger than our total fifo size)
+ * then we might use draining feature to transfer the remaining bytes.
+ */
+
+ dev->threshold = clamp(size, (u8) 1, dev->fifo_size);
+
+ buf = omap_i2c_read_reg(dev, OMAP_I2C_BUF_REG);
+
+ if (is_rx) {
+ /* Clear RX Threshold */
+ buf &= ~(0x3f << 8);
+ buf |= ((dev->threshold - 1) << 8) | OMAP_I2C_BUF_RXFIF_CLR;
+ } else {
+ /* Clear TX Threshold */
+ buf &= ~0x3f;
+ buf |= (dev->threshold - 1) | OMAP_I2C_BUF_TXFIF_CLR;
+ }
+
+ omap_i2c_write_reg(dev, OMAP_I2C_BUF_REG, buf);
+
+ if (dev->rev < OMAP_I2C_REV_ON_3630_4430)
+ dev->b_hw = 1; /* Enable hardware fixes */
+
+ /* calculate wakeup latency constraint for MPU */
+ dev->latency = (1000000 * dev->threshold) / (1000 * dev->speed / 8);
+}
+
/*
* Low level master read/write transaction.
*/
@@ -477,6 +513,9 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
if (msg->len == 0)
return -EINVAL;
+ dev->receiver = !!(msg->flags & I2C_M_RD);
+ omap_i2c_resize_fifo(dev, msg->len, dev->receiver);
+
omap_i2c_write_reg(dev, OMAP_I2C_SA_REG, msg->addr);
/* REVISIT: Could the STB bit of I2C_CON be used with probing? */
@@ -590,8 +629,16 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
if (r < 0)
goto out;
- if (dev->set_mpu_wkup_lat != NULL)
- dev->set_mpu_wkup_lat(dev->dev, dev->latency);
+ /*
+ * When waiting for completion of a i2c transfer, we need to
+ * set a wake up latency constraint for the MPU. This is to
+ * ensure quick enough wakeup from idle, when transfer
+ * completes.
+ */
+ if (dev->latency)
+ pm_qos_add_request(&dev->pm_qos_request,
+ PM_QOS_CPU_DMA_LATENCY,
+ dev->latency);
for (i = 0; i < num; i++) {
r = omap_i2c_xfer_msg(adap, &msgs[i], (i == (num - 1)));
@@ -599,15 +646,16 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
break;
}
- if (dev->set_mpu_wkup_lat != NULL)
- dev->set_mpu_wkup_lat(dev->dev, -1);
+ if (dev->latency)
+ pm_qos_remove_request(&dev->pm_qos_request);
if (r == 0)
r = num;
omap_i2c_wait_for_bb(dev);
out:
- pm_runtime_put(dev->dev);
+ pm_runtime_mark_last_busy(dev->dev);
+ pm_runtime_put_autosuspend(dev->dev);
return r;
}
@@ -725,186 +773,252 @@ omap_i2c_omap1_isr(int this_irq, void *dev_id)
* data to DATA_REG. Otherwise some data bytes can be lost while transferring
* them from the memory to the I2C interface.
*/
-static int errata_omap3_i462(struct omap_i2c_dev *dev, u16 *stat, int *err)
+static int errata_omap3_i462(struct omap_i2c_dev *dev)
{
unsigned long timeout = 10000;
+ u16 stat;
- while (--timeout && !(*stat & OMAP_I2C_STAT_XUDF)) {
- if (*stat & (OMAP_I2C_STAT_NACK | OMAP_I2C_STAT_AL)) {
- omap_i2c_ack_stat(dev, *stat & (OMAP_I2C_STAT_XRDY |
+ do {
+ stat = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG);
+ if (stat & OMAP_I2C_STAT_XUDF)
+ break;
+
+ if (stat & (OMAP_I2C_STAT_NACK | OMAP_I2C_STAT_AL)) {
+ omap_i2c_ack_stat(dev, (OMAP_I2C_STAT_XRDY |
OMAP_I2C_STAT_XDR));
- return -ETIMEDOUT;
+ if (stat & OMAP_I2C_STAT_NACK) {
+ dev->cmd_err |= OMAP_I2C_STAT_NACK;
+ omap_i2c_ack_stat(dev, OMAP_I2C_STAT_NACK);
+ }
+
+ if (stat & OMAP_I2C_STAT_AL) {
+ dev_err(dev->dev, "Arbitration lost\n");
+ dev->cmd_err |= OMAP_I2C_STAT_AL;
+ omap_i2c_ack_stat(dev, OMAP_I2C_STAT_NACK);
+ }
+
+ return -EIO;
}
cpu_relax();
- *stat = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG);
- }
+ } while (--timeout);
if (!timeout) {
dev_err(dev->dev, "timeout waiting on XUDF bit\n");
return 0;
}
- *err |= OMAP_I2C_STAT_XUDF;
return 0;
}
+static void omap_i2c_receive_data(struct omap_i2c_dev *dev, u8 num_bytes,
+ bool is_rdr)
+{
+ u16 w;
+
+ while (num_bytes--) {
+ w = omap_i2c_read_reg(dev, OMAP_I2C_DATA_REG);
+ *dev->buf++ = w;
+ dev->buf_len--;
+
+ /*
+ * Data reg in 2430, omap3 and
+ * omap4 is 8 bit wide
+ */
+ if (dev->flags & OMAP_I2C_FLAG_16BIT_DATA_REG) {
+ *dev->buf++ = w >> 8;
+ dev->buf_len--;
+ }
+ }
+}
+
+static int omap_i2c_transmit_data(struct omap_i2c_dev *dev, u8 num_bytes,
+ bool is_xdr)
+{
+ u16 w;
+
+ while (num_bytes--) {
+ w = *dev->buf++;
+ dev->buf_len--;
+
+ /*
+ * Data reg in 2430, omap3 and
+ * omap4 is 8 bit wide
+ */
+ if (dev->flags & OMAP_I2C_FLAG_16BIT_DATA_REG) {
+ w |= *dev->buf++ << 8;
+ dev->buf_len--;
+ }
+
+ if (dev->errata & I2C_OMAP_ERRATA_I462) {
+ int ret;
+
+ ret = errata_omap3_i462(dev);
+ if (ret < 0)
+ return ret;
+ }
+
+ omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w);
+ }
+
+ return 0;
+}
+
+static irqreturn_t
+omap_i2c_isr(int irq, void *dev_id)
+{
+ struct omap_i2c_dev *dev = dev_id;
+ irqreturn_t ret = IRQ_HANDLED;
+ u16 mask;
+ u16 stat;
+
+ spin_lock(&dev->lock);
+ mask = omap_i2c_read_reg(dev, OMAP_I2C_IE_REG);
+ stat = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG);
+
+ if (stat & mask)
+ ret = IRQ_WAKE_THREAD;
+
+ spin_unlock(&dev->lock);
+
+ return ret;
+}
+
static irqreturn_t
-omap_i2c_isr(int this_irq, void *dev_id)
+omap_i2c_isr_thread(int this_irq, void *dev_id)
{
struct omap_i2c_dev *dev = dev_id;
+ unsigned long flags;
u16 bits;
- u16 stat, w;
- int err, count = 0;
+ u16 stat;
+ int err = 0, count = 0;
+
+ spin_lock_irqsave(&dev->lock, flags);
+ do {
+ bits = omap_i2c_read_reg(dev, OMAP_I2C_IE_REG);
+ stat = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG);
+ stat &= bits;
+
+ /* If we're in receiver mode, ignore XDR/XRDY */
+ if (dev->receiver)
+ stat &= ~(OMAP_I2C_STAT_XDR | OMAP_I2C_STAT_XRDY);
+ else
+ stat &= ~(OMAP_I2C_STAT_RDR | OMAP_I2C_STAT_RRDY);
- if (pm_runtime_suspended(dev->dev))
- return IRQ_NONE;
+ if (!stat) {
+ /* my work here is done */
+ goto out;
+ }
- bits = omap_i2c_read_reg(dev, OMAP_I2C_IE_REG);
- while ((stat = (omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG))) & bits) {
dev_dbg(dev->dev, "IRQ (ISR = 0x%04x)\n", stat);
if (count++ == 100) {
dev_warn(dev->dev, "Too much work in one IRQ\n");
break;
}
- err = 0;
-complete:
- /*
- * Ack the stat in one go, but [R/X]DR and [R/X]RDY should be
- * acked after the data operation is complete.
- * Ref: TRM SWPU114Q Figure 18-31
- */
- omap_i2c_write_reg(dev, OMAP_I2C_STAT_REG, stat &
- ~(OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR |
- OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR));
-
- if (stat & OMAP_I2C_STAT_NACK)
+ if (stat & OMAP_I2C_STAT_NACK) {
err |= OMAP_I2C_STAT_NACK;
+ omap_i2c_ack_stat(dev, OMAP_I2C_STAT_NACK);
+ break;
+ }
if (stat & OMAP_I2C_STAT_AL) {
dev_err(dev->dev, "Arbitration lost\n");
err |= OMAP_I2C_STAT_AL;
+ omap_i2c_ack_stat(dev, OMAP_I2C_STAT_AL);
+ break;
}
+
/*
* ProDB0017052: Clear ARDY bit twice
*/
if (stat & (OMAP_I2C_STAT_ARDY | OMAP_I2C_STAT_NACK |
OMAP_I2C_STAT_AL)) {
- omap_i2c_ack_stat(dev, stat &
- (OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR |
- OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR |
- OMAP_I2C_STAT_ARDY));
- omap_i2c_complete_cmd(dev, err);
- return IRQ_HANDLED;
+ omap_i2c_ack_stat(dev, (OMAP_I2C_STAT_RRDY |
+ OMAP_I2C_STAT_RDR |
+ OMAP_I2C_STAT_XRDY |
+ OMAP_I2C_STAT_XDR |
+ OMAP_I2C_STAT_ARDY));
+ break;
}
- if (stat & (OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR)) {
+
+ if (stat & OMAP_I2C_STAT_RDR) {
u8 num_bytes = 1;
+ if (dev->fifo_size)
+ num_bytes = dev->buf_len;
+
+ omap_i2c_receive_data(dev, num_bytes, true);
+
if (dev->errata & I2C_OMAP_ERRATA_I207)
i2c_omap_errata_i207(dev, stat);
- if (dev->fifo_size) {
- if (stat & OMAP_I2C_STAT_RRDY)
- num_bytes = dev->fifo_size;
- else /* read RXSTAT on RDR interrupt */
- num_bytes = (omap_i2c_read_reg(dev,
- OMAP_I2C_BUFSTAT_REG)
- >> 8) & 0x3F;
- }
- while (num_bytes) {
- num_bytes--;
- w = omap_i2c_read_reg(dev, OMAP_I2C_DATA_REG);
- if (dev->buf_len) {
- *dev->buf++ = w;
- dev->buf_len--;
- /*
- * Data reg in 2430, omap3 and
- * omap4 is 8 bit wide
- */
- if (dev->flags &
- OMAP_I2C_FLAG_16BIT_DATA_REG) {
- if (dev->buf_len) {
- *dev->buf++ = w >> 8;
- dev->buf_len--;
- }
- }
- } else {
- if (stat & OMAP_I2C_STAT_RRDY)
- dev_err(dev->dev,
- "RRDY IRQ while no data"
- " requested\n");
- if (stat & OMAP_I2C_STAT_RDR)
- dev_err(dev->dev,
- "RDR IRQ while no data"
- " requested\n");
- break;
- }
- }
- omap_i2c_ack_stat(dev,
- stat & (OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR));
+ omap_i2c_ack_stat(dev, OMAP_I2C_STAT_RDR);
+ break;
+ }
+
+ if (stat & OMAP_I2C_STAT_RRDY) {
+ u8 num_bytes = 1;
+
+ if (dev->threshold)
+ num_bytes = dev->threshold;
+
+ omap_i2c_receive_data(dev, num_bytes, false);
+ omap_i2c_ack_stat(dev, OMAP_I2C_STAT_RRDY);
continue;
}
- if (stat & (OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR)) {
+
+ if (stat & OMAP_I2C_STAT_XDR) {
u8 num_bytes = 1;
- if (dev->fifo_size) {
- if (stat & OMAP_I2C_STAT_XRDY)
- num_bytes = dev->fifo_size;
- else /* read TXSTAT on XDR interrupt */
- num_bytes = omap_i2c_read_reg(dev,
- OMAP_I2C_BUFSTAT_REG)
- & 0x3F;
- }
- while (num_bytes) {
- num_bytes--;
- w = 0;
- if (dev->buf_len) {
- w = *dev->buf++;
- dev->buf_len--;
- /*
- * Data reg in 2430, omap3 and
- * omap4 is 8 bit wide
- */
- if (dev->flags &
- OMAP_I2C_FLAG_16BIT_DATA_REG) {
- if (dev->buf_len) {
- w |= *dev->buf++ << 8;
- dev->buf_len--;
- }
- }
- } else {
- if (stat & OMAP_I2C_STAT_XRDY)
- dev_err(dev->dev,
- "XRDY IRQ while no "
- "data to send\n");
- if (stat & OMAP_I2C_STAT_XDR)
- dev_err(dev->dev,
- "XDR IRQ while no "
- "data to send\n");
- break;
- }
-
- if ((dev->errata & I2C_OMAP_ERRATA_I462) &&
- errata_omap3_i462(dev, &stat, &err))
- goto complete;
-
- omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w);
- }
- omap_i2c_ack_stat(dev,
- stat & (OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR));
+ int ret;
+
+ if (dev->fifo_size)
+ num_bytes = dev->buf_len;
+
+ ret = omap_i2c_transmit_data(dev, num_bytes, true);
+ if (ret < 0)
+ break;
+
+ omap_i2c_ack_stat(dev, OMAP_I2C_STAT_XDR);
+ break;
+ }
+
+ if (stat & OMAP_I2C_STAT_XRDY) {
+ u8 num_bytes = 1;
+ int ret;
+
+ if (dev->threshold)
+ num_bytes = dev->threshold;
+
+ ret = omap_i2c_transmit_data(dev, num_bytes, false);
+ if (ret < 0)
+ break;
+
+ omap_i2c_ack_stat(dev, OMAP_I2C_STAT_XRDY);
continue;
}
+
if (stat & OMAP_I2C_STAT_ROVR) {
dev_err(dev->dev, "Receive overrun\n");
- dev->cmd_err |= OMAP_I2C_STAT_ROVR;
+ err |= OMAP_I2C_STAT_ROVR;
+ omap_i2c_ack_stat(dev, OMAP_I2C_STAT_ROVR);
+ break;
}
+
if (stat & OMAP_I2C_STAT_XUDF) {
dev_err(dev->dev, "Transmit underflow\n");
- dev->cmd_err |= OMAP_I2C_STAT_XUDF;
+ err |= OMAP_I2C_STAT_XUDF;
+ omap_i2c_ack_stat(dev, OMAP_I2C_STAT_XUDF);
+ break;
}
- }
+ } while (stat);
+
+ omap_i2c_complete_cmd(dev, err);
+
+out:
+ spin_unlock_irqrestore(&dev->lock, flags);
- return count ? IRQ_HANDLED : IRQ_NONE;
+ return IRQ_HANDLED;
}
static const struct i2c_algorithm omap_i2c_algo = {
@@ -943,12 +1057,12 @@ omap_i2c_probe(struct platform_device *pdev)
{
struct omap_i2c_dev *dev;
struct i2c_adapter *adap;
- struct resource *mem, *irq, *ioarea;
+ struct resource *mem;
const struct omap_i2c_bus_platform_data *pdata =
pdev->dev.platform_data;
struct device_node *node = pdev->dev.of_node;
const struct of_device_id *match;
- irq_handler_t isr;
+ int irq;
int r;
/* NOTE: driver uses the static register mapping */
@@ -957,23 +1071,23 @@ omap_i2c_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "no mem resource?\n");
return -ENODEV;
}
- irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
- if (!irq) {
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
dev_err(&pdev->dev, "no irq resource?\n");
- return -ENODEV;
+ return irq;
}
- ioarea = request_mem_region(mem->start, resource_size(mem),
- pdev->name);
- if (!ioarea) {
- dev_err(&pdev->dev, "I2C region already claimed\n");
- return -EBUSY;
+ dev = devm_kzalloc(&pdev->dev, sizeof(struct omap_i2c_dev), GFP_KERNEL);
+ if (!dev) {
+ dev_err(&pdev->dev, "Menory allocation failed\n");
+ return -ENOMEM;
}
- dev = kzalloc(sizeof(struct omap_i2c_dev), GFP_KERNEL);
- if (!dev) {
- r = -ENOMEM;
- goto err_release_region;
+ dev->base = devm_request_and_ioremap(&pdev->dev, mem);
+ if (!dev->base) {
+ dev_err(&pdev->dev, "I2C region already claimed\n");
+ return -ENOMEM;
}
match = of_match_device(of_match_ptr(omap_i2c_of_match), &pdev->dev);
@@ -990,17 +1104,13 @@ omap_i2c_probe(struct platform_device *pdev)
} else if (pdata != NULL) {
dev->speed = pdata->clkrate;
dev->flags = pdata->flags;
- dev->set_mpu_wkup_lat = pdata->set_mpu_wkup_lat;
dev->dtrev = pdata->rev;
}
dev->dev = &pdev->dev;
- dev->irq = irq->start;
- dev->base = ioremap(mem->start, resource_size(mem));
- if (!dev->base) {
- r = -ENOMEM;
- goto err_free_mem;
- }
+ dev->irq = irq;
+
+ spin_lock_init(&dev->lock);
platform_set_drvdata(pdev, dev);
init_completion(&dev->cmd_complete);
@@ -1013,6 +1123,9 @@ omap_i2c_probe(struct platform_device *pdev)
dev->regs = (u8 *)reg_map_ip_v1;
pm_runtime_enable(dev->dev);
+ pm_runtime_set_autosuspend_delay(dev->dev, OMAP_I2C_PM_TIMEOUT);
+ pm_runtime_use_autosuspend(dev->dev);
+
r = pm_runtime_get_sync(dev->dev);
if (IS_ERR_VALUE(r))
goto err_free_mem;
@@ -1042,32 +1155,31 @@ omap_i2c_probe(struct platform_device *pdev)
dev->fifo_size = (dev->fifo_size / 2);
- if (dev->rev >= OMAP_I2C_REV_ON_3630_4430)
- dev->b_hw = 0; /* Disable hardware fixes */
- else
+ if (dev->rev < OMAP_I2C_REV_ON_3630_4430)
dev->b_hw = 1; /* Enable hardware fixes */
/* calculate wakeup latency constraint for MPU */
- if (dev->set_mpu_wkup_lat != NULL)
- dev->latency = (1000000 * dev->fifo_size) /
- (1000 * dev->speed / 8);
+ dev->latency = (1000000 * dev->fifo_size) /
+ (1000 * dev->speed / 8);
}
/* reset ASAP, clearing any IRQs */
omap_i2c_init(dev);
- isr = (dev->rev < OMAP_I2C_OMAP1_REV_2) ? omap_i2c_omap1_isr :
- omap_i2c_isr;
- r = request_irq(dev->irq, isr, IRQF_NO_SUSPEND, pdev->name, dev);
+ if (dev->rev < OMAP_I2C_OMAP1_REV_2)
+ r = devm_request_irq(&pdev->dev, dev->irq, omap_i2c_omap1_isr,
+ IRQF_NO_SUSPEND, pdev->name, dev);
+ else
+ r = devm_request_threaded_irq(&pdev->dev, dev->irq,
+ omap_i2c_isr, omap_i2c_isr_thread,
+ IRQF_NO_SUSPEND | IRQF_ONESHOT,
+ pdev->name, dev);
if (r) {
dev_err(dev->dev, "failure requesting irq %i\n", dev->irq);
goto err_unuse_clocks;
}
- dev_info(dev->dev, "bus %d rev%d.%d.%d at %d kHz\n", pdev->id,
- dev->dtrev, dev->rev >> 4, dev->rev & 0xf, dev->speed);
-
adap = &dev->adapter;
i2c_set_adapdata(adap, dev);
adap->owner = THIS_MODULE;
@@ -1082,27 +1194,25 @@ omap_i2c_probe(struct platform_device *pdev)
r = i2c_add_numbered_adapter(adap);
if (r) {
dev_err(dev->dev, "failure adding adapter\n");
- goto err_free_irq;
+ goto err_unuse_clocks;
}
+ dev_info(dev->dev, "bus %d rev%d.%d.%d at %d kHz\n", adap->nr,
+ dev->dtrev, dev->rev >> 4, dev->rev & 0xf, dev->speed);
+
of_i2c_register_devices(adap);
- pm_runtime_put(dev->dev);
+ pm_runtime_mark_last_busy(dev->dev);
+ pm_runtime_put_autosuspend(dev->dev);
return 0;
-err_free_irq:
- free_irq(dev->irq, dev);
err_unuse_clocks:
omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0);
pm_runtime_put(dev->dev);
- iounmap(dev->base);
pm_runtime_disable(&pdev->dev);
err_free_mem:
platform_set_drvdata(pdev, NULL);
- kfree(dev);
-err_release_region:
- release_mem_region(mem->start, resource_size(mem));
return r;
}
@@ -1110,12 +1220,10 @@ err_release_region:
static int __devexit omap_i2c_remove(struct platform_device *pdev)
{
struct omap_i2c_dev *dev = platform_get_drvdata(pdev);
- struct resource *mem;
int ret;
platform_set_drvdata(pdev, NULL);
- free_irq(dev->irq, dev);
i2c_del_adapter(&dev->adapter);
ret = pm_runtime_get_sync(&pdev->dev);
if (IS_ERR_VALUE(ret))
@@ -1124,10 +1232,6 @@ static int __devexit omap_i2c_remove(struct platform_device *pdev)
omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0);
pm_runtime_put(&pdev->dev);
pm_runtime_disable(&pdev->dev);
- iounmap(dev->base);
- kfree(dev);
- mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- release_mem_region(mem->start, resource_size(mem));
return 0;
}
diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c
new file mode 100644
index 0000000..f9399d1
--- /dev/null
+++ b/drivers/i2c/busses/i2c-rcar.c
@@ -0,0 +1,709 @@
+/*
+ * drivers/i2c/busses/i2c-rcar.c
+ *
+ * Copyright (C) 2012 Renesas Solutions Corp.
+ * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+ *
+ * This file is based on the drivers/i2c/busses/i2c-sh7760.c
+ * (c) 2005-2008 MSC Vertriebsges.m.b.H, Manuel Lauss <mlau@msc-ge.com>
+ *
+ * This file used out-of-tree driver i2c-rcar.c
+ * Copyright (C) 2011-2012 Renesas Electronics 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
+ *
+ * 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/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/i2c.h>
+#include <linux/i2c/i2c-rcar.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+/* register offsets */
+#define ICSCR 0x00 /* slave ctrl */
+#define ICMCR 0x04 /* master ctrl */
+#define ICSSR 0x08 /* slave status */
+#define ICMSR 0x0C /* master status */
+#define ICSIER 0x10 /* slave irq enable */
+#define ICMIER 0x14 /* master irq enable */
+#define ICCCR 0x18 /* clock dividers */
+#define ICSAR 0x1C /* slave address */
+#define ICMAR 0x20 /* master address */
+#define ICRXTX 0x24 /* data port */
+
+/* ICMCR */
+#define MDBS (1 << 7) /* non-fifo mode switch */
+#define FSCL (1 << 6) /* override SCL pin */
+#define FSDA (1 << 5) /* override SDA pin */
+#define OBPC (1 << 4) /* override pins */
+#define MIE (1 << 3) /* master if enable */
+#define TSBE (1 << 2)
+#define FSB (1 << 1) /* force stop bit */
+#define ESG (1 << 0) /* en startbit gen */
+
+/* ICMSR */
+#define MNR (1 << 6) /* nack received */
+#define MAL (1 << 5) /* arbitration lost */
+#define MST (1 << 4) /* sent a stop */
+#define MDE (1 << 3)
+#define MDT (1 << 2)
+#define MDR (1 << 1)
+#define MAT (1 << 0) /* slave addr xfer done */
+
+/* ICMIE */
+#define MNRE (1 << 6) /* nack irq en */
+#define MALE (1 << 5) /* arblos irq en */
+#define MSTE (1 << 4) /* stop irq en */
+#define MDEE (1 << 3)
+#define MDTE (1 << 2)
+#define MDRE (1 << 1)
+#define MATE (1 << 0) /* address sent irq en */
+
+
+enum {
+ RCAR_BUS_PHASE_ADDR,
+ RCAR_BUS_PHASE_DATA,
+ RCAR_BUS_PHASE_STOP,
+};
+
+enum {
+ RCAR_IRQ_CLOSE,
+ RCAR_IRQ_OPEN_FOR_SEND,
+ RCAR_IRQ_OPEN_FOR_RECV,
+ RCAR_IRQ_OPEN_FOR_STOP,
+};
+
+/*
+ * flags
+ */
+#define ID_LAST_MSG (1 << 0)
+#define ID_IOERROR (1 << 1)
+#define ID_DONE (1 << 2)
+#define ID_ARBLOST (1 << 3)
+#define ID_NACK (1 << 4)
+
+struct rcar_i2c_priv {
+ void __iomem *io;
+ struct i2c_adapter adap;
+ struct i2c_msg *msg;
+
+ spinlock_t lock;
+ wait_queue_head_t wait;
+
+ int pos;
+ int irq;
+ u32 icccr;
+ u32 flags;
+};
+
+#define rcar_i2c_priv_to_dev(p) ((p)->adap.dev.parent)
+#define rcar_i2c_is_recv(p) ((p)->msg->flags & I2C_M_RD)
+
+#define rcar_i2c_flags_set(p, f) ((p)->flags |= (f))
+#define rcar_i2c_flags_has(p, f) ((p)->flags & (f))
+
+#define LOOP_TIMEOUT 1024
+
+/*
+ * basic functions
+ */
+static void rcar_i2c_write(struct rcar_i2c_priv *priv, int reg, u32 val)
+{
+ writel(val, priv->io + reg);
+}
+
+static u32 rcar_i2c_read(struct rcar_i2c_priv *priv, int reg)
+{
+ return readl(priv->io + reg);
+}
+
+static void rcar_i2c_init(struct rcar_i2c_priv *priv)
+{
+ /*
+ * reset slave mode.
+ * slave mode is not used on this driver
+ */
+ rcar_i2c_write(priv, ICSIER, 0);
+ rcar_i2c_write(priv, ICSAR, 0);
+ rcar_i2c_write(priv, ICSCR, 0);
+ rcar_i2c_write(priv, ICSSR, 0);
+
+ /* reset master mode */
+ rcar_i2c_write(priv, ICMIER, 0);
+ rcar_i2c_write(priv, ICMCR, 0);
+ rcar_i2c_write(priv, ICMSR, 0);
+ rcar_i2c_write(priv, ICMAR, 0);
+}
+
+static void rcar_i2c_irq_mask(struct rcar_i2c_priv *priv, int open)
+{
+ u32 val = MNRE | MALE | MSTE | MATE; /* default */
+
+ switch (open) {
+ case RCAR_IRQ_OPEN_FOR_SEND:
+ val |= MDEE; /* default + send */
+ break;
+ case RCAR_IRQ_OPEN_FOR_RECV:
+ val |= MDRE; /* default + read */
+ break;
+ case RCAR_IRQ_OPEN_FOR_STOP:
+ val = MSTE; /* stop irq only */
+ break;
+ case RCAR_IRQ_CLOSE:
+ default:
+ val = 0; /* all close */
+ break;
+ }
+ rcar_i2c_write(priv, ICMIER, val);
+}
+
+static void rcar_i2c_set_addr(struct rcar_i2c_priv *priv, u32 recv)
+{
+ rcar_i2c_write(priv, ICMAR, (priv->msg->addr << 1) | recv);
+}
+
+/*
+ * bus control functions
+ */
+static int rcar_i2c_bus_barrier(struct rcar_i2c_priv *priv)
+{
+ int i;
+
+ for (i = 0; i < LOOP_TIMEOUT; i++) {
+ /* make sure that bus is not busy */
+ if (!(rcar_i2c_read(priv, ICMCR) & FSDA))
+ return 0;
+ udelay(1);
+ }
+
+ return -EBUSY;
+}
+
+static void rcar_i2c_bus_phase(struct rcar_i2c_priv *priv, int phase)
+{
+ switch (phase) {
+ case RCAR_BUS_PHASE_ADDR:
+ rcar_i2c_write(priv, ICMCR, MDBS | MIE | ESG);
+ break;
+ case RCAR_BUS_PHASE_DATA:
+ rcar_i2c_write(priv, ICMCR, MDBS | MIE);
+ break;
+ case RCAR_BUS_PHASE_STOP:
+ rcar_i2c_write(priv, ICMCR, MDBS | MIE | FSB);
+ break;
+ }
+}
+
+/*
+ * clock function
+ */
+static int rcar_i2c_clock_calculate(struct rcar_i2c_priv *priv,
+ u32 bus_speed,
+ struct device *dev)
+{
+ struct clk *clkp = clk_get(NULL, "peripheral_clk");
+ u32 scgd, cdf;
+ u32 round, ick;
+ u32 scl;
+
+ if (!clkp) {
+ dev_err(dev, "there is no peripheral_clk\n");
+ return -EIO;
+ }
+
+ /*
+ * calculate SCL clock
+ * see
+ * ICCCR
+ *
+ * ick = clkp / (1 + CDF)
+ * SCL = ick / (20 + SCGD * 8 + F[(ticf + tr + intd) * ick])
+ *
+ * ick : I2C internal clock < 20 MHz
+ * ticf : I2C SCL falling time = 35 ns here
+ * tr : I2C SCL rising time = 200 ns here
+ * intd : LSI internal delay = 50 ns here
+ * clkp : peripheral_clk
+ * F[] : integer up-valuation
+ */
+ for (cdf = 0; cdf < 4; cdf++) {
+ ick = clk_get_rate(clkp) / (1 + cdf);
+ if (ick < 20000000)
+ goto ick_find;
+ }
+ dev_err(dev, "there is no best CDF\n");
+ return -EIO;
+
+ick_find:
+ /*
+ * it is impossible to calculate large scale
+ * number on u32. separate it
+ *
+ * F[(ticf + tr + intd) * ick]
+ * = F[(35 + 200 + 50)ns * ick]
+ * = F[285 * ick / 1000000000]
+ * = F[(ick / 1000000) * 285 / 1000]
+ */
+ round = (ick + 500000) / 1000000 * 285;
+ round = (round + 500) / 1000;
+
+ /*
+ * SCL = ick / (20 + SCGD * 8 + F[(ticf + tr + intd) * ick])
+ *
+ * Calculation result (= SCL) should be less than
+ * bus_speed for hardware safety
+ */
+ for (scgd = 0; scgd < 0x40; scgd++) {
+ scl = ick / (20 + (scgd * 8) + round);
+ if (scl <= bus_speed)
+ goto scgd_find;
+ }
+ dev_err(dev, "it is impossible to calculate best SCL\n");
+ return -EIO;
+
+scgd_find:
+ dev_dbg(dev, "clk %d/%d(%lu), round %u, CDF:0x%x, SCGD: 0x%x\n",
+ scl, bus_speed, clk_get_rate(clkp), round, cdf, scgd);
+
+ /*
+ * keep icccr value
+ */
+ priv->icccr = (scgd << 2 | cdf);
+
+ return 0;
+}
+
+static void rcar_i2c_clock_start(struct rcar_i2c_priv *priv)
+{
+ rcar_i2c_write(priv, ICCCR, priv->icccr);
+}
+
+/*
+ * status functions
+ */
+static u32 rcar_i2c_status_get(struct rcar_i2c_priv *priv)
+{
+ return rcar_i2c_read(priv, ICMSR);
+}
+
+#define rcar_i2c_status_clear(priv) rcar_i2c_status_bit_clear(priv, 0xffffffff)
+static void rcar_i2c_status_bit_clear(struct rcar_i2c_priv *priv, u32 bit)
+{
+ rcar_i2c_write(priv, ICMSR, ~bit);
+}
+
+/*
+ * recv/send functions
+ */
+static int rcar_i2c_recv(struct rcar_i2c_priv *priv)
+{
+ rcar_i2c_set_addr(priv, 1);
+ rcar_i2c_status_clear(priv);
+ rcar_i2c_bus_phase(priv, RCAR_BUS_PHASE_ADDR);
+ rcar_i2c_irq_mask(priv, RCAR_IRQ_OPEN_FOR_RECV);
+
+ return 0;
+}
+
+static int rcar_i2c_send(struct rcar_i2c_priv *priv)
+{
+ int ret;
+
+ /*
+ * It should check bus status when send case
+ */
+ ret = rcar_i2c_bus_barrier(priv);
+ if (ret < 0)
+ return ret;
+
+ rcar_i2c_set_addr(priv, 0);
+ rcar_i2c_status_clear(priv);
+ rcar_i2c_bus_phase(priv, RCAR_BUS_PHASE_ADDR);
+ rcar_i2c_irq_mask(priv, RCAR_IRQ_OPEN_FOR_SEND);
+
+ return 0;
+}
+
+#define rcar_i2c_send_restart(priv) rcar_i2c_status_bit_clear(priv, (MAT | MDE))
+#define rcar_i2c_recv_restart(priv) rcar_i2c_status_bit_clear(priv, (MAT | MDR))
+
+/*
+ * interrupt functions
+ */
+static int rcar_i2c_irq_send(struct rcar_i2c_priv *priv, u32 msr)
+{
+ struct i2c_msg *msg = priv->msg;
+
+ /*
+ * FIXME
+ * sometimes, unknown interrupt happened.
+ * Do nothing
+ */
+ if (!(msr & MDE))
+ return 0;
+
+ /*
+ * If address transfer phase finished,
+ * goto data phase.
+ */
+ if (msr & MAT)
+ rcar_i2c_bus_phase(priv, RCAR_BUS_PHASE_DATA);
+
+ if (priv->pos < msg->len) {
+ /*
+ * Prepare next data to ICRXTX register.
+ * This data will go to _SHIFT_ register.
+ *
+ * *
+ * [ICRXTX] -> [SHIFT] -> [I2C bus]
+ */
+ rcar_i2c_write(priv, ICRXTX, msg->buf[priv->pos]);
+ priv->pos++;
+
+ } else {
+ /*
+ * The last data was pushed to ICRXTX on _PREV_ empty irq.
+ * It is on _SHIFT_ register, and will sent to I2C bus.
+ *
+ * *
+ * [ICRXTX] -> [SHIFT] -> [I2C bus]
+ */
+
+ if (priv->flags & ID_LAST_MSG)
+ /*
+ * If current msg is the _LAST_ msg,
+ * prepare stop condition here.
+ * ID_DONE will be set on STOP irq.
+ */
+ rcar_i2c_bus_phase(priv, RCAR_BUS_PHASE_STOP);
+ else
+ /*
+ * If current msg is _NOT_ last msg,
+ * it doesn't call stop phase.
+ * thus, there is no STOP irq.
+ * return ID_DONE here.
+ */
+ return ID_DONE;
+ }
+
+ rcar_i2c_send_restart(priv);
+
+ return 0;
+}
+
+static int rcar_i2c_irq_recv(struct rcar_i2c_priv *priv, u32 msr)
+{
+ struct i2c_msg *msg = priv->msg;
+
+ /*
+ * FIXME
+ * sometimes, unknown interrupt happened.
+ * Do nothing
+ */
+ if (!(msr & MDR))
+ return 0;
+
+ if (msr & MAT) {
+ /*
+ * Address transfer phase finished,
+ * but, there is no data at this point.
+ * Do nothing.
+ */
+ } else if (priv->pos < msg->len) {
+ /*
+ * get received data
+ */
+ msg->buf[priv->pos] = rcar_i2c_read(priv, ICRXTX);
+ priv->pos++;
+ }
+
+ /*
+ * If next received data is the _LAST_,
+ * go to STOP phase,
+ * otherwise, go to DATA phase.
+ */
+ if (priv->pos + 1 >= msg->len)
+ rcar_i2c_bus_phase(priv, RCAR_BUS_PHASE_STOP);
+ else
+ rcar_i2c_bus_phase(priv, RCAR_BUS_PHASE_DATA);
+
+ rcar_i2c_recv_restart(priv);
+
+ return 0;
+}
+
+static irqreturn_t rcar_i2c_irq(int irq, void *ptr)
+{
+ struct rcar_i2c_priv *priv = ptr;
+ struct device *dev = rcar_i2c_priv_to_dev(priv);
+ u32 msr;
+
+ /*-------------- spin lock -----------------*/
+ spin_lock(&priv->lock);
+
+ msr = rcar_i2c_status_get(priv);
+
+ /*
+ * Arbitration lost
+ */
+ if (msr & MAL) {
+ /*
+ * CAUTION
+ *
+ * When arbitration lost, device become _slave_ mode.
+ */
+ dev_dbg(dev, "Arbitration Lost\n");
+ rcar_i2c_flags_set(priv, (ID_DONE | ID_ARBLOST));
+ goto out;
+ }
+
+ /*
+ * Stop
+ */
+ if (msr & MST) {
+ dev_dbg(dev, "Stop\n");
+ rcar_i2c_flags_set(priv, ID_DONE);
+ goto out;
+ }
+
+ /*
+ * Nack
+ */
+ if (msr & MNR) {
+ dev_dbg(dev, "Nack\n");
+
+ /* go to stop phase */
+ rcar_i2c_bus_phase(priv, RCAR_BUS_PHASE_STOP);
+ rcar_i2c_irq_mask(priv, RCAR_IRQ_OPEN_FOR_STOP);
+ rcar_i2c_flags_set(priv, ID_NACK);
+ goto out;
+ }
+
+ /*
+ * recv/send
+ */
+ if (rcar_i2c_is_recv(priv))
+ rcar_i2c_flags_set(priv, rcar_i2c_irq_recv(priv, msr));
+ else
+ rcar_i2c_flags_set(priv, rcar_i2c_irq_send(priv, msr));
+
+out:
+ if (rcar_i2c_flags_has(priv, ID_DONE)) {
+ rcar_i2c_irq_mask(priv, RCAR_IRQ_CLOSE);
+ rcar_i2c_status_clear(priv);
+ wake_up(&priv->wait);
+ }
+
+ spin_unlock(&priv->lock);
+ /*-------------- spin unlock -----------------*/
+
+ return IRQ_HANDLED;
+}
+
+static int rcar_i2c_master_xfer(struct i2c_adapter *adap,
+ struct i2c_msg *msgs,
+ int num)
+{
+ struct rcar_i2c_priv *priv = i2c_get_adapdata(adap);
+ struct device *dev = rcar_i2c_priv_to_dev(priv);
+ unsigned long flags;
+ int i, ret, timeout;
+
+ pm_runtime_get_sync(dev);
+
+ /*-------------- spin lock -----------------*/
+ spin_lock_irqsave(&priv->lock, flags);
+
+ rcar_i2c_init(priv);
+ rcar_i2c_clock_start(priv);
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+ /*-------------- spin unlock -----------------*/
+
+ ret = -EINVAL;
+ for (i = 0; i < num; i++) {
+ /*-------------- spin lock -----------------*/
+ spin_lock_irqsave(&priv->lock, flags);
+
+ /* init each data */
+ priv->msg = &msgs[i];
+ priv->pos = 0;
+ priv->flags = 0;
+ if (priv->msg == &msgs[num - 1])
+ rcar_i2c_flags_set(priv, ID_LAST_MSG);
+
+ /* start send/recv */
+ if (rcar_i2c_is_recv(priv))
+ ret = rcar_i2c_recv(priv);
+ else
+ ret = rcar_i2c_send(priv);
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+ /*-------------- spin unlock -----------------*/
+
+ if (ret < 0)
+ break;
+
+ /*
+ * wait result
+ */
+ timeout = wait_event_timeout(priv->wait,
+ rcar_i2c_flags_has(priv, ID_DONE),
+ 5 * HZ);
+ if (!timeout) {
+ ret = -ETIMEDOUT;
+ break;
+ }
+
+ /*
+ * error handling
+ */
+ if (rcar_i2c_flags_has(priv, ID_NACK)) {
+ ret = -EREMOTEIO;
+ break;
+ }
+
+ if (rcar_i2c_flags_has(priv, ID_ARBLOST)) {
+ ret = -EAGAIN;
+ break;
+ }
+
+ if (rcar_i2c_flags_has(priv, ID_IOERROR)) {
+ ret = -EIO;
+ break;
+ }
+
+ ret = i + 1; /* The number of transfer */
+ }
+
+ pm_runtime_put(dev);
+
+ if (ret < 0)
+ dev_err(dev, "error %d : %x\n", ret, priv->flags);
+
+ return ret;
+}
+
+static u32 rcar_i2c_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm rcar_i2c_algo = {
+ .master_xfer = rcar_i2c_master_xfer,
+ .functionality = rcar_i2c_func,
+};
+
+static int __devinit rcar_i2c_probe(struct platform_device *pdev)
+{
+ struct i2c_rcar_platform_data *pdata = pdev->dev.platform_data;
+ struct rcar_i2c_priv *priv;
+ struct i2c_adapter *adap;
+ struct resource *res;
+ struct device *dev = &pdev->dev;
+ u32 bus_speed;
+ int ret;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(dev, "no mmio resources\n");
+ return -ENODEV;
+ }
+
+ priv = devm_kzalloc(dev, sizeof(struct rcar_i2c_priv), GFP_KERNEL);
+ if (!priv) {
+ dev_err(dev, "no mem for private data\n");
+ return -ENOMEM;
+ }
+
+ bus_speed = 100000; /* default 100 kHz */
+ if (pdata && pdata->bus_speed)
+ bus_speed = pdata->bus_speed;
+ ret = rcar_i2c_clock_calculate(priv, bus_speed, dev);
+ if (ret < 0)
+ return ret;
+
+ priv->io = devm_ioremap(dev, res->start, resource_size(res));
+ if (!priv->io) {
+ dev_err(dev, "cannot ioremap\n");
+ return -ENODEV;
+ }
+
+ priv->irq = platform_get_irq(pdev, 0);
+ init_waitqueue_head(&priv->wait);
+ spin_lock_init(&priv->lock);
+
+ adap = &priv->adap;
+ adap->nr = pdev->id;
+ adap->algo = &rcar_i2c_algo;
+ adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
+ adap->retries = 3;
+ adap->dev.parent = dev;
+ i2c_set_adapdata(adap, priv);
+ strlcpy(adap->name, pdev->name, sizeof(adap->name));
+
+ ret = devm_request_irq(dev, priv->irq, rcar_i2c_irq, 0,
+ dev_name(dev), priv);
+ if (ret < 0) {
+ dev_err(dev, "cannot get irq %d\n", priv->irq);
+ return ret;
+ }
+
+ ret = i2c_add_numbered_adapter(adap);
+ if (ret < 0) {
+ dev_err(dev, "reg adap failed: %d\n", ret);
+ return ret;
+ }
+
+ pm_runtime_enable(dev);
+ platform_set_drvdata(pdev, priv);
+
+ dev_info(dev, "probed\n");
+
+ return 0;
+}
+
+static int __devexit rcar_i2c_remove(struct platform_device *pdev)
+{
+ struct rcar_i2c_priv *priv = platform_get_drvdata(pdev);
+ struct device *dev = &pdev->dev;
+
+ i2c_del_adapter(&priv->adap);
+ pm_runtime_disable(dev);
+
+ return 0;
+}
+
+static struct platform_driver rcar_i2c_drv = {
+ .driver = {
+ .name = "i2c-rcar",
+ .owner = THIS_MODULE,
+ },
+ .probe = rcar_i2c_probe,
+ .remove = __devexit_p(rcar_i2c_remove),
+};
+
+module_platform_driver(rcar_i2c_drv);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Renesas R-Car I2C bus driver");
+MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c
index 4d07dea..3e0335f 100644
--- a/drivers/i2c/busses/i2c-s3c2410.c
+++ b/drivers/i2c/busses/i2c-s3c2410.c
@@ -601,14 +601,14 @@ static int s3c24xx_i2c_xfer(struct i2c_adapter *adap,
int ret;
pm_runtime_get_sync(&adap->dev);
- clk_enable(i2c->clk);
+ clk_prepare_enable(i2c->clk);
for (retry = 0; retry < adap->retries; retry++) {
ret = s3c24xx_i2c_doxfer(i2c, msgs, num);
if (ret != -EAGAIN) {
- clk_disable(i2c->clk);
+ clk_disable_unprepare(i2c->clk);
pm_runtime_put(&adap->dev);
return ret;
}
@@ -618,7 +618,7 @@ static int s3c24xx_i2c_xfer(struct i2c_adapter *adap,
udelay(100);
}
- clk_disable(i2c->clk);
+ clk_disable_unprepare(i2c->clk);
pm_runtime_put(&adap->dev);
return -EREMOTEIO;
}
@@ -977,7 +977,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
dev_dbg(&pdev->dev, "clock source %p\n", i2c->clk);
- clk_enable(i2c->clk);
+ clk_prepare_enable(i2c->clk);
/* map the registers */
@@ -1065,7 +1065,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
pm_runtime_enable(&i2c->adap.dev);
dev_info(&pdev->dev, "%s: S3C I2C adapter\n", dev_name(&i2c->adap.dev));
- clk_disable(i2c->clk);
+ clk_disable_unprepare(i2c->clk);
return 0;
err_cpufreq:
@@ -1082,7 +1082,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
kfree(i2c->ioarea);
err_clk:
- clk_disable(i2c->clk);
+ clk_disable_unprepare(i2c->clk);
clk_put(i2c->clk);
err_noclk:
@@ -1106,7 +1106,7 @@ static int s3c24xx_i2c_remove(struct platform_device *pdev)
i2c_del_adapter(&i2c->adap);
free_irq(i2c->irq, i2c);
- clk_disable(i2c->clk);
+ clk_disable_unprepare(i2c->clk);
clk_put(i2c->clk);
iounmap(i2c->regs);
@@ -1135,9 +1135,9 @@ static int s3c24xx_i2c_resume(struct device *dev)
struct s3c24xx_i2c *i2c = platform_get_drvdata(pdev);
i2c->suspended = 0;
- clk_enable(i2c->clk);
+ clk_prepare_enable(i2c->clk);
s3c24xx_i2c_init(i2c);
- clk_disable(i2c->clk);
+ clk_disable_unprepare(i2c->clk);
return 0;
}
diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c
index 1983adc..a7568c3 100644
--- a/drivers/infiniband/core/cma.c
+++ b/drivers/infiniband/core/cma.c
@@ -3498,7 +3498,8 @@ out:
}
static const struct ibnl_client_cbs cma_cb_table[] = {
- [RDMA_NL_RDMA_CM_ID_STATS] = { .dump = cma_get_id_stats },
+ [RDMA_NL_RDMA_CM_ID_STATS] = { .dump = cma_get_id_stats,
+ .module = THIS_MODULE },
};
static int __init cma_init(void)
diff --git a/drivers/infiniband/core/netlink.c b/drivers/infiniband/core/netlink.c
index fe10a94..da06abd 100644
--- a/drivers/infiniband/core/netlink.c
+++ b/drivers/infiniband/core/netlink.c
@@ -154,6 +154,7 @@ static int ibnl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
{
struct netlink_dump_control c = {
.dump = client->cb_table[op].dump,
+ .module = client->cb_table[op].module,
};
return netlink_dump_start(nls, skb, nlh, &c);
}
diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c
index 9e1449f..cf23c46 100644
--- a/drivers/infiniband/ulp/srpt/ib_srpt.c
+++ b/drivers/infiniband/ulp/srpt/ib_srpt.c
@@ -3564,16 +3564,6 @@ static int srpt_get_tcm_cmd_state(struct se_cmd *se_cmd)
return srpt_get_cmd_state(ioctx);
}
-static u16 srpt_set_fabric_sense_len(struct se_cmd *cmd, u32 sense_length)
-{
- return 0;
-}
-
-static u16 srpt_get_fabric_sense_len(void)
-{
- return 0;
-}
-
/**
* srpt_parse_i_port_id() - Parse an initiator port ID.
* @name: ASCII representation of a 128-bit initiator port ID.
@@ -3953,8 +3943,6 @@ static struct target_core_fabric_ops srpt_template = {
.queue_data_in = srpt_queue_response,
.queue_status = srpt_queue_status,
.queue_tm_rsp = srpt_queue_response,
- .get_fabric_sense_len = srpt_get_fabric_sense_len,
- .set_fabric_sense_len = srpt_set_fabric_sense_len,
/*
* Setup function pointers for generic logic in
* target_core_fabric_configfs.c
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 16578d3..f508def 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -63,6 +63,17 @@ config LEDS_LM3533
hardware-accelerated blinking with maximum on and off periods of 9.8
and 77 seconds respectively.
+config LEDS_LM3642
+ tristate "LED support for LM3642 Chip"
+ depends on LEDS_CLASS && I2C
+ select REGMAP_I2C
+ help
+ This option enables support for LEDs connected to LM3642.
+ The LM3642 is a 4MHz fixed-frequency synchronous boost
+ converter plus 1.5A constant current driver for a high-current
+ white LED.
+
+
config LEDS_LOCOMO
tristate "LED Support for Locomo device"
depends on LEDS_CLASS
@@ -192,11 +203,12 @@ config LEDS_LP5521
programming the engines.
config LEDS_LP5523
- tristate "LED Support for N.S. LP5523 LED driver chip"
+ tristate "LED Support for TI/National LP5523/55231 LED driver chip"
depends on LEDS_CLASS && I2C
help
- If you say yes here you get support for the National Semiconductor
- LP5523 LED driver. It is 9 channel chip with programmable engines.
+ If you say yes here you get support for TI/National Semiconductor
+ LP5523/55231 LED driver.
+ It is 9 channel chip with programmable engines.
Driver provides direct control via LED class and interface for
programming the engines.
@@ -422,13 +434,13 @@ config LEDS_MAX8997
This option enables support for on-chip LED drivers on
MAXIM MAX8997 PMIC.
-config LEDS_LM3556
- tristate "LED support for LM3556 Chip"
+config LEDS_LM355x
+ tristate "LED support for LM355x Chips, LM3554 and LM3556"
depends on LEDS_CLASS && I2C
select REGMAP_I2C
help
- This option enables support for LEDs connected to LM3556.
- LM3556 includes Torch, Flash and Indicator functions.
+ This option enables support for LEDs connected to LM355x.
+ LM355x includes Torch, Flash and Indicator functions.
config LEDS_OT200
tristate "LED support for the Bachmann OT200"
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index a9b627c..3fb9641 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -11,6 +11,7 @@ obj-$(CONFIG_LEDS_BD2802) += leds-bd2802.o
obj-$(CONFIG_LEDS_LOCOMO) += leds-locomo.o
obj-$(CONFIG_LEDS_LM3530) += leds-lm3530.o
obj-$(CONFIG_LEDS_LM3533) += leds-lm3533.o
+obj-$(CONFIG_LEDS_LM3642) += leds-lm3642.o
obj-$(CONFIG_LEDS_MIKROTIK_RB532) += leds-rb532.o
obj-$(CONFIG_LEDS_S3C24XX) += leds-s3c24xx.o
obj-$(CONFIG_LEDS_NET48XX) += leds-net48xx.o
@@ -48,7 +49,7 @@ obj-$(CONFIG_LEDS_NETXBIG) += leds-netxbig.o
obj-$(CONFIG_LEDS_ASIC3) += leds-asic3.o
obj-$(CONFIG_LEDS_RENESAS_TPU) += leds-renesas-tpu.o
obj-$(CONFIG_LEDS_MAX8997) += leds-max8997.o
-obj-$(CONFIG_LEDS_LM3556) += leds-lm3556.o
+obj-$(CONFIG_LEDS_LM355x) += leds-lm355x.o
obj-$(CONFIG_LEDS_BLINKM) += leds-blinkm.o
# LED SPI Drivers
diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c
index c599095..48cce18 100644
--- a/drivers/leds/led-class.c
+++ b/drivers/leds/led-class.c
@@ -124,6 +124,16 @@ static void led_timer_function(unsigned long data)
mod_timer(&led_cdev->blink_timer, jiffies + msecs_to_jiffies(delay));
}
+static void set_brightness_delayed(struct work_struct *ws)
+{
+ struct led_classdev *led_cdev =
+ container_of(ws, struct led_classdev, set_brightness_work);
+
+ led_stop_software_blink(led_cdev);
+
+ __led_set_brightness(led_cdev, led_cdev->delayed_set_value);
+}
+
/**
* led_classdev_suspend - suspend an led_classdev.
* @led_cdev: the led_classdev to suspend.
@@ -191,6 +201,8 @@ int led_classdev_register(struct device *parent, struct led_classdev *led_cdev)
led_update_brightness(led_cdev);
+ INIT_WORK(&led_cdev->set_brightness_work, set_brightness_delayed);
+
init_timer(&led_cdev->blink_timer);
led_cdev->blink_timer.function = led_timer_function;
led_cdev->blink_timer.data = (unsigned long)led_cdev;
@@ -221,7 +233,10 @@ void led_classdev_unregister(struct led_classdev *led_cdev)
up_write(&led_cdev->trigger_lock);
#endif
+ cancel_work_sync(&led_cdev->set_brightness_work);
+
/* Stop blinking */
+ led_stop_software_blink(led_cdev);
led_set_brightness(led_cdev, LED_OFF);
device_unregister(led_cdev->dev);
diff --git a/drivers/leds/led-core.c b/drivers/leds/led-core.c
index 2ab05af..ce8921a 100644
--- a/drivers/leds/led-core.c
+++ b/drivers/leds/led-core.c
@@ -103,13 +103,23 @@ void led_blink_set_oneshot(struct led_classdev *led_cdev,
}
EXPORT_SYMBOL(led_blink_set_oneshot);
-void led_set_brightness(struct led_classdev *led_cdev,
- enum led_brightness brightness)
+void led_stop_software_blink(struct led_classdev *led_cdev)
{
- /* stop and clear soft-blink timer */
del_timer_sync(&led_cdev->blink_timer);
led_cdev->blink_delay_on = 0;
led_cdev->blink_delay_off = 0;
+}
+EXPORT_SYMBOL_GPL(led_stop_software_blink);
+
+void led_set_brightness(struct led_classdev *led_cdev,
+ enum led_brightness brightness)
+{
+ /* delay brightness setting if need to stop soft-blink timer */
+ if (led_cdev->blink_delay_on || led_cdev->blink_delay_off) {
+ led_cdev->delayed_set_value = brightness;
+ schedule_work(&led_cdev->set_brightness_work);
+ return;
+ }
__led_set_brightness(led_cdev, brightness);
}
diff --git a/drivers/leds/led-triggers.c b/drivers/leds/led-triggers.c
index 363975b..262eb41 100644
--- a/drivers/leds/led-triggers.c
+++ b/drivers/leds/led-triggers.c
@@ -102,6 +102,12 @@ EXPORT_SYMBOL_GPL(led_trigger_show);
void led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trig)
{
unsigned long flags;
+ char *event = NULL;
+ char *envp[2];
+ const char *name;
+
+ name = trig ? trig->name : "none";
+ event = kasprintf(GFP_KERNEL, "TRIGGER=%s", name);
/* Remove any existing trigger */
if (led_cdev->trigger) {
@@ -109,6 +115,8 @@ void led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trig)
list_del(&led_cdev->trig_list);
write_unlock_irqrestore(&led_cdev->trigger->leddev_list_lock,
flags);
+ cancel_work_sync(&led_cdev->set_brightness_work);
+ led_stop_software_blink(led_cdev);
if (led_cdev->trigger->deactivate)
led_cdev->trigger->deactivate(led_cdev);
led_cdev->trigger = NULL;
@@ -122,6 +130,13 @@ void led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trig)
if (trig->activate)
trig->activate(led_cdev);
}
+
+ if (event) {
+ envp[0] = event;
+ envp[1] = NULL;
+ kobject_uevent_env(&led_cdev->dev->kobj, KOBJ_CHANGE, envp);
+ kfree(event);
+ }
}
EXPORT_SYMBOL_GPL(led_trigger_set);
@@ -224,7 +239,7 @@ void led_trigger_event(struct led_trigger *trig,
struct led_classdev *led_cdev;
led_cdev = list_entry(entry, struct led_classdev, trig_list);
- __led_set_brightness(led_cdev, brightness);
+ led_set_brightness(led_cdev, brightness);
}
read_unlock(&trig->leddev_list_lock);
}
diff --git a/drivers/leds/leds-clevo-mail.c b/drivers/leds/leds-clevo-mail.c
index 1ed1677..e024b0b 100644
--- a/drivers/leds/leds-clevo-mail.c
+++ b/drivers/leds/leds-clevo-mail.c
@@ -31,7 +31,7 @@ static int __init clevo_mail_led_dmi_callback(const struct dmi_system_id *id)
}
/*
- * struct mail_led_whitelist - List of known good models
+ * struct clevo_mail_led_dmi_table - List of known good models
*
* Contains the known good models this driver is compatible with.
* When adding a new model try to be as strict as possible. This
@@ -39,7 +39,7 @@ static int __init clevo_mail_led_dmi_callback(const struct dmi_system_id *id)
* detected as working, but in reality it is not) as low as
* possible.
*/
-static struct dmi_system_id __initdata mail_led_whitelist[] = {
+static struct dmi_system_id __initdata clevo_mail_led_dmi_table[] = {
{
.callback = clevo_mail_led_dmi_callback,
.ident = "Clevo D410J",
@@ -59,11 +59,10 @@ static struct dmi_system_id __initdata mail_led_whitelist[] = {
},
{
.callback = clevo_mail_led_dmi_callback,
- .ident = "Positivo Mobile",
+ .ident = "Clevo M5x0V",
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "CLEVO Co. "),
DMI_MATCH(DMI_BOARD_NAME, "M5X0V "),
- DMI_MATCH(DMI_PRODUCT_NAME, "Positivo Mobile"),
DMI_MATCH(DMI_PRODUCT_VERSION, "VT6198")
}
},
@@ -89,6 +88,7 @@ static struct dmi_system_id __initdata mail_led_whitelist[] = {
},
{ }
};
+MODULE_DEVICE_TABLE(dmi, clevo_mail_led_dmi_table);
static void clevo_mail_led_set(struct led_classdev *led_cdev,
enum led_brightness value)
@@ -180,7 +180,7 @@ static int __init clevo_mail_led_init(void)
/* Check with the help of DMI if we are running on supported hardware */
if (!nodetect) {
- count = dmi_check_system(mail_led_whitelist);
+ count = dmi_check_system(clevo_mail_led_dmi_table);
} else {
count = 1;
printk(KERN_ERR KBUILD_MODNAME ": Skipping DMI detection. "
diff --git a/drivers/leds/leds-gpio.c b/drivers/leds/leds-gpio.c
index c032b21..087d1e6 100644
--- a/drivers/leds/leds-gpio.c
+++ b/drivers/leds/leds-gpio.c
@@ -20,6 +20,7 @@
#include <linux/slab.h>
#include <linux/workqueue.h>
#include <linux/module.h>
+#include <linux/pinctrl/consumer.h>
struct gpio_led_data {
struct led_classdev cdev;
@@ -170,11 +171,10 @@ static struct gpio_leds_priv * __devinit gpio_leds_create_of(struct platform_dev
{
struct device_node *np = pdev->dev.of_node, *child;
struct gpio_leds_priv *priv;
- int count = 0, ret;
+ int count, ret;
/* count LEDs in this device, so we know how much to allocate */
- for_each_child_of_node(np, child)
- count++;
+ count = of_get_child_count(np);
if (!count)
return NULL;
@@ -228,7 +228,6 @@ static struct gpio_leds_priv * __devinit gpio_leds_create_of(struct platform_dev
{
return NULL;
}
-#define of_gpio_leds_match NULL
#endif /* CONFIG_OF_GPIO */
@@ -236,8 +235,14 @@ static int __devinit gpio_led_probe(struct platform_device *pdev)
{
struct gpio_led_platform_data *pdata = pdev->dev.platform_data;
struct gpio_leds_priv *priv;
+ struct pinctrl *pinctrl;
int i, ret = 0;
+ pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
+ if (IS_ERR(pinctrl))
+ dev_warn(&pdev->dev,
+ "pins are not configured from the driver\n");
+
if (pdata && pdata->num_leds) {
priv = devm_kzalloc(&pdev->dev,
sizeof_gpio_leds_priv(pdata->num_leds),
@@ -270,13 +275,13 @@ static int __devinit gpio_led_probe(struct platform_device *pdev)
static int __devexit gpio_led_remove(struct platform_device *pdev)
{
- struct gpio_leds_priv *priv = dev_get_drvdata(&pdev->dev);
+ struct gpio_leds_priv *priv = platform_get_drvdata(pdev);
int i;
for (i = 0; i < priv->num_leds; i++)
delete_gpio_led(&priv->leds[i]);
- dev_set_drvdata(&pdev->dev, NULL);
+ platform_set_drvdata(pdev, NULL);
return 0;
}
@@ -287,7 +292,7 @@ static struct platform_driver gpio_led_driver = {
.driver = {
.name = "leds-gpio",
.owner = THIS_MODULE,
- .of_match_table = of_gpio_leds_match,
+ .of_match_table = of_match_ptr(of_gpio_leds_match),
},
};
diff --git a/drivers/leds/leds-lm3530.c b/drivers/leds/leds-lm3530.c
index 23637bd..b26306f 100644
--- a/drivers/leds/leds-lm3530.c
+++ b/drivers/leds/leds-lm3530.c
@@ -150,7 +150,7 @@ static int lm3530_get_mode_from_str(const char *str)
if (sysfs_streq(str, mode_map[i].mode))
return mode_map[i].mode_val;
- return -1;
+ return -EINVAL;
}
static void lm3530_als_configure(struct lm3530_platform_data *pdata,
@@ -358,7 +358,7 @@ static ssize_t lm3530_mode_set(struct device *dev, struct device_attribute
mode = lm3530_get_mode_from_str(buf);
if (mode < 0) {
dev_err(dev, "Invalid mode\n");
- return -EINVAL;
+ return mode;
}
drvdata->mode = mode;
@@ -416,7 +416,7 @@ static int __devinit lm3530_probe(struct i2c_client *client,
i2c_set_clientdata(client, drvdata);
- drvdata->regulator = regulator_get(&client->dev, "vin");
+ drvdata->regulator = devm_regulator_get(&client->dev, "vin");
if (IS_ERR(drvdata->regulator)) {
dev_err(&client->dev, "regulator get failed\n");
err = PTR_ERR(drvdata->regulator);
@@ -429,15 +429,13 @@ static int __devinit lm3530_probe(struct i2c_client *client,
if (err < 0) {
dev_err(&client->dev,
"Register Init failed: %d\n", err);
- err = -ENODEV;
- goto err_reg_init;
+ return err;
}
}
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;
- goto err_class_register;
+ return err;
}
err = device_create_file(drvdata->led_dev.dev, &dev_attr_mode);
@@ -451,9 +449,6 @@ static int __devinit lm3530_probe(struct i2c_client *client,
err_create_file:
led_classdev_unregister(&drvdata->led_dev);
-err_class_register:
-err_reg_init:
- regulator_put(drvdata->regulator);
return err;
}
@@ -465,7 +460,6 @@ static int __devexit lm3530_remove(struct i2c_client *client)
if (drvdata->enable)
regulator_disable(drvdata->regulator);
- regulator_put(drvdata->regulator);
led_classdev_unregister(&drvdata->led_dev);
return 0;
}
diff --git a/drivers/leds/leds-lm3556.c b/drivers/leds/leds-lm3556.c
deleted file mode 100644
index 3062abd..0000000
--- a/drivers/leds/leds-lm3556.c
+++ /dev/null
@@ -1,512 +0,0 @@
-/*
- * Simple driver for Texas Instruments LM3556 LED Flash driver chip (Rev0x03)
- * Copyright (C) 2012 Texas Instruments
- *
- * 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.
- *
- * Please refer Documentation/leds/leds-lm3556.txt file.
- */
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/i2c.h>
-#include <linux/leds.h>
-#include <linux/slab.h>
-#include <linux/platform_device.h>
-#include <linux/fs.h>
-#include <linux/regmap.h>
-#include <linux/platform_data/leds-lm3556.h>
-
-#define REG_FILT_TIME (0x0)
-#define REG_IVFM_MODE (0x1)
-#define REG_NTC (0x2)
-#define REG_INDIC_TIME (0x3)
-#define REG_INDIC_BLINK (0x4)
-#define REG_INDIC_PERIOD (0x5)
-#define REG_TORCH_TIME (0x6)
-#define REG_CONF (0x7)
-#define REG_FLASH (0x8)
-#define REG_I_CTRL (0x9)
-#define REG_ENABLE (0xA)
-#define REG_FLAG (0xB)
-#define REG_MAX (0xB)
-
-#define IVFM_FILTER_TIME_SHIFT (3)
-#define UVLO_EN_SHIFT (7)
-#define HYSTERSIS_SHIFT (5)
-#define IVM_D_TH_SHIFT (2)
-#define IVFM_ADJ_MODE_SHIFT (0)
-#define NTC_EVENT_LVL_SHIFT (5)
-#define NTC_TRIP_TH_SHIFT (2)
-#define NTC_BIAS_I_LVL_SHIFT (0)
-#define INDIC_RAMP_UP_TIME_SHIFT (3)
-#define INDIC_RAMP_DN_TIME_SHIFT (0)
-#define INDIC_N_BLANK_SHIFT (4)
-#define INDIC_PULSE_TIME_SHIFT (0)
-#define INDIC_N_PERIOD_SHIFT (0)
-#define TORCH_RAMP_UP_TIME_SHIFT (3)
-#define TORCH_RAMP_DN_TIME_SHIFT (0)
-#define STROBE_USUAGE_SHIFT (7)
-#define STROBE_PIN_POLARITY_SHIFT (6)
-#define TORCH_PIN_POLARITY_SHIFT (5)
-#define TX_PIN_POLARITY_SHIFT (4)
-#define TX_EVENT_LVL_SHIFT (3)
-#define IVFM_EN_SHIFT (2)
-#define NTC_MODE_SHIFT (1)
-#define INDIC_MODE_SHIFT (0)
-#define INDUCTOR_I_LIMIT_SHIFT (6)
-#define FLASH_RAMP_TIME_SHIFT (3)
-#define FLASH_TOUT_TIME_SHIFT (0)
-#define TORCH_I_SHIFT (4)
-#define FLASH_I_SHIFT (0)
-#define NTC_EN_SHIFT (7)
-#define TX_PIN_EN_SHIFT (6)
-#define STROBE_PIN_EN_SHIFT (5)
-#define TORCH_PIN_EN_SHIFT (4)
-#define PRECHG_MODE_EN_SHIFT (3)
-#define PASS_MODE_ONLY_EN_SHIFT (2)
-#define MODE_BITS_SHIFT (0)
-
-#define IVFM_FILTER_TIME_MASK (0x3)
-#define UVLO_EN_MASK (0x1)
-#define HYSTERSIS_MASK (0x3)
-#define IVM_D_TH_MASK (0x7)
-#define IVFM_ADJ_MODE_MASK (0x3)
-#define NTC_EVENT_LVL_MASK (0x1)
-#define NTC_TRIP_TH_MASK (0x7)
-#define NTC_BIAS_I_LVL_MASK (0x3)
-#define INDIC_RAMP_UP_TIME_MASK (0x7)
-#define INDIC_RAMP_DN_TIME_MASK (0x7)
-#define INDIC_N_BLANK_MASK (0x7)
-#define INDIC_PULSE_TIME_MASK (0x7)
-#define INDIC_N_PERIOD_MASK (0x7)
-#define TORCH_RAMP_UP_TIME_MASK (0x7)
-#define TORCH_RAMP_DN_TIME_MASK (0x7)
-#define STROBE_USUAGE_MASK (0x1)
-#define STROBE_PIN_POLARITY_MASK (0x1)
-#define TORCH_PIN_POLARITY_MASK (0x1)
-#define TX_PIN_POLARITY_MASK (0x1)
-#define TX_EVENT_LVL_MASK (0x1)
-#define IVFM_EN_MASK (0x1)
-#define NTC_MODE_MASK (0x1)
-#define INDIC_MODE_MASK (0x1)
-#define INDUCTOR_I_LIMIT_MASK (0x3)
-#define FLASH_RAMP_TIME_MASK (0x7)
-#define FLASH_TOUT_TIME_MASK (0x7)
-#define TORCH_I_MASK (0x7)
-#define FLASH_I_MASK (0xF)
-#define NTC_EN_MASK (0x1)
-#define TX_PIN_EN_MASK (0x1)
-#define STROBE_PIN_EN_MASK (0x1)
-#define TORCH_PIN_EN_MASK (0x1)
-#define PRECHG_MODE_EN_MASK (0x1)
-#define PASS_MODE_ONLY_EN_MASK (0x1)
-#define MODE_BITS_MASK (0x13)
-#define EX_PIN_CONTROL_MASK (0xF1)
-#define EX_PIN_ENABLE_MASK (0x70)
-
-enum lm3556_indic_pulse_time {
- PULSE_TIME_0_MS = 0,
- PULSE_TIME_32_MS,
- PULSE_TIME_64_MS,
- PULSE_TIME_92_MS,
- PULSE_TIME_128_MS,
- PULSE_TIME_160_MS,
- PULSE_TIME_196_MS,
- PULSE_TIME_224_MS,
- PULSE_TIME_256_MS,
- PULSE_TIME_288_MS,
- PULSE_TIME_320_MS,
- PULSE_TIME_352_MS,
- PULSE_TIME_384_MS,
- PULSE_TIME_416_MS,
- PULSE_TIME_448_MS,
- PULSE_TIME_480_MS,
-};
-
-enum lm3556_indic_n_blank {
- INDIC_N_BLANK_0 = 0,
- INDIC_N_BLANK_1,
- INDIC_N_BLANK_2,
- INDIC_N_BLANK_3,
- INDIC_N_BLANK_4,
- INDIC_N_BLANK_5,
- INDIC_N_BLANK_6,
- INDIC_N_BLANK_7,
- INDIC_N_BLANK_8,
- INDIC_N_BLANK_9,
- INDIC_N_BLANK_10,
- INDIC_N_BLANK_11,
- INDIC_N_BLANK_12,
- INDIC_N_BLANK_13,
- INDIC_N_BLANK_14,
- INDIC_N_BLANK_15,
-};
-
-enum lm3556_indic_period {
- INDIC_PERIOD_0 = 0,
- INDIC_PERIOD_1,
- INDIC_PERIOD_2,
- INDIC_PERIOD_3,
- INDIC_PERIOD_4,
- INDIC_PERIOD_5,
- INDIC_PERIOD_6,
- INDIC_PERIOD_7,
-};
-
-enum lm3556_mode {
- MODES_STASNDBY = 0,
- MODES_INDIC,
- MODES_TORCH,
- MODES_FLASH
-};
-
-#define INDIC_PATTERN_SIZE 4
-
-struct indicator {
- u8 blinking;
- u8 period_cnt;
-};
-
-struct lm3556_chip_data {
- struct device *dev;
-
- struct led_classdev cdev_flash;
- struct led_classdev cdev_torch;
- struct led_classdev cdev_indicator;
-
- struct lm3556_platform_data *pdata;
- struct regmap *regmap;
- struct mutex lock;
-
- unsigned int last_flag;
-};
-
-/* indicator pattern */
-static struct indicator indicator_pattern[INDIC_PATTERN_SIZE] = {
- [0] = {(INDIC_N_BLANK_1 << INDIC_N_BLANK_SHIFT)
- | PULSE_TIME_32_MS, INDIC_PERIOD_1},
- [1] = {(INDIC_N_BLANK_15 << INDIC_N_BLANK_SHIFT)
- | PULSE_TIME_32_MS, INDIC_PERIOD_2},
- [2] = {(INDIC_N_BLANK_10 << INDIC_N_BLANK_SHIFT)
- | PULSE_TIME_32_MS, INDIC_PERIOD_4},
- [3] = {(INDIC_N_BLANK_5 << INDIC_N_BLANK_SHIFT)
- | PULSE_TIME_32_MS, INDIC_PERIOD_7},
-};
-
-/* chip initialize */
-static int __devinit lm3556_chip_init(struct lm3556_chip_data *chip)
-{
- unsigned int reg_val;
- int ret;
- struct lm3556_platform_data *pdata = chip->pdata;
-
- /* set config register */
- ret = regmap_read(chip->regmap, REG_CONF, &reg_val);
- if (ret < 0) {
- dev_err(chip->dev, "Failed to read REG_CONF Register\n");
- goto out;
- }
-
- reg_val &= (~EX_PIN_CONTROL_MASK);
- reg_val |= ((pdata->torch_pin_polarity & 0x01)
- << TORCH_PIN_POLARITY_SHIFT);
- reg_val |= ((pdata->strobe_usuage & 0x01) << STROBE_USUAGE_SHIFT);
- reg_val |= ((pdata->strobe_pin_polarity & 0x01)
- << STROBE_PIN_POLARITY_SHIFT);
- reg_val |= ((pdata->tx_pin_polarity & 0x01) << TX_PIN_POLARITY_SHIFT);
- reg_val |= ((pdata->indicator_mode & 0x01) << INDIC_MODE_SHIFT);
-
- ret = regmap_write(chip->regmap, REG_CONF, reg_val);
- if (ret < 0) {
- dev_err(chip->dev, "Failed to write REG_CONF Regisgter\n");
- goto out;
- }
-
- /* set enable register */
- ret = regmap_read(chip->regmap, REG_ENABLE, &reg_val);
- if (ret < 0) {
- dev_err(chip->dev, "Failed to read REG_ENABLE Register\n");
- goto out;
- }
-
- reg_val &= (~EX_PIN_ENABLE_MASK);
- reg_val |= ((pdata->torch_pin_en & 0x01) << TORCH_PIN_EN_SHIFT);
- reg_val |= ((pdata->strobe_pin_en & 0x01) << STROBE_PIN_EN_SHIFT);
- reg_val |= ((pdata->tx_pin_en & 0x01) << TX_PIN_EN_SHIFT);
-
- ret = regmap_write(chip->regmap, REG_ENABLE, reg_val);
- if (ret < 0) {
- dev_err(chip->dev, "Failed to write REG_ENABLE Regisgter\n");
- goto out;
- }
-
-out:
- return ret;
-}
-
-/* chip control */
-static int lm3556_control(struct lm3556_chip_data *chip,
- u8 brightness, enum lm3556_mode opmode)
-{
- int ret;
- struct lm3556_platform_data *pdata = chip->pdata;
-
- ret = regmap_read(chip->regmap, REG_FLAG, &chip->last_flag);
- if (ret < 0) {
- dev_err(chip->dev, "Failed to read REG_FLAG Register\n");
- goto out;
- }
-
- if (chip->last_flag)
- dev_info(chip->dev, "Last FLAG is 0x%x\n", chip->last_flag);
-
- /* brightness 0 means off-state */
- if (!brightness)
- opmode = MODES_STASNDBY;
-
- switch (opmode) {
- case MODES_TORCH:
- ret = regmap_update_bits(chip->regmap, REG_I_CTRL,
- TORCH_I_MASK << TORCH_I_SHIFT,
- (brightness - 1) << TORCH_I_SHIFT);
-
- if (pdata->torch_pin_en)
- opmode |= (TORCH_PIN_EN_MASK << TORCH_PIN_EN_SHIFT);
- break;
-
- case MODES_FLASH:
- ret = regmap_update_bits(chip->regmap, REG_I_CTRL,
- FLASH_I_MASK << FLASH_I_SHIFT,
- (brightness - 1) << FLASH_I_SHIFT);
- break;
-
- case MODES_INDIC:
- ret = regmap_update_bits(chip->regmap, REG_I_CTRL,
- TORCH_I_MASK << TORCH_I_SHIFT,
- (brightness - 1) << TORCH_I_SHIFT);
- break;
-
- case MODES_STASNDBY:
- if (pdata->torch_pin_en)
- opmode |= (TORCH_PIN_EN_MASK << TORCH_PIN_EN_SHIFT);
- break;
-
- default:
- return ret;
- }
- if (ret < 0) {
- dev_err(chip->dev, "Failed to write REG_I_CTRL Register\n");
- goto out;
- }
- ret = regmap_update_bits(chip->regmap, REG_ENABLE,
- MODE_BITS_MASK << MODE_BITS_SHIFT,
- opmode << MODE_BITS_SHIFT);
-
-out:
- return ret;
-}
-
-/* torch */
-static void lm3556_torch_brightness_set(struct led_classdev *cdev,
- enum led_brightness brightness)
-{
- struct lm3556_chip_data *chip =
- container_of(cdev, struct lm3556_chip_data, cdev_torch);
-
- mutex_lock(&chip->lock);
- lm3556_control(chip, brightness, MODES_TORCH);
- mutex_unlock(&chip->lock);
-}
-
-/* flash */
-static void lm3556_strobe_brightness_set(struct led_classdev *cdev,
- enum led_brightness brightness)
-{
- struct lm3556_chip_data *chip =
- container_of(cdev, struct lm3556_chip_data, cdev_flash);
-
- mutex_lock(&chip->lock);
- lm3556_control(chip, brightness, MODES_FLASH);
- mutex_unlock(&chip->lock);
-}
-
-/* indicator */
-static void lm3556_indicator_brightness_set(struct led_classdev *cdev,
- enum led_brightness brightness)
-{
- struct lm3556_chip_data *chip =
- container_of(cdev, struct lm3556_chip_data, cdev_indicator);
-
- mutex_lock(&chip->lock);
- lm3556_control(chip, brightness, MODES_INDIC);
- mutex_unlock(&chip->lock);
-}
-
-/* indicator pattern */
-static ssize_t lm3556_indicator_pattern_store(struct device *dev,
- struct device_attribute *devAttr,
- const char *buf, size_t size)
-{
- ssize_t ret;
- struct led_classdev *led_cdev = dev_get_drvdata(dev);
- struct lm3556_chip_data *chip =
- container_of(led_cdev, struct lm3556_chip_data, cdev_indicator);
- unsigned int state;
-
- ret = kstrtouint(buf, 10, &state);
- if (ret)
- goto out;
- if (state > INDIC_PATTERN_SIZE - 1)
- state = INDIC_PATTERN_SIZE - 1;
-
- ret = regmap_write(chip->regmap, REG_INDIC_BLINK,
- indicator_pattern[state].blinking);
- if (ret < 0) {
- dev_err(chip->dev, "Failed to write REG_ENABLE Regisgter\n");
- goto out;
- }
-
- ret = regmap_write(chip->regmap, REG_INDIC_PERIOD,
- indicator_pattern[state].period_cnt);
- if (ret < 0) {
- dev_err(chip->dev, "Failed to write REG_ENABLE Regisgter\n");
- goto out;
- }
-
- return size;
-out:
- dev_err(chip->dev, "Indicator pattern doesn't saved\n");
- return size;
-}
-
-static DEVICE_ATTR(pattern, 0666, NULL, lm3556_indicator_pattern_store);
-
-static const struct regmap_config lm3556_regmap = {
- .reg_bits = 8,
- .val_bits = 8,
- .max_register = REG_MAX,
-};
-
-/* module initialize */
-static int __devinit lm3556_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
-{
- struct lm3556_platform_data *pdata = client->dev.platform_data;
- struct lm3556_chip_data *chip;
-
- int err;
-
- if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
- dev_err(&client->dev, "i2c functionality check fail.\n");
- return -EOPNOTSUPP;
- }
-
- if (pdata == NULL) {
- dev_err(&client->dev, "Needs Platform Data.\n");
- return -ENODATA;
- }
-
- chip =
- devm_kzalloc(&client->dev, sizeof(struct lm3556_chip_data),
- GFP_KERNEL);
- if (!chip)
- return -ENOMEM;
-
- chip->dev = &client->dev;
- chip->pdata = pdata;
-
- chip->regmap = devm_regmap_init_i2c(client, &lm3556_regmap);
- if (IS_ERR(chip->regmap)) {
- err = PTR_ERR(chip->regmap);
- dev_err(&client->dev, "Failed to allocate register map: %d\n",
- err);
- return err;
- }
-
- mutex_init(&chip->lock);
- i2c_set_clientdata(client, chip);
-
- err = lm3556_chip_init(chip);
- if (err < 0)
- goto err_out;
-
- /* flash */
- chip->cdev_flash.name = "flash";
- chip->cdev_flash.max_brightness = 16;
- chip->cdev_flash.brightness_set = lm3556_strobe_brightness_set;
- err = led_classdev_register((struct device *)
- &client->dev, &chip->cdev_flash);
- if (err < 0)
- goto err_out;
- /* torch */
- chip->cdev_torch.name = "torch";
- chip->cdev_torch.max_brightness = 8;
- chip->cdev_torch.brightness_set = lm3556_torch_brightness_set;
- err = led_classdev_register((struct device *)
- &client->dev, &chip->cdev_torch);
- if (err < 0)
- goto err_create_torch_file;
- /* indicator */
- chip->cdev_indicator.name = "indicator";
- chip->cdev_indicator.max_brightness = 8;
- chip->cdev_indicator.brightness_set = lm3556_indicator_brightness_set;
- err = led_classdev_register((struct device *)
- &client->dev, &chip->cdev_indicator);
- if (err < 0)
- goto err_create_indicator_file;
-
- err = device_create_file(chip->cdev_indicator.dev, &dev_attr_pattern);
- if (err < 0)
- goto err_create_pattern_file;
-
- dev_info(&client->dev, "LM3556 is initialized\n");
- return 0;
-
-err_create_pattern_file:
- led_classdev_unregister(&chip->cdev_indicator);
-err_create_indicator_file:
- led_classdev_unregister(&chip->cdev_torch);
-err_create_torch_file:
- led_classdev_unregister(&chip->cdev_flash);
-err_out:
- return err;
-}
-
-static int __devexit lm3556_remove(struct i2c_client *client)
-{
- struct lm3556_chip_data *chip = i2c_get_clientdata(client);
-
- device_remove_file(chip->cdev_indicator.dev, &dev_attr_pattern);
- led_classdev_unregister(&chip->cdev_indicator);
- led_classdev_unregister(&chip->cdev_torch);
- led_classdev_unregister(&chip->cdev_flash);
- regmap_write(chip->regmap, REG_ENABLE, 0);
- return 0;
-}
-
-static const struct i2c_device_id lm3556_id[] = {
- {LM3556_NAME, 0},
- {}
-};
-
-MODULE_DEVICE_TABLE(i2c, lm3556_id);
-
-static struct i2c_driver lm3556_i2c_driver = {
- .driver = {
- .name = LM3556_NAME,
- .owner = THIS_MODULE,
- .pm = NULL,
- },
- .probe = lm3556_probe,
- .remove = __devexit_p(lm3556_remove),
- .id_table = lm3556_id,
-};
-
-module_i2c_driver(lm3556_i2c_driver);
-
-MODULE_DESCRIPTION("Texas Instruments Flash Lighting driver for LM3556");
-MODULE_AUTHOR("Daniel Jeong <daniel.jeong@ti.com>");
-MODULE_AUTHOR("G.Shark Jeong <gshark.jeong@gmail.com>");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/leds/leds-lm355x.c b/drivers/leds/leds-lm355x.c
new file mode 100644
index 0000000..065ec01
--- /dev/null
+++ b/drivers/leds/leds-lm355x.c
@@ -0,0 +1,572 @@
+/*
+* Simple driver for Texas Instruments LM355x LED Flash driver chip
+* Copyright (C) 2012 Texas Instruments
+*
+* 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/delay.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <linux/leds.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/fs.h>
+#include <linux/regmap.h>
+#include <linux/workqueue.h>
+#include <linux/platform_data/leds-lm355x.h>
+
+enum lm355x_type {
+ CHIP_LM3554 = 0,
+ CHIP_LM3556,
+};
+
+enum lm355x_regs {
+ REG_FLAG = 0,
+ REG_TORCH_CFG,
+ REG_TORCH_CTRL,
+ REG_STROBE_CFG,
+ REG_FLASH_CTRL,
+ REG_INDI_CFG,
+ REG_INDI_CTRL,
+ REG_OPMODE,
+ REG_MAX,
+};
+
+/* operation mode */
+enum lm355x_mode {
+ MODE_SHDN = 0,
+ MODE_INDIC,
+ MODE_TORCH,
+ MODE_FLASH
+};
+
+/* register map info. */
+struct lm355x_reg_data {
+ u8 regno;
+ u8 mask;
+ u8 shift;
+};
+
+struct lm355x_chip_data {
+ struct device *dev;
+ enum lm355x_type type;
+
+ struct led_classdev cdev_flash;
+ struct led_classdev cdev_torch;
+ struct led_classdev cdev_indicator;
+
+ struct work_struct work_flash;
+ struct work_struct work_torch;
+ struct work_struct work_indicator;
+
+ u8 br_flash;
+ u8 br_torch;
+ u8 br_indicator;
+
+ struct lm355x_platform_data *pdata;
+ struct regmap *regmap;
+ struct mutex lock;
+
+ unsigned int last_flag;
+ struct lm355x_reg_data *regs;
+};
+
+/* specific indicator function for lm3556 */
+enum lm3556_indic_pulse_time {
+ PULSE_TIME_0_MS = 0,
+ PULSE_TIME_32_MS,
+ PULSE_TIME_64_MS,
+ PULSE_TIME_92_MS,
+ PULSE_TIME_128_MS,
+ PULSE_TIME_160_MS,
+ PULSE_TIME_196_MS,
+ PULSE_TIME_224_MS,
+ PULSE_TIME_256_MS,
+ PULSE_TIME_288_MS,
+ PULSE_TIME_320_MS,
+ PULSE_TIME_352_MS,
+ PULSE_TIME_384_MS,
+ PULSE_TIME_416_MS,
+ PULSE_TIME_448_MS,
+ PULSE_TIME_480_MS,
+};
+
+enum lm3556_indic_n_blank {
+ INDIC_N_BLANK_0 = 0,
+ INDIC_N_BLANK_1,
+ INDIC_N_BLANK_2,
+ INDIC_N_BLANK_3,
+ INDIC_N_BLANK_4,
+ INDIC_N_BLANK_5,
+ INDIC_N_BLANK_6,
+ INDIC_N_BLANK_7,
+ INDIC_N_BLANK_8,
+ INDIC_N_BLANK_9,
+ INDIC_N_BLANK_10,
+ INDIC_N_BLANK_11,
+ INDIC_N_BLANK_12,
+ INDIC_N_BLANK_13,
+ INDIC_N_BLANK_14,
+ INDIC_N_BLANK_15,
+};
+
+enum lm3556_indic_period {
+ INDIC_PERIOD_0 = 0,
+ INDIC_PERIOD_1,
+ INDIC_PERIOD_2,
+ INDIC_PERIOD_3,
+ INDIC_PERIOD_4,
+ INDIC_PERIOD_5,
+ INDIC_PERIOD_6,
+ INDIC_PERIOD_7,
+};
+
+#define INDIC_PATTERN_SIZE 4
+
+struct indicator {
+ u8 blinking;
+ u8 period_cnt;
+};
+
+/* indicator pattern data only for lm3556 */
+static struct indicator indicator_pattern[INDIC_PATTERN_SIZE] = {
+ [0] = {(INDIC_N_BLANK_1 << 4) | PULSE_TIME_32_MS, INDIC_PERIOD_1},
+ [1] = {(INDIC_N_BLANK_15 << 4) | PULSE_TIME_32_MS, INDIC_PERIOD_2},
+ [2] = {(INDIC_N_BLANK_10 << 4) | PULSE_TIME_32_MS, INDIC_PERIOD_4},
+ [3] = {(INDIC_N_BLANK_5 << 4) | PULSE_TIME_32_MS, INDIC_PERIOD_7},
+};
+
+static struct lm355x_reg_data lm3554_regs[REG_MAX] = {
+ [REG_FLAG] = {0xD0, 0xBF, 0},
+ [REG_TORCH_CFG] = {0xE0, 0x80, 7},
+ [REG_TORCH_CTRL] = {0xA0, 0x38, 3},
+ [REG_STROBE_CFG] = {0xE0, 0x04, 2},
+ [REG_FLASH_CTRL] = {0xB0, 0x78, 3},
+ [REG_INDI_CFG] = {0xE0, 0x08, 3},
+ [REG_INDI_CTRL] = {0xA0, 0xC0, 6},
+ [REG_OPMODE] = {0xA0, 0x03, 0},
+};
+
+static struct lm355x_reg_data lm3556_regs[REG_MAX] = {
+ [REG_FLAG] = {0x0B, 0xFF, 0},
+ [REG_TORCH_CFG] = {0x0A, 0x10, 4},
+ [REG_TORCH_CTRL] = {0x09, 0x70, 4},
+ [REG_STROBE_CFG] = {0x0A, 0x20, 5},
+ [REG_FLASH_CTRL] = {0x09, 0x0F, 0},
+ [REG_INDI_CFG] = {0xFF, 0xFF, 0},
+ [REG_INDI_CTRL] = {0x09, 0x70, 4},
+ [REG_OPMODE] = {0x0A, 0x03, 0},
+};
+
+static char lm355x_name[][I2C_NAME_SIZE] = {
+ [CHIP_LM3554] = LM3554_NAME,
+ [CHIP_LM3556] = LM3556_NAME,
+};
+
+/* chip initialize */
+static int __devinit lm355x_chip_init(struct lm355x_chip_data *chip)
+{
+ int ret;
+ unsigned int reg_val;
+ struct lm355x_platform_data *pdata = chip->pdata;
+
+ /* input and output pins configuration */
+ switch (chip->type) {
+ case CHIP_LM3554:
+ reg_val = pdata->pin_tx2 | pdata->ntc_pin;
+ ret = regmap_update_bits(chip->regmap, 0xE0, 0x28, reg_val);
+ if (ret < 0)
+ goto out;
+ reg_val = pdata->pass_mode;
+ ret = regmap_update_bits(chip->regmap, 0xA0, 0x04, reg_val);
+ if (ret < 0)
+ goto out;
+ break;
+
+ case CHIP_LM3556:
+ reg_val = pdata->pin_tx2 | pdata->ntc_pin | pdata->pass_mode;
+ ret = regmap_update_bits(chip->regmap, 0x0A, 0xC4, reg_val);
+ if (ret < 0)
+ goto out;
+ break;
+ default:
+ return -ENODATA;
+ }
+
+ return ret;
+out:
+ dev_err(chip->dev, "%s:i2c access fail to register\n", __func__);
+ return ret;
+}
+
+/* chip control */
+static void lm355x_control(struct lm355x_chip_data *chip,
+ u8 brightness, enum lm355x_mode opmode)
+{
+ int ret;
+ unsigned int reg_val;
+ struct lm355x_platform_data *pdata = chip->pdata;
+ struct lm355x_reg_data *preg = chip->regs;
+
+ ret = regmap_read(chip->regmap, preg[REG_FLAG].regno, &chip->last_flag);
+ if (ret < 0)
+ goto out;
+ if (chip->last_flag & preg[REG_FLAG].mask)
+ dev_info(chip->dev, "%s Last FLAG is 0x%x\n",
+ lm355x_name[chip->type],
+ chip->last_flag & preg[REG_FLAG].mask);
+ /* brightness 0 means shutdown */
+ if (!brightness)
+ opmode = MODE_SHDN;
+
+ switch (opmode) {
+ case MODE_TORCH:
+ ret =
+ regmap_update_bits(chip->regmap, preg[REG_TORCH_CTRL].regno,
+ preg[REG_TORCH_CTRL].mask,
+ (brightness - 1)
+ << preg[REG_TORCH_CTRL].shift);
+ if (ret < 0)
+ goto out;
+
+ if (pdata->pin_tx1 != LM355x_PIN_TORCH_DISABLE) {
+ ret =
+ regmap_update_bits(chip->regmap,
+ preg[REG_TORCH_CFG].regno,
+ preg[REG_TORCH_CFG].mask,
+ 0x01 <<
+ preg[REG_TORCH_CFG].shift);
+ if (ret < 0)
+ goto out;
+ opmode = MODE_SHDN;
+ dev_info(chip->dev,
+ "torch brt is set - ext. torch pin mode\n");
+ }
+ break;
+
+ case MODE_FLASH:
+
+ ret =
+ regmap_update_bits(chip->regmap, preg[REG_FLASH_CTRL].regno,
+ preg[REG_FLASH_CTRL].mask,
+ (brightness - 1)
+ << preg[REG_FLASH_CTRL].shift);
+ if (ret < 0)
+ goto out;
+
+ if (pdata->pin_strobe != LM355x_PIN_STROBE_DISABLE) {
+ if (chip->type == CHIP_LM3554)
+ reg_val = 0x00;
+ else
+ reg_val = 0x01;
+ ret =
+ regmap_update_bits(chip->regmap,
+ preg[REG_STROBE_CFG].regno,
+ preg[REG_STROBE_CFG].mask,
+ reg_val <<
+ preg[REG_STROBE_CFG].shift);
+ if (ret < 0)
+ goto out;
+ opmode = MODE_SHDN;
+ dev_info(chip->dev,
+ "flash brt is set - ext. strobe pin mode\n");
+ }
+ break;
+
+ case MODE_INDIC:
+ ret =
+ regmap_update_bits(chip->regmap, preg[REG_INDI_CTRL].regno,
+ preg[REG_INDI_CTRL].mask,
+ (brightness - 1)
+ << preg[REG_INDI_CTRL].shift);
+ if (ret < 0)
+ goto out;
+
+ if (pdata->pin_tx2 != LM355x_PIN_TX_DISABLE) {
+ ret =
+ regmap_update_bits(chip->regmap,
+ preg[REG_INDI_CFG].regno,
+ preg[REG_INDI_CFG].mask,
+ 0x01 <<
+ preg[REG_INDI_CFG].shift);
+ if (ret < 0)
+ goto out;
+ opmode = MODE_SHDN;
+ }
+ break;
+ case MODE_SHDN:
+ break;
+ default:
+ return;
+ }
+ /* operation mode control */
+ ret = regmap_update_bits(chip->regmap, preg[REG_OPMODE].regno,
+ preg[REG_OPMODE].mask,
+ opmode << preg[REG_OPMODE].shift);
+ if (ret < 0)
+ goto out;
+ return;
+out:
+ dev_err(chip->dev, "%s:i2c access fail to register\n", __func__);
+ return;
+}
+
+/* torch */
+static void lm355x_deferred_torch_brightness_set(struct work_struct *work)
+{
+ struct lm355x_chip_data *chip =
+ container_of(work, struct lm355x_chip_data, work_torch);
+
+ mutex_lock(&chip->lock);
+ lm355x_control(chip, chip->br_torch, MODE_TORCH);
+ mutex_unlock(&chip->lock);
+}
+
+static void lm355x_torch_brightness_set(struct led_classdev *cdev,
+ enum led_brightness brightness)
+{
+ struct lm355x_chip_data *chip =
+ container_of(cdev, struct lm355x_chip_data, cdev_torch);
+
+ chip->br_torch = brightness;
+ schedule_work(&chip->work_torch);
+}
+
+/* flash */
+static void lm355x_deferred_strobe_brightness_set(struct work_struct *work)
+{
+ struct lm355x_chip_data *chip =
+ container_of(work, struct lm355x_chip_data, work_flash);
+
+ mutex_lock(&chip->lock);
+ lm355x_control(chip, chip->br_flash, MODE_FLASH);
+ mutex_unlock(&chip->lock);
+}
+
+static void lm355x_strobe_brightness_set(struct led_classdev *cdev,
+ enum led_brightness brightness)
+{
+ struct lm355x_chip_data *chip =
+ container_of(cdev, struct lm355x_chip_data, cdev_flash);
+
+ chip->br_flash = brightness;
+ schedule_work(&chip->work_flash);
+}
+
+/* indicator */
+static void lm355x_deferred_indicator_brightness_set(struct work_struct *work)
+{
+ struct lm355x_chip_data *chip =
+ container_of(work, struct lm355x_chip_data, work_indicator);
+
+ mutex_lock(&chip->lock);
+ lm355x_control(chip, chip->br_indicator, MODE_INDIC);
+ mutex_unlock(&chip->lock);
+}
+
+static void lm355x_indicator_brightness_set(struct led_classdev *cdev,
+ enum led_brightness brightness)
+{
+ struct lm355x_chip_data *chip =
+ container_of(cdev, struct lm355x_chip_data, cdev_indicator);
+
+ chip->br_indicator = brightness;
+ schedule_work(&chip->work_indicator);
+}
+
+/* indicator pattern only for lm3556*/
+static ssize_t lm3556_indicator_pattern_store(struct device *dev,
+ struct device_attribute *devAttr,
+ const char *buf, size_t size)
+{
+ ssize_t ret;
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
+ struct lm355x_chip_data *chip =
+ container_of(led_cdev, struct lm355x_chip_data, cdev_indicator);
+ unsigned int state;
+
+ ret = kstrtouint(buf, 10, &state);
+ if (ret)
+ goto out;
+ if (state > INDIC_PATTERN_SIZE - 1)
+ state = INDIC_PATTERN_SIZE - 1;
+
+ ret = regmap_write(chip->regmap, 0x04,
+ indicator_pattern[state].blinking);
+ if (ret < 0)
+ goto out;
+
+ ret = regmap_write(chip->regmap, 0x05,
+ indicator_pattern[state].period_cnt);
+ if (ret < 0)
+ goto out;
+
+ return size;
+out:
+ dev_err(chip->dev, "%s:i2c access fail to register\n", __func__);
+ return size;
+}
+
+static DEVICE_ATTR(pattern, 0666, NULL, lm3556_indicator_pattern_store);
+
+static const struct regmap_config lm355x_regmap = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = 0xFF,
+};
+
+/* module initialize */
+static int __devinit lm355x_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct lm355x_platform_data *pdata = client->dev.platform_data;
+ struct lm355x_chip_data *chip;
+
+ int err;
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+ dev_err(&client->dev, "i2c functionality check fail.\n");
+ return -EOPNOTSUPP;
+ }
+
+ if (pdata == NULL) {
+ dev_err(&client->dev, "needs Platform Data.\n");
+ return -ENODATA;
+ }
+
+ chip = devm_kzalloc(&client->dev,
+ sizeof(struct lm355x_chip_data), GFP_KERNEL);
+ if (!chip)
+ return -ENOMEM;
+
+ chip->dev = &client->dev;
+ chip->type = id->driver_data;
+ switch (id->driver_data) {
+ case CHIP_LM3554:
+ chip->regs = lm3554_regs;
+ break;
+ case CHIP_LM3556:
+ chip->regs = lm3556_regs;
+ break;
+ default:
+ return -ENOSYS;
+ }
+ chip->pdata = pdata;
+
+ chip->regmap = devm_regmap_init_i2c(client, &lm355x_regmap);
+ if (IS_ERR(chip->regmap)) {
+ err = PTR_ERR(chip->regmap);
+ dev_err(&client->dev,
+ "Failed to allocate register map: %d\n", err);
+ return err;
+ }
+
+ mutex_init(&chip->lock);
+ i2c_set_clientdata(client, chip);
+
+ err = lm355x_chip_init(chip);
+ if (err < 0)
+ goto err_out;
+
+ /* flash */
+ INIT_WORK(&chip->work_flash, lm355x_deferred_strobe_brightness_set);
+ chip->cdev_flash.name = "flash";
+ chip->cdev_flash.max_brightness = 16;
+ chip->cdev_flash.brightness_set = lm355x_strobe_brightness_set;
+ err = led_classdev_register((struct device *)
+ &client->dev, &chip->cdev_flash);
+ if (err < 0)
+ goto err_out;
+ /* torch */
+ INIT_WORK(&chip->work_torch, lm355x_deferred_torch_brightness_set);
+ chip->cdev_torch.name = "torch";
+ chip->cdev_torch.max_brightness = 8;
+ chip->cdev_torch.brightness_set = lm355x_torch_brightness_set;
+ err = led_classdev_register((struct device *)
+ &client->dev, &chip->cdev_torch);
+ if (err < 0)
+ goto err_create_torch_file;
+ /* indicator */
+ INIT_WORK(&chip->work_indicator,
+ lm355x_deferred_indicator_brightness_set);
+ chip->cdev_indicator.name = "indicator";
+ if (id->driver_data == CHIP_LM3554)
+ chip->cdev_indicator.max_brightness = 4;
+ else
+ chip->cdev_indicator.max_brightness = 8;
+ chip->cdev_indicator.brightness_set = lm355x_indicator_brightness_set;
+ err = led_classdev_register((struct device *)
+ &client->dev, &chip->cdev_indicator);
+ if (err < 0)
+ goto err_create_indicator_file;
+ /* indicator pattern control only for LM3554 */
+ if (id->driver_data == CHIP_LM3556) {
+ err =
+ device_create_file(chip->cdev_indicator.dev,
+ &dev_attr_pattern);
+ if (err < 0)
+ goto err_create_pattern_file;
+ }
+
+ dev_info(&client->dev, "%s is initialized\n",
+ lm355x_name[id->driver_data]);
+ return 0;
+
+err_create_pattern_file:
+ led_classdev_unregister(&chip->cdev_indicator);
+err_create_indicator_file:
+ led_classdev_unregister(&chip->cdev_torch);
+err_create_torch_file:
+ led_classdev_unregister(&chip->cdev_flash);
+err_out:
+ return err;
+}
+
+static int __devexit lm355x_remove(struct i2c_client *client)
+{
+ struct lm355x_chip_data *chip = i2c_get_clientdata(client);
+ struct lm355x_reg_data *preg = chip->regs;
+
+ regmap_write(chip->regmap, preg[REG_OPMODE].regno, 0);
+ if (chip->type == CHIP_LM3556)
+ device_remove_file(chip->cdev_indicator.dev, &dev_attr_pattern);
+ led_classdev_unregister(&chip->cdev_indicator);
+ flush_work(&chip->work_indicator);
+ led_classdev_unregister(&chip->cdev_torch);
+ flush_work(&chip->work_torch);
+ led_classdev_unregister(&chip->cdev_flash);
+ flush_work(&chip->work_flash);
+ dev_info(&client->dev, "%s is removed\n", lm355x_name[chip->type]);
+
+ return 0;
+}
+
+static const struct i2c_device_id lm355x_id[] = {
+ {LM3554_NAME, CHIP_LM3554},
+ {LM3556_NAME, CHIP_LM3556},
+ {}
+};
+
+MODULE_DEVICE_TABLE(i2c, lm355x_id);
+
+static struct i2c_driver lm355x_i2c_driver = {
+ .driver = {
+ .name = LM355x_NAME,
+ .owner = THIS_MODULE,
+ .pm = NULL,
+ },
+ .probe = lm355x_probe,
+ .remove = __devexit_p(lm355x_remove),
+ .id_table = lm355x_id,
+};
+
+module_i2c_driver(lm355x_i2c_driver);
+
+MODULE_DESCRIPTION("Texas Instruments Flash Lighting driver for LM355x");
+MODULE_AUTHOR("Daniel Jeong <daniel.jeong@ti.com>");
+MODULE_AUTHOR("G.Shark Jeong <gshark.jeong@gmail.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/leds/leds-lm3642.c b/drivers/leds/leds-lm3642.c
new file mode 100644
index 0000000..3285006
--- /dev/null
+++ b/drivers/leds/leds-lm3642.c
@@ -0,0 +1,462 @@
+/*
+* Simple driver for Texas Instruments LM3642 LED Flash driver chip
+* Copyright (C) 2012 Texas Instruments
+*
+* 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/delay.h>
+#include <linux/i2c.h>
+#include <linux/leds.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/fs.h>
+#include <linux/regmap.h>
+#include <linux/workqueue.h>
+#include <linux/platform_data/leds-lm3642.h>
+
+#define REG_FILT_TIME (0x0)
+#define REG_IVFM_MODE (0x1)
+#define REG_TORCH_TIME (0x6)
+#define REG_FLASH (0x8)
+#define REG_I_CTRL (0x9)
+#define REG_ENABLE (0xA)
+#define REG_FLAG (0xB)
+#define REG_MAX (0xB)
+
+#define UVLO_EN_SHIFT (7)
+#define IVM_D_TH_SHIFT (2)
+#define TORCH_RAMP_UP_TIME_SHIFT (3)
+#define TORCH_RAMP_DN_TIME_SHIFT (0)
+#define INDUCTOR_I_LIMIT_SHIFT (6)
+#define FLASH_RAMP_TIME_SHIFT (3)
+#define FLASH_TOUT_TIME_SHIFT (0)
+#define TORCH_I_SHIFT (4)
+#define FLASH_I_SHIFT (0)
+#define IVFM_SHIFT (7)
+#define TX_PIN_EN_SHIFT (6)
+#define STROBE_PIN_EN_SHIFT (5)
+#define TORCH_PIN_EN_SHIFT (4)
+#define MODE_BITS_SHIFT (0)
+
+#define UVLO_EN_MASK (0x1)
+#define IVM_D_TH_MASK (0x7)
+#define TORCH_RAMP_UP_TIME_MASK (0x7)
+#define TORCH_RAMP_DN_TIME_MASK (0x7)
+#define INDUCTOR_I_LIMIT_MASK (0x1)
+#define FLASH_RAMP_TIME_MASK (0x7)
+#define FLASH_TOUT_TIME_MASK (0x7)
+#define TORCH_I_MASK (0x7)
+#define FLASH_I_MASK (0xF)
+#define IVFM_MASK (0x1)
+#define TX_PIN_EN_MASK (0x1)
+#define STROBE_PIN_EN_MASK (0x1)
+#define TORCH_PIN_EN_MASK (0x1)
+#define MODE_BITS_MASK (0x73)
+#define EX_PIN_CONTROL_MASK (0x71)
+#define EX_PIN_ENABLE_MASK (0x70)
+
+enum lm3642_mode {
+ MODES_STASNDBY = 0,
+ MODES_INDIC,
+ MODES_TORCH,
+ MODES_FLASH
+};
+
+struct lm3642_chip_data {
+ struct device *dev;
+
+ struct led_classdev cdev_flash;
+ struct led_classdev cdev_torch;
+ struct led_classdev cdev_indicator;
+
+ struct work_struct work_flash;
+ struct work_struct work_torch;
+ struct work_struct work_indicator;
+
+ u8 br_flash;
+ u8 br_torch;
+ u8 br_indicator;
+
+ enum lm3642_torch_pin_enable torch_pin;
+ enum lm3642_strobe_pin_enable strobe_pin;
+ enum lm3642_tx_pin_enable tx_pin;
+
+ struct lm3642_platform_data *pdata;
+ struct regmap *regmap;
+ struct mutex lock;
+
+ unsigned int last_flag;
+};
+
+/* chip initialize */
+static int __devinit lm3642_chip_init(struct lm3642_chip_data *chip)
+{
+ int ret;
+ struct lm3642_platform_data *pdata = chip->pdata;
+
+ /* set enable register */
+ ret = regmap_update_bits(chip->regmap, REG_ENABLE, EX_PIN_ENABLE_MASK,
+ pdata->tx_pin);
+ if (ret < 0)
+ dev_err(chip->dev, "Failed to update REG_ENABLE Register\n");
+ return ret;
+}
+
+/* chip control */
+static int lm3642_control(struct lm3642_chip_data *chip,
+ u8 brightness, enum lm3642_mode opmode)
+{
+ int ret;
+
+ ret = regmap_read(chip->regmap, REG_FLAG, &chip->last_flag);
+ if (ret < 0) {
+ dev_err(chip->dev, "Failed to read REG_FLAG Register\n");
+ goto out;
+ }
+
+ if (chip->last_flag)
+ dev_info(chip->dev, "Last FLAG is 0x%x\n", chip->last_flag);
+
+ /* brightness 0 means off-state */
+ if (!brightness)
+ opmode = MODES_STASNDBY;
+
+ switch (opmode) {
+ case MODES_TORCH:
+ ret = regmap_update_bits(chip->regmap, REG_I_CTRL,
+ TORCH_I_MASK << TORCH_I_SHIFT,
+ (brightness - 1) << TORCH_I_SHIFT);
+
+ if (chip->torch_pin)
+ opmode |= (TORCH_PIN_EN_MASK << TORCH_PIN_EN_SHIFT);
+ break;
+
+ case MODES_FLASH:
+ ret = regmap_update_bits(chip->regmap, REG_I_CTRL,
+ FLASH_I_MASK << FLASH_I_SHIFT,
+ (brightness - 1) << FLASH_I_SHIFT);
+
+ if (chip->strobe_pin)
+ opmode |= (STROBE_PIN_EN_MASK << STROBE_PIN_EN_SHIFT);
+ break;
+
+ case MODES_INDIC:
+ ret = regmap_update_bits(chip->regmap, REG_I_CTRL,
+ TORCH_I_MASK << TORCH_I_SHIFT,
+ (brightness - 1) << TORCH_I_SHIFT);
+ break;
+
+ case MODES_STASNDBY:
+
+ break;
+
+ default:
+ return ret;
+ }
+ if (ret < 0) {
+ dev_err(chip->dev, "Failed to write REG_I_CTRL Register\n");
+ goto out;
+ }
+
+ if (chip->tx_pin)
+ opmode |= (TX_PIN_EN_MASK << TX_PIN_EN_SHIFT);
+
+ ret = regmap_update_bits(chip->regmap, REG_ENABLE,
+ MODE_BITS_MASK << MODE_BITS_SHIFT,
+ opmode << MODE_BITS_SHIFT);
+out:
+ return ret;
+}
+
+/* torch */
+
+/* torch pin config for lm3642*/
+static ssize_t lm3642_torch_pin_store(struct device *dev,
+ struct device_attribute *devAttr,
+ const char *buf, size_t size)
+{
+ ssize_t ret;
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
+ struct lm3642_chip_data *chip =
+ container_of(led_cdev, struct lm3642_chip_data, cdev_indicator);
+ unsigned int state;
+
+ ret = kstrtouint(buf, 10, &state);
+ if (ret)
+ goto out_strtoint;
+ if (state != 0)
+ state = 0x01 << TORCH_PIN_EN_SHIFT;
+
+ chip->torch_pin = state;
+ ret = regmap_update_bits(chip->regmap, REG_ENABLE,
+ TORCH_PIN_EN_MASK << TORCH_PIN_EN_SHIFT,
+ state);
+ if (ret < 0)
+ goto out;
+
+ return size;
+out:
+ dev_err(chip->dev, "%s:i2c access fail to register\n", __func__);
+ return size;
+out_strtoint:
+ dev_err(chip->dev, "%s: fail to change str to int\n", __func__);
+ return size;
+}
+
+static DEVICE_ATTR(torch_pin, 0666, NULL, lm3642_torch_pin_store);
+
+static void lm3642_deferred_torch_brightness_set(struct work_struct *work)
+{
+ struct lm3642_chip_data *chip =
+ container_of(work, struct lm3642_chip_data, work_torch);
+
+ mutex_lock(&chip->lock);
+ lm3642_control(chip, chip->br_torch, MODES_TORCH);
+ mutex_unlock(&chip->lock);
+}
+
+static void lm3642_torch_brightness_set(struct led_classdev *cdev,
+ enum led_brightness brightness)
+{
+ struct lm3642_chip_data *chip =
+ container_of(cdev, struct lm3642_chip_data, cdev_torch);
+
+ chip->br_torch = brightness;
+ schedule_work(&chip->work_torch);
+}
+
+/* flash */
+
+/* strobe pin config for lm3642*/
+static ssize_t lm3642_strobe_pin_store(struct device *dev,
+ struct device_attribute *devAttr,
+ const char *buf, size_t size)
+{
+ ssize_t ret;
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
+ struct lm3642_chip_data *chip =
+ container_of(led_cdev, struct lm3642_chip_data, cdev_indicator);
+ unsigned int state;
+
+ ret = kstrtouint(buf, 10, &state);
+ if (ret)
+ goto out_strtoint;
+ if (state != 0)
+ state = 0x01 << STROBE_PIN_EN_SHIFT;
+
+ chip->strobe_pin = state;
+ ret = regmap_update_bits(chip->regmap, REG_ENABLE,
+ STROBE_PIN_EN_MASK << STROBE_PIN_EN_SHIFT,
+ state);
+ if (ret < 0)
+ goto out;
+
+ return size;
+out:
+ dev_err(chip->dev, "%s:i2c access fail to register\n", __func__);
+ return size;
+out_strtoint:
+ dev_err(chip->dev, "%s: fail to change str to int\n", __func__);
+ return size;
+}
+
+static DEVICE_ATTR(strobe_pin, 0666, NULL, lm3642_strobe_pin_store);
+
+static void lm3642_deferred_strobe_brightness_set(struct work_struct *work)
+{
+ struct lm3642_chip_data *chip =
+ container_of(work, struct lm3642_chip_data, work_flash);
+
+ mutex_lock(&chip->lock);
+ lm3642_control(chip, chip->br_flash, MODES_FLASH);
+ mutex_unlock(&chip->lock);
+}
+
+static void lm3642_strobe_brightness_set(struct led_classdev *cdev,
+ enum led_brightness brightness)
+{
+ struct lm3642_chip_data *chip =
+ container_of(cdev, struct lm3642_chip_data, cdev_flash);
+
+ chip->br_flash = brightness;
+ schedule_work(&chip->work_flash);
+}
+
+/* indicator */
+static void lm3642_deferred_indicator_brightness_set(struct work_struct *work)
+{
+ struct lm3642_chip_data *chip =
+ container_of(work, struct lm3642_chip_data, work_indicator);
+
+ mutex_lock(&chip->lock);
+ lm3642_control(chip, chip->br_indicator, MODES_INDIC);
+ mutex_unlock(&chip->lock);
+}
+
+static void lm3642_indicator_brightness_set(struct led_classdev *cdev,
+ enum led_brightness brightness)
+{
+ struct lm3642_chip_data *chip =
+ container_of(cdev, struct lm3642_chip_data, cdev_indicator);
+
+ chip->br_indicator = brightness;
+ schedule_work(&chip->work_indicator);
+}
+
+static const struct regmap_config lm3642_regmap = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = REG_MAX,
+};
+
+static int __devinit lm3642_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct lm3642_platform_data *pdata = client->dev.platform_data;
+ struct lm3642_chip_data *chip;
+
+ int err;
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+ dev_err(&client->dev, "i2c functionality check fail.\n");
+ return -EOPNOTSUPP;
+ }
+
+ if (pdata == NULL) {
+ dev_err(&client->dev, "needs Platform Data.\n");
+ return -ENODATA;
+ }
+
+ chip = devm_kzalloc(&client->dev,
+ sizeof(struct lm3642_chip_data), GFP_KERNEL);
+ if (!chip)
+ return -ENOMEM;
+
+ chip->dev = &client->dev;
+ chip->pdata = pdata;
+
+ chip->tx_pin = pdata->tx_pin;
+ chip->torch_pin = pdata->torch_pin;
+ chip->strobe_pin = pdata->strobe_pin;
+
+ chip->regmap = devm_regmap_init_i2c(client, &lm3642_regmap);
+ if (IS_ERR(chip->regmap)) {
+ err = PTR_ERR(chip->regmap);
+ dev_err(&client->dev, "Failed to allocate register map: %d\n",
+ err);
+ return err;
+ }
+
+ mutex_init(&chip->lock);
+ i2c_set_clientdata(client, chip);
+
+ err = lm3642_chip_init(chip);
+ if (err < 0)
+ goto err_out;
+
+ /* flash */
+ INIT_WORK(&chip->work_flash, lm3642_deferred_strobe_brightness_set);
+ chip->cdev_flash.name = "flash";
+ chip->cdev_flash.max_brightness = 16;
+ chip->cdev_flash.brightness_set = lm3642_strobe_brightness_set;
+ err = led_classdev_register((struct device *)
+ &client->dev, &chip->cdev_flash);
+ if (err < 0) {
+ dev_err(chip->dev, "failed to register flash\n");
+ goto err_out;
+ }
+ err = device_create_file(chip->cdev_flash.dev, &dev_attr_strobe_pin);
+ if (err < 0) {
+ dev_err(chip->dev, "failed to create strobe-pin file\n");
+ goto err_create_flash_pin_file;
+ }
+
+ /* torch */
+ INIT_WORK(&chip->work_torch, lm3642_deferred_torch_brightness_set);
+ chip->cdev_torch.name = "torch";
+ chip->cdev_torch.max_brightness = 8;
+ chip->cdev_torch.brightness_set = lm3642_torch_brightness_set;
+ err = led_classdev_register((struct device *)
+ &client->dev, &chip->cdev_torch);
+ if (err < 0) {
+ dev_err(chip->dev, "failed to register torch\n");
+ goto err_create_torch_file;
+ }
+ err = device_create_file(chip->cdev_torch.dev, &dev_attr_torch_pin);
+ if (err < 0) {
+ dev_err(chip->dev, "failed to create torch-pin file\n");
+ goto err_create_torch_pin_file;
+ }
+
+ /* indicator */
+ INIT_WORK(&chip->work_indicator,
+ lm3642_deferred_indicator_brightness_set);
+ chip->cdev_indicator.name = "indicator";
+ chip->cdev_indicator.max_brightness = 8;
+ chip->cdev_indicator.brightness_set = lm3642_indicator_brightness_set;
+ err = led_classdev_register((struct device *)
+ &client->dev, &chip->cdev_indicator);
+ if (err < 0) {
+ dev_err(chip->dev, "failed to register indicator\n");
+ goto err_create_indicator_file;
+ }
+
+ dev_info(&client->dev, "LM3642 is initialized\n");
+ return 0;
+
+err_create_indicator_file:
+ device_remove_file(chip->cdev_torch.dev, &dev_attr_torch_pin);
+err_create_torch_pin_file:
+ led_classdev_unregister(&chip->cdev_torch);
+err_create_torch_file:
+ device_remove_file(chip->cdev_flash.dev, &dev_attr_strobe_pin);
+err_create_flash_pin_file:
+ led_classdev_unregister(&chip->cdev_flash);
+err_out:
+ return err;
+}
+
+static int __devexit lm3642_remove(struct i2c_client *client)
+{
+ struct lm3642_chip_data *chip = i2c_get_clientdata(client);
+
+ led_classdev_unregister(&chip->cdev_indicator);
+ flush_work(&chip->work_indicator);
+ device_remove_file(chip->cdev_torch.dev, &dev_attr_torch_pin);
+ led_classdev_unregister(&chip->cdev_torch);
+ flush_work(&chip->work_torch);
+ device_remove_file(chip->cdev_flash.dev, &dev_attr_strobe_pin);
+ led_classdev_unregister(&chip->cdev_flash);
+ flush_work(&chip->work_flash);
+ regmap_write(chip->regmap, REG_ENABLE, 0);
+ return 0;
+}
+
+static const struct i2c_device_id lm3642_id[] = {
+ {LM3642_NAME, 0},
+ {}
+};
+
+MODULE_DEVICE_TABLE(i2c, lm3642_id);
+
+static struct i2c_driver lm3642_i2c_driver = {
+ .driver = {
+ .name = LM3642_NAME,
+ .owner = THIS_MODULE,
+ .pm = NULL,
+ },
+ .probe = lm3642_probe,
+ .remove = __devexit_p(lm3642_remove),
+ .id_table = lm3642_id,
+};
+
+module_i2c_driver(lm3642_i2c_driver);
+
+MODULE_DESCRIPTION("Texas Instruments Flash Lighting driver for LM3642");
+MODULE_AUTHOR("Daniel Jeong <daniel.jeong@ti.com>");
+MODULE_AUTHOR("G.Shark Jeong <gshark.jeong@gmail.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/leds/leds-lp5523.c b/drivers/leds/leds-lp5523.c
index fbc12ac..97994ff 100644
--- a/drivers/leds/leds-lp5523.c
+++ b/drivers/leds/leds-lp5523.c
@@ -104,6 +104,11 @@
#define LED_ACTIVE(mux, led) (!!(mux & (0x0001 << led)))
#define SHIFT_MASK(id) (((id) - 1) * 2)
+enum lp5523_chip_id {
+ LP5523,
+ LP55231,
+};
+
struct lp5523_engine {
int id;
u8 mode;
@@ -150,7 +155,7 @@ static inline struct lp5523_chip *led_to_lp5523(struct lp5523_led *led)
leds[led->id]);
}
-static int lp5523_set_mode(struct lp5523_engine *engine, u8 mode);
+static void lp5523_set_mode(struct lp5523_engine *engine, u8 mode);
static int lp5523_set_engine_mode(struct lp5523_engine *engine, u8 mode);
static int lp5523_load_program(struct lp5523_engine *engine, const u8 *pattern);
@@ -177,7 +182,7 @@ static int lp5523_detect(struct i2c_client *client)
int ret;
u8 buf;
- ret = lp5523_write(client, LP5523_REG_ENABLE, 0x40);
+ ret = lp5523_write(client, LP5523_REG_ENABLE, LP5523_ENABLE);
if (ret)
return ret;
ret = lp5523_read(client, LP5523_REG_ENABLE, &buf);
@@ -338,7 +343,8 @@ static int lp5523_mux_parse(const char *buf, u16 *mux, size_t len)
{
int i;
u16 tmp_mux = 0;
- len = len < LP5523_LEDS ? len : LP5523_LEDS;
+
+ len = min_t(int, len, LP5523_LEDS);
for (i = 0; i < len; i++) {
switch (buf[i]) {
case '1':
@@ -546,6 +552,9 @@ static int lp5523_do_store_load(struct lp5523_engine *engine,
unsigned cmd;
u8 pattern[LP5523_PROGRAM_LENGTH] = {0};
+ if (engine->mode != LP5523_CMD_LOAD)
+ return -EINVAL;
+
while ((offset < len - 1) && (i < LP5523_PROGRAM_LENGTH)) {
/* separate sscanfs because length is working only for %s */
ret = sscanf(buf + offset, "%2s%n ", c, &nrchars);
@@ -563,12 +572,7 @@ static int lp5523_do_store_load(struct lp5523_engine *engine,
goto fail;
mutex_lock(&chip->lock);
-
- if (engine->mode == LP5523_CMD_LOAD)
- ret = lp5523_load_program(engine, pattern);
- else
- ret = -EINVAL;
-
+ ret = lp5523_load_program(engine, pattern);
mutex_unlock(&chip->lock);
if (ret) {
@@ -755,6 +759,7 @@ static struct attribute *lp5523_attributes[] = {
&dev_attr_engine2_leds.attr,
&dev_attr_engine3_load.attr,
&dev_attr_engine3_leds.attr,
+ NULL,
};
static const struct attribute_group lp5523_group = {
@@ -789,26 +794,28 @@ static void lp5523_unregister_sysfs(struct i2c_client *client)
/*--------------------------------------------------------------*/
/* Set chip operating mode */
/*--------------------------------------------------------------*/
-static int lp5523_set_mode(struct lp5523_engine *engine, u8 mode)
+static void lp5523_set_mode(struct lp5523_engine *engine, u8 mode)
{
- int ret = 0;
-
/* if in that mode already do nothing, except for run */
if (mode == engine->mode && mode != LP5523_CMD_RUN)
- return 0;
+ return;
- if (mode == LP5523_CMD_RUN) {
- ret = lp5523_run_program(engine);
- } else if (mode == LP5523_CMD_LOAD) {
+ switch (mode) {
+ case LP5523_CMD_RUN:
+ lp5523_run_program(engine);
+ break;
+ case LP5523_CMD_LOAD:
lp5523_set_engine_mode(engine, LP5523_CMD_DISABLED);
lp5523_set_engine_mode(engine, LP5523_CMD_LOAD);
- } else if (mode == LP5523_CMD_DISABLED) {
+ break;
+ case LP5523_CMD_DISABLED:
lp5523_set_engine_mode(engine, LP5523_CMD_DISABLED);
+ break;
+ default:
+ return;
}
engine->mode = mode;
-
- return ret;
}
/*--------------------------------------------------------------*/
@@ -827,7 +834,8 @@ static int __init lp5523_init_engine(struct lp5523_engine *engine, int id)
}
static int __devinit lp5523_init_led(struct lp5523_led *led, struct device *dev,
- int chan, struct lp5523_platform_data *pdata)
+ int chan, struct lp5523_platform_data *pdata,
+ const char *chip_name)
{
char name[32];
int res;
@@ -846,10 +854,14 @@ static int __devinit lp5523_init_led(struct lp5523_led *led, struct device *dev,
return -EINVAL;
}
- snprintf(name, sizeof(name), "%s:channel%d",
- pdata->label ?: "lp5523", chan);
+ if (pdata->led_config[chan].name) {
+ led->cdev.name = pdata->led_config[chan].name;
+ } else {
+ snprintf(name, sizeof(name), "%s:channel%d",
+ pdata->label ? : chip_name, chan);
+ led->cdev.name = name;
+ }
- led->cdev.name = name;
led->cdev.brightness_set = lp5523_set_brightness;
res = led_classdev_register(dev, &led->cdev);
if (res < 0) {
@@ -917,7 +929,7 @@ static int __devinit lp5523_probe(struct i2c_client *client,
if (ret)
goto fail1;
- dev_info(&client->dev, "LP5523 Programmable led chip found\n");
+ dev_info(&client->dev, "%s Programmable led chip found\n", id->name);
/* Initialize engines */
for (i = 0; i < ARRAY_SIZE(chip->engines); i++) {
@@ -945,7 +957,8 @@ static int __devinit lp5523_probe(struct i2c_client *client,
INIT_WORK(&chip->leds[led].brightness_work,
lp5523_led_brightness_work);
- ret = lp5523_init_led(&chip->leds[led], &client->dev, i, pdata);
+ ret = lp5523_init_led(&chip->leds[led], &client->dev, i, pdata,
+ id->name);
if (ret) {
dev_err(&client->dev, "error initializing leds\n");
goto fail2;
@@ -970,7 +983,7 @@ static int __devinit lp5523_probe(struct i2c_client *client,
fail2:
for (i = 0; i < chip->num_leds; i++) {
led_classdev_unregister(&chip->leds[i].cdev);
- cancel_work_sync(&chip->leds[i].brightness_work);
+ flush_work(&chip->leds[i].brightness_work);
}
fail1:
if (pdata->enable)
@@ -985,11 +998,14 @@ static int lp5523_remove(struct i2c_client *client)
struct lp5523_chip *chip = i2c_get_clientdata(client);
int i;
+ /* Disable engine mode */
+ lp5523_write(client, LP5523_REG_OP_MODE, LP5523_CMD_DISABLED);
+
lp5523_unregister_sysfs(client);
for (i = 0; i < chip->num_leds; i++) {
led_classdev_unregister(&chip->leds[i].cdev);
- cancel_work_sync(&chip->leds[i].brightness_work);
+ flush_work(&chip->leds[i].brightness_work);
}
if (chip->pdata->enable)
@@ -1000,7 +1016,8 @@ static int lp5523_remove(struct i2c_client *client)
}
static const struct i2c_device_id lp5523_id[] = {
- { "lp5523", 0 },
+ { "lp5523", LP5523 },
+ { "lp55231", LP55231 },
{ }
};
@@ -1008,7 +1025,7 @@ MODULE_DEVICE_TABLE(i2c, lp5523_id);
static struct i2c_driver lp5523_driver = {
.driver = {
- .name = "lp5523",
+ .name = "lp5523x",
},
.probe = lp5523_probe,
.remove = lp5523_remove,
diff --git a/drivers/leds/leds-pca9633.c b/drivers/leds/leds-pca9633.c
index edcd706..2f2f9c4 100644
--- a/drivers/leds/leds-pca9633.c
+++ b/drivers/leds/leds-pca9633.c
@@ -22,6 +22,7 @@
#include <linux/i2c.h>
#include <linux/workqueue.h>
#include <linux/slab.h>
+#include <linux/platform_data/leds-pca9633.h>
/* LED select registers determine the source that drives LED outputs */
#define PCA9633_LED_OFF 0x0 /* LED driver off */
@@ -96,13 +97,13 @@ static int __devinit pca9633_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct pca9633_led *pca9633;
- struct led_platform_data *pdata;
+ struct pca9633_platform_data *pdata;
int i, err;
pdata = client->dev.platform_data;
if (pdata) {
- if (pdata->num_leds <= 0 || pdata->num_leds > 4) {
+ if (pdata->leds.num_leds <= 0 || pdata->leds.num_leds > 4) {
dev_err(&client->dev, "board info must claim at most 4 LEDs");
return -EINVAL;
}
@@ -119,14 +120,14 @@ static int __devinit pca9633_probe(struct i2c_client *client,
pca9633[i].led_num = i;
/* Platform data can specify LED names and default triggers */
- if (pdata && i < pdata->num_leds) {
- if (pdata->leds[i].name)
+ if (pdata && i < pdata->leds.num_leds) {
+ if (pdata->leds.leds[i].name)
snprintf(pca9633[i].name,
sizeof(pca9633[i].name), "pca9633:%s",
- pdata->leds[i].name);
- if (pdata->leds[i].default_trigger)
+ pdata->leds.leds[i].name);
+ if (pdata->leds.leds[i].default_trigger)
pca9633[i].led_cdev.default_trigger =
- pdata->leds[i].default_trigger;
+ pdata->leds.leds[i].default_trigger;
} else {
snprintf(pca9633[i].name, sizeof(pca9633[i].name),
"pca9633:%d", i);
@@ -145,6 +146,10 @@ static int __devinit pca9633_probe(struct i2c_client *client,
/* Disable LED all-call address and set normal mode */
i2c_smbus_write_byte_data(client, PCA9633_MODE1, 0x00);
+ /* Configure output: open-drain or totem pole (push-pull) */
+ if (pdata && pdata->outdrv == PCA9633_OPEN_DRAIN)
+ i2c_smbus_write_byte_data(client, PCA9633_MODE2, 0x01);
+
/* Turn off LEDs */
i2c_smbus_write_byte_data(client, PCA9633_LEDOUT, 0x00);
diff --git a/drivers/leds/leds-wm8350.c b/drivers/leds/leds-wm8350.c
index 4c62113..88f23f8 100644
--- a/drivers/leds/leds-wm8350.c
+++ b/drivers/leds/leds-wm8350.c
@@ -201,7 +201,7 @@ static int wm8350_led_probe(struct platform_device *pdev)
struct regulator *isink, *dcdc;
struct wm8350_led *led;
struct wm8350_led_platform_data *pdata = pdev->dev.platform_data;
- int ret, i;
+ int i;
if (pdata == NULL) {
dev_err(&pdev->dev, "no platform data\n");
@@ -214,24 +214,21 @@ static int wm8350_led_probe(struct platform_device *pdev)
return -EINVAL;
}
- isink = regulator_get(&pdev->dev, "led_isink");
+ isink = devm_regulator_get(&pdev->dev, "led_isink");
if (IS_ERR(isink)) {
printk(KERN_ERR "%s: can't get ISINK\n", __func__);
return PTR_ERR(isink);
}
- dcdc = regulator_get(&pdev->dev, "led_vcc");
+ dcdc = devm_regulator_get(&pdev->dev, "led_vcc");
if (IS_ERR(dcdc)) {
printk(KERN_ERR "%s: can't get DCDC\n", __func__);
- ret = PTR_ERR(dcdc);
- goto err_isink;
+ return PTR_ERR(dcdc);
}
led = devm_kzalloc(&pdev->dev, sizeof(*led), GFP_KERNEL);
- if (led == NULL) {
- ret = -ENOMEM;
- goto err_dcdc;
- }
+ if (led == NULL)
+ return -ENOMEM;
led->cdev.brightness_set = wm8350_led_set;
led->cdev.default_trigger = pdata->default_trigger;
@@ -257,17 +254,7 @@ static int wm8350_led_probe(struct platform_device *pdev)
led->value = LED_OFF;
platform_set_drvdata(pdev, led);
- ret = led_classdev_register(&pdev->dev, &led->cdev);
- if (ret < 0)
- goto err_dcdc;
-
- return 0;
-
- err_dcdc:
- regulator_put(dcdc);
- err_isink:
- regulator_put(isink);
- return ret;
+ return led_classdev_register(&pdev->dev, &led->cdev);
}
static int wm8350_led_remove(struct platform_device *pdev)
@@ -277,8 +264,6 @@ static int wm8350_led_remove(struct platform_device *pdev)
led_classdev_unregister(&led->cdev);
flush_work(&led->work);
wm8350_led_disable(led);
- regulator_put(led->dcdc);
- regulator_put(led->isink);
return 0;
}
diff --git a/drivers/leds/leds.h b/drivers/leds/leds.h
index d02acd4..4c50365 100644
--- a/drivers/leds/leds.h
+++ b/drivers/leds/leds.h
@@ -32,6 +32,8 @@ static inline int led_get_brightness(struct led_classdev *led_cdev)
return led_cdev->brightness;
}
+void led_stop_software_blink(struct led_classdev *led_cdev);
+
extern struct rw_semaphore leds_list_lock;
extern struct list_head leds_list;
diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c
index 664743d..bbf459b 100644
--- a/drivers/md/dm-crypt.c
+++ b/drivers/md/dm-crypt.c
@@ -798,14 +798,6 @@ static int crypt_convert(struct crypt_config *cc,
return 0;
}
-static void dm_crypt_bio_destructor(struct bio *bio)
-{
- struct dm_crypt_io *io = bio->bi_private;
- struct crypt_config *cc = io->cc;
-
- bio_free(bio, cc->bs);
-}
-
/*
* Generate a new unfragmented bio with the given size
* This should never violate the device limitations
@@ -974,7 +966,6 @@ static void clone_init(struct dm_crypt_io *io, struct bio *clone)
clone->bi_end_io = crypt_endio;
clone->bi_bdev = cc->dev->bdev;
clone->bi_rw = io->base_bio->bi_rw;
- clone->bi_destructor = dm_crypt_bio_destructor;
}
static int kcryptd_io_read(struct dm_crypt_io *io, gfp_t gfp)
@@ -988,19 +979,14 @@ static int kcryptd_io_read(struct dm_crypt_io *io, gfp_t gfp)
* copy the required bvecs because we need the original
* one in order to decrypt the whole bio data *afterwards*.
*/
- clone = bio_alloc_bioset(gfp, bio_segments(base_bio), cc->bs);
+ clone = bio_clone_bioset(base_bio, gfp, cc->bs);
if (!clone)
return 1;
crypt_inc_pending(io);
clone_init(io, clone);
- clone->bi_idx = 0;
- clone->bi_vcnt = bio_segments(base_bio);
- clone->bi_size = base_bio->bi_size;
clone->bi_sector = cc->start + io->sector;
- memcpy(clone->bi_io_vec, bio_iovec(base_bio),
- sizeof(struct bio_vec) * clone->bi_vcnt);
generic_make_request(clone);
return 0;
diff --git a/drivers/md/dm-io.c b/drivers/md/dm-io.c
index ea5dd28..1c46f97 100644
--- a/drivers/md/dm-io.c
+++ b/drivers/md/dm-io.c
@@ -249,16 +249,6 @@ static void vm_dp_init(struct dpages *dp, void *data)
dp->context_ptr = data;
}
-static void dm_bio_destructor(struct bio *bio)
-{
- unsigned region;
- struct io *io;
-
- retrieve_io_and_region_from_bio(bio, &io, &region);
-
- bio_free(bio, io->client->bios);
-}
-
/*
* Functions for getting the pages from kernel memory.
*/
@@ -317,7 +307,6 @@ static void do_region(int rw, unsigned region, struct dm_io_region *where,
bio->bi_sector = where->sector + (where->count - remaining);
bio->bi_bdev = where->bdev;
bio->bi_end_io = endio;
- bio->bi_destructor = dm_bio_destructor;
store_io_and_region_in_bio(bio, io, region);
if (rw & REQ_DISCARD) {
diff --git a/drivers/md/dm.c b/drivers/md/dm.c
index 67ffa39..66ceaff 100644
--- a/drivers/md/dm.c
+++ b/drivers/md/dm.c
@@ -86,12 +86,17 @@ struct dm_rq_target_io {
};
/*
- * For request-based dm.
- * One of these is allocated per bio.
+ * For request-based dm - the bio clones we allocate are embedded in these
+ * structs.
+ *
+ * We allocate these with bio_alloc_bioset, using the front_pad parameter when
+ * the bioset is created - this means the bio has to come at the end of the
+ * struct.
*/
struct dm_rq_clone_bio_info {
struct bio *orig;
struct dm_rq_target_io *tio;
+ struct bio clone;
};
union map_info *dm_get_mapinfo(struct bio *bio)
@@ -211,6 +216,11 @@ struct dm_md_mempools {
static struct kmem_cache *_io_cache;
static struct kmem_cache *_tio_cache;
static struct kmem_cache *_rq_tio_cache;
+
+/*
+ * Unused now, and needs to be deleted. But since io_pool is overloaded and it's
+ * still used for _io_cache, I'm leaving this for a later cleanup
+ */
static struct kmem_cache *_rq_bio_info_cache;
static int __init local_init(void)
@@ -467,16 +477,6 @@ static void free_rq_tio(struct dm_rq_target_io *tio)
mempool_free(tio, tio->md->tio_pool);
}
-static struct dm_rq_clone_bio_info *alloc_bio_info(struct mapped_device *md)
-{
- return mempool_alloc(md->io_pool, GFP_ATOMIC);
-}
-
-static void free_bio_info(struct dm_rq_clone_bio_info *info)
-{
- mempool_free(info, info->tio->md->io_pool);
-}
-
static int md_in_flight(struct mapped_device *md)
{
return atomic_read(&md->pending[READ]) +
@@ -681,11 +681,6 @@ static void clone_endio(struct bio *bio, int error)
}
}
- /*
- * Store md for cleanup instead of tio which is about to get freed.
- */
- bio->bi_private = md->bs;
-
free_tio(md, tio);
bio_put(bio);
dec_pending(io, error);
@@ -1036,11 +1031,6 @@ static void __map_bio(struct dm_target *ti, struct bio *clone,
/* error the io and bail out, or requeue it if needed */
md = tio->io->md;
dec_pending(tio->io, r);
- /*
- * Store bio_set for cleanup.
- */
- clone->bi_end_io = NULL;
- clone->bi_private = md->bs;
bio_put(clone);
free_tio(md, tio);
} else if (r) {
@@ -1059,13 +1049,6 @@ struct clone_info {
unsigned short idx;
};
-static void dm_bio_destructor(struct bio *bio)
-{
- struct bio_set *bs = bio->bi_private;
-
- bio_free(bio, bs);
-}
-
/*
* Creates a little bio that just does part of a bvec.
*/
@@ -1077,7 +1060,6 @@ static struct bio *split_bvec(struct bio *bio, sector_t sector,
struct bio_vec *bv = bio->bi_io_vec + idx;
clone = bio_alloc_bioset(GFP_NOIO, 1, bs);
- clone->bi_destructor = dm_bio_destructor;
*clone->bi_io_vec = *bv;
clone->bi_sector = sector;
@@ -1090,7 +1072,7 @@ static struct bio *split_bvec(struct bio *bio, sector_t sector,
clone->bi_flags |= 1 << BIO_CLONED;
if (bio_integrity(bio)) {
- bio_integrity_clone(clone, bio, GFP_NOIO, bs);
+ bio_integrity_clone(clone, bio, GFP_NOIO);
bio_integrity_trim(clone,
bio_sector_offset(bio, idx, offset), len);
}
@@ -1109,7 +1091,6 @@ static struct bio *clone_bio(struct bio *bio, sector_t sector,
clone = bio_alloc_bioset(GFP_NOIO, bio->bi_max_vecs, bs);
__bio_clone(clone, bio);
- clone->bi_destructor = dm_bio_destructor;
clone->bi_sector = sector;
clone->bi_idx = idx;
clone->bi_vcnt = idx + bv_count;
@@ -1117,7 +1098,7 @@ static struct bio *clone_bio(struct bio *bio, sector_t sector,
clone->bi_flags &= ~(1 << BIO_SEG_VALID);
if (bio_integrity(bio)) {
- bio_integrity_clone(clone, bio, GFP_NOIO, bs);
+ bio_integrity_clone(clone, bio, GFP_NOIO);
if (idx != bio->bi_idx || clone->bi_size < bio->bi_size)
bio_integrity_trim(clone,
@@ -1152,9 +1133,8 @@ static void __issue_target_request(struct clone_info *ci, struct dm_target *ti,
* ci->bio->bi_max_vecs is BIO_INLINE_VECS anyway, for both flush
* and discard, so no need for concern about wasted bvec allocations.
*/
- clone = bio_alloc_bioset(GFP_NOIO, ci->bio->bi_max_vecs, ci->md->bs);
- __bio_clone(clone, ci->bio);
- clone->bi_destructor = dm_bio_destructor;
+ clone = bio_clone_bioset(ci->bio, GFP_NOIO, ci->md->bs);
+
if (len) {
clone->bi_sector = ci->sector;
clone->bi_size = to_bytes(len);
@@ -1484,30 +1464,17 @@ void dm_dispatch_request(struct request *rq)
}
EXPORT_SYMBOL_GPL(dm_dispatch_request);
-static void dm_rq_bio_destructor(struct bio *bio)
-{
- struct dm_rq_clone_bio_info *info = bio->bi_private;
- struct mapped_device *md = info->tio->md;
-
- free_bio_info(info);
- bio_free(bio, md->bs);
-}
-
static int dm_rq_bio_constructor(struct bio *bio, struct bio *bio_orig,
void *data)
{
struct dm_rq_target_io *tio = data;
- struct mapped_device *md = tio->md;
- struct dm_rq_clone_bio_info *info = alloc_bio_info(md);
-
- if (!info)
- return -ENOMEM;
+ struct dm_rq_clone_bio_info *info =
+ container_of(bio, struct dm_rq_clone_bio_info, clone);
info->orig = bio_orig;
info->tio = tio;
bio->bi_end_io = end_clone_bio;
bio->bi_private = info;
- bio->bi_destructor = dm_rq_bio_destructor;
return 0;
}
@@ -2771,7 +2738,10 @@ struct dm_md_mempools *dm_alloc_md_mempools(unsigned type, unsigned integrity)
if (!pools->tio_pool)
goto free_io_pool_and_out;
- pools->bs = bioset_create(pool_size, 0);
+ pools->bs = (type == DM_TYPE_BIO_BASED) ?
+ bioset_create(pool_size, 0) :
+ bioset_create(pool_size,
+ offsetof(struct dm_rq_clone_bio_info, clone));
if (!pools->bs)
goto free_tio_pool_and_out;
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 308e87b..95c8801 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -155,32 +155,17 @@ static int start_readonly;
* like bio_clone, but with a local bio set
*/
-static void mddev_bio_destructor(struct bio *bio)
-{
- struct mddev *mddev, **mddevp;
-
- mddevp = (void*)bio;
- mddev = mddevp[-1];
-
- bio_free(bio, mddev->bio_set);
-}
-
struct bio *bio_alloc_mddev(gfp_t gfp_mask, int nr_iovecs,
struct mddev *mddev)
{
struct bio *b;
- struct mddev **mddevp;
if (!mddev || !mddev->bio_set)
return bio_alloc(gfp_mask, nr_iovecs);
- b = bio_alloc_bioset(gfp_mask, nr_iovecs,
- mddev->bio_set);
+ b = bio_alloc_bioset(gfp_mask, nr_iovecs, mddev->bio_set);
if (!b)
return NULL;
- mddevp = (void*)b;
- mddevp[-1] = mddev;
- b->bi_destructor = mddev_bio_destructor;
return b;
}
EXPORT_SYMBOL_GPL(bio_alloc_mddev);
@@ -188,32 +173,10 @@ EXPORT_SYMBOL_GPL(bio_alloc_mddev);
struct bio *bio_clone_mddev(struct bio *bio, gfp_t gfp_mask,
struct mddev *mddev)
{
- struct bio *b;
- struct mddev **mddevp;
-
if (!mddev || !mddev->bio_set)
return bio_clone(bio, gfp_mask);
- b = bio_alloc_bioset(gfp_mask, bio->bi_max_vecs,
- mddev->bio_set);
- if (!b)
- return NULL;
- mddevp = (void*)b;
- mddevp[-1] = mddev;
- b->bi_destructor = mddev_bio_destructor;
- __bio_clone(b, bio);
- if (bio_integrity(bio)) {
- int ret;
-
- ret = bio_integrity_clone(b, bio, gfp_mask, mddev->bio_set);
-
- if (ret < 0) {
- bio_put(b);
- return NULL;
- }
- }
-
- return b;
+ return bio_clone_bioset(bio, gfp_mask, mddev->bio_set);
}
EXPORT_SYMBOL_GPL(bio_clone_mddev);
@@ -5006,8 +4969,7 @@ int md_run(struct mddev *mddev)
}
if (mddev->bio_set == NULL)
- mddev->bio_set = bioset_create(BIO_POOL_SIZE,
- sizeof(struct mddev *));
+ mddev->bio_set = bioset_create(BIO_POOL_SIZE, 0);
spin_lock(&pers_lock);
pers = find_pers(mddev->level, mddev->clevel);
diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c
index de63a1f..a9e4fa9 100644
--- a/drivers/md/raid0.c
+++ b/drivers/md/raid0.c
@@ -422,6 +422,7 @@ static int raid0_run(struct mddev *mddev)
if (md_check_no_bitmap(mddev))
return -EINVAL;
blk_queue_max_hw_sectors(mddev->queue, mddev->chunk_sectors);
+ blk_queue_max_write_same_sectors(mddev->queue, mddev->chunk_sectors);
/* if private is not null, we are here after takeover */
if (mddev->private == NULL) {
diff --git a/drivers/media/platform/omap/omap_vout.c b/drivers/media/platform/omap/omap_vout.c
index 134016f..a3b1a34 100644
--- a/drivers/media/platform/omap/omap_vout.c
+++ b/drivers/media/platform/omap/omap_vout.c
@@ -455,11 +455,15 @@ static int omapvid_init(struct omap_vout_device *vout, u32 addr)
win = &vout->win;
for (i = 0; i < ovid->num_overlays; i++) {
+ struct omap_dss_device *dssdev;
+
ovl = ovid->overlays[i];
- if (!ovl->manager || !ovl->manager->device)
+ dssdev = ovl->get_device(ovl);
+
+ if (!dssdev)
return -EINVAL;
- timing = &ovl->manager->device->panel.timings;
+ timing = &dssdev->panel.timings;
outw = win->w.width;
outh = win->w.height;
@@ -516,8 +520,11 @@ static int omapvid_apply_changes(struct omap_vout_device *vout)
struct omapvideo_info *ovid = &vout->vid_info;
for (i = 0; i < ovid->num_overlays; i++) {
+ struct omap_dss_device *dssdev;
+
ovl = ovid->overlays[i];
- if (!ovl->manager || !ovl->manager->device)
+ dssdev = ovl->get_device(ovl);
+ if (!dssdev)
return -EINVAL;
ovl->manager->apply(ovl->manager);
}
@@ -580,12 +587,14 @@ static void omap_vout_isr(void *arg, unsigned int irqstatus)
ovid = &vout->vid_info;
ovl = ovid->overlays[0];
- /* get the display device attached to the overlay */
- if (!ovl->manager || !ovl->manager->device)
- return;
mgr_id = ovl->manager->id;
- cur_display = ovl->manager->device;
+
+ /* get the display device attached to the overlay */
+ cur_display = ovl->get_device(ovl);
+
+ if (!cur_display)
+ return;
spin_lock(&vout->vbq_lock);
do_gettimeofday(&timevalue);
@@ -949,7 +958,9 @@ static int omap_vout_release(struct file *file)
/* Disable all the overlay managers connected with this interface */
for (i = 0; i < ovid->num_overlays; i++) {
struct omap_overlay *ovl = ovid->overlays[i];
- if (ovl->manager && ovl->manager->device)
+ struct omap_dss_device *dssdev = ovl->get_device(ovl);
+
+ if (dssdev)
ovl->disable(ovl);
}
/* Turn off the pipeline */
@@ -1082,14 +1093,17 @@ static int vidioc_try_fmt_vid_out(struct file *file, void *fh,
struct omapvideo_info *ovid;
struct omap_video_timings *timing;
struct omap_vout_device *vout = fh;
+ struct omap_dss_device *dssdev;
ovid = &vout->vid_info;
ovl = ovid->overlays[0];
+ /* get the display device attached to the overlay */
+ dssdev = ovl->get_device(ovl);
- if (!ovl->manager || !ovl->manager->device)
+ if (!dssdev)
return -EINVAL;
- /* get the display device attached to the overlay */
- timing = &ovl->manager->device->panel.timings;
+
+ timing = &dssdev->panel.timings;
vout->fbuf.fmt.height = timing->y_res;
vout->fbuf.fmt.width = timing->x_res;
@@ -1106,6 +1120,7 @@ static int vidioc_s_fmt_vid_out(struct file *file, void *fh,
struct omapvideo_info *ovid;
struct omap_video_timings *timing;
struct omap_vout_device *vout = fh;
+ struct omap_dss_device *dssdev;
if (vout->streaming)
return -EBUSY;
@@ -1114,13 +1129,14 @@ static int vidioc_s_fmt_vid_out(struct file *file, void *fh,
ovid = &vout->vid_info;
ovl = ovid->overlays[0];
+ dssdev = ovl->get_device(ovl);
/* get the display device attached to the overlay */
- if (!ovl->manager || !ovl->manager->device) {
+ if (!dssdev) {
ret = -EINVAL;
goto s_fmt_vid_out_exit;
}
- timing = &ovl->manager->device->panel.timings;
+ timing = &dssdev->panel.timings;
/* We dont support RGB24-packed mode if vrfb rotation
* is enabled*/
@@ -1299,6 +1315,7 @@ static int vidioc_s_crop(struct file *file, void *fh, const struct v4l2_crop *cr
struct omapvideo_info *ovid;
struct omap_overlay *ovl;
struct omap_video_timings *timing;
+ struct omap_dss_device *dssdev;
if (vout->streaming)
return -EBUSY;
@@ -1306,13 +1323,15 @@ static int vidioc_s_crop(struct file *file, void *fh, const struct v4l2_crop *cr
mutex_lock(&vout->lock);
ovid = &vout->vid_info;
ovl = ovid->overlays[0];
+ /* get the display device attached to the overlay */
+ dssdev = ovl->get_device(ovl);
- if (!ovl->manager || !ovl->manager->device) {
+ if (!dssdev) {
ret = -EINVAL;
goto s_crop_err;
}
- /* get the display device attached to the overlay */
- timing = &ovl->manager->device->panel.timings;
+
+ timing = &dssdev->panel.timings;
if (is_rotation_90_or_270(vout)) {
vout->fbuf.fmt.height = timing->x_res;
@@ -1668,7 +1687,7 @@ static int vidioc_streamon(struct file *file, void *fh, enum v4l2_buf_type i)
for (j = 0; j < ovid->num_overlays; j++) {
struct omap_overlay *ovl = ovid->overlays[j];
- if (ovl->manager && ovl->manager->device) {
+ if (ovl->get_device(ovl)) {
struct omap_overlay_info info;
ovl->get_overlay_info(ovl, &info);
info.paddr = addr;
@@ -1691,8 +1710,9 @@ static int vidioc_streamon(struct file *file, void *fh, enum v4l2_buf_type i)
for (j = 0; j < ovid->num_overlays; j++) {
struct omap_overlay *ovl = ovid->overlays[j];
+ struct omap_dss_device *dssdev = ovl->get_device(ovl);
- if (ovl->manager && ovl->manager->device) {
+ if (dssdev) {
ret = ovl->enable(ovl);
if (ret)
goto streamon_err1;
@@ -1727,8 +1747,9 @@ static int vidioc_streamoff(struct file *file, void *fh, enum v4l2_buf_type i)
for (j = 0; j < ovid->num_overlays; j++) {
struct omap_overlay *ovl = ovid->overlays[j];
+ struct omap_dss_device *dssdev = ovl->get_device(ovl);
- if (ovl->manager && ovl->manager->device)
+ if (dssdev)
ovl->disable(ovl);
}
@@ -1891,8 +1912,8 @@ static int __init omap_vout_setup_video_data(struct omap_vout_device *vout)
struct video_device *vfd;
struct v4l2_pix_format *pix;
struct v4l2_control *control;
- struct omap_dss_device *display =
- vout->vid_info.overlays[0]->manager->device;
+ struct omap_overlay *ovl = vout->vid_info.overlays[0];
+ struct omap_dss_device *display = ovl->get_device(ovl);
/* set the default pix */
pix = &vout->pix;
@@ -2207,8 +2228,10 @@ static int __init omap_vout_probe(struct platform_device *pdev)
*/
for (i = 1; i < vid_dev->num_overlays; i++) {
ovl = omap_dss_get_overlay(i);
- if (ovl->manager && ovl->manager->device) {
- def_display = ovl->manager->device;
+ dssdev = ovl->get_device(ovl);
+
+ if (dssdev) {
+ def_display = dssdev;
} else {
dev_warn(&pdev->dev, "cannot find display\n");
def_display = NULL;
@@ -2255,8 +2278,10 @@ probe_err1:
for (i = 1; i < vid_dev->num_overlays; i++) {
def_display = NULL;
ovl = omap_dss_get_overlay(i);
- if (ovl->manager && ovl->manager->device)
- def_display = ovl->manager->device;
+ dssdev = ovl->get_device(ovl);
+
+ if (dssdev)
+ def_display = dssdev;
if (def_display && def_display->driver)
def_display->driver->disable(def_display);
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 99c7335..b151b7c 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -60,16 +60,6 @@ config ATMEL_PWM
purposes including software controlled power-efficient backlights
on LCD displays, motor control, and waveform generation.
-config AB8500_PWM
- bool "AB8500 PWM support"
- depends on AB8500_CORE && ARCH_U8500
- select HAVE_PWM
- depends on !PWM
- help
- This driver exports functions to enable/disble/config/free Pulse
- Width Modulation in the Analog Baseband Chip AB8500.
- It is used by led and backlight driver to control the intensity.
-
config ATMEL_TCLIB
bool "Atmel AT32/AT91 Timer/Counter Library"
depends on (AVR32 || ARCH_AT91)
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index b88df7a..2129377 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -44,7 +44,6 @@ obj-$(CONFIG_VMWARE_BALLOON) += vmw_balloon.o
obj-$(CONFIG_ARM_CHARLCD) += arm-charlcd.o
obj-$(CONFIG_PCH_PHUB) += pch_phub.o
obj-y += ti-st/
-obj-$(CONFIG_AB8500_PWM) += ab8500-pwm.o
obj-y += lis3lv02d/
obj-y += carma/
obj-$(CONFIG_USB_SWITCH_FSA9480) += fsa9480.o
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 8ac5246..06c42cf 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -26,6 +26,7 @@
#include <linux/suspend.h>
#include <linux/fault-inject.h>
#include <linux/random.h>
+#include <linux/slab.h>
#include <linux/mmc/card.h>
#include <linux/mmc/host.h>
@@ -41,6 +42,12 @@
#include "sd_ops.h"
#include "sdio_ops.h"
+/*
+ * Background operations can take a long time, depending on the housekeeping
+ * operations the card has to perform.
+ */
+#define MMC_BKOPS_MAX_TIMEOUT (4 * 60 * 1000) /* max time to wait in ms */
+
static struct workqueue_struct *workqueue;
static const unsigned freqs[] = { 400000, 300000, 200000, 100000 };
@@ -245,6 +252,70 @@ mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
host->ops->request(host, mrq);
}
+/**
+ * mmc_start_bkops - start BKOPS for supported cards
+ * @card: MMC card to start BKOPS
+ * @form_exception: A flag to indicate if this function was
+ * called due to an exception raised by the card
+ *
+ * Start background operations whenever requested.
+ * When the urgent BKOPS bit is set in a R1 command response
+ * then background operations should be started immediately.
+*/
+void mmc_start_bkops(struct mmc_card *card, bool from_exception)
+{
+ int err;
+ int timeout;
+ bool use_busy_signal;
+
+ BUG_ON(!card);
+
+ if (!card->ext_csd.bkops_en || mmc_card_doing_bkops(card))
+ return;
+
+ err = mmc_read_bkops_status(card);
+ if (err) {
+ pr_err("%s: Failed to read bkops status: %d\n",
+ mmc_hostname(card->host), err);
+ return;
+ }
+
+ if (!card->ext_csd.raw_bkops_status)
+ return;
+
+ if (card->ext_csd.raw_bkops_status < EXT_CSD_BKOPS_LEVEL_2 &&
+ from_exception)
+ return;
+
+ mmc_claim_host(card->host);
+ if (card->ext_csd.raw_bkops_status >= EXT_CSD_BKOPS_LEVEL_2) {
+ timeout = MMC_BKOPS_MAX_TIMEOUT;
+ use_busy_signal = true;
+ } else {
+ timeout = 0;
+ use_busy_signal = false;
+ }
+
+ err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+ EXT_CSD_BKOPS_START, 1, timeout, use_busy_signal);
+ if (err) {
+ pr_warn("%s: Error %d starting bkops\n",
+ mmc_hostname(card->host), err);
+ goto out;
+ }
+
+ /*
+ * For urgent bkops status (LEVEL_2 and more)
+ * bkops executed synchronously, otherwise
+ * the operation is in progress
+ */
+ if (!use_busy_signal)
+ mmc_card_set_doing_bkops(card);
+out:
+ mmc_release_host(card->host);
+}
+EXPORT_SYMBOL(mmc_start_bkops);
+
static void mmc_wait_done(struct mmc_request *mrq)
{
complete(&mrq->completion);
@@ -354,6 +425,14 @@ struct mmc_async_req *mmc_start_req(struct mmc_host *host,
if (host->areq) {
mmc_wait_for_req_done(host, host->areq->mrq);
err = host->areq->err_check(host->card, host->areq);
+ /*
+ * Check BKOPS urgency for each R1 response
+ */
+ if (host->card && mmc_card_mmc(host->card) &&
+ ((mmc_resp_type(host->areq->mrq->cmd) == MMC_RSP_R1) ||
+ (mmc_resp_type(host->areq->mrq->cmd) == MMC_RSP_R1B)) &&
+ (host->areq->mrq->cmd->resp[0] & R1_EXCEPTION_EVENT))
+ mmc_start_bkops(host->card, true);
}
if (!err && areq)
@@ -398,7 +477,7 @@ EXPORT_SYMBOL(mmc_wait_for_req);
* @card: the MMC card associated with the HPI transfer
*
* Issued High Priority Interrupt, and check for card status
- * util out-of prg-state.
+ * until out-of prg-state.
*/
int mmc_interrupt_hpi(struct mmc_card *card)
{
@@ -424,8 +503,9 @@ int mmc_interrupt_hpi(struct mmc_card *card)
case R1_STATE_IDLE:
case R1_STATE_READY:
case R1_STATE_STBY:
+ case R1_STATE_TRAN:
/*
- * In idle states, HPI is not needed and the caller
+ * In idle and transfer states, HPI is not needed and the caller
* can issue the next intended command immediately
*/
goto out;
@@ -489,6 +569,64 @@ int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, int retries
EXPORT_SYMBOL(mmc_wait_for_cmd);
/**
+ * mmc_stop_bkops - stop ongoing BKOPS
+ * @card: MMC card to check BKOPS
+ *
+ * Send HPI command to stop ongoing background operations to
+ * allow rapid servicing of foreground operations, e.g. read/
+ * writes. Wait until the card comes out of the programming state
+ * to avoid errors in servicing read/write requests.
+ */
+int mmc_stop_bkops(struct mmc_card *card)
+{
+ int err = 0;
+
+ BUG_ON(!card);
+ err = mmc_interrupt_hpi(card);
+
+ /*
+ * If err is EINVAL, we can't issue an HPI.
+ * It should complete the BKOPS.
+ */
+ if (!err || (err == -EINVAL)) {
+ mmc_card_clr_doing_bkops(card);
+ err = 0;
+ }
+
+ return err;
+}
+EXPORT_SYMBOL(mmc_stop_bkops);
+
+int mmc_read_bkops_status(struct mmc_card *card)
+{
+ int err;
+ u8 *ext_csd;
+
+ /*
+ * In future work, we should consider storing the entire ext_csd.
+ */
+ ext_csd = kmalloc(512, GFP_KERNEL);
+ if (!ext_csd) {
+ pr_err("%s: could not allocate buffer to receive the ext_csd.\n",
+ mmc_hostname(card->host));
+ return -ENOMEM;
+ }
+
+ mmc_claim_host(card->host);
+ err = mmc_send_ext_csd(card, ext_csd);
+ mmc_release_host(card->host);
+ if (err)
+ goto out;
+
+ card->ext_csd.raw_bkops_status = ext_csd[EXT_CSD_BKOPS_STATUS];
+ card->ext_csd.raw_exception_status = ext_csd[EXT_CSD_EXP_EVENTS_STATUS];
+out:
+ kfree(ext_csd);
+ return err;
+}
+EXPORT_SYMBOL(mmc_read_bkops_status);
+
+/**
* mmc_set_data_timeout - set the timeout for a data command
* @data: data phase for command
* @card: the MMC card associated with the data transfer
@@ -975,7 +1113,8 @@ int mmc_regulator_set_ocr(struct mmc_host *mmc,
int tmp;
int voltage;
- /* REVISIT mmc_vddrange_to_ocrmask() may have set some
+ /*
+ * REVISIT mmc_vddrange_to_ocrmask() may have set some
* bits this regulator doesn't quite support ... don't
* be too picky, most cards and regulators are OK with
* a 0.1V range goof (it's a small error percentage).
@@ -989,12 +1128,13 @@ int mmc_regulator_set_ocr(struct mmc_host *mmc,
max_uV = min_uV + 100 * 1000;
}
- /* avoid needless changes to this voltage; the regulator
- * might not allow this operation
+ /*
+ * If we're using a fixed/static regulator, don't call
+ * regulator_set_voltage; it would fail.
*/
voltage = regulator_get_voltage(supply);
- if (mmc->caps2 & MMC_CAP2_BROKEN_VOLTAGE)
+ if (regulator_count_voltages(supply) == 1)
min_uV = max_uV = voltage;
if (voltage < 0)
@@ -1133,48 +1273,6 @@ void mmc_set_driver_type(struct mmc_host *host, unsigned int drv_type)
mmc_host_clk_release(host);
}
-static void mmc_poweroff_notify(struct mmc_host *host)
-{
- struct mmc_card *card;
- unsigned int timeout;
- unsigned int notify_type = EXT_CSD_NO_POWER_NOTIFICATION;
- int err = 0;
-
- card = host->card;
- mmc_claim_host(host);
-
- /*
- * Send power notify command only if card
- * is mmc and notify state is powered ON
- */
- if (card && mmc_card_mmc(card) &&
- (card->poweroff_notify_state == MMC_POWERED_ON)) {
-
- if (host->power_notify_type == MMC_HOST_PW_NOTIFY_SHORT) {
- notify_type = EXT_CSD_POWER_OFF_SHORT;
- timeout = card->ext_csd.generic_cmd6_time;
- card->poweroff_notify_state = MMC_POWEROFF_SHORT;
- } else {
- notify_type = EXT_CSD_POWER_OFF_LONG;
- timeout = card->ext_csd.power_off_longtime;
- card->poweroff_notify_state = MMC_POWEROFF_LONG;
- }
-
- err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
- EXT_CSD_POWER_OFF_NOTIFICATION,
- notify_type, timeout);
-
- if (err && err != -EBADMSG)
- pr_err("Device failed to respond within %d poweroff "
- "time. Forcefully powering down the device\n",
- timeout);
-
- /* Set the card state to no notification after the poweroff */
- card->poweroff_notify_state = MMC_NO_POWER_NOTIFICATION;
- }
- mmc_release_host(host);
-}
-
/*
* Apply power to the MMC stack. This is a two-stage process.
* First, we enable power to the card without the clock running.
@@ -1237,8 +1335,6 @@ static void mmc_power_up(struct mmc_host *host)
void mmc_power_off(struct mmc_host *host)
{
- int err = 0;
-
if (host->ios.power_mode == MMC_POWER_OFF)
return;
@@ -1247,22 +1343,6 @@ void mmc_power_off(struct mmc_host *host)
host->ios.clock = 0;
host->ios.vdd = 0;
- /*
- * For eMMC 4.5 device send AWAKE command before
- * POWER_OFF_NOTIFY command, because in sleep state
- * eMMC 4.5 devices respond to only RESET and AWAKE cmd
- */
- if (host->card && mmc_card_is_sleep(host->card) &&
- host->bus_ops->resume) {
- err = host->bus_ops->resume(host);
-
- if (!err)
- mmc_poweroff_notify(host);
- else
- pr_warning("%s: error %d during resume "
- "(continue with poweroff sequence)\n",
- mmc_hostname(host), err);
- }
/*
* Reset ocr mask to be the highest possible voltage supported for
@@ -2052,6 +2132,11 @@ void mmc_rescan(struct work_struct *work)
if (host->rescan_disable)
return;
+ /* If there is a non-removable card registered, only scan once */
+ if ((host->caps & MMC_CAP_NONREMOVABLE) && host->rescan_entered)
+ return;
+ host->rescan_entered = 1;
+
mmc_bus_get(host);
/*
@@ -2327,9 +2412,14 @@ int mmc_suspend_host(struct mmc_host *host)
mmc_bus_get(host);
if (host->bus_ops && !host->bus_dead) {
-
- if (host->bus_ops->suspend)
+ if (host->bus_ops->suspend) {
+ if (mmc_card_doing_bkops(host->card)) {
+ err = mmc_stop_bkops(host->card);
+ if (err)
+ goto out;
+ }
err = host->bus_ops->suspend(host);
+ }
if (err == -ENOSYS || !host->bus_ops->resume) {
/*
@@ -2411,15 +2501,24 @@ int mmc_pm_notify(struct notifier_block *notify_block,
struct mmc_host *host = container_of(
notify_block, struct mmc_host, pm_notify);
unsigned long flags;
-
+ int err = 0;
switch (mode) {
case PM_HIBERNATION_PREPARE:
case PM_SUSPEND_PREPARE:
+ if (host->card && mmc_card_mmc(host->card) &&
+ mmc_card_doing_bkops(host->card)) {
+ err = mmc_stop_bkops(host->card);
+ if (err) {
+ pr_err("%s: didn't stop bkops\n",
+ mmc_hostname(host));
+ return err;
+ }
+ mmc_card_clr_doing_bkops(host->card);
+ }
spin_lock_irqsave(&host->lock, flags);
host->rescan_disable = 1;
- host->power_notify_type = MMC_HOST_PW_NOTIFY_SHORT;
spin_unlock_irqrestore(&host->lock, flags);
cancel_delayed_work_sync(&host->detect);
@@ -2443,7 +2542,6 @@ int mmc_pm_notify(struct notifier_block *notify_block,
spin_lock_irqsave(&host->lock, flags);
host->rescan_disable = 0;
- host->power_notify_type = MMC_HOST_PW_NOTIFY_LONG;
spin_unlock_irqrestore(&host->lock, flags);
mmc_detect_change(host, 0);
diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
index 9ab5b17..d96c643 100644
--- a/drivers/mmc/core/debugfs.c
+++ b/drivers/mmc/core/debugfs.c
@@ -281,7 +281,7 @@ static int mmc_ext_csd_open(struct inode *inode, struct file *filp)
if (err)
goto out_free;
- for (i = 511; i >= 0; i--)
+ for (i = 0; i < 512; i++)
n += sprintf(buf + n, "%02x", ext_csd[i]);
n += sprintf(buf + n, "\n");
BUG_ON(n != EXT_CSD_STR_LEN);
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 396b258..7cc4638 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -463,6 +463,17 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
}
if (card->ext_csd.rev >= 5) {
+ /* check whether the eMMC card supports BKOPS */
+ if (ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1) {
+ card->ext_csd.bkops = 1;
+ card->ext_csd.bkops_en = ext_csd[EXT_CSD_BKOPS_EN];
+ card->ext_csd.raw_bkops_status =
+ ext_csd[EXT_CSD_BKOPS_STATUS];
+ if (!card->ext_csd.bkops_en)
+ pr_info("%s: BKOPS_EN bit is not set\n",
+ mmc_hostname(card->host));
+ }
+
/* check whether the eMMC card supports HPI */
if (ext_csd[EXT_CSD_HPI_FEATURES] & 0x1) {
card->ext_csd.hpi = 1;
@@ -996,7 +1007,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
* so check for success and update the flag
*/
if (!err)
- card->poweroff_notify_state = MMC_POWERED_ON;
+ card->ext_csd.power_off_notification = EXT_CSD_POWER_ON;
}
/*
@@ -1262,6 +1273,35 @@ err:
return err;
}
+static int mmc_can_poweroff_notify(const struct mmc_card *card)
+{
+ return card &&
+ mmc_card_mmc(card) &&
+ (card->ext_csd.power_off_notification == EXT_CSD_POWER_ON);
+}
+
+static int mmc_poweroff_notify(struct mmc_card *card, unsigned int notify_type)
+{
+ unsigned int timeout = card->ext_csd.generic_cmd6_time;
+ int err;
+
+ /* Use EXT_CSD_POWER_OFF_SHORT as default notification type. */
+ if (notify_type == EXT_CSD_POWER_OFF_LONG)
+ timeout = card->ext_csd.power_off_longtime;
+
+ err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+ EXT_CSD_POWER_OFF_NOTIFICATION,
+ notify_type, timeout);
+ if (err)
+ pr_err("%s: Power Off Notification timed out, %u\n",
+ mmc_hostname(card->host), timeout);
+
+ /* Disable the power off notification after the switch operation. */
+ card->ext_csd.power_off_notification = EXT_CSD_NO_POWER_NOTIFICATION;
+
+ return err;
+}
+
/*
* Host is being removed. Free up the current card.
*/
@@ -1322,11 +1362,11 @@ static int mmc_suspend(struct mmc_host *host)
BUG_ON(!host->card);
mmc_claim_host(host);
- if (mmc_card_can_sleep(host)) {
+ if (mmc_can_poweroff_notify(host->card))
+ err = mmc_poweroff_notify(host->card, EXT_CSD_POWER_OFF_SHORT);
+ else if (mmc_card_can_sleep(host))
err = mmc_card_sleep(host);
- if (!err)
- mmc_card_set_sleep(host->card);
- } else if (!mmc_host_is_spi(host))
+ else if (!mmc_host_is_spi(host))
err = mmc_deselect_cards(host);
host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_200);
mmc_release_host(host);
@@ -1348,11 +1388,7 @@ static int mmc_resume(struct mmc_host *host)
BUG_ON(!host->card);
mmc_claim_host(host);
- if (mmc_card_is_sleep(host->card)) {
- err = mmc_card_awake(host);
- mmc_card_clr_sleep(host->card);
- } else
- err = mmc_init_card(host, host->ocr, host->card);
+ err = mmc_init_card(host, host->ocr, host->card);
mmc_release_host(host);
return err;
@@ -1363,7 +1399,6 @@ static int mmc_power_restore(struct mmc_host *host)
int ret;
host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_200);
- mmc_card_clr_sleep(host->card);
mmc_claim_host(host);
ret = mmc_init_card(host, host->ocr, host->card);
mmc_release_host(host);
diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
index 0ed2cc5..a0e1720 100644
--- a/drivers/mmc/core/mmc_ops.c
+++ b/drivers/mmc/core/mmc_ops.c
@@ -230,6 +230,10 @@ mmc_send_cxd_native(struct mmc_host *host, u32 arg, u32 *cxd, int opcode)
return 0;
}
+/*
+ * NOTE: void *buf, caller for the buf is required to use DMA-capable
+ * buffer or on-stack buffer (with some overhead in callee).
+ */
static int
mmc_send_cxd_data(struct mmc_card *card, struct mmc_host *host,
u32 opcode, void *buf, unsigned len)
@@ -239,13 +243,19 @@ mmc_send_cxd_data(struct mmc_card *card, struct mmc_host *host,
struct mmc_data data = {0};
struct scatterlist sg;
void *data_buf;
+ int is_on_stack;
- /* dma onto stack is unsafe/nonportable, but callers to this
- * routine normally provide temporary on-stack buffers ...
- */
- data_buf = kmalloc(len, GFP_KERNEL);
- if (data_buf == NULL)
- return -ENOMEM;
+ is_on_stack = object_is_on_stack(buf);
+ if (is_on_stack) {
+ /*
+ * dma onto stack is unsafe/nonportable, but callers to this
+ * routine normally provide temporary on-stack buffers ...
+ */
+ data_buf = kmalloc(len, GFP_KERNEL);
+ if (!data_buf)
+ return -ENOMEM;
+ } else
+ data_buf = buf;
mrq.cmd = &cmd;
mrq.data = &data;
@@ -280,8 +290,10 @@ mmc_send_cxd_data(struct mmc_card *card, struct mmc_host *host,
mmc_wait_for_req(host, &mrq);
- memcpy(buf, data_buf, len);
- kfree(data_buf);
+ if (is_on_stack) {
+ memcpy(buf, data_buf, len);
+ kfree(data_buf);
+ }
if (cmd.error)
return cmd.error;
@@ -294,24 +306,32 @@ mmc_send_cxd_data(struct mmc_card *card, struct mmc_host *host,
int mmc_send_csd(struct mmc_card *card, u32 *csd)
{
int ret, i;
+ u32 *csd_tmp;
if (!mmc_host_is_spi(card->host))
return mmc_send_cxd_native(card->host, card->rca << 16,
csd, MMC_SEND_CSD);
- ret = mmc_send_cxd_data(card, card->host, MMC_SEND_CSD, csd, 16);
+ csd_tmp = kmalloc(16, GFP_KERNEL);
+ if (!csd_tmp)
+ return -ENOMEM;
+
+ ret = mmc_send_cxd_data(card, card->host, MMC_SEND_CSD, csd_tmp, 16);
if (ret)
- return ret;
+ goto err;
for (i = 0;i < 4;i++)
- csd[i] = be32_to_cpu(csd[i]);
+ csd[i] = be32_to_cpu(csd_tmp[i]);
- return 0;
+err:
+ kfree(csd_tmp);
+ return ret;
}
int mmc_send_cid(struct mmc_host *host, u32 *cid)
{
int ret, i;
+ u32 *cid_tmp;
if (!mmc_host_is_spi(host)) {
if (!host->card)
@@ -320,14 +340,20 @@ int mmc_send_cid(struct mmc_host *host, u32 *cid)
cid, MMC_SEND_CID);
}
- ret = mmc_send_cxd_data(NULL, host, MMC_SEND_CID, cid, 16);
+ cid_tmp = kmalloc(16, GFP_KERNEL);
+ if (!cid_tmp)
+ return -ENOMEM;
+
+ ret = mmc_send_cxd_data(NULL, host, MMC_SEND_CID, cid_tmp, 16);
if (ret)
- return ret;
+ goto err;
for (i = 0;i < 4;i++)
- cid[i] = be32_to_cpu(cid[i]);
+ cid[i] = be32_to_cpu(cid_tmp[i]);
- return 0;
+err:
+ kfree(cid_tmp);
+ return ret;
}
int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd)
@@ -367,18 +393,19 @@ int mmc_spi_set_crc(struct mmc_host *host, int use_crc)
}
/**
- * mmc_switch - modify EXT_CSD register
+ * __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
+ * @use_busy_signal: use the busy signal as response type
*
* 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 __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
+ unsigned int timeout_ms, bool use_busy_signal)
{
int err;
struct mmc_command cmd = {0};
@@ -392,13 +419,23 @@ int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
(index << 16) |
(value << 8) |
set;
- cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
+ cmd.flags = MMC_CMD_AC;
+ if (use_busy_signal)
+ cmd.flags |= MMC_RSP_SPI_R1B | MMC_RSP_R1B;
+ else
+ cmd.flags |= MMC_RSP_SPI_R1 | MMC_RSP_R1;
+
+
cmd.cmd_timeout_ms = timeout_ms;
err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES);
if (err)
return err;
+ /* No need to check card status in case of unblocking command */
+ if (!use_busy_signal)
+ return 0;
+
/* Must check status to be sure of no errors */
do {
err = mmc_send_status(card, &status);
@@ -423,6 +460,13 @@ int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
return 0;
}
+EXPORT_SYMBOL_GPL(__mmc_switch);
+
+int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
+ unsigned int timeout_ms)
+{
+ return __mmc_switch(card, set, index, value, timeout_ms, true);
+}
EXPORT_SYMBOL_GPL(mmc_switch);
int mmc_send_status(struct mmc_card *card, u32 *status)
diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c
index 236842e..6bf6879 100644
--- a/drivers/mmc/core/sdio_bus.c
+++ b/drivers/mmc/core/sdio_bus.c
@@ -193,14 +193,7 @@ static int sdio_bus_remove(struct device *dev)
}
#ifdef CONFIG_PM
-
-static int pm_no_operation(struct device *dev)
-{
- return 0;
-}
-
static const struct dev_pm_ops sdio_bus_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(pm_no_operation, pm_no_operation)
SET_RUNTIME_PM_OPS(
pm_generic_runtime_suspend,
pm_generic_runtime_resume,
diff --git a/drivers/mmc/core/slot-gpio.c b/drivers/mmc/core/slot-gpio.c
index 0582429..08c6b3d 100644
--- a/drivers/mmc/core/slot-gpio.c
+++ b/drivers/mmc/core/slot-gpio.c
@@ -100,7 +100,13 @@ int mmc_gpio_request_ro(struct mmc_host *host, unsigned int gpio)
ctx = host->slot.handler_priv;
- return gpio_request_one(gpio, GPIOF_DIR_IN, ctx->ro_label);
+ ret = gpio_request_one(gpio, GPIOF_DIR_IN, ctx->ro_label);
+ if (ret < 0)
+ return ret;
+
+ ctx->ro_gpio = gpio;
+
+ return 0;
}
EXPORT_SYMBOL(mmc_gpio_request_ro);
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index aa131b3..9bf10e7 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -540,6 +540,15 @@ config MMC_DW_PLTFM
If unsure, say Y.
+config MMC_DW_EXYNOS
+ tristate "Exynos specific extentions for Synopsys DW Memory Card Interface"
+ depends on MMC_DW
+ select MMC_DW_PLTFM
+ help
+ This selects support for Samsung Exynos SoC specific extensions to the
+ Synopsys DesignWare Memory Card Interface driver. Select this option
+ for platforms based on Exynos4 and Exynos5 SoC's.
+
config MMC_DW_PCI
tristate "Synopsys Designware MCI support on PCI bus"
depends on MMC_DW && PCI
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index 8922b06..17ad0a7 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -39,6 +39,7 @@ obj-$(CONFIG_MMC_VIA_SDMMC) += via-sdmmc.o
obj-$(CONFIG_SDH_BFIN) += bfin_sdh.o
obj-$(CONFIG_MMC_DW) += dw_mmc.o
obj-$(CONFIG_MMC_DW_PLTFM) += dw_mmc-pltfm.o
+obj-$(CONFIG_MMC_DW_EXYNOS) += dw_mmc-exynos.o
obj-$(CONFIG_MMC_DW_PCI) += dw_mmc-pci.o
obj-$(CONFIG_MMC_SH_MMCIF) += sh_mmcif.o
obj-$(CONFIG_MMC_JZ4740) += jz4740_mmc.o
diff --git a/drivers/mmc/host/atmel-mci-regs.h b/drivers/mmc/host/atmel-mci-regs.h
index ab56f7d..c97001e 100644
--- a/drivers/mmc/host/atmel-mci-regs.h
+++ b/drivers/mmc/host/atmel-mci-regs.h
@@ -140,6 +140,13 @@
#define atmci_writel(port,reg,value) \
__raw_writel((value), (port)->regs + reg)
+/* On AVR chips the Peripheral DMA Controller is not connected to MCI. */
+#ifdef CONFIG_AVR32
+# define ATMCI_PDC_CONNECTED 0
+#else
+# define ATMCI_PDC_CONNECTED 1
+#endif
+
/*
* Fix sconfig's burst size according to atmel MCI. We need to convert them as:
* 1 -> 0, 4 -> 1, 8 -> 2, 16 -> 3.
diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
index 852d5fb..ddf096e 100644
--- a/drivers/mmc/host/atmel-mci.c
+++ b/drivers/mmc/host/atmel-mci.c
@@ -19,6 +19,9 @@
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
#include <linux/platform_device.h>
#include <linux/scatterlist.h>
#include <linux/seq_file.h>
@@ -71,7 +74,7 @@ enum atmci_pdc_buf {
};
struct atmel_mci_caps {
- bool has_dma;
+ bool has_dma_conf_reg;
bool has_pdc;
bool has_cfg_reg;
bool has_cstor_reg;
@@ -418,7 +421,7 @@ static int atmci_regs_show(struct seq_file *s, void *v)
atmci_show_status_reg(s, "SR", buf[ATMCI_SR / 4]);
atmci_show_status_reg(s, "IMR", buf[ATMCI_IMR / 4]);
- if (host->caps.has_dma) {
+ if (host->caps.has_dma_conf_reg) {
u32 val;
val = buf[ATMCI_DMA / 4];
@@ -500,6 +503,70 @@ err:
dev_err(&mmc->class_dev, "failed to initialize debugfs for slot\n");
}
+#if defined(CONFIG_OF)
+static const struct of_device_id atmci_dt_ids[] = {
+ { .compatible = "atmel,hsmci" },
+ { /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, atmci_dt_ids);
+
+static struct mci_platform_data __devinit*
+atmci_of_init(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct device_node *cnp;
+ struct mci_platform_data *pdata;
+ u32 slot_id;
+
+ if (!np) {
+ dev_err(&pdev->dev, "device node not found\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata) {
+ dev_err(&pdev->dev, "could not allocate memory for pdata\n");
+ return ERR_PTR(-ENOMEM);
+ }
+
+ for_each_child_of_node(np, cnp) {
+ if (of_property_read_u32(cnp, "reg", &slot_id)) {
+ dev_warn(&pdev->dev, "reg property is missing for %s\n",
+ cnp->full_name);
+ continue;
+ }
+
+ if (slot_id >= ATMCI_MAX_NR_SLOTS) {
+ dev_warn(&pdev->dev, "can't have more than %d slots\n",
+ ATMCI_MAX_NR_SLOTS);
+ break;
+ }
+
+ if (of_property_read_u32(cnp, "bus-width",
+ &pdata->slot[slot_id].bus_width))
+ pdata->slot[slot_id].bus_width = 1;
+
+ pdata->slot[slot_id].detect_pin =
+ of_get_named_gpio(cnp, "cd-gpios", 0);
+
+ pdata->slot[slot_id].detect_is_active_high =
+ of_property_read_bool(cnp, "cd-inverted");
+
+ pdata->slot[slot_id].wp_pin =
+ of_get_named_gpio(cnp, "wp-gpios", 0);
+ }
+
+ return pdata;
+}
+#else /* CONFIG_OF */
+static inline struct mci_platform_data*
+atmci_of_init(struct platform_device *dev)
+{
+ return ERR_PTR(-EINVAL);
+}
+#endif
+
static inline unsigned int atmci_get_version(struct atmel_mci *host)
{
return atmci_readl(host, ATMCI_VERSION) & 0x00000fff;
@@ -774,7 +841,7 @@ static void atmci_dma_complete(void *arg)
dev_vdbg(&host->pdev->dev, "DMA complete\n");
- if (host->caps.has_dma)
+ if (host->caps.has_dma_conf_reg)
/* Disable DMA hardware handshaking on MCI */
atmci_writel(host, ATMCI_DMA, atmci_readl(host, ATMCI_DMA) & ~ATMCI_DMAEN);
@@ -961,7 +1028,9 @@ atmci_prepare_data_dma(struct atmel_mci *host, struct mmc_data *data)
maxburst = atmci_convert_chksize(host->dma_conf.dst_maxburst);
}
- atmci_writel(host, ATMCI_DMA, ATMCI_DMA_CHKSIZE(maxburst) | ATMCI_DMAEN);
+ if (host->caps.has_dma_conf_reg)
+ atmci_writel(host, ATMCI_DMA, ATMCI_DMA_CHKSIZE(maxburst) |
+ ATMCI_DMAEN);
sglen = dma_map_sg(chan->device->dev, data->sg,
data->sg_len, direction);
@@ -2046,6 +2115,13 @@ static int __init atmci_init_slot(struct atmel_mci *host,
slot->sdc_reg = sdc_reg;
slot->sdio_irq = sdio_irq;
+ dev_dbg(&mmc->class_dev,
+ "slot[%u]: bus_width=%u, detect_pin=%d, "
+ "detect_is_active_high=%s, wp_pin=%d\n",
+ id, slot_data->bus_width, slot_data->detect_pin,
+ slot_data->detect_is_active_high ? "true" : "false",
+ slot_data->wp_pin);
+
mmc->ops = &atmci_ops;
mmc->f_min = DIV_ROUND_UP(host->bus_hz, 512);
mmc->f_max = host->bus_hz / 2;
@@ -2169,7 +2245,10 @@ static bool atmci_configure_dma(struct atmel_mci *host)
pdata = host->pdev->dev.platform_data;
- if (pdata && find_slave_dev(pdata->dma_slave)) {
+ if (!pdata)
+ return false;
+
+ if (pdata->dma_slave && find_slave_dev(pdata->dma_slave)) {
dma_cap_mask_t mask;
/* Try to grab a DMA channel */
@@ -2210,8 +2289,8 @@ static void __init atmci_get_cap(struct atmel_mci *host)
dev_info(&host->pdev->dev,
"version: 0x%x\n", version);
- host->caps.has_dma = 0;
- host->caps.has_pdc = 1;
+ host->caps.has_dma_conf_reg = 0;
+ host->caps.has_pdc = ATMCI_PDC_CONNECTED;
host->caps.has_cfg_reg = 0;
host->caps.has_cstor_reg = 0;
host->caps.has_highspeed = 0;
@@ -2228,12 +2307,7 @@ static void __init atmci_get_cap(struct atmel_mci *host)
host->caps.has_odd_clk_div = 1;
case 0x400:
case 0x300:
-#ifdef CONFIG_AT_HDMAC
- host->caps.has_dma = 1;
-#else
- dev_info(&host->pdev->dev,
- "has dma capability but dma engine is not selected, then use pio\n");
-#endif
+ host->caps.has_dma_conf_reg = 1;
host->caps.has_pdc = 0;
host->caps.has_cfg_reg = 1;
host->caps.has_cstor_reg = 1;
@@ -2268,8 +2342,14 @@ static int __init atmci_probe(struct platform_device *pdev)
if (!regs)
return -ENXIO;
pdata = pdev->dev.platform_data;
- if (!pdata)
- return -ENXIO;
+ if (!pdata) {
+ pdata = atmci_of_init(pdev);
+ if (IS_ERR(pdata)) {
+ dev_err(&pdev->dev, "platform data not available\n");
+ return PTR_ERR(pdata);
+ }
+ }
+
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
@@ -2308,7 +2388,7 @@ static int __init atmci_probe(struct platform_device *pdev)
/* Get MCI capabilities and set operations according to it */
atmci_get_cap(host);
- if (host->caps.has_dma && atmci_configure_dma(host)) {
+ if (atmci_configure_dma(host)) {
host->prepare_data = &atmci_prepare_data_dma;
host->submit_data = &atmci_submit_data_dma;
host->stop_transfer = &atmci_stop_transfer_dma;
@@ -2487,6 +2567,7 @@ static struct platform_driver atmci_driver = {
.driver = {
.name = "atmel_mci",
.pm = ATMCI_PM_OPS,
+ .of_match_table = of_match_ptr(atmci_dt_ids),
},
};
diff --git a/drivers/mmc/host/bfin_sdh.c b/drivers/mmc/host/bfin_sdh.c
index a17dd73..b9b463e 100644
--- a/drivers/mmc/host/bfin_sdh.c
+++ b/drivers/mmc/host/bfin_sdh.c
@@ -24,9 +24,7 @@
#include <asm/portmux.h>
#include <asm/bfin_sdh.h>
-#if defined(CONFIG_BF51x)
-#define bfin_read_SDH_PWR_CTL bfin_read_RSI_PWR_CTL
-#define bfin_write_SDH_PWR_CTL bfin_write_RSI_PWR_CTL
+#if defined(CONFIG_BF51x) || defined(__ADSPBF60x__)
#define bfin_read_SDH_CLK_CTL bfin_read_RSI_CLK_CTL
#define bfin_write_SDH_CLK_CTL bfin_write_RSI_CLK_CTL
#define bfin_write_SDH_ARGUMENT bfin_write_RSI_ARGUMENT
@@ -45,8 +43,16 @@
#define bfin_write_SDH_E_STATUS bfin_write_RSI_E_STATUS
#define bfin_read_SDH_STATUS bfin_read_RSI_STATUS
#define bfin_write_SDH_MASK0 bfin_write_RSI_MASK0
+#define bfin_write_SDH_E_MASK bfin_write_RSI_E_MASK
#define bfin_read_SDH_CFG bfin_read_RSI_CFG
#define bfin_write_SDH_CFG bfin_write_RSI_CFG
+# if defined(__ADSPBF60x__)
+# define bfin_read_SDH_BLK_SIZE bfin_read_RSI_BLKSZ
+# define bfin_write_SDH_BLK_SIZE bfin_write_RSI_BLKSZ
+# else
+# define bfin_read_SDH_PWR_CTL bfin_read_RSI_PWR_CTL
+# define bfin_write_SDH_PWR_CTL bfin_write_RSI_PWR_CTL
+# endif
#endif
struct sdh_host {
@@ -62,6 +68,7 @@ struct sdh_host {
dma_addr_t sg_dma;
int dma_len;
+ unsigned long sclk;
unsigned int imask;
unsigned int power_mode;
unsigned int clk_div;
@@ -127,11 +134,15 @@ static int sdh_setup_data(struct sdh_host *host, struct mmc_data *data)
/* Only supports power-of-2 block size */
if (data->blksz & (data->blksz - 1))
return -EINVAL;
+#ifndef RSI_BLKSZ
data_ctl |= ((ffs(data->blksz) - 1) << 4);
+#else
+ bfin_write_SDH_BLK_SIZE(data->blksz);
+#endif
bfin_write_SDH_DATA_CTL(data_ctl);
/* the time of a host clock period in ns */
- cycle_ns = 1000000000 / (get_sclk() / (2 * (host->clk_div + 1)));
+ cycle_ns = 1000000000 / (host->sclk / (2 * (host->clk_div + 1)));
timeout = data->timeout_ns / cycle_ns;
timeout += data->timeout_clks;
bfin_write_SDH_DATA_TIMER(timeout);
@@ -145,8 +156,13 @@ static int sdh_setup_data(struct sdh_host *host, struct mmc_data *data)
sdh_enable_stat_irq(host, (DAT_CRC_FAIL | DAT_TIME_OUT | DAT_END));
host->dma_len = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len, host->dma_dir);
-#if defined(CONFIG_BF54x)
- dma_cfg |= DMAFLOW_ARRAY | NDSIZE_5 | RESTART | WDSIZE_32 | DMAEN;
+#if defined(CONFIG_BF54x) || defined(CONFIG_BF60x)
+ dma_cfg |= DMAFLOW_ARRAY | RESTART | WDSIZE_32 | DMAEN;
+# ifdef RSI_BLKSZ
+ dma_cfg |= PSIZE_32 | NDSIZE_3;
+# else
+ dma_cfg |= NDSIZE_5;
+# endif
{
struct scatterlist *sg;
int i;
@@ -156,7 +172,7 @@ static int sdh_setup_data(struct sdh_host *host, struct mmc_data *data)
host->sg_cpu[i].x_count = sg_dma_len(sg) / 4;
host->sg_cpu[i].x_modify = 4;
dev_dbg(mmc_dev(host->mmc), "%d: start_addr:0x%lx, "
- "cfg:0x%x, x_count:0x%x, x_modify:0x%x\n",
+ "cfg:0x%lx, x_count:0x%lx, x_modify:0x%lx\n",
i, host->sg_cpu[i].start_addr,
host->sg_cpu[i].cfg, host->sg_cpu[i].x_count,
host->sg_cpu[i].x_modify);
@@ -172,6 +188,7 @@ static int sdh_setup_data(struct sdh_host *host, struct mmc_data *data)
set_dma_curr_desc_addr(host->dma_ch, (unsigned long *)host->sg_dma);
set_dma_x_count(host->dma_ch, 0);
set_dma_x_modify(host->dma_ch, 0);
+ SSYNC();
set_dma_config(host->dma_ch, dma_cfg);
#elif defined(CONFIG_BF51x)
/* RSI DMA doesn't work in array mode */
@@ -179,6 +196,7 @@ static int sdh_setup_data(struct sdh_host *host, struct mmc_data *data)
set_dma_start_addr(host->dma_ch, sg_dma_address(&data->sg[0]));
set_dma_x_count(host->dma_ch, length / 4);
set_dma_x_modify(host->dma_ch, 4);
+ SSYNC();
set_dma_config(host->dma_ch, dma_cfg);
#endif
bfin_write_SDH_DATA_CTL(bfin_read_SDH_DATA_CTL() | DTX_DMA_E | DTX_E);
@@ -296,7 +314,6 @@ static int sdh_data_done(struct sdh_host *host, unsigned int stat)
else
data->bytes_xfered = 0;
- sdh_disable_stat_irq(host, DAT_END | DAT_TIME_OUT | DAT_CRC_FAIL | RX_OVERRUN | TX_UNDERRUN);
bfin_write_SDH_STATUS_CLR(DAT_END_STAT | DAT_TIMEOUT_STAT | \
DAT_CRC_FAIL_STAT | DAT_BLK_END_STAT | RX_OVERRUN | TX_UNDERRUN);
bfin_write_SDH_DATA_CTL(0);
@@ -321,74 +338,115 @@ static void sdh_request(struct mmc_host *mmc, struct mmc_request *mrq)
dev_dbg(mmc_dev(host->mmc), "%s enter, mrp:%p, cmd:%p\n", __func__, mrq, mrq->cmd);
WARN_ON(host->mrq != NULL);
+ spin_lock(&host->lock);
host->mrq = mrq;
host->data = mrq->data;
if (mrq->data && mrq->data->flags & MMC_DATA_READ) {
ret = sdh_setup_data(host, mrq->data);
if (ret)
- return;
+ goto data_err;
}
sdh_start_cmd(host, mrq->cmd);
+data_err:
+ spin_unlock(&host->lock);
}
static void sdh_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
{
struct sdh_host *host;
- unsigned long flags;
u16 clk_ctl = 0;
+#ifndef RSI_BLKSZ
u16 pwr_ctl = 0;
+#endif
u16 cfg;
host = mmc_priv(mmc);
- spin_lock_irqsave(&host->lock, flags);
- if (ios->clock) {
- unsigned long sys_clk, ios_clk;
- unsigned char clk_div;
- ios_clk = 2 * ios->clock;
- sys_clk = get_sclk();
- clk_div = sys_clk / ios_clk;
- if (sys_clk % ios_clk == 0)
- clk_div -= 1;
- clk_div = min_t(unsigned char, clk_div, 0xFF);
- clk_ctl |= clk_div;
- clk_ctl |= CLK_E;
- host->clk_div = clk_div;
- } else
- sdh_stop_clock(host);
-
- if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN)
-#ifdef CONFIG_SDH_BFIN_MISSING_CMD_PULLUP_WORKAROUND
- pwr_ctl |= ROD_CTL;
-#else
- pwr_ctl |= SD_CMD_OD | ROD_CTL;
-#endif
+ spin_lock(&host->lock);
- if (ios->bus_width == MMC_BUS_WIDTH_4) {
- cfg = bfin_read_SDH_CFG();
+ cfg = bfin_read_SDH_CFG();
+ cfg |= MWE;
+ switch (ios->bus_width) {
+ case MMC_BUS_WIDTH_4:
+#ifndef RSI_BLKSZ
cfg &= ~PD_SDDAT3;
+#endif
cfg |= PUP_SDDAT3;
/* Enable 4 bit SDIO */
- cfg |= (SD4E | MWE);
- bfin_write_SDH_CFG(cfg);
- clk_ctl |= WIDE_BUS;
- } else {
- cfg = bfin_read_SDH_CFG();
- cfg |= MWE;
- bfin_write_SDH_CFG(cfg);
+ cfg |= SD4E;
+ clk_ctl |= WIDE_BUS_4;
+ break;
+ case MMC_BUS_WIDTH_8:
+#ifndef RSI_BLKSZ
+ cfg &= ~PD_SDDAT3;
+#endif
+ cfg |= PUP_SDDAT3;
+ /* Disable 4 bit SDIO */
+ cfg &= ~SD4E;
+ clk_ctl |= BYTE_BUS_8;
+ break;
+ default:
+ cfg &= ~PUP_SDDAT3;
+ /* Disable 4 bit SDIO */
+ cfg &= ~SD4E;
}
- bfin_write_SDH_CLK_CTL(clk_ctl);
-
host->power_mode = ios->power_mode;
- if (ios->power_mode == MMC_POWER_ON)
+#ifndef RSI_BLKSZ
+ if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN) {
+ pwr_ctl |= ROD_CTL;
+# ifndef CONFIG_SDH_BFIN_MISSING_CMD_PULLUP_WORKAROUND
+ pwr_ctl |= SD_CMD_OD;
+# endif
+ }
+
+ if (ios->power_mode != MMC_POWER_OFF)
pwr_ctl |= PWR_ON;
+ else
+ pwr_ctl &= ~PWR_ON;
bfin_write_SDH_PWR_CTL(pwr_ctl);
+#else
+# ifndef CONFIG_SDH_BFIN_MISSING_CMD_PULLUP_WORKAROUND
+ if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN)
+ cfg |= SD_CMD_OD;
+ else
+ cfg &= ~SD_CMD_OD;
+# endif
+
+
+ if (ios->power_mode != MMC_POWER_OFF)
+ cfg |= PWR_ON;
+ else
+ cfg &= ~PWR_ON;
+
+ bfin_write_SDH_CFG(cfg);
+#endif
SSYNC();
- spin_unlock_irqrestore(&host->lock, flags);
+ if (ios->power_mode == MMC_POWER_ON && ios->clock) {
+ unsigned char clk_div;
+ clk_div = (get_sclk() / ios->clock - 1) / 2;
+ clk_div = min_t(unsigned char, clk_div, 0xFF);
+ clk_ctl |= clk_div;
+ clk_ctl |= CLK_E;
+ host->clk_div = clk_div;
+ bfin_write_SDH_CLK_CTL(clk_ctl);
+
+ } else
+ sdh_stop_clock(host);
+
+ /* set up sdh interrupt mask*/
+ if (ios->power_mode == MMC_POWER_ON)
+ bfin_write_SDH_MASK0(DAT_END | DAT_TIME_OUT | DAT_CRC_FAIL |
+ RX_OVERRUN | TX_UNDERRUN | CMD_SENT | CMD_RESP_END |
+ CMD_TIME_OUT | CMD_CRC_FAIL);
+ else
+ bfin_write_SDH_MASK0(0);
+ SSYNC();
+
+ spin_unlock(&host->lock);
dev_dbg(mmc_dev(host->mmc), "SDH: clk_div = 0x%x actual clock:%ld expected clock:%d\n",
host->clk_div,
@@ -405,7 +463,7 @@ static irqreturn_t sdh_dma_irq(int irq, void *devid)
{
struct sdh_host *host = devid;
- dev_dbg(mmc_dev(host->mmc), "%s enter, irq_stat: 0x%04x\n", __func__,
+ dev_dbg(mmc_dev(host->mmc), "%s enter, irq_stat: 0x%04lx\n", __func__,
get_dma_curr_irqstat(host->dma_ch));
clear_dma_irqstat(host->dma_ch);
SSYNC();
@@ -420,6 +478,9 @@ static irqreturn_t sdh_stat_irq(int irq, void *devid)
int handled = 0;
dev_dbg(mmc_dev(host->mmc), "%s enter\n", __func__);
+
+ spin_lock(&host->lock);
+
status = bfin_read_SDH_E_STATUS();
if (status & SD_CARD_DET) {
mmc_detect_change(host->mmc, 0);
@@ -437,11 +498,30 @@ static irqreturn_t sdh_stat_irq(int irq, void *devid)
if (status & (DAT_END | DAT_TIME_OUT | DAT_CRC_FAIL | RX_OVERRUN | TX_UNDERRUN))
handled |= sdh_data_done(host, status);
+ spin_unlock(&host->lock);
+
dev_dbg(mmc_dev(host->mmc), "%s exit\n\n", __func__);
return IRQ_RETVAL(handled);
}
+static void sdh_reset(void)
+{
+#if defined(CONFIG_BF54x)
+ /* Secure Digital Host shares DMA with Nand controller */
+ bfin_write_DMAC1_PERIMUX(bfin_read_DMAC1_PERIMUX() | 0x1);
+#endif
+
+ bfin_write_SDH_CFG(bfin_read_SDH_CFG() | CLKS_EN);
+ SSYNC();
+
+ /* Disable card inserting detection pin. set MMC_CAP_NEEDS_POLL, and
+ * mmc stack will do the detection.
+ */
+ bfin_write_SDH_CFG((bfin_read_SDH_CFG() & 0x1F) | (PUP_SDDAT | PUP_SDDAT3));
+ SSYNC();
+}
+
static int __devinit sdh_probe(struct platform_device *pdev)
{
struct mmc_host *mmc;
@@ -462,8 +542,16 @@ static int __devinit sdh_probe(struct platform_device *pdev)
}
mmc->ops = &sdh_ops;
- mmc->max_segs = 32;
+#if defined(CONFIG_BF51x)
+ mmc->max_segs = 1;
+#else
+ mmc->max_segs = PAGE_SIZE / sizeof(struct dma_desc_array);
+#endif
+#ifdef RSI_BLKSZ
+ mmc->max_seg_size = -1;
+#else
mmc->max_seg_size = 1 << 16;
+#endif
mmc->max_blk_size = 1 << 11;
mmc->max_blk_count = 1 << 11;
mmc->max_req_size = PAGE_SIZE;
@@ -473,6 +561,7 @@ static int __devinit sdh_probe(struct platform_device *pdev)
mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_NEEDS_POLL;
host = mmc_priv(mmc);
host->mmc = mmc;
+ host->sclk = get_sclk();
spin_lock_init(&host->lock);
host->irq = drv_data->irq_int0;
@@ -497,7 +586,6 @@ static int __devinit sdh_probe(struct platform_device *pdev)
}
platform_set_drvdata(pdev, mmc);
- mmc_add_host(mmc);
ret = request_irq(host->irq, sdh_stat_irq, 0, "SDH Status IRQ", host);
if (ret) {
@@ -510,20 +598,10 @@ static int __devinit sdh_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "unable to request peripheral pins\n");
goto out4;
}
-#if defined(CONFIG_BF54x)
- /* Secure Digital Host shares DMA with Nand controller */
- bfin_write_DMAC1_PERIMUX(bfin_read_DMAC1_PERIMUX() | 0x1);
-#endif
-
- bfin_write_SDH_CFG(bfin_read_SDH_CFG() | CLKS_EN);
- SSYNC();
- /* Disable card inserting detection pin. set MMC_CAP_NEES_POLL, and
- * mmc stack will do the detection.
- */
- bfin_write_SDH_CFG((bfin_read_SDH_CFG() & 0x1F) | (PUP_SDDAT | PUP_SDDAT3));
- SSYNC();
+ sdh_reset();
+ mmc_add_host(mmc);
return 0;
out4:
@@ -571,7 +649,6 @@ static int sdh_suspend(struct platform_device *dev, pm_message_t state)
if (mmc)
ret = mmc_suspend_host(mmc);
- bfin_write_SDH_PWR_CTL(bfin_read_SDH_PWR_CTL() & ~PWR_ON);
peripheral_free_list(drv_data->pin_req);
return ret;
@@ -589,16 +666,7 @@ static int sdh_resume(struct platform_device *dev)
return ret;
}
- bfin_write_SDH_PWR_CTL(bfin_read_SDH_PWR_CTL() | PWR_ON);
-#if defined(CONFIG_BF54x)
- /* Secure Digital Host shares DMA with Nand controller */
- bfin_write_DMAC1_PERIMUX(bfin_read_DMAC1_PERIMUX() | 0x1);
-#endif
- bfin_write_SDH_CFG(bfin_read_SDH_CFG() | CLKS_EN);
- SSYNC();
-
- bfin_write_SDH_CFG((bfin_read_SDH_CFG() & 0x1F) | (PUP_SDDAT | PUP_SDDAT3));
- SSYNC();
+ sdh_reset();
if (mmc)
ret = mmc_resume_host(mmc);
diff --git a/drivers/mmc/host/davinci_mmc.c b/drivers/mmc/host/davinci_mmc.c
index 3dfd347..2063677 100644
--- a/drivers/mmc/host/davinci_mmc.c
+++ b/drivers/mmc/host/davinci_mmc.c
@@ -30,11 +30,12 @@
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/delay.h>
+#include <linux/dmaengine.h>
#include <linux/dma-mapping.h>
+#include <linux/edma.h>
#include <linux/mmc/mmc.h>
#include <linux/platform_data/mmc-davinci.h>
-#include <mach/edma.h>
/*
* Register Definitions
@@ -200,21 +201,13 @@ struct mmc_davinci_host {
u32 bytes_left;
u32 rxdma, txdma;
+ struct dma_chan *dma_tx;
+ struct dma_chan *dma_rx;
bool use_dma;
bool do_dma;
bool sdio_int;
bool active_request;
- /* Scatterlist DMA uses one or more parameter RAM entries:
- * the main one (associated with rxdma or txdma) plus zero or
- * more links. The entries for a given transfer differ only
- * by memory buffer (address, length) and link field.
- */
- struct edmacc_param tx_template;
- struct edmacc_param rx_template;
- unsigned n_link;
- u32 links[MAX_NR_SG - 1];
-
/* For PIO we walk scatterlists one segment at a time. */
unsigned int sg_len;
struct scatterlist *sg;
@@ -410,153 +403,74 @@ static void mmc_davinci_start_command(struct mmc_davinci_host *host,
static void davinci_abort_dma(struct mmc_davinci_host *host)
{
- int sync_dev;
+ struct dma_chan *sync_dev;
if (host->data_dir == DAVINCI_MMC_DATADIR_READ)
- sync_dev = host->rxdma;
+ sync_dev = host->dma_rx;
else
- sync_dev = host->txdma;
-
- edma_stop(sync_dev);
- edma_clean_channel(sync_dev);
-}
-
-static void
-mmc_davinci_xfer_done(struct mmc_davinci_host *host, struct mmc_data *data);
-
-static void mmc_davinci_dma_cb(unsigned channel, u16 ch_status, void *data)
-{
- if (DMA_COMPLETE != ch_status) {
- struct mmc_davinci_host *host = data;
-
- /* Currently means: DMA Event Missed, or "null" transfer
- * request was seen. In the future, TC errors (like bad
- * addresses) might be presented too.
- */
- dev_warn(mmc_dev(host->mmc), "DMA %s error\n",
- (host->data->flags & MMC_DATA_WRITE)
- ? "write" : "read");
- host->data->error = -EIO;
- mmc_davinci_xfer_done(host, host->data);
- }
-}
-
-/* Set up tx or rx template, to be modified and updated later */
-static void __init mmc_davinci_dma_setup(struct mmc_davinci_host *host,
- bool tx, struct edmacc_param *template)
-{
- unsigned sync_dev;
- const u16 acnt = 4;
- const u16 bcnt = rw_threshold >> 2;
- const u16 ccnt = 0;
- u32 src_port = 0;
- u32 dst_port = 0;
- s16 src_bidx, dst_bidx;
- s16 src_cidx, dst_cidx;
-
- /*
- * A-B Sync transfer: each DMA request is for one "frame" of
- * rw_threshold bytes, broken into "acnt"-size chunks repeated
- * "bcnt" times. Each segment needs "ccnt" such frames; since
- * we tell the block layer our mmc->max_seg_size limit, we can
- * trust (later) that it's within bounds.
- *
- * The FIFOs are read/written in 4-byte chunks (acnt == 4) and
- * EDMA will optimize memory operations to use larger bursts.
- */
- if (tx) {
- sync_dev = host->txdma;
-
- /* src_prt, ccnt, and link to be set up later */
- src_bidx = acnt;
- src_cidx = acnt * bcnt;
-
- dst_port = host->mem_res->start + DAVINCI_MMCDXR;
- dst_bidx = 0;
- dst_cidx = 0;
- } else {
- sync_dev = host->rxdma;
-
- src_port = host->mem_res->start + DAVINCI_MMCDRR;
- src_bidx = 0;
- src_cidx = 0;
-
- /* dst_prt, ccnt, and link to be set up later */
- dst_bidx = acnt;
- dst_cidx = acnt * bcnt;
- }
-
- /*
- * We can't use FIFO mode for the FIFOs because MMC FIFO addresses
- * are not 256-bit (32-byte) aligned. So we use INCR, and the W8BIT
- * parameter is ignored.
- */
- edma_set_src(sync_dev, src_port, INCR, W8BIT);
- edma_set_dest(sync_dev, dst_port, INCR, W8BIT);
+ sync_dev = host->dma_tx;
- edma_set_src_index(sync_dev, src_bidx, src_cidx);
- edma_set_dest_index(sync_dev, dst_bidx, dst_cidx);
-
- edma_set_transfer_params(sync_dev, acnt, bcnt, ccnt, 8, ABSYNC);
-
- edma_read_slot(sync_dev, template);
-
- /* don't bother with irqs or chaining */
- template->opt |= EDMA_CHAN_SLOT(sync_dev) << 12;
+ dmaengine_terminate_all(sync_dev);
}
-static void mmc_davinci_send_dma_request(struct mmc_davinci_host *host,
+static int mmc_davinci_send_dma_request(struct mmc_davinci_host *host,
struct mmc_data *data)
{
- struct edmacc_param *template;
- int channel, slot;
- unsigned link;
- struct scatterlist *sg;
- unsigned sg_len;
- unsigned bytes_left = host->bytes_left;
- const unsigned shift = ffs(rw_threshold) - 1;
+ struct dma_chan *chan;
+ struct dma_async_tx_descriptor *desc;
+ int ret = 0;
if (host->data_dir == DAVINCI_MMC_DATADIR_WRITE) {
- template = &host->tx_template;
- channel = host->txdma;
+ struct dma_slave_config dma_tx_conf = {
+ .direction = DMA_MEM_TO_DEV,
+ .dst_addr = host->mem_res->start + DAVINCI_MMCDXR,
+ .dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES,
+ .dst_maxburst =
+ rw_threshold / DMA_SLAVE_BUSWIDTH_4_BYTES,
+ };
+ chan = host->dma_tx;
+ dmaengine_slave_config(host->dma_tx, &dma_tx_conf);
+
+ desc = dmaengine_prep_slave_sg(host->dma_tx,
+ data->sg,
+ host->sg_len,
+ DMA_MEM_TO_DEV,
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ if (!desc) {
+ dev_dbg(mmc_dev(host->mmc),
+ "failed to allocate DMA TX descriptor");
+ ret = -1;
+ goto out;
+ }
} else {
- template = &host->rx_template;
- channel = host->rxdma;
- }
-
- /* We know sg_len and ccnt will never be out of range because
- * we told the mmc layer which in turn tells the block layer
- * to ensure that it only hands us one scatterlist segment
- * per EDMA PARAM entry. Update the PARAM
- * entries needed for each segment of this scatterlist.
- */
- for (slot = channel, link = 0, sg = data->sg, sg_len = host->sg_len;
- sg_len-- != 0 && bytes_left;
- sg = sg_next(sg), slot = host->links[link++]) {
- u32 buf = sg_dma_address(sg);
- unsigned count = sg_dma_len(sg);
-
- template->link_bcntrld = sg_len
- ? (EDMA_CHAN_SLOT(host->links[link]) << 5)
- : 0xffff;
-
- if (count > bytes_left)
- count = bytes_left;
- bytes_left -= count;
-
- if (host->data_dir == DAVINCI_MMC_DATADIR_WRITE)
- template->src = buf;
- else
- template->dst = buf;
- template->ccnt = count >> shift;
-
- edma_write_slot(slot, template);
+ struct dma_slave_config dma_rx_conf = {
+ .direction = DMA_DEV_TO_MEM,
+ .src_addr = host->mem_res->start + DAVINCI_MMCDRR,
+ .src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES,
+ .src_maxburst =
+ rw_threshold / DMA_SLAVE_BUSWIDTH_4_BYTES,
+ };
+ chan = host->dma_rx;
+ dmaengine_slave_config(host->dma_rx, &dma_rx_conf);
+
+ desc = dmaengine_prep_slave_sg(host->dma_rx,
+ data->sg,
+ host->sg_len,
+ DMA_DEV_TO_MEM,
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ if (!desc) {
+ dev_dbg(mmc_dev(host->mmc),
+ "failed to allocate DMA RX descriptor");
+ ret = -1;
+ goto out;
+ }
}
- if (host->version == MMC_CTLR_VERSION_2)
- edma_clear_event(channel);
+ dmaengine_submit(desc);
+ dma_async_issue_pending(chan);
- edma_start(channel);
+out:
+ return ret;
}
static int mmc_davinci_start_dma_transfer(struct mmc_davinci_host *host,
@@ -564,6 +478,7 @@ static int mmc_davinci_start_dma_transfer(struct mmc_davinci_host *host,
{
int i;
int mask = rw_threshold - 1;
+ int ret = 0;
host->sg_len = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
((data->flags & MMC_DATA_WRITE)
@@ -583,70 +498,48 @@ static int mmc_davinci_start_dma_transfer(struct mmc_davinci_host *host,
}
host->do_dma = 1;
- mmc_davinci_send_dma_request(host, data);
+ ret = mmc_davinci_send_dma_request(host, data);
- return 0;
+ return ret;
}
static void __init_or_module
davinci_release_dma_channels(struct mmc_davinci_host *host)
{
- unsigned i;
-
if (!host->use_dma)
return;
- for (i = 0; i < host->n_link; i++)
- edma_free_slot(host->links[i]);
-
- edma_free_channel(host->txdma);
- edma_free_channel(host->rxdma);
+ dma_release_channel(host->dma_tx);
+ dma_release_channel(host->dma_rx);
}
static int __init davinci_acquire_dma_channels(struct mmc_davinci_host *host)
{
- u32 link_size;
- int r, i;
-
- /* Acquire master DMA write channel */
- r = edma_alloc_channel(host->txdma, mmc_davinci_dma_cb, host,
- EVENTQ_DEFAULT);
- if (r < 0) {
- dev_warn(mmc_dev(host->mmc), "alloc %s channel err %d\n",
- "tx", r);
- return r;
- }
- mmc_davinci_dma_setup(host, true, &host->tx_template);
-
- /* Acquire master DMA read channel */
- r = edma_alloc_channel(host->rxdma, mmc_davinci_dma_cb, host,
- EVENTQ_DEFAULT);
- if (r < 0) {
- dev_warn(mmc_dev(host->mmc), "alloc %s channel err %d\n",
- "rx", r);
- goto free_master_write;
+ int r;
+ dma_cap_mask_t mask;
+
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_SLAVE, mask);
+
+ host->dma_tx =
+ dma_request_channel(mask, edma_filter_fn, &host->txdma);
+ if (!host->dma_tx) {
+ dev_err(mmc_dev(host->mmc), "Can't get dma_tx channel\n");
+ return -ENODEV;
}
- mmc_davinci_dma_setup(host, false, &host->rx_template);
- /* Allocate parameter RAM slots, which will later be bound to a
- * channel as needed to handle a scatterlist.
- */
- link_size = min_t(unsigned, host->nr_sg, ARRAY_SIZE(host->links));
- for (i = 0; i < link_size; i++) {
- r = edma_alloc_slot(EDMA_CTLR(host->txdma), EDMA_SLOT_ANY);
- if (r < 0) {
- dev_dbg(mmc_dev(host->mmc), "dma PaRAM alloc --> %d\n",
- r);
- break;
- }
- host->links[i] = r;
+ host->dma_rx =
+ dma_request_channel(mask, edma_filter_fn, &host->rxdma);
+ if (!host->dma_rx) {
+ dev_err(mmc_dev(host->mmc), "Can't get dma_rx channel\n");
+ r = -ENODEV;
+ goto free_master_write;
}
- host->n_link = i;
return 0;
free_master_write:
- edma_free_channel(host->txdma);
+ dma_release_channel(host->dma_tx);
return r;
}
@@ -1359,7 +1252,7 @@ static int __init davinci_mmcsd_probe(struct platform_device *pdev)
* Each hw_seg uses one EDMA parameter RAM slot, always one
* channel and then usually some linked slots.
*/
- mmc->max_segs = 1 + host->n_link;
+ mmc->max_segs = MAX_NR_SG;
/* EDMA limit per hw segment (one or two MBytes) */
mmc->max_seg_size = MAX_CCNT * rw_threshold;
diff --git a/drivers/mmc/host/dw_mmc-exynos.c b/drivers/mmc/host/dw_mmc-exynos.c
new file mode 100644
index 0000000..660bbc5
--- /dev/null
+++ b/drivers/mmc/host/dw_mmc-exynos.c
@@ -0,0 +1,253 @@
+/*
+ * Exynos Specific Extensions for Synopsys DW Multimedia Card Interface driver
+ *
+ * Copyright (C) 2012, Samsung Electronics Co., 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.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/dw_mmc.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+
+#include "dw_mmc.h"
+#include "dw_mmc-pltfm.h"
+
+#define NUM_PINS(x) (x + 2)
+
+#define SDMMC_CLKSEL 0x09C
+#define SDMMC_CLKSEL_CCLK_SAMPLE(x) (((x) & 7) << 0)
+#define SDMMC_CLKSEL_CCLK_DRIVE(x) (((x) & 7) << 16)
+#define SDMMC_CLKSEL_CCLK_DIVIDER(x) (((x) & 7) << 24)
+#define SDMMC_CLKSEL_GET_DRV_WD3(x) (((x) >> 16) & 0x7)
+#define SDMMC_CLKSEL_TIMING(x, y, z) (SDMMC_CLKSEL_CCLK_SAMPLE(x) | \
+ SDMMC_CLKSEL_CCLK_DRIVE(y) | \
+ SDMMC_CLKSEL_CCLK_DIVIDER(z))
+
+#define SDMMC_CMD_USE_HOLD_REG BIT(29)
+
+#define EXYNOS4210_FIXED_CIU_CLK_DIV 2
+#define EXYNOS4412_FIXED_CIU_CLK_DIV 4
+
+/* Variations in Exynos specific dw-mshc controller */
+enum dw_mci_exynos_type {
+ DW_MCI_TYPE_EXYNOS4210,
+ DW_MCI_TYPE_EXYNOS4412,
+ DW_MCI_TYPE_EXYNOS5250,
+};
+
+/* Exynos implementation specific driver private data */
+struct dw_mci_exynos_priv_data {
+ enum dw_mci_exynos_type ctrl_type;
+ u8 ciu_div;
+ u32 sdr_timing;
+ u32 ddr_timing;
+};
+
+static struct dw_mci_exynos_compatible {
+ char *compatible;
+ enum dw_mci_exynos_type ctrl_type;
+} exynos_compat[] = {
+ {
+ .compatible = "samsung,exynos4210-dw-mshc",
+ .ctrl_type = DW_MCI_TYPE_EXYNOS4210,
+ }, {
+ .compatible = "samsung,exynos4412-dw-mshc",
+ .ctrl_type = DW_MCI_TYPE_EXYNOS4412,
+ }, {
+ .compatible = "samsung,exynos5250-dw-mshc",
+ .ctrl_type = DW_MCI_TYPE_EXYNOS5250,
+ },
+};
+
+static int dw_mci_exynos_priv_init(struct dw_mci *host)
+{
+ struct dw_mci_exynos_priv_data *priv;
+ int idx;
+
+ priv = devm_kzalloc(host->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv) {
+ dev_err(host->dev, "mem alloc failed for private data\n");
+ return -ENOMEM;
+ }
+
+ for (idx = 0; idx < ARRAY_SIZE(exynos_compat); idx++) {
+ if (of_device_is_compatible(host->dev->of_node,
+ exynos_compat[idx].compatible))
+ priv->ctrl_type = exynos_compat[idx].ctrl_type;
+ }
+
+ host->priv = priv;
+ return 0;
+}
+
+static int dw_mci_exynos_setup_clock(struct dw_mci *host)
+{
+ struct dw_mci_exynos_priv_data *priv = host->priv;
+
+ if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS5250)
+ host->bus_hz /= (priv->ciu_div + 1);
+ else if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS4412)
+ host->bus_hz /= EXYNOS4412_FIXED_CIU_CLK_DIV;
+ else if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS4210)
+ host->bus_hz /= EXYNOS4210_FIXED_CIU_CLK_DIV;
+
+ return 0;
+}
+
+static void dw_mci_exynos_prepare_command(struct dw_mci *host, u32 *cmdr)
+{
+ /*
+ * Exynos4412 and Exynos5250 extends the use of CMD register with the
+ * use of bit 29 (which is reserved on standard MSHC controllers) for
+ * optionally bypassing the HOLD register for command and data. The
+ * HOLD register should be bypassed in case there is no phase shift
+ * applied on CMD/DATA that is sent to the card.
+ */
+ if (SDMMC_CLKSEL_GET_DRV_WD3(mci_readl(host, CLKSEL)))
+ *cmdr |= SDMMC_CMD_USE_HOLD_REG;
+}
+
+static void dw_mci_exynos_set_ios(struct dw_mci *host, struct mmc_ios *ios)
+{
+ struct dw_mci_exynos_priv_data *priv = host->priv;
+
+ if (ios->timing == MMC_TIMING_UHS_DDR50)
+ mci_writel(host, CLKSEL, priv->ddr_timing);
+ else
+ mci_writel(host, CLKSEL, priv->sdr_timing);
+}
+
+static int dw_mci_exynos_parse_dt(struct dw_mci *host)
+{
+ struct dw_mci_exynos_priv_data *priv = host->priv;
+ struct device_node *np = host->dev->of_node;
+ u32 timing[2];
+ u32 div = 0;
+ int ret;
+
+ of_property_read_u32(np, "samsung,dw-mshc-ciu-div", &div);
+ priv->ciu_div = div;
+
+ ret = of_property_read_u32_array(np,
+ "samsung,dw-mshc-sdr-timing", timing, 2);
+ if (ret)
+ return ret;
+
+ priv->sdr_timing = SDMMC_CLKSEL_TIMING(timing[0], timing[1], div);
+
+ ret = of_property_read_u32_array(np,
+ "samsung,dw-mshc-ddr-timing", timing, 2);
+ if (ret)
+ return ret;
+
+ priv->ddr_timing = SDMMC_CLKSEL_TIMING(timing[0], timing[1], div);
+ return 0;
+}
+
+static int dw_mci_exynos_setup_bus(struct dw_mci *host,
+ struct device_node *slot_np, u8 bus_width)
+{
+ int idx, gpio, ret;
+
+ if (!slot_np)
+ return -EINVAL;
+
+ /* cmd + clock + bus-width pins */
+ for (idx = 0; idx < NUM_PINS(bus_width); idx++) {
+ gpio = of_get_gpio(slot_np, idx);
+ if (!gpio_is_valid(gpio)) {
+ dev_err(host->dev, "invalid gpio: %d\n", gpio);
+ return -EINVAL;
+ }
+
+ ret = devm_gpio_request(host->dev, gpio, "dw-mci-bus");
+ if (ret) {
+ dev_err(host->dev, "gpio [%d] request failed\n", gpio);
+ return -EBUSY;
+ }
+ }
+
+ gpio = of_get_named_gpio(slot_np, "wp-gpios", 0);
+ if (gpio_is_valid(gpio)) {
+ if (devm_gpio_request(host->dev, gpio, "dw-mci-wp"))
+ dev_info(host->dev, "gpio [%d] request failed\n",
+ gpio);
+ } else {
+ dev_info(host->dev, "wp gpio not available");
+ host->pdata->quirks |= DW_MCI_QUIRK_NO_WRITE_PROTECT;
+ }
+
+ if (host->pdata->quirks & DW_MCI_QUIRK_BROKEN_CARD_DETECTION)
+ return 0;
+
+ gpio = of_get_named_gpio(slot_np, "samsung,cd-pinmux-gpio", 0);
+ if (gpio_is_valid(gpio)) {
+ if (devm_gpio_request(host->dev, gpio, "dw-mci-cd"))
+ dev_err(host->dev, "gpio [%d] request failed\n", gpio);
+ } else {
+ dev_info(host->dev, "cd gpio not available");
+ }
+
+ return 0;
+}
+
+/* Exynos5250 controller specific capabilities */
+static unsigned long exynos5250_dwmmc_caps[4] = {
+ MMC_CAP_UHS_DDR50 | MMC_CAP_1_8V_DDR |
+ MMC_CAP_8_BIT_DATA | MMC_CAP_CMD23,
+ MMC_CAP_CMD23,
+ MMC_CAP_CMD23,
+ MMC_CAP_CMD23,
+};
+
+static struct dw_mci_drv_data exynos5250_drv_data = {
+ .caps = exynos5250_dwmmc_caps,
+ .init = dw_mci_exynos_priv_init,
+ .setup_clock = dw_mci_exynos_setup_clock,
+ .prepare_command = dw_mci_exynos_prepare_command,
+ .set_ios = dw_mci_exynos_set_ios,
+ .parse_dt = dw_mci_exynos_parse_dt,
+ .setup_bus = dw_mci_exynos_setup_bus,
+};
+
+static const struct of_device_id dw_mci_exynos_match[] = {
+ { .compatible = "samsung,exynos5250-dw-mshc",
+ .data = (void *)&exynos5250_drv_data, },
+ {},
+};
+MODULE_DEVICE_TABLE(of, dw_mci_pltfm_match);
+
+int dw_mci_exynos_probe(struct platform_device *pdev)
+{
+ struct dw_mci_drv_data *drv_data;
+ const struct of_device_id *match;
+
+ match = of_match_node(dw_mci_exynos_match, pdev->dev.of_node);
+ drv_data = match->data;
+ return dw_mci_pltfm_register(pdev, drv_data);
+}
+
+static struct platform_driver dw_mci_exynos_pltfm_driver = {
+ .probe = dw_mci_exynos_probe,
+ .remove = __exit_p(dw_mci_pltfm_remove),
+ .driver = {
+ .name = "dwmmc_exynos",
+ .of_match_table = of_match_ptr(dw_mci_exynos_match),
+ .pm = &dw_mci_pltfm_pmops,
+ },
+};
+
+module_platform_driver(dw_mci_exynos_pltfm_driver);
+
+MODULE_DESCRIPTION("Samsung Specific DW-MSHC Driver Extension");
+MODULE_AUTHOR("Thomas Abraham <thomas.ab@samsung.com");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:dwmmc-exynos");
diff --git a/drivers/mmc/host/dw_mmc-pci.c b/drivers/mmc/host/dw_mmc-pci.c
index dc0d25a..edb37e9 100644
--- a/drivers/mmc/host/dw_mmc-pci.c
+++ b/drivers/mmc/host/dw_mmc-pci.c
@@ -59,7 +59,7 @@ static int __devinit dw_mci_pci_probe(struct pci_dev *pdev,
host->irq = pdev->irq;
host->irq_flags = IRQF_SHARED;
- host->dev = pdev->dev;
+ host->dev = &pdev->dev;
host->pdata = &pci_board_data;
host->regs = pci_iomap(pdev, PCI_BAR_NO, COMPLETE_BAR);
@@ -140,18 +140,7 @@ static struct pci_driver dw_mci_pci_driver = {
},
};
-static int __init dw_mci_init(void)
-{
- return pci_register_driver(&dw_mci_pci_driver);
-}
-
-static void __exit dw_mci_exit(void)
-{
- pci_unregister_driver(&dw_mci_pci_driver);
-}
-
-module_init(dw_mci_init);
-module_exit(dw_mci_exit);
+module_pci_driver(dw_mci_pci_driver);
MODULE_DESCRIPTION("DW Multimedia Card PCI Interface driver");
MODULE_AUTHOR("Shashidhar Hiremath <shashidharh@vayavyalabs.com>");
diff --git a/drivers/mmc/host/dw_mmc-pltfm.c b/drivers/mmc/host/dw_mmc-pltfm.c
index 92ec3eb..c960ca7 100644
--- a/drivers/mmc/host/dw_mmc-pltfm.c
+++ b/drivers/mmc/host/dw_mmc-pltfm.c
@@ -19,59 +19,63 @@
#include <linux/mmc/host.h>
#include <linux/mmc/mmc.h>
#include <linux/mmc/dw_mmc.h>
+#include <linux/of.h>
+
#include "dw_mmc.h"
-static int dw_mci_pltfm_probe(struct platform_device *pdev)
+int dw_mci_pltfm_register(struct platform_device *pdev,
+ struct dw_mci_drv_data *drv_data)
{
struct dw_mci *host;
struct resource *regs;
int ret;
- host = kzalloc(sizeof(struct dw_mci), GFP_KERNEL);
+ host = devm_kzalloc(&pdev->dev, sizeof(struct dw_mci), GFP_KERNEL);
if (!host)
return -ENOMEM;
regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!regs) {
- ret = -ENXIO;
- goto err_free;
- }
+ if (!regs)
+ return -ENXIO;
host->irq = platform_get_irq(pdev, 0);
- if (host->irq < 0) {
- ret = host->irq;
- goto err_free;
- }
+ if (host->irq < 0)
+ return host->irq;
- host->dev = pdev->dev;
+ host->drv_data = drv_data;
+ host->dev = &pdev->dev;
host->irq_flags = 0;
host->pdata = pdev->dev.platform_data;
- ret = -ENOMEM;
- host->regs = ioremap(regs->start, resource_size(regs));
+ host->regs = devm_request_and_ioremap(&pdev->dev, regs);
if (!host->regs)
- goto err_free;
+ return -ENOMEM;
+
+ if (host->drv_data->init) {
+ ret = host->drv_data->init(host);
+ if (ret)
+ return ret;
+ }
+
platform_set_drvdata(pdev, host);
ret = dw_mci_probe(host);
- if (ret)
- goto err_out;
- return ret;
-err_out:
- iounmap(host->regs);
-err_free:
- kfree(host);
return ret;
}
+EXPORT_SYMBOL_GPL(dw_mci_pltfm_register);
-static int __exit dw_mci_pltfm_remove(struct platform_device *pdev)
+static int __devinit dw_mci_pltfm_probe(struct platform_device *pdev)
+{
+ return dw_mci_pltfm_register(pdev, NULL);
+}
+
+static int __devexit dw_mci_pltfm_remove(struct platform_device *pdev)
{
struct dw_mci *host = platform_get_drvdata(pdev);
platform_set_drvdata(pdev, NULL);
dw_mci_remove(host);
- iounmap(host->regs);
- kfree(host);
return 0;
}
+EXPORT_SYMBOL_GPL(dw_mci_pltfm_remove);
#ifdef CONFIG_PM_SLEEP
/*
@@ -105,12 +109,20 @@ static int dw_mci_pltfm_resume(struct device *dev)
#define dw_mci_pltfm_resume NULL
#endif /* CONFIG_PM_SLEEP */
-static SIMPLE_DEV_PM_OPS(dw_mci_pltfm_pmops, dw_mci_pltfm_suspend, dw_mci_pltfm_resume);
+SIMPLE_DEV_PM_OPS(dw_mci_pltfm_pmops, dw_mci_pltfm_suspend, dw_mci_pltfm_resume);
+EXPORT_SYMBOL_GPL(dw_mci_pltfm_pmops);
+
+static const struct of_device_id dw_mci_pltfm_match[] = {
+ { .compatible = "snps,dw-mshc", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, dw_mci_pltfm_match);
static struct platform_driver dw_mci_pltfm_driver = {
.remove = __exit_p(dw_mci_pltfm_remove),
.driver = {
.name = "dw_mmc",
+ .of_match_table = of_match_ptr(dw_mci_pltfm_match),
.pm = &dw_mci_pltfm_pmops,
},
};
diff --git a/drivers/mmc/host/dw_mmc-pltfm.h b/drivers/mmc/host/dw_mmc-pltfm.h
new file mode 100644
index 0000000..301f245
--- /dev/null
+++ b/drivers/mmc/host/dw_mmc-pltfm.h
@@ -0,0 +1,20 @@
+/*
+ * Synopsys DesignWare Multimedia Card Interface Platform driver
+ *
+ * Copyright (C) 2012, Samsung Electronics Co., 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.
+ */
+
+#ifndef _DW_MMC_PLTFM_H_
+#define _DW_MMC_PLTFM_H_
+
+extern int dw_mci_pltfm_register(struct platform_device *pdev,
+ struct dw_mci_drv_data *drv_data);
+extern int __devexit dw_mci_pltfm_remove(struct platform_device *pdev);
+extern const struct dev_pm_ops dw_mci_pltfm_pmops;
+
+#endif /* _DW_MMC_PLTFM_H_ */
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index af40d22..c2828f3 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -33,6 +33,7 @@
#include <linux/bitops.h>
#include <linux/regulator/consumer.h>
#include <linux/workqueue.h>
+#include <linux/of.h>
#include "dw_mmc.h"
@@ -230,6 +231,7 @@ static void dw_mci_set_timeout(struct dw_mci *host)
static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd)
{
struct mmc_data *data;
+ struct dw_mci_slot *slot = mmc_priv(mmc);
u32 cmdr;
cmd->error = -EINPROGRESS;
@@ -259,6 +261,9 @@ static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd)
cmdr |= SDMMC_CMD_DAT_WR;
}
+ if (slot->host->drv_data->prepare_command)
+ slot->host->drv_data->prepare_command(slot->host, &cmdr);
+
return cmdr;
}
@@ -266,7 +271,7 @@ static void dw_mci_start_command(struct dw_mci *host,
struct mmc_command *cmd, u32 cmd_flags)
{
host->cmd = cmd;
- dev_vdbg(&host->dev,
+ dev_vdbg(host->dev,
"start command: ARGR=0x%08x CMDR=0x%08x\n",
cmd->arg, cmd_flags);
@@ -308,7 +313,7 @@ static void dw_mci_dma_cleanup(struct dw_mci *host)
if (data)
if (!data->host_cookie)
- dma_unmap_sg(&host->dev,
+ dma_unmap_sg(host->dev,
data->sg,
data->sg_len,
dw_mci_get_dma_dir(data));
@@ -334,7 +339,7 @@ static void dw_mci_idmac_complete_dma(struct dw_mci *host)
{
struct mmc_data *data = host->data;
- dev_vdbg(&host->dev, "DMA complete\n");
+ dev_vdbg(host->dev, "DMA complete\n");
host->dma_ops->cleanup(host);
@@ -405,23 +410,11 @@ static void dw_mci_idmac_start_dma(struct dw_mci *host, unsigned int sg_len)
static int dw_mci_idmac_init(struct dw_mci *host)
{
struct idmac_desc *p;
- int i, dma_support;
+ int i;
/* Number of descriptors in the ring buffer */
host->ring_size = PAGE_SIZE / sizeof(struct idmac_desc);
- /* Check if Hardware Configuration Register has support for DMA */
- dma_support = (mci_readl(host, HCON) >> 16) & 0x3;
-
- if (!dma_support || dma_support > 2) {
- dev_err(&host->dev,
- "Host Controller does not support IDMA Tx.\n");
- host->dma_ops = NULL;
- return -ENODEV;
- }
-
- dev_info(&host->dev, "Using internal DMA controller.\n");
-
/* Forward link the descriptor list */
for (i = 0, p = host->sg_cpu; i < host->ring_size - 1; i++, p++)
p->des3 = host->sg_dma + (sizeof(struct idmac_desc) * (i + 1));
@@ -476,7 +469,7 @@ static int dw_mci_pre_dma_transfer(struct dw_mci *host,
return -EINVAL;
}
- sg_len = dma_map_sg(&host->dev,
+ sg_len = dma_map_sg(host->dev,
data->sg,
data->sg_len,
dw_mci_get_dma_dir(data));
@@ -519,7 +512,7 @@ static void dw_mci_post_req(struct mmc_host *mmc,
return;
if (data->host_cookie)
- dma_unmap_sg(&slot->host->dev,
+ dma_unmap_sg(slot->host->dev,
data->sg,
data->sg_len,
dw_mci_get_dma_dir(data));
@@ -545,7 +538,7 @@ static int dw_mci_submit_data_dma(struct dw_mci *host, struct mmc_data *data)
host->using_dma = 1;
- dev_vdbg(&host->dev,
+ dev_vdbg(host->dev,
"sd sg_cpu: %#lx sg_dma: %#lx sg_len: %d\n",
(unsigned long)host->sg_cpu, (unsigned long)host->sg_dma,
sg_len);
@@ -814,6 +807,9 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
slot->clock = ios->clock;
}
+ if (slot->host->drv_data->set_ios)
+ slot->host->drv_data->set_ios(slot->host, ios);
+
switch (ios->power_mode) {
case MMC_POWER_UP:
set_bit(DW_MMC_CARD_NEED_INIT, &slot->flags);
@@ -830,7 +826,9 @@ static int dw_mci_get_ro(struct mmc_host *mmc)
struct dw_mci_board *brd = slot->host->pdata;
/* Use platform get_ro function, else try on board write protect */
- if (brd->get_ro)
+ if (brd->quirks & DW_MCI_QUIRK_NO_WRITE_PROTECT)
+ read_only = 0;
+ else if (brd->get_ro)
read_only = brd->get_ro(slot->id);
else
read_only =
@@ -939,12 +937,12 @@ static void dw_mci_request_end(struct dw_mci *host, struct mmc_request *mrq)
slot = list_entry(host->queue.next,
struct dw_mci_slot, queue_node);
list_del(&slot->queue_node);
- dev_vdbg(&host->dev, "list not empty: %s is next\n",
+ dev_vdbg(host->dev, "list not empty: %s is next\n",
mmc_hostname(slot->mmc));
host->state = STATE_SENDING_CMD;
dw_mci_start_request(host, slot);
} else {
- dev_vdbg(&host->dev, "list empty\n");
+ dev_vdbg(host->dev, "list empty\n");
host->state = STATE_IDLE;
}
@@ -1083,7 +1081,7 @@ static void dw_mci_tasklet_func(unsigned long priv)
data->bytes_xfered = 0;
data->error = -ETIMEDOUT;
} else {
- dev_err(&host->dev,
+ dev_err(host->dev,
"data FIFO error "
"(status=%08x)\n",
status);
@@ -1767,12 +1765,60 @@ static void dw_mci_work_routine_card(struct work_struct *work)
}
}
-static int __init dw_mci_init_slot(struct dw_mci *host, unsigned int id)
+#ifdef CONFIG_OF
+/* given a slot id, find out the device node representing that slot */
+static struct device_node *dw_mci_of_find_slot_node(struct device *dev, u8 slot)
+{
+ struct device_node *np;
+ const __be32 *addr;
+ int len;
+
+ if (!dev || !dev->of_node)
+ return NULL;
+
+ for_each_child_of_node(dev->of_node, np) {
+ addr = of_get_property(np, "reg", &len);
+ if (!addr || (len < sizeof(int)))
+ continue;
+ if (be32_to_cpup(addr) == slot)
+ return np;
+ }
+ return NULL;
+}
+
+/* find out bus-width for a given slot */
+static u32 dw_mci_of_get_bus_wd(struct device *dev, u8 slot)
+{
+ struct device_node *np = dw_mci_of_find_slot_node(dev, slot);
+ u32 bus_wd = 1;
+
+ if (!np)
+ return 1;
+
+ if (of_property_read_u32(np, "bus-width", &bus_wd))
+ dev_err(dev, "bus-width property not found, assuming width"
+ " as 1\n");
+ return bus_wd;
+}
+#else /* CONFIG_OF */
+static u32 dw_mci_of_get_bus_wd(struct device *dev, u8 slot)
+{
+ return 1;
+}
+static struct device_node *dw_mci_of_find_slot_node(struct device *dev, u8 slot)
+{
+ return NULL;
+}
+#endif /* CONFIG_OF */
+
+static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
{
struct mmc_host *mmc;
struct dw_mci_slot *slot;
+ int ctrl_id, ret;
+ u8 bus_width;
- mmc = mmc_alloc_host(sizeof(struct dw_mci_slot), &host->dev);
+ mmc = mmc_alloc_host(sizeof(struct dw_mci_slot), host->dev);
if (!mmc)
return -ENOMEM;
@@ -1780,6 +1826,7 @@ static int __init dw_mci_init_slot(struct dw_mci *host, unsigned int id)
slot->id = id;
slot->mmc = mmc;
slot->host = host;
+ host->slot[id] = slot;
mmc->ops = &dw_mci_ops;
mmc->f_min = DIV_ROUND_UP(host->bus_hz, 510);
@@ -1800,21 +1847,44 @@ static int __init dw_mci_init_slot(struct dw_mci *host, unsigned int id)
if (host->pdata->caps)
mmc->caps = host->pdata->caps;
+ if (host->dev->of_node) {
+ ctrl_id = of_alias_get_id(host->dev->of_node, "mshc");
+ if (ctrl_id < 0)
+ ctrl_id = 0;
+ } else {
+ ctrl_id = to_platform_device(host->dev)->id;
+ }
+ if (host->drv_data && host->drv_data->caps)
+ mmc->caps |= host->drv_data->caps[ctrl_id];
+
if (host->pdata->caps2)
mmc->caps2 = host->pdata->caps2;
if (host->pdata->get_bus_wd)
- if (host->pdata->get_bus_wd(slot->id) >= 4)
- mmc->caps |= MMC_CAP_4_BIT_DATA;
+ bus_width = host->pdata->get_bus_wd(slot->id);
+ else if (host->dev->of_node)
+ bus_width = dw_mci_of_get_bus_wd(host->dev, slot->id);
+ else
+ bus_width = 1;
+
+ if (host->drv_data->setup_bus) {
+ struct device_node *slot_np;
+ slot_np = dw_mci_of_find_slot_node(host->dev, slot->id);
+ ret = host->drv_data->setup_bus(host, slot_np, bus_width);
+ if (ret)
+ goto err_setup_bus;
+ }
+
+ switch (bus_width) {
+ case 8:
+ mmc->caps |= MMC_CAP_8_BIT_DATA;
+ case 4:
+ mmc->caps |= MMC_CAP_4_BIT_DATA;
+ }
if (host->pdata->quirks & DW_MCI_QUIRK_HIGHSPEED)
mmc->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED;
- if (mmc->caps2 & MMC_CAP2_POWEROFF_NOTIFY)
- mmc->power_notify_type = MMC_HOST_PW_NOTIFY_SHORT;
- else
- mmc->power_notify_type = MMC_HOST_PW_NOTIFY_NONE;
-
if (host->pdata->blk_settings) {
mmc->max_segs = host->pdata->blk_settings->max_segs;
mmc->max_blk_size = host->pdata->blk_settings->max_blk_size;
@@ -1850,7 +1920,6 @@ static int __init dw_mci_init_slot(struct dw_mci *host, unsigned int id)
else
clear_bit(DW_MMC_CARD_PRESENT, &slot->flags);
- host->slot[id] = slot;
mmc_add_host(mmc);
#if defined(CONFIG_DEBUG_FS)
@@ -1867,6 +1936,10 @@ static int __init dw_mci_init_slot(struct dw_mci *host, unsigned int id)
queue_work(host->card_workqueue, &host->card_work);
return 0;
+
+err_setup_bus:
+ mmc_free_host(mmc);
+ return -EINVAL;
}
static void dw_mci_cleanup_slot(struct dw_mci_slot *slot, unsigned int id)
@@ -1884,10 +1957,10 @@ static void dw_mci_cleanup_slot(struct dw_mci_slot *slot, unsigned int id)
static void dw_mci_init_dma(struct dw_mci *host)
{
/* Alloc memory for sg translation */
- host->sg_cpu = dma_alloc_coherent(&host->dev, PAGE_SIZE,
+ host->sg_cpu = dma_alloc_coherent(host->dev, PAGE_SIZE,
&host->sg_dma, GFP_KERNEL);
if (!host->sg_cpu) {
- dev_err(&host->dev, "%s: could not alloc DMA memory\n",
+ dev_err(host->dev, "%s: could not alloc DMA memory\n",
__func__);
goto no_dma;
}
@@ -1895,6 +1968,7 @@ static void dw_mci_init_dma(struct dw_mci *host)
/* Determine which DMA interface to use */
#ifdef CONFIG_MMC_DW_IDMAC
host->dma_ops = &dw_mci_idmac_ops;
+ dev_info(&host->dev, "Using internal DMA controller.\n");
#endif
if (!host->dma_ops)
@@ -1903,12 +1977,12 @@ static void dw_mci_init_dma(struct dw_mci *host)
if (host->dma_ops->init && host->dma_ops->start &&
host->dma_ops->stop && host->dma_ops->cleanup) {
if (host->dma_ops->init(host)) {
- dev_err(&host->dev, "%s: Unable to initialize "
+ dev_err(host->dev, "%s: Unable to initialize "
"DMA Controller.\n", __func__);
goto no_dma;
}
} else {
- dev_err(&host->dev, "DMA initialization not found.\n");
+ dev_err(host->dev, "DMA initialization not found.\n");
goto no_dma;
}
@@ -1916,7 +1990,7 @@ static void dw_mci_init_dma(struct dw_mci *host)
return;
no_dma:
- dev_info(&host->dev, "Using PIO mode.\n");
+ dev_info(host->dev, "Using PIO mode.\n");
host->use_dma = 0;
return;
}
@@ -1942,30 +2016,133 @@ static bool mci_wait_reset(struct device *dev, struct dw_mci *host)
return false;
}
+#ifdef CONFIG_OF
+static struct dw_mci_of_quirks {
+ char *quirk;
+ int id;
+} of_quirks[] = {
+ {
+ .quirk = "supports-highspeed",
+ .id = DW_MCI_QUIRK_HIGHSPEED,
+ }, {
+ .quirk = "broken-cd",
+ .id = DW_MCI_QUIRK_BROKEN_CARD_DETECTION,
+ },
+};
+
+static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
+{
+ struct dw_mci_board *pdata;
+ struct device *dev = host->dev;
+ struct device_node *np = dev->of_node;
+ int idx, ret;
+
+ pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata) {
+ dev_err(dev, "could not allocate memory for pdata\n");
+ return ERR_PTR(-ENOMEM);
+ }
+
+ /* find out number of slots supported */
+ if (of_property_read_u32(dev->of_node, "num-slots",
+ &pdata->num_slots)) {
+ dev_info(dev, "num-slots property not found, "
+ "assuming 1 slot is available\n");
+ pdata->num_slots = 1;
+ }
+
+ /* get quirks */
+ for (idx = 0; idx < ARRAY_SIZE(of_quirks); idx++)
+ if (of_get_property(np, of_quirks[idx].quirk, NULL))
+ pdata->quirks |= of_quirks[idx].id;
+
+ if (of_property_read_u32(np, "fifo-depth", &pdata->fifo_depth))
+ dev_info(dev, "fifo-depth property not found, using "
+ "value of FIFOTH register as default\n");
+
+ of_property_read_u32(np, "card-detect-delay", &pdata->detect_delay_ms);
+
+ if (host->drv_data->parse_dt) {
+ ret = host->drv_data->parse_dt(host);
+ if (ret)
+ return ERR_PTR(ret);
+ }
+
+ return pdata;
+}
+
+#else /* CONFIG_OF */
+static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
+{
+ return ERR_PTR(-EINVAL);
+}
+#endif /* CONFIG_OF */
+
int dw_mci_probe(struct dw_mci *host)
{
int width, i, ret = 0;
u32 fifo_size;
+ int init_slots = 0;
- if (!host->pdata || !host->pdata->init) {
- dev_err(&host->dev,
- "Platform data must supply init function\n");
- return -ENODEV;
+ if (!host->pdata) {
+ host->pdata = dw_mci_parse_dt(host);
+ if (IS_ERR(host->pdata)) {
+ dev_err(host->dev, "platform data not available\n");
+ return -EINVAL;
+ }
}
if (!host->pdata->select_slot && host->pdata->num_slots > 1) {
- dev_err(&host->dev,
+ dev_err(host->dev,
"Platform data must supply select_slot function\n");
return -ENODEV;
}
- if (!host->pdata->bus_hz) {
- dev_err(&host->dev,
+ host->biu_clk = clk_get(host->dev, "biu");
+ if (IS_ERR(host->biu_clk)) {
+ dev_dbg(host->dev, "biu clock not available\n");
+ } else {
+ ret = clk_prepare_enable(host->biu_clk);
+ if (ret) {
+ dev_err(host->dev, "failed to enable biu clock\n");
+ clk_put(host->biu_clk);
+ return ret;
+ }
+ }
+
+ host->ciu_clk = clk_get(host->dev, "ciu");
+ if (IS_ERR(host->ciu_clk)) {
+ dev_dbg(host->dev, "ciu clock not available\n");
+ } else {
+ ret = clk_prepare_enable(host->ciu_clk);
+ if (ret) {
+ dev_err(host->dev, "failed to enable ciu clock\n");
+ clk_put(host->ciu_clk);
+ goto err_clk_biu;
+ }
+ }
+
+ if (IS_ERR(host->ciu_clk))
+ host->bus_hz = host->pdata->bus_hz;
+ else
+ host->bus_hz = clk_get_rate(host->ciu_clk);
+
+ if (host->drv_data->setup_clock) {
+ ret = host->drv_data->setup_clock(host);
+ if (ret) {
+ dev_err(host->dev,
+ "implementation specific clock setup failed\n");
+ goto err_clk_ciu;
+ }
+ }
+
+ if (!host->bus_hz) {
+ dev_err(host->dev,
"Platform data must supply bus speed\n");
- return -ENODEV;
+ ret = -ENODEV;
+ goto err_clk_ciu;
}
- host->bus_hz = host->pdata->bus_hz;
host->quirks = host->pdata->quirks;
spin_lock_init(&host->lock);
@@ -1998,7 +2175,7 @@ int dw_mci_probe(struct dw_mci *host)
}
/* Reset all blocks */
- if (!mci_wait_reset(&host->dev, host))
+ if (!mci_wait_reset(host->dev, host))
return -ENODEV;
host->dma_ops = host->pdata->dma_ops;
@@ -2054,10 +2231,18 @@ int dw_mci_probe(struct dw_mci *host)
/* We need at least one slot to succeed */
for (i = 0; i < host->num_slots; i++) {
ret = dw_mci_init_slot(host, i);
- if (ret) {
- ret = -ENODEV;
- goto err_init_slot;
- }
+ if (ret)
+ dev_dbg(host->dev, "slot %d init failed\n", i);
+ else
+ init_slots++;
+ }
+
+ if (init_slots) {
+ dev_info(host->dev, "%d slots initialized\n", init_slots);
+ } else {
+ dev_dbg(host->dev, "attempted to initialize %d slots, "
+ "but failed on all\n", host->num_slots);
+ goto err_init_slot;
}
/*
@@ -2065,7 +2250,7 @@ int dw_mci_probe(struct dw_mci *host)
* Need to check the version-id and set data-offset for DATA register.
*/
host->verid = SDMMC_GET_VERID(mci_readl(host, VERID));
- dev_info(&host->dev, "Version ID is %04x\n", host->verid);
+ dev_info(host->dev, "Version ID is %04x\n", host->verid);
if (host->verid < DW_MMC_240A)
host->data_offset = DATA_OFFSET;
@@ -2082,22 +2267,16 @@ int dw_mci_probe(struct dw_mci *host)
DW_MCI_ERROR_FLAGS | SDMMC_INT_CD);
mci_writel(host, CTRL, SDMMC_CTRL_INT_ENABLE); /* Enable mci interrupt */
- dev_info(&host->dev, "DW MMC controller at irq %d, "
+ dev_info(host->dev, "DW MMC controller at irq %d, "
"%d bit host data width, "
"%u deep fifo\n",
host->irq, width, fifo_size);
if (host->quirks & DW_MCI_QUIRK_IDMAC_DTO)
- dev_info(&host->dev, "Internal DMAC interrupt fix enabled.\n");
+ dev_info(host->dev, "Internal DMAC interrupt fix enabled.\n");
return 0;
err_init_slot:
- /* De-init any initialized slots */
- while (i > 0) {
- if (host->slot[i])
- dw_mci_cleanup_slot(host->slot[i], i);
- i--;
- }
free_irq(host->irq, host);
err_workqueue:
@@ -2106,13 +2285,24 @@ err_workqueue:
err_dmaunmap:
if (host->use_dma && host->dma_ops->exit)
host->dma_ops->exit(host);
- dma_free_coherent(&host->dev, PAGE_SIZE,
+ dma_free_coherent(host->dev, PAGE_SIZE,
host->sg_cpu, host->sg_dma);
if (host->vmmc) {
regulator_disable(host->vmmc);
regulator_put(host->vmmc);
}
+
+err_clk_ciu:
+ if (!IS_ERR(host->ciu_clk)) {
+ clk_disable_unprepare(host->ciu_clk);
+ clk_put(host->ciu_clk);
+ }
+err_clk_biu:
+ if (!IS_ERR(host->biu_clk)) {
+ clk_disable_unprepare(host->biu_clk);
+ clk_put(host->biu_clk);
+ }
return ret;
}
EXPORT_SYMBOL(dw_mci_probe);
@@ -2125,7 +2315,7 @@ void dw_mci_remove(struct dw_mci *host)
mci_writel(host, INTMASK, 0); /* disable all mmc interrupt first */
for (i = 0; i < host->num_slots; i++) {
- dev_dbg(&host->dev, "remove slot %d\n", i);
+ dev_dbg(host->dev, "remove slot %d\n", i);
if (host->slot[i])
dw_mci_cleanup_slot(host->slot[i], i);
}
@@ -2136,7 +2326,7 @@ void dw_mci_remove(struct dw_mci *host)
free_irq(host->irq, host);
destroy_workqueue(host->card_workqueue);
- dma_free_coherent(&host->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
+ dma_free_coherent(host->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
if (host->use_dma && host->dma_ops->exit)
host->dma_ops->exit(host);
@@ -2146,6 +2336,12 @@ void dw_mci_remove(struct dw_mci *host)
regulator_put(host->vmmc);
}
+ if (!IS_ERR(host->ciu_clk))
+ clk_disable_unprepare(host->ciu_clk);
+ if (!IS_ERR(host->biu_clk))
+ clk_disable_unprepare(host->biu_clk);
+ clk_put(host->ciu_clk);
+ clk_put(host->biu_clk);
}
EXPORT_SYMBOL(dw_mci_remove);
@@ -2188,7 +2384,7 @@ int dw_mci_resume(struct dw_mci *host)
if (host->vmmc)
regulator_enable(host->vmmc);
- if (!mci_wait_reset(&host->dev, host)) {
+ if (!mci_wait_reset(host->dev, host)) {
ret = -ENODEV;
return ret;
}
diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h
index 15c27e1..53b8fd9 100644
--- a/drivers/mmc/host/dw_mmc.h
+++ b/drivers/mmc/host/dw_mmc.h
@@ -182,4 +182,28 @@ extern int dw_mci_suspend(struct dw_mci *host);
extern int dw_mci_resume(struct dw_mci *host);
#endif
+/**
+ * dw_mci driver data - dw-mshc implementation specific driver data.
+ * @caps: mmc subsystem specified capabilities of the controller(s).
+ * @init: early implementation specific initialization.
+ * @setup_clock: implementation specific clock configuration.
+ * @prepare_command: handle CMD register extensions.
+ * @set_ios: handle bus specific extensions.
+ * @parse_dt: parse implementation specific device tree properties.
+ * @setup_bus: initialize io-interface
+ *
+ * Provide controller implementation specific extensions. The usage of this
+ * data structure is fully optional and usage of each member in this structure
+ * is optional as well.
+ */
+struct dw_mci_drv_data {
+ unsigned long *caps;
+ int (*init)(struct dw_mci *host);
+ int (*setup_clock)(struct dw_mci *host);
+ void (*prepare_command)(struct dw_mci *host, u32 *cmdr);
+ void (*set_ios)(struct dw_mci *host, struct mmc_ios *ios);
+ int (*parse_dt)(struct dw_mci *host);
+ int (*setup_bus)(struct dw_mci *host,
+ struct device_node *slot_np, u8 bus_width);
+};
#endif /* _DW_MMC_H_ */
diff --git a/drivers/mmc/host/mmc_spi.c b/drivers/mmc/host/mmc_spi.c
index 273306c..a600eab 100644
--- a/drivers/mmc/host/mmc_spi.c
+++ b/drivers/mmc/host/mmc_spi.c
@@ -1532,20 +1532,7 @@ static struct spi_driver mmc_spi_driver = {
.remove = __devexit_p(mmc_spi_remove),
};
-
-static int __init mmc_spi_init(void)
-{
- return spi_register_driver(&mmc_spi_driver);
-}
-module_init(mmc_spi_init);
-
-
-static void __exit mmc_spi_exit(void)
-{
- spi_unregister_driver(&mmc_spi_driver);
-}
-module_exit(mmc_spi_exit);
-
+module_spi_driver(mmc_spi_driver);
MODULE_AUTHOR("Mike Lavender, David Brownell, "
"Hans-Peter Nilsson, Jan Nikitenko");
diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
index 50ff19a..edc3e9b 100644
--- a/drivers/mmc/host/mmci.c
+++ b/drivers/mmc/host/mmci.c
@@ -1309,14 +1309,10 @@ static int __devinit mmci_probe(struct amba_device *dev,
goto host_free;
}
- ret = clk_prepare(host->clk);
+ ret = clk_prepare_enable(host->clk);
if (ret)
goto clk_free;
- ret = clk_enable(host->clk);
- if (ret)
- goto clk_unprep;
-
host->plat = plat;
host->variant = variant;
host->mclk = clk_get_rate(host->clk);
@@ -1515,9 +1511,7 @@ static int __devinit mmci_probe(struct amba_device *dev,
err_gpio_cd:
iounmap(host->base);
clk_disable:
- clk_disable(host->clk);
- clk_unprep:
- clk_unprepare(host->clk);
+ clk_disable_unprepare(host->clk);
clk_free:
clk_put(host->clk);
host_free:
@@ -1564,8 +1558,7 @@ static int __devexit mmci_remove(struct amba_device *dev)
gpio_free(host->gpio_cd);
iounmap(host->base);
- clk_disable(host->clk);
- clk_unprepare(host->clk);
+ clk_disable_unprepare(host->clk);
clk_put(host->clk);
if (host->vcc)
diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c
index 7b1161d..565c2e4 100644
--- a/drivers/mmc/host/mxcmmc.c
+++ b/drivers/mmc/host/mxcmmc.c
@@ -44,6 +44,7 @@
#include <mach/hardware.h>
#define DRIVER_NAME "mxc-mmc"
+#define MXCMCI_TIMEOUT_MS 10000
#define MMC_REG_STR_STP_CLK 0x00
#define MMC_REG_STATUS 0x04
@@ -150,6 +151,8 @@ struct mxcmci_host {
int dmareq;
struct dma_slave_config dma_slave_config;
struct imx_dma_data dma_data;
+
+ struct timer_list watchdog;
};
static void mxcmci_set_clk_rate(struct mxcmci_host *host, unsigned int clk_ios);
@@ -271,9 +274,32 @@ static int mxcmci_setup_data(struct mxcmci_host *host, struct mmc_data *data)
dmaengine_submit(host->desc);
dma_async_issue_pending(host->dma);
+ mod_timer(&host->watchdog, jiffies + msecs_to_jiffies(MXCMCI_TIMEOUT_MS));
+
return 0;
}
+static void mxcmci_cmd_done(struct mxcmci_host *host, unsigned int stat);
+static void mxcmci_data_done(struct mxcmci_host *host, unsigned int stat);
+
+static void mxcmci_dma_callback(void *data)
+{
+ struct mxcmci_host *host = data;
+ u32 stat;
+
+ del_timer(&host->watchdog);
+
+ stat = readl(host->base + MMC_REG_STATUS);
+ writel(stat & ~STATUS_DATA_TRANS_DONE, host->base + MMC_REG_STATUS);
+
+ dev_dbg(mmc_dev(host->mmc), "%s: 0x%08x\n", __func__, stat);
+
+ if (stat & STATUS_READ_OP_DONE)
+ writel(STATUS_READ_OP_DONE, host->base + MMC_REG_STATUS);
+
+ mxcmci_data_done(host, stat);
+}
+
static int mxcmci_start_cmd(struct mxcmci_host *host, struct mmc_command *cmd,
unsigned int cmdat)
{
@@ -305,8 +331,14 @@ static int mxcmci_start_cmd(struct mxcmci_host *host, struct mmc_command *cmd,
int_cntr = INT_END_CMD_RES_EN;
- if (mxcmci_use_dma(host))
- int_cntr |= INT_READ_OP_EN | INT_WRITE_OP_DONE_EN;
+ if (mxcmci_use_dma(host)) {
+ if (host->dma_dir == DMA_FROM_DEVICE) {
+ host->desc->callback = mxcmci_dma_callback;
+ host->desc->callback_param = host;
+ } else {
+ int_cntr |= INT_WRITE_OP_DONE_EN;
+ }
+ }
spin_lock_irqsave(&host->lock, flags);
if (host->use_sdio)
@@ -345,11 +377,9 @@ static int mxcmci_finish_data(struct mxcmci_host *host, unsigned int stat)
struct mmc_data *data = host->data;
int data_error;
- if (mxcmci_use_dma(host)) {
- dmaengine_terminate_all(host->dma);
+ if (mxcmci_use_dma(host))
dma_unmap_sg(host->dma->device->dev, data->sg, data->sg_len,
host->dma_dir);
- }
if (stat & STATUS_ERR_MASK) {
dev_dbg(mmc_dev(host->mmc), "request failed. status: 0x%08x\n",
@@ -624,8 +654,10 @@ static irqreturn_t mxcmci_irq(int irq, void *devid)
mxcmci_cmd_done(host, stat);
if (mxcmci_use_dma(host) &&
- (stat & (STATUS_DATA_TRANS_DONE | STATUS_WRITE_OP_DONE)))
+ (stat & (STATUS_DATA_TRANS_DONE | STATUS_WRITE_OP_DONE))) {
+ del_timer(&host->watchdog);
mxcmci_data_done(host, stat);
+ }
if (host->default_irq_mask &&
(stat & (STATUS_CARD_INSERTION | STATUS_CARD_REMOVAL)))
@@ -836,6 +868,34 @@ static bool filter(struct dma_chan *chan, void *param)
return true;
}
+static void mxcmci_watchdog(unsigned long data)
+{
+ struct mmc_host *mmc = (struct mmc_host *)data;
+ struct mxcmci_host *host = mmc_priv(mmc);
+ struct mmc_request *req = host->req;
+ unsigned int stat = readl(host->base + MMC_REG_STATUS);
+
+ if (host->dma_dir == DMA_FROM_DEVICE) {
+ dmaengine_terminate_all(host->dma);
+ dev_err(mmc_dev(host->mmc),
+ "%s: read time out (status = 0x%08x)\n",
+ __func__, stat);
+ } else {
+ dev_err(mmc_dev(host->mmc),
+ "%s: write time out (status = 0x%08x)\n",
+ __func__, stat);
+ mxcmci_softreset(host);
+ }
+
+ /* Mark transfer as erroneus and inform the upper layers */
+
+ host->data->error = -ETIMEDOUT;
+ host->req = NULL;
+ host->cmd = NULL;
+ host->data = NULL;
+ mmc_request_done(host->mmc, req);
+}
+
static const struct mmc_host_ops mxcmci_ops = {
.request = mxcmci_request,
.set_ios = mxcmci_set_ios,
@@ -968,6 +1028,10 @@ static int mxcmci_probe(struct platform_device *pdev)
mmc_add_host(mmc);
+ init_timer(&host->watchdog);
+ host->watchdog.function = &mxcmci_watchdog;
+ host->watchdog.data = (unsigned long)mmc;
+
return 0;
out_free_irq:
diff --git a/drivers/mmc/host/omap.c b/drivers/mmc/host/omap.c
index c6259a8..48ad361 100644
--- a/drivers/mmc/host/omap.c
+++ b/drivers/mmc/host/omap.c
@@ -27,16 +27,10 @@
#include <linux/mmc/card.h>
#include <linux/clk.h>
#include <linux/scatterlist.h>
-#include <linux/i2c/tps65010.h>
#include <linux/slab.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-
#include <plat/mmc.h>
-#include <asm/gpio.h>
#include <plat/dma.h>
-#include <plat/fpga.h>
#define OMAP_MMC_REG_CMD 0x00
#define OMAP_MMC_REG_ARGL 0x01
@@ -105,7 +99,6 @@ struct mmc_omap_slot {
u16 saved_con;
u16 bus_mode;
unsigned int fclk_freq;
- unsigned powered:1;
struct tasklet_struct cover_tasklet;
struct timer_list cover_timer;
@@ -137,7 +130,6 @@ struct mmc_omap_host {
unsigned int phys_base;
int irq;
unsigned char bus_mode;
- unsigned char hw_bus_mode;
unsigned int reg_shift;
struct work_struct cmd_abort_work;
@@ -695,22 +687,29 @@ mmc_omap_xfer_data(struct mmc_omap_host *host, int write)
host->buffer += nwords;
}
-static inline void mmc_omap_report_irq(u16 status)
+#ifdef CONFIG_MMC_DEBUG
+static void mmc_omap_report_irq(struct mmc_omap_host *host, u16 status)
{
static const char *mmc_omap_status_bits[] = {
"EOC", "CD", "CB", "BRS", "EOFB", "DTO", "DCRC", "CTO",
"CCRC", "CRW", "AF", "AE", "OCRB", "CIRQ", "CERR"
};
- int i, c = 0;
+ int i;
+ char res[64], *buf = res;
+
+ buf += sprintf(buf, "MMC IRQ 0x%x:", status);
for (i = 0; i < ARRAY_SIZE(mmc_omap_status_bits); i++)
- if (status & (1 << i)) {
- if (c)
- printk(" ");
- printk("%s", mmc_omap_status_bits[i]);
- c++;
- }
+ if (status & (1 << i))
+ buf += sprintf(buf, " %s", mmc_omap_status_bits[i]);
+ dev_vdbg(mmc_dev(host->mmc), "%s\n", res);
}
+#else
+static void mmc_omap_report_irq(struct mmc_omap_host *host, u16 status)
+{
+}
+#endif
+
static irqreturn_t mmc_omap_irq(int irq, void *dev_id)
{
@@ -744,12 +743,10 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id)
cmd = host->cmd->opcode;
else
cmd = -1;
-#ifdef CONFIG_MMC_DEBUG
dev_dbg(mmc_dev(host->mmc), "MMC IRQ %04x (CMD %d): ",
status, cmd);
- mmc_omap_report_irq(status);
- printk("\n");
-#endif
+ mmc_omap_report_irq(host, status);
+
if (host->total_bytes_left) {
if ((status & OMAP_MMC_STAT_A_FULL) ||
(status & OMAP_MMC_STAT_END_OF_DATA))
diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index 38adc33..54bfd0c 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -35,7 +35,6 @@
#include <linux/mmc/core.h>
#include <linux/mmc/mmc.h>
#include <linux/io.h>
-#include <linux/semaphore.h>
#include <linux/gpio.h>
#include <linux/regulator/consumer.h>
#include <linux/pm_runtime.h>
@@ -44,7 +43,6 @@
#include <plat/cpu.h>
/* OMAP HSMMC Host Controller Registers */
-#define OMAP_HSMMC_SYSCONFIG 0x0010
#define OMAP_HSMMC_SYSSTATUS 0x0014
#define OMAP_HSMMC_CON 0x002C
#define OMAP_HSMMC_BLK 0x0104
@@ -161,8 +159,6 @@ struct omap_hsmmc_host {
unsigned int dma_sg_idx;
unsigned char bus_mode;
unsigned char power_mode;
- u32 *buffer;
- u32 bytesleft;
int suspended;
int irq;
int use_dma, dma_ch;
@@ -171,7 +167,6 @@ struct omap_hsmmc_host {
int slot_id;
int response_busy;
int context_loss;
- int vdd;
int protect_card;
int reqs_blocked;
int use_reg;
@@ -300,12 +295,12 @@ static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host)
struct regulator *reg;
int ocr_value = 0;
- mmc_slot(host).set_power = omap_hsmmc_set_power;
-
reg = regulator_get(host->dev, "vmmc");
if (IS_ERR(reg)) {
dev_dbg(host->dev, "vmmc regulator missing\n");
+ return PTR_ERR(reg);
} else {
+ mmc_slot(host).set_power = omap_hsmmc_set_power;
host->vcc = reg;
ocr_value = mmc_regulator_get_ocrmask(reg);
if (!mmc_slot(host).ocr_mask) {
@@ -495,7 +490,7 @@ static void omap_hsmmc_set_clock(struct omap_hsmmc_host *host)
unsigned long regval;
unsigned long timeout;
- dev_dbg(mmc_dev(host->mmc), "Set clock to %uHz\n", ios->clock);
+ dev_vdbg(mmc_dev(host->mmc), "Set clock to %uHz\n", ios->clock);
omap_hsmmc_stop_clock(host);
@@ -579,21 +574,8 @@ static int omap_hsmmc_context_restore(struct omap_hsmmc_host *host)
if (host->context_loss == context_loss)
return 1;
- /* Wait for hardware reset */
- timeout = jiffies + msecs_to_jiffies(MMC_TIMEOUT_MS);
- while ((OMAP_HSMMC_READ(host->base, SYSSTATUS) & RESETDONE) != RESETDONE
- && time_before(jiffies, timeout))
- ;
-
- /* Do software reset */
- OMAP_HSMMC_WRITE(host->base, SYSCONFIG, SOFTRESET);
- timeout = jiffies + msecs_to_jiffies(MMC_TIMEOUT_MS);
- while ((OMAP_HSMMC_READ(host->base, SYSSTATUS) & RESETDONE) != RESETDONE
- && time_before(jiffies, timeout))
- ;
-
- OMAP_HSMMC_WRITE(host->base, SYSCONFIG,
- OMAP_HSMMC_READ(host->base, SYSCONFIG) | AUTOIDLE);
+ if (!OMAP_HSMMC_READ(host->base, SYSSTATUS) & RESETDONE)
+ return 1;
if (host->pdata->controller_flags & OMAP_HSMMC_SUPPORTS_DUAL_VOLT) {
if (host->power_mode != MMC_POWER_OFF &&
@@ -745,7 +727,7 @@ omap_hsmmc_start_command(struct omap_hsmmc_host *host, struct mmc_command *cmd,
{
int cmdreg = 0, resptype = 0, cmdtype = 0;
- dev_dbg(mmc_dev(host->mmc), "%s: CMD%d, argument 0x%08x\n",
+ dev_vdbg(mmc_dev(host->mmc), "%s: CMD%d, argument 0x%08x\n",
mmc_hostname(host->mmc), cmd->opcode, cmd->arg);
host->cmd = cmd;
@@ -934,7 +916,7 @@ static void omap_hsmmc_dbg_report_irq(struct omap_hsmmc_host *host, u32 status)
buf += len;
}
- dev_dbg(mmc_dev(host->mmc), "%s\n", res);
+ dev_vdbg(mmc_dev(host->mmc), "%s\n", res);
}
#else
static inline void omap_hsmmc_dbg_report_irq(struct omap_hsmmc_host *host,
@@ -981,72 +963,40 @@ static inline void omap_hsmmc_reset_controller_fsm(struct omap_hsmmc_host *host,
__func__);
}
+static void hsmmc_command_incomplete(struct omap_hsmmc_host *host, int err)
+{
+ omap_hsmmc_reset_controller_fsm(host, SRC);
+ host->cmd->error = err;
+
+ if (host->data) {
+ omap_hsmmc_reset_controller_fsm(host, SRD);
+ omap_hsmmc_dma_cleanup(host, err);
+ }
+
+}
+
static void omap_hsmmc_do_irq(struct omap_hsmmc_host *host, int status)
{
struct mmc_data *data;
int end_cmd = 0, end_trans = 0;
- if (!host->req_in_progress) {
- do {
- OMAP_HSMMC_WRITE(host->base, STAT, status);
- /* Flush posted write */
- status = OMAP_HSMMC_READ(host->base, STAT);
- } while (status & INT_EN_MASK);
- return;
- }
-
data = host->data;
- dev_dbg(mmc_dev(host->mmc), "IRQ Status is %x\n", status);
+ dev_vdbg(mmc_dev(host->mmc), "IRQ Status is %x\n", status);
if (status & ERR) {
omap_hsmmc_dbg_report_irq(host, status);
- if ((status & CMD_TIMEOUT) ||
- (status & CMD_CRC)) {
- if (host->cmd) {
- if (status & CMD_TIMEOUT) {
- omap_hsmmc_reset_controller_fsm(host,
- SRC);
- host->cmd->error = -ETIMEDOUT;
- } else {
- host->cmd->error = -EILSEQ;
- }
- end_cmd = 1;
- }
- if (host->data || host->response_busy) {
- if (host->data)
- omap_hsmmc_dma_cleanup(host,
- -ETIMEDOUT);
- host->response_busy = 0;
- omap_hsmmc_reset_controller_fsm(host, SRD);
- }
- }
- if ((status & DATA_TIMEOUT) ||
- (status & DATA_CRC)) {
- if (host->data || host->response_busy) {
- int err = (status & DATA_TIMEOUT) ?
- -ETIMEDOUT : -EILSEQ;
-
- if (host->data)
- omap_hsmmc_dma_cleanup(host, err);
- else
- host->mrq->cmd->error = err;
- host->response_busy = 0;
- omap_hsmmc_reset_controller_fsm(host, SRD);
- end_trans = 1;
- }
- }
- if (status & CARD_ERR) {
- dev_dbg(mmc_dev(host->mmc),
- "Ignoring card err CMD%d\n", host->cmd->opcode);
- if (host->cmd)
- end_cmd = 1;
- if (host->data)
- end_trans = 1;
+ if (status & (CMD_TIMEOUT | DATA_TIMEOUT))
+ hsmmc_command_incomplete(host, -ETIMEDOUT);
+ else if (status & (CMD_CRC | DATA_CRC))
+ hsmmc_command_incomplete(host, -EILSEQ);
+
+ end_cmd = 1;
+ if (host->data || host->response_busy) {
+ end_trans = 1;
+ host->response_busy = 0;
}
}
- OMAP_HSMMC_WRITE(host->base, STAT, status);
-
if (end_cmd || ((status & CC) && host->cmd))
omap_hsmmc_cmd_done(host, host->cmd);
if ((end_trans || (status & TC)) && host->mrq)
@@ -1062,11 +1012,13 @@ static irqreturn_t omap_hsmmc_irq(int irq, void *dev_id)
int status;
status = OMAP_HSMMC_READ(host->base, STAT);
- do {
+ while (status & INT_EN_MASK && host->req_in_progress) {
omap_hsmmc_do_irq(host, status);
+
/* Flush posted write */
+ OMAP_HSMMC_WRITE(host->base, STAT, status);
status = OMAP_HSMMC_READ(host->base, STAT);
- } while (status & INT_EN_MASK);
+ }
return IRQ_HANDLED;
}
@@ -1501,12 +1453,10 @@ static void omap_hsmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
case MMC_POWER_OFF:
mmc_slot(host).set_power(host->dev, host->slot_id,
0, 0);
- host->vdd = 0;
break;
case MMC_POWER_UP:
mmc_slot(host).set_power(host->dev, host->slot_id,
1, ios->vdd);
- host->vdd = ios->vdd;
break;
case MMC_POWER_ON:
do_send_init_stream = 1;
@@ -1598,10 +1548,6 @@ static void omap_hsmmc_conf_bus_power(struct omap_hsmmc_host *host)
value = OMAP_HSMMC_READ(host->base, CAPA);
OMAP_HSMMC_WRITE(host->base, CAPA, value | capa);
- /* Set the controller to AUTO IDLE mode */
- value = OMAP_HSMMC_READ(host->base, SYSCONFIG);
- OMAP_HSMMC_WRITE(host->base, SYSCONFIG, value | AUTOIDLE);
-
/* Set SD bus power bit */
set_sd_bus_power(host);
}
@@ -1659,8 +1605,6 @@ static int omap_hsmmc_regs_show(struct seq_file *s, void *data)
pm_runtime_get_sync(host->dev);
- seq_printf(s, "SYSCONFIG:\t0x%08x\n",
- OMAP_HSMMC_READ(host->base, SYSCONFIG));
seq_printf(s, "CON:\t\t0x%08x\n",
OMAP_HSMMC_READ(host->base, CON));
seq_printf(s, "HCTL:\t\t0x%08x\n",
@@ -2105,8 +2049,7 @@ static int omap_hsmmc_suspend(struct device *dev)
if (ret) {
host->suspended = 0;
if (host->pdata->resume) {
- ret = host->pdata->resume(dev, host->slot_id);
- if (ret)
+ if (host->pdata->resume(dev, host->slot_id))
dev_dbg(dev, "Unmask interrupt failed\n");
}
goto err;
diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c
index ca3915d..3f9d6d5 100644
--- a/drivers/mmc/host/pxamci.c
+++ b/drivers/mmc/host/pxamci.c
@@ -30,6 +30,9 @@
#include <linux/regulator/consumer.h>
#include <linux/gpio.h>
#include <linux/gfp.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/of_device.h>
#include <asm/sizes.h>
@@ -573,6 +576,50 @@ static irqreturn_t pxamci_detect_irq(int irq, void *devid)
return IRQ_HANDLED;
}
+#ifdef CONFIG_OF
+static const struct of_device_id pxa_mmc_dt_ids[] = {
+ { .compatible = "marvell,pxa-mmc" },
+ { }
+};
+
+MODULE_DEVICE_TABLE(of, pxa_mmc_dt_ids);
+
+static int __devinit pxamci_of_init(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct pxamci_platform_data *pdata;
+ u32 tmp;
+
+ if (!np)
+ return 0;
+
+ pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata)
+ return -ENOMEM;
+
+ pdata->gpio_card_detect =
+ of_get_named_gpio(np, "cd-gpios", 0);
+ pdata->gpio_card_ro =
+ of_get_named_gpio(np, "wp-gpios", 0);
+
+ /* pxa-mmc specific */
+ pdata->gpio_power =
+ of_get_named_gpio(np, "pxa-mmc,gpio-power", 0);
+
+ if (of_property_read_u32(np, "pxa-mmc,detect-delay-ms", &tmp) == 0)
+ pdata->detect_delay_ms = tmp;
+
+ pdev->dev.platform_data = pdata;
+
+ return 0;
+}
+#else
+static int __devinit pxamci_of_init(struct platform_device *pdev)
+{
+ return 0;
+}
+#endif
+
static int pxamci_probe(struct platform_device *pdev)
{
struct mmc_host *mmc;
@@ -580,6 +627,10 @@ static int pxamci_probe(struct platform_device *pdev)
struct resource *r, *dmarx, *dmatx;
int ret, irq, gpio_cd = -1, gpio_ro = -1, gpio_power = -1;
+ ret = pxamci_of_init(pdev);
+ if (ret)
+ return ret;
+
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
irq = platform_get_irq(pdev, 0);
if (!r || irq < 0)
@@ -866,6 +917,7 @@ static struct platform_driver pxamci_driver = {
.driver = {
.name = DRIVER_NAME,
.owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(pxa_mmc_dt_ids),
#ifdef CONFIG_PM
.pm = &pxamci_pm_ops,
#endif
diff --git a/drivers/mmc/host/sdhci-dove.c b/drivers/mmc/host/sdhci-dove.c
index a6e53a1..90140eb 100644
--- a/drivers/mmc/host/sdhci-dove.c
+++ b/drivers/mmc/host/sdhci-dove.c
@@ -24,6 +24,7 @@
#include <linux/err.h>
#include <linux/module.h>
#include <linux/mmc/host.h>
+#include <linux/of.h>
#include "sdhci-pltfm.h"
@@ -126,11 +127,18 @@ static int __devexit sdhci_dove_remove(struct platform_device *pdev)
return sdhci_pltfm_unregister(pdev);
}
+static const struct of_device_id sdhci_dove_of_match_table[] __devinitdata = {
+ { .compatible = "marvell,dove-sdhci", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, sdhci_dove_of_match_table);
+
static struct platform_driver sdhci_dove_driver = {
.driver = {
.name = "sdhci-dove",
.owner = THIS_MODULE,
.pm = SDHCI_PLTFM_PMOPS,
+ .of_match_table = of_match_ptr(sdhci_dove_of_match_table),
},
.probe = sdhci_dove_probe,
.remove = __devexit_p(sdhci_dove_remove),
diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c
index f8eb1fb..ae5fcbf 100644
--- a/drivers/mmc/host/sdhci-of-esdhc.c
+++ b/drivers/mmc/host/sdhci-of-esdhc.c
@@ -21,6 +21,32 @@
#include "sdhci-pltfm.h"
#include "sdhci-esdhc.h"
+#define VENDOR_V_22 0x12
+static u32 esdhc_readl(struct sdhci_host *host, int reg)
+{
+ u32 ret;
+
+ ret = in_be32(host->ioaddr + reg);
+ /*
+ * The bit of ADMA flag in eSDHC is not compatible with standard
+ * SDHC register, so set fake flag SDHCI_CAN_DO_ADMA2 when ADMA is
+ * supported by eSDHC.
+ * And for many FSL eSDHC controller, the reset value of field
+ * SDHCI_CAN_DO_ADMA1 is one, but some of them can't support ADMA,
+ * only these vendor version is greater than 2.2/0x12 support ADMA.
+ * For FSL eSDHC, must aligned 4-byte, so use 0xFC to read the
+ * the verdor version number, oxFE is SDHCI_HOST_VERSION.
+ */
+ if ((reg == SDHCI_CAPABILITIES) && (ret & SDHCI_CAN_DO_ADMA1)) {
+ u32 tmp = in_be32(host->ioaddr + SDHCI_SLOT_INT_STATUS);
+ tmp = (tmp & SDHCI_VENDOR_VER_MASK) >> SDHCI_VENDOR_VER_SHIFT;
+ if (tmp > VENDOR_V_22)
+ ret |= SDHCI_CAN_DO_ADMA2;
+ }
+
+ return ret;
+}
+
static u16 esdhc_readw(struct sdhci_host *host, int reg)
{
u16 ret;
@@ -144,7 +170,7 @@ static void esdhc_of_resume(struct sdhci_host *host)
#endif
static struct sdhci_ops sdhci_esdhc_ops = {
- .read_l = sdhci_be32bs_readl,
+ .read_l = esdhc_readl,
.read_w = esdhc_readw,
.read_b = esdhc_readb,
.write_l = sdhci_be32bs_writel,
@@ -161,9 +187,13 @@ static struct sdhci_ops sdhci_esdhc_ops = {
};
static struct sdhci_pltfm_data sdhci_esdhc_pdata = {
- /* card detection could be handled via GPIO */
+ /*
+ * card detection could be handled via GPIO
+ * eSDHC cannot support End Attribute in NOP ADMA descriptor
+ */
.quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_BROKEN_CARD_DETECTION
- | SDHCI_QUIRK_NO_CARD_NO_RESET,
+ | SDHCI_QUIRK_NO_CARD_NO_RESET
+ | SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
.ops = &sdhci_esdhc_ops,
};
diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c
index 9722d43..4bb74b0 100644
--- a/drivers/mmc/host/sdhci-pci.c
+++ b/drivers/mmc/host/sdhci-pci.c
@@ -1476,24 +1476,7 @@ static struct pci_driver sdhci_driver = {
},
};
-/*****************************************************************************\
- * *
- * Driver init/exit *
- * *
-\*****************************************************************************/
-
-static int __init sdhci_drv_init(void)
-{
- return pci_register_driver(&sdhci_driver);
-}
-
-static void __exit sdhci_drv_exit(void)
-{
- pci_unregister_driver(&sdhci_driver);
-}
-
-module_init(sdhci_drv_init);
-module_exit(sdhci_drv_exit);
+module_pci_driver(sdhci_driver);
MODULE_AUTHOR("Pierre Ossman <pierre@ossman.eu>");
MODULE_DESCRIPTION("Secure Digital Host Controller Interface PCI driver");
diff --git a/drivers/mmc/host/sdhci-pltfm.c b/drivers/mmc/host/sdhci-pltfm.c
index d9a4ef4..65551a9 100644
--- a/drivers/mmc/host/sdhci-pltfm.c
+++ b/drivers/mmc/host/sdhci-pltfm.c
@@ -75,6 +75,9 @@ void sdhci_get_of_property(struct platform_device *pdev)
if (sdhci_of_wp_inverted(np))
host->quirks |= SDHCI_QUIRK_INVERTED_WRITE_PROTECT;
+ if (of_get_property(np, "broken-cd", NULL))
+ host->quirks |= SDHCI_QUIRK_BROKEN_CARD_DETECTION;
+
if (of_device_is_compatible(np, "fsl,p2020-rev1-esdhc"))
host->quirks |= SDHCI_QUIRK_BROKEN_DMA;
diff --git a/drivers/mmc/host/sdhci-pxav2.c b/drivers/mmc/host/sdhci-pxav2.c
index b6ee885..8e63a9c 100644
--- a/drivers/mmc/host/sdhci-pxav2.c
+++ b/drivers/mmc/host/sdhci-pxav2.c
@@ -197,7 +197,7 @@ static int __devinit sdhci_pxav2_probe(struct platform_device *pdev)
goto err_clk_get;
}
pltfm_host->clk = clk;
- clk_enable(clk);
+ clk_prepare_enable(clk);
host->quirks = SDHCI_QUIRK_BROKEN_ADMA
| SDHCI_QUIRK_BROKEN_TIMEOUT_VAL
@@ -239,7 +239,7 @@ static int __devinit sdhci_pxav2_probe(struct platform_device *pdev)
return 0;
err_add_host:
- clk_disable(clk);
+ clk_disable_unprepare(clk);
clk_put(clk);
err_clk_get:
sdhci_pltfm_free(pdev);
@@ -255,7 +255,7 @@ static int __devexit sdhci_pxav2_remove(struct platform_device *pdev)
sdhci_remove_host(host, 1);
- clk_disable(pltfm_host->clk);
+ clk_disable_unprepare(pltfm_host->clk);
clk_put(pltfm_host->clk);
sdhci_pltfm_free(pdev);
kfree(pxa);
diff --git a/drivers/mmc/host/sdhci-pxav3.c b/drivers/mmc/host/sdhci-pxav3.c
index 07fe383..e918a2b 100644
--- a/drivers/mmc/host/sdhci-pxav3.c
+++ b/drivers/mmc/host/sdhci-pxav3.c
@@ -24,12 +24,14 @@
#include <linux/gpio.h>
#include <linux/mmc/card.h>
#include <linux/mmc/host.h>
+#include <linux/mmc/slot-gpio.h>
#include <linux/platform_data/pxa_sdhci.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
+#include <linux/of_gpio.h>
#include "sdhci.h"
#include "sdhci-pltfm.h"
@@ -182,6 +184,7 @@ static struct sdhci_pxa_platdata *pxav3_get_mmc_pdata(struct device *dev)
struct device_node *np = dev->of_node;
u32 bus_width;
u32 clk_delay_cycles;
+ enum of_gpio_flags gpio_flags;
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata)
@@ -198,6 +201,10 @@ static struct sdhci_pxa_platdata *pxav3_get_mmc_pdata(struct device *dev)
if (clk_delay_cycles > 0)
pdata->clk_delay_cycles = clk_delay_cycles;
+ pdata->ext_cd_gpio = of_get_named_gpio_flags(np, "cd-gpios", 0, &gpio_flags);
+ if (gpio_flags != OF_GPIO_ACTIVE_LOW)
+ pdata->host_caps2 |= MMC_CAP2_CD_ACTIVE_HIGH;
+
return pdata;
}
#else
@@ -231,14 +238,14 @@ static int __devinit sdhci_pxav3_probe(struct platform_device *pdev)
pltfm_host = sdhci_priv(host);
pltfm_host->priv = pxa;
- clk = clk_get(dev, "PXA-SDHCLK");
+ clk = clk_get(dev, NULL);
if (IS_ERR(clk)) {
dev_err(dev, "failed to get io clock\n");
ret = PTR_ERR(clk);
goto err_clk_get;
}
pltfm_host->clk = clk;
- clk_enable(clk);
+ clk_prepare_enable(clk);
host->quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL
| SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC
@@ -266,12 +273,25 @@ static int __devinit sdhci_pxav3_probe(struct platform_device *pdev)
host->quirks |= pdata->quirks;
if (pdata->host_caps)
host->mmc->caps |= pdata->host_caps;
+ if (pdata->host_caps2)
+ host->mmc->caps2 |= pdata->host_caps2;
if (pdata->pm_caps)
host->mmc->pm_caps |= pdata->pm_caps;
+
+ if (gpio_is_valid(pdata->ext_cd_gpio)) {
+ ret = mmc_gpio_request_cd(host->mmc, pdata->ext_cd_gpio);
+ if (ret) {
+ dev_err(mmc_dev(host->mmc),
+ "failed to allocate card detect gpio\n");
+ goto err_cd_req;
+ }
+ }
}
host->ops = &pxav3_sdhci_ops;
+ sdhci_get_of_property(pdev);
+
ret = sdhci_add_host(host);
if (ret) {
dev_err(&pdev->dev, "failed to add host\n");
@@ -283,8 +303,10 @@ static int __devinit sdhci_pxav3_probe(struct platform_device *pdev)
return 0;
err_add_host:
- clk_disable(clk);
+ clk_disable_unprepare(clk);
clk_put(clk);
+ mmc_gpio_free_cd(host->mmc);
+err_cd_req:
err_clk_get:
sdhci_pltfm_free(pdev);
kfree(pxa);
@@ -296,11 +318,16 @@ static int __devexit sdhci_pxav3_remove(struct platform_device *pdev)
struct sdhci_host *host = platform_get_drvdata(pdev);
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_pxa *pxa = pltfm_host->priv;
+ struct sdhci_pxa_platdata *pdata = pdev->dev.platform_data;
sdhci_remove_host(host, 1);
- clk_disable(pltfm_host->clk);
+ clk_disable_unprepare(pltfm_host->clk);
clk_put(pltfm_host->clk);
+
+ if (gpio_is_valid(pdata->ext_cd_gpio))
+ mmc_gpio_free_cd(host->mmc);
+
sdhci_pltfm_free(pdev);
kfree(pxa);
diff --git a/drivers/mmc/host/sdhci-s3c.c b/drivers/mmc/host/sdhci-s3c.c
index a50c205..2903949 100644
--- a/drivers/mmc/host/sdhci-s3c.c
+++ b/drivers/mmc/host/sdhci-s3c.c
@@ -34,6 +34,9 @@
#define MAX_BUS_CLK (4)
+/* Number of gpio's used is max data bus width + command and clock lines */
+#define NUM_GPIOS(x) (x + 2)
+
/**
* struct sdhci_s3c - S3C SDHCI instance
* @host: The SDHCI host created
@@ -41,6 +44,7 @@
* @ioarea: The resource created when we claimed the IO area.
* @pdata: The platform data for this controller.
* @cur_clk: The index of the current bus clock.
+ * @gpios: List of gpio numbers parsed from device tree.
* @clk_io: The clock for the internal bus interface.
* @clk_bus: The clocks that are available for the SD/MMC bus clock.
*/
@@ -52,6 +56,7 @@ struct sdhci_s3c {
unsigned int cur_clk;
int ext_cd_irq;
int ext_cd_gpio;
+ int *gpios;
struct clk *clk_io;
struct clk *clk_bus[MAX_BUS_CLK];
@@ -166,7 +171,7 @@ static unsigned int sdhci_s3c_consider_clock(struct sdhci_s3c *ourhost,
dev_dbg(&ourhost->pdev->dev, "clk %d: rate %ld, want %d, got %ld\n",
src, rate, wanted, rate / div);
- return (wanted - (rate / div));
+ return wanted - (rate / div);
}
/**
@@ -203,10 +208,12 @@ static void sdhci_s3c_set_clock(struct sdhci_host *host, unsigned int clock)
best_src, clock, best);
/* select the new clock source */
-
if (ourhost->cur_clk != best_src) {
struct clk *clk = ourhost->clk_bus[best_src];
+ clk_enable(clk);
+ clk_disable(ourhost->clk_bus[ourhost->cur_clk]);
+
/* turn clock off to card before changing clock source */
writew(0, host->ioaddr + SDHCI_CLOCK_CONTROL);
@@ -288,6 +295,7 @@ static unsigned int sdhci_cmu_get_min_clock(struct sdhci_host *host)
static void sdhci_cmu_set_clock(struct sdhci_host *host, unsigned int clock)
{
struct sdhci_s3c *ourhost = to_s3c(host);
+ struct device *dev = &ourhost->pdev->dev;
unsigned long timeout;
u16 clk = 0;
@@ -309,8 +317,8 @@ static void sdhci_cmu_set_clock(struct sdhci_host *host, unsigned int clock)
while (!((clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL))
& SDHCI_CLOCK_INT_STABLE)) {
if (timeout == 0) {
- printk(KERN_ERR "%s: Internal clock never "
- "stabilised.\n", mmc_hostname(host->mmc));
+ dev_err(dev, "%s: Internal clock never stabilised.\n",
+ mmc_hostname(host->mmc));
return;
}
timeout--;
@@ -404,7 +412,9 @@ static void sdhci_s3c_setup_card_detect_gpio(struct sdhci_s3c *sc)
if (sc->ext_cd_irq &&
request_threaded_irq(sc->ext_cd_irq, NULL,
sdhci_s3c_gpio_card_detect_thread,
- IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+ IRQF_TRIGGER_RISING |
+ IRQF_TRIGGER_FALLING |
+ IRQF_ONESHOT,
dev_name(dev), sc) == 0) {
int status = gpio_get_value(sc->ext_cd_gpio);
if (pdata->ext_cd_gpio_invert)
@@ -419,9 +429,121 @@ static void sdhci_s3c_setup_card_detect_gpio(struct sdhci_s3c *sc)
}
}
+#ifdef CONFIG_OF
+static int __devinit sdhci_s3c_parse_dt(struct device *dev,
+ struct sdhci_host *host, struct s3c_sdhci_platdata *pdata)
+{
+ struct device_node *node = dev->of_node;
+ struct sdhci_s3c *ourhost = to_s3c(host);
+ u32 max_width;
+ int gpio, cnt, ret;
+
+ /* if the bus-width property is not specified, assume width as 1 */
+ if (of_property_read_u32(node, "bus-width", &max_width))
+ max_width = 1;
+ pdata->max_width = max_width;
+
+ ourhost->gpios = devm_kzalloc(dev, NUM_GPIOS(pdata->max_width) *
+ sizeof(int), GFP_KERNEL);
+ if (!ourhost->gpios)
+ return -ENOMEM;
+
+ /* get the card detection method */
+ if (of_get_property(node, "broken-cd", 0)) {
+ pdata->cd_type = S3C_SDHCI_CD_NONE;
+ goto setup_bus;
+ }
+
+ if (of_get_property(node, "non-removable", 0)) {
+ pdata->cd_type = S3C_SDHCI_CD_PERMANENT;
+ goto setup_bus;
+ }
+
+ gpio = of_get_named_gpio(node, "cd-gpios", 0);
+ if (gpio_is_valid(gpio)) {
+ pdata->cd_type = S3C_SDHCI_CD_GPIO;
+ goto found_cd;
+ } else if (gpio != -ENOENT) {
+ dev_err(dev, "invalid card detect gpio specified\n");
+ return -EINVAL;
+ }
+
+ gpio = of_get_named_gpio(node, "samsung,cd-pinmux-gpio", 0);
+ if (gpio_is_valid(gpio)) {
+ pdata->cd_type = S3C_SDHCI_CD_INTERNAL;
+ goto found_cd;
+ } else if (gpio != -ENOENT) {
+ dev_err(dev, "invalid card detect gpio specified\n");
+ return -EINVAL;
+ }
+
+ dev_info(dev, "assuming no card detect line available\n");
+ pdata->cd_type = S3C_SDHCI_CD_NONE;
+
+ found_cd:
+ if (pdata->cd_type == S3C_SDHCI_CD_GPIO) {
+ pdata->ext_cd_gpio = gpio;
+ ourhost->ext_cd_gpio = -1;
+ if (of_get_property(node, "cd-inverted", NULL))
+ pdata->ext_cd_gpio_invert = 1;
+ } else if (pdata->cd_type == S3C_SDHCI_CD_INTERNAL) {
+ ret = gpio_request(gpio, "sdhci-cd");
+ if (ret) {
+ dev_err(dev, "card detect gpio request failed\n");
+ return -EINVAL;
+ }
+ ourhost->ext_cd_gpio = gpio;
+ }
+
+ setup_bus:
+ /* get the gpios for command, clock and data lines */
+ for (cnt = 0; cnt < NUM_GPIOS(pdata->max_width); cnt++) {
+ gpio = of_get_gpio(node, cnt);
+ if (!gpio_is_valid(gpio)) {
+ dev_err(dev, "invalid gpio[%d]\n", cnt);
+ goto err_free_dt_cd_gpio;
+ }
+ ourhost->gpios[cnt] = gpio;
+ }
+
+ for (cnt = 0; cnt < NUM_GPIOS(pdata->max_width); cnt++) {
+ ret = gpio_request(ourhost->gpios[cnt], "sdhci-gpio");
+ if (ret) {
+ dev_err(dev, "gpio[%d] request failed\n", cnt);
+ goto err_free_dt_gpios;
+ }
+ }
+
+ return 0;
+
+ err_free_dt_gpios:
+ while (--cnt >= 0)
+ gpio_free(ourhost->gpios[cnt]);
+ err_free_dt_cd_gpio:
+ if (pdata->cd_type == S3C_SDHCI_CD_INTERNAL)
+ gpio_free(ourhost->ext_cd_gpio);
+ return -EINVAL;
+}
+#else
+static int __devinit sdhci_s3c_parse_dt(struct device *dev,
+ struct sdhci_host *host, struct s3c_sdhci_platdata *pdata)
+{
+ return -EINVAL;
+}
+#endif
+
+static const struct of_device_id sdhci_s3c_dt_match[];
+
static inline struct sdhci_s3c_drv_data *sdhci_s3c_get_driver_data(
struct platform_device *pdev)
{
+#ifdef CONFIG_OF
+ if (pdev->dev.of_node) {
+ const struct of_device_id *match;
+ match = of_match_node(sdhci_s3c_dt_match, pdev->dev.of_node);
+ return (struct sdhci_s3c_drv_data *)match->data;
+ }
+#endif
return (struct sdhci_s3c_drv_data *)
platform_get_device_id(pdev)->driver_data;
}
@@ -436,7 +558,7 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev)
struct resource *res;
int ret, irq, ptr, clks;
- if (!pdev->dev.platform_data) {
+ if (!pdev->dev.platform_data && !pdev->dev.of_node) {
dev_err(dev, "no device data specified\n");
return -ENOENT;
}
@@ -452,21 +574,28 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev)
dev_err(dev, "sdhci_alloc_host() failed\n");
return PTR_ERR(host);
}
+ sc = sdhci_priv(host);
pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata) {
ret = -ENOMEM;
- goto err_io_clk;
+ goto err_pdata;
+ }
+
+ if (pdev->dev.of_node) {
+ ret = sdhci_s3c_parse_dt(&pdev->dev, host, pdata);
+ if (ret)
+ goto err_pdata;
+ } else {
+ memcpy(pdata, pdev->dev.platform_data, sizeof(*pdata));
+ sc->ext_cd_gpio = -1; /* invalid gpio number */
}
- memcpy(pdata, pdev->dev.platform_data, sizeof(*pdata));
drv_data = sdhci_s3c_get_driver_data(pdev);
- sc = sdhci_priv(host);
sc->host = host;
sc->pdev = pdev;
sc->pdata = pdata;
- sc->ext_cd_gpio = -1; /* invalid gpio number */
platform_set_drvdata(pdev, host);
@@ -486,9 +615,8 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev)
snprintf(name, 14, "mmc_busclk.%d", ptr);
clk = clk_get(dev, name);
- if (IS_ERR(clk)) {
+ if (IS_ERR(clk))
continue;
- }
clks++;
sc->clk_bus[ptr] = clk;
@@ -499,8 +627,6 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev)
*/
sc->cur_clk = ptr;
- clk_enable(clk);
-
dev_info(dev, "clock source %d: %s (%ld Hz)\n",
ptr, name, clk_get_rate(clk));
}
@@ -511,6 +637,10 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev)
goto err_no_busclks;
}
+#ifndef CONFIG_PM_RUNTIME
+ clk_enable(sc->clk_bus[sc->cur_clk]);
+#endif
+
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
host->ioaddr = devm_request_and_ioremap(&pdev->dev, res);
if (!host->ioaddr) {
@@ -616,12 +746,17 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev)
gpio_is_valid(pdata->ext_cd_gpio))
sdhci_s3c_setup_card_detect_gpio(sc);
+#ifdef CONFIG_PM_RUNTIME
+ clk_disable(sc->clk_io);
+#endif
return 0;
err_req_regs:
+#ifndef CONFIG_PM_RUNTIME
+ clk_disable(sc->clk_bus[sc->cur_clk]);
+#endif
for (ptr = 0; ptr < MAX_BUS_CLK; ptr++) {
if (sc->clk_bus[ptr]) {
- clk_disable(sc->clk_bus[ptr]);
clk_put(sc->clk_bus[ptr]);
}
}
@@ -631,6 +766,12 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev)
clk_put(sc->clk_io);
err_io_clk:
+ for (ptr = 0; ptr < NUM_GPIOS(sc->pdata->max_width); ptr++)
+ gpio_free(sc->gpios[ptr]);
+ if (pdata->cd_type == S3C_SDHCI_CD_INTERNAL)
+ gpio_free(sc->ext_cd_gpio);
+
+ err_pdata:
sdhci_free_host(host);
return ret;
@@ -638,9 +779,9 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev)
static int __devexit sdhci_s3c_remove(struct platform_device *pdev)
{
- struct s3c_sdhci_platdata *pdata = pdev->dev.platform_data;
struct sdhci_host *host = platform_get_drvdata(pdev);
struct sdhci_s3c *sc = sdhci_priv(host);
+ struct s3c_sdhci_platdata *pdata = sc->pdata;
int ptr;
if (pdata->cd_type == S3C_SDHCI_CD_EXTERNAL && pdata->ext_cd_cleanup)
@@ -652,19 +793,30 @@ static int __devexit sdhci_s3c_remove(struct platform_device *pdev)
if (gpio_is_valid(sc->ext_cd_gpio))
gpio_free(sc->ext_cd_gpio);
+#ifdef CONFIG_PM_RUNTIME
+ clk_enable(sc->clk_io);
+#endif
sdhci_remove_host(host, 1);
+ pm_runtime_dont_use_autosuspend(&pdev->dev);
pm_runtime_disable(&pdev->dev);
- for (ptr = 0; ptr < 3; ptr++) {
+#ifndef CONFIG_PM_RUNTIME
+ clk_disable(sc->clk_bus[sc->cur_clk]);
+#endif
+ for (ptr = 0; ptr < MAX_BUS_CLK; ptr++) {
if (sc->clk_bus[ptr]) {
- clk_disable(sc->clk_bus[ptr]);
clk_put(sc->clk_bus[ptr]);
}
}
clk_disable(sc->clk_io);
clk_put(sc->clk_io);
+ if (pdev->dev.of_node) {
+ for (ptr = 0; ptr < NUM_GPIOS(sc->pdata->max_width); ptr++)
+ gpio_free(sc->gpios[ptr]);
+ }
+
sdhci_free_host(host);
platform_set_drvdata(pdev, NULL);
@@ -691,15 +843,28 @@ static int sdhci_s3c_resume(struct device *dev)
static int sdhci_s3c_runtime_suspend(struct device *dev)
{
struct sdhci_host *host = dev_get_drvdata(dev);
+ struct sdhci_s3c *ourhost = to_s3c(host);
+ struct clk *busclk = ourhost->clk_io;
+ int ret;
+
+ ret = sdhci_runtime_suspend_host(host);
- return sdhci_runtime_suspend_host(host);
+ clk_disable(ourhost->clk_bus[ourhost->cur_clk]);
+ clk_disable(busclk);
+ return ret;
}
static int sdhci_s3c_runtime_resume(struct device *dev)
{
struct sdhci_host *host = dev_get_drvdata(dev);
+ struct sdhci_s3c *ourhost = to_s3c(host);
+ struct clk *busclk = ourhost->clk_io;
+ int ret;
- return sdhci_runtime_resume_host(host);
+ clk_enable(busclk);
+ clk_enable(ourhost->clk_bus[ourhost->cur_clk]);
+ ret = sdhci_runtime_resume_host(host);
+ return ret;
}
#endif
@@ -737,6 +902,16 @@ static struct platform_device_id sdhci_s3c_driver_ids[] = {
};
MODULE_DEVICE_TABLE(platform, sdhci_s3c_driver_ids);
+#ifdef CONFIG_OF
+static const struct of_device_id sdhci_s3c_dt_match[] = {
+ { .compatible = "samsung,s3c6410-sdhci", },
+ { .compatible = "samsung,exynos4210-sdhci",
+ .data = (void *)EXYNOS4_SDHCI_DRV_DATA },
+ {},
+};
+MODULE_DEVICE_TABLE(of, sdhci_s3c_dt_match);
+#endif
+
static struct platform_driver sdhci_s3c_driver = {
.probe = sdhci_s3c_probe,
.remove = __devexit_p(sdhci_s3c_remove),
@@ -744,6 +919,7 @@ static struct platform_driver sdhci_s3c_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "s3c-sdhci",
+ .of_match_table = of_match_ptr(sdhci_s3c_dt_match),
.pm = SDHCI_S3C_PMOPS,
},
};
diff --git a/drivers/mmc/host/sdhci-spear.c b/drivers/mmc/host/sdhci-spear.c
index 423da81..6be89c0 100644
--- a/drivers/mmc/host/sdhci-spear.c
+++ b/drivers/mmc/host/sdhci-spear.c
@@ -20,6 +20,8 @@
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
#include <linux/platform_device.h>
#include <linux/pm.h>
#include <linux/slab.h>
@@ -68,8 +70,42 @@ static irqreturn_t sdhci_gpio_irq(int irq, void *dev_id)
return IRQ_HANDLED;
}
+#ifdef CONFIG_OF
+static struct sdhci_plat_data * __devinit
+sdhci_probe_config_dt(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct sdhci_plat_data *pdata = NULL;
+ int cd_gpio;
+
+ cd_gpio = of_get_named_gpio(np, "cd-gpios", 0);
+ if (!gpio_is_valid(cd_gpio))
+ cd_gpio = -1;
+
+ /* If pdata is required */
+ if (cd_gpio != -1) {
+ pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata) {
+ dev_err(&pdev->dev, "DT: kzalloc failed\n");
+ return ERR_PTR(-ENOMEM);
+ }
+ }
+
+ pdata->card_int_gpio = cd_gpio;
+
+ return pdata;
+}
+#else
+static struct sdhci_plat_data * __devinit
+sdhci_probe_config_dt(struct platform_device *pdev)
+{
+ return ERR_PTR(-ENOSYS);
+}
+#endif
+
static int __devinit sdhci_probe(struct platform_device *pdev)
{
+ struct device_node *np = pdev->dev.of_node;
struct sdhci_host *host;
struct resource *iomem;
struct spear_sdhci *sdhci;
@@ -104,14 +140,22 @@ static int __devinit sdhci_probe(struct platform_device *pdev)
goto err;
}
- ret = clk_enable(sdhci->clk);
+ ret = clk_prepare_enable(sdhci->clk);
if (ret) {
dev_dbg(&pdev->dev, "Error enabling clock\n");
goto put_clk;
}
- /* overwrite platform_data */
- sdhci->data = dev_get_platdata(&pdev->dev);
+ if (np) {
+ sdhci->data = sdhci_probe_config_dt(pdev);
+ if (IS_ERR(sdhci->data)) {
+ dev_err(&pdev->dev, "DT: Failed to get pdata\n");
+ return -ENODEV;
+ }
+ } else {
+ sdhci->data = dev_get_platdata(&pdev->dev);
+ }
+
pdev->dev.platform_data = sdhci;
if (pdev->dev.parent)
@@ -216,7 +260,7 @@ set_drvdata:
free_host:
sdhci_free_host(host);
disable_clk:
- clk_disable(sdhci->clk);
+ clk_disable_unprepare(sdhci->clk);
put_clk:
clk_put(sdhci->clk);
err:
@@ -238,7 +282,7 @@ static int __devexit sdhci_remove(struct platform_device *pdev)
sdhci_remove_host(host, dead);
sdhci_free_host(host);
- clk_disable(sdhci->clk);
+ clk_disable_unprepare(sdhci->clk);
clk_put(sdhci->clk);
return 0;
@@ -253,7 +297,7 @@ static int sdhci_suspend(struct device *dev)
ret = sdhci_suspend_host(host);
if (!ret)
- clk_disable(sdhci->clk);
+ clk_disable_unprepare(sdhci->clk);
return ret;
}
@@ -264,7 +308,7 @@ static int sdhci_resume(struct device *dev)
struct spear_sdhci *sdhci = dev_get_platdata(dev);
int ret;
- ret = clk_enable(sdhci->clk);
+ ret = clk_prepare_enable(sdhci->clk);
if (ret) {
dev_dbg(dev, "Resume: Error enabling clock\n");
return ret;
@@ -276,11 +320,20 @@ static int sdhci_resume(struct device *dev)
static SIMPLE_DEV_PM_OPS(sdhci_pm_ops, sdhci_suspend, sdhci_resume);
+#ifdef CONFIG_OF
+static const struct of_device_id sdhci_spear_id_table[] = {
+ { .compatible = "st,spear300-sdhci" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, sdhci_spear_id_table);
+#endif
+
static struct platform_driver sdhci_driver = {
.driver = {
.name = "sdhci",
.owner = THIS_MODULE,
.pm = &sdhci_pm_ops,
+ .of_match_table = of_match_ptr(sdhci_spear_id_table),
},
.probe = sdhci_probe,
.remove = __devexit_p(sdhci_remove),
diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c
index d43e746..f9eb916 100644
--- a/drivers/mmc/host/sdhci-tegra.c
+++ b/drivers/mmc/host/sdhci-tegra.c
@@ -27,7 +27,6 @@
#include <asm/gpio.h>
-#include <mach/gpio-tegra.h>
#include <linux/platform_data/mmc-sdhci-tegra.h>
#include "sdhci-pltfm.h"
@@ -257,10 +256,9 @@ static int __devinit sdhci_tegra_probe(struct platform_device *pdev)
int rc;
match = of_match_device(sdhci_tegra_dt_match, &pdev->dev);
- if (match)
- soc_data = match->data;
- else
- soc_data = &soc_data_tegra20;
+ if (!match)
+ return -EINVAL;
+ soc_data = match->data;
host = sdhci_pltfm_init(pdev, soc_data->pdata);
if (IS_ERR(host))
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 9a11dc3..7922adb 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -28,6 +28,7 @@
#include <linux/mmc/mmc.h>
#include <linux/mmc/host.h>
#include <linux/mmc/card.h>
+#include <linux/mmc/slot-gpio.h>
#include "sdhci.h"
@@ -1293,6 +1294,13 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
present = sdhci_readl(host, SDHCI_PRESENT_STATE) &
SDHCI_CARD_PRESENT;
+ /* If we're using a cd-gpio, testing the presence bit might fail. */
+ if (!present) {
+ int ret = mmc_gpio_get_cd(host->mmc);
+ if (ret > 0)
+ present = true;
+ }
+
if (!present || host->flags & SDHCI_DEVICE_DEAD) {
host->mrq->cmd->error = -ENOMEDIUM;
tasklet_schedule(&host->finish_tasklet);
@@ -1597,57 +1605,65 @@ static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable)
spin_unlock_irqrestore(&host->lock, flags);
}
-static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,
- struct mmc_ios *ios)
+static int sdhci_do_3_3v_signal_voltage_switch(struct sdhci_host *host,
+ u16 ctrl)
{
- u8 pwr;
- u16 clk, ctrl;
- u32 present_state;
+ int ret;
- /*
- * Signal Voltage Switching is only applicable for Host Controllers
- * v3.00 and above.
- */
- if (host->version < SDHCI_SPEC_300)
- return 0;
+ /* Set 1.8V Signal Enable in the Host Control2 register to 0 */
+ ctrl &= ~SDHCI_CTRL_VDD_180;
+ sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
- /*
- * 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.
- */
+ if (host->vqmmc) {
+ ret = regulator_set_voltage(host->vqmmc, 3300000, 3300000);
+ if (ret) {
+ pr_warning("%s: Switching to 3.3V signalling voltage "
+ " failed\n", mmc_hostname(host->mmc));
+ return -EIO;
+ }
+ }
+ /* 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 (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);
+ if (!(ctrl & SDHCI_CTRL_VDD_180))
+ return 0;
- /* Wait for 5ms */
- usleep_range(5000, 5500);
+ pr_warning("%s: 3.3V regulator output did not became stable\n",
+ mmc_hostname(host->mmc));
- /* 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 {
- pr_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);
+ return -EIO;
+}
- /* 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
- */
+static int sdhci_do_1_8v_signal_voltage_switch(struct sdhci_host *host,
+ u16 ctrl)
+{
+ u8 pwr;
+ u16 clk;
+ u32 present_state;
+ int ret;
+
+ /* 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
+ */
+ if (host->vqmmc)
+ ret = regulator_set_voltage(host->vqmmc,
+ 1800000, 1800000);
+ else
+ ret = 0;
+
+ if (!ret) {
ctrl |= SDHCI_CTRL_VDD_180;
sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
@@ -1656,7 +1672,7 @@ static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,
ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
if (ctrl & SDHCI_CTRL_VDD_180) {
- /* Provide SDCLK again and wait for 1ms*/
+ /* 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);
@@ -1673,29 +1689,55 @@ static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,
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);
- if (host->vmmc)
- regulator_disable(host->vmmc);
+ /*
+ * 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);
+ if (host->vmmc)
+ regulator_disable(host->vmmc);
- /* Wait for 1ms as per the spec */
- usleep_range(1000, 1500);
- pwr |= SDHCI_POWER_ON;
- sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL);
- if (host->vmmc)
- regulator_enable(host->vmmc);
+ /* Wait for 1ms as per the spec */
+ usleep_range(1000, 1500);
+ pwr |= SDHCI_POWER_ON;
+ sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL);
+ if (host->vmmc)
+ regulator_enable(host->vmmc);
- pr_info(DRIVER_NAME ": Switching to 1.8V signalling "
- "voltage failed, retrying with S18R set to 0\n");
- return -EAGAIN;
- } else
+ pr_warning("%s: Switching to 1.8V signalling voltage failed, "
+ "retrying with S18R set to 0\n", mmc_hostname(host->mmc));
+
+ return -EAGAIN;
+}
+
+static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,
+ struct mmc_ios *ios)
+{
+ u16 ctrl;
+
+ /*
+ * 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)
+ return sdhci_do_3_3v_signal_voltage_switch(host, ctrl);
+ else if (!(ctrl & SDHCI_CTRL_VDD_180) &&
+ (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_180))
+ return sdhci_do_1_8v_signal_voltage_switch(host, ctrl);
+ else
/* No signal voltage switch required */
return 0;
}
@@ -2802,6 +2844,18 @@ int sdhci_add_host(struct sdhci_host *host)
!(host->mmc->caps & MMC_CAP_NONREMOVABLE))
mmc->caps |= MMC_CAP_NEEDS_POLL;
+ /* If vqmmc regulator and no 1.8V signalling, then there's no UHS */
+ host->vqmmc = regulator_get(mmc_dev(mmc), "vqmmc");
+ if (IS_ERR(host->vqmmc)) {
+ pr_info("%s: no vqmmc regulator found\n", mmc_hostname(mmc));
+ host->vqmmc = NULL;
+ }
+ else if (regulator_is_supported_voltage(host->vqmmc, 1800000, 1800000))
+ regulator_enable(host->vqmmc);
+ else
+ caps[1] &= ~(SDHCI_SUPPORT_SDR104 | SDHCI_SUPPORT_SDR50 |
+ SDHCI_SUPPORT_DDR50);
+
/* Any UHS-I mode in caps implies SDR12 and SDR25 support. */
if (caps[1] & (SDHCI_SUPPORT_SDR104 | SDHCI_SUPPORT_SDR50 |
SDHCI_SUPPORT_DDR50))
@@ -2832,15 +2886,6 @@ int sdhci_add_host(struct sdhci_host *host)
if (caps[1] & SDHCI_DRIVER_TYPE_D)
mmc->caps |= MMC_CAP_DRIVER_TYPE_D;
- /*
- * If Power Off Notify capability is enabled by the host,
- * set notify to short power off notify timeout value.
- */
- if (mmc->caps2 & MMC_CAP2_POWEROFF_NOTIFY)
- mmc->power_notify_type = MMC_HOST_PW_NOTIFY_SHORT;
- else
- mmc->power_notify_type = MMC_HOST_PW_NOTIFY_NONE;
-
/* Initial value for re-tuning timer count */
host->tuning_count = (caps[1] & SDHCI_RETUNING_TIMER_COUNT_MASK) >>
SDHCI_RETUNING_TIMER_COUNT_SHIFT;
@@ -2862,7 +2907,8 @@ int sdhci_add_host(struct sdhci_host *host)
if (IS_ERR(host->vmmc)) {
pr_info("%s: no vmmc regulator found\n", mmc_hostname(mmc));
host->vmmc = NULL;
- }
+ } else
+ regulator_enable(host->vmmc);
#ifdef CONFIG_REGULATOR
if (host->vmmc) {
@@ -3119,8 +3165,15 @@ void sdhci_remove_host(struct sdhci_host *host, int dead)
tasklet_kill(&host->card_tasklet);
tasklet_kill(&host->finish_tasklet);
- if (host->vmmc)
+ if (host->vmmc) {
+ regulator_disable(host->vmmc);
regulator_put(host->vmmc);
+ }
+
+ if (host->vqmmc) {
+ regulator_disable(host->vqmmc);
+ regulator_put(host->vqmmc);
+ }
kfree(host->adma_desc);
kfree(host->align_buffer);
diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c
index 5d81427..11d2bc3 100644
--- a/drivers/mmc/host/sh_mmcif.c
+++ b/drivers/mmc/host/sh_mmcif.c
@@ -1213,7 +1213,9 @@ static irqreturn_t sh_mmcif_intr(int irq, void *dev_id)
sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~INT_BUFRE);
sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MBUFRE);
} else if (state & INT_DTRANE) {
- sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~INT_DTRANE);
+ sh_mmcif_writel(host->addr, MMCIF_CE_INT,
+ ~(INT_CMD12DRE | INT_CMD12RBE |
+ INT_CMD12CRE | INT_DTRANE));
sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MDTRANE);
} else if (state & INT_CMD12RBE) {
sh_mmcif_writel(host->addr, MMCIF_CE_INT,
@@ -1229,6 +1231,10 @@ static irqreturn_t sh_mmcif_intr(int irq, void *dev_id)
host->sd_error = true;
dev_dbg(&host->pd->dev, "int err state = %08x\n", state);
}
+ if (host->state == STATE_IDLE) {
+ dev_info(&host->pd->dev, "Spurious IRQ status 0x%x", state);
+ return IRQ_HANDLED;
+ }
if (state & ~(INT_CMD12RBE | INT_CMD12CRE)) {
if (!host->dma_active)
return IRQ_WAKE_THREAD;
diff --git a/drivers/mmc/host/via-sdmmc.c b/drivers/mmc/host/via-sdmmc.c
index 4b83c43..f18bece 100644
--- a/drivers/mmc/host/via-sdmmc.c
+++ b/drivers/mmc/host/via-sdmmc.c
@@ -1337,21 +1337,7 @@ static struct pci_driver via_sd_driver = {
.resume = via_sd_resume,
};
-static int __init via_sd_drv_init(void)
-{
- pr_info(DRV_NAME ": VIA SD/MMC Card Reader driver "
- "(C) 2008 VIA Technologies, Inc.\n");
-
- return pci_register_driver(&via_sd_driver);
-}
-
-static void __exit via_sd_drv_exit(void)
-{
- pci_unregister_driver(&via_sd_driver);
-}
-
-module_init(via_sd_drv_init);
-module_exit(via_sd_drv_exit);
+module_pci_driver(via_sd_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("VIA Technologies Inc.");
diff --git a/drivers/mmc/host/vub300.c b/drivers/mmc/host/vub300.c
index 58eab9a..d5655a6 100644
--- a/drivers/mmc/host/vub300.c
+++ b/drivers/mmc/host/vub300.c
@@ -2358,9 +2358,9 @@ error5:
* which is contained at the end of struct mmc
*/
error4:
- usb_free_urb(command_out_urb);
-error1:
usb_free_urb(command_res_urb);
+error1:
+ usb_free_urb(command_out_urb);
error0:
return retval;
}
diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig
index 27143e0..73fcbbe 100644
--- a/drivers/mtd/Kconfig
+++ b/drivers/mtd/Kconfig
@@ -148,6 +148,13 @@ config MTD_BCM63XX_PARTS
This provides partions parsing for BCM63xx devices with CFE
bootloaders.
+config MTD_BCM47XX_PARTS
+ tristate "BCM47XX partitioning support"
+ depends on BCM47XX
+ help
+ This provides partitions parser for devices based on BCM47xx
+ boards.
+
comment "User Modules And Translation Layers"
config MTD_CHAR
diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile
index f901354..18a38e5 100644
--- a/drivers/mtd/Makefile
+++ b/drivers/mtd/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_MTD_CMDLINE_PARTS) += cmdlinepart.o
obj-$(CONFIG_MTD_AFS_PARTS) += afs.o
obj-$(CONFIG_MTD_AR7_PARTS) += ar7part.o
obj-$(CONFIG_MTD_BCM63XX_PARTS) += bcm63xxpart.o
+obj-$(CONFIG_MTD_BCM47XX_PARTS) += bcm47xxpart.o
# 'Users' - code which presents functionality to userspace.
obj-$(CONFIG_MTD_CHAR) += mtdchar.o
diff --git a/drivers/mtd/bcm47xxpart.c b/drivers/mtd/bcm47xxpart.c
new file mode 100644
index 0000000..e06d782
--- /dev/null
+++ b/drivers/mtd/bcm47xxpart.c
@@ -0,0 +1,202 @@
+/*
+ * BCM47XX MTD partitioning
+ *
+ * Copyright © 2012 Rafał Miłecki <zajec5@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <asm/mach-bcm47xx/nvram.h>
+
+/* 10 parts were found on sflash on Netgear WNDR4500 */
+#define BCM47XXPART_MAX_PARTS 12
+
+/*
+ * Amount of bytes we read when analyzing each block of flash memory.
+ * Set it big enough to allow detecting partition and reading important data.
+ */
+#define BCM47XXPART_BYTES_TO_READ 0x404
+
+/* Magics */
+#define BOARD_DATA_MAGIC 0x5246504D /* MPFR */
+#define POT_MAGIC1 0x54544f50 /* POTT */
+#define POT_MAGIC2 0x504f /* OP */
+#define ML_MAGIC1 0x39685a42
+#define ML_MAGIC2 0x26594131
+#define TRX_MAGIC 0x30524448
+
+struct trx_header {
+ uint32_t magic;
+ uint32_t length;
+ uint32_t crc32;
+ uint16_t flags;
+ uint16_t version;
+ uint32_t offset[3];
+} __packed;
+
+static void bcm47xxpart_add_part(struct mtd_partition *part, char *name,
+ u64 offset, uint32_t mask_flags)
+{
+ part->name = name;
+ part->offset = offset;
+ part->mask_flags = mask_flags;
+}
+
+static int bcm47xxpart_parse(struct mtd_info *master,
+ struct mtd_partition **pparts,
+ struct mtd_part_parser_data *data)
+{
+ struct mtd_partition *parts;
+ uint8_t i, curr_part = 0;
+ uint32_t *buf;
+ size_t bytes_read;
+ uint32_t offset;
+ uint32_t blocksize = 0x10000;
+ struct trx_header *trx;
+
+ /* Alloc */
+ parts = kzalloc(sizeof(struct mtd_partition) * BCM47XXPART_MAX_PARTS,
+ GFP_KERNEL);
+ buf = kzalloc(BCM47XXPART_BYTES_TO_READ, GFP_KERNEL);
+
+ /* Parse block by block looking for magics */
+ for (offset = 0; offset <= master->size - blocksize;
+ offset += blocksize) {
+ /* Nothing more in higher memory */
+ if (offset >= 0x2000000)
+ break;
+
+ if (curr_part > BCM47XXPART_MAX_PARTS) {
+ pr_warn("Reached maximum number of partitions, scanning stopped!\n");
+ break;
+ }
+
+ /* Read beginning of the block */
+ if (mtd_read(master, offset, BCM47XXPART_BYTES_TO_READ,
+ &bytes_read, (uint8_t *)buf) < 0) {
+ pr_err("mtd_read error while parsing (offset: 0x%X)!\n",
+ offset);
+ continue;
+ }
+
+ /* CFE has small NVRAM at 0x400 */
+ if (buf[0x400 / 4] == NVRAM_HEADER) {
+ bcm47xxpart_add_part(&parts[curr_part++], "boot",
+ offset, MTD_WRITEABLE);
+ continue;
+ }
+
+ /* Standard NVRAM */
+ if (buf[0x000 / 4] == NVRAM_HEADER) {
+ bcm47xxpart_add_part(&parts[curr_part++], "nvram",
+ offset, 0);
+ continue;
+ }
+
+ /*
+ * board_data starts with board_id which differs across boards,
+ * but we can use 'MPFR' (hopefully) magic at 0x100
+ */
+ if (buf[0x100 / 4] == BOARD_DATA_MAGIC) {
+ bcm47xxpart_add_part(&parts[curr_part++], "board_data",
+ offset, MTD_WRITEABLE);
+ continue;
+ }
+
+ /* POT(TOP) */
+ if (buf[0x000 / 4] == POT_MAGIC1 &&
+ (buf[0x004 / 4] & 0xFFFF) == POT_MAGIC2) {
+ bcm47xxpart_add_part(&parts[curr_part++], "POT", offset,
+ MTD_WRITEABLE);
+ continue;
+ }
+
+ /* ML */
+ if (buf[0x010 / 4] == ML_MAGIC1 &&
+ buf[0x014 / 4] == ML_MAGIC2) {
+ bcm47xxpart_add_part(&parts[curr_part++], "ML", offset,
+ MTD_WRITEABLE);
+ continue;
+ }
+
+ /* TRX */
+ if (buf[0x000 / 4] == TRX_MAGIC) {
+ trx = (struct trx_header *)buf;
+
+ i = 0;
+ /* We have LZMA loader if offset[2] points to sth */
+ if (trx->offset[2]) {
+ bcm47xxpart_add_part(&parts[curr_part++],
+ "loader",
+ offset + trx->offset[i],
+ 0);
+ i++;
+ }
+
+ bcm47xxpart_add_part(&parts[curr_part++], "linux",
+ offset + trx->offset[i], 0);
+ i++;
+
+ /*
+ * Pure rootfs size is known and can be calculated as:
+ * trx->length - trx->offset[i]. We don't fill it as
+ * we want to have jffs2 (overlay) in the same mtd.
+ */
+ bcm47xxpart_add_part(&parts[curr_part++], "rootfs",
+ offset + trx->offset[i], 0);
+ i++;
+
+ /*
+ * We have whole TRX scanned, skip to the next part. Use
+ * roundown (not roundup), as the loop will increase
+ * offset in next step.
+ */
+ offset = rounddown(offset + trx->length, blocksize);
+ continue;
+ }
+ }
+ kfree(buf);
+
+ /*
+ * Assume that partitions end at the beginning of the one they are
+ * followed by.
+ */
+ for (i = 0; i < curr_part - 1; i++)
+ parts[i].size = parts[i + 1].offset - parts[i].offset;
+ if (curr_part > 0)
+ parts[curr_part - 1].size =
+ master->size - parts[curr_part - 1].offset;
+
+ *pparts = parts;
+ return curr_part;
+};
+
+static struct mtd_part_parser bcm47xxpart_mtd_parser = {
+ .owner = THIS_MODULE,
+ .parse_fn = bcm47xxpart_parse,
+ .name = "bcm47xxpart",
+};
+
+static int __init bcm47xxpart_init(void)
+{
+ return register_mtd_parser(&bcm47xxpart_mtd_parser);
+}
+
+static void __exit bcm47xxpart_exit(void)
+{
+ deregister_mtd_parser(&bcm47xxpart_mtd_parser);
+}
+
+module_init(bcm47xxpart_init);
+module_exit(bcm47xxpart_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("MTD partitioning for BCM47XX flash memories");
diff --git a/drivers/mtd/chips/Kconfig b/drivers/mtd/chips/Kconfig
index b1e3c26..e469b01 100644
--- a/drivers/mtd/chips/Kconfig
+++ b/drivers/mtd/chips/Kconfig
@@ -43,9 +43,6 @@ choice
prompt "Flash cmd/query data swapping"
depends on MTD_CFI_ADV_OPTIONS
default MTD_CFI_NOSWAP
-
-config MTD_CFI_NOSWAP
- bool "NO"
---help---
This option defines the way in which the CPU attempts to arrange
data bits when writing the 'magic' commands to the chips. Saying
@@ -55,12 +52,8 @@ config MTD_CFI_NOSWAP
Specific arrangements are possible with the BIG_ENDIAN_BYTE and
LITTLE_ENDIAN_BYTE, if the bytes are reversed.
- If you have a LART, on which the data (and address) lines were
- connected in a fashion which ensured that the nets were as short
- as possible, resulting in a bit-shuffling which seems utterly
- random to the untrained eye, you need the LART_ENDIAN_BYTE option.
-
- Yes, there really exists something sicker than PDP-endian :)
+config MTD_CFI_NOSWAP
+ bool "NO"
config MTD_CFI_BE_BYTE_SWAP
bool "BIG_ENDIAN_BYTE"
diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c
index dbbd2ed..7751443 100644
--- a/drivers/mtd/chips/cfi_cmdset_0001.c
+++ b/drivers/mtd/chips/cfi_cmdset_0001.c
@@ -2043,7 +2043,7 @@ static int __xipram do_xxlock_oneblock(struct map_info *map, struct flchip *chip
{
struct cfi_private *cfi = map->fldrv_priv;
struct cfi_pri_intelext *extp = cfi->cmdset_priv;
- int udelay;
+ int mdelay;
int ret;
adr += chip->start;
@@ -2072,9 +2072,17 @@ static int __xipram do_xxlock_oneblock(struct map_info *map, struct flchip *chip
* If Instant Individual Block Locking supported then no need
* to delay.
*/
- udelay = (!extp || !(extp->FeatureSupport & (1 << 5))) ? 1000000/HZ : 0;
+ /*
+ * Unlocking may take up to 1.4 seconds on some Intel flashes. So
+ * lets use a max of 1.5 seconds (1500ms) as timeout.
+ *
+ * See "Clear Block Lock-Bits Time" on page 40 in
+ * "3 Volt Intel StrataFlash Memory" 28F128J3,28F640J3,28F320J3 manual
+ * from February 2003
+ */
+ mdelay = (!extp || !(extp->FeatureSupport & (1 << 5))) ? 1500 : 0;
- ret = WAIT_TIMEOUT(map, chip, adr, udelay, udelay * 100);
+ ret = WAIT_TIMEOUT(map, chip, adr, mdelay, mdelay * 1000);
if (ret) {
map_write(map, CMD(0x70), adr);
chip->state = FL_STATUS;
diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c
index 22d0493..5ff5c4a 100644
--- a/drivers/mtd/chips/cfi_cmdset_0002.c
+++ b/drivers/mtd/chips/cfi_cmdset_0002.c
@@ -431,6 +431,68 @@ static void cfi_fixup_major_minor(struct cfi_private *cfi,
}
}
+static int is_m29ew(struct cfi_private *cfi)
+{
+ if (cfi->mfr == CFI_MFR_INTEL &&
+ ((cfi->device_type == CFI_DEVICETYPE_X8 && (cfi->id & 0xff) == 0x7e) ||
+ (cfi->device_type == CFI_DEVICETYPE_X16 && cfi->id == 0x227e)))
+ return 1;
+ return 0;
+}
+
+/*
+ * From TN-13-07: Patching the Linux Kernel and U-Boot for M29 Flash, page 20:
+ * Some revisions of the M29EW suffer from erase suspend hang ups. In
+ * particular, it can occur when the sequence
+ * Erase Confirm -> Suspend -> Program -> Resume
+ * causes a lockup due to internal timing issues. The consequence is that the
+ * erase cannot be resumed without inserting a dummy command after programming
+ * and prior to resuming. [...] The work-around is to issue a dummy write cycle
+ * that writes an F0 command code before the RESUME command.
+ */
+static void cfi_fixup_m29ew_erase_suspend(struct map_info *map,
+ unsigned long adr)
+{
+ struct cfi_private *cfi = map->fldrv_priv;
+ /* before resume, insert a dummy 0xF0 cycle for Micron M29EW devices */
+ if (is_m29ew(cfi))
+ map_write(map, CMD(0xF0), adr);
+}
+
+/*
+ * From TN-13-07: Patching the Linux Kernel and U-Boot for M29 Flash, page 22:
+ *
+ * Some revisions of the M29EW (for example, A1 and A2 step revisions)
+ * are affected by a problem that could cause a hang up when an ERASE SUSPEND
+ * command is issued after an ERASE RESUME operation without waiting for a
+ * minimum delay. The result is that once the ERASE seems to be completed
+ * (no bits are toggling), the contents of the Flash memory block on which
+ * the erase was ongoing could be inconsistent with the expected values
+ * (typically, the array value is stuck to the 0xC0, 0xC4, 0x80, or 0x84
+ * values), causing a consequent failure of the ERASE operation.
+ * The occurrence of this issue could be high, especially when file system
+ * operations on the Flash are intensive. As a result, it is recommended
+ * that a patch be applied. Intensive file system operations can cause many
+ * calls to the garbage routine to free Flash space (also by erasing physical
+ * Flash blocks) and as a result, many consecutive SUSPEND and RESUME
+ * commands can occur. The problem disappears when a delay is inserted after
+ * the RESUME command by using the udelay() function available in Linux.
+ * The DELAY value must be tuned based on the customer's platform.
+ * The maximum value that fixes the problem in all cases is 500us.
+ * But, in our experience, a delay of 30 µs to 50 µs is sufficient
+ * in most cases.
+ * We have chosen 500µs because this latency is acceptable.
+ */
+static void cfi_fixup_m29ew_delay_after_resume(struct cfi_private *cfi)
+{
+ /*
+ * Resolving the Delay After Resume Issue see Micron TN-13-07
+ * Worst case delay must be 500µs but 30-50µs should be ok as well
+ */
+ if (is_m29ew(cfi))
+ cfi_udelay(500);
+}
+
struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary)
{
struct cfi_private *cfi = map->fldrv_priv;
@@ -776,7 +838,10 @@ static void put_chip(struct map_info *map, struct flchip *chip, unsigned long ad
switch(chip->oldstate) {
case FL_ERASING:
+ cfi_fixup_m29ew_erase_suspend(map,
+ chip->in_progress_block_addr);
map_write(map, cfi->sector_erase_cmd, chip->in_progress_block_addr);
+ cfi_fixup_m29ew_delay_after_resume(cfi);
chip->oldstate = FL_READY;
chip->state = FL_ERASING;
break;
@@ -916,6 +981,8 @@ static void __xipram xip_udelay(struct map_info *map, struct flchip *chip,
/* Disallow XIP again */
local_irq_disable();
+ /* Correct Erase Suspend Hangups for M29EW */
+ cfi_fixup_m29ew_erase_suspend(map, adr);
/* Resume the write or erase operation */
map_write(map, cfi->sector_erase_cmd, adr);
chip->state = oldstate;
diff --git a/drivers/mtd/cmdlinepart.c b/drivers/mtd/cmdlinepart.c
index 4558e0f..aed1b8a 100644
--- a/drivers/mtd/cmdlinepart.c
+++ b/drivers/mtd/cmdlinepart.c
@@ -39,11 +39,10 @@
#include <linux/kernel.h>
#include <linux/slab.h>
-
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
-#include <linux/bootmem.h>
#include <linux/module.h>
+#include <linux/err.h>
/* error message prefix */
#define ERRP "mtd: "
@@ -72,7 +71,7 @@ static struct cmdline_mtd_partition *partitions;
/* the command line passed to mtdpart_setup() */
static char *cmdline;
-static int cmdline_parsed = 0;
+static int cmdline_parsed;
/*
* Parse one partition definition for an MTD. Since there can be many
@@ -83,15 +82,14 @@ static int cmdline_parsed = 0;
* syntax has been verified ok.
*/
static struct mtd_partition * newpart(char *s,
- char **retptr,
- int *num_parts,
- int this_part,
- unsigned char **extra_mem_ptr,
- int extra_mem_size)
+ char **retptr,
+ int *num_parts,
+ int this_part,
+ unsigned char **extra_mem_ptr,
+ int extra_mem_size)
{
struct mtd_partition *parts;
- unsigned long size;
- unsigned long offset = OFFSET_CONTINUOUS;
+ unsigned long size, offset = OFFSET_CONTINUOUS;
char *name;
int name_len;
unsigned char *extra_mem;
@@ -99,124 +97,106 @@ static struct mtd_partition * newpart(char *s,
unsigned int mask_flags;
/* fetch the partition size */
- if (*s == '-')
- { /* assign all remaining space to this partition */
+ if (*s == '-') {
+ /* assign all remaining space to this partition */
size = SIZE_REMAINING;
s++;
- }
- else
- {
+ } else {
size = memparse(s, &s);
- if (size < PAGE_SIZE)
- {
+ if (size < PAGE_SIZE) {
printk(KERN_ERR ERRP "partition size too small (%lx)\n", size);
- return NULL;
+ return ERR_PTR(-EINVAL);
}
}
/* fetch partition name and flags */
mask_flags = 0; /* this is going to be a regular partition */
delim = 0;
- /* check for offset */
- if (*s == '@')
- {
- s++;
- offset = memparse(s, &s);
- }
- /* now look for name */
+
+ /* check for offset */
+ if (*s == '@') {
+ s++;
+ offset = memparse(s, &s);
+ }
+
+ /* now look for name */
if (*s == '(')
- {
delim = ')';
- }
- if (delim)
- {
+ if (delim) {
char *p;
- name = ++s;
+ name = ++s;
p = strchr(name, delim);
- if (!p)
- {
+ if (!p) {
printk(KERN_ERR ERRP "no closing %c found in partition name\n", delim);
- return NULL;
+ return ERR_PTR(-EINVAL);
}
name_len = p - name;
s = p + 1;
- }
- else
- {
- name = NULL;
+ } else {
+ name = NULL;
name_len = 13; /* Partition_000 */
}
/* record name length for memory allocation later */
extra_mem_size += name_len + 1;
- /* test for options */
- if (strncmp(s, "ro", 2) == 0)
- {
+ /* test for options */
+ if (strncmp(s, "ro", 2) == 0) {
mask_flags |= MTD_WRITEABLE;
s += 2;
- }
+ }
- /* if lk is found do NOT unlock the MTD partition*/
- if (strncmp(s, "lk", 2) == 0)
- {
+ /* if lk is found do NOT unlock the MTD partition*/
+ if (strncmp(s, "lk", 2) == 0) {
mask_flags |= MTD_POWERUP_LOCK;
s += 2;
- }
+ }
/* test if more partitions are following */
- if (*s == ',')
- {
- if (size == SIZE_REMAINING)
- {
+ if (*s == ',') {
+ if (size == SIZE_REMAINING) {
printk(KERN_ERR ERRP "no partitions allowed after a fill-up partition\n");
- return NULL;
+ return ERR_PTR(-EINVAL);
}
/* more partitions follow, parse them */
parts = newpart(s + 1, &s, num_parts, this_part + 1,
&extra_mem, extra_mem_size);
- if (!parts)
- return NULL;
- }
- else
- { /* this is the last partition: allocate space for all */
+ if (IS_ERR(parts))
+ return parts;
+ } else {
+ /* this is the last partition: allocate space for all */
int alloc_size;
*num_parts = this_part + 1;
alloc_size = *num_parts * sizeof(struct mtd_partition) +
extra_mem_size;
+
parts = kzalloc(alloc_size, GFP_KERNEL);
if (!parts)
- return NULL;
+ return ERR_PTR(-ENOMEM);
extra_mem = (unsigned char *)(parts + *num_parts);
}
+
/* enter this partition (offset will be calculated later if it is zero at this point) */
parts[this_part].size = size;
parts[this_part].offset = offset;
parts[this_part].mask_flags = mask_flags;
if (name)
- {
strlcpy(extra_mem, name, name_len + 1);
- }
else
- {
sprintf(extra_mem, "Partition_%03d", this_part);
- }
parts[this_part].name = extra_mem;
extra_mem += name_len + 1;
dbg(("partition %d: name <%s>, offset %llx, size %llx, mask flags %x\n",
- this_part,
- parts[this_part].name,
- parts[this_part].offset,
- parts[this_part].size,
- parts[this_part].mask_flags));
+ this_part, parts[this_part].name, parts[this_part].offset,
+ parts[this_part].size, parts[this_part].mask_flags));
/* return (updated) pointer to extra_mem memory */
if (extra_mem_ptr)
- *extra_mem_ptr = extra_mem;
+ *extra_mem_ptr = extra_mem;
/* return (updated) pointer command line string */
*retptr = s;
@@ -236,16 +216,16 @@ static int mtdpart_setup_real(char *s)
{
struct cmdline_mtd_partition *this_mtd;
struct mtd_partition *parts;
- int mtd_id_len;
- int num_parts;
+ int mtd_id_len, num_parts;
char *p, *mtd_id;
- mtd_id = s;
+ mtd_id = s;
+
/* fetch <mtd-id> */
- if (!(p = strchr(s, ':')))
- {
+ p = strchr(s, ':');
+ if (!p) {
printk(KERN_ERR ERRP "no mtd-id\n");
- return 0;
+ return -EINVAL;
}
mtd_id_len = p - mtd_id;
@@ -262,8 +242,7 @@ static int mtdpart_setup_real(char *s)
(unsigned char**)&this_mtd, /* out: extra mem */
mtd_id_len + 1 + sizeof(*this_mtd) +
sizeof(void*)-1 /*alignment*/);
- if(!parts)
- {
+ if (IS_ERR(parts)) {
/*
* An error occurred. We're either:
* a) out of memory, or
@@ -271,12 +250,12 @@ static int mtdpart_setup_real(char *s)
* Either way, this mtd is hosed and we're
* unlikely to succeed in parsing any more
*/
- return 0;
+ return PTR_ERR(parts);
}
/* align this_mtd */
this_mtd = (struct cmdline_mtd_partition *)
- ALIGN((unsigned long)this_mtd, sizeof(void*));
+ ALIGN((unsigned long)this_mtd, sizeof(void *));
/* enter results */
this_mtd->parts = parts;
this_mtd->num_parts = num_parts;
@@ -296,14 +275,14 @@ static int mtdpart_setup_real(char *s)
break;
/* does another spec follow? */
- if (*s != ';')
- {
+ if (*s != ';') {
printk(KERN_ERR ERRP "bad character after partition (%c)\n", *s);
- return 0;
+ return -EINVAL;
}
s++;
}
- return 1;
+
+ return 0;
}
/*
@@ -318,44 +297,58 @@ static int parse_cmdline_partitions(struct mtd_info *master,
struct mtd_part_parser_data *data)
{
unsigned long offset;
- int i;
+ int i, err;
struct cmdline_mtd_partition *part;
const char *mtd_id = master->name;
/* parse command line */
- if (!cmdline_parsed)
- mtdpart_setup_real(cmdline);
+ if (!cmdline_parsed) {
+ err = mtdpart_setup_real(cmdline);
+ if (err)
+ return err;
+ }
- for(part = partitions; part; part = part->next)
- {
- if ((!mtd_id) || (!strcmp(part->mtd_id, mtd_id)))
- {
- for(i = 0, offset = 0; i < part->num_parts; i++)
- {
+ for (part = partitions; part; part = part->next) {
+ if ((!mtd_id) || (!strcmp(part->mtd_id, mtd_id))) {
+ for (i = 0, offset = 0; i < part->num_parts; i++) {
if (part->parts[i].offset == OFFSET_CONTINUOUS)
- part->parts[i].offset = offset;
+ part->parts[i].offset = offset;
else
- offset = part->parts[i].offset;
+ offset = part->parts[i].offset;
+
if (part->parts[i].size == SIZE_REMAINING)
- part->parts[i].size = master->size - offset;
- if (offset + part->parts[i].size > master->size)
- {
+ part->parts[i].size = master->size - offset;
+
+ if (part->parts[i].size == 0) {
+ printk(KERN_WARNING ERRP
+ "%s: skipping zero sized partition\n",
+ part->mtd_id);
+ part->num_parts--;
+ memmove(&part->parts[i],
+ &part->parts[i + 1],
+ sizeof(*part->parts) * (part->num_parts - i));
+ continue;
+ }
+
+ if (offset + part->parts[i].size > master->size) {
printk(KERN_WARNING ERRP
"%s: partitioning exceeds flash size, truncating\n",
part->mtd_id);
part->parts[i].size = master->size - offset;
- part->num_parts = i;
}
offset += part->parts[i].size;
}
+
*pparts = kmemdup(part->parts,
sizeof(*part->parts) * part->num_parts,
GFP_KERNEL);
if (!*pparts)
return -ENOMEM;
+
return part->num_parts;
}
}
+
return 0;
}
diff --git a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig
index 4cdb2af..27f80cd 100644
--- a/drivers/mtd/devices/Kconfig
+++ b/drivers/mtd/devices/Kconfig
@@ -97,7 +97,7 @@ config MTD_M25P80
doesn't support the JEDEC ID instruction.
config M25PXX_USE_FAST_READ
- bool "Use FAST_READ OPCode allowing SPI CLK <= 50MHz"
+ bool "Use FAST_READ OPCode allowing SPI CLK >= 50MHz"
depends on MTD_M25P80
default y
help
@@ -120,6 +120,14 @@ config MTD_SST25L
Set up your spi devices with the right board-specific platform data,
if you want to specify device partitioning.
+config MTD_BCM47XXSFLASH
+ tristate "R/O support for serial flash on BCMA bus"
+ depends on BCMA_SFLASH
+ help
+ BCMA bus can have various flash memories attached, they are
+ registered by bcma as platform devices. This enables driver for
+ serial flash memories (only read-only mode is implemented).
+
config MTD_SLRAM
tristate "Uncached system RAM"
help
diff --git a/drivers/mtd/devices/Makefile b/drivers/mtd/devices/Makefile
index a4dd1d8..395733a 100644
--- a/drivers/mtd/devices/Makefile
+++ b/drivers/mtd/devices/Makefile
@@ -19,5 +19,6 @@ obj-$(CONFIG_MTD_DATAFLASH) += mtd_dataflash.o
obj-$(CONFIG_MTD_M25P80) += m25p80.o
obj-$(CONFIG_MTD_SPEAR_SMI) += spear_smi.o
obj-$(CONFIG_MTD_SST25L) += sst25l.o
+obj-$(CONFIG_MTD_BCM47XXSFLASH) += bcm47xxsflash.o
CFLAGS_docg3.o += -I$(src) \ No newline at end of file
diff --git a/drivers/mtd/devices/bcm47xxsflash.c b/drivers/mtd/devices/bcm47xxsflash.c
new file mode 100644
index 0000000..2dc5a6f
--- /dev/null
+++ b/drivers/mtd/devices/bcm47xxsflash.c
@@ -0,0 +1,105 @@
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/mtd/mtd.h>
+#include <linux/platform_device.h>
+#include <linux/bcma/bcma.h>
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Serial flash driver for BCMA bus");
+
+static const char *probes[] = { "bcm47xxpart", NULL };
+
+static int bcm47xxsflash_read(struct mtd_info *mtd, loff_t from, size_t len,
+ size_t *retlen, u_char *buf)
+{
+ struct bcma_sflash *sflash = mtd->priv;
+
+ /* Check address range */
+ if ((from + len) > mtd->size)
+ return -EINVAL;
+
+ memcpy_fromio(buf, (void __iomem *)KSEG0ADDR(sflash->window + from),
+ len);
+
+ return len;
+}
+
+static void bcm47xxsflash_fill_mtd(struct bcma_sflash *sflash,
+ struct mtd_info *mtd)
+{
+ mtd->priv = sflash;
+ mtd->name = "bcm47xxsflash";
+ mtd->owner = THIS_MODULE;
+ mtd->type = MTD_ROM;
+ mtd->size = sflash->size;
+ mtd->_read = bcm47xxsflash_read;
+
+ /* TODO: implement writing support and verify/change following code */
+ mtd->flags = MTD_CAP_ROM;
+ mtd->writebufsize = mtd->writesize = 1;
+}
+
+static int bcm47xxsflash_probe(struct platform_device *pdev)
+{
+ struct bcma_sflash *sflash = dev_get_platdata(&pdev->dev);
+ int err;
+
+ sflash->mtd = kzalloc(sizeof(struct mtd_info), GFP_KERNEL);
+ if (!sflash->mtd) {
+ err = -ENOMEM;
+ goto out;
+ }
+ bcm47xxsflash_fill_mtd(sflash, sflash->mtd);
+
+ err = mtd_device_parse_register(sflash->mtd, probes, NULL, NULL, 0);
+ if (err) {
+ pr_err("Failed to register MTD device: %d\n", err);
+ goto err_dev_reg;
+ }
+
+ return 0;
+
+err_dev_reg:
+ kfree(sflash->mtd);
+out:
+ return err;
+}
+
+static int __devexit bcm47xxsflash_remove(struct platform_device *pdev)
+{
+ struct bcma_sflash *sflash = dev_get_platdata(&pdev->dev);
+
+ mtd_device_unregister(sflash->mtd);
+ kfree(sflash->mtd);
+
+ return 0;
+}
+
+static struct platform_driver bcma_sflash_driver = {
+ .remove = __devexit_p(bcm47xxsflash_remove),
+ .driver = {
+ .name = "bcma_sflash",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init bcm47xxsflash_init(void)
+{
+ int err;
+
+ err = platform_driver_probe(&bcma_sflash_driver, bcm47xxsflash_probe);
+ if (err)
+ pr_err("Failed to register BCMA serial flash driver: %d\n",
+ err);
+
+ return err;
+}
+
+static void __exit bcm47xxsflash_exit(void)
+{
+ platform_driver_unregister(&bcma_sflash_driver);
+}
+
+module_init(bcm47xxsflash_init);
+module_exit(bcm47xxsflash_exit);
diff --git a/drivers/mtd/devices/doc2001plus.c b/drivers/mtd/devices/doc2001plus.c
index 04eb2e4..4f2220a 100644
--- a/drivers/mtd/devices/doc2001plus.c
+++ b/drivers/mtd/devices/doc2001plus.c
@@ -659,23 +659,15 @@ static int doc_read(struct mtd_info *mtd, loff_t from, size_t len,
#ifdef ECC_DEBUG
printk("%s(%d): Millennium Plus ECC error (from=0x%x:\n",
__FILE__, __LINE__, (int)from);
- printk(" syndrome= %02x:%02x:%02x:%02x:%02x:"
- "%02x\n",
- syndrome[0], syndrome[1], syndrome[2],
- syndrome[3], syndrome[4], syndrome[5]);
- printk(" eccbuf= %02x:%02x:%02x:%02x:%02x:"
- "%02x\n",
- eccbuf[0], eccbuf[1], eccbuf[2],
- eccbuf[3], eccbuf[4], eccbuf[5]);
+ printk(" syndrome= %*phC\n", 6, syndrome);
+ printk(" eccbuf= %*phC\n", 6, eccbuf);
#endif
ret = -EIO;
}
}
#ifdef PSYCHO_DEBUG
- printk("ECC DATA at %lx: %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n",
- (long)from, eccbuf[0], eccbuf[1], eccbuf[2], eccbuf[3],
- eccbuf[4], eccbuf[5]);
+ printk("ECC DATA at %lx: %*ph\n", (long)from, 6, eccbuf);
#endif
/* disable the ECC engine */
WriteDOC(DOC_ECC_DIS, docptr , Mplus_ECCConf);
diff --git a/drivers/mtd/devices/docg3.c b/drivers/mtd/devices/docg3.c
index f70854d..d34d83b 100644
--- a/drivers/mtd/devices/docg3.c
+++ b/drivers/mtd/devices/docg3.c
@@ -919,19 +919,13 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t from,
eccconf1 = doc_register_readb(docg3, DOC_ECCCONF1);
if (nboob >= DOC_LAYOUT_OOB_SIZE) {
- doc_dbg("OOB - INFO: %02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
- oobbuf[0], oobbuf[1], oobbuf[2], oobbuf[3],
- oobbuf[4], oobbuf[5], oobbuf[6]);
+ doc_dbg("OOB - INFO: %*phC\n", 7, oobbuf);
doc_dbg("OOB - HAMMING: %02x\n", oobbuf[7]);
- doc_dbg("OOB - BCH_ECC: %02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
- oobbuf[8], oobbuf[9], oobbuf[10], oobbuf[11],
- oobbuf[12], oobbuf[13], oobbuf[14]);
+ doc_dbg("OOB - BCH_ECC: %*phC\n", 7, oobbuf + 8);
doc_dbg("OOB - UNUSED: %02x\n", oobbuf[15]);
}
doc_dbg("ECC checks: ECCConf1=%x\n", eccconf1);
- doc_dbg("ECC HW_ECC: %02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
- hwecc[0], hwecc[1], hwecc[2], hwecc[3], hwecc[4],
- hwecc[5], hwecc[6]);
+ doc_dbg("ECC HW_ECC: %*phC\n", 7, hwecc);
ret = -EIO;
if (is_prot_seq_error(docg3))
diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c
index 5d0d68c..03838ba 100644
--- a/drivers/mtd/devices/m25p80.c
+++ b/drivers/mtd/devices/m25p80.c
@@ -633,11 +633,14 @@ static const struct spi_device_id m25p_ids[] = {
{ "at26df161a", INFO(0x1f4601, 0, 64 * 1024, 32, SECT_4K) },
{ "at26df321", INFO(0x1f4700, 0, 64 * 1024, 64, SECT_4K) },
+ { "at45db081d", INFO(0x1f2500, 0, 64 * 1024, 16, SECT_4K) },
+
/* EON -- en25xxx */
{ "en25f32", INFO(0x1c3116, 0, 64 * 1024, 64, SECT_4K) },
{ "en25p32", INFO(0x1c2016, 0, 64 * 1024, 64, 0) },
{ "en25q32b", INFO(0x1c3016, 0, 64 * 1024, 64, 0) },
{ "en25p64", INFO(0x1c2017, 0, 64 * 1024, 128, 0) },
+ { "en25q64", INFO(0x1c3017, 0, 64 * 1024, 128, SECT_4K) },
/* Everspin */
{ "mr25h256", CAT25_INFO( 32 * 1024, 1, 256, 2) },
@@ -646,6 +649,7 @@ static const struct spi_device_id m25p_ids[] = {
{ "160s33b", INFO(0x898911, 0, 64 * 1024, 32, 0) },
{ "320s33b", INFO(0x898912, 0, 64 * 1024, 64, 0) },
{ "640s33b", INFO(0x898913, 0, 64 * 1024, 128, 0) },
+ { "n25q064", INFO(0x20ba17, 0, 64 * 1024, 128, 0) },
/* Macronix */
{ "mx25l2005a", INFO(0xc22012, 0, 64 * 1024, 4, SECT_4K) },
@@ -659,15 +663,15 @@ static const struct spi_device_id m25p_ids[] = {
{ "mx25l25635e", INFO(0xc22019, 0, 64 * 1024, 512, 0) },
{ "mx25l25655e", INFO(0xc22619, 0, 64 * 1024, 512, 0) },
+ /* Micron */
+ { "n25q128", INFO(0x20ba18, 0, 64 * 1024, 256, 0) },
+ { "n25q256a", INFO(0x20ba19, 0, 64 * 1024, 512, SECT_4K) },
+
/* Spansion -- single (large) sector size only, at least
* for the chips listed here (without boot sectors).
*/
- { "s25sl004a", INFO(0x010212, 0, 64 * 1024, 8, 0) },
- { "s25sl008a", INFO(0x010213, 0, 64 * 1024, 16, 0) },
- { "s25sl016a", INFO(0x010214, 0, 64 * 1024, 32, 0) },
- { "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) },
+ { "s25sl032p", INFO(0x010215, 0x4d00, 64 * 1024, 64, 0) },
+ { "s25sl064p", INFO(0x010216, 0x4d00, 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) },
@@ -676,6 +680,11 @@ static const struct spi_device_id m25p_ids[] = {
{ "s25sl12801", INFO(0x012018, 0x0301, 64 * 1024, 256, 0) },
{ "s25fl129p0", INFO(0x012018, 0x4d00, 256 * 1024, 64, 0) },
{ "s25fl129p1", INFO(0x012018, 0x4d01, 64 * 1024, 256, 0) },
+ { "s25sl004a", INFO(0x010212, 0, 64 * 1024, 8, 0) },
+ { "s25sl008a", INFO(0x010213, 0, 64 * 1024, 16, 0) },
+ { "s25sl016a", INFO(0x010214, 0, 64 * 1024, 32, 0) },
+ { "s25sl032a", INFO(0x010215, 0, 64 * 1024, 64, 0) },
+ { "s25sl064a", INFO(0x010216, 0, 64 * 1024, 128, 0) },
{ "s25fl016k", INFO(0xef4015, 0, 64 * 1024, 32, SECT_4K) },
{ "s25fl064k", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K) },
@@ -699,6 +708,7 @@ static const struct spi_device_id m25p_ids[] = {
{ "m25p32", INFO(0x202016, 0, 64 * 1024, 64, 0) },
{ "m25p64", INFO(0x202017, 0, 64 * 1024, 128, 0) },
{ "m25p128", INFO(0x202018, 0, 256 * 1024, 64, 0) },
+ { "n25q032", INFO(0x20ba16, 0, 64 * 1024, 64, 0) },
{ "m25p05-nonjedec", INFO(0, 0, 32 * 1024, 2, 0) },
{ "m25p10-nonjedec", INFO(0, 0, 32 * 1024, 4, 0) },
@@ -714,6 +724,7 @@ static const struct spi_device_id m25p_ids[] = {
{ "m45pe80", INFO(0x204014, 0, 64 * 1024, 16, 0) },
{ "m45pe16", INFO(0x204015, 0, 64 * 1024, 32, 0) },
+ { "m25pe20", INFO(0x208012, 0, 64 * 1024, 4, 0) },
{ "m25pe80", INFO(0x208014, 0, 64 * 1024, 16, 0) },
{ "m25pe16", INFO(0x208015, 0, 64 * 1024, 32, SECT_4K) },
@@ -730,6 +741,7 @@ static const struct spi_device_id m25p_ids[] = {
{ "w25x16", INFO(0xef3015, 0, 64 * 1024, 32, SECT_4K) },
{ "w25x32", INFO(0xef3016, 0, 64 * 1024, 64, SECT_4K) },
{ "w25q32", INFO(0xef4016, 0, 64 * 1024, 64, SECT_4K) },
+ { "w25q32dw", INFO(0xef6016, 0, 64 * 1024, 64, SECT_4K) },
{ "w25x64", INFO(0xef3017, 0, 64 * 1024, 128, SECT_4K) },
{ "w25q64", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K) },
{ "w25q80", INFO(0xef5014, 0, 64 * 1024, 16, SECT_4K) },
diff --git a/drivers/mtd/devices/spear_smi.c b/drivers/mtd/devices/spear_smi.c
index 6796036..dcc3c95 100644
--- a/drivers/mtd/devices/spear_smi.c
+++ b/drivers/mtd/devices/spear_smi.c
@@ -26,6 +26,7 @@
#include <linux/module.h>
#include <linux/param.h>
#include <linux/platform_device.h>
+#include <linux/pm.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
#include <linux/mtd/spear_smi.h>
@@ -240,8 +241,8 @@ static int spear_smi_read_sr(struct spear_smi *dev, u32 bank)
/* copy dev->status (lower 16 bits) in order to release lock */
if (ret > 0)
ret = dev->status & 0xffff;
- else
- ret = -EIO;
+ else if (ret == 0)
+ ret = -ETIMEDOUT;
/* restore the ctrl regs state */
writel(ctrlreg1, dev->io_base + SMI_CR1);
@@ -269,16 +270,19 @@ static int spear_smi_wait_till_ready(struct spear_smi *dev, u32 bank,
finish = jiffies + timeout;
do {
status = spear_smi_read_sr(dev, bank);
- if (status < 0)
- continue; /* try till timeout */
- else if (!(status & SR_WIP))
+ if (status < 0) {
+ if (status == -ETIMEDOUT)
+ continue; /* try till finish */
+ return status;
+ } else if (!(status & SR_WIP)) {
return 0;
+ }
cond_resched();
} while (!time_after_eq(jiffies, finish));
dev_err(&dev->pdev->dev, "smi controller is busy, timeout\n");
- return status;
+ return -EBUSY;
}
/**
@@ -335,6 +339,9 @@ static void spear_smi_hw_init(struct spear_smi *dev)
val = HOLD1 | BANK_EN | DSEL_TIME | (prescale << 8);
mutex_lock(&dev->lock);
+ /* clear all interrupt conditions */
+ writel(0, dev->io_base + SMI_SR);
+
writel(val, dev->io_base + SMI_CR1);
mutex_unlock(&dev->lock);
}
@@ -391,11 +398,11 @@ static int spear_smi_write_enable(struct spear_smi *dev, u32 bank)
writel(ctrlreg1, dev->io_base + SMI_CR1);
writel(0, dev->io_base + SMI_CR2);
- if (ret <= 0) {
+ if (ret == 0) {
ret = -EIO;
dev_err(&dev->pdev->dev,
"smi controller failed on write enable\n");
- } else {
+ } else if (ret > 0) {
/* check whether write mode status is set for required bank */
if (dev->status & (1 << (bank + WM_SHIFT)))
ret = 0;
@@ -462,10 +469,10 @@ static int spear_smi_erase_sector(struct spear_smi *dev,
ret = wait_event_interruptible_timeout(dev->cmd_complete,
dev->status & TFF, SMI_CMD_TIMEOUT);
- if (ret <= 0) {
+ if (ret == 0) {
ret = -EIO;
dev_err(&dev->pdev->dev, "sector erase failed\n");
- } else
+ } else if (ret > 0)
ret = 0; /* success */
/* restore ctrl regs */
@@ -820,7 +827,7 @@ static int spear_smi_setup_banks(struct platform_device *pdev,
if (!flash_info)
return -ENODEV;
- flash = kzalloc(sizeof(*flash), GFP_ATOMIC);
+ flash = devm_kzalloc(&pdev->dev, sizeof(*flash), GFP_ATOMIC);
if (!flash)
return -ENOMEM;
flash->bank = bank;
@@ -831,15 +838,13 @@ static int spear_smi_setup_banks(struct platform_device *pdev,
flash_index = spear_smi_probe_flash(dev, bank);
if (flash_index < 0) {
dev_info(&dev->pdev->dev, "smi-nor%d not found\n", bank);
- ret = flash_index;
- goto err_probe;
+ return flash_index;
}
/* map the memory for nor flash chip */
- flash->base_addr = ioremap(flash_info->mem_base, flash_info->size);
- if (!flash->base_addr) {
- ret = -EIO;
- goto err_probe;
- }
+ flash->base_addr = devm_ioremap(&pdev->dev, flash_info->mem_base,
+ flash_info->size);
+ if (!flash->base_addr)
+ return -EIO;
dev->flash[bank] = flash;
flash->mtd.priv = dev;
@@ -881,17 +886,10 @@ static int spear_smi_setup_banks(struct platform_device *pdev,
count);
if (ret) {
dev_err(&dev->pdev->dev, "Err MTD partition=%d\n", ret);
- goto err_map;
+ return ret;
}
return 0;
-
-err_map:
- iounmap(flash->base_addr);
-
-err_probe:
- kfree(flash);
- return ret;
}
/**
@@ -928,20 +926,13 @@ static int __devinit spear_smi_probe(struct platform_device *pdev)
}
} else {
pdata = dev_get_platdata(&pdev->dev);
- if (pdata < 0) {
+ if (!pdata) {
ret = -ENODEV;
dev_err(&pdev->dev, "no platform data\n");
goto err;
}
}
- smi_base = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!smi_base) {
- ret = -ENODEV;
- dev_err(&pdev->dev, "invalid smi base address\n");
- goto err;
- }
-
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
ret = -ENODEV;
@@ -949,32 +940,26 @@ static int __devinit spear_smi_probe(struct platform_device *pdev)
goto err;
}
- dev = kzalloc(sizeof(*dev), GFP_ATOMIC);
+ dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_ATOMIC);
if (!dev) {
ret = -ENOMEM;
dev_err(&pdev->dev, "mem alloc fail\n");
goto err;
}
- smi_base = request_mem_region(smi_base->start, resource_size(smi_base),
- pdev->name);
- if (!smi_base) {
- ret = -EBUSY;
- dev_err(&pdev->dev, "request mem region fail\n");
- goto err_mem;
- }
+ smi_base = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- dev->io_base = ioremap(smi_base->start, resource_size(smi_base));
+ dev->io_base = devm_request_and_ioremap(&pdev->dev, smi_base);
if (!dev->io_base) {
ret = -EIO;
- dev_err(&pdev->dev, "ioremap fail\n");
- goto err_ioremap;
+ dev_err(&pdev->dev, "devm_request_and_ioremap fail\n");
+ goto err;
}
dev->pdev = pdev;
dev->clk_rate = pdata->clk_rate;
- if (dev->clk_rate < 0 || dev->clk_rate > SMI_MAX_CLOCK_FREQ)
+ if (dev->clk_rate > SMI_MAX_CLOCK_FREQ)
dev->clk_rate = SMI_MAX_CLOCK_FREQ;
dev->num_flashes = pdata->num_flashes;
@@ -984,17 +969,18 @@ static int __devinit spear_smi_probe(struct platform_device *pdev)
dev->num_flashes = MAX_NUM_FLASH_CHIP;
}
- dev->clk = clk_get(&pdev->dev, NULL);
+ dev->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(dev->clk)) {
ret = PTR_ERR(dev->clk);
- goto err_clk;
+ goto err;
}
ret = clk_prepare_enable(dev->clk);
if (ret)
- goto err_clk_prepare_enable;
+ goto err;
- ret = request_irq(irq, spear_smi_int_handler, 0, pdev->name, dev);
+ ret = devm_request_irq(&pdev->dev, irq, spear_smi_int_handler, 0,
+ pdev->name, dev);
if (ret) {
dev_err(&dev->pdev->dev, "SMI IRQ allocation failed\n");
goto err_irq;
@@ -1017,18 +1003,9 @@ static int __devinit spear_smi_probe(struct platform_device *pdev)
return 0;
err_bank_setup:
- free_irq(irq, dev);
platform_set_drvdata(pdev, NULL);
err_irq:
clk_disable_unprepare(dev->clk);
-err_clk_prepare_enable:
- clk_put(dev->clk);
-err_clk:
- iounmap(dev->io_base);
-err_ioremap:
- release_mem_region(smi_base->start, resource_size(smi_base));
-err_mem:
- kfree(dev);
err:
return ret;
}
@@ -1042,11 +1019,8 @@ err:
static int __devexit spear_smi_remove(struct platform_device *pdev)
{
struct spear_smi *dev;
- struct spear_smi_plat_data *pdata;
struct spear_snor_flash *flash;
- struct resource *smi_base;
- int ret;
- int i, irq;
+ int ret, i;
dev = platform_get_drvdata(pdev);
if (!dev) {
@@ -1054,8 +1028,6 @@ static int __devexit spear_smi_remove(struct platform_device *pdev)
return -ENODEV;
}
- pdata = dev_get_platdata(&pdev->dev);
-
/* clean up for all nor flash */
for (i = 0; i < dev->num_flashes; i++) {
flash = dev->flash[i];
@@ -1066,49 +1038,41 @@ static int __devexit spear_smi_remove(struct platform_device *pdev)
ret = mtd_device_unregister(&flash->mtd);
if (ret)
dev_err(&pdev->dev, "error removing mtd\n");
-
- iounmap(flash->base_addr);
- kfree(flash);
}
- irq = platform_get_irq(pdev, 0);
- free_irq(irq, dev);
-
clk_disable_unprepare(dev->clk);
- clk_put(dev->clk);
- iounmap(dev->io_base);
- kfree(dev);
-
- smi_base = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- release_mem_region(smi_base->start, resource_size(smi_base));
platform_set_drvdata(pdev, NULL);
return 0;
}
-int spear_smi_suspend(struct platform_device *pdev, pm_message_t state)
+#ifdef CONFIG_PM
+static int spear_smi_suspend(struct device *dev)
{
- struct spear_smi *dev = platform_get_drvdata(pdev);
+ struct spear_smi *sdev = dev_get_drvdata(dev);
- if (dev && dev->clk)
- clk_disable_unprepare(dev->clk);
+ if (sdev && sdev->clk)
+ clk_disable_unprepare(sdev->clk);
return 0;
}
-int spear_smi_resume(struct platform_device *pdev)
+static int spear_smi_resume(struct device *dev)
{
- struct spear_smi *dev = platform_get_drvdata(pdev);
+ struct spear_smi *sdev = dev_get_drvdata(dev);
int ret = -EPERM;
- if (dev && dev->clk)
- ret = clk_prepare_enable(dev->clk);
+ if (sdev && sdev->clk)
+ ret = clk_prepare_enable(sdev->clk);
if (!ret)
- spear_smi_hw_init(dev);
+ spear_smi_hw_init(sdev);
return ret;
}
+static SIMPLE_DEV_PM_OPS(spear_smi_pm_ops, spear_smi_suspend, spear_smi_resume);
+#endif
+
#ifdef CONFIG_OF
static const struct of_device_id spear_smi_id_table[] = {
{ .compatible = "st,spear600-smi" },
@@ -1123,11 +1087,12 @@ static struct platform_driver spear_smi_driver = {
.bus = &platform_bus_type,
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(spear_smi_id_table),
+#ifdef CONFIG_PM
+ .pm = &spear_smi_pm_ops,
+#endif
},
.probe = spear_smi_probe,
.remove = __devexit_p(spear_smi_remove),
- .suspend = spear_smi_suspend,
- .resume = spear_smi_resume,
};
static int spear_smi_init(void)
diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig
index 5ba2458..2e47c2e 100644
--- a/drivers/mtd/maps/Kconfig
+++ b/drivers/mtd/maps/Kconfig
@@ -373,7 +373,7 @@ config MTD_FORTUNET
have such a board, say 'Y'.
config MTD_AUTCPU12
- tristate "NV-RAM mapping AUTCPU12 board"
+ bool "NV-RAM mapping AUTCPU12 board"
depends on ARCH_AUTCPU12
help
This enables access to the NV-RAM on autronix autcpu12 board.
@@ -443,22 +443,10 @@ config MTD_GPIO_ADDR
config MTD_UCLINUX
bool "Generic uClinux RAM/ROM filesystem support"
- depends on MTD_RAM=y && !MMU
+ depends on MTD_RAM=y && (!MMU || COLDFIRE)
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_MAP_BANK_WIDTH_4
- select MTD_MAP_BANK_WIDTH_1
- select MTD_CFI_I1
- select MTD_CFI_I4
- help
- Map driver for WindRiver PowerQUICC II MPC82xx board. Drives
- all three flash regions on CS0, CS1 and CS6 if they are configured
- correctly by the boot loader.
-
config MTD_DMV182
tristate "Map driver for Dy-4 SVME/DMV-182 board."
depends on DMV182
diff --git a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile
index 68a9a91..deb43e9 100644
--- a/drivers/mtd/maps/Makefile
+++ b/drivers/mtd/maps/Makefile
@@ -47,7 +47,6 @@ obj-$(CONFIG_MTD_SCB2_FLASH) += scb2_flash.o
obj-$(CONFIG_MTD_H720X) += h720x-flash.o
obj-$(CONFIG_MTD_IXP4XX) += ixp4xx.o
obj-$(CONFIG_MTD_IXP2000) += ixp2000.o
-obj-$(CONFIG_MTD_WRSBC8260) += wr_sbc82xx_flash.o
obj-$(CONFIG_MTD_DMV182) += dmv182.o
obj-$(CONFIG_MTD_PLATRAM) += plat-ram.o
obj-$(CONFIG_MTD_INTEL_VR_NOR) += intel_vr_nor.o
diff --git a/drivers/mtd/maps/autcpu12-nvram.c b/drivers/mtd/maps/autcpu12-nvram.c
index e5bfd0e..76fb594 100644
--- a/drivers/mtd/maps/autcpu12-nvram.c
+++ b/drivers/mtd/maps/autcpu12-nvram.c
@@ -15,43 +15,54 @@
* 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/sizes.h>
-#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
-#include <linux/ioport.h>
#include <linux/init.h>
-#include <asm/io.h>
-#include <asm/sizes.h>
-#include <mach/hardware.h>
-#include <mach/autcpu12.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
#include <linux/mtd/mtd.h>
#include <linux/mtd/map.h>
-#include <linux/mtd/partitions.h>
-
-
-static struct mtd_info *sram_mtd;
-struct map_info autcpu12_sram_map = {
- .name = "SRAM",
- .size = 32768,
- .bankwidth = 4,
- .phys = 0x12000000,
+struct autcpu12_nvram_priv {
+ struct mtd_info *mtd;
+ struct map_info map;
};
-static int __init init_autcpu12_sram (void)
+static int __devinit autcpu12_nvram_probe(struct platform_device *pdev)
{
- int err, save0, save1;
+ map_word tmp, save0, save1;
+ struct resource *res;
+ struct autcpu12_nvram_priv *priv;
- autcpu12_sram_map.virt = ioremap(0x12000000, SZ_128K);
- if (!autcpu12_sram_map.virt) {
- printk("Failed to ioremap autcpu12 NV-RAM space\n");
- err = -EIO;
- goto out;
+ priv = devm_kzalloc(&pdev->dev,
+ sizeof(struct autcpu12_nvram_priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, priv);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "failed to get memory resource\n");
+ return -ENOENT;
+ }
+
+ priv->map.bankwidth = 4;
+ priv->map.phys = res->start;
+ priv->map.size = resource_size(res);
+ priv->map.virt = devm_request_and_ioremap(&pdev->dev, res);
+ strcpy((char *)priv->map.name, res->name);
+ if (!priv->map.virt) {
+ dev_err(&pdev->dev, "failed to remap mem resource\n");
+ return -EBUSY;
}
- simple_map_init(&autcpu_sram_map);
+
+ simple_map_init(&priv->map);
/*
* Check for 32K/128K
@@ -61,65 +72,59 @@ static int __init init_autcpu12_sram (void)
* Read and check result on ofs 0x0
* Restore contents
*/
- save0 = map_read32(&autcpu12_sram_map,0);
- save1 = map_read32(&autcpu12_sram_map,0x10000);
- map_write32(&autcpu12_sram_map,~save0,0x10000);
- /* if we find this pattern on 0x0, we have 32K size
- * restore contents and exit
- */
- if ( map_read32(&autcpu12_sram_map,0) != save0) {
- map_write32(&autcpu12_sram_map,save0,0x0);
- goto map;
+ save0 = map_read(&priv->map, 0);
+ save1 = map_read(&priv->map, 0x10000);
+ tmp.x[0] = ~save0.x[0];
+ map_write(&priv->map, tmp, 0x10000);
+ tmp = map_read(&priv->map, 0);
+ /* if we find this pattern on 0x0, we have 32K size */
+ if (!map_word_equal(&priv->map, tmp, save0)) {
+ map_write(&priv->map, save0, 0x0);
+ priv->map.size = SZ_32K;
+ } else
+ map_write(&priv->map, save1, 0x10000);
+
+ priv->mtd = do_map_probe("map_ram", &priv->map);
+ if (!priv->mtd) {
+ dev_err(&pdev->dev, "probing failed\n");
+ return -ENXIO;
}
- /* We have a 128K found, restore 0x10000 and set size
- * to 128K
- */
- map_write32(&autcpu12_sram_map,save1,0x10000);
- autcpu12_sram_map.size = SZ_128K;
-
-map:
- sram_mtd = do_map_probe("map_ram", &autcpu12_sram_map);
- if (!sram_mtd) {
- printk("NV-RAM probe failed\n");
- err = -ENXIO;
- goto out_ioremap;
- }
-
- sram_mtd->owner = THIS_MODULE;
- sram_mtd->erasesize = 16;
- if (mtd_device_register(sram_mtd, NULL, 0)) {
- printk("NV-RAM device addition failed\n");
- err = -ENOMEM;
- goto out_probe;
+ priv->mtd->owner = THIS_MODULE;
+ priv->mtd->erasesize = 16;
+ priv->mtd->dev.parent = &pdev->dev;
+ if (!mtd_device_register(priv->mtd, NULL, 0)) {
+ dev_info(&pdev->dev,
+ "NV-RAM device size %ldKiB registered on AUTCPU12\n",
+ priv->map.size / SZ_1K);
+ return 0;
}
- printk("NV-RAM device size %ldKiB registered on AUTCPU12\n",autcpu12_sram_map.size/SZ_1K);
-
- return 0;
-
-out_probe:
- map_destroy(sram_mtd);
- sram_mtd = 0;
-
-out_ioremap:
- iounmap((void *)autcpu12_sram_map.virt);
-out:
- return err;
+ map_destroy(priv->mtd);
+ dev_err(&pdev->dev, "NV-RAM device addition failed\n");
+ return -ENOMEM;
}
-static void __exit cleanup_autcpu12_maps(void)
+static int __devexit autcpu12_nvram_remove(struct platform_device *pdev)
{
- if (sram_mtd) {
- mtd_device_unregister(sram_mtd);
- map_destroy(sram_mtd);
- iounmap((void *)autcpu12_sram_map.virt);
- }
+ struct autcpu12_nvram_priv *priv = platform_get_drvdata(pdev);
+
+ mtd_device_unregister(priv->mtd);
+ map_destroy(priv->mtd);
+
+ return 0;
}
-module_init(init_autcpu12_sram);
-module_exit(cleanup_autcpu12_maps);
+static struct platform_driver autcpu12_nvram_driver = {
+ .driver = {
+ .name = "autcpu12_nvram",
+ .owner = THIS_MODULE,
+ },
+ .probe = autcpu12_nvram_probe,
+ .remove = __devexit_p(autcpu12_nvram_remove),
+};
+module_platform_driver(autcpu12_nvram_driver);
MODULE_AUTHOR("Thomas Gleixner");
-MODULE_DESCRIPTION("autcpu12 NV-RAM map driver");
+MODULE_DESCRIPTION("autcpu12 NVRAM map driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/maps/pci.c b/drivers/mtd/maps/pci.c
index f14ce0a..1c30c1a 100644
--- a/drivers/mtd/maps/pci.c
+++ b/drivers/mtd/maps/pci.c
@@ -43,26 +43,14 @@ static map_word mtd_pci_read8(struct map_info *_map, unsigned long ofs)
struct map_pci_info *map = (struct map_pci_info *)_map;
map_word val;
val.x[0]= readb(map->base + map->translate(map, ofs));
-// printk("read8 : %08lx => %02x\n", ofs, val.x[0]);
return val;
}
-#if 0
-static map_word mtd_pci_read16(struct map_info *_map, unsigned long ofs)
-{
- struct map_pci_info *map = (struct map_pci_info *)_map;
- map_word val;
- val.x[0] = readw(map->base + map->translate(map, ofs));
-// printk("read16: %08lx => %04x\n", ofs, val.x[0]);
- return val;
-}
-#endif
static map_word mtd_pci_read32(struct map_info *_map, unsigned long ofs)
{
struct map_pci_info *map = (struct map_pci_info *)_map;
map_word val;
val.x[0] = readl(map->base + map->translate(map, ofs));
-// printk("read32: %08lx => %08x\n", ofs, val.x[0]);
return val;
}
@@ -75,22 +63,12 @@ static void mtd_pci_copyfrom(struct map_info *_map, void *to, unsigned long from
static void mtd_pci_write8(struct map_info *_map, map_word val, unsigned long ofs)
{
struct map_pci_info *map = (struct map_pci_info *)_map;
-// printk("write8 : %08lx <= %02x\n", ofs, val.x[0]);
writeb(val.x[0], map->base + map->translate(map, ofs));
}
-#if 0
-static void mtd_pci_write16(struct map_info *_map, map_word val, unsigned long ofs)
-{
- struct map_pci_info *map = (struct map_pci_info *)_map;
-// printk("write16: %08lx <= %04x\n", ofs, val.x[0]);
- writew(val.x[0], map->base + map->translate(map, ofs));
-}
-#endif
static void mtd_pci_write32(struct map_info *_map, map_word val, unsigned long ofs)
{
struct map_pci_info *map = (struct map_pci_info *)_map;
-// printk("write32: %08lx <= %08x\n", ofs, val.x[0]);
writel(val.x[0], map->base + map->translate(map, ofs));
}
@@ -358,4 +336,3 @@ MODULE_LICENSE("GPL");
MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
MODULE_DESCRIPTION("Generic PCI map driver");
MODULE_DEVICE_TABLE(pci, mtd_pci_ids);
-
diff --git a/drivers/mtd/maps/physmap_of.c b/drivers/mtd/maps/physmap_of.c
index 2e6fb68..6f19aca 100644
--- a/drivers/mtd/maps/physmap_of.c
+++ b/drivers/mtd/maps/physmap_of.c
@@ -169,6 +169,7 @@ static int __devinit of_flash_probe(struct platform_device *dev)
struct mtd_info **mtd_list = NULL;
resource_size_t res_size;
struct mtd_part_parser_data ppdata;
+ bool map_indirect;
match = of_match_device(of_flash_match, &dev->dev);
if (!match)
@@ -192,6 +193,8 @@ static int __devinit of_flash_probe(struct platform_device *dev)
}
count /= reg_tuple_size;
+ map_indirect = of_property_read_bool(dp, "no-unaligned-direct-access");
+
err = -ENOMEM;
info = kzalloc(sizeof(struct of_flash) +
sizeof(struct of_flash_list) * count, GFP_KERNEL);
@@ -247,6 +250,17 @@ static int __devinit of_flash_probe(struct platform_device *dev)
simple_map_init(&info->list[i].map);
+ /*
+ * On some platforms (e.g. MPC5200) a direct 1:1 mapping
+ * may cause problems with JFFS2 usage, as the local bus (LPB)
+ * doesn't support unaligned accesses as implemented in the
+ * JFFS2 code via memcpy(). By setting NO_XIP, the
+ * flash will not be exposed directly to the MTD users
+ * (e.g. JFFS2) any more.
+ */
+ if (map_indirect)
+ info->list[i].map.phys = NO_XIP;
+
if (probe_type) {
info->list[i].mtd = do_map_probe(probe_type,
&info->list[i].map);
diff --git a/drivers/mtd/maps/rbtx4939-flash.c b/drivers/mtd/maps/rbtx4939-flash.c
index 6f52e1f..49c3fe7 100644
--- a/drivers/mtd/maps/rbtx4939-flash.c
+++ b/drivers/mtd/maps/rbtx4939-flash.c
@@ -100,8 +100,6 @@ static int rbtx4939_flash_probe(struct platform_device *dev)
goto err_out;
}
info->mtd->owner = THIS_MODULE;
- if (err)
- goto err_out;
err = mtd_device_parse_register(info->mtd, NULL, NULL, pdata->parts,
pdata->nr_parts);
diff --git a/drivers/mtd/maps/uclinux.c b/drivers/mtd/maps/uclinux.c
index c3bb304..299bf88 100644
--- a/drivers/mtd/maps/uclinux.c
+++ b/drivers/mtd/maps/uclinux.c
@@ -67,10 +67,16 @@ static int __init uclinux_mtd_init(void)
printk("uclinux[mtd]: RAM probe address=0x%x size=0x%x\n",
(int) mapp->phys, (int) mapp->size);
- mapp->virt = ioremap_nocache(mapp->phys, mapp->size);
+ /*
+ * The filesystem is guaranteed to be in direct mapped memory. It is
+ * directly following the kernels own bss region. Following the same
+ * mechanism used by architectures setting up traditional initrds we
+ * use phys_to_virt to get the virtual address of its start.
+ */
+ mapp->virt = phys_to_virt(mapp->phys);
if (mapp->virt == 0) {
- printk("uclinux[mtd]: ioremap_nocache() failed\n");
+ printk("uclinux[mtd]: no virtual mapping?\n");
return(-EIO);
}
@@ -79,7 +85,6 @@ static int __init uclinux_mtd_init(void)
mtd = do_map_probe("map_ram", mapp);
if (!mtd) {
printk("uclinux[mtd]: failed to find a mapping?\n");
- iounmap(mapp->virt);
return(-ENXIO);
}
@@ -102,10 +107,8 @@ static void __exit uclinux_mtd_cleanup(void)
map_destroy(uclinux_ram_mtdinfo);
uclinux_ram_mtdinfo = NULL;
}
- if (uclinux_ram_map.virt) {
- iounmap((void *) uclinux_ram_map.virt);
+ if (uclinux_ram_map.virt)
uclinux_ram_map.virt = 0;
- }
}
/****************************************************************************/
diff --git a/drivers/mtd/maps/wr_sbc82xx_flash.c b/drivers/mtd/maps/wr_sbc82xx_flash.c
deleted file mode 100644
index e7534c8..0000000
--- a/drivers/mtd/maps/wr_sbc82xx_flash.c
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * Map for flash chips on Wind River PowerQUICC II SBC82xx board.
- *
- * Copyright (C) 2004 Red Hat, Inc.
- *
- * Author: David Woodhouse <dwmw2@infradead.org>
- *
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <asm/io.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/map.h>
-#include <linux/mtd/partitions.h>
-
-#include <asm/immap_cpm2.h>
-
-static struct mtd_info *sbcmtd[3];
-
-struct map_info sbc82xx_flash_map[3] = {
- {.name = "Boot flash"},
- {.name = "Alternate boot flash"},
- {.name = "User flash"}
-};
-
-static struct mtd_partition smallflash_parts[] = {
- {
- .name = "space",
- .size = 0x100000,
- .offset = 0,
- }, {
- .name = "bootloader",
- .size = MTDPART_SIZ_FULL,
- .offset = MTDPART_OFS_APPEND,
- }
-};
-
-static struct mtd_partition bigflash_parts[] = {
- {
- .name = "bootloader",
- .size = 0x00100000,
- .offset = 0,
- }, {
- .name = "file system",
- .size = 0x01f00000,
- .offset = MTDPART_OFS_APPEND,
- }, {
- .name = "boot config",
- .size = 0x00100000,
- .offset = MTDPART_OFS_APPEND,
- }, {
- .name = "space",
- .size = 0x01f00000,
- .offset = MTDPART_OFS_APPEND,
- }
-};
-
-static const char *part_probes[] __initconst = {"cmdlinepart", "RedBoot", NULL};
-
-#define init_sbc82xx_one_flash(map, br, or) \
-do { \
- (map).phys = (br & 1) ? (br & 0xffff8000) : 0; \
- (map).size = (br & 1) ? (~(or & 0xffff8000) + 1) : 0; \
- switch (br & 0x00001800) { \
- case 0x00000000: \
- case 0x00000800: (map).bankwidth = 1; break; \
- case 0x00001000: (map).bankwidth = 2; break; \
- case 0x00001800: (map).bankwidth = 4; break; \
- } \
-} while (0);
-
-static int __init init_sbc82xx_flash(void)
-{
- volatile memctl_cpm2_t *mc = &cpm2_immr->im_memctl;
- int bigflash;
- int i;
-
-#ifdef CONFIG_SBC8560
- mc = ioremap(0xff700000 + 0x5000, sizeof(memctl_cpm2_t));
-#else
- mc = &cpm2_immr->im_memctl;
-#endif
-
- bigflash = 1;
- if ((mc->memc_br0 & 0x00001800) == 0x00001800)
- bigflash = 0;
-
- init_sbc82xx_one_flash(sbc82xx_flash_map[0], mc->memc_br0, mc->memc_or0);
- init_sbc82xx_one_flash(sbc82xx_flash_map[1], mc->memc_br6, mc->memc_or6);
- init_sbc82xx_one_flash(sbc82xx_flash_map[2], mc->memc_br1, mc->memc_or1);
-
-#ifdef CONFIG_SBC8560
- iounmap((void *) mc);
-#endif
-
- for (i=0; i<3; i++) {
- int8_t flashcs[3] = { 0, 6, 1 };
- int nr_parts;
- struct mtd_partition *defparts;
-
- printk(KERN_NOTICE "PowerQUICC II %s (%ld MiB on CS%d",
- sbc82xx_flash_map[i].name,
- (sbc82xx_flash_map[i].size >> 20),
- flashcs[i]);
- if (!sbc82xx_flash_map[i].phys) {
- /* We know it can't be at zero. */
- printk("): disabled by bootloader.\n");
- continue;
- }
- printk(" at %08lx)\n", sbc82xx_flash_map[i].phys);
-
- sbc82xx_flash_map[i].virt = ioremap(sbc82xx_flash_map[i].phys,
- sbc82xx_flash_map[i].size);
-
- if (!sbc82xx_flash_map[i].virt) {
- printk("Failed to ioremap\n");
- continue;
- }
-
- simple_map_init(&sbc82xx_flash_map[i]);
-
- sbcmtd[i] = do_map_probe("cfi_probe", &sbc82xx_flash_map[i]);
-
- if (!sbcmtd[i])
- continue;
-
- sbcmtd[i]->owner = THIS_MODULE;
-
- /* No partitioning detected. Use default */
- if (i == 2) {
- defparts = NULL;
- nr_parts = 0;
- } else if (i == bigflash) {
- defparts = bigflash_parts;
- nr_parts = ARRAY_SIZE(bigflash_parts);
- } else {
- defparts = smallflash_parts;
- nr_parts = ARRAY_SIZE(smallflash_parts);
- }
-
- mtd_device_parse_register(sbcmtd[i], part_probes, NULL,
- defparts, nr_parts);
- }
- return 0;
-}
-
-static void __exit cleanup_sbc82xx_flash(void)
-{
- int i;
-
- for (i=0; i<3; i++) {
- if (!sbcmtd[i])
- continue;
-
- mtd_device_unregister(sbcmtd[i]);
-
- map_destroy(sbcmtd[i]);
-
- iounmap((void *)sbc82xx_flash_map[i].virt);
- sbc82xx_flash_map[i].virt = 0;
- }
-}
-
-module_init(init_sbc82xx_flash);
-module_exit(cleanup_sbc82xx_flash);
-
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
-MODULE_DESCRIPTION("Flash map driver for WindRiver PowerQUICC II");
diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c
index 73ae81a..82c0616 100644
--- a/drivers/mtd/mtdchar.c
+++ b/drivers/mtd/mtdchar.c
@@ -1162,7 +1162,11 @@ static int mtdchar_mmap(struct file *file, struct vm_area_struct *vma)
resource_size_t start, off;
unsigned long len, vma_len;
- if (mtd->type == MTD_RAM || mtd->type == MTD_ROM) {
+ /* This is broken because it assumes the MTD device is map-based
+ and that mtd->priv is a valid struct map_info. It should be
+ replaced with something that uses the mtd_get_unmapped_area()
+ operation properly. */
+ if (0 /*mtd->type == MTD_RAM || mtd->type == MTD_ROM*/) {
off = get_vm_offset(vma);
start = map->phys;
len = PAGE_ALIGN((start & ~PAGE_MASK) + map->size);
diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
index b9adff5..374c46d 100644
--- a/drivers/mtd/mtdcore.c
+++ b/drivers/mtd/mtdcore.c
@@ -858,6 +858,27 @@ int mtd_panic_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen,
}
EXPORT_SYMBOL_GPL(mtd_panic_write);
+int mtd_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops)
+{
+ int ret_code;
+ ops->retlen = ops->oobretlen = 0;
+ if (!mtd->_read_oob)
+ return -EOPNOTSUPP;
+ /*
+ * In cases where ops->datbuf != NULL, mtd->_read_oob() has semantics
+ * similar to mtd->_read(), returning a non-negative integer
+ * representing max bitflips. In other cases, mtd->_read_oob() may
+ * return -EUCLEAN. In all cases, perform similar logic to mtd_read().
+ */
+ ret_code = mtd->_read_oob(mtd, from, ops);
+ if (unlikely(ret_code < 0))
+ return ret_code;
+ if (mtd->ecc_strength == 0)
+ return 0; /* device lacks ecc */
+ return ret_code >= mtd->bitflip_threshold ? -EUCLEAN : 0;
+}
+EXPORT_SYMBOL_GPL(mtd_read_oob);
+
/*
* Method to access the protection register area, present in some flash
* devices. The user data is one time programmable but the factory data is read
diff --git a/drivers/mtd/mtdoops.c b/drivers/mtd/mtdoops.c
index 438737a..f5b3f91 100644
--- a/drivers/mtd/mtdoops.c
+++ b/drivers/mtd/mtdoops.c
@@ -169,14 +169,7 @@ static void mtdoops_workfunc_erase(struct work_struct *work)
cxt->nextpage = 0;
}
- while (1) {
- ret = mtd_block_isbad(mtd, cxt->nextpage * record_size);
- if (!ret)
- break;
- if (ret < 0) {
- printk(KERN_ERR "mtdoops: block_isbad failed, aborting\n");
- return;
- }
+ while ((ret = mtd_block_isbad(mtd, cxt->nextpage * record_size)) > 0) {
badblock:
printk(KERN_WARNING "mtdoops: bad block at %08lx\n",
cxt->nextpage * record_size);
@@ -190,6 +183,11 @@ badblock:
}
}
+ if (ret < 0) {
+ printk(KERN_ERR "mtdoops: mtd_block_isbad failed, aborting\n");
+ return;
+ }
+
for (j = 0, ret = -1; (j < 3) && (ret < 0); j++)
ret = mtdoops_erase_block(cxt, cxt->nextpage * record_size);
diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c
index 3a49e6d..70fa70a 100644
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -711,6 +711,8 @@ static const char *default_mtd_part_types[] = {
* partition parsers, specified in @types. However, if @types is %NULL, then
* the default list of parsers is used. The default list contains only the
* "cmdlinepart" and "ofpart" parsers ATM.
+ * Note: If there are more then one parser in @types, the kernel only takes the
+ * partitions parsed out by the first parser.
*
* This function may return:
* o a negative error code in case of failure
@@ -735,11 +737,12 @@ int parse_mtd_partitions(struct mtd_info *master, const char **types,
if (!parser)
continue;
ret = (*parser->parse_fn)(master, pparts, data);
+ put_partition_parser(parser);
if (ret > 0) {
printk(KERN_NOTICE "%d %s partitions found on MTD device %s\n",
ret, parser->name, master->name);
+ break;
}
- put_partition_parser(parser);
}
return ret;
}
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index 598cd0a..4883139 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -22,15 +22,6 @@ menuconfig MTD_NAND
if MTD_NAND
-config MTD_NAND_VERIFY_WRITE
- bool "Verify NAND page writes"
- help
- This adds an extra check when data is written to the flash. The
- NAND flash device internally checks only bits transitioning
- from 1 to 0. There is a rare possibility that even though the
- device thinks the write was successful, a bit could have been
- flipped accidentally due to device wear or something else.
-
config MTD_NAND_BCH
tristate
select BCH
@@ -267,22 +258,6 @@ config MTD_NAND_S3C2410_CLKSTOP
when the is NAND chip selected or released, but will save
approximately 5mA of power when there is nothing happening.
-config MTD_NAND_BCM_UMI
- tristate "NAND Flash support for BCM Reference Boards"
- depends on ARCH_BCMRING
- help
- This enables the NAND flash controller on the BCM UMI block.
-
- No board specific support is done by this driver, each board
- must advertise a platform_device for the driver to attach.
-
-config MTD_NAND_BCM_UMI_HWCS
- bool "BCM UMI NAND Hardware CS"
- depends on MTD_NAND_BCM_UMI
- help
- Enable the use of the BCM UMI block's internal CS using NAND.
- This should only be used if you know the external NAND CS can toggle.
-
config MTD_NAND_DISKONCHIP
tristate "DiskOnChip 2000, Millennium and Millennium Plus (NAND reimplementation) (EXPERIMENTAL)"
depends on EXPERIMENTAL
@@ -356,7 +331,7 @@ config MTD_NAND_DISKONCHIP_BBTWRITE
config MTD_NAND_DOCG4
tristate "Support for DiskOnChip G4 (EXPERIMENTAL)"
- depends on EXPERIMENTAL
+ depends on EXPERIMENTAL && HAS_IOMEM
select BCH
select BITREVERSE
help
@@ -414,6 +389,28 @@ config MTD_NAND_PXA3xx
This enables the driver for the NAND flash device found on
PXA3xx processors
+config MTD_NAND_SLC_LPC32XX
+ tristate "NXP LPC32xx SLC Controller"
+ depends on ARCH_LPC32XX
+ help
+ Enables support for NXP's LPC32XX SLC (i.e. for Single Level Cell
+ chips) NAND controller. This is the default for the PHYTEC 3250
+ reference board which contains a NAND256R3A2CZA6 chip.
+
+ Please check the actual NAND chip connected and its support
+ by the SLC NAND controller.
+
+config MTD_NAND_MLC_LPC32XX
+ tristate "NXP LPC32xx MLC Controller"
+ depends on ARCH_LPC32XX
+ help
+ Uses the LPC32XX MLC (i.e. for Multi Level Cell chips) NAND
+ controller. This is the default for the WORK92105 controller
+ board.
+
+ Please check the actual NAND chip connected and its support
+ by the MLC NAND controller.
+
config MTD_NAND_CM_X270
tristate "Support for NAND Flash on CM-X270 modules"
depends on MACH_ARMCORE
@@ -439,10 +436,10 @@ config MTD_NAND_NANDSIM
MTD nand layer.
config MTD_NAND_GPMI_NAND
- bool "GPMI NAND Flash Controller driver"
+ tristate "GPMI NAND Flash Controller driver"
depends on MTD_NAND && MXS_DMA
help
- Enables NAND Flash support for IMX23 or IMX28.
+ Enables NAND Flash support for IMX23, IMX28 or IMX6.
The GPMI controller is very powerful, with the help of BCH
module, it can do the hardware ECC. The GPMI supports several
NAND flashs at the same time. The GPMI may conflicts with other
@@ -510,7 +507,7 @@ config MTD_NAND_MPC5121_NFC
config MTD_NAND_MXC
tristate "MXC NAND support"
- depends on IMX_HAVE_PLATFORM_MXC_NAND
+ depends on ARCH_MXC
help
This enables the driver for the NAND flash controller on the
MXC processors.
@@ -567,4 +564,12 @@ config MTD_NAND_FSMC
Enables support for NAND Flash chips on the ST Microelectronics
Flexible Static Memory Controller (FSMC)
+config MTD_NAND_XWAY
+ tristate "Support for NAND on Lantiq XWAY SoC"
+ depends on LANTIQ && SOC_TYPE_XWAY
+ select MTD_NAND_PLATFORM
+ help
+ Enables support for NAND Flash chips on Lantiq XWAY SoCs. NAND is attached
+ to the External Bus Unit (EBU).
+
endif # MTD_NAND
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index d4b4d87..2cbd091 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -40,16 +40,18 @@ obj-$(CONFIG_MTD_NAND_ORION) += orion_nand.o
obj-$(CONFIG_MTD_NAND_FSL_ELBC) += fsl_elbc_nand.o
obj-$(CONFIG_MTD_NAND_FSL_IFC) += fsl_ifc_nand.o
obj-$(CONFIG_MTD_NAND_FSL_UPM) += fsl_upm.o
+obj-$(CONFIG_MTD_NAND_SLC_LPC32XX) += lpc32xx_slc.o
+obj-$(CONFIG_MTD_NAND_MLC_LPC32XX) += lpc32xx_mlc.o
obj-$(CONFIG_MTD_NAND_SH_FLCTL) += sh_flctl.o
obj-$(CONFIG_MTD_NAND_MXC) += mxc_nand.o
obj-$(CONFIG_MTD_NAND_SOCRATES) += socrates_nand.o
obj-$(CONFIG_MTD_NAND_TXX9NDFMC) += txx9ndfmc.o
obj-$(CONFIG_MTD_NAND_NUC900) += nuc900_nand.o
obj-$(CONFIG_MTD_NAND_NOMADIK) += nomadik_nand.o
-obj-$(CONFIG_MTD_NAND_BCM_UMI) += bcm_umi_nand.o nand_bcm_umi.o
obj-$(CONFIG_MTD_NAND_MPC5121_NFC) += mpc5121_nfc.o
obj-$(CONFIG_MTD_NAND_RICOH) += r852.o
obj-$(CONFIG_MTD_NAND_JZ4740) += jz4740_nand.o
obj-$(CONFIG_MTD_NAND_GPMI_NAND) += gpmi-nand/
+obj-$(CONFIG_MTD_NAND_XWAY) += xway_nand.o
nand-objs := nand_base.o nand_bbt.o
diff --git a/drivers/mtd/nand/ams-delta.c b/drivers/mtd/nand/ams-delta.c
index a7040af..9e7723a 100644
--- a/drivers/mtd/nand/ams-delta.c
+++ b/drivers/mtd/nand/ams-delta.c
@@ -107,18 +107,6 @@ static void ams_delta_read_buf(struct mtd_info *mtd, u_char *buf, int len)
buf[i] = ams_delta_read_byte(mtd);
}
-static int ams_delta_verify_buf(struct mtd_info *mtd, const u_char *buf,
- int len)
-{
- int i;
-
- for (i=0; i<len; i++)
- if (buf[i] != ams_delta_read_byte(mtd))
- return -EFAULT;
-
- return 0;
-}
-
/*
* Command control function
*
@@ -237,7 +225,6 @@ static int __devinit ams_delta_init(struct platform_device *pdev)
this->read_byte = ams_delta_read_byte;
this->write_buf = ams_delta_write_buf;
this->read_buf = ams_delta_read_buf;
- this->verify_buf = ams_delta_verify_buf;
this->cmd_ctrl = ams_delta_hwcontrol;
if (gpio_request(AMS_DELTA_GPIO_PIN_NAND_RB, "nand_rdy") == 0) {
this->dev_ready = ams_delta_nand_ready;
diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
index 97ac671..9144557 100644
--- a/drivers/mtd/nand/atmel_nand.c
+++ b/drivers/mtd/nand/atmel_nand.c
@@ -1,20 +1,22 @@
/*
- * Copyright (C) 2003 Rick Bronson
+ * Copyright © 2003 Rick Bronson
*
* Derived from drivers/mtd/nand/autcpu12.c
- * Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de)
+ * Copyright © 2001 Thomas Gleixner (gleixner@autronix.de)
*
* Derived from drivers/mtd/spia.c
- * Copyright (C) 2000 Steven J. Hill (sjhill@cotw.com)
+ * Copyright © 2000 Steven J. Hill (sjhill@cotw.com)
*
*
* Add Hardware ECC support for AT91SAM9260 / AT91SAM9263
- * Richard Genoud (richard.genoud@gmail.com), Adeneo Copyright (C) 2007
+ * Richard Genoud (richard.genoud@gmail.com), Adeneo Copyright © 2007
*
* Derived from Das U-Boot source code
* (u-boot-1.1.5/board/atmel/at91sam9263ek/nand.c)
- * (C) Copyright 2006 ATMEL Rousset, Lacressonniere Nicolas
+ * © Copyright 2006 ATMEL Rousset, Lacressonniere Nicolas
*
+ * Add Programmable Multibit ECC support for various AT91 SoC
+ * © Copyright 2012 ATMEL, Hong Xu
*
* 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 +95,36 @@ struct atmel_nand_host {
struct completion comp;
struct dma_chan *dma_chan;
+
+ bool has_pmecc;
+ u8 pmecc_corr_cap;
+ u16 pmecc_sector_size;
+ u32 pmecc_lookup_table_offset;
+
+ int pmecc_bytes_per_sector;
+ int pmecc_sector_number;
+ int pmecc_degree; /* Degree of remainders */
+ int pmecc_cw_len; /* Length of codeword */
+
+ void __iomem *pmerrloc_base;
+ void __iomem *pmecc_rom_base;
+
+ /* lookup table for alpha_to and index_of */
+ void __iomem *pmecc_alpha_to;
+ void __iomem *pmecc_index_of;
+
+ /* data for pmecc computation */
+ int16_t *pmecc_partial_syn;
+ int16_t *pmecc_si;
+ int16_t *pmecc_smu; /* Sigma table */
+ int16_t *pmecc_lmu; /* polynomal order */
+ int *pmecc_mu;
+ int *pmecc_dmu;
+ int *pmecc_delta;
};
+static struct nand_ecclayout atmel_pmecc_oobinfo;
+
static int cpu_has_dma(void)
{
return cpu_is_at91sam9rl() || cpu_is_at91sam9g45();
@@ -288,6 +318,703 @@ static void atmel_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
}
/*
+ * Return number of ecc bytes per sector according to sector size and
+ * correction capability
+ *
+ * Following table shows what at91 PMECC supported:
+ * Correction Capability Sector_512_bytes Sector_1024_bytes
+ * ===================== ================ =================
+ * 2-bits 4-bytes 4-bytes
+ * 4-bits 7-bytes 7-bytes
+ * 8-bits 13-bytes 14-bytes
+ * 12-bits 20-bytes 21-bytes
+ * 24-bits 39-bytes 42-bytes
+ */
+static int __devinit pmecc_get_ecc_bytes(int cap, int sector_size)
+{
+ int m = 12 + sector_size / 512;
+ return (m * cap + 7) / 8;
+}
+
+static void __devinit pmecc_config_ecc_layout(struct nand_ecclayout *layout,
+ int oobsize, int ecc_len)
+{
+ int i;
+
+ layout->eccbytes = ecc_len;
+
+ /* ECC will occupy the last ecc_len bytes continuously */
+ for (i = 0; i < ecc_len; i++)
+ layout->eccpos[i] = oobsize - ecc_len + i;
+
+ layout->oobfree[0].offset = 2;
+ layout->oobfree[0].length =
+ oobsize - ecc_len - layout->oobfree[0].offset;
+}
+
+static void __devinit __iomem *pmecc_get_alpha_to(struct atmel_nand_host *host)
+{
+ int table_size;
+
+ table_size = host->pmecc_sector_size == 512 ?
+ PMECC_LOOKUP_TABLE_SIZE_512 : PMECC_LOOKUP_TABLE_SIZE_1024;
+
+ return host->pmecc_rom_base + host->pmecc_lookup_table_offset +
+ table_size * sizeof(int16_t);
+}
+
+static void pmecc_data_free(struct atmel_nand_host *host)
+{
+ kfree(host->pmecc_partial_syn);
+ kfree(host->pmecc_si);
+ kfree(host->pmecc_lmu);
+ kfree(host->pmecc_smu);
+ kfree(host->pmecc_mu);
+ kfree(host->pmecc_dmu);
+ kfree(host->pmecc_delta);
+}
+
+static int __devinit pmecc_data_alloc(struct atmel_nand_host *host)
+{
+ const int cap = host->pmecc_corr_cap;
+
+ host->pmecc_partial_syn = kzalloc((2 * cap + 1) * sizeof(int16_t),
+ GFP_KERNEL);
+ host->pmecc_si = kzalloc((2 * cap + 1) * sizeof(int16_t), GFP_KERNEL);
+ host->pmecc_lmu = kzalloc((cap + 1) * sizeof(int16_t), GFP_KERNEL);
+ host->pmecc_smu = kzalloc((cap + 2) * (2 * cap + 1) * sizeof(int16_t),
+ GFP_KERNEL);
+ host->pmecc_mu = kzalloc((cap + 1) * sizeof(int), GFP_KERNEL);
+ host->pmecc_dmu = kzalloc((cap + 1) * sizeof(int), GFP_KERNEL);
+ host->pmecc_delta = kzalloc((cap + 1) * sizeof(int), GFP_KERNEL);
+
+ if (host->pmecc_partial_syn &&
+ host->pmecc_si &&
+ host->pmecc_lmu &&
+ host->pmecc_smu &&
+ host->pmecc_mu &&
+ host->pmecc_dmu &&
+ host->pmecc_delta)
+ return 0;
+
+ /* error happened */
+ pmecc_data_free(host);
+ return -ENOMEM;
+}
+
+static void pmecc_gen_syndrome(struct mtd_info *mtd, int sector)
+{
+ struct nand_chip *nand_chip = mtd->priv;
+ struct atmel_nand_host *host = nand_chip->priv;
+ int i;
+ uint32_t value;
+
+ /* Fill odd syndromes */
+ for (i = 0; i < host->pmecc_corr_cap; i++) {
+ value = pmecc_readl_rem_relaxed(host->ecc, sector, i / 2);
+ if (i & 1)
+ value >>= 16;
+ value &= 0xffff;
+ host->pmecc_partial_syn[(2 * i) + 1] = (int16_t)value;
+ }
+}
+
+static void pmecc_substitute(struct mtd_info *mtd)
+{
+ struct nand_chip *nand_chip = mtd->priv;
+ struct atmel_nand_host *host = nand_chip->priv;
+ int16_t __iomem *alpha_to = host->pmecc_alpha_to;
+ int16_t __iomem *index_of = host->pmecc_index_of;
+ int16_t *partial_syn = host->pmecc_partial_syn;
+ const int cap = host->pmecc_corr_cap;
+ int16_t *si;
+ int i, j;
+
+ /* si[] is a table that holds the current syndrome value,
+ * an element of that table belongs to the field
+ */
+ si = host->pmecc_si;
+
+ memset(&si[1], 0, sizeof(int16_t) * (2 * cap - 1));
+
+ /* Computation 2t syndromes based on S(x) */
+ /* Odd syndromes */
+ for (i = 1; i < 2 * cap; i += 2) {
+ for (j = 0; j < host->pmecc_degree; j++) {
+ if (partial_syn[i] & ((unsigned short)0x1 << j))
+ si[i] = readw_relaxed(alpha_to + i * j) ^ si[i];
+ }
+ }
+ /* Even syndrome = (Odd syndrome) ** 2 */
+ for (i = 2, j = 1; j <= cap; i = ++j << 1) {
+ if (si[j] == 0) {
+ si[i] = 0;
+ } else {
+ int16_t tmp;
+
+ tmp = readw_relaxed(index_of + si[j]);
+ tmp = (tmp * 2) % host->pmecc_cw_len;
+ si[i] = readw_relaxed(alpha_to + tmp);
+ }
+ }
+
+ return;
+}
+
+static void pmecc_get_sigma(struct mtd_info *mtd)
+{
+ struct nand_chip *nand_chip = mtd->priv;
+ struct atmel_nand_host *host = nand_chip->priv;
+
+ int16_t *lmu = host->pmecc_lmu;
+ int16_t *si = host->pmecc_si;
+ int *mu = host->pmecc_mu;
+ int *dmu = host->pmecc_dmu; /* Discrepancy */
+ int *delta = host->pmecc_delta; /* Delta order */
+ int cw_len = host->pmecc_cw_len;
+ const int16_t cap = host->pmecc_corr_cap;
+ const int num = 2 * cap + 1;
+ int16_t __iomem *index_of = host->pmecc_index_of;
+ int16_t __iomem *alpha_to = host->pmecc_alpha_to;
+ int i, j, k;
+ uint32_t dmu_0_count, tmp;
+ int16_t *smu = host->pmecc_smu;
+
+ /* index of largest delta */
+ int ro;
+ int largest;
+ int diff;
+
+ dmu_0_count = 0;
+
+ /* First Row */
+
+ /* Mu */
+ mu[0] = -1;
+
+ memset(smu, 0, sizeof(int16_t) * num);
+ smu[0] = 1;
+
+ /* discrepancy set to 1 */
+ dmu[0] = 1;
+ /* polynom order set to 0 */
+ lmu[0] = 0;
+ delta[0] = (mu[0] * 2 - lmu[0]) >> 1;
+
+ /* Second Row */
+
+ /* Mu */
+ mu[1] = 0;
+ /* Sigma(x) set to 1 */
+ memset(&smu[num], 0, sizeof(int16_t) * num);
+ smu[num] = 1;
+
+ /* discrepancy set to S1 */
+ dmu[1] = si[1];
+
+ /* polynom order set to 0 */
+ lmu[1] = 0;
+
+ delta[1] = (mu[1] * 2 - lmu[1]) >> 1;
+
+ /* Init the Sigma(x) last row */
+ memset(&smu[(cap + 1) * num], 0, sizeof(int16_t) * num);
+
+ for (i = 1; i <= cap; i++) {
+ mu[i + 1] = i << 1;
+ /* Begin Computing Sigma (Mu+1) and L(mu) */
+ /* check if discrepancy is set to 0 */
+ if (dmu[i] == 0) {
+ dmu_0_count++;
+
+ tmp = ((cap - (lmu[i] >> 1) - 1) / 2);
+ if ((cap - (lmu[i] >> 1) - 1) & 0x1)
+ tmp += 2;
+ else
+ tmp += 1;
+
+ if (dmu_0_count == tmp) {
+ for (j = 0; j <= (lmu[i] >> 1) + 1; j++)
+ smu[(cap + 1) * num + j] =
+ smu[i * num + j];
+
+ lmu[cap + 1] = lmu[i];
+ return;
+ }
+
+ /* copy polynom */
+ for (j = 0; j <= lmu[i] >> 1; j++)
+ smu[(i + 1) * num + j] = smu[i * num + j];
+
+ /* copy previous polynom order to the next */
+ lmu[i + 1] = lmu[i];
+ } else {
+ ro = 0;
+ largest = -1;
+ /* find largest delta with dmu != 0 */
+ for (j = 0; j < i; j++) {
+ if ((dmu[j]) && (delta[j] > largest)) {
+ largest = delta[j];
+ ro = j;
+ }
+ }
+
+ /* compute difference */
+ diff = (mu[i] - mu[ro]);
+
+ /* Compute degree of the new smu polynomial */
+ if ((lmu[i] >> 1) > ((lmu[ro] >> 1) + diff))
+ lmu[i + 1] = lmu[i];
+ else
+ lmu[i + 1] = ((lmu[ro] >> 1) + diff) * 2;
+
+ /* Init smu[i+1] with 0 */
+ for (k = 0; k < num; k++)
+ smu[(i + 1) * num + k] = 0;
+
+ /* Compute smu[i+1] */
+ for (k = 0; k <= lmu[ro] >> 1; k++) {
+ int16_t a, b, c;
+
+ if (!(smu[ro * num + k] && dmu[i]))
+ continue;
+ a = readw_relaxed(index_of + dmu[i]);
+ b = readw_relaxed(index_of + dmu[ro]);
+ c = readw_relaxed(index_of + smu[ro * num + k]);
+ tmp = a + (cw_len - b) + c;
+ a = readw_relaxed(alpha_to + tmp % cw_len);
+ smu[(i + 1) * num + (k + diff)] = a;
+ }
+
+ for (k = 0; k <= lmu[i] >> 1; k++)
+ smu[(i + 1) * num + k] ^= smu[i * num + k];
+ }
+
+ /* End Computing Sigma (Mu+1) and L(mu) */
+ /* In either case compute delta */
+ delta[i + 1] = (mu[i + 1] * 2 - lmu[i + 1]) >> 1;
+
+ /* Do not compute discrepancy for the last iteration */
+ if (i >= cap)
+ continue;
+
+ for (k = 0; k <= (lmu[i + 1] >> 1); k++) {
+ tmp = 2 * (i - 1);
+ if (k == 0) {
+ dmu[i + 1] = si[tmp + 3];
+ } else if (smu[(i + 1) * num + k] && si[tmp + 3 - k]) {
+ int16_t a, b, c;
+ a = readw_relaxed(index_of +
+ smu[(i + 1) * num + k]);
+ b = si[2 * (i - 1) + 3 - k];
+ c = readw_relaxed(index_of + b);
+ tmp = a + c;
+ tmp %= cw_len;
+ dmu[i + 1] = readw_relaxed(alpha_to + tmp) ^
+ dmu[i + 1];
+ }
+ }
+ }
+
+ return;
+}
+
+static int pmecc_err_location(struct mtd_info *mtd)
+{
+ struct nand_chip *nand_chip = mtd->priv;
+ struct atmel_nand_host *host = nand_chip->priv;
+ unsigned long end_time;
+ const int cap = host->pmecc_corr_cap;
+ const int num = 2 * cap + 1;
+ int sector_size = host->pmecc_sector_size;
+ int err_nbr = 0; /* number of error */
+ int roots_nbr; /* number of roots */
+ int i;
+ uint32_t val;
+ int16_t *smu = host->pmecc_smu;
+
+ pmerrloc_writel(host->pmerrloc_base, ELDIS, PMERRLOC_DISABLE);
+
+ for (i = 0; i <= host->pmecc_lmu[cap + 1] >> 1; i++) {
+ pmerrloc_writel_sigma_relaxed(host->pmerrloc_base, i,
+ smu[(cap + 1) * num + i]);
+ err_nbr++;
+ }
+
+ val = (err_nbr - 1) << 16;
+ if (sector_size == 1024)
+ val |= 1;
+
+ pmerrloc_writel(host->pmerrloc_base, ELCFG, val);
+ pmerrloc_writel(host->pmerrloc_base, ELEN,
+ sector_size * 8 + host->pmecc_degree * cap);
+
+ end_time = jiffies + msecs_to_jiffies(PMECC_MAX_TIMEOUT_MS);
+ while (!(pmerrloc_readl_relaxed(host->pmerrloc_base, ELISR)
+ & PMERRLOC_CALC_DONE)) {
+ if (unlikely(time_after(jiffies, end_time))) {
+ dev_err(host->dev, "PMECC: Timeout to calculate error location.\n");
+ return -1;
+ }
+ cpu_relax();
+ }
+
+ roots_nbr = (pmerrloc_readl_relaxed(host->pmerrloc_base, ELISR)
+ & PMERRLOC_ERR_NUM_MASK) >> 8;
+ /* Number of roots == degree of smu hence <= cap */
+ if (roots_nbr == host->pmecc_lmu[cap + 1] >> 1)
+ return err_nbr - 1;
+
+ /* Number of roots does not match the degree of smu
+ * unable to correct error */
+ return -1;
+}
+
+static void pmecc_correct_data(struct mtd_info *mtd, uint8_t *buf, uint8_t *ecc,
+ int sector_num, int extra_bytes, int err_nbr)
+{
+ struct nand_chip *nand_chip = mtd->priv;
+ struct atmel_nand_host *host = nand_chip->priv;
+ int i = 0;
+ int byte_pos, bit_pos, sector_size, pos;
+ uint32_t tmp;
+ uint8_t err_byte;
+
+ sector_size = host->pmecc_sector_size;
+
+ while (err_nbr) {
+ tmp = pmerrloc_readl_el_relaxed(host->pmerrloc_base, i) - 1;
+ byte_pos = tmp / 8;
+ bit_pos = tmp % 8;
+
+ if (byte_pos >= (sector_size + extra_bytes))
+ BUG(); /* should never happen */
+
+ if (byte_pos < sector_size) {
+ err_byte = *(buf + byte_pos);
+ *(buf + byte_pos) ^= (1 << bit_pos);
+
+ pos = sector_num * host->pmecc_sector_size + byte_pos;
+ dev_info(host->dev, "Bit flip in data area, byte_pos: %d, bit_pos: %d, 0x%02x -> 0x%02x\n",
+ pos, bit_pos, err_byte, *(buf + byte_pos));
+ } else {
+ /* Bit flip in OOB area */
+ tmp = sector_num * host->pmecc_bytes_per_sector
+ + (byte_pos - sector_size);
+ err_byte = ecc[tmp];
+ ecc[tmp] ^= (1 << bit_pos);
+
+ pos = tmp + nand_chip->ecc.layout->eccpos[0];
+ dev_info(host->dev, "Bit flip in OOB, oob_byte_pos: %d, bit_pos: %d, 0x%02x -> 0x%02x\n",
+ pos, bit_pos, err_byte, ecc[tmp]);
+ }
+
+ i++;
+ err_nbr--;
+ }
+
+ return;
+}
+
+static int pmecc_correction(struct mtd_info *mtd, u32 pmecc_stat, uint8_t *buf,
+ u8 *ecc)
+{
+ struct nand_chip *nand_chip = mtd->priv;
+ struct atmel_nand_host *host = nand_chip->priv;
+ int i, err_nbr, eccbytes;
+ uint8_t *buf_pos;
+
+ eccbytes = nand_chip->ecc.bytes;
+ for (i = 0; i < eccbytes; i++)
+ if (ecc[i] != 0xff)
+ goto normal_check;
+ /* Erased page, return OK */
+ return 0;
+
+normal_check:
+ for (i = 0; i < host->pmecc_sector_number; i++) {
+ err_nbr = 0;
+ if (pmecc_stat & 0x1) {
+ buf_pos = buf + i * host->pmecc_sector_size;
+
+ pmecc_gen_syndrome(mtd, i);
+ pmecc_substitute(mtd);
+ pmecc_get_sigma(mtd);
+
+ err_nbr = pmecc_err_location(mtd);
+ if (err_nbr == -1) {
+ dev_err(host->dev, "PMECC: Too many errors\n");
+ mtd->ecc_stats.failed++;
+ return -EIO;
+ } else {
+ pmecc_correct_data(mtd, buf_pos, ecc, i,
+ host->pmecc_bytes_per_sector, err_nbr);
+ mtd->ecc_stats.corrected += err_nbr;
+ }
+ }
+ pmecc_stat >>= 1;
+ }
+
+ return 0;
+}
+
+static int atmel_nand_pmecc_read_page(struct mtd_info *mtd,
+ struct nand_chip *chip, uint8_t *buf, int oob_required, int page)
+{
+ struct atmel_nand_host *host = chip->priv;
+ int eccsize = chip->ecc.size;
+ uint8_t *oob = chip->oob_poi;
+ uint32_t *eccpos = chip->ecc.layout->eccpos;
+ uint32_t stat;
+ unsigned long end_time;
+
+ pmecc_writel(host->ecc, CTRL, PMECC_CTRL_RST);
+ pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE);
+ pmecc_writel(host->ecc, CFG, (pmecc_readl_relaxed(host->ecc, CFG)
+ & ~PMECC_CFG_WRITE_OP) | PMECC_CFG_AUTO_ENABLE);
+
+ pmecc_writel(host->ecc, CTRL, PMECC_CTRL_ENABLE);
+ pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DATA);
+
+ chip->read_buf(mtd, buf, eccsize);
+ chip->read_buf(mtd, oob, mtd->oobsize);
+
+ end_time = jiffies + msecs_to_jiffies(PMECC_MAX_TIMEOUT_MS);
+ while ((pmecc_readl_relaxed(host->ecc, SR) & PMECC_SR_BUSY)) {
+ if (unlikely(time_after(jiffies, end_time))) {
+ dev_err(host->dev, "PMECC: Timeout to get error status.\n");
+ return -EIO;
+ }
+ cpu_relax();
+ }
+
+ stat = pmecc_readl_relaxed(host->ecc, ISR);
+ if (stat != 0)
+ if (pmecc_correction(mtd, stat, buf, &oob[eccpos[0]]) != 0)
+ return -EIO;
+
+ return 0;
+}
+
+static int atmel_nand_pmecc_write_page(struct mtd_info *mtd,
+ struct nand_chip *chip, const uint8_t *buf, int oob_required)
+{
+ struct atmel_nand_host *host = chip->priv;
+ uint32_t *eccpos = chip->ecc.layout->eccpos;
+ int i, j;
+ unsigned long end_time;
+
+ pmecc_writel(host->ecc, CTRL, PMECC_CTRL_RST);
+ pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE);
+
+ pmecc_writel(host->ecc, CFG, (pmecc_readl_relaxed(host->ecc, CFG) |
+ PMECC_CFG_WRITE_OP) & ~PMECC_CFG_AUTO_ENABLE);
+
+ pmecc_writel(host->ecc, CTRL, PMECC_CTRL_ENABLE);
+ pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DATA);
+
+ chip->write_buf(mtd, (u8 *)buf, mtd->writesize);
+
+ end_time = jiffies + msecs_to_jiffies(PMECC_MAX_TIMEOUT_MS);
+ while ((pmecc_readl_relaxed(host->ecc, SR) & PMECC_SR_BUSY)) {
+ if (unlikely(time_after(jiffies, end_time))) {
+ dev_err(host->dev, "PMECC: Timeout to get ECC value.\n");
+ return -EIO;
+ }
+ cpu_relax();
+ }
+
+ for (i = 0; i < host->pmecc_sector_number; i++) {
+ for (j = 0; j < host->pmecc_bytes_per_sector; j++) {
+ int pos;
+
+ pos = i * host->pmecc_bytes_per_sector + j;
+ chip->oob_poi[eccpos[pos]] =
+ pmecc_readb_ecc_relaxed(host->ecc, i, j);
+ }
+ }
+ chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+ return 0;
+}
+
+static void atmel_pmecc_core_init(struct mtd_info *mtd)
+{
+ struct nand_chip *nand_chip = mtd->priv;
+ struct atmel_nand_host *host = nand_chip->priv;
+ uint32_t val = 0;
+ struct nand_ecclayout *ecc_layout;
+
+ pmecc_writel(host->ecc, CTRL, PMECC_CTRL_RST);
+ pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE);
+
+ switch (host->pmecc_corr_cap) {
+ case 2:
+ val = PMECC_CFG_BCH_ERR2;
+ break;
+ case 4:
+ val = PMECC_CFG_BCH_ERR4;
+ break;
+ case 8:
+ val = PMECC_CFG_BCH_ERR8;
+ break;
+ case 12:
+ val = PMECC_CFG_BCH_ERR12;
+ break;
+ case 24:
+ val = PMECC_CFG_BCH_ERR24;
+ break;
+ }
+
+ if (host->pmecc_sector_size == 512)
+ val |= PMECC_CFG_SECTOR512;
+ else if (host->pmecc_sector_size == 1024)
+ val |= PMECC_CFG_SECTOR1024;
+
+ switch (host->pmecc_sector_number) {
+ case 1:
+ val |= PMECC_CFG_PAGE_1SECTOR;
+ break;
+ case 2:
+ val |= PMECC_CFG_PAGE_2SECTORS;
+ break;
+ case 4:
+ val |= PMECC_CFG_PAGE_4SECTORS;
+ break;
+ case 8:
+ val |= PMECC_CFG_PAGE_8SECTORS;
+ break;
+ }
+
+ val |= (PMECC_CFG_READ_OP | PMECC_CFG_SPARE_DISABLE
+ | PMECC_CFG_AUTO_DISABLE);
+ pmecc_writel(host->ecc, CFG, val);
+
+ ecc_layout = nand_chip->ecc.layout;
+ pmecc_writel(host->ecc, SAREA, mtd->oobsize - 1);
+ pmecc_writel(host->ecc, SADDR, ecc_layout->eccpos[0]);
+ pmecc_writel(host->ecc, EADDR,
+ ecc_layout->eccpos[ecc_layout->eccbytes - 1]);
+ /* See datasheet about PMECC Clock Control Register */
+ pmecc_writel(host->ecc, CLK, 2);
+ pmecc_writel(host->ecc, IDR, 0xff);
+ pmecc_writel(host->ecc, CTRL, PMECC_CTRL_ENABLE);
+}
+
+static int __init atmel_pmecc_nand_init_params(struct platform_device *pdev,
+ struct atmel_nand_host *host)
+{
+ struct mtd_info *mtd = &host->mtd;
+ struct nand_chip *nand_chip = &host->nand_chip;
+ struct resource *regs, *regs_pmerr, *regs_rom;
+ int cap, sector_size, err_no;
+
+ cap = host->pmecc_corr_cap;
+ sector_size = host->pmecc_sector_size;
+ dev_info(host->dev, "Initialize PMECC params, cap: %d, sector: %d\n",
+ cap, sector_size);
+
+ regs = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (!regs) {
+ dev_warn(host->dev,
+ "Can't get I/O resource regs for PMECC controller, rolling back on software ECC\n");
+ nand_chip->ecc.mode = NAND_ECC_SOFT;
+ return 0;
+ }
+
+ host->ecc = ioremap(regs->start, resource_size(regs));
+ if (host->ecc == NULL) {
+ dev_err(host->dev, "ioremap failed\n");
+ err_no = -EIO;
+ goto err_pmecc_ioremap;
+ }
+
+ regs_pmerr = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+ regs_rom = platform_get_resource(pdev, IORESOURCE_MEM, 3);
+ if (regs_pmerr && regs_rom) {
+ host->pmerrloc_base = ioremap(regs_pmerr->start,
+ resource_size(regs_pmerr));
+ host->pmecc_rom_base = ioremap(regs_rom->start,
+ resource_size(regs_rom));
+ }
+
+ if (!host->pmerrloc_base || !host->pmecc_rom_base) {
+ dev_err(host->dev,
+ "Can not get I/O resource for PMECC ERRLOC controller or ROM!\n");
+ err_no = -EIO;
+ goto err_pmloc_ioremap;
+ }
+
+ /* ECC is calculated for the whole page (1 step) */
+ nand_chip->ecc.size = mtd->writesize;
+
+ /* set ECC page size and oob layout */
+ switch (mtd->writesize) {
+ case 2048:
+ host->pmecc_degree = PMECC_GF_DIMENSION_13;
+ host->pmecc_cw_len = (1 << host->pmecc_degree) - 1;
+ host->pmecc_sector_number = mtd->writesize / sector_size;
+ host->pmecc_bytes_per_sector = pmecc_get_ecc_bytes(
+ cap, sector_size);
+ host->pmecc_alpha_to = pmecc_get_alpha_to(host);
+ host->pmecc_index_of = host->pmecc_rom_base +
+ host->pmecc_lookup_table_offset;
+
+ nand_chip->ecc.steps = 1;
+ nand_chip->ecc.strength = cap;
+ nand_chip->ecc.bytes = host->pmecc_bytes_per_sector *
+ host->pmecc_sector_number;
+ if (nand_chip->ecc.bytes > mtd->oobsize - 2) {
+ dev_err(host->dev, "No room for ECC bytes\n");
+ err_no = -EINVAL;
+ goto err_no_ecc_room;
+ }
+ pmecc_config_ecc_layout(&atmel_pmecc_oobinfo,
+ mtd->oobsize,
+ nand_chip->ecc.bytes);
+ nand_chip->ecc.layout = &atmel_pmecc_oobinfo;
+ break;
+ case 512:
+ case 1024:
+ case 4096:
+ /* TODO */
+ dev_warn(host->dev,
+ "Unsupported page size for PMECC, use Software ECC\n");
+ default:
+ /* page size not handled by HW ECC */
+ /* switching back to soft ECC */
+ nand_chip->ecc.mode = NAND_ECC_SOFT;
+ return 0;
+ }
+
+ /* Allocate data for PMECC computation */
+ err_no = pmecc_data_alloc(host);
+ if (err_no) {
+ dev_err(host->dev,
+ "Cannot allocate memory for PMECC computation!\n");
+ goto err_pmecc_data_alloc;
+ }
+
+ nand_chip->ecc.read_page = atmel_nand_pmecc_read_page;
+ nand_chip->ecc.write_page = atmel_nand_pmecc_write_page;
+
+ atmel_pmecc_core_init(mtd);
+
+ return 0;
+
+err_pmecc_data_alloc:
+err_no_ecc_room:
+err_pmloc_ioremap:
+ iounmap(host->ecc);
+ if (host->pmerrloc_base)
+ iounmap(host->pmerrloc_base);
+ if (host->pmecc_rom_base)
+ iounmap(host->pmecc_rom_base);
+err_pmecc_ioremap:
+ return err_no;
+}
+
+/*
* Calculate HW ECC
*
* function called after a write
@@ -481,7 +1208,8 @@ static void atmel_nand_hwctl(struct mtd_info *mtd, int mode)
static int __devinit atmel_of_init_port(struct atmel_nand_host *host,
struct device_node *np)
{
- u32 val;
+ u32 val, table_offset;
+ u32 offset[2];
int ecc_mode;
struct atmel_nand_data *board = &host->board;
enum of_gpio_flags flags;
@@ -517,6 +1245,50 @@ static int __devinit atmel_of_init_port(struct atmel_nand_host *host,
board->enable_pin = of_get_gpio(np, 1);
board->det_pin = of_get_gpio(np, 2);
+ host->has_pmecc = of_property_read_bool(np, "atmel,has-pmecc");
+
+ if (!(board->ecc_mode == NAND_ECC_HW) || !host->has_pmecc)
+ return 0; /* Not using PMECC */
+
+ /* use PMECC, get correction capability, sector size and lookup
+ * table offset.
+ */
+ if (of_property_read_u32(np, "atmel,pmecc-cap", &val) != 0) {
+ dev_err(host->dev, "Cannot decide PMECC Capability\n");
+ return -EINVAL;
+ } else if ((val != 2) && (val != 4) && (val != 8) && (val != 12) &&
+ (val != 24)) {
+ dev_err(host->dev,
+ "Unsupported PMECC correction capability: %d; should be 2, 4, 8, 12 or 24\n",
+ val);
+ return -EINVAL;
+ }
+ host->pmecc_corr_cap = (u8)val;
+
+ if (of_property_read_u32(np, "atmel,pmecc-sector-size", &val) != 0) {
+ dev_err(host->dev, "Cannot decide PMECC Sector Size\n");
+ return -EINVAL;
+ } else if ((val != 512) && (val != 1024)) {
+ dev_err(host->dev,
+ "Unsupported PMECC sector size: %d; should be 512 or 1024 bytes\n",
+ val);
+ return -EINVAL;
+ }
+ host->pmecc_sector_size = (u16)val;
+
+ if (of_property_read_u32_array(np, "atmel,pmecc-lookup-table-offset",
+ offset, 2) != 0) {
+ dev_err(host->dev, "Cannot get PMECC lookup table offset\n");
+ return -EINVAL;
+ }
+ table_offset = host->pmecc_sector_size == 512 ? offset[0] : offset[1];
+
+ if (!table_offset) {
+ dev_err(host->dev, "Invalid PMECC lookup table offset\n");
+ return -EINVAL;
+ }
+ host->pmecc_lookup_table_offset = table_offset;
+
return 0;
}
#else
@@ -527,6 +1299,66 @@ static int __devinit atmel_of_init_port(struct atmel_nand_host *host,
}
#endif
+static int __init atmel_hw_nand_init_params(struct platform_device *pdev,
+ struct atmel_nand_host *host)
+{
+ struct mtd_info *mtd = &host->mtd;
+ struct nand_chip *nand_chip = &host->nand_chip;
+ struct resource *regs;
+
+ regs = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (!regs) {
+ dev_err(host->dev,
+ "Can't get I/O resource regs, use software ECC\n");
+ nand_chip->ecc.mode = NAND_ECC_SOFT;
+ return 0;
+ }
+
+ host->ecc = ioremap(regs->start, resource_size(regs));
+ if (host->ecc == NULL) {
+ dev_err(host->dev, "ioremap failed\n");
+ return -EIO;
+ }
+
+ /* ECC is calculated for the whole page (1 step) */
+ nand_chip->ecc.size = mtd->writesize;
+
+ /* set ECC page size and oob layout */
+ switch (mtd->writesize) {
+ case 512:
+ nand_chip->ecc.layout = &atmel_oobinfo_small;
+ ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_528);
+ break;
+ case 1024:
+ nand_chip->ecc.layout = &atmel_oobinfo_large;
+ ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_1056);
+ break;
+ case 2048:
+ nand_chip->ecc.layout = &atmel_oobinfo_large;
+ ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_2112);
+ break;
+ case 4096:
+ nand_chip->ecc.layout = &atmel_oobinfo_large;
+ ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_4224);
+ break;
+ default:
+ /* page size not handled by HW ECC */
+ /* switching back to soft ECC */
+ nand_chip->ecc.mode = NAND_ECC_SOFT;
+ return 0;
+ }
+
+ /* set up for HW ECC */
+ nand_chip->ecc.calculate = atmel_nand_calculate;
+ nand_chip->ecc.correct = atmel_nand_correct;
+ nand_chip->ecc.hwctl = atmel_nand_hwctl;
+ nand_chip->ecc.read_page = atmel_nand_read_page;
+ nand_chip->ecc.bytes = 4;
+ nand_chip->ecc.strength = 1;
+
+ return 0;
+}
+
/*
* Probe for the NAND device.
*/
@@ -535,7 +1367,6 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
struct atmel_nand_host *host;
struct mtd_info *mtd;
struct nand_chip *nand_chip;
- struct resource *regs;
struct resource *mem;
struct mtd_part_parser_data ppdata = {};
int res;
@@ -568,7 +1399,7 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
if (pdev->dev.of_node) {
res = atmel_of_init_port(host, pdev->dev.of_node);
if (res)
- goto err_nand_ioremap;
+ goto err_ecc_ioremap;
} else {
memcpy(&host->board, pdev->dev.platform_data,
sizeof(struct atmel_nand_data));
@@ -583,33 +1414,45 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
nand_chip->IO_ADDR_W = host->io_base;
nand_chip->cmd_ctrl = atmel_nand_cmd_ctrl;
- if (gpio_is_valid(host->board.rdy_pin))
- nand_chip->dev_ready = atmel_nand_device_ready;
+ if (gpio_is_valid(host->board.rdy_pin)) {
+ res = gpio_request(host->board.rdy_pin, "nand_rdy");
+ if (res < 0) {
+ dev_err(&pdev->dev,
+ "can't request rdy gpio %d\n",
+ host->board.rdy_pin);
+ goto err_ecc_ioremap;
+ }
- nand_chip->ecc.mode = host->board.ecc_mode;
+ res = gpio_direction_input(host->board.rdy_pin);
+ if (res < 0) {
+ dev_err(&pdev->dev,
+ "can't request input direction rdy gpio %d\n",
+ host->board.rdy_pin);
+ goto err_ecc_ioremap;
+ }
- regs = platform_get_resource(pdev, IORESOURCE_MEM, 1);
- if (!regs && nand_chip->ecc.mode == NAND_ECC_HW) {
- printk(KERN_ERR "atmel_nand: can't get I/O resource "
- "regs\nFalling back on software ECC\n");
- nand_chip->ecc.mode = NAND_ECC_SOFT;
+ nand_chip->dev_ready = atmel_nand_device_ready;
}
- if (nand_chip->ecc.mode == NAND_ECC_HW) {
- host->ecc = ioremap(regs->start, resource_size(regs));
- if (host->ecc == NULL) {
- printk(KERN_ERR "atmel_nand: ioremap failed\n");
- res = -EIO;
+ if (gpio_is_valid(host->board.enable_pin)) {
+ res = gpio_request(host->board.enable_pin, "nand_enable");
+ if (res < 0) {
+ dev_err(&pdev->dev,
+ "can't request enable gpio %d\n",
+ host->board.enable_pin);
+ goto err_ecc_ioremap;
+ }
+
+ res = gpio_direction_output(host->board.enable_pin, 1);
+ if (res < 0) {
+ dev_err(&pdev->dev,
+ "can't request output direction enable gpio %d\n",
+ host->board.enable_pin);
goto err_ecc_ioremap;
}
- nand_chip->ecc.calculate = atmel_nand_calculate;
- nand_chip->ecc.correct = atmel_nand_correct;
- nand_chip->ecc.hwctl = atmel_nand_hwctl;
- nand_chip->ecc.read_page = atmel_nand_read_page;
- nand_chip->ecc.bytes = 4;
- nand_chip->ecc.strength = 1;
}
+ nand_chip->ecc.mode = host->board.ecc_mode;
nand_chip->chip_delay = 20; /* 20us command delay time */
if (host->board.bus_width_16) /* 16-bit bus width */
@@ -622,6 +1465,22 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
atmel_nand_enable(host);
if (gpio_is_valid(host->board.det_pin)) {
+ res = gpio_request(host->board.det_pin, "nand_det");
+ if (res < 0) {
+ dev_err(&pdev->dev,
+ "can't request det gpio %d\n",
+ host->board.det_pin);
+ goto err_no_card;
+ }
+
+ res = gpio_direction_input(host->board.det_pin);
+ if (res < 0) {
+ dev_err(&pdev->dev,
+ "can't request input direction det gpio %d\n",
+ host->board.det_pin);
+ goto err_no_card;
+ }
+
if (gpio_get_value(host->board.det_pin)) {
printk(KERN_INFO "No SmartMedia card inserted.\n");
res = -ENXIO;
@@ -661,40 +1520,13 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
}
if (nand_chip->ecc.mode == NAND_ECC_HW) {
- /* ECC is calculated for the whole page (1 step) */
- nand_chip->ecc.size = mtd->writesize;
-
- /* set ECC page size and oob layout */
- switch (mtd->writesize) {
- case 512:
- nand_chip->ecc.layout = &atmel_oobinfo_small;
- ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_528);
- break;
- case 1024:
- nand_chip->ecc.layout = &atmel_oobinfo_large;
- ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_1056);
- break;
- case 2048:
- nand_chip->ecc.layout = &atmel_oobinfo_large;
- ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_2112);
- break;
- case 4096:
- nand_chip->ecc.layout = &atmel_oobinfo_large;
- ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_4224);
- break;
- default:
- /* page size not handled by HW ECC */
- /* switching back to soft ECC */
- nand_chip->ecc.mode = NAND_ECC_SOFT;
- nand_chip->ecc.calculate = NULL;
- nand_chip->ecc.correct = NULL;
- nand_chip->ecc.hwctl = NULL;
- nand_chip->ecc.read_page = NULL;
- nand_chip->ecc.postpad = 0;
- nand_chip->ecc.prepad = 0;
- nand_chip->ecc.bytes = 0;
- break;
- }
+ if (host->has_pmecc)
+ res = atmel_pmecc_nand_init_params(pdev, host);
+ else
+ res = atmel_hw_nand_init_params(pdev, host);
+
+ if (res != 0)
+ goto err_hw_ecc;
}
/* second phase scan */
@@ -711,14 +1543,23 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
return res;
err_scan_tail:
+ if (host->has_pmecc && host->nand_chip.ecc.mode == NAND_ECC_HW) {
+ pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE);
+ pmecc_data_free(host);
+ }
+ if (host->ecc)
+ iounmap(host->ecc);
+ if (host->pmerrloc_base)
+ iounmap(host->pmerrloc_base);
+ if (host->pmecc_rom_base)
+ iounmap(host->pmecc_rom_base);
+err_hw_ecc:
err_scan_ident:
err_no_card:
atmel_nand_disable(host);
platform_set_drvdata(pdev, NULL);
if (host->dma_chan)
dma_release_channel(host->dma_chan);
- if (host->ecc)
- iounmap(host->ecc);
err_ecc_ioremap:
iounmap(host->io_base);
err_nand_ioremap:
@@ -738,8 +1579,28 @@ static int __exit atmel_nand_remove(struct platform_device *pdev)
atmel_nand_disable(host);
+ if (host->has_pmecc && host->nand_chip.ecc.mode == NAND_ECC_HW) {
+ pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE);
+ pmerrloc_writel(host->pmerrloc_base, ELDIS,
+ PMERRLOC_DISABLE);
+ pmecc_data_free(host);
+ }
+
+ if (gpio_is_valid(host->board.det_pin))
+ gpio_free(host->board.det_pin);
+
+ if (gpio_is_valid(host->board.enable_pin))
+ gpio_free(host->board.enable_pin);
+
+ if (gpio_is_valid(host->board.rdy_pin))
+ gpio_free(host->board.rdy_pin);
+
if (host->ecc)
iounmap(host->ecc);
+ if (host->pmecc_rom_base)
+ iounmap(host->pmecc_rom_base);
+ if (host->pmerrloc_base)
+ iounmap(host->pmerrloc_base);
if (host->dma_chan)
dma_release_channel(host->dma_chan);
diff --git a/drivers/mtd/nand/atmel_nand_ecc.h b/drivers/mtd/nand/atmel_nand_ecc.h
index 578c776..8a1e9a6 100644
--- a/drivers/mtd/nand/atmel_nand_ecc.h
+++ b/drivers/mtd/nand/atmel_nand_ecc.h
@@ -3,7 +3,7 @@
* Based on AT91SAM9260 datasheet revision B.
*
* Copyright (C) 2007 Andrew Victor
- * Copyright (C) 2007 Atmel Corporation.
+ * Copyright (C) 2007 - 2012 Atmel 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
@@ -36,4 +36,116 @@
#define ATMEL_ECC_NPR 0x10 /* NParity register */
#define ATMEL_ECC_NPARITY (0xffff << 0) /* NParity */
+/* PMECC Register Definitions */
+#define ATMEL_PMECC_CFG 0x000 /* Configuration Register */
+#define PMECC_CFG_BCH_ERR2 (0 << 0)
+#define PMECC_CFG_BCH_ERR4 (1 << 0)
+#define PMECC_CFG_BCH_ERR8 (2 << 0)
+#define PMECC_CFG_BCH_ERR12 (3 << 0)
+#define PMECC_CFG_BCH_ERR24 (4 << 0)
+
+#define PMECC_CFG_SECTOR512 (0 << 4)
+#define PMECC_CFG_SECTOR1024 (1 << 4)
+
+#define PMECC_CFG_PAGE_1SECTOR (0 << 8)
+#define PMECC_CFG_PAGE_2SECTORS (1 << 8)
+#define PMECC_CFG_PAGE_4SECTORS (2 << 8)
+#define PMECC_CFG_PAGE_8SECTORS (3 << 8)
+
+#define PMECC_CFG_READ_OP (0 << 12)
+#define PMECC_CFG_WRITE_OP (1 << 12)
+
+#define PMECC_CFG_SPARE_ENABLE (1 << 16)
+#define PMECC_CFG_SPARE_DISABLE (0 << 16)
+
+#define PMECC_CFG_AUTO_ENABLE (1 << 20)
+#define PMECC_CFG_AUTO_DISABLE (0 << 20)
+
+#define ATMEL_PMECC_SAREA 0x004 /* Spare area size */
+#define ATMEL_PMECC_SADDR 0x008 /* PMECC starting address */
+#define ATMEL_PMECC_EADDR 0x00c /* PMECC ending address */
+#define ATMEL_PMECC_CLK 0x010 /* PMECC clock control */
+#define PMECC_CLK_133MHZ (2 << 0)
+
+#define ATMEL_PMECC_CTRL 0x014 /* PMECC control register */
+#define PMECC_CTRL_RST (1 << 0)
+#define PMECC_CTRL_DATA (1 << 1)
+#define PMECC_CTRL_USER (1 << 2)
+#define PMECC_CTRL_ENABLE (1 << 4)
+#define PMECC_CTRL_DISABLE (1 << 5)
+
+#define ATMEL_PMECC_SR 0x018 /* PMECC status register */
+#define PMECC_SR_BUSY (1 << 0)
+#define PMECC_SR_ENABLE (1 << 4)
+
+#define ATMEL_PMECC_IER 0x01c /* PMECC interrupt enable */
+#define PMECC_IER_ENABLE (1 << 0)
+#define ATMEL_PMECC_IDR 0x020 /* PMECC interrupt disable */
+#define PMECC_IER_DISABLE (1 << 0)
+#define ATMEL_PMECC_IMR 0x024 /* PMECC interrupt mask */
+#define PMECC_IER_MASK (1 << 0)
+#define ATMEL_PMECC_ISR 0x028 /* PMECC interrupt status */
+#define ATMEL_PMECC_ECCx 0x040 /* PMECC ECC x */
+#define ATMEL_PMECC_REMx 0x240 /* PMECC REM x */
+
+/* PMERRLOC Register Definitions */
+#define ATMEL_PMERRLOC_ELCFG 0x000 /* Error location config */
+#define PMERRLOC_ELCFG_SECTOR_512 (0 << 0)
+#define PMERRLOC_ELCFG_SECTOR_1024 (1 << 0)
+#define PMERRLOC_ELCFG_NUM_ERRORS(n) ((n) << 16)
+
+#define ATMEL_PMERRLOC_ELPRIM 0x004 /* Error location primitive */
+#define ATMEL_PMERRLOC_ELEN 0x008 /* Error location enable */
+#define ATMEL_PMERRLOC_ELDIS 0x00c /* Error location disable */
+#define PMERRLOC_DISABLE (1 << 0)
+
+#define ATMEL_PMERRLOC_ELSR 0x010 /* Error location status */
+#define PMERRLOC_ELSR_BUSY (1 << 0)
+#define ATMEL_PMERRLOC_ELIER 0x014 /* Error location int enable */
+#define ATMEL_PMERRLOC_ELIDR 0x018 /* Error location int disable */
+#define ATMEL_PMERRLOC_ELIMR 0x01c /* Error location int mask */
+#define ATMEL_PMERRLOC_ELISR 0x020 /* Error location int status */
+#define PMERRLOC_ERR_NUM_MASK (0x1f << 8)
+#define PMERRLOC_CALC_DONE (1 << 0)
+#define ATMEL_PMERRLOC_SIGMAx 0x028 /* Error location SIGMA x */
+#define ATMEL_PMERRLOC_ELx 0x08c /* Error location x */
+
+/* Register access macros for PMECC */
+#define pmecc_readl_relaxed(addr, reg) \
+ readl_relaxed((addr) + ATMEL_PMECC_##reg)
+
+#define pmecc_writel(addr, reg, value) \
+ writel((value), (addr) + ATMEL_PMECC_##reg)
+
+#define pmecc_readb_ecc_relaxed(addr, sector, n) \
+ readb_relaxed((addr) + ATMEL_PMECC_ECCx + ((sector) * 0x40) + (n))
+
+#define pmecc_readl_rem_relaxed(addr, sector, n) \
+ readl_relaxed((addr) + ATMEL_PMECC_REMx + ((sector) * 0x40) + ((n) * 4))
+
+#define pmerrloc_readl_relaxed(addr, reg) \
+ readl_relaxed((addr) + ATMEL_PMERRLOC_##reg)
+
+#define pmerrloc_writel(addr, reg, value) \
+ writel((value), (addr) + ATMEL_PMERRLOC_##reg)
+
+#define pmerrloc_writel_sigma_relaxed(addr, n, value) \
+ writel_relaxed((value), (addr) + ATMEL_PMERRLOC_SIGMAx + ((n) * 4))
+
+#define pmerrloc_readl_sigma_relaxed(addr, n) \
+ readl_relaxed((addr) + ATMEL_PMERRLOC_SIGMAx + ((n) * 4))
+
+#define pmerrloc_readl_el_relaxed(addr, n) \
+ readl_relaxed((addr) + ATMEL_PMERRLOC_ELx + ((n) * 4))
+
+/* Galois field dimension */
+#define PMECC_GF_DIMENSION_13 13
+#define PMECC_GF_DIMENSION_14 14
+
+#define PMECC_LOOKUP_TABLE_SIZE_512 0x2000
+#define PMECC_LOOKUP_TABLE_SIZE_1024 0x4000
+
+/* Time out value for reading PMECC status register */
+#define PMECC_MAX_TIMEOUT_MS 100
+
#endif
diff --git a/drivers/mtd/nand/au1550nd.c b/drivers/mtd/nand/au1550nd.c
index 9f609d2..5c47b20 100644
--- a/drivers/mtd/nand/au1550nd.c
+++ b/drivers/mtd/nand/au1550nd.c
@@ -141,28 +141,6 @@ static void au_read_buf(struct mtd_info *mtd, u_char *buf, int len)
}
/**
- * au_verify_buf - Verify chip data against buffer
- * @mtd: MTD device structure
- * @buf: buffer containing the data to compare
- * @len: number of bytes to compare
- *
- * verify function for 8bit buswidth
- */
-static int au_verify_buf(struct mtd_info *mtd, const u_char *buf, int len)
-{
- int i;
- struct nand_chip *this = mtd->priv;
-
- for (i = 0; i < len; i++) {
- if (buf[i] != readb(this->IO_ADDR_R))
- return -EFAULT;
- au_sync();
- }
-
- return 0;
-}
-
-/**
* au_write_buf16 - write buffer to chip
* @mtd: MTD device structure
* @buf: data buffer
@@ -205,29 +183,6 @@ static void au_read_buf16(struct mtd_info *mtd, u_char *buf, int len)
}
}
-/**
- * au_verify_buf16 - Verify chip data against buffer
- * @mtd: MTD device structure
- * @buf: buffer containing the data to compare
- * @len: number of bytes to compare
- *
- * verify function for 16bit buswidth
- */
-static int au_verify_buf16(struct mtd_info *mtd, const u_char *buf, int len)
-{
- int i;
- struct nand_chip *this = mtd->priv;
- u16 *p = (u16 *) buf;
- len >>= 1;
-
- for (i = 0; i < len; i++) {
- if (p[i] != readw(this->IO_ADDR_R))
- return -EFAULT;
- au_sync();
- }
- return 0;
-}
-
/* Select the chip by setting nCE to low */
#define NAND_CTL_SETNCE 1
/* Deselect the chip by setting nCE to high */
@@ -516,7 +471,6 @@ static int __devinit au1550nd_probe(struct platform_device *pdev)
this->read_word = au_read_word;
this->write_buf = (pd->devwidth) ? au_write_buf16 : au_write_buf;
this->read_buf = (pd->devwidth) ? au_read_buf16 : au_read_buf;
- this->verify_buf = (pd->devwidth) ? au_verify_buf16 : au_verify_buf;
ret = nand_scan(&ctx->info, 1);
if (ret) {
diff --git a/drivers/mtd/nand/bcm_umi_bch.c b/drivers/mtd/nand/bcm_umi_bch.c
deleted file mode 100644
index 5914bb3..0000000
--- a/drivers/mtd/nand/bcm_umi_bch.c
+++ /dev/null
@@ -1,217 +0,0 @@
-/*****************************************************************************
-* Copyright 2004 - 2009 Broadcom Corporation. All rights reserved.
-*
-* Unless you and Broadcom execute a separate written software license
-* agreement governing use of this software, this software is licensed to you
-* under the terms of the GNU General Public License version 2, available at
-* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
-*
-* Notwithstanding the above, under no circumstances may you combine this
-* software in any way with any other Broadcom software provided under a
-* license other than the GPL, without Broadcom's express prior written
-* consent.
-*****************************************************************************/
-
-/* ---- Include Files ---------------------------------------------------- */
-#include "nand_bcm_umi.h"
-
-/* ---- External Variable Declarations ----------------------------------- */
-/* ---- External Function Prototypes ------------------------------------- */
-/* ---- Public Variables ------------------------------------------------- */
-/* ---- Private Constants and Types -------------------------------------- */
-
-/* ---- Private Function Prototypes -------------------------------------- */
-static int bcm_umi_bch_read_page_hwecc(struct mtd_info *mtd,
- struct nand_chip *chip, uint8_t *buf, int oob_required, int page);
-static void bcm_umi_bch_write_page_hwecc(struct mtd_info *mtd,
- struct nand_chip *chip, const uint8_t *buf, int oob_required);
-
-/* ---- Private Variables ------------------------------------------------ */
-
-/*
-** nand_hw_eccoob
-** New oob placement block for use with hardware ecc generation.
-*/
-static struct nand_ecclayout nand_hw_eccoob_512 = {
- /* Reserve 5 for BI indicator */
- .oobfree = {
-#if (NAND_ECC_NUM_BYTES > 3)
- {.offset = 0, .length = 2}
-#else
- {.offset = 0, .length = 5},
- {.offset = 6, .length = 7}
-#endif
- }
-};
-
-/*
-** We treat the OOB for a 2K page as if it were 4 512 byte oobs,
-** except the BI is at byte 0.
-*/
-static struct nand_ecclayout nand_hw_eccoob_2048 = {
- /* Reserve 0 as BI indicator */
- .oobfree = {
-#if (NAND_ECC_NUM_BYTES > 10)
- {.offset = 1, .length = 2},
-#elif (NAND_ECC_NUM_BYTES > 7)
- {.offset = 1, .length = 5},
- {.offset = 16, .length = 6},
- {.offset = 32, .length = 6},
- {.offset = 48, .length = 6}
-#else
- {.offset = 1, .length = 8},
- {.offset = 16, .length = 9},
- {.offset = 32, .length = 9},
- {.offset = 48, .length = 9}
-#endif
- }
-};
-
-/* We treat the OOB for a 4K page as if it were 8 512 byte oobs,
- * except the BI is at byte 0. */
-static struct nand_ecclayout nand_hw_eccoob_4096 = {
- /* Reserve 0 as BI indicator */
- .oobfree = {
-#if (NAND_ECC_NUM_BYTES > 10)
- {.offset = 1, .length = 2},
- {.offset = 16, .length = 3},
- {.offset = 32, .length = 3},
- {.offset = 48, .length = 3},
- {.offset = 64, .length = 3},
- {.offset = 80, .length = 3},
- {.offset = 96, .length = 3},
- {.offset = 112, .length = 3}
-#else
- {.offset = 1, .length = 5},
- {.offset = 16, .length = 6},
- {.offset = 32, .length = 6},
- {.offset = 48, .length = 6},
- {.offset = 64, .length = 6},
- {.offset = 80, .length = 6},
- {.offset = 96, .length = 6},
- {.offset = 112, .length = 6}
-#endif
- }
-};
-
-/* ---- Private Functions ------------------------------------------------ */
-/* ==== Public Functions ================================================= */
-
-/****************************************************************************
-*
-* bcm_umi_bch_read_page_hwecc - hardware ecc based page read function
-* @mtd: mtd info structure
-* @chip: nand chip info structure
-* @buf: buffer to store read data
-* @oob_required: caller expects OOB data read to chip->oob_poi
-*
-***************************************************************************/
-static int bcm_umi_bch_read_page_hwecc(struct mtd_info *mtd,
- struct nand_chip *chip, uint8_t * buf,
- int oob_required, int page)
-{
- int sectorIdx = 0;
- int eccsize = chip->ecc.size;
- int eccsteps = chip->ecc.steps;
- uint8_t *datap = buf;
- uint8_t eccCalc[NAND_ECC_NUM_BYTES];
- int sectorOobSize = mtd->oobsize / eccsteps;
- int stat;
- unsigned int max_bitflips = 0;
-
- for (sectorIdx = 0; sectorIdx < eccsteps;
- sectorIdx++, datap += eccsize) {
- if (sectorIdx > 0) {
- /* Seek to page location within sector */
- chip->cmdfunc(mtd, NAND_CMD_RNDOUT, sectorIdx * eccsize,
- -1);
- }
-
- /* Enable hardware ECC before reading the buf */
- nand_bcm_umi_bch_enable_read_hwecc();
-
- /* Read in data */
- bcm_umi_nand_read_buf(mtd, datap, eccsize);
-
- /* Pause hardware ECC after reading the buf */
- nand_bcm_umi_bch_pause_read_ecc_calc();
-
- /* Read the OOB ECC */
- chip->cmdfunc(mtd, NAND_CMD_RNDOUT,
- mtd->writesize + sectorIdx * sectorOobSize, -1);
- nand_bcm_umi_bch_read_oobEcc(mtd->writesize, eccCalc,
- NAND_ECC_NUM_BYTES,
- chip->oob_poi +
- sectorIdx * sectorOobSize);
-
- /* Correct any ECC detected errors */
- stat =
- nand_bcm_umi_bch_correct_page(datap, eccCalc,
- NAND_ECC_NUM_BYTES);
-
- /* Update Stats */
- if (stat < 0) {
-#if defined(NAND_BCM_UMI_DEBUG)
- printk(KERN_WARNING "%s uncorr_err sectorIdx=%d\n",
- __func__, sectorIdx);
- printk(KERN_WARNING
- "%s data %02x %02x %02x %02x "
- "%02x %02x %02x %02x\n",
- __func__, datap[0], datap[1], datap[2], datap[3],
- datap[4], datap[5], datap[6], datap[7]);
- printk(KERN_WARNING
- "%s ecc %02x %02x %02x %02x "
- "%02x %02x %02x %02x %02x %02x "
- "%02x %02x %02x\n",
- __func__, eccCalc[0], eccCalc[1], eccCalc[2],
- eccCalc[3], eccCalc[4], eccCalc[5], eccCalc[6],
- eccCalc[7], eccCalc[8], eccCalc[9], eccCalc[10],
- eccCalc[11], eccCalc[12]);
- BUG();
-#endif
- mtd->ecc_stats.failed++;
- } else {
-#if defined(NAND_BCM_UMI_DEBUG)
- if (stat > 0) {
- printk(KERN_INFO
- "%s %d correctable_errors detected\n",
- __func__, stat);
- }
-#endif
- mtd->ecc_stats.corrected += stat;
- max_bitflips = max_t(unsigned int, max_bitflips, stat);
- }
- }
- return max_bitflips;
-}
-
-/****************************************************************************
-*
-* bcm_umi_bch_write_page_hwecc - hardware ecc based page write function
-* @mtd: mtd info structure
-* @chip: nand chip info structure
-* @buf: data buffer
-* @oob_required: must write chip->oob_poi to OOB
-*
-***************************************************************************/
-static void bcm_umi_bch_write_page_hwecc(struct mtd_info *mtd,
- struct nand_chip *chip, const uint8_t *buf, int oob_required)
-{
- int sectorIdx = 0;
- int eccsize = chip->ecc.size;
- int eccsteps = chip->ecc.steps;
- const uint8_t *datap = buf;
- uint8_t *oobp = chip->oob_poi;
- int sectorOobSize = mtd->oobsize / eccsteps;
-
- for (sectorIdx = 0; sectorIdx < eccsteps;
- sectorIdx++, datap += eccsize, oobp += sectorOobSize) {
- /* Enable hardware ECC before writing the buf */
- nand_bcm_umi_bch_enable_write_hwecc();
- bcm_umi_nand_write_buf(mtd, datap, eccsize);
- nand_bcm_umi_bch_write_oobEcc(mtd->writesize, oobp,
- NAND_ECC_NUM_BYTES);
- }
-
- bcm_umi_nand_write_buf(mtd, chip->oob_poi, mtd->oobsize);
-}
diff --git a/drivers/mtd/nand/bcm_umi_nand.c b/drivers/mtd/nand/bcm_umi_nand.c
deleted file mode 100644
index d0d1bd4..0000000
--- a/drivers/mtd/nand/bcm_umi_nand.c
+++ /dev/null
@@ -1,555 +0,0 @@
-/*****************************************************************************
-* Copyright 2004 - 2009 Broadcom Corporation. All rights reserved.
-*
-* Unless you and Broadcom execute a separate written software license
-* agreement governing use of this software, this software is licensed to you
-* under the terms of the GNU General Public License version 2, available at
-* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
-*
-* Notwithstanding the above, under no circumstances may you combine this
-* software in any way with any other Broadcom software provided under a
-* license other than the GPL, without Broadcom's express prior written
-* consent.
-*****************************************************************************/
-
-/* ---- Include Files ---------------------------------------------------- */
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/ioport.h>
-#include <linux/device.h>
-#include <linux/delay.h>
-#include <linux/err.h>
-#include <linux/io.h>
-#include <linux/platform_device.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
-#include <linux/mtd/nand_ecc.h>
-#include <linux/mtd/partitions.h>
-
-#include <asm/mach-types.h>
-
-#include <mach/reg_nand.h>
-#include <mach/reg_umi.h>
-
-#include "nand_bcm_umi.h"
-
-#include <mach/memory_settings.h>
-
-#define USE_DMA 1
-#include <mach/dma.h>
-#include <linux/dma-mapping.h>
-#include <linux/completion.h>
-
-/* ---- External Variable Declarations ----------------------------------- */
-/* ---- External Function Prototypes ------------------------------------- */
-/* ---- Public Variables ------------------------------------------------- */
-/* ---- Private Constants and Types -------------------------------------- */
-static const __devinitconst char gBanner[] = KERN_INFO \
- "BCM UMI MTD NAND Driver: 1.00\n";
-
-#if NAND_ECC_BCH
-static uint8_t scan_ff_pattern[] = { 0xff };
-
-static struct nand_bbt_descr largepage_bbt = {
- .options = 0,
- .offs = 0,
- .len = 1,
- .pattern = scan_ff_pattern
-};
-#endif
-
-/*
-** Preallocate a buffer to avoid having to do this every dma operation.
-** This is the size of the preallocated coherent DMA buffer.
-*/
-#if USE_DMA
-#define DMA_MIN_BUFLEN 512
-#define DMA_MAX_BUFLEN PAGE_SIZE
-#define USE_DIRECT_IO(len) (((len) < DMA_MIN_BUFLEN) || \
- ((len) > DMA_MAX_BUFLEN))
-
-/*
- * The current NAND data space goes from 0x80001900 to 0x80001FFF,
- * which is only 0x700 = 1792 bytes long. This is too small for 2K, 4K page
- * size NAND flash. Need to break the DMA down to multiple 1Ks.
- *
- * Need to make sure REG_NAND_DATA_PADDR + DMA_MAX_LEN < 0x80002000
- */
-#define DMA_MAX_LEN 1024
-
-#else /* !USE_DMA */
-#define DMA_MIN_BUFLEN 0
-#define DMA_MAX_BUFLEN 0
-#define USE_DIRECT_IO(len) 1
-#endif
-/* ---- Private Function Prototypes -------------------------------------- */
-static void bcm_umi_nand_read_buf(struct mtd_info *mtd, u_char * buf, int len);
-static void bcm_umi_nand_write_buf(struct mtd_info *mtd, const u_char * buf,
- int len);
-
-/* ---- Private Variables ------------------------------------------------ */
-static struct mtd_info *board_mtd;
-static void __iomem *bcm_umi_io_base;
-static void *virtPtr;
-static dma_addr_t physPtr;
-static struct completion nand_comp;
-
-/* ---- Private Functions ------------------------------------------------ */
-#if NAND_ECC_BCH
-#include "bcm_umi_bch.c"
-#else
-#include "bcm_umi_hamming.c"
-#endif
-
-#if USE_DMA
-
-/* Handler called when the DMA finishes. */
-static void nand_dma_handler(DMA_Device_t dev, int reason, void *userData)
-{
- complete(&nand_comp);
-}
-
-static int nand_dma_init(void)
-{
- int rc;
-
- rc = dma_set_device_handler(DMA_DEVICE_NAND_MEM_TO_MEM,
- nand_dma_handler, NULL);
- if (rc != 0) {
- printk(KERN_ERR "dma_set_device_handler failed: %d\n", rc);
- return rc;
- }
-
- virtPtr =
- dma_alloc_coherent(NULL, DMA_MAX_BUFLEN, &physPtr, GFP_KERNEL);
- if (virtPtr == NULL) {
- printk(KERN_ERR "NAND - Failed to allocate memory for DMA buffer\n");
- return -ENOMEM;
- }
-
- return 0;
-}
-
-static void nand_dma_term(void)
-{
- if (virtPtr != NULL)
- dma_free_coherent(NULL, DMA_MAX_BUFLEN, virtPtr, physPtr);
-}
-
-static void nand_dma_read(void *buf, int len)
-{
- int offset = 0;
- int tmp_len = 0;
- int len_left = len;
- DMA_Handle_t hndl;
-
- if (virtPtr == NULL)
- panic("nand_dma_read: virtPtr == NULL\n");
-
- if ((void *)physPtr == NULL)
- panic("nand_dma_read: physPtr == NULL\n");
-
- hndl = dma_request_channel(DMA_DEVICE_NAND_MEM_TO_MEM);
- if (hndl < 0) {
- printk(KERN_ERR
- "nand_dma_read: unable to allocate dma channel: %d\n",
- (int)hndl);
- panic("\n");
- }
-
- while (len_left > 0) {
- if (len_left > DMA_MAX_LEN) {
- tmp_len = DMA_MAX_LEN;
- len_left -= DMA_MAX_LEN;
- } else {
- tmp_len = len_left;
- len_left = 0;
- }
-
- init_completion(&nand_comp);
- dma_transfer_mem_to_mem(hndl, REG_NAND_DATA_PADDR,
- physPtr + offset, tmp_len);
- wait_for_completion(&nand_comp);
-
- offset += tmp_len;
- }
-
- dma_free_channel(hndl);
-
- if (buf != NULL)
- memcpy(buf, virtPtr, len);
-}
-
-static void nand_dma_write(const void *buf, int len)
-{
- int offset = 0;
- int tmp_len = 0;
- int len_left = len;
- DMA_Handle_t hndl;
-
- if (buf == NULL)
- panic("nand_dma_write: buf == NULL\n");
-
- if (virtPtr == NULL)
- panic("nand_dma_write: virtPtr == NULL\n");
-
- if ((void *)physPtr == NULL)
- panic("nand_dma_write: physPtr == NULL\n");
-
- memcpy(virtPtr, buf, len);
-
-
- hndl = dma_request_channel(DMA_DEVICE_NAND_MEM_TO_MEM);
- if (hndl < 0) {
- printk(KERN_ERR
- "nand_dma_write: unable to allocate dma channel: %d\n",
- (int)hndl);
- panic("\n");
- }
-
- while (len_left > 0) {
- if (len_left > DMA_MAX_LEN) {
- tmp_len = DMA_MAX_LEN;
- len_left -= DMA_MAX_LEN;
- } else {
- tmp_len = len_left;
- len_left = 0;
- }
-
- init_completion(&nand_comp);
- dma_transfer_mem_to_mem(hndl, physPtr + offset,
- REG_NAND_DATA_PADDR, tmp_len);
- wait_for_completion(&nand_comp);
-
- offset += tmp_len;
- }
-
- dma_free_channel(hndl);
-}
-
-#endif
-
-static int nand_dev_ready(struct mtd_info *mtd)
-{
- return nand_bcm_umi_dev_ready();
-}
-
-/****************************************************************************
-*
-* bcm_umi_nand_inithw
-*
-* This routine does the necessary hardware (board-specific)
-* initializations. This includes setting up the timings, etc.
-*
-***************************************************************************/
-int bcm_umi_nand_inithw(void)
-{
- /* Configure nand timing parameters */
- writel(readl(&REG_UMI_NAND_TCR) & ~0x7ffff, &REG_UMI_NAND_TCR);
- writel(readl(&REG_UMI_NAND_TCR) | HW_CFG_NAND_TCR, &REG_UMI_NAND_TCR);
-
-#if !defined(CONFIG_MTD_NAND_BCM_UMI_HWCS)
- /* enable software control of CS */
- writel(readl(&REG_UMI_NAND_TCR) | REG_UMI_NAND_TCR_CS_SWCTRL, &REG_UMI_NAND_TCR);
-#endif
-
- /* keep NAND chip select asserted */
- writel(readl(&REG_UMI_NAND_RCSR) | REG_UMI_NAND_RCSR_CS_ASSERTED, &REG_UMI_NAND_RCSR);
-
- writel(readl(&REG_UMI_NAND_TCR) & ~REG_UMI_NAND_TCR_WORD16, &REG_UMI_NAND_TCR);
- /* enable writes to flash */
- writel(readl(&REG_UMI_MMD_ICR) | REG_UMI_MMD_ICR_FLASH_WP, &REG_UMI_MMD_ICR);
-
- writel(NAND_CMD_RESET, bcm_umi_io_base + REG_NAND_CMD_OFFSET);
- nand_bcm_umi_wait_till_ready();
-
-#if NAND_ECC_BCH
- nand_bcm_umi_bch_config_ecc(NAND_ECC_NUM_BYTES);
-#endif
-
- return 0;
-}
-
-/* Used to turn latch the proper register for access. */
-static void bcm_umi_nand_hwcontrol(struct mtd_info *mtd, int cmd,
- unsigned int ctrl)
-{
- /* send command to hardware */
- struct nand_chip *chip = mtd->priv;
- if (ctrl & NAND_CTRL_CHANGE) {
- if (ctrl & NAND_CLE) {
- chip->IO_ADDR_W = bcm_umi_io_base + REG_NAND_CMD_OFFSET;
- goto CMD;
- }
- if (ctrl & NAND_ALE) {
- chip->IO_ADDR_W =
- bcm_umi_io_base + REG_NAND_ADDR_OFFSET;
- goto CMD;
- }
- chip->IO_ADDR_W = bcm_umi_io_base + REG_NAND_DATA8_OFFSET;
- }
-
-CMD:
- /* Send command to chip directly */
- if (cmd != NAND_CMD_NONE)
- writeb(cmd, chip->IO_ADDR_W);
-}
-
-static void bcm_umi_nand_write_buf(struct mtd_info *mtd, const u_char * buf,
- int len)
-{
- if (USE_DIRECT_IO(len)) {
- /* Do it the old way if the buffer is small or too large.
- * Probably quicker than starting and checking dma. */
- int i;
- struct nand_chip *this = mtd->priv;
-
- for (i = 0; i < len; i++)
- writeb(buf[i], this->IO_ADDR_W);
- }
-#if USE_DMA
- else
- nand_dma_write(buf, len);
-#endif
-}
-
-static void bcm_umi_nand_read_buf(struct mtd_info *mtd, u_char * buf, int len)
-{
- if (USE_DIRECT_IO(len)) {
- int i;
- struct nand_chip *this = mtd->priv;
-
- for (i = 0; i < len; i++)
- buf[i] = readb(this->IO_ADDR_R);
- }
-#if USE_DMA
- else
- nand_dma_read(buf, len);
-#endif
-}
-
-static uint8_t readbackbuf[NAND_MAX_PAGESIZE];
-static int bcm_umi_nand_verify_buf(struct mtd_info *mtd, const u_char * buf,
- int len)
-{
- /*
- * Try to readback page with ECC correction. This is necessary
- * for MLC parts which may have permanently stuck bits.
- */
- struct nand_chip *chip = mtd->priv;
- int ret = chip->ecc.read_page(mtd, chip, readbackbuf, 0, 0);
- if (ret < 0)
- return -EFAULT;
- else {
- if (memcmp(readbackbuf, buf, len) == 0)
- return 0;
-
- return -EFAULT;
- }
- return 0;
-}
-
-static int __devinit bcm_umi_nand_probe(struct platform_device *pdev)
-{
- struct nand_chip *this;
- struct resource *r;
- int err = 0;
-
- printk(gBanner);
-
- /* Allocate memory for MTD device structure and private data */
- board_mtd =
- kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip),
- GFP_KERNEL);
- if (!board_mtd) {
- printk(KERN_WARNING
- "Unable to allocate NAND MTD device structure.\n");
- return -ENOMEM;
- }
-
- r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-
- if (!r) {
- err = -ENXIO;
- goto out_free;
- }
-
- /* map physical address */
- bcm_umi_io_base = ioremap(r->start, resource_size(r));
-
- if (!bcm_umi_io_base) {
- printk(KERN_ERR "ioremap to access BCM UMI NAND chip failed\n");
- err = -EIO;
- goto out_free;
- }
-
- /* Get pointer to private data */
- this = (struct nand_chip *)(&board_mtd[1]);
-
- /* Initialize structures */
- memset((char *)board_mtd, 0, sizeof(struct mtd_info));
- memset((char *)this, 0, sizeof(struct nand_chip));
-
- /* Link the private data with the MTD structure */
- board_mtd->priv = this;
-
- /* Initialize the NAND hardware. */
- if (bcm_umi_nand_inithw() < 0) {
- printk(KERN_ERR "BCM UMI NAND chip could not be initialized\n");
- err = -EIO;
- goto out_unmap;
- }
-
- /* Set address of NAND IO lines */
- this->IO_ADDR_W = bcm_umi_io_base + REG_NAND_DATA8_OFFSET;
- this->IO_ADDR_R = bcm_umi_io_base + REG_NAND_DATA8_OFFSET;
-
- /* Set command delay time, see datasheet for correct value */
- this->chip_delay = 0;
- /* Assign the device ready function, if available */
- this->dev_ready = nand_dev_ready;
- this->options = 0;
-
- this->write_buf = bcm_umi_nand_write_buf;
- this->read_buf = bcm_umi_nand_read_buf;
- this->verify_buf = bcm_umi_nand_verify_buf;
-
- this->cmd_ctrl = bcm_umi_nand_hwcontrol;
- this->ecc.mode = NAND_ECC_HW;
- this->ecc.size = 512;
- this->ecc.bytes = NAND_ECC_NUM_BYTES;
-#if NAND_ECC_BCH
- this->ecc.read_page = bcm_umi_bch_read_page_hwecc;
- this->ecc.write_page = bcm_umi_bch_write_page_hwecc;
-#else
- this->ecc.correct = nand_correct_data512;
- this->ecc.calculate = bcm_umi_hamming_get_hw_ecc;
- this->ecc.hwctl = bcm_umi_hamming_enable_hwecc;
-#endif
-
-#if USE_DMA
- err = nand_dma_init();
- if (err != 0)
- goto out_unmap;
-#endif
-
- /* Figure out the size of the device that we have.
- * We need to do this to figure out which ECC
- * layout we'll be using.
- */
-
- err = nand_scan_ident(board_mtd, 1, NULL);
- if (err) {
- printk(KERN_ERR "nand_scan failed: %d\n", err);
- goto out_unmap;
- }
-
- /* Now that we know the nand size, we can setup the ECC layout */
-
- switch (board_mtd->writesize) { /* writesize is the pagesize */
- case 4096:
- this->ecc.layout = &nand_hw_eccoob_4096;
- break;
- case 2048:
- this->ecc.layout = &nand_hw_eccoob_2048;
- break;
- case 512:
- this->ecc.layout = &nand_hw_eccoob_512;
- break;
- default:
- {
- printk(KERN_ERR "NAND - Unrecognized pagesize: %d\n",
- board_mtd->writesize);
- err = -EINVAL;
- goto out_unmap;
- }
- }
-
-#if NAND_ECC_BCH
- if (board_mtd->writesize > 512) {
- if (this->bbt_options & NAND_BBT_USE_FLASH)
- largepage_bbt.options = NAND_BBT_SCAN2NDPAGE;
- this->badblock_pattern = &largepage_bbt;
- }
-
- this->ecc.strength = 8;
-
-#endif
-
- /* Now finish off the scan, now that ecc.layout has been initialized. */
-
- err = nand_scan_tail(board_mtd);
- if (err) {
- printk(KERN_ERR "nand_scan failed: %d\n", err);
- goto out_unmap;
- }
-
- /* Register the partitions */
- board_mtd->name = "bcm_umi-nand";
- mtd_device_parse_register(board_mtd, NULL, NULL, NULL, 0);
-
- /* Return happy */
- return 0;
-out_unmap:
- iounmap(bcm_umi_io_base);
-out_free:
- kfree(board_mtd);
- return err;
-}
-
-static int bcm_umi_nand_remove(struct platform_device *pdev)
-{
-#if USE_DMA
- nand_dma_term();
-#endif
-
- /* Release resources, unregister device */
- nand_release(board_mtd);
-
- /* unmap physical address */
- iounmap(bcm_umi_io_base);
-
- /* Free the MTD device structure */
- kfree(board_mtd);
-
- return 0;
-}
-
-#ifdef CONFIG_PM
-static int bcm_umi_nand_suspend(struct platform_device *pdev,
- pm_message_t state)
-{
- printk(KERN_ERR "MTD NAND suspend is being called\n");
- return 0;
-}
-
-static int bcm_umi_nand_resume(struct platform_device *pdev)
-{
- printk(KERN_ERR "MTD NAND resume is being called\n");
- return 0;
-}
-#else
-#define bcm_umi_nand_suspend NULL
-#define bcm_umi_nand_resume NULL
-#endif
-
-static struct platform_driver nand_driver = {
- .driver = {
- .name = "bcm-nand",
- .owner = THIS_MODULE,
- },
- .probe = bcm_umi_nand_probe,
- .remove = bcm_umi_nand_remove,
- .suspend = bcm_umi_nand_suspend,
- .resume = bcm_umi_nand_resume,
-};
-
-module_platform_driver(nand_driver);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Broadcom");
-MODULE_DESCRIPTION("BCM UMI MTD NAND driver");
diff --git a/drivers/mtd/nand/bf5xx_nand.c b/drivers/mtd/nand/bf5xx_nand.c
index 3f1c185..ab0caa7 100644
--- a/drivers/mtd/nand/bf5xx_nand.c
+++ b/drivers/mtd/nand/bf5xx_nand.c
@@ -566,11 +566,13 @@ static int bf5xx_nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip
return 0;
}
-static void bf5xx_nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
- const uint8_t *buf, int oob_required)
+static int bf5xx_nand_write_page_raw(struct mtd_info *mtd,
+ struct nand_chip *chip, const uint8_t *buf, int oob_required)
{
bf5xx_nand_write_buf(mtd, buf, mtd->writesize);
bf5xx_nand_write_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+ return 0;
}
/*
diff --git a/drivers/mtd/nand/cafe_nand.c b/drivers/mtd/nand/cafe_nand.c
index f3f6cfe..2bb7170 100644
--- a/drivers/mtd/nand/cafe_nand.c
+++ b/drivers/mtd/nand/cafe_nand.c
@@ -377,7 +377,7 @@ static int cafe_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
* @buf: buffer to store read data
* @oob_required: caller expects OOB data read to chip->oob_poi
*
- * The hw generator calculates the error syndrome automatically. Therefor
+ * The hw generator calculates the error syndrome automatically. Therefore
* we need a special oob layout and handling.
*/
static int cafe_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip,
@@ -520,7 +520,7 @@ static struct nand_bbt_descr cafe_bbt_mirror_descr_512 = {
};
-static void cafe_nand_write_page_lowlevel(struct mtd_info *mtd,
+static int cafe_nand_write_page_lowlevel(struct mtd_info *mtd,
struct nand_chip *chip,
const uint8_t *buf, int oob_required)
{
@@ -531,6 +531,8 @@ static void cafe_nand_write_page_lowlevel(struct mtd_info *mtd,
/* Set up ECC autogeneration */
cafe->ctl2 |= (1<<30);
+
+ return 0;
}
static int cafe_nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
@@ -542,9 +544,12 @@ static int cafe_nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
if (unlikely(raw))
- chip->ecc.write_page_raw(mtd, chip, buf, oob_required);
+ status = chip->ecc.write_page_raw(mtd, chip, buf, oob_required);
else
- chip->ecc.write_page(mtd, chip, buf, oob_required);
+ status = chip->ecc.write_page(mtd, chip, buf, oob_required);
+
+ if (status < 0)
+ return status;
/*
* Cached progamming disabled for now, Not sure if its worth the
@@ -571,13 +576,6 @@ static int cafe_nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
status = chip->waitfunc(mtd, chip);
}
-#ifdef CONFIG_MTD_NAND_VERIFY_WRITE
- /* Send command to read back the data */
- chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
-
- if (chip->verify_buf(mtd, buf, mtd->writesize))
- return -EIO;
-#endif
return 0;
}
diff --git a/drivers/mtd/nand/cmx270_nand.c b/drivers/mtd/nand/cmx270_nand.c
index 1024bfc..39b2ef8 100644
--- a/drivers/mtd/nand/cmx270_nand.c
+++ b/drivers/mtd/nand/cmx270_nand.c
@@ -76,18 +76,6 @@ static void cmx270_read_buf(struct mtd_info *mtd, u_char *buf, int len)
*buf++ = readl(this->IO_ADDR_R) >> 16;
}
-static int cmx270_verify_buf(struct mtd_info *mtd, const u_char *buf, int len)
-{
- int i;
- struct nand_chip *this = mtd->priv;
-
- for (i=0; i<len; i++)
- if (buf[i] != (u_char)(readl(this->IO_ADDR_R) >> 16))
- return -EFAULT;
-
- return 0;
-}
-
static inline void nand_cs_on(void)
{
gpio_set_value(GPIO_NAND_CS, 0);
@@ -209,7 +197,6 @@ static int __init cmx270_init(void)
this->read_byte = cmx270_read_byte;
this->read_buf = cmx270_read_buf;
this->write_buf = cmx270_write_buf;
- this->verify_buf = cmx270_verify_buf;
/* Scan to find existence of the device */
if (nand_scan (cmx270_nand_mtd, 1)) {
diff --git a/drivers/mtd/nand/davinci_nand.c b/drivers/mtd/nand/davinci_nand.c
index f1deb1e..945047a 100644
--- a/drivers/mtd/nand/davinci_nand.c
+++ b/drivers/mtd/nand/davinci_nand.c
@@ -33,6 +33,7 @@
#include <linux/mtd/nand.h>
#include <linux/mtd/partitions.h>
#include <linux/slab.h>
+#include <linux/of_device.h>
#include <linux/platform_data/mtd-davinci.h>
#include <linux/platform_data/mtd-davinci-aemif.h>
@@ -518,9 +519,75 @@ static struct nand_ecclayout hwecc4_2048 __initconst = {
},
};
+#if defined(CONFIG_OF)
+static const struct of_device_id davinci_nand_of_match[] = {
+ {.compatible = "ti,davinci-nand", },
+ {},
+}
+MODULE_DEVICE_TABLE(of, davinci_nand_of_match);
+
+static struct davinci_nand_pdata
+ *nand_davinci_get_pdata(struct platform_device *pdev)
+{
+ if (!pdev->dev.platform_data && pdev->dev.of_node) {
+ struct davinci_nand_pdata *pdata;
+ const char *mode;
+ u32 prop;
+ int len;
+
+ pdata = devm_kzalloc(&pdev->dev,
+ sizeof(struct davinci_nand_pdata),
+ GFP_KERNEL);
+ pdev->dev.platform_data = pdata;
+ if (!pdata)
+ return NULL;
+ if (!of_property_read_u32(pdev->dev.of_node,
+ "ti,davinci-chipselect", &prop))
+ pdev->id = prop;
+ if (!of_property_read_u32(pdev->dev.of_node,
+ "ti,davinci-mask-ale", &prop))
+ pdata->mask_ale = prop;
+ if (!of_property_read_u32(pdev->dev.of_node,
+ "ti,davinci-mask-cle", &prop))
+ pdata->mask_cle = prop;
+ if (!of_property_read_u32(pdev->dev.of_node,
+ "ti,davinci-mask-chipsel", &prop))
+ pdata->mask_chipsel = prop;
+ if (!of_property_read_string(pdev->dev.of_node,
+ "ti,davinci-ecc-mode", &mode)) {
+ if (!strncmp("none", mode, 4))
+ pdata->ecc_mode = NAND_ECC_NONE;
+ if (!strncmp("soft", mode, 4))
+ pdata->ecc_mode = NAND_ECC_SOFT;
+ if (!strncmp("hw", mode, 2))
+ pdata->ecc_mode = NAND_ECC_HW;
+ }
+ if (!of_property_read_u32(pdev->dev.of_node,
+ "ti,davinci-ecc-bits", &prop))
+ pdata->ecc_bits = prop;
+ if (!of_property_read_u32(pdev->dev.of_node,
+ "ti,davinci-nand-buswidth", &prop))
+ if (prop == 16)
+ pdata->options |= NAND_BUSWIDTH_16;
+ if (of_find_property(pdev->dev.of_node,
+ "ti,davinci-nand-use-bbt", &len))
+ pdata->bbt_options = NAND_BBT_USE_FLASH;
+ }
+
+ return pdev->dev.platform_data;
+}
+#else
+#define davinci_nand_of_match NULL
+static struct davinci_nand_pdata
+ *nand_davinci_get_pdata(struct platform_device *pdev)
+{
+ return pdev->dev.platform_data;
+}
+#endif
+
static int __init nand_davinci_probe(struct platform_device *pdev)
{
- struct davinci_nand_pdata *pdata = pdev->dev.platform_data;
+ struct davinci_nand_pdata *pdata;
struct davinci_nand_info *info;
struct resource *res1;
struct resource *res2;
@@ -530,6 +597,7 @@ static int __init nand_davinci_probe(struct platform_device *pdev)
uint32_t val;
nand_ecc_modes_t ecc_mode;
+ pdata = nand_davinci_get_pdata(pdev);
/* insist on board-specific configuration */
if (!pdata)
return -ENODEV;
@@ -656,7 +724,7 @@ static int __init nand_davinci_probe(struct platform_device *pdev)
goto err_clk;
}
- ret = clk_enable(info->clk);
+ ret = clk_prepare_enable(info->clk);
if (ret < 0) {
dev_dbg(&pdev->dev, "unable to enable AEMIF clock, err %d\n",
ret);
@@ -767,7 +835,7 @@ syndrome_done:
err_scan:
err_timing:
- clk_disable(info->clk);
+ clk_disable_unprepare(info->clk);
err_clk_enable:
clk_put(info->clk);
@@ -804,7 +872,7 @@ static int __exit nand_davinci_remove(struct platform_device *pdev)
nand_release(&info->mtd);
- clk_disable(info->clk);
+ clk_disable_unprepare(info->clk);
clk_put(info->clk);
kfree(info);
@@ -816,6 +884,8 @@ static struct platform_driver nand_davinci_driver = {
.remove = __exit_p(nand_davinci_remove),
.driver = {
.name = "davinci_nand",
+ .owner = THIS_MODULE,
+ .of_match_table = davinci_nand_of_match,
},
};
MODULE_ALIAS("platform:davinci_nand");
diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c
index 0650aaf..e706a23 100644
--- a/drivers/mtd/nand/denali.c
+++ b/drivers/mtd/nand/denali.c
@@ -1028,7 +1028,7 @@ static void denali_setup_dma(struct denali_nand_info *denali, int op)
/* writes a page. user specifies type, and this function handles the
* configuration details. */
-static void write_page(struct mtd_info *mtd, struct nand_chip *chip,
+static int 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);
@@ -1078,6 +1078,8 @@ static void write_page(struct mtd_info *mtd, struct nand_chip *chip,
denali_enable_dma(denali, false);
dma_sync_single_for_cpu(denali->dev, addr, size, DMA_TO_DEVICE);
+
+ return 0;
}
/* NAND core entry points */
@@ -1086,24 +1088,24 @@ static void write_page(struct mtd_info *mtd, struct nand_chip *chip,
* writing a page with ECC or without is similar, all the work is done
* by write_page above.
* */
-static void denali_write_page(struct mtd_info *mtd, struct nand_chip *chip,
+static int denali_write_page(struct mtd_info *mtd, struct nand_chip *chip,
const uint8_t *buf, int oob_required)
{
/* for regular page writes, we let HW handle all the ECC
* data written to the device. */
- write_page(mtd, chip, buf, false);
+ return write_page(mtd, chip, buf, false);
}
/* This is the callback that the NAND core calls to write a page without ECC.
* raw access is similar to ECC page writes, so all the work is done in the
* write_page() function above.
*/
-static void denali_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
+static int denali_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
const uint8_t *buf, int oob_required)
{
/* for raw page writes, we want to disable ECC and simply write
whatever data is in the buffer. */
- write_page(mtd, chip, buf, true);
+ return write_page(mtd, chip, buf, true);
}
static int denali_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c
index e2ca067..256eb30 100644
--- a/drivers/mtd/nand/diskonchip.c
+++ b/drivers/mtd/nand/diskonchip.c
@@ -376,19 +376,6 @@ static void doc2000_readbuf_dword(struct mtd_info *mtd, u_char *buf, int len)
}
}
-static int doc2000_verifybuf(struct mtd_info *mtd, const u_char *buf, int len)
-{
- struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = this->priv;
- void __iomem *docptr = doc->virtadr;
- int i;
-
- for (i = 0; i < len; i++)
- if (buf[i] != ReadDOC(docptr, 2k_CDSN_IO))
- return -EFAULT;
- return 0;
-}
-
static uint16_t __init doc200x_ident_chip(struct mtd_info *mtd, int nr)
{
struct nand_chip *this = mtd->priv;
@@ -526,26 +513,6 @@ static void doc2001_readbuf(struct mtd_info *mtd, u_char *buf, int len)
buf[i] = ReadDOC(docptr, LastDataRead);
}
-static int doc2001_verifybuf(struct mtd_info *mtd, const u_char *buf, int len)
-{
- struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = this->priv;
- void __iomem *docptr = doc->virtadr;
- int i;
-
- /* Start read pipeline */
- ReadDOC(docptr, ReadPipeInit);
-
- for (i = 0; i < len - 1; i++)
- if (buf[i] != ReadDOC(docptr, Mil_CDSN_IO)) {
- ReadDOC(docptr, LastDataRead);
- return i;
- }
- if (buf[i] != ReadDOC(docptr, LastDataRead))
- return i;
- return 0;
-}
-
static u_char doc2001plus_read_byte(struct mtd_info *mtd)
{
struct nand_chip *this = mtd->priv;
@@ -610,33 +577,6 @@ static void doc2001plus_readbuf(struct mtd_info *mtd, u_char *buf, int len)
printk("\n");
}
-static int doc2001plus_verifybuf(struct mtd_info *mtd, const u_char *buf, int len)
-{
- struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = this->priv;
- void __iomem *docptr = doc->virtadr;
- int i;
-
- if (debug)
- printk("verifybuf of %d bytes: ", len);
-
- /* Start read pipeline */
- ReadDOC(docptr, Mplus_ReadPipeInit);
- ReadDOC(docptr, Mplus_ReadPipeInit);
-
- for (i = 0; i < len - 2; i++)
- if (buf[i] != ReadDOC(docptr, Mil_CDSN_IO)) {
- ReadDOC(docptr, Mplus_LastDataRead);
- ReadDOC(docptr, Mplus_LastDataRead);
- return i;
- }
- if (buf[len - 2] != ReadDOC(docptr, Mplus_LastDataRead))
- return len - 2;
- if (buf[len - 1] != ReadDOC(docptr, Mplus_LastDataRead))
- return len - 1;
- return 0;
-}
-
static void doc2001plus_select_chip(struct mtd_info *mtd, int chip)
{
struct nand_chip *this = mtd->priv;
@@ -1432,7 +1372,6 @@ static inline int __init doc2000_init(struct mtd_info *mtd)
this->read_byte = doc2000_read_byte;
this->write_buf = doc2000_writebuf;
this->read_buf = doc2000_readbuf;
- this->verify_buf = doc2000_verifybuf;
this->scan_bbt = nftl_scan_bbt;
doc->CDSNControl = CDSN_CTRL_FLASH_IO | CDSN_CTRL_ECC_IO;
@@ -1449,7 +1388,6 @@ static inline int __init doc2001_init(struct mtd_info *mtd)
this->read_byte = doc2001_read_byte;
this->write_buf = doc2001_writebuf;
this->read_buf = doc2001_readbuf;
- this->verify_buf = doc2001_verifybuf;
ReadDOC(doc->virtadr, ChipID);
ReadDOC(doc->virtadr, ChipID);
@@ -1480,7 +1418,6 @@ static inline int __init doc2001plus_init(struct mtd_info *mtd)
this->read_byte = doc2001plus_read_byte;
this->write_buf = doc2001plus_writebuf;
this->read_buf = doc2001plus_readbuf;
- this->verify_buf = doc2001plus_verifybuf;
this->scan_bbt = inftl_scan_bbt;
this->cmd_ctrl = NULL;
this->select_chip = doc2001plus_select_chip;
diff --git a/drivers/mtd/nand/docg4.c b/drivers/mtd/nand/docg4.c
index a225e49..799da5d 100644
--- a/drivers/mtd/nand/docg4.c
+++ b/drivers/mtd/nand/docg4.c
@@ -378,9 +378,9 @@ static int correct_data(struct mtd_info *mtd, uint8_t *buf, int page)
* bit flips(s) are not reported in stats.
*/
- if (doc->oob_buf[15]) {
+ if (nand->oob_poi[15]) {
int bit, numsetbits = 0;
- unsigned long written_flag = doc->oob_buf[15];
+ unsigned long written_flag = nand->oob_poi[15];
for_each_set_bit(bit, &written_flag, 8)
numsetbits++;
if (numsetbits > 4) { /* assume blank */
@@ -428,7 +428,7 @@ static int correct_data(struct mtd_info *mtd, uint8_t *buf, int page)
/* if error within oob area preceeding ecc bytes... */
if (errpos[i] > DOCG4_PAGE_SIZE * 8)
change_bit(errpos[i] - DOCG4_PAGE_SIZE * 8,
- (unsigned long *)doc->oob_buf);
+ (unsigned long *)nand->oob_poi);
else /* error in page data */
change_bit(errpos[i], (unsigned long *)buf);
@@ -748,18 +748,12 @@ static int read_page(struct mtd_info *mtd, struct nand_chip *nand,
docg4_read_buf(mtd, buf, DOCG4_PAGE_SIZE); /* read the page data */
- /*
- * Diskonchips read oob immediately after a page read. Mtd
- * infrastructure issues a separate command for reading oob after the
- * page is read. So we save the oob bytes in a local buffer and just
- * copy it if the next command reads oob from the same page.
- */
-
+ /* this device always reads oob after page data */
/* first 14 oob bytes read from I/O reg */
- docg4_read_buf(mtd, doc->oob_buf, 14);
+ docg4_read_buf(mtd, nand->oob_poi, 14);
/* last 2 read from another reg */
- buf16 = (uint16_t *)(doc->oob_buf + 14);
+ buf16 = (uint16_t *)(nand->oob_poi + 14);
*buf16 = readw(docptr + DOCG4_MYSTERY_REG);
write_nop(docptr);
@@ -782,6 +776,8 @@ static int read_page(struct mtd_info *mtd, struct nand_chip *nand,
}
writew(0, docptr + DOC_DATAEND);
+ if (bits_corrected == -EBADMSG) /* uncorrectable errors */
+ return 0;
return bits_corrected;
}
@@ -807,21 +803,6 @@ static int docg4_read_oob(struct mtd_info *mtd, struct nand_chip *nand,
dev_dbg(doc->dev, "%s: page %x\n", __func__, page);
- /*
- * Oob bytes are read as part of a normal page read. If the previous
- * nand command was a read of the page whose oob is now being read, just
- * copy the oob bytes that we saved in a local buffer and avoid a
- * separate oob read.
- */
- if (doc->last_command.command == NAND_CMD_READ0 &&
- doc->last_command.page == page) {
- memcpy(nand->oob_poi, doc->oob_buf, 16);
- return 0;
- }
-
- /*
- * Separate read of oob data only.
- */
docg4_command(mtd, NAND_CMD_READ0, nand->ecc.size, page);
writew(DOC_ECCCONF0_READ_MODE | DOCG4_OOB_SIZE, docptr + DOC_ECCCONF0);
@@ -898,7 +879,7 @@ static void docg4_erase_block(struct mtd_info *mtd, int page)
write_nop(docptr);
}
-static void write_page(struct mtd_info *mtd, struct nand_chip *nand,
+static int write_page(struct mtd_info *mtd, struct nand_chip *nand,
const uint8_t *buf, bool use_ecc)
{
struct docg4_priv *doc = nand->priv;
@@ -950,15 +931,17 @@ static void write_page(struct mtd_info *mtd, struct nand_chip *nand,
write_nop(docptr);
writew(0, docptr + DOC_DATAEND);
write_nop(docptr);
+
+ return 0;
}
-static void docg4_write_page_raw(struct mtd_info *mtd, struct nand_chip *nand,
+static int docg4_write_page_raw(struct mtd_info *mtd, struct nand_chip *nand,
const uint8_t *buf, int oob_required)
{
return write_page(mtd, nand, buf, false);
}
-static void docg4_write_page(struct mtd_info *mtd, struct nand_chip *nand,
+static int docg4_write_page(struct mtd_info *mtd, struct nand_chip *nand,
const uint8_t *buf, int oob_required)
{
return write_page(mtd, nand, buf, true);
diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c
index 7842938..cc1480a 100644
--- a/drivers/mtd/nand/fsl_elbc_nand.c
+++ b/drivers/mtd/nand/fsl_elbc_nand.c
@@ -614,41 +614,6 @@ static void fsl_elbc_read_buf(struct mtd_info *mtd, u8 *buf, int len)
len, avail);
}
-/*
- * Verify buffer against the FCM Controller Data Buffer
- */
-static int fsl_elbc_verify_buf(struct mtd_info *mtd, const u_char *buf, int len)
-{
- struct nand_chip *chip = mtd->priv;
- struct fsl_elbc_mtd *priv = chip->priv;
- struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand;
- int i;
-
- if (len < 0) {
- dev_err(priv->dev, "write_buf of %d bytes", len);
- return -EINVAL;
- }
-
- if ((unsigned int)len >
- elbc_fcm_ctrl->read_bytes - elbc_fcm_ctrl->index) {
- dev_err(priv->dev,
- "verify_buf beyond end of buffer "
- "(%d requested, %u available)\n",
- len, elbc_fcm_ctrl->read_bytes - elbc_fcm_ctrl->index);
-
- elbc_fcm_ctrl->index = elbc_fcm_ctrl->read_bytes;
- return -EINVAL;
- }
-
- for (i = 0; i < len; i++)
- if (in_8(&elbc_fcm_ctrl->addr[elbc_fcm_ctrl->index + i])
- != buf[i])
- break;
-
- elbc_fcm_ctrl->index += len;
- return i == len && elbc_fcm_ctrl->status == LTESR_CC ? 0 : -EIO;
-}
-
/* This function is called after Program and Erase Operations to
* check for success or failure.
*/
@@ -766,11 +731,13 @@ static int fsl_elbc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
/* ECC will be calculated automatically, and errors will be detected in
* waitfunc.
*/
-static void fsl_elbc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
+static int fsl_elbc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
const uint8_t *buf, int oob_required)
{
fsl_elbc_write_buf(mtd, buf, mtd->writesize);
fsl_elbc_write_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+ return 0;
}
static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv)
@@ -796,7 +763,6 @@ static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv)
chip->read_byte = fsl_elbc_read_byte;
chip->write_buf = fsl_elbc_write_buf;
chip->read_buf = fsl_elbc_read_buf;
- chip->verify_buf = fsl_elbc_verify_buf;
chip->select_chip = fsl_elbc_select_chip;
chip->cmdfunc = fsl_elbc_cmdfunc;
chip->waitfunc = fsl_elbc_wait;
@@ -805,7 +771,6 @@ static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv)
chip->bbt_md = &bbt_mirror_descr;
/* set up nand options */
- chip->options = NAND_NO_READRDY;
chip->bbt_options = NAND_BBT_USE_FLASH;
chip->controller = &elbc_fcm_ctrl->controller;
@@ -916,7 +881,8 @@ static int __devinit fsl_elbc_nand_probe(struct platform_device *pdev)
elbc_fcm_ctrl->chips[bank] = priv;
priv->bank = bank;
priv->ctrl = fsl_lbc_ctrl_dev;
- priv->dev = dev;
+ priv->dev = &pdev->dev;
+ dev_set_drvdata(priv->dev, priv);
priv->vbase = ioremap(res.start, resource_size(&res));
if (!priv->vbase) {
@@ -963,11 +929,10 @@ err:
static int fsl_elbc_nand_remove(struct platform_device *pdev)
{
- int i;
struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = fsl_lbc_ctrl_dev->nand;
- for (i = 0; i < MAX_BANKS; i++)
- if (elbc_fcm_ctrl->chips[i])
- fsl_elbc_chip_remove(elbc_fcm_ctrl->chips[i]);
+ struct fsl_elbc_mtd *priv = dev_get_drvdata(&pdev->dev);
+
+ fsl_elbc_chip_remove(priv);
mutex_lock(&fsl_elbc_nand_mutex);
elbc_fcm_ctrl->counter--;
diff --git a/drivers/mtd/nand/fsl_ifc_nand.c b/drivers/mtd/nand/fsl_ifc_nand.c
index 01e2f2e..3551a99 100644
--- a/drivers/mtd/nand/fsl_ifc_nand.c
+++ b/drivers/mtd/nand/fsl_ifc_nand.c
@@ -194,7 +194,7 @@ static int is_blank(struct mtd_info *mtd, unsigned int bufnum)
struct nand_chip *chip = mtd->priv;
struct fsl_ifc_mtd *priv = chip->priv;
u8 __iomem *addr = priv->vbase + bufnum * (mtd->writesize * 2);
- u32 __iomem *mainarea = (u32 *)addr;
+ u32 __iomem *mainarea = (u32 __iomem *)addr;
u8 __iomem *oob = addr + mtd->writesize;
int i;
@@ -592,8 +592,8 @@ static uint8_t fsl_ifc_read_byte16(struct mtd_info *mtd)
* next byte.
*/
if (ifc_nand_ctrl->index < ifc_nand_ctrl->read_bytes) {
- data = in_be16((uint16_t *)&ifc_nand_ctrl->
- addr[ifc_nand_ctrl->index]);
+ data = in_be16((uint16_t __iomem *)&ifc_nand_ctrl->
+ addr[ifc_nand_ctrl->index]);
ifc_nand_ctrl->index += 2;
return (uint8_t) data;
}
@@ -628,46 +628,6 @@ static void fsl_ifc_read_buf(struct mtd_info *mtd, u8 *buf, int len)
}
/*
- * Verify buffer against the IFC Controller Data Buffer
- */
-static int fsl_ifc_verify_buf(struct mtd_info *mtd,
- const u_char *buf, int len)
-{
- struct nand_chip *chip = mtd->priv;
- struct fsl_ifc_mtd *priv = chip->priv;
- struct fsl_ifc_ctrl *ctrl = priv->ctrl;
- struct fsl_ifc_nand_ctrl *nctrl = ifc_nand_ctrl;
- int i;
-
- if (len < 0) {
- dev_err(priv->dev, "%s: write_buf of %d bytes", __func__, len);
- return -EINVAL;
- }
-
- if ((unsigned int)len > nctrl->read_bytes - nctrl->index) {
- dev_err(priv->dev,
- "%s: beyond end of buffer (%d requested, %u available)\n",
- __func__, len, nctrl->read_bytes - nctrl->index);
-
- nctrl->index = nctrl->read_bytes;
- return -EINVAL;
- }
-
- for (i = 0; i < len; i++)
- if (in_8(&nctrl->addr[nctrl->index + i]) != buf[i])
- break;
-
- nctrl->index += len;
-
- if (i != len)
- return -EIO;
- if (ctrl->nand_stat != IFC_NAND_EVTER_STAT_OPC)
- return -EIO;
-
- return 0;
-}
-
-/*
* This function is called after Program and Erase Operations to
* check for success or failure.
*/
@@ -722,11 +682,13 @@ static int fsl_ifc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
/* ECC will be calculated automatically, and errors will be detected in
* waitfunc.
*/
-static void fsl_ifc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
+static int fsl_ifc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
const uint8_t *buf, int oob_required)
{
fsl_ifc_write_buf(mtd, buf, mtd->writesize);
fsl_ifc_write_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+ return 0;
}
static int fsl_ifc_chip_init_tail(struct mtd_info *mtd)
@@ -844,7 +806,6 @@ static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv)
chip->write_buf = fsl_ifc_write_buf;
chip->read_buf = fsl_ifc_read_buf;
- chip->verify_buf = fsl_ifc_verify_buf;
chip->select_chip = fsl_ifc_select_chip;
chip->cmdfunc = fsl_ifc_cmdfunc;
chip->waitfunc = fsl_ifc_wait;
@@ -855,7 +816,6 @@ static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv)
out_be32(&ifc->ifc_nand.ncfgr, 0x0);
/* set up nand options */
- chip->options = NAND_NO_READRDY;
chip->bbt_options = NAND_BBT_USE_FLASH;
diff --git a/drivers/mtd/nand/gpio.c b/drivers/mtd/nand/gpio.c
index 27000a5..bc73bc5 100644
--- a/drivers/mtd/nand/gpio.c
+++ b/drivers/mtd/nand/gpio.c
@@ -100,23 +100,6 @@ static void gpio_nand_readbuf(struct mtd_info *mtd, u_char *buf, int len)
readsb(this->IO_ADDR_R, buf, len);
}
-static int gpio_nand_verifybuf(struct mtd_info *mtd, const u_char *buf, int len)
-{
- struct nand_chip *this = mtd->priv;
- unsigned char read, *p = (unsigned char *) buf;
- int i, err = 0;
-
- for (i = 0; i < len; i++) {
- read = readb(this->IO_ADDR_R);
- if (read != p[i]) {
- pr_debug("%s: err at %d (read %04x vs %04x)\n",
- __func__, i, read, p[i]);
- err = -EFAULT;
- }
- }
- return err;
-}
-
static void gpio_nand_writebuf16(struct mtd_info *mtd, const u_char *buf,
int len)
{
@@ -148,26 +131,6 @@ static void gpio_nand_readbuf16(struct mtd_info *mtd, u_char *buf, int len)
}
}
-static int gpio_nand_verifybuf16(struct mtd_info *mtd, const u_char *buf,
- int len)
-{
- struct nand_chip *this = mtd->priv;
- unsigned short read, *p = (unsigned short *) buf;
- int i, err = 0;
- len >>= 1;
-
- for (i = 0; i < len; i++) {
- read = readw(this->IO_ADDR_R);
- if (read != p[i]) {
- pr_debug("%s: err at %d (read %04x vs %04x)\n",
- __func__, i, read, p[i]);
- err = -EFAULT;
- }
- }
- return err;
-}
-
-
static int gpio_nand_devready(struct mtd_info *mtd)
{
struct gpiomtd *gpiomtd = gpio_nand_getpriv(mtd);
@@ -391,11 +354,9 @@ static int __devinit gpio_nand_probe(struct platform_device *dev)
if (this->options & NAND_BUSWIDTH_16) {
this->read_buf = gpio_nand_readbuf16;
this->write_buf = gpio_nand_writebuf16;
- this->verify_buf = gpio_nand_verifybuf16;
} else {
this->read_buf = gpio_nand_readbuf;
this->write_buf = gpio_nand_writebuf;
- this->verify_buf = gpio_nand_verifybuf;
}
/* set the mtd private data for the nand driver */
@@ -456,20 +417,7 @@ static struct platform_driver gpio_nand_driver = {
},
};
-static int __init gpio_nand_init(void)
-{
- printk(KERN_INFO "GPIO NAND driver, © 2004 Simtec Electronics\n");
-
- return platform_driver_register(&gpio_nand_driver);
-}
-
-static void __exit gpio_nand_exit(void)
-{
- platform_driver_unregister(&gpio_nand_driver);
-}
-
-module_init(gpio_nand_init);
-module_exit(gpio_nand_exit);
+module_platform_driver(gpio_nand_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c
index a1f4332..3502acc 100644
--- a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c
+++ b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c
@@ -26,7 +26,7 @@
#include "gpmi-regs.h"
#include "bch-regs.h"
-struct timing_threshod timing_default_threshold = {
+static struct timing_threshod timing_default_threshold = {
.max_data_setup_cycles = (BM_GPMI_TIMING0_DATA_SETUP >>
BP_GPMI_TIMING0_DATA_SETUP),
.internal_data_setup_in_ns = 0,
@@ -124,12 +124,42 @@ error:
return -ETIMEDOUT;
}
+static int __gpmi_enable_clk(struct gpmi_nand_data *this, bool v)
+{
+ struct clk *clk;
+ int ret;
+ int i;
+
+ for (i = 0; i < GPMI_CLK_MAX; i++) {
+ clk = this->resources.clock[i];
+ if (!clk)
+ break;
+
+ if (v) {
+ ret = clk_prepare_enable(clk);
+ if (ret)
+ goto err_clk;
+ } else {
+ clk_disable_unprepare(clk);
+ }
+ }
+ return 0;
+
+err_clk:
+ for (; i > 0; i--)
+ clk_disable_unprepare(this->resources.clock[i - 1]);
+ return ret;
+}
+
+#define gpmi_enable_clk(x) __gpmi_enable_clk(x, true)
+#define gpmi_disable_clk(x) __gpmi_enable_clk(x, false)
+
int gpmi_init(struct gpmi_nand_data *this)
{
struct resources *r = &this->resources;
int ret;
- ret = clk_prepare_enable(r->clock);
+ ret = gpmi_enable_clk(this);
if (ret)
goto err_out;
ret = gpmi_reset_block(r->gpmi_regs, false);
@@ -149,7 +179,7 @@ int gpmi_init(struct gpmi_nand_data *this)
/* Select BCH ECC. */
writel(BM_GPMI_CTRL1_BCH_MODE, r->gpmi_regs + HW_GPMI_CTRL1_SET);
- clk_disable_unprepare(r->clock);
+ gpmi_disable_clk(this);
return 0;
err_out:
return ret;
@@ -205,7 +235,7 @@ int bch_set_geometry(struct gpmi_nand_data *this)
ecc_strength = bch_geo->ecc_strength >> 1;
page_size = bch_geo->page_size;
- ret = clk_prepare_enable(r->clock);
+ ret = gpmi_enable_clk(this);
if (ret)
goto err_out;
@@ -240,7 +270,7 @@ int bch_set_geometry(struct gpmi_nand_data *this)
writel(BM_BCH_CTRL_COMPLETE_IRQ_EN,
r->bch_regs + HW_BCH_CTRL_SET);
- clk_disable_unprepare(r->clock);
+ gpmi_disable_clk(this);
return 0;
err_out:
return ret;
@@ -263,6 +293,7 @@ static int gpmi_nfc_compute_hardware_timing(struct gpmi_nand_data *this,
struct gpmi_nfc_hardware_timing *hw)
{
struct timing_threshod *nfc = &timing_default_threshold;
+ struct resources *r = &this->resources;
struct nand_chip *nand = &this->nand;
struct nand_timing target = this->timing;
bool improved_timing_is_available;
@@ -302,8 +333,9 @@ static int gpmi_nfc_compute_hardware_timing(struct gpmi_nand_data *this,
(target.tRHOH_in_ns >= 0) ;
/* Inspect the clock. */
+ nfc->clock_frequency_in_hz = clk_get_rate(r->clock[0]);
clock_frequency_in_hz = nfc->clock_frequency_in_hz;
- clock_period_in_ns = 1000000000 / clock_frequency_in_hz;
+ clock_period_in_ns = NSEC_PER_SEC / clock_frequency_in_hz;
/*
* The NFC quantizes setup and hold parameters in terms of clock cycles.
@@ -698,17 +730,230 @@ return_results:
hw->address_setup_in_cycles = address_setup_in_cycles;
hw->use_half_periods = dll_use_half_periods;
hw->sample_delay_factor = sample_delay_factor;
+ hw->device_busy_timeout = GPMI_DEFAULT_BUSY_TIMEOUT;
+ hw->wrn_dly_sel = BV_GPMI_CTRL1_WRN_DLY_SEL_4_TO_8NS;
/* Return success. */
return 0;
}
+/*
+ * <1> Firstly, we should know what's the GPMI-clock means.
+ * The GPMI-clock is the internal clock in the gpmi nand controller.
+ * If you set 100MHz to gpmi nand controller, the GPMI-clock's period
+ * is 10ns. Mark the GPMI-clock's period as GPMI-clock-period.
+ *
+ * <2> Secondly, we should know what's the frequency on the nand chip pins.
+ * The frequency on the nand chip pins is derived from the GPMI-clock.
+ * We can get it from the following equation:
+ *
+ * F = G / (DS + DH)
+ *
+ * F : the frequency on the nand chip pins.
+ * G : the GPMI clock, such as 100MHz.
+ * DS : GPMI_HW_GPMI_TIMING0:DATA_SETUP
+ * DH : GPMI_HW_GPMI_TIMING0:DATA_HOLD
+ *
+ * <3> Thirdly, when the frequency on the nand chip pins is above 33MHz,
+ * the nand EDO(extended Data Out) timing could be applied.
+ * The GPMI implements a feedback read strobe to sample the read data.
+ * The feedback read strobe can be delayed to support the nand EDO timing
+ * where the read strobe may deasserts before the read data is valid, and
+ * read data is valid for some time after read strobe.
+ *
+ * The following figure illustrates some aspects of a NAND Flash read:
+ *
+ * |<---tREA---->|
+ * | |
+ * | | |
+ * |<--tRP-->| |
+ * | | |
+ * __ ___|__________________________________
+ * RDN \________/ |
+ * |
+ * /---------\
+ * Read Data --------------< >---------
+ * \---------/
+ * | |
+ * |<-D->|
+ * FeedbackRDN ________ ____________
+ * \___________/
+ *
+ * D stands for delay, set in the HW_GPMI_CTRL1:RDN_DELAY.
+ *
+ *
+ * <4> Now, we begin to describe how to compute the right RDN_DELAY.
+ *
+ * 4.1) From the aspect of the nand chip pins:
+ * Delay = (tREA + C - tRP) {1}
+ *
+ * tREA : the maximum read access time. From the ONFI nand standards,
+ * we know that tREA is 16ns in mode 5, tREA is 20ns is mode 4.
+ * Please check it in : www.onfi.org
+ * C : a constant for adjust the delay. default is 4.
+ * tRP : the read pulse width.
+ * Specified by the HW_GPMI_TIMING0:DATA_SETUP:
+ * tRP = (GPMI-clock-period) * DATA_SETUP
+ *
+ * 4.2) From the aspect of the GPMI nand controller:
+ * Delay = RDN_DELAY * 0.125 * RP {2}
+ *
+ * RP : the DLL reference period.
+ * if (GPMI-clock-period > DLL_THRETHOLD)
+ * RP = GPMI-clock-period / 2;
+ * else
+ * RP = GPMI-clock-period;
+ *
+ * Set the HW_GPMI_CTRL1:HALF_PERIOD if GPMI-clock-period
+ * is greater DLL_THRETHOLD. In other SOCs, the DLL_THRETHOLD
+ * is 16ns, but in mx6q, we use 12ns.
+ *
+ * 4.3) since {1} equals {2}, we get:
+ *
+ * (tREA + 4 - tRP) * 8
+ * RDN_DELAY = --------------------- {3}
+ * RP
+ *
+ * 4.4) We only support the fastest asynchronous mode of ONFI nand.
+ * For some ONFI nand, the mode 4 is the fastest mode;
+ * while for some ONFI nand, the mode 5 is the fastest mode.
+ * So we only support the mode 4 and mode 5. It is no need to
+ * support other modes.
+ */
+static void gpmi_compute_edo_timing(struct gpmi_nand_data *this,
+ struct gpmi_nfc_hardware_timing *hw)
+{
+ struct resources *r = &this->resources;
+ unsigned long rate = clk_get_rate(r->clock[0]);
+ int mode = this->timing_mode;
+ int dll_threshold = 16; /* in ns */
+ unsigned long delay;
+ unsigned long clk_period;
+ int t_rea;
+ int c = 4;
+ int t_rp;
+ int rp;
+
+ /*
+ * [1] for GPMI_HW_GPMI_TIMING0:
+ * The async mode requires 40MHz for mode 4, 50MHz for mode 5.
+ * The GPMI can support 100MHz at most. So if we want to
+ * get the 40MHz or 50MHz, we have to set DS=1, DH=1.
+ * Set the ADDRESS_SETUP to 0 in mode 4.
+ */
+ hw->data_setup_in_cycles = 1;
+ hw->data_hold_in_cycles = 1;
+ hw->address_setup_in_cycles = ((mode == 5) ? 1 : 0);
+
+ /* [2] for GPMI_HW_GPMI_TIMING1 */
+ hw->device_busy_timeout = 0x9000;
+
+ /* [3] for GPMI_HW_GPMI_CTRL1 */
+ hw->wrn_dly_sel = BV_GPMI_CTRL1_WRN_DLY_SEL_NO_DELAY;
+
+ if (GPMI_IS_MX6Q(this))
+ dll_threshold = 12;
+
+ /*
+ * Enlarge 10 times for the numerator and denominator in {3}.
+ * This make us to get more accurate result.
+ */
+ clk_period = NSEC_PER_SEC / (rate / 10);
+ dll_threshold *= 10;
+ t_rea = ((mode == 5) ? 16 : 20) * 10;
+ c *= 10;
+
+ t_rp = clk_period * 1; /* DATA_SETUP is 1 */
+
+ if (clk_period > dll_threshold) {
+ hw->use_half_periods = 1;
+ rp = clk_period / 2;
+ } else {
+ hw->use_half_periods = 0;
+ rp = clk_period;
+ }
+
+ /*
+ * Multiply the numerator with 10, we could do a round off:
+ * 7.8 round up to 8; 7.4 round down to 7.
+ */
+ delay = (((t_rea + c - t_rp) * 8) * 10) / rp;
+ delay = (delay + 5) / 10;
+
+ hw->sample_delay_factor = delay;
+}
+
+static int enable_edo_mode(struct gpmi_nand_data *this, int mode)
+{
+ struct resources *r = &this->resources;
+ struct nand_chip *nand = &this->nand;
+ struct mtd_info *mtd = &this->mtd;
+ uint8_t feature[ONFI_SUBFEATURE_PARAM_LEN] = {};
+ unsigned long rate;
+ int ret;
+
+ nand->select_chip(mtd, 0);
+
+ /* [1] send SET FEATURE commond to NAND */
+ feature[0] = mode;
+ ret = nand->onfi_set_features(mtd, nand,
+ ONFI_FEATURE_ADDR_TIMING_MODE, feature);
+ if (ret)
+ goto err_out;
+
+ /* [2] send GET FEATURE command to double-check the timing mode */
+ memset(feature, 0, ONFI_SUBFEATURE_PARAM_LEN);
+ ret = nand->onfi_get_features(mtd, nand,
+ ONFI_FEATURE_ADDR_TIMING_MODE, feature);
+ if (ret || feature[0] != mode)
+ goto err_out;
+
+ nand->select_chip(mtd, -1);
+
+ /* [3] set the main IO clock, 100MHz for mode 5, 80MHz for mode 4. */
+ rate = (mode == 5) ? 100000000 : 80000000;
+ clk_set_rate(r->clock[0], rate);
+
+ /* Let the gpmi_begin() re-compute the timing again. */
+ this->flags &= ~GPMI_TIMING_INIT_OK;
+
+ this->flags |= GPMI_ASYNC_EDO_ENABLED;
+ this->timing_mode = mode;
+ dev_info(this->dev, "enable the asynchronous EDO mode %d\n", mode);
+ return 0;
+
+err_out:
+ nand->select_chip(mtd, -1);
+ dev_err(this->dev, "mode:%d ,failed in set feature.\n", mode);
+ return -EINVAL;
+}
+
+int gpmi_extra_init(struct gpmi_nand_data *this)
+{
+ struct nand_chip *chip = &this->nand;
+
+ /* Enable the asynchronous EDO feature. */
+ if (GPMI_IS_MX6Q(this) && chip->onfi_version) {
+ int mode = onfi_get_async_timing_mode(chip);
+
+ /* We only support the timing mode 4 and mode 5. */
+ if (mode & ONFI_TIMING_MODE_5)
+ mode = 5;
+ else if (mode & ONFI_TIMING_MODE_4)
+ mode = 4;
+ else
+ return 0;
+
+ return enable_edo_mode(this, mode);
+ }
+ return 0;
+}
+
/* Begin the I/O */
void gpmi_begin(struct gpmi_nand_data *this)
{
struct resources *r = &this->resources;
- struct timing_threshod *nfc = &timing_default_threshold;
- unsigned char *gpmi_regs = r->gpmi_regs;
+ void __iomem *gpmi_regs = r->gpmi_regs;
unsigned int clock_period_in_ns;
uint32_t reg;
unsigned int dll_wait_time_in_us;
@@ -716,60 +961,66 @@ void gpmi_begin(struct gpmi_nand_data *this)
int ret;
/* Enable the clock. */
- ret = clk_prepare_enable(r->clock);
+ ret = gpmi_enable_clk(this);
if (ret) {
pr_err("We failed in enable the clk\n");
goto err_out;
}
- /* set ready/busy timeout */
- writel(0x500 << BP_GPMI_TIMING1_BUSY_TIMEOUT,
- gpmi_regs + HW_GPMI_TIMING1);
-
- /* Get the timing information we need. */
- nfc->clock_frequency_in_hz = clk_get_rate(r->clock);
- clock_period_in_ns = 1000000000 / nfc->clock_frequency_in_hz;
+ /* Only initialize the timing once */
+ if (this->flags & GPMI_TIMING_INIT_OK)
+ return;
+ this->flags |= GPMI_TIMING_INIT_OK;
- gpmi_nfc_compute_hardware_timing(this, &hw);
+ if (this->flags & GPMI_ASYNC_EDO_ENABLED)
+ gpmi_compute_edo_timing(this, &hw);
+ else
+ gpmi_nfc_compute_hardware_timing(this, &hw);
- /* Set up all the simple timing parameters. */
+ /* [1] Set HW_GPMI_TIMING0 */
reg = BF_GPMI_TIMING0_ADDRESS_SETUP(hw.address_setup_in_cycles) |
BF_GPMI_TIMING0_DATA_HOLD(hw.data_hold_in_cycles) |
BF_GPMI_TIMING0_DATA_SETUP(hw.data_setup_in_cycles) ;
writel(reg, gpmi_regs + HW_GPMI_TIMING0);
- /*
- * DLL_ENABLE must be set to 0 when setting RDN_DELAY or HALF_PERIOD.
- */
+ /* [2] Set HW_GPMI_TIMING1 */
+ writel(BF_GPMI_TIMING1_BUSY_TIMEOUT(hw.device_busy_timeout),
+ gpmi_regs + HW_GPMI_TIMING1);
+
+ /* [3] The following code is to set the HW_GPMI_CTRL1. */
+
+ /* Set the WRN_DLY_SEL */
+ writel(BM_GPMI_CTRL1_WRN_DLY_SEL, gpmi_regs + HW_GPMI_CTRL1_CLR);
+ writel(BF_GPMI_CTRL1_WRN_DLY_SEL(hw.wrn_dly_sel),
+ gpmi_regs + HW_GPMI_CTRL1_SET);
+
+ /* DLL_ENABLE must be set to 0 when setting RDN_DELAY or HALF_PERIOD. */
writel(BM_GPMI_CTRL1_DLL_ENABLE, gpmi_regs + HW_GPMI_CTRL1_CLR);
/* Clear out the DLL control fields. */
- writel(BM_GPMI_CTRL1_RDN_DELAY, gpmi_regs + HW_GPMI_CTRL1_CLR);
- writel(BM_GPMI_CTRL1_HALF_PERIOD, gpmi_regs + HW_GPMI_CTRL1_CLR);
+ reg = BM_GPMI_CTRL1_RDN_DELAY | BM_GPMI_CTRL1_HALF_PERIOD;
+ writel(reg, gpmi_regs + HW_GPMI_CTRL1_CLR);
/* If no sample delay is called for, return immediately. */
if (!hw.sample_delay_factor)
return;
- /* Configure the HALF_PERIOD flag. */
- if (hw.use_half_periods)
- writel(BM_GPMI_CTRL1_HALF_PERIOD,
- gpmi_regs + HW_GPMI_CTRL1_SET);
+ /* Set RDN_DELAY or HALF_PERIOD. */
+ reg = ((hw.use_half_periods) ? BM_GPMI_CTRL1_HALF_PERIOD : 0)
+ | BF_GPMI_CTRL1_RDN_DELAY(hw.sample_delay_factor);
- /* Set the delay factor. */
- writel(BF_GPMI_CTRL1_RDN_DELAY(hw.sample_delay_factor),
- gpmi_regs + HW_GPMI_CTRL1_SET);
+ writel(reg, gpmi_regs + HW_GPMI_CTRL1_SET);
- /* Enable the DLL. */
+ /* At last, we enable the DLL. */
writel(BM_GPMI_CTRL1_DLL_ENABLE, gpmi_regs + HW_GPMI_CTRL1_SET);
/*
* After we enable the GPMI DLL, we have to wait 64 clock cycles before
- * we can use the GPMI.
- *
- * Calculate the amount of time we need to wait, in microseconds.
+ * we can use the GPMI. Calculate the amount of time we need to wait,
+ * in microseconds.
*/
+ clock_period_in_ns = NSEC_PER_SEC / clk_get_rate(r->clock[0]);
dll_wait_time_in_us = (clock_period_in_ns * 64) / 1000;
if (!dll_wait_time_in_us)
@@ -784,8 +1035,7 @@ err_out:
void gpmi_end(struct gpmi_nand_data *this)
{
- struct resources *r = &this->resources;
- clk_disable_unprepare(r->clock);
+ gpmi_disable_clk(this);
}
/* Clears a BCH interrupt. */
diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
index a6cad5c..d79696b 100644
--- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
+++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
@@ -18,6 +18,9 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/clk.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
@@ -27,6 +30,7 @@
#include <linux/pinctrl/consumer.h>
#include <linux/of.h>
#include <linux/of_device.h>
+#include <linux/of_mtd.h>
#include "gpmi-nand.h"
/* add our owner bbt descriptor */
@@ -113,7 +117,7 @@ int common_nfc_set_geometry(struct gpmi_nand_data *this)
/* We use the same ECC strength for all chunks. */
geo->ecc_strength = get_ecc_strength(this);
if (!geo->ecc_strength) {
- pr_err("We get a wrong ECC strength.\n");
+ pr_err("wrong ECC strength.\n");
return -EINVAL;
}
@@ -316,7 +320,7 @@ acquire_register_block(struct gpmi_nand_data *this, const char *res_name)
struct platform_device *pdev = this->pdev;
struct resources *res = &this->resources;
struct resource *r;
- void *p;
+ void __iomem *p;
r = platform_get_resource_byname(pdev, IORESOURCE_MEM, res_name);
if (!r) {
@@ -423,8 +427,8 @@ static int __devinit acquire_dma_channels(struct gpmi_nand_data *this)
struct platform_device *pdev = this->pdev;
struct resource *r_dma;
struct device_node *dn;
- int dma_channel;
- unsigned int ret;
+ u32 dma_channel;
+ int ret;
struct dma_chan *dma_chan;
dma_cap_mask_t mask;
@@ -464,9 +468,73 @@ acquire_err:
return -EINVAL;
}
+static void gpmi_put_clks(struct gpmi_nand_data *this)
+{
+ struct resources *r = &this->resources;
+ struct clk *clk;
+ int i;
+
+ for (i = 0; i < GPMI_CLK_MAX; i++) {
+ clk = r->clock[i];
+ if (clk) {
+ clk_put(clk);
+ r->clock[i] = NULL;
+ }
+ }
+}
+
+static char *extra_clks_for_mx6q[GPMI_CLK_MAX] = {
+ "gpmi_apb", "gpmi_bch", "gpmi_bch_apb", "per1_bch",
+};
+
+static int __devinit gpmi_get_clks(struct gpmi_nand_data *this)
+{
+ struct resources *r = &this->resources;
+ char **extra_clks = NULL;
+ struct clk *clk;
+ int i;
+
+ /* The main clock is stored in the first. */
+ r->clock[0] = clk_get(this->dev, "gpmi_io");
+ if (IS_ERR(r->clock[0]))
+ goto err_clock;
+
+ /* Get extra clocks */
+ if (GPMI_IS_MX6Q(this))
+ extra_clks = extra_clks_for_mx6q;
+ if (!extra_clks)
+ return 0;
+
+ for (i = 1; i < GPMI_CLK_MAX; i++) {
+ if (extra_clks[i - 1] == NULL)
+ break;
+
+ clk = clk_get(this->dev, extra_clks[i - 1]);
+ if (IS_ERR(clk))
+ goto err_clock;
+
+ r->clock[i] = clk;
+ }
+
+ if (GPMI_IS_MX6Q(this))
+ /*
+ * Set the default value for the gpmi clock in mx6q:
+ *
+ * If you want to use the ONFI nand which is in the
+ * Synchronous Mode, you should change the clock as you need.
+ */
+ clk_set_rate(r->clock[0], 22000000);
+
+ return 0;
+
+err_clock:
+ dev_dbg(this->dev, "failed in finding the clocks.\n");
+ gpmi_put_clks(this);
+ return -ENOMEM;
+}
+
static int __devinit acquire_resources(struct gpmi_nand_data *this)
{
- struct resources *res = &this->resources;
struct pinctrl *pinctrl;
int ret;
@@ -492,12 +560,9 @@ static int __devinit acquire_resources(struct gpmi_nand_data *this)
goto exit_pin;
}
- res->clock = clk_get(&this->pdev->dev, NULL);
- if (IS_ERR(res->clock)) {
- pr_err("can not get the clock\n");
- ret = -ENOENT;
+ ret = gpmi_get_clks(this);
+ if (ret)
goto exit_clock;
- }
return 0;
exit_clock:
@@ -512,9 +577,7 @@ exit_regs:
static void release_resources(struct gpmi_nand_data *this)
{
- struct resources *r = &this->resources;
-
- clk_put(r->clock);
+ gpmi_put_clks(this);
release_register_block(this);
release_bch_irq(this);
release_dma_channels(this);
@@ -667,12 +730,12 @@ static int gpmi_alloc_dma_buffer(struct gpmi_nand_data *this)
struct device *dev = this->dev;
/* [1] Allocate a command buffer. PAGE_SIZE is enough. */
- this->cmd_buffer = kzalloc(PAGE_SIZE, GFP_DMA);
+ this->cmd_buffer = kzalloc(PAGE_SIZE, GFP_DMA | GFP_KERNEL);
if (this->cmd_buffer == NULL)
goto error_alloc;
/* [2] Allocate a read/write data buffer. PAGE_SIZE is enough. */
- this->data_buffer_dma = kzalloc(PAGE_SIZE, GFP_DMA);
+ this->data_buffer_dma = kzalloc(PAGE_SIZE, GFP_DMA | GFP_KERNEL);
if (this->data_buffer_dma == NULL)
goto error_alloc;
@@ -930,7 +993,7 @@ exit_nfc:
return ret;
}
-static void gpmi_ecc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
+static int gpmi_ecc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
const uint8_t *buf, int oob_required)
{
struct gpmi_nand_data *this = chip->priv;
@@ -972,7 +1035,7 @@ static void gpmi_ecc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
&payload_virt, &payload_phys);
if (ret) {
pr_err("Inadequate payload DMA buffer\n");
- return;
+ return 0;
}
ret = send_page_prepare(this,
@@ -1002,6 +1065,8 @@ exit_auxiliary:
nfc_geo->payload_size,
payload_virt, payload_phys);
}
+
+ return 0;
}
/*
@@ -1064,6 +1129,9 @@ exit_auxiliary:
* ECC-based or raw view of the page is implicit in which function it calls
* (there is a similar pair of ECC-based/raw functions for writing).
*
+ * FIXME: The following paragraph is incorrect, now that there exist
+ * ecc.read_oob_raw and ecc.write_oob_raw functions.
+ *
* Since MTD assumes the OOB is not covered by ECC, there is no pair of
* ECC-based/raw functions for reading or or writing the OOB. The fact that the
* caller wants an ECC-based or raw view of the page is not propagated down to
@@ -1190,7 +1258,6 @@ static int mx23_check_transcription_stamp(struct gpmi_nand_data *this)
unsigned int search_area_size_in_strides;
unsigned int stride;
unsigned int page;
- loff_t byte;
uint8_t *buffer = chip->buffers->databuf;
int saved_chip_number;
int found_an_ncb_fingerprint = false;
@@ -1207,9 +1274,8 @@ static int mx23_check_transcription_stamp(struct gpmi_nand_data *this)
dev_dbg(dev, "Scanning for an NCB fingerprint...\n");
for (stride = 0; stride < search_area_size_in_strides; stride++) {
- /* Compute the page and byte addresses. */
+ /* Compute the page addresses. */
page = stride * rom_geo->stride_size_in_pages;
- byte = page * mtd->writesize;
dev_dbg(dev, "Looking for a fingerprint in page 0x%x\n", page);
@@ -1251,7 +1317,6 @@ static int mx23_write_transcription_stamp(struct gpmi_nand_data *this)
unsigned int block;
unsigned int stride;
unsigned int page;
- loff_t byte;
uint8_t *buffer = chip->buffers->databuf;
int saved_chip_number;
int status;
@@ -1300,9 +1365,8 @@ static int mx23_write_transcription_stamp(struct gpmi_nand_data *this)
/* Loop through the first search area, writing NCB fingerprints. */
dev_dbg(dev, "Writing NCB fingerprints...\n");
for (stride = 0; stride < search_area_size_in_strides; stride++) {
- /* Compute the page and byte addresses. */
+ /* Compute the page addresses. */
page = stride * rom_geo->stride_size_in_pages;
- byte = page * mtd->writesize;
/* Write the first page of the current stride. */
dev_dbg(dev, "Writing an NCB fingerprint in page 0x%x\n", page);
@@ -1436,6 +1500,7 @@ static int gpmi_pre_bbt_scan(struct gpmi_nand_data *this)
/* Adjust the ECC strength according to the chip. */
this->nand.ecc.strength = this->bch_geometry.ecc_strength;
this->mtd.ecc_strength = this->bch_geometry.ecc_strength;
+ this->mtd.bitflip_threshold = this->bch_geometry.ecc_strength;
/* NAND boot init, depends on the gpmi_set_geometry(). */
return nand_boot_init(this);
@@ -1452,11 +1517,19 @@ static int gpmi_scan_bbt(struct mtd_info *mtd)
if (ret)
return ret;
+ /*
+ * Can we enable the extra features? such as EDO or Sync mode.
+ *
+ * We do not check the return value now. That's means if we fail in
+ * enable the extra features, we still can run in the normal way.
+ */
+ gpmi_extra_init(this);
+
/* use the default BBT implementation */
return nand_default_bbt(mtd);
}
-void gpmi_nfc_exit(struct gpmi_nand_data *this)
+static void gpmi_nfc_exit(struct gpmi_nand_data *this)
{
nand_release(&this->mtd);
gpmi_free_dma_buffer(this);
@@ -1497,6 +1570,8 @@ static int __devinit gpmi_nfc_init(struct gpmi_nand_data *this)
chip->ecc.size = 1;
chip->ecc.strength = 8;
chip->ecc.layout = &gpmi_hw_ecclayout;
+ if (of_get_nand_on_flash_bbt(this->dev->of_node))
+ chip->bbt_options |= NAND_BBT_USE_FLASH | NAND_BBT_NO_OOB;
/* Allocate a temporary DMA buffer for reading ID in the nand_scan() */
this->bch_geometry.payload_size = 1024;
@@ -1579,6 +1654,8 @@ static int __devinit gpmi_nand_probe(struct platform_device *pdev)
if (ret)
goto exit_nfc_init;
+ dev_info(this->dev, "driver registered.\n");
+
return 0;
exit_nfc_init:
@@ -1586,10 +1663,12 @@ exit_nfc_init:
exit_acquire_resources:
platform_set_drvdata(pdev, NULL);
kfree(this);
+ dev_err(this->dev, "driver registration failed: %d\n", ret);
+
return ret;
}
-static int __exit gpmi_nand_remove(struct platform_device *pdev)
+static int __devexit gpmi_nand_remove(struct platform_device *pdev)
{
struct gpmi_nand_data *this = platform_get_drvdata(pdev);
@@ -1606,29 +1685,10 @@ static struct platform_driver gpmi_nand_driver = {
.of_match_table = gpmi_nand_id_table,
},
.probe = gpmi_nand_probe,
- .remove = __exit_p(gpmi_nand_remove),
+ .remove = __devexit_p(gpmi_nand_remove),
.id_table = gpmi_ids,
};
-
-static int __init gpmi_nand_init(void)
-{
- int err;
-
- err = platform_driver_register(&gpmi_nand_driver);
- if (err == 0)
- printk(KERN_INFO "GPMI NAND driver registered. (IMX)\n");
- else
- pr_err("i.MX GPMI NAND driver registration failed\n");
- return err;
-}
-
-static void __exit gpmi_nand_exit(void)
-{
- platform_driver_unregister(&gpmi_nand_driver);
-}
-
-module_init(gpmi_nand_init);
-module_exit(gpmi_nand_exit);
+module_platform_driver(gpmi_nand_driver);
MODULE_AUTHOR("Freescale Semiconductor, Inc.");
MODULE_DESCRIPTION("i.MX GPMI NAND Flash Controller Driver");
diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.h b/drivers/mtd/nand/gpmi-nand/gpmi-nand.h
index ce5daa1..7ac25c1 100644
--- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.h
+++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.h
@@ -22,14 +22,15 @@
#include <linux/dma-mapping.h>
#include <linux/fsl/mxs-dma.h>
+#define GPMI_CLK_MAX 5 /* MX6Q needs five clocks */
struct resources {
- void *gpmi_regs;
- void *bch_regs;
+ void __iomem *gpmi_regs;
+ void __iomem *bch_regs;
unsigned int bch_low_interrupt;
unsigned int bch_high_interrupt;
unsigned int dma_low_channel;
unsigned int dma_high_channel;
- struct clk *clock;
+ struct clk *clock[GPMI_CLK_MAX];
};
/**
@@ -121,6 +122,11 @@ struct nand_timing {
};
struct gpmi_nand_data {
+ /* flags */
+#define GPMI_ASYNC_EDO_ENABLED (1 << 0)
+#define GPMI_TIMING_INIT_OK (1 << 1)
+ int flags;
+
/* System Interface */
struct device *dev;
struct platform_device *pdev;
@@ -131,6 +137,7 @@ struct gpmi_nand_data {
/* Flash Hardware */
struct nand_timing timing;
+ int timing_mode;
/* BCH */
struct bch_geometry bch_geometry;
@@ -188,16 +195,28 @@ struct gpmi_nand_data {
* @data_setup_in_cycles: The data setup time, in cycles.
* @data_hold_in_cycles: The data hold time, in cycles.
* @address_setup_in_cycles: The address setup time, in cycles.
+ * @device_busy_timeout: The timeout waiting for NAND Ready/Busy,
+ * this value is the number of cycles multiplied
+ * by 4096.
* @use_half_periods: Indicates the clock is running slowly, so the
* NFC DLL should use half-periods.
* @sample_delay_factor: The sample delay factor.
+ * @wrn_dly_sel: The delay on the GPMI write strobe.
*/
struct gpmi_nfc_hardware_timing {
+ /* for HW_GPMI_TIMING0 */
uint8_t data_setup_in_cycles;
uint8_t data_hold_in_cycles;
uint8_t address_setup_in_cycles;
+
+ /* for HW_GPMI_TIMING1 */
+ uint16_t device_busy_timeout;
+#define GPMI_DEFAULT_BUSY_TIMEOUT 0x500 /* default busy timeout value.*/
+
+ /* for HW_GPMI_CTRL1 */
bool use_half_periods;
uint8_t sample_delay_factor;
+ uint8_t wrn_dly_sel;
};
/**
@@ -246,6 +265,7 @@ extern int start_dma_with_bch_irq(struct gpmi_nand_data *,
/* GPMI-NAND helper function library */
extern int gpmi_init(struct gpmi_nand_data *);
+extern int gpmi_extra_init(struct gpmi_nand_data *);
extern void gpmi_clear_bch(struct gpmi_nand_data *);
extern void gpmi_dump_info(struct gpmi_nand_data *);
extern int bch_set_geometry(struct gpmi_nand_data *);
diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-regs.h b/drivers/mtd/nand/gpmi-nand/gpmi-regs.h
index 8343124..53397cc 100644
--- a/drivers/mtd/nand/gpmi-nand/gpmi-regs.h
+++ b/drivers/mtd/nand/gpmi-nand/gpmi-regs.h
@@ -108,6 +108,15 @@
#define HW_GPMI_CTRL1_CLR 0x00000068
#define HW_GPMI_CTRL1_TOG 0x0000006c
+#define BP_GPMI_CTRL1_WRN_DLY_SEL 22
+#define BM_GPMI_CTRL1_WRN_DLY_SEL (0x3 << BP_GPMI_CTRL1_WRN_DLY_SEL)
+#define BF_GPMI_CTRL1_WRN_DLY_SEL(v) \
+ (((v) << BP_GPMI_CTRL1_WRN_DLY_SEL) & BM_GPMI_CTRL1_WRN_DLY_SEL)
+#define BV_GPMI_CTRL1_WRN_DLY_SEL_4_TO_8NS 0x0
+#define BV_GPMI_CTRL1_WRN_DLY_SEL_6_TO_10NS 0x1
+#define BV_GPMI_CTRL1_WRN_DLY_SEL_7_TO_12NS 0x2
+#define BV_GPMI_CTRL1_WRN_DLY_SEL_NO_DELAY 0x3
+
#define BM_GPMI_CTRL1_BCH_MODE (1 << 18)
#define BP_GPMI_CTRL1_DLL_ENABLE 17
@@ -154,6 +163,9 @@
#define HW_GPMI_TIMING1 0x00000080
#define BP_GPMI_TIMING1_BUSY_TIMEOUT 16
+#define BM_GPMI_TIMING1_BUSY_TIMEOUT (0xffff << BP_GPMI_TIMING1_BUSY_TIMEOUT)
+#define BF_GPMI_TIMING1_BUSY_TIMEOUT(v) \
+ (((v) << BP_GPMI_TIMING1_BUSY_TIMEOUT) & BM_GPMI_TIMING1_BUSY_TIMEOUT)
#define HW_GPMI_TIMING2 0x00000090
#define HW_GPMI_DATA 0x000000a0
diff --git a/drivers/mtd/nand/lpc32xx_mlc.c b/drivers/mtd/nand/lpc32xx_mlc.c
new file mode 100644
index 0000000..c29b7ac
--- /dev/null
+++ b/drivers/mtd/nand/lpc32xx_mlc.c
@@ -0,0 +1,924 @@
+/*
+ * Driver for NAND MLC Controller in LPC32xx
+ *
+ * Author: Roland Stigge <stigge@antcom.de>
+ *
+ * Copyright © 2011 WORK Microwave GmbH
+ * Copyright © 2011, 2012 Roland Stigge
+ *
+ * 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.
+ *
+ *
+ * NAND Flash Controller Operation:
+ * - Read: Auto Decode
+ * - Write: Auto Encode
+ * - Tested Page Sizes: 2048, 4096
+ */
+
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/completion.h>
+#include <linux/interrupt.h>
+#include <linux/of.h>
+#include <linux/of_mtd.h>
+#include <linux/of_gpio.h>
+#include <linux/mtd/lpc32xx_mlc.h>
+#include <linux/io.h>
+#include <linux/mm.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
+#include <linux/mtd/nand_ecc.h>
+
+#define DRV_NAME "lpc32xx_mlc"
+
+/**********************************************************************
+* MLC NAND controller register offsets
+**********************************************************************/
+
+#define MLC_BUFF(x) (x + 0x00000)
+#define MLC_DATA(x) (x + 0x08000)
+#define MLC_CMD(x) (x + 0x10000)
+#define MLC_ADDR(x) (x + 0x10004)
+#define MLC_ECC_ENC_REG(x) (x + 0x10008)
+#define MLC_ECC_DEC_REG(x) (x + 0x1000C)
+#define MLC_ECC_AUTO_ENC_REG(x) (x + 0x10010)
+#define MLC_ECC_AUTO_DEC_REG(x) (x + 0x10014)
+#define MLC_RPR(x) (x + 0x10018)
+#define MLC_WPR(x) (x + 0x1001C)
+#define MLC_RUBP(x) (x + 0x10020)
+#define MLC_ROBP(x) (x + 0x10024)
+#define MLC_SW_WP_ADD_LOW(x) (x + 0x10028)
+#define MLC_SW_WP_ADD_HIG(x) (x + 0x1002C)
+#define MLC_ICR(x) (x + 0x10030)
+#define MLC_TIME_REG(x) (x + 0x10034)
+#define MLC_IRQ_MR(x) (x + 0x10038)
+#define MLC_IRQ_SR(x) (x + 0x1003C)
+#define MLC_LOCK_PR(x) (x + 0x10044)
+#define MLC_ISR(x) (x + 0x10048)
+#define MLC_CEH(x) (x + 0x1004C)
+
+/**********************************************************************
+* MLC_CMD bit definitions
+**********************************************************************/
+#define MLCCMD_RESET 0xFF
+
+/**********************************************************************
+* MLC_ICR bit definitions
+**********************************************************************/
+#define MLCICR_WPROT (1 << 3)
+#define MLCICR_LARGEBLOCK (1 << 2)
+#define MLCICR_LONGADDR (1 << 1)
+#define MLCICR_16BIT (1 << 0) /* unsupported by LPC32x0! */
+
+/**********************************************************************
+* MLC_TIME_REG bit definitions
+**********************************************************************/
+#define MLCTIMEREG_TCEA_DELAY(n) (((n) & 0x03) << 24)
+#define MLCTIMEREG_BUSY_DELAY(n) (((n) & 0x1F) << 19)
+#define MLCTIMEREG_NAND_TA(n) (((n) & 0x07) << 16)
+#define MLCTIMEREG_RD_HIGH(n) (((n) & 0x0F) << 12)
+#define MLCTIMEREG_RD_LOW(n) (((n) & 0x0F) << 8)
+#define MLCTIMEREG_WR_HIGH(n) (((n) & 0x0F) << 4)
+#define MLCTIMEREG_WR_LOW(n) (((n) & 0x0F) << 0)
+
+/**********************************************************************
+* MLC_IRQ_MR and MLC_IRQ_SR bit definitions
+**********************************************************************/
+#define MLCIRQ_NAND_READY (1 << 5)
+#define MLCIRQ_CONTROLLER_READY (1 << 4)
+#define MLCIRQ_DECODE_FAILURE (1 << 3)
+#define MLCIRQ_DECODE_ERROR (1 << 2)
+#define MLCIRQ_ECC_READY (1 << 1)
+#define MLCIRQ_WRPROT_FAULT (1 << 0)
+
+/**********************************************************************
+* MLC_LOCK_PR bit definitions
+**********************************************************************/
+#define MLCLOCKPR_MAGIC 0xA25E
+
+/**********************************************************************
+* MLC_ISR bit definitions
+**********************************************************************/
+#define MLCISR_DECODER_FAILURE (1 << 6)
+#define MLCISR_ERRORS ((1 << 4) | (1 << 5))
+#define MLCISR_ERRORS_DETECTED (1 << 3)
+#define MLCISR_ECC_READY (1 << 2)
+#define MLCISR_CONTROLLER_READY (1 << 1)
+#define MLCISR_NAND_READY (1 << 0)
+
+/**********************************************************************
+* MLC_CEH bit definitions
+**********************************************************************/
+#define MLCCEH_NORMAL (1 << 0)
+
+struct lpc32xx_nand_cfg_mlc {
+ uint32_t tcea_delay;
+ uint32_t busy_delay;
+ uint32_t nand_ta;
+ uint32_t rd_high;
+ uint32_t rd_low;
+ uint32_t wr_high;
+ uint32_t wr_low;
+ int wp_gpio;
+ struct mtd_partition *parts;
+ unsigned num_parts;
+};
+
+static struct nand_ecclayout lpc32xx_nand_oob = {
+ .eccbytes = 40,
+ .eccpos = { 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 54, 55, 56, 57, 58, 59, 60, 61, 62, 63 },
+ .oobfree = {
+ { .offset = 0,
+ .length = 6, },
+ { .offset = 16,
+ .length = 6, },
+ { .offset = 32,
+ .length = 6, },
+ { .offset = 48,
+ .length = 6, },
+ },
+};
+
+static struct nand_bbt_descr lpc32xx_nand_bbt = {
+ .options = NAND_BBT_ABSPAGE | NAND_BBT_2BIT | NAND_BBT_NO_OOB |
+ NAND_BBT_WRITE,
+ .pages = { 524224, 0, 0, 0, 0, 0, 0, 0 },
+};
+
+static struct nand_bbt_descr lpc32xx_nand_bbt_mirror = {
+ .options = NAND_BBT_ABSPAGE | NAND_BBT_2BIT | NAND_BBT_NO_OOB |
+ NAND_BBT_WRITE,
+ .pages = { 524160, 0, 0, 0, 0, 0, 0, 0 },
+};
+
+struct lpc32xx_nand_host {
+ struct nand_chip nand_chip;
+ struct lpc32xx_mlc_platform_data *pdata;
+ struct clk *clk;
+ struct mtd_info mtd;
+ void __iomem *io_base;
+ int irq;
+ struct lpc32xx_nand_cfg_mlc *ncfg;
+ struct completion comp_nand;
+ struct completion comp_controller;
+ uint32_t llptr;
+ /*
+ * Physical addresses of ECC buffer, DMA data buffers, OOB data buffer
+ */
+ dma_addr_t oob_buf_phy;
+ /*
+ * Virtual addresses of ECC buffer, DMA data buffers, OOB data buffer
+ */
+ uint8_t *oob_buf;
+ /* Physical address of DMA base address */
+ dma_addr_t io_base_phy;
+
+ struct completion comp_dma;
+ struct dma_chan *dma_chan;
+ struct dma_slave_config dma_slave_config;
+ struct scatterlist sgl;
+ uint8_t *dma_buf;
+ uint8_t *dummy_buf;
+ int mlcsubpages; /* number of 512bytes-subpages */
+};
+
+/*
+ * Activate/Deactivate DMA Operation:
+ *
+ * Using the PL080 DMA Controller for transferring the 512 byte subpages
+ * instead of doing readl() / writel() in a loop slows it down significantly.
+ * Measurements via getnstimeofday() upon 512 byte subpage reads reveal:
+ *
+ * - readl() of 128 x 32 bits in a loop: ~20us
+ * - DMA read of 512 bytes (32 bit, 4...128 words bursts): ~60us
+ * - DMA read of 512 bytes (32 bit, no bursts): ~100us
+ *
+ * This applies to the transfer itself. In the DMA case: only the
+ * wait_for_completion() (DMA setup _not_ included).
+ *
+ * Note that the 512 bytes subpage transfer is done directly from/to a
+ * FIFO/buffer inside the NAND controller. Most of the time (~400-800us for a
+ * 2048 bytes page) is spent waiting for the NAND IRQ, anyway. (The NAND
+ * controller transferring data between its internal buffer to/from the NAND
+ * chip.)
+ *
+ * Therefore, using the PL080 DMA is disabled by default, for now.
+ *
+ */
+static int use_dma;
+
+static void lpc32xx_nand_setup(struct lpc32xx_nand_host *host)
+{
+ uint32_t clkrate, tmp;
+
+ /* Reset MLC controller */
+ writel(MLCCMD_RESET, MLC_CMD(host->io_base));
+ udelay(1000);
+
+ /* Get base clock for MLC block */
+ clkrate = clk_get_rate(host->clk);
+ if (clkrate == 0)
+ clkrate = 104000000;
+
+ /* Unlock MLC_ICR
+ * (among others, will be locked again automatically) */
+ writew(MLCLOCKPR_MAGIC, MLC_LOCK_PR(host->io_base));
+
+ /* Configure MLC Controller: Large Block, 5 Byte Address */
+ tmp = MLCICR_LARGEBLOCK | MLCICR_LONGADDR;
+ writel(tmp, MLC_ICR(host->io_base));
+
+ /* Unlock MLC_TIME_REG
+ * (among others, will be locked again automatically) */
+ writew(MLCLOCKPR_MAGIC, MLC_LOCK_PR(host->io_base));
+
+ /* Compute clock setup values, see LPC and NAND manual */
+ tmp = 0;
+ tmp |= MLCTIMEREG_TCEA_DELAY(clkrate / host->ncfg->tcea_delay + 1);
+ tmp |= MLCTIMEREG_BUSY_DELAY(clkrate / host->ncfg->busy_delay + 1);
+ tmp |= MLCTIMEREG_NAND_TA(clkrate / host->ncfg->nand_ta + 1);
+ tmp |= MLCTIMEREG_RD_HIGH(clkrate / host->ncfg->rd_high + 1);
+ tmp |= MLCTIMEREG_RD_LOW(clkrate / host->ncfg->rd_low);
+ tmp |= MLCTIMEREG_WR_HIGH(clkrate / host->ncfg->wr_high + 1);
+ tmp |= MLCTIMEREG_WR_LOW(clkrate / host->ncfg->wr_low);
+ writel(tmp, MLC_TIME_REG(host->io_base));
+
+ /* Enable IRQ for CONTROLLER_READY and NAND_READY */
+ writeb(MLCIRQ_CONTROLLER_READY | MLCIRQ_NAND_READY,
+ MLC_IRQ_MR(host->io_base));
+
+ /* Normal nCE operation: nCE controlled by controller */
+ writel(MLCCEH_NORMAL, MLC_CEH(host->io_base));
+}
+
+/*
+ * Hardware specific access to control lines
+ */
+static void lpc32xx_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
+ unsigned int ctrl)
+{
+ struct nand_chip *nand_chip = mtd->priv;
+ struct lpc32xx_nand_host *host = nand_chip->priv;
+
+ if (cmd != NAND_CMD_NONE) {
+ if (ctrl & NAND_CLE)
+ writel(cmd, MLC_CMD(host->io_base));
+ else
+ writel(cmd, MLC_ADDR(host->io_base));
+ }
+}
+
+/*
+ * Read Device Ready (NAND device _and_ controller ready)
+ */
+static int lpc32xx_nand_device_ready(struct mtd_info *mtd)
+{
+ struct nand_chip *nand_chip = mtd->priv;
+ struct lpc32xx_nand_host *host = nand_chip->priv;
+
+ if ((readb(MLC_ISR(host->io_base)) &
+ (MLCISR_CONTROLLER_READY | MLCISR_NAND_READY)) ==
+ (MLCISR_CONTROLLER_READY | MLCISR_NAND_READY))
+ return 1;
+
+ return 0;
+}
+
+static irqreturn_t lpc3xxx_nand_irq(int irq, struct lpc32xx_nand_host *host)
+{
+ uint8_t sr;
+
+ /* Clear interrupt flag by reading status */
+ sr = readb(MLC_IRQ_SR(host->io_base));
+ if (sr & MLCIRQ_NAND_READY)
+ complete(&host->comp_nand);
+ if (sr & MLCIRQ_CONTROLLER_READY)
+ complete(&host->comp_controller);
+
+ return IRQ_HANDLED;
+}
+
+static int lpc32xx_waitfunc_nand(struct mtd_info *mtd, struct nand_chip *chip)
+{
+ struct lpc32xx_nand_host *host = chip->priv;
+
+ if (readb(MLC_ISR(host->io_base)) & MLCISR_NAND_READY)
+ goto exit;
+
+ wait_for_completion(&host->comp_nand);
+
+ while (!(readb(MLC_ISR(host->io_base)) & MLCISR_NAND_READY)) {
+ /* Seems to be delayed sometimes by controller */
+ dev_dbg(&mtd->dev, "Warning: NAND not ready.\n");
+ cpu_relax();
+ }
+
+exit:
+ return NAND_STATUS_READY;
+}
+
+static int lpc32xx_waitfunc_controller(struct mtd_info *mtd,
+ struct nand_chip *chip)
+{
+ struct lpc32xx_nand_host *host = chip->priv;
+
+ if (readb(MLC_ISR(host->io_base)) & MLCISR_CONTROLLER_READY)
+ goto exit;
+
+ wait_for_completion(&host->comp_controller);
+
+ while (!(readb(MLC_ISR(host->io_base)) &
+ MLCISR_CONTROLLER_READY)) {
+ dev_dbg(&mtd->dev, "Warning: Controller not ready.\n");
+ cpu_relax();
+ }
+
+exit:
+ return NAND_STATUS_READY;
+}
+
+static int lpc32xx_waitfunc(struct mtd_info *mtd, struct nand_chip *chip)
+{
+ lpc32xx_waitfunc_nand(mtd, chip);
+ lpc32xx_waitfunc_controller(mtd, chip);
+
+ return NAND_STATUS_READY;
+}
+
+/*
+ * Enable NAND write protect
+ */
+static void lpc32xx_wp_enable(struct lpc32xx_nand_host *host)
+{
+ if (gpio_is_valid(host->ncfg->wp_gpio))
+ gpio_set_value(host->ncfg->wp_gpio, 0);
+}
+
+/*
+ * Disable NAND write protect
+ */
+static void lpc32xx_wp_disable(struct lpc32xx_nand_host *host)
+{
+ if (gpio_is_valid(host->ncfg->wp_gpio))
+ gpio_set_value(host->ncfg->wp_gpio, 1);
+}
+
+static void lpc32xx_dma_complete_func(void *completion)
+{
+ complete(completion);
+}
+
+static int lpc32xx_xmit_dma(struct mtd_info *mtd, void *mem, int len,
+ enum dma_transfer_direction dir)
+{
+ struct nand_chip *chip = mtd->priv;
+ struct lpc32xx_nand_host *host = chip->priv;
+ struct dma_async_tx_descriptor *desc;
+ int flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT;
+ int res;
+
+ sg_init_one(&host->sgl, mem, len);
+
+ res = dma_map_sg(host->dma_chan->device->dev, &host->sgl, 1,
+ DMA_BIDIRECTIONAL);
+ if (res != 1) {
+ dev_err(mtd->dev.parent, "Failed to map sg list\n");
+ return -ENXIO;
+ }
+ desc = dmaengine_prep_slave_sg(host->dma_chan, &host->sgl, 1, dir,
+ flags);
+ if (!desc) {
+ dev_err(mtd->dev.parent, "Failed to prepare slave sg\n");
+ goto out1;
+ }
+
+ init_completion(&host->comp_dma);
+ desc->callback = lpc32xx_dma_complete_func;
+ desc->callback_param = &host->comp_dma;
+
+ dmaengine_submit(desc);
+ dma_async_issue_pending(host->dma_chan);
+
+ wait_for_completion_timeout(&host->comp_dma, msecs_to_jiffies(1000));
+
+ dma_unmap_sg(host->dma_chan->device->dev, &host->sgl, 1,
+ DMA_BIDIRECTIONAL);
+ return 0;
+out1:
+ dma_unmap_sg(host->dma_chan->device->dev, &host->sgl, 1,
+ DMA_BIDIRECTIONAL);
+ return -ENXIO;
+}
+
+static int lpc32xx_read_page(struct mtd_info *mtd, struct nand_chip *chip,
+ uint8_t *buf, int oob_required, int page)
+{
+ struct lpc32xx_nand_host *host = chip->priv;
+ int i, j;
+ uint8_t *oobbuf = chip->oob_poi;
+ uint32_t mlc_isr;
+ int res;
+ uint8_t *dma_buf;
+ bool dma_mapped;
+
+ if ((void *)buf <= high_memory) {
+ dma_buf = buf;
+ dma_mapped = true;
+ } else {
+ dma_buf = host->dma_buf;
+ dma_mapped = false;
+ }
+
+ /* Writing Command and Address */
+ chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
+
+ /* For all sub-pages */
+ for (i = 0; i < host->mlcsubpages; i++) {
+ /* Start Auto Decode Command */
+ writeb(0x00, MLC_ECC_AUTO_DEC_REG(host->io_base));
+
+ /* Wait for Controller Ready */
+ lpc32xx_waitfunc_controller(mtd, chip);
+
+ /* Check ECC Error status */
+ mlc_isr = readl(MLC_ISR(host->io_base));
+ if (mlc_isr & MLCISR_DECODER_FAILURE) {
+ mtd->ecc_stats.failed++;
+ dev_warn(&mtd->dev, "%s: DECODER_FAILURE\n", __func__);
+ } else if (mlc_isr & MLCISR_ERRORS_DETECTED) {
+ mtd->ecc_stats.corrected += ((mlc_isr >> 4) & 0x3) + 1;
+ }
+
+ /* Read 512 + 16 Bytes */
+ if (use_dma) {
+ res = lpc32xx_xmit_dma(mtd, dma_buf + i * 512, 512,
+ DMA_DEV_TO_MEM);
+ if (res)
+ return res;
+ } else {
+ for (j = 0; j < (512 >> 2); j++) {
+ *((uint32_t *)(buf)) =
+ readl(MLC_BUFF(host->io_base));
+ buf += 4;
+ }
+ }
+ for (j = 0; j < (16 >> 2); j++) {
+ *((uint32_t *)(oobbuf)) =
+ readl(MLC_BUFF(host->io_base));
+ oobbuf += 4;
+ }
+ }
+
+ if (use_dma && !dma_mapped)
+ memcpy(buf, dma_buf, mtd->writesize);
+
+ return 0;
+}
+
+static int lpc32xx_write_page_lowlevel(struct mtd_info *mtd,
+ struct nand_chip *chip,
+ const uint8_t *buf, int oob_required)
+{
+ struct lpc32xx_nand_host *host = chip->priv;
+ const uint8_t *oobbuf = chip->oob_poi;
+ uint8_t *dma_buf = (uint8_t *)buf;
+ int res;
+ int i, j;
+
+ if (use_dma && (void *)buf >= high_memory) {
+ dma_buf = host->dma_buf;
+ memcpy(dma_buf, buf, mtd->writesize);
+ }
+
+ for (i = 0; i < host->mlcsubpages; i++) {
+ /* Start Encode */
+ writeb(0x00, MLC_ECC_ENC_REG(host->io_base));
+
+ /* Write 512 + 6 Bytes to Buffer */
+ if (use_dma) {
+ res = lpc32xx_xmit_dma(mtd, dma_buf + i * 512, 512,
+ DMA_MEM_TO_DEV);
+ if (res)
+ return res;
+ } else {
+ for (j = 0; j < (512 >> 2); j++) {
+ writel(*((uint32_t *)(buf)),
+ MLC_BUFF(host->io_base));
+ buf += 4;
+ }
+ }
+ writel(*((uint32_t *)(oobbuf)), MLC_BUFF(host->io_base));
+ oobbuf += 4;
+ writew(*((uint16_t *)(oobbuf)), MLC_BUFF(host->io_base));
+ oobbuf += 12;
+
+ /* Auto Encode w/ Bit 8 = 0 (see LPC MLC Controller manual) */
+ writeb(0x00, MLC_ECC_AUTO_ENC_REG(host->io_base));
+
+ /* Wait for Controller Ready */
+ lpc32xx_waitfunc_controller(mtd, chip);
+ }
+ return 0;
+}
+
+static int lpc32xx_write_page(struct mtd_info *mtd, struct nand_chip *chip,
+ const uint8_t *buf, int oob_required, int page,
+ int cached, int raw)
+{
+ int res;
+
+ chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
+ res = lpc32xx_write_page_lowlevel(mtd, chip, buf, oob_required);
+ chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
+ lpc32xx_waitfunc(mtd, chip);
+
+ return res;
+}
+
+static int lpc32xx_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
+ int page)
+{
+ struct lpc32xx_nand_host *host = chip->priv;
+
+ /* Read whole page - necessary with MLC controller! */
+ lpc32xx_read_page(mtd, chip, host->dummy_buf, 1, page);
+
+ return 0;
+}
+
+static int lpc32xx_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
+ int page)
+{
+ /* None, write_oob conflicts with the automatic LPC MLC ECC decoder! */
+ return 0;
+}
+
+/* Prepares MLC for transfers with H/W ECC enabled: always enabled anyway */
+static void lpc32xx_ecc_enable(struct mtd_info *mtd, int mode)
+{
+ /* Always enabled! */
+}
+
+static int lpc32xx_dma_setup(struct lpc32xx_nand_host *host)
+{
+ struct mtd_info *mtd = &host->mtd;
+ dma_cap_mask_t mask;
+
+ if (!host->pdata || !host->pdata->dma_filter) {
+ dev_err(mtd->dev.parent, "no DMA platform data\n");
+ return -ENOENT;
+ }
+
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_SLAVE, mask);
+ host->dma_chan = dma_request_channel(mask, host->pdata->dma_filter,
+ "nand-mlc");
+ if (!host->dma_chan) {
+ dev_err(mtd->dev.parent, "Failed to request DMA channel\n");
+ return -EBUSY;
+ }
+
+ /*
+ * Set direction to a sensible value even if the dmaengine driver
+ * should ignore it. With the default (DMA_MEM_TO_MEM), the amba-pl08x
+ * driver criticizes it as "alien transfer direction".
+ */
+ host->dma_slave_config.direction = DMA_DEV_TO_MEM;
+ host->dma_slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+ host->dma_slave_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+ host->dma_slave_config.src_maxburst = 128;
+ host->dma_slave_config.dst_maxburst = 128;
+ /* DMA controller does flow control: */
+ host->dma_slave_config.device_fc = false;
+ host->dma_slave_config.src_addr = MLC_BUFF(host->io_base_phy);
+ host->dma_slave_config.dst_addr = MLC_BUFF(host->io_base_phy);
+ if (dmaengine_slave_config(host->dma_chan, &host->dma_slave_config)) {
+ dev_err(mtd->dev.parent, "Failed to setup DMA slave\n");
+ goto out1;
+ }
+
+ return 0;
+out1:
+ dma_release_channel(host->dma_chan);
+ return -ENXIO;
+}
+
+static struct lpc32xx_nand_cfg_mlc *lpc32xx_parse_dt(struct device *dev)
+{
+ struct lpc32xx_nand_cfg_mlc *ncfg;
+ struct device_node *np = dev->of_node;
+
+ ncfg = devm_kzalloc(dev, sizeof(*ncfg), GFP_KERNEL);
+ if (!ncfg) {
+ dev_err(dev, "could not allocate memory for platform data\n");
+ return NULL;
+ }
+
+ of_property_read_u32(np, "nxp,tcea-delay", &ncfg->tcea_delay);
+ of_property_read_u32(np, "nxp,busy-delay", &ncfg->busy_delay);
+ of_property_read_u32(np, "nxp,nand-ta", &ncfg->nand_ta);
+ of_property_read_u32(np, "nxp,rd-high", &ncfg->rd_high);
+ of_property_read_u32(np, "nxp,rd-low", &ncfg->rd_low);
+ of_property_read_u32(np, "nxp,wr-high", &ncfg->wr_high);
+ of_property_read_u32(np, "nxp,wr-low", &ncfg->wr_low);
+
+ if (!ncfg->tcea_delay || !ncfg->busy_delay || !ncfg->nand_ta ||
+ !ncfg->rd_high || !ncfg->rd_low || !ncfg->wr_high ||
+ !ncfg->wr_low) {
+ dev_err(dev, "chip parameters not specified correctly\n");
+ return NULL;
+ }
+
+ ncfg->wp_gpio = of_get_named_gpio(np, "gpios", 0);
+
+ return ncfg;
+}
+
+/*
+ * Probe for NAND controller
+ */
+static int __devinit lpc32xx_nand_probe(struct platform_device *pdev)
+{
+ struct lpc32xx_nand_host *host;
+ struct mtd_info *mtd;
+ struct nand_chip *nand_chip;
+ struct resource *rc;
+ int res;
+ struct mtd_part_parser_data ppdata = {};
+
+ /* Allocate memory for the device structure (and zero it) */
+ host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL);
+ if (!host) {
+ dev_err(&pdev->dev, "failed to allocate device structure.\n");
+ return -ENOMEM;
+ }
+
+ rc = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (rc == NULL) {
+ dev_err(&pdev->dev, "No memory resource found for device!\r\n");
+ return -ENXIO;
+ }
+
+ host->io_base = devm_request_and_ioremap(&pdev->dev, rc);
+ if (host->io_base == NULL) {
+ dev_err(&pdev->dev, "ioremap failed\n");
+ return -EIO;
+ }
+ host->io_base_phy = rc->start;
+
+ mtd = &host->mtd;
+ nand_chip = &host->nand_chip;
+ if (pdev->dev.of_node)
+ host->ncfg = lpc32xx_parse_dt(&pdev->dev);
+ if (!host->ncfg) {
+ dev_err(&pdev->dev,
+ "Missing or bad NAND config from device tree\n");
+ return -ENOENT;
+ }
+ if (host->ncfg->wp_gpio == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+ if (gpio_is_valid(host->ncfg->wp_gpio) &&
+ gpio_request(host->ncfg->wp_gpio, "NAND WP")) {
+ dev_err(&pdev->dev, "GPIO not available\n");
+ return -EBUSY;
+ }
+ lpc32xx_wp_disable(host);
+
+ host->pdata = pdev->dev.platform_data;
+
+ nand_chip->priv = host; /* link the private data structures */
+ mtd->priv = nand_chip;
+ mtd->owner = THIS_MODULE;
+ mtd->dev.parent = &pdev->dev;
+
+ /* Get NAND clock */
+ host->clk = clk_get(&pdev->dev, NULL);
+ if (IS_ERR(host->clk)) {
+ dev_err(&pdev->dev, "Clock initialization failure\n");
+ res = -ENOENT;
+ goto err_exit1;
+ }
+ clk_enable(host->clk);
+
+ nand_chip->cmd_ctrl = lpc32xx_nand_cmd_ctrl;
+ nand_chip->dev_ready = lpc32xx_nand_device_ready;
+ nand_chip->chip_delay = 25; /* us */
+ nand_chip->IO_ADDR_R = MLC_DATA(host->io_base);
+ nand_chip->IO_ADDR_W = MLC_DATA(host->io_base);
+
+ /* Init NAND controller */
+ lpc32xx_nand_setup(host);
+
+ platform_set_drvdata(pdev, host);
+
+ /* Initialize function pointers */
+ nand_chip->ecc.hwctl = lpc32xx_ecc_enable;
+ nand_chip->ecc.read_page_raw = lpc32xx_read_page;
+ nand_chip->ecc.read_page = lpc32xx_read_page;
+ nand_chip->ecc.write_page_raw = lpc32xx_write_page_lowlevel;
+ nand_chip->ecc.write_page = lpc32xx_write_page_lowlevel;
+ nand_chip->ecc.write_oob = lpc32xx_write_oob;
+ nand_chip->ecc.read_oob = lpc32xx_read_oob;
+ nand_chip->ecc.strength = 4;
+ nand_chip->write_page = lpc32xx_write_page;
+ nand_chip->waitfunc = lpc32xx_waitfunc;
+
+ nand_chip->bbt_options = NAND_BBT_USE_FLASH | NAND_BBT_NO_OOB;
+ nand_chip->bbt_td = &lpc32xx_nand_bbt;
+ nand_chip->bbt_md = &lpc32xx_nand_bbt_mirror;
+
+ /* bitflip_threshold's default is defined as ecc_strength anyway.
+ * Unfortunately, it is set only later at add_mtd_device(). Meanwhile
+ * being 0, it causes bad block table scanning errors in
+ * nand_scan_tail(), so preparing it here. */
+ mtd->bitflip_threshold = nand_chip->ecc.strength;
+
+ if (use_dma) {
+ res = lpc32xx_dma_setup(host);
+ if (res) {
+ res = -EIO;
+ goto err_exit2;
+ }
+ }
+
+ /*
+ * Scan to find existance of the device and
+ * Get the type of NAND device SMALL block or LARGE block
+ */
+ if (nand_scan_ident(mtd, 1, NULL)) {
+ res = -ENXIO;
+ goto err_exit3;
+ }
+
+ host->dma_buf = devm_kzalloc(&pdev->dev, mtd->writesize, GFP_KERNEL);
+ if (!host->dma_buf) {
+ dev_err(&pdev->dev, "Error allocating dma_buf memory\n");
+ res = -ENOMEM;
+ goto err_exit3;
+ }
+
+ host->dummy_buf = devm_kzalloc(&pdev->dev, mtd->writesize, GFP_KERNEL);
+ if (!host->dummy_buf) {
+ dev_err(&pdev->dev, "Error allocating dummy_buf memory\n");
+ res = -ENOMEM;
+ goto err_exit3;
+ }
+
+ nand_chip->ecc.mode = NAND_ECC_HW;
+ nand_chip->ecc.size = mtd->writesize;
+ nand_chip->ecc.layout = &lpc32xx_nand_oob;
+ host->mlcsubpages = mtd->writesize / 512;
+
+ /* initially clear interrupt status */
+ readb(MLC_IRQ_SR(host->io_base));
+
+ init_completion(&host->comp_nand);
+ init_completion(&host->comp_controller);
+
+ host->irq = platform_get_irq(pdev, 0);
+ if ((host->irq < 0) || (host->irq >= NR_IRQS)) {
+ dev_err(&pdev->dev, "failed to get platform irq\n");
+ res = -EINVAL;
+ goto err_exit3;
+ }
+
+ if (request_irq(host->irq, (irq_handler_t)&lpc3xxx_nand_irq,
+ IRQF_TRIGGER_HIGH, DRV_NAME, host)) {
+ dev_err(&pdev->dev, "Error requesting NAND IRQ\n");
+ res = -ENXIO;
+ goto err_exit3;
+ }
+
+ /*
+ * Fills out all the uninitialized function pointers with the defaults
+ * And scans for a bad block table if appropriate.
+ */
+ if (nand_scan_tail(mtd)) {
+ res = -ENXIO;
+ goto err_exit4;
+ }
+
+ mtd->name = DRV_NAME;
+
+ ppdata.of_node = pdev->dev.of_node;
+ res = mtd_device_parse_register(mtd, NULL, &ppdata, host->ncfg->parts,
+ host->ncfg->num_parts);
+ if (!res)
+ return res;
+
+ nand_release(mtd);
+
+err_exit4:
+ free_irq(host->irq, host);
+err_exit3:
+ if (use_dma)
+ dma_release_channel(host->dma_chan);
+err_exit2:
+ clk_disable(host->clk);
+ clk_put(host->clk);
+ platform_set_drvdata(pdev, NULL);
+err_exit1:
+ lpc32xx_wp_enable(host);
+ gpio_free(host->ncfg->wp_gpio);
+
+ return res;
+}
+
+/*
+ * Remove NAND device
+ */
+static int __devexit lpc32xx_nand_remove(struct platform_device *pdev)
+{
+ struct lpc32xx_nand_host *host = platform_get_drvdata(pdev);
+ struct mtd_info *mtd = &host->mtd;
+
+ nand_release(mtd);
+ free_irq(host->irq, host);
+ if (use_dma)
+ dma_release_channel(host->dma_chan);
+
+ clk_disable(host->clk);
+ clk_put(host->clk);
+ platform_set_drvdata(pdev, NULL);
+
+ lpc32xx_wp_enable(host);
+ gpio_free(host->ncfg->wp_gpio);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int lpc32xx_nand_resume(struct platform_device *pdev)
+{
+ struct lpc32xx_nand_host *host = platform_get_drvdata(pdev);
+
+ /* Re-enable NAND clock */
+ clk_enable(host->clk);
+
+ /* Fresh init of NAND controller */
+ lpc32xx_nand_setup(host);
+
+ /* Disable write protect */
+ lpc32xx_wp_disable(host);
+
+ return 0;
+}
+
+static int lpc32xx_nand_suspend(struct platform_device *pdev, pm_message_t pm)
+{
+ struct lpc32xx_nand_host *host = platform_get_drvdata(pdev);
+
+ /* Enable write protect for safety */
+ lpc32xx_wp_enable(host);
+
+ /* Disable clock */
+ clk_disable(host->clk);
+ return 0;
+}
+
+#else
+#define lpc32xx_nand_resume NULL
+#define lpc32xx_nand_suspend NULL
+#endif
+
+static const struct of_device_id lpc32xx_nand_match[] = {
+ { .compatible = "nxp,lpc3220-mlc" },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, lpc32xx_nand_match);
+
+static struct platform_driver lpc32xx_nand_driver = {
+ .probe = lpc32xx_nand_probe,
+ .remove = __devexit_p(lpc32xx_nand_remove),
+ .resume = lpc32xx_nand_resume,
+ .suspend = lpc32xx_nand_suspend,
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(lpc32xx_nand_match),
+ },
+};
+
+module_platform_driver(lpc32xx_nand_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Roland Stigge <stigge@antcom.de>");
+MODULE_DESCRIPTION("NAND driver for the NXP LPC32XX MLC controller");
diff --git a/drivers/mtd/nand/lpc32xx_slc.c b/drivers/mtd/nand/lpc32xx_slc.c
new file mode 100644
index 0000000..32409c4
--- /dev/null
+++ b/drivers/mtd/nand/lpc32xx_slc.c
@@ -0,0 +1,1039 @@
+/*
+ * NXP LPC32XX NAND SLC driver
+ *
+ * Authors:
+ * Kevin Wells <kevin.wells@nxp.com>
+ * Roland Stigge <stigge@antcom.de>
+ *
+ * Copyright © 2011 NXP Semiconductors
+ * Copyright © 2012 Roland Stigge
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/mm.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
+#include <linux/mtd/nand_ecc.h>
+#include <linux/gpio.h>
+#include <linux/of.h>
+#include <linux/of_mtd.h>
+#include <linux/of_gpio.h>
+#include <linux/mtd/lpc32xx_slc.h>
+
+#define LPC32XX_MODNAME "lpc32xx-nand"
+
+/**********************************************************************
+* SLC NAND controller register offsets
+**********************************************************************/
+
+#define SLC_DATA(x) (x + 0x000)
+#define SLC_ADDR(x) (x + 0x004)
+#define SLC_CMD(x) (x + 0x008)
+#define SLC_STOP(x) (x + 0x00C)
+#define SLC_CTRL(x) (x + 0x010)
+#define SLC_CFG(x) (x + 0x014)
+#define SLC_STAT(x) (x + 0x018)
+#define SLC_INT_STAT(x) (x + 0x01C)
+#define SLC_IEN(x) (x + 0x020)
+#define SLC_ISR(x) (x + 0x024)
+#define SLC_ICR(x) (x + 0x028)
+#define SLC_TAC(x) (x + 0x02C)
+#define SLC_TC(x) (x + 0x030)
+#define SLC_ECC(x) (x + 0x034)
+#define SLC_DMA_DATA(x) (x + 0x038)
+
+/**********************************************************************
+* slc_ctrl register definitions
+**********************************************************************/
+#define SLCCTRL_SW_RESET (1 << 2) /* Reset the NAND controller bit */
+#define SLCCTRL_ECC_CLEAR (1 << 1) /* Reset ECC bit */
+#define SLCCTRL_DMA_START (1 << 0) /* Start DMA channel bit */
+
+/**********************************************************************
+* slc_cfg register definitions
+**********************************************************************/
+#define SLCCFG_CE_LOW (1 << 5) /* Force CE low bit */
+#define SLCCFG_DMA_ECC (1 << 4) /* Enable DMA ECC bit */
+#define SLCCFG_ECC_EN (1 << 3) /* ECC enable bit */
+#define SLCCFG_DMA_BURST (1 << 2) /* DMA burst bit */
+#define SLCCFG_DMA_DIR (1 << 1) /* DMA write(0)/read(1) bit */
+#define SLCCFG_WIDTH (1 << 0) /* External device width, 0=8bit */
+
+/**********************************************************************
+* slc_stat register definitions
+**********************************************************************/
+#define SLCSTAT_DMA_FIFO (1 << 2) /* DMA FIFO has data bit */
+#define SLCSTAT_SLC_FIFO (1 << 1) /* SLC FIFO has data bit */
+#define SLCSTAT_NAND_READY (1 << 0) /* NAND device is ready bit */
+
+/**********************************************************************
+* slc_int_stat, slc_ien, slc_isr, and slc_icr register definitions
+**********************************************************************/
+#define SLCSTAT_INT_TC (1 << 1) /* Transfer count bit */
+#define SLCSTAT_INT_RDY_EN (1 << 0) /* Ready interrupt bit */
+
+/**********************************************************************
+* slc_tac register definitions
+**********************************************************************/
+/* Clock setting for RDY write sample wait time in 2*n clocks */
+#define SLCTAC_WDR(n) (((n) & 0xF) << 28)
+/* Write pulse width in clock cycles, 1 to 16 clocks */
+#define SLCTAC_WWIDTH(n) (((n) & 0xF) << 24)
+/* Write hold time of control and data signals, 1 to 16 clocks */
+#define SLCTAC_WHOLD(n) (((n) & 0xF) << 20)
+/* Write setup time of control and data signals, 1 to 16 clocks */
+#define SLCTAC_WSETUP(n) (((n) & 0xF) << 16)
+/* Clock setting for RDY read sample wait time in 2*n clocks */
+#define SLCTAC_RDR(n) (((n) & 0xF) << 12)
+/* Read pulse width in clock cycles, 1 to 16 clocks */
+#define SLCTAC_RWIDTH(n) (((n) & 0xF) << 8)
+/* Read hold time of control and data signals, 1 to 16 clocks */
+#define SLCTAC_RHOLD(n) (((n) & 0xF) << 4)
+/* Read setup time of control and data signals, 1 to 16 clocks */
+#define SLCTAC_RSETUP(n) (((n) & 0xF) << 0)
+
+/**********************************************************************
+* slc_ecc register definitions
+**********************************************************************/
+/* ECC line party fetch macro */
+#define SLCECC_TO_LINEPAR(n) (((n) >> 6) & 0x7FFF)
+#define SLCECC_TO_COLPAR(n) ((n) & 0x3F)
+
+/*
+ * DMA requires storage space for the DMA local buffer and the hardware ECC
+ * storage area. The DMA local buffer is only used if DMA mapping fails
+ * during runtime.
+ */
+#define LPC32XX_DMA_DATA_SIZE 4096
+#define LPC32XX_ECC_SAVE_SIZE ((4096 / 256) * 4)
+
+/* Number of bytes used for ECC stored in NAND per 256 bytes */
+#define LPC32XX_SLC_DEV_ECC_BYTES 3
+
+/*
+ * If the NAND base clock frequency can't be fetched, this frequency will be
+ * used instead as the base. This rate is used to setup the timing registers
+ * used for NAND accesses.
+ */
+#define LPC32XX_DEF_BUS_RATE 133250000
+
+/* Milliseconds for DMA FIFO timeout (unlikely anyway) */
+#define LPC32XX_DMA_TIMEOUT 100
+
+/*
+ * NAND ECC Layout for small page NAND devices
+ * Note: For large and huge page devices, the default layouts are used
+ */
+static struct nand_ecclayout lpc32xx_nand_oob_16 = {
+ .eccbytes = 6,
+ .eccpos = {10, 11, 12, 13, 14, 15},
+ .oobfree = {
+ { .offset = 0, .length = 4 },
+ { .offset = 6, .length = 4 },
+ },
+};
+
+static u8 bbt_pattern[] = {'B', 'b', 't', '0' };
+static u8 mirror_pattern[] = {'1', 't', 'b', 'B' };
+
+/*
+ * Small page FLASH BBT descriptors, marker at offset 0, version at offset 6
+ * Note: Large page devices used the default layout
+ */
+static struct nand_bbt_descr bbt_smallpage_main_descr = {
+ .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
+ | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
+ .offs = 0,
+ .len = 4,
+ .veroffs = 6,
+ .maxblocks = 4,
+ .pattern = bbt_pattern
+};
+
+static struct nand_bbt_descr bbt_smallpage_mirror_descr = {
+ .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
+ | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
+ .offs = 0,
+ .len = 4,
+ .veroffs = 6,
+ .maxblocks = 4,
+ .pattern = mirror_pattern
+};
+
+/*
+ * NAND platform configuration structure
+ */
+struct lpc32xx_nand_cfg_slc {
+ uint32_t wdr_clks;
+ uint32_t wwidth;
+ uint32_t whold;
+ uint32_t wsetup;
+ uint32_t rdr_clks;
+ uint32_t rwidth;
+ uint32_t rhold;
+ uint32_t rsetup;
+ bool use_bbt;
+ int wp_gpio;
+ struct mtd_partition *parts;
+ unsigned num_parts;
+};
+
+struct lpc32xx_nand_host {
+ struct nand_chip nand_chip;
+ struct lpc32xx_slc_platform_data *pdata;
+ struct clk *clk;
+ struct mtd_info mtd;
+ void __iomem *io_base;
+ struct lpc32xx_nand_cfg_slc *ncfg;
+
+ struct completion comp;
+ struct dma_chan *dma_chan;
+ uint32_t dma_buf_len;
+ struct dma_slave_config dma_slave_config;
+ struct scatterlist sgl;
+
+ /*
+ * DMA and CPU addresses of ECC work area and data buffer
+ */
+ uint32_t *ecc_buf;
+ uint8_t *data_buf;
+ dma_addr_t io_base_dma;
+};
+
+static void lpc32xx_nand_setup(struct lpc32xx_nand_host *host)
+{
+ uint32_t clkrate, tmp;
+
+ /* Reset SLC controller */
+ writel(SLCCTRL_SW_RESET, SLC_CTRL(host->io_base));
+ udelay(1000);
+
+ /* Basic setup */
+ writel(0, SLC_CFG(host->io_base));
+ writel(0, SLC_IEN(host->io_base));
+ writel((SLCSTAT_INT_TC | SLCSTAT_INT_RDY_EN),
+ SLC_ICR(host->io_base));
+
+ /* Get base clock for SLC block */
+ clkrate = clk_get_rate(host->clk);
+ if (clkrate == 0)
+ clkrate = LPC32XX_DEF_BUS_RATE;
+
+ /* Compute clock setup values */
+ tmp = SLCTAC_WDR(host->ncfg->wdr_clks) |
+ SLCTAC_WWIDTH(1 + (clkrate / host->ncfg->wwidth)) |
+ SLCTAC_WHOLD(1 + (clkrate / host->ncfg->whold)) |
+ SLCTAC_WSETUP(1 + (clkrate / host->ncfg->wsetup)) |
+ SLCTAC_RDR(host->ncfg->rdr_clks) |
+ SLCTAC_RWIDTH(1 + (clkrate / host->ncfg->rwidth)) |
+ SLCTAC_RHOLD(1 + (clkrate / host->ncfg->rhold)) |
+ SLCTAC_RSETUP(1 + (clkrate / host->ncfg->rsetup));
+ writel(tmp, SLC_TAC(host->io_base));
+}
+
+/*
+ * Hardware specific access to control lines
+ */
+static void lpc32xx_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
+ unsigned int ctrl)
+{
+ uint32_t tmp;
+ struct nand_chip *chip = mtd->priv;
+ struct lpc32xx_nand_host *host = chip->priv;
+
+ /* Does CE state need to be changed? */
+ tmp = readl(SLC_CFG(host->io_base));
+ if (ctrl & NAND_NCE)
+ tmp |= SLCCFG_CE_LOW;
+ else
+ tmp &= ~SLCCFG_CE_LOW;
+ writel(tmp, SLC_CFG(host->io_base));
+
+ if (cmd != NAND_CMD_NONE) {
+ if (ctrl & NAND_CLE)
+ writel(cmd, SLC_CMD(host->io_base));
+ else
+ writel(cmd, SLC_ADDR(host->io_base));
+ }
+}
+
+/*
+ * Read the Device Ready pin
+ */
+static int lpc32xx_nand_device_ready(struct mtd_info *mtd)
+{
+ struct nand_chip *chip = mtd->priv;
+ struct lpc32xx_nand_host *host = chip->priv;
+ int rdy = 0;
+
+ if ((readl(SLC_STAT(host->io_base)) & SLCSTAT_NAND_READY) != 0)
+ rdy = 1;
+
+ return rdy;
+}
+
+/*
+ * Enable NAND write protect
+ */
+static void lpc32xx_wp_enable(struct lpc32xx_nand_host *host)
+{
+ if (gpio_is_valid(host->ncfg->wp_gpio))
+ gpio_set_value(host->ncfg->wp_gpio, 0);
+}
+
+/*
+ * Disable NAND write protect
+ */
+static void lpc32xx_wp_disable(struct lpc32xx_nand_host *host)
+{
+ if (gpio_is_valid(host->ncfg->wp_gpio))
+ gpio_set_value(host->ncfg->wp_gpio, 1);
+}
+
+/*
+ * Prepares SLC for transfers with H/W ECC enabled
+ */
+static void lpc32xx_nand_ecc_enable(struct mtd_info *mtd, int mode)
+{
+ /* Hardware ECC is enabled automatically in hardware as needed */
+}
+
+/*
+ * Calculates the ECC for the data
+ */
+static int lpc32xx_nand_ecc_calculate(struct mtd_info *mtd,
+ const unsigned char *buf,
+ unsigned char *code)
+{
+ /*
+ * ECC is calculated automatically in hardware during syndrome read
+ * and write operations, so it doesn't need to be calculated here.
+ */
+ return 0;
+}
+
+/*
+ * Read a single byte from NAND device
+ */
+static uint8_t lpc32xx_nand_read_byte(struct mtd_info *mtd)
+{
+ struct nand_chip *chip = mtd->priv;
+ struct lpc32xx_nand_host *host = chip->priv;
+
+ return (uint8_t)readl(SLC_DATA(host->io_base));
+}
+
+/*
+ * Simple device read without ECC
+ */
+static void lpc32xx_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+{
+ struct nand_chip *chip = mtd->priv;
+ struct lpc32xx_nand_host *host = chip->priv;
+
+ /* Direct device read with no ECC */
+ while (len-- > 0)
+ *buf++ = (uint8_t)readl(SLC_DATA(host->io_base));
+}
+
+/*
+ * Simple device write without ECC
+ */
+static void lpc32xx_nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
+{
+ struct nand_chip *chip = mtd->priv;
+ struct lpc32xx_nand_host *host = chip->priv;
+
+ /* Direct device write with no ECC */
+ while (len-- > 0)
+ writel((uint32_t)*buf++, SLC_DATA(host->io_base));
+}
+
+/*
+ * Read the OOB data from the device without ECC using FIFO method
+ */
+static int lpc32xx_nand_read_oob_syndrome(struct mtd_info *mtd,
+ struct nand_chip *chip, int page)
+{
+ chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
+ chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+ return 0;
+}
+
+/*
+ * Write the OOB data to the device without ECC using FIFO method
+ */
+static int lpc32xx_nand_write_oob_syndrome(struct mtd_info *mtd,
+ struct nand_chip *chip, int page)
+{
+ int status;
+
+ chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize, page);
+ chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+ /* Send command to program the OOB data */
+ chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
+
+ status = chip->waitfunc(mtd, chip);
+
+ return status & NAND_STATUS_FAIL ? -EIO : 0;
+}
+
+/*
+ * Fills in the ECC fields in the OOB buffer with the hardware generated ECC
+ */
+static void lpc32xx_slc_ecc_copy(uint8_t *spare, const uint32_t *ecc, int count)
+{
+ int i;
+
+ for (i = 0; i < (count * 3); i += 3) {
+ uint32_t ce = ecc[i / 3];
+ ce = ~(ce << 2) & 0xFFFFFF;
+ spare[i + 2] = (uint8_t)(ce & 0xFF);
+ ce >>= 8;
+ spare[i + 1] = (uint8_t)(ce & 0xFF);
+ ce >>= 8;
+ spare[i] = (uint8_t)(ce & 0xFF);
+ }
+}
+
+static void lpc32xx_dma_complete_func(void *completion)
+{
+ complete(completion);
+}
+
+static int lpc32xx_xmit_dma(struct mtd_info *mtd, dma_addr_t dma,
+ void *mem, int len, enum dma_transfer_direction dir)
+{
+ struct nand_chip *chip = mtd->priv;
+ struct lpc32xx_nand_host *host = chip->priv;
+ struct dma_async_tx_descriptor *desc;
+ int flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT;
+ int res;
+
+ host->dma_slave_config.direction = dir;
+ host->dma_slave_config.src_addr = dma;
+ host->dma_slave_config.dst_addr = dma;
+ host->dma_slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+ host->dma_slave_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+ host->dma_slave_config.src_maxburst = 4;
+ host->dma_slave_config.dst_maxburst = 4;
+ /* DMA controller does flow control: */
+ host->dma_slave_config.device_fc = false;
+ if (dmaengine_slave_config(host->dma_chan, &host->dma_slave_config)) {
+ dev_err(mtd->dev.parent, "Failed to setup DMA slave\n");
+ return -ENXIO;
+ }
+
+ sg_init_one(&host->sgl, mem, len);
+
+ res = dma_map_sg(host->dma_chan->device->dev, &host->sgl, 1,
+ DMA_BIDIRECTIONAL);
+ if (res != 1) {
+ dev_err(mtd->dev.parent, "Failed to map sg list\n");
+ return -ENXIO;
+ }
+ desc = dmaengine_prep_slave_sg(host->dma_chan, &host->sgl, 1, dir,
+ flags);
+ if (!desc) {
+ dev_err(mtd->dev.parent, "Failed to prepare slave sg\n");
+ goto out1;
+ }
+
+ init_completion(&host->comp);
+ desc->callback = lpc32xx_dma_complete_func;
+ desc->callback_param = &host->comp;
+
+ dmaengine_submit(desc);
+ dma_async_issue_pending(host->dma_chan);
+
+ wait_for_completion_timeout(&host->comp, msecs_to_jiffies(1000));
+
+ dma_unmap_sg(host->dma_chan->device->dev, &host->sgl, 1,
+ DMA_BIDIRECTIONAL);
+
+ return 0;
+out1:
+ dma_unmap_sg(host->dma_chan->device->dev, &host->sgl, 1,
+ DMA_BIDIRECTIONAL);
+ return -ENXIO;
+}
+
+/*
+ * DMA read/write transfers with ECC support
+ */
+static int lpc32xx_xfer(struct mtd_info *mtd, uint8_t *buf, int eccsubpages,
+ int read)
+{
+ struct nand_chip *chip = mtd->priv;
+ struct lpc32xx_nand_host *host = chip->priv;
+ int i, status = 0;
+ unsigned long timeout;
+ int res;
+ enum dma_transfer_direction dir =
+ read ? DMA_DEV_TO_MEM : DMA_MEM_TO_DEV;
+ uint8_t *dma_buf;
+ bool dma_mapped;
+
+ if ((void *)buf <= high_memory) {
+ dma_buf = buf;
+ dma_mapped = true;
+ } else {
+ dma_buf = host->data_buf;
+ dma_mapped = false;
+ if (!read)
+ memcpy(host->data_buf, buf, mtd->writesize);
+ }
+
+ if (read) {
+ writel(readl(SLC_CFG(host->io_base)) |
+ SLCCFG_DMA_DIR | SLCCFG_ECC_EN | SLCCFG_DMA_ECC |
+ SLCCFG_DMA_BURST, SLC_CFG(host->io_base));
+ } else {
+ writel((readl(SLC_CFG(host->io_base)) |
+ SLCCFG_ECC_EN | SLCCFG_DMA_ECC | SLCCFG_DMA_BURST) &
+ ~SLCCFG_DMA_DIR,
+ SLC_CFG(host->io_base));
+ }
+
+ /* Clear initial ECC */
+ writel(SLCCTRL_ECC_CLEAR, SLC_CTRL(host->io_base));
+
+ /* Transfer size is data area only */
+ writel(mtd->writesize, SLC_TC(host->io_base));
+
+ /* Start transfer in the NAND controller */
+ writel(readl(SLC_CTRL(host->io_base)) | SLCCTRL_DMA_START,
+ SLC_CTRL(host->io_base));
+
+ for (i = 0; i < chip->ecc.steps; i++) {
+ /* Data */
+ res = lpc32xx_xmit_dma(mtd, SLC_DMA_DATA(host->io_base_dma),
+ dma_buf + i * chip->ecc.size,
+ mtd->writesize / chip->ecc.steps, dir);
+ if (res)
+ return res;
+
+ /* Always _read_ ECC */
+ if (i == chip->ecc.steps - 1)
+ break;
+ if (!read) /* ECC availability delayed on write */
+ udelay(10);
+ res = lpc32xx_xmit_dma(mtd, SLC_ECC(host->io_base_dma),
+ &host->ecc_buf[i], 4, DMA_DEV_TO_MEM);
+ if (res)
+ return res;
+ }
+
+ /*
+ * According to NXP, the DMA can be finished here, but the NAND
+ * controller may still have buffered data. After porting to using the
+ * dmaengine DMA driver (amba-pl080), the condition (DMA_FIFO empty)
+ * appears to be always true, according to tests. Keeping the check for
+ * safety reasons for now.
+ */
+ if (readl(SLC_STAT(host->io_base)) & SLCSTAT_DMA_FIFO) {
+ dev_warn(mtd->dev.parent, "FIFO not empty!\n");
+ timeout = jiffies + msecs_to_jiffies(LPC32XX_DMA_TIMEOUT);
+ while ((readl(SLC_STAT(host->io_base)) & SLCSTAT_DMA_FIFO) &&
+ time_before(jiffies, timeout))
+ cpu_relax();
+ if (!time_before(jiffies, timeout)) {
+ dev_err(mtd->dev.parent, "FIFO held data too long\n");
+ status = -EIO;
+ }
+ }
+
+ /* Read last calculated ECC value */
+ if (!read)
+ udelay(10);
+ host->ecc_buf[chip->ecc.steps - 1] =
+ readl(SLC_ECC(host->io_base));
+
+ /* Flush DMA */
+ dmaengine_terminate_all(host->dma_chan);
+
+ if (readl(SLC_STAT(host->io_base)) & SLCSTAT_DMA_FIFO ||
+ readl(SLC_TC(host->io_base))) {
+ /* Something is left in the FIFO, something is wrong */
+ dev_err(mtd->dev.parent, "DMA FIFO failure\n");
+ status = -EIO;
+ }
+
+ /* Stop DMA & HW ECC */
+ writel(readl(SLC_CTRL(host->io_base)) & ~SLCCTRL_DMA_START,
+ SLC_CTRL(host->io_base));
+ writel(readl(SLC_CFG(host->io_base)) &
+ ~(SLCCFG_DMA_DIR | SLCCFG_ECC_EN | SLCCFG_DMA_ECC |
+ SLCCFG_DMA_BURST), SLC_CFG(host->io_base));
+
+ if (!dma_mapped && read)
+ memcpy(buf, host->data_buf, mtd->writesize);
+
+ return status;
+}
+
+/*
+ * Read the data and OOB data from the device, use ECC correction with the
+ * data, disable ECC for the OOB data
+ */
+static int lpc32xx_nand_read_page_syndrome(struct mtd_info *mtd,
+ struct nand_chip *chip, uint8_t *buf,
+ int oob_required, int page)
+{
+ struct lpc32xx_nand_host *host = chip->priv;
+ int stat, i, status;
+ uint8_t *oobecc, tmpecc[LPC32XX_ECC_SAVE_SIZE];
+
+ /* Issue read command */
+ chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
+
+ /* Read data and oob, calculate ECC */
+ status = lpc32xx_xfer(mtd, buf, chip->ecc.steps, 1);
+
+ /* Get OOB data */
+ chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+ /* Convert to stored ECC format */
+ lpc32xx_slc_ecc_copy(tmpecc, (uint32_t *) host->ecc_buf, chip->ecc.steps);
+
+ /* Pointer to ECC data retrieved from NAND spare area */
+ oobecc = chip->oob_poi + chip->ecc.layout->eccpos[0];
+
+ for (i = 0; i < chip->ecc.steps; i++) {
+ stat = chip->ecc.correct(mtd, buf, oobecc,
+ &tmpecc[i * chip->ecc.bytes]);
+ if (stat < 0)
+ mtd->ecc_stats.failed++;
+ else
+ mtd->ecc_stats.corrected += stat;
+
+ buf += chip->ecc.size;
+ oobecc += chip->ecc.bytes;
+ }
+
+ return status;
+}
+
+/*
+ * Read the data and OOB data from the device, no ECC correction with the
+ * data or OOB data
+ */
+static int lpc32xx_nand_read_page_raw_syndrome(struct mtd_info *mtd,
+ struct nand_chip *chip,
+ uint8_t *buf, int oob_required,
+ int page)
+{
+ /* Issue read command */
+ chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
+
+ /* Raw reads can just use the FIFO interface */
+ chip->read_buf(mtd, buf, chip->ecc.size * chip->ecc.steps);
+ chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+ return 0;
+}
+
+/*
+ * Write the data and OOB data to the device, use ECC with the data,
+ * disable ECC for the OOB data
+ */
+static int lpc32xx_nand_write_page_syndrome(struct mtd_info *mtd,
+ struct nand_chip *chip,
+ const uint8_t *buf, int oob_required)
+{
+ struct lpc32xx_nand_host *host = chip->priv;
+ uint8_t *pb = chip->oob_poi + chip->ecc.layout->eccpos[0];
+ int error;
+
+ /* Write data, calculate ECC on outbound data */
+ error = lpc32xx_xfer(mtd, (uint8_t *)buf, chip->ecc.steps, 0);
+ if (error)
+ return error;
+
+ /*
+ * The calculated ECC needs some manual work done to it before
+ * committing it to NAND. Process the calculated ECC and place
+ * the resultant values directly into the OOB buffer. */
+ lpc32xx_slc_ecc_copy(pb, (uint32_t *)host->ecc_buf, chip->ecc.steps);
+
+ /* Write ECC data to device */
+ chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+ return 0;
+}
+
+/*
+ * Write the data and OOB data to the device, no ECC correction with the
+ * data or OOB data
+ */
+static int lpc32xx_nand_write_page_raw_syndrome(struct mtd_info *mtd,
+ struct nand_chip *chip,
+ const uint8_t *buf,
+ int oob_required)
+{
+ /* Raw writes can just use the FIFO interface */
+ chip->write_buf(mtd, buf, chip->ecc.size * chip->ecc.steps);
+ chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+ return 0;
+}
+
+static int lpc32xx_nand_dma_setup(struct lpc32xx_nand_host *host)
+{
+ struct mtd_info *mtd = &host->mtd;
+ dma_cap_mask_t mask;
+
+ if (!host->pdata || !host->pdata->dma_filter) {
+ dev_err(mtd->dev.parent, "no DMA platform data\n");
+ return -ENOENT;
+ }
+
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_SLAVE, mask);
+ host->dma_chan = dma_request_channel(mask, host->pdata->dma_filter,
+ "nand-slc");
+ if (!host->dma_chan) {
+ dev_err(mtd->dev.parent, "Failed to request DMA channel\n");
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
+static struct lpc32xx_nand_cfg_slc *lpc32xx_parse_dt(struct device *dev)
+{
+ struct lpc32xx_nand_cfg_slc *ncfg;
+ struct device_node *np = dev->of_node;
+
+ ncfg = devm_kzalloc(dev, sizeof(*ncfg), GFP_KERNEL);
+ if (!ncfg) {
+ dev_err(dev, "could not allocate memory for NAND config\n");
+ return NULL;
+ }
+
+ of_property_read_u32(np, "nxp,wdr-clks", &ncfg->wdr_clks);
+ of_property_read_u32(np, "nxp,wwidth", &ncfg->wwidth);
+ of_property_read_u32(np, "nxp,whold", &ncfg->whold);
+ of_property_read_u32(np, "nxp,wsetup", &ncfg->wsetup);
+ of_property_read_u32(np, "nxp,rdr-clks", &ncfg->rdr_clks);
+ of_property_read_u32(np, "nxp,rwidth", &ncfg->rwidth);
+ of_property_read_u32(np, "nxp,rhold", &ncfg->rhold);
+ of_property_read_u32(np, "nxp,rsetup", &ncfg->rsetup);
+
+ if (!ncfg->wdr_clks || !ncfg->wwidth || !ncfg->whold ||
+ !ncfg->wsetup || !ncfg->rdr_clks || !ncfg->rwidth ||
+ !ncfg->rhold || !ncfg->rsetup) {
+ dev_err(dev, "chip parameters not specified correctly\n");
+ return NULL;
+ }
+
+ ncfg->use_bbt = of_get_nand_on_flash_bbt(np);
+ ncfg->wp_gpio = of_get_named_gpio(np, "gpios", 0);
+
+ return ncfg;
+}
+
+/*
+ * Probe for NAND controller
+ */
+static int __devinit lpc32xx_nand_probe(struct platform_device *pdev)
+{
+ struct lpc32xx_nand_host *host;
+ struct mtd_info *mtd;
+ struct nand_chip *chip;
+ struct resource *rc;
+ struct mtd_part_parser_data ppdata = {};
+ int res;
+
+ rc = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (rc == NULL) {
+ dev_err(&pdev->dev, "No memory resource found for device\n");
+ return -EBUSY;
+ }
+
+ /* Allocate memory for the device structure (and zero it) */
+ host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL);
+ if (!host) {
+ dev_err(&pdev->dev, "failed to allocate device structure\n");
+ return -ENOMEM;
+ }
+ host->io_base_dma = rc->start;
+
+ host->io_base = devm_request_and_ioremap(&pdev->dev, rc);
+ if (host->io_base == NULL) {
+ dev_err(&pdev->dev, "ioremap failed\n");
+ return -ENOMEM;
+ }
+
+ if (pdev->dev.of_node)
+ host->ncfg = lpc32xx_parse_dt(&pdev->dev);
+ if (!host->ncfg) {
+ dev_err(&pdev->dev,
+ "Missing or bad NAND config from device tree\n");
+ return -ENOENT;
+ }
+ if (host->ncfg->wp_gpio == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+ if (gpio_is_valid(host->ncfg->wp_gpio) &&
+ gpio_request(host->ncfg->wp_gpio, "NAND WP")) {
+ dev_err(&pdev->dev, "GPIO not available\n");
+ return -EBUSY;
+ }
+ lpc32xx_wp_disable(host);
+
+ host->pdata = pdev->dev.platform_data;
+
+ mtd = &host->mtd;
+ chip = &host->nand_chip;
+ chip->priv = host;
+ mtd->priv = chip;
+ mtd->owner = THIS_MODULE;
+ mtd->dev.parent = &pdev->dev;
+
+ /* Get NAND clock */
+ host->clk = clk_get(&pdev->dev, NULL);
+ if (IS_ERR(host->clk)) {
+ dev_err(&pdev->dev, "Clock failure\n");
+ res = -ENOENT;
+ goto err_exit1;
+ }
+ clk_enable(host->clk);
+
+ /* Set NAND IO addresses and command/ready functions */
+ chip->IO_ADDR_R = SLC_DATA(host->io_base);
+ chip->IO_ADDR_W = SLC_DATA(host->io_base);
+ chip->cmd_ctrl = lpc32xx_nand_cmd_ctrl;
+ chip->dev_ready = lpc32xx_nand_device_ready;
+ chip->chip_delay = 20; /* 20us command delay time */
+
+ /* Init NAND controller */
+ lpc32xx_nand_setup(host);
+
+ platform_set_drvdata(pdev, host);
+
+ /* NAND callbacks for LPC32xx SLC hardware */
+ chip->ecc.mode = NAND_ECC_HW_SYNDROME;
+ chip->read_byte = lpc32xx_nand_read_byte;
+ chip->read_buf = lpc32xx_nand_read_buf;
+ chip->write_buf = lpc32xx_nand_write_buf;
+ chip->ecc.read_page_raw = lpc32xx_nand_read_page_raw_syndrome;
+ chip->ecc.read_page = lpc32xx_nand_read_page_syndrome;
+ chip->ecc.write_page_raw = lpc32xx_nand_write_page_raw_syndrome;
+ chip->ecc.write_page = lpc32xx_nand_write_page_syndrome;
+ chip->ecc.write_oob = lpc32xx_nand_write_oob_syndrome;
+ chip->ecc.read_oob = lpc32xx_nand_read_oob_syndrome;
+ chip->ecc.calculate = lpc32xx_nand_ecc_calculate;
+ chip->ecc.correct = nand_correct_data;
+ chip->ecc.strength = 1;
+ chip->ecc.hwctl = lpc32xx_nand_ecc_enable;
+
+ /* bitflip_threshold's default is defined as ecc_strength anyway.
+ * Unfortunately, it is set only later at add_mtd_device(). Meanwhile
+ * being 0, it causes bad block table scanning errors in
+ * nand_scan_tail(), so preparing it here already. */
+ mtd->bitflip_threshold = chip->ecc.strength;
+
+ /*
+ * Allocate a large enough buffer for a single huge page plus
+ * extra space for the spare area and ECC storage area
+ */
+ host->dma_buf_len = LPC32XX_DMA_DATA_SIZE + LPC32XX_ECC_SAVE_SIZE;
+ host->data_buf = devm_kzalloc(&pdev->dev, host->dma_buf_len,
+ GFP_KERNEL);
+ if (host->data_buf == NULL) {
+ dev_err(&pdev->dev, "Error allocating memory\n");
+ res = -ENOMEM;
+ goto err_exit2;
+ }
+
+ res = lpc32xx_nand_dma_setup(host);
+ if (res) {
+ res = -EIO;
+ goto err_exit2;
+ }
+
+ /* Find NAND device */
+ if (nand_scan_ident(mtd, 1, NULL)) {
+ res = -ENXIO;
+ goto err_exit3;
+ }
+
+ /* OOB and ECC CPU and DMA work areas */
+ host->ecc_buf = (uint32_t *)(host->data_buf + LPC32XX_DMA_DATA_SIZE);
+
+ /*
+ * Small page FLASH has a unique OOB layout, but large and huge
+ * page FLASH use the standard layout. Small page FLASH uses a
+ * custom BBT marker layout.
+ */
+ if (mtd->writesize <= 512)
+ chip->ecc.layout = &lpc32xx_nand_oob_16;
+
+ /* These sizes remain the same regardless of page size */
+ chip->ecc.size = 256;
+ chip->ecc.bytes = LPC32XX_SLC_DEV_ECC_BYTES;
+ chip->ecc.prepad = chip->ecc.postpad = 0;
+
+ /* Avoid extra scan if using BBT, setup BBT support */
+ if (host->ncfg->use_bbt) {
+ chip->options |= NAND_SKIP_BBTSCAN;
+ chip->bbt_options |= NAND_BBT_USE_FLASH;
+
+ /*
+ * Use a custom BBT marker setup for small page FLASH that
+ * won't interfere with the ECC layout. Large and huge page
+ * FLASH use the standard layout.
+ */
+ if (mtd->writesize <= 512) {
+ chip->bbt_td = &bbt_smallpage_main_descr;
+ chip->bbt_md = &bbt_smallpage_mirror_descr;
+ }
+ }
+
+ /*
+ * Fills out all the uninitialized function pointers with the defaults
+ */
+ if (nand_scan_tail(mtd)) {
+ res = -ENXIO;
+ goto err_exit3;
+ }
+
+ /* Standard layout in FLASH for bad block tables */
+ if (host->ncfg->use_bbt) {
+ if (nand_default_bbt(mtd) < 0)
+ dev_err(&pdev->dev,
+ "Error initializing default bad block tables\n");
+ }
+
+ mtd->name = "nxp_lpc3220_slc";
+ ppdata.of_node = pdev->dev.of_node;
+ res = mtd_device_parse_register(mtd, NULL, &ppdata, host->ncfg->parts,
+ host->ncfg->num_parts);
+ if (!res)
+ return res;
+
+ nand_release(mtd);
+
+err_exit3:
+ dma_release_channel(host->dma_chan);
+err_exit2:
+ clk_disable(host->clk);
+ clk_put(host->clk);
+ platform_set_drvdata(pdev, NULL);
+err_exit1:
+ lpc32xx_wp_enable(host);
+ gpio_free(host->ncfg->wp_gpio);
+
+ return res;
+}
+
+/*
+ * Remove NAND device.
+ */
+static int __devexit lpc32xx_nand_remove(struct platform_device *pdev)
+{
+ uint32_t tmp;
+ struct lpc32xx_nand_host *host = platform_get_drvdata(pdev);
+ struct mtd_info *mtd = &host->mtd;
+
+ nand_release(mtd);
+ dma_release_channel(host->dma_chan);
+
+ /* Force CE high */
+ tmp = readl(SLC_CTRL(host->io_base));
+ tmp &= ~SLCCFG_CE_LOW;
+ writel(tmp, SLC_CTRL(host->io_base));
+
+ clk_disable(host->clk);
+ clk_put(host->clk);
+ platform_set_drvdata(pdev, NULL);
+ lpc32xx_wp_enable(host);
+ gpio_free(host->ncfg->wp_gpio);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int lpc32xx_nand_resume(struct platform_device *pdev)
+{
+ struct lpc32xx_nand_host *host = platform_get_drvdata(pdev);
+
+ /* Re-enable NAND clock */
+ clk_enable(host->clk);
+
+ /* Fresh init of NAND controller */
+ lpc32xx_nand_setup(host);
+
+ /* Disable write protect */
+ lpc32xx_wp_disable(host);
+
+ return 0;
+}
+
+static int lpc32xx_nand_suspend(struct platform_device *pdev, pm_message_t pm)
+{
+ uint32_t tmp;
+ struct lpc32xx_nand_host *host = platform_get_drvdata(pdev);
+
+ /* Force CE high */
+ tmp = readl(SLC_CTRL(host->io_base));
+ tmp &= ~SLCCFG_CE_LOW;
+ writel(tmp, SLC_CTRL(host->io_base));
+
+ /* Enable write protect for safety */
+ lpc32xx_wp_enable(host);
+
+ /* Disable clock */
+ clk_disable(host->clk);
+
+ return 0;
+}
+
+#else
+#define lpc32xx_nand_resume NULL
+#define lpc32xx_nand_suspend NULL
+#endif
+
+static const struct of_device_id lpc32xx_nand_match[] = {
+ { .compatible = "nxp,lpc3220-slc" },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, lpc32xx_nand_match);
+
+static struct platform_driver lpc32xx_nand_driver = {
+ .probe = lpc32xx_nand_probe,
+ .remove = __devexit_p(lpc32xx_nand_remove),
+ .resume = lpc32xx_nand_resume,
+ .suspend = lpc32xx_nand_suspend,
+ .driver = {
+ .name = LPC32XX_MODNAME,
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(lpc32xx_nand_match),
+ },
+};
+
+module_platform_driver(lpc32xx_nand_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Kevin Wells <kevin.wells@nxp.com>");
+MODULE_AUTHOR("Roland Stigge <stigge@antcom.de>");
+MODULE_DESCRIPTION("NAND driver for the NXP LPC32XX SLC controller");
diff --git a/drivers/mtd/nand/mpc5121_nfc.c b/drivers/mtd/nand/mpc5121_nfc.c
index c259c24..f776c85 100644
--- a/drivers/mtd/nand/mpc5121_nfc.c
+++ b/drivers/mtd/nand/mpc5121_nfc.c
@@ -506,27 +506,6 @@ static void mpc5121_nfc_write_buf(struct mtd_info *mtd,
mpc5121_nfc_buf_copy(mtd, (u_char *)buf, len, 1);
}
-/* Compare buffer with NAND flash */
-static int mpc5121_nfc_verify_buf(struct mtd_info *mtd,
- const u_char *buf, int len)
-{
- u_char tmp[256];
- uint bsize;
-
- while (len) {
- bsize = min(len, 256);
- mpc5121_nfc_read_buf(mtd, tmp, bsize);
-
- if (memcmp(buf, tmp, bsize))
- return 1;
-
- buf += bsize;
- len -= bsize;
- }
-
- return 0;
-}
-
/* Read byte from NFC buffers */
static u8 mpc5121_nfc_read_byte(struct mtd_info *mtd)
{
@@ -732,7 +711,6 @@ static int __devinit mpc5121_nfc_probe(struct platform_device *op)
chip->read_word = mpc5121_nfc_read_word;
chip->read_buf = mpc5121_nfc_read_buf;
chip->write_buf = mpc5121_nfc_write_buf;
- chip->verify_buf = mpc5121_nfc_verify_buf;
chip->select_chip = mpc5121_nfc_select_chip;
chip->bbt_options = NAND_BBT_USE_FLASH;
chip->ecc.mode = NAND_ECC_SOFT;
diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c
index 5683604..72e31d8 100644
--- a/drivers/mtd/nand/mxc_nand.c
+++ b/drivers/mtd/nand/mxc_nand.c
@@ -43,8 +43,8 @@
#define nfc_is_v21() (cpu_is_mx25() || cpu_is_mx35())
#define nfc_is_v1() (cpu_is_mx31() || cpu_is_mx27() || cpu_is_mx21())
-#define nfc_is_v3_2() (cpu_is_mx51() || cpu_is_mx53())
-#define nfc_is_v3() nfc_is_v3_2()
+#define nfc_is_v3_2a() cpu_is_mx51()
+#define nfc_is_v3_2b() cpu_is_mx53()
/* Addresses for NFC registers */
#define NFC_V1_V2_BUF_SIZE (host->regs + 0x00)
@@ -122,7 +122,7 @@
#define NFC_V3_CONFIG2_2CMD_PHASES (1 << 4)
#define NFC_V3_CONFIG2_NUM_ADDR_PHASE0 (1 << 5)
#define NFC_V3_CONFIG2_ECC_MODE_8 (1 << 6)
-#define NFC_V3_CONFIG2_PPB(x) (((x) & 0x3) << 7)
+#define NFC_V3_CONFIG2_PPB(x, shift) (((x) & 0x3) << shift)
#define NFC_V3_CONFIG2_NUM_ADDR_PHASE1(x) (((x) & 0x3) << 12)
#define NFC_V3_CONFIG2_INT_MSK (1 << 15)
#define NFC_V3_CONFIG2_ST_CMD(x) (((x) & 0xff) << 24)
@@ -174,6 +174,7 @@ struct mxc_nand_devtype_data {
int spare_len;
int eccbytes;
int eccsize;
+ int ppb_shift;
};
struct mxc_nand_host {
@@ -745,14 +746,6 @@ static void mxc_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
host->buf_start += n;
}
-/* Used by the upper layer to verify the data in NAND Flash
- * with the data in the buf. */
-static int mxc_nand_verify_buf(struct mtd_info *mtd,
- const u_char *buf, int len)
-{
- return -EFAULT;
-}
-
/* This function is used by upper layer for select and
* deselect of the NAND chip */
static void mxc_nand_select_chip_v1_v3(struct mtd_info *mtd, int chip)
@@ -784,7 +777,7 @@ static void mxc_nand_select_chip_v2(struct mtd_info *mtd, int chip)
if (chip == -1) {
/* Disable the NFC clock */
if (host->clk_act) {
- clk_disable(host->clk);
+ clk_disable_unprepare(host->clk);
host->clk_act = 0;
}
return;
@@ -792,7 +785,7 @@ static void mxc_nand_select_chip_v2(struct mtd_info *mtd, int chip)
if (!host->clk_act) {
/* Enable the NFC clock */
- clk_enable(host->clk);
+ clk_prepare_enable(host->clk);
host->clk_act = 1;
}
@@ -1021,7 +1014,9 @@ static void preset_v3(struct mtd_info *mtd)
}
if (mtd->writesize) {
- config2 |= NFC_V3_CONFIG2_PPB(ffs(mtd->erasesize / mtd->writesize) - 6);
+ config2 |= NFC_V3_CONFIG2_PPB(
+ ffs(mtd->erasesize / mtd->writesize) - 6,
+ host->devtype_data->ppb_shift);
host->eccsize = get_eccsize(mtd);
if (host->eccsize == 8)
config2 |= NFC_V3_CONFIG2_ECC_MODE_8;
@@ -1234,7 +1229,7 @@ static const struct mxc_nand_devtype_data imx25_nand_devtype_data = {
.eccsize = 0,
};
-/* v3: i.MX51, i.MX53 */
+/* v3.2a: i.MX51 */
static const struct mxc_nand_devtype_data imx51_nand_devtype_data = {
.preset = preset_v3,
.send_cmd = send_cmd_v3,
@@ -1258,6 +1253,34 @@ static const struct mxc_nand_devtype_data imx51_nand_devtype_data = {
.spare_len = 64,
.eccbytes = 0,
.eccsize = 0,
+ .ppb_shift = 7,
+};
+
+/* v3.2b: i.MX53 */
+static const struct mxc_nand_devtype_data imx53_nand_devtype_data = {
+ .preset = preset_v3,
+ .send_cmd = send_cmd_v3,
+ .send_addr = send_addr_v3,
+ .send_page = send_page_v3,
+ .send_read_id = send_read_id_v3,
+ .get_dev_status = get_dev_status_v3,
+ .check_int = check_int_v3,
+ .irq_control = irq_control_v3,
+ .get_ecc_status = get_ecc_status_v3,
+ .ecclayout_512 = &nandv2_hw_eccoob_smallpage,
+ .ecclayout_2k = &nandv2_hw_eccoob_largepage,
+ .ecclayout_4k = &nandv2_hw_eccoob_smallpage, /* XXX: needs fix */
+ .select_chip = mxc_nand_select_chip_v1_v3,
+ .correct_data = mxc_nand_correct_data_v2_v3,
+ .irqpending_quirk = 0,
+ .needs_ip = 1,
+ .regs_offset = 0,
+ .spare0_offset = 0x1000,
+ .axi_offset = 0x1e00,
+ .spare_len = 64,
+ .eccbytes = 0,
+ .eccsize = 0,
+ .ppb_shift = 8,
};
#ifdef CONFIG_OF_MTD
@@ -1274,6 +1297,9 @@ static const struct of_device_id mxcnd_dt_ids[] = {
}, {
.compatible = "fsl,imx51-nand",
.data = &imx51_nand_devtype_data,
+ }, {
+ .compatible = "fsl,imx53-nand",
+ .data = &imx53_nand_devtype_data,
},
{ /* sentinel */ }
};
@@ -1327,15 +1353,17 @@ static int __init mxcnd_probe_pdata(struct mxc_nand_host *host)
host->devtype_data = &imx27_nand_devtype_data;
} else if (nfc_is_v21()) {
host->devtype_data = &imx25_nand_devtype_data;
- } else if (nfc_is_v3_2()) {
+ } else if (nfc_is_v3_2a()) {
host->devtype_data = &imx51_nand_devtype_data;
+ } else if (nfc_is_v3_2b()) {
+ host->devtype_data = &imx53_nand_devtype_data;
} else
BUG();
return 0;
}
-static int __init mxcnd_probe(struct platform_device *pdev)
+static int __devinit mxcnd_probe(struct platform_device *pdev)
{
struct nand_chip *this;
struct mtd_info *mtd;
@@ -1344,8 +1372,8 @@ static int __init mxcnd_probe(struct platform_device *pdev)
int err = 0;
/* Allocate memory for MTD device structure and private data */
- host = kzalloc(sizeof(struct mxc_nand_host) + NAND_MAX_PAGESIZE +
- NAND_MAX_OOBSIZE, GFP_KERNEL);
+ host = devm_kzalloc(&pdev->dev, sizeof(struct mxc_nand_host) +
+ NAND_MAX_PAGESIZE + NAND_MAX_OOBSIZE, GFP_KERNEL);
if (!host)
return -ENOMEM;
@@ -1370,36 +1398,38 @@ static int __init mxcnd_probe(struct platform_device *pdev)
this->read_word = mxc_nand_read_word;
this->write_buf = mxc_nand_write_buf;
this->read_buf = mxc_nand_read_buf;
- this->verify_buf = mxc_nand_verify_buf;
- host->clk = clk_get(&pdev->dev, "nfc");
- if (IS_ERR(host->clk)) {
- err = PTR_ERR(host->clk);
- goto eclk;
- }
+ host->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(host->clk))
+ return PTR_ERR(host->clk);
- clk_prepare_enable(host->clk);
- host->clk_act = 1;
+ err = mxcnd_probe_dt(host);
+ if (err > 0)
+ err = mxcnd_probe_pdata(host);
+ if (err < 0)
+ return err;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- err = -ENODEV;
- goto eres;
- }
+ if (host->devtype_data->needs_ip) {
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENODEV;
+ host->regs_ip = devm_request_and_ioremap(&pdev->dev, res);
+ if (!host->regs_ip)
+ return -ENOMEM;
- host->base = ioremap(res->start, resource_size(res));
- if (!host->base) {
- err = -ENOMEM;
- goto eres;
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ } else {
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
}
- host->main_area0 = host->base;
+ if (!res)
+ return -ENODEV;
- err = mxcnd_probe_dt(host);
- if (err > 0)
- err = mxcnd_probe_pdata(host);
- if (err < 0)
- goto eirq;
+ host->base = devm_request_and_ioremap(&pdev->dev, res);
+ if (!host->base)
+ return -ENOMEM;
+
+ host->main_area0 = host->base;
if (host->devtype_data->regs_offset)
host->regs = host->base + host->devtype_data->regs_offset;
@@ -1414,19 +1444,6 @@ static int __init mxcnd_probe(struct platform_device *pdev)
this->ecc.size = 512;
this->ecc.layout = host->devtype_data->ecclayout_512;
- if (host->devtype_data->needs_ip) {
- res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
- if (!res) {
- err = -ENODEV;
- goto eirq;
- }
- host->regs_ip = ioremap(res->start, resource_size(res));
- if (!host->regs_ip) {
- err = -ENOMEM;
- goto eirq;
- }
- }
-
if (host->pdata.hw_ecc) {
this->ecc.calculate = mxc_nand_calculate_ecc;
this->ecc.hwctl = mxc_nand_enable_hwecc;
@@ -1458,9 +1475,13 @@ static int __init mxcnd_probe(struct platform_device *pdev)
*/
host->devtype_data->irq_control(host, 0);
- err = request_irq(host->irq, mxc_nfc_irq, IRQF_DISABLED, DRIVER_NAME, host);
+ err = devm_request_irq(&pdev->dev, host->irq, mxc_nfc_irq,
+ IRQF_DISABLED, DRIVER_NAME, host);
if (err)
- goto eirq;
+ return err;
+
+ clk_prepare_enable(host->clk);
+ host->clk_act = 1;
/*
* Now that we "own" the interrupt make sure the interrupt mask bit is
@@ -1512,15 +1533,7 @@ static int __init mxcnd_probe(struct platform_device *pdev)
return 0;
escan:
- free_irq(host->irq, host);
-eirq:
- if (host->regs_ip)
- iounmap(host->regs_ip);
- iounmap(host->base);
-eres:
- clk_put(host->clk);
-eclk:
- kfree(host);
+ clk_disable_unprepare(host->clk);
return err;
}
@@ -1529,16 +1542,9 @@ static int __devexit mxcnd_remove(struct platform_device *pdev)
{
struct mxc_nand_host *host = platform_get_drvdata(pdev);
- clk_put(host->clk);
-
platform_set_drvdata(pdev, NULL);
nand_release(&host->mtd);
- free_irq(host->irq, host);
- if (host->regs_ip)
- iounmap(host->regs_ip);
- iounmap(host->base);
- kfree(host);
return 0;
}
@@ -1549,22 +1555,10 @@ static struct platform_driver mxcnd_driver = {
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(mxcnd_dt_ids),
},
+ .probe = mxcnd_probe,
.remove = __devexit_p(mxcnd_remove),
};
-
-static int __init mxc_nd_init(void)
-{
- return platform_driver_probe(&mxcnd_driver, mxcnd_probe);
-}
-
-static void __exit mxc_nd_cleanup(void)
-{
- /* Unregister the device structure */
- platform_driver_unregister(&mxcnd_driver);
-}
-
-module_init(mxc_nd_init);
-module_exit(mxc_nd_cleanup);
+module_platform_driver(mxcnd_driver);
MODULE_AUTHOR("Freescale Semiconductor, Inc.");
MODULE_DESCRIPTION("MXC NAND MTD driver");
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index a11253a0..ec6841d 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -243,25 +243,6 @@ static void nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
}
/**
- * nand_verify_buf - [DEFAULT] Verify chip data against buffer
- * @mtd: MTD device structure
- * @buf: buffer containing the data to compare
- * @len: number of bytes to compare
- *
- * Default verify function for 8bit buswidth.
- */
-static int nand_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
-{
- int i;
- struct nand_chip *chip = mtd->priv;
-
- for (i = 0; i < len; i++)
- if (buf[i] != readb(chip->IO_ADDR_R))
- return -EFAULT;
- return 0;
-}
-
-/**
* nand_write_buf16 - [DEFAULT] write buffer to chip
* @mtd: MTD device structure
* @buf: data buffer
@@ -301,28 +282,6 @@ static void nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len)
}
/**
- * nand_verify_buf16 - [DEFAULT] Verify chip data against buffer
- * @mtd: MTD device structure
- * @buf: buffer containing the data to compare
- * @len: number of bytes to compare
- *
- * Default verify function for 16bit buswidth.
- */
-static int nand_verify_buf16(struct mtd_info *mtd, const uint8_t *buf, int len)
-{
- int i;
- struct nand_chip *chip = mtd->priv;
- u16 *p = (u16 *) buf;
- len >>= 1;
-
- for (i = 0; i < len; i++)
- if (p[i] != readw(chip->IO_ADDR_R))
- return -EFAULT;
-
- return 0;
-}
-
-/**
* nand_block_bad - [DEFAULT] Read bad block marker from the chip
* @mtd: MTD device structure
* @ofs: offset from device start
@@ -1525,7 +1484,8 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
ret = chip->ecc.read_page_raw(mtd, chip, bufpoi,
oob_required,
page);
- else if (!aligned && NAND_SUBPAGE_READ(chip) && !oob)
+ else if (!aligned && NAND_HAS_SUBPAGE_READ(chip) &&
+ !oob)
ret = chip->ecc.read_subpage(mtd, chip,
col, bytes, bufpoi);
else
@@ -1542,7 +1502,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
/* Transfer not aligned data */
if (!aligned) {
- if (!NAND_SUBPAGE_READ(chip) && !oob &&
+ if (!NAND_HAS_SUBPAGE_READ(chip) && !oob &&
!(mtd->ecc_stats.failed - stats.failed) &&
(ops->mode != MTD_OPS_RAW)) {
chip->pagebuf = realpage;
@@ -1565,14 +1525,6 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
oobreadlen -= toread;
}
}
-
- if (!(chip->options & NAND_NO_READRDY)) {
- /* Apply delay or wait for ready/busy pin */
- if (!chip->dev_ready)
- udelay(chip->chip_delay);
- else
- nand_wait_ready(mtd);
- }
} else {
memcpy(buf, chip->buffers->databuf + col, bytes);
buf += bytes;
@@ -1633,7 +1585,7 @@ static int nand_read(struct mtd_info *mtd, loff_t from, size_t len,
ops.len = len;
ops.datbuf = buf;
ops.oobbuf = NULL;
- ops.mode = 0;
+ ops.mode = MTD_OPS_PLACE_OOB;
ret = nand_do_read_ops(mtd, from, &ops);
*retlen = ops.retlen;
nand_release_device(mtd);
@@ -1837,14 +1789,6 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
len = min(len, readlen);
buf = nand_transfer_oob(chip, buf, ops, len);
- if (!(chip->options & NAND_NO_READRDY)) {
- /* Apply delay or wait for ready/busy pin */
- if (!chip->dev_ready)
- udelay(chip->chip_delay);
- else
- nand_wait_ready(mtd);
- }
-
readlen -= len;
if (!readlen)
break;
@@ -1927,12 +1871,14 @@ out:
*
* Not for syndrome calculating ECC controllers, which use a special oob layout.
*/
-static void nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
+static int nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
const uint8_t *buf, int oob_required)
{
chip->write_buf(mtd, buf, mtd->writesize);
if (oob_required)
chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+ return 0;
}
/**
@@ -1944,7 +1890,7 @@ static void nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
*
* We need a special oob layout and handling even when ECC isn't checked.
*/
-static void nand_write_page_raw_syndrome(struct mtd_info *mtd,
+static int nand_write_page_raw_syndrome(struct mtd_info *mtd,
struct nand_chip *chip,
const uint8_t *buf, int oob_required)
{
@@ -1974,6 +1920,8 @@ static void nand_write_page_raw_syndrome(struct mtd_info *mtd,
size = mtd->oobsize - (oob - chip->oob_poi);
if (size)
chip->write_buf(mtd, oob, size);
+
+ return 0;
}
/**
* nand_write_page_swecc - [REPLACEABLE] software ECC based page write function
@@ -1982,7 +1930,7 @@ static void nand_write_page_raw_syndrome(struct mtd_info *mtd,
* @buf: data buffer
* @oob_required: must write chip->oob_poi to OOB
*/
-static void nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
+static int nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
const uint8_t *buf, int oob_required)
{
int i, eccsize = chip->ecc.size;
@@ -1999,7 +1947,7 @@ static void nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
for (i = 0; i < chip->ecc.total; i++)
chip->oob_poi[eccpos[i]] = ecc_calc[i];
- chip->ecc.write_page_raw(mtd, chip, buf, 1);
+ return chip->ecc.write_page_raw(mtd, chip, buf, 1);
}
/**
@@ -2009,7 +1957,7 @@ static void nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
* @buf: data buffer
* @oob_required: must write chip->oob_poi to OOB
*/
-static void nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
+static int nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
const uint8_t *buf, int oob_required)
{
int i, eccsize = chip->ecc.size;
@@ -2029,6 +1977,8 @@ static void nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
chip->oob_poi[eccpos[i]] = ecc_calc[i];
chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+ return 0;
}
/**
@@ -2041,7 +1991,7 @@ static void nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
* The hw generator calculates the error syndrome automatically. Therefore we
* need a special oob layout and handling.
*/
-static void nand_write_page_syndrome(struct mtd_info *mtd,
+static int nand_write_page_syndrome(struct mtd_info *mtd,
struct nand_chip *chip,
const uint8_t *buf, int oob_required)
{
@@ -2075,6 +2025,8 @@ static void nand_write_page_syndrome(struct mtd_info *mtd,
i = mtd->oobsize - (oob - chip->oob_poi);
if (i)
chip->write_buf(mtd, oob, i);
+
+ return 0;
}
/**
@@ -2096,9 +2048,12 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
if (unlikely(raw))
- chip->ecc.write_page_raw(mtd, chip, buf, oob_required);
+ status = chip->ecc.write_page_raw(mtd, chip, buf, oob_required);
else
- chip->ecc.write_page(mtd, chip, buf, oob_required);
+ status = chip->ecc.write_page(mtd, chip, buf, oob_required);
+
+ if (status < 0)
+ return status;
/*
* Cached progamming disabled for now. Not sure if it's worth the
@@ -2125,16 +2080,6 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
status = chip->waitfunc(mtd, chip);
}
-#ifdef CONFIG_MTD_NAND_VERIFY_WRITE
- /* Send command to read back the data */
- chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
-
- if (chip->verify_buf(mtd, buf, mtd->writesize))
- return -EIO;
-
- /* Make sure the next page prog is preceded by a status read */
- chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
-#endif
return 0;
}
@@ -2336,7 +2281,7 @@ static int panic_nand_write(struct mtd_info *mtd, loff_t to, size_t len,
ops.len = len;
ops.datbuf = (uint8_t *)buf;
ops.oobbuf = NULL;
- ops.mode = 0;
+ ops.mode = MTD_OPS_PLACE_OOB;
ret = nand_do_write_ops(mtd, to, &ops);
@@ -2365,7 +2310,7 @@ static int nand_write(struct mtd_info *mtd, loff_t to, size_t len,
ops.len = len;
ops.datbuf = (uint8_t *)buf;
ops.oobbuf = NULL;
- ops.mode = 0;
+ ops.mode = MTD_OPS_PLACE_OOB;
ret = nand_do_write_ops(mtd, to, &ops);
*retlen = ops.retlen;
nand_release_device(mtd);
@@ -2755,6 +2700,50 @@ static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs)
}
/**
+ * nand_onfi_set_features- [REPLACEABLE] set features for ONFI nand
+ * @mtd: MTD device structure
+ * @chip: nand chip info structure
+ * @addr: feature address.
+ * @subfeature_param: the subfeature parameters, a four bytes array.
+ */
+static int nand_onfi_set_features(struct mtd_info *mtd, struct nand_chip *chip,
+ int addr, uint8_t *subfeature_param)
+{
+ int status;
+
+ if (!chip->onfi_version)
+ return -EINVAL;
+
+ chip->cmdfunc(mtd, NAND_CMD_SET_FEATURES, addr, -1);
+ chip->write_buf(mtd, subfeature_param, ONFI_SUBFEATURE_PARAM_LEN);
+ status = chip->waitfunc(mtd, chip);
+ if (status & NAND_STATUS_FAIL)
+ return -EIO;
+ return 0;
+}
+
+/**
+ * nand_onfi_get_features- [REPLACEABLE] get features for ONFI nand
+ * @mtd: MTD device structure
+ * @chip: nand chip info structure
+ * @addr: feature address.
+ * @subfeature_param: the subfeature parameters, a four bytes array.
+ */
+static int nand_onfi_get_features(struct mtd_info *mtd, struct nand_chip *chip,
+ int addr, uint8_t *subfeature_param)
+{
+ if (!chip->onfi_version)
+ return -EINVAL;
+
+ /* clear the sub feature parameters */
+ memset(subfeature_param, 0, ONFI_SUBFEATURE_PARAM_LEN);
+
+ chip->cmdfunc(mtd, NAND_CMD_GET_FEATURES, addr, -1);
+ chip->read_buf(mtd, subfeature_param, ONFI_SUBFEATURE_PARAM_LEN);
+ return 0;
+}
+
+/**
* nand_suspend - [MTD Interface] Suspend the NAND flash
* @mtd: MTD device structure
*/
@@ -2809,8 +2798,6 @@ static void nand_set_defaults(struct nand_chip *chip, int busw)
chip->write_buf = busw ? nand_write_buf16 : nand_write_buf;
if (!chip->read_buf)
chip->read_buf = busw ? nand_read_buf16 : nand_read_buf;
- if (!chip->verify_buf)
- chip->verify_buf = busw ? nand_verify_buf16 : nand_verify_buf;
if (!chip->scan_bbt)
chip->scan_bbt = nand_default_bbt;
@@ -2914,14 +2901,250 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,
if (le16_to_cpu(p->features) & 1)
*busw = NAND_BUSWIDTH_16;
- chip->options &= ~NAND_CHIPOPTIONS_MSK;
- chip->options |= NAND_NO_READRDY & NAND_CHIPOPTIONS_MSK;
-
pr_info("ONFI flash detected\n");
return 1;
}
/*
+ * nand_id_has_period - Check if an ID string has a given wraparound period
+ * @id_data: the ID string
+ * @arrlen: the length of the @id_data array
+ * @period: the period of repitition
+ *
+ * Check if an ID string is repeated within a given sequence of bytes at
+ * specific repetition interval period (e.g., {0x20,0x01,0x7F,0x20} has a
+ * period of 2). This is a helper function for nand_id_len(). Returns non-zero
+ * if the repetition has a period of @period; otherwise, returns zero.
+ */
+static int nand_id_has_period(u8 *id_data, int arrlen, int period)
+{
+ int i, j;
+ for (i = 0; i < period; i++)
+ for (j = i + period; j < arrlen; j += period)
+ if (id_data[i] != id_data[j])
+ return 0;
+ return 1;
+}
+
+/*
+ * nand_id_len - Get the length of an ID string returned by CMD_READID
+ * @id_data: the ID string
+ * @arrlen: the length of the @id_data array
+
+ * Returns the length of the ID string, according to known wraparound/trailing
+ * zero patterns. If no pattern exists, returns the length of the array.
+ */
+static int nand_id_len(u8 *id_data, int arrlen)
+{
+ int last_nonzero, period;
+
+ /* Find last non-zero byte */
+ for (last_nonzero = arrlen - 1; last_nonzero >= 0; last_nonzero--)
+ if (id_data[last_nonzero])
+ break;
+
+ /* All zeros */
+ if (last_nonzero < 0)
+ return 0;
+
+ /* Calculate wraparound period */
+ for (period = 1; period < arrlen; period++)
+ if (nand_id_has_period(id_data, arrlen, period))
+ break;
+
+ /* There's a repeated pattern */
+ if (period < arrlen)
+ return period;
+
+ /* There are trailing zeros */
+ if (last_nonzero < arrlen - 1)
+ return last_nonzero + 1;
+
+ /* No pattern detected */
+ return arrlen;
+}
+
+/*
+ * Many new NAND share similar device ID codes, which represent the size of the
+ * chip. The rest of the parameters must be decoded according to generic or
+ * manufacturer-specific "extended ID" decoding patterns.
+ */
+static void nand_decode_ext_id(struct mtd_info *mtd, struct nand_chip *chip,
+ u8 id_data[8], int *busw)
+{
+ int extid, id_len;
+ /* The 3rd id byte holds MLC / multichip data */
+ chip->cellinfo = id_data[2];
+ /* The 4th id byte is the important one */
+ extid = id_data[3];
+
+ id_len = nand_id_len(id_data, 8);
+
+ /*
+ * Field definitions are in the following datasheets:
+ * Old style (4,5 byte ID): Samsung K9GAG08U0M (p.32)
+ * New style (6 byte ID): Samsung K9GAG08U0F (p.44)
+ * Hynix MLC (6 byte ID): Hynix H27UBG8T2B (p.22)
+ *
+ * Check for ID length, cell type, and Hynix/Samsung ID to decide what
+ * to do.
+ */
+ if (id_len == 6 && id_data[0] == NAND_MFR_SAMSUNG) {
+ /* Calc pagesize */
+ mtd->writesize = 2048 << (extid & 0x03);
+ extid >>= 2;
+ /* Calc oobsize */
+ switch (((extid >> 2) & 0x04) | (extid & 0x03)) {
+ case 1:
+ mtd->oobsize = 128;
+ break;
+ case 2:
+ mtd->oobsize = 218;
+ break;
+ case 3:
+ mtd->oobsize = 400;
+ break;
+ case 4:
+ mtd->oobsize = 436;
+ break;
+ case 5:
+ mtd->oobsize = 512;
+ break;
+ case 6:
+ default: /* Other cases are "reserved" (unknown) */
+ mtd->oobsize = 640;
+ break;
+ }
+ extid >>= 2;
+ /* Calc blocksize */
+ mtd->erasesize = (128 * 1024) <<
+ (((extid >> 1) & 0x04) | (extid & 0x03));
+ *busw = 0;
+ } else if (id_len == 6 && id_data[0] == NAND_MFR_HYNIX &&
+ (chip->cellinfo & NAND_CI_CELLTYPE_MSK)) {
+ unsigned int tmp;
+
+ /* Calc pagesize */
+ mtd->writesize = 2048 << (extid & 0x03);
+ extid >>= 2;
+ /* Calc oobsize */
+ switch (((extid >> 2) & 0x04) | (extid & 0x03)) {
+ case 0:
+ mtd->oobsize = 128;
+ break;
+ case 1:
+ mtd->oobsize = 224;
+ break;
+ case 2:
+ mtd->oobsize = 448;
+ break;
+ case 3:
+ mtd->oobsize = 64;
+ break;
+ case 4:
+ mtd->oobsize = 32;
+ break;
+ case 5:
+ mtd->oobsize = 16;
+ break;
+ default:
+ mtd->oobsize = 640;
+ break;
+ }
+ extid >>= 2;
+ /* Calc blocksize */
+ tmp = ((extid >> 1) & 0x04) | (extid & 0x03);
+ if (tmp < 0x03)
+ mtd->erasesize = (128 * 1024) << tmp;
+ else if (tmp == 0x03)
+ mtd->erasesize = 768 * 1024;
+ else
+ mtd->erasesize = (64 * 1024) << tmp;
+ *busw = 0;
+ } else {
+ /* Calc pagesize */
+ mtd->writesize = 1024 << (extid & 0x03);
+ extid >>= 2;
+ /* Calc oobsize */
+ mtd->oobsize = (8 << (extid & 0x01)) *
+ (mtd->writesize >> 9);
+ extid >>= 2;
+ /* Calc blocksize. Blocksize is multiples of 64KiB */
+ mtd->erasesize = (64 * 1024) << (extid & 0x03);
+ extid >>= 2;
+ /* Get buswidth information */
+ *busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0;
+ }
+}
+
+/*
+ * Old devices have chip data hardcoded in the device ID table. nand_decode_id
+ * decodes a matching ID table entry and assigns the MTD size parameters for
+ * the chip.
+ */
+static void nand_decode_id(struct mtd_info *mtd, struct nand_chip *chip,
+ struct nand_flash_dev *type, u8 id_data[8],
+ int *busw)
+{
+ int maf_id = id_data[0];
+
+ mtd->erasesize = type->erasesize;
+ mtd->writesize = type->pagesize;
+ mtd->oobsize = mtd->writesize / 32;
+ *busw = type->options & NAND_BUSWIDTH_16;
+
+ /*
+ * Check for Spansion/AMD ID + repeating 5th, 6th byte since
+ * some Spansion chips have erasesize that conflicts with size
+ * listed in nand_ids table.
+ * Data sheet (5 byte ID): Spansion S30ML-P ORNAND (p.39)
+ */
+ if (maf_id == NAND_MFR_AMD && id_data[4] != 0x00 && id_data[5] == 0x00
+ && id_data[6] == 0x00 && id_data[7] == 0x00
+ && mtd->writesize == 512) {
+ mtd->erasesize = 128 * 1024;
+ mtd->erasesize <<= ((id_data[3] & 0x03) << 1);
+ }
+}
+
+/*
+ * Set the bad block marker/indicator (BBM/BBI) patterns according to some
+ * heuristic patterns using various detected parameters (e.g., manufacturer,
+ * page size, cell-type information).
+ */
+static void nand_decode_bbm_options(struct mtd_info *mtd,
+ struct nand_chip *chip, u8 id_data[8])
+{
+ int maf_id = id_data[0];
+
+ /* Set the bad block position */
+ if (mtd->writesize > 512 || (chip->options & NAND_BUSWIDTH_16))
+ chip->badblockpos = NAND_LARGE_BADBLOCK_POS;
+ else
+ chip->badblockpos = NAND_SMALL_BADBLOCK_POS;
+
+ /*
+ * Bad block marker is stored in the last page of each block on Samsung
+ * and Hynix MLC devices; stored in first two pages of each block on
+ * Micron devices with 2KiB pages and on SLC Samsung, Hynix, Toshiba,
+ * AMD/Spansion, and Macronix. All others scan only the first page.
+ */
+ if ((chip->cellinfo & NAND_CI_CELLTYPE_MSK) &&
+ (maf_id == NAND_MFR_SAMSUNG ||
+ maf_id == NAND_MFR_HYNIX))
+ chip->bbt_options |= NAND_BBT_SCANLASTPAGE;
+ else if ((!(chip->cellinfo & NAND_CI_CELLTYPE_MSK) &&
+ (maf_id == NAND_MFR_SAMSUNG ||
+ maf_id == NAND_MFR_HYNIX ||
+ maf_id == NAND_MFR_TOSHIBA ||
+ maf_id == NAND_MFR_AMD ||
+ maf_id == NAND_MFR_MACRONIX)) ||
+ (mtd->writesize == 2048 &&
+ maf_id == NAND_MFR_MICRON))
+ chip->bbt_options |= NAND_BBT_SCAN2NDPAGE;
+}
+
+/*
* Get the flash and manufacturer id and lookup if the type is supported.
*/
static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
@@ -2932,7 +3155,6 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
{
int i, maf_idx;
u8 id_data[8];
- int ret;
/* Select the device */
chip->select_chip(mtd, 0);
@@ -2959,7 +3181,8 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
- for (i = 0; i < 2; i++)
+ /* Read entire ID string */
+ for (i = 0; i < 8; i++)
id_data[i] = chip->read_byte(mtd);
if (id_data[0] != *maf_id || id_data[1] != *dev_id) {
@@ -2979,18 +3202,10 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
chip->onfi_version = 0;
if (!type->name || !type->pagesize) {
/* Check is chip is ONFI compliant */
- ret = nand_flash_detect_onfi(mtd, chip, &busw);
- if (ret)
+ if (nand_flash_detect_onfi(mtd, chip, &busw))
goto ident_done;
}
- chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
-
- /* Read entire ID string */
-
- for (i = 0; i < 8; i++)
- id_data[i] = chip->read_byte(mtd);
-
if (!type->name)
return ERR_PTR(-ENODEV);
@@ -3003,86 +3218,13 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
/* Set the pagesize, oobsize, erasesize by the driver */
busw = chip->init_size(mtd, chip, id_data);
} else if (!type->pagesize) {
- int extid;
- /* The 3rd id byte holds MLC / multichip data */
- chip->cellinfo = id_data[2];
- /* The 4th id byte is the important one */
- extid = id_data[3];
-
- /*
- * Field definitions are in the following datasheets:
- * Old style (4,5 byte ID): Samsung K9GAG08U0M (p.32)
- * New style (6 byte ID): Samsung K9GBG08U0M (p.40)
- *
- * Check for wraparound + Samsung ID + nonzero 6th byte
- * to decide what to do.
- */
- if (id_data[0] == id_data[6] && id_data[1] == id_data[7] &&
- id_data[0] == NAND_MFR_SAMSUNG &&
- (chip->cellinfo & NAND_CI_CELLTYPE_MSK) &&
- id_data[5] != 0x00) {
- /* Calc pagesize */
- mtd->writesize = 2048 << (extid & 0x03);
- extid >>= 2;
- /* Calc oobsize */
- switch (extid & 0x03) {
- case 1:
- mtd->oobsize = 128;
- break;
- case 2:
- mtd->oobsize = 218;
- break;
- case 3:
- mtd->oobsize = 400;
- break;
- default:
- mtd->oobsize = 436;
- break;
- }
- extid >>= 2;
- /* Calc blocksize */
- mtd->erasesize = (128 * 1024) <<
- (((extid >> 1) & 0x04) | (extid & 0x03));
- busw = 0;
- } else {
- /* Calc pagesize */
- mtd->writesize = 1024 << (extid & 0x03);
- extid >>= 2;
- /* Calc oobsize */
- mtd->oobsize = (8 << (extid & 0x01)) *
- (mtd->writesize >> 9);
- extid >>= 2;
- /* Calc blocksize. Blocksize is multiples of 64KiB */
- mtd->erasesize = (64 * 1024) << (extid & 0x03);
- extid >>= 2;
- /* Get buswidth information */
- busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0;
- }
+ /* Decode parameters from extended ID */
+ nand_decode_ext_id(mtd, chip, id_data, &busw);
} else {
- /*
- * Old devices have chip data hardcoded in the device id table.
- */
- mtd->erasesize = type->erasesize;
- mtd->writesize = type->pagesize;
- mtd->oobsize = mtd->writesize / 32;
- busw = type->options & NAND_BUSWIDTH_16;
-
- /*
- * Check for Spansion/AMD ID + repeating 5th, 6th byte since
- * some Spansion chips have erasesize that conflicts with size
- * listed in nand_ids table.
- * Data sheet (5 byte ID): Spansion S30ML-P ORNAND (p.39)
- */
- if (*maf_id == NAND_MFR_AMD && id_data[4] != 0x00 &&
- id_data[5] == 0x00 && id_data[6] == 0x00 &&
- id_data[7] == 0x00 && mtd->writesize == 512) {
- mtd->erasesize = 128 * 1024;
- mtd->erasesize <<= ((id_data[3] & 0x03) << 1);
- }
+ nand_decode_id(mtd, chip, type, id_data, &busw);
}
- /* Get chip options, preserve non chip based options */
- chip->options &= ~NAND_CHIPOPTIONS_MSK;
- chip->options |= type->options & NAND_CHIPOPTIONS_MSK;
+ /* Get chip options */
+ chip->options |= type->options;
/*
* Check if chip is not a Samsung device. Do not clear the
@@ -3112,6 +3254,8 @@ ident_done:
return ERR_PTR(-EINVAL);
}
+ nand_decode_bbm_options(mtd, chip, id_data);
+
/* Calculate the address shift from the page size */
chip->page_shift = ffs(mtd->writesize) - 1;
/* Convert chipsize to number of pages per chip -1 */
@@ -3128,33 +3272,6 @@ ident_done:
chip->badblockbits = 8;
- /* Set the bad block position */
- if (mtd->writesize > 512 || (busw & NAND_BUSWIDTH_16))
- chip->badblockpos = NAND_LARGE_BADBLOCK_POS;
- else
- chip->badblockpos = NAND_SMALL_BADBLOCK_POS;
-
- /*
- * Bad block marker is stored in the last page of each block
- * on Samsung and Hynix MLC devices; stored in first two pages
- * of each block on Micron devices with 2KiB pages and on
- * SLC Samsung, Hynix, Toshiba, AMD/Spansion, and Macronix.
- * All others scan only the first page.
- */
- if ((chip->cellinfo & NAND_CI_CELLTYPE_MSK) &&
- (*maf_id == NAND_MFR_SAMSUNG ||
- *maf_id == NAND_MFR_HYNIX))
- chip->bbt_options |= NAND_BBT_SCANLASTPAGE;
- else if ((!(chip->cellinfo & NAND_CI_CELLTYPE_MSK) &&
- (*maf_id == NAND_MFR_SAMSUNG ||
- *maf_id == NAND_MFR_HYNIX ||
- *maf_id == NAND_MFR_TOSHIBA ||
- *maf_id == NAND_MFR_AMD ||
- *maf_id == NAND_MFR_MACRONIX)) ||
- (mtd->writesize == 2048 &&
- *maf_id == NAND_MFR_MICRON))
- chip->bbt_options |= NAND_BBT_SCAN2NDPAGE;
-
/* Check for AND chips with 4 page planes */
if (chip->options & NAND_4PAGE_ARRAY)
chip->erase_cmd = multi_erase_cmd;
@@ -3284,6 +3401,12 @@ int nand_scan_tail(struct mtd_info *mtd)
if (!chip->write_page)
chip->write_page = nand_write_page;
+ /* set for ONFI nand */
+ if (!chip->onfi_set_features)
+ chip->onfi_set_features = nand_onfi_set_features;
+ if (!chip->onfi_get_features)
+ chip->onfi_get_features = nand_onfi_get_features;
+
/*
* Check ECC mode, default to software if 3byte/512byte hardware ECC is
* selected and we have 256 byte pagesize fallback to software ECC
@@ -3477,6 +3600,10 @@ int nand_scan_tail(struct mtd_info *mtd)
/* Invalidate the pagebuffer reference */
chip->pagebuf = -1;
+ /* Large page NAND with SOFT_ECC should support subpage reads */
+ if ((chip->ecc.mode == NAND_ECC_SOFT) && (chip->page_shift > 9))
+ chip->options |= NAND_SUBPAGE_READ;
+
/* Fill in remaining MTD driver data */
mtd->type = MTD_NANDFLASH;
mtd->flags = (chip->options & NAND_ROM) ? MTD_CAP_ROM :
diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c
index 30d1319..916d6e9 100644
--- a/drivers/mtd/nand/nand_bbt.c
+++ b/drivers/mtd/nand/nand_bbt.c
@@ -4,7 +4,7 @@
* Overview:
* Bad block table support for the NAND driver
*
- * Copyright (C) 2004 Thomas Gleixner (tglx@linutronix.de)
+ * Copyright © 2004 Thomas Gleixner (tglx@linutronix.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
@@ -22,7 +22,7 @@
* BBT on flash. If a BBT is found then the contents are read and the memory
* based BBT is created. If a mirrored BBT is selected then the mirror is
* searched too and the versions are compared. If the mirror has a greater
- * version number than the mirror BBT is used to build the memory based BBT.
+ * version number, then the mirror BBT is used to build the memory based BBT.
* If the tables are not versioned, then we "or" the bad block information.
* If one of the BBTs is out of date or does not exist it is (re)created.
* If no BBT exists at all then the device is scanned for factory marked
@@ -62,21 +62,20 @@
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/mtd/mtd.h>
+#include <linux/mtd/bbm.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/nand_ecc.h>
#include <linux/bitops.h>
#include <linux/delay.h>
#include <linux/vmalloc.h>
#include <linux/export.h>
+#include <linux/string.h>
static int check_pattern_no_oob(uint8_t *buf, struct nand_bbt_descr *td)
{
- int ret;
-
- ret = memcmp(buf, td->pattern, td->len);
- if (!ret)
- return ret;
- return -1;
+ if (memcmp(buf, td->pattern, td->len))
+ return -1;
+ return 0;
}
/**
@@ -92,19 +91,16 @@ static int check_pattern_no_oob(uint8_t *buf, struct nand_bbt_descr *td)
*/
static int check_pattern(uint8_t *buf, int len, int paglen, struct nand_bbt_descr *td)
{
- int i, end = 0;
+ int end = 0;
uint8_t *p = buf;
if (td->options & NAND_BBT_NO_OOB)
return check_pattern_no_oob(buf, td);
end = paglen + td->offs;
- if (td->options & NAND_BBT_SCANEMPTY) {
- for (i = 0; i < end; i++) {
- if (p[i] != 0xff)
- return -1;
- }
- }
+ if (td->options & NAND_BBT_SCANEMPTY)
+ if (memchr_inv(p, 0xff, end))
+ return -1;
p += end;
/* Compare the pattern */
@@ -114,10 +110,8 @@ static int check_pattern(uint8_t *buf, int len, int paglen, struct nand_bbt_desc
if (td->options & NAND_BBT_SCANEMPTY) {
p += td->len;
end += td->len;
- for (i = end; i < len; i++) {
- if (*p++ != 0xff)
- return -1;
- }
+ if (memchr_inv(p, 0xff, len - end))
+ return -1;
}
return 0;
}
@@ -133,14 +127,9 @@ static int check_pattern(uint8_t *buf, int len, int paglen, struct nand_bbt_desc
*/
static int check_short_pattern(uint8_t *buf, struct nand_bbt_descr *td)
{
- int i;
- uint8_t *p = buf;
-
/* Compare the pattern */
- for (i = 0; i < td->len; i++) {
- if (p[td->offs + i] != td->pattern[i])
- return -1;
- }
+ if (memcmp(buf + td->offs, td->pattern, td->len))
+ return -1;
return 0;
}
@@ -288,7 +277,7 @@ static int read_abs_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc
}
/* BBT marker is in the first page, no OOB */
-static int scan_read_raw_data(struct mtd_info *mtd, uint8_t *buf, loff_t offs,
+static int scan_read_data(struct mtd_info *mtd, uint8_t *buf, loff_t offs,
struct nand_bbt_descr *td)
{
size_t retlen;
@@ -301,14 +290,24 @@ static int scan_read_raw_data(struct mtd_info *mtd, uint8_t *buf, loff_t offs,
return mtd_read(mtd, offs, len, &retlen, buf);
}
-/* Scan read raw data from flash */
-static int scan_read_raw_oob(struct mtd_info *mtd, uint8_t *buf, loff_t offs,
+/**
+ * scan_read_oob - [GENERIC] Scan data+OOB region to buffer
+ * @mtd: MTD device structure
+ * @buf: temporary buffer
+ * @offs: offset at which to scan
+ * @len: length of data region to read
+ *
+ * Scan read data from data+OOB. May traverse multiple pages, interleaving
+ * page,OOB,page,OOB,... in buf. Completes transfer and returns the "strongest"
+ * ECC condition (error or bitflip). May quit on the first (non-ECC) error.
+ */
+static int scan_read_oob(struct mtd_info *mtd, uint8_t *buf, loff_t offs,
size_t len)
{
struct mtd_oob_ops ops;
- int res;
+ int res, ret = 0;
- ops.mode = MTD_OPS_RAW;
+ ops.mode = MTD_OPS_PLACE_OOB;
ops.ooboffs = 0;
ops.ooblen = mtd->oobsize;
@@ -318,24 +317,27 @@ static int scan_read_raw_oob(struct mtd_info *mtd, uint8_t *buf, loff_t offs,
ops.oobbuf = buf + ops.len;
res = mtd_read_oob(mtd, offs, &ops);
-
- if (res)
- return res;
+ if (res) {
+ if (!mtd_is_bitflip_or_eccerr(res))
+ return res;
+ else if (mtd_is_eccerr(res) || !ret)
+ ret = res;
+ }
buf += mtd->oobsize + mtd->writesize;
len -= mtd->writesize;
offs += mtd->writesize;
}
- return 0;
+ return ret;
}
-static int scan_read_raw(struct mtd_info *mtd, uint8_t *buf, loff_t offs,
+static int scan_read(struct mtd_info *mtd, uint8_t *buf, loff_t offs,
size_t len, struct nand_bbt_descr *td)
{
if (td->options & NAND_BBT_NO_OOB)
- return scan_read_raw_data(mtd, buf, offs, td);
+ return scan_read_data(mtd, buf, offs, td);
else
- return scan_read_raw_oob(mtd, buf, offs, len);
+ return scan_read_oob(mtd, buf, offs, len);
}
/* Scan write data with oob to flash */
@@ -373,14 +375,14 @@ static u32 bbt_get_ver_offs(struct mtd_info *mtd, struct nand_bbt_descr *td)
* Read the bad block table(s) for all chips starting at a given page. We
* assume that the bbt bits are in consecutive order.
*/
-static int read_abs_bbts(struct mtd_info *mtd, uint8_t *buf,
- struct nand_bbt_descr *td, struct nand_bbt_descr *md)
+static void read_abs_bbts(struct mtd_info *mtd, uint8_t *buf,
+ struct nand_bbt_descr *td, struct nand_bbt_descr *md)
{
struct nand_chip *this = mtd->priv;
/* Read the primary version, if available */
if (td->options & NAND_BBT_VERSION) {
- scan_read_raw(mtd, buf, (loff_t)td->pages[0] << this->page_shift,
+ scan_read(mtd, buf, (loff_t)td->pages[0] << this->page_shift,
mtd->writesize, td);
td->version[0] = buf[bbt_get_ver_offs(mtd, td)];
pr_info("Bad block table at page %d, version 0x%02X\n",
@@ -389,28 +391,27 @@ static int read_abs_bbts(struct mtd_info *mtd, uint8_t *buf,
/* Read the mirror version, if available */
if (md && (md->options & NAND_BBT_VERSION)) {
- scan_read_raw(mtd, buf, (loff_t)md->pages[0] << this->page_shift,
- mtd->writesize, td);
+ scan_read(mtd, buf, (loff_t)md->pages[0] << this->page_shift,
+ mtd->writesize, md);
md->version[0] = buf[bbt_get_ver_offs(mtd, md)];
pr_info("Bad block table at page %d, version 0x%02X\n",
md->pages[0], md->version[0]);
}
- return 1;
}
/* Scan a given block full */
static int scan_block_full(struct mtd_info *mtd, struct nand_bbt_descr *bd,
loff_t offs, uint8_t *buf, size_t readlen,
- int scanlen, int len)
+ int scanlen, int numpages)
{
int ret, j;
- ret = scan_read_raw_oob(mtd, buf, offs, readlen);
+ ret = scan_read_oob(mtd, buf, offs, readlen);
/* Ignore ECC errors when checking for BBM */
if (ret && !mtd_is_bitflip_or_eccerr(ret))
return ret;
- for (j = 0; j < len; j++, buf += scanlen) {
+ for (j = 0; j < numpages; j++, buf += scanlen) {
if (check_pattern(buf, scanlen, mtd->writesize, bd))
return 1;
}
@@ -419,7 +420,7 @@ static int scan_block_full(struct mtd_info *mtd, struct nand_bbt_descr *bd,
/* Scan a given block partially */
static int scan_block_fast(struct mtd_info *mtd, struct nand_bbt_descr *bd,
- loff_t offs, uint8_t *buf, int len)
+ loff_t offs, uint8_t *buf, int numpages)
{
struct mtd_oob_ops ops;
int j, ret;
@@ -430,7 +431,7 @@ static int scan_block_fast(struct mtd_info *mtd, struct nand_bbt_descr *bd,
ops.datbuf = NULL;
ops.mode = MTD_OPS_PLACE_OOB;
- for (j = 0; j < len; j++) {
+ for (j = 0; j < numpages; j++) {
/*
* Read the full oob until read_oob is fixed to handle single
* byte reads for 16 bit buswidth.
@@ -463,7 +464,7 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf,
struct nand_bbt_descr *bd, int chip)
{
struct nand_chip *this = mtd->priv;
- int i, numblocks, len, scanlen;
+ int i, numblocks, numpages, scanlen;
int startblock;
loff_t from;
size_t readlen;
@@ -471,11 +472,11 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf,
pr_info("Scanning device for bad blocks\n");
if (bd->options & NAND_BBT_SCANALLPAGES)
- len = 1 << (this->bbt_erase_shift - this->page_shift);
+ numpages = 1 << (this->bbt_erase_shift - this->page_shift);
else if (bd->options & NAND_BBT_SCAN2NDPAGE)
- len = 2;
+ numpages = 2;
else
- len = 1;
+ numpages = 1;
if (!(bd->options & NAND_BBT_SCANEMPTY)) {
/* We need only read few bytes from the OOB area */
@@ -484,7 +485,7 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf,
} else {
/* Full page content should be read */
scanlen = mtd->writesize + mtd->oobsize;
- readlen = len * mtd->writesize;
+ readlen = numpages * mtd->writesize;
}
if (chip == -1) {
@@ -508,7 +509,7 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf,
}
if (this->bbt_options & NAND_BBT_SCANLASTPAGE)
- from += mtd->erasesize - (mtd->writesize * len);
+ from += mtd->erasesize - (mtd->writesize * numpages);
for (i = startblock; i < numblocks;) {
int ret;
@@ -517,9 +518,9 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf,
if (bd->options & NAND_BBT_SCANALLPAGES)
ret = scan_block_full(mtd, bd, from, buf, readlen,
- scanlen, len);
+ scanlen, numpages);
else
- ret = scan_block_fast(mtd, bd, from, buf, len);
+ ret = scan_block_fast(mtd, bd, from, buf, numpages);
if (ret < 0)
return ret;
@@ -594,7 +595,7 @@ static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr
loff_t offs = (loff_t)actblock << this->bbt_erase_shift;
/* Read first page */
- scan_read_raw(mtd, buf, offs, mtd->writesize, td);
+ scan_read(mtd, buf, offs, mtd->writesize, td);
if (!check_pattern(buf, scanlen, mtd->writesize, td)) {
td->pages[i] = actblock << blocktopage;
if (td->options & NAND_BBT_VERSION) {
@@ -626,7 +627,9 @@ static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr
*
* Search and read the bad block table(s).
*/
-static int search_read_bbts(struct mtd_info *mtd, uint8_t * buf, struct nand_bbt_descr *td, struct nand_bbt_descr *md)
+static void search_read_bbts(struct mtd_info *mtd, uint8_t *buf,
+ struct nand_bbt_descr *td,
+ struct nand_bbt_descr *md)
{
/* Search the primary table */
search_bbt(mtd, buf, td);
@@ -634,9 +637,6 @@ static int search_read_bbts(struct mtd_info *mtd, uint8_t * buf, struct nand_bbt
/* Search the mirror table */
if (md)
search_bbt(mtd, buf, md);
-
- /* Force result check */
- return 1;
}
/**
@@ -1162,14 +1162,13 @@ int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
/* Is the bbt at a given page? */
if (td->options & NAND_BBT_ABSPAGE) {
- res = read_abs_bbts(mtd, buf, td, md);
+ read_abs_bbts(mtd, buf, td, md);
} else {
/* Search the bad block table using a pattern in oob */
- res = search_read_bbts(mtd, buf, td, md);
+ search_read_bbts(mtd, buf, td, md);
}
- if (res)
- res = check_create(mtd, buf, bd);
+ res = check_create(mtd, buf, bd);
/* Prevent the bbt regions from erasing / writing */
mark_bbt_region(mtd, td);
@@ -1260,7 +1259,7 @@ static struct nand_bbt_descr bbt_main_descr = {
.offs = 8,
.len = 4,
.veroffs = 12,
- .maxblocks = 4,
+ .maxblocks = NAND_BBT_SCAN_MAXBLOCKS,
.pattern = bbt_pattern
};
@@ -1270,27 +1269,27 @@ static struct nand_bbt_descr bbt_mirror_descr = {
.offs = 8,
.len = 4,
.veroffs = 12,
- .maxblocks = 4,
+ .maxblocks = NAND_BBT_SCAN_MAXBLOCKS,
.pattern = mirror_pattern
};
-static struct nand_bbt_descr bbt_main_no_bbt_descr = {
+static struct nand_bbt_descr bbt_main_no_oob_descr = {
.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
| NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP
| NAND_BBT_NO_OOB,
.len = 4,
.veroffs = 4,
- .maxblocks = 4,
+ .maxblocks = NAND_BBT_SCAN_MAXBLOCKS,
.pattern = bbt_pattern
};
-static struct nand_bbt_descr bbt_mirror_no_bbt_descr = {
+static struct nand_bbt_descr bbt_mirror_no_oob_descr = {
.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
| NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP
| NAND_BBT_NO_OOB,
.len = 4,
.veroffs = 4,
- .maxblocks = 4,
+ .maxblocks = NAND_BBT_SCAN_MAXBLOCKS,
.pattern = mirror_pattern
};
@@ -1355,8 +1354,8 @@ int nand_default_bbt(struct mtd_info *mtd)
/* Use the default pattern descriptors */
if (!this->bbt_td) {
if (this->bbt_options & NAND_BBT_NO_OOB) {
- this->bbt_td = &bbt_main_no_bbt_descr;
- this->bbt_md = &bbt_mirror_no_bbt_descr;
+ this->bbt_td = &bbt_main_no_oob_descr;
+ this->bbt_md = &bbt_mirror_no_oob_descr;
} else {
this->bbt_td = &bbt_main_descr;
this->bbt_md = &bbt_mirror_descr;
@@ -1406,3 +1405,4 @@ int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt)
EXPORT_SYMBOL(nand_scan_bbt);
EXPORT_SYMBOL(nand_default_bbt);
+EXPORT_SYMBOL_GPL(nand_update_bbt);
diff --git a/drivers/mtd/nand/nand_bcm_umi.c b/drivers/mtd/nand/nand_bcm_umi.c
deleted file mode 100644
index 46a6bc9..0000000
--- a/drivers/mtd/nand/nand_bcm_umi.c
+++ /dev/null
@@ -1,149 +0,0 @@
-/*****************************************************************************
-* Copyright 2004 - 2009 Broadcom Corporation. All rights reserved.
-*
-* Unless you and Broadcom execute a separate written software license
-* agreement governing use of this software, this software is licensed to you
-* under the terms of the GNU General Public License version 2, available at
-* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
-*
-* Notwithstanding the above, under no circumstances may you combine this
-* software in any way with any other Broadcom software provided under a
-* license other than the GPL, without Broadcom's express prior written
-* consent.
-*****************************************************************************/
-
-/* ---- Include Files ---------------------------------------------------- */
-#include <mach/reg_umi.h>
-#include "nand_bcm_umi.h"
-#ifdef BOOT0_BUILD
-#include <uart.h>
-#endif
-
-/* ---- External Variable Declarations ----------------------------------- */
-/* ---- External Function Prototypes ------------------------------------- */
-/* ---- Public Variables ------------------------------------------------- */
-/* ---- Private Constants and Types -------------------------------------- */
-/* ---- Private Function Prototypes -------------------------------------- */
-/* ---- Private Variables ------------------------------------------------ */
-/* ---- Private Functions ------------------------------------------------ */
-
-#if NAND_ECC_BCH
-/****************************************************************************
-* nand_bch_ecc_flip_bit - Routine to flip an errored bit
-*
-* PURPOSE:
-* This is a helper routine that flips the bit (0 -> 1 or 1 -> 0) of the
-* errored bit specified
-*
-* PARAMETERS:
-* datap - Container that holds the 512 byte data
-* errorLocation - Location of the bit that needs to be flipped
-*
-* RETURNS:
-* None
-****************************************************************************/
-static void nand_bcm_umi_bch_ecc_flip_bit(uint8_t *datap, int errorLocation)
-{
- int locWithinAByte = (errorLocation & REG_UMI_BCH_ERR_LOC_BYTE) >> 0;
- int locWithinAWord = (errorLocation & REG_UMI_BCH_ERR_LOC_WORD) >> 3;
- int locWithinAPage = (errorLocation & REG_UMI_BCH_ERR_LOC_PAGE) >> 5;
-
- uint8_t errorByte = 0;
- uint8_t byteMask = 1 << locWithinAByte;
-
- /* BCH uses big endian, need to change the location
- * bits to little endian */
- locWithinAWord = 3 - locWithinAWord;
-
- errorByte = datap[locWithinAPage * sizeof(uint32_t) + locWithinAWord];
-
-#ifdef BOOT0_BUILD
- puthexs("\nECC Correct Offset: ",
- locWithinAPage * sizeof(uint32_t) + locWithinAWord);
- puthexs(" errorByte:", errorByte);
- puthex8(" Bit: ", locWithinAByte);
-#endif
-
- if (errorByte & byteMask) {
- /* bit needs to be cleared */
- errorByte &= ~byteMask;
- } else {
- /* bit needs to be set */
- errorByte |= byteMask;
- }
-
- /* write back the value with the fixed bit */
- datap[locWithinAPage * sizeof(uint32_t) + locWithinAWord] = errorByte;
-}
-
-/****************************************************************************
-* nand_correct_page_bch - Routine to correct bit errors when reading NAND
-*
-* PURPOSE:
-* This routine reads the BCH registers to determine if there are any bit
-* errors during the read of the last 512 bytes of data + ECC bytes. If
-* errors exists, the routine fixes it.
-*
-* PARAMETERS:
-* datap - Container that holds the 512 byte data
-*
-* RETURNS:
-* 0 or greater = Number of errors corrected
-* (No errors are found or errors have been fixed)
-* -1 = Error(s) cannot be fixed
-****************************************************************************/
-int nand_bcm_umi_bch_correct_page(uint8_t *datap, uint8_t *readEccData,
- int numEccBytes)
-{
- int numErrors;
- int errorLocation;
- int idx;
- uint32_t regValue;
-
- /* wait for read ECC to be valid */
- regValue = nand_bcm_umi_bch_poll_read_ecc_calc();
-
- /*
- * read the control status register to determine if there
- * are error'ed bits
- * see if errors are correctible
- */
- if ((regValue & REG_UMI_BCH_CTRL_STATUS_UNCORR_ERR) > 0) {
- int i;
-
- for (i = 0; i < numEccBytes; i++) {
- if (readEccData[i] != 0xff) {
- /* errors cannot be fixed, return -1 */
- return -1;
- }
- }
- /* If ECC is unprogrammed then we can't correct,
- * assume everything OK */
- return 0;
- }
-
- if ((regValue & REG_UMI_BCH_CTRL_STATUS_CORR_ERR) == 0) {
- /* no errors */
- return 0;
- }
-
- /*
- * Fix errored bits by doing the following:
- * 1. Read the number of errors in the control and status register
- * 2. Read the error location registers that corresponds to the number
- * of errors reported
- * 3. Invert the bit in the data
- */
- numErrors = (regValue & REG_UMI_BCH_CTRL_STATUS_NB_CORR_ERROR) >> 20;
-
- for (idx = 0; idx < numErrors; idx++) {
- errorLocation =
- REG_UMI_BCH_ERR_LOC_ADDR(idx) & REG_UMI_BCH_ERR_LOC_MASK;
-
- /* Flip bit */
- nand_bcm_umi_bch_ecc_flip_bit(datap, errorLocation);
- }
- /* Errors corrected */
- return numErrors;
-}
-#endif
diff --git a/drivers/mtd/nand/nand_bcm_umi.h b/drivers/mtd/nand/nand_bcm_umi.h
deleted file mode 100644
index d901866..0000000
--- a/drivers/mtd/nand/nand_bcm_umi.h
+++ /dev/null
@@ -1,336 +0,0 @@
-/*****************************************************************************
-* Copyright 2003 - 2009 Broadcom Corporation. All rights reserved.
-*
-* Unless you and Broadcom execute a separate written software license
-* agreement governing use of this software, this software is licensed to you
-* under the terms of the GNU General Public License version 2, available at
-* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
-*
-* Notwithstanding the above, under no circumstances may you combine this
-* software in any way with any other Broadcom software provided under a
-* license other than the GPL, without Broadcom's express prior written
-* consent.
-*****************************************************************************/
-#ifndef NAND_BCM_UMI_H
-#define NAND_BCM_UMI_H
-
-/* ---- Include Files ---------------------------------------------------- */
-#include <mach/reg_umi.h>
-#include <mach/reg_nand.h>
-#include <mach/cfg_global.h>
-
-/* ---- Constants and Types ---------------------------------------------- */
-#if (CFG_GLOBAL_CHIP_FAMILY == CFG_GLOBAL_CHIP_FAMILY_BCMRING)
-#define NAND_ECC_BCH (CFG_GLOBAL_CHIP_REV > 0xA0)
-#else
-#define NAND_ECC_BCH 0
-#endif
-
-#define CFG_GLOBAL_NAND_ECC_BCH_NUM_BYTES 13
-
-#if NAND_ECC_BCH
-#ifdef BOOT0_BUILD
-#define NAND_ECC_NUM_BYTES 13
-#else
-#define NAND_ECC_NUM_BYTES CFG_GLOBAL_NAND_ECC_BCH_NUM_BYTES
-#endif
-#else
-#define NAND_ECC_NUM_BYTES 3
-#endif
-
-#define NAND_DATA_ACCESS_SIZE 512
-
-/* ---- Variable Externs ------------------------------------------ */
-/* ---- Function Prototypes --------------------------------------- */
-int nand_bcm_umi_bch_correct_page(uint8_t *datap, uint8_t *readEccData,
- int numEccBytes);
-
-/* Check in device is ready */
-static inline int nand_bcm_umi_dev_ready(void)
-{
- return readl(&REG_UMI_NAND_RCSR) & REG_UMI_NAND_RCSR_RDY;
-}
-
-/* Wait until device is ready */
-static inline void nand_bcm_umi_wait_till_ready(void)
-{
- while (nand_bcm_umi_dev_ready() == 0)
- ;
-}
-
-/* Enable Hamming ECC */
-static inline void nand_bcm_umi_hamming_enable_hwecc(void)
-{
- /* disable and reset ECC, 512 byte page */
- writel(readl(&REG_UMI_NAND_ECC_CSR) & ~(REG_UMI_NAND_ECC_CSR_ECC_ENABLE |
- REG_UMI_NAND_ECC_CSR_256BYTE), &REG_UMI_NAND_ECC_CSR);
- /* enable ECC */
- writel(readl(&REG_UMI_NAND_ECC_CSR) | REG_UMI_NAND_ECC_CSR_ECC_ENABLE,
- &REG_UMI_NAND_ECC_CSR);
-}
-
-#if NAND_ECC_BCH
-/* BCH ECC specifics */
-#define ECC_BITS_PER_CORRECTABLE_BIT 13
-
-/* Enable BCH Read ECC */
-static inline void nand_bcm_umi_bch_enable_read_hwecc(void)
-{
- /* disable and reset ECC */
- writel(REG_UMI_BCH_CTRL_STATUS_RD_ECC_VALID, &REG_UMI_BCH_CTRL_STATUS);
- /* Turn on ECC */
- writel(REG_UMI_BCH_CTRL_STATUS_ECC_RD_EN, &REG_UMI_BCH_CTRL_STATUS);
-}
-
-/* Enable BCH Write ECC */
-static inline void nand_bcm_umi_bch_enable_write_hwecc(void)
-{
- /* disable and reset ECC */
- writel(REG_UMI_BCH_CTRL_STATUS_WR_ECC_VALID, &REG_UMI_BCH_CTRL_STATUS);
- /* Turn on ECC */
- writel(REG_UMI_BCH_CTRL_STATUS_ECC_WR_EN, &REG_UMI_BCH_CTRL_STATUS);
-}
-
-/* Config number of BCH ECC bytes */
-static inline void nand_bcm_umi_bch_config_ecc(uint8_t numEccBytes)
-{
- uint32_t nValue;
- uint32_t tValue;
- uint32_t kValue;
- uint32_t numBits = numEccBytes * 8;
-
- /* disable and reset ECC */
- writel(REG_UMI_BCH_CTRL_STATUS_WR_ECC_VALID |
- REG_UMI_BCH_CTRL_STATUS_RD_ECC_VALID,
- &REG_UMI_BCH_CTRL_STATUS);
-
- /* Every correctible bit requires 13 ECC bits */
- tValue = (uint32_t) (numBits / ECC_BITS_PER_CORRECTABLE_BIT);
-
- /* Total data in number of bits for generating and computing BCH ECC */
- nValue = (NAND_DATA_ACCESS_SIZE + numEccBytes) * 8;
-
- /* K parameter is used internally. K = N - (T * 13) */
- kValue = nValue - (tValue * ECC_BITS_PER_CORRECTABLE_BIT);
-
- /* Write the settings */
- writel(nValue, &REG_UMI_BCH_N);
- writel(tValue, &REG_UMI_BCH_T);
- writel(kValue, &REG_UMI_BCH_K);
-}
-
-/* Pause during ECC read calculation to skip bytes in OOB */
-static inline void nand_bcm_umi_bch_pause_read_ecc_calc(void)
-{
- writel(REG_UMI_BCH_CTRL_STATUS_ECC_RD_EN | REG_UMI_BCH_CTRL_STATUS_PAUSE_ECC_DEC, &REG_UMI_BCH_CTRL_STATUS);
-}
-
-/* Resume during ECC read calculation after skipping bytes in OOB */
-static inline void nand_bcm_umi_bch_resume_read_ecc_calc(void)
-{
- writel(REG_UMI_BCH_CTRL_STATUS_ECC_RD_EN, &REG_UMI_BCH_CTRL_STATUS);
-}
-
-/* Poll read ECC calc to check when hardware completes */
-static inline uint32_t nand_bcm_umi_bch_poll_read_ecc_calc(void)
-{
- uint32_t regVal;
-
- do {
- /* wait for ECC to be valid */
- regVal = readl(&REG_UMI_BCH_CTRL_STATUS);
- } while ((regVal & REG_UMI_BCH_CTRL_STATUS_RD_ECC_VALID) == 0);
-
- return regVal;
-}
-
-/* Poll write ECC calc to check when hardware completes */
-static inline void nand_bcm_umi_bch_poll_write_ecc_calc(void)
-{
- /* wait for ECC to be valid */
- while ((readl(&REG_UMI_BCH_CTRL_STATUS) & REG_UMI_BCH_CTRL_STATUS_WR_ECC_VALID)
- == 0)
- ;
-}
-
-/* Read the OOB and ECC, for kernel write OOB to a buffer */
-#if defined(__KERNEL__) && !defined(STANDALONE)
-static inline void nand_bcm_umi_bch_read_oobEcc(uint32_t pageSize,
- uint8_t *eccCalc, int numEccBytes, uint8_t *oobp)
-#else
-static inline void nand_bcm_umi_bch_read_oobEcc(uint32_t pageSize,
- uint8_t *eccCalc, int numEccBytes)
-#endif
-{
- int eccPos = 0;
- int numToRead = 16; /* There are 16 bytes per sector in the OOB */
-
- /* ECC is already paused when this function is called */
- if (pageSize != NAND_DATA_ACCESS_SIZE) {
- /* skip BI */
-#if defined(__KERNEL__) && !defined(STANDALONE)
- *oobp++ = readb(&REG_NAND_DATA8);
-#else
- readb(&REG_NAND_DATA8);
-#endif
- numToRead--;
- }
-
- while (numToRead > numEccBytes) {
- /* skip free oob region */
-#if defined(__KERNEL__) && !defined(STANDALONE)
- *oobp++ = readb(&REG_NAND_DATA8);
-#else
- readb(&REG_NAND_DATA8);
-#endif
- numToRead--;
- }
-
- if (pageSize == NAND_DATA_ACCESS_SIZE) {
- /* read ECC bytes before BI */
- nand_bcm_umi_bch_resume_read_ecc_calc();
-
- while (numToRead > 11) {
-#if defined(__KERNEL__) && !defined(STANDALONE)
- *oobp = readb(&REG_NAND_DATA8);
- eccCalc[eccPos++] = *oobp;
- oobp++;
-#else
- eccCalc[eccPos++] = readb(&REG_NAND_DATA8);
-#endif
- numToRead--;
- }
-
- nand_bcm_umi_bch_pause_read_ecc_calc();
-
- if (numToRead == 11) {
- /* read BI */
-#if defined(__KERNEL__) && !defined(STANDALONE)
- *oobp++ = readb(&REG_NAND_DATA8);
-#else
- readb(&REG_NAND_DATA8);
-#endif
- numToRead--;
- }
-
- }
- /* read ECC bytes */
- nand_bcm_umi_bch_resume_read_ecc_calc();
- while (numToRead) {
-#if defined(__KERNEL__) && !defined(STANDALONE)
- *oobp = readb(&REG_NAND_DATA8);
- eccCalc[eccPos++] = *oobp;
- oobp++;
-#else
- eccCalc[eccPos++] = readb(&REG_NAND_DATA8);
-#endif
- numToRead--;
- }
-}
-
-/* Helper function to write ECC */
-static inline void NAND_BCM_UMI_ECC_WRITE(int numEccBytes, int eccBytePos,
- uint8_t *oobp, uint8_t eccVal)
-{
- if (eccBytePos <= numEccBytes)
- *oobp = eccVal;
-}
-
-/* Write OOB with ECC */
-static inline void nand_bcm_umi_bch_write_oobEcc(uint32_t pageSize,
- uint8_t *oobp, int numEccBytes)
-{
- uint32_t eccVal = 0xffffffff;
-
- /* wait for write ECC to be valid */
- nand_bcm_umi_bch_poll_write_ecc_calc();
-
- /*
- ** Get the hardware ecc from the 32-bit result registers.
- ** Read after 512 byte accesses. Format B3B2B1B0
- ** where B3 = ecc3, etc.
- */
-
- if (pageSize == NAND_DATA_ACCESS_SIZE) {
- /* Now fill in the ECC bytes */
- if (numEccBytes >= 13)
- eccVal = readl(&REG_UMI_BCH_WR_ECC_3);
-
- /* Usually we skip CM in oob[0,1] */
- NAND_BCM_UMI_ECC_WRITE(numEccBytes, 15, &oobp[0],
- (eccVal >> 16) & 0xff);
- NAND_BCM_UMI_ECC_WRITE(numEccBytes, 14, &oobp[1],
- (eccVal >> 8) & 0xff);
-
- /* Write ECC in oob[2,3,4] */
- NAND_BCM_UMI_ECC_WRITE(numEccBytes, 13, &oobp[2],
- eccVal & 0xff); /* ECC 12 */
-
- if (numEccBytes >= 9)
- eccVal = readl(&REG_UMI_BCH_WR_ECC_2);
-
- NAND_BCM_UMI_ECC_WRITE(numEccBytes, 12, &oobp[3],
- (eccVal >> 24) & 0xff); /* ECC11 */
- NAND_BCM_UMI_ECC_WRITE(numEccBytes, 11, &oobp[4],
- (eccVal >> 16) & 0xff); /* ECC10 */
-
- /* Always Skip BI in oob[5] */
- } else {
- /* Always Skip BI in oob[0] */
-
- /* Now fill in the ECC bytes */
- if (numEccBytes >= 13)
- eccVal = readl(&REG_UMI_BCH_WR_ECC_3);
-
- /* Usually skip CM in oob[1,2] */
- NAND_BCM_UMI_ECC_WRITE(numEccBytes, 15, &oobp[1],
- (eccVal >> 16) & 0xff);
- NAND_BCM_UMI_ECC_WRITE(numEccBytes, 14, &oobp[2],
- (eccVal >> 8) & 0xff);
-
- /* Write ECC in oob[3-15] */
- NAND_BCM_UMI_ECC_WRITE(numEccBytes, 13, &oobp[3],
- eccVal & 0xff); /* ECC12 */
-
- if (numEccBytes >= 9)
- eccVal = readl(&REG_UMI_BCH_WR_ECC_2);
-
- NAND_BCM_UMI_ECC_WRITE(numEccBytes, 12, &oobp[4],
- (eccVal >> 24) & 0xff); /* ECC11 */
- NAND_BCM_UMI_ECC_WRITE(numEccBytes, 11, &oobp[5],
- (eccVal >> 16) & 0xff); /* ECC10 */
- }
-
- /* Fill in the remainder of ECC locations */
- NAND_BCM_UMI_ECC_WRITE(numEccBytes, 10, &oobp[6],
- (eccVal >> 8) & 0xff); /* ECC9 */
- NAND_BCM_UMI_ECC_WRITE(numEccBytes, 9, &oobp[7],
- eccVal & 0xff); /* ECC8 */
-
- if (numEccBytes >= 5)
- eccVal = readl(&REG_UMI_BCH_WR_ECC_1);
-
- NAND_BCM_UMI_ECC_WRITE(numEccBytes, 8, &oobp[8],
- (eccVal >> 24) & 0xff); /* ECC7 */
- NAND_BCM_UMI_ECC_WRITE(numEccBytes, 7, &oobp[9],
- (eccVal >> 16) & 0xff); /* ECC6 */
- NAND_BCM_UMI_ECC_WRITE(numEccBytes, 6, &oobp[10],
- (eccVal >> 8) & 0xff); /* ECC5 */
- NAND_BCM_UMI_ECC_WRITE(numEccBytes, 5, &oobp[11],
- eccVal & 0xff); /* ECC4 */
-
- if (numEccBytes >= 1)
- eccVal = readl(&REG_UMI_BCH_WR_ECC_0);
-
- NAND_BCM_UMI_ECC_WRITE(numEccBytes, 4, &oobp[12],
- (eccVal >> 24) & 0xff); /* ECC3 */
- NAND_BCM_UMI_ECC_WRITE(numEccBytes, 3, &oobp[13],
- (eccVal >> 16) & 0xff); /* ECC2 */
- NAND_BCM_UMI_ECC_WRITE(numEccBytes, 2, &oobp[14],
- (eccVal >> 8) & 0xff); /* ECC1 */
- NAND_BCM_UMI_ECC_WRITE(numEccBytes, 1, &oobp[15],
- eccVal & 0xff); /* ECC0 */
-}
-#endif
-
-#endif /* NAND_BCM_UMI_H */
diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c
index 621b70b..e3aa274 100644
--- a/drivers/mtd/nand/nand_ids.c
+++ b/drivers/mtd/nand/nand_ids.c
@@ -70,7 +70,7 @@ struct nand_flash_dev nand_flash_ids[] = {
* These are the new chips with large page size. The pagesize and the
* erasesize is determined from the extended id bytes
*/
-#define LP_OPTIONS (NAND_SAMSUNG_LP_OPTIONS | NAND_NO_READRDY)
+#define LP_OPTIONS NAND_SAMSUNG_LP_OPTIONS
#define LP_OPTIONS16 (LP_OPTIONS | NAND_BUSWIDTH_16)
/* 512 Megabit */
@@ -157,7 +157,7 @@ struct nand_flash_dev nand_flash_ids[] = {
* writes possible, but not implemented now
*/
{"AND 128MiB 3,3V 8-bit", 0x01, 2048, 128, 0x4000,
- NAND_IS_AND | NAND_NO_READRDY | NAND_4PAGE_ARRAY | BBT_AUTO_REFRESH},
+ NAND_IS_AND | NAND_4PAGE_ARRAY | BBT_AUTO_REFRESH},
{NULL,}
};
@@ -174,8 +174,9 @@ struct nand_manufacturers nand_manuf_ids[] = {
{NAND_MFR_STMICRO, "ST Micro"},
{NAND_MFR_HYNIX, "Hynix"},
{NAND_MFR_MICRON, "Micron"},
- {NAND_MFR_AMD, "AMD"},
+ {NAND_MFR_AMD, "AMD/Spansion"},
{NAND_MFR_MACRONIX, "Macronix"},
+ {NAND_MFR_EON, "Eon"},
{0x0, "Unknown"}
};
diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c
index cf0cd31..a932c48 100644
--- a/drivers/mtd/nand/nandsim.c
+++ b/drivers/mtd/nand/nandsim.c
@@ -447,8 +447,6 @@ static unsigned int rptwear_cnt = 0;
/* MTD structure for NAND controller */
static struct mtd_info *nsmtd;
-static u_char ns_verify_buf[NS_LARGEST_PAGE_SIZE];
-
/*
* Allocate array of page pointers, create slab allocation for an array
* and initialize the array by NULL pointers.
@@ -2189,19 +2187,6 @@ static void ns_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
return;
}
-static int ns_nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len)
-{
- ns_nand_read_buf(mtd, (u_char *)&ns_verify_buf[0], len);
-
- if (!memcmp(buf, &ns_verify_buf[0], len)) {
- NS_DBG("verify_buf: the buffer is OK\n");
- return 0;
- } else {
- NS_DBG("verify_buf: the buffer is wrong\n");
- return -EFAULT;
- }
-}
-
/*
* Module initialization function
*/
@@ -2236,7 +2221,6 @@ static int __init ns_init_module(void)
chip->dev_ready = ns_device_ready;
chip->write_buf = ns_nand_write_buf;
chip->read_buf = ns_nand_read_buf;
- chip->verify_buf = ns_nand_verify_buf;
chip->read_word = ns_nand_read_word;
chip->ecc.mode = NAND_ECC_SOFT;
/* The NAND_SKIP_BBTSCAN option is necessary for 'overridesize' */
@@ -2333,6 +2317,7 @@ static int __init ns_init_module(void)
uint64_t new_size = (uint64_t)nsmtd->erasesize << overridesize;
if (new_size >> overridesize != nsmtd->erasesize) {
NS_ERR("overridesize is too big\n");
+ retval = -EINVAL;
goto err_exit;
}
/* N.B. This relies on nand_scan not doing anything with the size before we change it */
diff --git a/drivers/mtd/nand/ndfc.c b/drivers/mtd/nand/ndfc.c
index 2b6f632..5fd3f01 100644
--- a/drivers/mtd/nand/ndfc.c
+++ b/drivers/mtd/nand/ndfc.c
@@ -140,18 +140,6 @@ static void ndfc_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
out_be32(ndfc->ndfcbase + NDFC_DATA, *p++);
}
-static int ndfc_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
-{
- struct nand_chip *chip = mtd->priv;
- struct ndfc_controller *ndfc = chip->priv;
- uint32_t *p = (uint32_t *) buf;
-
- for(;len > 0; len -= 4)
- if (*p++ != in_be32(ndfc->ndfcbase + NDFC_DATA))
- return -EFAULT;
- return 0;
-}
-
/*
* Initialize chip structure
*/
@@ -172,7 +160,6 @@ static int ndfc_chip_init(struct ndfc_controller *ndfc,
chip->controller = &ndfc->ndfc_control;
chip->read_buf = ndfc_read_buf;
chip->write_buf = ndfc_write_buf;
- chip->verify_buf = ndfc_verify_buf;
chip->ecc.correct = nand_correct_data;
chip->ecc.hwctl = ndfc_enable_hwecc;
chip->ecc.calculate = ndfc_calculate_ecc;
diff --git a/drivers/mtd/nand/nuc900_nand.c b/drivers/mtd/nand/nuc900_nand.c
index 8febe46..94dc46b 100644
--- a/drivers/mtd/nand/nuc900_nand.c
+++ b/drivers/mtd/nand/nuc900_nand.c
@@ -112,22 +112,6 @@ static void nuc900_nand_write_buf(struct mtd_info *mtd,
write_data_reg(nand, buf[i]);
}
-static int nuc900_verify_buf(struct mtd_info *mtd,
- const unsigned char *buf, int len)
-{
- int i;
- struct nuc900_nand *nand;
-
- nand = container_of(mtd, struct nuc900_nand, mtd);
-
- for (i = 0; i < len; i++) {
- if (buf[i] != (unsigned char)read_data_reg(nand))
- return -EFAULT;
- }
-
- return 0;
-}
-
static int nuc900_check_rb(struct nuc900_nand *nand)
{
unsigned int val;
@@ -292,7 +276,6 @@ static int __devinit nuc900_nand_probe(struct platform_device *pdev)
chip->read_byte = nuc900_nand_read_byte;
chip->write_buf = nuc900_nand_write_buf;
chip->read_buf = nuc900_nand_read_buf;
- chip->verify_buf = nuc900_verify_buf;
chip->chip_delay = 50;
chip->options = 0;
chip->ecc.mode = NAND_ECC_SOFT;
diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
index fc81112..5b31386 100644
--- a/drivers/mtd/nand/omap2.c
+++ b/drivers/mtd/nand/omap2.c
@@ -425,7 +425,7 @@ static void omap_nand_dma_callback(void *data)
}
/*
- * omap_nand_dma_transfer: configer and start dma transfer
+ * omap_nand_dma_transfer: configure and start dma transfer
* @mtd: MTD device structure
* @addr: virtual address in RAM of source/destination
* @len: number of data bytes to be transferred
@@ -546,7 +546,7 @@ static void omap_write_buf_dma_pref(struct mtd_info *mtd,
}
/*
- * omap_nand_irq - GMPC irq handler
+ * omap_nand_irq - GPMC irq handler
* @this_irq: gpmc irq number
* @dev: omap_nand_info structure pointer is passed here
*/
@@ -698,27 +698,6 @@ out_copy:
}
/**
- * omap_verify_buf - Verify chip data against buffer
- * @mtd: MTD device structure
- * @buf: buffer containing the data to compare
- * @len: number of bytes to compare
- */
-static int omap_verify_buf(struct mtd_info *mtd, const u_char * buf, int len)
-{
- struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
- mtd);
- u16 *p = (u16 *) buf;
-
- len >>= 1;
- while (len--) {
- if (*p++ != cpu_to_le16(readw(info->nand.IO_ADDR_R)))
- return -EFAULT;
- }
-
- return 0;
-}
-
-/**
* gen_true_ecc - This function will generate true ECC value
* @ecc_buf: buffer to store ecc code
*
@@ -1326,8 +1305,8 @@ static int __devinit omap_nand_probe(struct platform_device *pdev)
/*
* If RDY/BSY line is connected to OMAP then use the omap ready
- * funcrtion and the generic nand_wait function which reads the status
- * register after monitoring the RDY/BSY line.Otherwise use a standard
+ * function and the generic nand_wait function which reads the status
+ * register after monitoring the RDY/BSY line. Otherwise use a standard
* chip delay which is slightly more than tR (AC Timing) of the NAND
* device and read status register until you get a failure or success
*/
@@ -1428,9 +1407,7 @@ static int __devinit omap_nand_probe(struct platform_device *pdev)
goto out_release_mem_region;
}
- info->nand.verify_buf = omap_verify_buf;
-
- /* selsect the ecc type */
+ /* select the ecc type */
if (pdata->ecc_opt == OMAP_ECC_HAMMING_CODE_DEFAULT)
info->nand.ecc.mode = NAND_ECC_SOFT;
else if ((pdata->ecc_opt == OMAP_ECC_HAMMING_CODE_HW) ||
@@ -1536,7 +1513,8 @@ static int omap_nand_remove(struct platform_device *pdev)
/* Release NAND device, its internal structures and partitions */
nand_release(&info->mtd);
iounmap(info->nand.IO_ADDR_R);
- kfree(&info->mtd);
+ release_mem_region(info->phys_base, NAND_IO_SIZE);
+ kfree(info);
return 0;
}
diff --git a/drivers/mtd/nand/orion_nand.c b/drivers/mtd/nand/orion_nand.c
index 131b58a..aefaf8c 100644
--- a/drivers/mtd/nand/orion_nand.c
+++ b/drivers/mtd/nand/orion_nand.c
@@ -21,7 +21,6 @@
#include <linux/err.h>
#include <asm/io.h>
#include <asm/sizes.h>
-#include <mach/hardware.h>
#include <linux/platform_data/mtd-orion_nand.h>
static void orion_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
diff --git a/drivers/mtd/nand/plat_nand.c b/drivers/mtd/nand/plat_nand.c
index 1bcb520..a47ee68 100644
--- a/drivers/mtd/nand/plat_nand.c
+++ b/drivers/mtd/nand/plat_nand.c
@@ -37,6 +37,11 @@ static int __devinit plat_nand_probe(struct platform_device *pdev)
const char **part_types;
int err = 0;
+ if (!pdata) {
+ dev_err(&pdev->dev, "platform_nand_data is missing\n");
+ return -EINVAL;
+ }
+
if (pdata->chip.nr_chips < 1) {
dev_err(&pdev->dev, "invalid number of chips specified\n");
return -EINVAL;
diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c
index c452271..37ee75c 100644
--- a/drivers/mtd/nand/pxa3xx_nand.c
+++ b/drivers/mtd/nand/pxa3xx_nand.c
@@ -683,11 +683,13 @@ static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command,
info->state = STATE_IDLE;
}
-static void pxa3xx_nand_write_page_hwecc(struct mtd_info *mtd,
+static int pxa3xx_nand_write_page_hwecc(struct mtd_info *mtd,
struct nand_chip *chip, const uint8_t *buf, int oob_required)
{
chip->write_buf(mtd, buf, mtd->writesize);
chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+ return 0;
}
static int pxa3xx_nand_read_page_hwecc(struct mtd_info *mtd,
@@ -771,12 +773,6 @@ static void pxa3xx_nand_write_buf(struct mtd_info *mtd,
info->buf_start += real_len;
}
-static int pxa3xx_nand_verify_buf(struct mtd_info *mtd,
- const uint8_t *buf, int len)
-{
- return 0;
-}
-
static void pxa3xx_nand_select_chip(struct mtd_info *mtd, int chip)
{
return;
@@ -1007,7 +1003,6 @@ KEEP_CONFIG:
chip->ecc.size = host->page_size;
chip->ecc.strength = 1;
- chip->options |= NAND_NO_READRDY;
if (host->reg_ndcr & NDCR_DWIDTH_M)
chip->options |= NAND_BUSWIDTH_16;
@@ -1070,7 +1065,6 @@ static int alloc_nand_resource(struct platform_device *pdev)
chip->read_byte = pxa3xx_nand_read_byte;
chip->read_buf = pxa3xx_nand_read_buf;
chip->write_buf = pxa3xx_nand_write_buf;
- chip->verify_buf = pxa3xx_nand_verify_buf;
}
spin_lock_init(&chip->controller->lock);
diff --git a/drivers/mtd/nand/r852.c b/drivers/mtd/nand/r852.c
index 8cb6277..4495f85 100644
--- a/drivers/mtd/nand/r852.c
+++ b/drivers/mtd/nand/r852.c
@@ -309,27 +309,6 @@ static uint8_t r852_read_byte(struct mtd_info *mtd)
return r852_read_reg(dev, R852_DATALINE);
}
-
-/*
- * Readback the buffer to verify it
- */
-int r852_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
-{
- struct r852_device *dev = r852_get_dev(mtd);
-
- /* We can't be sure about anything here... */
- if (dev->card_unstable)
- return -1;
-
- /* This will never happen, unless you wired up a nand chip
- with > 512 bytes page size to the reader */
- if (len > SM_SECTOR_SIZE)
- return 0;
-
- r852_read_buf(mtd, dev->tmp_buffer, len);
- return memcmp(buf, dev->tmp_buffer, len);
-}
-
/*
* Control several chip lines & send commands
*/
@@ -882,7 +861,6 @@ int r852_probe(struct pci_dev *pci_dev, const struct pci_device_id *id)
chip->read_byte = r852_read_byte;
chip->read_buf = r852_read_buf;
chip->write_buf = r852_write_buf;
- chip->verify_buf = r852_verify_buf;
/* ecc */
chip->ecc.mode = NAND_ECC_HW_SYNDROME;
diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c
index d804061..295e4be 100644
--- a/drivers/mtd/nand/s3c2410.c
+++ b/drivers/mtd/nand/s3c2410.c
@@ -21,6 +21,8 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#define pr_fmt(fmt) "nand-s3c2410: " fmt
+
#ifdef CONFIG_MTD_NAND_S3C2410_DEBUG
#define DEBUG
#endif
@@ -30,6 +32,7 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/string.h>
+#include <linux/io.h>
#include <linux/ioport.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
@@ -43,24 +46,9 @@
#include <linux/mtd/nand_ecc.h>
#include <linux/mtd/partitions.h>
-#include <asm/io.h>
-
#include <plat/regs-nand.h>
#include <linux/platform_data/mtd-nand-s3c2410.h>
-#ifdef CONFIG_MTD_NAND_S3C2410_HWECC
-static int hardware_ecc = 1;
-#else
-static int hardware_ecc = 0;
-#endif
-
-#ifdef CONFIG_MTD_NAND_S3C2410_CLKSTOP
-static const int clock_stop = 1;
-#else
-static const int clock_stop = 0;
-#endif
-
-
/* new oob placement block for use with hardware ecc generation
*/
@@ -109,9 +97,8 @@ enum s3c_nand_clk_state {
* @mtds: An array of MTD instances on this controoler.
* @platform: The platform data for this board.
* @device: The platform device we bound to.
- * @area: The IO area resource that came from request_mem_region().
* @clk: The clock resource for this controller.
- * @regs: The area mapped for the hardware registers described by @area.
+ * @regs: The area mapped for the hardware registers.
* @sel_reg: Pointer to the register controlling the NAND selection.
* @sel_bit: The bit in @sel_reg to select the NAND chip.
* @mtd_count: The number of MTDs created from this controller.
@@ -128,7 +115,6 @@ struct s3c2410_nand_info {
/* device info */
struct device *device;
- struct resource *area;
struct clk *clk;
void __iomem *regs;
void __iomem *sel_reg;
@@ -169,7 +155,11 @@ static struct s3c2410_platform_nand *to_nand_plat(struct platform_device *dev)
static inline int allow_clk_suspend(struct s3c2410_nand_info *info)
{
- return clock_stop;
+#ifdef CONFIG_MTD_NAND_S3C2410_CLKSTOP
+ return 1;
+#else
+ return 0;
+#endif
}
/**
@@ -215,7 +205,8 @@ static int s3c_nand_calc_rate(int wanted, unsigned long clk, int max)
pr_debug("result %d from %ld, %d\n", result, clk, wanted);
if (result > max) {
- printk("%d ns is too big for current clock rate %ld\n", wanted, clk);
+ pr_err("%d ns is too big for current clock rate %ld\n",
+ wanted, clk);
return -1;
}
@@ -225,7 +216,7 @@ static int s3c_nand_calc_rate(int wanted, unsigned long clk, int max)
return result;
}
-#define to_ns(ticks,clk) (((ticks) * NS_IN_KHZ) / (unsigned int)(clk))
+#define to_ns(ticks, clk) (((ticks) * NS_IN_KHZ) / (unsigned int)(clk))
/* controller setup */
@@ -268,7 +259,8 @@ static int s3c2410_nand_setrate(struct s3c2410_nand_info *info)
}
dev_info(info->device, "Tacls=%d, %dns Twrph0=%d %dns, Twrph1=%d %dns\n",
- tacls, to_ns(tacls, clkrate), twrph0, to_ns(twrph0, clkrate), twrph1, to_ns(twrph1, clkrate));
+ tacls, to_ns(tacls, clkrate), twrph0, to_ns(twrph0, clkrate),
+ twrph1, to_ns(twrph1, clkrate));
switch (info->cpu_type) {
case TYPE_S3C2410:
@@ -325,13 +317,13 @@ static int s3c2410_nand_inithw(struct s3c2410_nand_info *info)
if (ret < 0)
return ret;
- switch (info->cpu_type) {
- case TYPE_S3C2410:
+ switch (info->cpu_type) {
+ case TYPE_S3C2410:
default:
break;
- case TYPE_S3C2440:
- case TYPE_S3C2412:
+ case TYPE_S3C2440:
+ case TYPE_S3C2412:
/* enable the controller and de-assert nFCE */
writel(S3C2440_NFCONT_ENABLE, info->regs + S3C2440_NFCONT);
@@ -450,6 +442,7 @@ static int s3c2412_nand_devready(struct mtd_info *mtd)
/* ECC handling functions */
+#ifdef CONFIG_MTD_NAND_S3C2410_HWECC
static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat,
u_char *read_ecc, u_char *calc_ecc)
{
@@ -463,10 +456,8 @@ static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat,
diff1 = read_ecc[1] ^ calc_ecc[1];
diff2 = read_ecc[2] ^ calc_ecc[2];
- pr_debug("%s: rd %02x%02x%02x calc %02x%02x%02x diff %02x%02x%02x\n",
- __func__,
- read_ecc[0], read_ecc[1], read_ecc[2],
- calc_ecc[0], calc_ecc[1], calc_ecc[2],
+ pr_debug("%s: rd %*phN calc %*phN diff %02x%02x%02x\n",
+ __func__, 3, read_ecc, 3, calc_ecc,
diff0, diff1, diff2);
if (diff0 == 0 && diff1 == 0 && diff2 == 0)
@@ -546,7 +537,8 @@ static void s3c2412_nand_enable_hwecc(struct mtd_info *mtd, int mode)
unsigned long ctrl;
ctrl = readl(info->regs + S3C2440_NFCONT);
- writel(ctrl | S3C2412_NFCONT_INIT_MAIN_ECC, info->regs + S3C2440_NFCONT);
+ writel(ctrl | S3C2412_NFCONT_INIT_MAIN_ECC,
+ info->regs + S3C2440_NFCONT);
}
static void s3c2440_nand_enable_hwecc(struct mtd_info *mtd, int mode)
@@ -558,7 +550,8 @@ static void s3c2440_nand_enable_hwecc(struct mtd_info *mtd, int mode)
writel(ctrl | S3C2440_NFCONT_INITECC, info->regs + S3C2440_NFCONT);
}
-static int s3c2410_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code)
+static int s3c2410_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
+ u_char *ecc_code)
{
struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
@@ -566,13 +559,13 @@ static int s3c2410_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u
ecc_code[1] = readb(info->regs + S3C2410_NFECC + 1);
ecc_code[2] = readb(info->regs + S3C2410_NFECC + 2);
- pr_debug("%s: returning ecc %02x%02x%02x\n", __func__,
- ecc_code[0], ecc_code[1], ecc_code[2]);
+ pr_debug("%s: returning ecc %*phN\n", __func__, 3, ecc_code);
return 0;
}
-static int s3c2412_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code)
+static int s3c2412_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
+ u_char *ecc_code)
{
struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
unsigned long ecc = readl(info->regs + S3C2412_NFMECC0);
@@ -581,12 +574,13 @@ static int s3c2412_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u
ecc_code[1] = ecc >> 8;
ecc_code[2] = ecc >> 16;
- pr_debug("calculate_ecc: returning ecc %02x,%02x,%02x\n", ecc_code[0], ecc_code[1], ecc_code[2]);
+ pr_debug("%s: returning ecc %*phN\n", __func__, 3, ecc_code);
return 0;
}
-static int s3c2440_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code)
+static int s3c2440_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
+ u_char *ecc_code)
{
struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
unsigned long ecc = readl(info->regs + S3C2440_NFMECC0);
@@ -599,6 +593,7 @@ static int s3c2440_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u
return 0;
}
+#endif
/* over-ride the standard functions for a little more speed. We can
* use read/write block to move the data buffers to/from the controller
@@ -625,13 +620,15 @@ static void s3c2440_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
}
}
-static void s3c2410_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
+static void s3c2410_nand_write_buf(struct mtd_info *mtd, const u_char *buf,
+ int len)
{
struct nand_chip *this = mtd->priv;
writesb(this->IO_ADDR_W, buf, len);
}
-static void s3c2440_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
+static void s3c2440_nand_write_buf(struct mtd_info *mtd, const u_char *buf,
+ int len)
{
struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
@@ -675,7 +672,8 @@ static inline int s3c2410_nand_cpufreq_register(struct s3c2410_nand_info *info)
CPUFREQ_TRANSITION_NOTIFIER);
}
-static inline void s3c2410_nand_cpufreq_deregister(struct s3c2410_nand_info *info)
+static inline void
+s3c2410_nand_cpufreq_deregister(struct s3c2410_nand_info *info)
{
cpufreq_unregister_notifier(&info->freq_transition,
CPUFREQ_TRANSITION_NOTIFIER);
@@ -687,7 +685,8 @@ static inline int s3c2410_nand_cpufreq_register(struct s3c2410_nand_info *info)
return 0;
}
-static inline void s3c2410_nand_cpufreq_deregister(struct s3c2410_nand_info *info)
+static inline void
+s3c2410_nand_cpufreq_deregister(struct s3c2410_nand_info *info)
{
}
#endif
@@ -717,29 +716,12 @@ static int s3c24xx_nand_remove(struct platform_device *pdev)
pr_debug("releasing mtd %d (%p)\n", mtdno, ptr);
nand_release(&ptr->mtd);
}
-
- kfree(info->mtds);
}
/* free the common resources */
- if (!IS_ERR(info->clk)) {
+ if (!IS_ERR(info->clk))
s3c2410_nand_clk_set_state(info, CLOCK_DISABLE);
- clk_put(info->clk);
- }
-
- if (info->regs != NULL) {
- iounmap(info->regs);
- info->regs = NULL;
- }
-
- if (info->area != NULL) {
- release_resource(info->area);
- kfree(info->area);
- info->area = NULL;
- }
-
- kfree(info);
return 0;
}
@@ -810,7 +792,7 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
dev_info(info->device, "System booted from NAND\n");
break;
- }
+ }
chip->IO_ADDR_R = chip->IO_ADDR_W;
@@ -819,32 +801,31 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
nmtd->mtd.owner = THIS_MODULE;
nmtd->set = set;
- if (hardware_ecc) {
+#ifdef CONFIG_MTD_NAND_S3C2410_HWECC
+ chip->ecc.calculate = s3c2410_nand_calculate_ecc;
+ chip->ecc.correct = s3c2410_nand_correct_data;
+ chip->ecc.mode = NAND_ECC_HW;
+ chip->ecc.strength = 1;
+
+ switch (info->cpu_type) {
+ case TYPE_S3C2410:
+ chip->ecc.hwctl = s3c2410_nand_enable_hwecc;
chip->ecc.calculate = s3c2410_nand_calculate_ecc;
- chip->ecc.correct = s3c2410_nand_correct_data;
- chip->ecc.mode = NAND_ECC_HW;
- chip->ecc.strength = 1;
-
- switch (info->cpu_type) {
- case TYPE_S3C2410:
- chip->ecc.hwctl = s3c2410_nand_enable_hwecc;
- chip->ecc.calculate = s3c2410_nand_calculate_ecc;
- break;
-
- case TYPE_S3C2412:
- chip->ecc.hwctl = s3c2412_nand_enable_hwecc;
- chip->ecc.calculate = s3c2412_nand_calculate_ecc;
- break;
-
- case TYPE_S3C2440:
- chip->ecc.hwctl = s3c2440_nand_enable_hwecc;
- chip->ecc.calculate = s3c2440_nand_calculate_ecc;
- break;
+ break;
- }
- } else {
- chip->ecc.mode = NAND_ECC_SOFT;
+ case TYPE_S3C2412:
+ chip->ecc.hwctl = s3c2412_nand_enable_hwecc;
+ chip->ecc.calculate = s3c2412_nand_calculate_ecc;
+ break;
+
+ case TYPE_S3C2440:
+ chip->ecc.hwctl = s3c2440_nand_enable_hwecc;
+ chip->ecc.calculate = s3c2440_nand_calculate_ecc;
+ break;
}
+#else
+ chip->ecc.mode = NAND_ECC_SOFT;
+#endif
if (set->ecc_layout != NULL)
chip->ecc.layout = set->ecc_layout;
@@ -921,7 +902,7 @@ static void s3c2410_nand_update_chip(struct s3c2410_nand_info *info,
static int s3c24xx_nand_probe(struct platform_device *pdev)
{
struct s3c2410_platform_nand *plat = to_nand_plat(pdev);
- enum s3c_cpu_type cpu_type;
+ enum s3c_cpu_type cpu_type;
struct s3c2410_nand_info *info;
struct s3c2410_nand_mtd *nmtd;
struct s3c2410_nand_set *sets;
@@ -935,7 +916,7 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
pr_debug("s3c2410_nand_probe(%p)\n", pdev);
- info = kzalloc(sizeof(*info), GFP_KERNEL);
+ info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
if (info == NULL) {
dev_err(&pdev->dev, "no memory for flash info\n");
err = -ENOMEM;
@@ -949,7 +930,7 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
/* get the clock source and enable it */
- info->clk = clk_get(&pdev->dev, "nand");
+ info->clk = devm_clk_get(&pdev->dev, "nand");
if (IS_ERR(info->clk)) {
dev_err(&pdev->dev, "failed to get clock\n");
err = -ENOENT;
@@ -961,22 +942,14 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
/* allocate and map the resource */
/* currently we assume we have the one resource */
- res = pdev->resource;
+ res = pdev->resource;
size = resource_size(res);
- info->area = request_mem_region(res->start, size, pdev->name);
-
- if (info->area == NULL) {
- dev_err(&pdev->dev, "cannot reserve register region\n");
- err = -ENOENT;
- goto exit_error;
- }
-
- info->device = &pdev->dev;
- info->platform = plat;
- info->regs = ioremap(res->start, size);
- info->cpu_type = cpu_type;
+ info->device = &pdev->dev;
+ info->platform = plat;
+ info->cpu_type = cpu_type;
+ info->regs = devm_request_and_ioremap(&pdev->dev, res);
if (info->regs == NULL) {
dev_err(&pdev->dev, "cannot reserve register region\n");
err = -EIO;
@@ -999,7 +972,7 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
/* allocate our information */
size = nr_sets * sizeof(*info->mtds);
- info->mtds = kzalloc(size, GFP_KERNEL);
+ info->mtds = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
if (info->mtds == NULL) {
dev_err(&pdev->dev, "failed to allocate mtd storage\n");
err = -ENOMEM;
@@ -1011,7 +984,8 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
nmtd = info->mtds;
for (setno = 0; setno < nr_sets; setno++, nmtd++) {
- pr_debug("initialising set %d (%p, info %p)\n", setno, nmtd, info);
+ pr_debug("initialising set %d (%p, info %p)\n",
+ setno, nmtd, info);
s3c2410_nand_init_chip(info, nmtd, sets);
@@ -1134,20 +1108,7 @@ static struct platform_driver s3c24xx_nand_driver = {
},
};
-static int __init s3c2410_nand_init(void)
-{
- printk("S3C24XX NAND Driver, (c) 2004 Simtec Electronics\n");
-
- return platform_driver_register(&s3c24xx_nand_driver);
-}
-
-static void __exit s3c2410_nand_exit(void)
-{
- platform_driver_unregister(&s3c24xx_nand_driver);
-}
-
-module_init(s3c2410_nand_init);
-module_exit(s3c2410_nand_exit);
+module_platform_driver(s3c24xx_nand_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
diff --git a/drivers/mtd/nand/sh_flctl.c b/drivers/mtd/nand/sh_flctl.c
index aa9b8a5..4fbfe96 100644
--- a/drivers/mtd/nand/sh_flctl.c
+++ b/drivers/mtd/nand/sh_flctl.c
@@ -24,10 +24,12 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/delay.h>
+#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/slab.h>
+#include <linux/string.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
@@ -43,11 +45,17 @@ static struct nand_ecclayout flctl_4secc_oob_16 = {
};
static struct nand_ecclayout flctl_4secc_oob_64 = {
- .eccbytes = 10,
- .eccpos = {48, 49, 50, 51, 52, 53, 54, 55, 56, 57},
+ .eccbytes = 4 * 10,
+ .eccpos = {
+ 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 54, 55, 56, 57, 58, 59, 60, 61, 62, 63 },
.oobfree = {
- {.offset = 60,
- . length = 4} },
+ {.offset = 2, .length = 4},
+ {.offset = 16, .length = 6},
+ {.offset = 32, .length = 6},
+ {.offset = 48, .length = 6} },
};
static uint8_t scan_ff_pattern[] = { 0xff, 0xff };
@@ -61,15 +69,15 @@ static struct nand_bbt_descr flctl_4secc_smallpage = {
static struct nand_bbt_descr flctl_4secc_largepage = {
.options = NAND_BBT_SCAN2NDPAGE,
- .offs = 58,
+ .offs = 0,
.len = 2,
.pattern = scan_ff_pattern,
};
static void empty_fifo(struct sh_flctl *flctl)
{
- writel(0x000c0000, FLINTDMACR(flctl)); /* FIFO Clear */
- writel(0x00000000, FLINTDMACR(flctl)); /* Clear Error flags */
+ writel(flctl->flintdmacr_base | AC1CLR | AC0CLR, FLINTDMACR(flctl));
+ writel(flctl->flintdmacr_base, FLINTDMACR(flctl));
}
static void start_translation(struct sh_flctl *flctl)
@@ -158,27 +166,56 @@ static void wait_wfifo_ready(struct sh_flctl *flctl)
timeout_error(flctl, __func__);
}
-static int wait_recfifo_ready(struct sh_flctl *flctl, int sector_number)
+static enum flctl_ecc_res_t wait_recfifo_ready
+ (struct sh_flctl *flctl, int sector_number)
{
uint32_t timeout = LOOP_TIMEOUT_MAX;
- int checked[4];
void __iomem *ecc_reg[4];
int i;
+ int state = FL_SUCCESS;
uint32_t data, size;
- memset(checked, 0, sizeof(checked));
-
+ /*
+ * First this loops checks in FLDTCNTR if we are ready to read out the
+ * oob data. This is the case if either all went fine without errors or
+ * if the bottom part of the loop corrected the errors or marked them as
+ * uncorrectable and the controller is given time to push the data into
+ * the FIFO.
+ */
while (timeout--) {
+ /* check if all is ok and we can read out the OOB */
size = readl(FLDTCNTR(flctl)) >> 24;
- if (size & 0xFF)
- return 0; /* success */
+ if ((size & 0xFF) == 4)
+ return state;
+
+ /* check if a correction code has been calculated */
+ if (!(readl(FL4ECCCR(flctl)) & _4ECCEND)) {
+ /*
+ * either we wait for the fifo to be filled or a
+ * correction pattern is being generated
+ */
+ udelay(1);
+ continue;
+ }
- if (readl(FL4ECCCR(flctl)) & _4ECCFA)
- return 1; /* can't correct */
+ /* check for an uncorrectable error */
+ if (readl(FL4ECCCR(flctl)) & _4ECCFA) {
+ /* check if we face a non-empty page */
+ for (i = 0; i < 512; i++) {
+ if (flctl->done_buff[i] != 0xff) {
+ state = FL_ERROR; /* can't correct */
+ break;
+ }
+ }
- udelay(1);
- if (!(readl(FL4ECCCR(flctl)) & _4ECCEND))
+ if (state == FL_SUCCESS)
+ dev_dbg(&flctl->pdev->dev,
+ "reading empty sector %d, ecc error ignored\n",
+ sector_number);
+
+ writel(0, FL4ECCCR(flctl));
continue;
+ }
/* start error correction */
ecc_reg[0] = FL4ECCRESULT0(flctl);
@@ -187,28 +224,26 @@ static int wait_recfifo_ready(struct sh_flctl *flctl, int sector_number)
ecc_reg[3] = FL4ECCRESULT3(flctl);
for (i = 0; i < 3; i++) {
+ uint8_t org;
+ int index;
+
data = readl(ecc_reg[i]);
- if (data != INIT_FL4ECCRESULT_VAL && !checked[i]) {
- uint8_t org;
- int index;
-
- if (flctl->page_size)
- index = (512 * sector_number) +
- (data >> 16);
- else
- index = data >> 16;
-
- org = flctl->done_buff[index];
- flctl->done_buff[index] = org ^ (data & 0xFF);
- checked[i] = 1;
- }
- }
+ if (flctl->page_size)
+ index = (512 * sector_number) +
+ (data >> 16);
+ else
+ index = data >> 16;
+
+ org = flctl->done_buff[index];
+ flctl->done_buff[index] = org ^ (data & 0xFF);
+ }
+ state = FL_REPAIRABLE;
writel(0, FL4ECCCR(flctl));
}
timeout_error(flctl, __func__);
- return 1; /* timeout */
+ return FL_TIMEOUT; /* timeout */
}
static void wait_wecfifo_ready(struct sh_flctl *flctl)
@@ -241,31 +276,33 @@ static void read_fiforeg(struct sh_flctl *flctl, int rlen, int offset)
{
int i, len_4align;
unsigned long *buf = (unsigned long *)&flctl->done_buff[offset];
- void *fifo_addr = (void *)FLDTFIFO(flctl);
len_4align = (rlen + 3) / 4;
for (i = 0; i < len_4align; i++) {
wait_rfifo_ready(flctl);
- buf[i] = readl(fifo_addr);
+ buf[i] = readl(FLDTFIFO(flctl));
buf[i] = be32_to_cpu(buf[i]);
}
}
-static int read_ecfiforeg(struct sh_flctl *flctl, uint8_t *buff, int sector)
+static enum flctl_ecc_res_t read_ecfiforeg
+ (struct sh_flctl *flctl, uint8_t *buff, int sector)
{
int i;
+ enum flctl_ecc_res_t res;
unsigned long *ecc_buf = (unsigned long *)buff;
- void *fifo_addr = (void *)FLECFIFO(flctl);
- for (i = 0; i < 4; i++) {
- if (wait_recfifo_ready(flctl , sector))
- return 1;
- ecc_buf[i] = readl(fifo_addr);
- ecc_buf[i] = be32_to_cpu(ecc_buf[i]);
+ res = wait_recfifo_ready(flctl , sector);
+
+ if (res != FL_ERROR) {
+ for (i = 0; i < 4; i++) {
+ ecc_buf[i] = readl(FLECFIFO(flctl));
+ ecc_buf[i] = be32_to_cpu(ecc_buf[i]);
+ }
}
- return 0;
+ return res;
}
static void write_fiforeg(struct sh_flctl *flctl, int rlen, int offset)
@@ -281,6 +318,18 @@ static void write_fiforeg(struct sh_flctl *flctl, int rlen, int offset)
}
}
+static void write_ec_fiforeg(struct sh_flctl *flctl, int rlen, int offset)
+{
+ int i, len_4align;
+ unsigned long *data = (unsigned long *)&flctl->done_buff[offset];
+
+ len_4align = (rlen + 3) / 4;
+ for (i = 0; i < len_4align; i++) {
+ wait_wecfifo_ready(flctl);
+ writel(cpu_to_be32(data[i]), FLECFIFO(flctl));
+ }
+}
+
static void set_cmd_regs(struct mtd_info *mtd, uint32_t cmd, uint32_t flcmcdr_val)
{
struct sh_flctl *flctl = mtd_to_flctl(mtd);
@@ -346,73 +395,65 @@ static void set_cmd_regs(struct mtd_info *mtd, uint32_t cmd, uint32_t flcmcdr_va
static int flctl_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
uint8_t *buf, int oob_required, int page)
{
- int i, eccsize = chip->ecc.size;
- int eccbytes = chip->ecc.bytes;
- int eccsteps = chip->ecc.steps;
- uint8_t *p = buf;
- struct sh_flctl *flctl = mtd_to_flctl(mtd);
-
- for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
- chip->read_buf(mtd, p, eccsize);
-
- for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
- if (flctl->hwecc_cant_correct[i])
- mtd->ecc_stats.failed++;
- else
- mtd->ecc_stats.corrected += 0; /* FIXME */
- }
-
+ chip->read_buf(mtd, buf, mtd->writesize);
+ if (oob_required)
+ chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
return 0;
}
-static void flctl_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
+static int flctl_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
const uint8_t *buf, int oob_required)
{
- int i, eccsize = chip->ecc.size;
- int eccbytes = chip->ecc.bytes;
- int eccsteps = chip->ecc.steps;
- const uint8_t *p = buf;
-
- for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
- chip->write_buf(mtd, p, eccsize);
+ chip->write_buf(mtd, buf, mtd->writesize);
+ chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+ return 0;
}
static void execmd_read_page_sector(struct mtd_info *mtd, int page_addr)
{
struct sh_flctl *flctl = mtd_to_flctl(mtd);
int sector, page_sectors;
+ enum flctl_ecc_res_t ecc_result;
- if (flctl->page_size)
- page_sectors = 4;
- else
- page_sectors = 1;
-
- writel(readl(FLCMNCR(flctl)) | ACM_SACCES_MODE | _4ECCCORRECT,
- FLCMNCR(flctl));
+ page_sectors = flctl->page_size ? 4 : 1;
set_cmd_regs(mtd, NAND_CMD_READ0,
(NAND_CMD_READSTART << 8) | NAND_CMD_READ0);
- for (sector = 0; sector < page_sectors; sector++) {
- int ret;
+ writel(readl(FLCMNCR(flctl)) | ACM_SACCES_MODE | _4ECCCORRECT,
+ FLCMNCR(flctl));
+ writel(readl(FLCMDCR(flctl)) | page_sectors, FLCMDCR(flctl));
+ writel(page_addr << 2, FLADR(flctl));
- empty_fifo(flctl);
- writel(readl(FLCMDCR(flctl)) | 1, FLCMDCR(flctl));
- writel(page_addr << 2 | sector, FLADR(flctl));
+ empty_fifo(flctl);
+ start_translation(flctl);
- start_translation(flctl);
+ for (sector = 0; sector < page_sectors; sector++) {
read_fiforeg(flctl, 512, 512 * sector);
- ret = read_ecfiforeg(flctl,
+ ecc_result = read_ecfiforeg(flctl,
&flctl->done_buff[mtd->writesize + 16 * sector],
sector);
- if (ret)
- flctl->hwecc_cant_correct[sector] = 1;
-
- writel(0x0, FL4ECCCR(flctl));
- wait_completion(flctl);
+ switch (ecc_result) {
+ case FL_REPAIRABLE:
+ dev_info(&flctl->pdev->dev,
+ "applied ecc on page 0x%x", page_addr);
+ flctl->mtd.ecc_stats.corrected++;
+ break;
+ case FL_ERROR:
+ dev_warn(&flctl->pdev->dev,
+ "page 0x%x contains corrupted data\n",
+ page_addr);
+ flctl->mtd.ecc_stats.failed++;
+ break;
+ default:
+ ;
+ }
}
+
+ wait_completion(flctl);
+
writel(readl(FLCMNCR(flctl)) & ~(ACM_SACCES_MODE | _4ECCCORRECT),
FLCMNCR(flctl));
}
@@ -420,30 +461,20 @@ static void execmd_read_page_sector(struct mtd_info *mtd, int page_addr)
static void execmd_read_oob(struct mtd_info *mtd, int page_addr)
{
struct sh_flctl *flctl = mtd_to_flctl(mtd);
+ int page_sectors = flctl->page_size ? 4 : 1;
+ int i;
set_cmd_regs(mtd, NAND_CMD_READ0,
(NAND_CMD_READSTART << 8) | NAND_CMD_READ0);
empty_fifo(flctl);
- if (flctl->page_size) {
- int i;
- /* In case that the page size is 2k */
- for (i = 0; i < 16 * 3; i++)
- flctl->done_buff[i] = 0xFF;
-
- set_addr(mtd, 3 * 528 + 512, page_addr);
- writel(16, FLDTCNTR(flctl));
- start_translation(flctl);
- read_fiforeg(flctl, 16, 16 * 3);
- wait_completion(flctl);
- } else {
- /* In case that the page size is 512b */
- set_addr(mtd, 512, page_addr);
+ for (i = 0; i < page_sectors; i++) {
+ set_addr(mtd, (512 + 16) * i + 512 , page_addr);
writel(16, FLDTCNTR(flctl));
start_translation(flctl);
- read_fiforeg(flctl, 16, 0);
+ read_fiforeg(flctl, 16, 16 * i);
wait_completion(flctl);
}
}
@@ -451,34 +482,26 @@ static void execmd_read_oob(struct mtd_info *mtd, int page_addr)
static void execmd_write_page_sector(struct mtd_info *mtd)
{
struct sh_flctl *flctl = mtd_to_flctl(mtd);
- int i, page_addr = flctl->seqin_page_addr;
+ int page_addr = flctl->seqin_page_addr;
int sector, page_sectors;
- if (flctl->page_size)
- page_sectors = 4;
- else
- page_sectors = 1;
-
- writel(readl(FLCMNCR(flctl)) | ACM_SACCES_MODE, FLCMNCR(flctl));
+ page_sectors = flctl->page_size ? 4 : 1;
set_cmd_regs(mtd, NAND_CMD_PAGEPROG,
(NAND_CMD_PAGEPROG << 8) | NAND_CMD_SEQIN);
- for (sector = 0; sector < page_sectors; sector++) {
- empty_fifo(flctl);
- writel(readl(FLCMDCR(flctl)) | 1, FLCMDCR(flctl));
- writel(page_addr << 2 | sector, FLADR(flctl));
+ empty_fifo(flctl);
+ writel(readl(FLCMNCR(flctl)) | ACM_SACCES_MODE, FLCMNCR(flctl));
+ writel(readl(FLCMDCR(flctl)) | page_sectors, FLCMDCR(flctl));
+ writel(page_addr << 2, FLADR(flctl));
+ start_translation(flctl);
- start_translation(flctl);
+ for (sector = 0; sector < page_sectors; sector++) {
write_fiforeg(flctl, 512, 512 * sector);
-
- for (i = 0; i < 4; i++) {
- wait_wecfifo_ready(flctl); /* wait for write ready */
- writel(0xFFFFFFFF, FLECFIFO(flctl));
- }
- wait_completion(flctl);
+ write_ec_fiforeg(flctl, 16, mtd->writesize + 16 * sector);
}
+ wait_completion(flctl);
writel(readl(FLCMNCR(flctl)) & ~ACM_SACCES_MODE, FLCMNCR(flctl));
}
@@ -488,18 +511,12 @@ static void execmd_write_oob(struct mtd_info *mtd)
int page_addr = flctl->seqin_page_addr;
int sector, page_sectors;
- if (flctl->page_size) {
- sector = 3;
- page_sectors = 4;
- } else {
- sector = 0;
- page_sectors = 1;
- }
+ page_sectors = flctl->page_size ? 4 : 1;
set_cmd_regs(mtd, NAND_CMD_PAGEPROG,
(NAND_CMD_PAGEPROG << 8) | NAND_CMD_SEQIN);
- for (; sector < page_sectors; sector++) {
+ for (sector = 0; sector < page_sectors; sector++) {
empty_fifo(flctl);
set_addr(mtd, sector * 528 + 512, page_addr);
writel(16, FLDTCNTR(flctl)); /* set read size */
@@ -731,10 +748,9 @@ static void flctl_select_chip(struct mtd_info *mtd, int chipnr)
static void flctl_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
{
struct sh_flctl *flctl = mtd_to_flctl(mtd);
- int i, index = flctl->index;
+ int index = flctl->index;
- for (i = 0; i < len; i++)
- flctl->done_buff[index + i] = buf[i];
+ memcpy(&flctl->done_buff[index], buf, len);
flctl->index += len;
}
@@ -763,20 +779,11 @@ static uint16_t flctl_read_word(struct mtd_info *mtd)
static void flctl_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
{
- int i;
-
- for (i = 0; i < len; i++)
- buf[i] = flctl_read_byte(mtd);
-}
-
-static int flctl_verify_buf(struct mtd_info *mtd, const u_char *buf, int len)
-{
- int i;
+ struct sh_flctl *flctl = mtd_to_flctl(mtd);
+ int index = flctl->index;
- for (i = 0; i < len; i++)
- if (buf[i] != flctl_read_byte(mtd))
- return -EFAULT;
- return 0;
+ memcpy(buf, &flctl->done_buff[index], len);
+ flctl->index += len;
}
static int flctl_chip_init_tail(struct mtd_info *mtd)
@@ -831,7 +838,7 @@ static int flctl_chip_init_tail(struct mtd_info *mtd)
chip->ecc.mode = NAND_ECC_HW;
/* 4 symbols ECC enabled */
- flctl->flcmncr_base |= _4ECCEN | ECCPOS2 | ECCPOS_02;
+ flctl->flcmncr_base |= _4ECCEN;
} else {
chip->ecc.mode = NAND_ECC_SOFT;
}
@@ -839,6 +846,16 @@ static int flctl_chip_init_tail(struct mtd_info *mtd)
return 0;
}
+static irqreturn_t flctl_handle_flste(int irq, void *dev_id)
+{
+ struct sh_flctl *flctl = dev_id;
+
+ dev_err(&flctl->pdev->dev, "flste irq: %x\n", readl(FLINTDMACR(flctl)));
+ writel(flctl->flintdmacr_base, FLINTDMACR(flctl));
+
+ return IRQ_HANDLED;
+}
+
static int __devinit flctl_probe(struct platform_device *pdev)
{
struct resource *res;
@@ -847,6 +864,7 @@ static int __devinit flctl_probe(struct platform_device *pdev)
struct nand_chip *nand;
struct sh_flctl_platform_data *pdata;
int ret = -ENXIO;
+ int irq;
pdata = pdev->dev.platform_data;
if (pdata == NULL) {
@@ -872,14 +890,27 @@ static int __devinit flctl_probe(struct platform_device *pdev)
goto err_iomap;
}
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "failed to get flste irq data\n");
+ goto err_flste;
+ }
+
+ ret = request_irq(irq, flctl_handle_flste, IRQF_SHARED, "flste", flctl);
+ if (ret) {
+ dev_err(&pdev->dev, "request interrupt failed.\n");
+ goto err_flste;
+ }
+
platform_set_drvdata(pdev, flctl);
flctl_mtd = &flctl->mtd;
nand = &flctl->chip;
flctl_mtd->priv = nand;
flctl->pdev = pdev;
- flctl->flcmncr_base = pdata->flcmncr_val;
flctl->hwecc = pdata->has_hwecc;
flctl->holden = pdata->use_holden;
+ flctl->flcmncr_base = pdata->flcmncr_val;
+ flctl->flintdmacr_base = flctl->hwecc ? (STERINTE | ECERB) : STERINTE;
/* Set address of hardware control function */
/* 20 us command delay time */
@@ -888,7 +919,6 @@ static int __devinit flctl_probe(struct platform_device *pdev)
nand->read_byte = flctl_read_byte;
nand->write_buf = flctl_write_buf;
nand->read_buf = flctl_read_buf;
- nand->verify_buf = flctl_verify_buf;
nand->select_chip = flctl_select_chip;
nand->cmdfunc = flctl_cmdfunc;
@@ -918,6 +948,9 @@ static int __devinit flctl_probe(struct platform_device *pdev)
err_chip:
pm_runtime_disable(&pdev->dev);
+ free_irq(irq, flctl);
+err_flste:
+ iounmap(flctl->reg);
err_iomap:
kfree(flctl);
return ret;
@@ -929,6 +962,8 @@ static int __devexit flctl_remove(struct platform_device *pdev)
nand_release(&flctl->mtd);
pm_runtime_disable(&pdev->dev);
+ free_irq(platform_get_irq(pdev, 0), flctl);
+ iounmap(flctl->reg);
kfree(flctl);
return 0;
diff --git a/drivers/mtd/nand/socrates_nand.c b/drivers/mtd/nand/socrates_nand.c
index e02b08b..f3f28fa 100644
--- a/drivers/mtd/nand/socrates_nand.c
+++ b/drivers/mtd/nand/socrates_nand.c
@@ -98,24 +98,6 @@ static uint16_t socrates_nand_read_word(struct mtd_info *mtd)
return word;
}
-/**
- * socrates_nand_verify_buf - Verify chip data against buffer
- * @mtd: MTD device structure
- * @buf: buffer containing the data to compare
- * @len: number of bytes to compare
- */
-static int socrates_nand_verify_buf(struct mtd_info *mtd, const u8 *buf,
- int len)
-{
- int i;
-
- for (i = 0; i < len; i++) {
- if (buf[i] != socrates_nand_read_byte(mtd))
- return -EFAULT;
- }
- return 0;
-}
-
/*
* Hardware specific access to control-lines
*/
@@ -201,7 +183,6 @@ static int __devinit socrates_nand_probe(struct platform_device *ofdev)
nand_chip->read_word = socrates_nand_read_word;
nand_chip->write_buf = socrates_nand_write_buf;
nand_chip->read_buf = socrates_nand_read_buf;
- nand_chip->verify_buf = socrates_nand_verify_buf;
nand_chip->dev_ready = socrates_nand_device_ready;
nand_chip->ecc.mode = NAND_ECC_SOFT; /* enable ECC */
diff --git a/drivers/mtd/nand/tmio_nand.c b/drivers/mtd/nand/tmio_nand.c
index 5aa5180..508e9e0 100644
--- a/drivers/mtd/nand/tmio_nand.c
+++ b/drivers/mtd/nand/tmio_nand.c
@@ -256,18 +256,6 @@ static void tmio_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
tmio_ioread16_rep(tmio->fcr + FCR_DATA, buf, len >> 1);
}
-static int
-tmio_nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len)
-{
- struct tmio_nand *tmio = mtd_to_tmio(mtd);
- u16 *p = (u16 *) buf;
-
- for (len >>= 1; len; len--)
- if (*(p++) != tmio_ioread16(tmio->fcr + FCR_DATA))
- return -EFAULT;
- return 0;
-}
-
static void tmio_nand_enable_hwecc(struct mtd_info *mtd, int mode)
{
struct tmio_nand *tmio = mtd_to_tmio(mtd);
@@ -424,7 +412,6 @@ static int tmio_probe(struct platform_device *dev)
nand_chip->read_byte = tmio_nand_read_byte;
nand_chip->write_buf = tmio_nand_write_buf;
nand_chip->read_buf = tmio_nand_read_buf;
- nand_chip->verify_buf = tmio_nand_verify_buf;
/* set eccmode using hardware ECC */
nand_chip->ecc.mode = NAND_ECC_HW;
diff --git a/drivers/mtd/nand/txx9ndfmc.c b/drivers/mtd/nand/txx9ndfmc.c
index 26398dcf..e3d7266 100644
--- a/drivers/mtd/nand/txx9ndfmc.c
+++ b/drivers/mtd/nand/txx9ndfmc.c
@@ -131,18 +131,6 @@ static void txx9ndfmc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
*buf++ = __raw_readl(ndfdtr);
}
-static int txx9ndfmc_verify_buf(struct mtd_info *mtd, const uint8_t *buf,
- int len)
-{
- struct platform_device *dev = mtd_to_platdev(mtd);
- void __iomem *ndfdtr = ndregaddr(dev, TXX9_NDFDTR);
-
- while (len--)
- if (*buf++ != (uint8_t)__raw_readl(ndfdtr))
- return -EFAULT;
- return 0;
-}
-
static void txx9ndfmc_cmd_ctrl(struct mtd_info *mtd, int cmd,
unsigned int ctrl)
{
@@ -346,7 +334,6 @@ static int __init txx9ndfmc_probe(struct platform_device *dev)
chip->read_byte = txx9ndfmc_read_byte;
chip->read_buf = txx9ndfmc_read_buf;
chip->write_buf = txx9ndfmc_write_buf;
- chip->verify_buf = txx9ndfmc_verify_buf;
chip->cmd_ctrl = txx9ndfmc_cmd_ctrl;
chip->dev_ready = txx9ndfmc_dev_ready;
chip->ecc.calculate = txx9ndfmc_calculate_ecc;
diff --git a/drivers/mtd/nand/xway_nand.c b/drivers/mtd/nand/xway_nand.c
new file mode 100644
index 0000000..3f81dc8
--- /dev/null
+++ b/drivers/mtd/nand/xway_nand.c
@@ -0,0 +1,201 @@
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ * Copyright © 2012 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/mtd/nand.h>
+#include <linux/of_gpio.h>
+#include <linux/of_platform.h>
+
+#include <lantiq_soc.h>
+
+/* nand registers */
+#define EBU_ADDSEL1 0x24
+#define EBU_NAND_CON 0xB0
+#define EBU_NAND_WAIT 0xB4
+#define EBU_NAND_ECC0 0xB8
+#define EBU_NAND_ECC_AC 0xBC
+
+/* nand commands */
+#define NAND_CMD_ALE (1 << 2)
+#define NAND_CMD_CLE (1 << 3)
+#define NAND_CMD_CS (1 << 4)
+#define NAND_WRITE_CMD_RESET 0xff
+#define NAND_WRITE_CMD (NAND_CMD_CS | NAND_CMD_CLE)
+#define NAND_WRITE_ADDR (NAND_CMD_CS | NAND_CMD_ALE)
+#define NAND_WRITE_DATA (NAND_CMD_CS)
+#define NAND_READ_DATA (NAND_CMD_CS)
+#define NAND_WAIT_WR_C (1 << 3)
+#define NAND_WAIT_RD (0x1)
+
+/* we need to tel the ebu which addr we mapped the nand to */
+#define ADDSEL1_MASK(x) (x << 4)
+#define ADDSEL1_REGEN 1
+
+/* we need to tell the EBU that we have nand attached and set it up properly */
+#define BUSCON1_SETUP (1 << 22)
+#define BUSCON1_BCGEN_RES (0x3 << 12)
+#define BUSCON1_WAITWRC2 (2 << 8)
+#define BUSCON1_WAITRDC2 (2 << 6)
+#define BUSCON1_HOLDC1 (1 << 4)
+#define BUSCON1_RECOVC1 (1 << 2)
+#define BUSCON1_CMULT4 1
+
+#define NAND_CON_CE (1 << 20)
+#define NAND_CON_OUT_CS1 (1 << 10)
+#define NAND_CON_IN_CS1 (1 << 8)
+#define NAND_CON_PRE_P (1 << 7)
+#define NAND_CON_WP_P (1 << 6)
+#define NAND_CON_SE_P (1 << 5)
+#define NAND_CON_CS_P (1 << 4)
+#define NAND_CON_CSMUX (1 << 1)
+#define NAND_CON_NANDM 1
+
+static void xway_reset_chip(struct nand_chip *chip)
+{
+ unsigned long nandaddr = (unsigned long) chip->IO_ADDR_W;
+ unsigned long flags;
+
+ nandaddr &= ~NAND_WRITE_ADDR;
+ nandaddr |= NAND_WRITE_CMD;
+
+ /* finish with a reset */
+ spin_lock_irqsave(&ebu_lock, flags);
+ writeb(NAND_WRITE_CMD_RESET, (void __iomem *) nandaddr);
+ while ((ltq_ebu_r32(EBU_NAND_WAIT) & NAND_WAIT_WR_C) == 0)
+ ;
+ spin_unlock_irqrestore(&ebu_lock, flags);
+}
+
+static void xway_select_chip(struct mtd_info *mtd, int chip)
+{
+
+ switch (chip) {
+ case -1:
+ ltq_ebu_w32_mask(NAND_CON_CE, 0, EBU_NAND_CON);
+ ltq_ebu_w32_mask(NAND_CON_NANDM, 0, EBU_NAND_CON);
+ break;
+ case 0:
+ ltq_ebu_w32_mask(0, NAND_CON_NANDM, EBU_NAND_CON);
+ ltq_ebu_w32_mask(0, NAND_CON_CE, EBU_NAND_CON);
+ break;
+ default:
+ BUG();
+ }
+}
+
+static void xway_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
+{
+ struct nand_chip *this = mtd->priv;
+ unsigned long nandaddr = (unsigned long) this->IO_ADDR_W;
+ unsigned long flags;
+
+ if (ctrl & NAND_CTRL_CHANGE) {
+ nandaddr &= ~(NAND_WRITE_CMD | NAND_WRITE_ADDR);
+ if (ctrl & NAND_CLE)
+ nandaddr |= NAND_WRITE_CMD;
+ else
+ nandaddr |= NAND_WRITE_ADDR;
+ this->IO_ADDR_W = (void __iomem *) nandaddr;
+ }
+
+ if (cmd != NAND_CMD_NONE) {
+ spin_lock_irqsave(&ebu_lock, flags);
+ writeb(cmd, this->IO_ADDR_W);
+ while ((ltq_ebu_r32(EBU_NAND_WAIT) & NAND_WAIT_WR_C) == 0)
+ ;
+ spin_unlock_irqrestore(&ebu_lock, flags);
+ }
+}
+
+static int xway_dev_ready(struct mtd_info *mtd)
+{
+ return ltq_ebu_r32(EBU_NAND_WAIT) & NAND_WAIT_RD;
+}
+
+static unsigned char xway_read_byte(struct mtd_info *mtd)
+{
+ struct nand_chip *this = mtd->priv;
+ unsigned long nandaddr = (unsigned long) this->IO_ADDR_R;
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&ebu_lock, flags);
+ ret = ltq_r8((void __iomem *)(nandaddr + NAND_READ_DATA));
+ spin_unlock_irqrestore(&ebu_lock, flags);
+
+ return ret;
+}
+
+static int xway_nand_probe(struct platform_device *pdev)
+{
+ struct nand_chip *this = platform_get_drvdata(pdev);
+ unsigned long nandaddr = (unsigned long) this->IO_ADDR_W;
+ const __be32 *cs = of_get_property(pdev->dev.of_node,
+ "lantiq,cs", NULL);
+ u32 cs_flag = 0;
+
+ /* load our CS from the DT. Either we find a valid 1 or default to 0 */
+ if (cs && (*cs == 1))
+ cs_flag = NAND_CON_IN_CS1 | NAND_CON_OUT_CS1;
+
+ /* setup the EBU to run in NAND mode on our base addr */
+ ltq_ebu_w32(CPHYSADDR(nandaddr)
+ | ADDSEL1_MASK(3) | ADDSEL1_REGEN, EBU_ADDSEL1);
+
+ ltq_ebu_w32(BUSCON1_SETUP | BUSCON1_BCGEN_RES | BUSCON1_WAITWRC2
+ | BUSCON1_WAITRDC2 | BUSCON1_HOLDC1 | BUSCON1_RECOVC1
+ | BUSCON1_CMULT4, LTQ_EBU_BUSCON1);
+
+ ltq_ebu_w32(NAND_CON_NANDM | NAND_CON_CSMUX | NAND_CON_CS_P
+ | NAND_CON_SE_P | NAND_CON_WP_P | NAND_CON_PRE_P
+ | cs_flag, EBU_NAND_CON);
+
+ /* finish with a reset */
+ xway_reset_chip(this);
+
+ return 0;
+}
+
+/* allow users to override the partition in DT using the cmdline */
+static const char *part_probes[] = { "cmdlinepart", "ofpart", NULL };
+
+static struct platform_nand_data xway_nand_data = {
+ .chip = {
+ .nr_chips = 1,
+ .chip_delay = 30,
+ .part_probe_types = part_probes,
+ },
+ .ctrl = {
+ .probe = xway_nand_probe,
+ .cmd_ctrl = xway_cmd_ctrl,
+ .dev_ready = xway_dev_ready,
+ .select_chip = xway_select_chip,
+ .read_byte = xway_read_byte,
+ }
+};
+
+/*
+ * Try to find the node inside the DT. If it is available attach out
+ * platform_nand_data
+ */
+static int __init xway_register_nand(void)
+{
+ struct device_node *node;
+ struct platform_device *pdev;
+
+ node = of_find_compatible_node(NULL, NULL, "lantiq,nand-xway");
+ if (!node)
+ return -ENOENT;
+ pdev = of_find_device_by_node(node);
+ if (!pdev)
+ return -EINVAL;
+ pdev->dev.platform_data = &xway_nand_data;
+ of_node_put(node);
+ return 0;
+}
+
+subsys_initcall(xway_register_nand);
diff --git a/drivers/mtd/sm_ftl.c b/drivers/mtd/sm_ftl.c
index 9e2dfd5..8dd6ba5 100644
--- a/drivers/mtd/sm_ftl.c
+++ b/drivers/mtd/sm_ftl.c
@@ -346,7 +346,6 @@ static int sm_write_sector(struct sm_ftl *ftl,
ret = mtd_write_oob(mtd, sm_mkoffset(ftl, zone, block, boffset), &ops);
/* Now we assume that hardware will catch write bitflip errors */
- /* If you are paranoid, use CONFIG_MTD_NAND_VERIFY_WRITE */
if (ret) {
dbg("write to block %d at zone %d, failed with error %d",
diff --git a/drivers/mtd/tests/Makefile b/drivers/mtd/tests/Makefile
index b44dcab..bd0065c0 100644
--- a/drivers/mtd/tests/Makefile
+++ b/drivers/mtd/tests/Makefile
@@ -6,3 +6,4 @@ obj-$(CONFIG_MTD_TESTS) += mtd_stresstest.o
obj-$(CONFIG_MTD_TESTS) += mtd_subpagetest.o
obj-$(CONFIG_MTD_TESTS) += mtd_torturetest.o
obj-$(CONFIG_MTD_TESTS) += mtd_nandecctest.o
+obj-$(CONFIG_MTD_TESTS) += mtd_nandbiterrs.o
diff --git a/drivers/mtd/tests/mtd_nandbiterrs.c b/drivers/mtd/tests/mtd_nandbiterrs.c
new file mode 100644
index 0000000..cc8d62c
--- /dev/null
+++ b/drivers/mtd/tests/mtd_nandbiterrs.c
@@ -0,0 +1,460 @@
+/*
+ * Copyright © 2012 NetCommWireless
+ * Iwo Mergler <Iwo.Mergler@netcommwireless.com.au>
+ *
+ * Test for multi-bit error recovery on a NAND page This mostly tests the
+ * ECC controller / driver.
+ *
+ * There are two test modes:
+ *
+ * 0 - artificially inserting bit errors until the ECC fails
+ * This is the default method and fairly quick. It should
+ * be independent of the quality of the FLASH.
+ *
+ * 1 - re-writing the same pattern repeatedly until the ECC fails.
+ * This method relies on the physics of NAND FLASH to eventually
+ * generate '0' bits if '1' has been written sufficient times.
+ * Depending on the NAND, the first bit errors will appear after
+ * 1000 or more writes and then will usually snowball, reaching the
+ * limits of the ECC quickly.
+ *
+ * The test stops after 10000 cycles, should your FLASH be
+ * exceptionally good and not generate bit errors before that. Try
+ * a different page in that case.
+ *
+ * Please note that neither of these tests will significantly 'use up' any
+ * FLASH endurance. Only a maximum of two erase operations will be performed.
+ *
+ *
+ * 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; see the file COPYING. If not, write to the Free Software
+ * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/mtd/mtd.h>
+#include <linux/err.h>
+#include <linux/mtd/nand.h>
+#include <linux/slab.h>
+
+#define msg(FMT, VA...) pr_info("mtd_nandbiterrs: "FMT, ##VA)
+
+static int dev;
+module_param(dev, int, S_IRUGO);
+MODULE_PARM_DESC(dev, "MTD device number to use");
+
+static unsigned page_offset;
+module_param(page_offset, uint, S_IRUGO);
+MODULE_PARM_DESC(page_offset, "Page number relative to dev start");
+
+static unsigned seed;
+module_param(seed, uint, S_IRUGO);
+MODULE_PARM_DESC(seed, "Random seed");
+
+static int mode;
+module_param(mode, int, S_IRUGO);
+MODULE_PARM_DESC(mode, "0=incremental errors, 1=overwrite test");
+
+static unsigned max_overwrite = 10000;
+
+static loff_t offset; /* Offset of the page we're using. */
+static unsigned eraseblock; /* Eraseblock number for our page. */
+
+/* We assume that the ECC can correct up to a certain number
+ * of biterrors per subpage. */
+static unsigned subsize; /* Size of subpages */
+static unsigned subcount; /* Number of subpages per page */
+
+static struct mtd_info *mtd; /* MTD device */
+
+static uint8_t *wbuffer; /* One page write / compare buffer */
+static uint8_t *rbuffer; /* One page read buffer */
+
+/* 'random' bytes from known offsets */
+static uint8_t hash(unsigned offset)
+{
+ unsigned v = offset;
+ unsigned char c;
+ v ^= 0x7f7edfd3;
+ v = v ^ (v >> 3);
+ v = v ^ (v >> 5);
+ v = v ^ (v >> 13);
+ c = v & 0xFF;
+ /* Reverse bits of result. */
+ c = (c & 0x0F) << 4 | (c & 0xF0) >> 4;
+ c = (c & 0x33) << 2 | (c & 0xCC) >> 2;
+ c = (c & 0x55) << 1 | (c & 0xAA) >> 1;
+ return c;
+}
+
+static int erase_block(void)
+{
+ int err;
+ struct erase_info ei;
+ loff_t addr = eraseblock * mtd->erasesize;
+
+ msg("erase_block\n");
+
+ memset(&ei, 0, sizeof(struct erase_info));
+ ei.mtd = mtd;
+ ei.addr = addr;
+ ei.len = mtd->erasesize;
+
+ err = mtd_erase(mtd, &ei);
+ if (err || ei.state == MTD_ERASE_FAILED) {
+ msg("error %d while erasing\n", err);
+ if (!err)
+ err = -EIO;
+ return err;
+ }
+
+ return 0;
+}
+
+/* Writes wbuffer to page */
+static int write_page(int log)
+{
+ int err = 0;
+ size_t written;
+
+ if (log)
+ msg("write_page\n");
+
+ err = mtd_write(mtd, offset, mtd->writesize, &written, wbuffer);
+ if (err || written != mtd->writesize) {
+ msg("error: write failed at %#llx\n", (long long)offset);
+ if (!err)
+ err = -EIO;
+ }
+
+ return err;
+}
+
+/* Re-writes the data area while leaving the OOB alone. */
+static int rewrite_page(int log)
+{
+ int err = 0;
+ struct mtd_oob_ops ops;
+
+ if (log)
+ msg("rewrite page\n");
+
+ ops.mode = MTD_OPS_RAW; /* No ECC */
+ ops.len = mtd->writesize;
+ ops.retlen = 0;
+ ops.ooblen = 0;
+ ops.oobretlen = 0;
+ ops.ooboffs = 0;
+ ops.datbuf = wbuffer;
+ ops.oobbuf = NULL;
+
+ err = mtd_write_oob(mtd, offset, &ops);
+ if (err || ops.retlen != mtd->writesize) {
+ msg("error: write_oob failed (%d)\n", err);
+ if (!err)
+ err = -EIO;
+ }
+
+ return err;
+}
+
+/* Reads page into rbuffer. Returns number of corrected bit errors (>=0)
+ * or error (<0) */
+static int read_page(int log)
+{
+ int err = 0;
+ size_t read;
+ struct mtd_ecc_stats oldstats;
+
+ if (log)
+ msg("read_page\n");
+
+ /* Saving last mtd stats */
+ memcpy(&oldstats, &mtd->ecc_stats, sizeof(oldstats));
+
+ err = mtd_read(mtd, offset, mtd->writesize, &read, rbuffer);
+ if (err == -EUCLEAN)
+ err = mtd->ecc_stats.corrected - oldstats.corrected;
+
+ if (err < 0 || read != mtd->writesize) {
+ msg("error: read failed at %#llx\n", (long long)offset);
+ if (err >= 0)
+ err = -EIO;
+ }
+
+ return err;
+}
+
+/* Verifies rbuffer against random sequence */
+static int verify_page(int log)
+{
+ unsigned i, errs = 0;
+
+ if (log)
+ msg("verify_page\n");
+
+ for (i = 0; i < mtd->writesize; i++) {
+ if (rbuffer[i] != hash(i+seed)) {
+ msg("Error: page offset %u, expected %02x, got %02x\n",
+ i, hash(i+seed), rbuffer[i]);
+ errs++;
+ }
+ }
+
+ if (errs)
+ return -EIO;
+ else
+ return 0;
+}
+
+#define CBIT(v, n) ((v) & (1 << (n)))
+#define BCLR(v, n) ((v) = (v) & ~(1 << (n)))
+
+/* Finds the first '1' bit in wbuffer starting at offset 'byte'
+ * and sets it to '0'. */
+static int insert_biterror(unsigned byte)
+{
+ int bit;
+
+ while (byte < mtd->writesize) {
+ for (bit = 7; bit >= 0; bit--) {
+ if (CBIT(wbuffer[byte], bit)) {
+ BCLR(wbuffer[byte], bit);
+ msg("Inserted biterror @ %u/%u\n", byte, bit);
+ return 0;
+ }
+ }
+ byte++;
+ }
+ msg("biterror: Failed to find a '1' bit\n");
+ return -EIO;
+}
+
+/* Writes 'random' data to page and then introduces deliberate bit
+ * errors into the page, while verifying each step. */
+static int incremental_errors_test(void)
+{
+ int err = 0;
+ unsigned i;
+ unsigned errs_per_subpage = 0;
+
+ msg("incremental biterrors test\n");
+
+ for (i = 0; i < mtd->writesize; i++)
+ wbuffer[i] = hash(i+seed);
+
+ err = write_page(1);
+ if (err)
+ goto exit;
+
+ while (1) {
+
+ err = rewrite_page(1);
+ if (err)
+ goto exit;
+
+ err = read_page(1);
+ if (err > 0)
+ msg("Read reported %d corrected bit errors\n", err);
+ if (err < 0) {
+ msg("After %d biterrors per subpage, read reported error %d\n",
+ errs_per_subpage, err);
+ err = 0;
+ goto exit;
+ }
+
+ err = verify_page(1);
+ if (err) {
+ msg("ECC failure, read data is incorrect despite read success\n");
+ goto exit;
+ }
+
+ msg("Successfully corrected %d bit errors per subpage\n",
+ errs_per_subpage);
+
+ for (i = 0; i < subcount; i++) {
+ err = insert_biterror(i * subsize);
+ if (err < 0)
+ goto exit;
+ }
+ errs_per_subpage++;
+ }
+
+exit:
+ return err;
+}
+
+
+/* Writes 'random' data to page and then re-writes that same data repeatedly.
+ This eventually develops bit errors (bits written as '1' will slowly become
+ '0'), which are corrected as far as the ECC is capable of. */
+static int overwrite_test(void)
+{
+ int err = 0;
+ unsigned i;
+ unsigned max_corrected = 0;
+ unsigned opno = 0;
+ /* We don't expect more than this many correctable bit errors per
+ * page. */
+ #define MAXBITS 512
+ static unsigned bitstats[MAXBITS]; /* bit error histogram. */
+
+ memset(bitstats, 0, sizeof(bitstats));
+
+ msg("overwrite biterrors test\n");
+
+ for (i = 0; i < mtd->writesize; i++)
+ wbuffer[i] = hash(i+seed);
+
+ err = write_page(1);
+ if (err)
+ goto exit;
+
+ while (opno < max_overwrite) {
+
+ err = rewrite_page(0);
+ if (err)
+ break;
+
+ err = read_page(0);
+ if (err >= 0) {
+ if (err >= MAXBITS) {
+ msg("Implausible number of bit errors corrected\n");
+ err = -EIO;
+ break;
+ }
+ bitstats[err]++;
+ if (err > max_corrected) {
+ max_corrected = err;
+ msg("Read reported %d corrected bit errors\n",
+ err);
+ }
+ } else { /* err < 0 */
+ msg("Read reported error %d\n", err);
+ err = 0;
+ break;
+ }
+
+ err = verify_page(0);
+ if (err) {
+ bitstats[max_corrected] = opno;
+ msg("ECC failure, read data is incorrect despite read success\n");
+ break;
+ }
+
+ opno++;
+ }
+
+ /* At this point bitstats[0] contains the number of ops with no bit
+ * errors, bitstats[1] the number of ops with 1 bit error, etc. */
+ msg("Bit error histogram (%d operations total):\n", opno);
+ for (i = 0; i < max_corrected; i++)
+ msg("Page reads with %3d corrected bit errors: %d\n",
+ i, bitstats[i]);
+
+exit:
+ return err;
+}
+
+static int __init mtd_nandbiterrs_init(void)
+{
+ int err = 0;
+
+ msg("\n");
+ msg("==================================================\n");
+ msg("MTD device: %d\n", dev);
+
+ mtd = get_mtd_device(NULL, dev);
+ if (IS_ERR(mtd)) {
+ err = PTR_ERR(mtd);
+ msg("error: cannot get MTD device\n");
+ goto exit_mtddev;
+ }
+
+ if (mtd->type != MTD_NANDFLASH) {
+ msg("this test requires NAND flash\n");
+ err = -ENODEV;
+ goto exit_nand;
+ }
+
+ msg("MTD device size %llu, eraseblock=%u, page=%u, oob=%u\n",
+ (unsigned long long)mtd->size, mtd->erasesize,
+ mtd->writesize, mtd->oobsize);
+
+ subsize = mtd->writesize >> mtd->subpage_sft;
+ subcount = mtd->writesize / subsize;
+
+ msg("Device uses %d subpages of %d bytes\n", subcount, subsize);
+
+ offset = page_offset * mtd->writesize;
+ eraseblock = mtd_div_by_eb(offset, mtd);
+
+ msg("Using page=%u, offset=%llu, eraseblock=%u\n",
+ page_offset, offset, eraseblock);
+
+ wbuffer = kmalloc(mtd->writesize, GFP_KERNEL);
+ if (!wbuffer) {
+ err = -ENOMEM;
+ goto exit_wbuffer;
+ }
+
+ rbuffer = kmalloc(mtd->writesize, GFP_KERNEL);
+ if (!rbuffer) {
+ err = -ENOMEM;
+ goto exit_rbuffer;
+ }
+
+ err = erase_block();
+ if (err)
+ goto exit_error;
+
+ if (mode == 0)
+ err = incremental_errors_test();
+ else
+ err = overwrite_test();
+
+ if (err)
+ goto exit_error;
+
+ /* We leave the block un-erased in case of test failure. */
+ err = erase_block();
+ if (err)
+ goto exit_error;
+
+ err = -EIO;
+ msg("finished successfully.\n");
+ msg("==================================================\n");
+
+exit_error:
+ kfree(rbuffer);
+exit_rbuffer:
+ kfree(wbuffer);
+exit_wbuffer:
+ /* Nothing */
+exit_nand:
+ put_mtd_device(mtd);
+exit_mtddev:
+ return err;
+}
+
+static void __exit mtd_nandbiterrs_exit(void)
+{
+ return;
+}
+
+module_init(mtd_nandbiterrs_init);
+module_exit(mtd_nandbiterrs_exit);
+
+MODULE_DESCRIPTION("NAND bit error recovery test");
+MODULE_AUTHOR("Iwo Mergler");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/tests/mtd_nandecctest.c b/drivers/mtd/tests/mtd_nandecctest.c
index 70d6d7d..b437fa4 100644
--- a/drivers/mtd/tests/mtd_nandecctest.c
+++ b/drivers/mtd/tests/mtd_nandecctest.c
@@ -4,60 +4,287 @@
#include <linux/random.h>
#include <linux/string.h>
#include <linux/bitops.h>
-#include <linux/jiffies.h>
+#include <linux/slab.h>
#include <linux/mtd/nand_ecc.h>
+/*
+ * Test the implementation for software ECC
+ *
+ * No actual MTD device is needed, So we don't need to warry about losing
+ * important data by human error.
+ *
+ * This covers possible patterns of corruption which can be reliably corrected
+ * or detected.
+ */
+
#if defined(CONFIG_MTD_NAND) || defined(CONFIG_MTD_NAND_MODULE)
-static void inject_single_bit_error(void *data, size_t size)
+struct nand_ecc_test {
+ const char *name;
+ void (*prepare)(void *, void *, void *, void *, const size_t);
+ int (*verify)(void *, void *, void *, const size_t);
+};
+
+/*
+ * The reason for this __change_bit_le() instead of __change_bit() is to inject
+ * bit error properly within the region which is not a multiple of
+ * sizeof(unsigned long) on big-endian systems
+ */
+#ifdef __LITTLE_ENDIAN
+#define __change_bit_le(nr, addr) __change_bit(nr, addr)
+#elif defined(__BIG_ENDIAN)
+#define __change_bit_le(nr, addr) \
+ __change_bit((nr) ^ ((BITS_PER_LONG - 1) & ~0x7), addr)
+#else
+#error "Unknown byte order"
+#endif
+
+static void single_bit_error_data(void *error_data, void *correct_data,
+ size_t size)
{
- unsigned long offset = random32() % (size * BITS_PER_BYTE);
+ unsigned int offset = random32() % (size * BITS_PER_BYTE);
- __change_bit(offset, data);
+ memcpy(error_data, correct_data, size);
+ __change_bit_le(offset, error_data);
}
-static unsigned char data[512];
-static unsigned char error_data[512];
+static void double_bit_error_data(void *error_data, void *correct_data,
+ size_t size)
+{
+ unsigned int offset[2];
+
+ offset[0] = random32() % (size * BITS_PER_BYTE);
+ do {
+ offset[1] = random32() % (size * BITS_PER_BYTE);
+ } while (offset[0] == offset[1]);
-static int nand_ecc_test(const size_t size)
+ memcpy(error_data, correct_data, size);
+
+ __change_bit_le(offset[0], error_data);
+ __change_bit_le(offset[1], error_data);
+}
+
+static unsigned int random_ecc_bit(size_t size)
{
- unsigned char code[3];
- unsigned char error_code[3];
- char testname[30];
+ unsigned int offset = random32() % (3 * BITS_PER_BYTE);
+
+ if (size == 256) {
+ /*
+ * Don't inject a bit error into the insignificant bits (16th
+ * and 17th bit) in ECC code for 256 byte data block
+ */
+ while (offset == 16 || offset == 17)
+ offset = random32() % (3 * BITS_PER_BYTE);
+ }
- BUG_ON(sizeof(data) < size);
+ return offset;
+}
- sprintf(testname, "nand-ecc-%zu", size);
+static void single_bit_error_ecc(void *error_ecc, void *correct_ecc,
+ size_t size)
+{
+ unsigned int offset = random_ecc_bit(size);
- get_random_bytes(data, size);
+ memcpy(error_ecc, correct_ecc, 3);
+ __change_bit_le(offset, error_ecc);
+}
- memcpy(error_data, data, size);
- inject_single_bit_error(error_data, size);
+static void double_bit_error_ecc(void *error_ecc, void *correct_ecc,
+ size_t size)
+{
+ unsigned int offset[2];
- __nand_calculate_ecc(data, size, code);
- __nand_calculate_ecc(error_data, size, error_code);
- __nand_correct_data(error_data, code, error_code, size);
+ offset[0] = random_ecc_bit(size);
+ do {
+ offset[1] = random_ecc_bit(size);
+ } while (offset[0] == offset[1]);
- if (!memcmp(data, error_data, size)) {
- printk(KERN_INFO "mtd_nandecctest: ok - %s\n", testname);
+ memcpy(error_ecc, correct_ecc, 3);
+ __change_bit_le(offset[0], error_ecc);
+ __change_bit_le(offset[1], error_ecc);
+}
+
+static void no_bit_error(void *error_data, void *error_ecc,
+ void *correct_data, void *correct_ecc, const size_t size)
+{
+ memcpy(error_data, correct_data, size);
+ memcpy(error_ecc, correct_ecc, 3);
+}
+
+static int no_bit_error_verify(void *error_data, void *error_ecc,
+ void *correct_data, const size_t size)
+{
+ unsigned char calc_ecc[3];
+ int ret;
+
+ __nand_calculate_ecc(error_data, size, calc_ecc);
+ ret = __nand_correct_data(error_data, error_ecc, calc_ecc, size);
+ if (ret == 0 && !memcmp(correct_data, error_data, size))
return 0;
- }
- printk(KERN_ERR "mtd_nandecctest: not ok - %s\n", testname);
+ return -EINVAL;
+}
+
+static void single_bit_error_in_data(void *error_data, void *error_ecc,
+ void *correct_data, void *correct_ecc, const size_t size)
+{
+ single_bit_error_data(error_data, correct_data, size);
+ memcpy(error_ecc, correct_ecc, 3);
+}
+
+static void single_bit_error_in_ecc(void *error_data, void *error_ecc,
+ void *correct_data, void *correct_ecc, const size_t size)
+{
+ memcpy(error_data, correct_data, size);
+ single_bit_error_ecc(error_ecc, correct_ecc, size);
+}
+
+static int single_bit_error_correct(void *error_data, void *error_ecc,
+ void *correct_data, const size_t size)
+{
+ unsigned char calc_ecc[3];
+ int ret;
- printk(KERN_DEBUG "hexdump of data:\n");
- print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 16, 4,
- data, size, false);
- printk(KERN_DEBUG "hexdump of error data:\n");
- print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 16, 4,
+ __nand_calculate_ecc(error_data, size, calc_ecc);
+ ret = __nand_correct_data(error_data, error_ecc, calc_ecc, size);
+ if (ret == 1 && !memcmp(correct_data, error_data, size))
+ return 0;
+
+ return -EINVAL;
+}
+
+static void double_bit_error_in_data(void *error_data, void *error_ecc,
+ void *correct_data, void *correct_ecc, const size_t size)
+{
+ double_bit_error_data(error_data, correct_data, size);
+ memcpy(error_ecc, correct_ecc, 3);
+}
+
+static void single_bit_error_in_data_and_ecc(void *error_data, void *error_ecc,
+ void *correct_data, void *correct_ecc, const size_t size)
+{
+ single_bit_error_data(error_data, correct_data, size);
+ single_bit_error_ecc(error_ecc, correct_ecc, size);
+}
+
+static void double_bit_error_in_ecc(void *error_data, void *error_ecc,
+ void *correct_data, void *correct_ecc, const size_t size)
+{
+ memcpy(error_data, correct_data, size);
+ double_bit_error_ecc(error_ecc, correct_ecc, size);
+}
+
+static int double_bit_error_detect(void *error_data, void *error_ecc,
+ void *correct_data, const size_t size)
+{
+ unsigned char calc_ecc[3];
+ int ret;
+
+ __nand_calculate_ecc(error_data, size, calc_ecc);
+ ret = __nand_correct_data(error_data, error_ecc, calc_ecc, size);
+
+ return (ret == -1) ? 0 : -EINVAL;
+}
+
+static const struct nand_ecc_test nand_ecc_test[] = {
+ {
+ .name = "no-bit-error",
+ .prepare = no_bit_error,
+ .verify = no_bit_error_verify,
+ },
+ {
+ .name = "single-bit-error-in-data-correct",
+ .prepare = single_bit_error_in_data,
+ .verify = single_bit_error_correct,
+ },
+ {
+ .name = "single-bit-error-in-ecc-correct",
+ .prepare = single_bit_error_in_ecc,
+ .verify = single_bit_error_correct,
+ },
+ {
+ .name = "double-bit-error-in-data-detect",
+ .prepare = double_bit_error_in_data,
+ .verify = double_bit_error_detect,
+ },
+ {
+ .name = "single-bit-error-in-data-and-ecc-detect",
+ .prepare = single_bit_error_in_data_and_ecc,
+ .verify = double_bit_error_detect,
+ },
+ {
+ .name = "double-bit-error-in-ecc-detect",
+ .prepare = double_bit_error_in_ecc,
+ .verify = double_bit_error_detect,
+ },
+};
+
+static void dump_data_ecc(void *error_data, void *error_ecc, void *correct_data,
+ void *correct_ecc, const size_t size)
+{
+ pr_info("hexdump of error data:\n");
+ print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET, 16, 4,
error_data, size, false);
+ print_hex_dump(KERN_INFO, "hexdump of error ecc: ",
+ DUMP_PREFIX_NONE, 16, 1, error_ecc, 3, false);
+
+ pr_info("hexdump of correct data:\n");
+ print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET, 16, 4,
+ correct_data, size, false);
+ print_hex_dump(KERN_INFO, "hexdump of correct ecc: ",
+ DUMP_PREFIX_NONE, 16, 1, correct_ecc, 3, false);
+}
+
+static int nand_ecc_test_run(const size_t size)
+{
+ int i;
+ int err = 0;
+ void *error_data;
+ void *error_ecc;
+ void *correct_data;
+ void *correct_ecc;
- return -1;
+ error_data = kmalloc(size, GFP_KERNEL);
+ error_ecc = kmalloc(3, GFP_KERNEL);
+ correct_data = kmalloc(size, GFP_KERNEL);
+ correct_ecc = kmalloc(3, GFP_KERNEL);
+
+ if (!error_data || !error_ecc || !correct_data || !correct_ecc) {
+ err = -ENOMEM;
+ goto error;
+ }
+
+ get_random_bytes(correct_data, size);
+ __nand_calculate_ecc(correct_data, size, correct_ecc);
+
+ for (i = 0; i < ARRAY_SIZE(nand_ecc_test); i++) {
+ nand_ecc_test[i].prepare(error_data, error_ecc,
+ correct_data, correct_ecc, size);
+ err = nand_ecc_test[i].verify(error_data, error_ecc,
+ correct_data, size);
+
+ if (err) {
+ pr_err("mtd_nandecctest: not ok - %s-%zd\n",
+ nand_ecc_test[i].name, size);
+ dump_data_ecc(error_data, error_ecc,
+ correct_data, correct_ecc, size);
+ break;
+ }
+ pr_info("mtd_nandecctest: ok - %s-%zd\n",
+ nand_ecc_test[i].name, size);
+ }
+error:
+ kfree(error_data);
+ kfree(error_ecc);
+ kfree(correct_data);
+ kfree(correct_ecc);
+
+ return err;
}
#else
-static int nand_ecc_test(const size_t size)
+static int nand_ecc_test_run(const size_t size)
{
return 0;
}
@@ -66,12 +293,13 @@ static int nand_ecc_test(const size_t size)
static int __init ecc_test_init(void)
{
- srandom32(jiffies);
+ int err;
- nand_ecc_test(256);
- nand_ecc_test(512);
+ err = nand_ecc_test_run(256);
+ if (err)
+ return err;
- return 0;
+ return nand_ecc_test_run(512);
}
static void __exit ecc_test_exit(void)
diff --git a/drivers/mtd/tests/mtd_speedtest.c b/drivers/mtd/tests/mtd_speedtest.c
index 2aec4f3..42b0f74 100644
--- a/drivers/mtd/tests/mtd_speedtest.c
+++ b/drivers/mtd/tests/mtd_speedtest.c
@@ -26,6 +26,7 @@
#include <linux/mtd/mtd.h>
#include <linux/slab.h>
#include <linux/sched.h>
+#include <linux/random.h>
#define PRINT_PREF KERN_INFO "mtd_speedtest: "
@@ -47,25 +48,13 @@ static int ebcnt;
static int pgcnt;
static int goodebcnt;
static struct timeval start, finish;
-static unsigned long next = 1;
-
-static inline unsigned int simple_rand(void)
-{
- next = next * 1103515245 + 12345;
- return (unsigned int)((next / 65536) % 32768);
-}
-
-static inline void simple_srand(unsigned long seed)
-{
- next = seed;
-}
static void set_random_data(unsigned char *buf, size_t len)
{
size_t i;
for (i = 0; i < len; ++i)
- buf[i] = simple_rand();
+ buf[i] = random32();
}
static int erase_eraseblock(int ebnum)
@@ -407,7 +396,6 @@ static int __init mtd_speedtest_init(void)
goto out;
}
- simple_srand(1);
set_random_data(iobuf, mtd->erasesize);
err = scan_for_bad_eraseblocks();
diff --git a/drivers/mtd/tests/mtd_stresstest.c b/drivers/mtd/tests/mtd_stresstest.c
index 7b33f22..cb268ce 100644
--- a/drivers/mtd/tests/mtd_stresstest.c
+++ b/drivers/mtd/tests/mtd_stresstest.c
@@ -27,6 +27,7 @@
#include <linux/slab.h>
#include <linux/sched.h>
#include <linux/vmalloc.h>
+#include <linux/random.h>
#define PRINT_PREF KERN_INFO "mtd_stresstest: "
@@ -48,28 +49,13 @@ static int pgsize;
static int bufsize;
static int ebcnt;
static int pgcnt;
-static unsigned long next = 1;
-
-static inline unsigned int simple_rand(void)
-{
- next = next * 1103515245 + 12345;
- return (unsigned int)((next / 65536) % 32768);
-}
-
-static inline void simple_srand(unsigned long seed)
-{
- next = seed;
-}
static int rand_eb(void)
{
- int eb;
+ unsigned int eb;
again:
- if (ebcnt < 32768)
- eb = simple_rand();
- else
- eb = (simple_rand() << 15) | simple_rand();
+ eb = random32();
/* Read or write up 2 eraseblocks at a time - hence 'ebcnt - 1' */
eb %= (ebcnt - 1);
if (bbt[eb])
@@ -79,24 +65,18 @@ again:
static int rand_offs(void)
{
- int offs;
+ unsigned int offs;
- if (bufsize < 32768)
- offs = simple_rand();
- else
- offs = (simple_rand() << 15) | simple_rand();
+ offs = random32();
offs %= bufsize;
return offs;
}
static int rand_len(int offs)
{
- int len;
+ unsigned int len;
- if (bufsize < 32768)
- len = simple_rand();
- else
- len = (simple_rand() << 15) | simple_rand();
+ len = random32();
len %= (bufsize - offs);
return len;
}
@@ -211,7 +191,7 @@ static int do_write(void)
static int do_operation(void)
{
- if (simple_rand() & 1)
+ if (random32() & 1)
return do_read();
else
return do_write();
@@ -302,9 +282,8 @@ static int __init mtd_stresstest_init(void)
}
for (i = 0; i < ebcnt; i++)
offsets[i] = mtd->erasesize;
- simple_srand(current->pid);
for (i = 0; i < bufsize; i++)
- writebuf[i] = simple_rand();
+ writebuf[i] = random32();
err = scan_for_bad_eraseblocks();
if (err)
diff --git a/drivers/net/ethernet/amd/amd8111e.c b/drivers/net/ethernet/amd/amd8111e.c
index 64d0d9c..3491d43 100644
--- a/drivers/net/ethernet/amd/amd8111e.c
+++ b/drivers/net/ethernet/amd/amd8111e.c
@@ -1845,6 +1845,7 @@ static int __devinit amd8111e_probe_one(struct pci_dev *pdev,
if((pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM))==0){
printk(KERN_ERR "amd8111e: No Power Management capability, "
"exiting.\n");
+ err = -ENODEV;
goto err_free_reg;
}
@@ -1852,6 +1853,7 @@ static int __devinit amd8111e_probe_one(struct pci_dev *pdev,
if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) < 0) {
printk(KERN_ERR "amd8111e: DMA not supported,"
"exiting.\n");
+ err = -ENODEV;
goto err_free_reg;
}
diff --git a/drivers/net/ethernet/amd/au1000_eth.c b/drivers/net/ethernet/amd/au1000_eth.c
index 397596b..f195acf 100644
--- a/drivers/net/ethernet/amd/au1000_eth.c
+++ b/drivers/net/ethernet/amd/au1000_eth.c
@@ -1174,8 +1174,10 @@ static int __devinit au1000_probe(struct platform_device *pdev)
snprintf(aup->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x",
pdev->name, aup->mac_id);
aup->mii_bus->irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL);
- if (aup->mii_bus->irq == NULL)
+ if (aup->mii_bus->irq == NULL) {
+ err = -ENOMEM;
goto err_out;
+ }
for (i = 0; i < PHY_MAX_ADDR; ++i)
aup->mii_bus->irq[i] = PHY_POLL;
@@ -1190,7 +1192,8 @@ static int __devinit au1000_probe(struct platform_device *pdev)
goto err_mdiobus_reg;
}
- if (au1000_mii_probe(dev) != 0)
+ err = au1000_mii_probe(dev);
+ if (err != 0)
goto err_out;
pDBfree = NULL;
@@ -1205,6 +1208,7 @@ static int __devinit au1000_probe(struct platform_device *pdev)
}
aup->pDBfree = pDBfree;
+ err = -ENODEV;
for (i = 0; i < NUM_RX_DMA; i++) {
pDB = au1000_GetFreeDB(aup);
if (!pDB)
@@ -1213,6 +1217,8 @@ static int __devinit au1000_probe(struct platform_device *pdev)
aup->rx_dma_ring[i]->buff_stat = (unsigned)pDB->dma_addr;
aup->rx_db_inuse[i] = pDB;
}
+
+ err = -ENODEV;
for (i = 0; i < NUM_TX_DMA; i++) {
pDB = au1000_GetFreeDB(aup);
if (!pDB)
diff --git a/drivers/net/ethernet/calxeda/xgmac.c b/drivers/net/ethernet/calxeda/xgmac.c
index 2b4b4f5..16814b3 100644
--- a/drivers/net/ethernet/calxeda/xgmac.c
+++ b/drivers/net/ethernet/calxeda/xgmac.c
@@ -375,7 +375,6 @@ struct xgmac_priv {
unsigned int tx_tail;
void __iomem *base;
- struct sk_buff_head rx_recycle;
unsigned int dma_buf_sz;
dma_addr_t dma_rx_phy;
dma_addr_t dma_tx_phy;
@@ -672,9 +671,7 @@ static void xgmac_rx_refill(struct xgmac_priv *priv)
p = priv->dma_rx + entry;
if (priv->rx_skbuff[entry] == NULL) {
- skb = __skb_dequeue(&priv->rx_recycle);
- if (skb == NULL)
- skb = netdev_alloc_skb(priv->dev, priv->dma_buf_sz);
+ skb = netdev_alloc_skb(priv->dev, priv->dma_buf_sz);
if (unlikely(skb == NULL))
break;
@@ -887,17 +884,7 @@ static void xgmac_tx_complete(struct xgmac_priv *priv)
desc_get_buf_len(p), DMA_TO_DEVICE);
}
- /*
- * If there's room in the queue (limit it to size)
- * we add this skb back into the pool,
- * if it's the right size.
- */
- if ((skb_queue_len(&priv->rx_recycle) <
- DMA_RX_RING_SZ) &&
- skb_recycle_check(skb, priv->dma_buf_sz))
- __skb_queue_head(&priv->rx_recycle, skb);
- else
- dev_kfree_skb(skb);
+ dev_kfree_skb(skb);
}
if (dma_ring_space(priv->tx_head, priv->tx_tail, DMA_TX_RING_SZ) >
@@ -1016,7 +1003,6 @@ static int xgmac_open(struct net_device *dev)
dev->dev_addr);
}
- skb_queue_head_init(&priv->rx_recycle);
memset(&priv->xstats, 0, sizeof(struct xgmac_extra_stats));
/* Initialize the XGMAC and descriptors */
@@ -1053,7 +1039,6 @@ static int xgmac_stop(struct net_device *dev)
napi_disable(&priv->napi);
writel(0, priv->base + XGMAC_DMA_INTR_ENA);
- skb_queue_purge(&priv->rx_recycle);
/* Disable the MAC core */
xgmac_mac_disable(priv->base);
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
index 31752b2..a4da893 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
@@ -696,6 +696,7 @@ int t4_seeprom_wp(struct adapter *adapter, bool enable);
int get_vpd_params(struct adapter *adapter, struct vpd_params *p);
int t4_load_fw(struct adapter *adapter, const u8 *fw_data, unsigned int size);
unsigned int t4_flash_cfg_addr(struct adapter *adapter);
+int t4_load_cfg(struct adapter *adapter, const u8 *cfg_data, unsigned int size);
int t4_check_fw_version(struct adapter *adapter);
int t4_prep_adapter(struct adapter *adapter);
int t4_port_init(struct adapter *adap, int mbox, int pf, int vf);
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
index 6b9f6bb..604f4f8 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
@@ -443,7 +443,10 @@ int dbfifo_int_thresh = 10; /* 10 == 640 entry threshold */
module_param(dbfifo_int_thresh, int, 0644);
MODULE_PARM_DESC(dbfifo_int_thresh, "doorbell fifo interrupt threshold");
-int dbfifo_drain_delay = 1000; /* usecs to sleep while draining the dbfifo */
+/*
+ * usecs to sleep while draining the dbfifo
+ */
+static int dbfifo_drain_delay = 1000;
module_param(dbfifo_drain_delay, int, 0644);
MODULE_PARM_DESC(dbfifo_drain_delay,
"usecs to sleep while draining the dbfifo");
@@ -636,7 +639,7 @@ static void name_msix_vecs(struct adapter *adap)
static int request_msix_queue_irqs(struct adapter *adap)
{
struct sge *s = &adap->sge;
- int err, ethqidx, ofldqidx = 0, rdmaqidx = 0, msi = 2;
+ int err, ethqidx, ofldqidx = 0, rdmaqidx = 0, msi_index = 2;
err = request_irq(adap->msix_info[1].vec, t4_sge_intr_msix, 0,
adap->msix_info[1].desc, &s->fw_evtq);
@@ -644,56 +647,60 @@ static int request_msix_queue_irqs(struct adapter *adap)
return err;
for_each_ethrxq(s, ethqidx) {
- err = request_irq(adap->msix_info[msi].vec, t4_sge_intr_msix, 0,
- adap->msix_info[msi].desc,
+ err = request_irq(adap->msix_info[msi_index].vec,
+ t4_sge_intr_msix, 0,
+ adap->msix_info[msi_index].desc,
&s->ethrxq[ethqidx].rspq);
if (err)
goto unwind;
- msi++;
+ msi_index++;
}
for_each_ofldrxq(s, ofldqidx) {
- err = request_irq(adap->msix_info[msi].vec, t4_sge_intr_msix, 0,
- adap->msix_info[msi].desc,
+ err = request_irq(adap->msix_info[msi_index].vec,
+ t4_sge_intr_msix, 0,
+ adap->msix_info[msi_index].desc,
&s->ofldrxq[ofldqidx].rspq);
if (err)
goto unwind;
- msi++;
+ msi_index++;
}
for_each_rdmarxq(s, rdmaqidx) {
- err = request_irq(adap->msix_info[msi].vec, t4_sge_intr_msix, 0,
- adap->msix_info[msi].desc,
+ err = request_irq(adap->msix_info[msi_index].vec,
+ t4_sge_intr_msix, 0,
+ adap->msix_info[msi_index].desc,
&s->rdmarxq[rdmaqidx].rspq);
if (err)
goto unwind;
- msi++;
+ msi_index++;
}
return 0;
unwind:
while (--rdmaqidx >= 0)
- free_irq(adap->msix_info[--msi].vec,
+ free_irq(adap->msix_info[--msi_index].vec,
&s->rdmarxq[rdmaqidx].rspq);
while (--ofldqidx >= 0)
- free_irq(adap->msix_info[--msi].vec,
+ free_irq(adap->msix_info[--msi_index].vec,
&s->ofldrxq[ofldqidx].rspq);
while (--ethqidx >= 0)
- free_irq(adap->msix_info[--msi].vec, &s->ethrxq[ethqidx].rspq);
+ free_irq(adap->msix_info[--msi_index].vec,
+ &s->ethrxq[ethqidx].rspq);
free_irq(adap->msix_info[1].vec, &s->fw_evtq);
return err;
}
static void free_msix_queue_irqs(struct adapter *adap)
{
- int i, msi = 2;
+ int i, msi_index = 2;
struct sge *s = &adap->sge;
free_irq(adap->msix_info[1].vec, &s->fw_evtq);
for_each_ethrxq(s, i)
- free_irq(adap->msix_info[msi++].vec, &s->ethrxq[i].rspq);
+ free_irq(adap->msix_info[msi_index++].vec, &s->ethrxq[i].rspq);
for_each_ofldrxq(s, i)
- free_irq(adap->msix_info[msi++].vec, &s->ofldrxq[i].rspq);
+ free_irq(adap->msix_info[msi_index++].vec, &s->ofldrxq[i].rspq);
for_each_rdmarxq(s, i)
- free_irq(adap->msix_info[msi++].vec, &s->rdmarxq[i].rspq);
+ free_irq(adap->msix_info[msi_index++].vec, &s->rdmarxq[i].rspq);
}
/**
@@ -2535,9 +2542,8 @@ static int read_eq_indices(struct adapter *adap, u16 qid, u16 *pidx, u16 *cidx)
ret = t4_mem_win_read_len(adap, addr, (__be32 *)&indices, 8);
if (!ret) {
- indices = be64_to_cpu(indices);
- *cidx = (indices >> 25) & 0xffff;
- *pidx = (indices >> 9) & 0xffff;
+ *cidx = (be64_to_cpu(indices) >> 25) & 0xffff;
+ *pidx = (be64_to_cpu(indices) >> 9) & 0xffff;
}
return ret;
}
@@ -3634,10 +3640,10 @@ static int adap_init0_no_config(struct adapter *adapter, int reset)
* field selections will fit in the 36-bit budget.
*/
if (tp_vlan_pri_map != TP_VLAN_PRI_MAP_DEFAULT) {
- int i, bits = 0;
+ int j, bits = 0;
- for (i = TP_VLAN_PRI_MAP_FIRST; i <= TP_VLAN_PRI_MAP_LAST; i++)
- switch (tp_vlan_pri_map & (1 << i)) {
+ for (j = TP_VLAN_PRI_MAP_FIRST; j <= TP_VLAN_PRI_MAP_LAST; j++)
+ switch (tp_vlan_pri_map & (1 << j)) {
case 0:
/* compressed filter field not enabled */
break;
diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
index 137a244..32eec15 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
@@ -380,9 +380,11 @@ static int t4_mem_win_rw(struct adapter *adap, u32 addr, __be32 *data, int dir)
/* Collecting data 4 bytes at a time upto MEMWIN0_APERTURE */
for (i = 0; i < MEMWIN0_APERTURE; i = i+0x4) {
if (dir)
- *data++ = t4_read_reg(adap, (MEMWIN0_BASE + i));
+ *data++ = (__force __be32) t4_read_reg(adap,
+ (MEMWIN0_BASE + i));
else
- t4_write_reg(adap, (MEMWIN0_BASE + i), *data++);
+ t4_write_reg(adap, (MEMWIN0_BASE + i),
+ (__force u32) *data++);
}
return 0;
@@ -417,7 +419,7 @@ static int t4_memory_rw(struct adapter *adap, int mtype, u32 addr, u32 len,
if ((addr & 0x3) || (len & 0x3))
return -EINVAL;
- data = vmalloc(MEMWIN0_APERTURE/sizeof(__be32));
+ data = vmalloc(MEMWIN0_APERTURE);
if (!data)
return -ENOMEM;
@@ -744,7 +746,7 @@ static int t4_read_flash(struct adapter *adapter, unsigned int addr,
if (ret)
return ret;
if (byte_oriented)
- *data = htonl(*data);
+ *data = (__force __u32) (htonl(*data));
}
return 0;
}
@@ -992,7 +994,7 @@ int t4_load_fw(struct adapter *adap, const u8 *fw_data, unsigned int size)
int ret, addr;
unsigned int i;
u8 first_page[SF_PAGE_SIZE];
- const u32 *p = (const u32 *)fw_data;
+ const __be32 *p = (const __be32 *)fw_data;
const struct fw_hdr *hdr = (const struct fw_hdr *)fw_data;
unsigned int sf_sec_size = adap->params.sf_size / adap->params.sf_nsec;
unsigned int fw_img_start = adap->params.sf_fw_start;
@@ -2315,7 +2317,8 @@ int t4_mem_win_read_len(struct adapter *adap, u32 addr, __be32 *data, int len)
t4_read_reg(adap, PCIE_MEM_ACCESS_OFFSET);
for (i = 0; i < len; i += 4)
- *data++ = t4_read_reg(adap, (MEMWIN0_BASE + off + i));
+ *data++ = (__force __be32) t4_read_reg(adap,
+ (MEMWIN0_BASE + off + i));
return 0;
}
diff --git a/drivers/net/ethernet/dec/tulip/dmfe.c b/drivers/net/ethernet/dec/tulip/dmfe.c
index 4d6fe60..d23755e 100644
--- a/drivers/net/ethernet/dec/tulip/dmfe.c
+++ b/drivers/net/ethernet/dec/tulip/dmfe.c
@@ -446,13 +446,17 @@ static int __devinit dmfe_init_one (struct pci_dev *pdev,
/* Allocate Tx/Rx descriptor memory */
db->desc_pool_ptr = pci_alloc_consistent(pdev, sizeof(struct tx_desc) *
DESC_ALL_CNT + 0x20, &db->desc_pool_dma_ptr);
- if (!db->desc_pool_ptr)
+ if (!db->desc_pool_ptr) {
+ err = -ENOMEM;
goto err_out_res;
+ }
db->buf_pool_ptr = pci_alloc_consistent(pdev, TX_BUF_ALLOC *
TX_DESC_CNT + 4, &db->buf_pool_dma_ptr);
- if (!db->buf_pool_ptr)
+ if (!db->buf_pool_ptr) {
+ err = -ENOMEM;
goto err_out_free_desc;
+ }
db->first_tx_desc = (struct tx_desc *) db->desc_pool_ptr;
db->first_tx_desc_dma = db->desc_pool_dma_ptr;
@@ -462,8 +466,10 @@ static int __devinit dmfe_init_one (struct pci_dev *pdev,
db->chip_id = ent->driver_data;
/* IO type range. */
db->ioaddr = pci_iomap(pdev, 0, 0);
- if (!db->ioaddr)
+ if (!db->ioaddr) {
+ err = -ENOMEM;
goto err_out_free_buf;
+ }
db->chip_revision = pdev->revision;
db->wol_mode = 0;
diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c
index eb3f2cb..d1b6cc5 100644
--- a/drivers/net/ethernet/emulex/benet/be_main.c
+++ b/drivers/net/ethernet/emulex/benet/be_main.c
@@ -2129,8 +2129,11 @@ void be_detect_error(struct be_adapter *adapter)
ue_hi = (ue_hi & ~ue_hi_mask);
}
- if (ue_lo || ue_hi ||
- sliport_status & SLIPORT_STATUS_ERR_MASK) {
+ /* On certain platforms BE hardware can indicate spurious UEs.
+ * Allow the h/w to stop working completely in case of a real UE.
+ * Hence not setting the hw_error for UE detection.
+ */
+ if (sliport_status & SLIPORT_STATUS_ERR_MASK) {
adapter->hw_error = true;
dev_err(&adapter->pdev->dev,
"Error detected in the card\n");
diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c
index a1b52ec..1d03dcd 100644
--- a/drivers/net/ethernet/freescale/gianfar.c
+++ b/drivers/net/ethernet/freescale/gianfar.c
@@ -1765,7 +1765,6 @@ static void free_skb_resources(struct gfar_private *priv)
sizeof(struct rxbd8) * priv->total_rx_ring_size,
priv->tx_queue[0]->tx_bd_base,
priv->tx_queue[0]->tx_bd_dma_base);
- skb_queue_purge(&priv->rx_recycle);
}
void gfar_start(struct net_device *dev)
@@ -1943,8 +1942,6 @@ static int gfar_enet_open(struct net_device *dev)
enable_napi(priv);
- skb_queue_head_init(&priv->rx_recycle);
-
/* Initialize a bunch of registers */
init_registers(dev);
@@ -2533,16 +2530,7 @@ static int gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue)
bytes_sent += skb->len;
- /* If there's room in the queue (limit it to rx_buffer_size)
- * we add this skb back into the pool, if it's the right size
- */
- if (skb_queue_len(&priv->rx_recycle) < rx_queue->rx_ring_size &&
- skb_recycle_check(skb, priv->rx_buffer_size +
- RXBUF_ALIGNMENT)) {
- gfar_align_skb(skb);
- skb_queue_head(&priv->rx_recycle, skb);
- } else
- dev_kfree_skb_any(skb);
+ dev_kfree_skb_any(skb);
tx_queue->tx_skbuff[skb_dirtytx] = NULL;
@@ -2608,7 +2596,7 @@ static void gfar_new_rxbdp(struct gfar_priv_rx_q *rx_queue, struct rxbd8 *bdp,
static struct sk_buff *gfar_alloc_skb(struct net_device *dev)
{
struct gfar_private *priv = netdev_priv(dev);
- struct sk_buff *skb = NULL;
+ struct sk_buff *skb;
skb = netdev_alloc_skb(dev, priv->rx_buffer_size + RXBUF_ALIGNMENT);
if (!skb)
@@ -2621,14 +2609,7 @@ static struct sk_buff *gfar_alloc_skb(struct net_device *dev)
struct sk_buff *gfar_new_skb(struct net_device *dev)
{
- struct gfar_private *priv = netdev_priv(dev);
- struct sk_buff *skb = NULL;
-
- skb = skb_dequeue(&priv->rx_recycle);
- if (!skb)
- skb = gfar_alloc_skb(dev);
-
- return skb;
+ return gfar_alloc_skb(dev);
}
static inline void count_errors(unsigned short status, struct net_device *dev)
@@ -2787,7 +2768,7 @@ int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit)
if (unlikely(!newskb))
newskb = skb;
else if (skb)
- skb_queue_head(&priv->rx_recycle, skb);
+ dev_kfree_skb(skb);
} else {
/* Increment the number of packets */
rx_queue->stats.rx_packets++;
diff --git a/drivers/net/ethernet/freescale/gianfar.h b/drivers/net/ethernet/freescale/gianfar.h
index 4141ef2..22eabc1 100644
--- a/drivers/net/ethernet/freescale/gianfar.h
+++ b/drivers/net/ethernet/freescale/gianfar.h
@@ -1080,8 +1080,6 @@ struct gfar_private {
u32 cur_filer_idx;
- struct sk_buff_head rx_recycle;
-
/* RX queue filer rule set*/
struct ethtool_rx_list rx_list;
struct mutex rx_queue_access;
diff --git a/drivers/net/ethernet/freescale/ucc_geth.c b/drivers/net/ethernet/freescale/ucc_geth.c
index 1642884..0a70bb5 100644
--- a/drivers/net/ethernet/freescale/ucc_geth.c
+++ b/drivers/net/ethernet/freescale/ucc_geth.c
@@ -209,14 +209,12 @@ static struct list_head *dequeue(struct list_head *lh)
static struct sk_buff *get_new_skb(struct ucc_geth_private *ugeth,
u8 __iomem *bd)
{
- struct sk_buff *skb = NULL;
+ struct sk_buff *skb;
- skb = __skb_dequeue(&ugeth->rx_recycle);
+ skb = netdev_alloc_skb(ugeth->ndev,
+ ugeth->ug_info->uf_info.max_rx_buf_length +
+ UCC_GETH_RX_DATA_BUF_ALIGNMENT);
if (!skb)
- skb = netdev_alloc_skb(ugeth->ndev,
- ugeth->ug_info->uf_info.max_rx_buf_length +
- UCC_GETH_RX_DATA_BUF_ALIGNMENT);
- if (skb == NULL)
return NULL;
/* We need the data buffer to be aligned properly. We will reserve
@@ -2020,8 +2018,6 @@ static void ucc_geth_memclean(struct ucc_geth_private *ugeth)
iounmap(ugeth->ug_regs);
ugeth->ug_regs = NULL;
}
-
- skb_queue_purge(&ugeth->rx_recycle);
}
static void ucc_geth_set_multi(struct net_device *dev)
@@ -2230,8 +2226,6 @@ static int ucc_struct_init(struct ucc_geth_private *ugeth)
return -ENOMEM;
}
- skb_queue_head_init(&ugeth->rx_recycle);
-
return 0;
}
@@ -3274,12 +3268,7 @@ static int ucc_geth_rx(struct ucc_geth_private *ugeth, u8 rxQ, int rx_work_limit
if (netif_msg_rx_err(ugeth))
ugeth_err("%s, %d: ERROR!!! skb - 0x%08x",
__func__, __LINE__, (u32) skb);
- if (skb) {
- skb->data = skb->head + NET_SKB_PAD;
- skb->len = 0;
- skb_reset_tail_pointer(skb);
- __skb_queue_head(&ugeth->rx_recycle, skb);
- }
+ dev_kfree_skb(skb);
ugeth->rx_skbuff[rxQ][ugeth->skb_currx[rxQ]] = NULL;
dev->stats.rx_dropped++;
@@ -3349,13 +3338,7 @@ static int ucc_geth_tx(struct net_device *dev, u8 txQ)
dev->stats.tx_packets++;
- if (skb_queue_len(&ugeth->rx_recycle) < RX_BD_RING_LEN &&
- skb_recycle_check(skb,
- ugeth->ug_info->uf_info.max_rx_buf_length +
- UCC_GETH_RX_DATA_BUF_ALIGNMENT))
- __skb_queue_head(&ugeth->rx_recycle, skb);
- else
- dev_kfree_skb(skb);
+ dev_kfree_skb(skb);
ugeth->tx_skbuff[txQ][ugeth->skb_dirtytx[txQ]] = NULL;
ugeth->skb_dirtytx[txQ] =
diff --git a/drivers/net/ethernet/freescale/ucc_geth.h b/drivers/net/ethernet/freescale/ucc_geth.h
index f71b3e7..75f3371 100644
--- a/drivers/net/ethernet/freescale/ucc_geth.h
+++ b/drivers/net/ethernet/freescale/ucc_geth.h
@@ -1214,8 +1214,6 @@ struct ucc_geth_private {
/* index of the first skb which hasn't been transmitted yet. */
u16 skb_dirtytx[NUM_TX_QUEUES];
- struct sk_buff_head rx_recycle;
-
struct ugeth_mii_info *mii_info;
struct phy_device *phydev;
phy_interface_t phy_interface;
diff --git a/drivers/net/ethernet/intel/e1000e/hw.h b/drivers/net/ethernet/intel/e1000e/hw.h
index ed5b409..d37bfd9 100644
--- a/drivers/net/ethernet/intel/e1000e/hw.h
+++ b/drivers/net/ethernet/intel/e1000e/hw.h
@@ -412,6 +412,8 @@ enum e1e_registers {
#define E1000_DEV_ID_PCH2_LV_V 0x1503
#define E1000_DEV_ID_PCH_LPT_I217_LM 0x153A
#define E1000_DEV_ID_PCH_LPT_I217_V 0x153B
+#define E1000_DEV_ID_PCH_LPTLP_I218_LM 0x155A
+#define E1000_DEV_ID_PCH_LPTLP_I218_V 0x1559
#define E1000_REVISION_4 4
diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c
index fb659dd..de57a2b 100644
--- a/drivers/net/ethernet/intel/e1000e/netdev.c
+++ b/drivers/net/ethernet/intel/e1000e/netdev.c
@@ -6558,6 +6558,8 @@ static DEFINE_PCI_DEVICE_TABLE(e1000_pci_tbl) = {
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_LPT_I217_LM), board_pch_lpt },
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_LPT_I217_V), board_pch_lpt },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_LPTLP_I218_LM), board_pch_lpt },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_LPTLP_I218_V), board_pch_lpt },
{ 0, 0, 0, 0, 0, 0, 0 } /* terminate list */
};
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe.h b/drivers/net/ethernet/intel/ixgbe/ixgbe.h
index 5bd2676..30efc9f 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe.h
@@ -410,7 +410,7 @@ static inline u16 ixgbe_desc_unused(struct ixgbe_ring *ring)
#define IXGBE_TX_CTXTDESC(R, i) \
(&(((struct ixgbe_adv_tx_context_desc *)((R)->desc))[i]))
-#define IXGBE_MAX_JUMBO_FRAME_SIZE 16128
+#define IXGBE_MAX_JUMBO_FRAME_SIZE 9728 /* Maximum Supported Size 9.5KB */
#ifdef IXGBE_FCOE
/* Use 3K as the baby jumbo frame size for FCoE */
#define IXGBE_FCOE_JUMBO_FRAME_SIZE 3072
diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf.h b/drivers/net/ethernet/intel/ixgbevf/ixgbevf.h
index 383b4e1..4a9c9c2 100644
--- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf.h
+++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf.h
@@ -175,7 +175,7 @@ struct ixgbevf_q_vector {
#define IXGBEVF_TX_CTXTDESC(R, i) \
(&(((struct ixgbe_adv_tx_context_desc *)((R)->desc))[i]))
-#define IXGBE_MAX_JUMBO_FRAME_SIZE 16128
+#define IXGBE_MAX_JUMBO_FRAME_SIZE 9728 /* Maximum Supported Size 9.5KB */
#define OTHER_VECTOR 1
#define NON_Q_VECTORS (OTHER_VECTOR)
diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c
index 0ee9bd4..de1ad50 100644
--- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c
+++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c
@@ -1747,6 +1747,7 @@ err_tx_ring_allocation:
**/
static int ixgbevf_set_interrupt_capability(struct ixgbevf_adapter *adapter)
{
+ struct net_device *netdev = adapter->netdev;
int err = 0;
int vector, v_budget;
@@ -1775,6 +1776,12 @@ static int ixgbevf_set_interrupt_capability(struct ixgbevf_adapter *adapter)
ixgbevf_acquire_msix_vectors(adapter, v_budget);
+ err = netif_set_real_num_tx_queues(netdev, adapter->num_tx_queues);
+ if (err)
+ goto out;
+
+ err = netif_set_real_num_rx_queues(netdev, adapter->num_rx_queues);
+
out:
return err;
}
diff --git a/drivers/net/ethernet/marvell/mv643xx_eth.c b/drivers/net/ethernet/marvell/mv643xx_eth.c
index 087b9e0..84c1326 100644
--- a/drivers/net/ethernet/marvell/mv643xx_eth.c
+++ b/drivers/net/ethernet/marvell/mv643xx_eth.c
@@ -412,7 +412,6 @@ struct mv643xx_eth_private {
u8 work_rx_refill;
int skb_size;
- struct sk_buff_head rx_recycle;
/*
* RX state.
@@ -673,9 +672,7 @@ static int rxq_refill(struct rx_queue *rxq, int budget)
struct rx_desc *rx_desc;
int size;
- skb = __skb_dequeue(&mp->rx_recycle);
- if (skb == NULL)
- skb = netdev_alloc_skb(mp->dev, mp->skb_size);
+ skb = netdev_alloc_skb(mp->dev, mp->skb_size);
if (skb == NULL) {
mp->oom = 1;
@@ -989,14 +986,7 @@ static int txq_reclaim(struct tx_queue *txq, int budget, int force)
desc->byte_cnt, DMA_TO_DEVICE);
}
- if (skb != NULL) {
- if (skb_queue_len(&mp->rx_recycle) <
- mp->rx_ring_size &&
- skb_recycle_check(skb, mp->skb_size))
- __skb_queue_head(&mp->rx_recycle, skb);
- else
- dev_kfree_skb(skb);
- }
+ dev_kfree_skb(skb);
}
__netif_tx_unlock(nq);
@@ -2349,8 +2339,6 @@ static int mv643xx_eth_open(struct net_device *dev)
napi_enable(&mp->napi);
- skb_queue_head_init(&mp->rx_recycle);
-
mp->int_mask = INT_EXT;
for (i = 0; i < mp->rxq_count; i++) {
@@ -2445,8 +2433,6 @@ static int mv643xx_eth_stop(struct net_device *dev)
mib_counters_update(mp);
del_timer_sync(&mp->mib_counters_timer);
- skb_queue_purge(&mp->rx_recycle);
-
for (i = 0; i < mp->rxq_count; i++)
rxq_deinit(mp->rxq + i);
for (i = 0; i < mp->txq_count; i++)
diff --git a/drivers/net/ethernet/marvell/skge.c b/drivers/net/ethernet/marvell/skge.c
index 5a30bf8..9b9c2ac 100644
--- a/drivers/net/ethernet/marvell/skge.c
+++ b/drivers/net/ethernet/marvell/skge.c
@@ -3189,7 +3189,7 @@ static int skge_poll(struct napi_struct *napi, int to_do)
if (work_done < to_do) {
unsigned long flags;
- napi_gro_flush(napi);
+ napi_gro_flush(napi, false);
spin_lock_irqsave(&hw->hw_lock, flags);
__napi_complete(napi);
hw->intr_mask |= napimask[skge->port];
@@ -3945,8 +3945,10 @@ static int __devinit skge_probe(struct pci_dev *pdev,
skge_board_name(hw), hw->chip_rev);
dev = skge_devinit(hw, 0, using_dac);
- if (!dev)
+ if (!dev) {
+ err = -ENOMEM;
goto err_out_led_off;
+ }
/* Some motherboards are broken and has zero in ROM. */
if (!is_valid_ether_addr(dev->dev_addr))
@@ -4153,6 +4155,13 @@ static struct dmi_system_id skge_32bit_dma_boards[] = {
DMI_MATCH(DMI_BOARD_NAME, "nForce"),
},
},
+ {
+ .ident = "ASUS P5NSLI",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
+ DMI_MATCH(DMI_BOARD_NAME, "P5NSLI")
+ },
+ },
{}
};
diff --git a/drivers/net/ethernet/marvell/sky2.c b/drivers/net/ethernet/marvell/sky2.c
index 2b0748d..78946fe 100644
--- a/drivers/net/ethernet/marvell/sky2.c
+++ b/drivers/net/ethernet/marvell/sky2.c
@@ -4924,6 +4924,7 @@ static int __devinit sky2_probe(struct pci_dev *pdev,
if (~reg == 0) {
dev_err(&pdev->dev, "PCI configuration read error\n");
+ err = -EIO;
goto err_out;
}
@@ -4993,8 +4994,10 @@ static int __devinit sky2_probe(struct pci_dev *pdev,
hw->st_size = hw->ports * roundup_pow_of_two(3*RX_MAX_PENDING + TX_MAX_PENDING);
hw->st_le = pci_alloc_consistent(pdev, hw->st_size * sizeof(struct sky2_status_le),
&hw->st_dma);
- if (!hw->st_le)
+ if (!hw->st_le) {
+ err = -ENOMEM;
goto err_out_reset;
+ }
dev_info(&pdev->dev, "Yukon-2 %s chip revision %d\n",
sky2_name(hw->chip_id, buf1, sizeof(buf1)), hw->chip_rev);
diff --git a/drivers/net/ethernet/natsemi/natsemi.c b/drivers/net/ethernet/natsemi/natsemi.c
index 5b61d12..dbaaa99 100644
--- a/drivers/net/ethernet/natsemi/natsemi.c
+++ b/drivers/net/ethernet/natsemi/natsemi.c
@@ -947,8 +947,8 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev,
i = register_netdev(dev);
if (i)
goto err_register_netdev;
-
- if (NATSEMI_CREATE_FILE(pdev, dspcfg_workaround))
+ i = NATSEMI_CREATE_FILE(pdev, dspcfg_workaround);
+ if (i)
goto err_create_file;
if (netif_msg_drv(np)) {
diff --git a/drivers/net/ethernet/natsemi/xtsonic.c b/drivers/net/ethernet/natsemi/xtsonic.c
index e01c0a0..7dfe883 100644
--- a/drivers/net/ethernet/natsemi/xtsonic.c
+++ b/drivers/net/ethernet/natsemi/xtsonic.c
@@ -205,6 +205,7 @@ static int __init sonic_probe1(struct net_device *dev)
if (lp->descriptors == NULL) {
printk(KERN_ERR "%s: couldn't alloc DMA memory for "
" descriptors.\n", dev_name(lp->device));
+ err = -ENOMEM;
goto out;
}
diff --git a/drivers/net/ethernet/oki-semi/pch_gbe/Kconfig b/drivers/net/ethernet/oki-semi/pch_gbe/Kconfig
index 9730241..5296cc8 100644
--- a/drivers/net/ethernet/oki-semi/pch_gbe/Kconfig
+++ b/drivers/net/ethernet/oki-semi/pch_gbe/Kconfig
@@ -26,6 +26,9 @@ if PCH_GBE
config PCH_PTP
bool "PCH PTP clock support"
default n
+ depends on EXPERIMENTAL
+ select PPS
+ select PTP_1588_CLOCK
select PTP_1588_CLOCK_PCH
---help---
Say Y here if you want to use Precision Time Protocol (PTP) in the
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
index 473ce13..24ad17e 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
@@ -1601,7 +1601,8 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
adapter->netdev = netdev;
adapter->pdev = pdev;
- if (qlcnic_alloc_adapter_resources(adapter))
+ err = qlcnic_alloc_adapter_resources(adapter);
+ if (err)
goto err_out_free_netdev;
adapter->dev_rst_time = jiffies;
diff --git a/drivers/net/ethernet/realtek/8139cp.c b/drivers/net/ethernet/realtek/8139cp.c
index 995d0cf..1c81825 100644
--- a/drivers/net/ethernet/realtek/8139cp.c
+++ b/drivers/net/ethernet/realtek/8139cp.c
@@ -563,7 +563,7 @@ rx_next:
if (cpr16(IntrStatus) & cp_rx_intr_mask)
goto rx_status_loop;
- napi_gro_flush(napi);
+ napi_gro_flush(napi, false);
spin_lock_irqsave(&cp->lock, flags);
__napi_complete(napi);
cpw16_f(IntrMask, cp_intr_mask);
diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c
index bad8f2e..c8bfea0 100644
--- a/drivers/net/ethernet/renesas/sh_eth.c
+++ b/drivers/net/ethernet/renesas/sh_eth.c
@@ -2438,6 +2438,7 @@ static int sh_eth_drv_probe(struct platform_device *pdev)
rtsu = platform_get_resource(pdev, IORESOURCE_MEM, 1);
if (!rtsu) {
dev_err(&pdev->dev, "Not found TSU resource\n");
+ ret = -ENODEV;
goto out_release;
}
mdp->tsu_addr = ioremap(rtsu->start,
diff --git a/drivers/net/ethernet/sfc/ptp.c b/drivers/net/ethernet/sfc/ptp.c
index 5b3dd02..0767043f 100644
--- a/drivers/net/ethernet/sfc/ptp.c
+++ b/drivers/net/ethernet/sfc/ptp.c
@@ -640,8 +640,7 @@ static void efx_ptp_drop_time_expired_events(struct efx_nic *efx)
evt = list_entry(cursor, struct efx_ptp_event_rx,
link);
if (time_after(jiffies, evt->expiry)) {
- list_del(&evt->link);
- list_add(&evt->link, &ptp->evt_free_list);
+ list_move(&evt->link, &ptp->evt_free_list);
netif_warn(efx, hw, efx->net_dev,
"PTP rx event dropped\n");
}
@@ -684,8 +683,7 @@ static enum ptp_packet_state efx_ptp_match_rx(struct efx_nic *efx,
match->state = PTP_PACKET_STATE_MATCHED;
rc = PTP_PACKET_STATE_MATCHED;
- list_del(&evt->link);
- list_add(&evt->link, &ptp->evt_free_list);
+ list_move(&evt->link, &ptp->evt_free_list);
break;
}
}
@@ -820,8 +818,7 @@ static int efx_ptp_stop(struct efx_nic *efx)
/* Drop any pending receive events */
spin_lock_bh(&efx->ptp_data->evt_lock);
list_for_each_safe(cursor, next, &efx->ptp_data->evt_list) {
- list_del(cursor);
- list_add(cursor, &efx->ptp_data->evt_free_list);
+ list_move(cursor, &efx->ptp_data->evt_free_list);
}
spin_unlock_bh(&efx->ptp_data->evt_lock);
diff --git a/drivers/net/ethernet/sis/sis900.c b/drivers/net/ethernet/sis/sis900.c
index 203d9c6..fb9f6b3 100644
--- a/drivers/net/ethernet/sis/sis900.c
+++ b/drivers/net/ethernet/sis/sis900.c
@@ -478,8 +478,10 @@ static int __devinit sis900_probe(struct pci_dev *pci_dev,
/* IO region. */
ioaddr = pci_iomap(pci_dev, 0, 0);
- if (!ioaddr)
+ if (!ioaddr) {
+ ret = -ENOMEM;
goto err_out_cleardev;
+ }
sis_priv = netdev_priv(net_dev);
sis_priv->ioaddr = ioaddr;
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
index e872e1d..7d51a65 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
@@ -50,7 +50,6 @@ struct stmmac_priv {
unsigned int dirty_rx;
struct sk_buff **rx_skbuff;
dma_addr_t *rx_skbuff_dma;
- struct sk_buff_head rx_recycle;
struct net_device *dev;
dma_addr_t dma_rx_phy;
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 3be8833..c6cdbc4 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -747,18 +747,7 @@ static void stmmac_tx(struct stmmac_priv *priv)
priv->hw->ring->clean_desc3(p);
if (likely(skb != NULL)) {
- /*
- * If there's room in the queue (limit it to size)
- * we add this skb back into the pool,
- * if it's the right size.
- */
- if ((skb_queue_len(&priv->rx_recycle) <
- priv->dma_rx_size) &&
- skb_recycle_check(skb, priv->dma_buf_sz))
- __skb_queue_head(&priv->rx_recycle, skb);
- else
- dev_kfree_skb(skb);
-
+ dev_kfree_skb(skb);
priv->tx_skbuff[entry] = NULL;
}
@@ -1169,7 +1158,6 @@ static int stmmac_open(struct net_device *dev)
priv->eee_enabled = stmmac_eee_init(priv);
napi_enable(&priv->napi);
- skb_queue_head_init(&priv->rx_recycle);
netif_start_queue(dev);
return 0;
@@ -1222,7 +1210,6 @@ static int stmmac_release(struct net_device *dev)
kfree(priv->tm);
#endif
napi_disable(&priv->napi);
- skb_queue_purge(&priv->rx_recycle);
/* Free the IRQ lines */
free_irq(dev->irq, dev);
@@ -1388,10 +1375,7 @@ static inline void stmmac_rx_refill(struct stmmac_priv *priv)
if (likely(priv->rx_skbuff[entry] == NULL)) {
struct sk_buff *skb;
- skb = __skb_dequeue(&priv->rx_recycle);
- if (skb == NULL)
- skb = netdev_alloc_skb_ip_align(priv->dev,
- bfsize);
+ skb = netdev_alloc_skb_ip_align(priv->dev, bfsize);
if (unlikely(skb == NULL))
break;
diff --git a/drivers/net/ethernet/sun/niu.c b/drivers/net/ethernet/sun/niu.c
index 8419bf3..275b430 100644
--- a/drivers/net/ethernet/sun/niu.c
+++ b/drivers/net/ethernet/sun/niu.c
@@ -9788,6 +9788,7 @@ static int __devinit niu_pci_init_one(struct pci_dev *pdev,
if (!pci_is_pcie(pdev)) {
dev_err(&pdev->dev, "Cannot find PCI Express capability, aborting\n");
+ err = -ENODEV;
goto err_out_free_res;
}
diff --git a/drivers/net/ethernet/sun/sungem.c b/drivers/net/ethernet/sun/sungem.c
index 9ae12d0..6c8695e 100644
--- a/drivers/net/ethernet/sun/sungem.c
+++ b/drivers/net/ethernet/sun/sungem.c
@@ -2963,7 +2963,8 @@ static int __devinit gem_init_one(struct pci_dev *pdev,
goto err_out_iounmap;
}
- if (gem_get_device_address(gp))
+ err = gem_get_device_address(gp);
+ if (err)
goto err_out_free_consistent;
dev->netdev_ops = &gem_netdev_ops;
diff --git a/drivers/net/irda/irtty-sir.c b/drivers/net/irda/irtty-sir.c
index 30087ca..6e4d4b6 100644
--- a/drivers/net/irda/irtty-sir.c
+++ b/drivers/net/irda/irtty-sir.c
@@ -459,8 +459,10 @@ static int irtty_open(struct tty_struct *tty)
/* allocate private device info block */
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
- if (!priv)
+ if (!priv) {
+ ret = -ENOMEM;
goto out_put;
+ }
priv->magic = IRTTY_MAGIC;
priv->tty = tty;
diff --git a/drivers/net/irda/mcs7780.c b/drivers/net/irda/mcs7780.c
index 1a00b59..f07c340 100644
--- a/drivers/net/irda/mcs7780.c
+++ b/drivers/net/irda/mcs7780.c
@@ -920,8 +920,10 @@ static int mcs_probe(struct usb_interface *intf,
ndev->netdev_ops = &mcs_netdev_ops;
- if (!intf->cur_altsetting)
+ if (!intf->cur_altsetting) {
+ ret = -ENOMEM;
goto error2;
+ }
ret = mcs_find_endpoints(mcs, intf->cur_altsetting->endpoint,
intf->cur_altsetting->desc.bNumEndpoints);
diff --git a/drivers/net/irda/pxaficp_ir.c b/drivers/net/irda/pxaficp_ir.c
index 002a442..858de05 100644
--- a/drivers/net/irda/pxaficp_ir.c
+++ b/drivers/net/irda/pxaficp_ir.c
@@ -846,8 +846,10 @@ static int pxa_irda_probe(struct platform_device *pdev)
goto err_mem_2;
dev = alloc_irdadev(sizeof(struct pxa_irda));
- if (!dev)
+ if (!dev) {
+ err = -ENOMEM;
goto err_mem_3;
+ }
SET_NETDEV_DEV(dev, &pdev->dev);
si = netdev_priv(dev);
diff --git a/drivers/net/irda/sa1100_ir.c b/drivers/net/irda/sa1100_ir.c
index e250675..42fde9e 100644
--- a/drivers/net/irda/sa1100_ir.c
+++ b/drivers/net/irda/sa1100_ir.c
@@ -940,8 +940,10 @@ static int sa1100_irda_probe(struct platform_device *pdev)
goto err_mem_3;
dev = alloc_irdadev(sizeof(struct sa1100_irda));
- if (!dev)
+ if (!dev) {
+ err = -ENOMEM;
goto err_mem_4;
+ }
SET_NETDEV_DEV(dev, &pdev->dev);
diff --git a/drivers/net/irda/sh_irda.c b/drivers/net/irda/sh_irda.c
index eb315b8..4b746d9 100644
--- a/drivers/net/irda/sh_irda.c
+++ b/drivers/net/irda/sh_irda.c
@@ -808,8 +808,8 @@ static int __devinit sh_irda_probe(struct platform_device *pdev)
goto err_mem_4;
platform_set_drvdata(pdev, ndev);
-
- if (request_irq(irq, sh_irda_irq, IRQF_DISABLED, "sh_irda", self)) {
+ err = request_irq(irq, sh_irda_irq, IRQF_DISABLED, "sh_irda", self);
+ if (err) {
dev_warn(&pdev->dev, "Unable to attach sh_irda interrupt\n");
goto err_mem_4;
}
diff --git a/drivers/net/irda/sh_sir.c b/drivers/net/irda/sh_sir.c
index 7951094..624ac19 100644
--- a/drivers/net/irda/sh_sir.c
+++ b/drivers/net/irda/sh_sir.c
@@ -741,6 +741,7 @@ static int __devinit sh_sir_probe(struct platform_device *pdev)
self->clk = clk_get(&pdev->dev, clk_name);
if (IS_ERR(self->clk)) {
dev_err(&pdev->dev, "cannot get clock \"%s\"\n", clk_name);
+ err = -ENODEV;
goto err_mem_3;
}
@@ -760,8 +761,8 @@ static int __devinit sh_sir_probe(struct platform_device *pdev)
goto err_mem_4;
platform_set_drvdata(pdev, ndev);
-
- if (request_irq(irq, sh_sir_irq, IRQF_DISABLED, "sh_sir", self)) {
+ err = request_irq(irq, sh_sir_irq, IRQF_DISABLED, "sh_sir", self);
+ if (err) {
dev_warn(&pdev->dev, "Unable to attach sh_sir interrupt\n");
goto err_mem_4;
}
diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c
index 170eb41..c1ef300 100644
--- a/drivers/net/phy/mdio_bus.c
+++ b/drivers/net/phy/mdio_bus.c
@@ -26,6 +26,7 @@
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/of_device.h>
+#include <linux/of_mdio.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c
index 51de9ed..8be9bf0 100644
--- a/drivers/net/vxlan.c
+++ b/drivers/net/vxlan.c
@@ -28,7 +28,6 @@
#include <linux/igmp.h>
#include <linux/etherdevice.h>
#include <linux/if_ether.h>
-#include <linux/version.h>
#include <linux/hash.h>
#include <net/ip.h>
#include <net/icmp.h>
@@ -1084,13 +1083,13 @@ static int vxlan_fill_info(struct sk_buff *skb, const struct net_device *dev)
if (nla_put_u32(skb, IFLA_VXLAN_ID, vxlan->vni))
goto nla_put_failure;
- if (vxlan->gaddr && nla_put_u32(skb, IFLA_VXLAN_GROUP, vxlan->gaddr))
+ if (vxlan->gaddr && nla_put_be32(skb, IFLA_VXLAN_GROUP, vxlan->gaddr))
goto nla_put_failure;
if (vxlan->link && nla_put_u32(skb, IFLA_VXLAN_LINK, vxlan->link))
goto nla_put_failure;
- if (vxlan->saddr && nla_put_u32(skb, IFLA_VXLAN_LOCAL, vxlan->saddr))
+ if (vxlan->saddr && nla_put_be32(skb, IFLA_VXLAN_LOCAL, vxlan->saddr))
goto nla_put_failure;
if (nla_put_u8(skb, IFLA_VXLAN_TTL, vxlan->ttl) ||
diff --git a/drivers/net/wan/farsync.c b/drivers/net/wan/farsync.c
index 1a62318..b627132 100644
--- a/drivers/net/wan/farsync.c
+++ b/drivers/net/wan/farsync.c
@@ -597,7 +597,7 @@ fst_q_work_item(u64 * queue, int card_index)
* bottom half for the card. Note the limitation of 64 cards.
* That ought to be enough
*/
- mask = 1 << card_index;
+ mask = (u64)1 << card_index;
*queue |= mask;
spin_unlock_irqrestore(&fst_work_q_lock, flags);
}
diff --git a/drivers/power/avs/smartreflex.c b/drivers/power/avs/smartreflex.c
index d4957b4..24768a2 100644
--- a/drivers/power/avs/smartreflex.c
+++ b/drivers/power/avs/smartreflex.c
@@ -930,7 +930,7 @@ static int __init omap_sr_probe(struct platform_device *pdev)
if (!sr_info->base) {
dev_err(&pdev->dev, "%s: ioremap fail\n", __func__);
ret = -ENOMEM;
- goto err_release_region;
+ goto err_free_name;
}
if (irq)
@@ -969,7 +969,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_free_name;
+ goto err_debugfs;
}
(void) debugfs_create_file("autocomp", S_IRUGO | S_IWUSR,
@@ -1013,11 +1013,11 @@ static int __init omap_sr_probe(struct platform_device *pdev)
err_debugfs:
debugfs_remove_recursive(sr_info->dbg_dir);
-err_free_name:
- kfree(sr_info->name);
err_iounmap:
list_del(&sr_info->node);
iounmap(sr_info->base);
+err_free_name:
+ kfree(sr_info->name);
err_release_region:
release_mem_region(mem->start, resource_size(mem));
err_free_devinfo:
diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
index d7c6b83..ed81720 100644
--- a/drivers/pwm/Kconfig
+++ b/drivers/pwm/Kconfig
@@ -1,6 +1,5 @@
menuconfig PWM
bool "Pulse-Width Modulation (PWM) Support"
- depends on !MACH_JZ4740 && !PUV3_PWM
help
Generic Pulse-Width Modulation (PWM) support.
@@ -29,6 +28,15 @@ menuconfig PWM
if PWM
+config PWM_AB8500
+ tristate "AB8500 PWM support"
+ depends on AB8500_CORE && ARCH_U8500
+ help
+ Generic PWM framework driver for Analog Baseband AB8500.
+
+ To compile this driver as a module, choose M here: the module
+ will be called pwm-ab8500.
+
config PWM_BFIN
tristate "Blackfin PWM support"
depends on BFIN_GPTIMERS
@@ -47,6 +55,16 @@ config PWM_IMX
To compile this driver as a module, choose M here: the module
will be called pwm-imx.
+config PWM_JZ4740
+ tristate "Ingenic JZ4740 PWM support"
+ depends on MACH_JZ4740
+ help
+ Generic PWM framework driver for Ingenic JZ4740 based
+ machines.
+
+ To compile this driver as a module, choose M here: the module
+ will be called pwm-jz4740.
+
config PWM_LPC32XX
tristate "LPC32XX PWM support"
depends on ARCH_LPC32XX
@@ -67,6 +85,15 @@ config PWM_MXS
To compile this driver as a module, choose M here: the module
will be called pwm-mxs.
+config PWM_PUV3
+ tristate "PKUnity NetBook-0916 PWM support"
+ depends on ARCH_PUV3
+ help
+ Generic PWM framework driver for PKUnity NetBook-0916.
+
+ To compile this driver as a module, choose M here: the module
+ will be called pwm-puv3.
+
config PWM_PXA
tristate "PXA PWM support"
depends on ARCH_PXA
diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
index 78f123d..acfe482 100644
--- a/drivers/pwm/Makefile
+++ b/drivers/pwm/Makefile
@@ -1,8 +1,11 @@
obj-$(CONFIG_PWM) += core.o
+obj-$(CONFIG_PWM_AB8500) += pwm-ab8500.o
obj-$(CONFIG_PWM_BFIN) += pwm-bfin.o
obj-$(CONFIG_PWM_IMX) += pwm-imx.o
+obj-$(CONFIG_PWM_JZ4740) += pwm-jz4740.o
obj-$(CONFIG_PWM_LPC32XX) += pwm-lpc32xx.o
obj-$(CONFIG_PWM_MXS) += pwm-mxs.o
+obj-$(CONFIG_PWM_PUV3) += pwm-puv3.o
obj-$(CONFIG_PWM_PXA) += pwm-pxa.o
obj-$(CONFIG_PWM_SAMSUNG) += pwm-samsung.o
obj-$(CONFIG_PWM_TEGRA) += pwm-tegra.o
diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c
index c6e0507..f5acdaa 100644
--- a/drivers/pwm/core.c
+++ b/drivers/pwm/core.c
@@ -371,7 +371,7 @@ EXPORT_SYMBOL_GPL(pwm_free);
*/
int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
{
- if (!pwm || period_ns == 0 || duty_ns > period_ns)
+ if (!pwm || duty_ns < 0 || period_ns <= 0 || duty_ns > period_ns)
return -EINVAL;
return pwm->chip->ops->config(pwm->chip, pwm, duty_ns, period_ns);
@@ -379,6 +379,28 @@ int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
EXPORT_SYMBOL_GPL(pwm_config);
/**
+ * pwm_set_polarity() - configure the polarity of a PWM signal
+ * @pwm: PWM device
+ * @polarity: new polarity of the PWM signal
+ *
+ * Note that the polarity cannot be configured while the PWM device is enabled
+ */
+int pwm_set_polarity(struct pwm_device *pwm, enum pwm_polarity polarity)
+{
+ if (!pwm || !pwm->chip->ops)
+ return -EINVAL;
+
+ if (!pwm->chip->ops->set_polarity)
+ return -ENOSYS;
+
+ if (test_bit(PWMF_ENABLED, &pwm->flags))
+ return -EBUSY;
+
+ return pwm->chip->ops->set_polarity(pwm->chip, pwm, polarity);
+}
+EXPORT_SYMBOL_GPL(pwm_set_polarity);
+
+/**
* pwm_enable() - start a PWM output toggling
* @pwm: PWM device
*/
@@ -624,6 +646,64 @@ out:
}
EXPORT_SYMBOL_GPL(pwm_put);
+static void devm_pwm_release(struct device *dev, void *res)
+{
+ pwm_put(*(struct pwm_device **)res);
+}
+
+/**
+ * devm_pwm_get() - resource managed pwm_get()
+ * @dev: device for PWM consumer
+ * @con_id: consumer name
+ *
+ * This function performs like pwm_get() but the acquired PWM device will
+ * automatically be released on driver detach.
+ */
+struct pwm_device *devm_pwm_get(struct device *dev, const char *con_id)
+{
+ struct pwm_device **ptr, *pwm;
+
+ ptr = devres_alloc(devm_pwm_release, sizeof(**ptr), GFP_KERNEL);
+ if (!ptr)
+ return ERR_PTR(-ENOMEM);
+
+ pwm = pwm_get(dev, con_id);
+ if (!IS_ERR(pwm)) {
+ *ptr = pwm;
+ devres_add(dev, ptr);
+ } else {
+ devres_free(ptr);
+ }
+
+ return pwm;
+}
+EXPORT_SYMBOL_GPL(devm_pwm_get);
+
+static int devm_pwm_match(struct device *dev, void *res, void *data)
+{
+ struct pwm_device **p = res;
+
+ if (WARN_ON(!p || !*p))
+ return 0;
+
+ return *p == data;
+}
+
+/**
+ * devm_pwm_put() - resource managed pwm_put()
+ * @dev: device for PWM consumer
+ * @pwm: PWM device
+ *
+ * Release a PWM previously allocated using devm_pwm_get(). Calling this
+ * function is usually not needed because devm-allocated resources are
+ * automatically released on driver detach.
+ */
+void devm_pwm_put(struct device *dev, struct pwm_device *pwm)
+{
+ WARN_ON(devres_release(dev, devm_pwm_release, devm_pwm_match, pwm));
+}
+EXPORT_SYMBOL_GPL(devm_pwm_put);
+
#ifdef CONFIG_DEBUG_FS
static void pwm_dbg_show(struct pwm_chip *chip, struct seq_file *s)
{
diff --git a/drivers/misc/ab8500-pwm.c b/drivers/pwm/pwm-ab8500.c
index d7a9aa1..cfb72ca 100644
--- a/drivers/misc/ab8500-pwm.c
+++ b/drivers/pwm/pwm-ab8500.c
@@ -24,16 +24,12 @@
#define ENABLE_PWM 1
#define DISABLE_PWM 0
-struct pwm_device {
- struct device *dev;
- struct list_head node;
- const char *label;
- unsigned int pwm_id;
+struct ab8500_pwm_chip {
+ struct pwm_chip chip;
};
-static LIST_HEAD(pwm_list);
-
-int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
+static int ab8500_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
+ int duty_ns, int period_ns)
{
int ret = 0;
unsigned int higher_val, lower_val;
@@ -50,95 +46,94 @@ int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
*/
higher_val = ((duty_ns & 0x0300) >> 8);
- reg = AB8500_PWM_OUT_CTRL1_REG + ((pwm->pwm_id - 1) * 2);
+ reg = AB8500_PWM_OUT_CTRL1_REG + ((chip->base - 1) * 2);
- ret = abx500_set_register_interruptible(pwm->dev, AB8500_MISC,
+ ret = abx500_set_register_interruptible(chip->dev, AB8500_MISC,
reg, (u8)lower_val);
if (ret < 0)
return ret;
- ret = abx500_set_register_interruptible(pwm->dev, AB8500_MISC,
+ ret = abx500_set_register_interruptible(chip->dev, AB8500_MISC,
(reg + 1), (u8)higher_val);
return ret;
}
-EXPORT_SYMBOL(pwm_config);
-int pwm_enable(struct pwm_device *pwm)
+static int ab8500_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
{
int ret;
- ret = abx500_mask_and_set_register_interruptible(pwm->dev,
+ ret = abx500_mask_and_set_register_interruptible(chip->dev,
AB8500_MISC, AB8500_PWM_OUT_CTRL7_REG,
- 1 << (pwm->pwm_id-1), ENABLE_PWM);
+ 1 << (chip->base - 1), ENABLE_PWM);
if (ret < 0)
- dev_err(pwm->dev, "%s: Failed to disable PWM, Error %d\n",
+ dev_err(chip->dev, "%s: Failed to disable PWM, Error %d\n",
pwm->label, ret);
return ret;
}
-EXPORT_SYMBOL(pwm_enable);
-void pwm_disable(struct pwm_device *pwm)
+static void ab8500_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
{
int ret;
- ret = abx500_mask_and_set_register_interruptible(pwm->dev,
+ ret = abx500_mask_and_set_register_interruptible(chip->dev,
AB8500_MISC, AB8500_PWM_OUT_CTRL7_REG,
- 1 << (pwm->pwm_id-1), DISABLE_PWM);
+ 1 << (chip->base - 1), DISABLE_PWM);
if (ret < 0)
- dev_err(pwm->dev, "%s: Failed to disable PWM, Error %d\n",
+ dev_err(chip->dev, "%s: Failed to disable PWM, Error %d\n",
pwm->label, ret);
return;
}
-EXPORT_SYMBOL(pwm_disable);
-
-struct pwm_device *pwm_request(int pwm_id, const char *label)
-{
- struct pwm_device *pwm;
-
- list_for_each_entry(pwm, &pwm_list, node) {
- if (pwm->pwm_id == pwm_id) {
- pwm->label = label;
- pwm->pwm_id = pwm_id;
- return pwm;
- }
- }
-
- return ERR_PTR(-ENOENT);
-}
-EXPORT_SYMBOL(pwm_request);
-void pwm_free(struct pwm_device *pwm)
-{
- pwm_disable(pwm);
-}
-EXPORT_SYMBOL(pwm_free);
+static const struct pwm_ops ab8500_pwm_ops = {
+ .config = ab8500_pwm_config,
+ .enable = ab8500_pwm_enable,
+ .disable = ab8500_pwm_disable,
+};
static int __devinit ab8500_pwm_probe(struct platform_device *pdev)
{
- struct pwm_device *pwm;
+ struct ab8500_pwm_chip *ab8500;
+ int err;
+
/*
* Nothing to be done in probe, this is required to get the
* device which is required for ab8500 read and write
*/
- pwm = kzalloc(sizeof(struct pwm_device), GFP_KERNEL);
- if (pwm == NULL) {
+ ab8500 = kzalloc(sizeof(*ab8500), GFP_KERNEL);
+ if (ab8500 == NULL) {
dev_err(&pdev->dev, "failed to allocate memory\n");
return -ENOMEM;
}
- pwm->dev = &pdev->dev;
- pwm->pwm_id = pdev->id;
- list_add_tail(&pwm->node, &pwm_list);
- platform_set_drvdata(pdev, pwm);
- dev_dbg(pwm->dev, "pwm probe successful\n");
+
+ ab8500->chip.dev = &pdev->dev;
+ ab8500->chip.ops = &ab8500_pwm_ops;
+ ab8500->chip.base = pdev->id;
+ ab8500->chip.npwm = 1;
+
+ err = pwmchip_add(&ab8500->chip);
+ if (err < 0) {
+ kfree(ab8500);
+ return err;
+ }
+
+ dev_dbg(&pdev->dev, "pwm probe successful\n");
+ platform_set_drvdata(pdev, ab8500);
+
return 0;
}
static int __devexit ab8500_pwm_remove(struct platform_device *pdev)
{
- struct pwm_device *pwm = platform_get_drvdata(pdev);
- list_del(&pwm->node);
+ struct ab8500_pwm_chip *ab8500 = platform_get_drvdata(pdev);
+ int err;
+
+ err = pwmchip_remove(&ab8500->chip);
+ if (err < 0)
+ return err;
+
dev_dbg(&pdev->dev, "pwm driver removed\n");
- kfree(pwm);
+ kfree(ab8500);
+
return 0;
}
@@ -150,19 +145,8 @@ static struct platform_driver ab8500_pwm_driver = {
.probe = ab8500_pwm_probe,
.remove = __devexit_p(ab8500_pwm_remove),
};
+module_platform_driver(ab8500_pwm_driver);
-static int __init ab8500_pwm_init(void)
-{
- return platform_driver_register(&ab8500_pwm_driver);
-}
-
-static void __exit ab8500_pwm_exit(void)
-{
- platform_driver_unregister(&ab8500_pwm_driver);
-}
-
-subsys_initcall(ab8500_pwm_init);
-module_exit(ab8500_pwm_exit);
MODULE_AUTHOR("Arun MURTHY <arun.murthy@stericsson.com>");
MODULE_DESCRIPTION("AB8500 Pulse Width Modulation Driver");
MODULE_ALIAS("platform:ab8500-pwm");
diff --git a/drivers/pwm/pwm-bfin.c b/drivers/pwm/pwm-bfin.c
index d53c4e7..5da8e18 100644
--- a/drivers/pwm/pwm-bfin.c
+++ b/drivers/pwm/pwm-bfin.c
@@ -69,9 +69,6 @@ static int bfin_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
unsigned long period, duty;
unsigned long long val;
- if (duty_ns < 0 || duty_ns > period_ns)
- return -EINVAL;
-
val = (unsigned long long)get_sclk() * period_ns;
do_div(val, NSEC_PER_SEC);
period = val;
diff --git a/drivers/pwm/pwm-imx.c b/drivers/pwm/pwm-imx.c
index 2a0b353..8a5d3ae 100644
--- a/drivers/pwm/pwm-imx.c
+++ b/drivers/pwm/pwm-imx.c
@@ -16,8 +16,7 @@
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/pwm.h>
-#include <mach/hardware.h>
-
+#include <linux/of_device.h>
/* i.MX1 and i.MX21 share the same PWM function block: */
@@ -25,6 +24,7 @@
#define MX1_PWMS 0x04 /* PWM Sample Register */
#define MX1_PWMP 0x08 /* PWM Period Register */
+#define MX1_PWMC_EN (1 << 4)
/* i.MX27, i.MX31, i.MX35 share the same PWM function block: */
@@ -40,110 +40,165 @@
#define MX3_PWMCR_EN (1 << 0)
struct imx_chip {
- struct clk *clk;
+ struct clk *clk_per;
+ struct clk *clk_ipg;
- int clk_enabled;
+ int enabled;
void __iomem *mmio_base;
struct pwm_chip chip;
+
+ int (*config)(struct pwm_chip *chip,
+ struct pwm_device *pwm, int duty_ns, int period_ns);
+ void (*set_enable)(struct pwm_chip *chip, bool enable);
};
#define to_imx_chip(chip) container_of(chip, struct imx_chip, chip)
-static int imx_pwm_config(struct pwm_chip *chip,
+static int imx_pwm_config_v1(struct pwm_chip *chip,
struct pwm_device *pwm, int duty_ns, int period_ns)
{
struct imx_chip *imx = to_imx_chip(chip);
- if (!(cpu_is_mx1() || cpu_is_mx21())) {
- unsigned long long c;
- unsigned long period_cycles, duty_cycles, prescale;
- u32 cr;
-
- c = clk_get_rate(imx->clk);
- c = c * period_ns;
- do_div(c, 1000000000);
- period_cycles = c;
-
- prescale = period_cycles / 0x10000 + 1;
-
- period_cycles /= prescale;
- c = (unsigned long long)period_cycles * duty_ns;
- do_div(c, period_ns);
- duty_cycles = c;
-
- /*
- * according to imx pwm RM, the real period value should be
- * PERIOD value in PWMPR plus 2.
- */
- if (period_cycles > 2)
- period_cycles -= 2;
- else
- period_cycles = 0;
-
- writel(duty_cycles, imx->mmio_base + MX3_PWMSAR);
- writel(period_cycles, imx->mmio_base + MX3_PWMPR);
-
- cr = MX3_PWMCR_PRESCALER(prescale) |
- MX3_PWMCR_DOZEEN | MX3_PWMCR_WAITEN |
- MX3_PWMCR_DBGEN | MX3_PWMCR_EN;
-
- if (cpu_is_mx25())
- cr |= MX3_PWMCR_CLKSRC_IPG;
- else
- cr |= MX3_PWMCR_CLKSRC_IPG_HIGH;
-
- writel(cr, imx->mmio_base + MX3_PWMCR);
- } else if (cpu_is_mx1() || cpu_is_mx21()) {
- /* The PWM subsystem allows for exact frequencies. However,
- * I cannot connect a scope on my device to the PWM line and
- * thus cannot provide the program the PWM controller
- * exactly. Instead, I'm relying on the fact that the
- * Bootloader (u-boot or WinCE+haret) has programmed the PWM
- * function group already. So I'll just modify the PWM sample
- * register to follow the ratio of duty_ns vs. period_ns
- * accordingly.
- *
- * This is good enough for programming the brightness of
- * the LCD backlight.
- *
- * The real implementation would divide PERCLK[0] first by
- * both the prescaler (/1 .. /128) and then by CLKSEL
- * (/2 .. /16).
- */
- u32 max = readl(imx->mmio_base + MX1_PWMP);
- u32 p = max * duty_ns / period_ns;
- writel(max - p, imx->mmio_base + MX1_PWMS);
- } else {
- BUG();
- }
+ /*
+ * The PWM subsystem allows for exact frequencies. However,
+ * I cannot connect a scope on my device to the PWM line and
+ * thus cannot provide the program the PWM controller
+ * exactly. Instead, I'm relying on the fact that the
+ * Bootloader (u-boot or WinCE+haret) has programmed the PWM
+ * function group already. So I'll just modify the PWM sample
+ * register to follow the ratio of duty_ns vs. period_ns
+ * accordingly.
+ *
+ * This is good enough for programming the brightness of
+ * the LCD backlight.
+ *
+ * The real implementation would divide PERCLK[0] first by
+ * both the prescaler (/1 .. /128) and then by CLKSEL
+ * (/2 .. /16).
+ */
+ u32 max = readl(imx->mmio_base + MX1_PWMP);
+ u32 p = max * duty_ns / period_ns;
+ writel(max - p, imx->mmio_base + MX1_PWMS);
return 0;
}
+static void imx_pwm_set_enable_v1(struct pwm_chip *chip, bool enable)
+{
+ struct imx_chip *imx = to_imx_chip(chip);
+ u32 val;
+
+ val = readl(imx->mmio_base + MX1_PWMC);
+
+ if (enable)
+ val |= MX1_PWMC_EN;
+ else
+ val &= ~MX1_PWMC_EN;
+
+ writel(val, imx->mmio_base + MX1_PWMC);
+}
+
+static int imx_pwm_config_v2(struct pwm_chip *chip,
+ struct pwm_device *pwm, int duty_ns, int period_ns)
+{
+ struct imx_chip *imx = to_imx_chip(chip);
+ unsigned long long c;
+ unsigned long period_cycles, duty_cycles, prescale;
+ u32 cr;
+
+ c = clk_get_rate(imx->clk_per);
+ c = c * period_ns;
+ do_div(c, 1000000000);
+ period_cycles = c;
+
+ prescale = period_cycles / 0x10000 + 1;
+
+ period_cycles /= prescale;
+ c = (unsigned long long)period_cycles * duty_ns;
+ do_div(c, period_ns);
+ duty_cycles = c;
+
+ /*
+ * according to imx pwm RM, the real period value should be
+ * PERIOD value in PWMPR plus 2.
+ */
+ if (period_cycles > 2)
+ period_cycles -= 2;
+ else
+ period_cycles = 0;
+
+ writel(duty_cycles, imx->mmio_base + MX3_PWMSAR);
+ writel(period_cycles, imx->mmio_base + MX3_PWMPR);
+
+ cr = MX3_PWMCR_PRESCALER(prescale) |
+ MX3_PWMCR_DOZEEN | MX3_PWMCR_WAITEN |
+ MX3_PWMCR_DBGEN | MX3_PWMCR_CLKSRC_IPG_HIGH;
+
+ if (imx->enabled)
+ cr |= MX3_PWMCR_EN;
+
+ writel(cr, imx->mmio_base + MX3_PWMCR);
+
+ return 0;
+}
+
+static void imx_pwm_set_enable_v2(struct pwm_chip *chip, bool enable)
+{
+ struct imx_chip *imx = to_imx_chip(chip);
+ u32 val;
+
+ val = readl(imx->mmio_base + MX3_PWMCR);
+
+ if (enable)
+ val |= MX3_PWMCR_EN;
+ else
+ val &= ~MX3_PWMCR_EN;
+
+ writel(val, imx->mmio_base + MX3_PWMCR);
+}
+
+static int imx_pwm_config(struct pwm_chip *chip,
+ struct pwm_device *pwm, int duty_ns, int period_ns)
+{
+ struct imx_chip *imx = to_imx_chip(chip);
+ int ret;
+
+ ret = clk_prepare_enable(imx->clk_ipg);
+ if (ret)
+ return ret;
+
+ ret = imx->config(chip, pwm, duty_ns, period_ns);
+
+ clk_disable_unprepare(imx->clk_ipg);
+
+ return ret;
+}
+
static int imx_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
{
struct imx_chip *imx = to_imx_chip(chip);
- int rc = 0;
+ int ret;
- if (!imx->clk_enabled) {
- rc = clk_prepare_enable(imx->clk);
- if (!rc)
- imx->clk_enabled = 1;
- }
- return rc;
+ ret = clk_prepare_enable(imx->clk_per);
+ if (ret)
+ return ret;
+
+ imx->set_enable(chip, true);
+
+ imx->enabled = 1;
+
+ return 0;
}
static void imx_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
{
struct imx_chip *imx = to_imx_chip(chip);
- writel(0, imx->mmio_base + MX3_PWMCR);
+ imx->set_enable(chip, false);
- if (imx->clk_enabled) {
- clk_disable_unprepare(imx->clk);
- imx->clk_enabled = 0;
- }
+ clk_disable_unprepare(imx->clk_per);
+ imx->enabled = 0;
}
static struct pwm_ops imx_pwm_ops = {
@@ -153,30 +208,66 @@ static struct pwm_ops imx_pwm_ops = {
.owner = THIS_MODULE,
};
+struct imx_pwm_data {
+ int (*config)(struct pwm_chip *chip,
+ struct pwm_device *pwm, int duty_ns, int period_ns);
+ void (*set_enable)(struct pwm_chip *chip, bool enable);
+};
+
+static struct imx_pwm_data imx_pwm_data_v1 = {
+ .config = imx_pwm_config_v1,
+ .set_enable = imx_pwm_set_enable_v1,
+};
+
+static struct imx_pwm_data imx_pwm_data_v2 = {
+ .config = imx_pwm_config_v2,
+ .set_enable = imx_pwm_set_enable_v2,
+};
+
+static const struct of_device_id imx_pwm_dt_ids[] = {
+ { .compatible = "fsl,imx1-pwm", .data = &imx_pwm_data_v1, },
+ { .compatible = "fsl,imx27-pwm", .data = &imx_pwm_data_v2, },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, imx_pwm_dt_ids);
+
static int __devinit imx_pwm_probe(struct platform_device *pdev)
{
+ const struct of_device_id *of_id =
+ of_match_device(imx_pwm_dt_ids, &pdev->dev);
+ struct imx_pwm_data *data;
struct imx_chip *imx;
struct resource *r;
int ret = 0;
+ if (!of_id)
+ return -ENODEV;
+
imx = devm_kzalloc(&pdev->dev, sizeof(*imx), GFP_KERNEL);
if (imx == NULL) {
dev_err(&pdev->dev, "failed to allocate memory\n");
return -ENOMEM;
}
- imx->clk = devm_clk_get(&pdev->dev, "pwm");
+ imx->clk_per = devm_clk_get(&pdev->dev, "per");
+ if (IS_ERR(imx->clk_per)) {
+ dev_err(&pdev->dev, "getting per clock failed with %ld\n",
+ PTR_ERR(imx->clk_per));
+ return PTR_ERR(imx->clk_per);
+ }
- if (IS_ERR(imx->clk))
- return PTR_ERR(imx->clk);
+ imx->clk_ipg = devm_clk_get(&pdev->dev, "ipg");
+ if (IS_ERR(imx->clk_ipg)) {
+ dev_err(&pdev->dev, "getting ipg clock failed with %ld\n",
+ PTR_ERR(imx->clk_ipg));
+ return PTR_ERR(imx->clk_ipg);
+ }
imx->chip.ops = &imx_pwm_ops;
imx->chip.dev = &pdev->dev;
imx->chip.base = -1;
imx->chip.npwm = 1;
- imx->clk_enabled = 0;
-
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (r == NULL) {
dev_err(&pdev->dev, "no memory resource defined\n");
@@ -187,6 +278,10 @@ static int __devinit imx_pwm_probe(struct platform_device *pdev)
if (imx->mmio_base == NULL)
return -EADDRNOTAVAIL;
+ data = of_id->data;
+ imx->config = data->config;
+ imx->set_enable = data->set_enable;
+
ret = pwmchip_add(&imx->chip);
if (ret < 0)
return ret;
@@ -208,23 +303,14 @@ static int __devexit imx_pwm_remove(struct platform_device *pdev)
static struct platform_driver imx_pwm_driver = {
.driver = {
- .name = "mxc_pwm",
+ .name = "imx-pwm",
+ .of_match_table = of_match_ptr(imx_pwm_dt_ids),
},
.probe = imx_pwm_probe,
.remove = __devexit_p(imx_pwm_remove),
};
-static int __init imx_pwm_init(void)
-{
- return platform_driver_register(&imx_pwm_driver);
-}
-arch_initcall(imx_pwm_init);
-
-static void __exit imx_pwm_exit(void)
-{
- platform_driver_unregister(&imx_pwm_driver);
-}
-module_exit(imx_pwm_exit);
+module_platform_driver(imx_pwm_driver);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
diff --git a/drivers/pwm/pwm-jz4740.c b/drivers/pwm/pwm-jz4740.c
new file mode 100644
index 0000000..10250fc
--- /dev/null
+++ b/drivers/pwm/pwm-jz4740.c
@@ -0,0 +1,221 @@
+/*
+ * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
+ * JZ4740 platform PWM support
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * 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/clk.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pwm.h>
+
+#include <asm/mach-jz4740/gpio.h>
+#include <asm/mach-jz4740/timer.h>
+
+#define NUM_PWM 8
+
+static const unsigned int jz4740_pwm_gpio_list[NUM_PWM] = {
+ JZ_GPIO_PWM0,
+ JZ_GPIO_PWM1,
+ JZ_GPIO_PWM2,
+ JZ_GPIO_PWM3,
+ JZ_GPIO_PWM4,
+ JZ_GPIO_PWM5,
+ JZ_GPIO_PWM6,
+ JZ_GPIO_PWM7,
+};
+
+struct jz4740_pwm_chip {
+ struct pwm_chip chip;
+ struct clk *clk;
+};
+
+static inline struct jz4740_pwm_chip *to_jz4740(struct pwm_chip *chip)
+{
+ return container_of(chip, struct jz4740_pwm_chip, chip);
+}
+
+static int jz4740_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+ unsigned int gpio = jz4740_pwm_gpio_list[pwm->hwpwm];
+ int ret;
+
+ /*
+ * Timers 0 and 1 are used for system tasks, so they are unavailable
+ * for use as PWMs.
+ */
+ if (pwm->hwpwm < 2)
+ return -EBUSY;
+
+ ret = gpio_request(gpio, pwm->label);
+ if (ret) {
+ dev_err(chip->dev, "Failed to request GPIO#%u for PWM: %d\n",
+ gpio, ret);
+ return ret;
+ }
+
+ jz_gpio_set_function(gpio, JZ_GPIO_FUNC_PWM);
+
+ jz4740_timer_start(pwm->hwpwm);
+
+ return 0;
+}
+
+static void jz4740_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+ unsigned int gpio = jz4740_pwm_gpio_list[pwm->hwpwm];
+
+ jz4740_timer_set_ctrl(pwm->hwpwm, 0);
+
+ jz_gpio_set_function(gpio, JZ_GPIO_FUNC_NONE);
+ gpio_free(gpio);
+
+ jz4740_timer_stop(pwm->hwpwm);
+}
+
+static int jz4740_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+ uint32_t ctrl = jz4740_timer_get_ctrl(pwm->pwm);
+
+ ctrl |= JZ_TIMER_CTRL_PWM_ENABLE;
+ jz4740_timer_set_ctrl(pwm->hwpwm, ctrl);
+ jz4740_timer_enable(pwm->hwpwm);
+
+ return 0;
+}
+
+static void jz4740_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+ uint32_t ctrl = jz4740_timer_get_ctrl(pwm->hwpwm);
+
+ ctrl &= ~JZ_TIMER_CTRL_PWM_ENABLE;
+ jz4740_timer_disable(pwm->hwpwm);
+ jz4740_timer_set_ctrl(pwm->hwpwm, ctrl);
+}
+
+static int jz4740_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
+ int duty_ns, int period_ns)
+{
+ struct jz4740_pwm_chip *jz4740 = to_jz4740(pwm->chip);
+ unsigned long long tmp;
+ unsigned long period, duty;
+ unsigned int prescaler = 0;
+ uint16_t ctrl;
+ bool is_enabled;
+
+ tmp = (unsigned long long)clk_get_rate(jz4740->clk) * period_ns;
+ do_div(tmp, 1000000000);
+ period = tmp;
+
+ while (period > 0xffff && prescaler < 6) {
+ period >>= 2;
+ ++prescaler;
+ }
+
+ if (prescaler == 6)
+ return -EINVAL;
+
+ tmp = (unsigned long long)period * duty_ns;
+ do_div(tmp, period_ns);
+ duty = period - tmp;
+
+ if (duty >= period)
+ duty = period - 1;
+
+ is_enabled = jz4740_timer_is_enabled(pwm->hwpwm);
+ if (is_enabled)
+ jz4740_pwm_disable(chip, pwm);
+
+ jz4740_timer_set_count(pwm->hwpwm, 0);
+ jz4740_timer_set_duty(pwm->hwpwm, duty);
+ jz4740_timer_set_period(pwm->hwpwm, period);
+
+ ctrl = JZ_TIMER_CTRL_PRESCALER(prescaler) | JZ_TIMER_CTRL_SRC_EXT |
+ JZ_TIMER_CTRL_PWM_ABBRUPT_SHUTDOWN;
+
+ jz4740_timer_set_ctrl(pwm->hwpwm, ctrl);
+
+ if (is_enabled)
+ jz4740_pwm_enable(chip, pwm);
+
+ return 0;
+}
+
+static const struct pwm_ops jz4740_pwm_ops = {
+ .request = jz4740_pwm_request,
+ .free = jz4740_pwm_free,
+ .config = jz4740_pwm_config,
+ .enable = jz4740_pwm_enable,
+ .disable = jz4740_pwm_disable,
+ .owner = THIS_MODULE,
+};
+
+static int __devinit jz4740_pwm_probe(struct platform_device *pdev)
+{
+ struct jz4740_pwm_chip *jz4740;
+ int ret;
+
+ jz4740 = devm_kzalloc(&pdev->dev, sizeof(*jz4740), GFP_KERNEL);
+ if (!jz4740)
+ return -ENOMEM;
+
+ jz4740->clk = clk_get(NULL, "ext");
+ if (IS_ERR(jz4740->clk))
+ return PTR_ERR(jz4740->clk);
+
+ jz4740->chip.dev = &pdev->dev;
+ jz4740->chip.ops = &jz4740_pwm_ops;
+ jz4740->chip.npwm = NUM_PWM;
+ jz4740->chip.base = -1;
+
+ ret = pwmchip_add(&jz4740->chip);
+ if (ret < 0) {
+ clk_put(jz4740->clk);
+ return ret;
+ }
+
+ platform_set_drvdata(pdev, jz4740);
+
+ return 0;
+}
+
+static int __devexit jz4740_pwm_remove(struct platform_device *pdev)
+{
+ struct jz4740_pwm_chip *jz4740 = platform_get_drvdata(pdev);
+ int ret;
+
+ ret = pwmchip_remove(&jz4740->chip);
+ if (ret < 0)
+ return ret;
+
+ clk_put(jz4740->clk);
+
+ return 0;
+}
+
+static struct platform_driver jz4740_pwm_driver = {
+ .driver = {
+ .name = "jz4740-pwm",
+ .owner = THIS_MODULE,
+ },
+ .probe = jz4740_pwm_probe,
+ .remove = __devexit_p(jz4740_pwm_remove),
+};
+module_platform_driver(jz4740_pwm_driver);
+
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_DESCRIPTION("Ingenic JZ4740 PWM driver");
+MODULE_ALIAS("platform:jz4740-pwm");
+MODULE_LICENSE("GPL");
diff --git a/drivers/pwm/pwm-puv3.c b/drivers/pwm/pwm-puv3.c
new file mode 100644
index 0000000..2a93f37
--- /dev/null
+++ b/drivers/pwm/pwm-puv3.c
@@ -0,0 +1,161 @@
+/*
+ * linux/arch/unicore32/kernel/pwm.c
+ *
+ * Code specific to PKUnity SoC and UniCore ISA
+ *
+ * Maintained by GUAN Xue-tao <gxt@mprc.pku.edu.cn>
+ * Copyright (C) 2001-2010 Guan Xuetao
+ *
+ * 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/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/pwm.h>
+
+#include <asm/div64.h>
+#include <mach/hardware.h>
+
+struct puv3_pwm_chip {
+ struct pwm_chip chip;
+ void __iomem *base;
+ struct clk *clk;
+ bool enabled;
+};
+
+static inline struct puv3_pwm_chip *to_puv3(struct pwm_chip *chip)
+{
+ return container_of(chip, struct puv3_pwm_chip, chip);
+}
+
+/*
+ * period_ns = 10^9 * (PRESCALE + 1) * (PV + 1) / PWM_CLK_RATE
+ * duty_ns = 10^9 * (PRESCALE + 1) * DC / PWM_CLK_RATE
+ */
+static int puv3_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
+ int duty_ns, int period_ns)
+{
+ unsigned long period_cycles, prescale, pv, dc;
+ struct puv3_pwm_chip *puv3 = to_puv3(chip);
+ unsigned long long c;
+
+ c = clk_get_rate(puv3->clk);
+ c = c * period_ns;
+ do_div(c, 1000000000);
+ period_cycles = c;
+
+ if (period_cycles < 1)
+ period_cycles = 1;
+
+ prescale = (period_cycles - 1) / 1024;
+ pv = period_cycles / (prescale + 1) - 1;
+
+ if (prescale > 63)
+ return -EINVAL;
+
+ if (duty_ns == period_ns)
+ dc = OST_PWMDCCR_FDCYCLE;
+ else
+ dc = (pv + 1) * duty_ns / period_ns;
+
+ /*
+ * NOTE: the clock to PWM has to be enabled first
+ * before writing to the registers
+ */
+ clk_prepare_enable(puv3->clk);
+
+ writel(prescale, puv3->base + OST_PWM_PWCR);
+ writel(pv - dc, puv3->base + OST_PWM_DCCR);
+ writel(pv, puv3->base + OST_PWM_PCR);
+
+ clk_disable_unprepare(puv3->clk);
+
+ return 0;
+}
+
+static int puv3_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+ struct puv3_pwm_chip *puv3 = to_puv3(chip);
+
+ return clk_prepare_enable(puv3->clk);
+}
+
+static void puv3_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+ struct puv3_pwm_chip *puv3 = to_puv3(chip);
+
+ clk_disable_unprepare(puv3->clk);
+}
+
+static const struct pwm_ops puv3_pwm_ops = {
+ .config = puv3_pwm_config,
+ .enable = puv3_pwm_enable,
+ .disable = puv3_pwm_disable,
+ .owner = THIS_MODULE,
+};
+
+static int __devinit pwm_probe(struct platform_device *pdev)
+{
+ struct puv3_pwm_chip *puv3;
+ struct resource *r;
+ int ret;
+
+ puv3 = devm_kzalloc(&pdev->dev, sizeof(*puv3), GFP_KERNEL);
+ if (puv3 == NULL) {
+ dev_err(&pdev->dev, "failed to allocate memory\n");
+ return -ENOMEM;
+ }
+
+ puv3->clk = devm_clk_get(&pdev->dev, "OST_CLK");
+ if (IS_ERR(puv3->clk))
+ return PTR_ERR(puv3->clk);
+
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (r == NULL) {
+ dev_err(&pdev->dev, "no memory resource defined\n");
+ return -ENODEV;
+ }
+
+ puv3->base = devm_request_and_ioremap(&pdev->dev, r);
+ if (puv3->base == NULL)
+ return -EADDRNOTAVAIL;
+
+ puv3->chip.dev = &pdev->dev;
+ puv3->chip.ops = &puv3_pwm_ops;
+ puv3->chip.base = -1;
+ puv3->chip.npwm = 1;
+
+ ret = pwmchip_add(&puv3->chip);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret);
+ return ret;
+ }
+
+ platform_set_drvdata(pdev, puv3);
+ return 0;
+}
+
+static int __devexit pwm_remove(struct platform_device *pdev)
+{
+ struct puv3_pwm_chip *puv3 = platform_get_drvdata(pdev);
+
+ return pwmchip_remove(&puv3->chip);
+}
+
+static struct platform_driver puv3_pwm_driver = {
+ .driver = {
+ .name = "PKUnity-v3-PWM",
+ },
+ .probe = pwm_probe,
+ .remove = __devexit_p(pwm_remove),
+};
+module_platform_driver(puv3_pwm_driver);
+
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pwm/pwm-pxa.c b/drivers/pwm/pwm-pxa.c
index bd5867a..260c3a8 100644
--- a/drivers/pwm/pwm-pxa.c
+++ b/drivers/pwm/pwm-pxa.c
@@ -70,9 +70,6 @@ static int pxa_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
unsigned long offset;
int rc;
- if (period_ns == 0 || duty_ns > period_ns)
- return -EINVAL;
-
offset = pwm->hwpwm ? 0x10 : 0;
c = clk_get_rate(pc->clk);
diff --git a/drivers/pwm/pwm-samsung.c b/drivers/pwm/pwm-samsung.c
index e5187c0..023a3be 100644
--- a/drivers/pwm/pwm-samsung.c
+++ b/drivers/pwm/pwm-samsung.c
@@ -126,9 +126,6 @@ static int s3c_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
if (period_ns > NS_IN_HZ || duty_ns > NS_IN_HZ)
return -ERANGE;
- if (duty_ns > period_ns)
- return -EINVAL;
-
if (period_ns == s3c->period_ns &&
duty_ns == s3c->duty_ns)
return 0;
diff --git a/drivers/pwm/pwm-tiecap.c b/drivers/pwm/pwm-tiecap.c
index 4b66889..d6d4cf0 100644
--- a/drivers/pwm/pwm-tiecap.c
+++ b/drivers/pwm/pwm-tiecap.c
@@ -32,6 +32,7 @@
#define CAP3 0x10
#define CAP4 0x14
#define ECCTL2 0x2A
+#define ECCTL2_APWM_POL_LOW BIT(10)
#define ECCTL2_APWM_MODE BIT(9)
#define ECCTL2_SYNC_SEL_DISA (BIT(7) | BIT(6))
#define ECCTL2_TSCTR_FREERUN BIT(4)
@@ -59,7 +60,7 @@ static int ecap_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
unsigned long period_cycles, duty_cycles;
unsigned int reg_val;
- if (period_ns < 0 || duty_ns < 0 || period_ns > NSEC_PER_SEC)
+ if (period_ns > NSEC_PER_SEC)
return -ERANGE;
c = pc->clk_rate;
@@ -111,6 +112,26 @@ static int ecap_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
return 0;
}
+static int ecap_pwm_set_polarity(struct pwm_chip *chip, struct pwm_device *pwm,
+ enum pwm_polarity polarity)
+{
+ struct ecap_pwm_chip *pc = to_ecap_pwm_chip(chip);
+ unsigned short reg_val;
+
+ pm_runtime_get_sync(pc->chip.dev);
+ reg_val = readw(pc->mmio_base + ECCTL2);
+ if (polarity == PWM_POLARITY_INVERSED)
+ /* Duty cycle defines LOW period of PWM */
+ reg_val |= ECCTL2_APWM_POL_LOW;
+ else
+ /* Duty cycle defines HIGH period of PWM */
+ reg_val &= ~ECCTL2_APWM_POL_LOW;
+
+ writew(reg_val, pc->mmio_base + ECCTL2);
+ pm_runtime_put_sync(pc->chip.dev);
+ return 0;
+}
+
static int ecap_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
{
struct ecap_pwm_chip *pc = to_ecap_pwm_chip(chip);
@@ -157,6 +178,7 @@ static void ecap_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
static const struct pwm_ops ecap_pwm_ops = {
.free = ecap_pwm_free,
.config = ecap_pwm_config,
+ .set_polarity = ecap_pwm_set_polarity,
.enable = ecap_pwm_enable,
.disable = ecap_pwm_disable,
.owner = THIS_MODULE,
diff --git a/drivers/pwm/pwm-tiehrpwm.c b/drivers/pwm/pwm-tiehrpwm.c
index b1996bc..d3c1dff 100644
--- a/drivers/pwm/pwm-tiehrpwm.c
+++ b/drivers/pwm/pwm-tiehrpwm.c
@@ -81,6 +81,15 @@
#define AQCTL_ZRO_FRCHIGH BIT(1)
#define AQCTL_ZRO_FRCTOGGLE (BIT(1) | BIT(0))
+#define AQCTL_CHANA_POLNORMAL (AQCTL_CAU_FRCLOW | AQCTL_PRD_FRCHIGH | \
+ AQCTL_ZRO_FRCHIGH)
+#define AQCTL_CHANA_POLINVERSED (AQCTL_CAU_FRCHIGH | AQCTL_PRD_FRCLOW | \
+ AQCTL_ZRO_FRCLOW)
+#define AQCTL_CHANB_POLNORMAL (AQCTL_CBU_FRCLOW | AQCTL_PRD_FRCHIGH | \
+ AQCTL_ZRO_FRCHIGH)
+#define AQCTL_CHANB_POLINVERSED (AQCTL_CBU_FRCHIGH | AQCTL_PRD_FRCLOW | \
+ AQCTL_ZRO_FRCLOW)
+
#define AQSFRC_RLDCSF_MASK (BIT(7) | BIT(6))
#define AQSFRC_RLDCSF_ZRO 0
#define AQSFRC_RLDCSF_PRD BIT(6)
@@ -105,6 +114,7 @@ struct ehrpwm_pwm_chip {
unsigned int clk_rate;
void __iomem *mmio_base;
unsigned long period_cycles[NUM_PWM_CHANNEL];
+ enum pwm_polarity polarity[NUM_PWM_CHANNEL];
};
static inline struct ehrpwm_pwm_chip *to_ehrpwm_pwm_chip(struct pwm_chip *chip)
@@ -165,39 +175,37 @@ static int set_prescale_div(unsigned long rqst_prescaler,
return 1;
}
-static void configure_chans(struct ehrpwm_pwm_chip *pc, int chan,
- unsigned long duty_cycles)
+static void configure_polarity(struct ehrpwm_pwm_chip *pc, int chan)
{
- int cmp_reg, aqctl_reg;
+ int aqctl_reg;
unsigned short aqctl_val, aqctl_mask;
/*
- * Channels can be configured from action qualifier module.
- * Channel 0 configured with compare A register and for
- * up-counter mode.
- * Channel 1 configured with compare B register and for
- * up-counter mode.
+ * Configure PWM output to HIGH/LOW level on counter
+ * reaches compare register value and LOW/HIGH level
+ * on counter value reaches period register value and
+ * zero value on counter
*/
if (chan == 1) {
aqctl_reg = AQCTLB;
- cmp_reg = CMPB;
- /* Configure PWM Low from compare B value */
- aqctl_val = AQCTL_CBU_FRCLOW;
aqctl_mask = AQCTL_CBU_MASK;
+
+ if (pc->polarity[chan] == PWM_POLARITY_INVERSED)
+ aqctl_val = AQCTL_CHANB_POLINVERSED;
+ else
+ aqctl_val = AQCTL_CHANB_POLNORMAL;
} else {
- cmp_reg = CMPA;
aqctl_reg = AQCTLA;
- /* Configure PWM Low from compare A value*/
- aqctl_val = AQCTL_CAU_FRCLOW;
aqctl_mask = AQCTL_CAU_MASK;
+
+ if (pc->polarity[chan] == PWM_POLARITY_INVERSED)
+ aqctl_val = AQCTL_CHANA_POLINVERSED;
+ else
+ aqctl_val = AQCTL_CHANA_POLNORMAL;
}
- /* Configure PWM High from period value and zero value */
- aqctl_val |= AQCTL_PRD_FRCHIGH | AQCTL_ZRO_FRCHIGH;
aqctl_mask |= AQCTL_PRD_MASK | AQCTL_ZRO_MASK;
- ehrpwm_modify(pc->mmio_base, aqctl_reg, aqctl_mask, aqctl_val);
-
- ehrpwm_write(pc->mmio_base, cmp_reg, duty_cycles);
+ ehrpwm_modify(pc->mmio_base, aqctl_reg, aqctl_mask, aqctl_val);
}
/*
@@ -211,9 +219,9 @@ static int ehrpwm_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
unsigned long long c;
unsigned long period_cycles, duty_cycles;
unsigned short ps_divval, tb_divval;
- int i;
+ int i, cmp_reg;
- if (period_ns < 0 || duty_ns < 0 || period_ns > NSEC_PER_SEC)
+ if (period_ns > NSEC_PER_SEC)
return -ERANGE;
c = pc->clk_rate;
@@ -278,12 +286,29 @@ static int ehrpwm_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
ehrpwm_modify(pc->mmio_base, TBCTL, TBCTL_CTRMODE_MASK,
TBCTL_CTRMODE_UP);
- /* Configure the channel for duty cycle */
- configure_chans(pc, pwm->hwpwm, duty_cycles);
+ if (pwm->hwpwm == 1)
+ /* Channel 1 configured with compare B register */
+ cmp_reg = CMPB;
+ else
+ /* Channel 0 configured with compare A register */
+ cmp_reg = CMPA;
+
+ ehrpwm_write(pc->mmio_base, cmp_reg, duty_cycles);
+
pm_runtime_put_sync(chip->dev);
return 0;
}
+static int ehrpwm_pwm_set_polarity(struct pwm_chip *chip,
+ struct pwm_device *pwm, enum pwm_polarity polarity)
+{
+ struct ehrpwm_pwm_chip *pc = to_ehrpwm_pwm_chip(chip);
+
+ /* Configuration of polarity in hardware delayed, do at enable */
+ pc->polarity[pwm->hwpwm] = polarity;
+ return 0;
+}
+
static int ehrpwm_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
{
struct ehrpwm_pwm_chip *pc = to_ehrpwm_pwm_chip(chip);
@@ -307,6 +332,9 @@ static int ehrpwm_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
ehrpwm_modify(pc->mmio_base, AQCSFRC, aqcsfrc_mask, aqcsfrc_val);
+ /* Channels polarity can be configured from action qualifier module */
+ configure_polarity(pc, pwm->hwpwm);
+
/* Enable time counter for free_run */
ehrpwm_modify(pc->mmio_base, TBCTL, TBCTL_RUN_MASK, TBCTL_FREE_RUN);
return 0;
@@ -358,6 +386,7 @@ static void ehrpwm_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
static const struct pwm_ops ehrpwm_pwm_ops = {
.free = ehrpwm_pwm_free,
.config = ehrpwm_pwm_config,
+ .set_polarity = ehrpwm_pwm_set_polarity,
.enable = ehrpwm_pwm_enable,
.disable = ehrpwm_pwm_disable,
.owner = THIS_MODULE,
diff --git a/drivers/rapidio/rio-scan.c b/drivers/rapidio/rio-scan.c
index 48e9041..07da58b 100644
--- a/drivers/rapidio/rio-scan.c
+++ b/drivers/rapidio/rio-scan.c
@@ -55,9 +55,9 @@ static int rio_mport_phys_table[] = {
};
-/*
+/**
* rio_destid_alloc - Allocate next available destID for given network
- * net: RIO network
+ * @net: RIO network
*
* Returns next available device destination ID for the specified RIO network.
* Marks allocated ID as one in use.
@@ -69,14 +69,9 @@ static u16 rio_destid_alloc(struct rio_net *net)
struct rio_id_table *idtab = &net->destid_table;
spin_lock(&idtab->lock);
- destid = find_next_zero_bit(idtab->table, idtab->max, idtab->next);
- if (destid >= idtab->max)
- destid = find_first_zero_bit(idtab->table, idtab->max);
+ destid = find_first_zero_bit(idtab->table, idtab->max);
if (destid < idtab->max) {
- idtab->next = destid + 1;
- if (idtab->next >= idtab->max)
- idtab->next = 0;
set_bit(destid, idtab->table);
destid += idtab->start;
} else
@@ -86,10 +81,10 @@ static u16 rio_destid_alloc(struct rio_net *net)
return (u16)destid;
}
-/*
+/**
* rio_destid_reserve - Reserve the specivied destID
- * net: RIO network
- * destid: destID to reserve
+ * @net: RIO network
+ * @destid: destID to reserve
*
* Tries to reserve the specified destID.
* Returns 0 if successfull.
@@ -106,10 +101,10 @@ static int rio_destid_reserve(struct rio_net *net, u16 destid)
return oldbit;
}
-/*
+/**
* rio_destid_free - free a previously allocated destID
- * net: RIO network
- * destid: destID to free
+ * @net: RIO network
+ * @destid: destID to free
*
* Makes the specified destID available for use.
*/
@@ -123,9 +118,9 @@ static void rio_destid_free(struct rio_net *net, u16 destid)
spin_unlock(&idtab->lock);
}
-/*
+/**
* rio_destid_first - return first destID in use
- * net: RIO network
+ * @net: RIO network
*/
static u16 rio_destid_first(struct rio_net *net)
{
@@ -142,10 +137,10 @@ static u16 rio_destid_first(struct rio_net *net)
return (u16)destid;
}
-/*
+/**
* rio_destid_next - return next destID in use
- * net: RIO network
- * from: destination ID from which search shall continue
+ * @net: RIO network
+ * @from: destination ID from which search shall continue
*/
static u16 rio_destid_next(struct rio_net *net, u16 from)
{
@@ -1163,8 +1158,8 @@ static struct rio_net __devinit *rio_alloc_net(struct rio_mport *port,
net = kzalloc(sizeof(struct rio_net), GFP_KERNEL);
if (net && do_enum) {
- net->destid_table.table = kzalloc(
- BITS_TO_LONGS(RIO_MAX_ROUTE_ENTRIES(port->sys_size)) *
+ net->destid_table.table = kcalloc(
+ BITS_TO_LONGS(RIO_MAX_ROUTE_ENTRIES(port->sys_size)),
sizeof(long),
GFP_KERNEL);
@@ -1174,7 +1169,6 @@ static struct rio_net __devinit *rio_alloc_net(struct rio_mport *port,
net = NULL;
} else {
net->destid_table.start = start;
- net->destid_table.next = 0;
net->destid_table.max =
RIO_MAX_ROUTE_ENTRIES(port->sys_size);
spin_lock_init(&net->destid_table.lock);
@@ -1391,7 +1385,7 @@ int __devinit rio_disc_mport(struct rio_mport *mport)
while (time_before(jiffies, to_end)) {
if (rio_enum_complete(mport))
goto enum_done;
- schedule_timeout_uninterruptible(msecs_to_jiffies(10));
+ msleep(10);
}
pr_debug("RIO: discovery timeout on mport %d %s\n",
diff --git a/drivers/rapidio/rio.c b/drivers/rapidio/rio.c
index d4bd690..c17ae22 100644
--- a/drivers/rapidio/rio.c
+++ b/drivers/rapidio/rio.c
@@ -1275,49 +1275,68 @@ static void __devinit disc_work_handler(struct work_struct *_work)
pr_debug("RIO: discovery work for mport %d %s\n",
work->mport->id, work->mport->name);
rio_disc_mport(work->mport);
-
- kfree(work);
}
int __devinit rio_init_mports(void)
{
struct rio_mport *port;
struct rio_disc_work *work;
- int no_disc = 0;
+ int n = 0;
+
+ if (!next_portid)
+ return -ENODEV;
+ /*
+ * First, run enumerations and check if we need to perform discovery
+ * on any of the registered mports.
+ */
list_for_each_entry(port, &rio_mports, node) {
if (port->host_deviceid >= 0)
rio_enum_mport(port);
- else if (!no_disc) {
- if (!rio_wq) {
- rio_wq = alloc_workqueue("riodisc", 0, 0);
- if (!rio_wq) {
- pr_err("RIO: unable allocate rio_wq\n");
- no_disc = 1;
- continue;
- }
- }
-
- work = kzalloc(sizeof *work, GFP_KERNEL);
- if (!work) {
- pr_err("RIO: no memory for work struct\n");
- no_disc = 1;
- continue;
- }
-
- work->mport = port;
- INIT_WORK(&work->work, disc_work_handler);
- queue_work(rio_wq, &work->work);
- }
+ else
+ n++;
+ }
+
+ if (!n)
+ goto no_disc;
+
+ /*
+ * If we have mports that require discovery schedule a discovery work
+ * for each of them. If the code below fails to allocate needed
+ * resources, exit without error to keep results of enumeration
+ * process (if any).
+ * TODO: Implement restart of dicovery process for all or
+ * individual discovering mports.
+ */
+ rio_wq = alloc_workqueue("riodisc", 0, 0);
+ if (!rio_wq) {
+ pr_err("RIO: unable allocate rio_wq\n");
+ goto no_disc;
}
- if (rio_wq) {
- pr_debug("RIO: flush discovery workqueue\n");
- flush_workqueue(rio_wq);
- pr_debug("RIO: flush discovery workqueue finished\n");
+ work = kcalloc(n, sizeof *work, GFP_KERNEL);
+ if (!work) {
+ pr_err("RIO: no memory for work struct\n");
destroy_workqueue(rio_wq);
+ goto no_disc;
}
+ n = 0;
+ list_for_each_entry(port, &rio_mports, node) {
+ if (port->host_deviceid < 0) {
+ work[n].mport = port;
+ INIT_WORK(&work[n].work, disc_work_handler);
+ queue_work(rio_wq, &work[n].work);
+ n++;
+ }
+ }
+
+ flush_workqueue(rio_wq);
+ pr_debug("RIO: destroy discovery workqueue\n");
+ destroy_workqueue(rio_wq);
+ kfree(work);
+
+no_disc:
rio_init();
return 0;
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index e069f17..19c03ab 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -59,6 +59,7 @@ comment "RTC interfaces"
config RTC_INTF_SYSFS
boolean "/sys/class/rtc/rtcN (sysfs)"
depends on SYSFS
+ default RTC_CLASS
help
Say yes here if you want to use your RTCs using sysfs interfaces,
/sys/class/rtc/rtc0 through /sys/.../rtcN.
@@ -68,6 +69,7 @@ config RTC_INTF_SYSFS
config RTC_INTF_PROC
boolean "/proc/driver/rtc (procfs for rtcN)"
depends on PROC_FS
+ default RTC_CLASS
help
Say yes here if you want to use your system clock RTC through
the proc interface, /proc/driver/rtc.
@@ -79,6 +81,7 @@ config RTC_INTF_PROC
config RTC_INTF_DEV
boolean "/dev/rtcN (character devices)"
+ default RTC_CLASS
help
Say yes here if you want to use your RTCs using the /dev
interfaces, which "udev" sets up as /dev/rtc0 through
diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c
index a5a55da2..b6ad0de 100644
--- a/drivers/s390/block/dcssblk.c
+++ b/drivers/s390/block/dcssblk.c
@@ -69,23 +69,9 @@ static ssize_t dcssblk_add_store(struct device * dev, struct device_attribute *a
size_t count);
static ssize_t dcssblk_remove_store(struct device * dev, struct device_attribute *attr, const char * buf,
size_t count);
-static ssize_t dcssblk_save_store(struct device * dev, struct device_attribute *attr, const char * buf,
- size_t count);
-static ssize_t dcssblk_save_show(struct device *dev, struct device_attribute *attr, char *buf);
-static ssize_t dcssblk_shared_store(struct device * dev, struct device_attribute *attr, const char * buf,
- size_t count);
-static ssize_t dcssblk_shared_show(struct device *dev, struct device_attribute *attr, char *buf);
-static ssize_t dcssblk_seglist_show(struct device *dev,
- struct device_attribute *attr,
- char *buf);
static DEVICE_ATTR(add, S_IWUSR, NULL, dcssblk_add_store);
static DEVICE_ATTR(remove, S_IWUSR, NULL, dcssblk_remove_store);
-static DEVICE_ATTR(save, S_IWUSR | S_IRUSR, dcssblk_save_show,
- dcssblk_save_store);
-static DEVICE_ATTR(shared, S_IWUSR | S_IRUSR, dcssblk_shared_show,
- dcssblk_shared_store);
-static DEVICE_ATTR(seglist, S_IRUSR, dcssblk_seglist_show, NULL);
static struct device *dcssblk_root_dev;
@@ -416,6 +402,8 @@ out:
up_write(&dcssblk_devices_sem);
return rc;
}
+static DEVICE_ATTR(shared, S_IWUSR | S_IRUSR, dcssblk_shared_show,
+ dcssblk_shared_store);
/*
* device attribute for save operation on current copy
@@ -476,6 +464,8 @@ dcssblk_save_store(struct device *dev, struct device_attribute *attr, const char
up_write(&dcssblk_devices_sem);
return count;
}
+static DEVICE_ATTR(save, S_IWUSR | S_IRUSR, dcssblk_save_show,
+ dcssblk_save_store);
/*
* device attribute for showing all segments in a device
@@ -502,6 +492,21 @@ dcssblk_seglist_show(struct device *dev, struct device_attribute *attr,
up_read(&dcssblk_devices_sem);
return i;
}
+static DEVICE_ATTR(seglist, S_IRUSR, dcssblk_seglist_show, NULL);
+
+static struct attribute *dcssblk_dev_attrs[] = {
+ &dev_attr_shared.attr,
+ &dev_attr_save.attr,
+ &dev_attr_seglist.attr,
+ NULL,
+};
+static struct attribute_group dcssblk_dev_attr_group = {
+ .attrs = dcssblk_dev_attrs,
+};
+static const struct attribute_group *dcssblk_dev_attr_groups[] = {
+ &dcssblk_dev_attr_group,
+ NULL,
+};
/*
* device attribute for adding devices
@@ -590,6 +595,7 @@ dcssblk_add_store(struct device *dev, struct device_attribute *attr, const char
dev_set_name(&dev_info->dev, dev_info->segment_name);
dev_info->dev.release = dcssblk_release_segment;
+ dev_info->dev.groups = dcssblk_dev_attr_groups;
INIT_LIST_HEAD(&dev_info->lh);
dev_info->gd = alloc_disk(DCSSBLK_MINORS_PER_DISK);
if (dev_info->gd == NULL) {
@@ -637,21 +643,10 @@ dcssblk_add_store(struct device *dev, struct device_attribute *attr, const char
* register the device
*/
rc = device_register(&dev_info->dev);
- if (rc) {
- module_put(THIS_MODULE);
- goto dev_list_del;
- }
- get_device(&dev_info->dev);
- rc = device_create_file(&dev_info->dev, &dev_attr_shared);
- if (rc)
- goto unregister_dev;
- rc = device_create_file(&dev_info->dev, &dev_attr_save);
- if (rc)
- goto unregister_dev;
- rc = device_create_file(&dev_info->dev, &dev_attr_seglist);
if (rc)
- goto unregister_dev;
+ goto put_dev;
+ get_device(&dev_info->dev);
add_disk(dev_info->gd);
switch (dev_info->segment_type) {
@@ -668,12 +663,11 @@ dcssblk_add_store(struct device *dev, struct device_attribute *attr, const char
rc = count;
goto out;
-unregister_dev:
+put_dev:
list_del(&dev_info->lh);
blk_cleanup_queue(dev_info->dcssblk_queue);
dev_info->gd->queue = NULL;
put_disk(dev_info->gd);
- device_unregister(&dev_info->dev);
list_for_each_entry(seg_info, &dev_info->seg_list, lh) {
segment_unload(seg_info->segment_name);
}
diff --git a/drivers/s390/crypto/zcrypt_pcixcc.c b/drivers/s390/crypto/zcrypt_pcixcc.c
index c7275e3..899ffa1 100644
--- a/drivers/s390/crypto/zcrypt_pcixcc.c
+++ b/drivers/s390/crypto/zcrypt_pcixcc.c
@@ -39,7 +39,6 @@
#include "zcrypt_msgtype6.h"
#include "zcrypt_pcixcc.h"
#include "zcrypt_cca_key.h"
-#include "zcrypt_msgtype6.h"
#define PCIXCC_MIN_MOD_SIZE 16 /* 128 bits */
#define PCIXCC_MIN_MOD_SIZE_OLD 64 /* 512 bits */
diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c
index bddc97c..0e09d8f 100644
--- a/drivers/scsi/qla2xxx/qla_target.c
+++ b/drivers/scsi/qla2xxx/qla_target.c
@@ -1403,7 +1403,7 @@ static void qlt_24xx_send_task_mgmt_ctio(struct scsi_qla_host *ha,
ctio->u.status1.scsi_status =
__constant_cpu_to_le16(SS_RESPONSE_INFO_LEN_VALID);
ctio->u.status1.response_len = __constant_cpu_to_le16(8);
- ((uint32_t *)ctio->u.status1.sense_data)[0] = cpu_to_be32(resp_code);
+ ctio->u.status1.sense_data[0] = resp_code;
qla2x00_start_iocbs(ha, ha->req);
}
diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c
index 4752f65..2358c16 100644
--- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c
+++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c
@@ -735,17 +735,6 @@ static int tcm_qla2xxx_queue_tm_rsp(struct se_cmd *se_cmd)
return 0;
}
-static u16 tcm_qla2xxx_get_fabric_sense_len(void)
-{
- return 0;
-}
-
-static u16 tcm_qla2xxx_set_fabric_sense_len(struct se_cmd *se_cmd,
- u32 sense_length)
-{
- return 0;
-}
-
/* Local pointer to allocated TCM configfs fabric module */
struct target_fabric_configfs *tcm_qla2xxx_fabric_configfs;
struct target_fabric_configfs *tcm_qla2xxx_npiv_fabric_configfs;
@@ -1691,8 +1680,6 @@ static struct target_core_fabric_ops tcm_qla2xxx_ops = {
.queue_data_in = tcm_qla2xxx_queue_data_in,
.queue_status = tcm_qla2xxx_queue_status,
.queue_tm_rsp = tcm_qla2xxx_queue_tm_rsp,
- .get_fabric_sense_len = tcm_qla2xxx_get_fabric_sense_len,
- .set_fabric_sense_len = tcm_qla2xxx_set_fabric_sense_len,
/*
* Setup function pointers for generic logic in
* target_core_fabric_configfs.c
@@ -1740,8 +1727,6 @@ static struct target_core_fabric_ops tcm_qla2xxx_npiv_ops = {
.queue_data_in = tcm_qla2xxx_queue_data_in,
.queue_status = tcm_qla2xxx_queue_status,
.queue_tm_rsp = tcm_qla2xxx_queue_tm_rsp,
- .get_fabric_sense_len = tcm_qla2xxx_get_fabric_sense_len,
- .set_fabric_sense_len = tcm_qla2xxx_set_fabric_sense_len,
/*
* Setup function pointers for generic logic in
* target_core_fabric_configfs.c
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 8c2ff24..1acae35 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -134,6 +134,7 @@ config SPI_DAVINCI
tristate "Texas Instruments DaVinci/DA8x/OMAP-L/AM1x SoC SPI controller"
depends on ARCH_DAVINCI
select SPI_BITBANG
+ select TI_EDMA
help
SPI master controller for DaVinci/DA8x/OMAP-L/AM1x SPI modules.
diff --git a/drivers/spi/spi-davinci.c b/drivers/spi/spi-davinci.c
index 3afe2f4f..147dfa8 100644
--- a/drivers/spi/spi-davinci.c
+++ b/drivers/spi/spi-davinci.c
@@ -25,13 +25,14 @@
#include <linux/platform_device.h>
#include <linux/err.h>
#include <linux/clk.h>
+#include <linux/dmaengine.h>
#include <linux/dma-mapping.h>
+#include <linux/edma.h>
#include <linux/spi/spi.h>
#include <linux/spi/spi_bitbang.h>
#include <linux/slab.h>
#include <linux/platform_data/spi-davinci.h>
-#include <mach/edma.h>
#define SPI_NO_RESOURCE ((resource_size_t)-1)
@@ -113,14 +114,6 @@
#define SPIDEF 0x4c
#define SPIFMT0 0x50
-/* We have 2 DMA channels per CS, one for RX and one for TX */
-struct davinci_spi_dma {
- int tx_channel;
- int rx_channel;
- int dummy_param_slot;
- enum dma_event_q eventq;
-};
-
/* SPI Controller driver's private data. */
struct davinci_spi {
struct spi_bitbang bitbang;
@@ -134,11 +127,14 @@ struct davinci_spi {
const void *tx;
void *rx;
-#define SPI_TMP_BUFSZ (SMP_CACHE_BYTES + 1)
- u8 rx_tmp_buf[SPI_TMP_BUFSZ];
int rcount;
int wcount;
- struct davinci_spi_dma dma;
+
+ struct dma_chan *dma_rx;
+ struct dma_chan *dma_tx;
+ int dma_rx_chnum;
+ int dma_tx_chnum;
+
struct davinci_spi_platform_data *pdata;
void (*get_rx)(u32 rx_data, struct davinci_spi *);
@@ -496,21 +492,23 @@ out:
return errors;
}
-static void davinci_spi_dma_callback(unsigned lch, u16 status, void *data)
+static void davinci_spi_dma_rx_callback(void *data)
{
- struct davinci_spi *dspi = data;
- struct davinci_spi_dma *dma = &dspi->dma;
+ struct davinci_spi *dspi = (struct davinci_spi *)data;
- edma_stop(lch);
+ dspi->rcount = 0;
- if (status == DMA_COMPLETE) {
- if (lch == dma->rx_channel)
- dspi->rcount = 0;
- if (lch == dma->tx_channel)
- dspi->wcount = 0;
- }
+ if (!dspi->wcount && !dspi->rcount)
+ complete(&dspi->done);
+}
- if ((!dspi->wcount && !dspi->rcount) || (status != DMA_COMPLETE))
+static void davinci_spi_dma_tx_callback(void *data)
+{
+ struct davinci_spi *dspi = (struct davinci_spi *)data;
+
+ dspi->wcount = 0;
+
+ if (!dspi->wcount && !dspi->rcount)
complete(&dspi->done);
}
@@ -526,20 +524,20 @@ static void davinci_spi_dma_callback(unsigned lch, u16 status, void *data)
static int davinci_spi_bufs(struct spi_device *spi, struct spi_transfer *t)
{
struct davinci_spi *dspi;
- int data_type, ret;
+ int data_type, ret = -ENOMEM;
u32 tx_data, spidat1;
u32 errors = 0;
struct davinci_spi_config *spicfg;
struct davinci_spi_platform_data *pdata;
unsigned uninitialized_var(rx_buf_count);
- struct device *sdev;
+ void *dummy_buf = NULL;
+ struct scatterlist sg_rx, sg_tx;
dspi = spi_master_get_devdata(spi->master);
pdata = dspi->pdata;
spicfg = (struct davinci_spi_config *)spi->controller_data;
if (!spicfg)
spicfg = &davinci_spi_default_cfg;
- sdev = dspi->bitbang.master->dev.parent;
/* convert len to words based on bits_per_word */
data_type = dspi->bytes_per_word[spi->chip_select];
@@ -567,112 +565,83 @@ static int davinci_spi_bufs(struct spi_device *spi, struct spi_transfer *t)
spidat1 |= tx_data & 0xFFFF;
iowrite32(spidat1, dspi->base + SPIDAT1);
} else {
- struct davinci_spi_dma *dma;
- unsigned long tx_reg, rx_reg;
- struct edmacc_param param;
- void *rx_buf;
- int b, c;
-
- dma = &dspi->dma;
-
- tx_reg = (unsigned long)dspi->pbase + SPIDAT1;
- rx_reg = (unsigned long)dspi->pbase + SPIBUF;
-
- /*
- * Transmit DMA setup
- *
- * If there is transmit data, map the transmit buffer, set it
- * as the source of data and set the source B index to data
- * size. If there is no transmit data, set the transmit register
- * as the source of data, and set the source B index to zero.
- *
- * The destination is always the transmit register itself. And
- * the destination never increments.
- */
-
- if (t->tx_buf) {
- t->tx_dma = dma_map_single(&spi->dev, (void *)t->tx_buf,
- t->len, DMA_TO_DEVICE);
- if (dma_mapping_error(&spi->dev, t->tx_dma)) {
- dev_dbg(sdev, "Unable to DMA map %d bytes"
- "TX buffer\n", t->len);
- return -ENOMEM;
- }
- }
-
- /*
- * If number of words is greater than 65535, then we need
- * to configure a 3 dimension transfer. Use the BCNTRLD
- * feature to allow for transfers that aren't even multiples
- * of 65535 (or any other possible b size) by first transferring
- * the remainder amount then grabbing the next N blocks of
- * 65535 words.
- */
-
- c = dspi->wcount / (SZ_64K - 1); /* N 65535 Blocks */
- b = dspi->wcount - c * (SZ_64K - 1); /* Remainder */
- if (b)
- c++;
+ struct dma_slave_config dma_rx_conf = {
+ .direction = DMA_DEV_TO_MEM,
+ .src_addr = (unsigned long)dspi->pbase + SPIBUF,
+ .src_addr_width = data_type,
+ .src_maxburst = 1,
+ };
+ struct dma_slave_config dma_tx_conf = {
+ .direction = DMA_MEM_TO_DEV,
+ .dst_addr = (unsigned long)dspi->pbase + SPIDAT1,
+ .dst_addr_width = data_type,
+ .dst_maxburst = 1,
+ };
+ struct dma_async_tx_descriptor *rxdesc;
+ struct dma_async_tx_descriptor *txdesc;
+ void *buf;
+
+ dummy_buf = kzalloc(t->len, GFP_KERNEL);
+ if (!dummy_buf)
+ goto err_alloc_dummy_buf;
+
+ dmaengine_slave_config(dspi->dma_rx, &dma_rx_conf);
+ dmaengine_slave_config(dspi->dma_tx, &dma_tx_conf);
+
+ sg_init_table(&sg_rx, 1);
+ if (!t->rx_buf)
+ buf = dummy_buf;
else
- b = SZ_64K - 1;
-
- param.opt = TCINTEN | EDMA_TCC(dma->tx_channel);
- param.src = t->tx_buf ? t->tx_dma : tx_reg;
- param.a_b_cnt = b << 16 | data_type;
- param.dst = tx_reg;
- param.src_dst_bidx = t->tx_buf ? data_type : 0;
- param.link_bcntrld = 0xffffffff;
- param.src_dst_cidx = t->tx_buf ? data_type : 0;
- param.ccnt = c;
- edma_write_slot(dma->tx_channel, &param);
- edma_link(dma->tx_channel, dma->dummy_param_slot);
-
- /*
- * Receive DMA setup
- *
- * If there is receive buffer, use it to receive data. If there
- * is none provided, use a temporary receive buffer. Set the
- * destination B index to 0 so effectively only one byte is used
- * in the temporary buffer (address does not increment).
- *
- * The source of receive data is the receive data register. The
- * source address never increments.
- */
-
- if (t->rx_buf) {
- rx_buf = t->rx_buf;
- rx_buf_count = t->len;
- } else {
- rx_buf = dspi->rx_tmp_buf;
- rx_buf_count = sizeof(dspi->rx_tmp_buf);
+ buf = t->rx_buf;
+ t->rx_dma = dma_map_single(&spi->dev, buf,
+ t->len, DMA_FROM_DEVICE);
+ if (!t->rx_dma) {
+ ret = -EFAULT;
+ goto err_rx_map;
}
+ sg_dma_address(&sg_rx) = t->rx_dma;
+ sg_dma_len(&sg_rx) = t->len;
- t->rx_dma = dma_map_single(&spi->dev, rx_buf, rx_buf_count,
- DMA_FROM_DEVICE);
- if (dma_mapping_error(&spi->dev, t->rx_dma)) {
- dev_dbg(sdev, "Couldn't DMA map a %d bytes RX buffer\n",
- rx_buf_count);
- if (t->tx_buf)
- dma_unmap_single(&spi->dev, t->tx_dma, t->len,
- DMA_TO_DEVICE);
- return -ENOMEM;
+ sg_init_table(&sg_tx, 1);
+ if (!t->tx_buf)
+ buf = dummy_buf;
+ else
+ buf = (void *)t->tx_buf;
+ t->tx_dma = dma_map_single(&spi->dev, buf,
+ t->len, DMA_FROM_DEVICE);
+ if (!t->tx_dma) {
+ ret = -EFAULT;
+ goto err_tx_map;
}
-
- param.opt = TCINTEN | EDMA_TCC(dma->rx_channel);
- param.src = rx_reg;
- param.a_b_cnt = b << 16 | data_type;
- param.dst = t->rx_dma;
- param.src_dst_bidx = (t->rx_buf ? data_type : 0) << 16;
- param.link_bcntrld = 0xffffffff;
- param.src_dst_cidx = (t->rx_buf ? data_type : 0) << 16;
- param.ccnt = c;
- edma_write_slot(dma->rx_channel, &param);
+ sg_dma_address(&sg_tx) = t->tx_dma;
+ sg_dma_len(&sg_tx) = t->len;
+
+ rxdesc = dmaengine_prep_slave_sg(dspi->dma_rx,
+ &sg_rx, 1, DMA_DEV_TO_MEM,
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ if (!rxdesc)
+ goto err_desc;
+
+ txdesc = dmaengine_prep_slave_sg(dspi->dma_tx,
+ &sg_tx, 1, DMA_MEM_TO_DEV,
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ if (!txdesc)
+ goto err_desc;
+
+ rxdesc->callback = davinci_spi_dma_rx_callback;
+ rxdesc->callback_param = (void *)dspi;
+ txdesc->callback = davinci_spi_dma_tx_callback;
+ txdesc->callback_param = (void *)dspi;
if (pdata->cshold_bug)
iowrite16(spidat1 >> 16, dspi->base + SPIDAT1 + 2);
- edma_start(dma->rx_channel);
- edma_start(dma->tx_channel);
+ dmaengine_submit(rxdesc);
+ dmaengine_submit(txdesc);
+
+ dma_async_issue_pending(dspi->dma_rx);
+ dma_async_issue_pending(dspi->dma_tx);
+
set_io_bits(dspi->base + SPIINT, SPIINT_DMA_REQ_EN);
}
@@ -690,15 +659,13 @@ static int davinci_spi_bufs(struct spi_device *spi, struct spi_transfer *t)
clear_io_bits(dspi->base + SPIINT, SPIINT_MASKALL);
if (spicfg->io_type == SPI_IO_TYPE_DMA) {
-
- if (t->tx_buf)
- dma_unmap_single(&spi->dev, t->tx_dma, t->len,
- DMA_TO_DEVICE);
-
- dma_unmap_single(&spi->dev, t->rx_dma, rx_buf_count,
- DMA_FROM_DEVICE);
-
clear_io_bits(dspi->base + SPIINT, SPIINT_DMA_REQ_EN);
+
+ dma_unmap_single(&spi->dev, t->rx_dma,
+ t->len, DMA_FROM_DEVICE);
+ dma_unmap_single(&spi->dev, t->tx_dma,
+ t->len, DMA_TO_DEVICE);
+ kfree(dummy_buf);
}
clear_io_bits(dspi->base + SPIGCR1, SPIGCR1_SPIENA_MASK);
@@ -716,11 +683,20 @@ static int davinci_spi_bufs(struct spi_device *spi, struct spi_transfer *t)
}
if (dspi->rcount != 0 || dspi->wcount != 0) {
- dev_err(sdev, "SPI data transfer error\n");
+ dev_err(&spi->dev, "SPI data transfer error\n");
return -EIO;
}
return t->len;
+
+err_desc:
+ dma_unmap_single(&spi->dev, t->tx_dma, t->len, DMA_TO_DEVICE);
+err_tx_map:
+ dma_unmap_single(&spi->dev, t->rx_dma, t->len, DMA_FROM_DEVICE);
+err_rx_map:
+ kfree(dummy_buf);
+err_alloc_dummy_buf:
+ return ret;
}
/**
@@ -751,39 +727,33 @@ static irqreturn_t davinci_spi_irq(s32 irq, void *data)
static int davinci_spi_request_dma(struct davinci_spi *dspi)
{
+ dma_cap_mask_t mask;
+ struct device *sdev = dspi->bitbang.master->dev.parent;
int r;
- struct davinci_spi_dma *dma = &dspi->dma;
- r = edma_alloc_channel(dma->rx_channel, davinci_spi_dma_callback, dspi,
- dma->eventq);
- if (r < 0) {
- pr_err("Unable to request DMA channel for SPI RX\n");
- r = -EAGAIN;
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_SLAVE, mask);
+
+ dspi->dma_rx = dma_request_channel(mask, edma_filter_fn,
+ &dspi->dma_rx_chnum);
+ if (!dspi->dma_rx) {
+ dev_err(sdev, "request RX DMA channel failed\n");
+ r = -ENODEV;
goto rx_dma_failed;
}
- r = edma_alloc_channel(dma->tx_channel, davinci_spi_dma_callback, dspi,
- dma->eventq);
- if (r < 0) {
- pr_err("Unable to request DMA channel for SPI TX\n");
- r = -EAGAIN;
+ dspi->dma_tx = dma_request_channel(mask, edma_filter_fn,
+ &dspi->dma_tx_chnum);
+ if (!dspi->dma_tx) {
+ dev_err(sdev, "request TX DMA channel failed\n");
+ r = -ENODEV;
goto tx_dma_failed;
}
- r = edma_alloc_slot(EDMA_CTLR(dma->tx_channel), EDMA_SLOT_ANY);
- if (r < 0) {
- pr_err("Unable to request SPI TX DMA param slot\n");
- r = -EAGAIN;
- goto param_failed;
- }
- dma->dummy_param_slot = r;
- edma_link(dma->dummy_param_slot, dma->dummy_param_slot);
-
return 0;
-param_failed:
- edma_free_channel(dma->tx_channel);
+
tx_dma_failed:
- edma_free_channel(dma->rx_channel);
+ dma_release_channel(dspi->dma_rx);
rx_dma_failed:
return r;
}
@@ -898,9 +868,8 @@ static int __devinit davinci_spi_probe(struct platform_device *pdev)
dspi->bitbang.txrx_bufs = davinci_spi_bufs;
if (dma_rx_chan != SPI_NO_RESOURCE &&
dma_tx_chan != SPI_NO_RESOURCE) {
- dspi->dma.rx_channel = dma_rx_chan;
- dspi->dma.tx_channel = dma_tx_chan;
- dspi->dma.eventq = pdata->dma_event_q;
+ dspi->dma_rx_chnum = dma_rx_chan;
+ dspi->dma_tx_chnum = dma_tx_chan;
ret = davinci_spi_request_dma(dspi);
if (ret)
@@ -955,9 +924,8 @@ static int __devinit davinci_spi_probe(struct platform_device *pdev)
return ret;
free_dma:
- edma_free_channel(dspi->dma.tx_channel);
- edma_free_channel(dspi->dma.rx_channel);
- edma_free_slot(dspi->dma.dummy_param_slot);
+ dma_release_channel(dspi->dma_rx);
+ dma_release_channel(dspi->dma_tx);
free_clk:
clk_disable(dspi->clk);
clk_put(dspi->clk);
diff --git a/drivers/staging/omapdrm/omap_drv.c b/drivers/staging/omapdrm/omap_drv.c
index 2ec5264..ebdb0b6 100644
--- a/drivers/staging/omapdrm/omap_drv.c
+++ b/drivers/staging/omapdrm/omap_drv.c
@@ -106,7 +106,8 @@ static void dump_video_chains(void)
for (i = 0; i < omap_dss_get_num_overlays(); i++) {
struct omap_overlay *ovl = omap_dss_get_overlay(i);
struct omap_overlay_manager *mgr = ovl->manager;
- struct omap_dss_device *dssdev = mgr ? mgr->device : NULL;
+ struct omap_dss_device *dssdev = mgr ?
+ mgr->get_device(mgr) : NULL;
if (dssdev) {
DBG("%d: %s -> %s -> %s", i, ovl->name, mgr->name,
dssdev->name);
@@ -185,7 +186,7 @@ static int create_connector(struct drm_device *dev,
for (j = 0; j < priv->num_encoders; j++) {
struct omap_overlay_manager *mgr =
omap_encoder_get_manager(priv->encoders[j]);
- if (mgr->device == dssdev) {
+ if (mgr->get_device(mgr) == dssdev) {
drm_mode_connector_attach_encoder(connector,
priv->encoders[j]);
}
diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c
index 97c0f78..d6ce218 100644
--- a/drivers/target/iscsi/iscsi_target.c
+++ b/drivers/target/iscsi/iscsi_target.c
@@ -427,7 +427,7 @@ int iscsit_reset_np_thread(
return 0;
}
-int iscsit_del_np_comm(struct iscsi_np *np)
+static int iscsit_del_np_comm(struct iscsi_np *np)
{
if (np->np_socket)
sock_release(np->np_socket);
@@ -785,10 +785,6 @@ static int iscsit_handle_scsi_cmd(
hdr = (struct iscsi_scsi_req *) buf;
payload_length = ntoh24(hdr->dlength);
- hdr->itt = be32_to_cpu(hdr->itt);
- hdr->data_length = be32_to_cpu(hdr->data_length);
- hdr->cmdsn = be32_to_cpu(hdr->cmdsn);
- hdr->exp_statsn = be32_to_cpu(hdr->exp_statsn);
/* FIXME; Add checks for AdditionalHeaderSegment */
@@ -852,7 +848,7 @@ done:
buf, conn);
}
- if ((hdr->data_length == payload_length) &&
+ if ((be32_to_cpu(hdr->data_length )== payload_length) &&
(!(hdr->flags & ISCSI_FLAG_CMD_FINAL))) {
pr_err("Expected Data Transfer Length and Length of"
" Immediate Data are the same, but ISCSI_FLAG_CMD_FINAL"
@@ -861,7 +857,7 @@ done:
buf, conn);
}
- if (payload_length > hdr->data_length) {
+ if (payload_length > be32_to_cpu(hdr->data_length)) {
pr_err("DataSegmentLength: %u is greater than"
" EDTL: %u, protocol error.\n", payload_length,
hdr->data_length);
@@ -869,10 +865,10 @@ done:
buf, conn);
}
- if (payload_length > conn->conn_ops->MaxRecvDataSegmentLength) {
+ if (payload_length > conn->conn_ops->MaxXmitDataSegmentLength) {
pr_err("DataSegmentLength: %u is greater than"
- " MaxRecvDataSegmentLength: %u, protocol error.\n",
- payload_length, conn->conn_ops->MaxRecvDataSegmentLength);
+ " MaxXmitDataSegmentLength: %u, protocol error.\n",
+ payload_length, conn->conn_ops->MaxXmitDataSegmentLength);
return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1,
buf, conn);
}
@@ -932,8 +928,8 @@ done:
spin_unlock_bh(&conn->sess->ttt_lock);
} else if (hdr->flags & ISCSI_FLAG_CMD_WRITE)
cmd->targ_xfer_tag = 0xFFFFFFFF;
- cmd->cmd_sn = hdr->cmdsn;
- cmd->exp_stat_sn = hdr->exp_statsn;
+ cmd->cmd_sn = be32_to_cpu(hdr->cmdsn);
+ cmd->exp_stat_sn = be32_to_cpu(hdr->exp_statsn);
cmd->first_burst_len = payload_length;
if (cmd->data_direction == DMA_FROM_DEVICE) {
@@ -952,8 +948,9 @@ done:
* Initialize struct se_cmd descriptor from target_core_mod infrastructure
*/
transport_init_se_cmd(&cmd->se_cmd, &lio_target_fabric_configfs->tf_ops,
- conn->sess->se_sess, hdr->data_length, cmd->data_direction,
- sam_task_attr, &cmd->sense_buffer[0]);
+ conn->sess->se_sess, be32_to_cpu(hdr->data_length),
+ cmd->data_direction, sam_task_attr,
+ cmd->sense_buffer + 2);
pr_debug("Got SCSI Command, ITT: 0x%08x, CmdSN: 0x%08x,"
" ExpXferLen: %u, Length: %u, CID: %hu\n", hdr->itt,
@@ -1028,7 +1025,7 @@ attach_cmd:
1, 0, buf, cmd);
}
- iscsit_ack_from_expstatsn(conn, hdr->exp_statsn);
+ iscsit_ack_from_expstatsn(conn, be32_to_cpu(hdr->exp_statsn));
/*
* If no Immediate Data is attached, it's OK to return now.
@@ -1194,11 +1191,6 @@ static int iscsit_handle_data_out(struct iscsi_conn *conn, unsigned char *buf)
hdr = (struct iscsi_data *) buf;
payload_length = ntoh24(hdr->dlength);
- hdr->itt = be32_to_cpu(hdr->itt);
- hdr->ttt = be32_to_cpu(hdr->ttt);
- hdr->exp_statsn = be32_to_cpu(hdr->exp_statsn);
- hdr->datasn = be32_to_cpu(hdr->datasn);
- hdr->offset = be32_to_cpu(hdr->offset);
if (!payload_length) {
pr_err("DataOUT payload is ZERO, protocol error.\n");
@@ -1216,10 +1208,10 @@ static int iscsit_handle_data_out(struct iscsi_conn *conn, unsigned char *buf)
}
spin_unlock_bh(&conn->sess->session_stats_lock);
- if (payload_length > conn->conn_ops->MaxRecvDataSegmentLength) {
+ if (payload_length > conn->conn_ops->MaxXmitDataSegmentLength) {
pr_err("DataSegmentLength: %u is greater than"
- " MaxRecvDataSegmentLength: %u\n", payload_length,
- conn->conn_ops->MaxRecvDataSegmentLength);
+ " MaxXmitDataSegmentLength: %u\n", payload_length,
+ conn->conn_ops->MaxXmitDataSegmentLength);
return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1,
buf, conn);
}
@@ -1250,7 +1242,7 @@ static int iscsit_handle_data_out(struct iscsi_conn *conn, unsigned char *buf)
se_cmd = &cmd->se_cmd;
iscsit_mod_dataout_timer(cmd);
- if ((hdr->offset + payload_length) > cmd->se_cmd.data_length) {
+ if ((be32_to_cpu(hdr->offset) + payload_length) > cmd->se_cmd.data_length) {
pr_err("DataOut Offset: %u, Length %u greater than"
" iSCSI Command EDTL %u, protocol error.\n",
hdr->offset, payload_length, cmd->se_cmd.data_length);
@@ -1333,7 +1325,8 @@ static int iscsit_handle_data_out(struct iscsi_conn *conn, unsigned char *buf)
rx_size += payload_length;
iov = &cmd->iov_data[0];
- iov_ret = iscsit_map_iovec(cmd, iov, hdr->offset, payload_length);
+ iov_ret = iscsit_map_iovec(cmd, iov, be32_to_cpu(hdr->offset),
+ payload_length);
if (iov_ret < 0)
return -1;
@@ -1364,7 +1357,8 @@ static int iscsit_handle_data_out(struct iscsi_conn *conn, unsigned char *buf)
u32 data_crc;
data_crc = iscsit_do_crypto_hash_sg(&conn->conn_rx_hash, cmd,
- hdr->offset, payload_length, padding,
+ be32_to_cpu(hdr->offset),
+ payload_length, padding,
cmd->pad_bytes);
if (checksum != data_crc) {
@@ -1425,30 +1419,26 @@ static int iscsit_handle_nop_out(
hdr = (struct iscsi_nopout *) buf;
payload_length = ntoh24(hdr->dlength);
- hdr->itt = be32_to_cpu(hdr->itt);
- hdr->ttt = be32_to_cpu(hdr->ttt);
- hdr->cmdsn = be32_to_cpu(hdr->cmdsn);
- hdr->exp_statsn = be32_to_cpu(hdr->exp_statsn);
- if ((hdr->itt == 0xFFFFFFFF) && !(hdr->opcode & ISCSI_OP_IMMEDIATE)) {
+ if (hdr->itt == RESERVED_ITT && !(hdr->opcode & ISCSI_OP_IMMEDIATE)) {
pr_err("NOPOUT ITT is reserved, but Immediate Bit is"
" not set, protocol error.\n");
return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1,
buf, conn);
}
- if (payload_length > conn->conn_ops->MaxRecvDataSegmentLength) {
+ if (payload_length > conn->conn_ops->MaxXmitDataSegmentLength) {
pr_err("NOPOUT Ping Data DataSegmentLength: %u is"
- " greater than MaxRecvDataSegmentLength: %u, protocol"
+ " greater than MaxXmitDataSegmentLength: %u, protocol"
" error.\n", payload_length,
- conn->conn_ops->MaxRecvDataSegmentLength);
+ conn->conn_ops->MaxXmitDataSegmentLength);
return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1,
buf, conn);
}
pr_debug("Got NOPOUT Ping %s ITT: 0x%08x, TTT: 0x%09x,"
" CmdSN: 0x%08x, ExpStatSN: 0x%08x, Length: %u\n",
- (hdr->itt == 0xFFFFFFFF) ? "Response" : "Request",
+ hdr->itt == RESERVED_ITT ? "Response" : "Request",
hdr->itt, hdr->ttt, hdr->cmdsn, hdr->exp_statsn,
payload_length);
/*
@@ -1458,7 +1448,7 @@ static int iscsit_handle_nop_out(
* Either way, make sure we allocate an struct iscsi_cmd, as both
* can contain ping data.
*/
- if (hdr->ttt == 0xFFFFFFFF) {
+ if (hdr->ttt == cpu_to_be32(0xFFFFFFFF)) {
cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);
if (!cmd)
return iscsit_add_reject(
@@ -1471,12 +1461,12 @@ static int iscsit_handle_nop_out(
1 : 0);
conn->sess->init_task_tag = cmd->init_task_tag = hdr->itt;
cmd->targ_xfer_tag = 0xFFFFFFFF;
- cmd->cmd_sn = hdr->cmdsn;
- cmd->exp_stat_sn = hdr->exp_statsn;
+ cmd->cmd_sn = be32_to_cpu(hdr->cmdsn);
+ cmd->exp_stat_sn = be32_to_cpu(hdr->exp_statsn);
cmd->data_direction = DMA_NONE;
}
- if (payload_length && (hdr->ttt == 0xFFFFFFFF)) {
+ if (payload_length && hdr->ttt == cpu_to_be32(0xFFFFFFFF)) {
rx_size = payload_length;
ping_data = kzalloc(payload_length + 1, GFP_KERNEL);
if (!ping_data) {
@@ -1556,7 +1546,7 @@ static int iscsit_handle_nop_out(
pr_debug("Ping Data: \"%s\"\n", ping_data);
}
- if (hdr->itt != 0xFFFFFFFF) {
+ if (hdr->itt != RESERVED_ITT) {
if (!cmd) {
pr_err("Checking CmdSN for NOPOUT,"
" but cmd is NULL!\n");
@@ -1569,7 +1559,7 @@ static int iscsit_handle_nop_out(
list_add_tail(&cmd->i_conn_node, &conn->conn_cmd_list);
spin_unlock_bh(&conn->cmd_lock);
- iscsit_ack_from_expstatsn(conn, hdr->exp_statsn);
+ iscsit_ack_from_expstatsn(conn, be32_to_cpu(hdr->exp_statsn));
if (hdr->opcode & ISCSI_OP_IMMEDIATE) {
iscsit_add_cmd_to_response_queue(cmd, conn,
@@ -1590,11 +1580,11 @@ static int iscsit_handle_nop_out(
return 0;
}
- if (hdr->ttt != 0xFFFFFFFF) {
+ if (hdr->ttt != cpu_to_be32(0xFFFFFFFF)) {
/*
* This was a response to a unsolicited NOPIN ping.
*/
- cmd = iscsit_find_cmd_from_ttt(conn, hdr->ttt);
+ cmd = iscsit_find_cmd_from_ttt(conn, be32_to_cpu(hdr->ttt));
if (!cmd)
return -1;
@@ -1639,12 +1629,6 @@ static int iscsit_handle_task_mgt_cmd(
u8 function;
hdr = (struct iscsi_tm *) buf;
- hdr->itt = be32_to_cpu(hdr->itt);
- hdr->rtt = be32_to_cpu(hdr->rtt);
- hdr->cmdsn = be32_to_cpu(hdr->cmdsn);
- hdr->exp_statsn = be32_to_cpu(hdr->exp_statsn);
- hdr->refcmdsn = be32_to_cpu(hdr->refcmdsn);
- hdr->exp_datasn = be32_to_cpu(hdr->exp_datasn);
hdr->flags &= ~ISCSI_FLAG_CMD_FINAL;
function = hdr->flags;
@@ -1655,9 +1639,9 @@ static int iscsit_handle_task_mgt_cmd(
if ((function != ISCSI_TM_FUNC_ABORT_TASK) &&
((function != ISCSI_TM_FUNC_TASK_REASSIGN) &&
- (hdr->rtt != ISCSI_RESERVED_TAG))) {
+ hdr->rtt != RESERVED_ITT)) {
pr_err("RefTaskTag should be set to 0xFFFFFFFF.\n");
- hdr->rtt = ISCSI_RESERVED_TAG;
+ hdr->rtt = RESERVED_ITT;
}
if ((function == ISCSI_TM_FUNC_TASK_REASSIGN) &&
@@ -1669,8 +1653,8 @@ static int iscsit_handle_task_mgt_cmd(
buf, conn);
}
if ((function != ISCSI_TM_FUNC_ABORT_TASK) &&
- (hdr->refcmdsn != ISCSI_RESERVED_TAG))
- hdr->refcmdsn = ISCSI_RESERVED_TAG;
+ be32_to_cpu(hdr->refcmdsn) != ISCSI_RESERVED_TAG)
+ hdr->refcmdsn = cpu_to_be32(ISCSI_RESERVED_TAG);
cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);
if (!cmd)
@@ -1700,7 +1684,7 @@ static int iscsit_handle_task_mgt_cmd(
transport_init_se_cmd(&cmd->se_cmd,
&lio_target_fabric_configfs->tf_ops,
conn->sess->se_sess, 0, DMA_NONE,
- MSG_SIMPLE_TAG, &cmd->sense_buffer[0]);
+ MSG_SIMPLE_TAG, cmd->sense_buffer + 2);
switch (function) {
case ISCSI_TM_FUNC_ABORT_TASK:
@@ -1747,8 +1731,8 @@ static int iscsit_handle_task_mgt_cmd(
cmd->immediate_cmd = ((hdr->opcode & ISCSI_OP_IMMEDIATE) ? 1 : 0);
cmd->init_task_tag = hdr->itt;
cmd->targ_xfer_tag = 0xFFFFFFFF;
- cmd->cmd_sn = hdr->cmdsn;
- cmd->exp_stat_sn = hdr->exp_statsn;
+ cmd->cmd_sn = be32_to_cpu(hdr->cmdsn);
+ cmd->exp_stat_sn = be32_to_cpu(hdr->exp_statsn);
se_tmr = cmd->se_cmd.se_tmr_req;
tmr_req = cmd->tmr_req;
/*
@@ -1832,7 +1816,7 @@ attach:
ISCSI_REASON_PROTOCOL_ERROR,
1, 0, buf, cmd);
}
- iscsit_ack_from_expstatsn(conn, hdr->exp_statsn);
+ iscsit_ack_from_expstatsn(conn, be32_to_cpu(hdr->exp_statsn));
if (out_of_order_cmdsn || !(hdr->opcode & ISCSI_OP_IMMEDIATE))
return 0;
@@ -1869,15 +1853,11 @@ static int iscsit_handle_text_cmd(
hdr = (struct iscsi_text *) buf;
payload_length = ntoh24(hdr->dlength);
- hdr->itt = be32_to_cpu(hdr->itt);
- hdr->ttt = be32_to_cpu(hdr->ttt);
- hdr->cmdsn = be32_to_cpu(hdr->cmdsn);
- hdr->exp_statsn = be32_to_cpu(hdr->exp_statsn);
- if (payload_length > conn->conn_ops->MaxRecvDataSegmentLength) {
+ if (payload_length > conn->conn_ops->MaxXmitDataSegmentLength) {
pr_err("Unable to accept text parameter length: %u"
- "greater than MaxRecvDataSegmentLength %u.\n",
- payload_length, conn->conn_ops->MaxRecvDataSegmentLength);
+ "greater than MaxXmitDataSegmentLength %u.\n",
+ payload_length, conn->conn_ops->MaxXmitDataSegmentLength);
return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1,
buf, conn);
}
@@ -1989,15 +1969,15 @@ static int iscsit_handle_text_cmd(
cmd->immediate_cmd = ((hdr->opcode & ISCSI_OP_IMMEDIATE) ? 1 : 0);
conn->sess->init_task_tag = cmd->init_task_tag = hdr->itt;
cmd->targ_xfer_tag = 0xFFFFFFFF;
- cmd->cmd_sn = hdr->cmdsn;
- cmd->exp_stat_sn = hdr->exp_statsn;
+ cmd->cmd_sn = be32_to_cpu(hdr->cmdsn);
+ cmd->exp_stat_sn = be32_to_cpu(hdr->exp_statsn);
cmd->data_direction = DMA_NONE;
spin_lock_bh(&conn->cmd_lock);
list_add_tail(&cmd->i_conn_node, &conn->conn_cmd_list);
spin_unlock_bh(&conn->cmd_lock);
- iscsit_ack_from_expstatsn(conn, hdr->exp_statsn);
+ iscsit_ack_from_expstatsn(conn, be32_to_cpu(hdr->exp_statsn));
if (!(hdr->opcode & ISCSI_OP_IMMEDIATE)) {
cmdsn_ret = iscsit_sequence_cmd(conn, cmd, hdr->cmdsn);
@@ -2131,10 +2111,6 @@ static int iscsit_handle_logout_cmd(
hdr = (struct iscsi_logout *) buf;
reason_code = (hdr->flags & 0x7f);
- hdr->itt = be32_to_cpu(hdr->itt);
- hdr->cid = be16_to_cpu(hdr->cid);
- hdr->cmdsn = be32_to_cpu(hdr->cmdsn);
- hdr->exp_statsn = be32_to_cpu(hdr->exp_statsn);
if (tiqn) {
spin_lock(&tiqn->logout_stats.lock);
@@ -2166,9 +2142,9 @@ static int iscsit_handle_logout_cmd(
cmd->immediate_cmd = ((hdr->opcode & ISCSI_OP_IMMEDIATE) ? 1 : 0);
conn->sess->init_task_tag = cmd->init_task_tag = hdr->itt;
cmd->targ_xfer_tag = 0xFFFFFFFF;
- cmd->cmd_sn = hdr->cmdsn;
- cmd->exp_stat_sn = hdr->exp_statsn;
- cmd->logout_cid = hdr->cid;
+ cmd->cmd_sn = be32_to_cpu(hdr->cmdsn);
+ cmd->exp_stat_sn = be32_to_cpu(hdr->exp_statsn);
+ cmd->logout_cid = be16_to_cpu(hdr->cid);
cmd->logout_reason = reason_code;
cmd->data_direction = DMA_NONE;
@@ -2178,7 +2154,7 @@ static int iscsit_handle_logout_cmd(
*/
if ((reason_code == ISCSI_LOGOUT_REASON_CLOSE_SESSION) ||
((reason_code == ISCSI_LOGOUT_REASON_CLOSE_CONNECTION) &&
- (hdr->cid == conn->cid)))
+ be16_to_cpu(hdr->cid) == conn->cid))
logout_remove = 1;
spin_lock_bh(&conn->cmd_lock);
@@ -2186,7 +2162,7 @@ static int iscsit_handle_logout_cmd(
spin_unlock_bh(&conn->cmd_lock);
if (reason_code != ISCSI_LOGOUT_REASON_RECOVERY)
- iscsit_ack_from_expstatsn(conn, hdr->exp_statsn);
+ iscsit_ack_from_expstatsn(conn, be32_to_cpu(hdr->exp_statsn));
/*
* Immediate commands are executed, well, immediately.
@@ -2219,11 +2195,6 @@ static int iscsit_handle_snack(
hdr = (struct iscsi_snack *) buf;
hdr->flags &= ~ISCSI_FLAG_CMD_FINAL;
- hdr->itt = be32_to_cpu(hdr->itt);
- hdr->ttt = be32_to_cpu(hdr->ttt);
- hdr->exp_statsn = be32_to_cpu(hdr->exp_statsn);
- hdr->begrun = be32_to_cpu(hdr->begrun);
- hdr->runlength = be32_to_cpu(hdr->runlength);
pr_debug("Got ISCSI_INIT_SNACK, ITT: 0x%08x, ExpStatSN:"
" 0x%08x, Type: 0x%02x, BegRun: 0x%08x, RunLength: 0x%08x,"
@@ -2243,13 +2214,18 @@ static int iscsit_handle_snack(
switch (hdr->flags & ISCSI_FLAG_SNACK_TYPE_MASK) {
case 0:
return iscsit_handle_recovery_datain_or_r2t(conn, buf,
- hdr->itt, hdr->ttt, hdr->begrun, hdr->runlength);
+ hdr->itt,
+ be32_to_cpu(hdr->ttt),
+ be32_to_cpu(hdr->begrun),
+ be32_to_cpu(hdr->runlength));
case ISCSI_FLAG_SNACK_TYPE_STATUS:
- return iscsit_handle_status_snack(conn, hdr->itt, hdr->ttt,
- hdr->begrun, hdr->runlength);
+ return iscsit_handle_status_snack(conn, hdr->itt,
+ be32_to_cpu(hdr->ttt),
+ be32_to_cpu(hdr->begrun), be32_to_cpu(hdr->runlength));
case ISCSI_FLAG_SNACK_TYPE_DATA_ACK:
- return iscsit_handle_data_ack(conn, hdr->ttt, hdr->begrun,
- hdr->runlength);
+ return iscsit_handle_data_ack(conn, be32_to_cpu(hdr->ttt),
+ be32_to_cpu(hdr->begrun),
+ be32_to_cpu(hdr->runlength));
case ISCSI_FLAG_SNACK_TYPE_RDATA:
/* FIXME: Support R-Data SNACK */
pr_err("R-Data SNACK Not Supported.\n");
@@ -2414,7 +2390,7 @@ static int iscsit_send_conn_drop_async_message(
hdr = (struct iscsi_async *) cmd->pdu;
hdr->opcode = ISCSI_OP_ASYNC_EVENT;
hdr->flags = ISCSI_FLAG_CMD_FINAL;
- cmd->init_task_tag = 0xFFFFFFFF;
+ cmd->init_task_tag = RESERVED_ITT;
cmd->targ_xfer_tag = 0xFFFFFFFF;
put_unaligned_be64(0xFFFFFFFFFFFFFFFFULL, &hdr->rsvd4[0]);
cmd->stat_sn = conn->stat_sn++;
@@ -2536,12 +2512,17 @@ static int iscsit_send_data_in(
else
put_unaligned_le64(0xFFFFFFFFFFFFFFFFULL, &hdr->lun);
- hdr->itt = cpu_to_be32(cmd->init_task_tag);
- hdr->ttt = (hdr->flags & ISCSI_FLAG_DATA_ACK) ?
- cpu_to_be32(cmd->targ_xfer_tag) :
- 0xFFFFFFFF;
- hdr->statsn = (set_statsn) ? cpu_to_be32(cmd->stat_sn) :
- 0xFFFFFFFF;
+ hdr->itt = cmd->init_task_tag;
+
+ if (hdr->flags & ISCSI_FLAG_DATA_ACK)
+ hdr->ttt = cpu_to_be32(cmd->targ_xfer_tag);
+ else
+ hdr->ttt = cpu_to_be32(0xFFFFFFFF);
+ if (set_statsn)
+ hdr->statsn = cpu_to_be32(cmd->stat_sn);
+ else
+ hdr->statsn = cpu_to_be32(0xFFFFFFFF);
+
hdr->exp_cmdsn = cpu_to_be32(conn->sess->exp_cmd_sn);
hdr->max_cmdsn = cpu_to_be32(conn->sess->max_cmd_sn);
hdr->datasn = cpu_to_be32(datain.data_sn);
@@ -2708,7 +2689,7 @@ static int iscsit_send_logout_response(
hdr->opcode = ISCSI_OP_LOGOUT_RSP;
hdr->flags |= ISCSI_FLAG_CMD_FINAL;
hdr->response = cmd->logout_response;
- hdr->itt = cpu_to_be32(cmd->init_task_tag);
+ hdr->itt = cmd->init_task_tag;
cmd->stat_sn = conn->stat_sn++;
hdr->statsn = cpu_to_be32(cmd->stat_sn);
@@ -2759,7 +2740,7 @@ static int iscsit_send_unsolicited_nopin(
memset(hdr, 0, ISCSI_HDR_LEN);
hdr->opcode = ISCSI_OP_NOOP_IN;
hdr->flags |= ISCSI_FLAG_CMD_FINAL;
- hdr->itt = cpu_to_be32(cmd->init_task_tag);
+ hdr->itt = cmd->init_task_tag;
hdr->ttt = cpu_to_be32(cmd->targ_xfer_tag);
cmd->stat_sn = conn->stat_sn;
hdr->statsn = cpu_to_be32(cmd->stat_sn);
@@ -2816,7 +2797,7 @@ static int iscsit_send_nopin_response(
hdr->flags |= ISCSI_FLAG_CMD_FINAL;
hton24(hdr->dlength, cmd->buf_ptr_size);
put_unaligned_le64(0xFFFFFFFFFFFFFFFFULL, &hdr->lun);
- hdr->itt = cpu_to_be32(cmd->init_task_tag);
+ hdr->itt = cmd->init_task_tag;
hdr->ttt = cpu_to_be32(cmd->targ_xfer_tag);
cmd->stat_sn = conn->stat_sn++;
hdr->statsn = cpu_to_be32(cmd->stat_sn);
@@ -2906,7 +2887,7 @@ static int iscsit_send_r2t(
hdr->flags |= ISCSI_FLAG_CMD_FINAL;
int_to_scsilun(cmd->se_cmd.orig_fe_lun,
(struct scsi_lun *)&hdr->lun);
- hdr->itt = cpu_to_be32(cmd->init_task_tag);
+ hdr->itt = cmd->init_task_tag;
spin_lock_bh(&conn->sess->ttt_lock);
r2t->targ_xfer_tag = conn->sess->targ_xfer_tag++;
if (r2t->targ_xfer_tag == 0xFFFFFFFF)
@@ -3074,7 +3055,7 @@ static int iscsit_send_status(
}
hdr->response = cmd->iscsi_response;
hdr->cmd_status = cmd->se_cmd.scsi_status;
- hdr->itt = cpu_to_be32(cmd->init_task_tag);
+ hdr->itt = cmd->init_task_tag;
hdr->statsn = cpu_to_be32(cmd->stat_sn);
iscsit_increment_maxcmdsn(cmd, conn->sess);
@@ -3092,15 +3073,18 @@ static int iscsit_send_status(
if (cmd->se_cmd.sense_buffer &&
((cmd->se_cmd.se_cmd_flags & SCF_TRANSPORT_TASK_SENSE) ||
(cmd->se_cmd.se_cmd_flags & SCF_EMULATED_TASK_SENSE))) {
+ put_unaligned_be16(cmd->se_cmd.scsi_sense_length, cmd->sense_buffer);
+ cmd->se_cmd.scsi_sense_length += sizeof (__be16);
+
padding = -(cmd->se_cmd.scsi_sense_length) & 3;
- hton24(hdr->dlength, cmd->se_cmd.scsi_sense_length);
- iov[iov_count].iov_base = cmd->se_cmd.sense_buffer;
+ hton24(hdr->dlength, (u32)cmd->se_cmd.scsi_sense_length);
+ iov[iov_count].iov_base = cmd->sense_buffer;
iov[iov_count++].iov_len =
(cmd->se_cmd.scsi_sense_length + padding);
tx_size += cmd->se_cmd.scsi_sense_length;
if (padding) {
- memset(cmd->se_cmd.sense_buffer +
+ memset(cmd->sense_buffer +
cmd->se_cmd.scsi_sense_length, 0, padding);
tx_size += padding;
pr_debug("Adding %u bytes of padding to"
@@ -3109,7 +3093,7 @@ static int iscsit_send_status(
if (conn->conn_ops->DataDigest) {
iscsit_do_crypto_hash_buf(&conn->conn_tx_hash,
- cmd->se_cmd.sense_buffer,
+ cmd->sense_buffer,
(cmd->se_cmd.scsi_sense_length + padding),
0, NULL, (u8 *)&cmd->data_crc);
@@ -3184,7 +3168,7 @@ static int iscsit_send_task_mgt_rsp(
hdr->opcode = ISCSI_OP_SCSI_TMFUNC_RSP;
hdr->flags = ISCSI_FLAG_CMD_FINAL;
hdr->response = iscsit_convert_tcm_tmr_rsp(se_tmr);
- hdr->itt = cpu_to_be32(cmd->init_task_tag);
+ hdr->itt = cmd->init_task_tag;
cmd->stat_sn = conn->stat_sn++;
hdr->statsn = cpu_to_be32(cmd->stat_sn);
@@ -3236,7 +3220,7 @@ static bool iscsit_check_inaddr_any(struct iscsi_np *np)
struct sockaddr_in * sock_in =
(struct sockaddr_in *)&np->np_sockaddr;
- if (sock_in->sin_addr.s_addr == INADDR_ANY)
+ if (sock_in->sin_addr.s_addr == htonl(INADDR_ANY))
ret = true;
}
@@ -3271,7 +3255,6 @@ static int iscsit_build_sendtargets_response(struct iscsi_cmd *cmd)
len += 1;
if ((len + payload_len) > buffer_len) {
- spin_unlock(&tiqn->tiqn_tpg_lock);
end_of_buf = 1;
goto eob;
}
@@ -3358,7 +3341,7 @@ static int iscsit_send_text_rsp(
hdr->opcode = ISCSI_OP_TEXT_RSP;
hdr->flags |= ISCSI_FLAG_CMD_FINAL;
hton24(hdr->dlength, text_length);
- hdr->itt = cpu_to_be32(cmd->init_task_tag);
+ hdr->itt = cmd->init_task_tag;
hdr->ttt = cpu_to_be32(cmd->targ_xfer_tag);
cmd->stat_sn = conn->stat_sn++;
hdr->statsn = cpu_to_be32(cmd->stat_sn);
@@ -3424,6 +3407,7 @@ static int iscsit_send_reject(
hdr->opcode = ISCSI_OP_REJECT;
hdr->flags |= ISCSI_FLAG_CMD_FINAL;
hton24(hdr->dlength, ISCSI_HDR_LEN);
+ hdr->ffffffff = cpu_to_be32(0xffffffff);
cmd->stat_sn = conn->stat_sn++;
hdr->statsn = cpu_to_be32(cmd->stat_sn);
hdr->exp_cmdsn = cpu_to_be32(conn->sess->exp_cmd_sn);
diff --git a/drivers/target/iscsi/iscsi_target.h b/drivers/target/iscsi/iscsi_target.h
index 12abb4c..f1e4f31 100644
--- a/drivers/target/iscsi/iscsi_target.h
+++ b/drivers/target/iscsi/iscsi_target.h
@@ -38,4 +38,9 @@ extern struct kmem_cache *lio_cmd_cache;
extern struct kmem_cache *lio_qr_cache;
extern struct kmem_cache *lio_r2t_cache;
+extern struct idr sess_idr;
+extern struct mutex auth_id_lock;
+extern spinlock_t sess_idr_lock;
+
+
#endif /*** ISCSI_TARGET_H ***/
diff --git a/drivers/target/iscsi/iscsi_target_configfs.c b/drivers/target/iscsi/iscsi_target_configfs.c
index a7b25e78..ff6fd4f 100644
--- a/drivers/target/iscsi/iscsi_target_configfs.c
+++ b/drivers/target/iscsi/iscsi_target_configfs.c
@@ -135,7 +135,7 @@ static struct configfs_attribute *lio_target_portal_attrs[] = {
#define MAX_PORTAL_LEN 256
-struct se_tpg_np *lio_target_call_addnptotpg(
+static struct se_tpg_np *lio_target_call_addnptotpg(
struct se_portal_group *se_tpg,
struct config_group *group,
const char *name)
@@ -1034,6 +1034,9 @@ TPG_PARAM_ATTR(ImmediateData, S_IRUGO | S_IWUSR);
DEF_TPG_PARAM(MaxRecvDataSegmentLength);
TPG_PARAM_ATTR(MaxRecvDataSegmentLength, S_IRUGO | S_IWUSR);
+DEF_TPG_PARAM(MaxXmitDataSegmentLength);
+TPG_PARAM_ATTR(MaxXmitDataSegmentLength, S_IRUGO | S_IWUSR);
+
DEF_TPG_PARAM(MaxBurstLength);
TPG_PARAM_ATTR(MaxBurstLength, S_IRUGO | S_IWUSR);
@@ -1079,6 +1082,7 @@ static struct configfs_attribute *lio_target_tpg_param_attrs[] = {
&iscsi_tpg_param_InitialR2T.attr,
&iscsi_tpg_param_ImmediateData.attr,
&iscsi_tpg_param_MaxRecvDataSegmentLength.attr,
+ &iscsi_tpg_param_MaxXmitDataSegmentLength.attr,
&iscsi_tpg_param_MaxBurstLength.attr,
&iscsi_tpg_param_FirstBurstLength.attr,
&iscsi_tpg_param_DefaultTime2Wait.attr,
@@ -1166,7 +1170,7 @@ static struct configfs_attribute *lio_target_tpg_attrs[] = {
/* Start items for lio_target_tiqn_cit */
-struct se_portal_group *lio_target_tiqn_addtpg(
+static struct se_portal_group *lio_target_tiqn_addtpg(
struct se_wwn *wwn,
struct config_group *group,
const char *name)
@@ -1216,7 +1220,7 @@ out:
return NULL;
}
-void lio_target_tiqn_deltpg(struct se_portal_group *se_tpg)
+static void lio_target_tiqn_deltpg(struct se_portal_group *se_tpg)
{
struct iscsi_portal_group *tpg;
struct iscsi_tiqn *tiqn;
@@ -1248,7 +1252,7 @@ static struct configfs_attribute *lio_target_wwn_attrs[] = {
NULL,
};
-struct se_wwn *lio_target_call_coreaddtiqn(
+static struct se_wwn *lio_target_call_coreaddtiqn(
struct target_fabric_configfs *tf,
struct config_group *group,
const char *name)
@@ -1296,7 +1300,7 @@ struct se_wwn *lio_target_call_coreaddtiqn(
return &tiqn->tiqn_wwn;
}
-void lio_target_call_coredeltiqn(
+static void lio_target_call_coredeltiqn(
struct se_wwn *wwn)
{
struct iscsi_tiqn *tiqn = container_of(wwn, struct iscsi_tiqn, tiqn_wwn);
@@ -1471,7 +1475,8 @@ static u32 iscsi_get_task_tag(struct se_cmd *se_cmd)
{
struct iscsi_cmd *cmd = container_of(se_cmd, struct iscsi_cmd, se_cmd);
- return cmd->init_task_tag;
+ /* only used for printks or comparism with ->ref_task_tag */
+ return (__force u32)cmd->init_task_tag;
}
static int iscsi_get_cmd_state(struct se_cmd *se_cmd)
@@ -1542,29 +1547,6 @@ static int lio_queue_status(struct se_cmd *se_cmd)
return 0;
}
-static u16 lio_set_fabric_sense_len(struct se_cmd *se_cmd, u32 sense_length)
-{
- unsigned char *buffer = se_cmd->sense_buffer;
- /*
- * From RFC-3720 10.4.7. Data Segment - Sense and Response Data Segment
- * 16-bit SenseLength.
- */
- buffer[0] = ((sense_length >> 8) & 0xff);
- buffer[1] = (sense_length & 0xff);
- /*
- * Return two byte offset into allocated sense_buffer.
- */
- return 2;
-}
-
-static u16 lio_get_fabric_sense_len(void)
-{
- /*
- * Return two byte offset into allocated sense_buffer.
- */
- return 2;
-}
-
static int lio_queue_tm_rsp(struct se_cmd *se_cmd)
{
struct iscsi_cmd *cmd = container_of(se_cmd, struct iscsi_cmd, se_cmd);
@@ -1748,8 +1730,6 @@ int iscsi_target_register_configfs(void)
fabric->tf_ops.queue_data_in = &lio_queue_data_in;
fabric->tf_ops.queue_status = &lio_queue_status;
fabric->tf_ops.queue_tm_rsp = &lio_queue_tm_rsp;
- fabric->tf_ops.set_fabric_sense_len = &lio_set_fabric_sense_len;
- fabric->tf_ops.get_fabric_sense_len = &lio_get_fabric_sense_len;
/*
* Setup function pointers for generic logic in target_core_fabric_configfs.c
*/
diff --git a/drivers/target/iscsi/iscsi_target_core.h b/drivers/target/iscsi/iscsi_target_core.h
index 8a908b2..2ba9f9b 100644
--- a/drivers/target/iscsi/iscsi_target_core.h
+++ b/drivers/target/iscsi/iscsi_target_core.h
@@ -25,10 +25,10 @@
#define NA_DATAOUT_TIMEOUT_RETRIES 5
#define NA_DATAOUT_TIMEOUT_RETRIES_MAX 15
#define NA_DATAOUT_TIMEOUT_RETRIES_MIN 1
-#define NA_NOPIN_TIMEOUT 5
+#define NA_NOPIN_TIMEOUT 15
#define NA_NOPIN_TIMEOUT_MAX 60
#define NA_NOPIN_TIMEOUT_MIN 3
-#define NA_NOPIN_RESPONSE_TIMEOUT 5
+#define NA_NOPIN_RESPONSE_TIMEOUT 30
#define NA_NOPIN_RESPONSE_TIMEOUT_MAX 60
#define NA_NOPIN_RESPONSE_TIMEOUT_MIN 3
#define NA_RANDOM_DATAIN_PDU_OFFSETS 0
@@ -239,6 +239,7 @@ struct iscsi_conn_ops {
u8 HeaderDigest; /* [0,1] == [None,CRC32C] */
u8 DataDigest; /* [0,1] == [None,CRC32C] */
u32 MaxRecvDataSegmentLength; /* [512..2**24-1] */
+ u32 MaxXmitDataSegmentLength; /* [512..2**24-1] */
u8 OFMarker; /* [0,1] == [No,Yes] */
u8 IFMarker; /* [0,1] == [No,Yes] */
u32 OFMarkInt; /* [1..65535] */
@@ -360,7 +361,7 @@ struct iscsi_cmd {
/* Command flags */
enum cmd_flags_table cmd_flags;
/* Initiator Task Tag assigned from Initiator */
- u32 init_task_tag;
+ itt_t init_task_tag;
/* Target Transfer Tag assigned from Target */
u32 targ_xfer_tag;
/* CmdSN assigned from Initiator */
@@ -478,7 +479,6 @@ struct iscsi_cmd {
struct iscsi_tmr_req {
bool task_reassign:1;
- u32 ref_cmd_sn;
u32 exp_data_sn;
struct iscsi_cmd *ref_cmd;
struct iscsi_conn_recovery *conn_recovery;
@@ -505,7 +505,7 @@ struct iscsi_conn {
u32 auth_id;
u32 conn_flags;
/* Used for iscsi_tx_login_rsp() */
- u32 login_itt;
+ itt_t login_itt;
u32 exp_statsn;
/* Per connection status sequence number */
u32 stat_sn;
@@ -578,6 +578,7 @@ struct iscsi_conn_recovery {
u16 cid;
u32 cmd_count;
u32 maxrecvdatasegmentlength;
+ u32 maxxmitdatasegmentlength;
int ready_for_reallegiance;
struct list_head conn_recovery_cmd_list;
spinlock_t conn_recovery_cmd_lock;
@@ -597,7 +598,7 @@ struct iscsi_session {
/* state session is currently in */
u32 session_state;
/* session wide counter: initiator assigned task tag */
- u32 init_task_tag;
+ itt_t init_task_tag;
/* session wide counter: target assigned task tag */
u32 targ_xfer_tag;
u32 cmdsn_window;
@@ -663,7 +664,7 @@ struct iscsi_login {
u8 version_max;
char isid[6];
u32 cmd_sn;
- u32 init_task_tag;
+ itt_t init_task_tag;
u32 initial_exp_statsn;
u32 rsp_length;
u16 cid;
diff --git a/drivers/target/iscsi/iscsi_target_erl0.c b/drivers/target/iscsi/iscsi_target_erl0.c
index 1a02016..8aacf61 100644
--- a/drivers/target/iscsi/iscsi_target_erl0.c
+++ b/drivers/target/iscsi/iscsi_target_erl0.c
@@ -48,9 +48,9 @@ void iscsit_set_dataout_sequence_values(
if (cmd->unsolicited_data) {
cmd->seq_start_offset = cmd->write_data_done;
cmd->seq_end_offset = (cmd->write_data_done +
- (cmd->se_cmd.data_length >
- conn->sess->sess_ops->FirstBurstLength) ?
- conn->sess->sess_ops->FirstBurstLength : cmd->se_cmd.data_length);
+ ((cmd->se_cmd.data_length >
+ conn->sess->sess_ops->FirstBurstLength) ?
+ conn->sess->sess_ops->FirstBurstLength : cmd->se_cmd.data_length));
return;
}
@@ -95,14 +95,15 @@ static int iscsit_dataout_within_command_recovery_check(
*/
if (conn->sess->sess_ops->DataSequenceInOrder) {
if ((cmd->cmd_flags & ICF_WITHIN_COMMAND_RECOVERY) &&
- (cmd->write_data_done != hdr->offset))
+ cmd->write_data_done != be32_to_cpu(hdr->offset))
goto dump;
cmd->cmd_flags &= ~ICF_WITHIN_COMMAND_RECOVERY;
} else {
struct iscsi_seq *seq;
- seq = iscsit_get_seq_holder(cmd, hdr->offset, payload_length);
+ seq = iscsit_get_seq_holder(cmd, be32_to_cpu(hdr->offset),
+ payload_length);
if (!seq)
return DATAOUT_CANNOT_RECOVER;
/*
@@ -111,15 +112,15 @@ static int iscsit_dataout_within_command_recovery_check(
cmd->seq_ptr = seq;
if (conn->sess->sess_ops->DataPDUInOrder) {
- if ((seq->status ==
- DATAOUT_SEQUENCE_WITHIN_COMMAND_RECOVERY) &&
- ((seq->offset != hdr->offset) ||
- (seq->data_sn != hdr->datasn)))
+ if (seq->status ==
+ DATAOUT_SEQUENCE_WITHIN_COMMAND_RECOVERY &&
+ (seq->offset != be32_to_cpu(hdr->offset) ||
+ seq->data_sn != be32_to_cpu(hdr->datasn)))
goto dump;
} else {
- if ((seq->status ==
- DATAOUT_SEQUENCE_WITHIN_COMMAND_RECOVERY) &&
- (seq->data_sn != hdr->datasn))
+ if (seq->status ==
+ DATAOUT_SEQUENCE_WITHIN_COMMAND_RECOVERY &&
+ seq->data_sn != be32_to_cpu(hdr->datasn))
goto dump;
}
@@ -148,12 +149,12 @@ static int iscsit_dataout_check_unsolicited_sequence(
u32 payload_length = ntoh24(hdr->dlength);
- if ((hdr->offset < cmd->seq_start_offset) ||
- ((hdr->offset + payload_length) > cmd->seq_end_offset)) {
+ if ((be32_to_cpu(hdr->offset) < cmd->seq_start_offset) ||
+ ((be32_to_cpu(hdr->offset) + payload_length) > cmd->seq_end_offset)) {
pr_err("Command ITT: 0x%08x with Offset: %u,"
" Length: %u outside of Unsolicited Sequence %u:%u while"
" DataSequenceInOrder=Yes.\n", cmd->init_task_tag,
- hdr->offset, payload_length, cmd->seq_start_offset,
+ be32_to_cpu(hdr->offset), payload_length, cmd->seq_start_offset,
cmd->seq_end_offset);
return DATAOUT_CANNOT_RECOVER;
}
@@ -236,12 +237,12 @@ static int iscsit_dataout_check_sequence(
* fullfilling an Recovery R2T, it's best to just dump the
* payload here, instead of erroring out.
*/
- if ((hdr->offset < cmd->seq_start_offset) ||
- ((hdr->offset + payload_length) > cmd->seq_end_offset)) {
+ if ((be32_to_cpu(hdr->offset) < cmd->seq_start_offset) ||
+ ((be32_to_cpu(hdr->offset) + payload_length) > cmd->seq_end_offset)) {
pr_err("Command ITT: 0x%08x with Offset: %u,"
" Length: %u outside of Sequence %u:%u while"
" DataSequenceInOrder=Yes.\n", cmd->init_task_tag,
- hdr->offset, payload_length, cmd->seq_start_offset,
+ be32_to_cpu(hdr->offset), payload_length, cmd->seq_start_offset,
cmd->seq_end_offset);
if (iscsit_dump_data_payload(conn, payload_length, 1) < 0)
@@ -251,7 +252,8 @@ static int iscsit_dataout_check_sequence(
next_burst_len = (cmd->next_burst_len + payload_length);
} else {
- seq = iscsit_get_seq_holder(cmd, hdr->offset, payload_length);
+ seq = iscsit_get_seq_holder(cmd, be32_to_cpu(hdr->offset),
+ payload_length);
if (!seq)
return DATAOUT_CANNOT_RECOVER;
/*
@@ -366,16 +368,16 @@ static int iscsit_dataout_check_datasn(
data_sn = seq->data_sn;
}
- if (hdr->datasn > data_sn) {
+ if (be32_to_cpu(hdr->datasn) > data_sn) {
pr_err("Command ITT: 0x%08x, received DataSN: 0x%08x"
" higher than expected 0x%08x.\n", cmd->init_task_tag,
- hdr->datasn, data_sn);
+ be32_to_cpu(hdr->datasn), data_sn);
recovery = 1;
goto recover;
- } else if (hdr->datasn < data_sn) {
+ } else if (be32_to_cpu(hdr->datasn) < data_sn) {
pr_err("Command ITT: 0x%08x, received DataSN: 0x%08x"
" lower than expected 0x%08x, discarding payload.\n",
- cmd->init_task_tag, hdr->datasn, data_sn);
+ cmd->init_task_tag, be32_to_cpu(hdr->datasn), data_sn);
dump = 1;
goto dump;
}
@@ -415,26 +417,27 @@ static int iscsit_dataout_pre_datapduinorder_yes(
* error has occured and fail the connection.
*/
if (conn->sess->sess_ops->DataSequenceInOrder) {
- if (hdr->offset != cmd->write_data_done) {
+ if (be32_to_cpu(hdr->offset) != cmd->write_data_done) {
pr_err("Command ITT: 0x%08x, received offset"
" %u different than expected %u.\n", cmd->init_task_tag,
- hdr->offset, cmd->write_data_done);
+ be32_to_cpu(hdr->offset), cmd->write_data_done);
recovery = 1;
goto recover;
}
} else {
struct iscsi_seq *seq = cmd->seq_ptr;
- if (hdr->offset > seq->offset) {
+ if (be32_to_cpu(hdr->offset) > seq->offset) {
pr_err("Command ITT: 0x%08x, received offset"
" %u greater than expected %u.\n", cmd->init_task_tag,
- hdr->offset, seq->offset);
+ be32_to_cpu(hdr->offset), seq->offset);
recovery = 1;
goto recover;
- } else if (hdr->offset < seq->offset) {
+ } else if (be32_to_cpu(hdr->offset) < seq->offset) {
pr_err("Command ITT: 0x%08x, received offset"
" %u less than expected %u, discarding payload.\n",
- cmd->init_task_tag, hdr->offset, seq->offset);
+ cmd->init_task_tag, be32_to_cpu(hdr->offset),
+ seq->offset);
dump = 1;
goto dump;
}
@@ -453,7 +456,7 @@ dump:
return DATAOUT_CANNOT_RECOVER;
return (recovery) ? iscsit_recover_dataout_sequence(cmd,
- hdr->offset, payload_length) :
+ be32_to_cpu(hdr->offset), payload_length) :
(dump) ? DATAOUT_WITHIN_COMMAND_RECOVERY : DATAOUT_NORMAL;
}
@@ -465,7 +468,8 @@ static int iscsit_dataout_pre_datapduinorder_no(
struct iscsi_data *hdr = (struct iscsi_data *) buf;
u32 payload_length = ntoh24(hdr->dlength);
- pdu = iscsit_get_pdu_holder(cmd, hdr->offset, payload_length);
+ pdu = iscsit_get_pdu_holder(cmd, be32_to_cpu(hdr->offset),
+ payload_length);
if (!pdu)
return DATAOUT_CANNOT_RECOVER;
@@ -479,7 +483,7 @@ static int iscsit_dataout_pre_datapduinorder_no(
case ISCSI_PDU_RECEIVED_OK:
pr_err("Command ITT: 0x%08x received already gotten"
" Offset: %u, Length: %u\n", cmd->init_task_tag,
- hdr->offset, payload_length);
+ be32_to_cpu(hdr->offset), payload_length);
return iscsit_dump_data_payload(cmd->conn, payload_length, 1);
default:
return DATAOUT_CANNOT_RECOVER;
@@ -553,7 +557,7 @@ static int iscsit_dataout_post_crc_passed(
if (cmd->unsolicited_data) {
if ((cmd->first_burst_len + payload_length) ==
conn->sess->sess_ops->FirstBurstLength) {
- if (iscsit_dataout_update_r2t(cmd, hdr->offset,
+ if (iscsit_dataout_update_r2t(cmd, be32_to_cpu(hdr->offset),
payload_length) < 0)
return DATAOUT_CANNOT_RECOVER;
send_r2t = 1;
@@ -561,7 +565,8 @@ static int iscsit_dataout_post_crc_passed(
if (!conn->sess->sess_ops->DataPDUInOrder) {
ret = iscsit_dataout_update_datapduinorder_no(cmd,
- hdr->datasn, (hdr->flags & ISCSI_FLAG_CMD_FINAL));
+ be32_to_cpu(hdr->datasn),
+ (hdr->flags & ISCSI_FLAG_CMD_FINAL));
if (ret == DATAOUT_CANNOT_RECOVER)
return ret;
}
@@ -586,7 +591,8 @@ static int iscsit_dataout_post_crc_passed(
if (conn->sess->sess_ops->DataSequenceInOrder) {
if ((cmd->next_burst_len + payload_length) ==
conn->sess->sess_ops->MaxBurstLength) {
- if (iscsit_dataout_update_r2t(cmd, hdr->offset,
+ if (iscsit_dataout_update_r2t(cmd,
+ be32_to_cpu(hdr->offset),
payload_length) < 0)
return DATAOUT_CANNOT_RECOVER;
send_r2t = 1;
@@ -594,7 +600,7 @@ static int iscsit_dataout_post_crc_passed(
if (!conn->sess->sess_ops->DataPDUInOrder) {
ret = iscsit_dataout_update_datapduinorder_no(
- cmd, hdr->datasn,
+ cmd, be32_to_cpu(hdr->datasn),
(hdr->flags & ISCSI_FLAG_CMD_FINAL));
if (ret == DATAOUT_CANNOT_RECOVER)
return ret;
@@ -610,7 +616,8 @@ static int iscsit_dataout_post_crc_passed(
if ((seq->next_burst_len + payload_length) ==
seq->xfer_len) {
- if (iscsit_dataout_update_r2t(cmd, hdr->offset,
+ if (iscsit_dataout_update_r2t(cmd,
+ be32_to_cpu(hdr->offset),
payload_length) < 0)
return DATAOUT_CANNOT_RECOVER;
send_r2t = 1;
@@ -618,7 +625,7 @@ static int iscsit_dataout_post_crc_passed(
if (!conn->sess->sess_ops->DataPDUInOrder) {
ret = iscsit_dataout_update_datapduinorder_no(
- cmd, hdr->datasn,
+ cmd, be32_to_cpu(hdr->datasn),
(hdr->flags & ISCSI_FLAG_CMD_FINAL));
if (ret == DATAOUT_CANNOT_RECOVER)
return ret;
@@ -678,14 +685,15 @@ static int iscsit_dataout_post_crc_failed(
}
recover:
- return iscsit_recover_dataout_sequence(cmd, hdr->offset, payload_length);
+ return iscsit_recover_dataout_sequence(cmd, be32_to_cpu(hdr->offset),
+ payload_length);
}
/*
* Called from iscsit_handle_data_out() before DataOUT Payload is received
* and CRC computed.
*/
-extern int iscsit_check_pre_dataout(
+int iscsit_check_pre_dataout(
struct iscsi_cmd *cmd,
unsigned char *buf)
{
@@ -789,7 +797,7 @@ static void iscsit_handle_time2retain_timeout(unsigned long data)
target_put_session(sess->se_sess);
}
-extern void iscsit_start_time2retain_handler(struct iscsi_session *sess)
+void iscsit_start_time2retain_handler(struct iscsi_session *sess)
{
int tpg_active;
/*
@@ -822,7 +830,7 @@ extern void iscsit_start_time2retain_handler(struct iscsi_session *sess)
/*
* Called with spin_lock_bh(&struct se_portal_group->session_lock) held
*/
-extern int iscsit_stop_time2retain_timer(struct iscsi_session *sess)
+int iscsit_stop_time2retain_timer(struct iscsi_session *sess)
{
struct iscsi_portal_group *tpg = ISCSI_TPG_S(sess);
struct se_portal_group *se_tpg = &tpg->tpg_se_tpg;
@@ -926,7 +934,7 @@ static void iscsit_handle_connection_cleanup(struct iscsi_conn *conn)
}
}
-extern void iscsit_take_action_for_connection_exit(struct iscsi_conn *conn)
+void iscsit_take_action_for_connection_exit(struct iscsi_conn *conn)
{
spin_lock_bh(&conn->state_lock);
if (atomic_read(&conn->connection_exit)) {
diff --git a/drivers/target/iscsi/iscsi_target_erl1.c b/drivers/target/iscsi/iscsi_target_erl1.c
index 3df8a2c..21f29d9 100644
--- a/drivers/target/iscsi/iscsi_target_erl1.c
+++ b/drivers/target/iscsi/iscsi_target_erl1.c
@@ -466,7 +466,7 @@ static int iscsit_handle_recovery_datain(
int iscsit_handle_recovery_datain_or_r2t(
struct iscsi_conn *conn,
unsigned char *buf,
- u32 init_task_tag,
+ itt_t init_task_tag,
u32 targ_xfer_tag,
u32 begrun,
u32 runlength)
@@ -498,7 +498,7 @@ int iscsit_handle_recovery_datain_or_r2t(
/* #warning FIXME: Status SNACK needs to be dependent on OPCODE!!! */
int iscsit_handle_status_snack(
struct iscsi_conn *conn,
- u32 init_task_tag,
+ itt_t init_task_tag,
u32 targ_xfer_tag,
u32 begrun,
u32 runlength)
diff --git a/drivers/target/iscsi/iscsi_target_erl1.h b/drivers/target/iscsi/iscsi_target_erl1.h
index 85e67e2..2a3ebf1 100644
--- a/drivers/target/iscsi/iscsi_target_erl1.h
+++ b/drivers/target/iscsi/iscsi_target_erl1.h
@@ -7,8 +7,8 @@ extern int iscsit_create_recovery_datain_values_datasequenceinorder_yes(
extern int iscsit_create_recovery_datain_values_datasequenceinorder_no(
struct iscsi_cmd *, struct iscsi_datain_req *);
extern int iscsit_handle_recovery_datain_or_r2t(struct iscsi_conn *, unsigned char *,
- u32, u32, u32, u32);
-extern int iscsit_handle_status_snack(struct iscsi_conn *, u32, u32,
+ itt_t, u32, u32, u32);
+extern int iscsit_handle_status_snack(struct iscsi_conn *, itt_t, u32,
u32, u32);
extern int iscsit_handle_data_ack(struct iscsi_conn *, u32, u32, u32);
extern int iscsit_dataout_datapduinorder_no_fbit(struct iscsi_cmd *, struct iscsi_pdu *);
diff --git a/drivers/target/iscsi/iscsi_target_erl2.c b/drivers/target/iscsi/iscsi_target_erl2.c
index 65aac14..17d8c20 100644
--- a/drivers/target/iscsi/iscsi_target_erl2.c
+++ b/drivers/target/iscsi/iscsi_target_erl2.c
@@ -36,7 +36,7 @@
*/
void iscsit_create_conn_recovery_datain_values(
struct iscsi_cmd *cmd,
- u32 exp_data_sn)
+ __be32 exp_data_sn)
{
u32 data_sn = 0;
struct iscsi_conn *conn = cmd->conn;
@@ -44,7 +44,7 @@ void iscsit_create_conn_recovery_datain_values(
cmd->next_burst_len = 0;
cmd->read_data_done = 0;
- while (exp_data_sn > data_sn) {
+ while (be32_to_cpu(exp_data_sn) > data_sn) {
if ((cmd->next_burst_len +
conn->conn_ops->MaxRecvDataSegmentLength) <
conn->sess->sess_ops->MaxBurstLength) {
@@ -193,15 +193,13 @@ int iscsit_remove_active_connection_recovery_entry(
return 0;
}
-int iscsit_remove_inactive_connection_recovery_entry(
+static void iscsit_remove_inactive_connection_recovery_entry(
struct iscsi_conn_recovery *cr,
struct iscsi_session *sess)
{
spin_lock(&sess->cr_i_lock);
list_del(&cr->cr_list);
spin_unlock(&sess->cr_i_lock);
-
- return 0;
}
/*
@@ -421,6 +419,7 @@ int iscsit_prepare_cmds_for_realligance(struct iscsi_conn *conn)
cr->cid = conn->cid;
cr->cmd_count = cmd_count;
cr->maxrecvdatasegmentlength = conn->conn_ops->MaxRecvDataSegmentLength;
+ cr->maxxmitdatasegmentlength = conn->conn_ops->MaxXmitDataSegmentLength;
cr->sess = conn->sess;
iscsit_attach_inactive_connection_recovery_entry(conn->sess, cr);
diff --git a/drivers/target/iscsi/iscsi_target_erl2.h b/drivers/target/iscsi/iscsi_target_erl2.h
index 22f8d24..63f2501 100644
--- a/drivers/target/iscsi/iscsi_target_erl2.h
+++ b/drivers/target/iscsi/iscsi_target_erl2.h
@@ -1,7 +1,7 @@
#ifndef ISCSI_TARGET_ERL2_H
#define ISCSI_TARGET_ERL2_H
-extern void iscsit_create_conn_recovery_datain_values(struct iscsi_cmd *, u32);
+extern void iscsit_create_conn_recovery_datain_values(struct iscsi_cmd *, __be32);
extern void iscsit_create_conn_recovery_dataout_values(struct iscsi_cmd *);
extern struct iscsi_conn_recovery *iscsit_get_inactive_connection_recovery_entry(
struct iscsi_session *, u16);
diff --git a/drivers/target/iscsi/iscsi_target_login.c b/drivers/target/iscsi/iscsi_target_login.c
index 6aba439..cdc8a10 100644
--- a/drivers/target/iscsi/iscsi_target_login.c
+++ b/drivers/target/iscsi/iscsi_target_login.c
@@ -39,10 +39,6 @@
#include "iscsi_target.h"
#include "iscsi_target_parameters.h"
-extern struct idr sess_idr;
-extern struct mutex auth_id_lock;
-extern spinlock_t sess_idr_lock;
-
static int iscsi_login_init_conn(struct iscsi_conn *conn)
{
INIT_LIST_HEAD(&conn->conn_list);
@@ -196,10 +192,10 @@ int iscsi_check_for_session_reinstatement(struct iscsi_conn *conn)
static void iscsi_login_set_conn_values(
struct iscsi_session *sess,
struct iscsi_conn *conn,
- u16 cid)
+ __be16 cid)
{
conn->sess = sess;
- conn->cid = cid;
+ conn->cid = be16_to_cpu(cid);
/*
* Generate a random Status sequence number (statsn) for the new
* iSCSI connection.
@@ -234,7 +230,7 @@ static int iscsi_login_zero_tsih_s1(
iscsi_login_set_conn_values(sess, conn, pdu->cid);
sess->init_task_tag = pdu->itt;
memcpy(&sess->isid, pdu->isid, 6);
- sess->exp_cmd_sn = pdu->cmdsn;
+ sess->exp_cmd_sn = be32_to_cpu(pdu->cmdsn);
INIT_LIST_HEAD(&sess->sess_conn_list);
INIT_LIST_HEAD(&sess->sess_ooo_cmdsn_list);
INIT_LIST_HEAD(&sess->cr_active_list);
@@ -275,7 +271,7 @@ static int iscsi_login_zero_tsih_s1(
* The FFP CmdSN window values will be allocated from the TPG's
* Initiator Node's ACL once the login has been successfully completed.
*/
- sess->max_cmd_sn = pdu->cmdsn;
+ sess->max_cmd_sn = be32_to_cpu(pdu->cmdsn);
sess->sess_ops = kzalloc(sizeof(struct iscsi_sess_ops), GFP_KERNEL);
if (!sess->sess_ops) {
@@ -453,7 +449,7 @@ static int iscsi_login_non_zero_tsih_s2(
(sess_p->time2retain_timer_flags & ISCSI_TF_EXPIRED))
continue;
if (!memcmp(sess_p->isid, pdu->isid, 6) &&
- (sess_p->tsih == pdu->tsih)) {
+ (sess_p->tsih == be16_to_cpu(pdu->tsih))) {
iscsit_inc_session_usage_count(sess_p);
iscsit_stop_time2retain_timer(sess_p);
sess = sess_p;
@@ -955,11 +951,7 @@ static int __iscsi_target_login_thread(struct iscsi_np *np)
}
pdu = (struct iscsi_login_req *) buffer;
- pdu->cid = be16_to_cpu(pdu->cid);
- pdu->tsih = be16_to_cpu(pdu->tsih);
- pdu->itt = be32_to_cpu(pdu->itt);
- pdu->cmdsn = be32_to_cpu(pdu->cmdsn);
- pdu->exp_statsn = be32_to_cpu(pdu->exp_statsn);
+
/*
* Used by iscsit_tx_login_rsp() for Login Resonses PDUs
* when Status-Class != 0.
diff --git a/drivers/target/iscsi/iscsi_target_nego.c b/drivers/target/iscsi/iscsi_target_nego.c
index 2dba448..e9053a0 100644
--- a/drivers/target/iscsi/iscsi_target_nego.c
+++ b/drivers/target/iscsi/iscsi_target_nego.c
@@ -44,7 +44,7 @@ void convert_null_to_semi(char *buf, int len)
buf[i] = ';';
}
-int strlen_semi(char *buf)
+static int strlen_semi(char *buf)
{
int i = 0;
@@ -339,14 +339,14 @@ static int iscsi_target_do_tx_login_io(struct iscsi_conn *conn, struct iscsi_log
hton24(login_rsp->dlength, login->rsp_length);
memcpy(login_rsp->isid, login->isid, 6);
login_rsp->tsih = cpu_to_be16(login->tsih);
- login_rsp->itt = cpu_to_be32(login->init_task_tag);
+ login_rsp->itt = login->init_task_tag;
login_rsp->statsn = cpu_to_be32(conn->stat_sn++);
login_rsp->exp_cmdsn = cpu_to_be32(conn->sess->exp_cmd_sn);
login_rsp->max_cmdsn = cpu_to_be32(conn->sess->max_cmd_sn);
pr_debug("Sending Login Response, Flags: 0x%02x, ITT: 0x%08x,"
" ExpCmdSN; 0x%08x, MaxCmdSN: 0x%08x, StatSN: 0x%08x, Length:"
- " %u\n", login_rsp->flags, ntohl(login_rsp->itt),
+ " %u\n", login_rsp->flags, (__force u32)login_rsp->itt,
ntohl(login_rsp->exp_cmdsn), ntohl(login_rsp->max_cmdsn),
ntohl(login_rsp->statsn), login->rsp_length);
@@ -360,12 +360,9 @@ static int iscsi_target_do_tx_login_io(struct iscsi_conn *conn, struct iscsi_log
return -1;
login->rsp_length = 0;
- login_rsp->tsih = be16_to_cpu(login_rsp->tsih);
- login_rsp->itt = be32_to_cpu(login_rsp->itt);
- login_rsp->statsn = be32_to_cpu(login_rsp->statsn);
mutex_lock(&sess->cmdsn_mutex);
- login_rsp->exp_cmdsn = be32_to_cpu(sess->exp_cmd_sn);
- login_rsp->max_cmdsn = be32_to_cpu(sess->max_cmd_sn);
+ login_rsp->exp_cmdsn = cpu_to_be32(sess->exp_cmd_sn);
+ login_rsp->max_cmdsn = cpu_to_be32(sess->max_cmd_sn);
mutex_unlock(&sess->cmdsn_mutex);
return 0;
@@ -381,11 +378,6 @@ static int iscsi_target_do_rx_login_io(struct iscsi_conn *conn, struct iscsi_log
login_req = (struct iscsi_login_req *) login->req;
payload_length = ntoh24(login_req->dlength);
- login_req->tsih = be16_to_cpu(login_req->tsih);
- login_req->itt = be32_to_cpu(login_req->itt);
- login_req->cid = be16_to_cpu(login_req->cid);
- login_req->cmdsn = be32_to_cpu(login_req->cmdsn);
- login_req->exp_statsn = be32_to_cpu(login_req->exp_statsn);
pr_debug("Got Login Command, Flags 0x%02x, ITT: 0x%08x,"
" CmdSN: 0x%08x, ExpStatSN: 0x%08x, CID: %hu, Length: %u\n",
@@ -550,7 +542,7 @@ static int iscsi_target_handle_csg_zero(
SENDER_INITIATOR|SENDER_RECEIVER,
login->req_buf,
payload_length,
- conn->param_list);
+ conn);
if (ret < 0)
return -1;
@@ -627,7 +619,7 @@ static int iscsi_target_handle_csg_one(struct iscsi_conn *conn, struct iscsi_log
SENDER_INITIATOR|SENDER_RECEIVER,
login->req_buf,
payload_length,
- conn->param_list);
+ conn);
if (ret < 0)
return -1;
@@ -762,11 +754,11 @@ static int iscsi_target_locate_portal(
login->version_min = login_req->min_version;
login->version_max = login_req->max_version;
memcpy(login->isid, login_req->isid, 6);
- login->cmd_sn = login_req->cmdsn;
+ login->cmd_sn = be32_to_cpu(login_req->cmdsn);
login->init_task_tag = login_req->itt;
- login->initial_exp_statsn = login_req->exp_statsn;
- login->cid = login_req->cid;
- login->tsih = login_req->tsih;
+ login->initial_exp_statsn = be32_to_cpu(login_req->exp_statsn);
+ login->cid = be16_to_cpu(login_req->cid);
+ login->tsih = be16_to_cpu(login_req->tsih);
if (iscsi_target_get_initial_payload(conn, login) < 0)
return -1;
@@ -1000,7 +992,6 @@ struct iscsi_login *iscsi_target_init_negotiation(
* Locates Target Portal from NP -> Target IQN
*/
if (iscsi_target_locate_portal(np, conn, login) < 0) {
- pr_err("iSCSI Login negotiation failed.\n");
goto out;
}
diff --git a/drivers/target/iscsi/iscsi_target_parameters.c b/drivers/target/iscsi/iscsi_target_parameters.c
index 240f7aa..90b7400 100644
--- a/drivers/target/iscsi/iscsi_target_parameters.c
+++ b/drivers/target/iscsi/iscsi_target_parameters.c
@@ -334,6 +334,13 @@ int iscsi_create_default_params(struct iscsi_param_list **param_list_ptr)
if (!param)
goto out;
+ param = iscsi_set_default_param(pl, MAXXMITDATASEGMENTLENGTH,
+ INITIAL_MAXXMITDATASEGMENTLENGTH,
+ PHASE_OPERATIONAL, SCOPE_CONNECTION_ONLY, SENDER_BOTH,
+ TYPERANGE_512_TO_16777215, USE_ALL);
+ if (!param)
+ goto out;
+
param = iscsi_set_default_param(pl, MAXRECVDATASEGMENTLENGTH,
INITIAL_MAXRECVDATASEGMENTLENGTH,
PHASE_OPERATIONAL, SCOPE_CONNECTION_ONLY, SENDER_BOTH,
@@ -467,6 +474,8 @@ int iscsi_set_keys_to_negotiate(
SET_PSTATE_NEGOTIATE(param);
} else if (!strcmp(param->name, MAXRECVDATASEGMENTLENGTH)) {
SET_PSTATE_NEGOTIATE(param);
+ } else if (!strcmp(param->name, MAXXMITDATASEGMENTLENGTH)) {
+ continue;
} else if (!strcmp(param->name, MAXBURSTLENGTH)) {
SET_PSTATE_NEGOTIATE(param);
} else if (!strcmp(param->name, FIRSTBURSTLENGTH)) {
@@ -1056,7 +1065,8 @@ out:
return proposer_values;
}
-static int iscsi_check_acceptor_state(struct iscsi_param *param, char *value)
+static int iscsi_check_acceptor_state(struct iscsi_param *param, char *value,
+ struct iscsi_conn *conn)
{
u8 acceptor_boolean_value = 0, proposer_boolean_value = 0;
char *negoitated_value = NULL;
@@ -1131,8 +1141,35 @@ static int iscsi_check_acceptor_state(struct iscsi_param *param, char *value)
return -1;
}
- if (!strcmp(param->name, MAXRECVDATASEGMENTLENGTH))
- SET_PSTATE_REPLY_OPTIONAL(param);
+ if (!strcmp(param->name, MAXRECVDATASEGMENTLENGTH)) {
+ struct iscsi_param *param_mxdsl;
+ unsigned long long tmp;
+ int rc;
+
+ rc = strict_strtoull(param->value, 0, &tmp);
+ if (rc < 0)
+ return -1;
+
+ conn->conn_ops->MaxRecvDataSegmentLength = tmp;
+ pr_debug("Saving op->MaxRecvDataSegmentLength from"
+ " original initiator received value: %u\n",
+ conn->conn_ops->MaxRecvDataSegmentLength);
+
+ param_mxdsl = iscsi_find_param_from_key(
+ MAXXMITDATASEGMENTLENGTH,
+ conn->param_list);
+ if (!param_mxdsl)
+ return -1;
+
+ rc = iscsi_update_param_value(param,
+ param_mxdsl->value);
+ if (rc < 0)
+ return -1;
+
+ pr_debug("Updated %s to target MXDSL value: %s\n",
+ param->name, param->value);
+ }
+
} else if (IS_TYPE_NUMBER_RANGE(param)) {
negoitated_value = iscsi_get_value_from_number_range(
param, value);
@@ -1526,8 +1563,9 @@ int iscsi_decode_text_input(
u8 sender,
char *textbuf,
u32 length,
- struct iscsi_param_list *param_list)
+ struct iscsi_conn *conn)
{
+ struct iscsi_param_list *param_list = conn->param_list;
char *tmpbuf, *start = NULL, *end = NULL;
tmpbuf = kzalloc(length + 1, GFP_KERNEL);
@@ -1585,7 +1623,7 @@ int iscsi_decode_text_input(
}
SET_PSTATE_RESPONSE_GOT(param);
} else {
- if (iscsi_check_acceptor_state(param, value) < 0) {
+ if (iscsi_check_acceptor_state(param, value, conn) < 0) {
kfree(tmpbuf);
return -1;
}
@@ -1720,6 +1758,18 @@ void iscsi_set_connection_parameters(
pr_debug("---------------------------------------------------"
"---------------\n");
list_for_each_entry(param, &param_list->param_list, p_list) {
+ /*
+ * Special case to set MAXXMITDATASEGMENTLENGTH from the
+ * target requested MaxRecvDataSegmentLength, even though
+ * this key is not sent over the wire.
+ */
+ if (!strcmp(param->name, MAXXMITDATASEGMENTLENGTH)) {
+ ops->MaxXmitDataSegmentLength =
+ simple_strtoul(param->value, &tmpptr, 0);
+ pr_debug("MaxXmitDataSegmentLength: %s\n",
+ param->value);
+ }
+
if (!IS_PSTATE_ACCEPTOR(param) && !IS_PSTATE_PROPOSER(param))
continue;
if (!strcmp(param->name, AUTHMETHOD)) {
@@ -1734,10 +1784,13 @@ void iscsi_set_connection_parameters(
pr_debug("DataDigest: %s\n",
param->value);
} else if (!strcmp(param->name, MAXRECVDATASEGMENTLENGTH)) {
- ops->MaxRecvDataSegmentLength =
- simple_strtoul(param->value, &tmpptr, 0);
- pr_debug("MaxRecvDataSegmentLength: %s\n",
- param->value);
+ /*
+ * At this point iscsi_check_acceptor_state() will have
+ * set ops->MaxRecvDataSegmentLength from the original
+ * initiator provided value.
+ */
+ pr_debug("MaxRecvDataSegmentLength: %u\n",
+ ops->MaxRecvDataSegmentLength);
} else if (!strcmp(param->name, OFMARKER)) {
ops->OFMarker = !strcmp(param->value, YES);
pr_debug("OFMarker: %s\n",
diff --git a/drivers/target/iscsi/iscsi_target_parameters.h b/drivers/target/iscsi/iscsi_target_parameters.h
index 6a37fd6..1e1b750 100644
--- a/drivers/target/iscsi/iscsi_target_parameters.h
+++ b/drivers/target/iscsi/iscsi_target_parameters.h
@@ -36,7 +36,7 @@ extern void iscsi_release_param_list(struct iscsi_param_list *);
extern struct iscsi_param *iscsi_find_param_from_key(char *, struct iscsi_param_list *);
extern int iscsi_extract_key_value(char *, char **, char **);
extern int iscsi_update_param_value(struct iscsi_param *, char *);
-extern int iscsi_decode_text_input(u8, u8, char *, u32, struct iscsi_param_list *);
+extern int iscsi_decode_text_input(u8, u8, char *, u32, struct iscsi_conn *);
extern int iscsi_encode_text_output(u8, u8, char *, u32 *,
struct iscsi_param_list *);
extern int iscsi_check_negotiated_keys(struct iscsi_param_list *);
@@ -70,6 +70,7 @@ extern void iscsi_set_session_parameters(struct iscsi_sess_ops *,
#define INITIALR2T "InitialR2T"
#define IMMEDIATEDATA "ImmediateData"
#define MAXRECVDATASEGMENTLENGTH "MaxRecvDataSegmentLength"
+#define MAXXMITDATASEGMENTLENGTH "MaxXmitDataSegmentLength"
#define MAXBURSTLENGTH "MaxBurstLength"
#define FIRSTBURSTLENGTH "FirstBurstLength"
#define DEFAULTTIME2WAIT "DefaultTime2Wait"
@@ -113,6 +114,10 @@ extern void iscsi_set_session_parameters(struct iscsi_sess_ops *,
#define INITIAL_INITIALR2T YES
#define INITIAL_IMMEDIATEDATA YES
#define INITIAL_MAXRECVDATASEGMENTLENGTH "8192"
+/*
+ * Match outgoing MXDSL default to incoming Open-iSCSI default
+ */
+#define INITIAL_MAXXMITDATASEGMENTLENGTH "262144"
#define INITIAL_MAXBURSTLENGTH "262144"
#define INITIAL_FIRSTBURSTLENGTH "65536"
#define INITIAL_DEFAULTTIME2WAIT "2"
diff --git a/drivers/target/iscsi/iscsi_target_seq_pdu_list.c b/drivers/target/iscsi/iscsi_target_seq_pdu_list.c
index 85a306e..edb592a 100644
--- a/drivers/target/iscsi/iscsi_target_seq_pdu_list.c
+++ b/drivers/target/iscsi/iscsi_target_seq_pdu_list.c
@@ -219,8 +219,14 @@ static void iscsit_determine_counts_for_list(
int check_immediate = 0;
u32 burstlength = 0, offset = 0;
u32 unsolicited_data_length = 0;
+ u32 mdsl;
struct iscsi_conn *conn = cmd->conn;
+ if (cmd->se_cmd.data_direction == DMA_TO_DEVICE)
+ mdsl = cmd->conn->conn_ops->MaxXmitDataSegmentLength;
+ else
+ mdsl = cmd->conn->conn_ops->MaxRecvDataSegmentLength;
+
if ((bl->type == PDULIST_IMMEDIATE) ||
(bl->type == PDULIST_IMMEDIATE_AND_UNSOLICITED))
check_immediate = 1;
@@ -243,14 +249,13 @@ static void iscsit_determine_counts_for_list(
continue;
}
if (unsolicited_data_length > 0) {
- if ((offset + conn->conn_ops->MaxRecvDataSegmentLength)
- >= cmd->se_cmd.data_length) {
+ if ((offset + mdsl) >= cmd->se_cmd.data_length) {
unsolicited_data_length -=
(cmd->se_cmd.data_length - offset);
offset += (cmd->se_cmd.data_length - offset);
continue;
}
- if ((offset + conn->conn_ops->MaxRecvDataSegmentLength)
+ if ((offset + mdsl)
>= conn->sess->sess_ops->FirstBurstLength) {
unsolicited_data_length -=
(conn->sess->sess_ops->FirstBurstLength -
@@ -262,17 +267,15 @@ static void iscsit_determine_counts_for_list(
continue;
}
- offset += conn->conn_ops->MaxRecvDataSegmentLength;
- unsolicited_data_length -=
- conn->conn_ops->MaxRecvDataSegmentLength;
+ offset += mdsl;
+ unsolicited_data_length -= mdsl;
continue;
}
- if ((offset + conn->conn_ops->MaxRecvDataSegmentLength) >=
- cmd->se_cmd.data_length) {
+ if ((offset + mdsl) >= cmd->se_cmd.data_length) {
offset += (cmd->se_cmd.data_length - offset);
continue;
}
- if ((burstlength + conn->conn_ops->MaxRecvDataSegmentLength) >=
+ if ((burstlength + mdsl) >=
conn->sess->sess_ops->MaxBurstLength) {
offset += (conn->sess->sess_ops->MaxBurstLength -
burstlength);
@@ -281,8 +284,8 @@ static void iscsit_determine_counts_for_list(
continue;
}
- burstlength += conn->conn_ops->MaxRecvDataSegmentLength;
- offset += conn->conn_ops->MaxRecvDataSegmentLength;
+ burstlength += mdsl;
+ offset += mdsl;
}
}
@@ -296,12 +299,17 @@ static int iscsit_do_build_pdu_and_seq_lists(
struct iscsi_build_list *bl)
{
int check_immediate = 0, datapduinorder, datasequenceinorder;
- u32 burstlength = 0, offset = 0, i = 0;
+ u32 burstlength = 0, offset = 0, i = 0, mdsl;
u32 pdu_count = 0, seq_no = 0, unsolicited_data_length = 0;
struct iscsi_conn *conn = cmd->conn;
struct iscsi_pdu *pdu = cmd->pdu_list;
struct iscsi_seq *seq = cmd->seq_list;
+ if (cmd->se_cmd.data_direction == DMA_TO_DEVICE)
+ mdsl = cmd->conn->conn_ops->MaxXmitDataSegmentLength;
+ else
+ mdsl = cmd->conn->conn_ops->MaxRecvDataSegmentLength;
+
datapduinorder = conn->sess->sess_ops->DataPDUInOrder;
datasequenceinorder = conn->sess->sess_ops->DataSequenceInOrder;
@@ -348,9 +356,7 @@ static int iscsit_do_build_pdu_and_seq_lists(
continue;
}
if (unsolicited_data_length > 0) {
- if ((offset +
- conn->conn_ops->MaxRecvDataSegmentLength) >=
- cmd->se_cmd.data_length) {
+ if ((offset + mdsl) >= cmd->se_cmd.data_length) {
if (!datapduinorder) {
pdu[i].type = PDUTYPE_UNSOLICITED;
pdu[i].length =
@@ -367,8 +373,7 @@ static int iscsit_do_build_pdu_and_seq_lists(
offset += (cmd->se_cmd.data_length - offset);
continue;
}
- if ((offset +
- conn->conn_ops->MaxRecvDataSegmentLength) >=
+ if ((offset + mdsl) >=
conn->sess->sess_ops->FirstBurstLength) {
if (!datapduinorder) {
pdu[i].type = PDUTYPE_UNSOLICITED;
@@ -396,17 +401,14 @@ static int iscsit_do_build_pdu_and_seq_lists(
if (!datapduinorder) {
pdu[i].type = PDUTYPE_UNSOLICITED;
- pdu[i++].length =
- conn->conn_ops->MaxRecvDataSegmentLength;
+ pdu[i++].length = mdsl;
}
- burstlength += conn->conn_ops->MaxRecvDataSegmentLength;
- offset += conn->conn_ops->MaxRecvDataSegmentLength;
- unsolicited_data_length -=
- conn->conn_ops->MaxRecvDataSegmentLength;
+ burstlength += mdsl;
+ offset += mdsl;
+ unsolicited_data_length -= mdsl;
continue;
}
- if ((offset + conn->conn_ops->MaxRecvDataSegmentLength) >=
- cmd->se_cmd.data_length) {
+ if ((offset + mdsl) >= cmd->se_cmd.data_length) {
if (!datapduinorder) {
pdu[i].type = PDUTYPE_NORMAL;
pdu[i].length = (cmd->se_cmd.data_length - offset);
@@ -420,7 +422,7 @@ static int iscsit_do_build_pdu_and_seq_lists(
offset += (cmd->se_cmd.data_length - offset);
continue;
}
- if ((burstlength + conn->conn_ops->MaxRecvDataSegmentLength) >=
+ if ((burstlength + mdsl) >=
conn->sess->sess_ops->MaxBurstLength) {
if (!datapduinorder) {
pdu[i].type = PDUTYPE_NORMAL;
@@ -445,11 +447,10 @@ static int iscsit_do_build_pdu_and_seq_lists(
if (!datapduinorder) {
pdu[i].type = PDUTYPE_NORMAL;
- pdu[i++].length =
- conn->conn_ops->MaxRecvDataSegmentLength;
+ pdu[i++].length = mdsl;
}
- burstlength += conn->conn_ops->MaxRecvDataSegmentLength;
- offset += conn->conn_ops->MaxRecvDataSegmentLength;
+ burstlength += mdsl;
+ offset += mdsl;
}
if (!datasequenceinorder) {
diff --git a/drivers/target/iscsi/iscsi_target_tmr.c b/drivers/target/iscsi/iscsi_target_tmr.c
index f62fe12..4a99820 100644
--- a/drivers/target/iscsi/iscsi_target_tmr.c
+++ b/drivers/target/iscsi/iscsi_target_tmr.c
@@ -50,21 +50,20 @@ u8 iscsit_tmr_abort_task(
if (!ref_cmd) {
pr_err("Unable to locate RefTaskTag: 0x%08x on CID:"
" %hu.\n", hdr->rtt, conn->cid);
- return ((hdr->refcmdsn >= conn->sess->exp_cmd_sn) &&
- (hdr->refcmdsn <= conn->sess->max_cmd_sn)) ?
+ return (be32_to_cpu(hdr->refcmdsn) >= conn->sess->exp_cmd_sn &&
+ be32_to_cpu(hdr->refcmdsn) <= conn->sess->max_cmd_sn) ?
ISCSI_TMF_RSP_COMPLETE : ISCSI_TMF_RSP_NO_TASK;
}
- if (ref_cmd->cmd_sn != hdr->refcmdsn) {
+ if (ref_cmd->cmd_sn != be32_to_cpu(hdr->refcmdsn)) {
pr_err("RefCmdSN 0x%08x does not equal"
" task's CmdSN 0x%08x. Rejecting ABORT_TASK.\n",
hdr->refcmdsn, ref_cmd->cmd_sn);
return ISCSI_TMF_RSP_REJECTED;
}
- se_tmr->ref_task_tag = hdr->rtt;
+ se_tmr->ref_task_tag = (__force u32)hdr->rtt;
tmr_req->ref_cmd = ref_cmd;
- tmr_req->ref_cmd_sn = hdr->refcmdsn;
- tmr_req->exp_data_sn = hdr->exp_datasn;
+ tmr_req->exp_data_sn = be32_to_cpu(hdr->exp_datasn);
return ISCSI_TMF_RSP_COMPLETE;
}
@@ -146,7 +145,7 @@ u8 iscsit_tmr_task_reassign(
}
/*
* Temporary check to prevent connection recovery for
- * connections with a differing MaxRecvDataSegmentLength.
+ * connections with a differing Max*DataSegmentLength.
*/
if (cr->maxrecvdatasegmentlength !=
conn->conn_ops->MaxRecvDataSegmentLength) {
@@ -155,6 +154,13 @@ u8 iscsit_tmr_task_reassign(
" TMR TASK_REASSIGN.\n");
return ISCSI_TMF_RSP_REJECTED;
}
+ if (cr->maxxmitdatasegmentlength !=
+ conn->conn_ops->MaxXmitDataSegmentLength) {
+ pr_err("Unable to perform connection recovery for"
+ " differing MaxXmitDataSegmentLength, rejecting"
+ " TMR TASK_REASSIGN.\n");
+ return ISCSI_TMF_RSP_REJECTED;
+ }
ref_lun = scsilun_to_int(&hdr->lun);
if (ref_lun != ref_cmd->se_cmd.orig_fe_lun) {
@@ -164,10 +170,9 @@ u8 iscsit_tmr_task_reassign(
return ISCSI_TMF_RSP_REJECTED;
}
- se_tmr->ref_task_tag = hdr->rtt;
+ se_tmr->ref_task_tag = (__force u32)hdr->rtt;
tmr_req->ref_cmd = ref_cmd;
- tmr_req->ref_cmd_sn = hdr->refcmdsn;
- tmr_req->exp_data_sn = hdr->exp_datasn;
+ tmr_req->exp_data_sn = be32_to_cpu(hdr->exp_datasn);
tmr_req->conn_recovery = cr;
tmr_req->task_reassign = 1;
/*
@@ -455,7 +460,7 @@ static int iscsit_task_reassign_complete(
* Right now the only one that its really needed for is
* connection recovery releated TASK_REASSIGN.
*/
-extern int iscsit_tmr_post_handler(struct iscsi_cmd *cmd, struct iscsi_conn *conn)
+int iscsit_tmr_post_handler(struct iscsi_cmd *cmd, struct iscsi_conn *conn)
{
struct iscsi_tmr_req *tmr_req = cmd->tmr_req;
struct se_tmr_req *se_tmr = cmd->se_cmd.se_tmr_req;
@@ -470,7 +475,7 @@ extern int iscsit_tmr_post_handler(struct iscsi_cmd *cmd, struct iscsi_conn *con
/*
* Nothing to do here, but leave it for good measure. :-)
*/
-int iscsit_task_reassign_prepare_read(
+static int iscsit_task_reassign_prepare_read(
struct iscsi_tmr_req *tmr_req,
struct iscsi_conn *conn)
{
@@ -545,7 +550,7 @@ static void iscsit_task_reassign_prepare_unsolicited_dataout(
}
}
-int iscsit_task_reassign_prepare_write(
+static int iscsit_task_reassign_prepare_write(
struct iscsi_tmr_req *tmr_req,
struct iscsi_conn *conn)
{
diff --git a/drivers/target/iscsi/iscsi_target_tpg.c b/drivers/target/iscsi/iscsi_target_tpg.c
index a38a3f8..de9ea32 100644
--- a/drivers/target/iscsi/iscsi_target_tpg.c
+++ b/drivers/target/iscsi/iscsi_target_tpg.c
@@ -677,6 +677,12 @@ int iscsit_ta_generate_node_acls(
pr_debug("iSCSI_TPG[%hu] - Generate Initiator Portal Group ACLs: %s\n",
tpg->tpgt, (a->generate_node_acls) ? "Enabled" : "Disabled");
+ if (flag == 1 && a->cache_dynamic_acls == 0) {
+ pr_debug("Explicitly setting cache_dynamic_acls=1 when "
+ "generate_node_acls=1\n");
+ a->cache_dynamic_acls = 1;
+ }
+
return 0;
}
@@ -716,6 +722,12 @@ int iscsit_ta_cache_dynamic_acls(
return -EINVAL;
}
+ if (a->generate_node_acls == 1 && flag == 0) {
+ pr_debug("Skipping cache_dynamic_acls=0 when"
+ " generate_node_acls=1\n");
+ return 0;
+ }
+
a->cache_dynamic_acls = flag;
pr_debug("iSCSI_TPG[%hu] - Cache Dynamic Initiator Portal Group"
" ACLs %s\n", tpg->tpgt, (a->cache_dynamic_acls) ?
diff --git a/drivers/target/iscsi/iscsi_target_tq.c b/drivers/target/iscsi/iscsi_target_tq.c
index 977e1cf..9d881a0 100644
--- a/drivers/target/iscsi/iscsi_target_tq.c
+++ b/drivers/target/iscsi/iscsi_target_tq.c
@@ -40,7 +40,7 @@ static void iscsi_add_ts_to_active_list(struct iscsi_thread_set *ts)
spin_unlock(&active_ts_lock);
}
-extern void iscsi_add_ts_to_inactive_list(struct iscsi_thread_set *ts)
+static void iscsi_add_ts_to_inactive_list(struct iscsi_thread_set *ts)
{
spin_lock(&inactive_ts_lock);
list_add_tail(&ts->ts_list, &inactive_ts_list);
@@ -76,7 +76,7 @@ static struct iscsi_thread_set *iscsi_get_ts_from_inactive_list(void)
return ts;
}
-extern int iscsi_allocate_thread_sets(u32 thread_pair_count)
+int iscsi_allocate_thread_sets(u32 thread_pair_count)
{
int allocated_thread_pair_count = 0, i, thread_id;
struct iscsi_thread_set *ts = NULL;
@@ -140,7 +140,7 @@ extern int iscsi_allocate_thread_sets(u32 thread_pair_count)
return allocated_thread_pair_count;
}
-extern void iscsi_deallocate_thread_sets(void)
+void iscsi_deallocate_thread_sets(void)
{
u32 released_count = 0;
struct iscsi_thread_set *ts = NULL;
diff --git a/drivers/target/iscsi/iscsi_target_tq.h b/drivers/target/iscsi/iscsi_target_tq.h
index 26e6a95..547d118 100644
--- a/drivers/target/iscsi/iscsi_target_tq.h
+++ b/drivers/target/iscsi/iscsi_target_tq.h
@@ -5,7 +5,6 @@
* Defines for thread sets.
*/
extern int iscsi_thread_set_force_reinstatement(struct iscsi_conn *);
-extern void iscsi_add_ts_to_inactive_list(struct iscsi_thread_set *);
extern int iscsi_allocate_thread_sets(u32);
extern void iscsi_deallocate_thread_sets(void);
extern void iscsi_activate_thread_set(struct iscsi_conn *, struct iscsi_thread_set *);
diff --git a/drivers/target/iscsi/iscsi_target_util.c b/drivers/target/iscsi/iscsi_target_util.c
index b42cdeb..afd98cc 100644
--- a/drivers/target/iscsi/iscsi_target_util.c
+++ b/drivers/target/iscsi/iscsi_target_util.c
@@ -274,14 +274,14 @@ static inline int iscsit_check_received_cmdsn(struct iscsi_session *sess, u32 cm
int iscsit_sequence_cmd(
struct iscsi_conn *conn,
struct iscsi_cmd *cmd,
- u32 cmdsn)
+ __be32 cmdsn)
{
int ret;
int cmdsn_ret;
mutex_lock(&conn->sess->cmdsn_mutex);
- cmdsn_ret = iscsit_check_received_cmdsn(conn->sess, cmdsn);
+ cmdsn_ret = iscsit_check_received_cmdsn(conn->sess, be32_to_cpu(cmdsn));
switch (cmdsn_ret) {
case CMDSN_NORMAL_OPERATION:
ret = iscsit_execute_cmd(cmd, 0);
@@ -289,7 +289,7 @@ int iscsit_sequence_cmd(
iscsit_execute_ooo_cmdsns(conn->sess);
break;
case CMDSN_HIGHER_THAN_EXP:
- ret = iscsit_handle_ooo_cmdsn(conn->sess, cmd, cmdsn);
+ ret = iscsit_handle_ooo_cmdsn(conn->sess, cmd, be32_to_cpu(cmdsn));
break;
case CMDSN_LOWER_THAN_EXP:
cmd->i_state = ISTATE_REMOVE;
@@ -351,7 +351,7 @@ int iscsit_check_unsolicited_dataout(struct iscsi_cmd *cmd, unsigned char *buf)
struct iscsi_cmd *iscsit_find_cmd_from_itt(
struct iscsi_conn *conn,
- u32 init_task_tag)
+ itt_t init_task_tag)
{
struct iscsi_cmd *cmd;
@@ -371,7 +371,7 @@ struct iscsi_cmd *iscsit_find_cmd_from_itt(
struct iscsi_cmd *iscsit_find_cmd_from_itt_or_dump(
struct iscsi_conn *conn,
- u32 init_task_tag,
+ itt_t init_task_tag,
u32 length)
{
struct iscsi_cmd *cmd;
@@ -417,7 +417,7 @@ int iscsit_find_cmd_for_recovery(
struct iscsi_session *sess,
struct iscsi_cmd **cmd_ptr,
struct iscsi_conn_recovery **cr_ptr,
- u32 init_task_tag)
+ itt_t init_task_tag)
{
struct iscsi_cmd *cmd = NULL;
struct iscsi_conn_recovery *cr;
@@ -855,7 +855,7 @@ static int iscsit_add_nopin(struct iscsi_conn *conn, int want_response)
cmd->iscsi_opcode = ISCSI_OP_NOOP_IN;
state = (want_response) ? ISTATE_SEND_NOPIN_WANT_RESPONSE :
ISTATE_SEND_NOPIN_NO_RESPONSE;
- cmd->init_task_tag = 0xFFFFFFFF;
+ cmd->init_task_tag = RESERVED_ITT;
spin_lock_bh(&conn->sess->ttt_lock);
cmd->targ_xfer_tag = (want_response) ? conn->sess->targ_xfer_tag++ :
0xFFFFFFFF;
@@ -1222,7 +1222,7 @@ int iscsit_tx_login_rsp(struct iscsi_conn *conn, u8 status_class, u8 status_deta
hdr->opcode = ISCSI_OP_LOGIN_RSP;
hdr->status_class = status_class;
hdr->status_detail = status_detail;
- hdr->itt = cpu_to_be32(conn->login_itt);
+ hdr->itt = conn->login_itt;
iov.iov_base = &iscsi_hdr;
iov.iov_len = ISCSI_HDR_LEN;
diff --git a/drivers/target/iscsi/iscsi_target_util.h b/drivers/target/iscsi/iscsi_target_util.h
index e1c729b..44054bd3 100644
--- a/drivers/target/iscsi/iscsi_target_util.h
+++ b/drivers/target/iscsi/iscsi_target_util.h
@@ -12,14 +12,14 @@ extern struct iscsi_cmd *iscsit_allocate_cmd(struct iscsi_conn *, gfp_t);
extern struct iscsi_seq *iscsit_get_seq_holder_for_datain(struct iscsi_cmd *, u32);
extern struct iscsi_seq *iscsit_get_seq_holder_for_r2t(struct iscsi_cmd *);
extern struct iscsi_r2t *iscsit_get_holder_for_r2tsn(struct iscsi_cmd *, u32);
-int iscsit_sequence_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd, u32 cmdsn);
+int iscsit_sequence_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd, __be32 cmdsn);
extern int iscsit_check_unsolicited_dataout(struct iscsi_cmd *, unsigned char *);
-extern struct iscsi_cmd *iscsit_find_cmd_from_itt(struct iscsi_conn *, u32);
+extern struct iscsi_cmd *iscsit_find_cmd_from_itt(struct iscsi_conn *, itt_t);
extern struct iscsi_cmd *iscsit_find_cmd_from_itt_or_dump(struct iscsi_conn *,
- u32, u32);
+ itt_t, u32);
extern struct iscsi_cmd *iscsit_find_cmd_from_ttt(struct iscsi_conn *, u32);
extern int iscsit_find_cmd_for_recovery(struct iscsi_session *, struct iscsi_cmd **,
- struct iscsi_conn_recovery **, u32);
+ struct iscsi_conn_recovery **, itt_t);
extern void iscsit_add_cmd_to_immediate_queue(struct iscsi_cmd *, struct iscsi_conn *, u8);
extern struct iscsi_queue_req *iscsit_get_cmd_from_immediate_queue(struct iscsi_conn *);
extern void iscsit_add_cmd_to_response_queue(struct iscsi_cmd *, struct iscsi_conn *, u8);
diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c
index 5491c63..2d444b1 100644
--- a/drivers/target/loopback/tcm_loop.c
+++ b/drivers/target/loopback/tcm_loop.c
@@ -166,7 +166,7 @@ static void tcm_loop_submission_work(struct work_struct *work)
struct tcm_loop_tpg *tl_tpg;
struct scatterlist *sgl_bidi = NULL;
u32 sgl_bidi_count = 0;
- int ret;
+ int rc;
tl_hba = *(struct tcm_loop_hba **)shost_priv(sc->device->host);
tl_tpg = &tl_hba->tl_hba_tpgs[sc->device->id];
@@ -187,12 +187,6 @@ static void tcm_loop_submission_work(struct work_struct *work)
set_host_byte(sc, DID_ERROR);
goto out_done;
}
-
- transport_init_se_cmd(se_cmd, tl_tpg->tl_se_tpg.se_tpg_tfo,
- tl_nexus->se_sess,
- scsi_bufflen(sc), sc->sc_data_direction,
- tcm_loop_sam_attr(sc), &tl_cmd->tl_sense_buf[0]);
-
if (scsi_bidi_cmnd(sc)) {
struct scsi_data_buffer *sdb = scsi_in(sc);
@@ -201,56 +195,16 @@ static void tcm_loop_submission_work(struct work_struct *work)
se_cmd->se_cmd_flags |= SCF_BIDI;
}
-
- if (transport_lookup_cmd_lun(se_cmd, tl_cmd->sc->device->lun) < 0) {
- kmem_cache_free(tcm_loop_cmd_cache, tl_cmd);
+ rc = target_submit_cmd_map_sgls(se_cmd, tl_nexus->se_sess, sc->cmnd,
+ &tl_cmd->tl_sense_buf[0], tl_cmd->sc->device->lun,
+ scsi_bufflen(sc), tcm_loop_sam_attr(sc),
+ sc->sc_data_direction, 0,
+ scsi_sglist(sc), scsi_sg_count(sc),
+ sgl_bidi, sgl_bidi_count);
+ if (rc < 0) {
set_host_byte(sc, DID_NO_CONNECT);
goto out_done;
}
-
- /*
- * Because some userspace code via scsi-generic do not memset their
- * associated read buffers, go ahead and do that here for type
- * non-data CDBs. Also note that this is currently guaranteed to be a
- * single SGL for this case by target core in
- * target_setup_cmd_from_cdb() -> transport_generic_cmd_sequencer().
- */
- if (!(se_cmd->se_cmd_flags & SCF_SCSI_DATA_CDB) &&
- se_cmd->data_direction == DMA_FROM_DEVICE) {
- struct scatterlist *sg = scsi_sglist(sc);
- unsigned char *buf = kmap(sg_page(sg)) + sg->offset;
-
- if (buf != NULL) {
- memset(buf, 0, sg->length);
- kunmap(sg_page(sg));
- }
- }
-
- ret = target_setup_cmd_from_cdb(se_cmd, sc->cmnd);
- if (ret == -ENOMEM) {
- transport_send_check_condition_and_sense(se_cmd,
- TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE, 0);
- transport_generic_free_cmd(se_cmd, 0);
- return;
- } else if (ret < 0) {
- if (se_cmd->se_cmd_flags & SCF_SCSI_RESERVATION_CONFLICT)
- tcm_loop_queue_status(se_cmd);
- else
- transport_send_check_condition_and_sense(se_cmd,
- se_cmd->scsi_sense_reason, 0);
- transport_generic_free_cmd(se_cmd, 0);
- return;
- }
-
- ret = transport_generic_map_mem_to_cmd(se_cmd, scsi_sglist(sc),
- scsi_sg_count(sc), sgl_bidi, sgl_bidi_count);
- if (ret) {
- transport_send_check_condition_and_sense(se_cmd,
- se_cmd->scsi_sense_reason, 0);
- transport_generic_free_cmd(se_cmd, 0);
- return;
- }
- transport_handle_cdb_direct(se_cmd);
return;
out_done:
@@ -846,16 +800,6 @@ static int tcm_loop_queue_tm_rsp(struct se_cmd *se_cmd)
return 0;
}
-static u16 tcm_loop_set_fabric_sense_len(struct se_cmd *se_cmd, u32 sense_length)
-{
- return 0;
-}
-
-static u16 tcm_loop_get_fabric_sense_len(void)
-{
- return 0;
-}
-
static char *tcm_loop_dump_proto_id(struct tcm_loop_hba *tl_hba)
{
switch (tl_hba->tl_proto_id) {
@@ -1373,8 +1317,6 @@ static int tcm_loop_register_configfs(void)
fabric->tf_ops.queue_data_in = &tcm_loop_queue_data_in;
fabric->tf_ops.queue_status = &tcm_loop_queue_status;
fabric->tf_ops.queue_tm_rsp = &tcm_loop_queue_tm_rsp;
- 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;
/*
* Setup function pointers for generic logic in target_core_fabric_configfs.c
diff --git a/drivers/target/sbp/sbp_target.c b/drivers/target/sbp/sbp_target.c
index 39ddba5..0d6d7c1 100644
--- a/drivers/target/sbp/sbp_target.c
+++ b/drivers/target/sbp/sbp_target.c
@@ -660,8 +660,7 @@ static void session_reconnect_expired(struct sbp_session *sess)
spin_lock_bh(&sess->lock);
list_for_each_entry_safe(login, temp, &sess->login_list, link) {
login->sess = NULL;
- list_del(&login->link);
- list_add_tail(&login->link, &login_list);
+ list_move_tail(&login->link, &login_list);
}
spin_unlock_bh(&sess->lock);
@@ -1847,16 +1846,6 @@ static int sbp_queue_tm_rsp(struct se_cmd *se_cmd)
return 0;
}
-static u16 sbp_set_fabric_sense_len(struct se_cmd *se_cmd, u32 sense_length)
-{
- return 0;
-}
-
-static u16 sbp_get_fabric_sense_len(void)
-{
- return 0;
-}
-
static int sbp_check_stop_free(struct se_cmd *se_cmd)
{
struct sbp_target_request *req = container_of(se_cmd,
@@ -2068,7 +2057,7 @@ static int sbp_update_unit_directory(struct sbp_tport *tport)
return ret;
}
-static ssize_t sbp_parse_wwn(const char *name, u64 *wwn, int strict)
+static ssize_t sbp_parse_wwn(const char *name, u64 *wwn)
{
const char *cp;
char c, nibble;
@@ -2088,7 +2077,7 @@ static ssize_t sbp_parse_wwn(const char *name, u64 *wwn, int strict)
err = 3;
if (isdigit(c))
nibble = c - '0';
- else if (isxdigit(c) && (islower(c) || !strict))
+ else if (isxdigit(c))
nibble = tolower(c) - 'a' + 10;
else
goto fail;
@@ -2117,7 +2106,7 @@ static struct se_node_acl *sbp_make_nodeacl(
u64 guid = 0;
u32 nexus_depth = 1;
- if (sbp_parse_wwn(name, &guid, 1) < 0)
+ if (sbp_parse_wwn(name, &guid) < 0)
return ERR_PTR(-EINVAL);
se_nacl_new = sbp_alloc_fabric_acl(se_tpg);
@@ -2253,7 +2242,7 @@ static struct se_wwn *sbp_make_tport(
struct sbp_tport *tport;
u64 guid = 0;
- if (sbp_parse_wwn(name, &guid, 1) < 0)
+ if (sbp_parse_wwn(name, &guid) < 0)
return ERR_PTR(-EINVAL);
tport = kzalloc(sizeof(*tport), GFP_KERNEL);
@@ -2534,8 +2523,6 @@ static struct target_core_fabric_ops sbp_ops = {
.queue_data_in = sbp_queue_data_in,
.queue_status = sbp_queue_status,
.queue_tm_rsp = sbp_queue_tm_rsp,
- .get_fabric_sense_len = sbp_get_fabric_sense_len,
- .set_fabric_sense_len = sbp_set_fabric_sense_len,
.check_stop_free = sbp_check_stop_free,
.fabric_make_wwn = sbp_make_tport,
@@ -2556,9 +2543,9 @@ static int sbp_register_configfs(void)
int ret;
fabric = target_fabric_configfs_init(THIS_MODULE, "sbp");
- if (!fabric) {
+ if (IS_ERR(fabric)) {
pr_err("target_fabric_configfs_init() failed\n");
- return -ENOMEM;
+ return PTR_ERR(fabric);
}
fabric->tf_ops = sbp_ops;
diff --git a/drivers/target/target_core_alua.c b/drivers/target/target_core_alua.c
index 41641ba..9a5f9a7 100644
--- a/drivers/target/target_core_alua.c
+++ b/drivers/target/target_core_alua.c
@@ -344,7 +344,7 @@ int target_emulate_set_target_port_groups(struct se_cmd *cmd)
*/
rtpi = get_unaligned_be16(ptr + 2);
/*
- * Locate the matching relative target port identifer
+ * Locate the matching relative target port identifier
* for the struct se_device storage object.
*/
spin_lock(&dev->se_port_lock);
diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c
index 801efa8..015f5be 100644
--- a/drivers/target/target_core_configfs.c
+++ b/drivers/target/target_core_configfs.c
@@ -457,14 +457,6 @@ static int target_fabric_tf_ops_check(
pr_err("Missing tfo->queue_tm_rsp()\n");
return -EINVAL;
}
- if (!tfo->set_fabric_sense_len) {
- pr_err("Missing tfo->set_fabric_sense_len()\n");
- return -EINVAL;
- }
- if (!tfo->get_fabric_sense_len) {
- pr_err("Missing tfo->get_fabric_sense_len()\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
@@ -1208,7 +1200,7 @@ static ssize_t target_core_dev_pr_show_attr_res_pr_holder_tg_port(
" Target Node Endpoint: %s\n", tfo->get_fabric_name(),
tfo->tpg_get_wwn(se_tpg));
len += sprintf(page+len, "SPC-3 Reservation: Relative Port"
- " Identifer Tag: %hu %s Portal Group Tag: %hu"
+ " Identifier Tag: %hu %s Portal Group Tag: %hu"
" %s Logical Unit: %u\n", lun->lun_sep->sep_rtpi,
tfo->get_fabric_name(), tfo->tpg_get_tag(se_tpg),
tfo->get_fabric_name(), lun->unpacked_lun);
@@ -3132,6 +3124,7 @@ static int __init target_core_init_configfs(void)
GFP_KERNEL);
if (!target_cg->default_groups) {
pr_err("Unable to allocate target_cg->default_groups\n");
+ ret = -ENOMEM;
goto out_global;
}
@@ -3147,6 +3140,7 @@ static int __init target_core_init_configfs(void)
GFP_KERNEL);
if (!hba_cg->default_groups) {
pr_err("Unable to allocate hba_cg->default_groups\n");
+ ret = -ENOMEM;
goto out_global;
}
config_group_init_type_name(&alua_group,
@@ -3162,6 +3156,7 @@ static int __init target_core_init_configfs(void)
GFP_KERNEL);
if (!alua_cg->default_groups) {
pr_err("Unable to allocate alua_cg->default_groups\n");
+ ret = -ENOMEM;
goto out_global;
}
@@ -3173,14 +3168,17 @@ static int __init target_core_init_configfs(void)
* Add core/alua/lu_gps/default_lu_gp
*/
lu_gp = core_alua_allocate_lu_gp("default_lu_gp", 1);
- if (IS_ERR(lu_gp))
+ if (IS_ERR(lu_gp)) {
+ ret = -ENOMEM;
goto out_global;
+ }
lu_gp_cg = &alua_lu_gps_group;
lu_gp_cg->default_groups = kzalloc(sizeof(struct config_group) * 2,
GFP_KERNEL);
if (!lu_gp_cg->default_groups) {
pr_err("Unable to allocate lu_gp_cg->default_groups\n");
+ ret = -ENOMEM;
goto out_global;
}
diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c
index 9fc9a60..8d774da 100644
--- a/drivers/target/target_core_device.c
+++ b/drivers/target/target_core_device.c
@@ -531,7 +531,7 @@ static struct se_port *core_alloc_port(struct se_device *dev)
}
again:
/*
- * Allocate the next RELATIVE TARGET PORT IDENTIFER for this struct se_device
+ * Allocate the next RELATIVE TARGET PORT IDENTIFIER for this struct se_device
* Here is the table from spc4r17 section 7.7.3.8.
*
* Table 473 -- RELATIVE TARGET PORT IDENTIFIER field
@@ -548,7 +548,7 @@ again:
list_for_each_entry(port_tmp, &dev->dev_sep_list, sep_list) {
/*
- * Make sure RELATIVE TARGET PORT IDENTIFER is unique
+ * Make sure RELATIVE TARGET PORT IDENTIFIER is unique
* for 16-bit wrap..
*/
if (port->sep_rtpi == port_tmp->sep_rtpi)
@@ -595,7 +595,7 @@ static void core_export_port(
}
dev->dev_port_count++;
- port->sep_index = port->sep_rtpi; /* RELATIVE TARGET PORT IDENTIFER */
+ port->sep_index = port->sep_rtpi; /* RELATIVE TARGET PORT IDENTIFIER */
}
/*
@@ -988,8 +988,9 @@ int se_dev_set_emulate_fua_write(struct se_device *dev, int flag)
return -EINVAL;
}
- if (flag && dev->transport->fua_write_emulated == 0) {
- pr_err("fua_write_emulated not supported\n");
+ if (flag &&
+ dev->transport->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV) {
+ pr_err("emulate_fua_write not supported for pSCSI\n");
return -EINVAL;
}
dev->se_sub_dev->se_dev_attrib.emulate_fua_write = flag;
@@ -1019,8 +1020,9 @@ int se_dev_set_emulate_write_cache(struct se_device *dev, int flag)
pr_err("Illegal value %d\n", flag);
return -EINVAL;
}
- if (flag && dev->transport->write_cache_emulated == 0) {
- pr_err("write_cache_emulated not supported\n");
+ if (flag &&
+ dev->transport->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV) {
+ pr_err("emulate_write_cache not supported for pSCSI\n");
return -EINVAL;
}
dev->se_sub_dev->se_dev_attrib.emulate_write_cache = flag;
diff --git a/drivers/target/target_core_fabric_configfs.c b/drivers/target/target_core_fabric_configfs.c
index ea479e5..bca737b 100644
--- a/drivers/target/target_core_fabric_configfs.c
+++ b/drivers/target/target_core_fabric_configfs.c
@@ -22,7 +22,6 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
-#include <generated/utsrelease.h>
#include <linux/utsname.h>
#include <linux/init.h>
#include <linux/fs.h>
diff --git a/drivers/target/target_core_fabric_lib.c b/drivers/target/target_core_fabric_lib.c
index 283a36e..e460d62 100644
--- a/drivers/target/target_core_fabric_lib.c
+++ b/drivers/target/target_core_fabric_lib.c
@@ -338,7 +338,7 @@ u32 iscsi_get_pr_transport_id_len(
* 00b: iSCSI Initiator device TransportID format
*/
if (pr_reg->isid_present_at_reg) {
- len += 5; /* For ",i,0x" ASCII seperator */
+ len += 5; /* For ",i,0x" ASCII separator */
len += 7; /* For iSCSI Initiator Session ID + Null terminator */
*format_code = 1;
} else
@@ -415,20 +415,20 @@ char *iscsi_parse_pr_out_transport_id(
*out_tid_len = (add_len + 4);
}
/*
- * Check for ',i,0x' seperator between iSCSI Name and iSCSI Initiator
+ * Check for ',i,0x' separator between iSCSI Name and iSCSI Initiator
* Session ID as defined in Table 390 - iSCSI initiator port TransportID
* format.
*/
if (format_code == 0x40) {
p = strstr(&buf[4], ",i,0x");
if (!p) {
- pr_err("Unable to locate \",i,0x\" seperator"
+ pr_err("Unable to locate \",i,0x\" separator"
" for Initiator port identifier: %s\n",
&buf[4]);
return NULL;
}
*p = '\0'; /* Terminate iSCSI Name */
- p += 5; /* Skip over ",i,0x" seperator */
+ p += 5; /* Skip over ",i,0x" separator */
*port_nexus_ptr = p;
/*
diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c
index cbb5aaf..0360383 100644
--- a/drivers/target/target_core_file.c
+++ b/drivers/target/target_core_file.c
@@ -125,6 +125,19 @@ static struct se_device *fd_create_virtdevice(
* of pure timestamp updates.
*/
flags = O_RDWR | O_CREAT | O_LARGEFILE | O_DSYNC;
+ /*
+ * Optionally allow fd_buffered_io=1 to be enabled for people
+ * who want use the fs buffer cache as an WriteCache mechanism.
+ *
+ * This means that in event of a hard failure, there is a risk
+ * of silent data-loss if the SCSI client has *not* performed a
+ * forced unit access (FUA) write, or issued SYNCHRONIZE_CACHE
+ * to write-out the entire device cache.
+ */
+ if (fd_dev->fbd_flags & FDBD_HAS_BUFFERED_IO_WCE) {
+ pr_debug("FILEIO: Disabling O_DSYNC, using buffered FILEIO\n");
+ flags &= ~O_DSYNC;
+ }
file = filp_open(fd_dev->fd_dev_name, flags, 0600);
if (IS_ERR(file)) {
@@ -188,6 +201,12 @@ static struct se_device *fd_create_virtdevice(
if (!dev)
goto fail;
+ if (fd_dev->fbd_flags & FDBD_HAS_BUFFERED_IO_WCE) {
+ pr_debug("FILEIO: Forcing setting of emulate_write_cache=1"
+ " with FDBD_HAS_BUFFERED_IO_WCE\n");
+ dev->se_sub_dev->se_dev_attrib.emulate_write_cache = 1;
+ }
+
fd_dev->fd_dev_id = fd_host->fd_host_dev_id_count++;
fd_dev->fd_queue_depth = dev->queue_depth;
@@ -407,6 +426,7 @@ enum {
static match_table_t tokens = {
{Opt_fd_dev_name, "fd_dev_name=%s"},
{Opt_fd_dev_size, "fd_dev_size=%s"},
+ {Opt_fd_buffered_io, "fd_buffered_io=%d"},
{Opt_err, NULL}
};
@@ -418,7 +438,7 @@ static ssize_t fd_set_configfs_dev_params(
struct fd_dev *fd_dev = se_dev->se_dev_su_ptr;
char *orig, *ptr, *arg_p, *opts;
substring_t args[MAX_OPT_ARGS];
- int ret = 0, token;
+ int ret = 0, arg, token;
opts = kstrdup(page, GFP_KERNEL);
if (!opts)
@@ -459,6 +479,19 @@ static ssize_t fd_set_configfs_dev_params(
" bytes\n", fd_dev->fd_dev_size);
fd_dev->fbd_flags |= FBDF_HAS_SIZE;
break;
+ case Opt_fd_buffered_io:
+ match_int(args, &arg);
+ if (arg != 1) {
+ pr_err("bogus fd_buffered_io=%d value\n", arg);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ pr_debug("FILEIO: Using buffered I/O"
+ " operations for struct fd_dev\n");
+
+ fd_dev->fbd_flags |= FDBD_HAS_BUFFERED_IO_WCE;
+ break;
default:
break;
}
@@ -490,8 +523,10 @@ static ssize_t fd_show_configfs_dev_params(
ssize_t bl = 0;
bl = sprintf(b + bl, "TCM FILEIO ID: %u", fd_dev->fd_dev_id);
- bl += sprintf(b + bl, " File: %s Size: %llu Mode: O_DSYNC\n",
- fd_dev->fd_dev_name, fd_dev->fd_dev_size);
+ bl += sprintf(b + bl, " File: %s Size: %llu Mode: %s\n",
+ fd_dev->fd_dev_name, fd_dev->fd_dev_size,
+ (fd_dev->fbd_flags & FDBD_HAS_BUFFERED_IO_WCE) ?
+ "Buffered-WCE" : "O_DSYNC");
return bl;
}
@@ -546,8 +581,6 @@ static struct se_subsystem_api fileio_template = {
.name = "fileio",
.owner = THIS_MODULE,
.transport_type = TRANSPORT_PLUGIN_VHBA_PDEV,
- .write_cache_emulated = 1,
- .fua_write_emulated = 1,
.attach_hba = fd_attach_hba,
.detach_hba = fd_detach_hba,
.allocate_virtdevice = fd_allocate_virtdevice,
diff --git a/drivers/target/target_core_file.h b/drivers/target/target_core_file.h
index 70ce7fd..876ae53 100644
--- a/drivers/target/target_core_file.h
+++ b/drivers/target/target_core_file.h
@@ -14,6 +14,7 @@
#define FBDF_HAS_PATH 0x01
#define FBDF_HAS_SIZE 0x02
+#define FDBD_HAS_BUFFERED_IO_WCE 0x04
struct fd_dev {
u32 fbd_flags;
diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c
index 9ba4954..57d7674 100644
--- a/drivers/target/target_core_iblock.c
+++ b/drivers/target/target_core_iblock.c
@@ -454,14 +454,11 @@ static ssize_t iblock_set_configfs_dev_params(struct se_hba *hba,
ret = -EEXIST;
goto out;
}
- arg_p = match_strdup(&args[0]);
- if (!arg_p) {
- ret = -ENOMEM;
+ if (match_strlcpy(ib_dev->ibd_udev_path, &args[0],
+ SE_UDEV_PATH_LEN) == 0) {
+ ret = -EINVAL;
break;
}
- snprintf(ib_dev->ibd_udev_path, SE_UDEV_PATH_LEN,
- "%s", arg_p);
- kfree(arg_p);
pr_debug("IBLOCK: Referencing UDEV path: %s\n",
ib_dev->ibd_udev_path);
ib_dev->ibd_flags |= IBDF_HAS_UDEV_PATH;
@@ -556,14 +553,6 @@ static void iblock_complete_cmd(struct se_cmd *cmd)
kfree(ibr);
}
-static void iblock_bio_destructor(struct bio *bio)
-{
- struct se_cmd *cmd = bio->bi_private;
- struct iblock_dev *ib_dev = cmd->se_dev->dev_ptr;
-
- bio_free(bio, ib_dev->ibd_bio_set);
-}
-
static struct bio *
iblock_get_bio(struct se_cmd *cmd, sector_t lba, u32 sg_num)
{
@@ -585,7 +574,6 @@ iblock_get_bio(struct se_cmd *cmd, sector_t lba, u32 sg_num)
bio->bi_bdev = ib_dev->ibd_bd;
bio->bi_private = cmd;
- bio->bi_destructor = iblock_bio_destructor;
bio->bi_end_io = &iblock_bio_done;
bio->bi_sector = lba;
return bio;
@@ -657,6 +645,12 @@ static int iblock_execute_rw(struct se_cmd *cmd)
goto fail;
cmd->priv = ibr;
+ if (!sgl_nents) {
+ atomic_set(&ibr->pending, 1);
+ iblock_complete_cmd(cmd);
+ return 0;
+ }
+
bio = iblock_get_bio(cmd, block_lba, sgl_nents);
if (!bio)
goto fail_free_ibr;
@@ -769,8 +763,6 @@ static struct se_subsystem_api iblock_template = {
.name = "iblock",
.owner = THIS_MODULE,
.transport_type = TRANSPORT_PLUGIN_VHBA_PDEV,
- .write_cache_emulated = 1,
- .fua_write_emulated = 1,
.attach_hba = iblock_attach_hba,
.detach_hba = iblock_detach_hba,
.allocate_virtdevice = iblock_allocate_virtdevice,
diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c
index 956c84c..8c323a9 100644
--- a/drivers/target/target_core_pr.c
+++ b/drivers/target/target_core_pr.c
@@ -197,10 +197,10 @@ int target_scsi2_reservation_release(struct se_cmd *cmd)
{
struct se_device *dev = cmd->se_dev;
struct se_session *sess = cmd->se_sess;
- struct se_portal_group *tpg = sess->se_tpg;
+ struct se_portal_group *tpg;
int ret = 0, rc;
- if (!sess || !tpg)
+ if (!sess || !sess->se_tpg)
goto out;
rc = target_check_scsi2_reservation_conflict(cmd);
if (rc == 1)
@@ -228,6 +228,7 @@ int target_scsi2_reservation_release(struct se_cmd *cmd)
dev->dev_res_bin_isid = 0;
dev->dev_flags &= ~DF_SPC2_RESERVATIONS_WITH_ISID;
}
+ tpg = sess->se_tpg;
pr_debug("SCSI-2 Released reservation for %s LUN: %u ->"
" MAPPED LUN: %u for %s\n", tpg->se_tpg_tfo->get_fabric_name(),
cmd->se_lun->unpacked_lun, cmd->se_deve->mapped_lun,
@@ -245,7 +246,7 @@ int target_scsi2_reservation_reserve(struct se_cmd *cmd)
{
struct se_device *dev = cmd->se_dev;
struct se_session *sess = cmd->se_sess;
- struct se_portal_group *tpg = sess->se_tpg;
+ struct se_portal_group *tpg;
int ret = 0, rc;
if ((cmd->t_task_cdb[1] & 0x01) &&
@@ -260,7 +261,7 @@ int target_scsi2_reservation_reserve(struct se_cmd *cmd)
* This is currently the case for target_core_mod passthrough struct se_cmd
* ops
*/
- if (!sess || !tpg)
+ if (!sess || !sess->se_tpg)
goto out;
rc = target_check_scsi2_reservation_conflict(cmd);
if (rc == 1)
@@ -272,6 +273,7 @@ int target_scsi2_reservation_reserve(struct se_cmd *cmd)
}
ret = 0;
+ tpg = sess->se_tpg;
spin_lock(&dev->dev_reservation_lock);
if (dev->dev_reserved_node_acl &&
(dev->dev_reserved_node_acl != sess->se_node_acl)) {
@@ -1620,7 +1622,7 @@ static int core_scsi3_decode_spec_i_port(
goto out;
}
/*
- * Locate the desination initiator ACL to be registered
+ * Locate the destination initiator ACL to be registered
* from the decoded fabric module specific TransportID
* at *i_str.
*/
@@ -4257,7 +4259,7 @@ static int core_scsi3_pri_read_full_status(struct se_cmd *cmd)
buf[off++] = ((port->sep_rtpi >> 8) & 0xff);
buf[off++] = (port->sep_rtpi & 0xff);
} else
- off += 2; /* Skip over RELATIVE TARGET PORT IDENTIFER */
+ off += 2; /* Skip over RELATIVE TARGET PORT IDENTIFIER */
/*
* Now, have the $FABRIC_MOD fill in the protocol identifier
diff --git a/drivers/target/target_core_pscsi.c b/drivers/target/target_core_pscsi.c
index 9d7ce3d..617c086 100644
--- a/drivers/target/target_core_pscsi.c
+++ b/drivers/target/target_core_pscsi.c
@@ -264,7 +264,7 @@ pscsi_get_inquiry_vpd_device_ident(struct scsi_device *sdev,
" length zero!\n");
break;
}
- pr_debug("T10 VPD Identifer Length: %d\n", ident_len);
+ pr_debug("T10 VPD Identifier Length: %d\n", ident_len);
vpd = kzalloc(sizeof(struct t10_vpd), GFP_KERNEL);
if (!vpd) {
diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c
index a9dd946..868f8aa 100644
--- a/drivers/target/target_core_sbc.c
+++ b/drivers/target/target_core_sbc.c
@@ -40,8 +40,9 @@
static int sbc_emulate_readcapacity(struct se_cmd *cmd)
{
struct se_device *dev = cmd->se_dev;
- unsigned char *buf;
unsigned long long blocks_long = dev->transport->get_blocks(dev);
+ unsigned char *rbuf;
+ unsigned char buf[8];
u32 blocks;
if (blocks_long >= 0x00000000ffffffff)
@@ -49,8 +50,6 @@ static int sbc_emulate_readcapacity(struct se_cmd *cmd)
else
blocks = (u32)blocks_long;
- buf = transport_kmap_data_sg(cmd);
-
buf[0] = (blocks >> 24) & 0xff;
buf[1] = (blocks >> 16) & 0xff;
buf[2] = (blocks >> 8) & 0xff;
@@ -60,7 +59,11 @@ static int sbc_emulate_readcapacity(struct se_cmd *cmd)
buf[6] = (dev->se_sub_dev->se_dev_attrib.block_size >> 8) & 0xff;
buf[7] = dev->se_sub_dev->se_dev_attrib.block_size & 0xff;
- transport_kunmap_data_sg(cmd);
+ rbuf = transport_kmap_data_sg(cmd);
+ if (rbuf) {
+ memcpy(rbuf, buf, min_t(u32, sizeof(buf), cmd->data_length));
+ transport_kunmap_data_sg(cmd);
+ }
target_complete_cmd(cmd, GOOD);
return 0;
@@ -69,11 +72,11 @@ static int sbc_emulate_readcapacity(struct se_cmd *cmd)
static int sbc_emulate_readcapacity_16(struct se_cmd *cmd)
{
struct se_device *dev = cmd->se_dev;
- unsigned char *buf;
+ unsigned char *rbuf;
+ unsigned char buf[32];
unsigned long long blocks = dev->transport->get_blocks(dev);
- buf = transport_kmap_data_sg(cmd);
-
+ memset(buf, 0, sizeof(buf));
buf[0] = (blocks >> 56) & 0xff;
buf[1] = (blocks >> 48) & 0xff;
buf[2] = (blocks >> 40) & 0xff;
@@ -93,7 +96,11 @@ static int sbc_emulate_readcapacity_16(struct se_cmd *cmd)
if (dev->se_sub_dev->se_dev_attrib.emulate_tpu || dev->se_sub_dev->se_dev_attrib.emulate_tpws)
buf[14] = 0x80;
- transport_kunmap_data_sg(cmd);
+ rbuf = transport_kmap_data_sg(cmd);
+ if (rbuf) {
+ memcpy(rbuf, buf, min_t(u32, sizeof(buf), cmd->data_length));
+ transport_kunmap_data_sg(cmd);
+ }
target_complete_cmd(cmd, GOOD);
return 0;
diff --git a/drivers/target/target_core_spc.c b/drivers/target/target_core_spc.c
index 388a922..9229bd9 100644
--- a/drivers/target/target_core_spc.c
+++ b/drivers/target/target_core_spc.c
@@ -600,30 +600,11 @@ static int spc_emulate_inquiry(struct se_cmd *cmd)
{
struct se_device *dev = cmd->se_dev;
struct se_portal_group *tpg = cmd->se_lun->lun_sep->sep_tpg;
- unsigned char *buf, *map_buf;
+ unsigned char *rbuf;
unsigned char *cdb = cmd->t_task_cdb;
+ unsigned char buf[SE_INQUIRY_BUF];
int p, ret;
- map_buf = transport_kmap_data_sg(cmd);
- /*
- * If SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC is not set, then we
- * know we actually allocated a full page. Otherwise, if the
- * data buffer is too small, allocate a temporary buffer so we
- * don't have to worry about overruns in all our INQUIRY
- * emulation handling.
- */
- if (cmd->data_length < SE_INQUIRY_BUF &&
- (cmd->se_cmd_flags & SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC)) {
- buf = kzalloc(SE_INQUIRY_BUF, GFP_KERNEL);
- if (!buf) {
- transport_kunmap_data_sg(cmd);
- cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
- return -ENOMEM;
- }
- } else {
- buf = map_buf;
- }
-
if (dev == tpg->tpg_virt_lun0.lun_se_dev)
buf[0] = 0x3f; /* Not connected */
else
@@ -655,11 +636,11 @@ static int spc_emulate_inquiry(struct se_cmd *cmd)
ret = -EINVAL;
out:
- if (buf != map_buf) {
- memcpy(map_buf, buf, cmd->data_length);
- kfree(buf);
+ rbuf = transport_kmap_data_sg(cmd);
+ if (rbuf) {
+ memcpy(rbuf, buf, min_t(u32, sizeof(buf), cmd->data_length));
+ transport_kunmap_data_sg(cmd);
}
- transport_kunmap_data_sg(cmd);
if (!ret)
target_complete_cmd(cmd, GOOD);
@@ -803,7 +784,7 @@ static int spc_emulate_modesense(struct se_cmd *cmd)
unsigned char *rbuf;
int type = dev->transport->get_device_type(dev);
int ten = (cmd->t_task_cdb[0] == MODE_SENSE_10);
- int offset = ten ? 8 : 4;
+ u32 offset = ten ? 8 : 4;
int length = 0;
unsigned char buf[SE_MODE_PAGE_BUF];
@@ -836,6 +817,7 @@ static int spc_emulate_modesense(struct se_cmd *cmd)
offset -= 2;
buf[0] = (offset >> 8) & 0xff;
buf[1] = offset & 0xff;
+ offset += 2;
if ((cmd->se_lun->lun_access & TRANSPORT_LUNFLAGS_READ_ONLY) ||
(cmd->se_deve &&
@@ -845,13 +827,10 @@ static int spc_emulate_modesense(struct se_cmd *cmd)
if ((dev->se_sub_dev->se_dev_attrib.emulate_write_cache > 0) &&
(dev->se_sub_dev->se_dev_attrib.emulate_fua_write > 0))
spc_modesense_dpofua(&buf[3], type);
-
- if ((offset + 2) > cmd->data_length)
- offset = cmd->data_length;
-
} else {
offset -= 1;
buf[0] = offset & 0xff;
+ offset += 1;
if ((cmd->se_lun->lun_access & TRANSPORT_LUNFLAGS_READ_ONLY) ||
(cmd->se_deve &&
@@ -861,14 +840,13 @@ static int spc_emulate_modesense(struct se_cmd *cmd)
if ((dev->se_sub_dev->se_dev_attrib.emulate_write_cache > 0) &&
(dev->se_sub_dev->se_dev_attrib.emulate_fua_write > 0))
spc_modesense_dpofua(&buf[2], type);
-
- if ((offset + 1) > cmd->data_length)
- offset = cmd->data_length;
}
rbuf = transport_kmap_data_sg(cmd);
- memcpy(rbuf, buf, offset);
- transport_kunmap_data_sg(cmd);
+ if (rbuf) {
+ memcpy(rbuf, buf, min(offset, cmd->data_length));
+ transport_kunmap_data_sg(cmd);
+ }
target_complete_cmd(cmd, GOOD);
return 0;
diff --git a/drivers/target/target_core_stat.c b/drivers/target/target_core_stat.c
index 3d44beb..cb6b003 100644
--- a/drivers/target/target_core_stat.c
+++ b/drivers/target/target_core_stat.c
@@ -32,7 +32,6 @@
#include <linux/delay.h>
#include <linux/timer.h>
#include <linux/string.h>
-#include <generated/utsrelease.h>
#include <linux/utsname.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c
index b8628a5..a531fe2 100644
--- a/drivers/target/target_core_tpg.c
+++ b/drivers/target/target_core_tpg.c
@@ -303,7 +303,7 @@ struct se_node_acl *core_tpg_check_initiator_node_acl(
}
/*
* Here we only create demo-mode MappedLUNs from the active
- * TPG LUNs if the fabric is not explictly asking for
+ * TPG LUNs if the fabric is not explicitly asking for
* tpg_check_demo_mode_login_only() == 1.
*/
if ((tpg->se_tpg_tfo->tpg_check_demo_mode_login_only == NULL) ||
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c
index 269f544..c33baff 100644
--- a/drivers/target/target_core_transport.c
+++ b/drivers/target/target_core_transport.c
@@ -55,8 +55,6 @@
#include "target_core_pr.h"
#include "target_core_ua.h"
-static int sub_api_initialized;
-
static struct workqueue_struct *target_completion_wq;
static struct kmem_cache *se_sess_cache;
struct kmem_cache *se_ua_cache;
@@ -195,6 +193,7 @@ u32 scsi_get_new_index(scsi_index_t type)
void transport_subsystem_check_init(void)
{
int ret;
+ static int sub_api_initialized;
if (sub_api_initialized)
return;
@@ -211,12 +210,7 @@ void transport_subsystem_check_init(void)
if (ret != 0)
pr_err("Unable to load target_core_pscsi\n");
- ret = request_module("target_core_stgt");
- if (ret != 0)
- pr_err("Unable to load target_core_stgt\n");
-
sub_api_initialized = 1;
- return;
}
struct se_session *transport_init_session(void)
@@ -573,9 +567,7 @@ static void target_complete_failure_work(struct work_struct *work)
*/
static unsigned char *transport_get_sense_buffer(struct se_cmd *cmd)
{
- unsigned char *buffer = cmd->sense_buffer;
struct se_device *dev = cmd->se_dev;
- u32 offset = 0;
WARN_ON(!cmd->se_lun);
@@ -585,14 +577,11 @@ static unsigned char *transport_get_sense_buffer(struct se_cmd *cmd)
if (cmd->se_cmd_flags & SCF_SENT_CHECK_CONDITION)
return NULL;
- offset = cmd->se_tfo->set_fabric_sense_len(cmd, TRANSPORT_SENSE_BUFFER);
-
- /* Automatically padded */
- cmd->scsi_sense_length = TRANSPORT_SENSE_BUFFER + offset;
+ cmd->scsi_sense_length = TRANSPORT_SENSE_BUFFER;
pr_debug("HBA_[%u]_PLUG[%s]: Requesting sense for SAM STATUS: 0x%02x\n",
dev->se_hba->hba_id, dev->transport->name, cmd->scsi_status);
- return &buffer[offset];
+ return cmd->sense_buffer;
}
void target_complete_cmd(struct se_cmd *cmd, u8 scsi_status)
@@ -969,7 +958,7 @@ int
transport_set_vpd_ident(struct t10_vpd *vpd, unsigned char *page_83)
{
static const char hex_str[] = "0123456789abcdef";
- int j = 0, i = 4; /* offset to start of the identifer */
+ int j = 0, i = 4; /* offset to start of the identifier */
/*
* The VPD Code Set (encoding)
@@ -1466,8 +1455,9 @@ int transport_handle_cdb_direct(
}
EXPORT_SYMBOL(transport_handle_cdb_direct);
-/**
- * target_submit_cmd - lookup unpacked lun and submit uninitialized se_cmd
+/*
+ * target_submit_cmd_map_sgls - lookup unpacked lun and submit uninitialized
+ * se_cmd + use pre-allocated SGL memory.
*
* @se_cmd: command descriptor to submit
* @se_sess: associated se_sess for endpoint
@@ -1478,6 +1468,10 @@ EXPORT_SYMBOL(transport_handle_cdb_direct);
* @task_addr: SAM task attribute
* @data_dir: DMA data direction
* @flags: flags for command submission from target_sc_flags_tables
+ * @sgl: struct scatterlist memory for unidirectional mapping
+ * @sgl_count: scatterlist count for unidirectional mapping
+ * @sgl_bidi: struct scatterlist memory for bidirectional READ mapping
+ * @sgl_bidi_count: scatterlist count for bidirectional READ mapping
*
* Returns non zero to signal active I/O shutdown failure. All other
* setup exceptions will be returned as a SCSI CHECK_CONDITION response,
@@ -1485,10 +1479,12 @@ EXPORT_SYMBOL(transport_handle_cdb_direct);
*
* This may only be called from process context, and also currently
* assumes internal allocation of fabric payload buffer by target-core.
- **/
-int target_submit_cmd(struct se_cmd *se_cmd, struct se_session *se_sess,
+ */
+int target_submit_cmd_map_sgls(struct se_cmd *se_cmd, struct se_session *se_sess,
unsigned char *cdb, unsigned char *sense, u32 unpacked_lun,
- u32 data_length, int task_attr, int data_dir, int flags)
+ u32 data_length, int task_attr, int data_dir, int flags,
+ struct scatterlist *sgl, u32 sgl_count,
+ struct scatterlist *sgl_bidi, u32 sgl_bidi_count)
{
struct se_portal_group *se_tpg;
int rc;
@@ -1535,7 +1531,42 @@ int target_submit_cmd(struct se_cmd *se_cmd, struct se_session *se_sess,
transport_generic_request_failure(se_cmd);
return 0;
}
+ /*
+ * When a non zero sgl_count has been passed perform SGL passthrough
+ * mapping for pre-allocated fabric memory instead of having target
+ * core perform an internal SGL allocation..
+ */
+ if (sgl_count != 0) {
+ BUG_ON(!sgl);
+
+ /*
+ * A work-around for tcm_loop as some userspace code via
+ * scsi-generic do not memset their associated read buffers,
+ * so go ahead and do that here for type non-data CDBs. Also
+ * note that this is currently guaranteed to be a single SGL
+ * for this case by target core in target_setup_cmd_from_cdb()
+ * -> transport_generic_cmd_sequencer().
+ */
+ if (!(se_cmd->se_cmd_flags & SCF_SCSI_DATA_CDB) &&
+ se_cmd->data_direction == DMA_FROM_DEVICE) {
+ unsigned char *buf = NULL;
+
+ if (sgl)
+ buf = kmap(sg_page(sgl)) + sgl->offset;
+
+ if (buf) {
+ memset(buf, 0, sgl->length);
+ kunmap(sg_page(sgl));
+ }
+ }
+ rc = transport_generic_map_mem_to_cmd(se_cmd, sgl, sgl_count,
+ sgl_bidi, sgl_bidi_count);
+ if (rc != 0) {
+ transport_generic_request_failure(se_cmd);
+ return 0;
+ }
+ }
/*
* Check if we need to delay processing because of ALUA
* Active/NonOptimized primary access state..
@@ -1545,6 +1576,38 @@ int target_submit_cmd(struct se_cmd *se_cmd, struct se_session *se_sess,
transport_handle_cdb_direct(se_cmd);
return 0;
}
+EXPORT_SYMBOL(target_submit_cmd_map_sgls);
+
+/*
+ * target_submit_cmd - lookup unpacked lun and submit uninitialized se_cmd
+ *
+ * @se_cmd: command descriptor to submit
+ * @se_sess: associated se_sess for endpoint
+ * @cdb: pointer to SCSI CDB
+ * @sense: pointer to SCSI sense buffer
+ * @unpacked_lun: unpacked LUN to reference for struct se_lun
+ * @data_length: fabric expected data transfer length
+ * @task_addr: SAM task attribute
+ * @data_dir: DMA data direction
+ * @flags: flags for command submission from target_sc_flags_tables
+ *
+ * Returns non zero to signal active I/O shutdown failure. All other
+ * setup exceptions will be returned as a SCSI CHECK_CONDITION response,
+ * but still return zero here.
+ *
+ * This may only be called from process context, and also currently
+ * assumes internal allocation of fabric payload buffer by target-core.
+ *
+ * It also assumes interal target core SGL memory allocation.
+ */
+int target_submit_cmd(struct se_cmd *se_cmd, struct se_session *se_sess,
+ unsigned char *cdb, unsigned char *sense, u32 unpacked_lun,
+ u32 data_length, int task_attr, int data_dir, int flags)
+{
+ return target_submit_cmd_map_sgls(se_cmd, se_sess, cdb, sense,
+ unpacked_lun, data_length, task_attr, data_dir,
+ flags, NULL, 0, NULL, 0);
+}
EXPORT_SYMBOL(target_submit_cmd);
static void target_complete_tmr_failure(struct work_struct *work)
@@ -2300,23 +2363,6 @@ int transport_generic_new_cmd(struct se_cmd *cmd)
if (ret < 0)
goto out_fail;
}
- /*
- * If this command doesn't have any payload and we don't have to call
- * into the fabric for data transfers, go ahead and complete it right
- * away.
- */
- if (!cmd->data_length &&
- cmd->t_task_cdb[0] != REQUEST_SENSE &&
- cmd->se_dev->transport->transport_type != TRANSPORT_PLUGIN_PHBA_PDEV) {
- spin_lock_irq(&cmd->t_state_lock);
- cmd->t_state = TRANSPORT_COMPLETE;
- cmd->transport_state |= CMD_T_ACTIVE;
- spin_unlock_irq(&cmd->t_state_lock);
-
- INIT_WORK(&cmd->work, target_complete_ok_work);
- queue_work(target_completion_wq, &cmd->work);
- return 0;
- }
atomic_inc(&cmd->t_fe_count);
@@ -2771,7 +2817,7 @@ bool transport_wait_for_tasks(struct se_cmd *cmd)
spin_lock_irqsave(&cmd->t_state_lock, flags);
cmd->transport_state &= ~(CMD_T_ACTIVE | CMD_T_STOP);
- pr_debug("wait_for_tasks: Stopped wait_for_compltion("
+ pr_debug("wait_for_tasks: Stopped wait_for_completion("
"&cmd->t_transport_stop_comp) for ITT: 0x%08x\n",
cmd->se_tfo->get_task_tag(cmd));
@@ -2810,7 +2856,6 @@ int transport_send_check_condition_and_sense(
{
unsigned char *buffer = cmd->sense_buffer;
unsigned long flags;
- int offset;
u8 asc = 0, ascq = 0;
spin_lock_irqsave(&cmd->t_state_lock, flags);
@@ -2826,14 +2871,7 @@ int transport_send_check_condition_and_sense(
if (!from_transport)
cmd->se_cmd_flags |= SCF_EMULATED_TASK_SENSE;
- /*
- * Data Segment and SenseLength of the fabric response PDU.
- *
- * TRANSPORT_SENSE_BUFFER is now set to SCSI_SENSE_BUFFERSIZE
- * from include/scsi/scsi_cmnd.h
- */
- offset = cmd->se_tfo->set_fabric_sense_len(cmd,
- TRANSPORT_SENSE_BUFFER);
+
/*
* Actual SENSE DATA, see SPC-3 7.23.2 SPC_SENSE_KEY_OFFSET uses
* SENSE KEY values from include/scsi/scsi.h
@@ -2841,151 +2879,151 @@ int transport_send_check_condition_and_sense(
switch (reason) {
case TCM_NON_EXISTENT_LUN:
/* CURRENT ERROR */
- buffer[offset] = 0x70;
- buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10;
+ buffer[0] = 0x70;
+ buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10;
/* ILLEGAL REQUEST */
- buffer[offset+SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST;
+ buffer[SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST;
/* LOGICAL UNIT NOT SUPPORTED */
- buffer[offset+SPC_ASC_KEY_OFFSET] = 0x25;
+ buffer[SPC_ASC_KEY_OFFSET] = 0x25;
break;
case TCM_UNSUPPORTED_SCSI_OPCODE:
case TCM_SECTOR_COUNT_TOO_MANY:
/* CURRENT ERROR */
- buffer[offset] = 0x70;
- buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10;
+ buffer[0] = 0x70;
+ buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10;
/* ILLEGAL REQUEST */
- buffer[offset+SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST;
+ buffer[SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST;
/* INVALID COMMAND OPERATION CODE */
- buffer[offset+SPC_ASC_KEY_OFFSET] = 0x20;
+ buffer[SPC_ASC_KEY_OFFSET] = 0x20;
break;
case TCM_UNKNOWN_MODE_PAGE:
/* CURRENT ERROR */
- buffer[offset] = 0x70;
- buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10;
+ buffer[0] = 0x70;
+ buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10;
/* ILLEGAL REQUEST */
- buffer[offset+SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST;
+ buffer[SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST;
/* INVALID FIELD IN CDB */
- buffer[offset+SPC_ASC_KEY_OFFSET] = 0x24;
+ buffer[SPC_ASC_KEY_OFFSET] = 0x24;
break;
case TCM_CHECK_CONDITION_ABORT_CMD:
/* CURRENT ERROR */
- buffer[offset] = 0x70;
- buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10;
+ buffer[0] = 0x70;
+ buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10;
/* ABORTED COMMAND */
- buffer[offset+SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND;
+ buffer[SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND;
/* BUS DEVICE RESET FUNCTION OCCURRED */
- buffer[offset+SPC_ASC_KEY_OFFSET] = 0x29;
- buffer[offset+SPC_ASCQ_KEY_OFFSET] = 0x03;
+ buffer[SPC_ASC_KEY_OFFSET] = 0x29;
+ buffer[SPC_ASCQ_KEY_OFFSET] = 0x03;
break;
case TCM_INCORRECT_AMOUNT_OF_DATA:
/* CURRENT ERROR */
- buffer[offset] = 0x70;
- buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10;
+ buffer[0] = 0x70;
+ buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10;
/* ABORTED COMMAND */
- buffer[offset+SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND;
+ buffer[SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND;
/* WRITE ERROR */
- buffer[offset+SPC_ASC_KEY_OFFSET] = 0x0c;
+ buffer[SPC_ASC_KEY_OFFSET] = 0x0c;
/* NOT ENOUGH UNSOLICITED DATA */
- buffer[offset+SPC_ASCQ_KEY_OFFSET] = 0x0d;
+ buffer[SPC_ASCQ_KEY_OFFSET] = 0x0d;
break;
case TCM_INVALID_CDB_FIELD:
/* CURRENT ERROR */
- buffer[offset] = 0x70;
- buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10;
+ buffer[0] = 0x70;
+ buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10;
/* ILLEGAL REQUEST */
- buffer[offset+SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST;
+ buffer[SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST;
/* INVALID FIELD IN CDB */
- buffer[offset+SPC_ASC_KEY_OFFSET] = 0x24;
+ buffer[SPC_ASC_KEY_OFFSET] = 0x24;
break;
case TCM_INVALID_PARAMETER_LIST:
/* CURRENT ERROR */
- buffer[offset] = 0x70;
- buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10;
+ buffer[0] = 0x70;
+ buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10;
/* ILLEGAL REQUEST */
- buffer[offset+SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST;
+ buffer[SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST;
/* INVALID FIELD IN PARAMETER LIST */
- buffer[offset+SPC_ASC_KEY_OFFSET] = 0x26;
+ buffer[SPC_ASC_KEY_OFFSET] = 0x26;
break;
case TCM_UNEXPECTED_UNSOLICITED_DATA:
/* CURRENT ERROR */
- buffer[offset] = 0x70;
- buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10;
+ buffer[0] = 0x70;
+ buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10;
/* ABORTED COMMAND */
- buffer[offset+SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND;
+ buffer[SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND;
/* WRITE ERROR */
- buffer[offset+SPC_ASC_KEY_OFFSET] = 0x0c;
+ buffer[SPC_ASC_KEY_OFFSET] = 0x0c;
/* UNEXPECTED_UNSOLICITED_DATA */
- buffer[offset+SPC_ASCQ_KEY_OFFSET] = 0x0c;
+ buffer[SPC_ASCQ_KEY_OFFSET] = 0x0c;
break;
case TCM_SERVICE_CRC_ERROR:
/* CURRENT ERROR */
- buffer[offset] = 0x70;
- buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10;
+ buffer[0] = 0x70;
+ buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10;
/* ABORTED COMMAND */
- buffer[offset+SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND;
+ buffer[SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND;
/* PROTOCOL SERVICE CRC ERROR */
- buffer[offset+SPC_ASC_KEY_OFFSET] = 0x47;
+ buffer[SPC_ASC_KEY_OFFSET] = 0x47;
/* N/A */
- buffer[offset+SPC_ASCQ_KEY_OFFSET] = 0x05;
+ buffer[SPC_ASCQ_KEY_OFFSET] = 0x05;
break;
case TCM_SNACK_REJECTED:
/* CURRENT ERROR */
- buffer[offset] = 0x70;
- buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10;
+ buffer[0] = 0x70;
+ buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10;
/* ABORTED COMMAND */
- buffer[offset+SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND;
+ buffer[SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND;
/* READ ERROR */
- buffer[offset+SPC_ASC_KEY_OFFSET] = 0x11;
+ buffer[SPC_ASC_KEY_OFFSET] = 0x11;
/* FAILED RETRANSMISSION REQUEST */
- buffer[offset+SPC_ASCQ_KEY_OFFSET] = 0x13;
+ buffer[SPC_ASCQ_KEY_OFFSET] = 0x13;
break;
case TCM_WRITE_PROTECTED:
/* CURRENT ERROR */
- buffer[offset] = 0x70;
- buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10;
+ buffer[0] = 0x70;
+ buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10;
/* DATA PROTECT */
- buffer[offset+SPC_SENSE_KEY_OFFSET] = DATA_PROTECT;
+ buffer[SPC_SENSE_KEY_OFFSET] = DATA_PROTECT;
/* WRITE PROTECTED */
- buffer[offset+SPC_ASC_KEY_OFFSET] = 0x27;
+ buffer[SPC_ASC_KEY_OFFSET] = 0x27;
break;
case TCM_ADDRESS_OUT_OF_RANGE:
/* CURRENT ERROR */
- buffer[offset] = 0x70;
- buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10;
+ buffer[0] = 0x70;
+ buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10;
/* ILLEGAL REQUEST */
- buffer[offset+SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST;
+ buffer[SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST;
/* LOGICAL BLOCK ADDRESS OUT OF RANGE */
- buffer[offset+SPC_ASC_KEY_OFFSET] = 0x21;
+ buffer[SPC_ASC_KEY_OFFSET] = 0x21;
break;
case TCM_CHECK_CONDITION_UNIT_ATTENTION:
/* CURRENT ERROR */
- buffer[offset] = 0x70;
- buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10;
+ buffer[0] = 0x70;
+ buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10;
/* UNIT ATTENTION */
- buffer[offset+SPC_SENSE_KEY_OFFSET] = UNIT_ATTENTION;
+ buffer[SPC_SENSE_KEY_OFFSET] = UNIT_ATTENTION;
core_scsi3_ua_for_check_condition(cmd, &asc, &ascq);
- buffer[offset+SPC_ASC_KEY_OFFSET] = asc;
- buffer[offset+SPC_ASCQ_KEY_OFFSET] = ascq;
+ buffer[SPC_ASC_KEY_OFFSET] = asc;
+ buffer[SPC_ASCQ_KEY_OFFSET] = ascq;
break;
case TCM_CHECK_CONDITION_NOT_READY:
/* CURRENT ERROR */
- buffer[offset] = 0x70;
- buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10;
+ buffer[0] = 0x70;
+ buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10;
/* Not Ready */
- buffer[offset+SPC_SENSE_KEY_OFFSET] = NOT_READY;
+ buffer[SPC_SENSE_KEY_OFFSET] = NOT_READY;
transport_get_sense_codes(cmd, &asc, &ascq);
- buffer[offset+SPC_ASC_KEY_OFFSET] = asc;
- buffer[offset+SPC_ASCQ_KEY_OFFSET] = ascq;
+ buffer[SPC_ASC_KEY_OFFSET] = asc;
+ buffer[SPC_ASCQ_KEY_OFFSET] = ascq;
break;
case TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE:
default:
/* CURRENT ERROR */
- buffer[offset] = 0x70;
- buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10;
+ buffer[0] = 0x70;
+ buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10;
/* ILLEGAL REQUEST */
- buffer[offset+SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST;
+ buffer[SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST;
/* LOGICAL UNIT COMMUNICATION FAILURE */
- buffer[offset+SPC_ASC_KEY_OFFSET] = 0x80;
+ buffer[SPC_ASC_KEY_OFFSET] = 0x80;
break;
}
/*
@@ -2996,7 +3034,7 @@ int transport_send_check_condition_and_sense(
* Automatically padded, this value is encoded in the fabric's
* data_length response PDU containing the SCSI defined sense data.
*/
- cmd->scsi_sense_length = TRANSPORT_SENSE_BUFFER + offset;
+ cmd->scsi_sense_length = TRANSPORT_SENSE_BUFFER;
after_reason:
return cmd->se_tfo->queue_status(cmd);
diff --git a/drivers/target/tcm_fc/tfc_cmd.c b/drivers/target/tcm_fc/tfc_cmd.c
index 823e692..b406f17 100644
--- a/drivers/target/tcm_fc/tfc_cmd.c
+++ b/drivers/target/tcm_fc/tfc_cmd.c
@@ -19,7 +19,6 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
-#include <generated/utsrelease.h>
#include <linux/utsname.h>
#include <linux/init.h>
#include <linux/slab.h>
diff --git a/drivers/target/tcm_fc/tfc_conf.c b/drivers/target/tcm_fc/tfc_conf.c
index 9501844..b74feb0 100644
--- a/drivers/target/tcm_fc/tfc_conf.c
+++ b/drivers/target/tcm_fc/tfc_conf.c
@@ -495,16 +495,6 @@ static void ft_set_default_node_attr(struct se_node_acl *se_nacl)
{
}
-static u16 ft_get_fabric_sense_len(void)
-{
- return 0;
-}
-
-static u16 ft_set_fabric_sense_len(struct se_cmd *se_cmd, u32 sense_len)
-{
- return 0;
-}
-
static u32 ft_tpg_get_inst_index(struct se_portal_group *se_tpg)
{
struct ft_tpg *tpg = se_tpg->se_tpg_fabric_ptr;
@@ -542,8 +532,6 @@ static struct target_core_fabric_ops ft_fabric_ops = {
.queue_data_in = ft_queue_data_in,
.queue_status = ft_queue_status,
.queue_tm_rsp = ft_queue_tm_resp,
- .get_fabric_sense_len = ft_get_fabric_sense_len,
- .set_fabric_sense_len = ft_set_fabric_sense_len,
/*
* Setup function pointers for generic logic in
* target_core_fabric_configfs.c
diff --git a/drivers/target/tcm_fc/tfc_io.c b/drivers/target/tcm_fc/tfc_io.c
index ad36ede1..b6fd4cf 100644
--- a/drivers/target/tcm_fc/tfc_io.c
+++ b/drivers/target/tcm_fc/tfc_io.c
@@ -28,7 +28,6 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
-#include <generated/utsrelease.h>
#include <linux/utsname.h>
#include <linux/init.h>
#include <linux/slab.h>
@@ -328,11 +327,12 @@ drop:
*/
void ft_invl_hw_context(struct ft_cmd *cmd)
{
- struct fc_seq *seq = cmd->seq;
+ struct fc_seq *seq;
struct fc_exch *ep = NULL;
struct fc_lport *lport = NULL;
BUG_ON(!cmd);
+ seq = cmd->seq;
/* Cleanup the DDP context in HW if DDP was setup */
if (cmd->was_ddp_setup && seq) {
diff --git a/drivers/target/tcm_fc/tfc_sess.c b/drivers/target/tcm_fc/tfc_sess.c
index 3c9e5b5..9585010 100644
--- a/drivers/target/tcm_fc/tfc_sess.c
+++ b/drivers/target/tcm_fc/tfc_sess.c
@@ -19,7 +19,6 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
-#include <generated/utsrelease.h>
#include <linux/utsname.h>
#include <linux/init.h>
#include <linux/slab.h>
diff --git a/drivers/usb/gadget/tcm_usb_gadget.c b/drivers/usb/gadget/tcm_usb_gadget.c
index eaa1005..97e68b3 100644
--- a/drivers/usb/gadget/tcm_usb_gadget.c
+++ b/drivers/usb/gadget/tcm_usb_gadget.c
@@ -1472,16 +1472,6 @@ static int usbg_queue_tm_rsp(struct se_cmd *se_cmd)
return 0;
}
-static u16 usbg_set_fabric_sense_len(struct se_cmd *se_cmd, u32 sense_length)
-{
- return 0;
-}
-
-static u16 usbg_get_fabric_sense_len(void)
-{
- return 0;
-}
-
static const char *usbg_check_wwn(const char *name)
{
const char *n;
@@ -1822,7 +1812,7 @@ static ssize_t tcm_usbg_tpg_store_nexus(
ret = tcm_usbg_drop_nexus(tpg);
return (!ret) ? count : ret;
}
- if (strlen(page) > USBG_NAMELEN) {
+ if (strlen(page) >= USBG_NAMELEN) {
pr_err("Emulated NAA Sas Address: %s, exceeds"
" max: %d\n", page, USBG_NAMELEN);
return -EINVAL;
@@ -1907,8 +1897,6 @@ static struct target_core_fabric_ops usbg_ops = {
.queue_data_in = usbg_send_read_response,
.queue_status = usbg_send_status_response,
.queue_tm_rsp = usbg_queue_tm_rsp,
- .get_fabric_sense_len = usbg_get_fabric_sense_len,
- .set_fabric_sense_len = usbg_set_fabric_sense_len,
.check_stop_free = usbg_check_stop_free,
.fabric_make_wwn = usbg_make_tport,
@@ -1968,7 +1956,6 @@ static void usbg_deregister_configfs(void)
static struct usb_interface_descriptor bot_intf_desc = {
.bLength = sizeof(bot_intf_desc),
.bDescriptorType = USB_DT_INTERFACE,
- .bAlternateSetting = 0,
.bNumEndpoints = 2,
.bAlternateSetting = USB_G_ALT_INT_BBB,
.bInterfaceClass = USB_CLASS_MASS_STORAGE,
diff --git a/drivers/vfio/pci/vfio_pci.c b/drivers/vfio/pci/vfio_pci.c
index 6d369fe..6c11994 100644
--- a/drivers/vfio/pci/vfio_pci.c
+++ b/drivers/vfio/pci/vfio_pci.c
@@ -408,7 +408,7 @@ static int vfio_pci_mmap(void *device_data, struct vm_area_struct *vma)
struct vfio_pci_device *vdev = device_data;
struct pci_dev *pdev = vdev->pdev;
unsigned int index;
- u64 phys_len, req_len, pgoff, req_start, phys;
+ u64 phys_len, req_len, pgoff, req_start;
int ret;
index = vma->vm_pgoff >> (VFIO_PCI_OFFSET_SHIFT - PAGE_SHIFT);
@@ -463,10 +463,9 @@ static int vfio_pci_mmap(void *device_data, struct vm_area_struct *vma)
vma->vm_private_data = vdev;
vma->vm_flags |= VM_IO | VM_DONTEXPAND | VM_DONTDUMP;
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+ vma->vm_pgoff = (pci_resource_start(pdev, index) >> PAGE_SHIFT) + pgoff;
- phys = (pci_resource_start(pdev, index) >> PAGE_SHIFT) + pgoff;
-
- return remap_pfn_range(vma, vma->vm_start, phys,
+ return remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
req_len, vma->vm_page_prot);
}
diff --git a/drivers/vfio/pci/vfio_pci_intrs.c b/drivers/vfio/pci/vfio_pci_intrs.c
index d8dedc7..3639371 100644
--- a/drivers/vfio/pci/vfio_pci_intrs.c
+++ b/drivers/vfio/pci/vfio_pci_intrs.c
@@ -366,6 +366,17 @@ static int vfio_intx_enable(struct vfio_pci_device *vdev)
return -ENOMEM;
vdev->num_ctx = 1;
+
+ /*
+ * If the virtual interrupt is masked, restore it. Devices
+ * supporting DisINTx can be masked at the hardware level
+ * here, non-PCI-2.3 devices will have to wait until the
+ * interrupt is enabled.
+ */
+ vdev->ctx[0].masked = vdev->virq_disabled;
+ if (vdev->pci_2_3)
+ pci_intx(vdev->pdev, !vdev->ctx[0].masked);
+
vdev->irq_type = VFIO_PCI_INTX_IRQ_INDEX;
return 0;
@@ -400,25 +411,26 @@ static int vfio_intx_set_signal(struct vfio_pci_device *vdev, int fd)
return PTR_ERR(trigger);
}
+ vdev->ctx[0].trigger = trigger;
+
if (!vdev->pci_2_3)
irqflags = 0;
ret = request_irq(pdev->irq, vfio_intx_handler,
irqflags, vdev->ctx[0].name, vdev);
if (ret) {
+ vdev->ctx[0].trigger = NULL;
kfree(vdev->ctx[0].name);
eventfd_ctx_put(trigger);
return ret;
}
- vdev->ctx[0].trigger = trigger;
-
/*
* INTx disable will stick across the new irq setup,
* disable_irq won't.
*/
spin_lock_irqsave(&vdev->irqlock, flags);
- if (!vdev->pci_2_3 && (vdev->ctx[0].masked || vdev->virq_disabled))
+ if (!vdev->pci_2_3 && vdev->ctx[0].masked)
disable_irq_nosync(pdev->irq);
spin_unlock_irqrestore(&vdev->irqlock, flags);
diff --git a/drivers/vhost/tcm_vhost.c b/drivers/vhost/tcm_vhost.c
index ed8e2e6..aa31692 100644
--- a/drivers/vhost/tcm_vhost.c
+++ b/drivers/vhost/tcm_vhost.c
@@ -330,17 +330,6 @@ static int tcm_vhost_queue_tm_rsp(struct se_cmd *se_cmd)
return 0;
}
-static u16 tcm_vhost_set_fabric_sense_len(struct se_cmd *se_cmd,
- u32 sense_length)
-{
- return 0;
-}
-
-static u16 tcm_vhost_get_fabric_sense_len(void)
-{
- return 0;
-}
-
static void vhost_scsi_free_cmd(struct tcm_vhost_cmd *tv_cmd)
{
struct se_cmd *se_cmd = &tv_cmd->tvc_se_cmd;
@@ -426,10 +415,7 @@ static struct tcm_vhost_cmd *vhost_scsi_allocate_cmd(
{
struct tcm_vhost_cmd *tv_cmd;
struct tcm_vhost_nexus *tv_nexus;
- struct se_portal_group *se_tpg = &tv_tpg->se_tpg;
struct se_session *se_sess;
- struct se_cmd *se_cmd;
- int sam_task_attr;
tv_nexus = tv_tpg->tpg_nexus;
if (!tv_nexus) {
@@ -445,23 +431,11 @@ static struct tcm_vhost_cmd *vhost_scsi_allocate_cmd(
}
INIT_LIST_HEAD(&tv_cmd->tvc_completion_list);
tv_cmd->tvc_tag = v_req->tag;
+ tv_cmd->tvc_task_attr = v_req->task_attr;
+ tv_cmd->tvc_exp_data_len = exp_data_len;
+ tv_cmd->tvc_data_direction = data_direction;
+ tv_cmd->tvc_nexus = tv_nexus;
- se_cmd = &tv_cmd->tvc_se_cmd;
- /*
- * Locate the SAM Task Attr from virtio_scsi_cmd_req
- */
- sam_task_attr = v_req->task_attr;
- /*
- * Initialize struct se_cmd descriptor from TCM infrastructure
- */
- transport_init_se_cmd(se_cmd, se_tpg->se_tpg_tfo, se_sess, exp_data_len,
- data_direction, sam_task_attr,
- &tv_cmd->tvc_sense_buf[0]);
-
-#if 0 /* FIXME: vhost_scsi_allocate_cmd() BIDI operation */
- if (bidi)
- se_cmd->se_cmd_flags |= SCF_BIDI;
-#endif
return tv_cmd;
}
@@ -560,37 +534,10 @@ static void tcm_vhost_submission_work(struct work_struct *work)
{
struct tcm_vhost_cmd *tv_cmd =
container_of(work, struct tcm_vhost_cmd, work);
+ struct tcm_vhost_nexus *tv_nexus;
struct se_cmd *se_cmd = &tv_cmd->tvc_se_cmd;
struct scatterlist *sg_ptr, *sg_bidi_ptr = NULL;
int rc, sg_no_bidi = 0;
- /*
- * Locate the struct se_lun pointer based on v_req->lun, and
- * attach it to struct se_cmd
- */
- rc = transport_lookup_cmd_lun(&tv_cmd->tvc_se_cmd, tv_cmd->tvc_lun);
- if (rc < 0) {
- pr_err("Failed to look up lun: %d\n", tv_cmd->tvc_lun);
- transport_send_check_condition_and_sense(&tv_cmd->tvc_se_cmd,
- tv_cmd->tvc_se_cmd.scsi_sense_reason, 0);
- transport_generic_free_cmd(se_cmd, 0);
- return;
- }
-
- rc = target_setup_cmd_from_cdb(se_cmd, tv_cmd->tvc_cdb);
- if (rc == -ENOMEM) {
- transport_send_check_condition_and_sense(se_cmd,
- TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE, 0);
- transport_generic_free_cmd(se_cmd, 0);
- return;
- } else if (rc < 0) {
- if (se_cmd->se_cmd_flags & SCF_SCSI_RESERVATION_CONFLICT)
- tcm_vhost_queue_status(se_cmd);
- else
- transport_send_check_condition_and_sense(se_cmd,
- se_cmd->scsi_sense_reason, 0);
- transport_generic_free_cmd(se_cmd, 0);
- return;
- }
if (tv_cmd->tvc_sgl_count) {
sg_ptr = tv_cmd->tvc_sgl;
@@ -608,17 +555,19 @@ static void tcm_vhost_submission_work(struct work_struct *work)
} else {
sg_ptr = NULL;
}
-
- rc = transport_generic_map_mem_to_cmd(se_cmd, sg_ptr,
- tv_cmd->tvc_sgl_count, sg_bidi_ptr,
- sg_no_bidi);
+ tv_nexus = tv_cmd->tvc_nexus;
+
+ rc = target_submit_cmd_map_sgls(se_cmd, tv_nexus->tvn_se_sess,
+ tv_cmd->tvc_cdb, &tv_cmd->tvc_sense_buf[0],
+ tv_cmd->tvc_lun, tv_cmd->tvc_exp_data_len,
+ tv_cmd->tvc_task_attr, tv_cmd->tvc_data_direction,
+ 0, sg_ptr, tv_cmd->tvc_sgl_count,
+ sg_bidi_ptr, sg_no_bidi);
if (rc < 0) {
transport_send_check_condition_and_sense(se_cmd,
- se_cmd->scsi_sense_reason, 0);
+ TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE, 0);
transport_generic_free_cmd(se_cmd, 0);
- return;
}
- transport_handle_cdb_direct(se_cmd);
}
static void vhost_scsi_handle_vq(struct vhost_scsi *vs)
@@ -1531,8 +1480,6 @@ static struct target_core_fabric_ops tcm_vhost_ops = {
.queue_data_in = tcm_vhost_queue_data_in,
.queue_status = tcm_vhost_queue_status,
.queue_tm_rsp = tcm_vhost_queue_tm_rsp,
- .get_fabric_sense_len = tcm_vhost_get_fabric_sense_len,
- .set_fabric_sense_len = tcm_vhost_set_fabric_sense_len,
/*
* Setup callers for generic logic in target_core_fabric_configfs.c
*/
diff --git a/drivers/vhost/tcm_vhost.h b/drivers/vhost/tcm_vhost.h
index d9e9355..7e87c63 100644
--- a/drivers/vhost/tcm_vhost.h
+++ b/drivers/vhost/tcm_vhost.h
@@ -5,6 +5,12 @@
struct tcm_vhost_cmd {
/* Descriptor from vhost_get_vq_desc() for virt_queue segment */
int tvc_vq_desc;
+ /* virtio-scsi initiator task attribute */
+ int tvc_task_attr;
+ /* virtio-scsi initiator data direction */
+ enum dma_data_direction tvc_data_direction;
+ /* Expected data transfer length from virtio-scsi header */
+ u32 tvc_exp_data_len;
/* The Tag from include/linux/virtio_scsi.h:struct virtio_scsi_cmd_req */
u64 tvc_tag;
/* The number of scatterlists associated with this cmd */
@@ -17,6 +23,8 @@ struct tcm_vhost_cmd {
struct virtio_scsi_cmd_resp __user *tvc_resp;
/* Pointer to vhost_scsi for our device */
struct vhost_scsi *tvc_vhost;
+ /* Pointer to vhost nexus memory */
+ struct tcm_vhost_nexus *tvc_nexus;
/* The TCM I/O descriptor that is accessed via container_of() */
struct se_cmd tvc_se_cmd;
/* work item used for cmwq dispatch to tcm_vhost_submission_work() */
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 20c33c4..d08d799 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -2139,21 +2139,6 @@ config FB_UDL
mplayer -vo fbdev. Supports all USB 2.0 era DisplayLink devices.
To compile as a module, choose M here: the module name is udlfb.
-config FB_PNX4008_DUM
- tristate "Display Update Module support on Philips PNX4008 board"
- depends on FB && ARCH_PNX4008
- ---help---
- Say Y here to enable support for PNX4008 Display Update Module (DUM)
-
-config FB_PNX4008_DUM_RGB
- tristate "RGB Framebuffer support on Philips PNX4008 board"
- depends on FB_PNX4008_DUM
- select FB_CFB_FILLRECT
- select FB_CFB_COPYAREA
- select FB_CFB_IMAGEBLIT
- ---help---
- Say Y here to enable support for PNX4008 RGB Framebuffer
-
config FB_IBM_GXT4500
tristate "Framebuffer support for IBM GXT4500P adaptor"
depends on FB && PPC
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 1940359..23e948e 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -127,8 +127,6 @@ obj-$(CONFIG_FB_S3C) += s3c-fb.o
obj-$(CONFIG_FB_S3C2410) += s3c2410fb.o
obj-$(CONFIG_FB_FSL_DIU) += fsl-diu-fb.o
obj-$(CONFIG_FB_COBALT) += cobalt_lcdfb.o
-obj-$(CONFIG_FB_PNX4008_DUM) += pnx4008/
-obj-$(CONFIG_FB_PNX4008_DUM_RGB) += pnx4008/
obj-$(CONFIG_FB_IBM_GXT4500) += gxt4500.o
obj-$(CONFIG_FB_PS3) += ps3fb.o
obj-$(CONFIG_FB_SM501) += sm501fb.o
diff --git a/drivers/video/amifb.c b/drivers/video/amifb.c
index 887df9d..7fa1bf8 100644
--- a/drivers/video/amifb.c
+++ b/drivers/video/amifb.c
@@ -949,7 +949,6 @@ static int round_down_bpp = 1; /* for mode probing */
static int amifb_ilbm = 0; /* interleaved or normal bitplanes */
-static int amifb_inverse = 0;
static u32 amifb_hfmin __initdata; /* monitor hfreq lower limit (Hz) */
static u32 amifb_hfmax __initdata; /* monitor hfreq upper limit (Hz) */
@@ -2355,7 +2354,6 @@ static int __init amifb_setup(char *options)
if (!*this_opt)
continue;
if (!strcmp(this_opt, "inverse")) {
- amifb_inverse = 1;
fb_invert_cmaps();
} else if (!strcmp(this_opt, "ilbm"))
amifb_ilbm = 1;
diff --git a/drivers/video/arcfb.c b/drivers/video/arcfb.c
index a1d58e9..4659d5d 100644
--- a/drivers/video/arcfb.c
+++ b/drivers/video/arcfb.c
@@ -552,6 +552,7 @@ static int __devinit arcfb_probe(struct platform_device *dev)
"arcfb", info)) {
printk(KERN_INFO
"arcfb: Failed req IRQ %d\n", par->irq);
+ retval = -EBUSY;
goto err1;
}
}
diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
index 1505539..94cac9f 100644
--- a/drivers/video/atmel_lcdfb.c
+++ b/drivers/video/atmel_lcdfb.c
@@ -931,8 +931,10 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
}
info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len);
- if (!info->screen_base)
+ if (!info->screen_base) {
+ ret = -ENOMEM;
goto release_intmem;
+ }
/*
* Don't clear the framebuffer -- someone may have set
@@ -960,6 +962,7 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
sinfo->mmio = ioremap(info->fix.mmio_start, info->fix.mmio_len);
if (!sinfo->mmio) {
dev_err(dev, "cannot map LCDC registers\n");
+ ret = -ENOMEM;
goto release_mem;
}
diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c
index 995f016..069983c 100644
--- a/drivers/video/backlight/pwm_bl.c
+++ b/drivers/video/backlight/pwm_bl.c
@@ -213,7 +213,7 @@ static int pwm_backlight_probe(struct platform_device *pdev)
pb->exit = data->exit;
pb->dev = &pdev->dev;
- pb->pwm = pwm_get(&pdev->dev, NULL);
+ pb->pwm = devm_pwm_get(&pdev->dev, NULL);
if (IS_ERR(pb->pwm)) {
dev_err(&pdev->dev, "unable to request PWM, trying legacy API\n");
@@ -246,7 +246,7 @@ static int pwm_backlight_probe(struct platform_device *pdev)
if (IS_ERR(bl)) {
dev_err(&pdev->dev, "failed to register backlight\n");
ret = PTR_ERR(bl);
- goto err_bl;
+ goto err_alloc;
}
bl->props.brightness = data->dft_brightness;
@@ -255,8 +255,6 @@ static int pwm_backlight_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, bl);
return 0;
-err_bl:
- pwm_put(pb->pwm);
err_alloc:
if (data->exit)
data->exit(&pdev->dev);
@@ -271,7 +269,6 @@ static int pwm_backlight_remove(struct platform_device *pdev)
backlight_device_unregister(bl);
pwm_config(pb->pwm, 0, pb->period);
pwm_disable(pb->pwm);
- pwm_put(pb->pwm);
if (pb->exit)
pb->exit(&pdev->dev);
return 0;
diff --git a/drivers/video/bf537-lq035.c b/drivers/video/bf537-lq035.c
index befbc80..7347aa1 100644
--- a/drivers/video/bf537-lq035.c
+++ b/drivers/video/bf537-lq035.c
@@ -760,18 +760,20 @@ static int __devinit bfin_lq035_probe(struct platform_device *pdev)
bfin_lq035_fb.flags = FBINFO_DEFAULT;
- bfin_lq035_fb.pseudo_palette = kzalloc(sizeof(u32) * 16, GFP_KERNEL);
+ bfin_lq035_fb.pseudo_palette = devm_kzalloc(&pdev->dev,
+ sizeof(u32) * 16,
+ GFP_KERNEL);
if (bfin_lq035_fb.pseudo_palette == NULL) {
pr_err("failed to allocate pseudo_palette\n");
ret = -ENOMEM;
- goto out_palette;
+ goto out_table;
}
if (fb_alloc_cmap(&bfin_lq035_fb.cmap, NBR_PALETTE, 0) < 0) {
pr_err("failed to allocate colormap (%d entries)\n",
NBR_PALETTE);
ret = -EFAULT;
- goto out_cmap;
+ goto out_table;
}
if (register_framebuffer(&bfin_lq035_fb) < 0) {
@@ -804,9 +806,6 @@ out_lcd:
unregister_framebuffer(&bfin_lq035_fb);
out_reg:
fb_dealloc_cmap(&bfin_lq035_fb.cmap);
-out_cmap:
- kfree(bfin_lq035_fb.pseudo_palette);
-out_palette:
out_table:
dma_free_coherent(NULL, TOTAL_VIDEO_MEM_SIZE, fb_buffer, 0);
fb_buffer = NULL;
@@ -834,7 +833,6 @@ static int __devexit bfin_lq035_remove(struct platform_device *pdev)
free_dma(CH_PPI);
- kfree(bfin_lq035_fb.pseudo_palette);
fb_dealloc_cmap(&bfin_lq035_fb.cmap);
diff --git a/drivers/video/bf54x-lq043fb.c b/drivers/video/bf54x-lq043fb.c
index dc2f004..ff5663f 100644
--- a/drivers/video/bf54x-lq043fb.c
+++ b/drivers/video/bf54x-lq043fb.c
@@ -525,6 +525,7 @@ static int __devinit bfin_bf54x_probe(struct platform_device *pdev)
info = fbinfo->par;
info->fb = fbinfo;
info->dev = &pdev->dev;
+ spin_lock_init(&info->lock);
platform_set_drvdata(pdev, fbinfo);
@@ -601,7 +602,8 @@ static int __devinit bfin_bf54x_probe(struct platform_device *pdev)
fbinfo->fbops = &bfin_bf54x_fb_ops;
- fbinfo->pseudo_palette = kzalloc(sizeof(u32) * 16, GFP_KERNEL);
+ fbinfo->pseudo_palette = devm_kzalloc(&pdev->dev, sizeof(u32) * 16,
+ GFP_KERNEL);
if (!fbinfo->pseudo_palette) {
printk(KERN_ERR DRIVER_NAME
"Fail to allocate pseudo_palette\n");
@@ -616,7 +618,7 @@ static int __devinit bfin_bf54x_probe(struct platform_device *pdev)
"Fail to allocate colormap (%d entries)\n",
BFIN_LCD_NBR_PALETTE_ENTRIES);
ret = -EFAULT;
- goto out5;
+ goto out4;
}
if (request_ports(info)) {
@@ -671,8 +673,6 @@ out7:
free_ports(info);
out6:
fb_dealloc_cmap(&fbinfo->cmap);
-out5:
- kfree(fbinfo->pseudo_palette);
out4:
dma_free_coherent(NULL, fbinfo->fix.smem_len, info->fb_buffer,
info->dma_handle);
@@ -699,7 +699,6 @@ static int __devexit bfin_bf54x_remove(struct platform_device *pdev)
dma_free_coherent(NULL, fbinfo->fix.smem_len, info->fb_buffer,
info->dma_handle);
- kfree(fbinfo->pseudo_palette);
fb_dealloc_cmap(&fbinfo->cmap);
#ifndef NO_BL_SUPPORT
diff --git a/drivers/video/bfin-lq035q1-fb.c b/drivers/video/bfin-lq035q1-fb.c
index 353c02f..6fbc75c 100644
--- a/drivers/video/bfin-lq035q1-fb.c
+++ b/drivers/video/bfin-lq035q1-fb.c
@@ -577,6 +577,7 @@ static int __devinit bfin_lq035q1_probe(struct platform_device *pdev)
info = fbinfo->par;
info->fb = fbinfo;
info->dev = &pdev->dev;
+ spin_lock_init(&info->lock);
info->disp_info = pdev->dev.platform_data;
@@ -853,17 +854,7 @@ static struct platform_driver bfin_lq035q1_driver = {
},
};
-static int __init bfin_lq035q1_driver_init(void)
-{
- return platform_driver_register(&bfin_lq035q1_driver);
-}
-module_init(bfin_lq035q1_driver_init);
-
-static void __exit bfin_lq035q1_driver_cleanup(void)
-{
- platform_driver_unregister(&bfin_lq035q1_driver);
-}
-module_exit(bfin_lq035q1_driver_cleanup);
+module_platform_driver(bfin_lq035q1_driver);
MODULE_DESCRIPTION("Blackfin TFT LCD Driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/video/bfin-t350mcqb-fb.c b/drivers/video/bfin-t350mcqb-fb.c
index 7a0c05f..ae0fb24 100644
--- a/drivers/video/bfin-t350mcqb-fb.c
+++ b/drivers/video/bfin-t350mcqb-fb.c
@@ -447,6 +447,7 @@ static int __devinit bfin_t350mcqb_probe(struct platform_device *pdev)
info = fbinfo->par;
info->fb = fbinfo;
info->dev = &pdev->dev;
+ spin_lock_init(&info->lock);
platform_set_drvdata(pdev, fbinfo);
diff --git a/drivers/video/bw2.c b/drivers/video/bw2.c
index 7ba74cd..6bea9a9 100644
--- a/drivers/video/bw2.c
+++ b/drivers/video/bw2.c
@@ -319,8 +319,10 @@ static int __devinit bw2_probe(struct platform_device *op)
info->screen_base = of_ioremap(&op->resource[0], 0,
info->fix.smem_len, "bw2 ram");
- if (!info->screen_base)
+ if (!info->screen_base) {
+ err = -ENOMEM;
goto out_unmap_regs;
+ }
bw2_blank(FB_BLANK_UNBLANK, info);
diff --git a/drivers/video/cg3.c b/drivers/video/cg3.c
index f927a7b..c5e7612 100644
--- a/drivers/video/cg3.c
+++ b/drivers/video/cg3.c
@@ -398,7 +398,8 @@ static int __devinit cg3_probe(struct platform_device *op)
goto out_unmap_screen;
}
- if (fb_alloc_cmap(&info->cmap, 256, 0))
+ err = fb_alloc_cmap(&info->cmap, 256, 0);
+ if (err)
goto out_unmap_screen;
fb_set_cmap(&info->cmap, info);
diff --git a/drivers/video/cobalt_lcdfb.c b/drivers/video/cobalt_lcdfb.c
index eae46f6..01a4ee7 100644
--- a/drivers/video/cobalt_lcdfb.c
+++ b/drivers/video/cobalt_lcdfb.c
@@ -348,7 +348,8 @@ static int __devinit cobalt_lcdfb_probe(struct platform_device *dev)
}
info->screen_size = resource_size(res);
- info->screen_base = ioremap(res->start, info->screen_size);
+ info->screen_base = devm_ioremap(&dev->dev, res->start,
+ info->screen_size);
info->fbops = &cobalt_lcd_fbops;
info->fix = cobalt_lcdfb_fix;
info->fix.smem_start = res->start;
@@ -359,7 +360,6 @@ static int __devinit cobalt_lcdfb_probe(struct platform_device *dev)
retval = register_framebuffer(info);
if (retval < 0) {
- iounmap(info->screen_base);
framebuffer_release(info);
return retval;
}
@@ -380,7 +380,6 @@ static int __devexit cobalt_lcdfb_remove(struct platform_device *dev)
info = platform_get_drvdata(dev);
if (info) {
- iounmap(info->screen_base);
unregister_framebuffer(info);
framebuffer_release(info);
}
diff --git a/drivers/video/console/font_mini_4x6.c b/drivers/video/console/font_mini_4x6.c
index fa6e698..838caa1 100644
--- a/drivers/video/console/font_mini_4x6.c
+++ b/drivers/video/console/font_mini_4x6.c
@@ -1092,7 +1092,7 @@ static const unsigned char fontdata_mini_4x6[FONTDATAMAX] = {
/*{*/ /* Char 124: '|' */
0x44, /*= [ * ] */
0x44, /*= [ * ] */
- 0x00, /*= [ ] */
+ 0x44, /*= [ * ] */
0x44, /*= [ * ] */
0x44, /*= [ * ] */
0x00, /*= [ ] */
diff --git a/drivers/video/console/font_sun8x16.c b/drivers/video/console/font_sun8x16.c
index 5abf290..2681513 100644
--- a/drivers/video/console/font_sun8x16.c
+++ b/drivers/video/console/font_sun8x16.c
@@ -127,7 +127,7 @@ static const unsigned char fontdata_sun8x16[FONTDATAMAX] = {
/*y*/ 0x00,0x00,0x00,0x00,0x00,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0x7e,0x06,0x0c,0xf8,0x00,
/*z*/ 0x00,0x00,0x00,0x00,0x00,0xfe,0xcc,0x18,0x30,0x60,0xc6,0xfe,0x00,0x00,0x00,0x00,
/*{*/ 0x00,0x00,0x0e,0x18,0x18,0x18,0x70,0x18,0x18,0x18,0x18,0x0e,0x00,0x00,0x00,0x00,
-/*|*/ 0x00,0x00,0x18,0x18,0x18,0x18,0x00,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00,
+/*|*/ 0x00,0x00,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00,
/*}*/ 0x00,0x00,0x70,0x18,0x18,0x18,0x0e,0x18,0x18,0x18,0x18,0x70,0x00,0x00,0x00,0x00,
/*~*/ 0x00,0x00,0x76,0xdc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
/* */ 0x00,0x00,0x00,0x00,0x10,0x38,0x6c,0xc6,0xc6,0xc6,0xfe,0x00,0x00,0x00,0x00,0x00,
diff --git a/drivers/video/cyber2000fb.c b/drivers/video/cyber2000fb.c
index c1527f5..e40125c 100644
--- a/drivers/video/cyber2000fb.c
+++ b/drivers/video/cyber2000fb.c
@@ -1804,8 +1804,10 @@ cyberpro_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
cfb->irq = dev->irq;
cfb->region = pci_ioremap_bar(dev, 0);
- if (!cfb->region)
+ if (!cfb->region) {
+ err = -ENOMEM;
goto failed_ioremap;
+ }
cfb->regs = cfb->region + MMIO_OFFSET;
cfb->fb.device = &dev->dev;
diff --git a/drivers/video/da8xx-fb.c b/drivers/video/da8xx-fb.c
index 113d43a..80665f6 100644
--- a/drivers/video/da8xx-fb.c
+++ b/drivers/video/da8xx-fb.c
@@ -26,7 +26,9 @@
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/uaccess.h>
+#include <linux/pm_runtime.h>
#include <linux/interrupt.h>
+#include <linux/wait.h>
#include <linux/clk.h>
#include <linux/cpufreq.h>
#include <linux/console.h>
@@ -48,6 +50,7 @@
#define LCD_PL_LOAD_DONE BIT(6)
#define LCD_FIFO_UNDERFLOW BIT(5)
#define LCD_SYNC_LOST BIT(2)
+#define LCD_FRAME_DONE BIT(0)
/* LCD DMA Control Register */
#define LCD_DMA_BURST_SIZE(x) ((x) << 4)
@@ -86,6 +89,8 @@
#define LCD_V2_LIDD_CLK_EN BIT(1)
#define LCD_V2_CORE_CLK_EN BIT(0)
#define LCD_V2_LPP_B10 26
+#define LCD_V2_TFT_24BPP_MODE BIT(25)
+#define LCD_V2_TFT_24BPP_UNPACK BIT(26)
/* LCD Raster Timing 2 Register */
#define LCD_AC_BIAS_TRANSITIONS_PER_INT(x) ((x) << 16)
@@ -135,6 +140,8 @@ static void __iomem *da8xx_fb_reg_base;
static struct resource *lcdc_regs;
static unsigned int lcd_revision;
static irq_handler_t lcdc_irq_handler;
+static wait_queue_head_t frame_done_wq;
+static int frame_done_flag;
static inline unsigned int lcdc_read(unsigned int addr)
{
@@ -156,7 +163,6 @@ struct da8xx_fb_par {
unsigned int dma_end;
struct clk *lcdc_clk;
int irq;
- unsigned short pseudo_palette[16];
unsigned int palette_sz;
unsigned int pxl_clk;
int blank;
@@ -175,6 +181,7 @@ struct da8xx_fb_par {
unsigned int lcd_fck_rate;
#endif
void (*panel_power_ctrl)(int);
+ u32 pseudo_palette[16];
};
/* Variable Screen Information */
@@ -288,13 +295,26 @@ static inline void lcd_enable_raster(void)
}
/* Disable the Raster Engine of the LCD Controller */
-static inline void lcd_disable_raster(void)
+static inline void lcd_disable_raster(bool wait_for_frame_done)
{
u32 reg;
+ int ret;
reg = lcdc_read(LCD_RASTER_CTRL_REG);
if (reg & LCD_RASTER_ENABLE)
lcdc_write(reg & ~LCD_RASTER_ENABLE, LCD_RASTER_CTRL_REG);
+ else
+ /* return if already disabled */
+ return;
+
+ if ((wait_for_frame_done == true) && (lcd_revision == LCD_VERSION_2)) {
+ frame_done_flag = 0;
+ ret = wait_event_interruptible_timeout(frame_done_wq,
+ frame_done_flag != 0,
+ msecs_to_jiffies(50));
+ if (ret == 0)
+ pr_err("LCD Controller timed out\n");
+ }
}
static void lcd_blit(int load_mode, struct da8xx_fb_par *par)
@@ -321,7 +341,8 @@ static void lcd_blit(int load_mode, struct da8xx_fb_par *par)
} else {
reg_int = lcdc_read(LCD_INT_ENABLE_SET_REG) |
LCD_V2_END_OF_FRAME0_INT_ENA |
- LCD_V2_END_OF_FRAME1_INT_ENA;
+ LCD_V2_END_OF_FRAME1_INT_ENA |
+ LCD_FRAME_DONE;
lcdc_write(reg_int, LCD_INT_ENABLE_SET_REG);
}
reg_dma |= LCD_DUAL_FRAME_BUFFER_ENABLE;
@@ -499,6 +520,9 @@ static int lcd_cfg_frame_buffer(struct da8xx_fb_par *par, u32 width, u32 height,
{
u32 reg;
+ if (bpp > 16 && lcd_revision == LCD_VERSION_1)
+ return -EINVAL;
+
/* Set the Panel Width */
/* Pixels per line = (PPL + 1)*16 */
if (lcd_revision == LCD_VERSION_1) {
@@ -542,14 +566,19 @@ static int lcd_cfg_frame_buffer(struct da8xx_fb_par *par, u32 width, u32 height,
reg = lcdc_read(LCD_RASTER_CTRL_REG) & ~(1 << 8);
if (raster_order)
reg |= LCD_RASTER_ORDER;
- lcdc_write(reg, LCD_RASTER_CTRL_REG);
+
+ par->palette_sz = 16 * 2;
switch (bpp) {
case 1:
case 2:
case 4:
case 16:
- par->palette_sz = 16 * 2;
+ break;
+ case 24:
+ reg |= LCD_V2_TFT_24BPP_MODE;
+ case 32:
+ reg |= LCD_V2_TFT_24BPP_UNPACK;
break;
case 8:
@@ -560,9 +589,12 @@ static int lcd_cfg_frame_buffer(struct da8xx_fb_par *par, u32 width, u32 height,
return -EINVAL;
}
+ lcdc_write(reg, LCD_RASTER_CTRL_REG);
+
return 0;
}
+#define CNVT_TOHW(val, width) ((((val) << (width)) + 0x7FFF - (val)) >> 16)
static int fb_setcolreg(unsigned regno, unsigned red, unsigned green,
unsigned blue, unsigned transp,
struct fb_info *info)
@@ -578,13 +610,38 @@ static int fb_setcolreg(unsigned regno, unsigned red, unsigned green,
if (info->fix.visual == FB_VISUAL_DIRECTCOLOR)
return 1;
- if (info->var.bits_per_pixel == 4) {
- if (regno > 15)
- return 1;
+ if (info->var.bits_per_pixel > 16 && lcd_revision == LCD_VERSION_1)
+ return -EINVAL;
- if (info->var.grayscale) {
- pal = regno;
- } else {
+ switch (info->fix.visual) {
+ case FB_VISUAL_TRUECOLOR:
+ red = CNVT_TOHW(red, info->var.red.length);
+ green = CNVT_TOHW(green, info->var.green.length);
+ blue = CNVT_TOHW(blue, info->var.blue.length);
+ break;
+ case FB_VISUAL_PSEUDOCOLOR:
+ switch (info->var.bits_per_pixel) {
+ case 4:
+ if (regno > 15)
+ return -EINVAL;
+
+ if (info->var.grayscale) {
+ pal = regno;
+ } else {
+ red >>= 4;
+ green >>= 8;
+ blue >>= 12;
+
+ pal = red & 0x0f00;
+ pal |= green & 0x00f0;
+ pal |= blue & 0x000f;
+ }
+ if (regno == 0)
+ pal |= 0x2000;
+ palette[regno] = pal;
+ break;
+
+ case 8:
red >>= 4;
green >>= 8;
blue >>= 12;
@@ -592,36 +649,36 @@ static int fb_setcolreg(unsigned regno, unsigned red, unsigned green,
pal = (red & 0x0f00);
pal |= (green & 0x00f0);
pal |= (blue & 0x000f);
- }
- if (regno == 0)
- pal |= 0x2000;
- palette[regno] = pal;
-
- } else if (info->var.bits_per_pixel == 8) {
- red >>= 4;
- green >>= 8;
- blue >>= 12;
-
- pal = (red & 0x0f00);
- pal |= (green & 0x00f0);
- pal |= (blue & 0x000f);
- if (palette[regno] != pal) {
- update_hw = 1;
- palette[regno] = pal;
+ if (palette[regno] != pal) {
+ update_hw = 1;
+ palette[regno] = pal;
+ }
+ break;
}
- } else if ((info->var.bits_per_pixel == 16) && regno < 16) {
- red >>= (16 - info->var.red.length);
- red <<= info->var.red.offset;
+ break;
+ }
- green >>= (16 - info->var.green.length);
- green <<= info->var.green.offset;
+ /* Truecolor has hardware independent palette */
+ if (info->fix.visual == FB_VISUAL_TRUECOLOR) {
+ u32 v;
- blue >>= (16 - info->var.blue.length);
- blue <<= info->var.blue.offset;
+ if (regno > 15)
+ return -EINVAL;
- par->pseudo_palette[regno] = red | green | blue;
+ v = (red << info->var.red.offset) |
+ (green << info->var.green.offset) |
+ (blue << info->var.blue.offset);
+ switch (info->var.bits_per_pixel) {
+ case 16:
+ ((u16 *) (info->pseudo_palette))[regno] = v;
+ break;
+ case 24:
+ case 32:
+ ((u32 *) (info->pseudo_palette))[regno] = v;
+ break;
+ }
if (palette[0] != 0x4000) {
update_hw = 1;
palette[0] = 0x4000;
@@ -634,11 +691,12 @@ static int fb_setcolreg(unsigned regno, unsigned red, unsigned green,
return 0;
}
+#undef CNVT_TOHW
static void lcd_reset(struct da8xx_fb_par *par)
{
/* Disable the Raster if previously Enabled */
- lcd_disable_raster();
+ lcd_disable_raster(false);
/* DMA has to be disabled */
lcdc_write(0, LCD_DMA_CTRL_REG);
@@ -734,7 +792,7 @@ static irqreturn_t lcdc_irq_handler_rev02(int irq, void *arg)
u32 stat = lcdc_read(LCD_MASKED_STAT_REG);
if ((stat & LCD_SYNC_LOST) && (stat & LCD_FIFO_UNDERFLOW)) {
- lcd_disable_raster();
+ lcd_disable_raster(false);
lcdc_write(stat, LCD_MASKED_STAT_REG);
lcd_enable_raster();
} else if (stat & LCD_PL_LOAD_DONE) {
@@ -744,7 +802,7 @@ static irqreturn_t lcdc_irq_handler_rev02(int irq, void *arg)
* interrupt via the following write to the status register. If
* this is done after then one gets multiple PL done interrupts.
*/
- lcd_disable_raster();
+ lcd_disable_raster(false);
lcdc_write(stat, LCD_MASKED_STAT_REG);
@@ -775,6 +833,14 @@ static irqreturn_t lcdc_irq_handler_rev02(int irq, void *arg)
par->vsync_flag = 1;
wake_up_interruptible(&par->vsync_wait);
}
+
+ /* Set only when controller is disabled and at the end of
+ * active frame
+ */
+ if (stat & BIT(0)) {
+ frame_done_flag = 1;
+ wake_up_interruptible(&frame_done_wq);
+ }
}
lcdc_write(0, LCD_END_OF_INT_IND_REG);
@@ -789,7 +855,7 @@ static irqreturn_t lcdc_irq_handler_rev01(int irq, void *arg)
u32 reg_ras;
if ((stat & LCD_SYNC_LOST) && (stat & LCD_FIFO_UNDERFLOW)) {
- lcd_disable_raster();
+ lcd_disable_raster(false);
lcdc_write(stat, LCD_STAT_REG);
lcd_enable_raster();
} else if (stat & LCD_PL_LOAD_DONE) {
@@ -799,7 +865,7 @@ static irqreturn_t lcdc_irq_handler_rev01(int irq, void *arg)
* interrupt via the following write to the status register. If
* this is done after then one gets multiple PL done interrupts.
*/
- lcd_disable_raster();
+ lcd_disable_raster(false);
lcdc_write(stat, LCD_STAT_REG);
@@ -842,6 +908,9 @@ static int fb_check_var(struct fb_var_screeninfo *var,
{
int err = 0;
+ if (var->bits_per_pixel > 16 && lcd_revision == LCD_VERSION_1)
+ return -EINVAL;
+
switch (var->bits_per_pixel) {
case 1:
case 8:
@@ -877,6 +946,26 @@ static int fb_check_var(struct fb_var_screeninfo *var,
var->transp.length = 0;
var->nonstd = 0;
break;
+ case 24:
+ var->red.offset = 16;
+ var->red.length = 8;
+ var->green.offset = 8;
+ var->green.length = 8;
+ var->blue.offset = 0;
+ var->blue.length = 8;
+ var->nonstd = 0;
+ break;
+ case 32:
+ var->transp.offset = 24;
+ var->transp.length = 8;
+ var->red.offset = 16;
+ var->red.length = 8;
+ var->green.offset = 8;
+ var->green.length = 8;
+ var->blue.offset = 0;
+ var->blue.length = 8;
+ var->nonstd = 0;
+ break;
default:
err = -EINVAL;
}
@@ -898,9 +987,10 @@ static int lcd_da8xx_cpufreq_transition(struct notifier_block *nb,
if (val == CPUFREQ_POSTCHANGE) {
if (par->lcd_fck_rate != clk_get_rate(par->lcdc_clk)) {
par->lcd_fck_rate = clk_get_rate(par->lcdc_clk);
- lcd_disable_raster();
+ lcd_disable_raster(true);
lcd_calc_clk_divider(par);
- lcd_enable_raster();
+ if (par->blank == FB_BLANK_UNBLANK)
+ lcd_enable_raster();
}
}
@@ -935,7 +1025,7 @@ static int __devexit fb_remove(struct platform_device *dev)
if (par->panel_power_ctrl)
par->panel_power_ctrl(0);
- lcd_disable_raster();
+ lcd_disable_raster(true);
lcdc_write(0, LCD_RASTER_CTRL_REG);
/* disable DMA */
@@ -948,8 +1038,8 @@ static int __devexit fb_remove(struct platform_device *dev)
dma_free_coherent(NULL, par->vram_size, par->vram_virt,
par->vram_phys);
free_irq(par->irq, par);
- clk_disable(par->lcdc_clk);
- clk_put(par->lcdc_clk);
+ pm_runtime_put_sync(&dev->dev);
+ pm_runtime_disable(&dev->dev);
framebuffer_release(info);
iounmap(da8xx_fb_reg_base);
release_mem_region(lcdc_regs->start, resource_size(lcdc_regs));
@@ -1051,7 +1141,7 @@ static int cfb_blank(int blank, struct fb_info *info)
if (par->panel_power_ctrl)
par->panel_power_ctrl(0);
- lcd_disable_raster();
+ lcd_disable_raster(true);
break;
default:
ret = -EINVAL;
@@ -1183,9 +1273,9 @@ static int __devinit fb_probe(struct platform_device *device)
ret = -ENODEV;
goto err_ioremap;
}
- ret = clk_enable(fb_clk);
- if (ret)
- goto err_clk_put;
+
+ pm_runtime_enable(&device->dev);
+ pm_runtime_get_sync(&device->dev);
/* Determine LCD IP Version */
switch (lcdc_read(LCD_PID_REG)) {
@@ -1213,7 +1303,7 @@ static int __devinit fb_probe(struct platform_device *device)
if (i == ARRAY_SIZE(known_lcd_panels)) {
dev_err(&device->dev, "GLCD: No valid panel found\n");
ret = -ENODEV;
- goto err_clk_disable;
+ goto err_pm_runtime_disable;
} else
dev_info(&device->dev, "GLCD: Found %s panel\n",
fb_pdata->type);
@@ -1225,7 +1315,7 @@ static int __devinit fb_probe(struct platform_device *device)
if (!da8xx_fb_info) {
dev_dbg(&device->dev, "Memory allocation failed for fb_info\n");
ret = -ENOMEM;
- goto err_clk_disable;
+ goto err_pm_runtime_disable;
}
par = da8xx_fb_info->par;
@@ -1356,8 +1446,10 @@ static int __devinit fb_probe(struct platform_device *device)
if (lcd_revision == LCD_VERSION_1)
lcdc_irq_handler = lcdc_irq_handler_rev01;
- else
+ else {
+ init_waitqueue_head(&frame_done_wq);
lcdc_irq_handler = lcdc_irq_handler_rev02;
+ }
ret = request_irq(par->irq, lcdc_irq_handler, 0,
DRIVER_NAME, par);
@@ -1385,11 +1477,9 @@ err_release_fb_mem:
err_release_fb:
framebuffer_release(da8xx_fb_info);
-err_clk_disable:
- clk_disable(fb_clk);
-
-err_clk_put:
- clk_put(fb_clk);
+err_pm_runtime_disable:
+ pm_runtime_put_sync(&device->dev);
+ pm_runtime_disable(&device->dev);
err_ioremap:
iounmap(da8xx_fb_reg_base);
@@ -1401,6 +1491,69 @@ err_request_mem:
}
#ifdef CONFIG_PM
+struct lcdc_context {
+ u32 clk_enable;
+ u32 ctrl;
+ u32 dma_ctrl;
+ u32 raster_timing_0;
+ u32 raster_timing_1;
+ u32 raster_timing_2;
+ u32 int_enable_set;
+ u32 dma_frm_buf_base_addr_0;
+ u32 dma_frm_buf_ceiling_addr_0;
+ u32 dma_frm_buf_base_addr_1;
+ u32 dma_frm_buf_ceiling_addr_1;
+ u32 raster_ctrl;
+} reg_context;
+
+static void lcd_context_save(void)
+{
+ if (lcd_revision == LCD_VERSION_2) {
+ reg_context.clk_enable = lcdc_read(LCD_CLK_ENABLE_REG);
+ reg_context.int_enable_set = lcdc_read(LCD_INT_ENABLE_SET_REG);
+ }
+
+ reg_context.ctrl = lcdc_read(LCD_CTRL_REG);
+ reg_context.dma_ctrl = lcdc_read(LCD_DMA_CTRL_REG);
+ reg_context.raster_timing_0 = lcdc_read(LCD_RASTER_TIMING_0_REG);
+ reg_context.raster_timing_1 = lcdc_read(LCD_RASTER_TIMING_1_REG);
+ reg_context.raster_timing_2 = lcdc_read(LCD_RASTER_TIMING_2_REG);
+ reg_context.dma_frm_buf_base_addr_0 =
+ lcdc_read(LCD_DMA_FRM_BUF_BASE_ADDR_0_REG);
+ reg_context.dma_frm_buf_ceiling_addr_0 =
+ lcdc_read(LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG);
+ reg_context.dma_frm_buf_base_addr_1 =
+ lcdc_read(LCD_DMA_FRM_BUF_BASE_ADDR_1_REG);
+ reg_context.dma_frm_buf_ceiling_addr_1 =
+ lcdc_read(LCD_DMA_FRM_BUF_CEILING_ADDR_1_REG);
+ reg_context.raster_ctrl = lcdc_read(LCD_RASTER_CTRL_REG);
+ return;
+}
+
+static void lcd_context_restore(void)
+{
+ if (lcd_revision == LCD_VERSION_2) {
+ lcdc_write(reg_context.clk_enable, LCD_CLK_ENABLE_REG);
+ lcdc_write(reg_context.int_enable_set, LCD_INT_ENABLE_SET_REG);
+ }
+
+ lcdc_write(reg_context.ctrl, LCD_CTRL_REG);
+ lcdc_write(reg_context.dma_ctrl, LCD_DMA_CTRL_REG);
+ lcdc_write(reg_context.raster_timing_0, LCD_RASTER_TIMING_0_REG);
+ lcdc_write(reg_context.raster_timing_1, LCD_RASTER_TIMING_1_REG);
+ lcdc_write(reg_context.raster_timing_2, LCD_RASTER_TIMING_2_REG);
+ lcdc_write(reg_context.dma_frm_buf_base_addr_0,
+ LCD_DMA_FRM_BUF_BASE_ADDR_0_REG);
+ lcdc_write(reg_context.dma_frm_buf_ceiling_addr_0,
+ LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG);
+ lcdc_write(reg_context.dma_frm_buf_base_addr_1,
+ LCD_DMA_FRM_BUF_BASE_ADDR_1_REG);
+ lcdc_write(reg_context.dma_frm_buf_ceiling_addr_1,
+ LCD_DMA_FRM_BUF_CEILING_ADDR_1_REG);
+ lcdc_write(reg_context.raster_ctrl, LCD_RASTER_CTRL_REG);
+ return;
+}
+
static int fb_suspend(struct platform_device *dev, pm_message_t state)
{
struct fb_info *info = platform_get_drvdata(dev);
@@ -1411,8 +1564,9 @@ static int fb_suspend(struct platform_device *dev, pm_message_t state)
par->panel_power_ctrl(0);
fb_set_suspend(info, 1);
- lcd_disable_raster();
- clk_disable(par->lcdc_clk);
+ lcd_disable_raster(true);
+ lcd_context_save();
+ pm_runtime_put_sync(&dev->dev);
console_unlock();
return 0;
@@ -1423,11 +1577,14 @@ static int fb_resume(struct platform_device *dev)
struct da8xx_fb_par *par = info->par;
console_lock();
- clk_enable(par->lcdc_clk);
- lcd_enable_raster();
+ pm_runtime_get_sync(&dev->dev);
+ lcd_context_restore();
+ if (par->blank == FB_BLANK_UNBLANK) {
+ lcd_enable_raster();
- if (par->panel_power_ctrl)
- par->panel_power_ctrl(1);
+ if (par->panel_power_ctrl)
+ par->panel_power_ctrl(1);
+ }
fb_set_suspend(info, 0);
console_unlock();
diff --git a/drivers/video/ep93xx-fb.c b/drivers/video/ep93xx-fb.c
index f2c092d..755ef3e 100644
--- a/drivers/video/ep93xx-fb.c
+++ b/drivers/video/ep93xx-fb.c
@@ -529,7 +529,8 @@ static int __devinit ep93xxfb_probe(struct platform_device *pdev)
* any of the framebuffer registers.
*/
fbi->res = res;
- fbi->mmio_base = ioremap(res->start, resource_size(res));
+ fbi->mmio_base = devm_ioremap(&pdev->dev, res->start,
+ resource_size(res));
if (!fbi->mmio_base) {
err = -ENXIO;
goto failed_resource;
@@ -553,20 +554,20 @@ static int __devinit ep93xxfb_probe(struct platform_device *pdev)
if (err == 0) {
dev_err(info->dev, "No suitable video mode found\n");
err = -EINVAL;
- goto failed_mode;
+ goto failed_resource;
}
if (mach_info->setup) {
err = mach_info->setup(pdev);
if (err)
- goto failed_mode;
+ goto failed_resource;
}
err = ep93xxfb_check_var(&info->var, info);
if (err)
goto failed_check;
- fbi->clk = clk_get(info->dev, NULL);
+ fbi->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(fbi->clk)) {
err = PTR_ERR(fbi->clk);
fbi->clk = NULL;
@@ -578,19 +579,15 @@ static int __devinit ep93xxfb_probe(struct platform_device *pdev)
err = register_framebuffer(info);
if (err)
- goto failed;
+ goto failed_check;
dev_info(info->dev, "registered. Mode = %dx%d-%d\n",
info->var.xres, info->var.yres, info->var.bits_per_pixel);
return 0;
-failed:
- clk_put(fbi->clk);
failed_check:
if (fbi->mach_info->teardown)
fbi->mach_info->teardown(pdev);
-failed_mode:
- iounmap(fbi->mmio_base);
failed_resource:
ep93xxfb_dealloc_videomem(info);
failed_videomem:
@@ -609,8 +606,6 @@ static int __devexit ep93xxfb_remove(struct platform_device *pdev)
unregister_framebuffer(info);
clk_disable(fbi->clk);
- clk_put(fbi->clk);
- iounmap(fbi->mmio_base);
ep93xxfb_dealloc_videomem(info);
fb_dealloc_cmap(&info->cmap);
diff --git a/drivers/video/exynos/exynos_dp_core.c b/drivers/video/exynos/exynos_dp_core.c
index c6c016a..d55470e 100644
--- a/drivers/video/exynos/exynos_dp_core.c
+++ b/drivers/video/exynos/exynos_dp_core.c
@@ -29,6 +29,9 @@ static int exynos_dp_init_dp(struct exynos_dp_device *dp)
exynos_dp_swreset(dp);
+ exynos_dp_init_analog_param(dp);
+ exynos_dp_init_interrupt(dp);
+
/* SW defined function Normal operation */
exynos_dp_enable_sw_function(dp);
@@ -260,7 +263,7 @@ static void exynos_dp_set_lane_lane_pre_emphasis(struct exynos_dp_device *dp,
static void exynos_dp_link_start(struct exynos_dp_device *dp)
{
- u8 buf[5];
+ u8 buf[4];
int lane;
int lane_count;
@@ -295,10 +298,10 @@ static void exynos_dp_link_start(struct exynos_dp_device *dp)
exynos_dp_set_training_pattern(dp, TRAINING_PTN1);
/* Set RX training pattern */
- buf[0] = DPCD_SCRAMBLING_DISABLED |
- DPCD_TRAINING_PATTERN_1;
exynos_dp_write_byte_to_dpcd(dp,
- DPCD_ADDR_TRAINING_PATTERN_SET, buf[0]);
+ DPCD_ADDR_TRAINING_PATTERN_SET,
+ DPCD_SCRAMBLING_DISABLED |
+ DPCD_TRAINING_PATTERN_1);
for (lane = 0; lane < lane_count; lane++)
buf[lane] = DPCD_PRE_EMPHASIS_PATTERN2_LEVEL0 |
@@ -308,7 +311,7 @@ static void exynos_dp_link_start(struct exynos_dp_device *dp)
lane_count, buf);
}
-static unsigned char exynos_dp_get_lane_status(u8 link_status[6], int lane)
+static unsigned char exynos_dp_get_lane_status(u8 link_status[2], int lane)
{
int shift = (lane & 1) * 4;
u8 link_value = link_status[lane>>1];
@@ -316,7 +319,7 @@ static unsigned char exynos_dp_get_lane_status(u8 link_status[6], int lane)
return (link_value >> shift) & 0xf;
}
-static int exynos_dp_clock_recovery_ok(u8 link_status[6], int lane_count)
+static int exynos_dp_clock_recovery_ok(u8 link_status[2], int lane_count)
{
int lane;
u8 lane_status;
@@ -329,22 +332,23 @@ static int exynos_dp_clock_recovery_ok(u8 link_status[6], int lane_count)
return 0;
}
-static int exynos_dp_channel_eq_ok(u8 link_status[6], int lane_count)
+static int exynos_dp_channel_eq_ok(u8 link_align[3], int lane_count)
{
int lane;
u8 lane_align;
u8 lane_status;
- lane_align = link_status[2];
+ lane_align = link_align[2];
if ((lane_align & DPCD_INTERLANE_ALIGN_DONE) == 0)
return -EINVAL;
for (lane = 0; lane < lane_count; lane++) {
- lane_status = exynos_dp_get_lane_status(link_status, lane);
+ lane_status = exynos_dp_get_lane_status(link_align, lane);
lane_status &= DPCD_CHANNEL_EQ_BITS;
if (lane_status != DPCD_CHANNEL_EQ_BITS)
return -EINVAL;
}
+
return 0;
}
@@ -417,69 +421,17 @@ static unsigned int exynos_dp_get_lane_link_training(
static void exynos_dp_reduce_link_rate(struct exynos_dp_device *dp)
{
- if (dp->link_train.link_rate == LINK_RATE_2_70GBPS) {
- /* set to reduced bit rate */
- dp->link_train.link_rate = LINK_RATE_1_62GBPS;
- dev_err(dp->dev, "set to bandwidth %.2x\n",
- dp->link_train.link_rate);
- dp->link_train.lt_state = START;
- } else {
- exynos_dp_training_pattern_dis(dp);
- /* set enhanced mode if available */
- exynos_dp_set_enhanced_mode(dp);
- dp->link_train.lt_state = FAILED;
- }
-}
+ exynos_dp_training_pattern_dis(dp);
+ exynos_dp_set_enhanced_mode(dp);
-static void exynos_dp_get_adjust_train(struct exynos_dp_device *dp,
- u8 adjust_request[2])
-{
- int lane;
- int lane_count;
- u8 voltage_swing;
- u8 pre_emphasis;
- u8 training_lane;
-
- lane_count = dp->link_train.lane_count;
- for (lane = 0; lane < lane_count; lane++) {
- voltage_swing = exynos_dp_get_adjust_request_voltage(
- adjust_request, lane);
- pre_emphasis = exynos_dp_get_adjust_request_pre_emphasis(
- adjust_request, lane);
- training_lane = DPCD_VOLTAGE_SWING_SET(voltage_swing) |
- DPCD_PRE_EMPHASIS_SET(pre_emphasis);
-
- if (voltage_swing == VOLTAGE_LEVEL_3 ||
- pre_emphasis == PRE_EMPHASIS_LEVEL_3) {
- training_lane |= DPCD_MAX_SWING_REACHED;
- training_lane |= DPCD_MAX_PRE_EMPHASIS_REACHED;
- }
- dp->link_train.training_lane[lane] = training_lane;
- }
-}
-
-static int exynos_dp_check_max_cr_loop(struct exynos_dp_device *dp,
- u8 voltage_swing)
-{
- int lane;
- int lane_count;
-
- lane_count = dp->link_train.lane_count;
- for (lane = 0; lane < lane_count; lane++) {
- if (voltage_swing == VOLTAGE_LEVEL_3 ||
- dp->link_train.cr_loop[lane] == MAX_CR_LOOP)
- return -EINVAL;
- }
- return 0;
+ dp->link_train.lt_state = FAILED;
}
static int exynos_dp_process_clock_recovery(struct exynos_dp_device *dp)
{
- u8 data;
- u8 link_status[6];
+ u8 link_status[2];
int lane;
int lane_count;
- u8 buf[5];
u8 adjust_request[2];
u8 voltage_swing;
@@ -488,100 +440,154 @@ static int exynos_dp_process_clock_recovery(struct exynos_dp_device *dp)
usleep_range(100, 101);
- exynos_dp_read_bytes_from_dpcd(dp, DPCD_ADDR_LANE0_1_STATUS,
- 6, link_status);
lane_count = dp->link_train.lane_count;
+ exynos_dp_read_bytes_from_dpcd(dp, DPCD_ADDR_LANE0_1_STATUS,
+ 2, link_status);
+
if (exynos_dp_clock_recovery_ok(link_status, lane_count) == 0) {
/* set training pattern 2 for EQ */
exynos_dp_set_training_pattern(dp, TRAINING_PTN2);
- adjust_request[0] = link_status[4];
- adjust_request[1] = link_status[5];
+ for (lane = 0; lane < lane_count; lane++) {
+ exynos_dp_read_bytes_from_dpcd(dp,
+ DPCD_ADDR_ADJUST_REQUEST_LANE0_1,
+ 2, adjust_request);
+ voltage_swing = exynos_dp_get_adjust_request_voltage(
+ adjust_request, lane);
+ pre_emphasis = exynos_dp_get_adjust_request_pre_emphasis(
+ adjust_request, lane);
+ training_lane = DPCD_VOLTAGE_SWING_SET(voltage_swing) |
+ DPCD_PRE_EMPHASIS_SET(pre_emphasis);
- exynos_dp_get_adjust_train(dp, adjust_request);
+ if (voltage_swing == VOLTAGE_LEVEL_3)
+ training_lane |= DPCD_MAX_SWING_REACHED;
+ if (pre_emphasis == PRE_EMPHASIS_LEVEL_3)
+ training_lane |= DPCD_MAX_PRE_EMPHASIS_REACHED;
- buf[0] = DPCD_SCRAMBLING_DISABLED |
- DPCD_TRAINING_PATTERN_2;
- exynos_dp_write_byte_to_dpcd(dp,
- DPCD_ADDR_TRAINING_PATTERN_SET,
- buf[0]);
+ dp->link_train.training_lane[lane] = training_lane;
- for (lane = 0; lane < lane_count; lane++) {
exynos_dp_set_lane_link_training(dp,
dp->link_train.training_lane[lane],
lane);
- buf[lane] = dp->link_train.training_lane[lane];
- exynos_dp_write_byte_to_dpcd(dp,
- DPCD_ADDR_TRAINING_LANE0_SET + lane,
- buf[lane]);
}
- dp->link_train.lt_state = EQUALIZER_TRAINING;
- } else {
- exynos_dp_read_byte_from_dpcd(dp,
- DPCD_ADDR_ADJUST_REQUEST_LANE0_1,
- &data);
- adjust_request[0] = data;
- exynos_dp_read_byte_from_dpcd(dp,
- DPCD_ADDR_ADJUST_REQUEST_LANE2_3,
- &data);
- adjust_request[1] = data;
+ exynos_dp_write_byte_to_dpcd(dp,
+ DPCD_ADDR_TRAINING_PATTERN_SET,
+ DPCD_SCRAMBLING_DISABLED |
+ DPCD_TRAINING_PATTERN_2);
+
+ exynos_dp_write_bytes_to_dpcd(dp,
+ DPCD_ADDR_TRAINING_LANE0_SET,
+ lane_count,
+ dp->link_train.training_lane);
+ dev_info(dp->dev, "Link Training Clock Recovery success\n");
+ dp->link_train.lt_state = EQUALIZER_TRAINING;
+ } else {
for (lane = 0; lane < lane_count; lane++) {
training_lane = exynos_dp_get_lane_link_training(
dp, lane);
+ exynos_dp_read_bytes_from_dpcd(dp,
+ DPCD_ADDR_ADJUST_REQUEST_LANE0_1,
+ 2, adjust_request);
voltage_swing = exynos_dp_get_adjust_request_voltage(
adjust_request, lane);
pre_emphasis = exynos_dp_get_adjust_request_pre_emphasis(
adjust_request, lane);
- if ((DPCD_VOLTAGE_SWING_GET(training_lane) == voltage_swing) &&
- (DPCD_PRE_EMPHASIS_GET(training_lane) == pre_emphasis))
- dp->link_train.cr_loop[lane]++;
- dp->link_train.training_lane[lane] = training_lane;
- }
- if (exynos_dp_check_max_cr_loop(dp, voltage_swing) != 0) {
- exynos_dp_reduce_link_rate(dp);
- } else {
- exynos_dp_get_adjust_train(dp, adjust_request);
+ if (voltage_swing == VOLTAGE_LEVEL_3 ||
+ pre_emphasis == PRE_EMPHASIS_LEVEL_3) {
+ dev_err(dp->dev, "voltage or pre emphasis reached max level\n");
+ goto reduce_link_rate;
+ }
- for (lane = 0; lane < lane_count; lane++) {
- exynos_dp_set_lane_link_training(dp,
- dp->link_train.training_lane[lane],
- lane);
- buf[lane] = dp->link_train.training_lane[lane];
- exynos_dp_write_byte_to_dpcd(dp,
- DPCD_ADDR_TRAINING_LANE0_SET + lane,
- buf[lane]);
+ if ((DPCD_VOLTAGE_SWING_GET(training_lane) ==
+ voltage_swing) &&
+ (DPCD_PRE_EMPHASIS_GET(training_lane) ==
+ pre_emphasis)) {
+ dp->link_train.cr_loop[lane]++;
+ if (dp->link_train.cr_loop[lane] == MAX_CR_LOOP) {
+ dev_err(dp->dev, "CR Max loop\n");
+ goto reduce_link_rate;
+ }
}
+
+ training_lane = DPCD_VOLTAGE_SWING_SET(voltage_swing) |
+ DPCD_PRE_EMPHASIS_SET(pre_emphasis);
+
+ if (voltage_swing == VOLTAGE_LEVEL_3)
+ training_lane |= DPCD_MAX_SWING_REACHED;
+ if (pre_emphasis == PRE_EMPHASIS_LEVEL_3)
+ training_lane |= DPCD_MAX_PRE_EMPHASIS_REACHED;
+
+ dp->link_train.training_lane[lane] = training_lane;
+
+ exynos_dp_set_lane_link_training(dp,
+ dp->link_train.training_lane[lane], lane);
}
+
+ exynos_dp_write_bytes_to_dpcd(dp,
+ DPCD_ADDR_TRAINING_LANE0_SET,
+ lane_count,
+ dp->link_train.training_lane);
}
return 0;
+
+reduce_link_rate:
+ exynos_dp_reduce_link_rate(dp);
+ return -EIO;
}
static int exynos_dp_process_equalizer_training(struct exynos_dp_device *dp)
{
- u8 link_status[6];
+ u8 link_status[2];
+ u8 link_align[3];
int lane;
int lane_count;
- u8 buf[5];
u32 reg;
u8 adjust_request[2];
+ u8 voltage_swing;
+ u8 pre_emphasis;
+ u8 training_lane;
usleep_range(400, 401);
- exynos_dp_read_bytes_from_dpcd(dp, DPCD_ADDR_LANE0_1_STATUS,
- 6, link_status);
lane_count = dp->link_train.lane_count;
+ exynos_dp_read_bytes_from_dpcd(dp, DPCD_ADDR_LANE0_1_STATUS,
+ 2, link_status);
+
if (exynos_dp_clock_recovery_ok(link_status, lane_count) == 0) {
- adjust_request[0] = link_status[4];
- adjust_request[1] = link_status[5];
+ link_align[0] = link_status[0];
+ link_align[1] = link_status[1];
- if (exynos_dp_channel_eq_ok(link_status, lane_count) == 0) {
+ exynos_dp_read_byte_from_dpcd(dp,
+ DPCD_ADDR_LANE_ALIGN_STATUS_UPDATED,
+ &link_align[2]);
+
+ for (lane = 0; lane < lane_count; lane++) {
+ exynos_dp_read_bytes_from_dpcd(dp,
+ DPCD_ADDR_ADJUST_REQUEST_LANE0_1,
+ 2, adjust_request);
+ voltage_swing = exynos_dp_get_adjust_request_voltage(
+ adjust_request, lane);
+ pre_emphasis = exynos_dp_get_adjust_request_pre_emphasis(
+ adjust_request, lane);
+ training_lane = DPCD_VOLTAGE_SWING_SET(voltage_swing) |
+ DPCD_PRE_EMPHASIS_SET(pre_emphasis);
+
+ if (voltage_swing == VOLTAGE_LEVEL_3)
+ training_lane |= DPCD_MAX_SWING_REACHED;
+ if (pre_emphasis == PRE_EMPHASIS_LEVEL_3)
+ training_lane |= DPCD_MAX_PRE_EMPHASIS_REACHED;
+
+ dp->link_train.training_lane[lane] = training_lane;
+ }
+
+ if (exynos_dp_channel_eq_ok(link_align, lane_count) == 0) {
/* traing pattern Set to Normal */
exynos_dp_training_pattern_dis(dp);
@@ -596,39 +602,42 @@ static int exynos_dp_process_equalizer_training(struct exynos_dp_device *dp)
dp->link_train.lane_count = reg;
dev_dbg(dp->dev, "final lane count = %.2x\n",
dp->link_train.lane_count);
+
/* set enhanced mode if available */
exynos_dp_set_enhanced_mode(dp);
-
dp->link_train.lt_state = FINISHED;
} else {
/* not all locked */
dp->link_train.eq_loop++;
if (dp->link_train.eq_loop > MAX_EQ_LOOP) {
- exynos_dp_reduce_link_rate(dp);
- } else {
- exynos_dp_get_adjust_train(dp, adjust_request);
-
- for (lane = 0; lane < lane_count; lane++) {
- exynos_dp_set_lane_link_training(dp,
- dp->link_train.training_lane[lane],
- lane);
- buf[lane] = dp->link_train.training_lane[lane];
- exynos_dp_write_byte_to_dpcd(dp,
- DPCD_ADDR_TRAINING_LANE0_SET + lane,
- buf[lane]);
- }
+ dev_err(dp->dev, "EQ Max loop\n");
+ goto reduce_link_rate;
}
+
+ for (lane = 0; lane < lane_count; lane++)
+ exynos_dp_set_lane_link_training(dp,
+ dp->link_train.training_lane[lane],
+ lane);
+
+ exynos_dp_write_bytes_to_dpcd(dp,
+ DPCD_ADDR_TRAINING_LANE0_SET,
+ lane_count,
+ dp->link_train.training_lane);
}
} else {
- exynos_dp_reduce_link_rate(dp);
+ goto reduce_link_rate;
}
return 0;
+
+reduce_link_rate:
+ exynos_dp_reduce_link_rate(dp);
+ return -EIO;
}
static void exynos_dp_get_max_rx_bandwidth(struct exynos_dp_device *dp,
- u8 *bandwidth)
+ u8 *bandwidth)
{
u8 data;
@@ -641,7 +650,7 @@ static void exynos_dp_get_max_rx_bandwidth(struct exynos_dp_device *dp,
}
static void exynos_dp_get_max_rx_lane_count(struct exynos_dp_device *dp,
- u8 *lane_count)
+ u8 *lane_count)
{
u8 data;
@@ -693,13 +702,7 @@ static void exynos_dp_init_training(struct exynos_dp_device *dp,
static int exynos_dp_sw_link_training(struct exynos_dp_device *dp)
{
int retval = 0;
- int training_finished;
-
- /* Turn off unnecessary lane */
- if (dp->link_train.lane_count == 1)
- exynos_dp_set_analog_power_down(dp, CH1_BLOCK, 1);
-
- training_finished = 0;
+ int training_finished = 0;
dp->link_train.lt_state = START;
@@ -710,10 +713,14 @@ static int exynos_dp_sw_link_training(struct exynos_dp_device *dp)
exynos_dp_link_start(dp);
break;
case CLOCK_RECOVERY:
- exynos_dp_process_clock_recovery(dp);
+ retval = exynos_dp_process_clock_recovery(dp);
+ if (retval)
+ dev_err(dp->dev, "LT CR failed!\n");
break;
case EQUALIZER_TRAINING:
- exynos_dp_process_equalizer_training(dp);
+ retval = exynos_dp_process_equalizer_training(dp);
+ if (retval)
+ dev_err(dp->dev, "LT EQ failed!\n");
break;
case FINISHED:
training_finished = 1;
@@ -872,40 +879,33 @@ static int __devinit exynos_dp_probe(struct platform_device *pdev)
dp->dev = &pdev->dev;
- dp->clock = clk_get(&pdev->dev, "dp");
+ dp->clock = devm_clk_get(&pdev->dev, "dp");
if (IS_ERR(dp->clock)) {
dev_err(&pdev->dev, "failed to get clock\n");
return PTR_ERR(dp->clock);
}
- clk_enable(dp->clock);
+ clk_prepare_enable(dp->clock);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(&pdev->dev, "failed to get registers\n");
- ret = -EINVAL;
- goto err_clock;
- }
dp->reg_base = devm_request_and_ioremap(&pdev->dev, res);
if (!dp->reg_base) {
dev_err(&pdev->dev, "failed to ioremap\n");
- ret = -ENOMEM;
- goto err_clock;
+ return -ENOMEM;
}
dp->irq = platform_get_irq(pdev, 0);
if (!dp->irq) {
dev_err(&pdev->dev, "failed to get irq\n");
- ret = -ENODEV;
- goto err_clock;
+ return -ENODEV;
}
ret = devm_request_irq(&pdev->dev, dp->irq, exynos_dp_irq_handler, 0,
"exynos-dp", dp);
if (ret) {
dev_err(&pdev->dev, "failed to request irq\n");
- goto err_clock;
+ return ret;
}
dp->video_info = pdata->video_info;
@@ -917,7 +917,7 @@ static int __devinit exynos_dp_probe(struct platform_device *pdev)
ret = exynos_dp_detect_hpd(dp);
if (ret) {
dev_err(&pdev->dev, "unable to detect hpd\n");
- goto err_clock;
+ return ret;
}
exynos_dp_handle_edid(dp);
@@ -926,7 +926,7 @@ static int __devinit exynos_dp_probe(struct platform_device *pdev)
dp->video_info->link_rate);
if (ret) {
dev_err(&pdev->dev, "unable to do link train\n");
- goto err_clock;
+ return ret;
}
exynos_dp_enable_scramble(dp, 1);
@@ -940,17 +940,12 @@ static int __devinit exynos_dp_probe(struct platform_device *pdev)
ret = exynos_dp_config_video(dp, dp->video_info);
if (ret) {
dev_err(&pdev->dev, "unable to config video\n");
- goto err_clock;
+ return ret;
}
platform_set_drvdata(pdev, dp);
return 0;
-
-err_clock:
- clk_put(dp->clock);
-
- return ret;
}
static int __devexit exynos_dp_remove(struct platform_device *pdev)
@@ -961,8 +956,7 @@ static int __devexit exynos_dp_remove(struct platform_device *pdev)
if (pdata && pdata->phy_exit)
pdata->phy_exit();
- clk_disable(dp->clock);
- clk_put(dp->clock);
+ clk_disable_unprepare(dp->clock);
return 0;
}
@@ -977,7 +971,7 @@ static int exynos_dp_suspend(struct device *dev)
if (pdata && pdata->phy_exit)
pdata->phy_exit();
- clk_disable(dp->clock);
+ clk_disable_unprepare(dp->clock);
return 0;
}
@@ -991,7 +985,7 @@ static int exynos_dp_resume(struct device *dev)
if (pdata && pdata->phy_init)
pdata->phy_init();
- clk_enable(dp->clock);
+ clk_prepare_enable(dp->clock);
exynos_dp_init_dp(dp);
diff --git a/drivers/video/exynos/exynos_dp_core.h b/drivers/video/exynos/exynos_dp_core.h
index 8526e54..57b8a65 100644
--- a/drivers/video/exynos/exynos_dp_core.h
+++ b/drivers/video/exynos/exynos_dp_core.h
@@ -43,7 +43,7 @@ void exynos_dp_init_interrupt(struct exynos_dp_device *dp);
void exynos_dp_reset(struct exynos_dp_device *dp);
void exynos_dp_swreset(struct exynos_dp_device *dp);
void exynos_dp_config_interrupt(struct exynos_dp_device *dp);
-u32 exynos_dp_get_pll_lock_status(struct exynos_dp_device *dp);
+enum pll_status exynos_dp_get_pll_lock_status(struct exynos_dp_device *dp);
void exynos_dp_set_pll_power_down(struct exynos_dp_device *dp, bool enable);
void exynos_dp_set_analog_power_down(struct exynos_dp_device *dp,
enum analog_power_block block,
@@ -105,7 +105,7 @@ u32 exynos_dp_get_lane1_link_training(struct exynos_dp_device *dp);
u32 exynos_dp_get_lane2_link_training(struct exynos_dp_device *dp);
u32 exynos_dp_get_lane3_link_training(struct exynos_dp_device *dp);
void exynos_dp_reset_macro(struct exynos_dp_device *dp);
-int exynos_dp_init_video(struct exynos_dp_device *dp);
+void exynos_dp_init_video(struct exynos_dp_device *dp);
void exynos_dp_set_video_color_format(struct exynos_dp_device *dp,
u32 color_depth,
@@ -144,7 +144,7 @@ void exynos_dp_disable_scrambling(struct exynos_dp_device *dp);
#define DPCD_ADDR_TRAINING_PATTERN_SET 0x0102
#define DPCD_ADDR_TRAINING_LANE0_SET 0x0103
#define DPCD_ADDR_LANE0_1_STATUS 0x0202
-#define DPCD_ADDR_LANE_ALIGN__STATUS_UPDATED 0x0204
+#define DPCD_ADDR_LANE_ALIGN_STATUS_UPDATED 0x0204
#define DPCD_ADDR_ADJUST_REQUEST_LANE0_1 0x0206
#define DPCD_ADDR_ADJUST_REQUEST_LANE2_3 0x0207
#define DPCD_ADDR_TEST_REQUEST 0x0218
diff --git a/drivers/video/exynos/exynos_dp_reg.c b/drivers/video/exynos/exynos_dp_reg.c
index 2db5b9a..3f5ca8a 100644
--- a/drivers/video/exynos/exynos_dp_reg.c
+++ b/drivers/video/exynos/exynos_dp_reg.c
@@ -77,7 +77,7 @@ void exynos_dp_init_analog_param(struct exynos_dp_device *dp)
writel(reg, dp->reg_base + EXYNOS_DP_ANALOG_CTL_3);
reg = PD_RING_OSC | AUX_TERMINAL_CTRL_50_OHM |
- TX_CUR1_2X | TX_CUR_8_MA;
+ TX_CUR1_2X | TX_CUR_16_MA;
writel(reg, dp->reg_base + EXYNOS_DP_PLL_FILTER_CTL_1);
reg = CH3_AMP_400_MV | CH2_AMP_400_MV |
@@ -148,9 +148,6 @@ void exynos_dp_reset(struct exynos_dp_device *dp)
writel(0x2, dp->reg_base + EXYNOS_DP_M_AUD_GEN_FILTER_TH);
writel(0x00000101, dp->reg_base + EXYNOS_DP_SOC_GENERAL_CTL);
-
- exynos_dp_init_analog_param(dp);
- exynos_dp_init_interrupt(dp);
}
void exynos_dp_swreset(struct exynos_dp_device *dp)
@@ -179,7 +176,7 @@ void exynos_dp_config_interrupt(struct exynos_dp_device *dp)
writel(reg, dp->reg_base + EXYNOS_DP_INT_STA_MASK);
}
-u32 exynos_dp_get_pll_lock_status(struct exynos_dp_device *dp)
+enum pll_status exynos_dp_get_pll_lock_status(struct exynos_dp_device *dp)
{
u32 reg;
@@ -401,6 +398,7 @@ int exynos_dp_start_aux_transaction(struct exynos_dp_device *dp)
{
int reg;
int retval = 0;
+ int timeout_loop = 0;
/* Enable AUX CH operation */
reg = readl(dp->reg_base + EXYNOS_DP_AUX_CH_CTL_2);
@@ -409,8 +407,15 @@ int exynos_dp_start_aux_transaction(struct exynos_dp_device *dp)
/* Is AUX CH command reply received? */
reg = readl(dp->reg_base + EXYNOS_DP_INT_STA);
- while (!(reg & RPLY_RECEIV))
+ while (!(reg & RPLY_RECEIV)) {
+ timeout_loop++;
+ if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) {
+ dev_err(dp->dev, "AUX CH command reply failed!\n");
+ return -ETIMEDOUT;
+ }
reg = readl(dp->reg_base + EXYNOS_DP_INT_STA);
+ usleep_range(10, 11);
+ }
/* Clear interrupt source for AUX CH command reply */
writel(RPLY_RECEIV, dp->reg_base + EXYNOS_DP_INT_STA);
@@ -471,7 +476,8 @@ int exynos_dp_write_byte_to_dpcd(struct exynos_dp_device *dp,
if (retval == 0)
break;
else
- dev_err(dp->dev, "Aux Transaction fail!\n");
+ dev_dbg(dp->dev, "%s: Aux Transaction fail!\n",
+ __func__);
}
return retval;
@@ -511,7 +517,8 @@ int exynos_dp_read_byte_from_dpcd(struct exynos_dp_device *dp,
if (retval == 0)
break;
else
- dev_err(dp->dev, "Aux Transaction fail!\n");
+ dev_dbg(dp->dev, "%s: Aux Transaction fail!\n",
+ __func__);
}
/* Read data buffer */
@@ -575,7 +582,8 @@ int exynos_dp_write_bytes_to_dpcd(struct exynos_dp_device *dp,
if (retval == 0)
break;
else
- dev_err(dp->dev, "Aux Transaction fail!\n");
+ dev_dbg(dp->dev, "%s: Aux Transaction fail!\n",
+ __func__);
}
start_offset += cur_data_count;
@@ -632,7 +640,8 @@ int exynos_dp_read_bytes_from_dpcd(struct exynos_dp_device *dp,
if (retval == 0)
break;
else
- dev_err(dp->dev, "Aux Transaction fail!\n");
+ dev_dbg(dp->dev, "%s: Aux Transaction fail!\n",
+ __func__);
}
for (cur_data_idx = 0; cur_data_idx < cur_data_count;
@@ -677,7 +686,7 @@ int exynos_dp_select_i2c_device(struct exynos_dp_device *dp,
/* Start AUX transaction */
retval = exynos_dp_start_aux_transaction(dp);
if (retval != 0)
- dev_err(dp->dev, "Aux Transaction fail!\n");
+ dev_dbg(dp->dev, "%s: Aux Transaction fail!\n", __func__);
return retval;
}
@@ -717,7 +726,8 @@ int exynos_dp_read_byte_from_i2c(struct exynos_dp_device *dp,
if (retval == 0)
break;
else
- dev_err(dp->dev, "Aux Transaction fail!\n");
+ dev_dbg(dp->dev, "%s: Aux Transaction fail!\n",
+ __func__);
}
/* Read data */
@@ -777,7 +787,9 @@ int exynos_dp_read_bytes_from_i2c(struct exynos_dp_device *dp,
if (retval == 0)
break;
else
- dev_err(dp->dev, "Aux Transaction fail!\n");
+ dev_dbg(dp->dev,
+ "%s: Aux Transaction fail!\n",
+ __func__);
}
/* Check if Rx sends defer */
reg = readl(dp->reg_base + EXYNOS_DP_AUX_RX_COMM);
@@ -883,7 +895,9 @@ void exynos_dp_set_lane0_pre_emphasis(struct exynos_dp_device *dp, u32 level)
{
u32 reg;
- reg = level << PRE_EMPHASIS_SET_SHIFT;
+ reg = readl(dp->reg_base + EXYNOS_DP_LN0_LINK_TRAINING_CTL);
+ reg &= ~PRE_EMPHASIS_SET_MASK;
+ reg |= level << PRE_EMPHASIS_SET_SHIFT;
writel(reg, dp->reg_base + EXYNOS_DP_LN0_LINK_TRAINING_CTL);
}
@@ -891,7 +905,9 @@ void exynos_dp_set_lane1_pre_emphasis(struct exynos_dp_device *dp, u32 level)
{
u32 reg;
- reg = level << PRE_EMPHASIS_SET_SHIFT;
+ reg = readl(dp->reg_base + EXYNOS_DP_LN1_LINK_TRAINING_CTL);
+ reg &= ~PRE_EMPHASIS_SET_MASK;
+ reg |= level << PRE_EMPHASIS_SET_SHIFT;
writel(reg, dp->reg_base + EXYNOS_DP_LN1_LINK_TRAINING_CTL);
}
@@ -899,7 +915,9 @@ void exynos_dp_set_lane2_pre_emphasis(struct exynos_dp_device *dp, u32 level)
{
u32 reg;
- reg = level << PRE_EMPHASIS_SET_SHIFT;
+ reg = readl(dp->reg_base + EXYNOS_DP_LN2_LINK_TRAINING_CTL);
+ reg &= ~PRE_EMPHASIS_SET_MASK;
+ reg |= level << PRE_EMPHASIS_SET_SHIFT;
writel(reg, dp->reg_base + EXYNOS_DP_LN2_LINK_TRAINING_CTL);
}
@@ -907,7 +925,9 @@ void exynos_dp_set_lane3_pre_emphasis(struct exynos_dp_device *dp, u32 level)
{
u32 reg;
- reg = level << PRE_EMPHASIS_SET_SHIFT;
+ reg = readl(dp->reg_base + EXYNOS_DP_LN3_LINK_TRAINING_CTL);
+ reg &= ~PRE_EMPHASIS_SET_MASK;
+ reg |= level << PRE_EMPHASIS_SET_SHIFT;
writel(reg, dp->reg_base + EXYNOS_DP_LN3_LINK_TRAINING_CTL);
}
@@ -994,7 +1014,7 @@ void exynos_dp_reset_macro(struct exynos_dp_device *dp)
writel(reg, dp->reg_base + EXYNOS_DP_PHY_TEST);
}
-int exynos_dp_init_video(struct exynos_dp_device *dp)
+void exynos_dp_init_video(struct exynos_dp_device *dp)
{
u32 reg;
@@ -1012,8 +1032,6 @@ int exynos_dp_init_video(struct exynos_dp_device *dp)
reg = VID_HRES_TH(2) | VID_VRES_TH(0);
writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_8);
-
- return 0;
}
void exynos_dp_set_video_color_format(struct exynos_dp_device *dp,
diff --git a/drivers/video/exynos/exynos_dp_reg.h b/drivers/video/exynos/exynos_dp_reg.h
index 125b27c..1f2f014c 100644
--- a/drivers/video/exynos/exynos_dp_reg.h
+++ b/drivers/video/exynos/exynos_dp_reg.h
@@ -187,7 +187,7 @@
#define PD_RING_OSC (0x1 << 6)
#define AUX_TERMINAL_CTRL_50_OHM (0x2 << 4)
#define TX_CUR1_2X (0x1 << 2)
-#define TX_CUR_8_MA (0x2 << 0)
+#define TX_CUR_16_MA (0x3 << 0)
/* EXYNOS_DP_TX_AMP_TUNING_CTL */
#define CH3_AMP_400_MV (0x0 << 24)
@@ -285,6 +285,7 @@
#define SW_TRAINING_PATTERN_SET_NORMAL (0x0 << 0)
/* EXYNOS_DP_LN0_LINK_TRAINING_CTL */
+#define PRE_EMPHASIS_SET_MASK (0x3 << 3)
#define PRE_EMPHASIS_SET_SHIFT (3)
/* EXYNOS_DP_DEBUG_CTL */
diff --git a/drivers/video/exynos/exynos_mipi_dsi.c b/drivers/video/exynos/exynos_mipi_dsi.c
index 663c308..07d70a3 100644
--- a/drivers/video/exynos/exynos_mipi_dsi.c
+++ b/drivers/video/exynos/exynos_mipi_dsi.c
@@ -205,7 +205,8 @@ int exynos_mipi_dsi_register_lcd_device(struct mipi_dsim_lcd_device *lcd_dev)
return 0;
}
-struct mipi_dsim_ddi *exynos_mipi_dsi_find_lcd_device(struct mipi_dsim_lcd_driver *lcd_drv)
+static struct mipi_dsim_ddi *exynos_mipi_dsi_find_lcd_device(
+ struct mipi_dsim_lcd_driver *lcd_drv)
{
struct mipi_dsim_ddi *dsim_ddi, *next;
struct mipi_dsim_lcd_device *lcd_dev;
@@ -265,7 +266,8 @@ int exynos_mipi_dsi_register_lcd_driver(struct mipi_dsim_lcd_driver *lcd_drv)
}
-struct mipi_dsim_ddi *exynos_mipi_dsi_bind_lcd_ddi(struct mipi_dsim_device *dsim,
+static struct mipi_dsim_ddi *exynos_mipi_dsi_bind_lcd_ddi(
+ struct mipi_dsim_device *dsim,
const char *name)
{
struct mipi_dsim_ddi *dsim_ddi, *next;
@@ -373,6 +375,7 @@ static int exynos_mipi_dsi_probe(struct platform_device *pdev)
dsim->clock = clk_get(&pdev->dev, "dsim0");
if (IS_ERR(dsim->clock)) {
dev_err(&pdev->dev, "failed to get dsim clock source\n");
+ ret = -ENODEV;
goto err_clock_get;
}
@@ -381,6 +384,7 @@ static int exynos_mipi_dsi_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(&pdev->dev, "failed to get io memory region\n");
+ ret = -ENODEV;
goto err_platform_get;
}
@@ -405,6 +409,7 @@ static int exynos_mipi_dsi_probe(struct platform_device *pdev)
dsim_ddi = exynos_mipi_dsi_bind_lcd_ddi(dsim, dsim_pd->lcd_panel_name);
if (!dsim_ddi) {
dev_err(&pdev->dev, "mipi_dsim_ddi object not found.\n");
+ ret = -EINVAL;
goto err_bind;
}
diff --git a/drivers/video/exynos/exynos_mipi_dsi_common.c b/drivers/video/exynos/exynos_mipi_dsi_common.c
index 47b533a..3cd29a4 100644
--- a/drivers/video/exynos/exynos_mipi_dsi_common.c
+++ b/drivers/video/exynos/exynos_mipi_dsi_common.c
@@ -79,11 +79,6 @@ irqreturn_t exynos_mipi_dsi_interrupt_handler(int irq, void *dev_id)
struct mipi_dsim_device *dsim = dev_id;
unsigned int intsrc, intmsk;
- if (dsim == NULL) {
- dev_err(dsim->dev, "%s: wrong parameter\n", __func__);
- return IRQ_NONE;
- }
-
intsrc = exynos_mipi_dsi_read_interrupt(dsim);
intmsk = exynos_mipi_dsi_read_interrupt_mask(dsim);
intmsk = ~intmsk & intsrc;
@@ -288,9 +283,6 @@ int exynos_mipi_dsi_wr_data(struct mipi_dsim_device *dsim, unsigned int data_id,
mutex_unlock(&dsim->lock);
return -EINVAL;
}
-
- mutex_unlock(&dsim->lock);
- return 0;
}
static unsigned int exynos_mipi_dsi_long_data_rd(struct mipi_dsim_device *dsim,
diff --git a/drivers/video/fsl-diu-fb.c b/drivers/video/fsl-diu-fb.c
index 458c006..ede9e55 100644
--- a/drivers/video/fsl-diu-fb.c
+++ b/drivers/video/fsl-diu-fb.c
@@ -1501,8 +1501,8 @@ static int __devinit fsl_diu_probe(struct platform_device *pdev)
unsigned int i;
int ret;
- data = dma_alloc_coherent(&pdev->dev, sizeof(struct fsl_diu_data),
- &dma_addr, GFP_DMA | __GFP_ZERO);
+ data = dmam_alloc_coherent(&pdev->dev, sizeof(struct fsl_diu_data),
+ &dma_addr, GFP_DMA | __GFP_ZERO);
if (!data)
return -ENOMEM;
data->dma_addr = dma_addr;
@@ -1628,9 +1628,6 @@ error:
iounmap(data->diu_reg);
- dma_free_coherent(&pdev->dev, sizeof(struct fsl_diu_data), data,
- data->dma_addr);
-
return ret;
}
@@ -1648,9 +1645,6 @@ static int fsl_diu_remove(struct platform_device *pdev)
iounmap(data->diu_reg);
- dma_free_coherent(&pdev->dev, sizeof(struct fsl_diu_data), data,
- data->dma_addr);
-
return 0;
}
diff --git a/drivers/video/gbefb.c b/drivers/video/gbefb.c
index 05e2a8a..3dad319 100644
--- a/drivers/video/gbefb.c
+++ b/drivers/video/gbefb.c
@@ -20,6 +20,7 @@
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/module.h>
+#include <linux/io.h>
#ifdef CONFIG_X86
#include <asm/mtrr.h>
@@ -28,7 +29,6 @@
#include <asm/addrspace.h>
#endif
#include <asm/byteorder.h>
-#include <asm/io.h>
#include <asm/tlbflush.h>
#include <video/gbe.h>
@@ -1156,7 +1156,8 @@ static int __devinit gbefb_probe(struct platform_device *p_dev)
goto out_release_framebuffer;
}
- gbe = (struct sgi_gbe *) ioremap(GBE_BASE, sizeof(struct sgi_gbe));
+ gbe = (struct sgi_gbe *) devm_ioremap(&p_dev->dev, GBE_BASE,
+ sizeof(struct sgi_gbe));
if (!gbe) {
printk(KERN_ERR "gbefb: couldn't map mmio region\n");
ret = -ENXIO;
@@ -1170,12 +1171,13 @@ static int __devinit gbefb_probe(struct platform_device *p_dev)
if (!gbe_tiles.cpu) {
printk(KERN_ERR "gbefb: couldn't allocate tiles table\n");
ret = -ENOMEM;
- goto out_unmap;
+ goto out_release_mem_region;
}
if (gbe_mem_phys) {
/* memory was allocated at boot time */
- gbe_mem = ioremap_nocache(gbe_mem_phys, gbe_mem_size);
+ gbe_mem = devm_ioremap_nocache(&p_dev->dev, gbe_mem_phys,
+ gbe_mem_size);
if (!gbe_mem) {
printk(KERN_ERR "gbefb: couldn't map framebuffer\n");
ret = -ENOMEM;
@@ -1241,13 +1243,9 @@ static int __devinit gbefb_probe(struct platform_device *p_dev)
out_gbe_unmap:
if (gbe_dma_addr)
dma_free_coherent(NULL, gbe_mem_size, gbe_mem, gbe_mem_phys);
- else
- iounmap(gbe_mem);
out_tiles_free:
dma_free_coherent(NULL, GBE_TLB_SIZE * sizeof(uint16_t),
(void *)gbe_tiles.cpu, gbe_tiles.dma);
-out_unmap:
- iounmap(gbe);
out_release_mem_region:
release_mem_region(GBE_BASE, sizeof(struct sgi_gbe));
out_release_framebuffer:
@@ -1264,12 +1262,9 @@ static int __devexit gbefb_remove(struct platform_device* p_dev)
gbe_turn_off();
if (gbe_dma_addr)
dma_free_coherent(NULL, gbe_mem_size, gbe_mem, gbe_mem_phys);
- else
- iounmap(gbe_mem);
dma_free_coherent(NULL, GBE_TLB_SIZE * sizeof(uint16_t),
(void *)gbe_tiles.cpu, gbe_tiles.dma);
release_mem_region(GBE_BASE, sizeof(struct sgi_gbe));
- iounmap(gbe);
gbefb_remove_sysfs(&p_dev->dev);
framebuffer_release(info);
diff --git a/drivers/video/hpfb.c b/drivers/video/hpfb.c
index ebf8495..7324865 100644
--- a/drivers/video/hpfb.c
+++ b/drivers/video/hpfb.c
@@ -210,6 +210,7 @@ static int __devinit hpfb_init_one(unsigned long phys_base,
unsigned long virt_base)
{
unsigned long fboff, fb_width, fb_height, fb_start;
+ int ret;
fb_regs = virt_base;
fboff = (in_8(fb_regs + HPFB_FBOMSB) << 8) | in_8(fb_regs + HPFB_FBOLSB);
@@ -290,19 +291,29 @@ static int __devinit hpfb_init_one(unsigned long phys_base,
fb_info.var = hpfb_defined;
fb_info.screen_base = (char *)fb_start;
- fb_alloc_cmap(&fb_info.cmap, 1 << hpfb_defined.bits_per_pixel, 0);
+ ret = fb_alloc_cmap(&fb_info.cmap, 1 << hpfb_defined.bits_per_pixel, 0);
+ if (ret < 0)
+ goto unmap_screen_base;
- if (register_framebuffer(&fb_info) < 0) {
- fb_dealloc_cmap(&fb_info.cmap);
- iounmap(fb_info.screen_base);
- fb_info.screen_base = NULL;
- return 1;
- }
+ ret = register_framebuffer(&fb_info);
+ if (ret < 0)
+ goto dealloc_cmap;
printk(KERN_INFO "fb%d: %s frame buffer device\n",
fb_info.node, fb_info.fix.id);
return 0;
+
+dealloc_cmap:
+ fb_dealloc_cmap(&fb_info.cmap);
+
+unmap_screen_base:
+ if (fb_info.screen_base) {
+ iounmap(fb_info.screen_base);
+ fb_info.screen_base = NULL;
+ }
+
+ return ret;
}
/*
@@ -345,6 +356,9 @@ static void __devexit hpfb_remove_one(struct dio_dev *d)
if (d->scode >= DIOII_SCBASE)
iounmap((void *)fb_regs);
release_mem_region(d->resource.start, resource_size(&d->resource));
+ fb_dealloc_cmap(&fb_info.cmap);
+ if (fb_info.screen_base)
+ iounmap(fb_info.screen_base);
}
static struct dio_device_id hpfb_dio_tbl[] = {
diff --git a/drivers/video/imxfb.c b/drivers/video/imxfb.c
index 53ffdfc..cf2688d 100644
--- a/drivers/video/imxfb.c
+++ b/drivers/video/imxfb.c
@@ -803,6 +803,7 @@ static int __init imxfb_probe(struct platform_device *pdev)
fbi->regs = ioremap(res->start, resource_size(res));
if (fbi->regs == NULL) {
dev_err(&pdev->dev, "Cannot map frame buffer registers\n");
+ ret = -ENOMEM;
goto failed_ioremap;
}
diff --git a/drivers/video/jz4740_fb.c b/drivers/video/jz4740_fb.c
index 3c63fc2..4d25711 100644
--- a/drivers/video/jz4740_fb.c
+++ b/drivers/video/jz4740_fb.c
@@ -632,23 +632,10 @@ static int __devinit jzfb_probe(struct platform_device *pdev)
return -ENXIO;
}
- mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!mem) {
- dev_err(&pdev->dev, "Failed to get register memory resource\n");
- return -ENXIO;
- }
-
- mem = request_mem_region(mem->start, resource_size(mem), pdev->name);
- if (!mem) {
- dev_err(&pdev->dev, "Failed to request register memory region\n");
- return -EBUSY;
- }
-
fb = framebuffer_alloc(sizeof(struct jzfb), &pdev->dev);
if (!fb) {
dev_err(&pdev->dev, "Failed to allocate framebuffer device\n");
- ret = -ENOMEM;
- goto err_release_mem_region;
+ return -ENOMEM;
}
fb->fbops = &jzfb_ops;
@@ -657,27 +644,26 @@ static int __devinit jzfb_probe(struct platform_device *pdev)
jzfb = fb->par;
jzfb->pdev = pdev;
jzfb->pdata = pdata;
- jzfb->mem = mem;
- jzfb->ldclk = clk_get(&pdev->dev, "lcd");
+ jzfb->ldclk = devm_clk_get(&pdev->dev, "lcd");
if (IS_ERR(jzfb->ldclk)) {
ret = PTR_ERR(jzfb->ldclk);
dev_err(&pdev->dev, "Failed to get lcd clock: %d\n", ret);
goto err_framebuffer_release;
}
- jzfb->lpclk = clk_get(&pdev->dev, "lcd_pclk");
+ jzfb->lpclk = devm_clk_get(&pdev->dev, "lcd_pclk");
if (IS_ERR(jzfb->lpclk)) {
ret = PTR_ERR(jzfb->lpclk);
dev_err(&pdev->dev, "Failed to get lcd pixel clock: %d\n", ret);
- goto err_put_ldclk;
+ goto err_framebuffer_release;
}
- jzfb->base = ioremap(mem->start, resource_size(mem));
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ jzfb->base = devm_request_and_ioremap(&pdev->dev, mem);
if (!jzfb->base) {
- dev_err(&pdev->dev, "Failed to ioremap register memory region\n");
ret = -EBUSY;
- goto err_put_lpclk;
+ goto err_framebuffer_release;
}
platform_set_drvdata(pdev, jzfb);
@@ -693,7 +679,7 @@ static int __devinit jzfb_probe(struct platform_device *pdev)
ret = jzfb_alloc_devmem(jzfb);
if (ret) {
dev_err(&pdev->dev, "Failed to allocate video memory\n");
- goto err_iounmap;
+ goto err_framebuffer_release;
}
fb->fix = jzfb_fix;
@@ -734,16 +720,8 @@ err_free_devmem:
fb_dealloc_cmap(&fb->cmap);
jzfb_free_devmem(jzfb);
-err_iounmap:
- iounmap(jzfb->base);
-err_put_lpclk:
- clk_put(jzfb->lpclk);
-err_put_ldclk:
- clk_put(jzfb->ldclk);
err_framebuffer_release:
framebuffer_release(fb);
-err_release_mem_region:
- release_mem_region(mem->start, resource_size(mem));
return ret;
}
@@ -756,17 +734,11 @@ static int __devexit jzfb_remove(struct platform_device *pdev)
jz_gpio_bulk_free(jz_lcd_ctrl_pins, jzfb_num_ctrl_pins(jzfb));
jz_gpio_bulk_free(jz_lcd_data_pins, jzfb_num_data_pins(jzfb));
- iounmap(jzfb->base);
- release_mem_region(jzfb->mem->start, resource_size(jzfb->mem));
-
fb_dealloc_cmap(&jzfb->fb->cmap);
jzfb_free_devmem(jzfb);
platform_set_drvdata(pdev, NULL);
- clk_put(jzfb->lpclk);
- clk_put(jzfb->ldclk);
-
framebuffer_release(jzfb->fb);
return 0;
diff --git a/drivers/video/mb862xx/mb862xxfbdrv.c b/drivers/video/mb862xx/mb862xxfbdrv.c
index 57d940b..d68e332 100644
--- a/drivers/video/mb862xx/mb862xxfbdrv.c
+++ b/drivers/video/mb862xx/mb862xxfbdrv.c
@@ -1052,12 +1052,14 @@ static int __devinit mb862xx_pci_probe(struct pci_dev *pdev,
break;
default:
/* should never occur */
+ ret = -EIO;
goto rel_reg;
}
par->fb_base = ioremap(par->fb_base_phys, par->mapped_vram);
if (par->fb_base == NULL) {
dev_err(dev, "Cannot map framebuffer\n");
+ ret = -EIO;
goto rel_reg;
}
@@ -1073,11 +1075,13 @@ static int __devinit mb862xx_pci_probe(struct pci_dev *pdev,
dev_dbg(dev, "mmio phys 0x%llx 0x%lx\n",
(unsigned long long)par->mmio_base_phys, (ulong)par->mmio_len);
- if (mb862xx_pci_gdc_init(par))
+ ret = mb862xx_pci_gdc_init(par);
+ if (ret)
goto io_unmap;
- if (request_irq(par->irq, mb862xx_intr, IRQF_SHARED,
- DRV_NAME, (void *)par)) {
+ ret = request_irq(par->irq, mb862xx_intr, IRQF_SHARED,
+ DRV_NAME, (void *)par);
+ if (ret) {
dev_err(dev, "Cannot request irq\n");
goto io_unmap;
}
diff --git a/drivers/video/mbx/mbxfb.c b/drivers/video/mbx/mbxfb.c
index 85e4f44..6563e50 100644
--- a/drivers/video/mbx/mbxfb.c
+++ b/drivers/video/mbx/mbxfb.c
@@ -26,8 +26,7 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/uaccess.h>
-
-#include <asm/io.h>
+#include <linux/io.h>
#include <video/mbxfb.h>
@@ -939,8 +938,9 @@ static int __devinit mbxfb_probe(struct platform_device *dev)
}
mfbi->reg_phys_addr = mfbi->reg_res->start;
- mfbi->reg_virt_addr = ioremap_nocache(mfbi->reg_phys_addr,
- res_size(mfbi->reg_req));
+ mfbi->reg_virt_addr = devm_ioremap_nocache(&dev->dev,
+ mfbi->reg_phys_addr,
+ res_size(mfbi->reg_req));
if (!mfbi->reg_virt_addr) {
dev_err(&dev->dev, "failed to ioremap Marathon registers\n");
ret = -EINVAL;
@@ -948,12 +948,12 @@ static int __devinit mbxfb_probe(struct platform_device *dev)
}
virt_base_2700 = mfbi->reg_virt_addr;
- mfbi->fb_virt_addr = ioremap_nocache(mfbi->fb_phys_addr,
- res_size(mfbi->fb_req));
+ mfbi->fb_virt_addr = devm_ioremap_nocache(&dev->dev, mfbi->fb_phys_addr,
+ res_size(mfbi->fb_req));
if (!mfbi->fb_virt_addr) {
dev_err(&dev->dev, "failed to ioremap frame buffer\n");
ret = -EINVAL;
- goto err4;
+ goto err3;
}
fbi->screen_base = (char __iomem *)(mfbi->fb_virt_addr + 0x60000);
@@ -971,7 +971,7 @@ static int __devinit mbxfb_probe(struct platform_device *dev)
if (ret < 0) {
dev_err(&dev->dev, "fb_alloc_cmap failed\n");
ret = -EINVAL;
- goto err5;
+ goto err3;
}
platform_set_drvdata(dev, fbi);
@@ -996,10 +996,6 @@ static int __devinit mbxfb_probe(struct platform_device *dev)
err6:
fb_dealloc_cmap(&fbi->cmap);
-err5:
- iounmap(mfbi->fb_virt_addr);
-err4:
- iounmap(mfbi->reg_virt_addr);
err3:
release_mem_region(mfbi->reg_res->start, res_size(mfbi->reg_res));
err2:
@@ -1026,10 +1022,7 @@ static int __devexit mbxfb_remove(struct platform_device *dev)
if (mfbi->platform_remove)
mfbi->platform_remove(fbi);
- if (mfbi->fb_virt_addr)
- iounmap(mfbi->fb_virt_addr);
- if (mfbi->reg_virt_addr)
- iounmap(mfbi->reg_virt_addr);
+
if (mfbi->reg_req)
release_mem_region(mfbi->reg_req->start,
res_size(mfbi->reg_req));
diff --git a/drivers/video/msm/mddi.c b/drivers/video/msm/mddi.c
index bf73f04..35ac9e8 100644
--- a/drivers/video/msm/mddi.c
+++ b/drivers/video/msm/mddi.c
@@ -26,9 +26,6 @@
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/sched.h>
-#include <mach/msm_iomap.h>
-#include <mach/irqs.h>
-#include <mach/board.h>
#include <linux/platform_data/video-msm_fb.h>
#include "mddi_hw.h"
diff --git a/drivers/video/msm/mddi_client_nt35399.c b/drivers/video/msm/mddi_client_nt35399.c
index d7a5bf8..f96df32e 100644
--- a/drivers/video/msm/mddi_client_nt35399.c
+++ b/drivers/video/msm/mddi_client_nt35399.c
@@ -189,8 +189,9 @@ static int mddi_nt35399_probe(struct platform_device *pdev)
int ret;
- struct panel_info *panel = kzalloc(sizeof(struct panel_info),
- GFP_KERNEL);
+ struct panel_info *panel = devm_kzalloc(&pdev->dev,
+ sizeof(struct panel_info),
+ GFP_KERNEL);
printk(KERN_DEBUG "%s: enter.\n", __func__);
@@ -233,7 +234,6 @@ static int mddi_nt35399_remove(struct platform_device *pdev)
struct panel_info *panel = platform_get_drvdata(pdev);
setup_vsync(panel, 0);
- kfree(panel);
return 0;
}
diff --git a/drivers/video/msm/mdp.c b/drivers/video/msm/mdp.c
index 2e0f3ba..f2566c1 100644
--- a/drivers/video/msm/mdp.c
+++ b/drivers/video/msm/mdp.c
@@ -25,7 +25,6 @@
#include <linux/major.h>
#include <linux/slab.h>
-#include <mach/msm_iomap.h>
#include <linux/platform_data/video-msm_fb.h>
#include <linux/platform_device.h>
#include <linux/export.h>
diff --git a/drivers/video/msm/mdp_hw.h b/drivers/video/msm/mdp_hw.h
index a0bacf5..35848d7 100644
--- a/drivers/video/msm/mdp_hw.h
+++ b/drivers/video/msm/mdp_hw.h
@@ -15,7 +15,6 @@
#ifndef _MDP_HW_H_
#define _MDP_HW_H_
-#include <mach/msm_iomap.h>
#include <linux/platform_data/video-msm_fb.h>
struct mdp_info {
diff --git a/drivers/video/mx3fb.c b/drivers/video/mx3fb.c
index d738108..ce1d452 100644
--- a/drivers/video/mx3fb.c
+++ b/drivers/video/mx3fb.c
@@ -1568,7 +1568,8 @@ static int mx3fb_remove(struct platform_device *dev)
static struct platform_driver mx3fb_driver = {
.driver = {
- .name = MX3FB_NAME,
+ .name = MX3FB_NAME,
+ .owner = THIS_MODULE,
},
.probe = mx3fb_probe,
.remove = mx3fb_remove,
diff --git a/drivers/video/nuc900fb.c b/drivers/video/nuc900fb.c
index 9338755..475dfee 100644
--- a/drivers/video/nuc900fb.c
+++ b/drivers/video/nuc900fb.c
@@ -387,7 +387,7 @@ static int nuc900fb_init_registers(struct fb_info *info)
* The buffer should be a non-cached, non-buffered, memory region
* to allow palette and pixel writes without flushing the cache.
*/
-static int __init nuc900fb_map_video_memory(struct fb_info *info)
+static int __devinit nuc900fb_map_video_memory(struct fb_info *info)
{
struct nuc900fb_info *fbi = info->par;
dma_addr_t map_dma;
diff --git a/drivers/video/omap/hwa742.c b/drivers/video/omap/hwa742.c
index 9f1d23c..f349ee6 100644
--- a/drivers/video/omap/hwa742.c
+++ b/drivers/video/omap/hwa742.c
@@ -27,7 +27,6 @@
#include <linux/clk.h>
#include <linux/interrupt.h>
-#include <plat/dma.h>
#include "omapfb.h"
#define HWA742_REV_CODE_REG 0x0
diff --git a/drivers/video/omap/lcd_palmte.c b/drivers/video/omap/lcd_palmte.c
index 88c31eb..ff4fb62 100644
--- a/drivers/video/omap/lcd_palmte.c
+++ b/drivers/video/omap/lcd_palmte.c
@@ -23,7 +23,6 @@
#include <linux/platform_device.h>
#include <linux/io.h>
-#include <plat/fpga.h>
#include "omapfb.h"
static int palmte_panel_init(struct lcd_panel *panel,
diff --git a/drivers/video/omap/omapfb_main.c b/drivers/video/omap/omapfb_main.c
index f54b463..4351c43 100644
--- a/drivers/video/omap/omapfb_main.c
+++ b/drivers/video/omap/omapfb_main.c
@@ -131,15 +131,6 @@ static void omapfb_rqueue_unlock(struct omapfb_device *fbdev)
* LCD controller and LCD DMA
* ---------------------------------------------------------------------------
*/
-/* Lookup table to map elem size to elem type. */
-static const int dma_elem_type[] = {
- 0,
- OMAP_DMA_DATA_TYPE_S8,
- OMAP_DMA_DATA_TYPE_S16,
- 0,
- OMAP_DMA_DATA_TYPE_S32,
-};
-
/*
* Allocate resources needed for LCD controller and LCD DMA operations. Video
* memory is allocated from system memory according to the virtual display
diff --git a/drivers/video/omap2/displays/panel-acx565akm.c b/drivers/video/omap2/displays/panel-acx565akm.c
index eaeed43..c835aa7 100644
--- a/drivers/video/omap2/displays/panel-acx565akm.c
+++ b/drivers/video/omap2/displays/panel-acx565akm.c
@@ -600,6 +600,9 @@ static int acx_panel_power_on(struct omap_dss_device *dssdev)
mutex_lock(&md->mutex);
+ omapdss_sdi_set_timings(dssdev, &dssdev->panel.timings);
+ omapdss_sdi_set_datapairs(dssdev, dssdev->phy.sdi.datapairs);
+
r = omapdss_sdi_display_enable(dssdev);
if (r) {
pr_err("%s sdi enable failed\n", __func__);
@@ -731,18 +734,9 @@ static int acx_panel_resume(struct omap_dss_device *dssdev)
static void acx_panel_set_timings(struct omap_dss_device *dssdev,
struct omap_video_timings *timings)
{
- int r;
-
- if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
- omapdss_sdi_display_disable(dssdev);
+ omapdss_sdi_set_timings(dssdev, timings);
dssdev->panel.timings = *timings;
-
- if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) {
- r = omapdss_sdi_display_enable(dssdev);
- if (r)
- dev_err(&dssdev->dev, "%s enable failed\n", __func__);
- }
}
static int acx_panel_check_timings(struct omap_dss_device *dssdev,
diff --git a/drivers/video/omap2/displays/panel-generic-dpi.c b/drivers/video/omap2/displays/panel-generic-dpi.c
index bc5af25..88295c5 100644
--- a/drivers/video/omap2/displays/panel-generic-dpi.c
+++ b/drivers/video/omap2/displays/panel-generic-dpi.c
@@ -545,6 +545,8 @@ struct panel_drv_data {
struct omap_dss_device *dssdev;
struct panel_config *panel_config;
+
+ struct mutex lock;
};
static inline struct panel_generic_dpi_data
@@ -563,6 +565,9 @@ static int generic_dpi_panel_power_on(struct omap_dss_device *dssdev)
if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
return 0;
+ omapdss_dpi_set_timings(dssdev, &dssdev->panel.timings);
+ omapdss_dpi_set_data_lines(dssdev, dssdev->phy.dpi.data_lines);
+
r = omapdss_dpi_display_enable(dssdev);
if (r)
goto err0;
@@ -634,6 +639,8 @@ static int generic_dpi_panel_probe(struct omap_dss_device *dssdev)
drv_data->dssdev = dssdev;
drv_data->panel_config = panel_config;
+ mutex_init(&drv_data->lock);
+
dev_set_drvdata(&dssdev->dev, drv_data);
return 0;
@@ -652,56 +659,108 @@ static void __exit generic_dpi_panel_remove(struct omap_dss_device *dssdev)
static int generic_dpi_panel_enable(struct omap_dss_device *dssdev)
{
- int r = 0;
+ struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev);
+ int r;
+
+ mutex_lock(&drv_data->lock);
r = generic_dpi_panel_power_on(dssdev);
if (r)
- return r;
+ goto err;
dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+err:
+ mutex_unlock(&drv_data->lock);
- return 0;
+ return r;
}
static void generic_dpi_panel_disable(struct omap_dss_device *dssdev)
{
+ struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev);
+
+ mutex_lock(&drv_data->lock);
+
generic_dpi_panel_power_off(dssdev);
dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
+
+ mutex_unlock(&drv_data->lock);
}
static int generic_dpi_panel_suspend(struct omap_dss_device *dssdev)
{
+ struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev);
+
+ mutex_lock(&drv_data->lock);
+
generic_dpi_panel_power_off(dssdev);
dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
+ mutex_unlock(&drv_data->lock);
+
return 0;
}
static int generic_dpi_panel_resume(struct omap_dss_device *dssdev)
{
- int r = 0;
+ struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev);
+ int r;
+
+ mutex_lock(&drv_data->lock);
r = generic_dpi_panel_power_on(dssdev);
if (r)
- return r;
+ goto err;
dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
- return 0;
+err:
+ mutex_unlock(&drv_data->lock);
+
+ return r;
}
static void generic_dpi_panel_set_timings(struct omap_dss_device *dssdev,
struct omap_video_timings *timings)
{
- dpi_set_timings(dssdev, timings);
+ struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev);
+
+ mutex_lock(&drv_data->lock);
+
+ omapdss_dpi_set_timings(dssdev, timings);
+
+ dssdev->panel.timings = *timings;
+
+ mutex_unlock(&drv_data->lock);
+}
+
+static void generic_dpi_panel_get_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev);
+
+ mutex_lock(&drv_data->lock);
+
+ *timings = dssdev->panel.timings;
+
+ mutex_unlock(&drv_data->lock);
}
static int generic_dpi_panel_check_timings(struct omap_dss_device *dssdev,
struct omap_video_timings *timings)
{
- return dpi_check_timings(dssdev, timings);
+ struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev);
+ int r;
+
+ mutex_lock(&drv_data->lock);
+
+ r = dpi_check_timings(dssdev, timings);
+
+ mutex_unlock(&drv_data->lock);
+
+ return r;
}
static struct omap_dss_driver dpi_driver = {
@@ -714,6 +773,7 @@ static struct omap_dss_driver dpi_driver = {
.resume = generic_dpi_panel_resume,
.set_timings = generic_dpi_panel_set_timings,
+ .get_timings = generic_dpi_panel_get_timings,
.check_timings = generic_dpi_panel_check_timings,
.driver = {
diff --git a/drivers/video/omap2/displays/panel-lgphilips-lb035q02.c b/drivers/video/omap2/displays/panel-lgphilips-lb035q02.c
index 8028077..90c1cab 100644
--- a/drivers/video/omap2/displays/panel-lgphilips-lb035q02.c
+++ b/drivers/video/omap2/displays/panel-lgphilips-lb035q02.c
@@ -55,6 +55,9 @@ static int lb035q02_panel_power_on(struct omap_dss_device *dssdev)
if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
return 0;
+ omapdss_dpi_set_timings(dssdev, &dssdev->panel.timings);
+ omapdss_dpi_set_data_lines(dssdev, dssdev->phy.dpi.data_lines);
+
r = omapdss_dpi_display_enable(dssdev);
if (r)
goto err0;
diff --git a/drivers/video/omap2/displays/panel-n8x0.c b/drivers/video/omap2/displays/panel-n8x0.c
index e6c1153..3fc5ad0 100644
--- a/drivers/video/omap2/displays/panel-n8x0.c
+++ b/drivers/video/omap2/displays/panel-n8x0.c
@@ -150,11 +150,17 @@ static void blizzard_ctrl_setup_update(struct omap_dss_device *dssdev,
BLIZZARD_SRC_WRITE_LCD :
BLIZZARD_SRC_WRITE_LCD_DESTRUCTIVE;
- omap_rfbi_configure(dssdev, 16, 8);
+ omapdss_rfbi_set_pixel_size(dssdev, 16);
+ omapdss_rfbi_set_data_lines(dssdev, 8);
+
+ omap_rfbi_configure(dssdev);
blizzard_write(BLIZZARD_INPUT_WIN_X_START_0, tmp, 18);
- omap_rfbi_configure(dssdev, 16, 16);
+ omapdss_rfbi_set_pixel_size(dssdev, 16);
+ omapdss_rfbi_set_data_lines(dssdev, 16);
+
+ omap_rfbi_configure(dssdev);
}
static void mipid_transfer(struct spi_device *spi, int cmd, const u8 *wbuf,
@@ -297,6 +303,12 @@ static int n8x0_panel_power_on(struct omap_dss_device *dssdev)
goto err_plat_en;
}
+ omapdss_rfbi_set_size(dssdev, dssdev->panel.timings.x_res,
+ dssdev->panel.timings.y_res);
+ omapdss_rfbi_set_pixel_size(dssdev, dssdev->ctrl.pixel_size);
+ omapdss_rfbi_set_data_lines(dssdev, dssdev->phy.rfbi.data_lines);
+ omapdss_rfbi_set_interface_timings(dssdev, &dssdev->ctrl.rfbi_timings);
+
r = omapdss_rfbi_display_enable(dssdev);
if (r)
goto err_rfbi_en;
@@ -477,6 +489,7 @@ static int n8x0_panel_probe(struct omap_dss_device *dssdev)
dssdev->panel.timings.y_res = 480;
dssdev->ctrl.pixel_size = 16;
dssdev->ctrl.rfbi_timings = n8x0_panel_timings;
+ dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE;
memset(&props, 0, sizeof(props));
props.max_brightness = 127;
@@ -625,17 +638,25 @@ static int n8x0_panel_update(struct omap_dss_device *dssdev,
u16 x, u16 y, u16 w, u16 h)
{
struct panel_drv_data *ddata = get_drv_data(dssdev);
+ u16 dw, dh;
dev_dbg(&dssdev->dev, "update\n");
+ dw = dssdev->panel.timings.x_res;
+ dh = dssdev->panel.timings.y_res;
+
+ if (x != 0 || y != 0 || w != dw || h != dh) {
+ dev_err(&dssdev->dev, "invaid update region %d, %d, %d, %d\n",
+ x, y, w, h);
+ return -EINVAL;
+ }
+
mutex_lock(&ddata->lock);
rfbi_bus_lock();
- omap_rfbi_prepare_update(dssdev, &x, &y, &w, &h);
-
blizzard_ctrl_setup_update(dssdev, x, y, w, h);
- omap_rfbi_update(dssdev, x, y, w, h, update_done, NULL);
+ omap_rfbi_update(dssdev, update_done, NULL);
mutex_unlock(&ddata->lock);
diff --git a/drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c b/drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c
index b122b0f..908fd26 100644
--- a/drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c
+++ b/drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c
@@ -175,6 +175,9 @@ static int nec_8048_panel_power_on(struct omap_dss_device *dssdev)
if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
return 0;
+ omapdss_dpi_set_timings(dssdev, &dssdev->panel.timings);
+ omapdss_dpi_set_data_lines(dssdev, dssdev->phy.dpi.data_lines);
+
r = omapdss_dpi_display_enable(dssdev);
if (r)
goto err0;
diff --git a/drivers/video/omap2/displays/panel-picodlp.c b/drivers/video/omap2/displays/panel-picodlp.c
index 2d35bd3..9df8764 100644
--- a/drivers/video/omap2/displays/panel-picodlp.c
+++ b/drivers/video/omap2/displays/panel-picodlp.c
@@ -377,6 +377,10 @@ static int picodlp_panel_power_on(struct omap_dss_device *dssdev)
* then only i2c commands can be successfully sent to dpp2600
*/
msleep(1000);
+
+ omapdss_dpi_set_timings(dssdev, &dssdev->panel.timings);
+ omapdss_dpi_set_data_lines(dssdev, dssdev->phy.dpi.data_lines);
+
r = omapdss_dpi_display_enable(dssdev);
if (r) {
dev_err(&dssdev->dev, "failed to enable DPI\n");
diff --git a/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c b/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c
index bd86ba9..1ec3b27 100644
--- a/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c
+++ b/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c
@@ -142,6 +142,9 @@ static int sharp_ls_power_on(struct omap_dss_device *dssdev)
if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
return 0;
+ omapdss_dpi_set_timings(dssdev, &dssdev->panel.timings);
+ omapdss_dpi_set_data_lines(dssdev, dssdev->phy.dpi.data_lines);
+
r = omapdss_dpi_display_enable(dssdev);
if (r)
goto err0;
diff --git a/drivers/video/omap2/displays/panel-taal.c b/drivers/video/omap2/displays/panel-taal.c
index 6b5e6e0..f2f6446 100644
--- a/drivers/video/omap2/displays/panel-taal.c
+++ b/drivers/video/omap2/displays/panel-taal.c
@@ -121,6 +121,18 @@ struct taal_data {
struct omap_dss_device *dssdev;
+ /* panel specific HW info */
+ struct panel_config *panel_config;
+
+ /* panel HW configuration from DT or platform data */
+ int reset_gpio;
+ int ext_te_gpio;
+
+ bool use_dsi_backlight;
+
+ struct omap_dsi_pin_config pin_config;
+
+ /* runtime variables */
bool enabled;
u8 rotate;
bool mirror;
@@ -145,16 +157,8 @@ struct taal_data {
bool ulps_enabled;
unsigned ulps_timeout;
struct delayed_work ulps_work;
-
- struct panel_config *panel_config;
};
-static inline struct nokia_dsi_panel_data
-*get_panel_data(const struct omap_dss_device *dssdev)
-{
- return (struct nokia_dsi_panel_data *) dssdev->data;
-}
-
static void taal_esd_work(struct work_struct *work);
static void taal_ulps_work(struct work_struct *work);
@@ -371,7 +375,6 @@ static void taal_cancel_ulps_work(struct omap_dss_device *dssdev)
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)
@@ -383,7 +386,8 @@ static int taal_enter_ulps(struct omap_dss_device *dssdev)
if (r)
goto err;
- disable_irq(gpio_to_irq(panel_data->ext_te_gpio));
+ if (gpio_is_valid(td->ext_te_gpio))
+ disable_irq(gpio_to_irq(td->ext_te_gpio));
omapdss_dsi_display_disable(dssdev, false, true);
@@ -405,7 +409,6 @@ err:
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)
@@ -425,7 +428,8 @@ static int taal_exit_ulps(struct omap_dss_device *dssdev)
goto err2;
}
- enable_irq(gpio_to_irq(panel_data->ext_te_gpio));
+ if (gpio_is_valid(td->ext_te_gpio))
+ enable_irq(gpio_to_irq(td->ext_te_gpio));
taal_queue_ulps_work(dssdev);
@@ -438,7 +442,8 @@ err2:
r = taal_panel_reset(dssdev);
if (!r) {
- enable_irq(gpio_to_irq(panel_data->ext_te_gpio));
+ if (gpio_is_valid(td->ext_te_gpio))
+ enable_irq(gpio_to_irq(td->ext_te_gpio));
td->ulps_enabled = false;
}
err1:
@@ -835,94 +840,135 @@ static struct attribute_group taal_attr_group = {
static void taal_hw_reset(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);
- if (panel_data->reset_gpio == -1)
+ if (!gpio_is_valid(td->reset_gpio))
return;
- gpio_set_value(panel_data->reset_gpio, 1);
+ gpio_set_value(td->reset_gpio, 1);
if (td->panel_config->reset_sequence.high)
udelay(td->panel_config->reset_sequence.high);
/* reset the panel */
- gpio_set_value(panel_data->reset_gpio, 0);
+ gpio_set_value(td->reset_gpio, 0);
/* assert reset */
if (td->panel_config->reset_sequence.low)
udelay(td->panel_config->reset_sequence.low);
- gpio_set_value(panel_data->reset_gpio, 1);
+ gpio_set_value(td->reset_gpio, 1);
/* wait after releasing reset */
if (td->panel_config->sleep.hw_reset)
msleep(td->panel_config->sleep.hw_reset);
}
+static void taal_probe_pdata(struct taal_data *td,
+ const struct nokia_dsi_panel_data *pdata)
+{
+ td->reset_gpio = pdata->reset_gpio;
+
+ if (pdata->use_ext_te)
+ td->ext_te_gpio = pdata->ext_te_gpio;
+ else
+ td->ext_te_gpio = -1;
+
+ td->esd_interval = pdata->esd_interval;
+ td->ulps_timeout = pdata->ulps_timeout;
+
+ td->use_dsi_backlight = pdata->use_dsi_backlight;
+
+ td->pin_config = pdata->pin_config;
+}
+
static int taal_probe(struct omap_dss_device *dssdev)
{
struct backlight_properties props;
struct taal_data *td;
struct backlight_device *bldev = NULL;
- struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev);
- struct panel_config *panel_config = NULL;
int r, i;
+ const char *panel_name;
dev_dbg(&dssdev->dev, "probe\n");
- if (!panel_data || !panel_data->name) {
- r = -EINVAL;
- goto err;
+ td = devm_kzalloc(&dssdev->dev, sizeof(*td), GFP_KERNEL);
+ if (!td)
+ return -ENOMEM;
+
+ dev_set_drvdata(&dssdev->dev, td);
+ td->dssdev = dssdev;
+
+ if (dssdev->data) {
+ const struct nokia_dsi_panel_data *pdata = dssdev->data;
+
+ taal_probe_pdata(td, pdata);
+
+ panel_name = pdata->name;
+ } else {
+ return -ENODEV;
}
+ if (panel_name == NULL)
+ return -EINVAL;
+
for (i = 0; i < ARRAY_SIZE(panel_configs); i++) {
- if (strcmp(panel_data->name, panel_configs[i].name) == 0) {
- panel_config = &panel_configs[i];
+ if (strcmp(panel_name, panel_configs[i].name) == 0) {
+ td->panel_config = &panel_configs[i];
break;
}
}
- if (!panel_config) {
- r = -EINVAL;
- goto err;
- }
+ if (!td->panel_config)
+ return -EINVAL;
- dssdev->panel.timings = panel_config->timings;
+ dssdev->panel.timings = td->panel_config->timings;
dssdev->panel.dsi_pix_fmt = OMAP_DSS_DSI_FMT_RGB888;
-
- td = kzalloc(sizeof(*td), GFP_KERNEL);
- if (!td) {
- r = -ENOMEM;
- goto err;
- }
- 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;
+ dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE |
+ OMAP_DSS_DISPLAY_CAP_TEAR_ELIM;
mutex_init(&td->lock);
atomic_set(&td->do_update, 0);
- 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;
+ if (gpio_is_valid(td->reset_gpio)) {
+ r = devm_gpio_request_one(&dssdev->dev, td->reset_gpio,
+ GPIOF_OUT_INIT_LOW, "taal rst");
+ if (r) {
+ dev_err(&dssdev->dev, "failed to request reset gpio\n");
+ return r;
+ }
}
- INIT_DEFERRABLE_WORK(&td->esd_work, taal_esd_work);
- INIT_DELAYED_WORK(&td->ulps_work, taal_ulps_work);
- dev_set_drvdata(&dssdev->dev, td);
+ if (gpio_is_valid(td->ext_te_gpio)) {
+ r = devm_gpio_request_one(&dssdev->dev, td->ext_te_gpio,
+ GPIOF_IN, "taal irq");
+ if (r) {
+ dev_err(&dssdev->dev, "GPIO request failed\n");
+ return r;
+ }
+
+ r = devm_request_irq(&dssdev->dev, gpio_to_irq(td->ext_te_gpio),
+ taal_te_isr,
+ IRQF_TRIGGER_RISING,
+ "taal vsync", dssdev);
- if (gpio_is_valid(panel_data->reset_gpio)) {
- r = gpio_request_one(panel_data->reset_gpio, GPIOF_OUT_INIT_LOW,
- "taal rst");
if (r) {
- dev_err(&dssdev->dev, "failed to request reset gpio\n");
- goto err_rst_gpio;
+ dev_err(&dssdev->dev, "IRQ request failed\n");
+ return r;
}
+
+ INIT_DEFERRABLE_WORK(&td->te_timeout_work,
+ taal_te_timeout_work_callback);
+
+ dev_dbg(&dssdev->dev, "Using GPIO TE\n");
}
+ td->workqueue = create_singlethread_workqueue("taal_esd");
+ if (td->workqueue == NULL) {
+ dev_err(&dssdev->dev, "can't create ESD workqueue\n");
+ return -ENOMEM;
+ }
+ INIT_DEFERRABLE_WORK(&td->esd_work, taal_esd_work);
+ INIT_DELAYED_WORK(&td->ulps_work, taal_ulps_work);
+
taal_hw_reset(dssdev);
- if (panel_data->use_dsi_backlight) {
+ if (td->use_dsi_backlight) {
memset(&props, 0, sizeof(struct backlight_properties));
props.max_brightness = 255;
@@ -943,31 +989,6 @@ static int taal_probe(struct omap_dss_device *dssdev)
taal_bl_update_status(bldev);
}
- if (panel_data->use_ext_te) {
- int gpio = panel_data->ext_te_gpio;
-
- r = gpio_request_one(gpio, GPIOF_IN, "taal irq");
- if (r) {
- dev_err(&dssdev->dev, "GPIO request failed\n");
- goto err_gpio;
- }
-
- r = request_irq(gpio_to_irq(gpio), taal_te_isr,
- IRQF_TRIGGER_RISING,
- "taal vsync", dssdev);
-
- if (r) {
- dev_err(&dssdev->dev, "IRQ request failed\n");
- gpio_free(gpio);
- goto err_irq;
- }
-
- INIT_DEFERRABLE_WORK(&td->te_timeout_work,
- taal_te_timeout_work_callback);
-
- dev_dbg(&dssdev->dev, "Using GPIO TE\n");
- }
-
r = omap_dsi_request_vc(dssdev, &td->channel);
if (r) {
dev_err(&dssdev->dev, "failed to get virtual channel\n");
@@ -991,29 +1012,16 @@ static int taal_probe(struct omap_dss_device *dssdev)
err_vc_id:
omap_dsi_release_vc(dssdev, td->channel);
err_req_vc:
- if (panel_data->use_ext_te)
- free_irq(gpio_to_irq(panel_data->ext_te_gpio), dssdev);
-err_irq:
- if (panel_data->use_ext_te)
- gpio_free(panel_data->ext_te_gpio);
-err_gpio:
if (bldev != NULL)
backlight_device_unregister(bldev);
err_bl:
- if (gpio_is_valid(panel_data->reset_gpio))
- gpio_free(panel_data->reset_gpio);
-err_rst_gpio:
destroy_workqueue(td->workqueue);
-err_wq:
- kfree(td);
-err:
return r;
}
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);
struct backlight_device *bldev;
dev_dbg(&dssdev->dev, "remove\n");
@@ -1021,12 +1029,6 @@ static void __exit taal_remove(struct omap_dss_device *dssdev)
sysfs_remove_group(&dssdev->dev.kobj, &taal_attr_group);
omap_dsi_release_vc(dssdev, td->channel);
- if (panel_data->use_ext_te) {
- int gpio = panel_data->ext_te_gpio;
- free_irq(gpio_to_irq(gpio), dssdev);
- gpio_free(gpio);
- }
-
bldev = td->bldev;
if (bldev != NULL) {
bldev->props.power = FB_BLANK_POWERDOWN;
@@ -1040,26 +1042,31 @@ static void __exit taal_remove(struct omap_dss_device *dssdev)
/* reset, to be sure that the panel is in a valid state */
taal_hw_reset(dssdev);
-
- if (gpio_is_valid(panel_data->reset_gpio))
- gpio_free(panel_data->reset_gpio);
-
- kfree(td);
}
static int taal_power_on(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);
u8 id1, id2, id3;
int r;
- r = omapdss_dsi_configure_pins(dssdev, &panel_data->pin_config);
+ r = omapdss_dsi_configure_pins(dssdev, &td->pin_config);
if (r) {
dev_err(&dssdev->dev, "failed to configure DSI pins\n");
goto err0;
};
+ omapdss_dsi_set_size(dssdev, dssdev->panel.timings.x_res,
+ dssdev->panel.timings.y_res);
+ omapdss_dsi_set_pixel_format(dssdev, OMAP_DSS_DSI_FMT_RGB888);
+ omapdss_dsi_set_operation_mode(dssdev, OMAP_DSS_DSI_CMD_MODE);
+
+ r = omapdss_dsi_set_clocks(dssdev, 216000000, 10000000);
+ if (r) {
+ dev_err(&dssdev->dev, "failed to set HS and LP clocks\n");
+ goto err0;
+ }
+
r = omapdss_dsi_display_enable(dssdev);
if (r) {
dev_err(&dssdev->dev, "failed to enable DSI\n");
@@ -1356,7 +1363,6 @@ static int taal_update(struct omap_dss_device *dssdev,
u16 x, u16 y, u16 w, u16 h)
{
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, "update %d, %d, %d x %d\n", x, y, w, h);
@@ -1380,7 +1386,7 @@ static int taal_update(struct omap_dss_device *dssdev,
if (r)
goto err;
- if (td->te_enabled && panel_data->use_ext_te) {
+ if (td->te_enabled && gpio_is_valid(td->ext_te_gpio)) {
schedule_delayed_work(&td->te_timeout_work,
msecs_to_jiffies(250));
atomic_set(&td->do_update, 1);
@@ -1419,7 +1425,6 @@ static int taal_sync(struct omap_dss_device *dssdev)
static int _taal_enable_te(struct omap_dss_device *dssdev, bool enable)
{
struct taal_data *td = dev_get_drvdata(&dssdev->dev);
- struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev);
int r;
if (enable)
@@ -1427,7 +1432,7 @@ static int _taal_enable_te(struct omap_dss_device *dssdev, bool enable)
else
r = taal_dcs_write_0(td, MIPI_DCS_SET_TEAR_OFF);
- if (!panel_data->use_ext_te)
+ if (!gpio_is_valid(td->ext_te_gpio))
omapdss_dsi_enable_te(dssdev, enable);
if (td->panel_config->sleep.enable_te)
@@ -1487,6 +1492,7 @@ static int taal_get_te(struct omap_dss_device *dssdev)
static int taal_rotate(struct omap_dss_device *dssdev, u8 rotate)
{
struct taal_data *td = dev_get_drvdata(&dssdev->dev);
+ u16 dw, dh;
int r;
dev_dbg(&dssdev->dev, "rotate %d\n", rotate);
@@ -1508,6 +1514,16 @@ static int taal_rotate(struct omap_dss_device *dssdev, u8 rotate)
goto err;
}
+ if (rotate == 0 || rotate == 2) {
+ dw = dssdev->panel.timings.x_res;
+ dh = dssdev->panel.timings.y_res;
+ } else {
+ dw = dssdev->panel.timings.y_res;
+ dh = dssdev->panel.timings.x_res;
+ }
+
+ omapdss_dsi_set_size(dssdev, dw, dh);
+
td->rotate = rotate;
dsi_bus_unlock(dssdev);
@@ -1726,7 +1742,6 @@ static void taal_esd_work(struct work_struct *work)
struct taal_data *td = container_of(work, struct taal_data,
esd_work.work);
struct omap_dss_device *dssdev = td->dssdev;
- struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev);
u8 state1, state2;
int r;
@@ -1773,7 +1788,7 @@ static void taal_esd_work(struct work_struct *work)
}
/* Self-diagnostics result is also shown on TE GPIO line. We need
* to re-enable TE after self diagnostics */
- if (td->te_enabled && panel_data->use_ext_te) {
+ if (td->te_enabled && gpio_is_valid(td->ext_te_gpio)) {
r = taal_dcs_write_1(td, MIPI_DCS_SET_TEAR_ON, 0);
if (r)
goto err;
diff --git a/drivers/video/omap2/displays/panel-tfp410.c b/drivers/video/omap2/displays/panel-tfp410.c
index 40cc0cfa..383811c 100644
--- a/drivers/video/omap2/displays/panel-tfp410.c
+++ b/drivers/video/omap2/displays/panel-tfp410.c
@@ -65,6 +65,9 @@ static int tfp410_power_on(struct omap_dss_device *dssdev)
if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
return 0;
+ omapdss_dpi_set_timings(dssdev, &dssdev->panel.timings);
+ omapdss_dpi_set_data_lines(dssdev, dssdev->phy.dpi.data_lines);
+
r = omapdss_dpi_display_enable(dssdev);
if (r)
goto err0;
@@ -116,8 +119,8 @@ static int tfp410_probe(struct omap_dss_device *dssdev)
}
if (gpio_is_valid(ddata->pd_gpio)) {
- r = gpio_request_one(ddata->pd_gpio, GPIOF_OUT_INIT_LOW,
- "tfp410 pd");
+ r = devm_gpio_request_one(&dssdev->dev, ddata->pd_gpio,
+ GPIOF_OUT_INIT_LOW, "tfp410 pd");
if (r) {
dev_err(&dssdev->dev, "Failed to request PD GPIO %d\n",
ddata->pd_gpio);
@@ -132,8 +135,7 @@ static int tfp410_probe(struct omap_dss_device *dssdev)
if (!adapter) {
dev_err(&dssdev->dev, "Failed to get I2C adapter, bus %d\n",
i2c_bus_num);
- r = -EINVAL;
- goto err_i2c;
+ return -EINVAL;
}
ddata->i2c_adapter = adapter;
@@ -142,10 +144,6 @@ static int tfp410_probe(struct omap_dss_device *dssdev)
dev_set_drvdata(&dssdev->dev, ddata);
return 0;
-err_i2c:
- if (gpio_is_valid(ddata->pd_gpio))
- gpio_free(ddata->pd_gpio);
- return r;
}
static void __exit tfp410_remove(struct omap_dss_device *dssdev)
@@ -157,9 +155,6 @@ static void __exit tfp410_remove(struct omap_dss_device *dssdev)
if (ddata->i2c_adapter)
i2c_put_adapter(ddata->i2c_adapter);
- if (gpio_is_valid(ddata->pd_gpio))
- gpio_free(ddata->pd_gpio);
-
dev_set_drvdata(&dssdev->dev, NULL);
mutex_unlock(&ddata->lock);
@@ -231,7 +226,8 @@ static void tfp410_set_timings(struct omap_dss_device *dssdev,
struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
mutex_lock(&ddata->lock);
- dpi_set_timings(dssdev, timings);
+ omapdss_dpi_set_timings(dssdev, timings);
+ dssdev->panel.timings = *timings;
mutex_unlock(&ddata->lock);
}
diff --git a/drivers/video/omap2/displays/panel-tpo-td043mtea1.c b/drivers/video/omap2/displays/panel-tpo-td043mtea1.c
index fa7baa6..b5e6dbc 100644
--- a/drivers/video/omap2/displays/panel-tpo-td043mtea1.c
+++ b/drivers/video/omap2/displays/panel-tpo-td043mtea1.c
@@ -337,6 +337,9 @@ static int tpo_td043_enable_dss(struct omap_dss_device *dssdev)
if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
return 0;
+ omapdss_dpi_set_timings(dssdev, &dssdev->panel.timings);
+ omapdss_dpi_set_data_lines(dssdev, dssdev->phy.dpi.data_lines);
+
r = omapdss_dpi_display_enable(dssdev);
if (r)
goto err0;
@@ -480,7 +483,9 @@ static void tpo_td043_remove(struct omap_dss_device *dssdev)
static void tpo_td043_set_timings(struct omap_dss_device *dssdev,
struct omap_video_timings *timings)
{
- dpi_set_timings(dssdev, timings);
+ omapdss_dpi_set_timings(dssdev, timings);
+
+ dssdev->panel.timings = *timings;
}
static int tpo_td043_check_timings(struct omap_dss_device *dssdev,
diff --git a/drivers/video/omap2/dss/Kconfig b/drivers/video/omap2/dss/Kconfig
index b337a84..80f5390 100644
--- a/drivers/video/omap2/dss/Kconfig
+++ b/drivers/video/omap2/dss/Kconfig
@@ -84,7 +84,7 @@ config OMAP2_DSS_SDI
config OMAP2_DSS_DSI
bool "DSI support"
- depends on ARCH_OMAP3 || ARCH_OMAP4
+ depends on ARCH_OMAP3 || ARCH_OMAP4 || ARCH_OMAP5
default n
help
MIPI DSI (Display Serial Interface) support.
diff --git a/drivers/video/omap2/dss/Makefile b/drivers/video/omap2/dss/Makefile
index 5c450b0..4549869 100644
--- a/drivers/video/omap2/dss/Makefile
+++ b/drivers/video/omap2/dss/Makefile
@@ -1,9 +1,9 @@
obj-$(CONFIG_OMAP2_DSS) += omapdss.o
omapdss-y := core.o dss.o dss_features.o dispc.o dispc_coefs.o display.o \
- manager.o overlay.o apply.o
+ manager.o manager-sysfs.o overlay.o overlay-sysfs.o output.o apply.o
omapdss-$(CONFIG_OMAP2_DSS_DPI) += dpi.o
omapdss-$(CONFIG_OMAP2_DSS_RFBI) += rfbi.o
-omapdss-$(CONFIG_OMAP2_DSS_VENC) += venc.o
+omapdss-$(CONFIG_OMAP2_DSS_VENC) += venc.o venc_panel.o
omapdss-$(CONFIG_OMAP2_DSS_SDI) += sdi.o
omapdss-$(CONFIG_OMAP2_DSS_DSI) += dsi.o
omapdss-$(CONFIG_OMAP4_DSS_HDMI) += hdmi.o \
diff --git a/drivers/video/omap2/dss/apply.c b/drivers/video/omap2/dss/apply.c
index 0fefc68..19d66f4 100644
--- a/drivers/video/omap2/dss/apply.c
+++ b/drivers/video/omap2/dss/apply.c
@@ -111,9 +111,6 @@ static struct {
struct ovl_priv_data ovl_priv_data_array[MAX_DSS_OVERLAYS];
struct mgr_priv_data mgr_priv_data_array[MAX_DSS_MANAGERS];
- bool fifo_merge_dirty;
- bool fifo_merge;
-
bool irq_enabled;
} dss_data;
@@ -424,17 +421,25 @@ static void wait_pending_extra_info_updates(void)
int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr)
{
unsigned long timeout = msecs_to_jiffies(500);
- struct mgr_priv_data *mp;
+ struct mgr_priv_data *mp = get_mgr_priv(mgr);
u32 irq;
+ unsigned long flags;
int r;
int i;
- struct omap_dss_device *dssdev = mgr->device;
- if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
+ spin_lock_irqsave(&data_lock, flags);
+
+ if (mgr_manual_update(mgr)) {
+ spin_unlock_irqrestore(&data_lock, flags);
return 0;
+ }
- if (mgr_manual_update(mgr))
+ if (!mp->enabled) {
+ spin_unlock_irqrestore(&data_lock, flags);
return 0;
+ }
+
+ spin_unlock_irqrestore(&data_lock, flags);
r = dispc_runtime_get();
if (r)
@@ -442,10 +447,8 @@ int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr)
irq = dispc_mgr_get_vsync_irq(mgr->id);
- mp = get_mgr_priv(mgr);
i = 0;
while (1) {
- unsigned long flags;
bool shadow_dirty, dirty;
spin_lock_irqsave(&data_lock, flags);
@@ -489,21 +492,30 @@ int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl)
{
unsigned long timeout = msecs_to_jiffies(500);
struct ovl_priv_data *op;
- struct omap_dss_device *dssdev;
+ struct mgr_priv_data *mp;
u32 irq;
+ unsigned long flags;
int r;
int i;
if (!ovl->manager)
return 0;
- dssdev = ovl->manager->device;
+ mp = get_mgr_priv(ovl->manager);
+
+ spin_lock_irqsave(&data_lock, flags);
- if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
+ if (ovl_manual_update(ovl)) {
+ spin_unlock_irqrestore(&data_lock, flags);
return 0;
+ }
- if (ovl_manual_update(ovl))
+ if (!mp->enabled) {
+ spin_unlock_irqrestore(&data_lock, flags);
return 0;
+ }
+
+ spin_unlock_irqrestore(&data_lock, flags);
r = dispc_runtime_get();
if (r)
@@ -514,7 +526,6 @@ int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl)
op = get_ovl_priv(ovl);
i = 0;
while (1) {
- unsigned long flags;
bool shadow_dirty, dirty;
spin_lock_irqsave(&data_lock, flags);
@@ -573,7 +584,7 @@ static void dss_ovl_write_regs(struct omap_overlay *ovl)
replication = dss_ovl_use_replication(mp->lcd_config, oi->color_mode);
- r = dispc_ovl_setup(ovl->id, oi, replication, &mp->timings);
+ r = dispc_ovl_setup(ovl->id, oi, replication, &mp->timings, false);
if (r) {
/*
* We can't do much here, as this function can be called from
@@ -677,40 +688,11 @@ static void dss_mgr_write_regs_extra(struct omap_overlay_manager *mgr)
mp->shadow_extra_info_dirty = true;
}
-static void dss_write_regs_common(void)
-{
- const int num_mgrs = omap_dss_get_num_overlay_managers();
- int i;
-
- if (!dss_data.fifo_merge_dirty)
- return;
-
- for (i = 0; i < num_mgrs; ++i) {
- struct omap_overlay_manager *mgr;
- struct mgr_priv_data *mp;
-
- mgr = omap_dss_get_overlay_manager(i);
- mp = get_mgr_priv(mgr);
-
- if (mp->enabled) {
- if (dss_data.fifo_merge_dirty) {
- dispc_enable_fifomerge(dss_data.fifo_merge);
- dss_data.fifo_merge_dirty = false;
- }
-
- if (mp->updating)
- mp->shadow_info_dirty = true;
- }
- }
-}
-
static void dss_write_regs(void)
{
const int num_mgrs = omap_dss_get_num_overlay_managers();
int i;
- dss_write_regs_common();
-
for (i = 0; i < num_mgrs; ++i) {
struct omap_overlay_manager *mgr;
struct mgr_priv_data *mp;
@@ -799,8 +781,6 @@ void dss_mgr_start_update(struct omap_overlay_manager *mgr)
dss_mgr_write_regs(mgr);
dss_mgr_write_regs_extra(mgr);
- dss_write_regs_common();
-
mp->updating = true;
if (!dss_data.irq_enabled && need_isr())
@@ -984,20 +964,11 @@ static void dss_apply_ovl_fifo_thresholds(struct omap_overlay *ovl,
op->extra_info_dirty = true;
}
-static void dss_apply_fifo_merge(bool use_fifo_merge)
-{
- if (dss_data.fifo_merge == use_fifo_merge)
- return;
-
- dss_data.fifo_merge = use_fifo_merge;
- dss_data.fifo_merge_dirty = true;
-}
-
-static void dss_ovl_setup_fifo(struct omap_overlay *ovl,
- bool use_fifo_merge)
+static void dss_ovl_setup_fifo(struct omap_overlay *ovl)
{
struct ovl_priv_data *op = get_ovl_priv(ovl);
u32 fifo_low, fifo_high;
+ bool use_fifo_merge = false;
if (!op->enabled && !op->enabling)
return;
@@ -1008,8 +979,7 @@ static void dss_ovl_setup_fifo(struct omap_overlay *ovl,
dss_apply_ovl_fifo_thresholds(ovl, fifo_low, fifo_high);
}
-static void dss_mgr_setup_fifos(struct omap_overlay_manager *mgr,
- bool use_fifo_merge)
+static void dss_mgr_setup_fifos(struct omap_overlay_manager *mgr)
{
struct omap_overlay *ovl;
struct mgr_priv_data *mp;
@@ -1020,94 +990,19 @@ static void dss_mgr_setup_fifos(struct omap_overlay_manager *mgr,
return;
list_for_each_entry(ovl, &mgr->overlays, list)
- dss_ovl_setup_fifo(ovl, use_fifo_merge);
-}
-
-static void dss_setup_fifos(bool use_fifo_merge)
-{
- const int num_mgrs = omap_dss_get_num_overlay_managers();
- struct omap_overlay_manager *mgr;
- int i;
-
- for (i = 0; i < num_mgrs; ++i) {
- mgr = omap_dss_get_overlay_manager(i);
- dss_mgr_setup_fifos(mgr, use_fifo_merge);
- }
+ dss_ovl_setup_fifo(ovl);
}
-static int get_num_used_managers(void)
+static void dss_setup_fifos(void)
{
const int num_mgrs = omap_dss_get_num_overlay_managers();
struct omap_overlay_manager *mgr;
- struct mgr_priv_data *mp;
int i;
- int enabled_mgrs;
-
- enabled_mgrs = 0;
for (i = 0; i < num_mgrs; ++i) {
mgr = omap_dss_get_overlay_manager(i);
- mp = get_mgr_priv(mgr);
-
- if (!mp->enabled)
- continue;
-
- enabled_mgrs++;
+ dss_mgr_setup_fifos(mgr);
}
-
- return enabled_mgrs;
-}
-
-static int get_num_used_overlays(void)
-{
- const int num_ovls = omap_dss_get_num_overlays();
- struct omap_overlay *ovl;
- struct ovl_priv_data *op;
- struct mgr_priv_data *mp;
- int i;
- int enabled_ovls;
-
- enabled_ovls = 0;
-
- for (i = 0; i < num_ovls; ++i) {
- ovl = omap_dss_get_overlay(i);
- op = get_ovl_priv(ovl);
-
- if (!op->enabled && !op->enabling)
- continue;
-
- mp = get_mgr_priv(ovl->manager);
-
- if (!mp->enabled)
- continue;
-
- enabled_ovls++;
- }
-
- return enabled_ovls;
-}
-
-static bool get_use_fifo_merge(void)
-{
- int enabled_mgrs = get_num_used_managers();
- int enabled_ovls = get_num_used_overlays();
-
- if (!dss_has_feature(FEAT_FIFO_MERGE))
- return false;
-
- /*
- * In theory the only requirement for fifomerge is enabled_ovls <= 1.
- * However, if we have two managers enabled and set/unset the fifomerge,
- * we need to set the GO bits in particular sequence for the managers,
- * and wait in between.
- *
- * This is rather difficult as new apply calls can happen at any time,
- * so we simplify the problem by requiring also that enabled_mgrs <= 1.
- * In practice this shouldn't matter, because when only one overlay is
- * enabled, most likely only one output is enabled.
- */
-
- return enabled_mgrs <= 1 && enabled_ovls <= 1;
}
int dss_mgr_enable(struct omap_overlay_manager *mgr)
@@ -1115,7 +1010,6 @@ int dss_mgr_enable(struct omap_overlay_manager *mgr)
struct mgr_priv_data *mp = get_mgr_priv(mgr);
unsigned long flags;
int r;
- bool fifo_merge;
mutex_lock(&apply_lock);
@@ -1133,23 +1027,11 @@ int dss_mgr_enable(struct omap_overlay_manager *mgr)
goto err;
}
- /* step 1: setup fifos/fifomerge before enabling the manager */
-
- fifo_merge = get_use_fifo_merge();
- dss_setup_fifos(fifo_merge);
- dss_apply_fifo_merge(fifo_merge);
+ dss_setup_fifos();
dss_write_regs();
dss_set_go_bits();
- spin_unlock_irqrestore(&data_lock, flags);
-
- /* wait until fifo config is in */
- wait_pending_extra_info_updates();
-
- /* step 2: enable the manager */
- spin_lock_irqsave(&data_lock, flags);
-
if (!mgr_manual_update(mgr))
mp->updating = true;
@@ -1174,7 +1056,6 @@ void dss_mgr_disable(struct omap_overlay_manager *mgr)
{
struct mgr_priv_data *mp = get_mgr_priv(mgr);
unsigned long flags;
- bool fifo_merge;
mutex_lock(&apply_lock);
@@ -1189,16 +1070,8 @@ void dss_mgr_disable(struct omap_overlay_manager *mgr)
mp->updating = false;
mp->enabled = false;
- fifo_merge = get_use_fifo_merge();
- dss_setup_fifos(fifo_merge);
- dss_apply_fifo_merge(fifo_merge);
-
- dss_write_regs();
- dss_set_go_bits();
-
spin_unlock_irqrestore(&data_lock, flags);
- wait_pending_extra_info_updates();
out:
mutex_unlock(&apply_lock);
}
@@ -1237,29 +1110,29 @@ void dss_mgr_get_info(struct omap_overlay_manager *mgr,
spin_unlock_irqrestore(&data_lock, flags);
}
-int dss_mgr_set_device(struct omap_overlay_manager *mgr,
- struct omap_dss_device *dssdev)
+int dss_mgr_set_output(struct omap_overlay_manager *mgr,
+ struct omap_dss_output *output)
{
int r;
mutex_lock(&apply_lock);
- if (dssdev->manager) {
- DSSERR("display '%s' already has a manager '%s'\n",
- dssdev->name, dssdev->manager->name);
+ if (mgr->output) {
+ DSSERR("manager %s is already connected to an output\n",
+ mgr->name);
r = -EINVAL;
goto err;
}
- if ((mgr->supported_displays & dssdev->type) == 0) {
- DSSERR("display '%s' does not support manager '%s'\n",
- dssdev->name, mgr->name);
+ if ((mgr->supported_outputs & output->id) == 0) {
+ DSSERR("output does not support manager %s\n",
+ mgr->name);
r = -EINVAL;
goto err;
}
- dssdev->manager = mgr;
- mgr->device = dssdev;
+ output->manager = mgr;
+ mgr->output = output;
mutex_unlock(&apply_lock);
@@ -1269,40 +1142,46 @@ err:
return r;
}
-int dss_mgr_unset_device(struct omap_overlay_manager *mgr)
+int dss_mgr_unset_output(struct omap_overlay_manager *mgr)
{
int r;
+ struct mgr_priv_data *mp = get_mgr_priv(mgr);
+ unsigned long flags;
mutex_lock(&apply_lock);
- if (!mgr->device) {
- DSSERR("failed to unset display, display not set.\n");
+ if (!mgr->output) {
+ DSSERR("failed to unset output, output not set\n");
r = -EINVAL;
goto err;
}
- /*
- * Don't allow currently enabled displays to have the overlay manager
- * pulled out from underneath them
- */
- if (mgr->device->state != OMAP_DSS_DISPLAY_DISABLED) {
+ spin_lock_irqsave(&data_lock, flags);
+
+ if (mp->enabled) {
+ DSSERR("output can't be unset when manager is enabled\n");
r = -EINVAL;
- goto err;
+ goto err1;
}
- mgr->device->manager = NULL;
- mgr->device = NULL;
+ spin_unlock_irqrestore(&data_lock, flags);
+
+ mgr->output->manager = NULL;
+ mgr->output = NULL;
mutex_unlock(&apply_lock);
return 0;
+err1:
+ spin_unlock_irqrestore(&data_lock, flags);
err:
mutex_unlock(&apply_lock);
+
return r;
}
static void dss_apply_mgr_timings(struct omap_overlay_manager *mgr,
- struct omap_video_timings *timings)
+ const struct omap_video_timings *timings)
{
struct mgr_priv_data *mp = get_mgr_priv(mgr);
@@ -1311,24 +1190,22 @@ static void dss_apply_mgr_timings(struct omap_overlay_manager *mgr,
}
void dss_mgr_set_timings(struct omap_overlay_manager *mgr,
- struct omap_video_timings *timings)
+ const struct omap_video_timings *timings)
{
unsigned long flags;
-
- mutex_lock(&apply_lock);
+ struct mgr_priv_data *mp = get_mgr_priv(mgr);
spin_lock_irqsave(&data_lock, flags);
- dss_apply_mgr_timings(mgr, timings);
-
- dss_write_regs();
- dss_set_go_bits();
+ if (mp->updating) {
+ DSSERR("cannot set timings for %s: manager needs to be disabled\n",
+ mgr->name);
+ goto out;
+ }
+ dss_apply_mgr_timings(mgr, timings);
+out:
spin_unlock_irqrestore(&data_lock, flags);
-
- wait_pending_extra_info_updates();
-
- mutex_unlock(&apply_lock);
}
static void dss_apply_mgr_lcd_config(struct omap_overlay_manager *mgr,
@@ -1346,7 +1223,7 @@ void dss_mgr_set_lcd_config(struct omap_overlay_manager *mgr,
unsigned long flags;
struct mgr_priv_data *mp = get_mgr_priv(mgr);
- mutex_lock(&apply_lock);
+ spin_lock_irqsave(&data_lock, flags);
if (mp->enabled) {
DSSERR("cannot apply lcd config for %s: manager needs to be disabled\n",
@@ -1354,19 +1231,9 @@ void dss_mgr_set_lcd_config(struct omap_overlay_manager *mgr,
goto out;
}
- spin_lock_irqsave(&data_lock, flags);
-
dss_apply_mgr_lcd_config(mgr, config);
-
- dss_write_regs();
- dss_set_go_bits();
-
- spin_unlock_irqrestore(&data_lock, flags);
-
- wait_pending_extra_info_updates();
-
out:
- mutex_unlock(&apply_lock);
+ spin_unlock_irqrestore(&data_lock, flags);
}
int dss_ovl_set_info(struct omap_overlay *ovl,
@@ -1483,6 +1350,13 @@ int dss_ovl_unset_manager(struct omap_overlay *ovl)
goto err;
}
+ spin_unlock_irqrestore(&data_lock, flags);
+
+ /* wait for pending extra_info updates to ensure the ovl is disabled */
+ wait_pending_extra_info_updates();
+
+ spin_lock_irqsave(&data_lock, flags);
+
op->channel = -1;
ovl->manager = NULL;
@@ -1517,7 +1391,6 @@ int dss_ovl_enable(struct omap_overlay *ovl)
{
struct ovl_priv_data *op = get_ovl_priv(ovl);
unsigned long flags;
- bool fifo_merge;
int r;
mutex_lock(&apply_lock);
@@ -1527,7 +1400,7 @@ int dss_ovl_enable(struct omap_overlay *ovl)
goto err1;
}
- if (ovl->manager == NULL || ovl->manager->device == NULL) {
+ if (ovl->manager == NULL || ovl->manager->output == NULL) {
r = -EINVAL;
goto err1;
}
@@ -1543,22 +1416,7 @@ int dss_ovl_enable(struct omap_overlay *ovl)
goto err2;
}
- /* step 1: configure fifos/fifomerge for currently enabled ovls */
-
- fifo_merge = get_use_fifo_merge();
- dss_setup_fifos(fifo_merge);
- dss_apply_fifo_merge(fifo_merge);
-
- dss_write_regs();
- dss_set_go_bits();
-
- spin_unlock_irqrestore(&data_lock, flags);
-
- /* wait for fifo configs to go in */
- wait_pending_extra_info_updates();
-
- /* step 2: enable the overlay */
- spin_lock_irqsave(&data_lock, flags);
+ dss_setup_fifos();
op->enabling = false;
dss_apply_ovl_enable(ovl, true);
@@ -1568,9 +1426,6 @@ int dss_ovl_enable(struct omap_overlay *ovl)
spin_unlock_irqrestore(&data_lock, flags);
- /* wait for overlay to be enabled */
- wait_pending_extra_info_updates();
-
mutex_unlock(&apply_lock);
return 0;
@@ -1586,7 +1441,6 @@ int dss_ovl_disable(struct omap_overlay *ovl)
{
struct ovl_priv_data *op = get_ovl_priv(ovl);
unsigned long flags;
- bool fifo_merge;
int r;
mutex_lock(&apply_lock);
@@ -1596,39 +1450,19 @@ int dss_ovl_disable(struct omap_overlay *ovl)
goto err;
}
- if (ovl->manager == NULL || ovl->manager->device == NULL) {
+ if (ovl->manager == NULL || ovl->manager->output == NULL) {
r = -EINVAL;
goto err;
}
- /* step 1: disable the overlay */
spin_lock_irqsave(&data_lock, flags);
dss_apply_ovl_enable(ovl, false);
-
dss_write_regs();
dss_set_go_bits();
spin_unlock_irqrestore(&data_lock, flags);
- /* wait for the overlay to be disabled */
- wait_pending_extra_info_updates();
-
- /* step 2: configure fifos/fifomerge */
- spin_lock_irqsave(&data_lock, flags);
-
- fifo_merge = get_use_fifo_merge();
- dss_setup_fifos(fifo_merge);
- dss_apply_fifo_merge(fifo_merge);
-
- dss_write_regs();
- dss_set_go_bits();
-
- spin_unlock_irqrestore(&data_lock, flags);
-
- /* wait for fifo config to go in */
- wait_pending_extra_info_updates();
-
mutex_unlock(&apply_lock);
return 0;
diff --git a/drivers/video/omap2/dss/core.c b/drivers/video/omap2/dss/core.c
index 58bd9c2..b2af72d 100644
--- a/drivers/video/omap2/dss/core.c
+++ b/drivers/video/omap2/dss/core.c
@@ -33,6 +33,7 @@
#include <linux/device.h>
#include <linux/regulator/consumer.h>
#include <linux/suspend.h>
+#include <linux/slab.h>
#include <video/omapdss.h>
@@ -57,6 +58,11 @@ bool dss_debug;
module_param_named(debug, dss_debug, bool, 0644);
#endif
+const char *dss_get_default_display_name(void)
+{
+ return core.default_display_name;
+}
+
/* REGULATORS */
struct regulator *dss_get_vdds_dsi(void)
@@ -347,17 +353,14 @@ static int dss_driver_probe(struct device *dev)
int r;
struct omap_dss_driver *dssdrv = to_dss_driver(dev->driver);
struct omap_dss_device *dssdev = to_dss_device(dev);
- bool force;
DSSDBG("driver_probe: dev %s/%s, drv %s\n",
dev_name(dev), dssdev->driver_name,
dssdrv->driver.name);
- dss_init_device(core.pdev, dssdev);
-
- force = core.default_display_name &&
- strcmp(core.default_display_name, dssdev->name) == 0;
- dss_recheck_connections(dssdev, force);
+ r = dss_init_device(core.pdev, dssdev);
+ if (r)
+ return r;
r = dssdrv->probe(dssdev);
@@ -416,54 +419,44 @@ void omap_dss_unregister_driver(struct omap_dss_driver *dssdriver)
EXPORT_SYMBOL(omap_dss_unregister_driver);
/* DEVICE */
-static void reset_device(struct device *dev, int check)
-{
- u8 *dev_p = (u8 *)dev;
- u8 *dev_end = dev_p + sizeof(*dev);
- void *saved_pdata;
-
- saved_pdata = dev->platform_data;
- if (check) {
- /*
- * Check if there is any other setting than platform_data
- * in struct device; warn that these will be reset by our
- * init.
- */
- dev->platform_data = NULL;
- while (dev_p < dev_end) {
- if (*dev_p) {
- WARN("%s: struct device fields will be "
- "discarded\n",
- __func__);
- break;
- }
- dev_p++;
- }
- }
- memset(dev, 0, sizeof(*dev));
- dev->platform_data = saved_pdata;
-}
-
static void omap_dss_dev_release(struct device *dev)
{
- reset_device(dev, 0);
+ struct omap_dss_device *dssdev = to_dss_device(dev);
+ kfree(dssdev);
}
-int omap_dss_register_device(struct omap_dss_device *dssdev,
- struct device *parent, int disp_num)
+static int disp_num_counter;
+
+struct omap_dss_device *dss_alloc_and_init_device(struct device *parent)
{
- WARN_ON(!dssdev->driver_name);
+ struct omap_dss_device *dssdev;
+
+ dssdev = kzalloc(sizeof(*dssdev), GFP_KERNEL);
+ if (!dssdev)
+ return NULL;
- reset_device(&dssdev->dev, 1);
dssdev->dev.bus = &dss_bus_type;
dssdev->dev.parent = parent;
dssdev->dev.release = omap_dss_dev_release;
- dev_set_name(&dssdev->dev, "display%d", disp_num);
- return device_register(&dssdev->dev);
+ dev_set_name(&dssdev->dev, "display%d", disp_num_counter++);
+
+ device_initialize(&dssdev->dev);
+
+ return dssdev;
+}
+
+int dss_add_device(struct omap_dss_device *dssdev)
+{
+ return device_add(&dssdev->dev);
+}
+
+void dss_put_device(struct omap_dss_device *dssdev)
+{
+ put_device(&dssdev->dev);
}
-void omap_dss_unregister_device(struct omap_dss_device *dssdev)
+void dss_unregister_device(struct omap_dss_device *dssdev)
{
device_unregister(&dssdev->dev);
}
@@ -471,15 +464,25 @@ void omap_dss_unregister_device(struct omap_dss_device *dssdev)
static int dss_unregister_dss_dev(struct device *dev, void *data)
{
struct omap_dss_device *dssdev = to_dss_device(dev);
- omap_dss_unregister_device(dssdev);
+ dss_unregister_device(dssdev);
return 0;
}
-void omap_dss_unregister_child_devices(struct device *parent)
+void dss_unregister_child_devices(struct device *parent)
{
device_for_each_child(parent, NULL, dss_unregister_dss_dev);
}
+void dss_copy_device_pdata(struct omap_dss_device *dst,
+ const struct omap_dss_device *src)
+{
+ u8 *d = (u8 *)dst;
+ u8 *s = (u8 *)src;
+ size_t dsize = sizeof(struct device);
+
+ memcpy(d + dsize, s + dsize, sizeof(struct omap_dss_device) - dsize);
+}
+
/* BUS */
static int __init omap_dss_bus_register(void)
{
diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c
index ee9e296..b43477a 100644
--- a/drivers/video/omap2/dss/dispc.c
+++ b/drivers/video/omap2/dss/dispc.c
@@ -38,7 +38,6 @@
#include <linux/pm_runtime.h>
#include <plat/cpu.h>
-#include <plat/clock.h>
#include <video/omapdss.h>
@@ -82,6 +81,30 @@ struct dispc_irq_stats {
unsigned irqs[32];
};
+struct dispc_features {
+ u8 sw_start;
+ u8 fp_start;
+ u8 bp_start;
+ u16 sw_max;
+ u16 vp_max;
+ u16 hp_max;
+ int (*calc_scaling) (enum omap_plane plane,
+ const struct omap_video_timings *mgr_timings,
+ u16 width, u16 height, u16 out_width, u16 out_height,
+ enum omap_color_mode color_mode, bool *five_taps,
+ int *x_predecim, int *y_predecim, int *decim_x, int *decim_y,
+ u16 pos_x, unsigned long *core_clk, bool mem_to_mem);
+ unsigned long (*calc_core_clk) (enum omap_plane plane,
+ u16 width, u16 height, u16 out_width, u16 out_height,
+ bool mem_to_mem);
+ u8 num_fifos;
+
+ /* swap GFX & WB fifos */
+ bool gfx_fifo_workaround:1;
+};
+
+#define DISPC_MAX_NR_FIFOS 5
+
static struct {
struct platform_device *pdev;
void __iomem *base;
@@ -91,7 +114,9 @@ static struct {
int irq;
struct clk *dss_clk;
- u32 fifo_size[MAX_DSS_OVERLAYS];
+ u32 fifo_size[DISPC_MAX_NR_FIFOS];
+ /* maps which plane is using a fifo. fifo-id -> plane-id */
+ int fifo_assignment[DISPC_MAX_NR_FIFOS];
spinlock_t irq_lock;
u32 irq_error_mask;
@@ -102,6 +127,8 @@ static struct {
bool ctx_valid;
u32 ctx[DISPC_SZ_REGS / sizeof(u32)];
+ const struct dispc_features *feat;
+
#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
spinlock_t irq_stats_lock;
struct dispc_irq_stats irq_stats;
@@ -211,7 +238,14 @@ static const struct {
},
};
+struct color_conv_coef {
+ int ry, rcr, rcb, gy, gcr, gcb, by, bcr, bcb;
+ int full_range;
+};
+
static void _omap_dispc_set_irqs(void);
+static unsigned long dispc_plane_pclk_rate(enum omap_plane plane);
+static unsigned long dispc_plane_lclk_rate(enum omap_plane plane);
static inline void dispc_write_reg(const u16 idx, u32 val)
{
@@ -509,6 +543,11 @@ u32 dispc_mgr_get_framedone_irq(enum omap_channel channel)
return mgr_desc[channel].framedone_irq;
}
+u32 dispc_wb_get_framedone_irq(void)
+{
+ return DISPC_IRQ_FRAMEDONEWB;
+}
+
bool dispc_mgr_go_busy(enum omap_channel channel)
{
return mgr_fld_read(channel, DISPC_MGR_FLD_GO) == 1;
@@ -536,6 +575,30 @@ void dispc_mgr_go(enum omap_channel channel)
mgr_fld_write(channel, DISPC_MGR_FLD_GO, 1);
}
+bool dispc_wb_go_busy(void)
+{
+ return REG_GET(DISPC_CONTROL2, 6, 6) == 1;
+}
+
+void dispc_wb_go(void)
+{
+ enum omap_plane plane = OMAP_DSS_WB;
+ bool enable, go;
+
+ enable = REG_GET(DISPC_OVL_ATTRIBUTES(plane), 0, 0) == 1;
+
+ if (!enable)
+ return;
+
+ go = REG_GET(DISPC_CONTROL2, 6, 6) == 1;
+ if (go) {
+ DSSERR("GO bit not down for WB\n");
+ return;
+ }
+
+ REG_FLD_MOD(DISPC_CONTROL2, 1, 6, 6);
+}
+
static void dispc_ovl_write_firh_reg(enum omap_plane plane, int reg, u32 value)
{
dispc_write_reg(DISPC_OVL_FIR_COEF_H(plane, reg), value);
@@ -618,41 +681,41 @@ static void dispc_ovl_set_scale_coef(enum omap_plane plane, int fir_hinc,
}
}
-static void _dispc_setup_color_conv_coef(void)
-{
- int i;
- const struct color_conv_coef {
- int ry, rcr, rcb, gy, gcr, gcb, by, bcr, bcb;
- int full_range;
- } ctbl_bt601_5 = {
- 298, 409, 0, 298, -208, -100, 298, 0, 517, 0,
- };
-
- const struct color_conv_coef *ct;
+static void dispc_ovl_write_color_conv_coef(enum omap_plane plane,
+ const struct color_conv_coef *ct)
+{
#define CVAL(x, y) (FLD_VAL(x, 26, 16) | FLD_VAL(y, 10, 0))
- ct = &ctbl_bt601_5;
+ dispc_write_reg(DISPC_OVL_CONV_COEF(plane, 0), CVAL(ct->rcr, ct->ry));
+ dispc_write_reg(DISPC_OVL_CONV_COEF(plane, 1), CVAL(ct->gy, ct->rcb));
+ dispc_write_reg(DISPC_OVL_CONV_COEF(plane, 2), CVAL(ct->gcb, ct->gcr));
+ dispc_write_reg(DISPC_OVL_CONV_COEF(plane, 3), CVAL(ct->bcr, ct->by));
+ dispc_write_reg(DISPC_OVL_CONV_COEF(plane, 4), CVAL(0, ct->bcb));
- for (i = 1; i < dss_feat_get_num_ovls(); i++) {
- dispc_write_reg(DISPC_OVL_CONV_COEF(i, 0),
- CVAL(ct->rcr, ct->ry));
- dispc_write_reg(DISPC_OVL_CONV_COEF(i, 1),
- CVAL(ct->gy, ct->rcb));
- dispc_write_reg(DISPC_OVL_CONV_COEF(i, 2),
- CVAL(ct->gcb, ct->gcr));
- dispc_write_reg(DISPC_OVL_CONV_COEF(i, 3),
- CVAL(ct->bcr, ct->by));
- dispc_write_reg(DISPC_OVL_CONV_COEF(i, 4),
- CVAL(0, ct->bcb));
-
- REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(i), ct->full_range,
- 11, 11);
- }
+ REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), ct->full_range, 11, 11);
#undef CVAL
}
+static void dispc_setup_color_conv_coef(void)
+{
+ int i;
+ int num_ovl = dss_feat_get_num_ovls();
+ int num_wb = dss_feat_get_num_wbs();
+ const struct color_conv_coef ctbl_bt601_5_ovl = {
+ 298, 409, 0, 298, -208, -100, 298, 0, 517, 0,
+ };
+ const struct color_conv_coef ctbl_bt601_5_wb = {
+ 66, 112, -38, 129, -94, -74, 25, -18, 112, 0,
+ };
+
+ for (i = 1; i < num_ovl; i++)
+ dispc_ovl_write_color_conv_coef(i, &ctbl_bt601_5_ovl);
+
+ for (; i < num_wb; i++)
+ dispc_ovl_write_color_conv_coef(i, &ctbl_bt601_5_wb);
+}
static void dispc_ovl_set_ba0(enum omap_plane plane, u32 paddr)
{
@@ -674,24 +737,32 @@ static void dispc_ovl_set_ba1_uv(enum omap_plane plane, u32 paddr)
dispc_write_reg(DISPC_OVL_BA1_UV(plane), paddr);
}
-static void dispc_ovl_set_pos(enum omap_plane plane, int x, int y)
+static void dispc_ovl_set_pos(enum omap_plane plane,
+ enum omap_overlay_caps caps, int x, int y)
{
- u32 val = FLD_VAL(y, 26, 16) | FLD_VAL(x, 10, 0);
+ u32 val;
+
+ if ((caps & OMAP_DSS_OVL_CAP_POS) == 0)
+ return;
+
+ val = FLD_VAL(y, 26, 16) | FLD_VAL(x, 10, 0);
dispc_write_reg(DISPC_OVL_POSITION(plane), val);
}
-static void dispc_ovl_set_pic_size(enum omap_plane plane, int width, int height)
+static void dispc_ovl_set_input_size(enum omap_plane plane, int width,
+ int height)
{
u32 val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0);
- if (plane == OMAP_DSS_GFX)
+ if (plane == OMAP_DSS_GFX || plane == OMAP_DSS_WB)
dispc_write_reg(DISPC_OVL_SIZE(plane), val);
else
dispc_write_reg(DISPC_OVL_PICTURE_SIZE(plane), val);
}
-static void dispc_ovl_set_vid_size(enum omap_plane plane, int width, int height)
+static void dispc_ovl_set_output_size(enum omap_plane plane, int width,
+ int height)
{
u32 val;
@@ -699,14 +770,16 @@ static void dispc_ovl_set_vid_size(enum omap_plane plane, int width, int height)
val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0);
- dispc_write_reg(DISPC_OVL_SIZE(plane), val);
+ if (plane == OMAP_DSS_WB)
+ dispc_write_reg(DISPC_OVL_PICTURE_SIZE(plane), val);
+ else
+ dispc_write_reg(DISPC_OVL_SIZE(plane), val);
}
-static void dispc_ovl_set_zorder(enum omap_plane plane, u8 zorder)
+static void dispc_ovl_set_zorder(enum omap_plane plane,
+ enum omap_overlay_caps caps, u8 zorder)
{
- struct omap_overlay *ovl = omap_dss_get_overlay(plane);
-
- if ((ovl->caps & OMAP_DSS_OVL_CAP_ZORDER) == 0)
+ if ((caps & OMAP_DSS_OVL_CAP_ZORDER) == 0)
return;
REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), zorder, 27, 26);
@@ -723,23 +796,22 @@ static void dispc_ovl_enable_zorder_planes(void)
REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(i), 1, 25, 25);
}
-static void dispc_ovl_set_pre_mult_alpha(enum omap_plane plane, bool enable)
+static void dispc_ovl_set_pre_mult_alpha(enum omap_plane plane,
+ enum omap_overlay_caps caps, bool enable)
{
- struct omap_overlay *ovl = omap_dss_get_overlay(plane);
-
- if ((ovl->caps & OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA) == 0)
+ if ((caps & OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA) == 0)
return;
REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable ? 1 : 0, 28, 28);
}
-static void dispc_ovl_setup_global_alpha(enum omap_plane plane, u8 global_alpha)
+static void dispc_ovl_setup_global_alpha(enum omap_plane plane,
+ enum omap_overlay_caps caps, u8 global_alpha)
{
static const unsigned shifts[] = { 0, 8, 16, 24, };
int shift;
- struct omap_overlay *ovl = omap_dss_get_overlay(plane);
- if ((ovl->caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA) == 0)
+ if ((caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA) == 0)
return;
shift = shifts[plane];
@@ -947,10 +1019,17 @@ static enum omap_channel dispc_ovl_get_channel_out(enum omap_plane plane)
return channel;
}
+void dispc_wb_set_channel_in(enum dss_writeback_channel channel)
+{
+ enum omap_plane plane = OMAP_DSS_WB;
+
+ REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), channel, 18, 16);
+}
+
static void dispc_ovl_set_burst_size(enum omap_plane plane,
enum omap_burst_size burst_size)
{
- static const unsigned shifts[] = { 6, 14, 14, 14, };
+ static const unsigned shifts[] = { 6, 14, 14, 14, 14, };
int shift;
shift = shifts[plane];
@@ -1027,11 +1106,15 @@ static void dispc_ovl_set_vid_color_conv(enum omap_plane plane, bool enable)
dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), val);
}
-static void dispc_ovl_enable_replication(enum omap_plane plane, bool enable)
+static void dispc_ovl_enable_replication(enum omap_plane plane,
+ enum omap_overlay_caps caps, bool enable)
{
static const unsigned shifts[] = { 5, 10, 10, 10 };
int shift;
+ if ((caps & OMAP_DSS_OVL_CAP_REPLICATION) == 0)
+ return;
+
shift = shifts[plane];
REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable, shift, shift);
}
@@ -1045,10 +1128,10 @@ static void dispc_mgr_set_size(enum omap_channel channel, u16 width,
dispc_write_reg(DISPC_SIZE_MGR(channel), val);
}
-static void dispc_read_plane_fifo_sizes(void)
+static void dispc_init_fifos(void)
{
u32 size;
- int plane;
+ int fifo;
u8 start, end;
u32 unit;
@@ -1056,16 +1139,53 @@ static void dispc_read_plane_fifo_sizes(void)
dss_feat_get_reg_field(FEAT_REG_FIFOSIZE, &start, &end);
- for (plane = 0; plane < dss_feat_get_num_ovls(); ++plane) {
- size = REG_GET(DISPC_OVL_FIFO_SIZE_STATUS(plane), start, end);
+ for (fifo = 0; fifo < dispc.feat->num_fifos; ++fifo) {
+ size = REG_GET(DISPC_OVL_FIFO_SIZE_STATUS(fifo), start, end);
size *= unit;
- dispc.fifo_size[plane] = size;
+ dispc.fifo_size[fifo] = size;
+
+ /*
+ * By default fifos are mapped directly to overlays, fifo 0 to
+ * ovl 0, fifo 1 to ovl 1, etc.
+ */
+ dispc.fifo_assignment[fifo] = fifo;
+ }
+
+ /*
+ * The GFX fifo on OMAP4 is smaller than the other fifos. The small fifo
+ * causes problems with certain use cases, like using the tiler in 2D
+ * mode. The below hack swaps the fifos of GFX and WB planes, thus
+ * giving GFX plane a larger fifo. WB but should work fine with a
+ * smaller fifo.
+ */
+ if (dispc.feat->gfx_fifo_workaround) {
+ u32 v;
+
+ v = dispc_read_reg(DISPC_GLOBAL_BUFFER);
+
+ v = FLD_MOD(v, 4, 2, 0); /* GFX BUF top to WB */
+ v = FLD_MOD(v, 4, 5, 3); /* GFX BUF bottom to WB */
+ v = FLD_MOD(v, 0, 26, 24); /* WB BUF top to GFX */
+ v = FLD_MOD(v, 0, 29, 27); /* WB BUF bottom to GFX */
+
+ dispc_write_reg(DISPC_GLOBAL_BUFFER, v);
+
+ dispc.fifo_assignment[OMAP_DSS_GFX] = OMAP_DSS_WB;
+ dispc.fifo_assignment[OMAP_DSS_WB] = OMAP_DSS_GFX;
}
}
static u32 dispc_ovl_get_fifo_size(enum omap_plane plane)
{
- return dispc.fifo_size[plane];
+ int fifo;
+ u32 size = 0;
+
+ for (fifo = 0; fifo < dispc.feat->num_fifos; ++fifo) {
+ if (dispc.fifo_assignment[fifo] == plane)
+ size += dispc.fifo_size[fifo];
+ }
+
+ return size;
}
void dispc_ovl_set_fifo_threshold(enum omap_plane plane, u32 low, u32 high)
@@ -1141,6 +1261,14 @@ void dispc_ovl_compute_fifo_thresholds(enum omap_plane plane,
if (manual_update && dss_has_feature(FEAT_OMAP3_DSI_FIFO_BUG)) {
*fifo_low = ovl_fifo_size - burst_size * 2;
*fifo_high = total_fifo_size - burst_size;
+ } else if (plane == OMAP_DSS_WB) {
+ /*
+ * Most optimal configuration for writeback is to push out data
+ * to the interconnect the moment writeback pushes enough pixels
+ * in the FIFO to form a burst
+ */
+ *fifo_low = 0;
+ *fifo_high = burst_size;
} else {
*fifo_low = ovl_fifo_size - burst_size;
*fifo_high = total_fifo_size - buf_unit;
@@ -1383,6 +1511,7 @@ static void dispc_ovl_set_scaling_uv(enum omap_plane plane,
{
int scale_x = out_width != orig_width;
int scale_y = out_height != orig_height;
+ bool chroma_upscale = plane != OMAP_DSS_WB ? true : false;
if (!dss_has_feature(FEAT_HANDLE_UV_SEPARATE))
return;
@@ -1390,7 +1519,8 @@ static void dispc_ovl_set_scaling_uv(enum omap_plane plane,
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);
+ if (plane != OMAP_DSS_WB)
+ REG_FLD_MOD(DISPC_OVL_ATTRIBUTES2(plane), 0, 8, 8);
return;
}
@@ -1399,23 +1529,34 @@ static void dispc_ovl_set_scaling_uv(enum omap_plane plane,
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;
+ if (chroma_upscale) {
+ /* UV is subsampled by 2 horizontally and vertically */
+ orig_height >>= 1;
+ orig_width >>= 1;
+ } else {
+ /* UV is downsampled by 2 horizontally and vertically */
+ orig_height <<= 1;
+ 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
- */
+ /* 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;
+ rotation == OMAP_DSS_ROT_180) {
+ if (chroma_upscale)
+ /* UV is subsampled by 2 horizontally */
+ orig_width >>= 1;
+ else
+ /* UV is downsampled by 2 horizontally */
+ orig_width <<= 1;
+ }
+
/* must use FIR for YUV422 if rotated */
if (rotation != OMAP_DSS_ROT_0)
scale_x = scale_y = true;
+
break;
default:
BUG();
@@ -1431,8 +1572,10 @@ static void dispc_ovl_set_scaling_uv(enum omap_plane plane,
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);
+ if (plane != OMAP_DSS_WB)
+ 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 */
@@ -1848,22 +1991,19 @@ static void calc_tiler_rotation_offset(u16 screen_width, u16 width,
* This function is used to avoid synclosts in OMAP3, because of some
* undocumented horizontal position and timing related limitations.
*/
-static int check_horiz_timing_omap3(enum omap_channel channel,
+static int check_horiz_timing_omap3(enum omap_plane plane,
const struct omap_video_timings *t, u16 pos_x,
u16 width, u16 height, u16 out_width, u16 out_height)
{
int DS = DIV_ROUND_UP(height, out_height);
- unsigned long nonactive, lclk, pclk;
+ unsigned long nonactive;
static const u8 limits[3] = { 8, 10, 20 };
u64 val, blank;
+ unsigned long pclk = dispc_plane_pclk_rate(plane);
+ unsigned long lclk = dispc_plane_lclk_rate(plane);
int i;
nonactive = t->x_res + t->hfp + t->hsw + t->hbp - out_width;
- pclk = dispc_mgr_pclk_rate(channel);
- if (dss_mgr_is_lcd(channel))
- lclk = dispc_mgr_lclk_rate(channel);
- else
- lclk = dispc_fclk_rate();
i = 0;
if (out_height < height)
@@ -1900,13 +2040,14 @@ static int check_horiz_timing_omap3(enum omap_channel channel,
return 0;
}
-static unsigned long calc_core_clk_five_taps(enum omap_channel channel,
+static unsigned long calc_core_clk_five_taps(enum omap_plane plane,
const struct omap_video_timings *mgr_timings, u16 width,
u16 height, u16 out_width, u16 out_height,
enum omap_color_mode color_mode)
{
u32 core_clk = 0;
- u64 tmp, pclk = dispc_mgr_pclk_rate(channel);
+ u64 tmp;
+ unsigned long pclk = dispc_plane_pclk_rate(plane);
if (height <= out_height && width <= out_width)
return (unsigned long) pclk;
@@ -1940,11 +2081,22 @@ static unsigned long calc_core_clk_five_taps(enum omap_channel channel,
return core_clk;
}
-static unsigned long calc_core_clk(enum omap_channel channel, u16 width,
- u16 height, u16 out_width, u16 out_height)
+static unsigned long calc_core_clk_24xx(enum omap_plane plane, u16 width,
+ u16 height, u16 out_width, u16 out_height, bool mem_to_mem)
+{
+ unsigned long pclk = dispc_plane_pclk_rate(plane);
+
+ if (height > out_height && width > out_width)
+ return pclk * 4;
+ else
+ return pclk * 2;
+}
+
+static unsigned long calc_core_clk_34xx(enum omap_plane plane, u16 width,
+ u16 height, u16 out_width, u16 out_height, bool mem_to_mem)
{
unsigned int hf, vf;
- unsigned long pclk = dispc_mgr_pclk_rate(channel);
+ unsigned long pclk = dispc_plane_pclk_rate(plane);
/*
* FIXME how to determine the 'A' factor
@@ -1959,51 +2111,207 @@ static unsigned long calc_core_clk(enum omap_channel channel, u16 width,
hf = 2;
else
hf = 1;
-
if (height > out_height)
vf = 2;
else
vf = 1;
- if (cpu_is_omap24xx()) {
- if (vf > 1 && hf > 1)
- return pclk * 4;
- else
- return pclk * 2;
- } else if (cpu_is_omap34xx()) {
- return pclk * vf * hf;
- } else {
- if (hf > 1)
- return DIV_ROUND_UP(pclk, out_width) * width;
- else
- return pclk;
+ return pclk * vf * hf;
+}
+
+static unsigned long calc_core_clk_44xx(enum omap_plane plane, u16 width,
+ u16 height, u16 out_width, u16 out_height, bool mem_to_mem)
+{
+ unsigned long pclk;
+
+ /*
+ * If the overlay/writeback is in mem to mem mode, there are no
+ * downscaling limitations with respect to pixel clock, return 1 as
+ * required core clock to represent that we have sufficient enough
+ * core clock to do maximum downscaling
+ */
+ if (mem_to_mem)
+ return 1;
+
+ pclk = dispc_plane_pclk_rate(plane);
+
+ if (width > out_width)
+ return DIV_ROUND_UP(pclk, out_width) * width;
+ else
+ return pclk;
+}
+
+static int dispc_ovl_calc_scaling_24xx(enum omap_plane plane,
+ const struct omap_video_timings *mgr_timings,
+ u16 width, u16 height, u16 out_width, u16 out_height,
+ enum omap_color_mode color_mode, bool *five_taps,
+ int *x_predecim, int *y_predecim, int *decim_x, int *decim_y,
+ u16 pos_x, unsigned long *core_clk, bool mem_to_mem)
+{
+ int error;
+ u16 in_width, in_height;
+ int min_factor = min(*decim_x, *decim_y);
+ const int maxsinglelinewidth =
+ dss_feat_get_param_max(FEAT_PARAM_LINEWIDTH);
+
+ *five_taps = false;
+
+ do {
+ in_height = DIV_ROUND_UP(height, *decim_y);
+ in_width = DIV_ROUND_UP(width, *decim_x);
+ *core_clk = dispc.feat->calc_core_clk(plane, in_width,
+ in_height, out_width, out_height, mem_to_mem);
+ error = (in_width > maxsinglelinewidth || !*core_clk ||
+ *core_clk > dispc_core_clk_rate());
+ if (error) {
+ if (*decim_x == *decim_y) {
+ *decim_x = min_factor;
+ ++*decim_y;
+ } else {
+ swap(*decim_x, *decim_y);
+ if (*decim_x < *decim_y)
+ ++*decim_x;
+ }
+ }
+ } while (*decim_x <= *x_predecim && *decim_y <= *y_predecim && error);
+
+ if (in_width > maxsinglelinewidth) {
+ DSSERR("Cannot scale max input width exceeded");
+ return -EINVAL;
}
+ return 0;
}
-static int dispc_ovl_calc_scaling(enum omap_plane plane,
- enum omap_channel channel,
+static int dispc_ovl_calc_scaling_34xx(enum omap_plane plane,
const struct omap_video_timings *mgr_timings,
u16 width, u16 height, u16 out_width, u16 out_height,
enum omap_color_mode color_mode, bool *five_taps,
- int *x_predecim, int *y_predecim, u16 pos_x)
+ int *x_predecim, int *y_predecim, int *decim_x, int *decim_y,
+ u16 pos_x, unsigned long *core_clk, bool mem_to_mem)
{
- struct omap_overlay *ovl = omap_dss_get_overlay(plane);
- const int maxdownscale = dss_feat_get_param_max(FEAT_PARAM_DOWNSCALE);
+ int error;
+ u16 in_width, in_height;
+ int min_factor = min(*decim_x, *decim_y);
+ const int maxsinglelinewidth =
+ dss_feat_get_param_max(FEAT_PARAM_LINEWIDTH);
+
+ do {
+ in_height = DIV_ROUND_UP(height, *decim_y);
+ in_width = DIV_ROUND_UP(width, *decim_x);
+ *core_clk = calc_core_clk_five_taps(plane, mgr_timings,
+ in_width, in_height, out_width, out_height, color_mode);
+
+ error = check_horiz_timing_omap3(plane, mgr_timings,
+ pos_x, in_width, in_height, out_width,
+ out_height);
+
+ if (in_width > maxsinglelinewidth)
+ if (in_height > out_height &&
+ in_height < out_height * 2)
+ *five_taps = false;
+ if (!*five_taps)
+ *core_clk = dispc.feat->calc_core_clk(plane, in_width,
+ in_height, out_width, out_height,
+ mem_to_mem);
+
+ error = (error || in_width > maxsinglelinewidth * 2 ||
+ (in_width > maxsinglelinewidth && *five_taps) ||
+ !*core_clk || *core_clk > dispc_core_clk_rate());
+ if (error) {
+ if (*decim_x == *decim_y) {
+ *decim_x = min_factor;
+ ++*decim_y;
+ } else {
+ swap(*decim_x, *decim_y);
+ if (*decim_x < *decim_y)
+ ++*decim_x;
+ }
+ }
+ } while (*decim_x <= *x_predecim && *decim_y <= *y_predecim && error);
+
+ if (check_horiz_timing_omap3(plane, mgr_timings, pos_x, width, height,
+ out_width, out_height)){
+ DSSERR("horizontal timing too tight\n");
+ return -EINVAL;
+ }
+
+ if (in_width > (maxsinglelinewidth * 2)) {
+ DSSERR("Cannot setup scaling");
+ DSSERR("width exceeds maximum width possible");
+ return -EINVAL;
+ }
+
+ if (in_width > maxsinglelinewidth && *five_taps) {
+ DSSERR("cannot setup scaling with five taps");
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int dispc_ovl_calc_scaling_44xx(enum omap_plane plane,
+ const struct omap_video_timings *mgr_timings,
+ u16 width, u16 height, u16 out_width, u16 out_height,
+ enum omap_color_mode color_mode, bool *five_taps,
+ int *x_predecim, int *y_predecim, int *decim_x, int *decim_y,
+ u16 pos_x, unsigned long *core_clk, bool mem_to_mem)
+{
+ u16 in_width, in_width_max;
+ int decim_x_min = *decim_x;
+ u16 in_height = DIV_ROUND_UP(height, *decim_y);
const int maxsinglelinewidth =
dss_feat_get_param_max(FEAT_PARAM_LINEWIDTH);
+ unsigned long pclk = dispc_plane_pclk_rate(plane);
+ const int maxdownscale = dss_feat_get_param_max(FEAT_PARAM_DOWNSCALE);
+
+ if (mem_to_mem)
+ in_width_max = DIV_ROUND_UP(out_width, maxdownscale);
+ else
+ in_width_max = dispc_core_clk_rate() /
+ DIV_ROUND_UP(pclk, out_width);
+
+ *decim_x = DIV_ROUND_UP(width, in_width_max);
+
+ *decim_x = *decim_x > decim_x_min ? *decim_x : decim_x_min;
+ if (*decim_x > *x_predecim)
+ return -EINVAL;
+
+ do {
+ in_width = DIV_ROUND_UP(width, *decim_x);
+ } while (*decim_x <= *x_predecim &&
+ in_width > maxsinglelinewidth && ++*decim_x);
+
+ if (in_width > maxsinglelinewidth) {
+ DSSERR("Cannot scale width exceeds max line width");
+ return -EINVAL;
+ }
+
+ *core_clk = dispc.feat->calc_core_clk(plane, in_width, in_height,
+ out_width, out_height, mem_to_mem);
+ return 0;
+}
+
+static int dispc_ovl_calc_scaling(enum omap_plane plane,
+ enum omap_overlay_caps caps,
+ const struct omap_video_timings *mgr_timings,
+ u16 width, u16 height, u16 out_width, u16 out_height,
+ enum omap_color_mode color_mode, bool *five_taps,
+ int *x_predecim, int *y_predecim, u16 pos_x,
+ enum omap_dss_rotation_type rotation_type, bool mem_to_mem)
+{
+ const int maxdownscale = dss_feat_get_param_max(FEAT_PARAM_DOWNSCALE);
const int max_decim_limit = 16;
unsigned long core_clk = 0;
- int decim_x, decim_y, error, min_factor;
- u16 in_width, in_height, in_width_max = 0;
+ int decim_x, decim_y, ret;
if (width == out_width && height == out_height)
return 0;
- if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0)
+ if ((caps & OMAP_DSS_OVL_CAP_SCALE) == 0)
return -EINVAL;
*x_predecim = max_decim_limit;
- *y_predecim = max_decim_limit;
+ *y_predecim = (rotation_type == OMAP_DSS_ROT_TILER &&
+ dss_has_feature(FEAT_BURST_2D)) ? 2 : max_decim_limit;
if (color_mode == OMAP_DSS_COLOR_CLUT1 ||
color_mode == OMAP_DSS_COLOR_CLUT2 ||
@@ -2018,118 +2326,18 @@ static int dispc_ovl_calc_scaling(enum omap_plane plane,
decim_x = DIV_ROUND_UP(DIV_ROUND_UP(width, out_width), maxdownscale);
decim_y = DIV_ROUND_UP(DIV_ROUND_UP(height, out_height), maxdownscale);
- min_factor = min(decim_x, decim_y);
-
if (decim_x > *x_predecim || out_width > width * 8)
return -EINVAL;
if (decim_y > *y_predecim || out_height > height * 8)
return -EINVAL;
- if (cpu_is_omap24xx()) {
- *five_taps = false;
-
- do {
- in_height = DIV_ROUND_UP(height, decim_y);
- in_width = DIV_ROUND_UP(width, decim_x);
- core_clk = calc_core_clk(channel, in_width, in_height,
- out_width, out_height);
- error = (in_width > maxsinglelinewidth || !core_clk ||
- core_clk > dispc_core_clk_rate());
- if (error) {
- if (decim_x == decim_y) {
- decim_x = min_factor;
- decim_y++;
- } else {
- swap(decim_x, decim_y);
- if (decim_x < decim_y)
- decim_x++;
- }
- }
- } while (decim_x <= *x_predecim && decim_y <= *y_predecim &&
- error);
-
- if (in_width > maxsinglelinewidth) {
- DSSERR("Cannot scale max input width exceeded");
- return -EINVAL;
- }
- } else if (cpu_is_omap34xx()) {
-
- do {
- in_height = DIV_ROUND_UP(height, decim_y);
- in_width = DIV_ROUND_UP(width, decim_x);
- core_clk = calc_core_clk_five_taps(channel, mgr_timings,
- in_width, in_height, out_width, out_height,
- color_mode);
-
- error = check_horiz_timing_omap3(channel, mgr_timings,
- pos_x, in_width, in_height, out_width,
- out_height);
-
- if (in_width > maxsinglelinewidth)
- if (in_height > out_height &&
- in_height < out_height * 2)
- *five_taps = false;
- if (!*five_taps)
- core_clk = calc_core_clk(channel, in_width,
- in_height, out_width, out_height);
- error = (error || in_width > maxsinglelinewidth * 2 ||
- (in_width > maxsinglelinewidth && *five_taps) ||
- !core_clk || core_clk > dispc_core_clk_rate());
- if (error) {
- if (decim_x == decim_y) {
- decim_x = min_factor;
- decim_y++;
- } else {
- swap(decim_x, decim_y);
- if (decim_x < decim_y)
- decim_x++;
- }
- }
- } while (decim_x <= *x_predecim && decim_y <= *y_predecim
- && error);
-
- if (check_horiz_timing_omap3(channel, mgr_timings, pos_x, width,
- height, out_width, out_height)){
- DSSERR("horizontal timing too tight\n");
- return -EINVAL;
- }
-
- if (in_width > (maxsinglelinewidth * 2)) {
- DSSERR("Cannot setup scaling");
- DSSERR("width exceeds maximum width possible");
- return -EINVAL;
- }
-
- if (in_width > maxsinglelinewidth && *five_taps) {
- DSSERR("cannot setup scaling with five taps");
- return -EINVAL;
- }
- } else {
- int decim_x_min = decim_x;
- in_height = DIV_ROUND_UP(height, decim_y);
- in_width_max = dispc_core_clk_rate() /
- DIV_ROUND_UP(dispc_mgr_pclk_rate(channel),
- out_width);
- decim_x = DIV_ROUND_UP(width, in_width_max);
-
- decim_x = decim_x > decim_x_min ? decim_x : decim_x_min;
- if (decim_x > *x_predecim)
- return -EINVAL;
-
- do {
- in_width = DIV_ROUND_UP(width, decim_x);
- } while (decim_x <= *x_predecim &&
- in_width > maxsinglelinewidth && decim_x++);
-
- if (in_width > maxsinglelinewidth) {
- DSSERR("Cannot scale width exceeds max line width");
- return -EINVAL;
- }
-
- core_clk = calc_core_clk(channel, in_width, in_height,
- out_width, out_height);
- }
+ ret = dispc.feat->calc_scaling(plane, mgr_timings, width, height,
+ out_width, out_height, color_mode, five_taps,
+ x_predecim, y_predecim, &decim_x, &decim_y, pos_x, &core_clk,
+ mem_to_mem);
+ if (ret)
+ return ret;
DSSDBG("required core clk rate = %lu Hz\n", core_clk);
DSSDBG("current core clk rate = %lu Hz\n", dispc_core_clk_rate());
@@ -2147,69 +2355,64 @@ static int dispc_ovl_calc_scaling(enum omap_plane plane,
return 0;
}
-int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi,
- bool replication, const struct omap_video_timings *mgr_timings)
+static int dispc_ovl_setup_common(enum omap_plane plane,
+ enum omap_overlay_caps caps, u32 paddr, u32 p_uv_addr,
+ u16 screen_width, int pos_x, int pos_y, u16 width, u16 height,
+ u16 out_width, u16 out_height, enum omap_color_mode color_mode,
+ u8 rotation, bool mirror, u8 zorder, u8 pre_mult_alpha,
+ u8 global_alpha, enum omap_dss_rotation_type rotation_type,
+ bool replication, const struct omap_video_timings *mgr_timings,
+ bool mem_to_mem)
{
- struct omap_overlay *ovl = omap_dss_get_overlay(plane);
bool five_taps = true;
bool fieldmode = 0;
int r, cconv = 0;
unsigned offset0, offset1;
s32 row_inc;
s32 pix_inc;
- u16 frame_height = oi->height;
+ u16 frame_height = height;
unsigned int field_offset = 0;
- u16 in_height = oi->height;
- u16 in_width = oi->width;
- u16 out_width, out_height;
- enum omap_channel channel;
+ u16 in_height = height;
+ u16 in_width = width;
int x_predecim = 1, y_predecim = 1;
bool ilace = mgr_timings->interlace;
- channel = dispc_ovl_get_channel_out(plane);
-
- DSSDBG("dispc_ovl_setup %d, pa %x, pa_uv %x, sw %d, %d,%d, %dx%d -> "
- "%dx%d, cmode %x, rot %d, mir %d, ilace %d chan %d repl %d\n",
- plane, oi->paddr, oi->p_uv_addr,
- oi->screen_width, oi->pos_x, oi->pos_y, oi->width, oi->height,
- oi->out_width, oi->out_height, oi->color_mode, oi->rotation,
- oi->mirror, ilace, channel, replication);
-
- if (oi->paddr == 0)
+ if (paddr == 0)
return -EINVAL;
- out_width = oi->out_width == 0 ? oi->width : oi->out_width;
- out_height = oi->out_height == 0 ? oi->height : oi->out_height;
+ out_width = out_width == 0 ? width : out_width;
+ out_height = out_height == 0 ? height : out_height;
- if (ilace && oi->height == out_height)
+ if (ilace && height == out_height)
fieldmode = 1;
if (ilace) {
if (fieldmode)
in_height /= 2;
- oi->pos_y /= 2;
+ pos_y /= 2;
out_height /= 2;
DSSDBG("adjusting for ilace: height %d, pos_y %d, "
- "out_height %d\n",
- in_height, oi->pos_y, out_height);
+ "out_height %d\n", in_height, pos_y,
+ out_height);
}
- if (!dss_feat_color_mode_supported(plane, oi->color_mode))
+ if (!dss_feat_color_mode_supported(plane, color_mode))
return -EINVAL;
- r = dispc_ovl_calc_scaling(plane, channel, mgr_timings, in_width,
- in_height, out_width, out_height, oi->color_mode,
- &five_taps, &x_predecim, &y_predecim, oi->pos_x);
+ r = dispc_ovl_calc_scaling(plane, caps, mgr_timings, in_width,
+ in_height, out_width, out_height, color_mode,
+ &five_taps, &x_predecim, &y_predecim, pos_x,
+ rotation_type, mem_to_mem);
if (r)
return r;
in_width = DIV_ROUND_UP(in_width, x_predecim);
in_height = DIV_ROUND_UP(in_height, y_predecim);
- if (oi->color_mode == OMAP_DSS_COLOR_YUV2 ||
- oi->color_mode == OMAP_DSS_COLOR_UYVY ||
- oi->color_mode == OMAP_DSS_COLOR_NV12)
+ if (color_mode == OMAP_DSS_COLOR_YUV2 ||
+ color_mode == OMAP_DSS_COLOR_UYVY ||
+ color_mode == OMAP_DSS_COLOR_NV12)
cconv = 1;
if (ilace && !fieldmode) {
@@ -2235,70 +2438,144 @@ int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi,
row_inc = 0;
pix_inc = 0;
- if (oi->rotation_type == OMAP_DSS_ROT_TILER)
- calc_tiler_rotation_offset(oi->screen_width, in_width,
- oi->color_mode, fieldmode, field_offset,
+ if (rotation_type == OMAP_DSS_ROT_TILER)
+ calc_tiler_rotation_offset(screen_width, in_width,
+ color_mode, fieldmode, field_offset,
&offset0, &offset1, &row_inc, &pix_inc,
x_predecim, y_predecim);
- else if (oi->rotation_type == OMAP_DSS_ROT_DMA)
- calc_dma_rotation_offset(oi->rotation, oi->mirror,
- oi->screen_width, in_width, frame_height,
- oi->color_mode, fieldmode, field_offset,
+ else if (rotation_type == OMAP_DSS_ROT_DMA)
+ calc_dma_rotation_offset(rotation, mirror,
+ screen_width, in_width, frame_height,
+ color_mode, fieldmode, field_offset,
&offset0, &offset1, &row_inc, &pix_inc,
x_predecim, y_predecim);
else
- calc_vrfb_rotation_offset(oi->rotation, oi->mirror,
- oi->screen_width, in_width, frame_height,
- oi->color_mode, fieldmode, field_offset,
+ calc_vrfb_rotation_offset(rotation, mirror,
+ screen_width, in_width, frame_height,
+ color_mode, fieldmode, field_offset,
&offset0, &offset1, &row_inc, &pix_inc,
x_predecim, y_predecim);
DSSDBG("offset0 %u, offset1 %u, row_inc %d, pix_inc %d\n",
offset0, offset1, row_inc, pix_inc);
- dispc_ovl_set_color_mode(plane, oi->color_mode);
+ dispc_ovl_set_color_mode(plane, color_mode);
- dispc_ovl_configure_burst_type(plane, oi->rotation_type);
+ dispc_ovl_configure_burst_type(plane, rotation_type);
- dispc_ovl_set_ba0(plane, oi->paddr + offset0);
- dispc_ovl_set_ba1(plane, oi->paddr + offset1);
+ dispc_ovl_set_ba0(plane, paddr + offset0);
+ dispc_ovl_set_ba1(plane, paddr + offset1);
- if (OMAP_DSS_COLOR_NV12 == oi->color_mode) {
- dispc_ovl_set_ba0_uv(plane, oi->p_uv_addr + offset0);
- dispc_ovl_set_ba1_uv(plane, oi->p_uv_addr + offset1);
+ if (OMAP_DSS_COLOR_NV12 == color_mode) {
+ dispc_ovl_set_ba0_uv(plane, p_uv_addr + offset0);
+ dispc_ovl_set_ba1_uv(plane, p_uv_addr + offset1);
}
-
dispc_ovl_set_row_inc(plane, row_inc);
dispc_ovl_set_pix_inc(plane, pix_inc);
- DSSDBG("%d,%d %dx%d -> %dx%d\n", oi->pos_x, oi->pos_y, in_width,
+ DSSDBG("%d,%d %dx%d -> %dx%d\n", pos_x, pos_y, in_width,
in_height, out_width, out_height);
- dispc_ovl_set_pos(plane, oi->pos_x, oi->pos_y);
+ dispc_ovl_set_pos(plane, caps, pos_x, pos_y);
- dispc_ovl_set_pic_size(plane, in_width, in_height);
+ dispc_ovl_set_input_size(plane, in_width, in_height);
- if (ovl->caps & OMAP_DSS_OVL_CAP_SCALE) {
+ if (caps & OMAP_DSS_OVL_CAP_SCALE) {
dispc_ovl_set_scaling(plane, in_width, in_height, out_width,
out_height, ilace, five_taps, fieldmode,
- oi->color_mode, oi->rotation);
- dispc_ovl_set_vid_size(plane, out_width, out_height);
+ color_mode, rotation);
+ dispc_ovl_set_output_size(plane, out_width, out_height);
dispc_ovl_set_vid_color_conv(plane, cconv);
}
- dispc_ovl_set_rotation_attrs(plane, oi->rotation, oi->mirror,
- oi->color_mode);
+ dispc_ovl_set_rotation_attrs(plane, rotation, mirror, color_mode);
- dispc_ovl_set_zorder(plane, oi->zorder);
- dispc_ovl_set_pre_mult_alpha(plane, oi->pre_mult_alpha);
- dispc_ovl_setup_global_alpha(plane, oi->global_alpha);
+ dispc_ovl_set_zorder(plane, caps, zorder);
+ dispc_ovl_set_pre_mult_alpha(plane, caps, pre_mult_alpha);
+ dispc_ovl_setup_global_alpha(plane, caps, global_alpha);
- dispc_ovl_enable_replication(plane, replication);
+ dispc_ovl_enable_replication(plane, caps, replication);
return 0;
}
+int dispc_ovl_setup(enum omap_plane plane, const struct omap_overlay_info *oi,
+ bool replication, const struct omap_video_timings *mgr_timings,
+ bool mem_to_mem)
+{
+ int r;
+ struct omap_overlay *ovl = omap_dss_get_overlay(plane);
+ enum omap_channel channel;
+
+ channel = dispc_ovl_get_channel_out(plane);
+
+ DSSDBG("dispc_ovl_setup %d, pa %x, pa_uv %x, sw %d, %d,%d, %dx%d -> "
+ "%dx%d, cmode %x, rot %d, mir %d, chan %d repl %d\n",
+ plane, oi->paddr, oi->p_uv_addr, oi->screen_width, oi->pos_x,
+ oi->pos_y, oi->width, oi->height, oi->out_width, oi->out_height,
+ oi->color_mode, oi->rotation, oi->mirror, channel, replication);
+
+ r = dispc_ovl_setup_common(plane, ovl->caps, oi->paddr, oi->p_uv_addr,
+ oi->screen_width, oi->pos_x, oi->pos_y, oi->width, oi->height,
+ oi->out_width, oi->out_height, oi->color_mode, oi->rotation,
+ oi->mirror, oi->zorder, oi->pre_mult_alpha, oi->global_alpha,
+ oi->rotation_type, replication, mgr_timings, mem_to_mem);
+
+ return r;
+}
+
+int dispc_wb_setup(const struct omap_dss_writeback_info *wi,
+ bool mem_to_mem, const struct omap_video_timings *mgr_timings)
+{
+ int r;
+ u32 l;
+ enum omap_plane plane = OMAP_DSS_WB;
+ const int pos_x = 0, pos_y = 0;
+ const u8 zorder = 0, global_alpha = 0;
+ const bool replication = false;
+ bool truncation;
+ int in_width = mgr_timings->x_res;
+ int in_height = mgr_timings->y_res;
+ enum omap_overlay_caps caps =
+ OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA;
+
+ DSSDBG("dispc_wb_setup, pa %x, pa_uv %x, %d,%d -> %dx%d, cmode %x, "
+ "rot %d, mir %d\n", wi->paddr, wi->p_uv_addr, in_width,
+ in_height, wi->width, wi->height, wi->color_mode, wi->rotation,
+ wi->mirror);
+
+ r = dispc_ovl_setup_common(plane, caps, wi->paddr, wi->p_uv_addr,
+ wi->buf_width, pos_x, pos_y, in_width, in_height, wi->width,
+ wi->height, wi->color_mode, wi->rotation, wi->mirror, zorder,
+ wi->pre_mult_alpha, global_alpha, wi->rotation_type,
+ replication, mgr_timings, mem_to_mem);
+
+ switch (wi->color_mode) {
+ case OMAP_DSS_COLOR_RGB16:
+ case OMAP_DSS_COLOR_RGB24P:
+ case OMAP_DSS_COLOR_ARGB16:
+ case OMAP_DSS_COLOR_RGBA16:
+ case OMAP_DSS_COLOR_RGB12U:
+ case OMAP_DSS_COLOR_ARGB16_1555:
+ case OMAP_DSS_COLOR_XRGB16_1555:
+ case OMAP_DSS_COLOR_RGBX16:
+ truncation = true;
+ break;
+ default:
+ truncation = false;
+ break;
+ }
+
+ /* setup extra DISPC_WB_ATTRIBUTES */
+ l = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane));
+ l = FLD_MOD(l, truncation, 10, 10); /* TRUNCATIONENABLE */
+ l = FLD_MOD(l, mem_to_mem, 19, 19); /* WRITEBACKMODE */
+ dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), l);
+
+ return r;
+}
+
int dispc_ovl_enable(enum omap_plane plane, bool enable)
{
DSSDBG("dispc_enable_plane %d, %d\n", plane, enable);
@@ -2451,6 +2728,47 @@ void dispc_mgr_enable(enum omap_channel channel, bool enable)
BUG();
}
+void dispc_wb_enable(bool enable)
+{
+ enum omap_plane plane = OMAP_DSS_WB;
+ struct completion frame_done_completion;
+ bool is_on;
+ int r;
+ u32 irq;
+
+ is_on = REG_GET(DISPC_OVL_ATTRIBUTES(plane), 0, 0);
+ irq = DISPC_IRQ_FRAMEDONEWB;
+
+ if (!enable && is_on) {
+ init_completion(&frame_done_completion);
+
+ r = omap_dispc_register_isr(dispc_disable_isr,
+ &frame_done_completion, irq);
+ if (r)
+ DSSERR("failed to register FRAMEDONEWB isr\n");
+ }
+
+ REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable ? 1 : 0, 0, 0);
+
+ if (!enable && is_on) {
+ if (!wait_for_completion_timeout(&frame_done_completion,
+ msecs_to_jiffies(100)))
+ DSSERR("timeout waiting for FRAMEDONEWB\n");
+
+ r = omap_dispc_unregister_isr(dispc_disable_isr,
+ &frame_done_completion, irq);
+ if (r)
+ DSSERR("failed to unregister FRAMEDONEWB isr\n");
+ }
+}
+
+bool dispc_wb_is_enabled(void)
+{
+ enum omap_plane plane = OMAP_DSS_WB;
+
+ return REG_GET(DISPC_OVL_ATTRIBUTES(plane), 0, 0);
+}
+
void dispc_lcd_enable_signal_polarity(bool act_high)
{
if (!dss_has_feature(FEAT_LCDENABLEPOL))
@@ -2605,24 +2923,13 @@ static bool _dispc_mgr_size_ok(u16 width, u16 height)
static bool _dispc_lcd_timings_ok(int hsw, int hfp, int hbp,
int vsw, int vfp, int vbp)
{
- if (cpu_is_omap24xx() || omap_rev() < OMAP3430_REV_ES3_0) {
- if (hsw < 1 || hsw > 64 ||
- hfp < 1 || hfp > 256 ||
- hbp < 1 || hbp > 256 ||
- vsw < 1 || vsw > 64 ||
- vfp < 0 || vfp > 255 ||
- vbp < 0 || vbp > 255)
- return false;
- } else {
- if (hsw < 1 || hsw > 256 ||
- hfp < 1 || hfp > 4096 ||
- hbp < 1 || hbp > 4096 ||
- vsw < 1 || vsw > 256 ||
- vfp < 0 || vfp > 4095 ||
- vbp < 0 || vbp > 4095)
- return false;
- }
-
+ if (hsw < 1 || hsw > dispc.feat->sw_max ||
+ hfp < 1 || hfp > dispc.feat->hp_max ||
+ hbp < 1 || hbp > dispc.feat->hp_max ||
+ vsw < 1 || vsw > dispc.feat->sw_max ||
+ vfp < 0 || vfp > dispc.feat->vp_max ||
+ vbp < 0 || vbp > dispc.feat->vp_max)
+ return false;
return true;
}
@@ -2654,19 +2961,12 @@ static void _dispc_mgr_set_lcd_timings(enum omap_channel channel, int hsw,
u32 timing_h, timing_v, l;
bool onoff, rf, ipc;
- if (cpu_is_omap24xx() || omap_rev() < OMAP3430_REV_ES3_0) {
- timing_h = FLD_VAL(hsw-1, 5, 0) | FLD_VAL(hfp-1, 15, 8) |
- FLD_VAL(hbp-1, 27, 20);
-
- timing_v = FLD_VAL(vsw-1, 5, 0) | FLD_VAL(vfp, 15, 8) |
- FLD_VAL(vbp, 27, 20);
- } else {
- timing_h = FLD_VAL(hsw-1, 7, 0) | FLD_VAL(hfp-1, 19, 8) |
- FLD_VAL(hbp-1, 31, 20);
-
- timing_v = FLD_VAL(vsw-1, 7, 0) | FLD_VAL(vfp, 19, 8) |
- FLD_VAL(vbp, 31, 20);
- }
+ timing_h = FLD_VAL(hsw-1, dispc.feat->sw_start, 0) |
+ FLD_VAL(hfp-1, dispc.feat->fp_start, 8) |
+ FLD_VAL(hbp-1, dispc.feat->bp_start, 20);
+ timing_v = FLD_VAL(vsw-1, dispc.feat->sw_start, 0) |
+ FLD_VAL(vfp, dispc.feat->fp_start, 8) |
+ FLD_VAL(vbp, dispc.feat->bp_start, 20);
dispc_write_reg(DISPC_TIMING_H(channel), timing_h);
dispc_write_reg(DISPC_TIMING_V(channel), timing_v);
@@ -2872,6 +3172,23 @@ unsigned long dispc_core_clk_rate(void)
return fclk / lcd;
}
+static unsigned long dispc_plane_pclk_rate(enum omap_plane plane)
+{
+ enum omap_channel channel = dispc_ovl_get_channel_out(plane);
+
+ return dispc_mgr_pclk_rate(channel);
+}
+
+static unsigned long dispc_plane_lclk_rate(enum omap_plane plane)
+{
+ enum omap_channel channel = dispc_ovl_get_channel_out(plane);
+
+ if (dss_mgr_is_lcd(channel))
+ return dispc_mgr_lclk_rate(channel);
+ else
+ return dispc_fclk_rate();
+
+}
static void dispc_dump_clocks_channel(struct seq_file *s, enum omap_channel channel)
{
int lcd, pcd;
@@ -3492,7 +3809,7 @@ static void dispc_error_worker(struct work_struct *work)
ovl->name);
dispc_ovl_enable(ovl->id, false);
dispc_mgr_go(ovl->manager->id);
- mdelay(50);
+ msleep(50);
}
}
@@ -3504,7 +3821,7 @@ static void dispc_error_worker(struct work_struct *work)
bit = mgr_desc[i].sync_lost_irq;
if (bit & errors) {
- struct omap_dss_device *dssdev = mgr->device;
+ struct omap_dss_device *dssdev = mgr->get_device(mgr);
bool enable;
DSSERR("SYNC_LOST on channel %s, restarting the output "
@@ -3524,7 +3841,7 @@ static void dispc_error_worker(struct work_struct *work)
}
dispc_mgr_go(mgr->id);
- mdelay(50);
+ msleep(50);
if (enable)
dssdev->driver->enable(dssdev);
@@ -3535,9 +3852,13 @@ static void dispc_error_worker(struct work_struct *work)
DSSERR("OCP_ERR\n");
for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
struct omap_overlay_manager *mgr;
+ struct omap_dss_device *dssdev;
+
mgr = omap_dss_get_overlay_manager(i);
- if (mgr->device && mgr->device->driver)
- mgr->device->driver->disable(mgr->device);
+ dssdev = mgr->get_device(mgr);
+
+ if (dssdev && dssdev->driver)
+ dssdev->driver->disable(dssdev);
}
}
@@ -3661,17 +3982,98 @@ static void _omap_dispc_initial_config(void)
if (dss_has_feature(FEAT_FUNCGATED))
REG_FLD_MOD(DISPC_CONFIG, 1, 9, 9);
- _dispc_setup_color_conv_coef();
+ dispc_setup_color_conv_coef();
dispc_set_loadmode(OMAP_DSS_LOAD_FRAME_ONLY);
- dispc_read_plane_fifo_sizes();
+ dispc_init_fifos();
dispc_configure_burst_sizes();
dispc_ovl_enable_zorder_planes();
}
+static const struct dispc_features omap24xx_dispc_feats __initconst = {
+ .sw_start = 5,
+ .fp_start = 15,
+ .bp_start = 27,
+ .sw_max = 64,
+ .vp_max = 255,
+ .hp_max = 256,
+ .calc_scaling = dispc_ovl_calc_scaling_24xx,
+ .calc_core_clk = calc_core_clk_24xx,
+ .num_fifos = 3,
+};
+
+static const struct dispc_features omap34xx_rev1_0_dispc_feats __initconst = {
+ .sw_start = 5,
+ .fp_start = 15,
+ .bp_start = 27,
+ .sw_max = 64,
+ .vp_max = 255,
+ .hp_max = 256,
+ .calc_scaling = dispc_ovl_calc_scaling_34xx,
+ .calc_core_clk = calc_core_clk_34xx,
+ .num_fifos = 3,
+};
+
+static const struct dispc_features omap34xx_rev3_0_dispc_feats __initconst = {
+ .sw_start = 7,
+ .fp_start = 19,
+ .bp_start = 31,
+ .sw_max = 256,
+ .vp_max = 4095,
+ .hp_max = 4096,
+ .calc_scaling = dispc_ovl_calc_scaling_34xx,
+ .calc_core_clk = calc_core_clk_34xx,
+ .num_fifos = 3,
+};
+
+static const struct dispc_features omap44xx_dispc_feats __initconst = {
+ .sw_start = 7,
+ .fp_start = 19,
+ .bp_start = 31,
+ .sw_max = 256,
+ .vp_max = 4095,
+ .hp_max = 4096,
+ .calc_scaling = dispc_ovl_calc_scaling_44xx,
+ .calc_core_clk = calc_core_clk_44xx,
+ .num_fifos = 5,
+ .gfx_fifo_workaround = true,
+};
+
+static int __init dispc_init_features(struct device *dev)
+{
+ const struct dispc_features *src;
+ struct dispc_features *dst;
+
+ dst = devm_kzalloc(dev, sizeof(*dst), GFP_KERNEL);
+ if (!dst) {
+ dev_err(dev, "Failed to allocate DISPC Features\n");
+ return -ENOMEM;
+ }
+
+ if (cpu_is_omap24xx()) {
+ src = &omap24xx_dispc_feats;
+ } else if (cpu_is_omap34xx()) {
+ if (omap_rev() < OMAP3430_REV_ES3_0)
+ src = &omap34xx_rev1_0_dispc_feats;
+ else
+ src = &omap34xx_rev3_0_dispc_feats;
+ } else if (cpu_is_omap44xx()) {
+ src = &omap44xx_dispc_feats;
+ } else if (soc_is_omap54xx()) {
+ src = &omap44xx_dispc_feats;
+ } else {
+ return -ENODEV;
+ }
+
+ memcpy(dst, src, sizeof(*dst));
+ dispc.feat = dst;
+
+ return 0;
+}
+
/* DISPC HW IP initialisation */
static int __init omap_dispchw_probe(struct platform_device *pdev)
{
@@ -3682,6 +4084,10 @@ static int __init omap_dispchw_probe(struct platform_device *pdev)
dispc.pdev = pdev;
+ r = dispc_init_features(&dispc.pdev->dev);
+ if (r)
+ return r;
+
spin_lock_init(&dispc.irq_lock);
#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
diff --git a/drivers/video/omap2/dss/dispc.h b/drivers/video/omap2/dss/dispc.h
index 92d8a9b..222363c6 100644
--- a/drivers/video/omap2/dss/dispc.h
+++ b/drivers/video/omap2/dss/dispc.h
@@ -36,6 +36,7 @@
#define DISPC_CONTROL2 0x0238
#define DISPC_CONFIG2 0x0620
#define DISPC_DIVISOR 0x0804
+#define DISPC_GLOBAL_BUFFER 0x0800
#define DISPC_CONTROL3 0x0848
#define DISPC_CONFIG3 0x084C
@@ -355,6 +356,8 @@ static inline u16 DISPC_OVL_BASE(enum omap_plane plane)
return 0x014C;
case OMAP_DSS_VIDEO3:
return 0x0300;
+ case OMAP_DSS_WB:
+ return 0x0500;
default:
BUG();
return 0;
@@ -370,6 +373,7 @@ static inline u16 DISPC_BA0_OFFSET(enum omap_plane plane)
case OMAP_DSS_VIDEO2:
return 0x0000;
case OMAP_DSS_VIDEO3:
+ case OMAP_DSS_WB:
return 0x0008;
default:
BUG();
@@ -385,6 +389,7 @@ static inline u16 DISPC_BA1_OFFSET(enum omap_plane plane)
case OMAP_DSS_VIDEO2:
return 0x0004;
case OMAP_DSS_VIDEO3:
+ case OMAP_DSS_WB:
return 0x000C;
default:
BUG();
@@ -404,6 +409,8 @@ static inline u16 DISPC_BA0_UV_OFFSET(enum omap_plane plane)
return 0x04BC;
case OMAP_DSS_VIDEO3:
return 0x0310;
+ case OMAP_DSS_WB:
+ return 0x0118;
default:
BUG();
return 0;
@@ -422,6 +429,8 @@ static inline u16 DISPC_BA1_UV_OFFSET(enum omap_plane plane)
return 0x04C0;
case OMAP_DSS_VIDEO3:
return 0x0314;
+ case OMAP_DSS_WB:
+ return 0x011C;
default:
BUG();
return 0;
@@ -451,6 +460,7 @@ static inline u16 DISPC_SIZE_OFFSET(enum omap_plane plane)
case OMAP_DSS_VIDEO2:
return 0x000C;
case OMAP_DSS_VIDEO3:
+ case OMAP_DSS_WB:
return 0x00A8;
default:
BUG();
@@ -467,6 +477,7 @@ static inline u16 DISPC_ATTR_OFFSET(enum omap_plane plane)
case OMAP_DSS_VIDEO2:
return 0x0010;
case OMAP_DSS_VIDEO3:
+ case OMAP_DSS_WB:
return 0x0070;
default:
BUG();
@@ -486,6 +497,8 @@ static inline u16 DISPC_ATTR2_OFFSET(enum omap_plane plane)
return 0x04DC;
case OMAP_DSS_VIDEO3:
return 0x032C;
+ case OMAP_DSS_WB:
+ return 0x0310;
default:
BUG();
return 0;
@@ -501,6 +514,7 @@ static inline u16 DISPC_FIFO_THRESH_OFFSET(enum omap_plane plane)
case OMAP_DSS_VIDEO2:
return 0x0014;
case OMAP_DSS_VIDEO3:
+ case OMAP_DSS_WB:
return 0x008C;
default:
BUG();
@@ -517,6 +531,7 @@ static inline u16 DISPC_FIFO_SIZE_STATUS_OFFSET(enum omap_plane plane)
case OMAP_DSS_VIDEO2:
return 0x0018;
case OMAP_DSS_VIDEO3:
+ case OMAP_DSS_WB:
return 0x0088;
default:
BUG();
@@ -533,6 +548,7 @@ static inline u16 DISPC_ROW_INC_OFFSET(enum omap_plane plane)
case OMAP_DSS_VIDEO2:
return 0x001C;
case OMAP_DSS_VIDEO3:
+ case OMAP_DSS_WB:
return 0x00A4;
default:
BUG();
@@ -549,6 +565,7 @@ static inline u16 DISPC_PIX_INC_OFFSET(enum omap_plane plane)
case OMAP_DSS_VIDEO2:
return 0x0020;
case OMAP_DSS_VIDEO3:
+ case OMAP_DSS_WB:
return 0x0098;
default:
BUG();
@@ -598,6 +615,7 @@ static inline u16 DISPC_FIR_OFFSET(enum omap_plane plane)
case OMAP_DSS_VIDEO2:
return 0x0024;
case OMAP_DSS_VIDEO3:
+ case OMAP_DSS_WB:
return 0x0090;
default:
BUG();
@@ -617,6 +635,8 @@ static inline u16 DISPC_FIR2_OFFSET(enum omap_plane plane)
return 0x055C;
case OMAP_DSS_VIDEO3:
return 0x0424;
+ case OMAP_DSS_WB:
+ return 0x290;
default:
BUG();
return 0;
@@ -633,6 +653,7 @@ static inline u16 DISPC_PIC_SIZE_OFFSET(enum omap_plane plane)
case OMAP_DSS_VIDEO2:
return 0x0028;
case OMAP_DSS_VIDEO3:
+ case OMAP_DSS_WB:
return 0x0094;
default:
BUG();
@@ -651,6 +672,7 @@ static inline u16 DISPC_ACCU0_OFFSET(enum omap_plane plane)
case OMAP_DSS_VIDEO2:
return 0x002C;
case OMAP_DSS_VIDEO3:
+ case OMAP_DSS_WB:
return 0x0000;
default:
BUG();
@@ -670,6 +692,8 @@ static inline u16 DISPC_ACCU2_0_OFFSET(enum omap_plane plane)
return 0x0560;
case OMAP_DSS_VIDEO3:
return 0x0428;
+ case OMAP_DSS_WB:
+ return 0x0294;
default:
BUG();
return 0;
@@ -686,6 +710,7 @@ static inline u16 DISPC_ACCU1_OFFSET(enum omap_plane plane)
case OMAP_DSS_VIDEO2:
return 0x0030;
case OMAP_DSS_VIDEO3:
+ case OMAP_DSS_WB:
return 0x0004;
default:
BUG();
@@ -705,6 +730,8 @@ static inline u16 DISPC_ACCU2_1_OFFSET(enum omap_plane plane)
return 0x0564;
case OMAP_DSS_VIDEO3:
return 0x042C;
+ case OMAP_DSS_WB:
+ return 0x0298;
default:
BUG();
return 0;
@@ -722,6 +749,7 @@ static inline u16 DISPC_FIR_COEF_H_OFFSET(enum omap_plane plane, u16 i)
case OMAP_DSS_VIDEO2:
return 0x0034 + i * 0x8;
case OMAP_DSS_VIDEO3:
+ case OMAP_DSS_WB:
return 0x0010 + i * 0x8;
default:
BUG();
@@ -742,6 +770,8 @@ static inline u16 DISPC_FIR_COEF_H2_OFFSET(enum omap_plane plane, u16 i)
return 0x0568 + i * 0x8;
case OMAP_DSS_VIDEO3:
return 0x0430 + i * 0x8;
+ case OMAP_DSS_WB:
+ return 0x02A0 + i * 0x8;
default:
BUG();
return 0;
@@ -759,6 +789,7 @@ static inline u16 DISPC_FIR_COEF_HV_OFFSET(enum omap_plane plane, u16 i)
case OMAP_DSS_VIDEO2:
return 0x0038 + i * 0x8;
case OMAP_DSS_VIDEO3:
+ case OMAP_DSS_WB:
return 0x0014 + i * 0x8;
default:
BUG();
@@ -779,6 +810,8 @@ static inline u16 DISPC_FIR_COEF_HV2_OFFSET(enum omap_plane plane, u16 i)
return 0x056C + i * 0x8;
case OMAP_DSS_VIDEO3:
return 0x0434 + i * 0x8;
+ case OMAP_DSS_WB:
+ return 0x02A4 + i * 0x8;
default:
BUG();
return 0;
@@ -795,6 +828,7 @@ static inline u16 DISPC_CONV_COEF_OFFSET(enum omap_plane plane, u16 i)
case OMAP_DSS_VIDEO1:
case OMAP_DSS_VIDEO2:
case OMAP_DSS_VIDEO3:
+ case OMAP_DSS_WB:
return 0x0074 + i * 0x4;
default:
BUG();
@@ -814,6 +848,7 @@ static inline u16 DISPC_FIR_COEF_V_OFFSET(enum omap_plane plane, u16 i)
case OMAP_DSS_VIDEO2:
return 0x00B4 + i * 0x4;
case OMAP_DSS_VIDEO3:
+ case OMAP_DSS_WB:
return 0x0050 + i * 0x4;
default:
BUG();
@@ -834,6 +869,8 @@ static inline u16 DISPC_FIR_COEF_V2_OFFSET(enum omap_plane plane, u16 i)
return 0x05A8 + i * 0x4;
case OMAP_DSS_VIDEO3:
return 0x0470 + i * 0x4;
+ case OMAP_DSS_WB:
+ return 0x02E0 + i * 0x4;
default:
BUG();
return 0;
diff --git a/drivers/video/omap2/dss/display.c b/drivers/video/omap2/dss/display.c
index 5bd957e..ccf8550 100644
--- a/drivers/video/omap2/dss/display.c
+++ b/drivers/video/omap2/dss/display.c
@@ -142,7 +142,11 @@ static ssize_t display_timings_store(struct device *dev,
if (r)
return r;
+ dssdev->driver->disable(dssdev);
dssdev->driver->set_timings(dssdev, &t);
+ r = dssdev->driver->enable(dssdev);
+ if (r)
+ return r;
return size;
}
@@ -316,26 +320,117 @@ void omapdss_default_get_timings(struct omap_dss_device *dssdev,
}
EXPORT_SYMBOL(omapdss_default_get_timings);
-void dss_init_device(struct platform_device *pdev,
+/*
+ * Connect dssdev to a manager if the manager is free or if force is specified.
+ * Connect all overlays to that manager if they are free or if force is
+ * specified.
+ */
+static int dss_init_connections(struct omap_dss_device *dssdev, bool force)
+{
+ struct omap_dss_output *out;
+ struct omap_overlay_manager *mgr;
+ int i, r;
+
+ out = omapdss_get_output_from_dssdev(dssdev);
+
+ WARN_ON(dssdev->output);
+ WARN_ON(out->device);
+
+ r = omapdss_output_set_device(out, dssdev);
+ if (r) {
+ DSSERR("failed to connect output to new device\n");
+ return r;
+ }
+
+ mgr = omap_dss_get_overlay_manager(dssdev->channel);
+
+ if (mgr->output && !force)
+ return 0;
+
+ if (mgr->output)
+ mgr->unset_output(mgr);
+
+ r = mgr->set_output(mgr, out);
+ if (r) {
+ DSSERR("failed to connect manager to output of new device\n");
+
+ /* remove the output-device connection we just made */
+ omapdss_output_unset_device(out);
+ return r;
+ }
+
+ for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
+ struct omap_overlay *ovl = omap_dss_get_overlay(i);
+
+ if (!ovl->manager || force) {
+ if (ovl->manager)
+ ovl->unset_manager(ovl);
+
+ r = ovl->set_manager(ovl, mgr);
+ if (r) {
+ DSSERR("failed to set initial overlay\n");
+ return r;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static void dss_uninit_connections(struct omap_dss_device *dssdev)
+{
+ if (dssdev->output) {
+ struct omap_overlay_manager *mgr = dssdev->output->manager;
+
+ if (mgr)
+ mgr->unset_output(mgr);
+
+ omapdss_output_unset_device(dssdev->output);
+ }
+}
+
+int dss_init_device(struct platform_device *pdev,
struct omap_dss_device *dssdev)
{
struct device_attribute *attr;
- int i;
- int r;
+ int i, r;
+ const char *def_disp_name = dss_get_default_display_name();
+ bool force;
+
+ force = def_disp_name && strcmp(def_disp_name, dssdev->name) == 0;
+ dss_init_connections(dssdev, force);
/* create device sysfs files */
i = 0;
while ((attr = display_sysfs_attrs[i++]) != NULL) {
r = device_create_file(&dssdev->dev, attr);
- if (r)
+ if (r) {
+ for (i = i - 2; i >= 0; i--) {
+ attr = display_sysfs_attrs[i];
+ device_remove_file(&dssdev->dev, attr);
+ }
+
+ dss_uninit_connections(dssdev);
+
DSSERR("failed to create sysfs file\n");
+ return r;
+ }
}
/* create display? sysfs links */
r = sysfs_create_link(&pdev->dev.kobj, &dssdev->dev.kobj,
dev_name(&dssdev->dev));
- if (r)
+ if (r) {
+ while ((attr = display_sysfs_attrs[i++]) != NULL)
+ device_remove_file(&dssdev->dev, attr);
+
+ dss_uninit_connections(dssdev);
+
DSSERR("failed to create sysfs display link\n");
+ return r;
+ }
+
+ return 0;
}
void dss_uninit_device(struct platform_device *pdev,
@@ -349,8 +444,7 @@ void dss_uninit_device(struct platform_device *pdev,
while ((attr = display_sysfs_attrs[i++]) != NULL)
device_remove_file(&dssdev->dev, attr);
- if (dssdev->manager)
- dssdev->manager->unset_device(dssdev->manager);
+ dss_uninit_connections(dssdev);
}
static int dss_suspend_device(struct device *dev, void *data)
diff --git a/drivers/video/omap2/dss/dpi.c b/drivers/video/omap2/dss/dpi.c
index 3266be2..56748cf 100644
--- a/drivers/video/omap2/dss/dpi.c
+++ b/drivers/video/omap2/dss/dpi.c
@@ -29,17 +29,24 @@
#include <linux/errno.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
+#include <linux/string.h>
#include <video/omapdss.h>
-#include <plat/cpu.h>
#include "dss.h"
+#include "dss_features.h"
static struct {
struct regulator *vdds_dsi_reg;
struct platform_device *dsidev;
+ struct mutex lock;
+
+ struct omap_video_timings timings;
struct dss_lcd_mgr_config mgr_config;
+ int data_lines;
+
+ struct omap_dss_output output;
} dpi;
static struct platform_device *dpi_get_dsidev(enum omap_dss_clk_source clk)
@@ -121,7 +128,8 @@ static int dpi_set_dispc_clk(struct omap_dss_device *dssdev,
static int dpi_set_mode(struct omap_dss_device *dssdev)
{
- struct omap_video_timings *t = &dssdev->panel.timings;
+ struct omap_video_timings *t = &dpi.timings;
+ struct omap_overlay_manager *mgr = dssdev->output->manager;
int lck_div = 0, pck_div = 0;
unsigned long fck = 0;
unsigned long pck;
@@ -146,37 +154,44 @@ static int dpi_set_mode(struct omap_dss_device *dssdev)
t->pixel_clock = pck;
}
- dss_mgr_set_timings(dssdev->manager, t);
+ dss_mgr_set_timings(mgr, t);
return 0;
}
static void dpi_config_lcd_manager(struct omap_dss_device *dssdev)
{
+ struct omap_overlay_manager *mgr = dssdev->output->manager;
+
dpi.mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS;
dpi.mgr_config.stallmode = false;
dpi.mgr_config.fifohandcheck = false;
- dpi.mgr_config.video_port_width = dssdev->phy.dpi.data_lines;
+ dpi.mgr_config.video_port_width = dpi.data_lines;
dpi.mgr_config.lcden_sig_polarity = 0;
- dss_mgr_set_lcd_config(dssdev->manager, &dpi.mgr_config);
+ dss_mgr_set_lcd_config(mgr, &dpi.mgr_config);
}
int omapdss_dpi_display_enable(struct omap_dss_device *dssdev)
{
+ struct omap_dss_output *out = dssdev->output;
int r;
- if (cpu_is_omap34xx() && !dpi.vdds_dsi_reg) {
+ mutex_lock(&dpi.lock);
+
+ if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI) && !dpi.vdds_dsi_reg) {
DSSERR("no VDSS_DSI regulator\n");
- return -ENODEV;
+ r = -ENODEV;
+ goto err_no_reg;
}
- if (dssdev->manager == NULL) {
- DSSERR("failed to enable display: no manager\n");
- return -ENODEV;
+ if (out == NULL || out->manager == NULL) {
+ DSSERR("failed to enable display: no output/manager\n");
+ r = -ENODEV;
+ goto err_no_out_mgr;
}
r = omap_dss_start_device(dssdev);
@@ -185,7 +200,7 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev)
goto err_start_dev;
}
- if (cpu_is_omap34xx()) {
+ if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI)) {
r = regulator_enable(dpi.vdds_dsi_reg);
if (r)
goto err_reg_enable;
@@ -195,6 +210,10 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev)
if (r)
goto err_get_dispc;
+ r = dss_dpi_select_source(dssdev->channel);
+ if (r)
+ goto err_src_sel;
+
if (dpi_use_dsi_pll(dssdev)) {
r = dsi_runtime_get(dpi.dsidev);
if (r)
@@ -213,10 +232,12 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev)
mdelay(2);
- r = dss_mgr_enable(dssdev->manager);
+ r = dss_mgr_enable(out->manager);
if (r)
goto err_mgr_enable;
+ mutex_unlock(&dpi.lock);
+
return 0;
err_mgr_enable:
@@ -227,20 +248,28 @@ err_dsi_pll_init:
if (dpi_use_dsi_pll(dssdev))
dsi_runtime_put(dpi.dsidev);
err_get_dsi:
+err_src_sel:
dispc_runtime_put();
err_get_dispc:
- if (cpu_is_omap34xx())
+ if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI))
regulator_disable(dpi.vdds_dsi_reg);
err_reg_enable:
omap_dss_stop_device(dssdev);
err_start_dev:
+err_no_out_mgr:
+err_no_reg:
+ mutex_unlock(&dpi.lock);
return r;
}
EXPORT_SYMBOL(omapdss_dpi_display_enable);
void omapdss_dpi_display_disable(struct omap_dss_device *dssdev)
{
- dss_mgr_disable(dssdev->manager);
+ struct omap_overlay_manager *mgr = dssdev->output->manager;
+
+ mutex_lock(&dpi.lock);
+
+ dss_mgr_disable(mgr);
if (dpi_use_dsi_pll(dssdev)) {
dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK);
@@ -250,44 +279,39 @@ void omapdss_dpi_display_disable(struct omap_dss_device *dssdev)
dispc_runtime_put();
- if (cpu_is_omap34xx())
+ if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI))
regulator_disable(dpi.vdds_dsi_reg);
omap_dss_stop_device(dssdev);
+
+ mutex_unlock(&dpi.lock);
}
EXPORT_SYMBOL(omapdss_dpi_display_disable);
-void dpi_set_timings(struct omap_dss_device *dssdev,
- struct omap_video_timings *timings)
+void omapdss_dpi_set_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
{
- int r;
-
DSSDBG("dpi_set_timings\n");
- dssdev->panel.timings = *timings;
- if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) {
- r = dispc_runtime_get();
- if (r)
- return;
- dpi_set_mode(dssdev);
+ mutex_lock(&dpi.lock);
- dispc_runtime_put();
- } else {
- dss_mgr_set_timings(dssdev->manager, timings);
- }
+ dpi.timings = *timings;
+
+ mutex_unlock(&dpi.lock);
}
-EXPORT_SYMBOL(dpi_set_timings);
+EXPORT_SYMBOL(omapdss_dpi_set_timings);
int dpi_check_timings(struct omap_dss_device *dssdev,
struct omap_video_timings *timings)
{
int r;
+ struct omap_overlay_manager *mgr = dssdev->output->manager;
int lck_div, pck_div;
unsigned long fck;
unsigned long pck;
struct dispc_clock_info dispc_cinfo;
- if (dss_mgr_check_timings(dssdev->manager, timings))
+ if (dss_mgr_check_timings(mgr, timings))
return -EINVAL;
if (timings->pixel_clock == 0)
@@ -325,11 +349,22 @@ int dpi_check_timings(struct omap_dss_device *dssdev,
}
EXPORT_SYMBOL(dpi_check_timings);
+void omapdss_dpi_set_data_lines(struct omap_dss_device *dssdev, int data_lines)
+{
+ mutex_lock(&dpi.lock);
+
+ dpi.data_lines = data_lines;
+
+ mutex_unlock(&dpi.lock);
+}
+EXPORT_SYMBOL(omapdss_dpi_set_data_lines);
+
static int __init dpi_init_display(struct omap_dss_device *dssdev)
{
DSSDBG("init_display\n");
- if (cpu_is_omap34xx() && dpi.vdds_dsi_reg == NULL) {
+ if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI) &&
+ dpi.vdds_dsi_reg == NULL) {
struct regulator *vdds_dsi;
vdds_dsi = dss_get_vdds_dsi();
@@ -351,10 +386,14 @@ static int __init dpi_init_display(struct omap_dss_device *dssdev)
return 0;
}
-static void __init dpi_probe_pdata(struct platform_device *pdev)
+static struct omap_dss_device * __init dpi_find_dssdev(struct platform_device *pdev)
{
struct omap_dss_board_info *pdata = pdev->dev.platform_data;
- int i, r;
+ const char *def_disp_name = dss_get_default_display_name();
+ struct omap_dss_device *def_dssdev;
+ int i;
+
+ def_dssdev = NULL;
for (i = 0; i < pdata->num_devices; ++i) {
struct omap_dss_device *dssdev = pdata->devices[i];
@@ -362,21 +401,75 @@ static void __init dpi_probe_pdata(struct platform_device *pdev)
if (dssdev->type != OMAP_DISPLAY_TYPE_DPI)
continue;
- r = dpi_init_display(dssdev);
- if (r) {
- DSSERR("device %s init failed: %d\n", dssdev->name, r);
- continue;
+ if (def_dssdev == NULL)
+ def_dssdev = dssdev;
+
+ if (def_disp_name != NULL &&
+ strcmp(dssdev->name, def_disp_name) == 0) {
+ def_dssdev = dssdev;
+ break;
}
+ }
- r = omap_dss_register_device(dssdev, &pdev->dev, i);
- if (r)
- DSSERR("device %s register failed: %d\n",
- dssdev->name, r);
+ return def_dssdev;
+}
+
+static void __init dpi_probe_pdata(struct platform_device *dpidev)
+{
+ struct omap_dss_device *plat_dssdev;
+ struct omap_dss_device *dssdev;
+ int r;
+
+ plat_dssdev = dpi_find_dssdev(dpidev);
+
+ if (!plat_dssdev)
+ return;
+
+ dssdev = dss_alloc_and_init_device(&dpidev->dev);
+ if (!dssdev)
+ return;
+
+ dss_copy_device_pdata(dssdev, plat_dssdev);
+
+ r = dpi_init_display(dssdev);
+ if (r) {
+ DSSERR("device %s init failed: %d\n", dssdev->name, r);
+ dss_put_device(dssdev);
+ return;
+ }
+
+ r = dss_add_device(dssdev);
+ if (r) {
+ DSSERR("device %s register failed: %d\n", dssdev->name, r);
+ dss_put_device(dssdev);
+ return;
}
}
+static void __init dpi_init_output(struct platform_device *pdev)
+{
+ struct omap_dss_output *out = &dpi.output;
+
+ out->pdev = pdev;
+ out->id = OMAP_DSS_OUTPUT_DPI;
+ out->type = OMAP_DISPLAY_TYPE_DPI;
+
+ dss_register_output(out);
+}
+
+static void __exit dpi_uninit_output(struct platform_device *pdev)
+{
+ struct omap_dss_output *out = &dpi.output;
+
+ dss_unregister_output(out);
+}
+
static int __init omap_dpi_probe(struct platform_device *pdev)
{
+ mutex_init(&dpi.lock);
+
+ dpi_init_output(pdev);
+
dpi_probe_pdata(pdev);
return 0;
@@ -384,7 +477,9 @@ static int __init omap_dpi_probe(struct platform_device *pdev)
static int __exit omap_dpi_remove(struct platform_device *pdev)
{
- omap_dss_unregister_child_devices(&pdev->dev);
+ dss_unregister_child_devices(&pdev->dev);
+
+ dpi_uninit_output(pdev);
return 0;
}
diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c
index 05ee046..d64ac38 100644
--- a/drivers/video/omap2/dss/dsi.c
+++ b/drivers/video/omap2/dss/dsi.c
@@ -41,7 +41,6 @@
#include <video/omapdss.h>
#include <video/mipi_display.h>
-#include <plat/clock.h>
#include "dss.h"
#include "dss_features.h"
@@ -333,6 +332,12 @@ struct dsi_data {
unsigned scp_clk_refcount;
struct dss_lcd_mgr_config mgr_config;
+ struct omap_video_timings timings;
+ enum omap_dss_dsi_pixel_format pix_fmt;
+ enum omap_dss_dsi_mode mode;
+ struct omap_dss_dsi_videomode_timings vm_timings;
+
+ struct omap_dss_output output;
};
struct dsi_packet_sent_handler_data {
@@ -340,8 +345,6 @@ struct dsi_packet_sent_handler_data {
struct completion *completion;
};
-static struct platform_device *dsi_pdev_map[MAX_NUM_DSI];
-
#ifdef DEBUG
static bool dsi_perf;
module_param(dsi_perf, bool, 0644);
@@ -354,12 +357,19 @@ static inline struct dsi_data *dsi_get_dsidrv_data(struct platform_device *dside
static inline struct platform_device *dsi_get_dsidev_from_dssdev(struct omap_dss_device *dssdev)
{
- return dsi_pdev_map[dssdev->phy.dsi.module];
+ return dssdev->output->pdev;
}
struct platform_device *dsi_get_dsidev_from_id(int module)
{
- return dsi_pdev_map[module];
+ struct omap_dss_output *out;
+ enum omap_dss_output_id id;
+
+ id = module == 0 ? OMAP_DSS_OUTPUT_DSI1 : OMAP_DSS_OUTPUT_DSI2;
+
+ out = omap_dss_get_output(id);
+
+ return out->pdev;
}
static inline void dsi_write_reg(struct platform_device *dsidev,
@@ -1450,6 +1460,148 @@ found:
return 0;
}
+static int dsi_pll_calc_ddrfreq(struct platform_device *dsidev,
+ unsigned long req_clkin4ddr, struct dsi_clock_info *cinfo)
+{
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+ struct dsi_clock_info cur, best;
+
+ DSSDBG("dsi_pll_calc_ddrfreq\n");
+
+ memset(&best, 0, sizeof(best));
+ memset(&cur, 0, sizeof(cur));
+
+ cur.clkin = clk_get_rate(dsi->sys_clk);
+
+ for (cur.regn = 1; cur.regn < dsi->regn_max; ++cur.regn) {
+ cur.fint = cur.clkin / cur.regn;
+
+ if (cur.fint > dsi->fint_max || cur.fint < dsi->fint_min)
+ continue;
+
+ /* DSIPHY(MHz) = (2 * regm / regn) * clkin */
+ for (cur.regm = 1; cur.regm < dsi->regm_max; ++cur.regm) {
+ unsigned long a, b;
+
+ a = 2 * cur.regm * (cur.clkin/1000);
+ b = cur.regn;
+ cur.clkin4ddr = a / b * 1000;
+
+ if (cur.clkin4ddr > 1800 * 1000 * 1000)
+ break;
+
+ if (abs(cur.clkin4ddr - req_clkin4ddr) <
+ abs(best.clkin4ddr - req_clkin4ddr)) {
+ best = cur;
+ DSSDBG("best %ld\n", best.clkin4ddr);
+ }
+
+ if (cur.clkin4ddr == req_clkin4ddr)
+ goto found;
+ }
+ }
+found:
+ if (cinfo)
+ *cinfo = best;
+
+ return 0;
+}
+
+static void dsi_pll_calc_dsi_fck(struct platform_device *dsidev,
+ struct dsi_clock_info *cinfo)
+{
+ unsigned long max_dsi_fck;
+
+ max_dsi_fck = dss_feat_get_param_max(FEAT_PARAM_DSI_FCK);
+
+ cinfo->regm_dsi = DIV_ROUND_UP(cinfo->clkin4ddr, max_dsi_fck);
+ cinfo->dsi_pll_hsdiv_dsi_clk = cinfo->clkin4ddr / cinfo->regm_dsi;
+}
+
+static int dsi_pll_calc_dispc_fck(struct platform_device *dsidev,
+ unsigned long req_pck, struct dsi_clock_info *cinfo,
+ struct dispc_clock_info *dispc_cinfo)
+{
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+ unsigned regm_dispc, best_regm_dispc;
+ unsigned long dispc_clk, best_dispc_clk;
+ int min_fck_per_pck;
+ unsigned long max_dss_fck;
+ struct dispc_clock_info best_dispc;
+ bool match;
+
+ max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK);
+
+ min_fck_per_pck = CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK;
+
+ if (min_fck_per_pck &&
+ req_pck * min_fck_per_pck > max_dss_fck) {
+ DSSERR("Requested pixel clock not possible with the current "
+ "OMAP2_DSS_MIN_FCK_PER_PCK setting. Turning "
+ "the constraint off.\n");
+ min_fck_per_pck = 0;
+ }
+
+retry:
+ best_regm_dispc = 0;
+ best_dispc_clk = 0;
+ memset(&best_dispc, 0, sizeof(best_dispc));
+ match = false;
+
+ for (regm_dispc = 1; regm_dispc < dsi->regm_dispc_max; ++regm_dispc) {
+ struct dispc_clock_info cur_dispc;
+
+ dispc_clk = cinfo->clkin4ddr / regm_dispc;
+
+ /* this will narrow down the search a bit,
+ * but still give pixclocks below what was
+ * requested */
+ if (dispc_clk < req_pck)
+ break;
+
+ if (dispc_clk > max_dss_fck)
+ continue;
+
+ if (min_fck_per_pck && dispc_clk < req_pck * min_fck_per_pck)
+ continue;
+
+ match = true;
+
+ dispc_find_clk_divs(req_pck, dispc_clk, &cur_dispc);
+
+ if (abs(cur_dispc.pck - req_pck) <
+ abs(best_dispc.pck - req_pck)) {
+ best_regm_dispc = regm_dispc;
+ best_dispc_clk = dispc_clk;
+ best_dispc = cur_dispc;
+
+ if (cur_dispc.pck == req_pck)
+ goto found;
+ }
+ }
+
+ if (!match) {
+ if (min_fck_per_pck) {
+ DSSERR("Could not find suitable clock settings.\n"
+ "Turning FCK/PCK constraint off and"
+ "trying again.\n");
+ min_fck_per_pck = 0;
+ goto retry;
+ }
+
+ DSSERR("Could not find suitable clock settings.\n");
+
+ return -EINVAL;
+ }
+found:
+ cinfo->regm_dispc = best_regm_dispc;
+ cinfo->dsi_pll_hsdiv_dispc_clk = best_dispc_clk;
+
+ *dispc_cinfo = best_dispc;
+
+ return 0;
+}
+
int dsi_pll_set_clock_div(struct platform_device *dsidev,
struct dsi_clock_info *cinfo)
{
@@ -1526,21 +1678,27 @@ int dsi_pll_set_clock_div(struct platform_device *dsidev,
BUG_ON(cinfo->fint < dsi->fint_min || cinfo->fint > dsi->fint_max);
+ l = dsi_read_reg(dsidev, DSI_PLL_CONFIGURATION2);
+
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);
-
- if (dss_has_feature(FEAT_DSI_PLL_FREQSEL))
l = FLD_MOD(l, f, 4, 1); /* DSI_PLL_FREQSEL */
+ } else if (dss_has_feature(FEAT_DSI_PLL_SELFREQDCO)) {
+ f = cinfo->clkin4ddr < 1000000000 ? 0x2 : 0x4;
+
+ l = FLD_MOD(l, f, 4, 1); /* PLL_SELFREQDCO */
+ }
+
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 */
+ if (dss_has_feature(FEAT_DSI_PLL_REFSEL))
+ l = FLD_MOD(l, 3, 22, 21); /* REF_SYSCLK = sysclk */
dsi_write_reg(dsidev, DSI_PLL_CONFIGURATION2, l);
REG_FLD_MOD(dsidev, DSI_PLL_GO, 1, 0, 0); /* DSI_PLL_GO */
@@ -2004,15 +2162,16 @@ static unsigned dsi_get_line_buf_size(struct platform_device *dsidev)
return 1194 * 3; /* 1194x24 bits */
case 6:
return 1365 * 3; /* 1365x24 bits */
+ case 7:
+ return 1920 * 3; /* 1920x24 bits */
default:
BUG();
return 0;
}
}
-static int dsi_set_lane_config(struct omap_dss_device *dssdev)
+static int dsi_set_lane_config(struct platform_device *dsidev)
{
- struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
static const u8 offsets[] = { 0, 4, 8, 12, 16 };
static const enum dsi_lane_function functions[] = {
@@ -2136,9 +2295,16 @@ static void dsi_cio_timings(struct platform_device *dsidev)
dsi_write_reg(dsidev, DSI_DSIPHY_CFG0, r);
r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG1);
- r = FLD_MOD(r, tlpx_half, 22, 16);
+ r = FLD_MOD(r, tlpx_half, 20, 16);
r = FLD_MOD(r, tclk_trail, 15, 8);
r = FLD_MOD(r, tclk_zero, 7, 0);
+
+ if (dss_has_feature(FEAT_DSI_PHY_DCC)) {
+ r = FLD_MOD(r, 0, 21, 21); /* DCCEN = disable */
+ r = FLD_MOD(r, 1, 22, 22); /* CLKINP_DIVBY2EN = enable */
+ r = FLD_MOD(r, 1, 23, 23); /* CLKINP_SEL = enable */
+ }
+
dsi_write_reg(dsidev, DSI_DSIPHY_CFG1, r);
r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG2);
@@ -2147,10 +2313,9 @@ static void dsi_cio_timings(struct platform_device *dsidev)
}
/* lane masks have lane 0 at lsb. mask_p for positive lines, n for negative */
-static void dsi_cio_enable_lane_override(struct omap_dss_device *dssdev,
+static void dsi_cio_enable_lane_override(struct platform_device *dsidev,
unsigned mask_p, unsigned mask_n)
{
- struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
int i;
u32 l;
@@ -2197,9 +2362,8 @@ static void dsi_cio_disable_lane_override(struct platform_device *dsidev)
REG_FLD_MOD(dsidev, DSI_DSIPHY_CFG10, 0, 22, 17);
}
-static int dsi_cio_wait_tx_clk_esc_reset(struct omap_dss_device *dssdev)
+static int dsi_cio_wait_tx_clk_esc_reset(struct platform_device *dsidev)
{
- struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
int t, i;
bool in_use[DSI_MAX_NR_LANES];
@@ -2247,9 +2411,8 @@ static int dsi_cio_wait_tx_clk_esc_reset(struct omap_dss_device *dssdev)
}
/* return bitmask of enabled lanes, lane0 being the lsb */
-static unsigned dsi_get_lane_mask(struct omap_dss_device *dssdev)
+static unsigned dsi_get_lane_mask(struct platform_device *dsidev)
{
- struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
unsigned mask = 0;
int i;
@@ -2262,16 +2425,15 @@ static unsigned dsi_get_lane_mask(struct omap_dss_device *dssdev)
return mask;
}
-static int dsi_cio_init(struct omap_dss_device *dssdev)
+static int dsi_cio_init(struct platform_device *dsidev)
{
- struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
int r;
u32 l;
DSSDBGF();
- r = dss_dsi_enable_pads(dsi->module_id, dsi_get_lane_mask(dssdev));
+ r = dss_dsi_enable_pads(dsi->module_id, dsi_get_lane_mask(dsidev));
if (r)
return r;
@@ -2288,7 +2450,7 @@ static int dsi_cio_init(struct omap_dss_device *dssdev)
goto err_scp_clk_dom;
}
- r = dsi_set_lane_config(dssdev);
+ r = dsi_set_lane_config(dsidev);
if (r)
goto err_scp_clk_dom;
@@ -2323,7 +2485,7 @@ static int dsi_cio_init(struct omap_dss_device *dssdev)
mask_p |= 1 << i;
}
- dsi_cio_enable_lane_override(dssdev, mask_p, 0);
+ dsi_cio_enable_lane_override(dsidev, mask_p, 0);
}
r = dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_ON);
@@ -2340,7 +2502,7 @@ static int dsi_cio_init(struct omap_dss_device *dssdev)
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);
+ r = dsi_cio_wait_tx_clk_esc_reset(dsidev);
if (r)
goto err_tx_clk_esc_rst;
@@ -2360,10 +2522,10 @@ static int dsi_cio_init(struct omap_dss_device *dssdev)
dsi_cio_timings(dsidev);
- if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_VIDEO_MODE) {
+ if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) {
/* DDR_CLK_ALWAYS_ON */
REG_FLD_MOD(dsidev, DSI_CLK_CTRL,
- dssdev->panel.dsi_vm_data.ddr_clk_always_on, 13, 13);
+ dsi->vm_timings.ddr_clk_always_on, 13, 13);
}
dsi->ulps_enabled = false;
@@ -2381,13 +2543,12 @@ err_cio_pwr:
dsi_cio_disable_lane_override(dsidev);
err_scp_clk_dom:
dsi_disable_scp_clk(dsidev);
- dss_dsi_disable_pads(dsi->module_id, dsi_get_lane_mask(dssdev));
+ dss_dsi_disable_pads(dsi->module_id, dsi_get_lane_mask(dsidev));
return r;
}
-static void dsi_cio_uninit(struct omap_dss_device *dssdev)
+static void dsi_cio_uninit(struct platform_device *dsidev)
{
- struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
/* DDR_CLK_ALWAYS_ON */
@@ -2395,7 +2556,7 @@ static void dsi_cio_uninit(struct omap_dss_device *dssdev)
dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_OFF);
dsi_disable_scp_clk(dsidev);
- dss_dsi_disable_pads(dsi->module_id, dsi_get_lane_mask(dssdev));
+ dss_dsi_disable_pads(dsi->module_id, dsi_get_lane_mask(dsidev));
}
static void dsi_config_tx_fifo(struct platform_device *dsidev,
@@ -2685,6 +2846,7 @@ 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);
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
DSSDBG("dsi_vc_enable_hs(%d, %d)\n", channel, enable);
@@ -2701,7 +2863,7 @@ void omapdss_dsi_vc_enable_hs(struct omap_dss_device *dssdev, int channel,
dsi_force_tx_stop_mode_io(dsidev);
/* start the DDR clock by sending a NULL packet */
- if (dssdev->panel.dsi_vm_data.ddr_clk_always_on && enable)
+ if (dsi->vm_timings.ddr_clk_always_on && enable)
dsi_vc_send_null(dssdev, channel);
}
EXPORT_SYMBOL(omapdss_dsi_vc_enable_hs);
@@ -2987,10 +3149,9 @@ int dsi_vc_send_null(struct omap_dss_device *dssdev, int channel)
}
EXPORT_SYMBOL(dsi_vc_send_null);
-static int dsi_vc_write_nosync_common(struct omap_dss_device *dssdev,
+static int dsi_vc_write_nosync_common(struct platform_device *dsidev,
int channel, u8 *data, int len, enum dss_dsi_content_type type)
{
- struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
int r;
if (len == 0) {
@@ -3021,7 +3182,9 @@ static int dsi_vc_write_nosync_common(struct omap_dss_device *dssdev,
int dsi_vc_dcs_write_nosync(struct omap_dss_device *dssdev, int channel,
u8 *data, int len)
{
- return dsi_vc_write_nosync_common(dssdev, channel, data, len,
+ struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+
+ return dsi_vc_write_nosync_common(dsidev, channel, data, len,
DSS_DSI_CONTENT_DCS);
}
EXPORT_SYMBOL(dsi_vc_dcs_write_nosync);
@@ -3029,7 +3192,9 @@ EXPORT_SYMBOL(dsi_vc_dcs_write_nosync);
int dsi_vc_generic_write_nosync(struct omap_dss_device *dssdev, int channel,
u8 *data, int len)
{
- return dsi_vc_write_nosync_common(dssdev, channel, data, len,
+ struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+
+ return dsi_vc_write_nosync_common(dsidev, channel, data, len,
DSS_DSI_CONTENT_GENERIC);
}
EXPORT_SYMBOL(dsi_vc_generic_write_nosync);
@@ -3040,7 +3205,7 @@ static int dsi_vc_write_common(struct omap_dss_device *dssdev, int channel,
struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
int r;
- r = dsi_vc_write_nosync_common(dssdev, channel, data, len, type);
+ r = dsi_vc_write_nosync_common(dsidev, channel, data, len, type);
if (r)
goto err;
@@ -3118,10 +3283,9 @@ int dsi_vc_generic_write_2(struct omap_dss_device *dssdev, int channel,
}
EXPORT_SYMBOL(dsi_vc_generic_write_2);
-static int dsi_vc_dcs_send_read_request(struct omap_dss_device *dssdev,
+static int dsi_vc_dcs_send_read_request(struct platform_device *dsidev,
int channel, u8 dcs_cmd)
{
- struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
int r;
@@ -3139,10 +3303,9 @@ static int dsi_vc_dcs_send_read_request(struct omap_dss_device *dssdev,
return 0;
}
-static int dsi_vc_generic_send_read_request(struct omap_dss_device *dssdev,
+static int dsi_vc_generic_send_read_request(struct platform_device *dsidev,
int channel, u8 *reqdata, int reqlen)
{
- struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
u16 data;
u8 data_type;
@@ -3291,7 +3454,7 @@ int dsi_vc_dcs_read(struct omap_dss_device *dssdev, int channel, u8 dcs_cmd,
struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
int r;
- r = dsi_vc_dcs_send_read_request(dssdev, channel, dcs_cmd);
+ r = dsi_vc_dcs_send_read_request(dsidev, channel, dcs_cmd);
if (r)
goto err;
@@ -3322,7 +3485,7 @@ static int dsi_vc_generic_read(struct omap_dss_device *dssdev, int channel,
struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
int r;
- r = dsi_vc_generic_send_read_request(dssdev, channel, reqdata, reqlen);
+ r = dsi_vc_generic_send_read_request(dsidev, channel, reqdata, reqlen);
if (r)
return r;
@@ -3604,15 +3767,15 @@ static void dsi_set_hs_tx_timeout(struct platform_device *dsidev,
(total_ticks * 1000) / (fck / 1000 / 1000));
}
-static void dsi_config_vp_num_line_buffers(struct omap_dss_device *dssdev)
+static void dsi_config_vp_num_line_buffers(struct platform_device *dsidev)
{
- struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
int num_line_buffers;
- if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_VIDEO_MODE) {
- int bpp = dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt);
+ if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) {
+ int bpp = dsi_get_pixel_size(dsi->pix_fmt);
unsigned line_buf_size = dsi_get_line_buf_size(dsidev);
- struct omap_video_timings *timings = &dssdev->panel.timings;
+ struct omap_video_timings *timings = &dsi->timings;
/*
* Don't use line buffers if width is greater than the video
* port's line buffer size
@@ -3630,11 +3793,11 @@ static void dsi_config_vp_num_line_buffers(struct omap_dss_device *dssdev)
REG_FLD_MOD(dsidev, DSI_CTRL, num_line_buffers, 13, 12);
}
-static void dsi_config_vp_sync_events(struct omap_dss_device *dssdev)
+static void dsi_config_vp_sync_events(struct platform_device *dsidev)
{
- struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
- bool vsync_end = dssdev->panel.dsi_vm_data.vp_vsync_end;
- bool hsync_end = dssdev->panel.dsi_vm_data.vp_hsync_end;
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+ bool vsync_end = dsi->vm_timings.vp_vsync_end;
+ bool hsync_end = dsi->vm_timings.vp_hsync_end;
u32 r;
r = dsi_read_reg(dsidev, DSI_CTRL);
@@ -3648,13 +3811,13 @@ static void dsi_config_vp_sync_events(struct omap_dss_device *dssdev)
dsi_write_reg(dsidev, DSI_CTRL, r);
}
-static void dsi_config_blanking_modes(struct omap_dss_device *dssdev)
+static void dsi_config_blanking_modes(struct platform_device *dsidev)
{
- struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
- int blanking_mode = dssdev->panel.dsi_vm_data.blanking_mode;
- int hfp_blanking_mode = dssdev->panel.dsi_vm_data.hfp_blanking_mode;
- int hbp_blanking_mode = dssdev->panel.dsi_vm_data.hbp_blanking_mode;
- int hsa_blanking_mode = dssdev->panel.dsi_vm_data.hsa_blanking_mode;
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+ int blanking_mode = dsi->vm_timings.blanking_mode;
+ int hfp_blanking_mode = dsi->vm_timings.hfp_blanking_mode;
+ int hbp_blanking_mode = dsi->vm_timings.hbp_blanking_mode;
+ int hsa_blanking_mode = dsi->vm_timings.hsa_blanking_mode;
u32 r;
/*
@@ -3741,8 +3904,8 @@ static void dsi_config_cmd_mode_interleaving(struct omap_dss_device *dssdev)
int ddr_clk_pre, ddr_clk_post, enter_hs_mode_lat, exit_hs_mode_lat;
int tclk_trail, ths_exit, exiths_clk;
bool ddr_alwon;
- struct omap_video_timings *timings = &dssdev->panel.timings;
- int bpp = dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt);
+ struct omap_video_timings *timings = &dsi->timings;
+ int bpp = dsi_get_pixel_size(dsi->pix_fmt);
int ndl = dsi->num_lanes_used - 1;
int dsi_fclk_hsdiv = dssdev->clocks.dsi.regm_dsi + 1;
int hsa_interleave_hs = 0, hsa_interleave_lp = 0;
@@ -3852,6 +4015,7 @@ static void dsi_config_cmd_mode_interleaving(struct omap_dss_device *dssdev)
static int dsi_proto_config(struct omap_dss_device *dssdev)
{
struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
u32 r;
int buswidth = 0;
@@ -3871,7 +4035,7 @@ static int dsi_proto_config(struct omap_dss_device *dssdev)
dsi_set_lp_rx_timeout(dsidev, 0x1fff, true, true);
dsi_set_hs_tx_timeout(dsidev, 0x1fff, true, true);
- switch (dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt)) {
+ switch (dsi_get_pixel_size(dsi->pix_fmt)) {
case 16:
buswidth = 0;
break;
@@ -3903,11 +4067,11 @@ static int dsi_proto_config(struct omap_dss_device *dssdev)
dsi_write_reg(dsidev, DSI_CTRL, r);
- dsi_config_vp_num_line_buffers(dssdev);
+ dsi_config_vp_num_line_buffers(dsidev);
- if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_VIDEO_MODE) {
- dsi_config_vp_sync_events(dssdev);
- dsi_config_blanking_modes(dssdev);
+ if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) {
+ dsi_config_vp_sync_events(dsidev);
+ dsi_config_blanking_modes(dsidev);
dsi_config_cmd_mode_interleaving(dssdev);
}
@@ -3919,9 +4083,8 @@ static int dsi_proto_config(struct omap_dss_device *dssdev)
return 0;
}
-static void dsi_proto_timings(struct omap_dss_device *dssdev)
+static void dsi_proto_timings(struct platform_device *dsidev)
{
- struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
unsigned tlpx, tclk_zero, tclk_prepare, tclk_trail;
unsigned tclk_pre, tclk_post;
@@ -3941,7 +4104,7 @@ static void dsi_proto_timings(struct omap_dss_device *dssdev)
ths_exit = FLD_GET(r, 7, 0);
r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG1);
- tlpx = FLD_GET(r, 22, 16) * 2;
+ tlpx = FLD_GET(r, 20, 16) * 2;
tclk_trail = FLD_GET(r, 15, 8);
tclk_zero = FLD_GET(r, 7, 0);
@@ -3984,18 +4147,18 @@ static void dsi_proto_timings(struct omap_dss_device *dssdev)
DSSDBG("enter_hs_mode_lat %u, exit_hs_mode_lat %u\n",
enter_hs_mode_lat, exit_hs_mode_lat);
- if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_VIDEO_MODE) {
+ if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) {
/* TODO: Implement a video mode check_timings function */
- int hsa = dssdev->panel.dsi_vm_data.hsa;
- int hfp = dssdev->panel.dsi_vm_data.hfp;
- int hbp = dssdev->panel.dsi_vm_data.hbp;
- int vsa = dssdev->panel.dsi_vm_data.vsa;
- int vfp = dssdev->panel.dsi_vm_data.vfp;
- int vbp = dssdev->panel.dsi_vm_data.vbp;
- int window_sync = dssdev->panel.dsi_vm_data.window_sync;
- bool hsync_end = dssdev->panel.dsi_vm_data.vp_hsync_end;
- struct omap_video_timings *timings = &dssdev->panel.timings;
- int bpp = dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt);
+ int hsa = dsi->vm_timings.hsa;
+ int hfp = dsi->vm_timings.hfp;
+ int hbp = dsi->vm_timings.hbp;
+ int vsa = dsi->vm_timings.vsa;
+ int vfp = dsi->vm_timings.vfp;
+ int vbp = dsi->vm_timings.vbp;
+ int window_sync = dsi->vm_timings.window_sync;
+ bool hsync_end = dsi->vm_timings.vp_hsync_end;
+ struct omap_video_timings *timings = &dsi->timings;
+ int bpp = dsi_get_pixel_size(dsi->pix_fmt);
int tl, t_he, width_bytes;
t_he = hsync_end ?
@@ -4100,16 +4263,84 @@ int omapdss_dsi_configure_pins(struct omap_dss_device *dssdev,
}
EXPORT_SYMBOL(omapdss_dsi_configure_pins);
-int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel)
+int omapdss_dsi_set_clocks(struct omap_dss_device *dssdev,
+ unsigned long ddr_clk, unsigned long lp_clk)
{
struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+ struct dsi_clock_info cinfo;
+ struct dispc_clock_info dispc_cinfo;
+ unsigned lp_clk_div;
+ unsigned long dsi_fclk;
int bpp = dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt);
+ unsigned long pck;
+ int r;
+
+ DSSDBGF("ddr_clk %lu, lp_clk %lu", ddr_clk, lp_clk);
+
+ mutex_lock(&dsi->lock);
+
+ /* Calculate PLL output clock */
+ r = dsi_pll_calc_ddrfreq(dsidev, ddr_clk * 4, &cinfo);
+ if (r)
+ goto err;
+
+ /* Calculate PLL's DSI clock */
+ dsi_pll_calc_dsi_fck(dsidev, &cinfo);
+
+ /* Calculate PLL's DISPC clock and pck & lck divs */
+ pck = cinfo.clkin4ddr / 16 * (dsi->num_lanes_used - 1) * 8 / bpp;
+ DSSDBG("finding dispc dividers for pck %lu\n", pck);
+ r = dsi_pll_calc_dispc_fck(dsidev, pck, &cinfo, &dispc_cinfo);
+ if (r)
+ goto err;
+
+ /* Calculate LP clock */
+ dsi_fclk = cinfo.dsi_pll_hsdiv_dsi_clk;
+ lp_clk_div = DIV_ROUND_UP(dsi_fclk, lp_clk * 2);
+
+ dssdev->clocks.dsi.regn = cinfo.regn;
+ dssdev->clocks.dsi.regm = cinfo.regm;
+ dssdev->clocks.dsi.regm_dispc = cinfo.regm_dispc;
+ dssdev->clocks.dsi.regm_dsi = cinfo.regm_dsi;
+
+ dssdev->clocks.dsi.lp_clk_div = lp_clk_div;
+
+ dssdev->clocks.dispc.channel.lck_div = dispc_cinfo.lck_div;
+ dssdev->clocks.dispc.channel.pck_div = dispc_cinfo.pck_div;
+
+ dssdev->clocks.dispc.dispc_fclk_src = OMAP_DSS_CLK_SRC_FCK;
+
+ dssdev->clocks.dispc.channel.lcd_clk_src =
+ dsi->module_id == 0 ?
+ OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC :
+ OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC;
+
+ dssdev->clocks.dsi.dsi_fclk_src =
+ dsi->module_id == 0 ?
+ OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI :
+ OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI;
+
+ mutex_unlock(&dsi->lock);
+ return 0;
+err:
+ mutex_unlock(&dsi->lock);
+ return r;
+}
+EXPORT_SYMBOL(omapdss_dsi_set_clocks);
+
+int dsi_enable_video_output(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);
+ struct omap_overlay_manager *mgr = dssdev->output->manager;
+ int bpp = dsi_get_pixel_size(dsi->pix_fmt);
u8 data_type;
u16 word_count;
int r;
- if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_VIDEO_MODE) {
- switch (dssdev->panel.dsi_pix_fmt) {
+ if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) {
+ switch (dsi->pix_fmt) {
case OMAP_DSS_DSI_FMT_RGB888:
data_type = MIPI_DSI_PACKED_PIXEL_STREAM_24;
break;
@@ -4133,7 +4364,7 @@ int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel)
/* MODE, 1 = video mode */
REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 1, 4, 4);
- word_count = DIV_ROUND_UP(dssdev->panel.timings.x_res * bpp, 8);
+ word_count = DIV_ROUND_UP(dsi->timings.x_res * bpp, 8);
dsi_vc_write_long_header(dsidev, channel, data_type,
word_count, 0);
@@ -4142,9 +4373,9 @@ int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel)
dsi_if_enable(dsidev, true);
}
- r = dss_mgr_enable(dssdev->manager);
+ r = dss_mgr_enable(mgr);
if (r) {
- if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_VIDEO_MODE) {
+ if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) {
dsi_if_enable(dsidev, false);
dsi_vc_enable(dsidev, channel, false);
}
@@ -4159,8 +4390,10 @@ EXPORT_SYMBOL(dsi_enable_video_output);
void dsi_disable_video_output(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);
+ struct omap_overlay_manager *mgr = dssdev->output->manager;
- if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_VIDEO_MODE) {
+ if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) {
dsi_if_enable(dsidev, false);
dsi_vc_enable(dsidev, channel, false);
@@ -4171,15 +4404,15 @@ void dsi_disable_video_output(struct omap_dss_device *dssdev, int channel)
dsi_if_enable(dsidev, true);
}
- dss_mgr_disable(dssdev->manager);
+ dss_mgr_disable(mgr);
}
EXPORT_SYMBOL(dsi_disable_video_output);
-static void dsi_update_screen_dispc(struct omap_dss_device *dssdev,
- u16 w, u16 h)
+static void dsi_update_screen_dispc(struct omap_dss_device *dssdev)
{
struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+ struct omap_overlay_manager *mgr = dssdev->output->manager;
unsigned bytespp;
unsigned bytespl;
unsigned bytespf;
@@ -4190,12 +4423,14 @@ static void dsi_update_screen_dispc(struct omap_dss_device *dssdev,
int r;
const unsigned channel = dsi->update_channel;
const unsigned line_buf_size = dsi_get_line_buf_size(dsidev);
+ u16 w = dsi->timings.x_res;
+ u16 h = dsi->timings.y_res;
DSSDBG("dsi_update_screen_dispc(%dx%d)\n", w, h);
dsi_vc_config_source(dsidev, channel, DSI_VC_SOURCE_VP);
- bytespp = dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt) / 8;
+ bytespp = dsi_get_pixel_size(dsi->pix_fmt) / 8;
bytespl = w * bytespp;
bytespf = bytespl * h;
@@ -4239,7 +4474,9 @@ static void dsi_update_screen_dispc(struct omap_dss_device *dssdev,
msecs_to_jiffies(250));
BUG_ON(r == 0);
- dss_mgr_start_update(dssdev->manager);
+ dss_mgr_set_timings(mgr, &dsi->timings);
+
+ dss_mgr_start_update(mgr);
if (dsi->te_enabled) {
/* disable LP_RX_TO, so that we can receive TE. Time to wait
@@ -4297,8 +4534,7 @@ static void dsi_framedone_timeout_work_callback(struct work_struct *work)
static void dsi_framedone_irq_callback(void *data, u32 mask)
{
- struct omap_dss_device *dssdev = (struct omap_dss_device *) data;
- struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+ struct platform_device *dsidev = (struct platform_device *) data;
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
/* Note: We get FRAMEDONE when DISPC has finished sending pixels and
@@ -4325,13 +4561,14 @@ int omap_dsi_update(struct omap_dss_device *dssdev, int channel,
dsi->framedone_callback = callback;
dsi->framedone_data = data;
- dssdev->driver->get_resolution(dssdev, &dw, &dh);
+ dw = dsi->timings.x_res;
+ dh = dsi->timings.y_res;
#ifdef DEBUG
dsi->update_bytes = dw * dh *
- dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt) / 8;
+ dsi_get_pixel_size(dsi->pix_fmt) / 8;
#endif
- dsi_update_screen_dispc(dssdev, dw, dh);
+ dsi_update_screen_dispc(dssdev);
return 0;
}
@@ -4367,28 +4604,22 @@ static int dsi_display_init_dispc(struct omap_dss_device *dssdev)
{
struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
- struct omap_video_timings timings;
+ struct omap_overlay_manager *mgr = dssdev->output->manager;
int r;
u32 irq = 0;
- if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_CMD_MODE) {
- u16 dw, dh;
-
- dssdev->driver->get_resolution(dssdev, &dw, &dh);
-
- timings.x_res = dw;
- timings.y_res = dh;
- timings.hsw = 1;
- timings.hfp = 1;
- timings.hbp = 1;
- timings.vsw = 1;
- timings.vfp = 0;
- timings.vbp = 0;
+ if (dsi->mode == OMAP_DSS_DSI_CMD_MODE) {
+ dsi->timings.hsw = 1;
+ dsi->timings.hfp = 1;
+ dsi->timings.hbp = 1;
+ dsi->timings.vsw = 1;
+ dsi->timings.vfp = 0;
+ dsi->timings.vbp = 0;
- irq = dispc_mgr_get_framedone_irq(dssdev->manager->id);
+ irq = dispc_mgr_get_framedone_irq(mgr->id);
r = omap_dispc_register_isr(dsi_framedone_irq_callback,
- (void *) dssdev, irq);
+ (void *) dsidev, irq);
if (r) {
DSSERR("can't get FRAMEDONE irq\n");
goto err;
@@ -4397,8 +4628,6 @@ static int dsi_display_init_dispc(struct omap_dss_device *dssdev)
dsi->mgr_config.stallmode = true;
dsi->mgr_config.fifohandcheck = true;
} else {
- timings = dssdev->panel.timings;
-
dsi->mgr_config.stallmode = false;
dsi->mgr_config.fifohandcheck = false;
}
@@ -4407,14 +4636,14 @@ static int dsi_display_init_dispc(struct omap_dss_device *dssdev)
* override interlace, logic level and edge related parameters in
* omap_video_timings with default values
*/
- timings.interlace = false;
- timings.hsync_level = OMAPDSS_SIG_ACTIVE_HIGH;
- timings.vsync_level = OMAPDSS_SIG_ACTIVE_HIGH;
- timings.data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE;
- timings.de_level = OMAPDSS_SIG_ACTIVE_HIGH;
- timings.sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES;
+ dsi->timings.interlace = false;
+ dsi->timings.hsync_level = OMAPDSS_SIG_ACTIVE_HIGH;
+ dsi->timings.vsync_level = OMAPDSS_SIG_ACTIVE_HIGH;
+ dsi->timings.data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE;
+ dsi->timings.de_level = OMAPDSS_SIG_ACTIVE_HIGH;
+ dsi->timings.sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES;
- dss_mgr_set_timings(dssdev->manager, &timings);
+ dss_mgr_set_timings(mgr, &dsi->timings);
r = dsi_configure_dispc_clocks(dssdev);
if (r)
@@ -4422,29 +4651,33 @@ static int dsi_display_init_dispc(struct omap_dss_device *dssdev)
dsi->mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS;
dsi->mgr_config.video_port_width =
- dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt);
+ dsi_get_pixel_size(dsi->pix_fmt);
dsi->mgr_config.lcden_sig_polarity = 0;
- dss_mgr_set_lcd_config(dssdev->manager, &dsi->mgr_config);
+ dss_mgr_set_lcd_config(mgr, &dsi->mgr_config);
return 0;
err1:
- if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_CMD_MODE)
+ if (dsi->mode == OMAP_DSS_DSI_CMD_MODE)
omap_dispc_unregister_isr(dsi_framedone_irq_callback,
- (void *) dssdev, irq);
+ (void *) dsidev, irq);
err:
return r;
}
static void dsi_display_uninit_dispc(struct omap_dss_device *dssdev)
{
- if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_CMD_MODE) {
+ struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+ struct omap_overlay_manager *mgr = dssdev->output->manager;
+
+ if (dsi->mode == OMAP_DSS_DSI_CMD_MODE) {
u32 irq;
- irq = dispc_mgr_get_framedone_irq(dssdev->manager->id);
+ irq = dispc_mgr_get_framedone_irq(mgr->id);
omap_dispc_unregister_isr(dsi_framedone_irq_callback,
- (void *) dssdev, irq);
+ (void *) dsidev, irq);
}
}
@@ -4477,6 +4710,7 @@ static int dsi_display_init_dsi(struct omap_dss_device *dssdev)
{
struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+ struct omap_overlay_manager *mgr = dssdev->output->manager;
int r;
r = dsi_pll_init(dsidev, true, true);
@@ -4489,18 +4723,18 @@ static int dsi_display_init_dsi(struct omap_dss_device *dssdev)
dss_select_dispc_clk_source(dssdev->clocks.dispc.dispc_fclk_src);
dss_select_dsi_clk_source(dsi->module_id, dssdev->clocks.dsi.dsi_fclk_src);
- dss_select_lcd_clk_source(dssdev->manager->id,
+ dss_select_lcd_clk_source(mgr->id,
dssdev->clocks.dispc.channel.lcd_clk_src);
DSSDBG("PLL OK\n");
- r = dsi_cio_init(dssdev);
+ r = dsi_cio_init(dsidev);
if (r)
goto err2;
_dsi_print_reset_status(dsidev);
- dsi_proto_timings(dssdev);
+ dsi_proto_timings(dsidev);
dsi_set_lp_clk_divisor(dssdev);
if (1)
@@ -4520,11 +4754,11 @@ static int dsi_display_init_dsi(struct omap_dss_device *dssdev)
return 0;
err3:
- dsi_cio_uninit(dssdev);
+ dsi_cio_uninit(dsidev);
err2:
dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK);
dss_select_dsi_clk_source(dsi->module_id, OMAP_DSS_CLK_SRC_FCK);
- dss_select_lcd_clk_source(dssdev->manager->id, OMAP_DSS_CLK_SRC_FCK);
+ dss_select_lcd_clk_source(mgr->id, OMAP_DSS_CLK_SRC_FCK);
err1:
dsi_pll_uninit(dsidev, true);
@@ -4537,6 +4771,7 @@ static void dsi_display_uninit_dsi(struct omap_dss_device *dssdev,
{
struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+ struct omap_overlay_manager *mgr = dssdev->output->manager;
if (enter_ulps && !dsi->ulps_enabled)
dsi_enter_ulps(dsidev);
@@ -4550,8 +4785,8 @@ static void dsi_display_uninit_dsi(struct omap_dss_device *dssdev,
dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK);
dss_select_dsi_clk_source(dsi->module_id, OMAP_DSS_CLK_SRC_FCK);
- dss_select_lcd_clk_source(dssdev->manager->id, OMAP_DSS_CLK_SRC_FCK);
- dsi_cio_uninit(dssdev);
+ dss_select_lcd_clk_source(mgr->id, OMAP_DSS_CLK_SRC_FCK);
+ dsi_cio_uninit(dsidev);
dsi_pll_uninit(dsidev, disconnect_lanes);
}
@@ -4559,6 +4794,7 @@ 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);
+ struct omap_dss_output *out = dssdev->output;
int r = 0;
DSSDBG("dsi_display_enable\n");
@@ -4567,8 +4803,8 @@ int omapdss_dsi_display_enable(struct omap_dss_device *dssdev)
mutex_lock(&dsi->lock);
- if (dssdev->manager == NULL) {
- DSSERR("failed to enable display: no manager\n");
+ if (out == NULL || out->manager == NULL) {
+ DSSERR("failed to enable display: no output/manager\n");
r = -ENODEV;
goto err_start_dev;
}
@@ -4653,17 +4889,83 @@ int omapdss_dsi_enable_te(struct omap_dss_device *dssdev, bool enable)
}
EXPORT_SYMBOL(omapdss_dsi_enable_te);
-static int __init dsi_init_display(struct omap_dss_device *dssdev)
+void omapdss_dsi_set_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
{
struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
- DSSDBG("DSI init\n");
+ mutex_lock(&dsi->lock);
- if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_CMD_MODE) {
- dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE |
- OMAP_DSS_DISPLAY_CAP_TEAR_ELIM;
- }
+ dsi->timings = *timings;
+
+ mutex_unlock(&dsi->lock);
+}
+EXPORT_SYMBOL(omapdss_dsi_set_timings);
+
+void omapdss_dsi_set_size(struct omap_dss_device *dssdev, u16 w, u16 h)
+{
+ struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+ mutex_lock(&dsi->lock);
+
+ dsi->timings.x_res = w;
+ dsi->timings.y_res = h;
+
+ mutex_unlock(&dsi->lock);
+}
+EXPORT_SYMBOL(omapdss_dsi_set_size);
+
+void omapdss_dsi_set_pixel_format(struct omap_dss_device *dssdev,
+ enum omap_dss_dsi_pixel_format fmt)
+{
+ struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+ mutex_lock(&dsi->lock);
+
+ dsi->pix_fmt = fmt;
+
+ mutex_unlock(&dsi->lock);
+}
+EXPORT_SYMBOL(omapdss_dsi_set_pixel_format);
+
+void omapdss_dsi_set_operation_mode(struct omap_dss_device *dssdev,
+ enum omap_dss_dsi_mode mode)
+{
+ struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+ mutex_lock(&dsi->lock);
+
+ dsi->mode = mode;
+
+ mutex_unlock(&dsi->lock);
+}
+EXPORT_SYMBOL(omapdss_dsi_set_operation_mode);
+
+void omapdss_dsi_set_videomode_timings(struct omap_dss_device *dssdev,
+ struct omap_dss_dsi_videomode_timings *timings)
+{
+ struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+ mutex_lock(&dsi->lock);
+
+ dsi->vm_timings = *timings;
+
+ mutex_unlock(&dsi->lock);
+}
+EXPORT_SYMBOL(omapdss_dsi_set_videomode_timings);
+
+static int __init dsi_init_display(struct omap_dss_device *dssdev)
+{
+ struct platform_device *dsidev =
+ dsi_get_dsidev_from_id(dssdev->phy.dsi.module);
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+ DSSDBG("DSI init\n");
if (dsi->vdds_dsi_reg == NULL) {
struct regulator *vdds_dsi;
@@ -4806,11 +5108,15 @@ static void dsi_put_clocks(struct platform_device *dsidev)
clk_put(dsi->sys_clk);
}
-static void __init dsi_probe_pdata(struct platform_device *dsidev)
+static struct omap_dss_device * __init dsi_find_dssdev(struct platform_device *pdev)
{
- struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
- struct omap_dss_board_info *pdata = dsidev->dev.platform_data;
- int i, r;
+ struct omap_dss_board_info *pdata = pdev->dev.platform_data;
+ struct dsi_data *dsi = dsi_get_dsidrv_data(pdev);
+ const char *def_disp_name = dss_get_default_display_name();
+ struct omap_dss_device *def_dssdev;
+ int i;
+
+ def_dssdev = NULL;
for (i = 0; i < pdata->num_devices; ++i) {
struct omap_dss_device *dssdev = pdata->devices[i];
@@ -4821,19 +5127,73 @@ static void __init dsi_probe_pdata(struct platform_device *dsidev)
if (dssdev->phy.dsi.module != dsi->module_id)
continue;
- r = dsi_init_display(dssdev);
- if (r) {
- DSSERR("device %s init failed: %d\n", dssdev->name, r);
- continue;
+ if (def_dssdev == NULL)
+ def_dssdev = dssdev;
+
+ if (def_disp_name != NULL &&
+ strcmp(dssdev->name, def_disp_name) == 0) {
+ def_dssdev = dssdev;
+ break;
}
+ }
- r = omap_dss_register_device(dssdev, &dsidev->dev, i);
- if (r)
- DSSERR("device %s register failed: %d\n",
- dssdev->name, r);
+ return def_dssdev;
+}
+
+static void __init dsi_probe_pdata(struct platform_device *dsidev)
+{
+ struct omap_dss_device *plat_dssdev;
+ struct omap_dss_device *dssdev;
+ int r;
+
+ plat_dssdev = dsi_find_dssdev(dsidev);
+
+ if (!plat_dssdev)
+ return;
+
+ dssdev = dss_alloc_and_init_device(&dsidev->dev);
+ if (!dssdev)
+ return;
+
+ dss_copy_device_pdata(dssdev, plat_dssdev);
+
+ r = dsi_init_display(dssdev);
+ if (r) {
+ DSSERR("device %s init failed: %d\n", dssdev->name, r);
+ dss_put_device(dssdev);
+ return;
+ }
+
+ r = dss_add_device(dssdev);
+ if (r) {
+ DSSERR("device %s register failed: %d\n", dssdev->name, r);
+ dss_put_device(dssdev);
+ return;
}
}
+static void __init dsi_init_output(struct platform_device *dsidev)
+{
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+ struct omap_dss_output *out = &dsi->output;
+
+ out->pdev = dsidev;
+ out->id = dsi->module_id == 0 ?
+ OMAP_DSS_OUTPUT_DSI1 : OMAP_DSS_OUTPUT_DSI2;
+
+ out->type = OMAP_DISPLAY_TYPE_DSI;
+
+ dss_register_output(out);
+}
+
+static void __exit dsi_uninit_output(struct platform_device *dsidev)
+{
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+ struct omap_dss_output *out = &dsi->output;
+
+ dss_unregister_output(out);
+}
+
/* DSI1 HW IP initialisation */
static int __init omap_dsihw_probe(struct platform_device *dsidev)
{
@@ -4848,7 +5208,6 @@ static int __init omap_dsihw_probe(struct platform_device *dsidev)
dsi->module_id = dsidev->id;
dsi->pdev = dsidev;
- dsi_pdev_map[dsi->module_id] = dsidev;
dev_set_drvdata(&dsidev->dev, dsi);
spin_lock_init(&dsi->irq_lock);
@@ -4928,6 +5287,8 @@ static int __init omap_dsihw_probe(struct platform_device *dsidev)
else
dsi->num_lanes_supported = 3;
+ dsi_init_output(dsidev);
+
dsi_probe_pdata(dsidev);
dsi_runtime_put(dsidev);
@@ -4957,7 +5318,9 @@ static int __exit omap_dsihw_remove(struct platform_device *dsidev)
WARN_ON(dsi->scp_clk_refcount > 0);
- omap_dss_unregister_child_devices(&dsidev->dev);
+ dss_unregister_child_devices(&dsidev->dev);
+
+ dsi_uninit_output(dsidev);
pm_runtime_disable(&dsidev->dev);
diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c
index 04b4586..2ab1c3e 100644
--- a/drivers/video/omap2/dss/dss.c
+++ b/drivers/video/omap2/dss/dss.c
@@ -31,11 +31,11 @@
#include <linux/clk.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
+#include <linux/gfp.h>
#include <video/omapdss.h>
#include <plat/cpu.h>
-#include <plat/clock.h>
#include "dss.h"
#include "dss_features.h"
@@ -65,6 +65,13 @@ struct dss_reg {
static int dss_runtime_get(void);
static void dss_runtime_put(void);
+struct dss_features {
+ u8 fck_div_max;
+ u8 dss_fck_multiplier;
+ const char *clk_name;
+ int (*dpi_select_source)(enum omap_channel channel);
+};
+
static struct {
struct platform_device *pdev;
void __iomem *base;
@@ -83,6 +90,8 @@ static struct {
bool ctx_valid;
u32 ctx[DSS_SZ_REGS / sizeof(u32)];
+
+ const struct dss_features *feat;
} dss;
static const char * const dss_generic_clk_source_names[] = {
@@ -144,7 +153,7 @@ static void dss_restore_context(void)
#undef SR
#undef RR
-void dss_sdi_init(u8 datapairs)
+void dss_sdi_init(int datapairs)
{
u32 l;
@@ -236,7 +245,6 @@ const char *dss_get_generic_clk_source_name(enum omap_dss_clk_source clk_src)
return dss_generic_clk_source_names[clk_src];
}
-
void dss_dump_clocks(struct seq_file *s)
{
unsigned long dpll4_ck_rate;
@@ -259,18 +267,10 @@ void dss_dump_clocks(struct seq_file *s)
seq_printf(s, "dpll4_ck %lu\n", dpll4_ck_rate);
- if (cpu_is_omap3630() || cpu_is_omap44xx())
- seq_printf(s, "%s (%s) = %lu / %lu = %lu\n",
- fclk_name, fclk_real_name,
- dpll4_ck_rate,
- dpll4_ck_rate / dpll4_m4_ck_rate,
- fclk_rate);
- else
- seq_printf(s, "%s (%s) = %lu / %lu * 2 = %lu\n",
- fclk_name, fclk_real_name,
- dpll4_ck_rate,
- dpll4_ck_rate / dpll4_m4_ck_rate,
- fclk_rate);
+ seq_printf(s, "%s (%s) = %lu / %lu * %d = %lu\n",
+ fclk_name, fclk_real_name, dpll4_ck_rate,
+ dpll4_ck_rate / dpll4_m4_ck_rate,
+ dss.feat->dss_fck_multiplier, fclk_rate);
} else {
seq_printf(s, "%s (%s) = %lu\n",
fclk_name, fclk_real_name,
@@ -431,31 +431,6 @@ enum omap_dss_clk_source dss_get_lcd_clk_source(enum omap_channel channel)
}
}
-/* calculate clock rates using dividers in cinfo */
-int dss_calc_clock_rates(struct dss_clock_info *cinfo)
-{
- if (dss.dpll4_m4_ck) {
- unsigned long prate;
- u16 fck_div_max = 16;
-
- if (cpu_is_omap3630() || cpu_is_omap44xx())
- fck_div_max = 32;
-
- if (cinfo->fck_div > fck_div_max || cinfo->fck_div == 0)
- return -EINVAL;
-
- prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
-
- cinfo->fck = prate / cinfo->fck_div;
- } else {
- if (cinfo->fck_div != 0)
- return -EINVAL;
- cinfo->fck = clk_get_rate(dss.dss_clk);
- }
-
- return 0;
-}
-
int dss_set_clock_div(struct dss_clock_info *cinfo)
{
if (dss.dpll4_m4_ck) {
@@ -478,26 +453,6 @@ int dss_set_clock_div(struct dss_clock_info *cinfo)
return 0;
}
-int dss_get_clock_div(struct dss_clock_info *cinfo)
-{
- cinfo->fck = clk_get_rate(dss.dss_clk);
-
- if (dss.dpll4_m4_ck) {
- unsigned long prate;
-
- prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
-
- if (cpu_is_omap3630() || cpu_is_omap44xx())
- cinfo->fck_div = prate / (cinfo->fck);
- else
- cinfo->fck_div = prate / (cinfo->fck / 2);
- } else {
- cinfo->fck_div = 0;
- }
-
- return 0;
-}
-
unsigned long dss_get_dpll4_rate(void)
{
if (dss.dpll4_m4_ck)
@@ -515,7 +470,7 @@ int dss_calc_clock_div(unsigned long req_pck, struct dss_clock_info *dss_cinfo,
unsigned long fck, max_dss_fck;
- u16 fck_div, fck_div_max = 16;
+ u16 fck_div;
int match = 0;
int min_fck_per_pck;
@@ -525,9 +480,8 @@ int dss_calc_clock_div(unsigned long req_pck, struct dss_clock_info *dss_cinfo,
max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK);
fck = clk_get_rate(dss.dss_clk);
- if (req_pck == dss.cache_req_pck &&
- ((cpu_is_omap34xx() && prate == dss.cache_prate) ||
- dss.cache_dss_cinfo.fck == fck)) {
+ if (req_pck == dss.cache_req_pck && prate == dss.cache_prate &&
+ dss.cache_dss_cinfo.fck == fck) {
DSSDBG("dispc clock info found from cache.\n");
*dss_cinfo = dss.cache_dss_cinfo;
*dispc_cinfo = dss.cache_dispc_cinfo;
@@ -564,16 +518,10 @@ retry:
goto found;
} else {
- if (cpu_is_omap3630() || cpu_is_omap44xx())
- fck_div_max = 32;
-
- for (fck_div = fck_div_max; fck_div > 0; --fck_div) {
+ for (fck_div = dss.feat->fck_div_max; fck_div > 0; --fck_div) {
struct dispc_clock_info cur_dispc;
- if (fck_div_max == 32)
- fck = prate / fck_div;
- else
- fck = prate / fck_div * 2;
+ fck = prate / fck_div * dss.feat->dss_fck_multiplier;
if (fck > max_dss_fck)
continue;
@@ -648,9 +596,18 @@ void dss_set_dac_pwrdn_bgz(bool enable)
REG_FLD_MOD(DSS_CONTROL, enable, 5, 5); /* DAC Power-Down Control */
}
-void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select hdmi)
+void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select src)
{
- REG_FLD_MOD(DSS_CONTROL, hdmi, 15, 15); /* VENC_HDMI_SWITCH */
+ enum omap_display_type dp;
+ dp = dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_DIGIT);
+
+ /* Complain about invalid selections */
+ WARN_ON((src == DSS_VENC_TV_CLK) && !(dp & OMAP_DISPLAY_TYPE_VENC));
+ WARN_ON((src == DSS_HDMI_M_PCLK) && !(dp & OMAP_DISPLAY_TYPE_HDMI));
+
+ /* Select only if we have options */
+ if ((dp & OMAP_DISPLAY_TYPE_VENC) && (dp & OMAP_DISPLAY_TYPE_HDMI))
+ REG_FLD_MOD(DSS_CONTROL, src, 15, 15); /* VENC_HDMI_SWITCH */
}
enum dss_hdmi_venc_clk_source_select dss_get_hdmi_venc_clk_source(void)
@@ -661,9 +618,71 @@ enum dss_hdmi_venc_clk_source_select dss_get_hdmi_venc_clk_source(void)
if ((displays & OMAP_DISPLAY_TYPE_HDMI) == 0)
return DSS_VENC_TV_CLK;
+ if ((displays & OMAP_DISPLAY_TYPE_VENC) == 0)
+ return DSS_HDMI_M_PCLK;
+
return REG_GET(DSS_CONTROL, 15, 15);
}
+static int dss_dpi_select_source_omap2_omap3(enum omap_channel channel)
+{
+ if (channel != OMAP_DSS_CHANNEL_LCD)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int dss_dpi_select_source_omap4(enum omap_channel channel)
+{
+ int val;
+
+ switch (channel) {
+ case OMAP_DSS_CHANNEL_LCD2:
+ val = 0;
+ break;
+ case OMAP_DSS_CHANNEL_DIGIT:
+ val = 1;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ REG_FLD_MOD(DSS_CONTROL, val, 17, 17);
+
+ return 0;
+}
+
+static int dss_dpi_select_source_omap5(enum omap_channel channel)
+{
+ int val;
+
+ switch (channel) {
+ case OMAP_DSS_CHANNEL_LCD:
+ val = 1;
+ break;
+ case OMAP_DSS_CHANNEL_LCD2:
+ val = 2;
+ break;
+ case OMAP_DSS_CHANNEL_LCD3:
+ val = 3;
+ break;
+ case OMAP_DSS_CHANNEL_DIGIT:
+ val = 0;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ REG_FLD_MOD(DSS_CONTROL, val, 17, 16);
+
+ return 0;
+}
+
+int dss_dpi_select_source(enum omap_channel channel)
+{
+ return dss.feat->dpi_select_source(channel);
+}
+
static int dss_get_clocks(void)
{
struct clk *clk;
@@ -678,22 +697,11 @@ static int dss_get_clocks(void)
dss.dss_clk = clk;
- if (cpu_is_omap34xx()) {
- clk = clk_get(NULL, "dpll4_m4_ck");
- if (IS_ERR(clk)) {
- DSSERR("Failed to get dpll4_m4_ck\n");
- r = PTR_ERR(clk);
- goto err;
- }
- } else if (cpu_is_omap44xx()) {
- clk = clk_get(NULL, "dpll_per_m5x2_ck");
- if (IS_ERR(clk)) {
- DSSERR("Failed to get dpll_per_m5x2_ck\n");
- r = PTR_ERR(clk);
- goto err;
- }
- } else { /* omap24xx */
- clk = NULL;
+ clk = clk_get(NULL, dss.feat->clk_name);
+ if (IS_ERR(clk)) {
+ DSSERR("Failed to get %s\n", dss.feat->clk_name);
+ r = PTR_ERR(clk);
+ goto err;
}
dss.dpll4_m4_ck = clk;
@@ -749,6 +757,71 @@ void dss_debug_dump_clocks(struct seq_file *s)
}
#endif
+static const struct dss_features omap24xx_dss_feats __initconst = {
+ .fck_div_max = 16,
+ .dss_fck_multiplier = 2,
+ .clk_name = NULL,
+ .dpi_select_source = &dss_dpi_select_source_omap2_omap3,
+};
+
+static const struct dss_features omap34xx_dss_feats __initconst = {
+ .fck_div_max = 16,
+ .dss_fck_multiplier = 2,
+ .clk_name = "dpll4_m4_ck",
+ .dpi_select_source = &dss_dpi_select_source_omap2_omap3,
+};
+
+static const struct dss_features omap3630_dss_feats __initconst = {
+ .fck_div_max = 32,
+ .dss_fck_multiplier = 1,
+ .clk_name = "dpll4_m4_ck",
+ .dpi_select_source = &dss_dpi_select_source_omap2_omap3,
+};
+
+static const struct dss_features omap44xx_dss_feats __initconst = {
+ .fck_div_max = 32,
+ .dss_fck_multiplier = 1,
+ .clk_name = "dpll_per_m5x2_ck",
+ .dpi_select_source = &dss_dpi_select_source_omap4,
+};
+
+static const struct dss_features omap54xx_dss_feats __initconst = {
+ .fck_div_max = 64,
+ .dss_fck_multiplier = 1,
+ .clk_name = "dpll_per_h12x2_ck",
+ .dpi_select_source = &dss_dpi_select_source_omap5,
+};
+
+static int __init dss_init_features(struct device *dev)
+{
+ const struct dss_features *src;
+ struct dss_features *dst;
+
+ dst = devm_kzalloc(dev, sizeof(*dst), GFP_KERNEL);
+ if (!dst) {
+ dev_err(dev, "Failed to allocate local DSS Features\n");
+ return -ENOMEM;
+ }
+
+ if (cpu_is_omap24xx())
+ src = &omap24xx_dss_feats;
+ else if (cpu_is_omap34xx())
+ src = &omap34xx_dss_feats;
+ else if (cpu_is_omap3630())
+ src = &omap3630_dss_feats;
+ else if (cpu_is_omap44xx())
+ src = &omap44xx_dss_feats;
+ else if (soc_is_omap54xx())
+ src = &omap54xx_dss_feats;
+ else
+ return -ENODEV;
+
+ memcpy(dst, src, sizeof(*dst));
+ dss.feat = dst;
+
+ return 0;
+}
+
/* DSS HW IP initialisation */
static int __init omap_dsshw_probe(struct platform_device *pdev)
{
@@ -758,6 +831,10 @@ static int __init omap_dsshw_probe(struct platform_device *pdev)
dss.pdev = pdev;
+ r = dss_init_features(&dss.pdev->dev);
+ if (r)
+ return r;
+
dss_mem = platform_get_resource(dss.pdev, IORESOURCE_MEM, 0);
if (!dss_mem) {
DSSERR("can't get IORESOURCE_MEM DSS\n");
diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h
index f67afe7..6728892 100644
--- a/drivers/video/omap2/dss/dss.h
+++ b/drivers/video/omap2/dss/dss.h
@@ -113,6 +113,17 @@ enum dss_dsi_content_type {
DSS_DSI_CONTENT_GENERIC,
};
+enum dss_writeback_channel {
+ DSS_WB_LCD1_MGR = 0,
+ DSS_WB_LCD2_MGR = 1,
+ DSS_WB_TV_MGR = 2,
+ DSS_WB_OVL0 = 3,
+ DSS_WB_OVL1 = 4,
+ DSS_WB_OVL2 = 5,
+ DSS_WB_OVL3 = 6,
+ DSS_WB_LCD3_MGR = 7,
+};
+
struct dss_clock_info {
/* rates that we get with dividers below */
unsigned long fck;
@@ -175,6 +186,7 @@ struct seq_file;
struct platform_device;
/* core */
+const char *dss_get_default_display_name(void);
struct bus_type *dss_get_bus(void);
struct regulator *dss_get_vdds_dsi(void);
struct regulator *dss_get_vdds_sdi(void);
@@ -184,10 +196,13 @@ void dss_dsi_disable_pads(int dsi_id, unsigned lane_mask);
int dss_set_min_bus_tput(struct device *dev, unsigned long tput);
int dss_debugfs_create_file(const char *name, void (*write)(struct seq_file *));
-int omap_dss_register_device(struct omap_dss_device *dssdev,
- struct device *parent, int disp_num);
-void omap_dss_unregister_device(struct omap_dss_device *dssdev);
-void omap_dss_unregister_child_devices(struct device *parent);
+struct omap_dss_device *dss_alloc_and_init_device(struct device *parent);
+int dss_add_device(struct omap_dss_device *dssdev);
+void dss_unregister_device(struct omap_dss_device *dssdev);
+void dss_unregister_child_devices(struct device *parent);
+void dss_put_device(struct omap_dss_device *dssdev);
+void dss_copy_device_pdata(struct omap_dss_device *dst,
+ const struct omap_dss_device *src);
/* apply */
void dss_apply_init(void);
@@ -205,8 +220,11 @@ void dss_mgr_get_info(struct omap_overlay_manager *mgr,
int dss_mgr_set_device(struct omap_overlay_manager *mgr,
struct omap_dss_device *dssdev);
int dss_mgr_unset_device(struct omap_overlay_manager *mgr);
+int dss_mgr_set_output(struct omap_overlay_manager *mgr,
+ struct omap_dss_output *output);
+int dss_mgr_unset_output(struct omap_overlay_manager *mgr);
void dss_mgr_set_timings(struct omap_overlay_manager *mgr,
- struct omap_video_timings *timings);
+ const struct omap_video_timings *timings);
void dss_mgr_set_lcd_config(struct omap_overlay_manager *mgr,
const struct dss_lcd_mgr_config *config);
const struct omap_video_timings *dss_mgr_get_timings(struct omap_overlay_manager *mgr);
@@ -222,12 +240,17 @@ int dss_ovl_set_manager(struct omap_overlay *ovl,
struct omap_overlay_manager *mgr);
int dss_ovl_unset_manager(struct omap_overlay *ovl);
+/* output */
+void dss_register_output(struct omap_dss_output *out);
+void dss_unregister_output(struct omap_dss_output *out);
+struct omap_dss_output *omapdss_get_output_from_dssdev(struct omap_dss_device *dssdev);
+
/* display */
int dss_suspend_all_devices(void);
int dss_resume_all_devices(void);
void dss_disable_all_devices(void);
-void dss_init_device(struct platform_device *pdev,
+int dss_init_device(struct platform_device *pdev,
struct omap_dss_device *dssdev);
void dss_uninit_device(struct platform_device *pdev,
struct omap_dss_device *dssdev);
@@ -254,22 +277,29 @@ static inline bool dss_mgr_is_lcd(enum omap_channel id)
return false;
}
+int dss_manager_kobj_init(struct omap_overlay_manager *mgr,
+ struct platform_device *pdev);
+void dss_manager_kobj_uninit(struct omap_overlay_manager *mgr);
+
/* overlay */
void dss_init_overlays(struct platform_device *pdev);
void dss_uninit_overlays(struct platform_device *pdev);
void dss_overlay_setup_dispc_manager(struct omap_overlay_manager *mgr);
-void dss_recheck_connections(struct omap_dss_device *dssdev, bool force);
int dss_ovl_simple_check(struct omap_overlay *ovl,
const struct omap_overlay_info *info);
int dss_ovl_check(struct omap_overlay *ovl, struct omap_overlay_info *info,
const struct omap_video_timings *mgr_timings);
bool dss_ovl_use_replication(struct dss_lcd_mgr_config config,
enum omap_color_mode mode);
+int dss_overlay_kobj_init(struct omap_overlay *ovl,
+ struct platform_device *pdev);
+void dss_overlay_kobj_uninit(struct omap_overlay *ovl);
/* DSS */
int dss_init_platform_driver(void) __init;
void dss_uninit_platform_driver(void);
+int dss_dpi_select_source(enum omap_channel channel);
void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select);
enum dss_hdmi_venc_clk_source_select dss_get_hdmi_venc_clk_source(void);
const char *dss_get_generic_clk_source_name(enum omap_dss_clk_source clk_src);
@@ -279,7 +309,7 @@ void dss_dump_clocks(struct seq_file *s);
void dss_debug_dump_clocks(struct seq_file *s);
#endif
-void dss_sdi_init(u8 datapairs);
+void dss_sdi_init(int datapairs);
int dss_sdi_enable(void);
void dss_sdi_disable(void);
@@ -296,9 +326,7 @@ void dss_set_venc_output(enum omap_dss_venc_type type);
void dss_set_dac_pwrdn_bgz(bool enable);
unsigned long dss_get_dpll4_rate(void);
-int dss_calc_clock_rates(struct dss_clock_info *cinfo);
int dss_set_clock_div(struct dss_clock_info *cinfo);
-int dss_get_clock_div(struct dss_clock_info *cinfo);
int dss_calc_clock_div(unsigned long req_pck, struct dss_clock_info *dss_cinfo,
struct dispc_clock_info *dispc_cinfo);
@@ -427,8 +455,9 @@ void dispc_ovl_set_fifo_threshold(enum omap_plane plane, u32 low, u32 high);
void dispc_ovl_compute_fifo_thresholds(enum omap_plane plane,
u32 *fifo_low, u32 *fifo_high, bool use_fifomerge,
bool manual_update);
-int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi,
- bool replication, const struct omap_video_timings *mgr_timings);
+int dispc_ovl_setup(enum omap_plane plane, const struct omap_overlay_info *oi,
+ bool replication, const struct omap_video_timings *mgr_timings,
+ bool mem_to_mem);
int dispc_ovl_enable(enum omap_plane plane, bool enable);
void dispc_ovl_set_channel_out(enum omap_plane plane,
enum omap_channel channel);
@@ -457,6 +486,15 @@ int dispc_mgr_get_clock_div(enum omap_channel channel,
void dispc_mgr_setup(enum omap_channel channel,
struct omap_overlay_manager_info *info);
+u32 dispc_wb_get_framedone_irq(void);
+bool dispc_wb_go_busy(void);
+void dispc_wb_go(void);
+void dispc_wb_enable(bool enable);
+bool dispc_wb_is_enabled(void);
+void dispc_wb_set_channel_in(enum dss_writeback_channel channel);
+int dispc_wb_setup(const struct omap_dss_writeback_info *wi,
+ bool mem_to_mem, const struct omap_video_timings *timings);
+
/* VENC */
#ifdef CONFIG_OMAP2_DSS_VENC
int venc_init_platform_driver(void) __init;
@@ -469,6 +507,20 @@ static inline unsigned long venc_get_pixel_clock(void)
return 0;
}
#endif
+int omapdss_venc_display_enable(struct omap_dss_device *dssdev);
+void omapdss_venc_display_disable(struct omap_dss_device *dssdev);
+void omapdss_venc_set_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings);
+int omapdss_venc_check_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings);
+u32 omapdss_venc_get_wss(struct omap_dss_device *dssdev);
+int omapdss_venc_set_wss(struct omap_dss_device *dssdev, u32 wss);
+void omapdss_venc_set_type(struct omap_dss_device *dssdev,
+ enum omap_dss_venc_type type);
+void omapdss_venc_invert_vid_out_polarity(struct omap_dss_device *dssdev,
+ bool invert_polarity);
+int venc_panel_init(void);
+void venc_panel_exit(void);
/* HDMI */
#ifdef CONFIG_OMAP4_DSS_HDMI
@@ -484,7 +536,8 @@ static inline unsigned long hdmi_get_pixel_clock(void)
#endif
int omapdss_hdmi_display_enable(struct omap_dss_device *dssdev);
void omapdss_hdmi_display_disable(struct omap_dss_device *dssdev);
-void omapdss_hdmi_display_set_timing(struct omap_dss_device *dssdev);
+void omapdss_hdmi_display_set_timing(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings);
int omapdss_hdmi_display_check_timing(struct omap_dss_device *dssdev,
struct omap_video_timings *timings);
int omapdss_hdmi_read_edid(u8 *buf, int len);
diff --git a/drivers/video/omap2/dss/dss_features.c b/drivers/video/omap2/dss/dss_features.c
index 9387097..acbc1e1 100644
--- a/drivers/video/omap2/dss/dss_features.c
+++ b/drivers/video/omap2/dss/dss_features.c
@@ -46,7 +46,9 @@ struct omap_dss_features {
const int num_mgrs;
const int num_ovls;
+ const int num_wbs;
const enum omap_display_type *supported_displays;
+ const enum omap_dss_output_id *supported_outputs;
const enum omap_color_mode *supported_color_modes;
const enum omap_overlay_caps *overlay_caps;
const char * const *clksrc_names;
@@ -106,6 +108,21 @@ static const struct dss_reg_field omap4_dss_reg_fields[] = {
[FEAT_REG_DSIPLL_REGM_DSI] = { 30, 26 },
};
+static const struct dss_reg_field omap5_dss_reg_fields[] = {
+ [FEAT_REG_FIRHINC] = { 12, 0 },
+ [FEAT_REG_FIRVINC] = { 28, 16 },
+ [FEAT_REG_FIFOLOWTHRESHOLD] = { 15, 0 },
+ [FEAT_REG_FIFOHIGHTHRESHOLD] = { 31, 16 },
+ [FEAT_REG_FIFOSIZE] = { 15, 0 },
+ [FEAT_REG_HORIZONTALACCU] = { 10, 0 },
+ [FEAT_REG_VERTICALACCU] = { 26, 16 },
+ [FEAT_REG_DISPC_CLK_SWITCH] = { 9, 7 },
+ [FEAT_REG_DSIPLL_REGN] = { 8, 1 },
+ [FEAT_REG_DSIPLL_REGM] = { 20, 9 },
+ [FEAT_REG_DSIPLL_REGM_DISPC] = { 25, 21 },
+ [FEAT_REG_DSIPLL_REGM_DSI] = { 30, 26 },
+};
+
static const enum omap_display_type omap2_dss_supported_displays[] = {
/* OMAP_DSS_CHANNEL_LCD */
OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI,
@@ -144,6 +161,76 @@ static const enum omap_display_type omap4_dss_supported_displays[] = {
OMAP_DISPLAY_TYPE_DSI,
};
+static const enum omap_display_type omap5_dss_supported_displays[] = {
+ /* OMAP_DSS_CHANNEL_LCD */
+ OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI |
+ OMAP_DISPLAY_TYPE_DSI,
+
+ /* OMAP_DSS_CHANNEL_DIGIT */
+ OMAP_DISPLAY_TYPE_HDMI | OMAP_DISPLAY_TYPE_DPI,
+
+ /* OMAP_DSS_CHANNEL_LCD2 */
+ OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI |
+ OMAP_DISPLAY_TYPE_DSI,
+};
+
+static const enum omap_dss_output_id omap2_dss_supported_outputs[] = {
+ /* OMAP_DSS_CHANNEL_LCD */
+ OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI,
+
+ /* OMAP_DSS_CHANNEL_DIGIT */
+ OMAP_DSS_OUTPUT_VENC,
+};
+
+static const enum omap_dss_output_id omap3430_dss_supported_outputs[] = {
+ /* OMAP_DSS_CHANNEL_LCD */
+ OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI |
+ OMAP_DSS_OUTPUT_SDI | OMAP_DSS_OUTPUT_DSI1,
+
+ /* OMAP_DSS_CHANNEL_DIGIT */
+ OMAP_DSS_OUTPUT_VENC,
+};
+
+static const enum omap_dss_output_id omap3630_dss_supported_outputs[] = {
+ /* OMAP_DSS_CHANNEL_LCD */
+ OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI |
+ OMAP_DSS_OUTPUT_DSI1,
+
+ /* OMAP_DSS_CHANNEL_DIGIT */
+ OMAP_DSS_OUTPUT_VENC,
+};
+
+static const enum omap_dss_output_id omap4_dss_supported_outputs[] = {
+ /* OMAP_DSS_CHANNEL_LCD */
+ OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI |
+ OMAP_DSS_OUTPUT_DSI1,
+
+ /* OMAP_DSS_CHANNEL_DIGIT */
+ OMAP_DSS_OUTPUT_VENC | OMAP_DSS_OUTPUT_HDMI |
+ OMAP_DSS_OUTPUT_DPI,
+
+ /* OMAP_DSS_CHANNEL_LCD2 */
+ OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI |
+ OMAP_DSS_OUTPUT_DSI2,
+};
+
+static const enum omap_dss_output_id omap5_dss_supported_outputs[] = {
+ /* OMAP_DSS_CHANNEL_LCD */
+ OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI |
+ OMAP_DSS_OUTPUT_DSI1 | OMAP_DSS_OUTPUT_DSI2,
+
+ /* OMAP_DSS_CHANNEL_DIGIT */
+ OMAP_DSS_OUTPUT_HDMI | OMAP_DSS_OUTPUT_DPI,
+
+ /* OMAP_DSS_CHANNEL_LCD2 */
+ OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI |
+ OMAP_DSS_OUTPUT_DSI1,
+
+ /* OMAP_DSS_CHANNEL_LCD3 */
+ OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI |
+ OMAP_DSS_OUTPUT_DSI2,
+};
+
static const enum omap_color_mode omap2_dss_supported_color_modes[] = {
/* OMAP_DSS_GFX */
OMAP_DSS_COLOR_CLUT1 | OMAP_DSS_COLOR_CLUT2 |
@@ -224,58 +311,80 @@ static const enum omap_color_mode omap4_dss_supported_color_modes[] = {
OMAP_DSS_COLOR_ARGB16 | OMAP_DSS_COLOR_XRGB16_1555 |
OMAP_DSS_COLOR_ARGB32 | OMAP_DSS_COLOR_RGBX16 |
OMAP_DSS_COLOR_RGBX32,
+
+ /* OMAP_DSS_WB */
+ 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 enum omap_overlay_caps omap2_dss_overlay_caps[] = {
/* OMAP_DSS_GFX */
- 0,
+ OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION,
/* OMAP_DSS_VIDEO1 */
- OMAP_DSS_OVL_CAP_SCALE,
+ OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_POS |
+ OMAP_DSS_OVL_CAP_REPLICATION,
/* OMAP_DSS_VIDEO2 */
- OMAP_DSS_OVL_CAP_SCALE,
+ OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_POS |
+ OMAP_DSS_OVL_CAP_REPLICATION,
};
static const enum omap_overlay_caps omap3430_dss_overlay_caps[] = {
/* OMAP_DSS_GFX */
- OMAP_DSS_OVL_CAP_GLOBAL_ALPHA,
+ OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | OMAP_DSS_OVL_CAP_POS |
+ OMAP_DSS_OVL_CAP_REPLICATION,
/* OMAP_DSS_VIDEO1 */
- OMAP_DSS_OVL_CAP_SCALE,
+ OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_POS |
+ OMAP_DSS_OVL_CAP_REPLICATION,
/* OMAP_DSS_VIDEO2 */
- OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA,
+ OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA |
+ OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION,
};
static const enum omap_overlay_caps omap3630_dss_overlay_caps[] = {
/* OMAP_DSS_GFX */
- OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA,
+ OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA |
+ OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION,
/* OMAP_DSS_VIDEO1 */
- OMAP_DSS_OVL_CAP_SCALE,
+ OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_POS |
+ OMAP_DSS_OVL_CAP_REPLICATION,
/* OMAP_DSS_VIDEO2 */
OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA |
- OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA,
+ OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | OMAP_DSS_OVL_CAP_POS |
+ OMAP_DSS_OVL_CAP_REPLICATION,
};
static const enum omap_overlay_caps omap4_dss_overlay_caps[] = {
/* OMAP_DSS_GFX */
OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA |
- OMAP_DSS_OVL_CAP_ZORDER,
+ OMAP_DSS_OVL_CAP_ZORDER | OMAP_DSS_OVL_CAP_POS |
+ OMAP_DSS_OVL_CAP_REPLICATION,
/* OMAP_DSS_VIDEO1 */
OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA |
- OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | OMAP_DSS_OVL_CAP_ZORDER,
+ OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | OMAP_DSS_OVL_CAP_ZORDER |
+ OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION,
/* OMAP_DSS_VIDEO2 */
OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA |
- OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | OMAP_DSS_OVL_CAP_ZORDER,
+ OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | OMAP_DSS_OVL_CAP_ZORDER |
+ OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION,
/* OMAP_DSS_VIDEO3 */
OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA |
- OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | OMAP_DSS_OVL_CAP_ZORDER,
+ OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | OMAP_DSS_OVL_CAP_ZORDER |
+ OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION,
};
static const char * const omap2_dss_clk_source_names[] = {
@@ -298,6 +407,14 @@ static const char * const omap4_dss_clk_source_names[] = {
[OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI] = "PLL2_CLK2",
};
+static const char * const omap5_dss_clk_source_names[] = {
+ [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC] = "DPLL_DSI1_A_CLK1",
+ [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI] = "DPLL_DSI1_A_CLK2",
+ [OMAP_DSS_CLK_SRC_FCK] = "DSS_CLK",
+ [OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC] = "DPLL_DSI1_C_CLK1",
+ [OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI] = "DPLL_DSI1_C_CLK2",
+};
+
static const struct dss_param_range omap2_dss_param_range[] = {
[FEAT_PARAM_DSS_FCK] = { 0, 173000000 },
[FEAT_PARAM_DSS_PCD] = { 2, 255 },
@@ -326,6 +443,7 @@ static const struct dss_param_range omap3_dss_param_range[] = {
[FEAT_PARAM_DSIPLL_REGM_DSI] = { 0, (1 << 4) - 1 },
[FEAT_PARAM_DSIPLL_FINT] = { 750000, 2100000 },
[FEAT_PARAM_DSIPLL_LPDIV] = { 1, (1 << 13) - 1},
+ [FEAT_PARAM_DSI_FCK] = { 0, 173000000 },
[FEAT_PARAM_DOWNSCALE] = { 1, 4 },
[FEAT_PARAM_LINEWIDTH] = { 1, 1024 },
[FEAT_PARAM_MGR_WIDTH] = { 1, 2048 },
@@ -341,6 +459,23 @@ static const struct dss_param_range omap4_dss_param_range[] = {
[FEAT_PARAM_DSIPLL_REGM_DSI] = { 0, (1 << 5) - 1 },
[FEAT_PARAM_DSIPLL_FINT] = { 500000, 2500000 },
[FEAT_PARAM_DSIPLL_LPDIV] = { 0, (1 << 13) - 1 },
+ [FEAT_PARAM_DSI_FCK] = { 0, 170000000 },
+ [FEAT_PARAM_DOWNSCALE] = { 1, 4 },
+ [FEAT_PARAM_LINEWIDTH] = { 1, 2048 },
+ [FEAT_PARAM_MGR_WIDTH] = { 1, 2048 },
+ [FEAT_PARAM_MGR_HEIGHT] = { 1, 2048 },
+};
+
+static const struct dss_param_range omap5_dss_param_range[] = {
+ [FEAT_PARAM_DSS_FCK] = { 0, 200000000 },
+ [FEAT_PARAM_DSS_PCD] = { 1, 255 },
+ [FEAT_PARAM_DSIPLL_REGN] = { 0, (1 << 8) - 1 },
+ [FEAT_PARAM_DSIPLL_REGM] = { 0, (1 << 12) - 1 },
+ [FEAT_PARAM_DSIPLL_REGM_DISPC] = { 0, (1 << 5) - 1 },
+ [FEAT_PARAM_DSIPLL_REGM_DSI] = { 0, (1 << 5) - 1 },
+ [FEAT_PARAM_DSIPLL_FINT] = { 500000, 2500000 },
+ [FEAT_PARAM_DSIPLL_LPDIV] = { 0, (1 << 13) - 1 },
+ [FEAT_PARAM_DSI_FCK] = { 0, 170000000 },
[FEAT_PARAM_DOWNSCALE] = { 1, 4 },
[FEAT_PARAM_LINEWIDTH] = { 1, 2048 },
[FEAT_PARAM_MGR_WIDTH] = { 1, 2048 },
@@ -373,6 +508,26 @@ static const enum dss_feat_id omap3430_dss_feat_list[] = {
FEAT_ALPHA_FIXED_ZORDER,
FEAT_FIFO_MERGE,
FEAT_OMAP3_DSI_FIFO_BUG,
+ FEAT_DPI_USES_VDDS_DSI,
+};
+
+static const enum dss_feat_id am35xx_dss_feat_list[] = {
+ FEAT_LCDENABLEPOL,
+ FEAT_LCDENABLESIGNAL,
+ FEAT_PCKFREEENABLE,
+ FEAT_FUNCGATED,
+ FEAT_LINEBUFFERSPLIT,
+ FEAT_ROWREPEATENABLE,
+ FEAT_RESIZECONF,
+ FEAT_DSI_PLL_FREQSEL,
+ FEAT_DSI_REVERSE_TXCLKESC,
+ FEAT_VENC_REQUIRES_TV_DAC_CLK,
+ FEAT_CPR,
+ FEAT_PRELOAD,
+ FEAT_FIR_COEF_V,
+ FEAT_ALPHA_FIXED_ZORDER,
+ FEAT_FIFO_MERGE,
+ FEAT_OMAP3_DSI_FIFO_BUG,
};
static const enum dss_feat_id omap3630_dss_feat_list[] = {
@@ -447,6 +602,28 @@ static const enum dss_feat_id omap4_dss_feat_list[] = {
FEAT_BURST_2D,
};
+static const enum dss_feat_id omap5_dss_feat_list[] = {
+ FEAT_MGR_LCD2,
+ 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_HDMI_AUDIO_USE_MCLK,
+ FEAT_HANDLE_UV_SEPARATE,
+ FEAT_ATTR2,
+ FEAT_CPR,
+ FEAT_PRELOAD,
+ FEAT_FIR_COEF_V,
+ FEAT_ALPHA_FREE_ZORDER,
+ FEAT_FIFO_MERGE,
+ FEAT_BURST_2D,
+ FEAT_DSI_PLL_SELFREQDCO,
+ FEAT_DSI_PLL_REFSEL,
+ FEAT_DSI_PHY_DCC,
+};
+
/* OMAP2 DSS Features */
static const struct omap_dss_features omap2_dss_features = {
.reg_fields = omap2_dss_reg_fields,
@@ -458,6 +635,7 @@ static const struct omap_dss_features omap2_dss_features = {
.num_mgrs = 2,
.num_ovls = 3,
.supported_displays = omap2_dss_supported_displays,
+ .supported_outputs = omap2_dss_supported_outputs,
.supported_color_modes = omap2_dss_supported_color_modes,
.overlay_caps = omap2_dss_overlay_caps,
.clksrc_names = omap2_dss_clk_source_names,
@@ -478,6 +656,31 @@ static const struct omap_dss_features omap3430_dss_features = {
.num_mgrs = 2,
.num_ovls = 3,
.supported_displays = omap3430_dss_supported_displays,
+ .supported_outputs = omap3430_dss_supported_outputs,
+ .supported_color_modes = omap3_dss_supported_color_modes,
+ .overlay_caps = omap3430_dss_overlay_caps,
+ .clksrc_names = omap3_dss_clk_source_names,
+ .dss_params = omap3_dss_param_range,
+ .supported_rotation_types = OMAP_DSS_ROT_DMA | OMAP_DSS_ROT_VRFB,
+ .buffer_size_unit = 1,
+ .burst_size_unit = 8,
+};
+
+/*
+ * AM35xx DSS Features. This is basically OMAP3 DSS Features without the
+ * vdds_dsi regulator.
+ */
+static const struct omap_dss_features am35xx_dss_features = {
+ .reg_fields = omap3_dss_reg_fields,
+ .num_reg_fields = ARRAY_SIZE(omap3_dss_reg_fields),
+
+ .features = am35xx_dss_feat_list,
+ .num_features = ARRAY_SIZE(am35xx_dss_feat_list),
+
+ .num_mgrs = 2,
+ .num_ovls = 3,
+ .supported_displays = omap3430_dss_supported_displays,
+ .supported_outputs = omap3430_dss_supported_outputs,
.supported_color_modes = omap3_dss_supported_color_modes,
.overlay_caps = omap3430_dss_overlay_caps,
.clksrc_names = omap3_dss_clk_source_names,
@@ -497,6 +700,7 @@ static const struct omap_dss_features omap3630_dss_features = {
.num_mgrs = 2,
.num_ovls = 3,
.supported_displays = omap3630_dss_supported_displays,
+ .supported_outputs = omap3630_dss_supported_outputs,
.supported_color_modes = omap3_dss_supported_color_modes,
.overlay_caps = omap3630_dss_overlay_caps,
.clksrc_names = omap3_dss_clk_source_names,
@@ -517,7 +721,9 @@ static const struct omap_dss_features omap4430_es1_0_dss_features = {
.num_mgrs = 3,
.num_ovls = 4,
+ .num_wbs = 1,
.supported_displays = omap4_dss_supported_displays,
+ .supported_outputs = omap4_dss_supported_outputs,
.supported_color_modes = omap4_dss_supported_color_modes,
.overlay_caps = omap4_dss_overlay_caps,
.clksrc_names = omap4_dss_clk_source_names,
@@ -537,7 +743,9 @@ static const struct omap_dss_features omap4430_es2_0_1_2_dss_features = {
.num_mgrs = 3,
.num_ovls = 4,
+ .num_wbs = 1,
.supported_displays = omap4_dss_supported_displays,
+ .supported_outputs = omap4_dss_supported_outputs,
.supported_color_modes = omap4_dss_supported_color_modes,
.overlay_caps = omap4_dss_overlay_caps,
.clksrc_names = omap4_dss_clk_source_names,
@@ -557,7 +765,9 @@ static const struct omap_dss_features omap4_dss_features = {
.num_mgrs = 3,
.num_ovls = 4,
+ .num_wbs = 1,
.supported_displays = omap4_dss_supported_displays,
+ .supported_outputs = omap4_dss_supported_outputs,
.supported_color_modes = omap4_dss_supported_color_modes,
.overlay_caps = omap4_dss_overlay_caps,
.clksrc_names = omap4_dss_clk_source_names,
@@ -567,6 +777,27 @@ static const struct omap_dss_features omap4_dss_features = {
.burst_size_unit = 16,
};
+/* OMAP5 DSS Features */
+static const struct omap_dss_features omap5_dss_features = {
+ .reg_fields = omap5_dss_reg_fields,
+ .num_reg_fields = ARRAY_SIZE(omap5_dss_reg_fields),
+
+ .features = omap5_dss_feat_list,
+ .num_features = ARRAY_SIZE(omap5_dss_feat_list),
+
+ .num_mgrs = 3,
+ .num_ovls = 4,
+ .supported_displays = omap5_dss_supported_displays,
+ .supported_outputs = omap5_dss_supported_outputs,
+ .supported_color_modes = omap4_dss_supported_color_modes,
+ .overlay_caps = omap4_dss_overlay_caps,
+ .clksrc_names = omap5_dss_clk_source_names,
+ .dss_params = omap5_dss_param_range,
+ .supported_rotation_types = OMAP_DSS_ROT_DMA | OMAP_DSS_ROT_TILER,
+ .buffer_size_unit = 16,
+ .burst_size_unit = 16,
+};
+
#if defined(CONFIG_OMAP4_DSS_HDMI)
/* HDMI OMAP4 Functions*/
static const struct ti_hdmi_ip_ops omap4_hdmi_functions = {
@@ -612,6 +843,11 @@ int dss_feat_get_num_ovls(void)
return omap_current_dss_features->num_ovls;
}
+int dss_feat_get_num_wbs(void)
+{
+ return omap_current_dss_features->num_wbs;
+}
+
unsigned long dss_feat_get_param_min(enum dss_range_param param)
{
return omap_current_dss_features->dss_params[param].min;
@@ -627,6 +863,11 @@ enum omap_display_type dss_feat_get_supported_displays(enum omap_channel channel
return omap_current_dss_features->supported_displays[channel];
}
+enum omap_dss_output_id dss_feat_get_supported_outputs(enum omap_channel channel)
+{
+ return omap_current_dss_features->supported_outputs[channel];
+}
+
enum omap_color_mode dss_feat_get_supported_color_modes(enum omap_plane plane)
{
return omap_current_dss_features->supported_color_modes[plane];
@@ -694,8 +935,13 @@ void dss_features_init(void)
omap_current_dss_features = &omap2_dss_features;
else if (cpu_is_omap3630())
omap_current_dss_features = &omap3630_dss_features;
- else if (cpu_is_omap34xx())
- omap_current_dss_features = &omap3430_dss_features;
+ else if (cpu_is_omap34xx()) {
+ if (soc_is_am35xx()) {
+ omap_current_dss_features = &am35xx_dss_features;
+ } else {
+ omap_current_dss_features = &omap3430_dss_features;
+ }
+ }
else if (omap_rev() == OMAP4430_REV_ES1_0)
omap_current_dss_features = &omap4430_es1_0_dss_features;
else if (omap_rev() == OMAP4430_REV_ES2_0 ||
@@ -704,6 +950,8 @@ void dss_features_init(void)
omap_current_dss_features = &omap4430_es2_0_1_2_dss_features;
else if (cpu_is_omap44xx())
omap_current_dss_features = &omap4_dss_features;
+ else if (soc_is_omap54xx())
+ omap_current_dss_features = &omap5_dss_features;
else
DSSWARN("Unsupported OMAP version");
}
diff --git a/drivers/video/omap2/dss/dss_features.h b/drivers/video/omap2/dss/dss_features.h
index 996ffcb..9218113 100644
--- a/drivers/video/omap2/dss/dss_features.h
+++ b/drivers/video/omap2/dss/dss_features.h
@@ -50,6 +50,7 @@ enum dss_feat_id {
FEAT_DSI_VC_OCP_WIDTH,
FEAT_DSI_REVERSE_TXCLKESC,
FEAT_DSI_GNQ,
+ FEAT_DPI_USES_VDDS_DSI,
FEAT_HDMI_CTS_SWMODE,
FEAT_HDMI_AUDIO_USE_MCLK,
FEAT_HANDLE_UV_SEPARATE,
@@ -64,6 +65,9 @@ enum dss_feat_id {
/* An unknown HW bug causing the normal FIFO thresholds not to work */
FEAT_OMAP3_DSI_FIFO_BUG,
FEAT_BURST_2D,
+ FEAT_DSI_PLL_SELFREQDCO,
+ FEAT_DSI_PLL_REFSEL,
+ FEAT_DSI_PHY_DCC,
};
/* DSS register field id */
@@ -91,6 +95,7 @@ enum dss_range_param {
FEAT_PARAM_DSIPLL_REGM_DSI,
FEAT_PARAM_DSIPLL_FINT,
FEAT_PARAM_DSIPLL_LPDIV,
+ FEAT_PARAM_DSI_FCK,
FEAT_PARAM_DOWNSCALE,
FEAT_PARAM_LINEWIDTH,
FEAT_PARAM_MGR_WIDTH,
@@ -100,9 +105,11 @@ enum dss_range_param {
/* DSS Feature Functions */
int dss_feat_get_num_mgrs(void);
int dss_feat_get_num_ovls(void);
+int dss_feat_get_num_wbs(void);
unsigned long dss_feat_get_param_min(enum dss_range_param param);
unsigned long dss_feat_get_param_max(enum dss_range_param param);
enum omap_display_type dss_feat_get_supported_displays(enum omap_channel channel);
+enum omap_dss_output_id dss_feat_get_supported_outputs(enum omap_channel channel);
enum omap_color_mode dss_feat_get_supported_color_modes(enum omap_plane plane);
enum omap_overlay_caps dss_feat_get_overlay_caps(enum omap_plane plane);
bool dss_feat_color_mode_supported(enum omap_plane plane,
diff --git a/drivers/video/omap2/dss/hdmi.c b/drivers/video/omap2/dss/hdmi.c
index 060216f..a48a7dd 100644
--- a/drivers/video/omap2/dss/hdmi.c
+++ b/drivers/video/omap2/dss/hdmi.c
@@ -32,6 +32,8 @@
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/clk.h>
+#include <linux/gpio.h>
+#include <linux/regulator/consumer.h>
#include <video/omapdss.h>
#include "ti_hdmi.h"
@@ -61,6 +63,13 @@ static struct {
struct hdmi_ip_data ip_data;
struct clk *sys_clk;
+ struct regulator *vdda_hdmi_dac_reg;
+
+ int ct_cp_hpd_gpio;
+ int ls_oe_gpio;
+ int hpd_gpio;
+
+ struct omap_dss_output output;
} hdmi;
/*
@@ -314,12 +323,47 @@ static void hdmi_runtime_put(void)
static int __init hdmi_init_display(struct omap_dss_device *dssdev)
{
+ int r;
+
+ struct gpio gpios[] = {
+ { hdmi.ct_cp_hpd_gpio, GPIOF_OUT_INIT_LOW, "hdmi_ct_cp_hpd" },
+ { hdmi.ls_oe_gpio, GPIOF_OUT_INIT_LOW, "hdmi_ls_oe" },
+ { hdmi.hpd_gpio, GPIOF_DIR_IN, "hdmi_hpd" },
+ };
+
DSSDBG("init_display\n");
dss_init_hdmi_ip_ops(&hdmi.ip_data);
+
+ if (hdmi.vdda_hdmi_dac_reg == NULL) {
+ struct regulator *reg;
+
+ reg = devm_regulator_get(&hdmi.pdev->dev, "vdda_hdmi_dac");
+
+ if (IS_ERR(reg)) {
+ DSSERR("can't get VDDA_HDMI_DAC regulator\n");
+ return PTR_ERR(reg);
+ }
+
+ hdmi.vdda_hdmi_dac_reg = reg;
+ }
+
+ r = gpio_request_array(gpios, ARRAY_SIZE(gpios));
+ if (r)
+ return r;
+
return 0;
}
+static void __exit hdmi_uninit_display(struct omap_dss_device *dssdev)
+{
+ DSSDBG("uninit_display\n");
+
+ gpio_free(hdmi.ct_cp_hpd_gpio);
+ gpio_free(hdmi.ls_oe_gpio);
+ gpio_free(hdmi.hpd_gpio);
+}
+
static const struct hdmi_config *hdmi_find_timing(
const struct hdmi_config *timings_arr,
int len)
@@ -459,32 +503,30 @@ static void hdmi_compute_pll(struct omap_dss_device *dssdev, int phy,
static int hdmi_power_on(struct omap_dss_device *dssdev)
{
int r;
- const struct hdmi_config *timing;
struct omap_video_timings *p;
+ struct omap_overlay_manager *mgr = dssdev->output->manager;
unsigned long phy;
+ gpio_set_value(hdmi.ct_cp_hpd_gpio, 1);
+ gpio_set_value(hdmi.ls_oe_gpio, 1);
+
+ /* wait 300us after CT_CP_HPD for the 5V power output to reach 90% */
+ udelay(300);
+
+ r = regulator_enable(hdmi.vdda_hdmi_dac_reg);
+ if (r)
+ goto err_vdac_enable;
+
r = hdmi_runtime_get();
if (r)
- return r;
+ goto err_runtime_get;
- dss_mgr_disable(dssdev->manager);
+ dss_mgr_disable(mgr);
- p = &dssdev->panel.timings;
+ p = &hdmi.ip_data.cfg.timings;
- DSSDBG("hdmi_power_on x_res= %d y_res = %d\n",
- dssdev->panel.timings.x_res,
- dssdev->panel.timings.y_res);
+ DSSDBG("hdmi_power_on x_res= %d y_res = %d\n", p->x_res, p->y_res);
- timing = hdmi_get_timings();
- if (timing == NULL) {
- /* HDMI code 4 corresponds to 640 * 480 VGA */
- hdmi.ip_data.cfg.cm.code = 4;
- /* DVI mode 1 corresponds to HDMI 0 to DVI */
- hdmi.ip_data.cfg.cm.mode = HDMI_DVI;
- hdmi.ip_data.cfg = vesa_timings[0];
- } else {
- hdmi.ip_data.cfg = *timing;
- }
phy = p->pixel_clock;
hdmi_compute_pll(dssdev, phy, &hdmi.ip_data.pll_data);
@@ -495,13 +537,13 @@ static int hdmi_power_on(struct omap_dss_device *dssdev)
r = hdmi.ip_data.ops->pll_enable(&hdmi.ip_data);
if (r) {
DSSDBG("Failed to lock PLL\n");
- goto err;
+ goto err_pll_enable;
}
r = hdmi.ip_data.ops->phy_enable(&hdmi.ip_data);
if (r) {
DSSDBG("Failed to start PHY\n");
- goto err;
+ goto err_phy_enable;
}
hdmi.ip_data.ops->video_configure(&hdmi.ip_data);
@@ -521,13 +563,13 @@ static int hdmi_power_on(struct omap_dss_device *dssdev)
dispc_enable_gamma_table(0);
/* tv size */
- dss_mgr_set_timings(dssdev->manager, &dssdev->panel.timings);
+ dss_mgr_set_timings(mgr, p);
r = hdmi.ip_data.ops->video_enable(&hdmi.ip_data);
if (r)
goto err_vid_enable;
- r = dss_mgr_enable(dssdev->manager);
+ r = dss_mgr_enable(mgr);
if (r)
goto err_mgr_enable;
@@ -537,20 +579,33 @@ err_mgr_enable:
hdmi.ip_data.ops->video_disable(&hdmi.ip_data);
err_vid_enable:
hdmi.ip_data.ops->phy_disable(&hdmi.ip_data);
+err_phy_enable:
hdmi.ip_data.ops->pll_disable(&hdmi.ip_data);
-err:
+err_pll_enable:
hdmi_runtime_put();
+err_runtime_get:
+ regulator_disable(hdmi.vdda_hdmi_dac_reg);
+err_vdac_enable:
+ gpio_set_value(hdmi.ct_cp_hpd_gpio, 0);
+ gpio_set_value(hdmi.ls_oe_gpio, 0);
return -EIO;
}
static void hdmi_power_off(struct omap_dss_device *dssdev)
{
- dss_mgr_disable(dssdev->manager);
+ struct omap_overlay_manager *mgr = dssdev->output->manager;
+
+ dss_mgr_disable(mgr);
hdmi.ip_data.ops->video_disable(&hdmi.ip_data);
hdmi.ip_data.ops->phy_disable(&hdmi.ip_data);
hdmi.ip_data.ops->pll_disable(&hdmi.ip_data);
hdmi_runtime_put();
+
+ regulator_disable(hdmi.vdda_hdmi_dac_reg);
+
+ gpio_set_value(hdmi.ct_cp_hpd_gpio, 0);
+ gpio_set_value(hdmi.ls_oe_gpio, 0);
}
int omapdss_hdmi_display_check_timing(struct omap_dss_device *dssdev,
@@ -567,25 +622,22 @@ int omapdss_hdmi_display_check_timing(struct omap_dss_device *dssdev,
}
-void omapdss_hdmi_display_set_timing(struct omap_dss_device *dssdev)
+void omapdss_hdmi_display_set_timing(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
{
struct hdmi_cm cm;
+ const struct hdmi_config *t;
- cm = hdmi_get_code(&dssdev->panel.timings);
- hdmi.ip_data.cfg.cm.code = cm.code;
- hdmi.ip_data.cfg.cm.mode = cm.mode;
+ mutex_lock(&hdmi.lock);
- if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) {
- int r;
+ cm = hdmi_get_code(timings);
+ hdmi.ip_data.cfg.cm = cm;
- hdmi_power_off(dssdev);
+ t = hdmi_get_timings();
+ if (t != NULL)
+ hdmi.ip_data.cfg = *t;
- r = hdmi_power_on(dssdev);
- if (r)
- DSSERR("failed to power on device\n");
- } else {
- dss_mgr_set_timings(dssdev->manager, &dssdev->panel.timings);
- }
+ mutex_unlock(&hdmi.lock);
}
static void hdmi_dump_regs(struct seq_file *s)
@@ -640,20 +692,20 @@ bool omapdss_hdmi_detect(void)
int omapdss_hdmi_display_enable(struct omap_dss_device *dssdev)
{
- struct omap_dss_hdmi_data *priv = dssdev->data;
+ struct omap_dss_output *out = dssdev->output;
int r = 0;
DSSDBG("ENTER hdmi_display_enable\n");
mutex_lock(&hdmi.lock);
- if (dssdev->manager == NULL) {
- DSSERR("failed to enable display: no manager\n");
+ if (out == NULL || out->manager == NULL) {
+ DSSERR("failed to enable display: no output/manager\n");
r = -ENODEV;
goto err0;
}
- hdmi.ip_data.hpd_gpio = priv->hpd_gpio;
+ hdmi.ip_data.hpd_gpio = hdmi.hpd_gpio;
r = omap_dss_start_device(dssdev);
if (r) {
@@ -661,26 +713,15 @@ int omapdss_hdmi_display_enable(struct omap_dss_device *dssdev)
goto err0;
}
- if (dssdev->platform_enable) {
- r = dssdev->platform_enable(dssdev);
- if (r) {
- DSSERR("failed to enable GPIO's\n");
- goto err1;
- }
- }
-
r = hdmi_power_on(dssdev);
if (r) {
DSSERR("failed to power on device\n");
- goto err2;
+ goto err1;
}
mutex_unlock(&hdmi.lock);
return 0;
-err2:
- if (dssdev->platform_disable)
- dssdev->platform_disable(dssdev);
err1:
omap_dss_stop_device(dssdev);
err0:
@@ -696,9 +737,6 @@ void omapdss_hdmi_display_disable(struct omap_dss_device *dssdev)
hdmi_power_off(dssdev);
- if (dssdev->platform_disable)
- dssdev->platform_disable(dssdev);
-
omap_dss_stop_device(dssdev);
mutex_unlock(&hdmi.lock);
@@ -869,10 +907,14 @@ int hdmi_audio_config(struct omap_dss_audio *audio)
#endif
-static void __init hdmi_probe_pdata(struct platform_device *pdev)
+static struct omap_dss_device * __init hdmi_find_dssdev(struct platform_device *pdev)
{
struct omap_dss_board_info *pdata = pdev->dev.platform_data;
- int r, i;
+ const char *def_disp_name = dss_get_default_display_name();
+ struct omap_dss_device *def_dssdev;
+ int i;
+
+ def_dssdev = NULL;
for (i = 0; i < pdata->num_devices; ++i) {
struct omap_dss_device *dssdev = pdata->devices[i];
@@ -880,17 +922,76 @@ static void __init hdmi_probe_pdata(struct platform_device *pdev)
if (dssdev->type != OMAP_DISPLAY_TYPE_HDMI)
continue;
- r = hdmi_init_display(dssdev);
- if (r) {
- DSSERR("device %s init failed: %d\n", dssdev->name, r);
- continue;
+ if (def_dssdev == NULL)
+ def_dssdev = dssdev;
+
+ if (def_disp_name != NULL &&
+ strcmp(dssdev->name, def_disp_name) == 0) {
+ def_dssdev = dssdev;
+ break;
}
+ }
- r = omap_dss_register_device(dssdev, &pdev->dev, i);
- if (r)
- DSSERR("device %s register failed: %d\n",
- dssdev->name, r);
+ return def_dssdev;
+}
+
+static void __init hdmi_probe_pdata(struct platform_device *pdev)
+{
+ struct omap_dss_device *plat_dssdev;
+ struct omap_dss_device *dssdev;
+ struct omap_dss_hdmi_data *priv;
+ int r;
+
+ plat_dssdev = hdmi_find_dssdev(pdev);
+
+ if (!plat_dssdev)
+ return;
+
+ dssdev = dss_alloc_and_init_device(&pdev->dev);
+ if (!dssdev)
+ return;
+
+ dss_copy_device_pdata(dssdev, plat_dssdev);
+
+ priv = dssdev->data;
+
+ hdmi.ct_cp_hpd_gpio = priv->ct_cp_hpd_gpio;
+ hdmi.ls_oe_gpio = priv->ls_oe_gpio;
+ hdmi.hpd_gpio = priv->hpd_gpio;
+
+ dssdev->channel = OMAP_DSS_CHANNEL_DIGIT;
+
+ r = hdmi_init_display(dssdev);
+ if (r) {
+ DSSERR("device %s init failed: %d\n", dssdev->name, r);
+ dss_put_device(dssdev);
+ return;
}
+
+ r = dss_add_device(dssdev);
+ if (r) {
+ DSSERR("device %s register failed: %d\n", dssdev->name, r);
+ dss_put_device(dssdev);
+ return;
+ }
+}
+
+static void __init hdmi_init_output(struct platform_device *pdev)
+{
+ struct omap_dss_output *out = &hdmi.output;
+
+ out->pdev = pdev;
+ out->id = OMAP_DSS_OUTPUT_HDMI;
+ out->type = OMAP_DISPLAY_TYPE_HDMI;
+
+ dss_register_output(out);
+}
+
+static void __exit hdmi_uninit_output(struct platform_device *pdev)
+{
+ struct omap_dss_output *out = &hdmi.output;
+
+ dss_unregister_output(out);
}
/* HDMI HW IP initialisation */
@@ -929,23 +1030,37 @@ static int __init omapdss_hdmihw_probe(struct platform_device *pdev)
hdmi.ip_data.core_av_offset = HDMI_CORE_AV;
hdmi.ip_data.pll_offset = HDMI_PLLCTRL;
hdmi.ip_data.phy_offset = HDMI_PHY;
+
mutex_init(&hdmi.ip_data.lock);
hdmi_panel_init();
dss_debugfs_create_file("hdmi", hdmi_dump_regs);
+ hdmi_init_output(pdev);
+
hdmi_probe_pdata(pdev);
return 0;
}
+static int __exit hdmi_remove_child(struct device *dev, void *data)
+{
+ struct omap_dss_device *dssdev = to_dss_device(dev);
+ hdmi_uninit_display(dssdev);
+ return 0;
+}
+
static int __exit omapdss_hdmihw_remove(struct platform_device *pdev)
{
- omap_dss_unregister_child_devices(&pdev->dev);
+ device_for_each_child(&pdev->dev, NULL, hdmi_remove_child);
+
+ dss_unregister_child_devices(&pdev->dev);
hdmi_panel_exit();
+ hdmi_uninit_output(pdev);
+
pm_runtime_disable(&pdev->dev);
hdmi_put_clocks();
diff --git a/drivers/video/omap2/dss/hdmi_panel.c b/drivers/video/omap2/dss/hdmi_panel.c
index e10844f..69fb115 100644
--- a/drivers/video/omap2/dss/hdmi_panel.c
+++ b/drivers/video/omap2/dss/hdmi_panel.c
@@ -41,17 +41,34 @@ static struct {
static int hdmi_panel_probe(struct omap_dss_device *dssdev)
{
+ /* Initialize default timings to VGA in DVI mode */
+ const struct omap_video_timings default_timings = {
+ .x_res = 640,
+ .y_res = 480,
+ .pixel_clock = 25175,
+ .hsw = 96,
+ .hfp = 16,
+ .hbp = 48,
+ .vsw = 2,
+ .vfp = 11,
+ .vbp = 31,
+
+ .vsync_level = OMAPDSS_SIG_ACTIVE_LOW,
+ .hsync_level = OMAPDSS_SIG_ACTIVE_LOW,
+
+ .interlace = false,
+ };
+
DSSDBG("ENTER hdmi_panel_probe\n");
- dssdev->panel.timings = (struct omap_video_timings)
- { 640, 480, 25175, 96, 16, 48, 2, 11, 31,
- OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW,
- false,
- };
+ dssdev->panel.timings = default_timings;
DSSDBG("hdmi_panel_probe x_res= %d y_res = %d\n",
dssdev->panel.timings.x_res,
dssdev->panel.timings.y_res);
+
+ omapdss_hdmi_display_set_timing(dssdev, &dssdev->panel.timings);
+
return 0;
}
@@ -228,6 +245,8 @@ static int hdmi_panel_enable(struct omap_dss_device *dssdev)
goto err;
}
+ omapdss_hdmi_display_set_timing(dssdev, &dssdev->panel.timings);
+
r = omapdss_hdmi_display_enable(dssdev);
if (r) {
DSSERR("failed to power on\n");
@@ -336,8 +355,8 @@ static void hdmi_set_timings(struct omap_dss_device *dssdev,
*/
hdmi_panel_audio_disable(dssdev);
+ omapdss_hdmi_display_set_timing(dssdev, timings);
dssdev->panel.timings = *timings;
- omapdss_hdmi_display_set_timing(dssdev);
mutex_unlock(&hdmi.lock);
}
diff --git a/drivers/video/omap2/dss/manager-sysfs.c b/drivers/video/omap2/dss/manager-sysfs.c
new file mode 100644
index 0000000..9a2fb59
--- /dev/null
+++ b/drivers/video/omap2/dss/manager-sysfs.c
@@ -0,0 +1,512 @@
+/*
+ * Copyright (C) 2009 Nokia Corporation
+ * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
+ *
+ * Some code and ideas taken from drivers/video/omap/ driver
+ * by Imre Deak.
+ *
+ * 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/>.
+ */
+
+#define DSS_SUBSYS_NAME "MANAGER"
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/jiffies.h>
+
+#include <video/omapdss.h>
+
+#include "dss.h"
+#include "dss_features.h"
+
+static ssize_t manager_name_show(struct omap_overlay_manager *mgr, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%s\n", mgr->name);
+}
+
+static ssize_t manager_display_show(struct omap_overlay_manager *mgr, char *buf)
+{
+ struct omap_dss_device *dssdev = mgr->get_device(mgr);
+
+ return snprintf(buf, PAGE_SIZE, "%s\n", dssdev ?
+ dssdev->name : "<none>");
+}
+
+static ssize_t manager_display_store(struct omap_overlay_manager *mgr,
+ const char *buf, size_t size)
+{
+ int r = 0;
+ size_t len = size;
+ struct omap_dss_device *dssdev = NULL;
+
+ int match(struct omap_dss_device *dssdev, void *data)
+ {
+ const char *str = data;
+ return sysfs_streq(dssdev->name, str);
+ }
+
+ if (buf[size-1] == '\n')
+ --len;
+
+ if (len > 0)
+ dssdev = omap_dss_find_device((void *)buf, match);
+
+ if (len > 0 && dssdev == NULL)
+ return -EINVAL;
+
+ if (dssdev)
+ DSSDBG("display %s found\n", dssdev->name);
+
+ if (mgr->output) {
+ r = mgr->unset_output(mgr);
+ if (r) {
+ DSSERR("failed to unset current output\n");
+ goto put_device;
+ }
+ }
+
+ if (dssdev) {
+ struct omap_dss_output *out = dssdev->output;
+
+ /*
+ * a registered device should have an output connected to it
+ * already
+ */
+ if (!out) {
+ DSSERR("device has no output connected to it\n");
+ goto put_device;
+ }
+
+ r = mgr->set_output(mgr, out);
+ if (r) {
+ DSSERR("failed to set manager output\n");
+ goto put_device;
+ }
+
+ r = mgr->apply(mgr);
+ if (r) {
+ DSSERR("failed to apply dispc config\n");
+ goto put_device;
+ }
+ }
+
+put_device:
+ if (dssdev)
+ omap_dss_put_device(dssdev);
+
+ return r ? r : size;
+}
+
+static ssize_t manager_default_color_show(struct omap_overlay_manager *mgr,
+ char *buf)
+{
+ struct omap_overlay_manager_info info;
+
+ mgr->get_manager_info(mgr, &info);
+
+ return snprintf(buf, PAGE_SIZE, "%#x\n", info.default_color);
+}
+
+static ssize_t manager_default_color_store(struct omap_overlay_manager *mgr,
+ const char *buf, size_t size)
+{
+ struct omap_overlay_manager_info info;
+ u32 color;
+ int r;
+
+ r = kstrtouint(buf, 0, &color);
+ if (r)
+ return r;
+
+ mgr->get_manager_info(mgr, &info);
+
+ info.default_color = color;
+
+ r = mgr->set_manager_info(mgr, &info);
+ if (r)
+ return r;
+
+ r = mgr->apply(mgr);
+ if (r)
+ return r;
+
+ return size;
+}
+
+static const char *trans_key_type_str[] = {
+ "gfx-destination",
+ "video-source",
+};
+
+static ssize_t manager_trans_key_type_show(struct omap_overlay_manager *mgr,
+ char *buf)
+{
+ enum omap_dss_trans_key_type key_type;
+ struct omap_overlay_manager_info info;
+
+ mgr->get_manager_info(mgr, &info);
+
+ key_type = info.trans_key_type;
+ BUG_ON(key_type >= ARRAY_SIZE(trans_key_type_str));
+
+ return snprintf(buf, PAGE_SIZE, "%s\n", trans_key_type_str[key_type]);
+}
+
+static ssize_t manager_trans_key_type_store(struct omap_overlay_manager *mgr,
+ const char *buf, size_t size)
+{
+ enum omap_dss_trans_key_type key_type;
+ struct omap_overlay_manager_info info;
+ int r;
+
+ for (key_type = OMAP_DSS_COLOR_KEY_GFX_DST;
+ key_type < ARRAY_SIZE(trans_key_type_str); key_type++) {
+ if (sysfs_streq(buf, trans_key_type_str[key_type]))
+ break;
+ }
+
+ if (key_type == ARRAY_SIZE(trans_key_type_str))
+ return -EINVAL;
+
+ mgr->get_manager_info(mgr, &info);
+
+ info.trans_key_type = key_type;
+
+ r = mgr->set_manager_info(mgr, &info);
+ if (r)
+ return r;
+
+ r = mgr->apply(mgr);
+ if (r)
+ return r;
+
+ return size;
+}
+
+static ssize_t manager_trans_key_value_show(struct omap_overlay_manager *mgr,
+ char *buf)
+{
+ struct omap_overlay_manager_info info;
+
+ mgr->get_manager_info(mgr, &info);
+
+ return snprintf(buf, PAGE_SIZE, "%#x\n", info.trans_key);
+}
+
+static ssize_t manager_trans_key_value_store(struct omap_overlay_manager *mgr,
+ const char *buf, size_t size)
+{
+ struct omap_overlay_manager_info info;
+ u32 key_value;
+ int r;
+
+ r = kstrtouint(buf, 0, &key_value);
+ if (r)
+ return r;
+
+ mgr->get_manager_info(mgr, &info);
+
+ info.trans_key = key_value;
+
+ r = mgr->set_manager_info(mgr, &info);
+ if (r)
+ return r;
+
+ r = mgr->apply(mgr);
+ if (r)
+ return r;
+
+ return size;
+}
+
+static ssize_t manager_trans_key_enabled_show(struct omap_overlay_manager *mgr,
+ char *buf)
+{
+ struct omap_overlay_manager_info info;
+
+ mgr->get_manager_info(mgr, &info);
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", info.trans_enabled);
+}
+
+static ssize_t manager_trans_key_enabled_store(struct omap_overlay_manager *mgr,
+ const char *buf, size_t size)
+{
+ struct omap_overlay_manager_info info;
+ bool enable;
+ int r;
+
+ r = strtobool(buf, &enable);
+ if (r)
+ return r;
+
+ mgr->get_manager_info(mgr, &info);
+
+ info.trans_enabled = enable;
+
+ r = mgr->set_manager_info(mgr, &info);
+ if (r)
+ return r;
+
+ r = mgr->apply(mgr);
+ if (r)
+ return r;
+
+ return size;
+}
+
+static ssize_t manager_alpha_blending_enabled_show(
+ struct omap_overlay_manager *mgr, char *buf)
+{
+ struct omap_overlay_manager_info info;
+
+ mgr->get_manager_info(mgr, &info);
+
+ WARN_ON(!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER));
+
+ return snprintf(buf, PAGE_SIZE, "%d\n",
+ info.partial_alpha_enabled);
+}
+
+static ssize_t manager_alpha_blending_enabled_store(
+ struct omap_overlay_manager *mgr,
+ const char *buf, size_t size)
+{
+ struct omap_overlay_manager_info info;
+ bool enable;
+ int r;
+
+ WARN_ON(!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER));
+
+ r = strtobool(buf, &enable);
+ if (r)
+ return r;
+
+ mgr->get_manager_info(mgr, &info);
+
+ info.partial_alpha_enabled = enable;
+
+ r = mgr->set_manager_info(mgr, &info);
+ if (r)
+ return r;
+
+ r = mgr->apply(mgr);
+ if (r)
+ return r;
+
+ return size;
+}
+
+static ssize_t manager_cpr_enable_show(struct omap_overlay_manager *mgr,
+ char *buf)
+{
+ struct omap_overlay_manager_info info;
+
+ mgr->get_manager_info(mgr, &info);
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", info.cpr_enable);
+}
+
+static ssize_t manager_cpr_enable_store(struct omap_overlay_manager *mgr,
+ const char *buf, size_t size)
+{
+ struct omap_overlay_manager_info info;
+ int r;
+ bool enable;
+
+ if (!dss_has_feature(FEAT_CPR))
+ return -ENODEV;
+
+ r = strtobool(buf, &enable);
+ if (r)
+ return r;
+
+ mgr->get_manager_info(mgr, &info);
+
+ if (info.cpr_enable == enable)
+ return size;
+
+ info.cpr_enable = enable;
+
+ r = mgr->set_manager_info(mgr, &info);
+ if (r)
+ return r;
+
+ r = mgr->apply(mgr);
+ if (r)
+ return r;
+
+ return size;
+}
+
+static ssize_t manager_cpr_coef_show(struct omap_overlay_manager *mgr,
+ char *buf)
+{
+ struct omap_overlay_manager_info info;
+
+ mgr->get_manager_info(mgr, &info);
+
+ return snprintf(buf, PAGE_SIZE,
+ "%d %d %d %d %d %d %d %d %d\n",
+ info.cpr_coefs.rr,
+ info.cpr_coefs.rg,
+ info.cpr_coefs.rb,
+ info.cpr_coefs.gr,
+ info.cpr_coefs.gg,
+ info.cpr_coefs.gb,
+ info.cpr_coefs.br,
+ info.cpr_coefs.bg,
+ info.cpr_coefs.bb);
+}
+
+static ssize_t manager_cpr_coef_store(struct omap_overlay_manager *mgr,
+ const char *buf, size_t size)
+{
+ struct omap_overlay_manager_info info;
+ struct omap_dss_cpr_coefs coefs;
+ int r, i;
+ s16 *arr;
+
+ if (!dss_has_feature(FEAT_CPR))
+ return -ENODEV;
+
+ if (sscanf(buf, "%hd %hd %hd %hd %hd %hd %hd %hd %hd",
+ &coefs.rr, &coefs.rg, &coefs.rb,
+ &coefs.gr, &coefs.gg, &coefs.gb,
+ &coefs.br, &coefs.bg, &coefs.bb) != 9)
+ return -EINVAL;
+
+ arr = (s16[]){ coefs.rr, coefs.rg, coefs.rb,
+ coefs.gr, coefs.gg, coefs.gb,
+ coefs.br, coefs.bg, coefs.bb };
+
+ for (i = 0; i < 9; ++i) {
+ if (arr[i] < -512 || arr[i] > 511)
+ return -EINVAL;
+ }
+
+ mgr->get_manager_info(mgr, &info);
+
+ info.cpr_coefs = coefs;
+
+ r = mgr->set_manager_info(mgr, &info);
+ if (r)
+ return r;
+
+ r = mgr->apply(mgr);
+ if (r)
+ return r;
+
+ return size;
+}
+
+struct manager_attribute {
+ struct attribute attr;
+ ssize_t (*show)(struct omap_overlay_manager *, char *);
+ ssize_t (*store)(struct omap_overlay_manager *, const char *, size_t);
+};
+
+#define MANAGER_ATTR(_name, _mode, _show, _store) \
+ struct manager_attribute manager_attr_##_name = \
+ __ATTR(_name, _mode, _show, _store)
+
+static MANAGER_ATTR(name, S_IRUGO, manager_name_show, NULL);
+static MANAGER_ATTR(display, S_IRUGO|S_IWUSR,
+ manager_display_show, manager_display_store);
+static MANAGER_ATTR(default_color, S_IRUGO|S_IWUSR,
+ manager_default_color_show, manager_default_color_store);
+static MANAGER_ATTR(trans_key_type, S_IRUGO|S_IWUSR,
+ manager_trans_key_type_show, manager_trans_key_type_store);
+static MANAGER_ATTR(trans_key_value, S_IRUGO|S_IWUSR,
+ manager_trans_key_value_show, manager_trans_key_value_store);
+static MANAGER_ATTR(trans_key_enabled, S_IRUGO|S_IWUSR,
+ manager_trans_key_enabled_show,
+ manager_trans_key_enabled_store);
+static MANAGER_ATTR(alpha_blending_enabled, S_IRUGO|S_IWUSR,
+ manager_alpha_blending_enabled_show,
+ manager_alpha_blending_enabled_store);
+static MANAGER_ATTR(cpr_enable, S_IRUGO|S_IWUSR,
+ manager_cpr_enable_show,
+ manager_cpr_enable_store);
+static MANAGER_ATTR(cpr_coef, S_IRUGO|S_IWUSR,
+ manager_cpr_coef_show,
+ manager_cpr_coef_store);
+
+
+static struct attribute *manager_sysfs_attrs[] = {
+ &manager_attr_name.attr,
+ &manager_attr_display.attr,
+ &manager_attr_default_color.attr,
+ &manager_attr_trans_key_type.attr,
+ &manager_attr_trans_key_value.attr,
+ &manager_attr_trans_key_enabled.attr,
+ &manager_attr_alpha_blending_enabled.attr,
+ &manager_attr_cpr_enable.attr,
+ &manager_attr_cpr_coef.attr,
+ NULL
+};
+
+static ssize_t manager_attr_show(struct kobject *kobj, struct attribute *attr,
+ char *buf)
+{
+ struct omap_overlay_manager *manager;
+ struct manager_attribute *manager_attr;
+
+ manager = container_of(kobj, struct omap_overlay_manager, kobj);
+ manager_attr = container_of(attr, struct manager_attribute, attr);
+
+ if (!manager_attr->show)
+ return -ENOENT;
+
+ return manager_attr->show(manager, buf);
+}
+
+static ssize_t manager_attr_store(struct kobject *kobj, struct attribute *attr,
+ const char *buf, size_t size)
+{
+ struct omap_overlay_manager *manager;
+ struct manager_attribute *manager_attr;
+
+ manager = container_of(kobj, struct omap_overlay_manager, kobj);
+ manager_attr = container_of(attr, struct manager_attribute, attr);
+
+ if (!manager_attr->store)
+ return -ENOENT;
+
+ return manager_attr->store(manager, buf, size);
+}
+
+static const struct sysfs_ops manager_sysfs_ops = {
+ .show = manager_attr_show,
+ .store = manager_attr_store,
+};
+
+static struct kobj_type manager_ktype = {
+ .sysfs_ops = &manager_sysfs_ops,
+ .default_attrs = manager_sysfs_attrs,
+};
+
+int dss_manager_kobj_init(struct omap_overlay_manager *mgr,
+ struct platform_device *pdev)
+{
+ return kobject_init_and_add(&mgr->kobj, &manager_ktype,
+ &pdev->dev.kobj, "manager%d", mgr->id);
+}
+
+void dss_manager_kobj_uninit(struct omap_overlay_manager *mgr)
+{
+ kobject_del(&mgr->kobj);
+ kobject_put(&mgr->kobj);
+}
diff --git a/drivers/video/omap2/dss/manager.c b/drivers/video/omap2/dss/manager.c
index 53710fa..c54d2f6 100644
--- a/drivers/video/omap2/dss/manager.c
+++ b/drivers/video/omap2/dss/manager.c
@@ -36,463 +36,15 @@
static int num_managers;
static struct omap_overlay_manager *managers;
-static ssize_t manager_name_show(struct omap_overlay_manager *mgr, char *buf)
+static inline struct omap_dss_device *dss_mgr_get_device(struct omap_overlay_manager *mgr)
{
- return snprintf(buf, PAGE_SIZE, "%s\n", mgr->name);
+ return mgr->output ? mgr->output->device : NULL;
}
-static ssize_t manager_display_show(struct omap_overlay_manager *mgr, char *buf)
-{
- return snprintf(buf, PAGE_SIZE, "%s\n",
- mgr->device ? mgr->device->name : "<none>");
-}
-
-static ssize_t manager_display_store(struct omap_overlay_manager *mgr,
- const char *buf, size_t size)
-{
- int r = 0;
- size_t len = size;
- struct omap_dss_device *dssdev = NULL;
-
- int match(struct omap_dss_device *dssdev, void *data)
- {
- const char *str = data;
- return sysfs_streq(dssdev->name, str);
- }
-
- if (buf[size-1] == '\n')
- --len;
-
- if (len > 0)
- dssdev = omap_dss_find_device((void *)buf, match);
-
- if (len > 0 && dssdev == NULL)
- return -EINVAL;
-
- if (dssdev)
- DSSDBG("display %s found\n", dssdev->name);
-
- if (mgr->device) {
- r = mgr->unset_device(mgr);
- if (r) {
- DSSERR("failed to unset display\n");
- goto put_device;
- }
- }
-
- if (dssdev) {
- r = mgr->set_device(mgr, dssdev);
- if (r) {
- DSSERR("failed to set manager\n");
- goto put_device;
- }
-
- r = mgr->apply(mgr);
- if (r) {
- DSSERR("failed to apply dispc config\n");
- goto put_device;
- }
- }
-
-put_device:
- if (dssdev)
- omap_dss_put_device(dssdev);
-
- return r ? r : size;
-}
-
-static ssize_t manager_default_color_show(struct omap_overlay_manager *mgr,
- char *buf)
-{
- struct omap_overlay_manager_info info;
-
- mgr->get_manager_info(mgr, &info);
-
- return snprintf(buf, PAGE_SIZE, "%#x\n", info.default_color);
-}
-
-static ssize_t manager_default_color_store(struct omap_overlay_manager *mgr,
- const char *buf, size_t size)
-{
- struct omap_overlay_manager_info info;
- u32 color;
- int r;
-
- r = kstrtouint(buf, 0, &color);
- if (r)
- return r;
-
- mgr->get_manager_info(mgr, &info);
-
- info.default_color = color;
-
- r = mgr->set_manager_info(mgr, &info);
- if (r)
- return r;
-
- r = mgr->apply(mgr);
- if (r)
- return r;
-
- return size;
-}
-
-static const char *trans_key_type_str[] = {
- "gfx-destination",
- "video-source",
-};
-
-static ssize_t manager_trans_key_type_show(struct omap_overlay_manager *mgr,
- char *buf)
-{
- enum omap_dss_trans_key_type key_type;
- struct omap_overlay_manager_info info;
-
- mgr->get_manager_info(mgr, &info);
-
- key_type = info.trans_key_type;
- BUG_ON(key_type >= ARRAY_SIZE(trans_key_type_str));
-
- return snprintf(buf, PAGE_SIZE, "%s\n", trans_key_type_str[key_type]);
-}
-
-static ssize_t manager_trans_key_type_store(struct omap_overlay_manager *mgr,
- const char *buf, size_t size)
-{
- enum omap_dss_trans_key_type key_type;
- struct omap_overlay_manager_info info;
- int r;
-
- for (key_type = OMAP_DSS_COLOR_KEY_GFX_DST;
- key_type < ARRAY_SIZE(trans_key_type_str); key_type++) {
- if (sysfs_streq(buf, trans_key_type_str[key_type]))
- break;
- }
-
- if (key_type == ARRAY_SIZE(trans_key_type_str))
- return -EINVAL;
-
- mgr->get_manager_info(mgr, &info);
-
- info.trans_key_type = key_type;
-
- r = mgr->set_manager_info(mgr, &info);
- if (r)
- return r;
-
- r = mgr->apply(mgr);
- if (r)
- return r;
-
- return size;
-}
-
-static ssize_t manager_trans_key_value_show(struct omap_overlay_manager *mgr,
- char *buf)
-{
- struct omap_overlay_manager_info info;
-
- mgr->get_manager_info(mgr, &info);
-
- return snprintf(buf, PAGE_SIZE, "%#x\n", info.trans_key);
-}
-
-static ssize_t manager_trans_key_value_store(struct omap_overlay_manager *mgr,
- const char *buf, size_t size)
-{
- struct omap_overlay_manager_info info;
- u32 key_value;
- int r;
-
- r = kstrtouint(buf, 0, &key_value);
- if (r)
- return r;
-
- mgr->get_manager_info(mgr, &info);
-
- info.trans_key = key_value;
-
- r = mgr->set_manager_info(mgr, &info);
- if (r)
- return r;
-
- r = mgr->apply(mgr);
- if (r)
- return r;
-
- return size;
-}
-
-static ssize_t manager_trans_key_enabled_show(struct omap_overlay_manager *mgr,
- char *buf)
-{
- struct omap_overlay_manager_info info;
-
- mgr->get_manager_info(mgr, &info);
-
- return snprintf(buf, PAGE_SIZE, "%d\n", info.trans_enabled);
-}
-
-static ssize_t manager_trans_key_enabled_store(struct omap_overlay_manager *mgr,
- const char *buf, size_t size)
-{
- struct omap_overlay_manager_info info;
- bool enable;
- int r;
-
- r = strtobool(buf, &enable);
- if (r)
- return r;
-
- mgr->get_manager_info(mgr, &info);
-
- info.trans_enabled = enable;
-
- r = mgr->set_manager_info(mgr, &info);
- if (r)
- return r;
-
- r = mgr->apply(mgr);
- if (r)
- return r;
-
- return size;
-}
-
-static ssize_t manager_alpha_blending_enabled_show(
- struct omap_overlay_manager *mgr, char *buf)
-{
- struct omap_overlay_manager_info info;
-
- mgr->get_manager_info(mgr, &info);
-
- WARN_ON(!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER));
-
- return snprintf(buf, PAGE_SIZE, "%d\n",
- info.partial_alpha_enabled);
-}
-
-static ssize_t manager_alpha_blending_enabled_store(
- struct omap_overlay_manager *mgr,
- const char *buf, size_t size)
-{
- struct omap_overlay_manager_info info;
- bool enable;
- int r;
-
- WARN_ON(!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER));
-
- r = strtobool(buf, &enable);
- if (r)
- return r;
-
- mgr->get_manager_info(mgr, &info);
-
- info.partial_alpha_enabled = enable;
-
- r = mgr->set_manager_info(mgr, &info);
- if (r)
- return r;
-
- r = mgr->apply(mgr);
- if (r)
- return r;
-
- return size;
-}
-
-static ssize_t manager_cpr_enable_show(struct omap_overlay_manager *mgr,
- char *buf)
-{
- struct omap_overlay_manager_info info;
-
- mgr->get_manager_info(mgr, &info);
-
- return snprintf(buf, PAGE_SIZE, "%d\n", info.cpr_enable);
-}
-
-static ssize_t manager_cpr_enable_store(struct omap_overlay_manager *mgr,
- const char *buf, size_t size)
-{
- struct omap_overlay_manager_info info;
- int r;
- bool enable;
-
- if (!dss_has_feature(FEAT_CPR))
- return -ENODEV;
-
- r = strtobool(buf, &enable);
- if (r)
- return r;
-
- mgr->get_manager_info(mgr, &info);
-
- if (info.cpr_enable == enable)
- return size;
-
- info.cpr_enable = enable;
-
- r = mgr->set_manager_info(mgr, &info);
- if (r)
- return r;
-
- r = mgr->apply(mgr);
- if (r)
- return r;
-
- return size;
-}
-
-static ssize_t manager_cpr_coef_show(struct omap_overlay_manager *mgr,
- char *buf)
-{
- struct omap_overlay_manager_info info;
-
- mgr->get_manager_info(mgr, &info);
-
- return snprintf(buf, PAGE_SIZE,
- "%d %d %d %d %d %d %d %d %d\n",
- info.cpr_coefs.rr,
- info.cpr_coefs.rg,
- info.cpr_coefs.rb,
- info.cpr_coefs.gr,
- info.cpr_coefs.gg,
- info.cpr_coefs.gb,
- info.cpr_coefs.br,
- info.cpr_coefs.bg,
- info.cpr_coefs.bb);
-}
-
-static ssize_t manager_cpr_coef_store(struct omap_overlay_manager *mgr,
- const char *buf, size_t size)
-{
- struct omap_overlay_manager_info info;
- struct omap_dss_cpr_coefs coefs;
- int r, i;
- s16 *arr;
-
- if (!dss_has_feature(FEAT_CPR))
- return -ENODEV;
-
- if (sscanf(buf, "%hd %hd %hd %hd %hd %hd %hd %hd %hd",
- &coefs.rr, &coefs.rg, &coefs.rb,
- &coefs.gr, &coefs.gg, &coefs.gb,
- &coefs.br, &coefs.bg, &coefs.bb) != 9)
- return -EINVAL;
-
- arr = (s16[]){ coefs.rr, coefs.rg, coefs.rb,
- coefs.gr, coefs.gg, coefs.gb,
- coefs.br, coefs.bg, coefs.bb };
-
- for (i = 0; i < 9; ++i) {
- if (arr[i] < -512 || arr[i] > 511)
- return -EINVAL;
- }
-
- mgr->get_manager_info(mgr, &info);
-
- info.cpr_coefs = coefs;
-
- r = mgr->set_manager_info(mgr, &info);
- if (r)
- return r;
-
- r = mgr->apply(mgr);
- if (r)
- return r;
-
- return size;
-}
-
-struct manager_attribute {
- struct attribute attr;
- ssize_t (*show)(struct omap_overlay_manager *, char *);
- ssize_t (*store)(struct omap_overlay_manager *, const char *, size_t);
-};
-
-#define MANAGER_ATTR(_name, _mode, _show, _store) \
- struct manager_attribute manager_attr_##_name = \
- __ATTR(_name, _mode, _show, _store)
-
-static MANAGER_ATTR(name, S_IRUGO, manager_name_show, NULL);
-static MANAGER_ATTR(display, S_IRUGO|S_IWUSR,
- manager_display_show, manager_display_store);
-static MANAGER_ATTR(default_color, S_IRUGO|S_IWUSR,
- manager_default_color_show, manager_default_color_store);
-static MANAGER_ATTR(trans_key_type, S_IRUGO|S_IWUSR,
- manager_trans_key_type_show, manager_trans_key_type_store);
-static MANAGER_ATTR(trans_key_value, S_IRUGO|S_IWUSR,
- manager_trans_key_value_show, manager_trans_key_value_store);
-static MANAGER_ATTR(trans_key_enabled, S_IRUGO|S_IWUSR,
- manager_trans_key_enabled_show,
- manager_trans_key_enabled_store);
-static MANAGER_ATTR(alpha_blending_enabled, S_IRUGO|S_IWUSR,
- manager_alpha_blending_enabled_show,
- manager_alpha_blending_enabled_store);
-static MANAGER_ATTR(cpr_enable, S_IRUGO|S_IWUSR,
- manager_cpr_enable_show,
- manager_cpr_enable_store);
-static MANAGER_ATTR(cpr_coef, S_IRUGO|S_IWUSR,
- manager_cpr_coef_show,
- manager_cpr_coef_store);
-
-
-static struct attribute *manager_sysfs_attrs[] = {
- &manager_attr_name.attr,
- &manager_attr_display.attr,
- &manager_attr_default_color.attr,
- &manager_attr_trans_key_type.attr,
- &manager_attr_trans_key_value.attr,
- &manager_attr_trans_key_enabled.attr,
- &manager_attr_alpha_blending_enabled.attr,
- &manager_attr_cpr_enable.attr,
- &manager_attr_cpr_coef.attr,
- NULL
-};
-
-static ssize_t manager_attr_show(struct kobject *kobj, struct attribute *attr,
- char *buf)
-{
- struct omap_overlay_manager *manager;
- struct manager_attribute *manager_attr;
-
- manager = container_of(kobj, struct omap_overlay_manager, kobj);
- manager_attr = container_of(attr, struct manager_attribute, attr);
-
- if (!manager_attr->show)
- return -ENOENT;
-
- return manager_attr->show(manager, buf);
-}
-
-static ssize_t manager_attr_store(struct kobject *kobj, struct attribute *attr,
- const char *buf, size_t size)
-{
- struct omap_overlay_manager *manager;
- struct manager_attribute *manager_attr;
-
- manager = container_of(kobj, struct omap_overlay_manager, kobj);
- manager_attr = container_of(attr, struct manager_attribute, attr);
-
- if (!manager_attr->store)
- return -ENOENT;
-
- return manager_attr->store(manager, buf, size);
-}
-
-static const struct sysfs_ops manager_sysfs_ops = {
- .show = manager_attr_show,
- .store = manager_attr_store,
-};
-
-static struct kobj_type manager_ktype = {
- .sysfs_ops = &manager_sysfs_ops,
- .default_attrs = manager_sysfs_attrs,
-};
-
static int dss_mgr_wait_for_vsync(struct omap_overlay_manager *mgr)
{
unsigned long timeout = msecs_to_jiffies(500);
+ struct omap_dss_device *dssdev = mgr->get_device(mgr);
u32 irq;
int r;
@@ -500,9 +52,9 @@ static int dss_mgr_wait_for_vsync(struct omap_overlay_manager *mgr)
if (r)
return r;
- if (mgr->device->type == OMAP_DISPLAY_TYPE_VENC)
+ if (dssdev->type == OMAP_DISPLAY_TYPE_VENC)
irq = DISPC_IRQ_EVSYNC_ODD;
- else if (mgr->device->type == OMAP_DISPLAY_TYPE_HDMI)
+ else if (dssdev->type == OMAP_DISPLAY_TYPE_HDMI)
irq = DISPC_IRQ_EVSYNC_EVEN;
else
irq = dispc_mgr_get_vsync_irq(mgr->id);
@@ -547,23 +99,24 @@ int dss_init_overlay_managers(struct platform_device *pdev)
break;
}
- mgr->set_device = &dss_mgr_set_device;
- mgr->unset_device = &dss_mgr_unset_device;
+ mgr->set_output = &dss_mgr_set_output;
+ mgr->unset_output = &dss_mgr_unset_output;
mgr->apply = &omap_dss_mgr_apply;
mgr->set_manager_info = &dss_mgr_set_info;
mgr->get_manager_info = &dss_mgr_get_info;
mgr->wait_for_go = &dss_mgr_wait_for_go;
mgr->wait_for_vsync = &dss_mgr_wait_for_vsync;
+ mgr->get_device = &dss_mgr_get_device;
mgr->caps = 0;
mgr->supported_displays =
dss_feat_get_supported_displays(mgr->id);
+ mgr->supported_outputs =
+ dss_feat_get_supported_outputs(mgr->id);
INIT_LIST_HEAD(&mgr->overlays);
- r = kobject_init_and_add(&mgr->kobj, &manager_ktype,
- &pdev->dev.kobj, "manager%d", i);
-
+ r = dss_manager_kobj_init(mgr, pdev);
if (r)
DSSERR("failed to create sysfs file\n");
}
@@ -577,9 +130,7 @@ void dss_uninit_overlay_managers(struct platform_device *pdev)
for (i = 0; i < num_managers; ++i) {
struct omap_overlay_manager *mgr = &managers[i];
-
- kobject_del(&mgr->kobj);
- kobject_put(&mgr->kobj);
+ dss_manager_kobj_uninit(mgr);
}
kfree(managers);
diff --git a/drivers/video/omap2/dss/output.c b/drivers/video/omap2/dss/output.c
new file mode 100644
index 0000000..813f266
--- /dev/null
+++ b/drivers/video/omap2/dss/output.c
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2012 Texas Instruments Ltd
+ * 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/>.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include <video/omapdss.h>
+
+#include "dss.h"
+
+static LIST_HEAD(output_list);
+static DEFINE_MUTEX(output_lock);
+
+int omapdss_output_set_device(struct omap_dss_output *out,
+ struct omap_dss_device *dssdev)
+{
+ int r;
+
+ mutex_lock(&output_lock);
+
+ if (out->device) {
+ DSSERR("output already has device %s connected to it\n",
+ out->device->name);
+ r = -EINVAL;
+ goto err;
+ }
+
+ if (out->type != dssdev->type) {
+ DSSERR("output type and display type don't match\n");
+ r = -EINVAL;
+ goto err;
+ }
+
+ out->device = dssdev;
+ dssdev->output = out;
+
+ mutex_unlock(&output_lock);
+
+ return 0;
+err:
+ mutex_unlock(&output_lock);
+
+ return r;
+}
+EXPORT_SYMBOL(omapdss_output_set_device);
+
+int omapdss_output_unset_device(struct omap_dss_output *out)
+{
+ int r;
+
+ mutex_lock(&output_lock);
+
+ if (!out->device) {
+ DSSERR("output doesn't have a device connected to it\n");
+ r = -EINVAL;
+ goto err;
+ }
+
+ if (out->device->state != OMAP_DSS_DISPLAY_DISABLED) {
+ DSSERR("device %s is not disabled, cannot unset device\n",
+ out->device->name);
+ r = -EINVAL;
+ goto err;
+ }
+
+ out->device->output = NULL;
+ out->device = NULL;
+
+ mutex_unlock(&output_lock);
+
+ return 0;
+err:
+ mutex_unlock(&output_lock);
+
+ return r;
+}
+EXPORT_SYMBOL(omapdss_output_unset_device);
+
+void dss_register_output(struct omap_dss_output *out)
+{
+ list_add_tail(&out->list, &output_list);
+}
+
+void dss_unregister_output(struct omap_dss_output *out)
+{
+ list_del(&out->list);
+}
+
+struct omap_dss_output *omap_dss_get_output(enum omap_dss_output_id id)
+{
+ struct omap_dss_output *out;
+
+ list_for_each_entry(out, &output_list, list) {
+ if (out->id == id)
+ return out;
+ }
+
+ return NULL;
+}
+
+struct omap_dss_output *omapdss_get_output_from_dssdev(struct omap_dss_device *dssdev)
+{
+ struct omap_dss_output *out = NULL;
+ enum omap_dss_output_id id;
+
+ switch (dssdev->type) {
+ case OMAP_DISPLAY_TYPE_DPI:
+ out = omap_dss_get_output(OMAP_DSS_OUTPUT_DPI);
+ break;
+ case OMAP_DISPLAY_TYPE_DBI:
+ out = omap_dss_get_output(OMAP_DSS_OUTPUT_DBI);
+ break;
+ case OMAP_DISPLAY_TYPE_SDI:
+ out = omap_dss_get_output(OMAP_DSS_OUTPUT_SDI);
+ break;
+ case OMAP_DISPLAY_TYPE_VENC:
+ out = omap_dss_get_output(OMAP_DSS_OUTPUT_VENC);
+ break;
+ case OMAP_DISPLAY_TYPE_HDMI:
+ out = omap_dss_get_output(OMAP_DSS_OUTPUT_HDMI);
+ break;
+ case OMAP_DISPLAY_TYPE_DSI:
+ id = dssdev->phy.dsi.module == 0 ? OMAP_DSS_OUTPUT_DSI1 :
+ OMAP_DSS_OUTPUT_DSI2;
+ out = omap_dss_get_output(id);
+ break;
+ default:
+ break;
+ }
+
+ return out;
+}
diff --git a/drivers/video/omap2/dss/overlay-sysfs.c b/drivers/video/omap2/dss/overlay-sysfs.c
new file mode 100644
index 0000000..4cc5ddebf
--- /dev/null
+++ b/drivers/video/omap2/dss/overlay-sysfs.c
@@ -0,0 +1,456 @@
+/*
+ * Copyright (C) 2009 Nokia Corporation
+ * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
+ *
+ * Some code and ideas taken from drivers/video/omap/ driver
+ * by Imre Deak.
+ *
+ * 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/>.
+ */
+
+#define DSS_SUBSYS_NAME "OVERLAY"
+
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/sysfs.h>
+#include <linux/kobject.h>
+#include <linux/platform_device.h>
+
+#include <video/omapdss.h>
+
+#include "dss.h"
+#include "dss_features.h"
+
+static ssize_t overlay_name_show(struct omap_overlay *ovl, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%s\n", ovl->name);
+}
+
+static ssize_t overlay_manager_show(struct omap_overlay *ovl, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%s\n",
+ ovl->manager ? ovl->manager->name : "<none>");
+}
+
+static ssize_t overlay_manager_store(struct omap_overlay *ovl, const char *buf,
+ size_t size)
+{
+ int i, r;
+ struct omap_overlay_manager *mgr = NULL;
+ struct omap_overlay_manager *old_mgr;
+ int len = size;
+
+ if (buf[size-1] == '\n')
+ --len;
+
+ if (len > 0) {
+ for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
+ mgr = omap_dss_get_overlay_manager(i);
+
+ if (sysfs_streq(buf, mgr->name))
+ break;
+
+ mgr = NULL;
+ }
+ }
+
+ if (len > 0 && mgr == NULL)
+ return -EINVAL;
+
+ if (mgr)
+ DSSDBG("manager %s found\n", mgr->name);
+
+ if (mgr == ovl->manager)
+ return size;
+
+ old_mgr = ovl->manager;
+
+ r = dispc_runtime_get();
+ if (r)
+ return r;
+
+ /* detach old manager */
+ if (old_mgr) {
+ r = ovl->unset_manager(ovl);
+ if (r) {
+ DSSERR("detach failed\n");
+ goto err;
+ }
+
+ r = old_mgr->apply(old_mgr);
+ if (r)
+ goto err;
+ }
+
+ if (mgr) {
+ r = ovl->set_manager(ovl, mgr);
+ if (r) {
+ DSSERR("Failed to attach overlay\n");
+ goto err;
+ }
+
+ r = mgr->apply(mgr);
+ if (r)
+ goto err;
+ }
+
+ dispc_runtime_put();
+
+ return size;
+
+err:
+ dispc_runtime_put();
+ return r;
+}
+
+static ssize_t overlay_input_size_show(struct omap_overlay *ovl, char *buf)
+{
+ struct omap_overlay_info info;
+
+ ovl->get_overlay_info(ovl, &info);
+
+ return snprintf(buf, PAGE_SIZE, "%d,%d\n",
+ info.width, info.height);
+}
+
+static ssize_t overlay_screen_width_show(struct omap_overlay *ovl, char *buf)
+{
+ struct omap_overlay_info info;
+
+ ovl->get_overlay_info(ovl, &info);
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", info.screen_width);
+}
+
+static ssize_t overlay_position_show(struct omap_overlay *ovl, char *buf)
+{
+ struct omap_overlay_info info;
+
+ ovl->get_overlay_info(ovl, &info);
+
+ return snprintf(buf, PAGE_SIZE, "%d,%d\n",
+ info.pos_x, info.pos_y);
+}
+
+static ssize_t overlay_position_store(struct omap_overlay *ovl,
+ const char *buf, size_t size)
+{
+ int r;
+ char *last;
+ struct omap_overlay_info info;
+
+ ovl->get_overlay_info(ovl, &info);
+
+ info.pos_x = simple_strtoul(buf, &last, 10);
+ ++last;
+ if (last - buf >= size)
+ return -EINVAL;
+
+ info.pos_y = simple_strtoul(last, &last, 10);
+
+ r = ovl->set_overlay_info(ovl, &info);
+ if (r)
+ return r;
+
+ if (ovl->manager) {
+ r = ovl->manager->apply(ovl->manager);
+ if (r)
+ return r;
+ }
+
+ return size;
+}
+
+static ssize_t overlay_output_size_show(struct omap_overlay *ovl, char *buf)
+{
+ struct omap_overlay_info info;
+
+ ovl->get_overlay_info(ovl, &info);
+
+ return snprintf(buf, PAGE_SIZE, "%d,%d\n",
+ info.out_width, info.out_height);
+}
+
+static ssize_t overlay_output_size_store(struct omap_overlay *ovl,
+ const char *buf, size_t size)
+{
+ int r;
+ char *last;
+ struct omap_overlay_info info;
+
+ ovl->get_overlay_info(ovl, &info);
+
+ info.out_width = simple_strtoul(buf, &last, 10);
+ ++last;
+ if (last - buf >= size)
+ return -EINVAL;
+
+ info.out_height = simple_strtoul(last, &last, 10);
+
+ r = ovl->set_overlay_info(ovl, &info);
+ if (r)
+ return r;
+
+ if (ovl->manager) {
+ r = ovl->manager->apply(ovl->manager);
+ if (r)
+ return r;
+ }
+
+ return size;
+}
+
+static ssize_t overlay_enabled_show(struct omap_overlay *ovl, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%d\n", ovl->is_enabled(ovl));
+}
+
+static ssize_t overlay_enabled_store(struct omap_overlay *ovl, const char *buf,
+ size_t size)
+{
+ int r;
+ bool enable;
+
+ r = strtobool(buf, &enable);
+ if (r)
+ return r;
+
+ if (enable)
+ r = ovl->enable(ovl);
+ else
+ r = ovl->disable(ovl);
+
+ if (r)
+ return r;
+
+ return size;
+}
+
+static ssize_t overlay_global_alpha_show(struct omap_overlay *ovl, char *buf)
+{
+ struct omap_overlay_info info;
+
+ ovl->get_overlay_info(ovl, &info);
+
+ return snprintf(buf, PAGE_SIZE, "%d\n",
+ info.global_alpha);
+}
+
+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;
+
+ if ((ovl->caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA) == 0)
+ return -ENODEV;
+
+ r = kstrtou8(buf, 0, &alpha);
+ if (r)
+ return r;
+
+ ovl->get_overlay_info(ovl, &info);
+
+ info.global_alpha = alpha;
+
+ r = ovl->set_overlay_info(ovl, &info);
+ if (r)
+ return r;
+
+ if (ovl->manager) {
+ r = ovl->manager->apply(ovl->manager);
+ if (r)
+ return r;
+ }
+
+ return size;
+}
+
+static ssize_t overlay_pre_mult_alpha_show(struct omap_overlay *ovl,
+ char *buf)
+{
+ struct omap_overlay_info info;
+
+ ovl->get_overlay_info(ovl, &info);
+
+ return snprintf(buf, PAGE_SIZE, "%d\n",
+ info.pre_mult_alpha);
+}
+
+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;
+
+ if ((ovl->caps & OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA) == 0)
+ return -ENODEV;
+
+ r = kstrtou8(buf, 0, &alpha);
+ if (r)
+ return r;
+
+ ovl->get_overlay_info(ovl, &info);
+
+ info.pre_mult_alpha = alpha;
+
+ r = ovl->set_overlay_info(ovl, &info);
+ if (r)
+ return r;
+
+ if (ovl->manager) {
+ r = ovl->manager->apply(ovl->manager);
+ if (r)
+ return r;
+ }
+
+ return size;
+}
+
+static ssize_t overlay_zorder_show(struct omap_overlay *ovl, char *buf)
+{
+ struct omap_overlay_info info;
+
+ ovl->get_overlay_info(ovl, &info);
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", info.zorder);
+}
+
+static ssize_t overlay_zorder_store(struct omap_overlay *ovl,
+ const char *buf, size_t size)
+{
+ int r;
+ u8 zorder;
+ struct omap_overlay_info info;
+
+ if ((ovl->caps & OMAP_DSS_OVL_CAP_ZORDER) == 0)
+ return -ENODEV;
+
+ r = kstrtou8(buf, 0, &zorder);
+ if (r)
+ return r;
+
+ ovl->get_overlay_info(ovl, &info);
+
+ info.zorder = zorder;
+
+ r = ovl->set_overlay_info(ovl, &info);
+ if (r)
+ return r;
+
+ if (ovl->manager) {
+ r = ovl->manager->apply(ovl->manager);
+ if (r)
+ return r;
+ }
+
+ return size;
+}
+
+struct overlay_attribute {
+ struct attribute attr;
+ ssize_t (*show)(struct omap_overlay *, char *);
+ ssize_t (*store)(struct omap_overlay *, const char *, size_t);
+};
+
+#define OVERLAY_ATTR(_name, _mode, _show, _store) \
+ struct overlay_attribute overlay_attr_##_name = \
+ __ATTR(_name, _mode, _show, _store)
+
+static OVERLAY_ATTR(name, S_IRUGO, overlay_name_show, NULL);
+static OVERLAY_ATTR(manager, S_IRUGO|S_IWUSR,
+ overlay_manager_show, overlay_manager_store);
+static OVERLAY_ATTR(input_size, S_IRUGO, overlay_input_size_show, NULL);
+static OVERLAY_ATTR(screen_width, S_IRUGO, overlay_screen_width_show, NULL);
+static OVERLAY_ATTR(position, S_IRUGO|S_IWUSR,
+ overlay_position_show, overlay_position_store);
+static OVERLAY_ATTR(output_size, S_IRUGO|S_IWUSR,
+ overlay_output_size_show, overlay_output_size_store);
+static OVERLAY_ATTR(enabled, S_IRUGO|S_IWUSR,
+ overlay_enabled_show, overlay_enabled_store);
+static OVERLAY_ATTR(global_alpha, S_IRUGO|S_IWUSR,
+ overlay_global_alpha_show, overlay_global_alpha_store);
+static OVERLAY_ATTR(pre_mult_alpha, S_IRUGO|S_IWUSR,
+ overlay_pre_mult_alpha_show,
+ overlay_pre_mult_alpha_store);
+static OVERLAY_ATTR(zorder, S_IRUGO|S_IWUSR,
+ overlay_zorder_show, overlay_zorder_store);
+
+static struct attribute *overlay_sysfs_attrs[] = {
+ &overlay_attr_name.attr,
+ &overlay_attr_manager.attr,
+ &overlay_attr_input_size.attr,
+ &overlay_attr_screen_width.attr,
+ &overlay_attr_position.attr,
+ &overlay_attr_output_size.attr,
+ &overlay_attr_enabled.attr,
+ &overlay_attr_global_alpha.attr,
+ &overlay_attr_pre_mult_alpha.attr,
+ &overlay_attr_zorder.attr,
+ NULL
+};
+
+static ssize_t overlay_attr_show(struct kobject *kobj, struct attribute *attr,
+ char *buf)
+{
+ struct omap_overlay *overlay;
+ struct overlay_attribute *overlay_attr;
+
+ overlay = container_of(kobj, struct omap_overlay, kobj);
+ overlay_attr = container_of(attr, struct overlay_attribute, attr);
+
+ if (!overlay_attr->show)
+ return -ENOENT;
+
+ return overlay_attr->show(overlay, buf);
+}
+
+static ssize_t overlay_attr_store(struct kobject *kobj, struct attribute *attr,
+ const char *buf, size_t size)
+{
+ struct omap_overlay *overlay;
+ struct overlay_attribute *overlay_attr;
+
+ overlay = container_of(kobj, struct omap_overlay, kobj);
+ overlay_attr = container_of(attr, struct overlay_attribute, attr);
+
+ if (!overlay_attr->store)
+ return -ENOENT;
+
+ return overlay_attr->store(overlay, buf, size);
+}
+
+static const struct sysfs_ops overlay_sysfs_ops = {
+ .show = overlay_attr_show,
+ .store = overlay_attr_store,
+};
+
+static struct kobj_type overlay_ktype = {
+ .sysfs_ops = &overlay_sysfs_ops,
+ .default_attrs = overlay_sysfs_attrs,
+};
+
+int dss_overlay_kobj_init(struct omap_overlay *ovl,
+ struct platform_device *pdev)
+{
+ return kobject_init_and_add(&ovl->kobj, &overlay_ktype,
+ &pdev->dev.kobj, "overlay%d", ovl->id);
+}
+
+void dss_overlay_kobj_uninit(struct omap_overlay *ovl)
+{
+ kobject_del(&ovl->kobj);
+ kobject_put(&ovl->kobj);
+}
diff --git a/drivers/video/omap2/dss/overlay.c b/drivers/video/omap2/dss/overlay.c
index 952c6fa..45f4994 100644
--- a/drivers/video/omap2/dss/overlay.c
+++ b/drivers/video/omap2/dss/overlay.c
@@ -26,13 +26,11 @@
#include <linux/module.h>
#include <linux/err.h>
#include <linux/sysfs.h>
-#include <linux/kobject.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <video/omapdss.h>
-#include <plat/cpu.h>
#include "dss.h"
#include "dss_features.h"
@@ -40,417 +38,13 @@
static int num_overlays;
static struct omap_overlay *overlays;
-static ssize_t overlay_name_show(struct omap_overlay *ovl, char *buf)
+static inline struct omap_dss_device *dss_ovl_get_device(struct omap_overlay *ovl)
{
- return snprintf(buf, PAGE_SIZE, "%s\n", ovl->name);
+ return ovl->manager ?
+ (ovl->manager->output ? ovl->manager->output->device : NULL) :
+ NULL;
}
-static ssize_t overlay_manager_show(struct omap_overlay *ovl, char *buf)
-{
- return snprintf(buf, PAGE_SIZE, "%s\n",
- ovl->manager ? ovl->manager->name : "<none>");
-}
-
-static ssize_t overlay_manager_store(struct omap_overlay *ovl, const char *buf,
- size_t size)
-{
- int i, r;
- struct omap_overlay_manager *mgr = NULL;
- struct omap_overlay_manager *old_mgr;
- int len = size;
-
- if (buf[size-1] == '\n')
- --len;
-
- if (len > 0) {
- for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
- mgr = omap_dss_get_overlay_manager(i);
-
- if (sysfs_streq(buf, mgr->name))
- break;
-
- mgr = NULL;
- }
- }
-
- if (len > 0 && mgr == NULL)
- return -EINVAL;
-
- if (mgr)
- DSSDBG("manager %s found\n", mgr->name);
-
- if (mgr == ovl->manager)
- return size;
-
- old_mgr = ovl->manager;
-
- r = dispc_runtime_get();
- if (r)
- return r;
-
- /* detach old manager */
- if (old_mgr) {
- r = ovl->unset_manager(ovl);
- if (r) {
- DSSERR("detach failed\n");
- goto err;
- }
-
- r = old_mgr->apply(old_mgr);
- if (r)
- goto err;
- }
-
- if (mgr) {
- r = ovl->set_manager(ovl, mgr);
- if (r) {
- DSSERR("Failed to attach overlay\n");
- goto err;
- }
-
- r = mgr->apply(mgr);
- if (r)
- goto err;
- }
-
- dispc_runtime_put();
-
- return size;
-
-err:
- dispc_runtime_put();
- return r;
-}
-
-static ssize_t overlay_input_size_show(struct omap_overlay *ovl, char *buf)
-{
- struct omap_overlay_info info;
-
- ovl->get_overlay_info(ovl, &info);
-
- return snprintf(buf, PAGE_SIZE, "%d,%d\n",
- info.width, info.height);
-}
-
-static ssize_t overlay_screen_width_show(struct omap_overlay *ovl, char *buf)
-{
- struct omap_overlay_info info;
-
- ovl->get_overlay_info(ovl, &info);
-
- return snprintf(buf, PAGE_SIZE, "%d\n", info.screen_width);
-}
-
-static ssize_t overlay_position_show(struct omap_overlay *ovl, char *buf)
-{
- struct omap_overlay_info info;
-
- ovl->get_overlay_info(ovl, &info);
-
- return snprintf(buf, PAGE_SIZE, "%d,%d\n",
- info.pos_x, info.pos_y);
-}
-
-static ssize_t overlay_position_store(struct omap_overlay *ovl,
- const char *buf, size_t size)
-{
- int r;
- char *last;
- struct omap_overlay_info info;
-
- ovl->get_overlay_info(ovl, &info);
-
- info.pos_x = simple_strtoul(buf, &last, 10);
- ++last;
- if (last - buf >= size)
- return -EINVAL;
-
- info.pos_y = simple_strtoul(last, &last, 10);
-
- r = ovl->set_overlay_info(ovl, &info);
- if (r)
- return r;
-
- if (ovl->manager) {
- r = ovl->manager->apply(ovl->manager);
- if (r)
- return r;
- }
-
- return size;
-}
-
-static ssize_t overlay_output_size_show(struct omap_overlay *ovl, char *buf)
-{
- struct omap_overlay_info info;
-
- ovl->get_overlay_info(ovl, &info);
-
- return snprintf(buf, PAGE_SIZE, "%d,%d\n",
- info.out_width, info.out_height);
-}
-
-static ssize_t overlay_output_size_store(struct omap_overlay *ovl,
- const char *buf, size_t size)
-{
- int r;
- char *last;
- struct omap_overlay_info info;
-
- ovl->get_overlay_info(ovl, &info);
-
- info.out_width = simple_strtoul(buf, &last, 10);
- ++last;
- if (last - buf >= size)
- return -EINVAL;
-
- info.out_height = simple_strtoul(last, &last, 10);
-
- r = ovl->set_overlay_info(ovl, &info);
- if (r)
- return r;
-
- if (ovl->manager) {
- r = ovl->manager->apply(ovl->manager);
- if (r)
- return r;
- }
-
- return size;
-}
-
-static ssize_t overlay_enabled_show(struct omap_overlay *ovl, char *buf)
-{
- return snprintf(buf, PAGE_SIZE, "%d\n", ovl->is_enabled(ovl));
-}
-
-static ssize_t overlay_enabled_store(struct omap_overlay *ovl, const char *buf,
- size_t size)
-{
- int r;
- bool enable;
-
- r = strtobool(buf, &enable);
- if (r)
- return r;
-
- if (enable)
- r = ovl->enable(ovl);
- else
- r = ovl->disable(ovl);
-
- if (r)
- return r;
-
- return size;
-}
-
-static ssize_t overlay_global_alpha_show(struct omap_overlay *ovl, char *buf)
-{
- struct omap_overlay_info info;
-
- ovl->get_overlay_info(ovl, &info);
-
- return snprintf(buf, PAGE_SIZE, "%d\n",
- info.global_alpha);
-}
-
-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;
-
- if ((ovl->caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA) == 0)
- return -ENODEV;
-
- r = kstrtou8(buf, 0, &alpha);
- if (r)
- return r;
-
- ovl->get_overlay_info(ovl, &info);
-
- info.global_alpha = alpha;
-
- r = ovl->set_overlay_info(ovl, &info);
- if (r)
- return r;
-
- if (ovl->manager) {
- r = ovl->manager->apply(ovl->manager);
- if (r)
- return r;
- }
-
- return size;
-}
-
-static ssize_t overlay_pre_mult_alpha_show(struct omap_overlay *ovl,
- char *buf)
-{
- struct omap_overlay_info info;
-
- ovl->get_overlay_info(ovl, &info);
-
- return snprintf(buf, PAGE_SIZE, "%d\n",
- info.pre_mult_alpha);
-}
-
-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;
-
- if ((ovl->caps & OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA) == 0)
- return -ENODEV;
-
- r = kstrtou8(buf, 0, &alpha);
- if (r)
- return r;
-
- ovl->get_overlay_info(ovl, &info);
-
- info.pre_mult_alpha = alpha;
-
- r = ovl->set_overlay_info(ovl, &info);
- if (r)
- return r;
-
- if (ovl->manager) {
- r = ovl->manager->apply(ovl->manager);
- if (r)
- return r;
- }
-
- return size;
-}
-
-static ssize_t overlay_zorder_show(struct omap_overlay *ovl, char *buf)
-{
- struct omap_overlay_info info;
-
- ovl->get_overlay_info(ovl, &info);
-
- return snprintf(buf, PAGE_SIZE, "%d\n", info.zorder);
-}
-
-static ssize_t overlay_zorder_store(struct omap_overlay *ovl,
- const char *buf, size_t size)
-{
- int r;
- u8 zorder;
- struct omap_overlay_info info;
-
- if ((ovl->caps & OMAP_DSS_OVL_CAP_ZORDER) == 0)
- return -ENODEV;
-
- r = kstrtou8(buf, 0, &zorder);
- if (r)
- return r;
-
- ovl->get_overlay_info(ovl, &info);
-
- info.zorder = zorder;
-
- r = ovl->set_overlay_info(ovl, &info);
- if (r)
- return r;
-
- if (ovl->manager) {
- r = ovl->manager->apply(ovl->manager);
- if (r)
- return r;
- }
-
- return size;
-}
-
-struct overlay_attribute {
- struct attribute attr;
- ssize_t (*show)(struct omap_overlay *, char *);
- ssize_t (*store)(struct omap_overlay *, const char *, size_t);
-};
-
-#define OVERLAY_ATTR(_name, _mode, _show, _store) \
- struct overlay_attribute overlay_attr_##_name = \
- __ATTR(_name, _mode, _show, _store)
-
-static OVERLAY_ATTR(name, S_IRUGO, overlay_name_show, NULL);
-static OVERLAY_ATTR(manager, S_IRUGO|S_IWUSR,
- overlay_manager_show, overlay_manager_store);
-static OVERLAY_ATTR(input_size, S_IRUGO, overlay_input_size_show, NULL);
-static OVERLAY_ATTR(screen_width, S_IRUGO, overlay_screen_width_show, NULL);
-static OVERLAY_ATTR(position, S_IRUGO|S_IWUSR,
- overlay_position_show, overlay_position_store);
-static OVERLAY_ATTR(output_size, S_IRUGO|S_IWUSR,
- overlay_output_size_show, overlay_output_size_store);
-static OVERLAY_ATTR(enabled, S_IRUGO|S_IWUSR,
- overlay_enabled_show, overlay_enabled_store);
-static OVERLAY_ATTR(global_alpha, S_IRUGO|S_IWUSR,
- overlay_global_alpha_show, overlay_global_alpha_store);
-static OVERLAY_ATTR(pre_mult_alpha, S_IRUGO|S_IWUSR,
- overlay_pre_mult_alpha_show,
- overlay_pre_mult_alpha_store);
-static OVERLAY_ATTR(zorder, S_IRUGO|S_IWUSR,
- overlay_zorder_show, overlay_zorder_store);
-
-static struct attribute *overlay_sysfs_attrs[] = {
- &overlay_attr_name.attr,
- &overlay_attr_manager.attr,
- &overlay_attr_input_size.attr,
- &overlay_attr_screen_width.attr,
- &overlay_attr_position.attr,
- &overlay_attr_output_size.attr,
- &overlay_attr_enabled.attr,
- &overlay_attr_global_alpha.attr,
- &overlay_attr_pre_mult_alpha.attr,
- &overlay_attr_zorder.attr,
- NULL
-};
-
-static ssize_t overlay_attr_show(struct kobject *kobj, struct attribute *attr,
- char *buf)
-{
- struct omap_overlay *overlay;
- struct overlay_attribute *overlay_attr;
-
- overlay = container_of(kobj, struct omap_overlay, kobj);
- overlay_attr = container_of(attr, struct overlay_attribute, attr);
-
- if (!overlay_attr->show)
- return -ENOENT;
-
- return overlay_attr->show(overlay, buf);
-}
-
-static ssize_t overlay_attr_store(struct kobject *kobj, struct attribute *attr,
- const char *buf, size_t size)
-{
- struct omap_overlay *overlay;
- struct overlay_attribute *overlay_attr;
-
- overlay = container_of(kobj, struct omap_overlay, kobj);
- overlay_attr = container_of(attr, struct overlay_attribute, attr);
-
- if (!overlay_attr->store)
- return -ENOENT;
-
- return overlay_attr->store(overlay, buf, size);
-}
-
-static const struct sysfs_ops overlay_sysfs_ops = {
- .show = overlay_attr_show,
- .store = overlay_attr_store,
-};
-
-static struct kobj_type overlay_ktype = {
- .sysfs_ops = &overlay_sysfs_ops,
- .default_attrs = overlay_sysfs_attrs,
-};
-
int omap_dss_get_num_overlays(void)
{
return num_overlays;
@@ -507,97 +101,25 @@ void dss_init_overlays(struct platform_device *pdev)
ovl->set_overlay_info = &dss_ovl_set_info;
ovl->get_overlay_info = &dss_ovl_get_info;
ovl->wait_for_go = &dss_mgr_wait_for_go_ovl;
+ ovl->get_device = &dss_ovl_get_device;
ovl->caps = dss_feat_get_overlay_caps(ovl->id);
ovl->supported_modes =
dss_feat_get_supported_color_modes(ovl->id);
- r = kobject_init_and_add(&ovl->kobj, &overlay_ktype,
- &pdev->dev.kobj, "overlay%d", i);
-
+ r = dss_overlay_kobj_init(ovl, pdev);
if (r)
DSSERR("failed to create sysfs file\n");
}
}
-/* connect overlays to the new device, if not already connected. if force
- * selected, connect always. */
-void dss_recheck_connections(struct omap_dss_device *dssdev, bool force)
-{
- int i;
- struct omap_overlay_manager *lcd_mgr;
- struct omap_overlay_manager *tv_mgr;
- struct omap_overlay_manager *lcd2_mgr = NULL;
- struct omap_overlay_manager *lcd3_mgr = NULL;
- struct omap_overlay_manager *mgr = NULL;
-
- lcd_mgr = omap_dss_get_overlay_manager(OMAP_DSS_CHANNEL_LCD);
- tv_mgr = omap_dss_get_overlay_manager(OMAP_DSS_CHANNEL_DIGIT);
- if (dss_has_feature(FEAT_MGR_LCD3))
- lcd3_mgr = omap_dss_get_overlay_manager(OMAP_DSS_CHANNEL_LCD3);
- if (dss_has_feature(FEAT_MGR_LCD2))
- lcd2_mgr = omap_dss_get_overlay_manager(OMAP_DSS_CHANNEL_LCD2);
-
- if (dssdev->channel == OMAP_DSS_CHANNEL_LCD3) {
- if (!lcd3_mgr->device || force) {
- if (lcd3_mgr->device)
- lcd3_mgr->unset_device(lcd3_mgr);
- lcd3_mgr->set_device(lcd3_mgr, dssdev);
- mgr = lcd3_mgr;
- }
- } else if (dssdev->channel == OMAP_DSS_CHANNEL_LCD2) {
- if (!lcd2_mgr->device || force) {
- if (lcd2_mgr->device)
- lcd2_mgr->unset_device(lcd2_mgr);
- lcd2_mgr->set_device(lcd2_mgr, dssdev);
- mgr = lcd2_mgr;
- }
- } else if (dssdev->type != OMAP_DISPLAY_TYPE_VENC
- && dssdev->type != OMAP_DISPLAY_TYPE_HDMI) {
- if (!lcd_mgr->device || force) {
- if (lcd_mgr->device)
- lcd_mgr->unset_device(lcd_mgr);
- lcd_mgr->set_device(lcd_mgr, dssdev);
- mgr = lcd_mgr;
- }
- }
-
- if (dssdev->type == OMAP_DISPLAY_TYPE_VENC
- || dssdev->type == OMAP_DISPLAY_TYPE_HDMI) {
- if (!tv_mgr->device || force) {
- if (tv_mgr->device)
- tv_mgr->unset_device(tv_mgr);
- tv_mgr->set_device(tv_mgr, dssdev);
- mgr = tv_mgr;
- }
- }
-
- if (mgr) {
- dispc_runtime_get();
-
- for (i = 0; i < dss_feat_get_num_ovls(); i++) {
- struct omap_overlay *ovl;
- ovl = omap_dss_get_overlay(i);
- if (!ovl->manager || force) {
- if (ovl->manager)
- ovl->unset_manager(ovl);
- ovl->set_manager(ovl, mgr);
- }
- }
-
- dispc_runtime_put();
- }
-}
-
void dss_uninit_overlays(struct platform_device *pdev)
{
int i;
for (i = 0; i < num_overlays; ++i) {
struct omap_overlay *ovl = &overlays[i];
-
- kobject_del(&ovl->kobj);
- kobject_put(&ovl->kobj);
+ dss_overlay_kobj_uninit(ovl);
}
kfree(overlays);
diff --git a/drivers/video/omap2/dss/rfbi.c b/drivers/video/omap2/dss/rfbi.c
index 7c08742..7282e5a 100644
--- a/drivers/video/omap2/dss/rfbi.c
+++ b/drivers/video/omap2/dss/rfbi.c
@@ -111,6 +111,13 @@ static struct {
struct omap_dss_device *dssdev[2];
struct semaphore bus_lock;
+
+ struct omap_video_timings timings;
+ int pixel_size;
+ int data_lines;
+ struct rfbi_timings intf_timings;
+
+ struct omap_dss_output output;
} rfbi;
static inline void rfbi_write_reg(const struct rfbi_reg idx, u32 val)
@@ -300,30 +307,23 @@ void omap_rfbi_write_pixels(const void __iomem *buf, int scr_width,
}
EXPORT_SYMBOL(omap_rfbi_write_pixels);
-static int rfbi_transfer_area(struct omap_dss_device *dssdev, u16 width,
- u16 height, void (*callback)(void *data), void *data)
+static int rfbi_transfer_area(struct omap_dss_device *dssdev,
+ void (*callback)(void *data), void *data)
{
u32 l;
int r;
- struct omap_video_timings timings = {
- .hsw = 1,
- .hfp = 1,
- .hbp = 1,
- .vsw = 1,
- .vfp = 0,
- .vbp = 0,
- .x_res = width,
- .y_res = height,
- };
+ struct omap_overlay_manager *mgr = dssdev->output->manager;
+ u16 width = rfbi.timings.x_res;
+ u16 height = rfbi.timings.y_res;
/*BUG_ON(callback == 0);*/
BUG_ON(rfbi.framedone_callback != NULL);
DSSDBG("rfbi_transfer_area %dx%d\n", width, height);
- dss_mgr_set_timings(dssdev->manager, &timings);
+ dss_mgr_set_timings(mgr, &rfbi.timings);
- r = dss_mgr_enable(dssdev->manager);
+ r = dss_mgr_enable(mgr);
if (r)
return r;
@@ -770,62 +770,45 @@ static int rfbi_configure(int rfbi_module, int bpp, int lines)
return 0;
}
-int omap_rfbi_configure(struct omap_dss_device *dssdev, int pixel_size,
- int data_lines)
+int omap_rfbi_configure(struct omap_dss_device *dssdev)
{
- return rfbi_configure(dssdev->phy.rfbi.channel, pixel_size, data_lines);
+ return rfbi_configure(dssdev->phy.rfbi.channel, rfbi.pixel_size,
+ rfbi.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)
+int omap_rfbi_update(struct omap_dss_device *dssdev, void (*callback)(void *),
+ void *data)
{
- u16 dw, dh;
- struct omap_video_timings timings = {
- .hsw = 1,
- .hfp = 1,
- .hbp = 1,
- .vsw = 1,
- .vfp = 0,
- .vbp = 0,
- .x_res = *w,
- .y_res = *h,
- };
-
- dssdev->driver->get_resolution(dssdev, &dw, &dh);
-
- if (*x > dw || *y > dh)
- return -EINVAL;
-
- if (*x + *w > dw)
- return -EINVAL;
-
- if (*y + *h > dh)
- return -EINVAL;
-
- if (*w == 1)
- return -EINVAL;
-
- if (*w == 0 || *h == 0)
- return -EINVAL;
-
- dss_mgr_set_timings(dssdev->manager, &timings);
+ return rfbi_transfer_area(dssdev, callback, data);
+}
+EXPORT_SYMBOL(omap_rfbi_update);
- return 0;
+void omapdss_rfbi_set_size(struct omap_dss_device *dssdev, u16 w, u16 h)
+{
+ rfbi.timings.x_res = w;
+ rfbi.timings.y_res = h;
}
-EXPORT_SYMBOL(omap_rfbi_prepare_update);
+EXPORT_SYMBOL(omapdss_rfbi_set_size);
-int omap_rfbi_update(struct omap_dss_device *dssdev,
- u16 x, u16 y, u16 w, u16 h,
- void (*callback)(void *), void *data)
+void omapdss_rfbi_set_pixel_size(struct omap_dss_device *dssdev, int pixel_size)
{
- int r;
+ rfbi.pixel_size = pixel_size;
+}
+EXPORT_SYMBOL(omapdss_rfbi_set_pixel_size);
- r = rfbi_transfer_area(dssdev, w, h, callback, data);
+void omapdss_rfbi_set_data_lines(struct omap_dss_device *dssdev, int data_lines)
+{
+ rfbi.data_lines = data_lines;
+}
+EXPORT_SYMBOL(omapdss_rfbi_set_data_lines);
- return r;
+void omapdss_rfbi_set_interface_timings(struct omap_dss_device *dssdev,
+ struct rfbi_timings *timings)
+{
+ rfbi.intf_timings = *timings;
}
-EXPORT_SYMBOL(omap_rfbi_update);
+EXPORT_SYMBOL(omapdss_rfbi_set_interface_timings);
static void rfbi_dump_regs(struct seq_file *s)
{
@@ -869,6 +852,7 @@ static void rfbi_dump_regs(struct seq_file *s)
static void rfbi_config_lcd_manager(struct omap_dss_device *dssdev)
{
+ struct omap_overlay_manager *mgr = dssdev->output->manager;
struct dss_lcd_mgr_config mgr_config;
mgr_config.io_pad_mode = DSS_IO_PAD_MODE_RFBI;
@@ -877,18 +861,40 @@ static void rfbi_config_lcd_manager(struct omap_dss_device *dssdev)
/* Do we need fifohandcheck for RFBI? */
mgr_config.fifohandcheck = false;
- mgr_config.video_port_width = dssdev->ctrl.pixel_size;
+ mgr_config.video_port_width = rfbi.pixel_size;
mgr_config.lcden_sig_polarity = 0;
- dss_mgr_set_lcd_config(dssdev->manager, &mgr_config);
+ dss_mgr_set_lcd_config(mgr, &mgr_config);
+
+ /*
+ * Set rfbi.timings with default values, the x_res and y_res fields
+ * are expected to be already configured by the panel driver via
+ * omapdss_rfbi_set_size()
+ */
+ rfbi.timings.hsw = 1;
+ rfbi.timings.hfp = 1;
+ rfbi.timings.hbp = 1;
+ rfbi.timings.vsw = 1;
+ rfbi.timings.vfp = 0;
+ rfbi.timings.vbp = 0;
+
+ rfbi.timings.interlace = false;
+ rfbi.timings.hsync_level = OMAPDSS_SIG_ACTIVE_HIGH;
+ rfbi.timings.vsync_level = OMAPDSS_SIG_ACTIVE_HIGH;
+ rfbi.timings.data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE;
+ rfbi.timings.de_level = OMAPDSS_SIG_ACTIVE_HIGH;
+ rfbi.timings.sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES;
+
+ dss_mgr_set_timings(mgr, &rfbi.timings);
}
int omapdss_rfbi_display_enable(struct omap_dss_device *dssdev)
{
+ struct omap_dss_output *out = dssdev->output;
int r;
- if (dssdev->manager == NULL) {
- DSSERR("failed to enable display: no manager\n");
+ if (out == NULL || out->manager == NULL) {
+ DSSERR("failed to enable display: no output/manager\n");
return -ENODEV;
}
@@ -911,13 +917,10 @@ int omapdss_rfbi_display_enable(struct omap_dss_device *dssdev)
rfbi_config_lcd_manager(dssdev);
- rfbi_configure(dssdev->phy.rfbi.channel,
- dssdev->ctrl.pixel_size,
- dssdev->phy.rfbi.data_lines);
-
- rfbi_set_timings(dssdev->phy.rfbi.channel,
- &dssdev->ctrl.rfbi_timings);
+ rfbi_configure(dssdev->phy.rfbi.channel, rfbi.pixel_size,
+ rfbi.data_lines);
+ rfbi_set_timings(dssdev->phy.rfbi.channel, &rfbi.intf_timings);
return 0;
err1:
@@ -941,14 +944,17 @@ EXPORT_SYMBOL(omapdss_rfbi_display_disable);
static int __init rfbi_init_display(struct omap_dss_device *dssdev)
{
rfbi.dssdev[dssdev->phy.rfbi.channel] = dssdev;
- dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE;
return 0;
}
-static void __init rfbi_probe_pdata(struct platform_device *pdev)
+static struct omap_dss_device * __init rfbi_find_dssdev(struct platform_device *pdev)
{
struct omap_dss_board_info *pdata = pdev->dev.platform_data;
- int i, r;
+ const char *def_disp_name = dss_get_default_display_name();
+ struct omap_dss_device *def_dssdev;
+ int i;
+
+ def_dssdev = NULL;
for (i = 0; i < pdata->num_devices; ++i) {
struct omap_dss_device *dssdev = pdata->devices[i];
@@ -956,17 +962,67 @@ static void __init rfbi_probe_pdata(struct platform_device *pdev)
if (dssdev->type != OMAP_DISPLAY_TYPE_DBI)
continue;
- r = rfbi_init_display(dssdev);
- if (r) {
- DSSERR("device %s init failed: %d\n", dssdev->name, r);
- continue;
+ if (def_dssdev == NULL)
+ def_dssdev = dssdev;
+
+ if (def_disp_name != NULL &&
+ strcmp(dssdev->name, def_disp_name) == 0) {
+ def_dssdev = dssdev;
+ break;
}
+ }
+
+ return def_dssdev;
+}
+
+static void __init rfbi_probe_pdata(struct platform_device *rfbidev)
+{
+ struct omap_dss_device *plat_dssdev;
+ struct omap_dss_device *dssdev;
+ int r;
+
+ plat_dssdev = rfbi_find_dssdev(rfbidev);
+
+ if (!plat_dssdev)
+ return;
+
+ dssdev = dss_alloc_and_init_device(&rfbidev->dev);
+ if (!dssdev)
+ return;
+
+ dss_copy_device_pdata(dssdev, plat_dssdev);
- r = omap_dss_register_device(dssdev, &pdev->dev, i);
- if (r)
- DSSERR("device %s register failed: %d\n",
- dssdev->name, r);
+ r = rfbi_init_display(dssdev);
+ if (r) {
+ DSSERR("device %s init failed: %d\n", dssdev->name, r);
+ dss_put_device(dssdev);
+ return;
}
+
+ r = dss_add_device(dssdev);
+ if (r) {
+ DSSERR("device %s register failed: %d\n", dssdev->name, r);
+ dss_put_device(dssdev);
+ return;
+ }
+}
+
+static void __init rfbi_init_output(struct platform_device *pdev)
+{
+ struct omap_dss_output *out = &rfbi.output;
+
+ out->pdev = pdev;
+ out->id = OMAP_DSS_OUTPUT_DBI;
+ out->type = OMAP_DISPLAY_TYPE_DBI;
+
+ dss_register_output(out);
+}
+
+static void __exit rfbi_uninit_output(struct platform_device *pdev)
+{
+ struct omap_dss_output *out = &rfbi.output;
+
+ dss_unregister_output(out);
}
/* RFBI HW IP initialisation */
@@ -1020,6 +1076,8 @@ static int __init omap_rfbihw_probe(struct platform_device *pdev)
dss_debugfs_create_file("rfbi", rfbi_dump_regs);
+ rfbi_init_output(pdev);
+
rfbi_probe_pdata(pdev);
return 0;
@@ -1031,8 +1089,12 @@ err_runtime_get:
static int __exit omap_rfbihw_remove(struct platform_device *pdev)
{
- omap_dss_unregister_child_devices(&pdev->dev);
+ dss_unregister_child_devices(&pdev->dev);
+
+ rfbi_uninit_output(pdev);
+
pm_runtime_disable(&pdev->dev);
+
return 0;
}
diff --git a/drivers/video/omap2/dss/sdi.c b/drivers/video/omap2/dss/sdi.c
index f43bfe1..7760851 100644
--- a/drivers/video/omap2/dss/sdi.c
+++ b/drivers/video/omap2/dss/sdi.c
@@ -25,6 +25,7 @@
#include <linux/regulator/consumer.h>
#include <linux/export.h>
#include <linux/platform_device.h>
+#include <linux/string.h>
#include <video/omapdss.h>
#include "dss.h"
@@ -34,10 +35,16 @@ static struct {
struct regulator *vdds_sdi_reg;
struct dss_lcd_mgr_config mgr_config;
+ struct omap_video_timings timings;
+ int datapairs;
+
+ struct omap_dss_output output;
} sdi;
static void sdi_config_lcd_manager(struct omap_dss_device *dssdev)
{
+ struct omap_overlay_manager *mgr = dssdev->output->manager;
+
sdi.mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS;
sdi.mgr_config.stallmode = false;
@@ -46,19 +53,20 @@ static void sdi_config_lcd_manager(struct omap_dss_device *dssdev)
sdi.mgr_config.video_port_width = 24;
sdi.mgr_config.lcden_sig_polarity = 1;
- dss_mgr_set_lcd_config(dssdev->manager, &sdi.mgr_config);
+ dss_mgr_set_lcd_config(mgr, &sdi.mgr_config);
}
int omapdss_sdi_display_enable(struct omap_dss_device *dssdev)
{
- struct omap_video_timings *t = &dssdev->panel.timings;
+ struct omap_dss_output *out = dssdev->output;
+ struct omap_video_timings *t = &sdi.timings;
struct dss_clock_info dss_cinfo;
struct dispc_clock_info dispc_cinfo;
unsigned long pck;
int r;
- if (dssdev->manager == NULL) {
- DSSERR("failed to enable display: no manager\n");
+ if (out == NULL || out->manager == NULL) {
+ DSSERR("failed to enable display: no output/manager\n");
return -ENODEV;
}
@@ -77,8 +85,8 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev)
goto err_get_dispc;
/* 15.5.9.1.2 */
- dssdev->panel.timings.data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE;
- dssdev->panel.timings.sync_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE;
+ t->data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE;
+ t->sync_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE;
r = dss_calc_clock_div(t->pixel_clock * 1000, &dss_cinfo, &dispc_cinfo);
if (r)
@@ -97,7 +105,7 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev)
}
- dss_mgr_set_timings(dssdev->manager, t);
+ dss_mgr_set_timings(out->manager, t);
r = dss_set_clock_div(&dss_cinfo);
if (r)
@@ -116,16 +124,15 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev)
* need to care about the shadow register mechanism for pck-free. The
* exact reason for this is unknown.
*/
- dispc_mgr_set_clock_div(dssdev->manager->id,
- &sdi.mgr_config.clock_info);
+ dispc_mgr_set_clock_div(out->manager->id, &sdi.mgr_config.clock_info);
- dss_sdi_init(dssdev->phy.sdi.datapairs);
+ dss_sdi_init(sdi.datapairs);
r = dss_sdi_enable();
if (r)
goto err_sdi_enable;
mdelay(2);
- r = dss_mgr_enable(dssdev->manager);
+ r = dss_mgr_enable(out->manager);
if (r)
goto err_mgr_enable;
@@ -148,7 +155,9 @@ EXPORT_SYMBOL(omapdss_sdi_display_enable);
void omapdss_sdi_display_disable(struct omap_dss_device *dssdev)
{
- dss_mgr_disable(dssdev->manager);
+ struct omap_overlay_manager *mgr = dssdev->output->manager;
+
+ dss_mgr_disable(mgr);
dss_sdi_disable();
@@ -160,6 +169,19 @@ void omapdss_sdi_display_disable(struct omap_dss_device *dssdev)
}
EXPORT_SYMBOL(omapdss_sdi_display_disable);
+void omapdss_sdi_set_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ sdi.timings = *timings;
+}
+EXPORT_SYMBOL(omapdss_sdi_set_timings);
+
+void omapdss_sdi_set_datapairs(struct omap_dss_device *dssdev, int datapairs)
+{
+ sdi.datapairs = datapairs;
+}
+EXPORT_SYMBOL(omapdss_sdi_set_datapairs);
+
static int __init sdi_init_display(struct omap_dss_device *dssdev)
{
DSSDBG("SDI init\n");
@@ -180,10 +202,14 @@ static int __init sdi_init_display(struct omap_dss_device *dssdev)
return 0;
}
-static void __init sdi_probe_pdata(struct platform_device *pdev)
+static struct omap_dss_device * __init sdi_find_dssdev(struct platform_device *pdev)
{
struct omap_dss_board_info *pdata = pdev->dev.platform_data;
- int i, r;
+ const char *def_disp_name = dss_get_default_display_name();
+ struct omap_dss_device *def_dssdev;
+ int i;
+
+ def_dssdev = NULL;
for (i = 0; i < pdata->num_devices; ++i) {
struct omap_dss_device *dssdev = pdata->devices[i];
@@ -191,21 +217,73 @@ static void __init sdi_probe_pdata(struct platform_device *pdev)
if (dssdev->type != OMAP_DISPLAY_TYPE_SDI)
continue;
- r = sdi_init_display(dssdev);
- if (r) {
- DSSERR("device %s init failed: %d\n", dssdev->name, r);
- continue;
+ if (def_dssdev == NULL)
+ def_dssdev = dssdev;
+
+ if (def_disp_name != NULL &&
+ strcmp(dssdev->name, def_disp_name) == 0) {
+ def_dssdev = dssdev;
+ break;
}
+ }
+
+ return def_dssdev;
+}
+
+static void __init sdi_probe_pdata(struct platform_device *sdidev)
+{
+ struct omap_dss_device *plat_dssdev;
+ struct omap_dss_device *dssdev;
+ int r;
+
+ plat_dssdev = sdi_find_dssdev(sdidev);
- r = omap_dss_register_device(dssdev, &pdev->dev, i);
- if (r)
- DSSERR("device %s register failed: %d\n",
- dssdev->name, r);
+ if (!plat_dssdev)
+ return;
+
+ dssdev = dss_alloc_and_init_device(&sdidev->dev);
+ if (!dssdev)
+ return;
+
+ dss_copy_device_pdata(dssdev, plat_dssdev);
+
+ r = sdi_init_display(dssdev);
+ if (r) {
+ DSSERR("device %s init failed: %d\n", dssdev->name, r);
+ dss_put_device(dssdev);
+ return;
}
+
+ r = dss_add_device(dssdev);
+ if (r) {
+ DSSERR("device %s register failed: %d\n", dssdev->name, r);
+ dss_put_device(dssdev);
+ return;
+ }
+}
+
+static void __init sdi_init_output(struct platform_device *pdev)
+{
+ struct omap_dss_output *out = &sdi.output;
+
+ out->pdev = pdev;
+ out->id = OMAP_DSS_OUTPUT_SDI;
+ out->type = OMAP_DISPLAY_TYPE_SDI;
+
+ dss_register_output(out);
+}
+
+static void __exit sdi_uninit_output(struct platform_device *pdev)
+{
+ struct omap_dss_output *out = &sdi.output;
+
+ dss_unregister_output(out);
}
static int __init omap_sdi_probe(struct platform_device *pdev)
{
+ sdi_init_output(pdev);
+
sdi_probe_pdata(pdev);
return 0;
@@ -213,7 +291,9 @@ static int __init omap_sdi_probe(struct platform_device *pdev)
static int __exit omap_sdi_remove(struct platform_device *pdev)
{
- omap_dss_unregister_child_devices(&pdev->dev);
+ dss_unregister_child_devices(&pdev->dev);
+
+ sdi_uninit_output(pdev);
return 0;
}
diff --git a/drivers/video/omap2/dss/venc.c b/drivers/video/omap2/dss/venc.c
index 3a22087..56efa3b 100644
--- a/drivers/video/omap2/dss/venc.c
+++ b/drivers/video/omap2/dss/venc.c
@@ -36,7 +36,6 @@
#include <linux/pm_runtime.h>
#include <video/omapdss.h>
-#include <plat/cpu.h>
#include "dss.h"
#include "dss_features.h"
@@ -300,6 +299,12 @@ static struct {
struct regulator *vdda_dac_reg;
struct clk *tv_dac_clk;
+
+ struct omap_video_timings timings;
+ enum omap_dss_venc_type type;
+ bool invert_polarity;
+
+ struct omap_dss_output output;
} venc;
static inline void venc_write_reg(int idx, u32 val)
@@ -424,65 +429,67 @@ static const struct venc_config *venc_timings_to_config(
static int venc_power_on(struct omap_dss_device *dssdev)
{
+ struct omap_overlay_manager *mgr = dssdev->output->manager;
u32 l;
int r;
+ r = venc_runtime_get();
+ if (r)
+ goto err0;
+
venc_reset();
- venc_write_config(venc_timings_to_config(&dssdev->panel.timings));
+ venc_write_config(venc_timings_to_config(&venc.timings));
- dss_set_venc_output(dssdev->phy.venc.type);
+ dss_set_venc_output(venc.type);
dss_set_dac_pwrdn_bgz(1);
l = 0;
- if (dssdev->phy.venc.type == OMAP_DSS_VENC_TYPE_COMPOSITE)
+ if (venc.type == OMAP_DSS_VENC_TYPE_COMPOSITE)
l |= 1 << 1;
else /* S-Video */
l |= (1 << 0) | (1 << 2);
- if (dssdev->phy.venc.invert_polarity == false)
+ if (venc.invert_polarity == false)
l |= 1 << 3;
venc_write_reg(VENC_OUTPUT_CONTROL, l);
- dss_mgr_set_timings(dssdev->manager, &dssdev->panel.timings);
+ dss_mgr_set_timings(mgr, &venc.timings);
r = regulator_enable(venc.vdda_dac_reg);
if (r)
- goto err;
-
- if (dssdev->platform_enable)
- dssdev->platform_enable(dssdev);
+ goto err1;
- r = dss_mgr_enable(dssdev->manager);
+ r = dss_mgr_enable(mgr);
if (r)
- goto err;
+ goto err2;
return 0;
-err:
+err2:
+ regulator_disable(venc.vdda_dac_reg);
+err1:
venc_write_reg(VENC_OUTPUT_CONTROL, 0);
dss_set_dac_pwrdn_bgz(0);
- if (dssdev->platform_disable)
- dssdev->platform_disable(dssdev);
-
- regulator_disable(venc.vdda_dac_reg);
-
+ venc_runtime_put();
+err0:
return r;
}
static void venc_power_off(struct omap_dss_device *dssdev)
{
+ struct omap_overlay_manager *mgr = dssdev->output->manager;
+
venc_write_reg(VENC_OUTPUT_CONTROL, 0);
dss_set_dac_pwrdn_bgz(0);
- dss_mgr_disable(dssdev->manager);
-
- if (dssdev->platform_disable)
- dssdev->platform_disable(dssdev);
+ dss_mgr_disable(mgr);
regulator_disable(venc.vdda_dac_reg);
+
+ venc_runtime_put();
}
unsigned long venc_get_pixel_clock(void)
@@ -491,171 +498,83 @@ unsigned long venc_get_pixel_clock(void)
return 13500000;
}
-static ssize_t display_output_type_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+int omapdss_venc_display_enable(struct omap_dss_device *dssdev)
{
- struct omap_dss_device *dssdev = to_dss_device(dev);
- const char *ret;
-
- switch (dssdev->phy.venc.type) {
- case OMAP_DSS_VENC_TYPE_COMPOSITE:
- ret = "composite";
- break;
- case OMAP_DSS_VENC_TYPE_SVIDEO:
- ret = "svideo";
- break;
- default:
- return -EINVAL;
- }
-
- return snprintf(buf, PAGE_SIZE, "%s\n", ret);
-}
+ struct omap_dss_output *out = dssdev->output;
+ int r;
-static ssize_t display_output_type_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t size)
-{
- struct omap_dss_device *dssdev = to_dss_device(dev);
- enum omap_dss_venc_type new_type;
-
- if (sysfs_streq("composite", buf))
- new_type = OMAP_DSS_VENC_TYPE_COMPOSITE;
- else if (sysfs_streq("svideo", buf))
- new_type = OMAP_DSS_VENC_TYPE_SVIDEO;
- else
- return -EINVAL;
+ DSSDBG("venc_display_enable\n");
mutex_lock(&venc.venc_lock);
- if (dssdev->phy.venc.type != new_type) {
- dssdev->phy.venc.type = new_type;
- if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) {
- venc_power_off(dssdev);
- venc_power_on(dssdev);
- }
+ if (out == NULL || out->manager == NULL) {
+ DSSERR("Failed to enable display: no output/manager\n");
+ r = -ENODEV;
+ goto err0;
}
- mutex_unlock(&venc.venc_lock);
-
- return size;
-}
-
-static DEVICE_ATTR(output_type, S_IRUGO | S_IWUSR,
- display_output_type_show, display_output_type_store);
-
-/* driver */
-static int venc_panel_probe(struct omap_dss_device *dssdev)
-{
- dssdev->panel.timings = omap_dss_pal_timings;
-
- return device_create_file(&dssdev->dev, &dev_attr_output_type);
-}
-
-static void venc_panel_remove(struct omap_dss_device *dssdev)
-{
- device_remove_file(&dssdev->dev, &dev_attr_output_type);
-}
-
-static int venc_panel_enable(struct omap_dss_device *dssdev)
-{
- int r = 0;
-
- DSSDBG("venc_enable_display\n");
-
- 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;
- }
+ if (dssdev->platform_enable)
+ dssdev->platform_enable(dssdev);
- r = venc_runtime_get();
- if (r)
- goto err1;
r = venc_power_on(dssdev);
if (r)
- goto err2;
+ goto err1;
venc.wss_data = 0;
- dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
-
mutex_unlock(&venc.venc_lock);
+
return 0;
-err2:
- venc_runtime_put();
err1:
+ if (dssdev->platform_disable)
+ dssdev->platform_disable(dssdev);
omap_dss_stop_device(dssdev);
err0:
mutex_unlock(&venc.venc_lock);
-
return r;
}
-static void venc_panel_disable(struct omap_dss_device *dssdev)
+void omapdss_venc_display_disable(struct omap_dss_device *dssdev)
{
- DSSDBG("venc_disable_display\n");
+ DSSDBG("venc_display_disable\n");
mutex_lock(&venc.venc_lock);
- if (dssdev->state == OMAP_DSS_DISPLAY_DISABLED)
- goto end;
-
- if (dssdev->state == OMAP_DSS_DISPLAY_SUSPENDED) {
- /* suspended is the same as disabled with venc */
- dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
- goto end;
- }
-
venc_power_off(dssdev);
- venc_runtime_put();
-
- dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
-
omap_dss_stop_device(dssdev);
-end:
- mutex_unlock(&venc.venc_lock);
-}
-static int venc_panel_suspend(struct omap_dss_device *dssdev)
-{
- venc_panel_disable(dssdev);
- return 0;
-}
+ if (dssdev->platform_disable)
+ dssdev->platform_disable(dssdev);
-static int venc_panel_resume(struct omap_dss_device *dssdev)
-{
- return venc_panel_enable(dssdev);
+ mutex_unlock(&venc.venc_lock);
}
-static void venc_set_timings(struct omap_dss_device *dssdev,
- struct omap_video_timings *timings)
+void omapdss_venc_set_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
{
DSSDBG("venc_set_timings\n");
+ mutex_lock(&venc.venc_lock);
+
/* Reset WSS data when the TV standard changes. */
- if (memcmp(&dssdev->panel.timings, timings, sizeof(*timings)))
+ if (memcmp(&venc.timings, timings, sizeof(*timings)))
venc.wss_data = 0;
- dssdev->panel.timings = *timings;
- if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) {
- /* turn the venc off and on to get new timings to use */
- venc_panel_disable(dssdev);
- venc_panel_enable(dssdev);
- } else {
- dss_mgr_set_timings(dssdev->manager, timings);
- }
+ venc.timings = *timings;
+
+ mutex_unlock(&venc.venc_lock);
}
-static int venc_check_timings(struct omap_dss_device *dssdev,
- struct omap_video_timings *timings)
+int omapdss_venc_check_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
{
DSSDBG("venc_check_timings\n");
@@ -668,13 +587,13 @@ static int venc_check_timings(struct omap_dss_device *dssdev,
return -EINVAL;
}
-static u32 venc_get_wss(struct omap_dss_device *dssdev)
+u32 omapdss_venc_get_wss(struct omap_dss_device *dssdev)
{
/* Invert due to VENC_L21_WC_CTL:INV=1 */
return (venc.wss_data >> 8) ^ 0xfffff;
}
-static int venc_set_wss(struct omap_dss_device *dssdev, u32 wss)
+int omapdss_venc_set_wss(struct omap_dss_device *dssdev, u32 wss)
{
const struct venc_config *config;
int r;
@@ -683,7 +602,7 @@ static int venc_set_wss(struct omap_dss_device *dssdev, u32 wss)
mutex_lock(&venc.venc_lock);
- config = venc_timings_to_config(&dssdev->panel.timings);
+ config = venc_timings_to_config(&venc.timings);
/* Invert due to VENC_L21_WC_CTL:INV=1 */
venc.wss_data = (wss ^ 0xfffff) << 8;
@@ -703,30 +622,25 @@ err:
return r;
}
-static struct omap_dss_driver venc_driver = {
- .probe = venc_panel_probe,
- .remove = venc_panel_remove,
+void omapdss_venc_set_type(struct omap_dss_device *dssdev,
+ enum omap_dss_venc_type type)
+{
+ mutex_lock(&venc.venc_lock);
- .enable = venc_panel_enable,
- .disable = venc_panel_disable,
- .suspend = venc_panel_suspend,
- .resume = venc_panel_resume,
+ venc.type = type;
- .get_resolution = omapdss_default_get_resolution,
- .get_recommended_bpp = omapdss_default_get_recommended_bpp,
+ mutex_unlock(&venc.venc_lock);
+}
- .set_timings = venc_set_timings,
- .check_timings = venc_check_timings,
+void omapdss_venc_invert_vid_out_polarity(struct omap_dss_device *dssdev,
+ bool invert_polarity)
+{
+ mutex_lock(&venc.venc_lock);
- .get_wss = venc_get_wss,
- .set_wss = venc_set_wss,
+ venc.invert_polarity = invert_polarity;
- .driver = {
- .name = "venc",
- .owner = THIS_MODULE,
- },
-};
-/* driver end */
+ mutex_unlock(&venc.venc_lock);
+}
static int __init venc_init_display(struct omap_dss_device *dssdev)
{
@@ -752,11 +666,6 @@ static void venc_dump_regs(struct seq_file *s)
{
#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, venc_read_reg(r))
- if (cpu_is_omap44xx()) {
- seq_printf(s, "VENC currently disabled on OMAP44xx\n");
- return;
- }
-
if (venc_runtime_get())
return;
@@ -832,10 +741,14 @@ static void venc_put_clocks(void)
clk_put(venc.tv_dac_clk);
}
-static void __init venc_probe_pdata(struct platform_device *pdev)
+static struct omap_dss_device * __init venc_find_dssdev(struct platform_device *pdev)
{
struct omap_dss_board_info *pdata = pdev->dev.platform_data;
- int r, i;
+ const char *def_disp_name = dss_get_default_display_name();
+ struct omap_dss_device *def_dssdev;
+ int i;
+
+ def_dssdev = NULL;
for (i = 0; i < pdata->num_devices; ++i) {
struct omap_dss_device *dssdev = pdata->devices[i];
@@ -843,17 +756,69 @@ static void __init venc_probe_pdata(struct platform_device *pdev)
if (dssdev->type != OMAP_DISPLAY_TYPE_VENC)
continue;
- r = venc_init_display(dssdev);
- if (r) {
- DSSERR("device %s init failed: %d\n", dssdev->name, r);
- continue;
+ if (def_dssdev == NULL)
+ def_dssdev = dssdev;
+
+ if (def_disp_name != NULL &&
+ strcmp(dssdev->name, def_disp_name) == 0) {
+ def_dssdev = dssdev;
+ break;
}
+ }
+
+ return def_dssdev;
+}
+
+static void __init venc_probe_pdata(struct platform_device *vencdev)
+{
+ struct omap_dss_device *plat_dssdev;
+ struct omap_dss_device *dssdev;
+ int r;
+
+ plat_dssdev = venc_find_dssdev(vencdev);
- r = omap_dss_register_device(dssdev, &pdev->dev, i);
- if (r)
- DSSERR("device %s register failed: %d\n",
- dssdev->name, r);
+ if (!plat_dssdev)
+ return;
+
+ dssdev = dss_alloc_and_init_device(&vencdev->dev);
+ if (!dssdev)
+ return;
+
+ dss_copy_device_pdata(dssdev, plat_dssdev);
+
+ dssdev->channel = OMAP_DSS_CHANNEL_DIGIT;
+
+ r = venc_init_display(dssdev);
+ if (r) {
+ DSSERR("device %s init failed: %d\n", dssdev->name, r);
+ dss_put_device(dssdev);
+ return;
}
+
+ r = dss_add_device(dssdev);
+ if (r) {
+ DSSERR("device %s register failed: %d\n", dssdev->name, r);
+ dss_put_device(dssdev);
+ return;
+ }
+}
+
+static void __init venc_init_output(struct platform_device *pdev)
+{
+ struct omap_dss_output *out = &venc.output;
+
+ out->pdev = pdev;
+ out->id = OMAP_DSS_OUTPUT_VENC;
+ out->type = OMAP_DISPLAY_TYPE_VENC;
+
+ dss_register_output(out);
+}
+
+static void __exit venc_uninit_output(struct platform_device *pdev)
+{
+ struct omap_dss_output *out = &venc.output;
+
+ dss_unregister_output(out);
}
/* VENC HW IP initialisation */
@@ -897,17 +862,19 @@ static int __init omap_venchw_probe(struct platform_device *pdev)
venc_runtime_put();
- r = omap_dss_register_driver(&venc_driver);
+ r = venc_panel_init();
if (r)
- goto err_reg_panel_driver;
+ goto err_panel_init;
dss_debugfs_create_file("venc", venc_dump_regs);
+ venc_init_output(pdev);
+
venc_probe_pdata(pdev);
return 0;
-err_reg_panel_driver:
+err_panel_init:
err_runtime_get:
pm_runtime_disable(&pdev->dev);
venc_put_clocks();
@@ -916,14 +883,16 @@ err_runtime_get:
static int __exit omap_venchw_remove(struct platform_device *pdev)
{
- omap_dss_unregister_child_devices(&pdev->dev);
+ dss_unregister_child_devices(&pdev->dev);
if (venc.vdda_dac_reg != NULL) {
regulator_put(venc.vdda_dac_reg);
venc.vdda_dac_reg = NULL;
}
- omap_dss_unregister_driver(&venc_driver);
+ venc_panel_exit();
+
+ venc_uninit_output(pdev);
pm_runtime_disable(&pdev->dev);
venc_put_clocks();
@@ -971,16 +940,10 @@ static struct platform_driver omap_venchw_driver = {
int __init venc_init_platform_driver(void)
{
- if (cpu_is_omap44xx())
- return 0;
-
return platform_driver_probe(&omap_venchw_driver, omap_venchw_probe);
}
void __exit venc_uninit_platform_driver(void)
{
- if (cpu_is_omap44xx())
- return;
-
platform_driver_unregister(&omap_venchw_driver);
}
diff --git a/drivers/video/omap2/dss/venc_panel.c b/drivers/video/omap2/dss/venc_panel.c
new file mode 100644
index 0000000..d55b878
--- /dev/null
+++ b/drivers/video/omap2/dss/venc_panel.c
@@ -0,0 +1,251 @@
+/*
+ * Copyright (C) 2009 Nokia Corporation
+ * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
+ *
+ * VENC panel 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.
+ *
+ * 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/>.
+ */
+
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/mutex.h>
+#include <linux/module.h>
+
+#include <video/omapdss.h>
+
+#include "dss.h"
+
+static struct {
+ struct mutex lock;
+} venc_panel;
+
+static ssize_t display_output_type_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct omap_dss_device *dssdev = to_dss_device(dev);
+ const char *ret;
+
+ switch (dssdev->phy.venc.type) {
+ case OMAP_DSS_VENC_TYPE_COMPOSITE:
+ ret = "composite";
+ break;
+ case OMAP_DSS_VENC_TYPE_SVIDEO:
+ ret = "svideo";
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return snprintf(buf, PAGE_SIZE, "%s\n", ret);
+}
+
+static ssize_t display_output_type_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t size)
+{
+ struct omap_dss_device *dssdev = to_dss_device(dev);
+ enum omap_dss_venc_type new_type;
+
+ if (sysfs_streq("composite", buf))
+ new_type = OMAP_DSS_VENC_TYPE_COMPOSITE;
+ else if (sysfs_streq("svideo", buf))
+ new_type = OMAP_DSS_VENC_TYPE_SVIDEO;
+ else
+ return -EINVAL;
+
+ mutex_lock(&venc_panel.lock);
+
+ if (dssdev->phy.venc.type != new_type) {
+ dssdev->phy.venc.type = new_type;
+ omapdss_venc_set_type(dssdev, new_type);
+ if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) {
+ omapdss_venc_display_disable(dssdev);
+ omapdss_venc_display_enable(dssdev);
+ }
+ }
+
+ mutex_unlock(&venc_panel.lock);
+
+ return size;
+}
+
+static DEVICE_ATTR(output_type, S_IRUGO | S_IWUSR,
+ display_output_type_show, display_output_type_store);
+
+static int venc_panel_probe(struct omap_dss_device *dssdev)
+{
+ /* set default timings to PAL */
+ const struct omap_video_timings default_timings = {
+ .x_res = 720,
+ .y_res = 574,
+ .pixel_clock = 13500,
+ .hsw = 64,
+ .hfp = 12,
+ .hbp = 68,
+ .vsw = 5,
+ .vfp = 5,
+ .vbp = 41,
+
+ .vsync_level = OMAPDSS_SIG_ACTIVE_HIGH,
+ .hsync_level = OMAPDSS_SIG_ACTIVE_HIGH,
+
+ .interlace = true,
+ };
+
+ mutex_init(&venc_panel.lock);
+
+ dssdev->panel.timings = default_timings;
+
+ return device_create_file(&dssdev->dev, &dev_attr_output_type);
+}
+
+static void venc_panel_remove(struct omap_dss_device *dssdev)
+{
+ device_remove_file(&dssdev->dev, &dev_attr_output_type);
+}
+
+static int venc_panel_enable(struct omap_dss_device *dssdev)
+{
+ int r;
+
+ dev_dbg(&dssdev->dev, "venc_panel_enable\n");
+
+ mutex_lock(&venc_panel.lock);
+
+ if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) {
+ r = -EINVAL;
+ goto err;
+ }
+
+ omapdss_venc_set_timings(dssdev, &dssdev->panel.timings);
+ omapdss_venc_set_type(dssdev, dssdev->phy.venc.type);
+ omapdss_venc_invert_vid_out_polarity(dssdev,
+ dssdev->phy.venc.invert_polarity);
+
+ r = omapdss_venc_display_enable(dssdev);
+ if (r)
+ goto err;
+
+ dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+
+ mutex_unlock(&venc_panel.lock);
+
+ return 0;
+err:
+ mutex_unlock(&venc_panel.lock);
+
+ return r;
+}
+
+static void venc_panel_disable(struct omap_dss_device *dssdev)
+{
+ dev_dbg(&dssdev->dev, "venc_panel_disable\n");
+
+ mutex_lock(&venc_panel.lock);
+
+ if (dssdev->state == OMAP_DSS_DISPLAY_DISABLED)
+ goto end;
+
+ if (dssdev->state == OMAP_DSS_DISPLAY_SUSPENDED) {
+ /* suspended is the same as disabled with venc */
+ dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
+ goto end;
+ }
+
+ omapdss_venc_display_disable(dssdev);
+
+ dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
+end:
+ mutex_unlock(&venc_panel.lock);
+}
+
+static int venc_panel_suspend(struct omap_dss_device *dssdev)
+{
+ venc_panel_disable(dssdev);
+ return 0;
+}
+
+static int venc_panel_resume(struct omap_dss_device *dssdev)
+{
+ return venc_panel_enable(dssdev);
+}
+
+static void venc_panel_set_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ dev_dbg(&dssdev->dev, "venc_panel_set_timings\n");
+
+ mutex_lock(&venc_panel.lock);
+
+ omapdss_venc_set_timings(dssdev, timings);
+ dssdev->panel.timings = *timings;
+
+ mutex_unlock(&venc_panel.lock);
+}
+
+static int venc_panel_check_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ dev_dbg(&dssdev->dev, "venc_panel_check_timings\n");
+
+ return omapdss_venc_check_timings(dssdev, timings);
+}
+
+static u32 venc_panel_get_wss(struct omap_dss_device *dssdev)
+{
+ dev_dbg(&dssdev->dev, "venc_panel_get_wss\n");
+
+ return omapdss_venc_get_wss(dssdev);
+}
+
+static int venc_panel_set_wss(struct omap_dss_device *dssdev, u32 wss)
+{
+ dev_dbg(&dssdev->dev, "venc_panel_set_wss\n");
+
+ return omapdss_venc_set_wss(dssdev, wss);
+}
+
+static struct omap_dss_driver venc_driver = {
+ .probe = venc_panel_probe,
+ .remove = venc_panel_remove,
+
+ .enable = venc_panel_enable,
+ .disable = venc_panel_disable,
+ .suspend = venc_panel_suspend,
+ .resume = venc_panel_resume,
+
+ .get_resolution = omapdss_default_get_resolution,
+ .get_recommended_bpp = omapdss_default_get_recommended_bpp,
+
+ .set_timings = venc_panel_set_timings,
+ .check_timings = venc_panel_check_timings,
+
+ .get_wss = venc_panel_get_wss,
+ .set_wss = venc_panel_set_wss,
+
+ .driver = {
+ .name = "venc",
+ .owner = THIS_MODULE,
+ },
+};
+
+int venc_panel_init(void)
+{
+ return omap_dss_register_driver(&venc_driver);
+}
+
+void venc_panel_exit(void)
+{
+ omap_dss_unregister_driver(&venc_driver);
+}
diff --git a/drivers/video/omap2/omapfb/omapfb-ioctl.c b/drivers/video/omap2/omapfb/omapfb-ioctl.c
index c6cf372..606b89f 100644
--- a/drivers/video/omap2/omapfb/omapfb-ioctl.c
+++ b/drivers/video/omap2/omapfb/omapfb-ioctl.c
@@ -599,6 +599,7 @@ int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg)
struct omapfb_info *ofbi = FB2OFB(fbi);
struct omapfb2_device *fbdev = ofbi->fbdev;
struct omap_dss_device *display = fb2display(fbi);
+ struct omap_overlay_manager *mgr;
union {
struct omapfb_update_window_old uwnd_o;
@@ -786,12 +787,14 @@ int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg)
case OMAPFB_WAITFORVSYNC:
DBG("ioctl WAITFORVSYNC\n");
- if (!display) {
+ if (!display && !display->output && !display->output->manager) {
r = -EINVAL;
break;
}
- r = display->manager->wait_for_vsync(display->manager);
+ mgr = display->output->manager;
+
+ r = mgr->wait_for_vsync(mgr);
break;
case OMAPFB_WAITFORGO:
diff --git a/drivers/video/omap2/omapfb/omapfb-main.c b/drivers/video/omap2/omapfb/omapfb-main.c
index 15373f4..16db158 100644
--- a/drivers/video/omap2/omapfb/omapfb-main.c
+++ b/drivers/video/omap2/omapfb/omapfb-main.c
@@ -1593,6 +1593,20 @@ static int omapfb_allocate_all_fbs(struct omapfb2_device *fbdev)
return 0;
}
+static void omapfb_clear_fb(struct fb_info *fbi)
+{
+ const struct fb_fillrect rect = {
+ .dx = 0,
+ .dy = 0,
+ .width = fbi->var.xres_virtual,
+ .height = fbi->var.yres_virtual,
+ .color = 0,
+ .rop = ROP_COPY,
+ };
+
+ cfb_fillrect(fbi, &rect);
+}
+
int omapfb_realloc_fbmem(struct fb_info *fbi, unsigned long size, int type)
{
struct omapfb_info *ofbi = FB2OFB(fbi);
@@ -1662,6 +1676,8 @@ int omapfb_realloc_fbmem(struct fb_info *fbi, unsigned long size, int type)
goto err;
}
+ omapfb_clear_fb(fbi);
+
return 0;
err:
omapfb_free_fbmem(fbi);
@@ -1946,6 +1962,16 @@ static int omapfb_create_framebuffers(struct omapfb2_device *fbdev)
}
}
+ for (i = 0; i < fbdev->num_fbs; i++) {
+ struct fb_info *fbi = fbdev->fbs[i];
+ struct omapfb_info *ofbi = FB2OFB(fbi);
+
+ if (ofbi->region->size == 0)
+ continue;
+
+ omapfb_clear_fb(fbi);
+ }
+
DBG("fb_infos initialized\n");
for (i = 0; i < fbdev->num_fbs; i++) {
@@ -2354,6 +2380,7 @@ static int __init omapfb_probe(struct platform_device *pdev)
struct omap_overlay *ovl;
struct omap_dss_device *def_display;
struct omap_dss_device *dssdev;
+ struct omap_dss_device *ovl_device;
DBG("omapfb_probe\n");
@@ -2427,8 +2454,9 @@ static int __init omapfb_probe(struct platform_device *pdev)
/* gfx overlay should be the default one. find a display
* connected to that, and use it as default display */
ovl = omap_dss_get_overlay(0);
- if (ovl->manager && ovl->manager->device) {
- def_display = ovl->manager->device;
+ ovl_device = ovl->get_device(ovl);
+ if (ovl_device) {
+ def_display = ovl_device;
} else {
dev_warn(&pdev->dev, "cannot find default display\n");
def_display = NULL;
diff --git a/drivers/video/omap2/omapfb/omapfb.h b/drivers/video/omap2/omapfb/omapfb.h
index 30361a0..5ced9b3 100644
--- a/drivers/video/omap2/omapfb/omapfb.h
+++ b/drivers/video/omap2/omapfb/omapfb.h
@@ -148,8 +148,9 @@ static inline struct omap_dss_device *fb2display(struct fb_info *fbi)
/* XXX: returns the display connected to first attached overlay */
for (i = 0; i < ofbi->num_overlays; i++) {
- if (ofbi->overlays[i]->manager)
- return ofbi->overlays[i]->manager->device;
+ struct omap_overlay *ovl = ofbi->overlays[i];
+
+ return ovl->get_device(ovl);
}
return NULL;
diff --git a/drivers/video/omap2/vram.c b/drivers/video/omap2/vram.c
index 87e421e..f2b15c4 100644
--- a/drivers/video/omap2/vram.c
+++ b/drivers/video/omap2/vram.c
@@ -34,7 +34,6 @@
#include <asm/setup.h>
#include <plat/vram.h>
-#include <plat/dma.h>
#ifdef DEBUG
#define DBG(format, ...) pr_debug("VRAM: " format, ## __VA_ARGS__)
@@ -250,59 +249,6 @@ int omap_vram_reserve(unsigned long paddr, size_t size)
}
EXPORT_SYMBOL(omap_vram_reserve);
-static void _omap_vram_dma_cb(int lch, u16 ch_status, void *data)
-{
- struct completion *compl = data;
- complete(compl);
-}
-
-static int _omap_vram_clear(u32 paddr, unsigned pages)
-{
- struct completion compl;
- unsigned elem_count;
- unsigned frame_count;
- int r;
- int lch;
-
- init_completion(&compl);
-
- r = omap_request_dma(OMAP_DMA_NO_DEVICE, "VRAM DMA",
- _omap_vram_dma_cb,
- &compl, &lch);
- if (r) {
- pr_err("VRAM: request_dma failed for memory clear\n");
- return -EBUSY;
- }
-
- elem_count = pages * PAGE_SIZE / 4;
- frame_count = 1;
-
- omap_set_dma_transfer_params(lch, OMAP_DMA_DATA_TYPE_S32,
- elem_count, frame_count,
- OMAP_DMA_SYNC_ELEMENT,
- 0, 0);
-
- omap_set_dma_dest_params(lch, 0, OMAP_DMA_AMODE_POST_INC,
- paddr, 0, 0);
-
- omap_set_dma_color_mode(lch, OMAP_DMA_CONSTANT_FILL, 0x000000);
-
- omap_start_dma(lch);
-
- if (wait_for_completion_timeout(&compl, msecs_to_jiffies(1000)) == 0) {
- omap_stop_dma(lch);
- pr_err("VRAM: dma timeout while clearing memory\n");
- r = -EIO;
- goto err;
- }
-
- r = 0;
-err:
- omap_free_dma(lch);
-
- return r;
-}
-
static int _omap_vram_alloc(unsigned pages, unsigned long *paddr)
{
struct vram_region *rm;
@@ -337,8 +283,6 @@ found:
*paddr = start;
- _omap_vram_clear(start, pages);
-
return 0;
}
diff --git a/drivers/video/pnx4008/Makefile b/drivers/video/pnx4008/Makefile
deleted file mode 100644
index 636aacc..0000000
--- a/drivers/video/pnx4008/Makefile
+++ /dev/null
@@ -1,7 +0,0 @@
-#
-# Makefile for the new PNX4008 framebuffer device driver
-#
-
-obj-$(CONFIG_FB_PNX4008_DUM) += sdum.o
-obj-$(CONFIG_FB_PNX4008_DUM_RGB) += pnxrgbfb.o
-
diff --git a/drivers/video/pnx4008/dum.h b/drivers/video/pnx4008/dum.h
deleted file mode 100644
index 1234d43..0000000
--- a/drivers/video/pnx4008/dum.h
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- * linux/drivers/video/pnx4008/dum.h
- *
- * Internal header for SDUM
- *
- * 2005 (c) Koninklijke Philips N.V. This file is licensed under
- * the terms of the GNU General Public License version 2. This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- */
-
-#ifndef __PNX008_DUM_H__
-#define __PNX008_DUM_H__
-
-#include <mach/platform.h>
-
-#define PNX4008_DUMCONF_VA_BASE IO_ADDRESS(PNX4008_DUMCONF_BASE)
-#define PNX4008_DUM_MAIN_VA_BASE IO_ADDRESS(PNX4008_DUM_MAINCFG_BASE)
-
-/* DUM CFG ADDRESSES */
-#define DUM_CH_BASE_ADR (PNX4008_DUMCONF_VA_BASE + 0x00)
-#define DUM_CH_MIN_ADR (PNX4008_DUMCONF_VA_BASE + 0x00)
-#define DUM_CH_MAX_ADR (PNX4008_DUMCONF_VA_BASE + 0x04)
-#define DUM_CH_CONF_ADR (PNX4008_DUMCONF_VA_BASE + 0x08)
-#define DUM_CH_STAT_ADR (PNX4008_DUMCONF_VA_BASE + 0x0C)
-#define DUM_CH_CTRL_ADR (PNX4008_DUMCONF_VA_BASE + 0x10)
-
-#define CH_MARG (0x100 / sizeof(u32))
-#define DUM_CH_MIN(i) (*((volatile u32 *)DUM_CH_MIN_ADR + (i) * CH_MARG))
-#define DUM_CH_MAX(i) (*((volatile u32 *)DUM_CH_MAX_ADR + (i) * CH_MARG))
-#define DUM_CH_CONF(i) (*((volatile u32 *)DUM_CH_CONF_ADR + (i) * CH_MARG))
-#define DUM_CH_STAT(i) (*((volatile u32 *)DUM_CH_STAT_ADR + (i) * CH_MARG))
-#define DUM_CH_CTRL(i) (*((volatile u32 *)DUM_CH_CTRL_ADR + (i) * CH_MARG))
-
-#define DUM_CONF_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x00)
-#define DUM_CTRL_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x04)
-#define DUM_STAT_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x08)
-#define DUM_DECODE_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x0C)
-#define DUM_COM_BASE_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x10)
-#define DUM_SYNC_C_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x14)
-#define DUM_CLK_DIV_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x18)
-#define DUM_DIRTY_LOW_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x20)
-#define DUM_DIRTY_HIGH_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x24)
-#define DUM_FORMAT_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x28)
-#define DUM_WTCFG1_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x30)
-#define DUM_RTCFG1_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x34)
-#define DUM_WTCFG2_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x38)
-#define DUM_RTCFG2_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x3C)
-#define DUM_TCFG_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x40)
-#define DUM_OUTP_FORMAT1_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x44)
-#define DUM_OUTP_FORMAT2_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x48)
-#define DUM_SYNC_MODE_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x4C)
-#define DUM_SYNC_OUT_C_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x50)
-
-#define DUM_CONF (*(volatile u32 *)(DUM_CONF_ADR))
-#define DUM_CTRL (*(volatile u32 *)(DUM_CTRL_ADR))
-#define DUM_STAT (*(volatile u32 *)(DUM_STAT_ADR))
-#define DUM_DECODE (*(volatile u32 *)(DUM_DECODE_ADR))
-#define DUM_COM_BASE (*(volatile u32 *)(DUM_COM_BASE_ADR))
-#define DUM_SYNC_C (*(volatile u32 *)(DUM_SYNC_C_ADR))
-#define DUM_CLK_DIV (*(volatile u32 *)(DUM_CLK_DIV_ADR))
-#define DUM_DIRTY_LOW (*(volatile u32 *)(DUM_DIRTY_LOW_ADR))
-#define DUM_DIRTY_HIGH (*(volatile u32 *)(DUM_DIRTY_HIGH_ADR))
-#define DUM_FORMAT (*(volatile u32 *)(DUM_FORMAT_ADR))
-#define DUM_WTCFG1 (*(volatile u32 *)(DUM_WTCFG1_ADR))
-#define DUM_RTCFG1 (*(volatile u32 *)(DUM_RTCFG1_ADR))
-#define DUM_WTCFG2 (*(volatile u32 *)(DUM_WTCFG2_ADR))
-#define DUM_RTCFG2 (*(volatile u32 *)(DUM_RTCFG2_ADR))
-#define DUM_TCFG (*(volatile u32 *)(DUM_TCFG_ADR))
-#define DUM_OUTP_FORMAT1 (*(volatile u32 *)(DUM_OUTP_FORMAT1_ADR))
-#define DUM_OUTP_FORMAT2 (*(volatile u32 *)(DUM_OUTP_FORMAT2_ADR))
-#define DUM_SYNC_MODE (*(volatile u32 *)(DUM_SYNC_MODE_ADR))
-#define DUM_SYNC_OUT_C (*(volatile u32 *)(DUM_SYNC_OUT_C_ADR))
-
-/* DUM SLAVE ADDRESSES */
-#define DUM_SLAVE_WRITE_ADR (PNX4008_DUM_MAINCFG_BASE + 0x0000000)
-#define DUM_SLAVE_READ1_I_ADR (PNX4008_DUM_MAINCFG_BASE + 0x1000000)
-#define DUM_SLAVE_READ1_R_ADR (PNX4008_DUM_MAINCFG_BASE + 0x1000004)
-#define DUM_SLAVE_READ2_I_ADR (PNX4008_DUM_MAINCFG_BASE + 0x1000008)
-#define DUM_SLAVE_READ2_R_ADR (PNX4008_DUM_MAINCFG_BASE + 0x100000C)
-
-#define DUM_SLAVE_WRITE_W ((volatile u32 *)(DUM_SLAVE_WRITE_ADR))
-#define DUM_SLAVE_WRITE_HW ((volatile u16 *)(DUM_SLAVE_WRITE_ADR))
-#define DUM_SLAVE_READ1_I ((volatile u8 *)(DUM_SLAVE_READ1_I_ADR))
-#define DUM_SLAVE_READ1_R ((volatile u16 *)(DUM_SLAVE_READ1_R_ADR))
-#define DUM_SLAVE_READ2_I ((volatile u8 *)(DUM_SLAVE_READ2_I_ADR))
-#define DUM_SLAVE_READ2_R ((volatile u16 *)(DUM_SLAVE_READ2_R_ADR))
-
-/* Sony display register addresses */
-#define DISP_0_REG (0x00)
-#define DISP_1_REG (0x01)
-#define DISP_CAL_REG (0x20)
-#define DISP_ID_REG (0x2A)
-#define DISP_XMIN_L_REG (0x30)
-#define DISP_XMIN_H_REG (0x31)
-#define DISP_YMIN_REG (0x32)
-#define DISP_XMAX_L_REG (0x34)
-#define DISP_XMAX_H_REG (0x35)
-#define DISP_YMAX_REG (0x36)
-#define DISP_SYNC_EN_REG (0x38)
-#define DISP_SYNC_RISE_L_REG (0x3C)
-#define DISP_SYNC_RISE_H_REG (0x3D)
-#define DISP_SYNC_FALL_L_REG (0x3E)
-#define DISP_SYNC_FALL_H_REG (0x3F)
-#define DISP_PIXEL_REG (0x0B)
-#define DISP_DUMMY1_REG (0x28)
-#define DISP_DUMMY2_REG (0x29)
-#define DISP_TIMING_REG (0x98)
-#define DISP_DUMP_REG (0x99)
-
-/* Sony display constants */
-#define SONY_ID1 (0x22)
-#define SONY_ID2 (0x23)
-
-/* Philips display register addresses */
-#define PH_DISP_ORIENT_REG (0x003)
-#define PH_DISP_YPOINT_REG (0x200)
-#define PH_DISP_XPOINT_REG (0x201)
-#define PH_DISP_PIXEL_REG (0x202)
-#define PH_DISP_YMIN_REG (0x406)
-#define PH_DISP_YMAX_REG (0x407)
-#define PH_DISP_XMIN_REG (0x408)
-#define PH_DISP_XMAX_REG (0x409)
-
-/* Misc constants */
-#define NO_VALID_DISPLAY_FOUND (0)
-#define DISPLAY2_IS_NOT_CONNECTED (0)
-
-/* register values */
-#define V_BAC_ENABLE (BIT(0))
-#define V_BAC_DISABLE_IDLE (BIT(1))
-#define V_BAC_DISABLE_TRIG (BIT(2))
-#define V_DUM_RESET (BIT(3))
-#define V_MUX_RESET (BIT(4))
-#define BAC_ENABLED (BIT(0))
-#define BAC_DISABLED 0
-
-/* Sony LCD commands */
-#define V_LCD_STANDBY_OFF ((BIT(25)) | (0 << 16) | DISP_0_REG)
-#define V_LCD_USE_9BIT_BUS ((BIT(25)) | (2 << 16) | DISP_1_REG)
-#define V_LCD_SYNC_RISE_L ((BIT(25)) | (0 << 16) | DISP_SYNC_RISE_L_REG)
-#define V_LCD_SYNC_RISE_H ((BIT(25)) | (0 << 16) | DISP_SYNC_RISE_H_REG)
-#define V_LCD_SYNC_FALL_L ((BIT(25)) | (160 << 16) | DISP_SYNC_FALL_L_REG)
-#define V_LCD_SYNC_FALL_H ((BIT(25)) | (0 << 16) | DISP_SYNC_FALL_H_REG)
-#define V_LCD_SYNC_ENABLE ((BIT(25)) | (128 << 16) | DISP_SYNC_EN_REG)
-#define V_LCD_DISPLAY_ON ((BIT(25)) | (64 << 16) | DISP_0_REG)
-
-enum {
- PAD_NONE,
- PAD_512,
- PAD_1024
-};
-
-enum {
- RGB888,
- RGB666,
- RGB565,
- BGR565,
- ARGB1555,
- ABGR1555,
- ARGB4444,
- ABGR4444
-};
-
-struct dum_setup {
- int sync_neg_edge;
- int round_robin;
- int mux_int;
- int synced_dirty_flag_int;
- int dirty_flag_int;
- int error_int;
- int pf_empty_int;
- int sf_empty_int;
- int bac_dis_int;
- u32 dirty_base_adr;
- u32 command_base_adr;
- u32 sync_clk_div;
- int sync_output;
- u32 sync_restart_val;
- u32 set_sync_high;
- u32 set_sync_low;
-};
-
-struct dum_ch_setup {
- int disp_no;
- u32 xmin;
- u32 ymin;
- u32 xmax;
- u32 ymax;
- int xmirror;
- int ymirror;
- int rotate;
- u32 minadr;
- u32 maxadr;
- u32 dirtybuffer;
- int pad;
- int format;
- int hwdirty;
- int slave_trans;
-};
-
-struct disp_window {
- u32 xmin_l;
- u32 xmin_h;
- u32 ymin;
- u32 xmax_l;
- u32 xmax_h;
- u32 ymax;
-};
-
-#endif /* #ifndef __PNX008_DUM_H__ */
diff --git a/drivers/video/pnx4008/fbcommon.h b/drivers/video/pnx4008/fbcommon.h
deleted file mode 100644
index 4ebc87d..0000000
--- a/drivers/video/pnx4008/fbcommon.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2005 Philips Semiconductors
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING. If not, write to
- * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA, or http://www.gnu.org/licenses/gpl.html
-*/
-
-#define QCIF_W (176)
-#define QCIF_H (144)
-
-#define CIF_W (352)
-#define CIF_H (288)
-
-#define LCD_X_RES 208
-#define LCD_Y_RES 320
-#define LCD_X_PAD 256
-#define LCD_BBP 4 /* Bytes Per Pixel */
-
-#define DISP_MAX_X_SIZE (320)
-#define DISP_MAX_Y_SIZE (208)
-
-#define RETURNVAL_BASE (0x400)
-
-enum fb_ioctl_returntype {
- ENORESOURCESLEFT = RETURNVAL_BASE,
- ERESOURCESNOTFREED,
- EPROCNOTOWNER,
- EFBNOTOWNER,
- ECOPYFAILED,
- EIOREMAPFAILED,
-};
diff --git a/drivers/video/pnx4008/pnxrgbfb.c b/drivers/video/pnx4008/pnxrgbfb.c
deleted file mode 100644
index 6d30428..0000000
--- a/drivers/video/pnx4008/pnxrgbfb.c
+++ /dev/null
@@ -1,198 +0,0 @@
-/*
- * drivers/video/pnx4008/pnxrgbfb.c
- *
- * PNX4008's framebuffer support
- *
- * Author: Grigory Tolstolytkin <gtolstolytkin@ru.mvista.com>
- * Based on Philips Semiconductors's code
- *
- * Copyrght (c) 2005 MontaVista Software, Inc.
- * Copyright (c) 2005 Philips Semiconductors
- * This file is licensed under the terms of the GNU General Public License
- * version 2. This program is licensed "as is" without any warranty of any
- * kind, whether express or implied.
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/vmalloc.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/fb.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-
-#include "sdum.h"
-#include "fbcommon.h"
-
-static u32 colreg[16];
-
-static struct fb_var_screeninfo rgbfb_var __initdata = {
- .xres = LCD_X_RES,
- .yres = LCD_Y_RES,
- .xres_virtual = LCD_X_RES,
- .yres_virtual = LCD_Y_RES,
- .bits_per_pixel = 32,
- .red.offset = 16,
- .red.length = 8,
- .green.offset = 8,
- .green.length = 8,
- .blue.offset = 0,
- .blue.length = 8,
- .left_margin = 0,
- .right_margin = 0,
- .upper_margin = 0,
- .lower_margin = 0,
- .vmode = FB_VMODE_NONINTERLACED,
-};
-static struct fb_fix_screeninfo rgbfb_fix __initdata = {
- .id = "RGBFB",
- .line_length = LCD_X_RES * LCD_BBP,
- .type = FB_TYPE_PACKED_PIXELS,
- .visual = FB_VISUAL_TRUECOLOR,
- .xpanstep = 0,
- .ypanstep = 0,
- .ywrapstep = 0,
- .accel = FB_ACCEL_NONE,
-};
-
-static int channel_owned;
-
-static int no_cursor(struct fb_info *info, struct fb_cursor *cursor)
-{
- return 0;
-}
-
-static int rgbfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
- u_int transp, struct fb_info *info)
-{
- if (regno > 15)
- return 1;
-
- colreg[regno] = ((red & 0xff00) << 8) | (green & 0xff00) |
- ((blue & 0xff00) >> 8);
- return 0;
-}
-
-static int rgbfb_mmap(struct fb_info *info, struct vm_area_struct *vma)
-{
- return pnx4008_sdum_mmap(info, vma, NULL);
-}
-
-static struct fb_ops rgbfb_ops = {
- .fb_mmap = rgbfb_mmap,
- .fb_setcolreg = rgbfb_setcolreg,
- .fb_fillrect = cfb_fillrect,
- .fb_copyarea = cfb_copyarea,
- .fb_imageblit = cfb_imageblit,
-};
-
-static int rgbfb_remove(struct platform_device *pdev)
-{
- struct fb_info *info = platform_get_drvdata(pdev);
-
- if (info) {
- unregister_framebuffer(info);
- fb_dealloc_cmap(&info->cmap);
- framebuffer_release(info);
- platform_set_drvdata(pdev, NULL);
- }
-
- pnx4008_free_dum_channel(channel_owned, pdev->id);
- pnx4008_set_dum_exit_notification(pdev->id);
-
- return 0;
-}
-
-static int __devinit rgbfb_probe(struct platform_device *pdev)
-{
- struct fb_info *info;
- struct dumchannel_uf chan_uf;
- int ret;
- char *option;
-
- info = framebuffer_alloc(sizeof(u32) * 16, &pdev->dev);
- if (!info) {
- ret = -ENOMEM;
- goto err;
- }
-
- pnx4008_get_fb_addresses(FB_TYPE_RGB, (void **)&info->screen_base,
- (dma_addr_t *) &rgbfb_fix.smem_start,
- &rgbfb_fix.smem_len);
-
- if ((ret = pnx4008_alloc_dum_channel(pdev->id)) < 0)
- goto err0;
- else {
- channel_owned = ret;
- chan_uf.channelnr = channel_owned;
- chan_uf.dirty = (u32 *) NULL;
- chan_uf.source = (u32 *) rgbfb_fix.smem_start;
- chan_uf.x_offset = 0;
- chan_uf.y_offset = 0;
- chan_uf.width = LCD_X_RES;
- chan_uf.height = LCD_Y_RES;
-
- if ((ret = pnx4008_put_dum_channel_uf(chan_uf, pdev->id))< 0)
- goto err1;
-
- if ((ret =
- pnx4008_set_dum_channel_sync(channel_owned, CONF_SYNC_ON,
- pdev->id)) < 0)
- goto err1;
-
- if ((ret =
- pnx4008_set_dum_channel_dirty_detect(channel_owned,
- CONF_DIRTYDETECTION_ON,
- pdev->id)) < 0)
- goto err1;
- }
-
- if (!fb_get_options("pnxrgbfb", &option) && option &&
- !strcmp(option, "nocursor"))
- rgbfb_ops.fb_cursor = no_cursor;
-
- info->node = -1;
- info->flags = FBINFO_FLAG_DEFAULT;
- info->fbops = &rgbfb_ops;
- info->fix = rgbfb_fix;
- info->var = rgbfb_var;
- info->screen_size = rgbfb_fix.smem_len;
- info->pseudo_palette = info->par;
- info->par = NULL;
-
- ret = fb_alloc_cmap(&info->cmap, 256, 0);
- if (ret < 0)
- goto err1;
-
- ret = register_framebuffer(info);
- if (ret < 0)
- goto err2;
- platform_set_drvdata(pdev, info);
-
- return 0;
-
-err2:
- fb_dealloc_cmap(&info->cmap);
-err1:
- pnx4008_free_dum_channel(channel_owned, pdev->id);
-err0:
- framebuffer_release(info);
-err:
- return ret;
-}
-
-static struct platform_driver rgbfb_driver = {
- .driver = {
- .name = "pnx4008-rgbfb",
- },
- .probe = rgbfb_probe,
- .remove = rgbfb_remove,
-};
-
-module_platform_driver(rgbfb_driver);
-
-MODULE_LICENSE("GPL");
diff --git a/drivers/video/pnx4008/sdum.c b/drivers/video/pnx4008/sdum.c
deleted file mode 100644
index c5c7414..0000000
--- a/drivers/video/pnx4008/sdum.c
+++ /dev/null
@@ -1,861 +0,0 @@
-/*
- * drivers/video/pnx4008/sdum.c
- *
- * Display Update Master support
- *
- * Authors: Grigory Tolstolytkin <gtolstolytkin@ru.mvista.com>
- * Vitaly Wool <vitalywool@gmail.com>
- * Based on Philips Semiconductors's code
- *
- * Copyrght (c) 2005-2006 MontaVista Software, Inc.
- * Copyright (c) 2005 Philips Semiconductors
- * This file is licensed under the terms of the GNU General Public License
- * version 2. This program is licensed "as is" without any warranty of any
- * kind, whether express or implied.
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/tty.h>
-#include <linux/vmalloc.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/platform_device.h>
-#include <linux/fb.h>
-#include <linux/init.h>
-#include <linux/dma-mapping.h>
-#include <linux/clk.h>
-#include <linux/gfp.h>
-#include <asm/uaccess.h>
-#include <asm/gpio.h>
-
-#include "sdum.h"
-#include "fbcommon.h"
-#include "dum.h"
-
-/* Framebuffers we have */
-
-static struct pnx4008_fb_addr {
- int fb_type;
- long addr_offset;
- long fb_length;
-} fb_addr[] = {
- [0] = {
- FB_TYPE_YUV, 0, 0xB0000
- },
- [1] = {
- FB_TYPE_RGB, 0xB0000, 0x50000
- },
-};
-
-static struct dum_data {
- u32 lcd_phys_start;
- u32 lcd_virt_start;
- u32 slave_phys_base;
- u32 *slave_virt_base;
- int fb_owning_channel[MAX_DUM_CHANNELS];
- struct dumchannel_uf chan_uf_store[MAX_DUM_CHANNELS];
-} dum_data;
-
-/* Different local helper functions */
-
-static u32 nof_pixels_dx(struct dum_ch_setup *ch_setup)
-{
- return (ch_setup->xmax - ch_setup->xmin + 1);
-}
-
-static u32 nof_pixels_dy(struct dum_ch_setup *ch_setup)
-{
- return (ch_setup->ymax - ch_setup->ymin + 1);
-}
-
-static u32 nof_pixels_dxy(struct dum_ch_setup *ch_setup)
-{
- return (nof_pixels_dx(ch_setup) * nof_pixels_dy(ch_setup));
-}
-
-static u32 nof_bytes(struct dum_ch_setup *ch_setup)
-{
- u32 r = nof_pixels_dxy(ch_setup);
- switch (ch_setup->format) {
- case RGB888:
- case RGB666:
- r *= 4;
- break;
-
- default:
- r *= 2;
- break;
- }
- return r;
-}
-
-static u32 build_command(int disp_no, u32 reg, u32 val)
-{
- return ((disp_no << 26) | BIT(25) | (val << 16) | (disp_no << 10) |
- (reg << 0));
-}
-
-static u32 build_double_index(int disp_no, u32 val)
-{
- return ((disp_no << 26) | (val << 16) | (disp_no << 10) | (val << 0));
-}
-
-static void build_disp_window(struct dum_ch_setup * ch_setup, struct disp_window * dw)
-{
- dw->ymin = ch_setup->ymin;
- dw->ymax = ch_setup->ymax;
- dw->xmin_l = ch_setup->xmin & 0xFF;
- dw->xmin_h = (ch_setup->xmin & BIT(8)) >> 8;
- dw->xmax_l = ch_setup->xmax & 0xFF;
- dw->xmax_h = (ch_setup->xmax & BIT(8)) >> 8;
-}
-
-static int put_channel(struct dumchannel chan)
-{
- int i = chan.channelnr;
-
- if (i < 0 || i > MAX_DUM_CHANNELS)
- return -EINVAL;
- else {
- DUM_CH_MIN(i) = chan.dum_ch_min;
- DUM_CH_MAX(i) = chan.dum_ch_max;
- DUM_CH_CONF(i) = chan.dum_ch_conf;
- DUM_CH_CTRL(i) = chan.dum_ch_ctrl;
- }
-
- return 0;
-}
-
-static void clear_channel(int channr)
-{
- struct dumchannel chan;
-
- chan.channelnr = channr;
- chan.dum_ch_min = 0;
- chan.dum_ch_max = 0;
- chan.dum_ch_conf = 0;
- chan.dum_ch_ctrl = 0;
-
- put_channel(chan);
-}
-
-static int put_cmd_string(struct cmdstring cmds)
-{
- u16 *cmd_str_virtaddr;
- u32 *cmd_ptr0_virtaddr;
- u32 cmd_str_physaddr;
-
- int i = cmds.channelnr;
-
- if (i < 0 || i > MAX_DUM_CHANNELS)
- return -EINVAL;
- else if ((cmd_ptr0_virtaddr =
- (int *)ioremap_nocache(DUM_COM_BASE,
- sizeof(int) * MAX_DUM_CHANNELS)) ==
- NULL)
- return -EIOREMAPFAILED;
- else {
- cmd_str_physaddr = ioread32(&cmd_ptr0_virtaddr[cmds.channelnr]);
- if ((cmd_str_virtaddr =
- (u16 *) ioremap_nocache(cmd_str_physaddr,
- sizeof(cmds))) == NULL) {
- iounmap(cmd_ptr0_virtaddr);
- return -EIOREMAPFAILED;
- } else {
- int t;
- for (t = 0; t < 8; t++)
- iowrite16(*((u16 *)&cmds.prestringlen + t),
- cmd_str_virtaddr + t);
-
- for (t = 0; t < cmds.prestringlen / 2; t++)
- iowrite16(*((u16 *)&cmds.precmd + t),
- cmd_str_virtaddr + t + 8);
-
- for (t = 0; t < cmds.poststringlen / 2; t++)
- iowrite16(*((u16 *)&cmds.postcmd + t),
- cmd_str_virtaddr + t + 8 +
- cmds.prestringlen / 2);
-
- iounmap(cmd_ptr0_virtaddr);
- iounmap(cmd_str_virtaddr);
- }
- }
-
- return 0;
-}
-
-static u32 dum_ch_setup(int ch_no, struct dum_ch_setup * ch_setup)
-{
- struct cmdstring cmds_c;
- struct cmdstring *cmds = &cmds_c;
- struct disp_window dw;
- int standard;
- u32 orientation = 0;
- struct dumchannel chan = { 0 };
- int ret;
-
- if ((ch_setup->xmirror) || (ch_setup->ymirror) || (ch_setup->rotate)) {
- standard = 0;
-
- orientation = BIT(1); /* always set 9-bit-bus */
- if (ch_setup->xmirror)
- orientation |= BIT(4);
- if (ch_setup->ymirror)
- orientation |= BIT(3);
- if (ch_setup->rotate)
- orientation |= BIT(0);
- } else
- standard = 1;
-
- cmds->channelnr = ch_no;
-
- /* build command string header */
- if (standard) {
- cmds->prestringlen = 32;
- cmds->poststringlen = 0;
- } else {
- cmds->prestringlen = 48;
- cmds->poststringlen = 16;
- }
-
- cmds->format =
- (u16) ((ch_setup->disp_no << 4) | (BIT(3)) | (ch_setup->format));
- cmds->reserved = 0x0;
- cmds->startaddr_low = (ch_setup->minadr & 0xFFFF);
- cmds->startaddr_high = (ch_setup->minadr >> 16);
-
- if ((ch_setup->minadr == 0) && (ch_setup->maxadr == 0)
- && (ch_setup->xmin == 0)
- && (ch_setup->ymin == 0) && (ch_setup->xmax == 0)
- && (ch_setup->ymax == 0)) {
- cmds->pixdatlen_low = 0;
- cmds->pixdatlen_high = 0;
- } else {
- u32 nbytes = nof_bytes(ch_setup);
- cmds->pixdatlen_low = (nbytes & 0xFFFF);
- cmds->pixdatlen_high = (nbytes >> 16);
- }
-
- if (ch_setup->slave_trans)
- cmds->pixdatlen_high |= BIT(15);
-
- /* build pre-string */
- build_disp_window(ch_setup, &dw);
-
- if (standard) {
- cmds->precmd[0] =
- build_command(ch_setup->disp_no, DISP_XMIN_L_REG, 0x99);
- cmds->precmd[1] =
- build_command(ch_setup->disp_no, DISP_XMIN_L_REG,
- dw.xmin_l);
- cmds->precmd[2] =
- build_command(ch_setup->disp_no, DISP_XMIN_H_REG,
- dw.xmin_h);
- cmds->precmd[3] =
- build_command(ch_setup->disp_no, DISP_YMIN_REG, dw.ymin);
- cmds->precmd[4] =
- build_command(ch_setup->disp_no, DISP_XMAX_L_REG,
- dw.xmax_l);
- cmds->precmd[5] =
- build_command(ch_setup->disp_no, DISP_XMAX_H_REG,
- dw.xmax_h);
- cmds->precmd[6] =
- build_command(ch_setup->disp_no, DISP_YMAX_REG, dw.ymax);
- cmds->precmd[7] =
- build_double_index(ch_setup->disp_no, DISP_PIXEL_REG);
- } else {
- if (dw.xmin_l == ch_no)
- cmds->precmd[0] =
- build_command(ch_setup->disp_no, DISP_XMIN_L_REG,
- 0x99);
- else
- cmds->precmd[0] =
- build_command(ch_setup->disp_no, DISP_XMIN_L_REG,
- ch_no);
-
- cmds->precmd[1] =
- build_command(ch_setup->disp_no, DISP_XMIN_L_REG,
- dw.xmin_l);
- cmds->precmd[2] =
- build_command(ch_setup->disp_no, DISP_XMIN_H_REG,
- dw.xmin_h);
- cmds->precmd[3] =
- build_command(ch_setup->disp_no, DISP_YMIN_REG, dw.ymin);
- cmds->precmd[4] =
- build_command(ch_setup->disp_no, DISP_XMAX_L_REG,
- dw.xmax_l);
- cmds->precmd[5] =
- build_command(ch_setup->disp_no, DISP_XMAX_H_REG,
- dw.xmax_h);
- cmds->precmd[6] =
- build_command(ch_setup->disp_no, DISP_YMAX_REG, dw.ymax);
- cmds->precmd[7] =
- build_command(ch_setup->disp_no, DISP_1_REG, orientation);
- cmds->precmd[8] =
- build_double_index(ch_setup->disp_no, DISP_PIXEL_REG);
- cmds->precmd[9] =
- build_double_index(ch_setup->disp_no, DISP_PIXEL_REG);
- cmds->precmd[0xA] =
- build_double_index(ch_setup->disp_no, DISP_PIXEL_REG);
- cmds->precmd[0xB] =
- build_double_index(ch_setup->disp_no, DISP_PIXEL_REG);
- cmds->postcmd[0] =
- build_command(ch_setup->disp_no, DISP_1_REG, BIT(1));
- cmds->postcmd[1] =
- build_command(ch_setup->disp_no, DISP_DUMMY1_REG, 1);
- cmds->postcmd[2] =
- build_command(ch_setup->disp_no, DISP_DUMMY1_REG, 2);
- cmds->postcmd[3] =
- build_command(ch_setup->disp_no, DISP_DUMMY1_REG, 3);
- }
-
- if ((ret = put_cmd_string(cmds_c)) != 0) {
- return ret;
- }
-
- chan.channelnr = cmds->channelnr;
- chan.dum_ch_min = ch_setup->dirtybuffer + ch_setup->minadr;
- chan.dum_ch_max = ch_setup->dirtybuffer + ch_setup->maxadr;
- chan.dum_ch_conf = 0x002;
- chan.dum_ch_ctrl = 0x04;
-
- put_channel(chan);
-
- return 0;
-}
-
-static u32 display_open(int ch_no, int auto_update, u32 * dirty_buffer,
- u32 * frame_buffer, u32 xpos, u32 ypos, u32 w, u32 h)
-{
-
- struct dum_ch_setup k;
- int ret;
-
- /* keep width & height within display area */
- if ((xpos + w) > DISP_MAX_X_SIZE)
- w = DISP_MAX_X_SIZE - xpos;
-
- if ((ypos + h) > DISP_MAX_Y_SIZE)
- h = DISP_MAX_Y_SIZE - ypos;
-
- /* assume 1 display only */
- k.disp_no = 0;
- k.xmin = xpos;
- k.ymin = ypos;
- k.xmax = xpos + (w - 1);
- k.ymax = ypos + (h - 1);
-
- /* adjust min and max values if necessary */
- if (k.xmin > DISP_MAX_X_SIZE - 1)
- k.xmin = DISP_MAX_X_SIZE - 1;
- if (k.ymin > DISP_MAX_Y_SIZE - 1)
- k.ymin = DISP_MAX_Y_SIZE - 1;
-
- if (k.xmax > DISP_MAX_X_SIZE - 1)
- k.xmax = DISP_MAX_X_SIZE - 1;
- if (k.ymax > DISP_MAX_Y_SIZE - 1)
- k.ymax = DISP_MAX_Y_SIZE - 1;
-
- k.xmirror = 0;
- k.ymirror = 0;
- k.rotate = 0;
- k.minadr = (u32) frame_buffer;
- k.maxadr = (u32) frame_buffer + (((w - 1) << 10) | ((h << 2) - 2));
- k.pad = PAD_1024;
- k.dirtybuffer = (u32) dirty_buffer;
- k.format = RGB888;
- k.hwdirty = 0;
- k.slave_trans = 0;
-
- ret = dum_ch_setup(ch_no, &k);
-
- return ret;
-}
-
-static void lcd_reset(void)
-{
- u32 *dum_pio_base = (u32 *)IO_ADDRESS(PNX4008_PIO_BASE);
-
- udelay(1);
- iowrite32(BIT(19), &dum_pio_base[2]);
- udelay(1);
- iowrite32(BIT(19), &dum_pio_base[1]);
- udelay(1);
-}
-
-static int dum_init(struct platform_device *pdev)
-{
- struct clk *clk;
-
- /* enable DUM clock */
- clk = clk_get(&pdev->dev, "dum_ck");
- if (IS_ERR(clk)) {
- printk(KERN_ERR "pnx4008_dum: Unable to access DUM clock\n");
- return PTR_ERR(clk);
- }
-
- clk_set_rate(clk, 1);
- clk_put(clk);
-
- DUM_CTRL = V_DUM_RESET;
-
- /* set priority to "round-robin". All other params to "false" */
- DUM_CONF = BIT(9);
-
- /* Display 1 */
- DUM_WTCFG1 = PNX4008_DUM_WT_CFG;
- DUM_RTCFG1 = PNX4008_DUM_RT_CFG;
- DUM_TCFG = PNX4008_DUM_T_CFG;
-
- return 0;
-}
-
-static void dum_chan_init(void)
-{
- int i = 0, ch = 0;
- u32 *cmdptrs;
- u32 *cmdstrings;
-
- DUM_COM_BASE =
- CMDSTRING_BASEADDR + BYTES_PER_CMDSTRING * NR_OF_CMDSTRINGS;
-
- if ((cmdptrs =
- (u32 *) ioremap_nocache(DUM_COM_BASE,
- sizeof(u32) * NR_OF_CMDSTRINGS)) == NULL)
- return;
-
- for (ch = 0; ch < NR_OF_CMDSTRINGS; ch++)
- iowrite32(CMDSTRING_BASEADDR + BYTES_PER_CMDSTRING * ch,
- cmdptrs + ch);
-
- for (ch = 0; ch < MAX_DUM_CHANNELS; ch++)
- clear_channel(ch);
-
- /* Clear the cmdstrings */
- cmdstrings =
- (u32 *)ioremap_nocache(*cmdptrs,
- BYTES_PER_CMDSTRING * NR_OF_CMDSTRINGS);
-
- if (!cmdstrings)
- goto out;
-
- for (i = 0; i < NR_OF_CMDSTRINGS * BYTES_PER_CMDSTRING / sizeof(u32);
- i++)
- iowrite32(0, cmdstrings + i);
-
- iounmap((u32 *)cmdstrings);
-
-out:
- iounmap((u32 *)cmdptrs);
-}
-
-static void lcd_init(void)
-{
- lcd_reset();
-
- DUM_OUTP_FORMAT1 = 0; /* RGB666 */
-
- udelay(1);
- iowrite32(V_LCD_STANDBY_OFF, dum_data.slave_virt_base);
- udelay(1);
- iowrite32(V_LCD_USE_9BIT_BUS, dum_data.slave_virt_base);
- udelay(1);
- iowrite32(V_LCD_SYNC_RISE_L, dum_data.slave_virt_base);
- udelay(1);
- iowrite32(V_LCD_SYNC_RISE_H, dum_data.slave_virt_base);
- udelay(1);
- iowrite32(V_LCD_SYNC_FALL_L, dum_data.slave_virt_base);
- udelay(1);
- iowrite32(V_LCD_SYNC_FALL_H, dum_data.slave_virt_base);
- udelay(1);
- iowrite32(V_LCD_SYNC_ENABLE, dum_data.slave_virt_base);
- udelay(1);
- iowrite32(V_LCD_DISPLAY_ON, dum_data.slave_virt_base);
- udelay(1);
-}
-
-/* Interface exported to framebuffer drivers */
-
-int pnx4008_get_fb_addresses(int fb_type, void **virt_addr,
- dma_addr_t *phys_addr, int *fb_length)
-{
- int i;
- int ret = -1;
- for (i = 0; i < ARRAY_SIZE(fb_addr); i++)
- if (fb_addr[i].fb_type == fb_type) {
- *virt_addr = (void *)(dum_data.lcd_virt_start +
- fb_addr[i].addr_offset);
- *phys_addr =
- dum_data.lcd_phys_start + fb_addr[i].addr_offset;
- *fb_length = fb_addr[i].fb_length;
- ret = 0;
- break;
- }
-
- return ret;
-}
-
-EXPORT_SYMBOL(pnx4008_get_fb_addresses);
-
-int pnx4008_alloc_dum_channel(int dev_id)
-{
- int i = 0;
-
- while ((i < MAX_DUM_CHANNELS) && (dum_data.fb_owning_channel[i] != -1))
- i++;
-
- if (i == MAX_DUM_CHANNELS)
- return -ENORESOURCESLEFT;
- else {
- dum_data.fb_owning_channel[i] = dev_id;
- return i;
- }
-}
-
-EXPORT_SYMBOL(pnx4008_alloc_dum_channel);
-
-int pnx4008_free_dum_channel(int channr, int dev_id)
-{
- if (channr < 0 || channr > MAX_DUM_CHANNELS)
- return -EINVAL;
- else if (dum_data.fb_owning_channel[channr] != dev_id)
- return -EFBNOTOWNER;
- else {
- clear_channel(channr);
- dum_data.fb_owning_channel[channr] = -1;
- }
-
- return 0;
-}
-
-EXPORT_SYMBOL(pnx4008_free_dum_channel);
-
-int pnx4008_put_dum_channel_uf(struct dumchannel_uf chan_uf, int dev_id)
-{
- int i = chan_uf.channelnr;
- int ret;
-
- if (i < 0 || i > MAX_DUM_CHANNELS)
- return -EINVAL;
- else if (dum_data.fb_owning_channel[i] != dev_id)
- return -EFBNOTOWNER;
- else if ((ret =
- display_open(chan_uf.channelnr, 0, chan_uf.dirty,
- chan_uf.source, chan_uf.y_offset,
- chan_uf.x_offset, chan_uf.height,
- chan_uf.width)) != 0)
- return ret;
- else {
- dum_data.chan_uf_store[i].dirty = chan_uf.dirty;
- dum_data.chan_uf_store[i].source = chan_uf.source;
- dum_data.chan_uf_store[i].x_offset = chan_uf.x_offset;
- dum_data.chan_uf_store[i].y_offset = chan_uf.y_offset;
- dum_data.chan_uf_store[i].width = chan_uf.width;
- dum_data.chan_uf_store[i].height = chan_uf.height;
- }
-
- return 0;
-}
-
-EXPORT_SYMBOL(pnx4008_put_dum_channel_uf);
-
-int pnx4008_set_dum_channel_sync(int channr, int val, int dev_id)
-{
- if (channr < 0 || channr > MAX_DUM_CHANNELS)
- return -EINVAL;
- else if (dum_data.fb_owning_channel[channr] != dev_id)
- return -EFBNOTOWNER;
- else {
- if (val == CONF_SYNC_ON) {
- DUM_CH_CONF(channr) |= CONF_SYNCENABLE;
- DUM_CH_CONF(channr) |= DUM_CHANNEL_CFG_SYNC_MASK |
- DUM_CHANNEL_CFG_SYNC_MASK_SET;
- } else if (val == CONF_SYNC_OFF)
- DUM_CH_CONF(channr) &= ~CONF_SYNCENABLE;
- else
- return -EINVAL;
- }
-
- return 0;
-}
-
-EXPORT_SYMBOL(pnx4008_set_dum_channel_sync);
-
-int pnx4008_set_dum_channel_dirty_detect(int channr, int val, int dev_id)
-{
- if (channr < 0 || channr > MAX_DUM_CHANNELS)
- return -EINVAL;
- else if (dum_data.fb_owning_channel[channr] != dev_id)
- return -EFBNOTOWNER;
- else {
- if (val == CONF_DIRTYDETECTION_ON)
- DUM_CH_CONF(channr) |= CONF_DIRTYENABLE;
- else if (val == CONF_DIRTYDETECTION_OFF)
- DUM_CH_CONF(channr) &= ~CONF_DIRTYENABLE;
- else
- return -EINVAL;
- }
-
- return 0;
-}
-
-EXPORT_SYMBOL(pnx4008_set_dum_channel_dirty_detect);
-
-#if 0 /* Functions not used currently, but likely to be used in future */
-
-static int get_channel(struct dumchannel *p_chan)
-{
- int i = p_chan->channelnr;
-
- if (i < 0 || i > MAX_DUM_CHANNELS)
- return -EINVAL;
- else {
- p_chan->dum_ch_min = DUM_CH_MIN(i);
- p_chan->dum_ch_max = DUM_CH_MAX(i);
- p_chan->dum_ch_conf = DUM_CH_CONF(i);
- p_chan->dum_ch_stat = DUM_CH_STAT(i);
- p_chan->dum_ch_ctrl = 0; /* WriteOnly control register */
- }
-
- return 0;
-}
-
-int pnx4008_get_dum_channel_uf(struct dumchannel_uf *p_chan_uf, int dev_id)
-{
- int i = p_chan_uf->channelnr;
-
- if (i < 0 || i > MAX_DUM_CHANNELS)
- return -EINVAL;
- else if (dum_data.fb_owning_channel[i] != dev_id)
- return -EFBNOTOWNER;
- else {
- p_chan_uf->dirty = dum_data.chan_uf_store[i].dirty;
- p_chan_uf->source = dum_data.chan_uf_store[i].source;
- p_chan_uf->x_offset = dum_data.chan_uf_store[i].x_offset;
- p_chan_uf->y_offset = dum_data.chan_uf_store[i].y_offset;
- p_chan_uf->width = dum_data.chan_uf_store[i].width;
- p_chan_uf->height = dum_data.chan_uf_store[i].height;
- }
-
- return 0;
-}
-
-EXPORT_SYMBOL(pnx4008_get_dum_channel_uf);
-
-int pnx4008_get_dum_channel_config(int channr, int dev_id)
-{
- int ret;
- struct dumchannel chan;
-
- if (channr < 0 || channr > MAX_DUM_CHANNELS)
- return -EINVAL;
- else if (dum_data.fb_owning_channel[channr] != dev_id)
- return -EFBNOTOWNER;
- else {
- chan.channelnr = channr;
- if ((ret = get_channel(&chan)) != 0)
- return ret;
- }
-
- return (chan.dum_ch_conf & DUM_CHANNEL_CFG_MASK);
-}
-
-EXPORT_SYMBOL(pnx4008_get_dum_channel_config);
-
-int pnx4008_force_update_dum_channel(int channr, int dev_id)
-{
- if (channr < 0 || channr > MAX_DUM_CHANNELS)
- return -EINVAL;
-
- else if (dum_data.fb_owning_channel[channr] != dev_id)
- return -EFBNOTOWNER;
- else
- DUM_CH_CTRL(channr) = CTRL_SETDIRTY;
-
- return 0;
-}
-
-EXPORT_SYMBOL(pnx4008_force_update_dum_channel);
-
-#endif
-
-int pnx4008_sdum_mmap(struct fb_info *info, struct vm_area_struct *vma,
- struct device *dev)
-{
- unsigned long off = vma->vm_pgoff << PAGE_SHIFT;
-
- if (off < info->fix.smem_len) {
- vma->vm_pgoff += 1;
- return dma_mmap_writecombine(dev, vma,
- (void *)dum_data.lcd_virt_start,
- dum_data.lcd_phys_start,
- FB_DMA_SIZE);
- }
- return -EINVAL;
-}
-
-EXPORT_SYMBOL(pnx4008_sdum_mmap);
-
-int pnx4008_set_dum_exit_notification(int dev_id)
-{
- int i;
-
- for (i = 0; i < MAX_DUM_CHANNELS; i++)
- if (dum_data.fb_owning_channel[i] == dev_id)
- return -ERESOURCESNOTFREED;
-
- return 0;
-}
-
-EXPORT_SYMBOL(pnx4008_set_dum_exit_notification);
-
-/* Platform device driver for DUM */
-
-static int sdum_suspend(struct platform_device *pdev, pm_message_t state)
-{
- int retval = 0;
- struct clk *clk;
-
- clk = clk_get(0, "dum_ck");
- if (!IS_ERR(clk)) {
- clk_set_rate(clk, 0);
- clk_put(clk);
- } else
- retval = PTR_ERR(clk);
-
- /* disable BAC */
- DUM_CTRL = V_BAC_DISABLE_IDLE;
-
- /* LCD standby & turn off display */
- lcd_reset();
-
- return retval;
-}
-
-static int sdum_resume(struct platform_device *pdev)
-{
- int retval = 0;
- struct clk *clk;
-
- clk = clk_get(0, "dum_ck");
- if (!IS_ERR(clk)) {
- clk_set_rate(clk, 1);
- clk_put(clk);
- } else
- retval = PTR_ERR(clk);
-
- /* wait for BAC disable */
- DUM_CTRL = V_BAC_DISABLE_TRIG;
-
- while (DUM_CTRL & BAC_ENABLED)
- udelay(10);
-
- /* re-init LCD */
- lcd_init();
-
- /* enable BAC and reset MUX */
- DUM_CTRL = V_BAC_ENABLE;
- udelay(1);
- DUM_CTRL = V_MUX_RESET;
- return 0;
-}
-
-static int __devinit sdum_probe(struct platform_device *pdev)
-{
- int ret = 0, i = 0;
-
- /* map frame buffer */
- dum_data.lcd_virt_start = (u32) dma_alloc_writecombine(&pdev->dev,
- FB_DMA_SIZE,
- &dum_data.lcd_phys_start,
- GFP_KERNEL);
-
- if (!dum_data.lcd_virt_start) {
- ret = -ENOMEM;
- goto out_3;
- }
-
- /* map slave registers */
- dum_data.slave_phys_base = PNX4008_DUM_SLAVE_BASE;
- dum_data.slave_virt_base =
- (u32 *) ioremap_nocache(dum_data.slave_phys_base, sizeof(u32));
-
- if (dum_data.slave_virt_base == NULL) {
- ret = -ENOMEM;
- goto out_2;
- }
-
- /* initialize DUM and LCD display */
- ret = dum_init(pdev);
- if (ret)
- goto out_1;
-
- dum_chan_init();
- lcd_init();
-
- DUM_CTRL = V_BAC_ENABLE;
- udelay(1);
- DUM_CTRL = V_MUX_RESET;
-
- /* set decode address and sync clock divider */
- DUM_DECODE = dum_data.lcd_phys_start & DUM_DECODE_MASK;
- DUM_CLK_DIV = PNX4008_DUM_CLK_DIV;
-
- for (i = 0; i < MAX_DUM_CHANNELS; i++)
- dum_data.fb_owning_channel[i] = -1;
-
- /*setup wakeup interrupt */
- start_int_set_rising_edge(SE_DISP_SYNC_INT);
- start_int_ack(SE_DISP_SYNC_INT);
- start_int_umask(SE_DISP_SYNC_INT);
-
- return 0;
-
-out_1:
- iounmap((void *)dum_data.slave_virt_base);
-out_2:
- dma_free_writecombine(&pdev->dev, FB_DMA_SIZE,
- (void *)dum_data.lcd_virt_start,
- dum_data.lcd_phys_start);
-out_3:
- return ret;
-}
-
-static int sdum_remove(struct platform_device *pdev)
-{
- struct clk *clk;
-
- start_int_mask(SE_DISP_SYNC_INT);
-
- clk = clk_get(0, "dum_ck");
- if (!IS_ERR(clk)) {
- clk_set_rate(clk, 0);
- clk_put(clk);
- }
-
- iounmap((void *)dum_data.slave_virt_base);
-
- dma_free_writecombine(&pdev->dev, FB_DMA_SIZE,
- (void *)dum_data.lcd_virt_start,
- dum_data.lcd_phys_start);
-
- return 0;
-}
-
-static struct platform_driver sdum_driver = {
- .driver = {
- .name = "pnx4008-sdum",
- },
- .probe = sdum_probe,
- .remove = sdum_remove,
- .suspend = sdum_suspend,
- .resume = sdum_resume,
-};
-
-module_platform_driver(sdum_driver);
-
-MODULE_LICENSE("GPL");
diff --git a/drivers/video/pnx4008/sdum.h b/drivers/video/pnx4008/sdum.h
deleted file mode 100644
index 189c3d6..0000000
--- a/drivers/video/pnx4008/sdum.h
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * Copyright (C) 2005 Philips Semiconductors
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING. If not, write to
- * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA, or http://www.gnu.org/licenses/gpl.html
-*/
-
-#define MAX_DUM_CHANNELS 64
-
-#define RGB_MEM_WINDOW(x) (0x10000000 + (x)*0x00100000)
-
-#define QCIF_OFFSET(x) (((x) == 0) ? 0x00000: ((x) == 1) ? 0x30000: -1)
-#define CIF_OFFSET(x) (((x) == 0) ? 0x00000: ((x) == 1) ? 0x60000: -1)
-
-#define CTRL_SETDIRTY (0x00000001)
-#define CONF_DIRTYENABLE (0x00000020)
-#define CONF_SYNCENABLE (0x00000004)
-
-#define DIRTY_ENABLED(conf) ((conf) & 0x0020)
-#define SYNC_ENABLED(conf) ((conf) & 0x0004)
-
-/* Display 1 & 2 Write Timing Configuration */
-#define PNX4008_DUM_WT_CFG 0x00372000
-
-/* Display 1 & 2 Read Timing Configuration */
-#define PNX4008_DUM_RT_CFG 0x00003A47
-
-/* DUM Transit State Timing Configuration */
-#define PNX4008_DUM_T_CFG 0x1D /* 29 HCLK cycles */
-
-/* DUM Sync count clock divider */
-#define PNX4008_DUM_CLK_DIV 0x02DD
-
-/* Memory size for framebuffer, allocated through dma_alloc_writecombine().
- * Must be PAGE aligned
- */
-#define FB_DMA_SIZE (PAGE_ALIGN(SZ_1M + PAGE_SIZE))
-
-#define OFFSET_RGBBUFFER (0xB0000)
-#define OFFSET_YUVBUFFER (0x00000)
-
-#define YUVBUFFER (lcd_video_start + OFFSET_YUVBUFFER)
-#define RGBBUFFER (lcd_video_start + OFFSET_RGBBUFFER)
-
-#define CMDSTRING_BASEADDR (0x00C000) /* iram */
-#define BYTES_PER_CMDSTRING (0x80)
-#define NR_OF_CMDSTRINGS (64)
-
-#define MAX_NR_PRESTRINGS (0x40)
-#define MAX_NR_POSTSTRINGS (0x40)
-
-/* various mask definitions */
-#define DUM_CLK_ENABLE 0x01
-#define DUM_CLK_DISABLE 0
-#define DUM_DECODE_MASK 0x1FFFFFFF
-#define DUM_CHANNEL_CFG_MASK 0x01FF
-#define DUM_CHANNEL_CFG_SYNC_MASK 0xFFFE00FF
-#define DUM_CHANNEL_CFG_SYNC_MASK_SET 0x0CA00
-
-#define SDUM_RETURNVAL_BASE (0x500)
-
-#define CONF_SYNC_OFF (0x602)
-#define CONF_SYNC_ON (0x603)
-
-#define CONF_DIRTYDETECTION_OFF (0x600)
-#define CONF_DIRTYDETECTION_ON (0x601)
-
-struct dumchannel_uf {
- int channelnr;
- u32 *dirty;
- u32 *source;
- u32 x_offset;
- u32 y_offset;
- u32 width;
- u32 height;
-};
-
-enum {
- FB_TYPE_YUV,
- FB_TYPE_RGB
-};
-
-struct cmdstring {
- int channelnr;
- uint16_t prestringlen;
- uint16_t poststringlen;
- uint16_t format;
- uint16_t reserved;
- uint16_t startaddr_low;
- uint16_t startaddr_high;
- uint16_t pixdatlen_low;
- uint16_t pixdatlen_high;
- u32 precmd[MAX_NR_PRESTRINGS];
- u32 postcmd[MAX_NR_POSTSTRINGS];
-
-};
-
-struct dumchannel {
- int channelnr;
- int dum_ch_min;
- int dum_ch_max;
- int dum_ch_conf;
- int dum_ch_stat;
- int dum_ch_ctrl;
-};
-
-int pnx4008_alloc_dum_channel(int dev_id);
-int pnx4008_free_dum_channel(int channr, int dev_id);
-
-int pnx4008_get_dum_channel_uf(struct dumchannel_uf *pChan_uf, int dev_id);
-int pnx4008_put_dum_channel_uf(struct dumchannel_uf chan_uf, int dev_id);
-
-int pnx4008_set_dum_channel_sync(int channr, int val, int dev_id);
-int pnx4008_set_dum_channel_dirty_detect(int channr, int val, int dev_id);
-
-int pnx4008_force_dum_update_channel(int channr, int dev_id);
-
-int pnx4008_get_dum_channel_config(int channr, int dev_id);
-
-int pnx4008_sdum_mmap(struct fb_info *info, struct vm_area_struct *vma, struct device *dev);
-int pnx4008_set_dum_exit_notification(int dev_id);
-
-int pnx4008_get_fb_addresses(int fb_type, void **virt_addr,
- dma_addr_t * phys_addr, int *fb_length);
diff --git a/drivers/video/ps3fb.c b/drivers/video/ps3fb.c
index 4e292f2..0b340d6 100644
--- a/drivers/video/ps3fb.c
+++ b/drivers/video/ps3fb.c
@@ -1034,6 +1034,7 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev)
if (status) {
dev_err(&dev->core, "%s: lv1_gpu_memory_allocate failed: %d\n",
__func__, status);
+ retval = -ENOMEM;
goto err_close_device;
}
dev_dbg(&dev->core, "ddr:lpar:0x%llx\n", ddr_lpar);
@@ -1046,6 +1047,7 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev)
dev_err(&dev->core,
"%s: lv1_gpu_context_allocate failed: %d\n", __func__,
status);
+ retval = -ENOMEM;
goto err_gpu_memory_free;
}
@@ -1053,6 +1055,7 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev)
dinfo = (void __force *)ioremap(lpar_driver_info, 128 * 1024);
if (!dinfo) {
dev_err(&dev->core, "%s: ioremap failed\n", __func__);
+ retval = -ENOMEM;
goto err_gpu_context_free;
}
@@ -1121,8 +1124,10 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev)
}
info = framebuffer_alloc(sizeof(struct ps3fb_par), &dev->core);
- if (!info)
+ if (!info) {
+ retval = -ENOMEM;
goto err_context_fb_close;
+ }
par = info->par;
par->mode_id = ~ps3fb_mode; /* != ps3fb_mode, to trigger change */
diff --git a/drivers/video/s3c-fb.c b/drivers/video/s3c-fb.c
index 69bf9d0..2ed7b63 100644
--- a/drivers/video/s3c-fb.c
+++ b/drivers/video/s3c-fb.c
@@ -25,8 +25,8 @@
#include <linux/interrupt.h>
#include <linux/pm_runtime.h>
+#include <video/samsung_fimd.h>
#include <mach/map.h>
-#include <plat/regs-fb-v4.h>
#include <plat/fb.h>
/* This driver will export a number of framebuffer interfaces depending
@@ -1398,35 +1398,28 @@ static int __devinit s3c_fb_probe(struct platform_device *pdev)
spin_lock_init(&sfb->slock);
- sfb->bus_clk = clk_get(dev, "lcd");
+ sfb->bus_clk = devm_clk_get(dev, "lcd");
if (IS_ERR(sfb->bus_clk)) {
dev_err(dev, "failed to get bus clock\n");
- ret = PTR_ERR(sfb->bus_clk);
- goto err_sfb;
+ return PTR_ERR(sfb->bus_clk);
}
- clk_enable(sfb->bus_clk);
+ clk_prepare_enable(sfb->bus_clk);
if (!sfb->variant.has_clksel) {
- sfb->lcd_clk = clk_get(dev, "sclk_fimd");
+ sfb->lcd_clk = devm_clk_get(dev, "sclk_fimd");
if (IS_ERR(sfb->lcd_clk)) {
dev_err(dev, "failed to get lcd clock\n");
ret = PTR_ERR(sfb->lcd_clk);
goto err_bus_clk;
}
- clk_enable(sfb->lcd_clk);
+ clk_prepare_enable(sfb->lcd_clk);
}
pm_runtime_enable(sfb->dev);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(dev, "failed to find registers\n");
- ret = -ENOENT;
- goto err_lcd_clk;
- }
-
sfb->regs = devm_request_and_ioremap(dev, res);
if (!sfb->regs) {
dev_err(dev, "failed to map registers\n");
@@ -1510,16 +1503,12 @@ err_pm_runtime:
err_lcd_clk:
pm_runtime_disable(sfb->dev);
- if (!sfb->variant.has_clksel) {
- clk_disable(sfb->lcd_clk);
- clk_put(sfb->lcd_clk);
- }
+ if (!sfb->variant.has_clksel)
+ clk_disable_unprepare(sfb->lcd_clk);
err_bus_clk:
- clk_disable(sfb->bus_clk);
- clk_put(sfb->bus_clk);
+ clk_disable_unprepare(sfb->bus_clk);
-err_sfb:
return ret;
}
@@ -1541,13 +1530,10 @@ static int __devexit s3c_fb_remove(struct platform_device *pdev)
if (sfb->windows[win])
s3c_fb_release_win(sfb, sfb->windows[win]);
- if (!sfb->variant.has_clksel) {
- clk_disable(sfb->lcd_clk);
- clk_put(sfb->lcd_clk);
- }
+ if (!sfb->variant.has_clksel)
+ clk_disable_unprepare(sfb->lcd_clk);
- clk_disable(sfb->bus_clk);
- clk_put(sfb->bus_clk);
+ clk_disable_unprepare(sfb->bus_clk);
pm_runtime_put_sync(sfb->dev);
pm_runtime_disable(sfb->dev);
@@ -1575,9 +1561,9 @@ static int s3c_fb_suspend(struct device *dev)
}
if (!sfb->variant.has_clksel)
- clk_disable(sfb->lcd_clk);
+ clk_disable_unprepare(sfb->lcd_clk);
- clk_disable(sfb->bus_clk);
+ clk_disable_unprepare(sfb->bus_clk);
pm_runtime_put_sync(sfb->dev);
@@ -1595,10 +1581,10 @@ static int s3c_fb_resume(struct device *dev)
pm_runtime_get_sync(sfb->dev);
- clk_enable(sfb->bus_clk);
+ clk_prepare_enable(sfb->bus_clk);
if (!sfb->variant.has_clksel)
- clk_enable(sfb->lcd_clk);
+ clk_prepare_enable(sfb->lcd_clk);
/* setup gpio and output polarity controls */
pd->setup_gpio();
@@ -1654,9 +1640,9 @@ static int s3c_fb_runtime_suspend(struct device *dev)
struct s3c_fb *sfb = platform_get_drvdata(pdev);
if (!sfb->variant.has_clksel)
- clk_disable(sfb->lcd_clk);
+ clk_disable_unprepare(sfb->lcd_clk);
- clk_disable(sfb->bus_clk);
+ clk_disable_unprepare(sfb->bus_clk);
return 0;
}
@@ -1667,10 +1653,10 @@ static int s3c_fb_runtime_resume(struct device *dev)
struct s3c_fb *sfb = platform_get_drvdata(pdev);
struct s3c_fb_platdata *pd = sfb->pdata;
- clk_enable(sfb->bus_clk);
+ clk_prepare_enable(sfb->bus_clk);
if (!sfb->variant.has_clksel)
- clk_enable(sfb->lcd_clk);
+ clk_prepare_enable(sfb->lcd_clk);
/* setup gpio and output polarity controls */
pd->setup_gpio();
diff --git a/drivers/video/s3c2410fb.c b/drivers/video/s3c2410fb.c
index 77f34c6..1083bb9 100644
--- a/drivers/video/s3c2410fb.c
+++ b/drivers/video/s3c2410fb.c
@@ -11,6 +11,8 @@
* Driver based on skeletonfb.c, sa1100fb.c and others.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/err.h>
@@ -48,7 +50,11 @@ static int debug = 1;
static int debug;
#endif
-#define dprintk(msg...) if (debug) printk(KERN_DEBUG "s3c2410fb: " msg);
+#define dprintk(msg...) \
+do { \
+ if (debug) \
+ pr_debug(msg); \
+} while (0)
/* useful functions */
@@ -598,11 +604,11 @@ static int s3c2410fb_debug_store(struct device *dev,
if (strnicmp(buf, "on", 2) == 0 ||
strnicmp(buf, "1", 1) == 0) {
debug = 1;
- printk(KERN_DEBUG "s3c2410fb: Debug On");
+ dev_dbg(dev, "s3c2410fb: Debug On");
} else if (strnicmp(buf, "off", 3) == 0 ||
strnicmp(buf, "0", 1) == 0) {
debug = 0;
- printk(KERN_DEBUG "s3c2410fb: Debug Off");
+ dev_dbg(dev, "s3c2410fb: Debug Off");
} else {
return -EINVAL;
}
@@ -921,7 +927,7 @@ static int __devinit s3c24xxfb_probe(struct platform_device *pdev,
info->clk = clk_get(NULL, "lcd");
if (IS_ERR(info->clk)) {
- printk(KERN_ERR "failed to get lcd clock source\n");
+ dev_err(&pdev->dev, "failed to get lcd clock source\n");
ret = PTR_ERR(info->clk);
goto release_irq;
}
@@ -929,7 +935,7 @@ static int __devinit s3c24xxfb_probe(struct platform_device *pdev,
clk_enable(info->clk);
dprintk("got and enabled clock\n");
- usleep_range(1000, 1000);
+ usleep_range(1000, 1100);
info->clk_rate = clk_get_rate(info->clk);
@@ -947,7 +953,7 @@ static int __devinit s3c24xxfb_probe(struct platform_device *pdev,
/* Initialize video memory */
ret = s3c2410fb_map_video_memory(fbinfo);
if (ret) {
- printk(KERN_ERR "Failed to allocate video RAM: %d\n", ret);
+ dev_err(&pdev->dev, "Failed to allocate video RAM: %d\n", ret);
ret = -ENOMEM;
goto release_clock;
}
@@ -970,7 +976,7 @@ static int __devinit s3c24xxfb_probe(struct platform_device *pdev,
ret = register_framebuffer(fbinfo);
if (ret < 0) {
- printk(KERN_ERR "Failed to register framebuffer device: %d\n",
+ dev_err(&pdev->dev, "Failed to register framebuffer device: %d\n",
ret);
goto free_cpufreq;
}
@@ -978,9 +984,9 @@ static int __devinit s3c24xxfb_probe(struct platform_device *pdev,
/* create device files */
ret = device_create_file(&pdev->dev, &dev_attr_debug);
if (ret)
- printk(KERN_ERR "failed to add debug attribute\n");
+ dev_err(&pdev->dev, "failed to add debug attribute\n");
- printk(KERN_INFO "fb%d: %s frame buffer device\n",
+ dev_info(&pdev->dev, "fb%d: %s frame buffer device\n",
fbinfo->node, fbinfo->fix.id);
return 0;
@@ -1028,7 +1034,7 @@ static int __devexit s3c2410fb_remove(struct platform_device *pdev)
s3c2410fb_cpufreq_deregister(info);
s3c2410fb_lcd_enable(info, 0);
- usleep_range(1000, 1000);
+ usleep_range(1000, 1100);
s3c2410fb_unmap_video_memory(fbinfo);
@@ -1065,7 +1071,7 @@ static int s3c2410fb_suspend(struct platform_device *dev, pm_message_t state)
* the LCD DMA engine is not going to get back on the bus
* before the clock goes off again (bjd) */
- usleep_range(1000, 1000);
+ usleep_range(1000, 1100);
clk_disable(info->clk);
return 0;
@@ -1077,7 +1083,7 @@ static int s3c2410fb_resume(struct platform_device *dev)
struct s3c2410fb_info *info = fbinfo->par;
clk_enable(info->clk);
- usleep_range(1000, 1000);
+ usleep_range(1000, 1100);
s3c2410fb_init_registers(fbinfo);
@@ -1134,8 +1140,8 @@ static void __exit s3c2410fb_cleanup(void)
module_init(s3c2410fb_init);
module_exit(s3c2410fb_cleanup);
-MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>, "
- "Ben Dooks <ben-linux@fluff.org>");
+MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>");
+MODULE_AUTHOR("Ben Dooks <ben-linux@fluff.org>");
MODULE_DESCRIPTION("Framebuffer driver for the s3c2410");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:s3c2410-lcd");
diff --git a/drivers/video/savage/savagefb_driver.c b/drivers/video/savage/savagefb_driver.c
index 0d0f52c..f4f53b0 100644
--- a/drivers/video/savage/savagefb_driver.c
+++ b/drivers/video/savage/savagefb_driver.c
@@ -2266,8 +2266,10 @@ static int __devinit savagefb_probe(struct pci_dev* dev,
lpitch = info->var.xres_virtual*((info->var.bits_per_pixel + 7) >> 3);
info->var.yres_virtual = info->fix.smem_len/lpitch;
- if (info->var.yres_virtual < info->var.yres)
+ if (info->var.yres_virtual < info->var.yres) {
+ err = -ENOMEM;
goto failed;
+ }
#if defined(CONFIG_FB_SAVAGE_ACCEL)
/*
diff --git a/drivers/video/sis/initextlfb.c b/drivers/video/sis/initextlfb.c
index 9dec64d..3ab18f5 100644
--- a/drivers/video/sis/initextlfb.c
+++ b/drivers/video/sis/initextlfb.c
@@ -65,7 +65,7 @@ sisfb_mode_rate_to_dclock(struct SiS_Private *SiS_Pr, unsigned char modeno,
}
#endif
- if(!(SiS_SearchModeID(SiS_Pr, &ModeNo, &ModeIdIndex))) {;
+ if(!(SiS_SearchModeID(SiS_Pr, &ModeNo, &ModeIdIndex))) {
printk(KERN_ERR "Could not find mode %x\n", ModeNo);
return 65000;
}
diff --git a/drivers/video/sunxvr1000.c b/drivers/video/sunxvr1000.c
index b7f27ac..729a507 100644
--- a/drivers/video/sunxvr1000.c
+++ b/drivers/video/sunxvr1000.c
@@ -141,8 +141,10 @@ static int __devinit gfb_probe(struct platform_device *op)
gp->fb_base = of_ioremap(&op->resource[6], 0,
gp->fb_size, "gfb fb");
- if (!gp->fb_base)
+ if (!gp->fb_base) {
+ err = -ENOMEM;
goto err_release_fb;
+ }
err = gfb_set_fbinfo(gp);
if (err)
diff --git a/drivers/video/sunxvr2500.c b/drivers/video/sunxvr2500.c
index 5848436..7fbcba8 100644
--- a/drivers/video/sunxvr2500.c
+++ b/drivers/video/sunxvr2500.c
@@ -181,8 +181,10 @@ static int __devinit s3d_pci_register(struct pci_dev *pdev,
sp->fb_size = info->fix.line_length * sp->height;
sp->fb_base = ioremap(sp->fb_base_phys, sp->fb_size);
- if (!sp->fb_base)
+ if (!sp->fb_base) {
+ err = -ENOMEM;
goto err_release_pci;
+ }
err = s3d_set_fbinfo(sp);
if (err)
diff --git a/drivers/video/sunxvr500.c b/drivers/video/sunxvr500.c
index eb931b8..6c71b1b 100644
--- a/drivers/video/sunxvr500.c
+++ b/drivers/video/sunxvr500.c
@@ -298,8 +298,10 @@ static int __devinit e3d_pci_register(struct pci_dev *pdev,
goto err_release_fb;
}
ep->ramdac = ioremap(ep->regs_base_phys + 0x8000, 0x1000);
- if (!ep->ramdac)
+ if (!ep->ramdac) {
+ err = -ENOMEM;
goto err_release_pci1;
+ }
ep->fb8_0_off = readl(ep->ramdac + RAMDAC_VID_8FB_0);
ep->fb8_0_off -= ep->fb_base_reg;
@@ -343,8 +345,10 @@ static int __devinit e3d_pci_register(struct pci_dev *pdev,
ep->fb_size = info->fix.line_length * ep->height;
ep->fb_base = ioremap(ep->fb_base_phys, ep->fb_size);
- if (!ep->fb_base)
+ if (!ep->fb_base) {
+ err = -ENOMEM;
goto err_release_pci0;
+ }
err = e3d_set_fbinfo(ep);
if (err)
diff --git a/drivers/video/udlfb.c b/drivers/video/udlfb.c
index f45eba3..86d449e 100644
--- a/drivers/video/udlfb.c
+++ b/drivers/video/udlfb.c
@@ -646,7 +646,7 @@ static ssize_t dlfb_ops_write(struct fb_info *info, const char __user *buf,
result = fb_sys_write(info, buf, count, ppos);
if (result > 0) {
- int start = max((int)(offset / info->fix.line_length) - 1, 0);
+ int start = max((int)(offset / info->fix.line_length), 0);
int lines = min((u32)((result / info->fix.line_length) + 1),
(u32)info->var.yres);
diff --git a/drivers/video/uvesafb.c b/drivers/video/uvesafb.c
index b0e2a42..2f8f82d 100644
--- a/drivers/video/uvesafb.c
+++ b/drivers/video/uvesafb.c
@@ -659,6 +659,8 @@ static int __devinit uvesafb_vbe_getedid(struct uvesafb_ktask *task,
task->t.flags = TF_BUF_RET | TF_BUF_ESDI;
task->t.buf_len = EDID_LENGTH;
task->buf = kzalloc(EDID_LENGTH, GFP_KERNEL);
+ if (!task->buf)
+ return -ENOMEM;
err = uvesafb_exec(task);
diff --git a/drivers/video/vermilion/vermilion.c b/drivers/video/vermilion/vermilion.c
index 89aef34..4709edc 100644
--- a/drivers/video/vermilion/vermilion.c
+++ b/drivers/video/vermilion/vermilion.c
@@ -1167,8 +1167,7 @@ void vmlfb_unregister_subsys(struct vml_sys *sys)
list_for_each_entry_safe(entry, next, &global_has_mode, head) {
printk(KERN_DEBUG MODULE_NAME ": subsys disable pipe\n");
vmlfb_disable_pipe(entry);
- list_del(&entry->head);
- list_add_tail(&entry->head, &global_no_mode);
+ list_move_tail(&entry->head, &global_no_mode);
}
mutex_unlock(&vml_mutex);
}
diff --git a/drivers/video/via/via_clock.c b/drivers/video/via/via_clock.c
index af8f26b..db1e392 100644
--- a/drivers/video/via/via_clock.c
+++ b/drivers/video/via/via_clock.c
@@ -25,6 +25,7 @@
#include <linux/kernel.h>
#include <linux/via-core.h>
+#include <asm/olpc.h>
#include "via_clock.h"
#include "global.h"
#include "debug.h"
@@ -289,6 +290,10 @@ static void dummy_set_pll(struct via_pll_config config)
printk(KERN_INFO "Using undocumented set PLL.\n%s", via_slap);
}
+static void noop_set_clock_state(u8 state)
+{
+}
+
void via_clock_init(struct via_clock *clock, int gfx_chip)
{
switch (gfx_chip) {
@@ -346,4 +351,18 @@ void via_clock_init(struct via_clock *clock, int gfx_chip)
break;
}
+
+ if (machine_is_olpc()) {
+ /* The OLPC XO-1.5 cannot suspend/resume reliably if the
+ * IGA1/IGA2 clocks are set as on or off (memory rot
+ * occasionally happens during suspend under such
+ * configurations).
+ *
+ * The only known stable scenario is to leave this bits as-is,
+ * which in their default states are documented to enable the
+ * clock only when it is needed.
+ */
+ clock->set_primary_clock_state = noop_set_clock_state;
+ clock->set_secondary_clock_state = noop_set_clock_state;
+ }
}
diff --git a/fs/9p/v9fs.c b/fs/9p/v9fs.c
index 392c5da..d934f04e7 100644
--- a/fs/9p/v9fs.c
+++ b/fs/9p/v9fs.c
@@ -184,10 +184,20 @@ static int v9fs_parse_options(struct v9fs_session_info *v9ses, char *opts)
v9ses->afid = option;
break;
case Opt_uname:
- match_strlcpy(v9ses->uname, &args[0], PATH_MAX);
+ kfree(v9ses->uname);
+ v9ses->uname = match_strdup(&args[0]);
+ if (!v9ses->uname) {
+ ret = -ENOMEM;
+ goto free_and_return;
+ }
break;
case Opt_remotename:
- match_strlcpy(v9ses->aname, &args[0], PATH_MAX);
+ kfree(v9ses->aname);
+ v9ses->aname = match_strdup(&args[0]);
+ if (!v9ses->aname) {
+ ret = -ENOMEM;
+ goto free_and_return;
+ }
break;
case Opt_nodevmap:
v9ses->nodev = 1;
@@ -287,21 +297,21 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses,
struct p9_fid *fid;
int rc;
- v9ses->uname = __getname();
+ v9ses->uname = kstrdup(V9FS_DEFUSER, GFP_KERNEL);
if (!v9ses->uname)
return ERR_PTR(-ENOMEM);
- v9ses->aname = __getname();
+ v9ses->aname = kstrdup(V9FS_DEFANAME, GFP_KERNEL);
if (!v9ses->aname) {
- __putname(v9ses->uname);
+ kfree(v9ses->uname);
return ERR_PTR(-ENOMEM);
}
init_rwsem(&v9ses->rename_sem);
rc = bdi_setup_and_register(&v9ses->bdi, "9p", BDI_CAP_MAP_COPY);
if (rc) {
- __putname(v9ses->aname);
- __putname(v9ses->uname);
+ kfree(v9ses->aname);
+ kfree(v9ses->uname);
return ERR_PTR(rc);
}
@@ -309,8 +319,6 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses,
list_add(&v9ses->slist, &v9fs_sessionlist);
spin_unlock(&v9fs_sessionlist_lock);
- strcpy(v9ses->uname, V9FS_DEFUSER);
- strcpy(v9ses->aname, V9FS_DEFANAME);
v9ses->uid = ~0;
v9ses->dfltuid = V9FS_DEFUID;
v9ses->dfltgid = V9FS_DEFGID;
@@ -412,8 +420,8 @@ void v9fs_session_close(struct v9fs_session_info *v9ses)
kfree(v9ses->cachetag);
}
#endif
- __putname(v9ses->uname);
- __putname(v9ses->aname);
+ kfree(v9ses->uname);
+ kfree(v9ses->aname);
bdi_destroy(&v9ses->bdi);
diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c
index cbf9dbb..890bed5 100644
--- a/fs/9p/vfs_inode.c
+++ b/fs/9p/vfs_inode.c
@@ -1276,12 +1276,12 @@ static int v9fs_readlink(struct dentry *dentry, char *buffer, int buflen)
}
/* copy extension buffer into buffer */
- strncpy(buffer, st->extension, buflen);
+ retval = min(strlen(st->extension)+1, (size_t)buflen);
+ memcpy(buffer, st->extension, retval);
- p9_debug(P9_DEBUG_VFS, "%s -> %s (%s)\n",
- dentry->d_name.name, st->extension, buffer);
+ p9_debug(P9_DEBUG_VFS, "%s -> %s (%.*s)\n",
+ dentry->d_name.name, st->extension, buflen, buffer);
- retval = strnlen(buffer, buflen);
done:
p9stat_free(st);
kfree(st);
diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c
index e7396cf..91b1165 100644
--- a/fs/autofs4/root.c
+++ b/fs/autofs4/root.c
@@ -392,10 +392,12 @@ static struct vfsmount *autofs4_d_automount(struct path *path)
ino->flags |= AUTOFS_INF_PENDING;
spin_unlock(&sbi->fs_lock);
status = autofs4_mount_wait(dentry);
- if (status)
- return ERR_PTR(status);
spin_lock(&sbi->fs_lock);
ino->flags &= ~AUTOFS_INF_PENDING;
+ if (status) {
+ spin_unlock(&sbi->fs_lock);
+ return ERR_PTR(status);
+ }
}
done:
if (!(ino->flags & AUTOFS_INF_EXPIRING)) {
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index e800dec..fbd9f60 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -36,7 +36,6 @@
#include <asm/uaccess.h>
#include <asm/param.h>
#include <asm/page.h>
-#include <asm/exec.h>
#ifndef user_long_t
#define user_long_t long
diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c
index 262db11..a460491 100644
--- a/fs/binfmt_elf_fdpic.c
+++ b/fs/binfmt_elf_fdpic.c
@@ -39,7 +39,6 @@
#include <asm/uaccess.h>
#include <asm/param.h>
#include <asm/pgalloc.h>
-#include <asm/exec.h>
typedef char *elf_caddr_t;
diff --git a/fs/bio-integrity.c b/fs/bio-integrity.c
index e85c04b..a3f28f3 100644
--- a/fs/bio-integrity.c
+++ b/fs/bio-integrity.c
@@ -70,23 +70,25 @@ static inline int use_bip_pool(unsigned int idx)
}
/**
- * bio_integrity_alloc_bioset - Allocate integrity payload and attach it to bio
+ * bio_integrity_alloc - Allocate integrity payload and attach it to bio
* @bio: bio to attach integrity metadata to
* @gfp_mask: Memory allocation mask
* @nr_vecs: Number of integrity metadata scatter-gather elements
- * @bs: bio_set to allocate from
*
* Description: This function prepares a bio for attaching integrity
* metadata. nr_vecs specifies the maximum number of pages containing
* integrity metadata that can be attached.
*/
-struct bio_integrity_payload *bio_integrity_alloc_bioset(struct bio *bio,
- gfp_t gfp_mask,
- unsigned int nr_vecs,
- struct bio_set *bs)
+struct bio_integrity_payload *bio_integrity_alloc(struct bio *bio,
+ gfp_t gfp_mask,
+ unsigned int nr_vecs)
{
struct bio_integrity_payload *bip;
unsigned int idx = vecs_to_idx(nr_vecs);
+ struct bio_set *bs = bio->bi_pool;
+
+ if (!bs)
+ bs = fs_bio_set;
BUG_ON(bio == NULL);
bip = NULL;
@@ -114,37 +116,22 @@ struct bio_integrity_payload *bio_integrity_alloc_bioset(struct bio *bio,
return bip;
}
-EXPORT_SYMBOL(bio_integrity_alloc_bioset);
-
-/**
- * bio_integrity_alloc - Allocate integrity payload and attach it to bio
- * @bio: bio to attach integrity metadata to
- * @gfp_mask: Memory allocation mask
- * @nr_vecs: Number of integrity metadata scatter-gather elements
- *
- * Description: This function prepares a bio for attaching integrity
- * metadata. nr_vecs specifies the maximum number of pages containing
- * integrity metadata that can be attached.
- */
-struct bio_integrity_payload *bio_integrity_alloc(struct bio *bio,
- gfp_t gfp_mask,
- unsigned int nr_vecs)
-{
- return bio_integrity_alloc_bioset(bio, gfp_mask, nr_vecs, fs_bio_set);
-}
EXPORT_SYMBOL(bio_integrity_alloc);
/**
* bio_integrity_free - Free bio integrity payload
* @bio: bio containing bip to be freed
- * @bs: bio_set this bio was allocated from
*
* Description: Used to free the integrity portion of a bio. Usually
* called from bio_free().
*/
-void bio_integrity_free(struct bio *bio, struct bio_set *bs)
+void bio_integrity_free(struct bio *bio)
{
struct bio_integrity_payload *bip = bio->bi_integrity;
+ struct bio_set *bs = bio->bi_pool;
+
+ if (!bs)
+ bs = fs_bio_set;
BUG_ON(bip == NULL);
@@ -730,19 +717,18 @@ EXPORT_SYMBOL(bio_integrity_split);
* @bio: New bio
* @bio_src: Original bio
* @gfp_mask: Memory allocation mask
- * @bs: bio_set to allocate bip from
*
* Description: Called to allocate a bip when cloning a bio
*/
int bio_integrity_clone(struct bio *bio, struct bio *bio_src,
- gfp_t gfp_mask, struct bio_set *bs)
+ gfp_t gfp_mask)
{
struct bio_integrity_payload *bip_src = bio_src->bi_integrity;
struct bio_integrity_payload *bip;
BUG_ON(bip_src == NULL);
- bip = bio_integrity_alloc_bioset(bio, gfp_mask, bip_src->bip_vcnt, bs);
+ bip = bio_integrity_alloc(bio, gfp_mask, bip_src->bip_vcnt);
if (bip == NULL)
return -EIO;
diff --git a/fs/bio.c b/fs/bio.c
index 71072ab..9298c65 100644
--- a/fs/bio.c
+++ b/fs/bio.c
@@ -55,6 +55,7 @@ static struct biovec_slab bvec_slabs[BIOVEC_NR_POOLS] __read_mostly = {
* IO code that does not need private memory pools.
*/
struct bio_set *fs_bio_set;
+EXPORT_SYMBOL(fs_bio_set);
/*
* Our slab pool management
@@ -233,26 +234,37 @@ fallback:
return bvl;
}
-void bio_free(struct bio *bio, struct bio_set *bs)
+static void __bio_free(struct bio *bio)
{
+ bio_disassociate_task(bio);
+
+ if (bio_integrity(bio))
+ bio_integrity_free(bio);
+}
+
+static void bio_free(struct bio *bio)
+{
+ struct bio_set *bs = bio->bi_pool;
void *p;
- if (bio_has_allocated_vec(bio))
- bvec_free_bs(bs, bio->bi_io_vec, BIO_POOL_IDX(bio));
+ __bio_free(bio);
- if (bio_integrity(bio))
- bio_integrity_free(bio, bs);
+ if (bs) {
+ if (bio_has_allocated_vec(bio))
+ bvec_free_bs(bs, bio->bi_io_vec, BIO_POOL_IDX(bio));
- /*
- * If we have front padding, adjust the bio pointer before freeing
- */
- p = bio;
- if (bs->front_pad)
+ /*
+ * If we have front padding, adjust the bio pointer before freeing
+ */
+ p = bio;
p -= bs->front_pad;
- mempool_free(p, bs->bio_pool);
+ mempool_free(p, bs->bio_pool);
+ } else {
+ /* Bio was allocated by bio_kmalloc() */
+ kfree(bio);
+ }
}
-EXPORT_SYMBOL(bio_free);
void bio_init(struct bio *bio)
{
@@ -263,48 +275,85 @@ void bio_init(struct bio *bio)
EXPORT_SYMBOL(bio_init);
/**
+ * bio_reset - reinitialize a bio
+ * @bio: bio to reset
+ *
+ * Description:
+ * After calling bio_reset(), @bio will be in the same state as a freshly
+ * allocated bio returned bio bio_alloc_bioset() - the only fields that are
+ * preserved are the ones that are initialized by bio_alloc_bioset(). See
+ * comment in struct bio.
+ */
+void bio_reset(struct bio *bio)
+{
+ unsigned long flags = bio->bi_flags & (~0UL << BIO_RESET_BITS);
+
+ __bio_free(bio);
+
+ memset(bio, 0, BIO_RESET_BYTES);
+ bio->bi_flags = flags|(1 << BIO_UPTODATE);
+}
+EXPORT_SYMBOL(bio_reset);
+
+/**
* bio_alloc_bioset - allocate a bio for I/O
* @gfp_mask: the GFP_ mask given to the slab allocator
* @nr_iovecs: number of iovecs to pre-allocate
* @bs: the bio_set to allocate from.
*
* Description:
- * bio_alloc_bioset will try its own mempool to satisfy the allocation.
- * If %__GFP_WAIT is set then we will block on the internal pool waiting
- * for a &struct bio to become free.
+ * If @bs is NULL, uses kmalloc() to allocate the bio; else the allocation is
+ * backed by the @bs's mempool.
*
- * Note that the caller must set ->bi_destructor on successful return
- * of a bio, to do the appropriate freeing of the bio once the reference
- * count drops to zero.
- **/
+ * When @bs is not NULL, if %__GFP_WAIT is set then bio_alloc will always be
+ * able to allocate a bio. This is due to the mempool guarantees. To make this
+ * work, callers must never allocate more than 1 bio at a time from this pool.
+ * Callers that need to allocate more than 1 bio must always submit the
+ * previously allocated bio for IO before attempting to allocate a new one.
+ * Failure to do so can cause deadlocks under memory pressure.
+ *
+ * RETURNS:
+ * Pointer to new bio on success, NULL on failure.
+ */
struct bio *bio_alloc_bioset(gfp_t gfp_mask, int nr_iovecs, struct bio_set *bs)
{
+ unsigned front_pad;
+ unsigned inline_vecs;
unsigned long idx = BIO_POOL_NONE;
struct bio_vec *bvl = NULL;
struct bio *bio;
void *p;
- p = mempool_alloc(bs->bio_pool, gfp_mask);
+ if (!bs) {
+ if (nr_iovecs > UIO_MAXIOV)
+ return NULL;
+
+ p = kmalloc(sizeof(struct bio) +
+ nr_iovecs * sizeof(struct bio_vec),
+ gfp_mask);
+ front_pad = 0;
+ inline_vecs = nr_iovecs;
+ } else {
+ p = mempool_alloc(bs->bio_pool, gfp_mask);
+ front_pad = bs->front_pad;
+ inline_vecs = BIO_INLINE_VECS;
+ }
+
if (unlikely(!p))
return NULL;
- bio = p + bs->front_pad;
+ bio = p + front_pad;
bio_init(bio);
- if (unlikely(!nr_iovecs))
- goto out_set;
-
- if (nr_iovecs <= BIO_INLINE_VECS) {
- bvl = bio->bi_inline_vecs;
- nr_iovecs = BIO_INLINE_VECS;
- } else {
+ if (nr_iovecs > inline_vecs) {
bvl = bvec_alloc_bs(gfp_mask, nr_iovecs, &idx, bs);
if (unlikely(!bvl))
goto err_free;
-
- nr_iovecs = bvec_nr_vecs(idx);
+ } else if (nr_iovecs) {
+ bvl = bio->bi_inline_vecs;
}
-out_set:
+
+ bio->bi_pool = bs;
bio->bi_flags |= idx << BIO_POOL_OFFSET;
bio->bi_max_vecs = nr_iovecs;
bio->bi_io_vec = bvl;
@@ -316,80 +365,6 @@ err_free:
}
EXPORT_SYMBOL(bio_alloc_bioset);
-static void bio_fs_destructor(struct bio *bio)
-{
- bio_free(bio, fs_bio_set);
-}
-
-/**
- * bio_alloc - allocate a new bio, memory pool backed
- * @gfp_mask: allocation mask to use
- * @nr_iovecs: number of iovecs
- *
- * bio_alloc will allocate a bio and associated bio_vec array that can hold
- * at least @nr_iovecs entries. Allocations will be done from the
- * fs_bio_set. Also see @bio_alloc_bioset and @bio_kmalloc.
- *
- * If %__GFP_WAIT is set, then bio_alloc will always be able to allocate
- * a bio. This is due to the mempool guarantees. To make this work, callers
- * must never allocate more than 1 bio at a time from this pool. Callers
- * that need to allocate more than 1 bio must always submit the previously
- * allocated bio for IO before attempting to allocate a new one. Failure to
- * do so can cause livelocks under memory pressure.
- *
- * RETURNS:
- * Pointer to new bio on success, NULL on failure.
- */
-struct bio *bio_alloc(gfp_t gfp_mask, unsigned int nr_iovecs)
-{
- struct bio *bio = bio_alloc_bioset(gfp_mask, nr_iovecs, fs_bio_set);
-
- if (bio)
- bio->bi_destructor = bio_fs_destructor;
-
- return bio;
-}
-EXPORT_SYMBOL(bio_alloc);
-
-static void bio_kmalloc_destructor(struct bio *bio)
-{
- if (bio_integrity(bio))
- bio_integrity_free(bio, fs_bio_set);
- kfree(bio);
-}
-
-/**
- * bio_kmalloc - allocate a bio for I/O using kmalloc()
- * @gfp_mask: the GFP_ mask given to the slab allocator
- * @nr_iovecs: number of iovecs to pre-allocate
- *
- * Description:
- * Allocate a new bio with @nr_iovecs bvecs. If @gfp_mask contains
- * %__GFP_WAIT, the allocation is guaranteed to succeed.
- *
- **/
-struct bio *bio_kmalloc(gfp_t gfp_mask, unsigned int nr_iovecs)
-{
- struct bio *bio;
-
- if (nr_iovecs > UIO_MAXIOV)
- return NULL;
-
- bio = kmalloc(sizeof(struct bio) + nr_iovecs * sizeof(struct bio_vec),
- gfp_mask);
- if (unlikely(!bio))
- return NULL;
-
- bio_init(bio);
- bio->bi_flags |= BIO_POOL_NONE << BIO_POOL_OFFSET;
- bio->bi_max_vecs = nr_iovecs;
- bio->bi_io_vec = bio->bi_inline_vecs;
- bio->bi_destructor = bio_kmalloc_destructor;
-
- return bio;
-}
-EXPORT_SYMBOL(bio_kmalloc);
-
void zero_fill_bio(struct bio *bio)
{
unsigned long flags;
@@ -420,11 +395,8 @@ void bio_put(struct bio *bio)
/*
* last put frees it
*/
- if (atomic_dec_and_test(&bio->bi_cnt)) {
- bio_disassociate_task(bio);
- bio->bi_next = NULL;
- bio->bi_destructor(bio);
- }
+ if (atomic_dec_and_test(&bio->bi_cnt))
+ bio_free(bio);
}
EXPORT_SYMBOL(bio_put);
@@ -466,26 +438,28 @@ void __bio_clone(struct bio *bio, struct bio *bio_src)
EXPORT_SYMBOL(__bio_clone);
/**
- * bio_clone - clone a bio
+ * bio_clone_bioset - clone a bio
* @bio: bio to clone
* @gfp_mask: allocation priority
+ * @bs: bio_set to allocate from
*
* Like __bio_clone, only also allocates the returned bio
*/
-struct bio *bio_clone(struct bio *bio, gfp_t gfp_mask)
+struct bio *bio_clone_bioset(struct bio *bio, gfp_t gfp_mask,
+ struct bio_set *bs)
{
- struct bio *b = bio_alloc_bioset(gfp_mask, bio->bi_max_vecs, fs_bio_set);
+ struct bio *b;
+ b = bio_alloc_bioset(gfp_mask, bio->bi_max_vecs, bs);
if (!b)
return NULL;
- b->bi_destructor = bio_fs_destructor;
__bio_clone(b, bio);
if (bio_integrity(bio)) {
int ret;
- ret = bio_integrity_clone(b, bio, gfp_mask, fs_bio_set);
+ ret = bio_integrity_clone(b, bio, gfp_mask);
if (ret < 0) {
bio_put(b);
@@ -495,7 +469,7 @@ struct bio *bio_clone(struct bio *bio, gfp_t gfp_mask)
return b;
}
-EXPORT_SYMBOL(bio_clone);
+EXPORT_SYMBOL(bio_clone_bioset);
/**
* bio_get_nr_vecs - return approx number of vecs
@@ -1501,7 +1475,7 @@ struct bio_pair *bio_split(struct bio *bi, int first_sectors)
trace_block_split(bdev_get_queue(bi->bi_bdev), bi,
bi->bi_sector + first_sectors);
- BUG_ON(bi->bi_vcnt != 1);
+ BUG_ON(bi->bi_vcnt != 1 && bi->bi_vcnt != 0);
BUG_ON(bi->bi_idx != 0);
atomic_set(&bp->cnt, 3);
bp->error = 0;
@@ -1511,17 +1485,22 @@ struct bio_pair *bio_split(struct bio *bi, int first_sectors)
bp->bio2.bi_size -= first_sectors << 9;
bp->bio1.bi_size = first_sectors << 9;
- bp->bv1 = bi->bi_io_vec[0];
- bp->bv2 = bi->bi_io_vec[0];
- bp->bv2.bv_offset += first_sectors << 9;
- bp->bv2.bv_len -= first_sectors << 9;
- bp->bv1.bv_len = first_sectors << 9;
+ if (bi->bi_vcnt != 0) {
+ bp->bv1 = bi->bi_io_vec[0];
+ bp->bv2 = bi->bi_io_vec[0];
+
+ if (bio_is_rw(bi)) {
+ bp->bv2.bv_offset += first_sectors << 9;
+ bp->bv2.bv_len -= first_sectors << 9;
+ bp->bv1.bv_len = first_sectors << 9;
+ }
- bp->bio1.bi_io_vec = &bp->bv1;
- bp->bio2.bi_io_vec = &bp->bv2;
+ bp->bio1.bi_io_vec = &bp->bv1;
+ bp->bio2.bi_io_vec = &bp->bv2;
- bp->bio1.bi_max_vecs = 1;
- bp->bio2.bi_max_vecs = 1;
+ bp->bio1.bi_max_vecs = 1;
+ bp->bio2.bi_max_vecs = 1;
+ }
bp->bio1.bi_end_io = bio_pair_end_1;
bp->bio2.bi_end_io = bio_pair_end_2;
diff --git a/fs/block_dev.c b/fs/block_dev.c
index 38e721b..b3c1d3d 100644
--- a/fs/block_dev.c
+++ b/fs/block_dev.c
@@ -116,6 +116,8 @@ EXPORT_SYMBOL(invalidate_bdev);
int set_blocksize(struct block_device *bdev, int size)
{
+ struct address_space *mapping;
+
/* Size must be a power of two, and between 512 and PAGE_SIZE */
if (size > PAGE_SIZE || size < 512 || !is_power_of_2(size))
return -EINVAL;
@@ -124,6 +126,19 @@ int set_blocksize(struct block_device *bdev, int size)
if (size < bdev_logical_block_size(bdev))
return -EINVAL;
+ /* Prevent starting I/O or mapping the device */
+ percpu_down_write(&bdev->bd_block_size_semaphore);
+
+ /* Check that the block device is not memory mapped */
+ mapping = bdev->bd_inode->i_mapping;
+ mutex_lock(&mapping->i_mmap_mutex);
+ if (mapping_mapped(mapping)) {
+ mutex_unlock(&mapping->i_mmap_mutex);
+ percpu_up_write(&bdev->bd_block_size_semaphore);
+ return -EBUSY;
+ }
+ mutex_unlock(&mapping->i_mmap_mutex);
+
/* Don't change the size if it is same as current */
if (bdev->bd_block_size != size) {
sync_blockdev(bdev);
@@ -131,6 +146,9 @@ int set_blocksize(struct block_device *bdev, int size)
bdev->bd_inode->i_blkbits = blksize_bits(size);
kill_bdev(bdev);
}
+
+ percpu_up_write(&bdev->bd_block_size_semaphore);
+
return 0;
}
@@ -441,6 +459,12 @@ static struct inode *bdev_alloc_inode(struct super_block *sb)
struct bdev_inode *ei = kmem_cache_alloc(bdev_cachep, GFP_KERNEL);
if (!ei)
return NULL;
+
+ if (unlikely(percpu_init_rwsem(&ei->bdev.bd_block_size_semaphore))) {
+ kmem_cache_free(bdev_cachep, ei);
+ return NULL;
+ }
+
return &ei->vfs_inode;
}
@@ -449,6 +473,8 @@ static void bdev_i_callback(struct rcu_head *head)
struct inode *inode = container_of(head, struct inode, i_rcu);
struct bdev_inode *bdi = BDEV_I(inode);
+ percpu_free_rwsem(&bdi->bdev.bd_block_size_semaphore);
+
kmem_cache_free(bdev_cachep, bdi);
}
@@ -1567,6 +1593,22 @@ static long block_ioctl(struct file *file, unsigned cmd, unsigned long arg)
return blkdev_ioctl(bdev, mode, cmd, arg);
}
+ssize_t blkdev_aio_read(struct kiocb *iocb, const struct iovec *iov,
+ unsigned long nr_segs, loff_t pos)
+{
+ ssize_t ret;
+ struct block_device *bdev = I_BDEV(iocb->ki_filp->f_mapping->host);
+
+ percpu_down_read(&bdev->bd_block_size_semaphore);
+
+ ret = generic_file_aio_read(iocb, iov, nr_segs, pos);
+
+ percpu_up_read(&bdev->bd_block_size_semaphore);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(blkdev_aio_read);
+
/*
* Write data to the block device. Only intended for the block device itself
* and the raw driver which basically is a fake block device.
@@ -1578,12 +1620,16 @@ ssize_t blkdev_aio_write(struct kiocb *iocb, const struct iovec *iov,
unsigned long nr_segs, loff_t pos)
{
struct file *file = iocb->ki_filp;
+ struct block_device *bdev = I_BDEV(file->f_mapping->host);
struct blk_plug plug;
ssize_t ret;
BUG_ON(iocb->ki_pos != pos);
blk_start_plug(&plug);
+
+ percpu_down_read(&bdev->bd_block_size_semaphore);
+
ret = __generic_file_aio_write(iocb, iov, nr_segs, &iocb->ki_pos);
if (ret > 0 || ret == -EIOCBQUEUED) {
ssize_t err;
@@ -1592,11 +1638,29 @@ ssize_t blkdev_aio_write(struct kiocb *iocb, const struct iovec *iov,
if (err < 0 && ret > 0)
ret = err;
}
+
+ percpu_up_read(&bdev->bd_block_size_semaphore);
+
blk_finish_plug(&plug);
+
return ret;
}
EXPORT_SYMBOL_GPL(blkdev_aio_write);
+static int blkdev_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ int ret;
+ struct block_device *bdev = I_BDEV(file->f_mapping->host);
+
+ percpu_down_read(&bdev->bd_block_size_semaphore);
+
+ ret = generic_file_mmap(file, vma);
+
+ percpu_up_read(&bdev->bd_block_size_semaphore);
+
+ return ret;
+}
+
/*
* Try to release a page associated with block device when the system
* is under memory pressure.
@@ -1627,9 +1691,9 @@ const struct file_operations def_blk_fops = {
.llseek = block_llseek,
.read = do_sync_read,
.write = do_sync_write,
- .aio_read = generic_file_aio_read,
+ .aio_read = blkdev_aio_read,
.aio_write = blkdev_aio_write,
- .mmap = generic_file_mmap,
+ .mmap = blkdev_mmap,
.fsync = blkdev_fsync,
.unlocked_ioctl = block_ioctl,
#ifdef CONFIG_COMPAT
diff --git a/fs/btrfs/backref.c b/fs/btrfs/backref.c
index ff6475f..f318793 100644
--- a/fs/btrfs/backref.c
+++ b/fs/btrfs/backref.c
@@ -16,6 +16,7 @@
* Boston, MA 021110-1307, USA.
*/
+#include <linux/vmalloc.h>
#include "ctree.h"
#include "disk-io.h"
#include "backref.h"
@@ -231,7 +232,7 @@ static int add_all_parents(struct btrfs_root *root, struct btrfs_path *path,
}
if (!ret) {
ret = ulist_add(parents, eb->start,
- (unsigned long)eie, GFP_NOFS);
+ (uintptr_t)eie, GFP_NOFS);
if (ret < 0)
break;
if (!extent_item_pos) {
@@ -363,8 +364,8 @@ static int __resolve_indirect_refs(struct btrfs_fs_info *fs_info,
ULIST_ITER_INIT(&uiter);
node = ulist_next(parents, &uiter);
ref->parent = node ? node->val : 0;
- ref->inode_list =
- node ? (struct extent_inode_elem *)node->aux : 0;
+ ref->inode_list = node ?
+ (struct extent_inode_elem *)(uintptr_t)node->aux : 0;
/* additional parents require new refs being added here */
while ((node = ulist_next(parents, &uiter))) {
@@ -375,8 +376,8 @@ static int __resolve_indirect_refs(struct btrfs_fs_info *fs_info,
}
memcpy(new_ref, ref, sizeof(*ref));
new_ref->parent = node->val;
- new_ref->inode_list =
- (struct extent_inode_elem *)node->aux;
+ new_ref->inode_list = (struct extent_inode_elem *)
+ (uintptr_t)node->aux;
list_add(&new_ref->list, &ref->list);
}
ulist_reinit(parents);
@@ -914,8 +915,8 @@ again:
free_extent_buffer(eb);
}
ret = ulist_add_merge(refs, ref->parent,
- (unsigned long)ref->inode_list,
- (unsigned long *)&eie, GFP_NOFS);
+ (uintptr_t)ref->inode_list,
+ (u64 *)&eie, GFP_NOFS);
if (!ret && extent_item_pos) {
/*
* we've recorded that parent, so we must extend
@@ -959,7 +960,7 @@ static void free_leaf_list(struct ulist *blocks)
while ((node = ulist_next(blocks, &uiter))) {
if (!node->aux)
continue;
- eie = (struct extent_inode_elem *)node->aux;
+ eie = (struct extent_inode_elem *)(uintptr_t)node->aux;
for (; eie; eie = eie_next) {
eie_next = eie->next;
kfree(eie);
@@ -1108,26 +1109,80 @@ static int inode_ref_info(u64 inum, u64 ioff, struct btrfs_root *fs_root,
found_key);
}
-/*
- * this iterates to turn a btrfs_inode_ref into a full filesystem path. elements
- * of the path are separated by '/' and the path is guaranteed to be
- * 0-terminated. the path is only given within the current file system.
- * Therefore, it never starts with a '/'. the caller is responsible to provide
- * "size" bytes in "dest". the dest buffer will be filled backwards. finally,
- * the start point of the resulting string is returned. this pointer is within
- * dest, normally.
- * in case the path buffer would overflow, the pointer is decremented further
- * as if output was written to the buffer, though no more output is actually
- * generated. that way, the caller can determine how much space would be
- * required for the path to fit into the buffer. in that case, the returned
- * value will be smaller than dest. callers must check this!
- */
-char *btrfs_iref_to_path(struct btrfs_root *fs_root, struct btrfs_path *path,
- struct btrfs_inode_ref *iref,
+int btrfs_find_one_extref(struct btrfs_root *root, u64 inode_objectid,
+ u64 start_off, struct btrfs_path *path,
+ struct btrfs_inode_extref **ret_extref,
+ u64 *found_off)
+{
+ int ret, slot;
+ struct btrfs_key key;
+ struct btrfs_key found_key;
+ struct btrfs_inode_extref *extref;
+ struct extent_buffer *leaf;
+ unsigned long ptr;
+
+ key.objectid = inode_objectid;
+ btrfs_set_key_type(&key, BTRFS_INODE_EXTREF_KEY);
+ key.offset = start_off;
+
+ ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
+ if (ret < 0)
+ return ret;
+
+ while (1) {
+ leaf = path->nodes[0];
+ slot = path->slots[0];
+ if (slot >= btrfs_header_nritems(leaf)) {
+ /*
+ * If the item at offset is not found,
+ * btrfs_search_slot will point us to the slot
+ * where it should be inserted. In our case
+ * that will be the slot directly before the
+ * next INODE_REF_KEY_V2 item. In the case
+ * that we're pointing to the last slot in a
+ * leaf, we must move one leaf over.
+ */
+ ret = btrfs_next_leaf(root, path);
+ if (ret) {
+ if (ret >= 1)
+ ret = -ENOENT;
+ break;
+ }
+ continue;
+ }
+
+ btrfs_item_key_to_cpu(leaf, &found_key, slot);
+
+ /*
+ * Check that we're still looking at an extended ref key for
+ * this particular objectid. If we have different
+ * objectid or type then there are no more to be found
+ * in the tree and we can exit.
+ */
+ ret = -ENOENT;
+ if (found_key.objectid != inode_objectid)
+ break;
+ if (btrfs_key_type(&found_key) != BTRFS_INODE_EXTREF_KEY)
+ break;
+
+ ret = 0;
+ ptr = btrfs_item_ptr_offset(leaf, path->slots[0]);
+ extref = (struct btrfs_inode_extref *)ptr;
+ *ret_extref = extref;
+ if (found_off)
+ *found_off = found_key.offset;
+ break;
+ }
+
+ return ret;
+}
+
+static char *ref_to_path(struct btrfs_root *fs_root,
+ struct btrfs_path *path,
+ u32 name_len, unsigned long name_off,
struct extent_buffer *eb_in, u64 parent,
char *dest, u32 size)
{
- u32 len;
int slot;
u64 next_inum;
int ret;
@@ -1135,17 +1190,17 @@ char *btrfs_iref_to_path(struct btrfs_root *fs_root, struct btrfs_path *path,
struct extent_buffer *eb = eb_in;
struct btrfs_key found_key;
int leave_spinning = path->leave_spinning;
+ struct btrfs_inode_ref *iref;
if (bytes_left >= 0)
dest[bytes_left] = '\0';
path->leave_spinning = 1;
while (1) {
- len = btrfs_inode_ref_name_len(eb, iref);
- bytes_left -= len;
+ bytes_left -= name_len;
if (bytes_left >= 0)
read_extent_buffer(eb, dest + bytes_left,
- (unsigned long)(iref + 1), len);
+ name_off, name_len);
if (eb != eb_in) {
btrfs_tree_read_unlock_blocking(eb);
free_extent_buffer(eb);
@@ -1155,6 +1210,7 @@ char *btrfs_iref_to_path(struct btrfs_root *fs_root, struct btrfs_path *path,
ret = -ENOENT;
if (ret)
break;
+
next_inum = found_key.offset;
/* regular exit ahead */
@@ -1170,8 +1226,11 @@ char *btrfs_iref_to_path(struct btrfs_root *fs_root, struct btrfs_path *path,
btrfs_set_lock_blocking_rw(eb, BTRFS_READ_LOCK);
}
btrfs_release_path(path);
-
iref = btrfs_item_ptr(eb, slot, struct btrfs_inode_ref);
+
+ name_len = btrfs_inode_ref_name_len(eb, iref);
+ name_off = (unsigned long)(iref + 1);
+
parent = next_inum;
--bytes_left;
if (bytes_left >= 0)
@@ -1188,12 +1247,39 @@ char *btrfs_iref_to_path(struct btrfs_root *fs_root, struct btrfs_path *path,
}
/*
+ * this iterates to turn a btrfs_inode_ref into a full filesystem path. elements
+ * of the path are separated by '/' and the path is guaranteed to be
+ * 0-terminated. the path is only given within the current file system.
+ * Therefore, it never starts with a '/'. the caller is responsible to provide
+ * "size" bytes in "dest". the dest buffer will be filled backwards. finally,
+ * the start point of the resulting string is returned. this pointer is within
+ * dest, normally.
+ * in case the path buffer would overflow, the pointer is decremented further
+ * as if output was written to the buffer, though no more output is actually
+ * generated. that way, the caller can determine how much space would be
+ * required for the path to fit into the buffer. in that case, the returned
+ * value will be smaller than dest. callers must check this!
+ */
+char *btrfs_iref_to_path(struct btrfs_root *fs_root,
+ struct btrfs_path *path,
+ struct btrfs_inode_ref *iref,
+ struct extent_buffer *eb_in, u64 parent,
+ char *dest, u32 size)
+{
+ return ref_to_path(fs_root, path,
+ btrfs_inode_ref_name_len(eb_in, iref),
+ (unsigned long)(iref + 1),
+ eb_in, parent, dest, size);
+}
+
+/*
* this makes the path point to (logical EXTENT_ITEM *)
* returns BTRFS_EXTENT_FLAG_DATA for data, BTRFS_EXTENT_FLAG_TREE_BLOCK for
* tree blocks and <0 on error.
*/
int extent_from_logical(struct btrfs_fs_info *fs_info, u64 logical,
- struct btrfs_path *path, struct btrfs_key *found_key)
+ struct btrfs_path *path, struct btrfs_key *found_key,
+ u64 *flags_ret)
{
int ret;
u64 flags;
@@ -1237,10 +1323,17 @@ int extent_from_logical(struct btrfs_fs_info *fs_info, u64 logical,
(unsigned long long)found_key->objectid,
(unsigned long long)found_key->offset,
(unsigned long long)flags, item_size);
- if (flags & BTRFS_EXTENT_FLAG_TREE_BLOCK)
- return BTRFS_EXTENT_FLAG_TREE_BLOCK;
- if (flags & BTRFS_EXTENT_FLAG_DATA)
- return BTRFS_EXTENT_FLAG_DATA;
+
+ WARN_ON(!flags_ret);
+ if (flags_ret) {
+ if (flags & BTRFS_EXTENT_FLAG_TREE_BLOCK)
+ *flags_ret = BTRFS_EXTENT_FLAG_TREE_BLOCK;
+ else if (flags & BTRFS_EXTENT_FLAG_DATA)
+ *flags_ret = BTRFS_EXTENT_FLAG_DATA;
+ else
+ BUG_ON(1);
+ return 0;
+ }
return -EIO;
}
@@ -1404,12 +1497,13 @@ int iterate_extent_inodes(struct btrfs_fs_info *fs_info,
ULIST_ITER_INIT(&root_uiter);
while (!ret && (root_node = ulist_next(roots, &root_uiter))) {
pr_debug("root %llu references leaf %llu, data list "
- "%#lx\n", root_node->val, ref_node->val,
- ref_node->aux);
- ret = iterate_leaf_refs(
- (struct extent_inode_elem *)ref_node->aux,
- root_node->val, extent_item_objectid,
- iterate, ctx);
+ "%#llx\n", root_node->val, ref_node->val,
+ (long long)ref_node->aux);
+ ret = iterate_leaf_refs((struct extent_inode_elem *)
+ (uintptr_t)ref_node->aux,
+ root_node->val,
+ extent_item_objectid,
+ iterate, ctx);
}
ulist_free(roots);
roots = NULL;
@@ -1432,15 +1526,15 @@ int iterate_inodes_from_logical(u64 logical, struct btrfs_fs_info *fs_info,
{
int ret;
u64 extent_item_pos;
+ u64 flags = 0;
struct btrfs_key found_key;
int search_commit_root = path->search_commit_root;
- ret = extent_from_logical(fs_info, logical, path,
- &found_key);
+ ret = extent_from_logical(fs_info, logical, path, &found_key, &flags);
btrfs_release_path(path);
if (ret < 0)
return ret;
- if (ret & BTRFS_EXTENT_FLAG_TREE_BLOCK)
+ if (flags & BTRFS_EXTENT_FLAG_TREE_BLOCK)
return -EINVAL;
extent_item_pos = logical - found_key.objectid;
@@ -1451,9 +1545,12 @@ int iterate_inodes_from_logical(u64 logical, struct btrfs_fs_info *fs_info,
return ret;
}
-static int iterate_irefs(u64 inum, struct btrfs_root *fs_root,
- struct btrfs_path *path,
- iterate_irefs_t *iterate, void *ctx)
+typedef int (iterate_irefs_t)(u64 parent, u32 name_len, unsigned long name_off,
+ struct extent_buffer *eb, void *ctx);
+
+static int iterate_inode_refs(u64 inum, struct btrfs_root *fs_root,
+ struct btrfs_path *path,
+ iterate_irefs_t *iterate, void *ctx)
{
int ret = 0;
int slot;
@@ -1470,7 +1567,7 @@ static int iterate_irefs(u64 inum, struct btrfs_root *fs_root,
while (!ret) {
path->leave_spinning = 1;
ret = inode_ref_info(inum, parent ? parent+1 : 0, fs_root, path,
- &found_key);
+ &found_key);
if (ret < 0)
break;
if (ret) {
@@ -1498,7 +1595,8 @@ static int iterate_irefs(u64 inum, struct btrfs_root *fs_root,
"tree %llu\n", cur,
(unsigned long long)found_key.objectid,
(unsigned long long)fs_root->objectid);
- ret = iterate(parent, iref, eb, ctx);
+ ret = iterate(parent, name_len,
+ (unsigned long)(iref + 1), eb, ctx);
if (ret)
break;
len = sizeof(*iref) + name_len;
@@ -1513,12 +1611,98 @@ static int iterate_irefs(u64 inum, struct btrfs_root *fs_root,
return ret;
}
+static int iterate_inode_extrefs(u64 inum, struct btrfs_root *fs_root,
+ struct btrfs_path *path,
+ iterate_irefs_t *iterate, void *ctx)
+{
+ int ret;
+ int slot;
+ u64 offset = 0;
+ u64 parent;
+ int found = 0;
+ struct extent_buffer *eb;
+ struct btrfs_inode_extref *extref;
+ struct extent_buffer *leaf;
+ u32 item_size;
+ u32 cur_offset;
+ unsigned long ptr;
+
+ while (1) {
+ ret = btrfs_find_one_extref(fs_root, inum, offset, path, &extref,
+ &offset);
+ if (ret < 0)
+ break;
+ if (ret) {
+ ret = found ? 0 : -ENOENT;
+ break;
+ }
+ ++found;
+
+ slot = path->slots[0];
+ eb = path->nodes[0];
+ /* make sure we can use eb after releasing the path */
+ atomic_inc(&eb->refs);
+
+ btrfs_tree_read_lock(eb);
+ btrfs_set_lock_blocking_rw(eb, BTRFS_READ_LOCK);
+ btrfs_release_path(path);
+
+ leaf = path->nodes[0];
+ item_size = btrfs_item_size_nr(leaf, path->slots[0]);
+ ptr = btrfs_item_ptr_offset(leaf, path->slots[0]);
+ cur_offset = 0;
+
+ while (cur_offset < item_size) {
+ u32 name_len;
+
+ extref = (struct btrfs_inode_extref *)(ptr + cur_offset);
+ parent = btrfs_inode_extref_parent(eb, extref);
+ name_len = btrfs_inode_extref_name_len(eb, extref);
+ ret = iterate(parent, name_len,
+ (unsigned long)&extref->name, eb, ctx);
+ if (ret)
+ break;
+
+ cur_offset += btrfs_inode_extref_name_len(leaf, extref);
+ cur_offset += sizeof(*extref);
+ }
+ btrfs_tree_read_unlock_blocking(eb);
+ free_extent_buffer(eb);
+
+ offset++;
+ }
+
+ btrfs_release_path(path);
+
+ return ret;
+}
+
+static int iterate_irefs(u64 inum, struct btrfs_root *fs_root,
+ struct btrfs_path *path, iterate_irefs_t *iterate,
+ void *ctx)
+{
+ int ret;
+ int found_refs = 0;
+
+ ret = iterate_inode_refs(inum, fs_root, path, iterate, ctx);
+ if (!ret)
+ ++found_refs;
+ else if (ret != -ENOENT)
+ return ret;
+
+ ret = iterate_inode_extrefs(inum, fs_root, path, iterate, ctx);
+ if (ret == -ENOENT && found_refs)
+ return 0;
+
+ return ret;
+}
+
/*
* returns 0 if the path could be dumped (probably truncated)
* returns <0 in case of an error
*/
-static int inode_to_path(u64 inum, struct btrfs_inode_ref *iref,
- struct extent_buffer *eb, void *ctx)
+static int inode_to_path(u64 inum, u32 name_len, unsigned long name_off,
+ struct extent_buffer *eb, void *ctx)
{
struct inode_fs_paths *ipath = ctx;
char *fspath;
@@ -1531,20 +1715,17 @@ static int inode_to_path(u64 inum, struct btrfs_inode_ref *iref,
ipath->fspath->bytes_left - s_ptr : 0;
fspath_min = (char *)ipath->fspath->val + (i + 1) * s_ptr;
- fspath = btrfs_iref_to_path(ipath->fs_root, ipath->btrfs_path, iref, eb,
- inum, fspath_min, bytes_left);
+ fspath = ref_to_path(ipath->fs_root, ipath->btrfs_path, name_len,
+ name_off, eb, inum, fspath_min,
+ bytes_left);
if (IS_ERR(fspath))
return PTR_ERR(fspath);
if (fspath > fspath_min) {
- pr_debug("path resolved: %s\n", fspath);
ipath->fspath->val[i] = (u64)(unsigned long)fspath;
++ipath->fspath->elem_cnt;
ipath->fspath->bytes_left = fspath - fspath_min;
} else {
- pr_debug("missed path, not enough space. missing bytes: %lu, "
- "constructed so far: %s\n",
- (unsigned long)(fspath_min - fspath), fspath_min);
++ipath->fspath->elem_missed;
ipath->fspath->bytes_missing += fspath_min - fspath;
ipath->fspath->bytes_left = 0;
@@ -1566,7 +1747,7 @@ static int inode_to_path(u64 inum, struct btrfs_inode_ref *iref,
int paths_from_inode(u64 inum, struct inode_fs_paths *ipath)
{
return iterate_irefs(inum, ipath->fs_root, ipath->btrfs_path,
- inode_to_path, ipath);
+ inode_to_path, ipath);
}
struct btrfs_data_container *init_data_container(u32 total_bytes)
@@ -1575,7 +1756,7 @@ struct btrfs_data_container *init_data_container(u32 total_bytes)
size_t alloc_bytes;
alloc_bytes = max_t(size_t, total_bytes, sizeof(*data));
- data = kmalloc(alloc_bytes, GFP_NOFS);
+ data = vmalloc(alloc_bytes);
if (!data)
return ERR_PTR(-ENOMEM);
@@ -1626,6 +1807,6 @@ void free_ipath(struct inode_fs_paths *ipath)
{
if (!ipath)
return;
- kfree(ipath->fspath);
+ vfree(ipath->fspath);
kfree(ipath);
}
diff --git a/fs/btrfs/backref.h b/fs/btrfs/backref.h
index 032f4dc..e755330 100644
--- a/fs/btrfs/backref.h
+++ b/fs/btrfs/backref.h
@@ -33,14 +33,13 @@ struct inode_fs_paths {
typedef int (iterate_extent_inodes_t)(u64 inum, u64 offset, u64 root,
void *ctx);
-typedef int (iterate_irefs_t)(u64 parent, struct btrfs_inode_ref *iref,
- struct extent_buffer *eb, void *ctx);
int inode_item_info(u64 inum, u64 ioff, struct btrfs_root *fs_root,
struct btrfs_path *path);
int extent_from_logical(struct btrfs_fs_info *fs_info, u64 logical,
- struct btrfs_path *path, struct btrfs_key *found_key);
+ struct btrfs_path *path, struct btrfs_key *found_key,
+ u64 *flags);
int tree_backref_for_extent(unsigned long *ptr, struct extent_buffer *eb,
struct btrfs_extent_item *ei, u32 item_size,
@@ -69,4 +68,9 @@ struct inode_fs_paths *init_ipath(s32 total_bytes, struct btrfs_root *fs_root,
struct btrfs_path *path);
void free_ipath(struct inode_fs_paths *ipath);
+int btrfs_find_one_extref(struct btrfs_root *root, u64 inode_objectid,
+ u64 start_off, struct btrfs_path *path,
+ struct btrfs_inode_extref **ret_extref,
+ u64 *found_off);
+
#endif
diff --git a/fs/btrfs/btrfs_inode.h b/fs/btrfs/btrfs_inode.h
index 5b2ad6b..ed8ca7c 100644
--- a/fs/btrfs/btrfs_inode.h
+++ b/fs/btrfs/btrfs_inode.h
@@ -38,6 +38,7 @@
#define BTRFS_INODE_DELALLOC_META_RESERVED 4
#define BTRFS_INODE_HAS_ORPHAN_ITEM 5
#define BTRFS_INODE_HAS_ASYNC_EXTENT 6
+#define BTRFS_INODE_NEEDS_FULL_SYNC 7
/* in memory btrfs inode */
struct btrfs_inode {
@@ -143,6 +144,9 @@ struct btrfs_inode {
/* flags field from the on disk inode */
u32 flags;
+ /* a local copy of root's last_log_commit */
+ unsigned long last_log_commit;
+
/*
* Counters to keep track of the number of extent item's we may use due
* to delalloc and such. outstanding_extents is the number of extent
@@ -202,15 +206,10 @@ static inline bool btrfs_is_free_space_inode(struct inode *inode)
static inline int btrfs_inode_in_log(struct inode *inode, u64 generation)
{
- struct btrfs_root *root = BTRFS_I(inode)->root;
- int ret = 0;
-
- mutex_lock(&root->log_mutex);
if (BTRFS_I(inode)->logged_trans == generation &&
- BTRFS_I(inode)->last_sub_trans <= root->last_log_commit)
- ret = 1;
- mutex_unlock(&root->log_mutex);
- return ret;
+ BTRFS_I(inode)->last_sub_trans <= BTRFS_I(inode)->last_log_commit)
+ return 1;
+ return 0;
}
#endif
diff --git a/fs/btrfs/check-integrity.c b/fs/btrfs/check-integrity.c
index 9197e2e..5a3e45d 100644
--- a/fs/btrfs/check-integrity.c
+++ b/fs/btrfs/check-integrity.c
@@ -37,8 +37,9 @@
* the file system was mounted, (i.e., they have been
* referenced by the super block) or they have been
* written since then and the write completion callback
- * was called and a FLUSH request to the device where
- * these blocks are located was received and completed.
+ * was called and no write error was indicated and a
+ * FLUSH request to the device where these blocks are
+ * located was received and completed.
* 2b. All referenced blocks need to have a generation
* number which is equal to the parent's number.
*
@@ -2601,6 +2602,17 @@ static int btrfsic_check_all_ref_blocks(struct btrfsic_state *state,
(unsigned long long)l->block_ref_to->dev_bytenr,
l->block_ref_to->mirror_num);
ret = -1;
+ } else if (l->block_ref_to->iodone_w_error) {
+ printk(KERN_INFO "btrfs: attempt to write superblock"
+ " which references block %c @%llu (%s/%llu/%d)"
+ " which has write error!\n",
+ btrfsic_get_block_type(state, l->block_ref_to),
+ (unsigned long long)
+ l->block_ref_to->logical_bytenr,
+ l->block_ref_to->dev_state->name,
+ (unsigned long long)l->block_ref_to->dev_bytenr,
+ l->block_ref_to->mirror_num);
+ ret = -1;
} else if (l->parent_generation !=
l->block_ref_to->generation &&
BTRFSIC_GENERATION_UNKNOWN !=
diff --git a/fs/btrfs/compression.c b/fs/btrfs/compression.c
index 43d1c5a..c6467aa 100644
--- a/fs/btrfs/compression.c
+++ b/fs/btrfs/compression.c
@@ -577,6 +577,7 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,
u64 em_start;
struct extent_map *em;
int ret = -ENOMEM;
+ int faili = 0;
u32 *sums;
tree = &BTRFS_I(inode)->io_tree;
@@ -626,9 +627,13 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,
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[pg_index])
+ if (!cb->compressed_pages[pg_index]) {
+ faili = pg_index - 1;
+ ret = -ENOMEM;
goto fail2;
+ }
}
+ faili = nr_pages - 1;
cb->nr_pages = nr_pages;
add_ra_bio_pages(inode, em_start + em_len, cb);
@@ -713,8 +718,10 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,
return 0;
fail2:
- for (pg_index = 0; pg_index < nr_pages; pg_index++)
- free_page((unsigned long)cb->compressed_pages[pg_index]);
+ while (faili >= 0) {
+ __free_page(cb->compressed_pages[faili]);
+ faili--;
+ }
kfree(cb->compressed_pages);
fail1:
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
index 6d183f6..b334362 100644
--- a/fs/btrfs/ctree.c
+++ b/fs/btrfs/ctree.c
@@ -4402,149 +4402,6 @@ void btrfs_extend_item(struct btrfs_trans_handle *trans,
}
/*
- * Given a key and some data, insert items into the tree.
- * This does all the path init required, making room in the tree if needed.
- * Returns the number of keys that were inserted.
- */
-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)
-{
- struct extent_buffer *leaf;
- struct btrfs_item *item;
- int ret = 0;
- int slot;
- int i;
- u32 nritems;
- u32 total_data = 0;
- u32 total_size = 0;
- unsigned int data_end;
- struct btrfs_disk_key disk_key;
- struct btrfs_key found_key;
- struct btrfs_map_token token;
-
- btrfs_init_map_token(&token);
-
- for (i = 0; i < nr; i++) {
- if (total_size + data_size[i] + sizeof(struct btrfs_item) >
- BTRFS_LEAF_DATA_SIZE(root)) {
- break;
- nr = i;
- }
- total_data += data_size[i];
- total_size += data_size[i] + sizeof(struct btrfs_item);
- }
- BUG_ON(nr == 0);
-
- ret = btrfs_search_slot(trans, root, cpu_key, path, total_size, 1);
- if (ret == 0)
- return -EEXIST;
- if (ret < 0)
- goto out;
-
- leaf = path->nodes[0];
-
- nritems = btrfs_header_nritems(leaf);
- data_end = leaf_data_end(root, leaf);
-
- if (btrfs_leaf_free_space(root, leaf) < total_size) {
- for (i = nr; i >= 0; i--) {
- total_data -= data_size[i];
- total_size -= data_size[i] + sizeof(struct btrfs_item);
- if (total_size < btrfs_leaf_free_space(root, leaf))
- break;
- }
- nr = i;
- }
-
- slot = path->slots[0];
- BUG_ON(slot < 0);
-
- if (slot != nritems) {
- unsigned int old_data = btrfs_item_end_nr(leaf, slot);
-
- item = btrfs_item_nr(leaf, slot);
- btrfs_item_key_to_cpu(leaf, &found_key, slot);
-
- /* figure out how many keys we can insert in here */
- total_data = data_size[0];
- for (i = 1; i < nr; i++) {
- if (btrfs_comp_cpu_keys(&found_key, cpu_key + i) <= 0)
- break;
- total_data += data_size[i];
- }
- nr = i;
-
- if (old_data < data_end) {
- btrfs_print_leaf(root, leaf);
- printk(KERN_CRIT "slot %d old_data %d data_end %d\n",
- slot, old_data, data_end);
- BUG_ON(1);
- }
- /*
- * item0..itemN ... dataN.offset..dataN.size .. data0.size
- */
- /* first correct the data pointers */
- for (i = slot; i < nritems; i++) {
- u32 ioff;
-
- item = btrfs_item_nr(leaf, i);
- ioff = btrfs_token_item_offset(leaf, item, &token);
- btrfs_set_token_item_offset(leaf, item,
- ioff - total_data, &token);
- }
- /* shift the items */
- memmove_extent_buffer(leaf, btrfs_item_nr_offset(slot + nr),
- btrfs_item_nr_offset(slot),
- (nritems - slot) * sizeof(struct btrfs_item));
-
- /* shift the data */
- memmove_extent_buffer(leaf, btrfs_leaf_data(leaf) +
- data_end - total_data, btrfs_leaf_data(leaf) +
- data_end, old_data - data_end);
- data_end = old_data;
- } else {
- /*
- * this sucks but it has to be done, if we are inserting at
- * the end of the leaf only insert 1 of the items, since we
- * have no way of knowing whats on the next leaf and we'd have
- * to drop our current locks to figure it out
- */
- nr = 1;
- }
-
- /* setup the item for the new data */
- for (i = 0; i < nr; i++) {
- btrfs_cpu_key_to_disk(&disk_key, cpu_key + i);
- btrfs_set_item_key(leaf, &disk_key, slot + i);
- item = btrfs_item_nr(leaf, slot + i);
- btrfs_set_token_item_offset(leaf, item,
- data_end - data_size[i], &token);
- data_end -= data_size[i];
- btrfs_set_token_item_size(leaf, item, data_size[i], &token);
- }
- btrfs_set_header_nritems(leaf, nritems + nr);
- btrfs_mark_buffer_dirty(leaf);
-
- ret = 0;
- if (slot == 0) {
- btrfs_cpu_key_to_disk(&disk_key, cpu_key);
- fixup_low_keys(trans, root, path, &disk_key, 1);
- }
-
- if (btrfs_leaf_free_space(root, leaf) < 0) {
- btrfs_print_leaf(root, leaf);
- BUG();
- }
-out:
- if (!ret)
- ret = nr;
- return ret;
-}
-
-/*
* this is a helper for btrfs_insert_empty_items, the main goal here is
* to save stack depth by doing the bulk of the work in a function
* that doesn't call btrfs_search_slot
@@ -5073,6 +4930,7 @@ static void tree_move_down(struct btrfs_root *root,
struct btrfs_path *path,
int *level, int root_level)
{
+ BUG_ON(*level == 0);
path->nodes[*level - 1] = read_node_slot(root, path->nodes[*level],
path->slots[*level]);
path->slots[*level - 1] = 0;
@@ -5089,7 +4947,7 @@ static int tree_move_next_or_upnext(struct btrfs_root *root,
path->slots[*level]++;
- while (path->slots[*level] == nritems) {
+ while (path->slots[*level] >= nritems) {
if (*level == root_level)
return -1;
@@ -5433,9 +5291,11 @@ int btrfs_compare_trees(struct btrfs_root *left_root,
goto out;
advance_right = ADVANCE;
} else {
+ WARN_ON(!extent_buffer_uptodate(left_path->nodes[0]));
ret = tree_compare_item(left_root, left_path,
right_path, tmp_buf);
if (ret) {
+ WARN_ON(!extent_buffer_uptodate(left_path->nodes[0]));
ret = changed_cb(left_root, right_root,
left_path, right_path,
&left_key,
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index 9821b67..926c9ff 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -154,6 +154,13 @@ struct btrfs_ordered_sum;
*/
#define BTRFS_NAME_LEN 255
+/*
+ * Theoretical limit is larger, but we keep this down to a sane
+ * value. That should limit greatly the possibility of collisions on
+ * inode ref items.
+ */
+#define BTRFS_LINK_MAX 65535U
+
/* 32 bytes in various csum fields */
#define BTRFS_CSUM_SIZE 32
@@ -489,6 +496,8 @@ struct btrfs_super_block {
*/
#define BTRFS_FEATURE_INCOMPAT_BIG_METADATA (1ULL << 5)
+#define BTRFS_FEATURE_INCOMPAT_EXTENDED_IREF (1ULL << 6)
+
#define BTRFS_FEATURE_COMPAT_SUPP 0ULL
#define BTRFS_FEATURE_COMPAT_RO_SUPP 0ULL
#define BTRFS_FEATURE_INCOMPAT_SUPP \
@@ -496,7 +505,8 @@ struct btrfs_super_block {
BTRFS_FEATURE_INCOMPAT_DEFAULT_SUBVOL | \
BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS | \
BTRFS_FEATURE_INCOMPAT_BIG_METADATA | \
- BTRFS_FEATURE_INCOMPAT_COMPRESS_LZO)
+ BTRFS_FEATURE_INCOMPAT_COMPRESS_LZO | \
+ BTRFS_FEATURE_INCOMPAT_EXTENDED_IREF)
/*
* A leaf is full of items. offset and size tell us where to find
@@ -643,6 +653,14 @@ struct btrfs_inode_ref {
/* name goes here */
} __attribute__ ((__packed__));
+struct btrfs_inode_extref {
+ __le64 parent_objectid;
+ __le64 index;
+ __le16 name_len;
+ __u8 name[0];
+ /* name goes here */
+} __attribute__ ((__packed__));
+
struct btrfs_timespec {
__le64 sec;
__le32 nsec;
@@ -1028,12 +1046,22 @@ struct btrfs_space_info {
wait_queue_head_t wait;
};
+#define BTRFS_BLOCK_RSV_GLOBAL 1
+#define BTRFS_BLOCK_RSV_DELALLOC 2
+#define BTRFS_BLOCK_RSV_TRANS 3
+#define BTRFS_BLOCK_RSV_CHUNK 4
+#define BTRFS_BLOCK_RSV_DELOPS 5
+#define BTRFS_BLOCK_RSV_EMPTY 6
+#define BTRFS_BLOCK_RSV_TEMP 7
+
struct btrfs_block_rsv {
u64 size;
u64 reserved;
struct btrfs_space_info *space_info;
spinlock_t lock;
- unsigned int full;
+ unsigned short full;
+ unsigned short type;
+ unsigned short failfast;
};
/*
@@ -1127,6 +1155,9 @@ struct btrfs_block_group_cache {
* Today it will only have one thing on it, but that may change
*/
struct list_head cluster_list;
+
+ /* For delayed block group creation */
+ struct list_head new_bg_list;
};
/* delayed seq elem */
@@ -1240,7 +1271,6 @@ struct btrfs_fs_info {
struct mutex reloc_mutex;
struct list_head trans_list;
- struct list_head hashers;
struct list_head dead_roots;
struct list_head caching_block_groups;
@@ -1366,9 +1396,6 @@ struct btrfs_fs_info {
struct rb_root defrag_inodes;
atomic_t defrag_running;
- spinlock_t ref_cache_lock;
- u64 total_ref_cache_size;
-
/*
* these three are in extended format (availability of single
* chunks is denoted by BTRFS_AVAIL_ALLOC_BIT_SINGLE bit, other
@@ -1441,6 +1468,8 @@ struct btrfs_fs_info {
/* next backup root to be overwritten */
int backup_root_index;
+
+ int num_tolerated_disk_barrier_failures;
};
/*
@@ -1481,9 +1510,9 @@ struct btrfs_root {
wait_queue_head_t log_commit_wait[2];
atomic_t log_writers;
atomic_t log_commit[2];
+ atomic_t log_batch;
unsigned long log_transid;
unsigned long last_log_commit;
- unsigned long log_batch;
pid_t log_start_pid;
bool log_multiple_pids;
@@ -1592,6 +1621,7 @@ struct btrfs_ioctl_defrag_range_args {
*/
#define BTRFS_INODE_ITEM_KEY 1
#define BTRFS_INODE_REF_KEY 12
+#define BTRFS_INODE_EXTREF_KEY 13
#define BTRFS_XATTR_ITEM_KEY 24
#define BTRFS_ORPHAN_ITEM_KEY 48
/* reserve 2-15 close to the inode for later flexibility */
@@ -1978,6 +2008,13 @@ BTRFS_SETGET_STACK_FUNCS(block_group_flags,
BTRFS_SETGET_FUNCS(inode_ref_name_len, struct btrfs_inode_ref, name_len, 16);
BTRFS_SETGET_FUNCS(inode_ref_index, struct btrfs_inode_ref, index, 64);
+/* struct btrfs_inode_extref */
+BTRFS_SETGET_FUNCS(inode_extref_parent, struct btrfs_inode_extref,
+ parent_objectid, 64);
+BTRFS_SETGET_FUNCS(inode_extref_name_len, struct btrfs_inode_extref,
+ name_len, 16);
+BTRFS_SETGET_FUNCS(inode_extref_index, struct btrfs_inode_extref, index, 64);
+
/* struct btrfs_inode_item */
BTRFS_SETGET_FUNCS(inode_generation, struct btrfs_inode_item, generation, 64);
BTRFS_SETGET_FUNCS(inode_sequence, struct btrfs_inode_item, sequence, 64);
@@ -2858,6 +2895,8 @@ int btrfs_make_block_group(struct btrfs_trans_handle *trans,
u64 size);
int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
struct btrfs_root *root, u64 group_start);
+void btrfs_create_pending_block_groups(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root);
u64 btrfs_reduce_alloc_profile(struct btrfs_root *root, u64 flags);
u64 btrfs_get_alloc_profile(struct btrfs_root *root, int data);
void btrfs_clear_space_info_full(struct btrfs_fs_info *info);
@@ -2874,8 +2913,9 @@ int btrfs_delalloc_reserve_metadata(struct inode *inode, u64 num_bytes);
void btrfs_delalloc_release_metadata(struct inode *inode, u64 num_bytes);
int btrfs_delalloc_reserve_space(struct inode *inode, u64 num_bytes);
void btrfs_delalloc_release_space(struct inode *inode, u64 num_bytes);
-void btrfs_init_block_rsv(struct btrfs_block_rsv *rsv);
-struct btrfs_block_rsv *btrfs_alloc_block_rsv(struct btrfs_root *root);
+void btrfs_init_block_rsv(struct btrfs_block_rsv *rsv, unsigned short type);
+struct btrfs_block_rsv *btrfs_alloc_block_rsv(struct btrfs_root *root,
+ unsigned short type);
void btrfs_free_block_rsv(struct btrfs_root *root,
struct btrfs_block_rsv *rsv);
int btrfs_block_rsv_add(struct btrfs_root *root,
@@ -3172,12 +3212,12 @@ int btrfs_del_inode_ref(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
const char *name, int name_len,
u64 inode_objectid, u64 ref_objectid, u64 *index);
-struct btrfs_inode_ref *
-btrfs_lookup_inode_ref(struct btrfs_trans_handle *trans,
- struct btrfs_root *root,
- struct btrfs_path *path,
- const char *name, int name_len,
- u64 inode_objectid, u64 ref_objectid, int mod);
+int btrfs_get_inode_ref_index(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root,
+ struct btrfs_path *path,
+ const char *name, int name_len,
+ u64 inode_objectid, u64 ref_objectid, int mod,
+ u64 *ret_index);
int btrfs_insert_empty_inode(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct btrfs_path *path, u64 objectid);
@@ -3185,6 +3225,19 @@ int btrfs_lookup_inode(struct btrfs_trans_handle *trans, struct btrfs_root
*root, struct btrfs_path *path,
struct btrfs_key *location, int mod);
+struct btrfs_inode_extref *
+btrfs_lookup_inode_extref(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root,
+ struct btrfs_path *path,
+ const char *name, int name_len,
+ u64 inode_objectid, u64 ref_objectid, int ins_len,
+ int cow);
+
+int btrfs_find_name_in_ext_backref(struct btrfs_path *path,
+ u64 ref_objectid, const char *name,
+ int name_len,
+ struct btrfs_inode_extref **extref_ret);
+
/* file-item.c */
int btrfs_del_csums(struct btrfs_trans_handle *trans,
struct btrfs_root *root, u64 bytenr, u64 len);
@@ -3249,6 +3302,8 @@ int btrfs_unlink_subvol(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct inode *dir, u64 objectid,
const char *name, int name_len);
+int btrfs_truncate_page(struct inode *inode, loff_t from, loff_t len,
+ int front);
int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct inode *inode, u64 new_size,
@@ -3308,16 +3363,27 @@ 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);
+void btrfs_get_block_group_info(struct list_head *groups_list,
+ struct btrfs_ioctl_space_info *space);
+
/* 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, loff_t start, loff_t end, int datasync);
-int btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end,
- int skip_pinned);
+void btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end,
+ int skip_pinned);
+int btrfs_replace_extent_cache(struct inode *inode, struct extent_map *replace,
+ u64 start, u64 end, int skip_pinned,
+ int modified);
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);
+int __btrfs_drop_extents(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root, struct inode *inode,
+ struct btrfs_path *path, u64 start, u64 end,
+ u64 *drop_end, int drop_cache);
+int btrfs_drop_extents(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root, struct inode *inode, u64 start,
+ u64 end, int drop_cache);
int btrfs_mark_extent_written(struct btrfs_trans_handle *trans,
struct inode *inode, u64 start, u64 end);
int btrfs_release_file(struct inode *inode, struct file *file);
@@ -3378,6 +3444,11 @@ static inline void __btrfs_set_fs_incompat(struct btrfs_fs_info *fs_info,
}
}
+/*
+ * Call btrfs_abort_transaction as early as possible when an error condition is
+ * detected, that way the exact line number is reported.
+ */
+
#define btrfs_abort_transaction(trans, root, errno) \
do { \
__btrfs_abort_transaction(trans, root, __func__, \
diff --git a/fs/btrfs/delayed-inode.c b/fs/btrfs/delayed-inode.c
index 52c85e2..478f66b 100644
--- a/fs/btrfs/delayed-inode.c
+++ b/fs/btrfs/delayed-inode.c
@@ -29,7 +29,7 @@ static struct kmem_cache *delayed_node_cache;
int __init btrfs_delayed_inode_init(void)
{
- delayed_node_cache = kmem_cache_create("delayed_node",
+ delayed_node_cache = kmem_cache_create("btrfs_delayed_node",
sizeof(struct btrfs_delayed_node),
0,
SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD,
@@ -650,7 +650,7 @@ static int btrfs_delayed_inode_reserve_metadata(
* we're accounted for.
*/
if (!src_rsv || (!trans->bytes_reserved &&
- src_rsv != &root->fs_info->delalloc_block_rsv)) {
+ src_rsv->type != BTRFS_BLOCK_RSV_DELALLOC)) {
ret = btrfs_block_rsv_add_noflush(root, dst_rsv, num_bytes);
/*
* Since we're under a transaction reserve_metadata_bytes could
@@ -668,7 +668,7 @@ static int btrfs_delayed_inode_reserve_metadata(
num_bytes, 1);
}
return ret;
- } else if (src_rsv == &root->fs_info->delalloc_block_rsv) {
+ } else if (src_rsv->type == BTRFS_BLOCK_RSV_DELALLOC) {
spin_lock(&BTRFS_I(inode)->lock);
if (test_and_clear_bit(BTRFS_INODE_DELALLOC_META_RESERVED,
&BTRFS_I(inode)->runtime_flags)) {
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 22e98e0..7cda519 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -46,6 +46,10 @@
#include "check-integrity.h"
#include "rcu-string.h"
+#ifdef CONFIG_X86
+#include <asm/cpufeature.h>
+#endif
+
static struct extent_io_ops btree_extent_io_ops;
static void end_workqueue_fn(struct btrfs_work *work);
static void free_fs_root(struct btrfs_root *root);
@@ -217,26 +221,16 @@ static struct extent_map *btree_get_extent(struct inode *inode,
write_lock(&em_tree->lock);
ret = add_extent_mapping(em_tree, em);
if (ret == -EEXIST) {
- u64 failed_start = em->start;
- u64 failed_len = em->len;
-
free_extent_map(em);
em = lookup_extent_mapping(em_tree, start, len);
- if (em) {
- ret = 0;
- } else {
- em = lookup_extent_mapping(em_tree, failed_start,
- failed_len);
- ret = -EIO;
- }
+ if (!em)
+ em = ERR_PTR(-EIO);
} else if (ret) {
free_extent_map(em);
- em = NULL;
+ em = ERR_PTR(ret);
}
write_unlock(&em_tree->lock);
- if (ret)
- em = ERR_PTR(ret);
out:
return em;
}
@@ -439,10 +433,6 @@ static int csum_dirty_buffer(struct btrfs_root *root, struct page *page)
WARN_ON(1);
return 0;
}
- if (eb->pages[0] != page) {
- WARN_ON(1);
- return 0;
- }
if (!PageUptodate(page)) {
WARN_ON(1);
return 0;
@@ -869,10 +859,22 @@ static int __btree_submit_bio_done(struct inode *inode, int rw, struct bio *bio,
return btrfs_map_bio(BTRFS_I(inode)->root, rw, bio, mirror_num, 1);
}
+static int check_async_write(struct inode *inode, unsigned long bio_flags)
+{
+ if (bio_flags & EXTENT_BIO_TREE_LOG)
+ return 0;
+#ifdef CONFIG_X86
+ if (cpu_has_xmm4_2)
+ return 0;
+#endif
+ return 1;
+}
+
static int btree_submit_bio_hook(struct inode *inode, int rw, struct bio *bio,
int mirror_num, unsigned long bio_flags,
u64 bio_offset)
{
+ int async = check_async_write(inode, bio_flags);
int ret;
if (!(rw & REQ_WRITE)) {
@@ -887,6 +889,12 @@ static int btree_submit_bio_hook(struct inode *inode, int rw, struct bio *bio,
return ret;
return btrfs_map_bio(BTRFS_I(inode)->root, rw, bio,
mirror_num, 0);
+ } else if (!async) {
+ ret = btree_csum_one_bio(bio);
+ if (ret)
+ return ret;
+ return btrfs_map_bio(BTRFS_I(inode)->root, rw, bio,
+ mirror_num, 0);
}
/*
@@ -1168,8 +1176,8 @@ static void __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize,
atomic_set(&root->log_commit[0], 0);
atomic_set(&root->log_commit[1], 0);
atomic_set(&root->log_writers, 0);
+ atomic_set(&root->log_batch, 0);
atomic_set(&root->orphan_inodes, 0);
- root->log_batch = 0;
root->log_transid = 0;
root->last_log_commit = 0;
extent_io_tree_init(&root->dirty_log_pages,
@@ -1667,9 +1675,10 @@ static int transaction_kthread(void *arg)
spin_unlock(&root->fs_info->trans_lock);
/* If the file system is aborted, this will always fail. */
- trans = btrfs_join_transaction(root);
+ trans = btrfs_attach_transaction(root);
if (IS_ERR(trans)) {
- cannot_commit = true;
+ if (PTR_ERR(trans) != -ENOENT)
+ cannot_commit = true;
goto sleep;
}
if (transid == trans->transid) {
@@ -1994,13 +2003,11 @@ int open_ctree(struct super_block *sb,
INIT_LIST_HEAD(&fs_info->trans_list);
INIT_LIST_HEAD(&fs_info->dead_roots);
INIT_LIST_HEAD(&fs_info->delayed_iputs);
- INIT_LIST_HEAD(&fs_info->hashers);
INIT_LIST_HEAD(&fs_info->delalloc_inodes);
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->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);
@@ -2014,12 +2021,15 @@ int open_ctree(struct super_block *sb,
INIT_LIST_HEAD(&fs_info->space_info);
INIT_LIST_HEAD(&fs_info->tree_mod_seq_list);
btrfs_mapping_init(&fs_info->mapping_tree);
- btrfs_init_block_rsv(&fs_info->global_block_rsv);
- btrfs_init_block_rsv(&fs_info->delalloc_block_rsv);
- btrfs_init_block_rsv(&fs_info->trans_block_rsv);
- btrfs_init_block_rsv(&fs_info->chunk_block_rsv);
- btrfs_init_block_rsv(&fs_info->empty_block_rsv);
- btrfs_init_block_rsv(&fs_info->delayed_block_rsv);
+ btrfs_init_block_rsv(&fs_info->global_block_rsv,
+ BTRFS_BLOCK_RSV_GLOBAL);
+ btrfs_init_block_rsv(&fs_info->delalloc_block_rsv,
+ BTRFS_BLOCK_RSV_DELALLOC);
+ btrfs_init_block_rsv(&fs_info->trans_block_rsv, BTRFS_BLOCK_RSV_TRANS);
+ btrfs_init_block_rsv(&fs_info->chunk_block_rsv, BTRFS_BLOCK_RSV_CHUNK);
+ btrfs_init_block_rsv(&fs_info->empty_block_rsv, BTRFS_BLOCK_RSV_EMPTY);
+ btrfs_init_block_rsv(&fs_info->delayed_block_rsv,
+ BTRFS_BLOCK_RSV_DELOPS);
atomic_set(&fs_info->nr_async_submits, 0);
atomic_set(&fs_info->async_delalloc_pages, 0);
atomic_set(&fs_info->async_submit_draining, 0);
@@ -2491,6 +2501,8 @@ retry_root_backup:
printk(KERN_ERR "Failed to read block groups: %d\n", ret);
goto fail_block_groups;
}
+ fs_info->num_tolerated_disk_barrier_failures =
+ btrfs_calc_num_tolerated_disk_barrier_failures(fs_info);
fs_info->cleaner_kthread = kthread_run(cleaner_kthread, tree_root,
"btrfs-cleaner");
@@ -2874,12 +2886,10 @@ static int write_dev_flush(struct btrfs_device *device, int wait)
printk_in_rcu("btrfs: disabling barriers on dev %s\n",
rcu_str_deref(device->name));
device->nobarriers = 1;
- }
- if (!bio_flagged(bio, BIO_UPTODATE)) {
+ } else if (!bio_flagged(bio, BIO_UPTODATE)) {
ret = -EIO;
- if (!bio_flagged(bio, BIO_EOPNOTSUPP))
- btrfs_dev_stat_inc_and_print(device,
- BTRFS_DEV_STAT_FLUSH_ERRS);
+ btrfs_dev_stat_inc_and_print(device,
+ BTRFS_DEV_STAT_FLUSH_ERRS);
}
/* drop the reference from the wait == 0 run */
@@ -2918,14 +2928,15 @@ static int barrier_all_devices(struct btrfs_fs_info *info)
{
struct list_head *head;
struct btrfs_device *dev;
- int errors = 0;
+ int errors_send = 0;
+ int errors_wait = 0;
int ret;
/* send down all the barriers */
head = &info->fs_devices->devices;
list_for_each_entry_rcu(dev, head, dev_list) {
if (!dev->bdev) {
- errors++;
+ errors_send++;
continue;
}
if (!dev->in_fs_metadata || !dev->writeable)
@@ -2933,13 +2944,13 @@ static int barrier_all_devices(struct btrfs_fs_info *info)
ret = write_dev_flush(dev, 0);
if (ret)
- errors++;
+ errors_send++;
}
/* wait for all the barriers */
list_for_each_entry_rcu(dev, head, dev_list) {
if (!dev->bdev) {
- errors++;
+ errors_wait++;
continue;
}
if (!dev->in_fs_metadata || !dev->writeable)
@@ -2947,13 +2958,87 @@ static int barrier_all_devices(struct btrfs_fs_info *info)
ret = write_dev_flush(dev, 1);
if (ret)
- errors++;
+ errors_wait++;
}
- if (errors)
+ if (errors_send > info->num_tolerated_disk_barrier_failures ||
+ errors_wait > info->num_tolerated_disk_barrier_failures)
return -EIO;
return 0;
}
+int btrfs_calc_num_tolerated_disk_barrier_failures(
+ struct btrfs_fs_info *fs_info)
+{
+ struct btrfs_ioctl_space_info space;
+ struct btrfs_space_info *sinfo;
+ u64 types[] = {BTRFS_BLOCK_GROUP_DATA,
+ BTRFS_BLOCK_GROUP_SYSTEM,
+ BTRFS_BLOCK_GROUP_METADATA,
+ BTRFS_BLOCK_GROUP_DATA | BTRFS_BLOCK_GROUP_METADATA};
+ int num_types = 4;
+ int i;
+ int c;
+ int num_tolerated_disk_barrier_failures =
+ (int)fs_info->fs_devices->num_devices;
+
+ for (i = 0; i < num_types; i++) {
+ struct btrfs_space_info *tmp;
+
+ sinfo = NULL;
+ rcu_read_lock();
+ list_for_each_entry_rcu(tmp, &fs_info->space_info, list) {
+ if (tmp->flags == types[i]) {
+ sinfo = tmp;
+ break;
+ }
+ }
+ rcu_read_unlock();
+
+ if (!sinfo)
+ continue;
+
+ down_read(&sinfo->groups_sem);
+ for (c = 0; c < BTRFS_NR_RAID_TYPES; c++) {
+ if (!list_empty(&sinfo->block_groups[c])) {
+ u64 flags;
+
+ btrfs_get_block_group_info(
+ &sinfo->block_groups[c], &space);
+ if (space.total_bytes == 0 ||
+ space.used_bytes == 0)
+ continue;
+ flags = space.flags;
+ /*
+ * return
+ * 0: if dup, single or RAID0 is configured for
+ * any of metadata, system or data, else
+ * 1: if RAID5 is configured, or if RAID1 or
+ * RAID10 is configured and only two mirrors
+ * are used, else
+ * 2: if RAID6 is configured, else
+ * num_mirrors - 1: if RAID1 or RAID10 is
+ * configured and more than
+ * 2 mirrors are used.
+ */
+ if (num_tolerated_disk_barrier_failures > 0 &&
+ ((flags & (BTRFS_BLOCK_GROUP_DUP |
+ BTRFS_BLOCK_GROUP_RAID0)) ||
+ ((flags & BTRFS_BLOCK_GROUP_PROFILE_MASK)
+ == 0)))
+ num_tolerated_disk_barrier_failures = 0;
+ else if (num_tolerated_disk_barrier_failures > 1
+ &&
+ (flags & (BTRFS_BLOCK_GROUP_RAID1 |
+ BTRFS_BLOCK_GROUP_RAID10)))
+ num_tolerated_disk_barrier_failures = 1;
+ }
+ }
+ up_read(&sinfo->groups_sem);
+ }
+
+ return num_tolerated_disk_barrier_failures;
+}
+
int write_all_supers(struct btrfs_root *root, int max_mirrors)
{
struct list_head *head;
@@ -2976,8 +3061,16 @@ 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;
- if (do_barriers)
- barrier_all_devices(root->fs_info);
+ if (do_barriers) {
+ ret = barrier_all_devices(root->fs_info);
+ if (ret) {
+ mutex_unlock(
+ &root->fs_info->fs_devices->device_list_mutex);
+ btrfs_error(root->fs_info, ret,
+ "errors while submitting device barriers.");
+ return ret;
+ }
+ }
list_for_each_entry_rcu(dev, head, dev_list) {
if (!dev->bdev) {
@@ -3211,10 +3304,6 @@ int close_ctree(struct btrfs_root *root)
printk(KERN_INFO "btrfs: at unmount delalloc count %llu\n",
(unsigned long long)fs_info->delalloc_bytes);
}
- if (fs_info->total_ref_cache_size) {
- printk(KERN_INFO "btrfs: at umount reference cache size %llu\n",
- (unsigned long long)fs_info->total_ref_cache_size);
- }
free_extent_buffer(fs_info->extent_root->node);
free_extent_buffer(fs_info->extent_root->commit_root);
@@ -3360,52 +3449,6 @@ int btrfs_read_buffer(struct extent_buffer *buf, u64 parent_transid)
return btree_read_extent_buffer_pages(root, buf, 0, parent_transid);
}
-int btree_lock_page_hook(struct page *page, void *data,
- void (*flush_fn)(void *))
-{
- struct inode *inode = page->mapping->host;
- struct btrfs_root *root = BTRFS_I(inode)->root;
- struct extent_buffer *eb;
-
- /*
- * We culled this eb but the page is still hanging out on the mapping,
- * carry on.
- */
- if (!PagePrivate(page))
- goto out;
-
- eb = (struct extent_buffer *)page->private;
- if (!eb) {
- WARN_ON(1);
- goto out;
- }
- if (page != eb->pages[0])
- goto out;
-
- if (!btrfs_try_tree_write_lock(eb)) {
- flush_fn(data);
- btrfs_tree_lock(eb);
- }
- btrfs_set_header_flag(eb, BTRFS_HEADER_FLAG_WRITTEN);
-
- if (test_and_clear_bit(EXTENT_BUFFER_DIRTY, &eb->bflags)) {
- spin_lock(&root->fs_info->delalloc_lock);
- if (root->fs_info->dirty_metadata_bytes >= eb->len)
- root->fs_info->dirty_metadata_bytes -= eb->len;
- else
- WARN_ON(1);
- spin_unlock(&root->fs_info->delalloc_lock);
- }
-
- btrfs_tree_unlock(eb);
-out:
- if (!trylock_page(page)) {
- flush_fn(data);
- lock_page(page);
- }
- return 0;
-}
-
static int btrfs_check_super_valid(struct btrfs_fs_info *fs_info,
int read_only)
{
@@ -3608,7 +3651,7 @@ static int btrfs_destroy_marked_extents(struct btrfs_root *root,
while (1) {
ret = find_first_extent_bit(dirty_pages, start, &start, &end,
- mark);
+ mark, NULL);
if (ret)
break;
@@ -3663,7 +3706,7 @@ static int btrfs_destroy_pinned_extent(struct btrfs_root *root,
again:
while (1) {
ret = find_first_extent_bit(unpin, 0, &start, &end,
- EXTENT_DIRTY);
+ EXTENT_DIRTY, NULL);
if (ret)
break;
@@ -3800,7 +3843,6 @@ int btrfs_cleanup_transaction(struct btrfs_root *root)
}
static struct extent_io_ops btree_extent_io_ops = {
- .write_cache_pages_lock_hook = btree_lock_page_hook,
.readpage_end_io_hook = btree_readpage_end_io_hook,
.readpage_io_failed_hook = btree_io_failed_hook,
.submit_bio_hook = btree_submit_bio_hook,
diff --git a/fs/btrfs/disk-io.h b/fs/btrfs/disk-io.h
index c5b00a7..2025a91 100644
--- a/fs/btrfs/disk-io.h
+++ b/fs/btrfs/disk-io.h
@@ -95,6 +95,8 @@ struct btrfs_root *btrfs_create_tree(struct btrfs_trans_handle *trans,
u64 objectid);
int btree_lock_page_hook(struct page *page, void *data,
void (*flush_fn)(void *));
+int btrfs_calc_num_tolerated_disk_barrier_failures(
+ struct btrfs_fs_info *fs_info);
#ifdef CONFIG_DEBUG_LOCK_ALLOC
void btrfs_init_lockdep(void);
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index ba58024..3d3e2c1 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -94,8 +94,8 @@ static int alloc_reserved_tree_block(struct btrfs_trans_handle *trans,
u64 flags, struct btrfs_disk_key *key,
int level, struct btrfs_key *ins);
static int do_chunk_alloc(struct btrfs_trans_handle *trans,
- struct btrfs_root *extent_root, u64 alloc_bytes,
- u64 flags, int force);
+ struct btrfs_root *extent_root, u64 flags,
+ int force);
static int find_next_key(struct btrfs_path *path, int level,
struct btrfs_key *key);
static void dump_space_info(struct btrfs_space_info *info, u64 bytes,
@@ -312,7 +312,8 @@ static u64 add_new_free_space(struct btrfs_block_group_cache *block_group,
while (start < end) {
ret = find_first_extent_bit(info->pinned_extents, start,
&extent_start, &extent_end,
- EXTENT_DIRTY | EXTENT_UPTODATE);
+ EXTENT_DIRTY | EXTENT_UPTODATE,
+ NULL);
if (ret)
break;
@@ -2361,10 +2362,6 @@ static noinline int run_clustered_refs(struct btrfs_trans_handle *trans,
}
next:
- do_chunk_alloc(trans, fs_info->extent_root,
- 2 * 1024 * 1024,
- btrfs_get_alloc_profile(root, 0),
- CHUNK_ALLOC_NO_FORCE);
cond_resched();
spin_lock(&delayed_refs->lock);
}
@@ -2478,10 +2475,6 @@ int btrfs_run_delayed_refs(struct btrfs_trans_handle *trans,
if (root == root->fs_info->extent_root)
root = root->fs_info->tree_root;
- do_chunk_alloc(trans, root->fs_info->extent_root,
- 2 * 1024 * 1024, btrfs_get_alloc_profile(root, 0),
- CHUNK_ALLOC_NO_FORCE);
-
btrfs_delayed_refs_qgroup_accounting(trans, root->fs_info);
delayed_refs = &trans->transaction->delayed_refs;
@@ -2551,6 +2544,12 @@ again:
}
if (run_all) {
+ if (!list_empty(&trans->new_bgs)) {
+ spin_unlock(&delayed_refs->lock);
+ btrfs_create_pending_block_groups(trans, root);
+ spin_lock(&delayed_refs->lock);
+ }
+
node = rb_first(&delayed_refs->root);
if (!node)
goto out;
@@ -3406,7 +3405,6 @@ alloc:
return PTR_ERR(trans);
ret = do_chunk_alloc(trans, root->fs_info->extent_root,
- bytes + 2 * 1024 * 1024,
alloc_target,
CHUNK_ALLOC_NO_FORCE);
btrfs_end_transaction(trans, root);
@@ -3488,8 +3486,7 @@ static void force_metadata_allocation(struct btrfs_fs_info *info)
}
static int should_alloc_chunk(struct btrfs_root *root,
- struct btrfs_space_info *sinfo, u64 alloc_bytes,
- int force)
+ struct btrfs_space_info *sinfo, int force)
{
struct btrfs_block_rsv *global_rsv = &root->fs_info->global_block_rsv;
u64 num_bytes = sinfo->total_bytes - sinfo->bytes_readonly;
@@ -3504,7 +3501,8 @@ static int should_alloc_chunk(struct btrfs_root *root,
* and purposes it's used space. Don't worry about locking the
* global_rsv, it doesn't change except when the transaction commits.
*/
- num_allocated += global_rsv->size;
+ if (sinfo->flags & BTRFS_BLOCK_GROUP_METADATA)
+ num_allocated += global_rsv->size;
/*
* in limited mode, we want to have some free space up to
@@ -3518,15 +3516,8 @@ static int should_alloc_chunk(struct btrfs_root *root,
if (num_bytes - num_allocated < thresh)
return 1;
}
- thresh = btrfs_super_total_bytes(root->fs_info->super_copy);
- /* 256MB or 2% of the FS */
- thresh = max_t(u64, 256 * 1024 * 1024, div_factor_fine(thresh, 2));
- /* system chunks need a much small threshold */
- if (sinfo->flags & BTRFS_BLOCK_GROUP_SYSTEM)
- thresh = 32 * 1024 * 1024;
-
- if (num_bytes > thresh && sinfo->bytes_used < div_factor(num_bytes, 8))
+ if (num_allocated + 2 * 1024 * 1024 < div_factor(num_bytes, 8))
return 0;
return 1;
}
@@ -3576,8 +3567,7 @@ static void check_system_chunk(struct btrfs_trans_handle *trans,
}
static int do_chunk_alloc(struct btrfs_trans_handle *trans,
- struct btrfs_root *extent_root, u64 alloc_bytes,
- u64 flags, int force)
+ struct btrfs_root *extent_root, u64 flags, int force)
{
struct btrfs_space_info *space_info;
struct btrfs_fs_info *fs_info = extent_root->fs_info;
@@ -3601,7 +3591,7 @@ again:
return 0;
}
- if (!should_alloc_chunk(extent_root, space_info, alloc_bytes, force)) {
+ if (!should_alloc_chunk(extent_root, space_info, force)) {
spin_unlock(&space_info->lock);
return 0;
} else if (space_info->chunk_alloc) {
@@ -3669,6 +3659,46 @@ out:
return ret;
}
+static int can_overcommit(struct btrfs_root *root,
+ struct btrfs_space_info *space_info, u64 bytes,
+ int flush)
+{
+ u64 profile = btrfs_get_alloc_profile(root, 0);
+ u64 avail;
+ u64 used;
+
+ used = space_info->bytes_used + space_info->bytes_reserved +
+ space_info->bytes_pinned + space_info->bytes_readonly +
+ space_info->bytes_may_use;
+
+ spin_lock(&root->fs_info->free_chunk_lock);
+ avail = root->fs_info->free_chunk_space;
+ spin_unlock(&root->fs_info->free_chunk_lock);
+
+ /*
+ * If we have dup, raid1 or raid10 then only half of the free
+ * space is actually useable.
+ */
+ if (profile & (BTRFS_BLOCK_GROUP_DUP |
+ BTRFS_BLOCK_GROUP_RAID1 |
+ BTRFS_BLOCK_GROUP_RAID10))
+ avail >>= 1;
+
+ /*
+ * If we aren't flushing don't let us overcommit too much, say
+ * 1/8th of the space. If we can flush, let it overcommit up to
+ * 1/2 of the space.
+ */
+ if (flush)
+ avail >>= 3;
+ else
+ avail >>= 1;
+
+ if (used + bytes < space_info->total_bytes + avail)
+ return 1;
+ return 0;
+}
+
/*
* shrink metadata reservation for delalloc
*/
@@ -3693,7 +3723,7 @@ static void shrink_delalloc(struct btrfs_root *root, u64 to_reclaim, u64 orig,
if (delalloc_bytes == 0) {
if (trans)
return;
- btrfs_wait_ordered_extents(root, 0, 0);
+ btrfs_wait_ordered_extents(root, 0);
return;
}
@@ -3703,11 +3733,15 @@ static void shrink_delalloc(struct btrfs_root *root, u64 to_reclaim, u64 orig,
writeback_inodes_sb_nr_if_idle(root->fs_info->sb, nr_pages,
WB_REASON_FS_FREE_SPACE);
+ /*
+ * We need to wait for the async pages to actually start before
+ * we do anything.
+ */
+ wait_event(root->fs_info->async_submit_wait,
+ !atomic_read(&root->fs_info->async_delalloc_pages));
+
spin_lock(&space_info->lock);
- if (space_info->bytes_used + space_info->bytes_reserved +
- space_info->bytes_pinned + space_info->bytes_readonly +
- space_info->bytes_may_use + orig <=
- space_info->total_bytes) {
+ if (can_overcommit(root, space_info, orig, !trans)) {
spin_unlock(&space_info->lock);
break;
}
@@ -3715,7 +3749,7 @@ static void shrink_delalloc(struct btrfs_root *root, u64 to_reclaim, u64 orig,
loops++;
if (wait_ordered && !trans) {
- btrfs_wait_ordered_extents(root, 0, 0);
+ btrfs_wait_ordered_extents(root, 0);
} else {
time_left = schedule_timeout_killable(1);
if (time_left)
@@ -3784,11 +3818,12 @@ commit:
}
enum flush_state {
- FLUSH_DELALLOC = 1,
- FLUSH_DELALLOC_WAIT = 2,
- FLUSH_DELAYED_ITEMS_NR = 3,
- FLUSH_DELAYED_ITEMS = 4,
- COMMIT_TRANS = 5,
+ FLUSH_DELAYED_ITEMS_NR = 1,
+ FLUSH_DELAYED_ITEMS = 2,
+ FLUSH_DELALLOC = 3,
+ FLUSH_DELALLOC_WAIT = 4,
+ ALLOC_CHUNK = 5,
+ COMMIT_TRANS = 6,
};
static int flush_space(struct btrfs_root *root,
@@ -3800,11 +3835,6 @@ static int flush_space(struct btrfs_root *root,
int ret = 0;
switch (state) {
- case FLUSH_DELALLOC:
- case FLUSH_DELALLOC_WAIT:
- shrink_delalloc(root, num_bytes, orig_bytes,
- state == FLUSH_DELALLOC_WAIT);
- break;
case FLUSH_DELAYED_ITEMS_NR:
case FLUSH_DELAYED_ITEMS:
if (state == FLUSH_DELAYED_ITEMS_NR) {
@@ -3825,6 +3855,24 @@ static int flush_space(struct btrfs_root *root,
ret = btrfs_run_delayed_items_nr(trans, root, nr);
btrfs_end_transaction(trans, root);
break;
+ case FLUSH_DELALLOC:
+ case FLUSH_DELALLOC_WAIT:
+ shrink_delalloc(root, num_bytes, orig_bytes,
+ state == FLUSH_DELALLOC_WAIT);
+ break;
+ case ALLOC_CHUNK:
+ trans = btrfs_join_transaction(root);
+ if (IS_ERR(trans)) {
+ ret = PTR_ERR(trans);
+ break;
+ }
+ ret = do_chunk_alloc(trans, root->fs_info->extent_root,
+ btrfs_get_alloc_profile(root, 0),
+ CHUNK_ALLOC_NO_FORCE);
+ btrfs_end_transaction(trans, root);
+ if (ret == -ENOSPC)
+ ret = 0;
+ break;
case COMMIT_TRANS:
ret = may_commit_transaction(root, space_info, orig_bytes, 0);
break;
@@ -3856,10 +3904,9 @@ static int reserve_metadata_bytes(struct btrfs_root *root,
struct btrfs_space_info *space_info = block_rsv->space_info;
u64 used;
u64 num_bytes = orig_bytes;
- int flush_state = FLUSH_DELALLOC;
+ int flush_state = FLUSH_DELAYED_ITEMS_NR;
int ret = 0;
bool flushing = false;
- bool committed = false;
again:
ret = 0;
@@ -3922,57 +3969,12 @@ again:
(orig_bytes * 2);
}
- if (ret) {
- u64 profile = btrfs_get_alloc_profile(root, 0);
- u64 avail;
-
- /*
- * If we have a lot of space that's pinned, don't bother doing
- * the overcommit dance yet and just commit the transaction.
- */
- avail = (space_info->total_bytes - space_info->bytes_used) * 8;
- do_div(avail, 10);
- if (space_info->bytes_pinned >= avail && flush && !committed) {
- space_info->flush = 1;
- flushing = true;
- spin_unlock(&space_info->lock);
- ret = may_commit_transaction(root, space_info,
- orig_bytes, 1);
- if (ret)
- goto out;
- committed = true;
- goto again;
- }
-
- spin_lock(&root->fs_info->free_chunk_lock);
- avail = root->fs_info->free_chunk_space;
-
- /*
- * If we have dup, raid1 or raid10 then only half of the free
- * space is actually useable.
- */
- if (profile & (BTRFS_BLOCK_GROUP_DUP |
- BTRFS_BLOCK_GROUP_RAID1 |
- BTRFS_BLOCK_GROUP_RAID10))
- avail >>= 1;
-
- /*
- * If we aren't flushing don't let us overcommit too much, say
- * 1/8th of the space. If we can flush, let it overcommit up to
- * 1/2 of the space.
- */
- if (flush)
- avail >>= 3;
- else
- avail >>= 1;
- spin_unlock(&root->fs_info->free_chunk_lock);
-
- if (used + num_bytes < space_info->total_bytes + avail) {
- space_info->bytes_may_use += orig_bytes;
- trace_btrfs_space_reservation(root->fs_info,
- "space_info", space_info->flags, orig_bytes, 1);
- ret = 0;
- }
+ if (ret && can_overcommit(root, space_info, orig_bytes, flush)) {
+ space_info->bytes_may_use += orig_bytes;
+ trace_btrfs_space_reservation(root->fs_info, "space_info",
+ space_info->flags, orig_bytes,
+ 1);
+ ret = 0;
}
/*
@@ -4114,13 +4116,15 @@ static int block_rsv_migrate_bytes(struct btrfs_block_rsv *src,
return 0;
}
-void btrfs_init_block_rsv(struct btrfs_block_rsv *rsv)
+void btrfs_init_block_rsv(struct btrfs_block_rsv *rsv, unsigned short type)
{
memset(rsv, 0, sizeof(*rsv));
spin_lock_init(&rsv->lock);
+ rsv->type = type;
}
-struct btrfs_block_rsv *btrfs_alloc_block_rsv(struct btrfs_root *root)
+struct btrfs_block_rsv *btrfs_alloc_block_rsv(struct btrfs_root *root,
+ unsigned short type)
{
struct btrfs_block_rsv *block_rsv;
struct btrfs_fs_info *fs_info = root->fs_info;
@@ -4129,7 +4133,7 @@ struct btrfs_block_rsv *btrfs_alloc_block_rsv(struct btrfs_root *root)
if (!block_rsv)
return NULL;
- btrfs_init_block_rsv(block_rsv);
+ btrfs_init_block_rsv(block_rsv, type);
block_rsv->space_info = __find_space_info(fs_info,
BTRFS_BLOCK_GROUP_METADATA);
return block_rsv;
@@ -4138,6 +4142,8 @@ struct btrfs_block_rsv *btrfs_alloc_block_rsv(struct btrfs_root *root)
void btrfs_free_block_rsv(struct btrfs_root *root,
struct btrfs_block_rsv *rsv)
{
+ if (!rsv)
+ return;
btrfs_block_rsv_release(root, rsv, (u64)-1);
kfree(rsv);
}
@@ -4416,10 +4422,10 @@ int btrfs_snap_reserve_metadata(struct btrfs_trans_handle *trans,
struct btrfs_block_rsv *src_rsv = get_block_rsv(trans, root);
struct btrfs_block_rsv *dst_rsv = &pending->block_rsv;
/*
- * two for root back/forward refs, two for directory entries
- * and one for root of the snapshot.
+ * two for root back/forward refs, two for directory entries,
+ * one for root of the snapshot and one for parent inode.
*/
- u64 num_bytes = btrfs_calc_trans_metadata_size(root, 5);
+ u64 num_bytes = btrfs_calc_trans_metadata_size(root, 6);
dst_rsv->space_info = src_rsv->space_info;
return block_rsv_migrate_bytes(src_rsv, dst_rsv, num_bytes);
}
@@ -5018,7 +5024,7 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans,
while (1) {
ret = find_first_extent_bit(unpin, 0, &start, &end,
- EXTENT_DIRTY);
+ EXTENT_DIRTY, NULL);
if (ret)
break;
@@ -5096,8 +5102,10 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
ret = remove_extent_backref(trans, extent_root, path,
NULL, refs_to_drop,
is_data);
- if (ret)
- goto abort;
+ if (ret) {
+ btrfs_abort_transaction(trans, extent_root, ret);
+ goto out;
+ }
btrfs_release_path(path);
path->leave_spinning = 1;
@@ -5115,8 +5123,10 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
btrfs_print_leaf(extent_root,
path->nodes[0]);
}
- if (ret < 0)
- goto abort;
+ if (ret < 0) {
+ btrfs_abort_transaction(trans, extent_root, ret);
+ goto out;
+ }
extent_slot = path->slots[0];
}
} else if (ret == -ENOENT) {
@@ -5130,7 +5140,8 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
(unsigned long long)owner_objectid,
(unsigned long long)owner_offset);
} else {
- goto abort;
+ btrfs_abort_transaction(trans, extent_root, ret);
+ goto out;
}
leaf = path->nodes[0];
@@ -5140,8 +5151,10 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
BUG_ON(found_extent || extent_slot != path->slots[0]);
ret = convert_extent_item_v0(trans, extent_root, path,
owner_objectid, 0);
- if (ret < 0)
- goto abort;
+ if (ret < 0) {
+ btrfs_abort_transaction(trans, extent_root, ret);
+ goto out;
+ }
btrfs_release_path(path);
path->leave_spinning = 1;
@@ -5158,8 +5171,11 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
(unsigned long long)bytenr);
btrfs_print_leaf(extent_root, path->nodes[0]);
}
- if (ret < 0)
- goto abort;
+ if (ret < 0) {
+ btrfs_abort_transaction(trans, extent_root, ret);
+ goto out;
+ }
+
extent_slot = path->slots[0];
leaf = path->nodes[0];
item_size = btrfs_item_size_nr(leaf, extent_slot);
@@ -5196,8 +5212,10 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
ret = remove_extent_backref(trans, extent_root, path,
iref, refs_to_drop,
is_data);
- if (ret)
- goto abort;
+ if (ret) {
+ btrfs_abort_transaction(trans, extent_root, ret);
+ goto out;
+ }
}
} else {
if (found_extent) {
@@ -5214,27 +5232,29 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
ret = btrfs_del_items(trans, extent_root, path, path->slots[0],
num_to_del);
- if (ret)
- goto abort;
+ if (ret) {
+ btrfs_abort_transaction(trans, extent_root, ret);
+ goto out;
+ }
btrfs_release_path(path);
if (is_data) {
ret = btrfs_del_csums(trans, root, bytenr, num_bytes);
- if (ret)
- goto abort;
+ if (ret) {
+ btrfs_abort_transaction(trans, extent_root, ret);
+ goto out;
+ }
}
ret = update_block_group(trans, root, bytenr, num_bytes, 0);
- if (ret)
- goto abort;
+ if (ret) {
+ btrfs_abort_transaction(trans, extent_root, ret);
+ goto out;
+ }
}
out:
btrfs_free_path(path);
return ret;
-
-abort:
- btrfs_abort_transaction(trans, extent_root, ret);
- goto out;
}
/*
@@ -5497,8 +5517,6 @@ static noinline int find_free_extent(struct btrfs_trans_handle *trans,
struct btrfs_block_group_cache *used_block_group;
u64 search_start = 0;
int empty_cluster = 2 * 1024 * 1024;
- int allowed_chunk_alloc = 0;
- int done_chunk_alloc = 0;
struct btrfs_space_info *space_info;
int loop = 0;
int index = 0;
@@ -5530,9 +5548,6 @@ static noinline int find_free_extent(struct btrfs_trans_handle *trans,
if (btrfs_mixed_space_info(space_info))
use_cluster = false;
- if (orig_root->ref_cows || empty_size)
- allowed_chunk_alloc = 1;
-
if (data & BTRFS_BLOCK_GROUP_METADATA && use_cluster) {
last_ptr = &root->fs_info->meta_alloc_cluster;
if (!btrfs_test_opt(root, SSD))
@@ -5806,10 +5821,6 @@ checks:
trace_btrfs_reserve_extent(orig_root, block_group,
search_start, num_bytes);
- if (offset < search_start)
- btrfs_add_free_space(used_block_group, offset,
- search_start - offset);
- BUG_ON(offset > search_start);
if (used_block_group != block_group)
btrfs_put_block_group(used_block_group);
btrfs_put_block_group(block_group);
@@ -5842,34 +5853,17 @@ loop:
index = 0;
loop++;
if (loop == LOOP_ALLOC_CHUNK) {
- if (allowed_chunk_alloc) {
- ret = do_chunk_alloc(trans, root, num_bytes +
- 2 * 1024 * 1024, data,
- CHUNK_ALLOC_LIMITED);
- /*
- * Do not bail out on ENOSPC since we
- * can do more things.
- */
- if (ret < 0 && ret != -ENOSPC) {
- btrfs_abort_transaction(trans,
- root, ret);
- goto out;
- }
- 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;
+ ret = do_chunk_alloc(trans, root, data,
+ CHUNK_ALLOC_FORCE);
+ /*
+ * Do not bail out on ENOSPC since we
+ * can do more things.
+ */
+ if (ret < 0 && ret != -ENOSPC) {
+ btrfs_abort_transaction(trans,
+ root, ret);
+ goto out;
}
-
- /*
- * 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) {
@@ -5944,20 +5938,6 @@ int btrfs_reserve_extent(struct btrfs_trans_handle *trans,
data = btrfs_get_alloc_profile(root, data);
again:
- /*
- * the only place that sets empty_size is btrfs_realloc_node, which
- * is not called recursively on allocations
- */
- if (empty_size || root->ref_cows) {
- ret = do_chunk_alloc(trans, root->fs_info->extent_root,
- num_bytes + 2 * 1024 * 1024, data,
- CHUNK_ALLOC_NO_FORCE);
- if (ret < 0 && ret != -ENOSPC) {
- btrfs_abort_transaction(trans, root, ret);
- return ret;
- }
- }
-
WARN_ON(num_bytes < root->sectorsize);
ret = find_free_extent(trans, root, num_bytes, empty_size,
hint_byte, ins, data);
@@ -5967,12 +5947,6 @@ again:
num_bytes = num_bytes >> 1;
num_bytes = num_bytes & ~(root->sectorsize - 1);
num_bytes = max(num_bytes, min_alloc_size);
- ret = do_chunk_alloc(trans, root->fs_info->extent_root,
- num_bytes, data, CHUNK_ALLOC_FORCE);
- if (ret < 0 && ret != -ENOSPC) {
- btrfs_abort_transaction(trans, root, ret);
- return ret;
- }
if (num_bytes == min_alloc_size)
final_tried = true;
goto again;
@@ -6314,7 +6288,7 @@ use_block_rsv(struct btrfs_trans_handle *trans,
ret = block_rsv_use_bytes(block_rsv, blocksize);
if (!ret)
return block_rsv;
- if (ret) {
+ if (ret && !block_rsv->failfast) {
static DEFINE_RATELIMIT_STATE(_rs,
DEFAULT_RATELIMIT_INTERVAL,
/*DEFAULT_RATELIMIT_BURST*/ 2);
@@ -7279,7 +7253,7 @@ int btrfs_set_block_group_ro(struct btrfs_root *root,
alloc_flags = update_block_group_flags(root, cache->flags);
if (alloc_flags != cache->flags) {
- ret = do_chunk_alloc(trans, root, 2 * 1024 * 1024, alloc_flags,
+ ret = do_chunk_alloc(trans, root, alloc_flags,
CHUNK_ALLOC_FORCE);
if (ret < 0)
goto out;
@@ -7289,7 +7263,7 @@ int btrfs_set_block_group_ro(struct btrfs_root *root,
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,
+ ret = do_chunk_alloc(trans, root, alloc_flags,
CHUNK_ALLOC_FORCE);
if (ret < 0)
goto out;
@@ -7303,7 +7277,7 @@ int btrfs_force_chunk_alloc(struct btrfs_trans_handle *trans,
struct btrfs_root *root, u64 type)
{
u64 alloc_flags = get_alloc_profile(root, type);
- return do_chunk_alloc(trans, root, 2 * 1024 * 1024, alloc_flags,
+ return do_chunk_alloc(trans, root, alloc_flags,
CHUNK_ALLOC_FORCE);
}
@@ -7810,6 +7784,34 @@ error:
return ret;
}
+void btrfs_create_pending_block_groups(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root)
+{
+ struct btrfs_block_group_cache *block_group, *tmp;
+ struct btrfs_root *extent_root = root->fs_info->extent_root;
+ struct btrfs_block_group_item item;
+ struct btrfs_key key;
+ int ret = 0;
+
+ list_for_each_entry_safe(block_group, tmp, &trans->new_bgs,
+ new_bg_list) {
+ list_del_init(&block_group->new_bg_list);
+
+ if (ret)
+ continue;
+
+ spin_lock(&block_group->lock);
+ memcpy(&item, &block_group->item, sizeof(item));
+ memcpy(&key, &block_group->key, sizeof(key));
+ spin_unlock(&block_group->lock);
+
+ ret = btrfs_insert_item(trans, extent_root, &key, &item,
+ sizeof(item));
+ if (ret)
+ btrfs_abort_transaction(trans, extent_root, ret);
+ }
+}
+
int btrfs_make_block_group(struct btrfs_trans_handle *trans,
struct btrfs_root *root, u64 bytes_used,
u64 type, u64 chunk_objectid, u64 chunk_offset,
@@ -7843,6 +7845,7 @@ int btrfs_make_block_group(struct btrfs_trans_handle *trans,
spin_lock_init(&cache->lock);
INIT_LIST_HEAD(&cache->list);
INIT_LIST_HEAD(&cache->cluster_list);
+ INIT_LIST_HEAD(&cache->new_bg_list);
btrfs_init_free_space_ctl(cache);
@@ -7874,12 +7877,7 @@ int btrfs_make_block_group(struct btrfs_trans_handle *trans,
ret = btrfs_add_block_group_cache(root->fs_info, cache);
BUG_ON(ret); /* Logic error */
- ret = btrfs_insert_item(trans, extent_root, &cache->key, &cache->item,
- sizeof(cache->item));
- if (ret) {
- btrfs_abort_transaction(trans, extent_root, ret);
- return ret;
- }
+ list_add_tail(&cache->new_bg_list, &trans->new_bgs);
set_avail_alloc_bits(extent_root->fs_info, type);
diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c
index b08ea47..8036d3a 100644
--- a/fs/btrfs/extent_io.c
+++ b/fs/btrfs/extent_io.c
@@ -45,6 +45,7 @@ struct extent_page_data {
struct bio *bio;
struct extent_io_tree *tree;
get_extent_t *get_extent;
+ unsigned long bio_flags;
/* tells writepage not to lock the state bits for this range
* it still does the unlocking
@@ -64,13 +65,13 @@ tree_fs_info(struct extent_io_tree *tree)
int __init extent_io_init(void)
{
- extent_state_cache = kmem_cache_create("extent_state",
+ extent_state_cache = kmem_cache_create("btrfs_extent_state",
sizeof(struct extent_state), 0,
SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD, NULL);
if (!extent_state_cache)
return -ENOMEM;
- extent_buffer_cache = kmem_cache_create("extent_buffers",
+ extent_buffer_cache = kmem_cache_create("btrfs_extent_buffer",
sizeof(struct extent_buffer), 0,
SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD, NULL);
if (!extent_buffer_cache)
@@ -942,6 +943,7 @@ int set_extent_bit(struct extent_io_tree *tree, u64 start, u64 end, int bits,
* @end: the end offset in bytes (inclusive)
* @bits: the bits to set in this range
* @clear_bits: the bits to clear in this range
+ * @cached_state: state that we're going to cache
* @mask: the allocation mask
*
* This will go through and set bits for the given range. If any states exist
@@ -951,7 +953,8 @@ int set_extent_bit(struct extent_io_tree *tree, u64 start, u64 end, int bits,
* boundary bits like LOCK.
*/
int convert_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
- int bits, int clear_bits, gfp_t mask)
+ int bits, int clear_bits,
+ struct extent_state **cached_state, gfp_t mask)
{
struct extent_state *state;
struct extent_state *prealloc = NULL;
@@ -968,6 +971,15 @@ again:
}
spin_lock(&tree->lock);
+ if (cached_state && *cached_state) {
+ state = *cached_state;
+ if (state->start <= start && state->end > start &&
+ state->tree) {
+ node = &state->rb_node;
+ goto hit_next;
+ }
+ }
+
/*
* this search will find all the extents that end after
* our range starts.
@@ -998,6 +1010,7 @@ hit_next:
*/
if (state->start == start && state->end <= end) {
set_state_bits(tree, state, &bits);
+ cache_state(state, cached_state);
state = clear_state_bit(tree, state, &clear_bits, 0);
if (last_end == (u64)-1)
goto out;
@@ -1038,6 +1051,7 @@ hit_next:
goto out;
if (state->end <= end) {
set_state_bits(tree, state, &bits);
+ cache_state(state, cached_state);
state = clear_state_bit(tree, state, &clear_bits, 0);
if (last_end == (u64)-1)
goto out;
@@ -1076,6 +1090,7 @@ hit_next:
&bits);
if (err)
extent_io_tree_panic(tree, err);
+ cache_state(prealloc, cached_state);
prealloc = NULL;
start = this_end + 1;
goto search_again;
@@ -1098,6 +1113,7 @@ hit_next:
extent_io_tree_panic(tree, err);
set_state_bits(tree, prealloc, &bits);
+ cache_state(prealloc, cached_state);
clear_state_bit(tree, prealloc, &clear_bits, 0);
prealloc = NULL;
goto out;
@@ -1150,6 +1166,14 @@ int set_extent_delalloc(struct extent_io_tree *tree, u64 start, u64 end,
NULL, cached_state, mask);
}
+int set_extent_defrag(struct extent_io_tree *tree, u64 start, u64 end,
+ struct extent_state **cached_state, gfp_t mask)
+{
+ return set_extent_bit(tree, start, end,
+ EXTENT_DELALLOC | EXTENT_UPTODATE | EXTENT_DEFRAG,
+ NULL, cached_state, mask);
+}
+
int clear_extent_dirty(struct extent_io_tree *tree, u64 start, u64 end,
gfp_t mask)
{
@@ -1294,18 +1318,42 @@ out:
* If nothing was found, 1 is returned. If found something, return 0.
*/
int find_first_extent_bit(struct extent_io_tree *tree, u64 start,
- u64 *start_ret, u64 *end_ret, int bits)
+ u64 *start_ret, u64 *end_ret, int bits,
+ struct extent_state **cached_state)
{
struct extent_state *state;
+ struct rb_node *n;
int ret = 1;
spin_lock(&tree->lock);
+ if (cached_state && *cached_state) {
+ state = *cached_state;
+ if (state->end == start - 1 && state->tree) {
+ n = rb_next(&state->rb_node);
+ while (n) {
+ state = rb_entry(n, struct extent_state,
+ rb_node);
+ if (state->state & bits)
+ goto got_it;
+ n = rb_next(n);
+ }
+ free_extent_state(*cached_state);
+ *cached_state = NULL;
+ goto out;
+ }
+ free_extent_state(*cached_state);
+ *cached_state = NULL;
+ }
+
state = find_first_extent_bit_state(tree, start, bits);
+got_it:
if (state) {
+ cache_state(state, cached_state);
*start_ret = state->start;
*end_ret = state->end;
ret = 0;
}
+out:
spin_unlock(&tree->lock);
return ret;
}
@@ -2068,7 +2116,7 @@ static int bio_readpage_error(struct bio *failed_bio, struct page *page,
}
read_unlock(&em_tree->lock);
- if (!em || IS_ERR(em)) {
+ if (!em) {
kfree(failrec);
return -EIO;
}
@@ -2304,8 +2352,8 @@ static void end_bio_extent_readpage(struct bio *bio, int err)
struct extent_state *cached = NULL;
struct extent_state *state;
- pr_debug("end_bio_extent_readpage: bi_vcnt=%d, idx=%d, err=%d, "
- "mirror=%ld\n", bio->bi_vcnt, bio->bi_idx, err,
+ pr_debug("end_bio_extent_readpage: bi_sector=%llu, err=%d, "
+ "mirror=%ld\n", (u64)bio->bi_sector, err,
(long int)bio->bi_bdev);
tree = &BTRFS_I(page->mapping->host)->io_tree;
@@ -2709,12 +2757,15 @@ static int __extent_read_full_page(struct extent_io_tree *tree,
end_bio_extent_readpage, mirror_num,
*bio_flags,
this_bio_flag);
- BUG_ON(ret == -ENOMEM);
- nr++;
- *bio_flags = this_bio_flag;
+ if (!ret) {
+ nr++;
+ *bio_flags = this_bio_flag;
+ }
}
- if (ret)
+ if (ret) {
SetPageError(page);
+ unlock_extent(tree, cur, cur + iosize - 1);
+ }
cur = cur + iosize;
pg_offset += iosize;
}
@@ -3161,12 +3212,16 @@ static int write_one_eb(struct extent_buffer *eb,
struct block_device *bdev = fs_info->fs_devices->latest_bdev;
u64 offset = eb->start;
unsigned long i, num_pages;
+ unsigned long bio_flags = 0;
int rw = (epd->sync_io ? WRITE_SYNC : WRITE);
int ret = 0;
clear_bit(EXTENT_BUFFER_IOERR, &eb->bflags);
num_pages = num_extent_pages(eb->start, eb->len);
atomic_set(&eb->io_pages, num_pages);
+ if (btrfs_header_owner(eb) == BTRFS_TREE_LOG_OBJECTID)
+ bio_flags = EXTENT_BIO_TREE_LOG;
+
for (i = 0; i < num_pages; i++) {
struct page *p = extent_buffer_page(eb, i);
@@ -3175,7 +3230,8 @@ static int write_one_eb(struct extent_buffer *eb,
ret = submit_extent_page(rw, eb->tree, p, offset >> 9,
PAGE_CACHE_SIZE, 0, bdev, &epd->bio,
-1, end_bio_extent_buffer_writepage,
- 0, 0, 0);
+ 0, epd->bio_flags, bio_flags);
+ epd->bio_flags = bio_flags;
if (ret) {
set_bit(EXTENT_BUFFER_IOERR, &eb->bflags);
SetPageError(p);
@@ -3210,6 +3266,7 @@ int btree_write_cache_pages(struct address_space *mapping,
.tree = tree,
.extent_locked = 0,
.sync_io = wbc->sync_mode == WB_SYNC_ALL,
+ .bio_flags = 0,
};
int ret = 0;
int done = 0;
@@ -3254,19 +3311,34 @@ retry:
break;
}
+ spin_lock(&mapping->private_lock);
+ if (!PagePrivate(page)) {
+ spin_unlock(&mapping->private_lock);
+ continue;
+ }
+
eb = (struct extent_buffer *)page->private;
+
+ /*
+ * Shouldn't happen and normally this would be a BUG_ON
+ * but no sense in crashing the users box for something
+ * we can survive anyway.
+ */
if (!eb) {
+ spin_unlock(&mapping->private_lock);
WARN_ON(1);
continue;
}
- if (eb == prev_eb)
+ if (eb == prev_eb) {
+ spin_unlock(&mapping->private_lock);
continue;
+ }
- if (!atomic_inc_not_zero(&eb->refs)) {
- WARN_ON(1);
+ ret = atomic_inc_not_zero(&eb->refs);
+ spin_unlock(&mapping->private_lock);
+ if (!ret)
continue;
- }
prev_eb = eb;
ret = lock_extent_buffer_for_io(eb, fs_info, &epd);
@@ -3457,7 +3529,7 @@ static void flush_epd_write_bio(struct extent_page_data *epd)
if (epd->sync_io)
rw = WRITE_SYNC;
- ret = submit_one_bio(rw, epd->bio, 0, 0);
+ ret = submit_one_bio(rw, epd->bio, 0, epd->bio_flags);
BUG_ON(ret < 0); /* -ENOMEM */
epd->bio = NULL;
}
@@ -3480,6 +3552,7 @@ int extent_write_full_page(struct extent_io_tree *tree, struct page *page,
.get_extent = get_extent,
.extent_locked = 0,
.sync_io = wbc->sync_mode == WB_SYNC_ALL,
+ .bio_flags = 0,
};
ret = __extent_writepage(page, wbc, &epd);
@@ -3504,6 +3577,7 @@ int extent_write_locked_range(struct extent_io_tree *tree, struct inode *inode,
.get_extent = get_extent,
.extent_locked = 1,
.sync_io = mode == WB_SYNC_ALL,
+ .bio_flags = 0,
};
struct writeback_control wbc_writepages = {
.sync_mode = mode,
@@ -3543,6 +3617,7 @@ int extent_writepages(struct extent_io_tree *tree,
.get_extent = get_extent,
.extent_locked = 0,
.sync_io = wbc->sync_mode == WB_SYNC_ALL,
+ .bio_flags = 0,
};
ret = extent_write_cache_pages(tree, mapping, wbc,
@@ -3920,18 +3995,6 @@ out:
return ret;
}
-inline struct page *extent_buffer_page(struct extent_buffer *eb,
- unsigned long i)
-{
- return eb->pages[i];
-}
-
-inline unsigned long num_extent_pages(u64 start, u64 len)
-{
- return ((start + len + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT) -
- (start >> PAGE_CACHE_SHIFT);
-}
-
static void __free_extent_buffer(struct extent_buffer *eb)
{
#if LEAK_DEBUG
@@ -4047,7 +4110,7 @@ struct extent_buffer *alloc_dummy_extent_buffer(u64 start, unsigned long len)
return eb;
err:
- for (i--; i > 0; i--)
+ for (i--; i >= 0; i--)
__free_page(eb->pages[i]);
__free_extent_buffer(eb);
return NULL;
@@ -4192,10 +4255,8 @@ struct extent_buffer *alloc_extent_buffer(struct extent_io_tree *tree,
for (i = 0; i < num_pages; i++, index++) {
p = find_or_create_page(mapping, index, GFP_NOFS);
- if (!p) {
- WARN_ON(1);
+ if (!p)
goto free_eb;
- }
spin_lock(&mapping->private_lock);
if (PagePrivate(p)) {
@@ -4338,7 +4399,6 @@ static int release_extent_buffer(struct extent_buffer *eb, gfp_t mask)
/* Should be safe to release our pages at this point */
btrfs_release_extent_buffer_page(eb, 0);
-
call_rcu(&eb->rcu_head, btrfs_release_extent_buffer_rcu);
return 1;
}
diff --git a/fs/btrfs/extent_io.h b/fs/btrfs/extent_io.h
index 25900af..711d12b 100644
--- a/fs/btrfs/extent_io.h
+++ b/fs/btrfs/extent_io.h
@@ -27,6 +27,7 @@
* type for this bio
*/
#define EXTENT_BIO_COMPRESSED 1
+#define EXTENT_BIO_TREE_LOG 2
#define EXTENT_BIO_FLAG_SHIFT 16
/* these are bit numbers for test/set bit */
@@ -232,11 +233,15 @@ int set_extent_dirty(struct extent_io_tree *tree, u64 start, u64 end,
int clear_extent_dirty(struct extent_io_tree *tree, u64 start, u64 end,
gfp_t mask);
int convert_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
- int bits, int clear_bits, gfp_t mask);
+ int bits, int clear_bits,
+ struct extent_state **cached_state, 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_defrag(struct extent_io_tree *tree, u64 start, u64 end,
+ struct extent_state **cached_state, gfp_t mask);
int find_first_extent_bit(struct extent_io_tree *tree, u64 start,
- u64 *start_ret, u64 *end_ret, int bits);
+ u64 *start_ret, u64 *end_ret, int bits,
+ struct extent_state **cached_state);
struct extent_state *find_first_extent_bit_state(struct extent_io_tree *tree,
u64 start, int bits);
int extent_invalidatepage(struct extent_io_tree *tree,
@@ -277,8 +282,18 @@ void free_extent_buffer_stale(struct extent_buffer *eb);
int read_extent_buffer_pages(struct extent_io_tree *tree,
struct extent_buffer *eb, u64 start, int wait,
get_extent_t *get_extent, int mirror_num);
-unsigned long num_extent_pages(u64 start, u64 len);
-struct page *extent_buffer_page(struct extent_buffer *eb, unsigned long i);
+
+static inline unsigned long num_extent_pages(u64 start, u64 len)
+{
+ return ((start + len + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT) -
+ (start >> PAGE_CACHE_SHIFT);
+}
+
+static inline struct page *extent_buffer_page(struct extent_buffer *eb,
+ unsigned long i)
+{
+ return eb->pages[i];
+}
static inline void extent_buffer_get(struct extent_buffer *eb)
{
diff --git a/fs/btrfs/extent_map.c b/fs/btrfs/extent_map.c
index 7c97b33..b8cbc8d 100644
--- a/fs/btrfs/extent_map.c
+++ b/fs/btrfs/extent_map.c
@@ -11,7 +11,7 @@ static struct kmem_cache *extent_map_cache;
int __init extent_map_init(void)
{
- extent_map_cache = kmem_cache_create("extent_map",
+ extent_map_cache = kmem_cache_create("btrfs_extent_map",
sizeof(struct extent_map), 0,
SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD, NULL);
if (!extent_map_cache)
@@ -35,6 +35,7 @@ void extent_map_exit(void)
void extent_map_tree_init(struct extent_map_tree *tree)
{
tree->map = RB_ROOT;
+ INIT_LIST_HEAD(&tree->modified_extents);
rwlock_init(&tree->lock);
}
@@ -54,7 +55,9 @@ struct extent_map *alloc_extent_map(void)
em->in_tree = 0;
em->flags = 0;
em->compress_type = BTRFS_COMPRESS_NONE;
+ em->generation = 0;
atomic_set(&em->refs, 1);
+ INIT_LIST_HEAD(&em->list);
return em;
}
@@ -72,6 +75,7 @@ void free_extent_map(struct extent_map *em)
WARN_ON(atomic_read(&em->refs) == 0);
if (atomic_dec_and_test(&em->refs)) {
WARN_ON(em->in_tree);
+ WARN_ON(!list_empty(&em->list));
kmem_cache_free(extent_map_cache, em);
}
}
@@ -198,6 +202,14 @@ static void try_merge_map(struct extent_map_tree *tree, struct extent_map *em)
em->block_len += merge->block_len;
em->block_start = merge->block_start;
merge->in_tree = 0;
+ if (merge->generation > em->generation) {
+ em->mod_start = em->start;
+ em->mod_len = em->len;
+ em->generation = merge->generation;
+ list_move(&em->list, &tree->modified_extents);
+ }
+
+ list_del_init(&merge->list);
rb_erase(&merge->rb_node, &tree->map);
free_extent_map(merge);
}
@@ -211,14 +223,34 @@ static void try_merge_map(struct extent_map_tree *tree, struct extent_map *em)
em->block_len += merge->len;
rb_erase(&merge->rb_node, &tree->map);
merge->in_tree = 0;
+ if (merge->generation > em->generation) {
+ em->mod_len = em->len;
+ em->generation = merge->generation;
+ list_move(&em->list, &tree->modified_extents);
+ }
+ list_del_init(&merge->list);
free_extent_map(merge);
}
}
-int unpin_extent_cache(struct extent_map_tree *tree, u64 start, u64 len)
+/**
+ * unpint_extent_cache - unpin an extent from the cache
+ * @tree: tree to unpin the extent in
+ * @start: logical offset in the file
+ * @len: length of the extent
+ * @gen: generation that this extent has been modified in
+ * @prealloc: if this is set we need to clear the prealloc flag
+ *
+ * Called after an extent has been written to disk properly. Set the generation
+ * to the generation that actually added the file item to the inode so we know
+ * we need to sync this extent when we call fsync().
+ */
+int unpin_extent_cache(struct extent_map_tree *tree, u64 start, u64 len,
+ u64 gen)
{
int ret = 0;
struct extent_map *em;
+ bool prealloc = false;
write_lock(&tree->lock);
em = lookup_extent_mapping(tree, start, len);
@@ -228,10 +260,24 @@ int unpin_extent_cache(struct extent_map_tree *tree, u64 start, u64 len)
if (!em)
goto out;
+ list_move(&em->list, &tree->modified_extents);
+ em->generation = gen;
clear_bit(EXTENT_FLAG_PINNED, &em->flags);
+ em->mod_start = em->start;
+ em->mod_len = em->len;
+
+ if (test_bit(EXTENT_FLAG_PREALLOC, &em->flags)) {
+ prealloc = true;
+ clear_bit(EXTENT_FLAG_PREALLOC, &em->flags);
+ }
try_merge_map(tree, em);
+ if (prealloc) {
+ em->mod_start = em->start;
+ em->mod_len = em->len;
+ }
+
free_extent_map(em);
out:
write_unlock(&tree->lock);
@@ -269,6 +315,9 @@ int add_extent_mapping(struct extent_map_tree *tree,
}
atomic_inc(&em->refs);
+ em->mod_start = em->start;
+ em->mod_len = em->len;
+
try_merge_map(tree, em);
out:
return ret;
@@ -358,6 +407,8 @@ int remove_extent_mapping(struct extent_map_tree *tree, struct extent_map *em)
WARN_ON(test_bit(EXTENT_FLAG_PINNED, &em->flags));
rb_erase(&em->rb_node, &tree->map);
+ if (!test_bit(EXTENT_FLAG_LOGGING, &em->flags))
+ list_del_init(&em->list);
em->in_tree = 0;
return ret;
}
diff --git a/fs/btrfs/extent_map.h b/fs/btrfs/extent_map.h
index 1195f09..6792255 100644
--- a/fs/btrfs/extent_map.h
+++ b/fs/btrfs/extent_map.h
@@ -13,6 +13,7 @@
#define EXTENT_FLAG_COMPRESSED 1
#define EXTENT_FLAG_VACANCY 2 /* no file extent item found */
#define EXTENT_FLAG_PREALLOC 3 /* pre-allocated extent */
+#define EXTENT_FLAG_LOGGING 4 /* Logging this extent */
struct extent_map {
struct rb_node rb_node;
@@ -20,18 +21,23 @@ struct extent_map {
/* all of these are in bytes */
u64 start;
u64 len;
+ u64 mod_start;
+ u64 mod_len;
u64 orig_start;
u64 block_start;
u64 block_len;
+ u64 generation;
unsigned long flags;
struct block_device *bdev;
atomic_t refs;
unsigned int in_tree;
unsigned int compress_type;
+ struct list_head list;
};
struct extent_map_tree {
struct rb_root map;
+ struct list_head modified_extents;
rwlock_t lock;
};
@@ -60,7 +66,7 @@ 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);
-int unpin_extent_cache(struct extent_map_tree *tree, u64 start, u64 len);
+int unpin_extent_cache(struct extent_map_tree *tree, u64 start, u64 len, u64 gen);
struct extent_map *search_extent_mapping(struct extent_map_tree *tree,
u64 start, u64 len);
#endif
diff --git a/fs/btrfs/file-item.c b/fs/btrfs/file-item.c
index 857d93c..1ad08e4e4 100644
--- a/fs/btrfs/file-item.c
+++ b/fs/btrfs/file-item.c
@@ -25,11 +25,12 @@
#include "transaction.h"
#include "print-tree.h"
-#define __MAX_CSUM_ITEMS(r, size) ((((BTRFS_LEAF_DATA_SIZE(r) - \
+#define __MAX_CSUM_ITEMS(r, size) ((unsigned long)(((BTRFS_LEAF_DATA_SIZE(r) - \
sizeof(struct btrfs_item) * 2) / \
size) - 1))
-#define MAX_CSUM_ITEMS(r, size) (min(__MAX_CSUM_ITEMS(r, size), PAGE_CACHE_SIZE))
+#define MAX_CSUM_ITEMS(r, size) (min_t(u32, __MAX_CSUM_ITEMS(r, size), \
+ PAGE_CACHE_SIZE))
#define MAX_ORDERED_SUM_BYTES(r) ((PAGE_SIZE - \
sizeof(struct btrfs_ordered_sum)) / \
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
index f6b40e8..9ab1bed 100644
--- a/fs/btrfs/file.c
+++ b/fs/btrfs/file.c
@@ -39,6 +39,7 @@
#include "tree-log.h"
#include "locking.h"
#include "compat.h"
+#include "volumes.h"
/*
* when auto defrag is enabled we
@@ -458,14 +459,15 @@ int btrfs_dirty_pages(struct btrfs_root *root, struct inode *inode,
* this drops all the extents in the cache that intersect the range
* [start, end]. Existing extents are split as required.
*/
-int btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end,
- int skip_pinned)
+void btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end,
+ int skip_pinned)
{
struct extent_map *em;
struct extent_map *split = NULL;
struct extent_map *split2 = NULL;
struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree;
u64 len = end - start + 1;
+ u64 gen;
int ret;
int testend = 1;
unsigned long flags;
@@ -477,11 +479,14 @@ int btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end,
testend = 0;
}
while (1) {
+ int no_splits = 0;
+
if (!split)
split = alloc_extent_map();
if (!split2)
split2 = alloc_extent_map();
- BUG_ON(!split || !split2); /* -ENOMEM */
+ if (!split || !split2)
+ no_splits = 1;
write_lock(&em_tree->lock);
em = lookup_extent_mapping(em_tree, start, len);
@@ -490,6 +495,7 @@ int btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end,
break;
}
flags = em->flags;
+ gen = em->generation;
if (skip_pinned && test_bit(EXTENT_FLAG_PINNED, &em->flags)) {
if (testend && em->start + em->len >= start + len) {
free_extent_map(em);
@@ -506,6 +512,8 @@ int btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end,
compressed = test_bit(EXTENT_FLAG_COMPRESSED, &em->flags);
clear_bit(EXTENT_FLAG_PINNED, &em->flags);
remove_extent_mapping(em_tree, em);
+ if (no_splits)
+ goto next;
if (em->block_start < EXTENT_MAP_LAST_BYTE &&
em->start < start) {
@@ -518,12 +526,13 @@ int btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end,
split->block_len = em->block_len;
else
split->block_len = split->len;
-
+ split->generation = gen;
split->bdev = em->bdev;
split->flags = flags;
split->compress_type = em->compress_type;
ret = add_extent_mapping(em_tree, split);
BUG_ON(ret); /* Logic error */
+ list_move(&split->list, &em_tree->modified_extents);
free_extent_map(split);
split = split2;
split2 = NULL;
@@ -537,6 +546,7 @@ int btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end,
split->bdev = em->bdev;
split->flags = flags;
split->compress_type = em->compress_type;
+ split->generation = gen;
if (compressed) {
split->block_len = em->block_len;
@@ -550,9 +560,11 @@ int btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end,
ret = add_extent_mapping(em_tree, split);
BUG_ON(ret); /* Logic error */
+ list_move(&split->list, &em_tree->modified_extents);
free_extent_map(split);
split = NULL;
}
+next:
write_unlock(&em_tree->lock);
/* once for us */
@@ -564,7 +576,6 @@ int btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end,
free_extent_map(split);
if (split2)
free_extent_map(split2);
- return 0;
}
/*
@@ -576,13 +587,13 @@ int btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end,
* it is either truncated or split. Anything entirely inside the range
* is deleted from the tree.
*/
-int btrfs_drop_extents(struct btrfs_trans_handle *trans, struct inode *inode,
- u64 start, u64 end, u64 *hint_byte, int drop_cache)
+int __btrfs_drop_extents(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root, struct inode *inode,
+ struct btrfs_path *path, u64 start, u64 end,
+ u64 *drop_end, int drop_cache)
{
- struct btrfs_root *root = BTRFS_I(inode)->root;
struct extent_buffer *leaf;
struct btrfs_file_extent_item *fi;
- struct btrfs_path *path;
struct btrfs_key key;
struct btrfs_key new_key;
u64 ino = btrfs_ino(inode);
@@ -597,14 +608,12 @@ int btrfs_drop_extents(struct btrfs_trans_handle *trans, struct inode *inode,
int recow;
int ret;
int modify_tree = -1;
+ int update_refs = (root->ref_cows || root == root->fs_info->tree_root);
+ int found = 0;
if (drop_cache)
btrfs_drop_extent_cache(inode, start, end - 1, 0);
- path = btrfs_alloc_path();
- if (!path)
- return -ENOMEM;
-
if (start >= BTRFS_I(inode)->disk_i_size)
modify_tree = 0;
@@ -666,6 +675,7 @@ next_slot:
goto next_slot;
}
+ found = 1;
search_start = max(key.offset, start);
if (recow || !modify_tree) {
modify_tree = -1;
@@ -707,14 +717,13 @@ next_slot:
extent_end - start);
btrfs_mark_buffer_dirty(leaf);
- if (disk_bytenr > 0) {
+ if (update_refs && disk_bytenr > 0) {
ret = btrfs_inc_extent_ref(trans, root,
disk_bytenr, num_bytes, 0,
root->root_key.objectid,
new_key.objectid,
start - extent_offset, 0);
BUG_ON(ret); /* -ENOMEM */
- *hint_byte = disk_bytenr;
}
key.offset = start;
}
@@ -734,10 +743,8 @@ next_slot:
btrfs_set_file_extent_num_bytes(leaf, fi,
extent_end - end);
btrfs_mark_buffer_dirty(leaf);
- if (disk_bytenr > 0) {
+ if (update_refs && disk_bytenr > 0)
inode_sub_bytes(inode, end - key.offset);
- *hint_byte = disk_bytenr;
- }
break;
}
@@ -753,10 +760,8 @@ next_slot:
btrfs_set_file_extent_num_bytes(leaf, fi,
start - key.offset);
btrfs_mark_buffer_dirty(leaf);
- if (disk_bytenr > 0) {
+ if (update_refs && disk_bytenr > 0)
inode_sub_bytes(inode, extent_end - start);
- *hint_byte = disk_bytenr;
- }
if (end == extent_end)
break;
@@ -777,12 +782,13 @@ next_slot:
del_nr++;
}
- if (extent_type == BTRFS_FILE_EXTENT_INLINE) {
+ if (update_refs &&
+ extent_type == BTRFS_FILE_EXTENT_INLINE) {
inode_sub_bytes(inode,
extent_end - key.offset);
extent_end = ALIGN(extent_end,
root->sectorsize);
- } else if (disk_bytenr > 0) {
+ } else if (update_refs && disk_bytenr > 0) {
ret = btrfs_free_extent(trans, root,
disk_bytenr, num_bytes, 0,
root->root_key.objectid,
@@ -791,7 +797,6 @@ next_slot:
BUG_ON(ret); /* -ENOMEM */
inode_sub_bytes(inode,
extent_end - key.offset);
- *hint_byte = disk_bytenr;
}
if (end == extent_end)
@@ -806,7 +811,7 @@ next_slot:
del_nr);
if (ret) {
btrfs_abort_transaction(trans, root, ret);
- goto out;
+ break;
}
del_nr = 0;
@@ -825,7 +830,24 @@ next_slot:
btrfs_abort_transaction(trans, root, ret);
}
-out:
+ if (drop_end)
+ *drop_end = found ? min(end, extent_end) : end;
+ btrfs_release_path(path);
+ return ret;
+}
+
+int btrfs_drop_extents(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root, struct inode *inode, u64 start,
+ u64 end, int drop_cache)
+{
+ struct btrfs_path *path;
+ int ret;
+
+ path = btrfs_alloc_path();
+ if (!path)
+ return -ENOMEM;
+ ret = __btrfs_drop_extents(trans, root, inode, path, start, end, NULL,
+ drop_cache);
btrfs_free_path(path);
return ret;
}
@@ -892,8 +914,6 @@ int btrfs_mark_extent_written(struct btrfs_trans_handle *trans,
int ret;
u64 ino = btrfs_ino(inode);
- btrfs_drop_extent_cache(inode, start, end - 1, 0);
-
path = btrfs_alloc_path();
if (!path)
return -ENOMEM;
@@ -935,12 +955,16 @@ again:
btrfs_set_item_key_safe(trans, root, path, &new_key);
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_num_bytes(leaf, fi,
extent_end - end);
btrfs_set_file_extent_offset(leaf, fi,
end - orig_offset);
fi = btrfs_item_ptr(leaf, path->slots[0] - 1,
struct btrfs_file_extent_item);
+ btrfs_set_file_extent_generation(leaf, fi,
+ trans->transid);
btrfs_set_file_extent_num_bytes(leaf, fi,
end - other_start);
btrfs_mark_buffer_dirty(leaf);
@@ -958,12 +982,16 @@ again:
struct btrfs_file_extent_item);
btrfs_set_file_extent_num_bytes(leaf, fi,
start - key.offset);
+ btrfs_set_file_extent_generation(leaf, fi,
+ trans->transid);
path->slots[0]++;
new_key.offset = start;
btrfs_set_item_key_safe(trans, root, path, &new_key);
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_num_bytes(leaf, fi,
other_end - start);
btrfs_set_file_extent_offset(leaf, fi,
@@ -991,12 +1019,14 @@ again:
leaf = path->nodes[0];
fi = btrfs_item_ptr(leaf, path->slots[0] - 1,
struct btrfs_file_extent_item);
+ btrfs_set_file_extent_generation(leaf, fi, trans->transid);
btrfs_set_file_extent_num_bytes(leaf, fi,
split - key.offset);
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_offset(leaf, fi, split - orig_offset);
btrfs_set_file_extent_num_bytes(leaf, fi,
extent_end - split);
@@ -1056,12 +1086,14 @@ again:
struct btrfs_file_extent_item);
btrfs_set_file_extent_type(leaf, fi,
BTRFS_FILE_EXTENT_REG);
+ btrfs_set_file_extent_generation(leaf, fi, trans->transid);
btrfs_mark_buffer_dirty(leaf);
} else {
fi = btrfs_item_ptr(leaf, del_slot - 1,
struct btrfs_file_extent_item);
btrfs_set_file_extent_type(leaf, fi,
BTRFS_FILE_EXTENT_REG);
+ btrfs_set_file_extent_generation(leaf, fi, trans->transid);
btrfs_set_file_extent_num_bytes(leaf, fi,
extent_end - key.offset);
btrfs_mark_buffer_dirty(leaf);
@@ -1173,8 +1205,8 @@ again:
clear_extent_bit(&BTRFS_I(inode)->io_tree, start_pos,
last_pos - 1, EXTENT_DIRTY | EXTENT_DELALLOC |
- EXTENT_DO_ACCOUNTING, 0, 0, &cached_state,
- GFP_NOFS);
+ EXTENT_DO_ACCOUNTING | EXTENT_DEFRAG,
+ 0, 0, &cached_state, GFP_NOFS);
unlock_extent_cached(&BTRFS_I(inode)->io_tree,
start_pos, last_pos - 1, &cached_state,
GFP_NOFS);
@@ -1514,16 +1546,24 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
trace_btrfs_sync_file(file, datasync);
+ /*
+ * We write the dirty pages in the range and wait until they complete
+ * out of the ->i_mutex. If so, we can flush the dirty pages by
+ * multi-task, and make the performance up.
+ */
+ ret = filemap_write_and_wait_range(inode->i_mapping, start, end);
+ if (ret)
+ return ret;
+
mutex_lock(&inode->i_mutex);
/*
- * we wait first, since the writeback may change the inode, also wait
- * ordered range does a filemape_write_and_wait_range which is why we
- * don't do it above like other file systems.
+ * We flush the dirty pages again to avoid some dirty pages in the
+ * range being left.
*/
- root->log_batch++;
+ atomic_inc(&root->log_batch);
btrfs_wait_ordered_range(inode, start, end);
- root->log_batch++;
+ atomic_inc(&root->log_batch);
/*
* check the transaction that last modified this inode
@@ -1544,6 +1584,14 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
BTRFS_I(inode)->last_trans <=
root->fs_info->last_trans_committed) {
BTRFS_I(inode)->last_trans = 0;
+
+ /*
+ * We'v had everything committed since the last time we were
+ * modified so clear this flag in case it was set for whatever
+ * reason, it's no longer relevant.
+ */
+ clear_bit(BTRFS_INODE_NEEDS_FULL_SYNC,
+ &BTRFS_I(inode)->runtime_flags);
mutex_unlock(&inode->i_mutex);
goto out;
}
@@ -1615,6 +1663,324 @@ static int btrfs_file_mmap(struct file *filp, struct vm_area_struct *vma)
return 0;
}
+static int hole_mergeable(struct inode *inode, struct extent_buffer *leaf,
+ int slot, u64 start, u64 end)
+{
+ struct btrfs_file_extent_item *fi;
+ struct btrfs_key key;
+
+ if (slot < 0 || slot >= btrfs_header_nritems(leaf))
+ return 0;
+
+ btrfs_item_key_to_cpu(leaf, &key, slot);
+ if (key.objectid != btrfs_ino(inode) ||
+ key.type != BTRFS_EXTENT_DATA_KEY)
+ return 0;
+
+ fi = btrfs_item_ptr(leaf, slot, struct btrfs_file_extent_item);
+
+ if (btrfs_file_extent_type(leaf, fi) != BTRFS_FILE_EXTENT_REG)
+ return 0;
+
+ if (btrfs_file_extent_disk_bytenr(leaf, fi))
+ return 0;
+
+ if (key.offset == end)
+ return 1;
+ if (key.offset + btrfs_file_extent_num_bytes(leaf, fi) == start)
+ return 1;
+ return 0;
+}
+
+static int fill_holes(struct btrfs_trans_handle *trans, struct inode *inode,
+ struct btrfs_path *path, u64 offset, u64 end)
+{
+ struct btrfs_root *root = BTRFS_I(inode)->root;
+ struct extent_buffer *leaf;
+ struct btrfs_file_extent_item *fi;
+ struct extent_map *hole_em;
+ struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree;
+ struct btrfs_key key;
+ int ret;
+
+ key.objectid = btrfs_ino(inode);
+ key.type = BTRFS_EXTENT_DATA_KEY;
+ key.offset = offset;
+
+
+ ret = btrfs_search_slot(trans, root, &key, path, 0, 1);
+ if (ret < 0)
+ return ret;
+ BUG_ON(!ret);
+
+ leaf = path->nodes[0];
+ if (hole_mergeable(inode, leaf, path->slots[0]-1, offset, end)) {
+ u64 num_bytes;
+
+ path->slots[0]--;
+ fi = btrfs_item_ptr(leaf, path->slots[0],
+ struct btrfs_file_extent_item);
+ num_bytes = btrfs_file_extent_num_bytes(leaf, fi) +
+ end - offset;
+ btrfs_set_file_extent_num_bytes(leaf, fi, num_bytes);
+ btrfs_set_file_extent_ram_bytes(leaf, fi, num_bytes);
+ btrfs_set_file_extent_offset(leaf, fi, 0);
+ btrfs_mark_buffer_dirty(leaf);
+ goto out;
+ }
+
+ if (hole_mergeable(inode, leaf, path->slots[0]+1, offset, end)) {
+ u64 num_bytes;
+
+ path->slots[0]++;
+ key.offset = offset;
+ btrfs_set_item_key_safe(trans, root, path, &key);
+ fi = btrfs_item_ptr(leaf, path->slots[0],
+ struct btrfs_file_extent_item);
+ num_bytes = btrfs_file_extent_num_bytes(leaf, fi) + end -
+ offset;
+ btrfs_set_file_extent_num_bytes(leaf, fi, num_bytes);
+ btrfs_set_file_extent_ram_bytes(leaf, fi, num_bytes);
+ btrfs_set_file_extent_offset(leaf, fi, 0);
+ btrfs_mark_buffer_dirty(leaf);
+ goto out;
+ }
+ btrfs_release_path(path);
+
+ ret = btrfs_insert_file_extent(trans, root, btrfs_ino(inode), offset,
+ 0, 0, end - offset, 0, end - offset,
+ 0, 0, 0);
+ if (ret)
+ return ret;
+
+out:
+ btrfs_release_path(path);
+
+ hole_em = alloc_extent_map();
+ if (!hole_em) {
+ btrfs_drop_extent_cache(inode, offset, end - 1, 0);
+ set_bit(BTRFS_INODE_NEEDS_FULL_SYNC,
+ &BTRFS_I(inode)->runtime_flags);
+ } else {
+ hole_em->start = offset;
+ hole_em->len = end - offset;
+ hole_em->orig_start = offset;
+
+ hole_em->block_start = EXTENT_MAP_HOLE;
+ hole_em->block_len = 0;
+ hole_em->bdev = root->fs_info->fs_devices->latest_bdev;
+ hole_em->compress_type = BTRFS_COMPRESS_NONE;
+ hole_em->generation = trans->transid;
+
+ do {
+ btrfs_drop_extent_cache(inode, offset, end - 1, 0);
+ write_lock(&em_tree->lock);
+ ret = add_extent_mapping(em_tree, hole_em);
+ if (!ret)
+ list_move(&hole_em->list,
+ &em_tree->modified_extents);
+ write_unlock(&em_tree->lock);
+ } while (ret == -EEXIST);
+ free_extent_map(hole_em);
+ if (ret)
+ set_bit(BTRFS_INODE_NEEDS_FULL_SYNC,
+ &BTRFS_I(inode)->runtime_flags);
+ }
+
+ return 0;
+}
+
+static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len)
+{
+ struct btrfs_root *root = BTRFS_I(inode)->root;
+ struct extent_state *cached_state = NULL;
+ struct btrfs_path *path;
+ struct btrfs_block_rsv *rsv;
+ struct btrfs_trans_handle *trans;
+ u64 mask = BTRFS_I(inode)->root->sectorsize - 1;
+ u64 lockstart = (offset + mask) & ~mask;
+ u64 lockend = ((offset + len) & ~mask) - 1;
+ u64 cur_offset = lockstart;
+ u64 min_size = btrfs_calc_trunc_metadata_size(root, 1);
+ u64 drop_end;
+ unsigned long nr;
+ int ret = 0;
+ int err = 0;
+ bool same_page = (offset >> PAGE_CACHE_SHIFT) ==
+ ((offset + len) >> PAGE_CACHE_SHIFT);
+
+ btrfs_wait_ordered_range(inode, offset, len);
+
+ mutex_lock(&inode->i_mutex);
+ if (offset >= inode->i_size) {
+ mutex_unlock(&inode->i_mutex);
+ return 0;
+ }
+
+ /*
+ * Only do this if we are in the same page and we aren't doing the
+ * entire page.
+ */
+ if (same_page && len < PAGE_CACHE_SIZE) {
+ ret = btrfs_truncate_page(inode, offset, len, 0);
+ mutex_unlock(&inode->i_mutex);
+ return ret;
+ }
+
+ /* zero back part of the first page */
+ ret = btrfs_truncate_page(inode, offset, 0, 0);
+ if (ret) {
+ mutex_unlock(&inode->i_mutex);
+ return ret;
+ }
+
+ /* zero the front end of the last page */
+ ret = btrfs_truncate_page(inode, offset + len, 0, 1);
+ if (ret) {
+ mutex_unlock(&inode->i_mutex);
+ return ret;
+ }
+
+ if (lockend < lockstart) {
+ mutex_unlock(&inode->i_mutex);
+ return 0;
+ }
+
+ while (1) {
+ struct btrfs_ordered_extent *ordered;
+
+ truncate_pagecache_range(inode, lockstart, lockend);
+
+ lock_extent_bits(&BTRFS_I(inode)->io_tree, lockstart, lockend,
+ 0, &cached_state);
+ ordered = btrfs_lookup_first_ordered_extent(inode, lockend);
+
+ /*
+ * We need to make sure we have no ordered extents in this range
+ * and nobody raced in and read a page in this range, if we did
+ * we need to try again.
+ */
+ if ((!ordered ||
+ (ordered->file_offset + ordered->len < lockstart ||
+ ordered->file_offset > lockend)) &&
+ !test_range_bit(&BTRFS_I(inode)->io_tree, lockstart,
+ lockend, EXTENT_UPTODATE, 0,
+ cached_state)) {
+ if (ordered)
+ btrfs_put_ordered_extent(ordered);
+ break;
+ }
+ if (ordered)
+ btrfs_put_ordered_extent(ordered);
+ unlock_extent_cached(&BTRFS_I(inode)->io_tree, lockstart,
+ lockend, &cached_state, GFP_NOFS);
+ btrfs_wait_ordered_range(inode, lockstart,
+ lockend - lockstart + 1);
+ }
+
+ path = btrfs_alloc_path();
+ if (!path) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ rsv = btrfs_alloc_block_rsv(root, BTRFS_BLOCK_RSV_TEMP);
+ if (!rsv) {
+ ret = -ENOMEM;
+ goto out_free;
+ }
+ rsv->size = btrfs_calc_trunc_metadata_size(root, 1);
+ rsv->failfast = 1;
+
+ /*
+ * 1 - update the inode
+ * 1 - removing the extents in the range
+ * 1 - adding the hole extent
+ */
+ trans = btrfs_start_transaction(root, 3);
+ if (IS_ERR(trans)) {
+ err = PTR_ERR(trans);
+ goto out_free;
+ }
+
+ ret = btrfs_block_rsv_migrate(&root->fs_info->trans_block_rsv, rsv,
+ min_size);
+ BUG_ON(ret);
+ trans->block_rsv = rsv;
+
+ while (cur_offset < lockend) {
+ ret = __btrfs_drop_extents(trans, root, inode, path,
+ cur_offset, lockend + 1,
+ &drop_end, 1);
+ if (ret != -ENOSPC)
+ break;
+
+ trans->block_rsv = &root->fs_info->trans_block_rsv;
+
+ ret = fill_holes(trans, inode, path, cur_offset, drop_end);
+ if (ret) {
+ err = ret;
+ break;
+ }
+
+ cur_offset = drop_end;
+
+ ret = btrfs_update_inode(trans, root, inode);
+ if (ret) {
+ err = ret;
+ break;
+ }
+
+ nr = trans->blocks_used;
+ btrfs_end_transaction(trans, root);
+ btrfs_btree_balance_dirty(root, nr);
+
+ trans = btrfs_start_transaction(root, 3);
+ if (IS_ERR(trans)) {
+ ret = PTR_ERR(trans);
+ trans = NULL;
+ break;
+ }
+
+ ret = btrfs_block_rsv_migrate(&root->fs_info->trans_block_rsv,
+ rsv, min_size);
+ BUG_ON(ret); /* shouldn't happen */
+ trans->block_rsv = rsv;
+ }
+
+ if (ret) {
+ err = ret;
+ goto out_trans;
+ }
+
+ trans->block_rsv = &root->fs_info->trans_block_rsv;
+ ret = fill_holes(trans, inode, path, cur_offset, drop_end);
+ if (ret) {
+ err = ret;
+ goto out_trans;
+ }
+
+out_trans:
+ if (!trans)
+ goto out_free;
+
+ trans->block_rsv = &root->fs_info->trans_block_rsv;
+ ret = btrfs_update_inode(trans, root, inode);
+ nr = trans->blocks_used;
+ btrfs_end_transaction(trans, root);
+ btrfs_btree_balance_dirty(root, nr);
+out_free:
+ btrfs_free_path(path);
+ btrfs_free_block_rsv(root, rsv);
+out:
+ unlock_extent_cached(&BTRFS_I(inode)->io_tree, lockstart, lockend,
+ &cached_state, GFP_NOFS);
+ mutex_unlock(&inode->i_mutex);
+ if (ret && !err)
+ err = ret;
+ return err;
+}
+
static long btrfs_fallocate(struct file *file, int mode,
loff_t offset, loff_t len)
{
@@ -1633,15 +1999,18 @@ static long btrfs_fallocate(struct file *file, int mode,
alloc_start = offset & ~mask;
alloc_end = (offset + len + mask) & ~mask;
- /* We only support the FALLOC_FL_KEEP_SIZE mode */
- if (mode & ~FALLOC_FL_KEEP_SIZE)
+ /* Make sure we aren't being give some crap mode */
+ if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE))
return -EOPNOTSUPP;
+ if (mode & FALLOC_FL_PUNCH_HOLE)
+ return btrfs_punch_hole(inode, offset, len);
+
/*
* Make sure we have enough space before we do the
* allocation.
*/
- ret = btrfs_check_data_free_space(inode, len);
+ ret = btrfs_check_data_free_space(inode, alloc_end - alloc_start + 1);
if (ret)
return ret;
@@ -1748,7 +2117,7 @@ static long btrfs_fallocate(struct file *file, int mode,
out:
mutex_unlock(&inode->i_mutex);
/* Let go of our reservation. */
- btrfs_free_reserved_data_space(inode, len);
+ btrfs_free_reserved_data_space(inode, alloc_end - alloc_start + 1);
return ret;
}
diff --git a/fs/btrfs/free-space-cache.c b/fs/btrfs/free-space-cache.c
index 6b10acf..1027b85 100644
--- a/fs/btrfs/free-space-cache.c
+++ b/fs/btrfs/free-space-cache.c
@@ -966,7 +966,7 @@ int __btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode,
block_group->key.offset)) {
ret = find_first_extent_bit(unpin, start,
&extent_start, &extent_end,
- EXTENT_DIRTY);
+ EXTENT_DIRTY, NULL);
if (ret) {
ret = 0;
break;
@@ -1454,9 +1454,7 @@ static int search_bitmap(struct btrfs_free_space_ctl *ctl,
max_t(u64, *offset, bitmap_info->offset));
bits = bytes_to_bits(*bytes, ctl->unit);
- for (i = find_next_bit(bitmap_info->bitmap, BITS_PER_BITMAP, i);
- i < BITS_PER_BITMAP;
- i = find_next_bit(bitmap_info->bitmap, BITS_PER_BITMAP, i + 1)) {
+ for_each_set_bit_from(i, bitmap_info->bitmap, BITS_PER_BITMAP) {
next_zero = find_next_zero_bit(bitmap_info->bitmap,
BITS_PER_BITMAP, i);
if ((next_zero - i) >= bits) {
@@ -2307,9 +2305,7 @@ static int btrfs_bitmap_cluster(struct btrfs_block_group_cache *block_group,
again:
found_bits = 0;
- for (i = find_next_bit(entry->bitmap, BITS_PER_BITMAP, i);
- i < BITS_PER_BITMAP;
- i = find_next_bit(entry->bitmap, BITS_PER_BITMAP, i + 1)) {
+ for_each_set_bit_from(i, entry->bitmap, BITS_PER_BITMAP) {
next_zero = find_next_zero_bit(entry->bitmap,
BITS_PER_BITMAP, i);
if (next_zero - i >= min_bits) {
diff --git a/fs/btrfs/hash.h b/fs/btrfs/hash.h
index db2ff97..1d98281 100644
--- a/fs/btrfs/hash.h
+++ b/fs/btrfs/hash.h
@@ -24,4 +24,14 @@ static inline u64 btrfs_name_hash(const char *name, int len)
{
return crc32c((u32)~1, name, len);
}
+
+/*
+ * Figure the key offset of an extended inode ref
+ */
+static inline u64 btrfs_extref_hash(u64 parent_objectid, const char *name,
+ int len)
+{
+ return (u64) crc32c(parent_objectid, name, len);
+}
+
#endif
diff --git a/fs/btrfs/inode-item.c b/fs/btrfs/inode-item.c
index a13cf1a..48b8fda 100644
--- a/fs/btrfs/inode-item.c
+++ b/fs/btrfs/inode-item.c
@@ -18,6 +18,7 @@
#include "ctree.h"
#include "disk-io.h"
+#include "hash.h"
#include "transaction.h"
#include "print-tree.h"
@@ -50,18 +51,57 @@ static int find_name_in_backref(struct btrfs_path *path, const char *name,
return 0;
}
-struct btrfs_inode_ref *
+int btrfs_find_name_in_ext_backref(struct btrfs_path *path, u64 ref_objectid,
+ const char *name, int name_len,
+ struct btrfs_inode_extref **extref_ret)
+{
+ struct extent_buffer *leaf;
+ struct btrfs_inode_extref *extref;
+ unsigned long ptr;
+ unsigned long name_ptr;
+ u32 item_size;
+ u32 cur_offset = 0;
+ int ref_name_len;
+
+ leaf = path->nodes[0];
+ item_size = btrfs_item_size_nr(leaf, path->slots[0]);
+ ptr = btrfs_item_ptr_offset(leaf, path->slots[0]);
+
+ /*
+ * Search all extended backrefs in this item. We're only
+ * looking through any collisions so most of the time this is
+ * just going to compare against one buffer. If all is well,
+ * we'll return success and the inode ref object.
+ */
+ while (cur_offset < item_size) {
+ extref = (struct btrfs_inode_extref *) (ptr + cur_offset);
+ name_ptr = (unsigned long)(&extref->name);
+ ref_name_len = btrfs_inode_extref_name_len(leaf, extref);
+
+ if (ref_name_len == name_len &&
+ btrfs_inode_extref_parent(leaf, extref) == ref_objectid &&
+ (memcmp_extent_buffer(leaf, name, name_ptr, name_len) == 0)) {
+ if (extref_ret)
+ *extref_ret = extref;
+ return 1;
+ }
+
+ cur_offset += ref_name_len + sizeof(*extref);
+ }
+ return 0;
+}
+
+static struct btrfs_inode_ref *
btrfs_lookup_inode_ref(struct btrfs_trans_handle *trans,
- struct btrfs_root *root,
- struct btrfs_path *path,
- const char *name, int name_len,
- u64 inode_objectid, u64 ref_objectid, int mod)
+ struct btrfs_root *root,
+ struct btrfs_path *path,
+ const char *name, int name_len,
+ u64 inode_objectid, u64 ref_objectid, int ins_len,
+ int cow)
{
+ int ret;
struct btrfs_key key;
struct btrfs_inode_ref *ref;
- int ins_len = mod < 0 ? -1 : 0;
- int cow = mod != 0;
- int ret;
key.objectid = inode_objectid;
key.type = BTRFS_INODE_REF_KEY;
@@ -77,13 +117,150 @@ btrfs_lookup_inode_ref(struct btrfs_trans_handle *trans,
return ref;
}
-int btrfs_del_inode_ref(struct btrfs_trans_handle *trans,
+/* Returns NULL if no extref found */
+struct btrfs_inode_extref *
+btrfs_lookup_inode_extref(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root,
+ struct btrfs_path *path,
+ const char *name, int name_len,
+ u64 inode_objectid, u64 ref_objectid, int ins_len,
+ int cow)
+{
+ int ret;
+ struct btrfs_key key;
+ struct btrfs_inode_extref *extref;
+
+ key.objectid = inode_objectid;
+ key.type = BTRFS_INODE_EXTREF_KEY;
+ key.offset = btrfs_extref_hash(ref_objectid, name, name_len);
+
+ ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow);
+ if (ret < 0)
+ return ERR_PTR(ret);
+ if (ret > 0)
+ return NULL;
+ if (!btrfs_find_name_in_ext_backref(path, ref_objectid, name, name_len, &extref))
+ return NULL;
+ return extref;
+}
+
+int btrfs_get_inode_ref_index(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root,
+ struct btrfs_path *path,
+ const char *name, int name_len,
+ u64 inode_objectid, u64 ref_objectid, int mod,
+ u64 *ret_index)
+{
+ struct btrfs_inode_ref *ref;
+ struct btrfs_inode_extref *extref;
+ int ins_len = mod < 0 ? -1 : 0;
+ int cow = mod != 0;
+
+ ref = btrfs_lookup_inode_ref(trans, root, path, name, name_len,
+ inode_objectid, ref_objectid, ins_len,
+ cow);
+ if (IS_ERR(ref))
+ return PTR_ERR(ref);
+
+ if (ref != NULL) {
+ *ret_index = btrfs_inode_ref_index(path->nodes[0], ref);
+ return 0;
+ }
+
+ btrfs_release_path(path);
+
+ extref = btrfs_lookup_inode_extref(trans, root, path, name,
+ name_len, inode_objectid,
+ ref_objectid, ins_len, cow);
+ if (IS_ERR(extref))
+ return PTR_ERR(extref);
+
+ if (extref) {
+ *ret_index = btrfs_inode_extref_index(path->nodes[0], extref);
+ return 0;
+ }
+
+ return -ENOENT;
+}
+
+int btrfs_del_inode_extref(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
const char *name, int name_len,
u64 inode_objectid, u64 ref_objectid, u64 *index)
{
struct btrfs_path *path;
struct btrfs_key key;
+ struct btrfs_inode_extref *extref;
+ struct extent_buffer *leaf;
+ int ret;
+ int del_len = name_len + sizeof(*extref);
+ unsigned long ptr;
+ unsigned long item_start;
+ u32 item_size;
+
+ key.objectid = inode_objectid;
+ btrfs_set_key_type(&key, BTRFS_INODE_EXTREF_KEY);
+ key.offset = btrfs_extref_hash(ref_objectid, name, name_len);
+
+ path = btrfs_alloc_path();
+ if (!path)
+ return -ENOMEM;
+
+ path->leave_spinning = 1;
+
+ ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
+ if (ret > 0)
+ ret = -ENOENT;
+ if (ret < 0)
+ goto out;
+
+ /*
+ * Sanity check - did we find the right item for this name?
+ * This should always succeed so error here will make the FS
+ * readonly.
+ */
+ if (!btrfs_find_name_in_ext_backref(path, ref_objectid,
+ name, name_len, &extref)) {
+ btrfs_std_error(root->fs_info, -ENOENT);
+ ret = -EROFS;
+ goto out;
+ }
+
+ leaf = path->nodes[0];
+ item_size = btrfs_item_size_nr(leaf, path->slots[0]);
+ if (index)
+ *index = btrfs_inode_extref_index(leaf, extref);
+
+ if (del_len == item_size) {
+ /*
+ * Common case only one ref in the item, remove the
+ * whole item.
+ */
+ ret = btrfs_del_item(trans, root, path);
+ goto out;
+ }
+
+ ptr = (unsigned long)extref;
+ item_start = btrfs_item_ptr_offset(leaf, path->slots[0]);
+
+ memmove_extent_buffer(leaf, ptr, ptr + del_len,
+ item_size - (ptr + del_len - item_start));
+
+ btrfs_truncate_item(trans, root, path, item_size - del_len, 1);
+
+out:
+ btrfs_free_path(path);
+
+ return ret;
+}
+
+int btrfs_del_inode_ref(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root,
+ const char *name, int name_len,
+ u64 inode_objectid, u64 ref_objectid, u64 *index)
+{
+ struct btrfs_path *path;
+ struct btrfs_key key;
struct btrfs_inode_ref *ref;
struct extent_buffer *leaf;
unsigned long ptr;
@@ -91,6 +268,7 @@ int btrfs_del_inode_ref(struct btrfs_trans_handle *trans,
u32 item_size;
u32 sub_item_len;
int ret;
+ int search_ext_refs = 0;
int del_len = name_len + sizeof(*ref);
key.objectid = inode_objectid;
@@ -106,12 +284,14 @@ int btrfs_del_inode_ref(struct btrfs_trans_handle *trans,
ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
if (ret > 0) {
ret = -ENOENT;
+ search_ext_refs = 1;
goto out;
} else if (ret < 0) {
goto out;
}
if (!find_name_in_backref(path, name, name_len, &ref)) {
ret = -ENOENT;
+ search_ext_refs = 1;
goto out;
}
leaf = path->nodes[0];
@@ -129,8 +309,78 @@ int btrfs_del_inode_ref(struct btrfs_trans_handle *trans,
item_start = btrfs_item_ptr_offset(leaf, path->slots[0]);
memmove_extent_buffer(leaf, ptr, ptr + sub_item_len,
item_size - (ptr + sub_item_len - item_start));
- btrfs_truncate_item(trans, root, path,
- item_size - sub_item_len, 1);
+ btrfs_truncate_item(trans, root, path, item_size - sub_item_len, 1);
+out:
+ btrfs_free_path(path);
+
+ if (search_ext_refs) {
+ /*
+ * No refs were found, or we could not find the
+ * name in our ref array. Find and remove the extended
+ * inode ref then.
+ */
+ return btrfs_del_inode_extref(trans, root, name, name_len,
+ inode_objectid, ref_objectid, index);
+ }
+
+ return ret;
+}
+
+/*
+ * btrfs_insert_inode_extref() - Inserts an extended inode ref into a tree.
+ *
+ * The caller must have checked against BTRFS_LINK_MAX already.
+ */
+static int btrfs_insert_inode_extref(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root,
+ const char *name, int name_len,
+ u64 inode_objectid, u64 ref_objectid, u64 index)
+{
+ struct btrfs_inode_extref *extref;
+ int ret;
+ int ins_len = name_len + sizeof(*extref);
+ unsigned long ptr;
+ struct btrfs_path *path;
+ struct btrfs_key key;
+ struct extent_buffer *leaf;
+ struct btrfs_item *item;
+
+ key.objectid = inode_objectid;
+ key.type = BTRFS_INODE_EXTREF_KEY;
+ key.offset = btrfs_extref_hash(ref_objectid, name, name_len);
+
+ path = btrfs_alloc_path();
+ if (!path)
+ return -ENOMEM;
+
+ path->leave_spinning = 1;
+ ret = btrfs_insert_empty_item(trans, root, path, &key,
+ ins_len);
+ if (ret == -EEXIST) {
+ if (btrfs_find_name_in_ext_backref(path, ref_objectid,
+ name, name_len, NULL))
+ goto out;
+
+ btrfs_extend_item(trans, root, path, ins_len);
+ ret = 0;
+ }
+ if (ret < 0)
+ goto out;
+
+ leaf = path->nodes[0];
+ item = btrfs_item_nr(leaf, path->slots[0]);
+ ptr = (unsigned long)btrfs_item_ptr(leaf, path->slots[0], char);
+ ptr += btrfs_item_size(leaf, item) - ins_len;
+ extref = (struct btrfs_inode_extref *)ptr;
+
+ btrfs_set_inode_extref_name_len(path->nodes[0], extref, name_len);
+ btrfs_set_inode_extref_index(path->nodes[0], extref, index);
+ btrfs_set_inode_extref_parent(path->nodes[0], extref, ref_objectid);
+
+ ptr = (unsigned long)&extref->name;
+ write_extent_buffer(path->nodes[0], name, ptr, name_len);
+ btrfs_mark_buffer_dirty(path->nodes[0]);
+
out:
btrfs_free_path(path);
return ret;
@@ -191,6 +441,19 @@ int btrfs_insert_inode_ref(struct btrfs_trans_handle *trans,
out:
btrfs_free_path(path);
+
+ if (ret == -EMLINK) {
+ struct btrfs_super_block *disk_super = root->fs_info->super_copy;
+ /* We ran out of space in the ref array. Need to
+ * add an extended ref. */
+ if (btrfs_super_incompat_flags(disk_super)
+ & BTRFS_FEATURE_INCOMPAT_EXTENDED_IREF)
+ ret = btrfs_insert_inode_extref(trans, root, name,
+ name_len,
+ inode_objectid,
+ ref_objectid, index);
+ }
+
return ret;
}
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index a6ed694..85a1e50 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -230,7 +230,6 @@ static noinline int cow_file_range_inline(struct btrfs_trans_handle *trans,
u64 inline_len = actual_end - start;
u64 aligned_end = (end + root->sectorsize - 1) &
~((u64)root->sectorsize - 1);
- u64 hint_byte;
u64 data_len = inline_len;
int ret;
@@ -247,8 +246,7 @@ static noinline int cow_file_range_inline(struct btrfs_trans_handle *trans,
return 1;
}
- ret = btrfs_drop_extents(trans, inode, start, aligned_end,
- &hint_byte, 1);
+ ret = btrfs_drop_extents(trans, root, inode, start, aligned_end, 1);
if (ret)
return ret;
@@ -664,7 +662,7 @@ retry:
async_extent->compressed_size,
async_extent->compressed_size,
0, alloc_hint, &ins, 1);
- if (ret)
+ if (ret && ret != -ENOSPC)
btrfs_abort_transaction(trans, root, ret);
btrfs_end_transaction(trans, root);
}
@@ -1308,6 +1306,7 @@ out_check:
em->block_start = disk_bytenr;
em->bdev = root->fs_info->fs_devices->latest_bdev;
set_bit(EXTENT_FLAG_PINNED, &em->flags);
+ set_bit(EXTENT_FLAG_PREALLOC, &em->flags);
while (1) {
write_lock(&em_tree->lock);
ret = add_extent_mapping(em_tree, em);
@@ -1364,11 +1363,7 @@ out_check:
}
error:
- if (nolock) {
- err = btrfs_end_transaction_nolock(trans, root);
- } else {
- err = btrfs_end_transaction(trans, root);
- }
+ err = btrfs_end_transaction(trans, root);
if (!ret)
ret = err;
@@ -1785,7 +1780,6 @@ static int insert_reserved_file_extent(struct btrfs_trans_handle *trans,
struct btrfs_path *path;
struct extent_buffer *leaf;
struct btrfs_key ins;
- u64 hint;
int ret;
path = btrfs_alloc_path();
@@ -1803,8 +1797,8 @@ static int insert_reserved_file_extent(struct btrfs_trans_handle *trans,
* the caller is expected to unpin it and allow it to be merged
* with the others.
*/
- ret = btrfs_drop_extents(trans, inode, file_pos, file_pos + num_bytes,
- &hint, 0);
+ ret = btrfs_drop_extents(trans, root, inode, file_pos,
+ file_pos + num_bytes, 0);
if (ret)
goto out;
@@ -1828,10 +1822,8 @@ static int insert_reserved_file_extent(struct btrfs_trans_handle *trans,
btrfs_set_file_extent_encryption(leaf, fi, encryption);
btrfs_set_file_extent_other_encoding(leaf, fi, other_encoding);
- btrfs_unlock_up_safe(path, 1);
- btrfs_set_lock_blocking(leaf);
-
btrfs_mark_buffer_dirty(leaf);
+ btrfs_release_path(path);
inode_add_bytes(inode, num_bytes);
@@ -1929,11 +1921,10 @@ static int btrfs_finish_ordered_io(struct btrfs_ordered_extent *ordered_extent)
ordered_extent->len,
compress_type, 0, 0,
BTRFS_FILE_EXTENT_REG);
- unpin_extent_cache(&BTRFS_I(inode)->extent_tree,
- ordered_extent->file_offset,
- ordered_extent->len);
}
-
+ unpin_extent_cache(&BTRFS_I(inode)->extent_tree,
+ ordered_extent->file_offset, ordered_extent->len,
+ trans->transid);
if (ret < 0) {
btrfs_abort_transaction(trans, root, ret);
goto out_unlock;
@@ -1949,6 +1940,8 @@ static int btrfs_finish_ordered_io(struct btrfs_ordered_extent *ordered_extent)
btrfs_abort_transaction(trans, root, ret);
goto out_unlock;
}
+ } else {
+ btrfs_set_inode_last_trans(trans, inode);
}
ret = 0;
out_unlock:
@@ -1958,12 +1951,8 @@ out_unlock:
out:
if (root != root->fs_info->tree_root)
btrfs_delalloc_release_metadata(inode, ordered_extent->len);
- if (trans) {
- if (nolock)
- btrfs_end_transaction_nolock(trans, root);
- else
- btrfs_end_transaction(trans, root);
- }
+ if (trans)
+ btrfs_end_transaction(trans, root);
if (ret)
clear_extent_uptodate(io_tree, ordered_extent->file_offset,
@@ -2119,7 +2108,6 @@ void btrfs_run_delayed_iputs(struct btrfs_root *root)
if (empty)
return;
- down_read(&root->fs_info->cleanup_work_sem);
spin_lock(&fs_info->delayed_iput_lock);
list_splice_init(&fs_info->delayed_iputs, &list);
spin_unlock(&fs_info->delayed_iput_lock);
@@ -2130,7 +2118,6 @@ void btrfs_run_delayed_iputs(struct btrfs_root *root)
iput(delayed->inode);
kfree(delayed);
}
- up_read(&root->fs_info->cleanup_work_sem);
}
enum btrfs_orphan_cleanup_state {
@@ -2198,7 +2185,7 @@ int btrfs_orphan_add(struct btrfs_trans_handle *trans, struct inode *inode)
int ret;
if (!root->orphan_block_rsv) {
- block_rsv = btrfs_alloc_block_rsv(root);
+ block_rsv = btrfs_alloc_block_rsv(root, BTRFS_BLOCK_RSV_TEMP);
if (!block_rsv)
return -ENOMEM;
}
@@ -2225,7 +2212,7 @@ int btrfs_orphan_add(struct btrfs_trans_handle *trans, struct inode *inode)
insert = 1;
#endif
insert = 1;
- atomic_dec(&root->orphan_inodes);
+ atomic_inc(&root->orphan_inodes);
}
if (!test_and_set_bit(BTRFS_INODE_ORPHAN_META_RESERVED,
@@ -2590,6 +2577,18 @@ static void btrfs_read_locked_inode(struct inode *inode)
inode_set_bytes(inode, btrfs_inode_nbytes(leaf, inode_item));
BTRFS_I(inode)->generation = btrfs_inode_generation(leaf, inode_item);
+ BTRFS_I(inode)->last_trans = btrfs_inode_transid(leaf, inode_item);
+
+ /*
+ * If we were modified in the current generation and evicted from memory
+ * and then re-read we need to do a full sync since we don't have any
+ * idea about which extents were modified before we were evicted from
+ * cache.
+ */
+ if (BTRFS_I(inode)->last_trans == root->fs_info->generation)
+ set_bit(BTRFS_INODE_NEEDS_FULL_SYNC,
+ &BTRFS_I(inode)->runtime_flags);
+
inode->i_version = btrfs_inode_sequence(leaf, inode_item);
inode->i_generation = BTRFS_I(inode)->generation;
inode->i_rdev = 0;
@@ -2894,7 +2893,6 @@ static struct btrfs_trans_handle *__unlink_start_trans(struct inode *dir,
struct btrfs_trans_handle *trans;
struct btrfs_root *root = BTRFS_I(dir)->root;
struct btrfs_path *path;
- struct btrfs_inode_ref *ref;
struct btrfs_dir_item *di;
struct inode *inode = dentry->d_inode;
u64 index;
@@ -3008,17 +3006,17 @@ static struct btrfs_trans_handle *__unlink_start_trans(struct inode *dir,
}
btrfs_release_path(path);
- ref = btrfs_lookup_inode_ref(trans, root, path,
- dentry->d_name.name, dentry->d_name.len,
- ino, dir_ino, 0);
- if (IS_ERR(ref)) {
- err = PTR_ERR(ref);
+ ret = btrfs_get_inode_ref_index(trans, root, path, dentry->d_name.name,
+ dentry->d_name.len, ino, dir_ino, 0,
+ &index);
+ if (ret) {
+ err = ret;
goto out;
}
- BUG_ON(!ref); /* Logic error */
+
if (check_path_shared(root, path))
goto out;
- index = btrfs_inode_ref_index(path->nodes[0], ref);
+
btrfs_release_path(path);
/*
@@ -3061,7 +3059,7 @@ out:
static void __unlink_end_trans(struct btrfs_trans_handle *trans,
struct btrfs_root *root)
{
- if (trans->block_rsv == &root->fs_info->global_block_rsv) {
+ if (trans->block_rsv->type == BTRFS_BLOCK_RSV_GLOBAL) {
btrfs_block_rsv_release(root, trans->block_rsv,
trans->bytes_reserved);
trans->block_rsv = &root->fs_info->trans_block_rsv;
@@ -3191,9 +3189,10 @@ static int btrfs_rmdir(struct inode *dir, struct dentry *dentry)
struct btrfs_trans_handle *trans;
unsigned long nr = 0;
- if (inode->i_size > BTRFS_EMPTY_DIR_SIZE ||
- btrfs_ino(inode) == BTRFS_FIRST_FREE_OBJECTID)
+ if (inode->i_size > BTRFS_EMPTY_DIR_SIZE)
return -ENOTEMPTY;
+ if (btrfs_ino(inode) == BTRFS_FIRST_FREE_OBJECTID)
+ return -EPERM;
trans = __unlink_start_trans(dir, dentry);
if (IS_ERR(trans))
@@ -3267,8 +3266,13 @@ int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans,
return -ENOMEM;
path->reada = -1;
+ /*
+ * We want to drop from the next block forward in case this new size is
+ * not block aligned since we will be keeping the last block of the
+ * extent just the way it is.
+ */
if (root->ref_cows || root == root->fs_info->tree_root)
- btrfs_drop_extent_cache(inode, new_size & (~mask), (u64)-1, 0);
+ btrfs_drop_extent_cache(inode, (new_size + mask) & (~mask), (u64)-1, 0);
/*
* This function is also used to drop the items in the log tree before
@@ -3429,12 +3433,6 @@ delete:
if (path->slots[0] == 0 ||
path->slots[0] != pending_del_slot) {
- if (root->ref_cows &&
- BTRFS_I(inode)->location.objectid !=
- BTRFS_FREE_INO_OBJECTID) {
- err = -EAGAIN;
- goto out;
- }
if (pending_del_nr) {
ret = btrfs_del_items(trans, root, path,
pending_del_slot,
@@ -3465,12 +3463,20 @@ error:
}
/*
- * taken from block_truncate_page, but does cow as it zeros out
- * any bytes left in the last page in the file.
+ * btrfs_truncate_page - read, zero a chunk and write a page
+ * @inode - inode that we're zeroing
+ * @from - the offset to start zeroing
+ * @len - the length to zero, 0 to zero the entire range respective to the
+ * offset
+ * @front - zero up to the offset instead of from the offset on
+ *
+ * This will find the page for the "from" offset and cow the page and zero the
+ * part we want to zero. This is used with truncate and hole punching.
*/
-static int btrfs_truncate_page(struct address_space *mapping, loff_t from)
+int btrfs_truncate_page(struct inode *inode, loff_t from, loff_t len,
+ int front)
{
- struct inode *inode = mapping->host;
+ struct address_space *mapping = inode->i_mapping;
struct btrfs_root *root = BTRFS_I(inode)->root;
struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree;
struct btrfs_ordered_extent *ordered;
@@ -3485,7 +3491,8 @@ static int btrfs_truncate_page(struct address_space *mapping, loff_t from)
u64 page_start;
u64 page_end;
- if ((offset & (blocksize - 1)) == 0)
+ if ((offset & (blocksize - 1)) == 0 &&
+ (!len || ((len & (blocksize - 1)) == 0)))
goto out;
ret = btrfs_delalloc_reserve_space(inode, PAGE_CACHE_SIZE);
if (ret)
@@ -3532,7 +3539,8 @@ again:
}
clear_extent_bit(&BTRFS_I(inode)->io_tree, page_start, page_end,
- EXTENT_DIRTY | EXTENT_DELALLOC | EXTENT_DO_ACCOUNTING,
+ EXTENT_DIRTY | EXTENT_DELALLOC |
+ EXTENT_DO_ACCOUNTING | EXTENT_DEFRAG,
0, 0, &cached_state, GFP_NOFS);
ret = btrfs_set_extent_delalloc(inode, page_start, page_end,
@@ -3545,8 +3553,13 @@ again:
ret = 0;
if (offset != PAGE_CACHE_SIZE) {
+ if (!len)
+ len = PAGE_CACHE_SIZE - offset;
kaddr = kmap(page);
- memset(kaddr + offset, 0, PAGE_CACHE_SIZE - offset);
+ if (front)
+ memset(kaddr, 0, offset);
+ else
+ memset(kaddr + offset, 0, len);
flush_dcache_page(page);
kunmap(page);
}
@@ -3577,6 +3590,7 @@ int btrfs_cont_expand(struct inode *inode, loff_t oldsize, loff_t size)
struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree;
struct extent_map *em = NULL;
struct extent_state *cached_state = NULL;
+ struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree;
u64 mask = root->sectorsize - 1;
u64 hole_start = (oldsize + mask) & ~mask;
u64 block_end = (size + mask) & ~mask;
@@ -3613,7 +3627,7 @@ int btrfs_cont_expand(struct inode *inode, loff_t oldsize, loff_t size)
last_byte = min(extent_map_end(em), block_end);
last_byte = (last_byte + mask) & ~mask;
if (!test_bit(EXTENT_FLAG_PREALLOC, &em->flags)) {
- u64 hint_byte = 0;
+ struct extent_map *hole_em;
hole_size = last_byte - cur_offset;
trans = btrfs_start_transaction(root, 3);
@@ -3622,9 +3636,9 @@ int btrfs_cont_expand(struct inode *inode, loff_t oldsize, loff_t size)
break;
}
- err = btrfs_drop_extents(trans, inode, cur_offset,
- cur_offset + hole_size,
- &hint_byte, 1);
+ err = btrfs_drop_extents(trans, root, inode,
+ cur_offset,
+ cur_offset + hole_size, 1);
if (err) {
btrfs_abort_transaction(trans, root, err);
btrfs_end_transaction(trans, root);
@@ -3641,9 +3655,39 @@ int btrfs_cont_expand(struct inode *inode, loff_t oldsize, loff_t size)
break;
}
- btrfs_drop_extent_cache(inode, hole_start,
- last_byte - 1, 0);
+ btrfs_drop_extent_cache(inode, cur_offset,
+ cur_offset + hole_size - 1, 0);
+ hole_em = alloc_extent_map();
+ if (!hole_em) {
+ set_bit(BTRFS_INODE_NEEDS_FULL_SYNC,
+ &BTRFS_I(inode)->runtime_flags);
+ goto next;
+ }
+ hole_em->start = cur_offset;
+ hole_em->len = hole_size;
+ hole_em->orig_start = cur_offset;
+ hole_em->block_start = EXTENT_MAP_HOLE;
+ hole_em->block_len = 0;
+ hole_em->bdev = root->fs_info->fs_devices->latest_bdev;
+ hole_em->compress_type = BTRFS_COMPRESS_NONE;
+ hole_em->generation = trans->transid;
+
+ while (1) {
+ write_lock(&em_tree->lock);
+ err = add_extent_mapping(em_tree, hole_em);
+ if (!err)
+ list_move(&hole_em->list,
+ &em_tree->modified_extents);
+ write_unlock(&em_tree->lock);
+ if (err != -EEXIST)
+ break;
+ btrfs_drop_extent_cache(inode, cur_offset,
+ cur_offset +
+ hole_size - 1, 0);
+ }
+ free_extent_map(hole_em);
+next:
btrfs_update_inode(trans, root, inode);
btrfs_end_transaction(trans, root);
}
@@ -3768,26 +3812,22 @@ void btrfs_evict_inode(struct inode *inode)
goto no_delete;
}
- rsv = btrfs_alloc_block_rsv(root);
+ rsv = btrfs_alloc_block_rsv(root, BTRFS_BLOCK_RSV_TEMP);
if (!rsv) {
btrfs_orphan_del(NULL, inode);
goto no_delete;
}
rsv->size = min_size;
+ rsv->failfast = 1;
global_rsv = &root->fs_info->global_block_rsv;
btrfs_i_size_write(inode, 0);
/*
- * This is a bit simpler than btrfs_truncate since
- *
- * 1) We've already reserved our space for our orphan item in the
- * unlink.
- * 2) We're going to delete the inode item, so we don't need to update
- * it at all.
- *
- * So we just need to reserve some slack space in case we add bytes when
- * doing the truncate.
+ * This is a bit simpler than btrfs_truncate since we've already
+ * reserved our space for our orphan item in the unlink, so we just
+ * need to reserve some slack space in case we add bytes and update
+ * inode item when doing the truncate.
*/
while (1) {
ret = btrfs_block_rsv_refill_noflush(root, rsv, min_size);
@@ -3808,7 +3848,7 @@ void btrfs_evict_inode(struct inode *inode)
goto no_delete;
}
- trans = btrfs_start_transaction(root, 0);
+ trans = btrfs_start_transaction_noflush(root, 1);
if (IS_ERR(trans)) {
btrfs_orphan_del(NULL, inode);
btrfs_free_block_rsv(root, rsv);
@@ -3818,9 +3858,13 @@ void btrfs_evict_inode(struct inode *inode)
trans->block_rsv = rsv;
ret = btrfs_truncate_inode_items(trans, root, inode, 0, 0);
- if (ret != -EAGAIN)
+ if (ret != -ENOSPC)
break;
+ trans->block_rsv = &root->fs_info->trans_block_rsv;
+ ret = btrfs_update_inode(trans, root, inode);
+ BUG_ON(ret);
+
nr = trans->blocks_used;
btrfs_end_transaction(trans, root);
trans = NULL;
@@ -4470,10 +4514,7 @@ int btrfs_write_inode(struct inode *inode, struct writeback_control *wbc)
trans = btrfs_join_transaction(root);
if (IS_ERR(trans))
return PTR_ERR(trans);
- if (nolock)
- ret = btrfs_end_transaction_nolock(trans, root);
- else
- ret = btrfs_commit_transaction(trans, root);
+ ret = btrfs_commit_transaction(trans, root);
}
return ret;
}
@@ -4671,6 +4712,14 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
BTRFS_I(inode)->generation = trans->transid;
inode->i_generation = BTRFS_I(inode)->generation;
+ /*
+ * We could have gotten an inode number from somebody who was fsynced
+ * and then removed in this same transaction, so let's just set full
+ * sync since it will be a full sync anyway and this will blow away the
+ * old info in the log.
+ */
+ set_bit(BTRFS_INODE_NEEDS_FULL_SYNC, &BTRFS_I(inode)->runtime_flags);
+
if (S_ISDIR(mode))
owner = 0;
else
@@ -4680,6 +4729,12 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
btrfs_set_key_type(&key[0], BTRFS_INODE_ITEM_KEY);
key[0].offset = 0;
+ /*
+ * Start new inodes with an inode_ref. This is slightly more
+ * efficient for small numbers of hard links since they will
+ * be packed into one item. Extended refs will kick in if we
+ * add more hard links than can fit in the ref item.
+ */
key[1].objectid = objectid;
btrfs_set_key_type(&key[1], BTRFS_INODE_REF_KEY);
key[1].offset = ref_objectid;
@@ -4986,7 +5041,7 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir,
if (root->objectid != BTRFS_I(inode)->root->objectid)
return -EXDEV;
- if (inode->i_nlink == ~0U)
+ if (inode->i_nlink >= BTRFS_LINK_MAX)
return -EMLINK;
err = btrfs_set_inode_index(dir, &index);
@@ -5450,7 +5505,8 @@ insert:
write_unlock(&em_tree->lock);
out:
- trace_btrfs_get_extent(root, em);
+ if (em)
+ trace_btrfs_get_extent(root, em);
if (path)
btrfs_free_path(path);
@@ -5836,6 +5892,48 @@ static int lock_extent_direct(struct inode *inode, u64 lockstart, u64 lockend,
return ret;
}
+static struct extent_map *create_pinned_em(struct inode *inode, u64 start,
+ u64 len, u64 orig_start,
+ u64 block_start, u64 block_len,
+ int type)
+{
+ struct extent_map_tree *em_tree;
+ struct extent_map *em;
+ struct btrfs_root *root = BTRFS_I(inode)->root;
+ int ret;
+
+ em_tree = &BTRFS_I(inode)->extent_tree;
+ em = alloc_extent_map();
+ if (!em)
+ return ERR_PTR(-ENOMEM);
+
+ em->start = start;
+ em->orig_start = orig_start;
+ em->len = len;
+ em->block_len = block_len;
+ em->block_start = block_start;
+ em->bdev = root->fs_info->fs_devices->latest_bdev;
+ set_bit(EXTENT_FLAG_PINNED, &em->flags);
+ if (type == BTRFS_ORDERED_PREALLOC)
+ set_bit(EXTENT_FLAG_PREALLOC, &em->flags);
+
+ do {
+ btrfs_drop_extent_cache(inode, em->start,
+ em->start + em->len - 1, 0);
+ write_lock(&em_tree->lock);
+ ret = add_extent_mapping(em_tree, em);
+ write_unlock(&em_tree->lock);
+ } while (ret == -EEXIST);
+
+ if (ret) {
+ free_extent_map(em);
+ return ERR_PTR(ret);
+ }
+
+ return em;
+}
+
+
static int btrfs_get_blocks_direct(struct inode *inode, sector_t iblock,
struct buffer_head *bh_result, int create)
{
@@ -5950,6 +6048,19 @@ static int btrfs_get_blocks_direct(struct inode *inode, sector_t iblock,
goto must_cow;
if (can_nocow_odirect(trans, inode, start, len) == 1) {
+ u64 orig_start = em->start;
+
+ if (type == BTRFS_ORDERED_PREALLOC) {
+ free_extent_map(em);
+ em = create_pinned_em(inode, start, len,
+ orig_start,
+ block_start, len, type);
+ if (IS_ERR(em)) {
+ btrfs_end_transaction(trans, root);
+ goto unlock_err;
+ }
+ }
+
ret = btrfs_add_ordered_extent_dio(inode, start,
block_start, len, len, type);
btrfs_end_transaction(trans, root);
@@ -5999,7 +6110,8 @@ unlock:
if (lockstart < lockend) {
if (create && len < lockend - lockstart) {
clear_extent_bit(&BTRFS_I(inode)->io_tree, lockstart,
- lockstart + len - 1, unlock_bits, 1, 0,
+ lockstart + len - 1,
+ unlock_bits | EXTENT_DEFRAG, 1, 0,
&cached_state, GFP_NOFS);
/*
* Beside unlock, we also need to cleanup reserved space
@@ -6007,8 +6119,8 @@ unlock:
*/
clear_extent_bit(&BTRFS_I(inode)->io_tree,
lockstart + len, lockend,
- unlock_bits | EXTENT_DO_ACCOUNTING,
- 1, 0, NULL, GFP_NOFS);
+ unlock_bits | EXTENT_DO_ACCOUNTING |
+ EXTENT_DEFRAG, 1, 0, NULL, GFP_NOFS);
} else {
clear_extent_bit(&BTRFS_I(inode)->io_tree, lockstart,
lockend, unlock_bits, 1, 0,
@@ -6573,8 +6685,8 @@ static void btrfs_invalidatepage(struct page *page, unsigned long offset)
*/
clear_extent_bit(tree, page_start, page_end,
EXTENT_DIRTY | EXTENT_DELALLOC |
- EXTENT_LOCKED | EXTENT_DO_ACCOUNTING, 1, 0,
- &cached_state, GFP_NOFS);
+ EXTENT_LOCKED | EXTENT_DO_ACCOUNTING |
+ EXTENT_DEFRAG, 1, 0, &cached_state, GFP_NOFS);
/*
* whoever cleared the private bit is responsible
* for the finish_ordered_io
@@ -6590,7 +6702,8 @@ static void btrfs_invalidatepage(struct page *page, unsigned long offset)
}
clear_extent_bit(tree, page_start, page_end,
EXTENT_LOCKED | EXTENT_DIRTY | EXTENT_DELALLOC |
- EXTENT_DO_ACCOUNTING, 1, 1, &cached_state, GFP_NOFS);
+ EXTENT_DO_ACCOUNTING | EXTENT_DEFRAG, 1, 1,
+ &cached_state, GFP_NOFS);
__btrfs_releasepage(page, GFP_NOFS);
ClearPageChecked(page);
@@ -6687,7 +6800,8 @@ again:
* prepare_pages in the normal write path.
*/
clear_extent_bit(&BTRFS_I(inode)->io_tree, page_start, page_end,
- EXTENT_DIRTY | EXTENT_DELALLOC | EXTENT_DO_ACCOUNTING,
+ EXTENT_DIRTY | EXTENT_DELALLOC |
+ EXTENT_DO_ACCOUNTING | EXTENT_DEFRAG,
0, 0, &cached_state, GFP_NOFS);
ret = btrfs_set_extent_delalloc(inode, page_start, page_end,
@@ -6718,6 +6832,7 @@ again:
BTRFS_I(inode)->last_trans = root->fs_info->generation;
BTRFS_I(inode)->last_sub_trans = BTRFS_I(inode)->root->log_transid;
+ BTRFS_I(inode)->last_log_commit = BTRFS_I(inode)->root->last_log_commit;
unlock_extent_cached(io_tree, page_start, page_end, &cached_state, GFP_NOFS);
@@ -6745,7 +6860,7 @@ static int btrfs_truncate(struct inode *inode)
u64 mask = root->sectorsize - 1;
u64 min_size = btrfs_calc_trunc_metadata_size(root, 1);
- ret = btrfs_truncate_page(inode->i_mapping, inode->i_size);
+ ret = btrfs_truncate_page(inode, inode->i_size, 0, 0);
if (ret)
return ret;
@@ -6788,10 +6903,11 @@ static int btrfs_truncate(struct inode *inode)
* 3) fs_info->trans_block_rsv - this will have 1 items worth left for
* updating the inode.
*/
- rsv = btrfs_alloc_block_rsv(root);
+ rsv = btrfs_alloc_block_rsv(root, BTRFS_BLOCK_RSV_TEMP);
if (!rsv)
return -ENOMEM;
rsv->size = min_size;
+ rsv->failfast = 1;
/*
* 1 for the truncate slack space
@@ -6837,36 +6953,21 @@ static int btrfs_truncate(struct inode *inode)
&BTRFS_I(inode)->runtime_flags))
btrfs_add_ordered_operation(trans, root, inode);
- while (1) {
- ret = btrfs_block_rsv_refill(root, rsv, min_size);
- if (ret) {
- /*
- * This can only happen with the original transaction we
- * started above, every other time we shouldn't have a
- * transaction started yet.
- */
- if (ret == -EAGAIN)
- goto end_trans;
- err = ret;
- break;
- }
-
- if (!trans) {
- /* Just need the 1 for updating the inode */
- trans = btrfs_start_transaction(root, 1);
- if (IS_ERR(trans)) {
- ret = err = PTR_ERR(trans);
- trans = NULL;
- break;
- }
- }
-
- trans->block_rsv = rsv;
+ /*
+ * So if we truncate and then write and fsync we normally would just
+ * write the extents that changed, which is a problem if we need to
+ * first truncate that entire inode. So set this flag so we write out
+ * all of the extents in the inode to the sync log so we're completely
+ * safe.
+ */
+ set_bit(BTRFS_INODE_NEEDS_FULL_SYNC, &BTRFS_I(inode)->runtime_flags);
+ trans->block_rsv = rsv;
+ while (1) {
ret = btrfs_truncate_inode_items(trans, root, inode,
inode->i_size,
BTRFS_EXTENT_DATA_KEY);
- if (ret != -EAGAIN) {
+ if (ret != -ENOSPC) {
err = ret;
break;
}
@@ -6877,11 +6978,22 @@ static int btrfs_truncate(struct inode *inode)
err = ret;
break;
}
-end_trans:
+
nr = trans->blocks_used;
btrfs_end_transaction(trans, root);
- trans = NULL;
btrfs_btree_balance_dirty(root, nr);
+
+ trans = btrfs_start_transaction(root, 2);
+ if (IS_ERR(trans)) {
+ ret = err = PTR_ERR(trans);
+ trans = NULL;
+ break;
+ }
+
+ ret = btrfs_block_rsv_migrate(&root->fs_info->trans_block_rsv,
+ rsv, min_size);
+ BUG_ON(ret); /* shouldn't happen */
+ trans->block_rsv = rsv;
}
if (ret == 0 && inode->i_nlink > 0) {
@@ -6965,6 +7077,7 @@ struct inode *btrfs_alloc_inode(struct super_block *sb)
ei->csum_bytes = 0;
ei->index_cnt = (u64)-1;
ei->last_unlink_trans = 0;
+ ei->last_log_commit = 0;
spin_lock_init(&ei->lock);
ei->outstanding_extents = 0;
@@ -7095,31 +7208,31 @@ void btrfs_destroy_cachep(void)
int btrfs_init_cachep(void)
{
- btrfs_inode_cachep = kmem_cache_create("btrfs_inode_cache",
+ btrfs_inode_cachep = kmem_cache_create("btrfs_inode",
sizeof(struct btrfs_inode), 0,
SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD, init_once);
if (!btrfs_inode_cachep)
goto fail;
- btrfs_trans_handle_cachep = kmem_cache_create("btrfs_trans_handle_cache",
+ btrfs_trans_handle_cachep = kmem_cache_create("btrfs_trans_handle",
sizeof(struct btrfs_trans_handle), 0,
SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD, NULL);
if (!btrfs_trans_handle_cachep)
goto fail;
- btrfs_transaction_cachep = kmem_cache_create("btrfs_transaction_cache",
+ btrfs_transaction_cachep = kmem_cache_create("btrfs_transaction",
sizeof(struct btrfs_transaction), 0,
SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD, NULL);
if (!btrfs_transaction_cachep)
goto fail;
- btrfs_path_cachep = kmem_cache_create("btrfs_path_cache",
+ btrfs_path_cachep = kmem_cache_create("btrfs_path",
sizeof(struct btrfs_path), 0,
SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD, NULL);
if (!btrfs_path_cachep)
goto fail;
- btrfs_free_space_cachep = kmem_cache_create("btrfs_free_space_cache",
+ btrfs_free_space_cachep = kmem_cache_create("btrfs_free_space",
sizeof(struct btrfs_free_space), 0,
SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD, NULL);
if (!btrfs_free_space_cachep)
@@ -7513,6 +7626,8 @@ static int __btrfs_prealloc_file_range(struct inode *inode, int mode,
loff_t actual_len, u64 *alloc_hint,
struct btrfs_trans_handle *trans)
{
+ struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree;
+ struct extent_map *em;
struct btrfs_root *root = BTRFS_I(inode)->root;
struct btrfs_key ins;
u64 cur_offset = start;
@@ -7553,6 +7668,37 @@ static int __btrfs_prealloc_file_range(struct inode *inode, int mode,
btrfs_drop_extent_cache(inode, cur_offset,
cur_offset + ins.offset -1, 0);
+ em = alloc_extent_map();
+ if (!em) {
+ set_bit(BTRFS_INODE_NEEDS_FULL_SYNC,
+ &BTRFS_I(inode)->runtime_flags);
+ goto next;
+ }
+
+ em->start = cur_offset;
+ em->orig_start = cur_offset;
+ em->len = ins.offset;
+ em->block_start = ins.objectid;
+ em->block_len = ins.offset;
+ em->bdev = root->fs_info->fs_devices->latest_bdev;
+ set_bit(EXTENT_FLAG_PREALLOC, &em->flags);
+ em->generation = trans->transid;
+
+ while (1) {
+ write_lock(&em_tree->lock);
+ ret = add_extent_mapping(em_tree, em);
+ if (!ret)
+ list_move(&em->list,
+ &em_tree->modified_extents);
+ write_unlock(&em_tree->lock);
+ if (ret != -EEXIST)
+ break;
+ btrfs_drop_extent_cache(inode, cur_offset,
+ cur_offset + ins.offset - 1,
+ 0);
+ }
+ free_extent_map(em);
+next:
num_bytes -= ins.offset;
cur_offset += ins.offset;
*alloc_hint = ins.objectid + ins.offset;
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index 47127c1..e568c47 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -181,6 +181,7 @@ static int btrfs_ioctl_setflags(struct file *file, void __user *arg)
int ret;
u64 ip_oldflags;
unsigned int i_oldflags;
+ umode_t mode;
if (btrfs_root_readonly(root))
return -EROFS;
@@ -203,6 +204,7 @@ static int btrfs_ioctl_setflags(struct file *file, void __user *arg)
ip_oldflags = ip->flags;
i_oldflags = inode->i_flags;
+ mode = inode->i_mode;
flags = btrfs_mask_flags(inode->i_mode, flags);
oldflags = btrfs_flags_to_ioctl(ip->flags);
@@ -237,10 +239,31 @@ static int btrfs_ioctl_setflags(struct file *file, void __user *arg)
ip->flags |= BTRFS_INODE_DIRSYNC;
else
ip->flags &= ~BTRFS_INODE_DIRSYNC;
- if (flags & FS_NOCOW_FL)
- ip->flags |= BTRFS_INODE_NODATACOW;
- else
- ip->flags &= ~BTRFS_INODE_NODATACOW;
+ if (flags & FS_NOCOW_FL) {
+ if (S_ISREG(mode)) {
+ /*
+ * It's safe to turn csums off here, no extents exist.
+ * Otherwise we want the flag to reflect the real COW
+ * status of the file and will not set it.
+ */
+ if (inode->i_size == 0)
+ ip->flags |= BTRFS_INODE_NODATACOW
+ | BTRFS_INODE_NODATASUM;
+ } else {
+ ip->flags |= BTRFS_INODE_NODATACOW;
+ }
+ } else {
+ /*
+ * Revert back under same assuptions as above
+ */
+ if (S_ISREG(mode)) {
+ if (inode->i_size == 0)
+ ip->flags &= ~(BTRFS_INODE_NODATACOW
+ | BTRFS_INODE_NODATASUM);
+ } else {
+ ip->flags &= ~BTRFS_INODE_NODATACOW;
+ }
+ }
/*
* The COMPRESS flag can only be changed by users, while the NOCOMPRESS
@@ -516,7 +539,8 @@ static int create_snapshot(struct btrfs_root *root, struct dentry *dentry,
if (!pending_snapshot)
return -ENOMEM;
- btrfs_init_block_rsv(&pending_snapshot->block_rsv);
+ btrfs_init_block_rsv(&pending_snapshot->block_rsv,
+ BTRFS_BLOCK_RSV_TEMP);
pending_snapshot->dentry = dentry;
pending_snapshot->root = root;
pending_snapshot->readonly = readonly;
@@ -525,7 +549,7 @@ static int create_snapshot(struct btrfs_root *root, struct dentry *dentry,
*inherit = NULL; /* take responsibility to free it */
}
- trans = btrfs_start_transaction(root->fs_info->extent_root, 5);
+ trans = btrfs_start_transaction(root->fs_info->extent_root, 6);
if (IS_ERR(trans)) {
ret = PTR_ERR(trans);
goto fail;
@@ -1022,8 +1046,8 @@ again:
page_start, page_end - 1, 0, &cached_state);
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);
+ EXTENT_DO_ACCOUNTING | EXTENT_DEFRAG, 0, 0,
+ &cached_state, GFP_NOFS);
if (i_done != page_cnt) {
spin_lock(&BTRFS_I(inode)->lock);
@@ -1034,8 +1058,8 @@ again:
}
- btrfs_set_extent_delalloc(inode, page_start, page_end - 1,
- &cached_state);
+ set_extent_defrag(&BTRFS_I(inode)->io_tree, page_start, page_end - 1,
+ &cached_state, GFP_NOFS);
unlock_extent_cached(&BTRFS_I(inode)->io_tree,
page_start, page_end - 1, &cached_state,
@@ -2351,7 +2375,6 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
int ret;
u64 len = olen;
u64 bs = root->fs_info->sb->s_blocksize;
- u64 hint_byte;
/*
* TODO:
@@ -2456,13 +2479,13 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
another, and lock file content */
while (1) {
struct btrfs_ordered_extent *ordered;
- lock_extent(&BTRFS_I(src)->io_tree, off, off+len);
- ordered = btrfs_lookup_first_ordered_extent(src, off+len);
+ lock_extent(&BTRFS_I(src)->io_tree, off, off + len - 1);
+ ordered = btrfs_lookup_first_ordered_extent(src, off + len - 1);
if (!ordered &&
- !test_range_bit(&BTRFS_I(src)->io_tree, off, off+len,
- EXTENT_DELALLOC, 0, NULL))
+ !test_range_bit(&BTRFS_I(src)->io_tree, off, off + len - 1,
+ EXTENT_DELALLOC, 0, NULL))
break;
- unlock_extent(&BTRFS_I(src)->io_tree, off, off+len);
+ unlock_extent(&BTRFS_I(src)->io_tree, off, off + len - 1);
if (ordered)
btrfs_put_ordered_extent(ordered);
btrfs_wait_ordered_range(src, off, len);
@@ -2536,7 +2559,7 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
btrfs_release_path(path);
if (key.offset + datal <= off ||
- key.offset >= off+len)
+ key.offset >= off + len - 1)
goto next;
memcpy(&new_key, &key, sizeof(new_key));
@@ -2574,10 +2597,10 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
datal -= off - key.offset;
}
- ret = btrfs_drop_extents(trans, inode,
+ ret = btrfs_drop_extents(trans, root, inode,
new_key.offset,
new_key.offset + datal,
- &hint_byte, 1);
+ 1);
if (ret) {
btrfs_abort_transaction(trans, root,
ret);
@@ -2637,8 +2660,8 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
new_key.offset += skip;
}
- if (key.offset + datal > off+len)
- trim = key.offset + datal - (off+len);
+ if (key.offset + datal > off + len)
+ trim = key.offset + datal - (off + len);
if (comp && (skip || trim)) {
ret = -EINVAL;
@@ -2648,10 +2671,10 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
size -= skip + trim;
datal -= skip + trim;
- ret = btrfs_drop_extents(trans, inode,
+ ret = btrfs_drop_extents(trans, root, inode,
new_key.offset,
new_key.offset + datal,
- &hint_byte, 1);
+ 1);
if (ret) {
btrfs_abort_transaction(trans, root,
ret);
@@ -2715,7 +2738,7 @@ next:
ret = 0;
out:
btrfs_release_path(path);
- unlock_extent(&BTRFS_I(src)->io_tree, off, off+len);
+ unlock_extent(&BTRFS_I(src)->io_tree, off, off + len - 1);
out_unlock:
mutex_unlock(&src->i_mutex);
mutex_unlock(&inode->i_mutex);
@@ -2850,8 +2873,8 @@ static long btrfs_ioctl_default_subvol(struct file *file, void __user *argp)
return 0;
}
-static void get_block_group_info(struct list_head *groups_list,
- struct btrfs_ioctl_space_info *space)
+void btrfs_get_block_group_info(struct list_head *groups_list,
+ struct btrfs_ioctl_space_info *space)
{
struct btrfs_block_group_cache *block_group;
@@ -2959,8 +2982,8 @@ long btrfs_ioctl_space_info(struct btrfs_root *root, void __user *arg)
down_read(&info->groups_sem);
for (c = 0; c < BTRFS_NR_RAID_TYPES; c++) {
if (!list_empty(&info->block_groups[c])) {
- get_block_group_info(&info->block_groups[c],
- &space);
+ btrfs_get_block_group_info(
+ &info->block_groups[c], &space);
memcpy(dest, &space, sizeof(space));
dest++;
space_args.total_spaces++;
@@ -3208,11 +3231,9 @@ static long btrfs_ioctl_logical_to_ino(struct btrfs_root *root,
{
int ret = 0;
int size;
- u64 extent_item_pos;
struct btrfs_ioctl_logical_ino_args *loi;
struct btrfs_data_container *inodes = NULL;
struct btrfs_path *path = NULL;
- struct btrfs_key key;
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
@@ -3230,7 +3251,7 @@ static long btrfs_ioctl_logical_to_ino(struct btrfs_root *root,
goto out;
}
- size = min_t(u32, loi->size, 4096);
+ size = min_t(u32, loi->size, 64 * 1024);
inodes = init_data_container(size);
if (IS_ERR(inodes)) {
ret = PTR_ERR(inodes);
@@ -3238,22 +3259,13 @@ static long btrfs_ioctl_logical_to_ino(struct btrfs_root *root,
goto out;
}
- ret = extent_from_logical(root->fs_info, loi->logical, path, &key);
- btrfs_release_path(path);
-
- if (ret & BTRFS_EXTENT_FLAG_TREE_BLOCK)
+ ret = iterate_inodes_from_logical(loi->logical, root->fs_info, path,
+ build_ino_list, inodes);
+ if (ret == -EINVAL)
ret = -ENOENT;
if (ret < 0)
goto out;
- extent_item_pos = loi->logical - key.objectid;
- ret = iterate_extent_inodes(root->fs_info, key.objectid,
- extent_item_pos, 0, build_ino_list,
- inodes);
-
- if (ret < 0)
- goto out;
-
ret = copy_to_user((void *)(unsigned long)loi->inodes,
(void *)(unsigned long)inodes, size);
if (ret)
@@ -3261,7 +3273,7 @@ static long btrfs_ioctl_logical_to_ino(struct btrfs_root *root,
out:
btrfs_free_path(path);
- kfree(inodes);
+ vfree(inodes);
kfree(loi);
return ret;
diff --git a/fs/btrfs/ordered-data.c b/fs/btrfs/ordered-data.c
index 051c7fe..7772f02 100644
--- a/fs/btrfs/ordered-data.c
+++ b/fs/btrfs/ordered-data.c
@@ -25,6 +25,8 @@
#include "btrfs_inode.h"
#include "extent_io.h"
+static struct kmem_cache *btrfs_ordered_extent_cache;
+
static u64 entry_end(struct btrfs_ordered_extent *entry)
{
if (entry->file_offset + entry->len < entry->file_offset)
@@ -187,7 +189,7 @@ static int __btrfs_add_ordered_extent(struct inode *inode, u64 file_offset,
struct btrfs_ordered_extent *entry;
tree = &BTRFS_I(inode)->ordered_tree;
- entry = kzalloc(sizeof(*entry), GFP_NOFS);
+ entry = kmem_cache_zalloc(btrfs_ordered_extent_cache, GFP_NOFS);
if (!entry)
return -ENOMEM;
@@ -421,7 +423,7 @@ void btrfs_put_ordered_extent(struct btrfs_ordered_extent *entry)
list_del(&sum->list);
kfree(sum);
}
- kfree(entry);
+ kmem_cache_free(btrfs_ordered_extent_cache, entry);
}
}
@@ -466,8 +468,7 @@ void btrfs_remove_ordered_extent(struct inode *inode,
* wait for all the ordered extents in a root. This is done when balancing
* space between drives.
*/
-void btrfs_wait_ordered_extents(struct btrfs_root *root,
- int nocow_only, int delay_iput)
+void btrfs_wait_ordered_extents(struct btrfs_root *root, int delay_iput)
{
struct list_head splice;
struct list_head *cur;
@@ -482,15 +483,6 @@ void btrfs_wait_ordered_extents(struct btrfs_root *root,
cur = splice.next;
ordered = list_entry(cur, struct btrfs_ordered_extent,
root_extent_list);
- if (nocow_only &&
- !test_bit(BTRFS_ORDERED_NOCOW, &ordered->flags) &&
- !test_bit(BTRFS_ORDERED_PREALLOC, &ordered->flags)) {
- list_move(&ordered->root_extent_list,
- &root->fs_info->ordered_extents);
- cond_resched_lock(&root->fs_info->ordered_extent_lock);
- continue;
- }
-
list_del_init(&ordered->root_extent_list);
atomic_inc(&ordered->refs);
@@ -775,7 +767,6 @@ int btrfs_ordered_update_i_size(struct inode *inode, u64 offset,
struct btrfs_ordered_inode_tree *tree = &BTRFS_I(inode)->ordered_tree;
u64 disk_i_size;
u64 new_i_size;
- u64 i_size_test;
u64 i_size = i_size_read(inode);
struct rb_node *node;
struct rb_node *prev = NULL;
@@ -835,55 +826,30 @@ int btrfs_ordered_update_i_size(struct inode *inode, u64 offset,
break;
if (test->file_offset >= i_size)
break;
- if (test->file_offset >= disk_i_size)
+ if (test->file_offset >= disk_i_size) {
+ /*
+ * we don't update disk_i_size now, so record this
+ * undealt i_size. Or we will not know the real
+ * i_size.
+ */
+ if (test->outstanding_isize < offset)
+ test->outstanding_isize = offset;
+ if (ordered &&
+ ordered->outstanding_isize >
+ test->outstanding_isize)
+ test->outstanding_isize =
+ ordered->outstanding_isize;
goto out;
- }
- new_i_size = min_t(u64, offset, i_size);
-
- /*
- * at this point, we know we can safely update i_size to at least
- * the offset from this ordered extent. But, we need to
- * walk forward and see if ios from higher up in the file have
- * finished.
- */
- if (ordered) {
- node = rb_next(&ordered->rb_node);
- } else {
- if (prev)
- node = rb_next(prev);
- else
- node = rb_first(&tree->tree);
- }
-
- /*
- * We are looking for an area between our current extent and the next
- * ordered extent to update the i_size to. There are 3 cases here
- *
- * 1) We don't actually have anything and we can update to i_size.
- * 2) We have stuff but they already did their i_size update so again we
- * can just update to i_size.
- * 3) We have an outstanding ordered extent so the most we can update
- * our disk_i_size to is the start of the next offset.
- */
- i_size_test = i_size;
- for (; node; node = rb_next(node)) {
- test = rb_entry(node, struct btrfs_ordered_extent, rb_node);
-
- if (test_bit(BTRFS_ORDERED_UPDATED_ISIZE, &test->flags))
- continue;
- if (test->file_offset > offset) {
- i_size_test = test->file_offset;
- break;
}
}
+ new_i_size = min_t(u64, offset, i_size);
/*
- * i_size_test is the end of a region after this ordered
- * extent where there are no ordered extents, we can safely set
- * disk_i_size to this.
+ * Some ordered extents may completed before the current one, and
+ * we hold the real i_size in ->outstanding_isize.
*/
- if (i_size_test > offset)
- new_i_size = min_t(u64, i_size_test, i_size);
+ if (ordered && ordered->outstanding_isize > new_i_size)
+ new_i_size = min_t(u64, ordered->outstanding_isize, i_size);
BTRFS_I(inode)->disk_i_size = new_i_size;
ret = 0;
out:
@@ -984,3 +950,20 @@ void btrfs_add_ordered_operation(struct btrfs_trans_handle *trans,
}
spin_unlock(&root->fs_info->ordered_extent_lock);
}
+
+int __init ordered_data_init(void)
+{
+ btrfs_ordered_extent_cache = kmem_cache_create("btrfs_ordered_extent",
+ sizeof(struct btrfs_ordered_extent), 0,
+ SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD,
+ NULL);
+ if (!btrfs_ordered_extent_cache)
+ return -ENOMEM;
+ return 0;
+}
+
+void ordered_data_exit(void)
+{
+ if (btrfs_ordered_extent_cache)
+ kmem_cache_destroy(btrfs_ordered_extent_cache);
+}
diff --git a/fs/btrfs/ordered-data.h b/fs/btrfs/ordered-data.h
index e03c560..dd27a0b 100644
--- a/fs/btrfs/ordered-data.h
+++ b/fs/btrfs/ordered-data.h
@@ -96,6 +96,13 @@ struct btrfs_ordered_extent {
/* number of bytes that still need writing */
u64 bytes_left;
+ /*
+ * the end of the ordered extent which is behind it but
+ * didn't update disk_i_size. Please see the comment of
+ * btrfs_ordered_update_i_size();
+ */
+ u64 outstanding_isize;
+
/* flags (described above) */
unsigned long flags;
@@ -183,6 +190,7 @@ void btrfs_run_ordered_operations(struct btrfs_root *root, int wait);
void btrfs_add_ordered_operation(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct inode *inode);
-void btrfs_wait_ordered_extents(struct btrfs_root *root,
- int nocow_only, int delay_iput);
+void btrfs_wait_ordered_extents(struct btrfs_root *root, int delay_iput);
+int __init ordered_data_init(void);
+void ordered_data_exit(void);
#endif
diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c
index b650155..5039686 100644
--- a/fs/btrfs/qgroup.c
+++ b/fs/btrfs/qgroup.c
@@ -1145,12 +1145,12 @@ int btrfs_qgroup_account_ref(struct btrfs_trans_handle *trans,
ulist_reinit(tmp);
/* XXX id not needed */
- ulist_add(tmp, qg->qgroupid, (unsigned long)qg, GFP_ATOMIC);
+ ulist_add(tmp, qg->qgroupid, (u64)(uintptr_t)qg, GFP_ATOMIC);
ULIST_ITER_INIT(&tmp_uiter);
while ((tmp_unode = ulist_next(tmp, &tmp_uiter))) {
struct btrfs_qgroup_list *glist;
- qg = (struct btrfs_qgroup *)tmp_unode->aux;
+ qg = (struct btrfs_qgroup *)(uintptr_t)tmp_unode->aux;
if (qg->refcnt < seq)
qg->refcnt = seq + 1;
else
@@ -1158,7 +1158,7 @@ int btrfs_qgroup_account_ref(struct btrfs_trans_handle *trans,
list_for_each_entry(glist, &qg->groups, next_group) {
ulist_add(tmp, glist->group->qgroupid,
- (unsigned long)glist->group,
+ (u64)(uintptr_t)glist->group,
GFP_ATOMIC);
}
}
@@ -1168,13 +1168,13 @@ int btrfs_qgroup_account_ref(struct btrfs_trans_handle *trans,
* step 2: walk from the new root
*/
ulist_reinit(tmp);
- ulist_add(tmp, qgroup->qgroupid, (unsigned long)qgroup, GFP_ATOMIC);
+ ulist_add(tmp, qgroup->qgroupid, (uintptr_t)qgroup, GFP_ATOMIC);
ULIST_ITER_INIT(&uiter);
while ((unode = ulist_next(tmp, &uiter))) {
struct btrfs_qgroup *qg;
struct btrfs_qgroup_list *glist;
- qg = (struct btrfs_qgroup *)unode->aux;
+ qg = (struct btrfs_qgroup *)(uintptr_t)unode->aux;
if (qg->refcnt < seq) {
/* not visited by step 1 */
qg->rfer += sgn * node->num_bytes;
@@ -1190,7 +1190,7 @@ int btrfs_qgroup_account_ref(struct btrfs_trans_handle *trans,
list_for_each_entry(glist, &qg->groups, next_group) {
ulist_add(tmp, glist->group->qgroupid,
- (unsigned long)glist->group, GFP_ATOMIC);
+ (uintptr_t)glist->group, GFP_ATOMIC);
}
}
@@ -1208,12 +1208,12 @@ int btrfs_qgroup_account_ref(struct btrfs_trans_handle *trans,
continue;
ulist_reinit(tmp);
- ulist_add(tmp, qg->qgroupid, (unsigned long)qg, GFP_ATOMIC);
+ ulist_add(tmp, qg->qgroupid, (uintptr_t)qg, GFP_ATOMIC);
ULIST_ITER_INIT(&tmp_uiter);
while ((tmp_unode = ulist_next(tmp, &tmp_uiter))) {
struct btrfs_qgroup_list *glist;
- qg = (struct btrfs_qgroup *)tmp_unode->aux;
+ qg = (struct btrfs_qgroup *)(uintptr_t)tmp_unode->aux;
if (qg->tag == seq)
continue;
@@ -1225,7 +1225,7 @@ int btrfs_qgroup_account_ref(struct btrfs_trans_handle *trans,
list_for_each_entry(glist, &qg->groups, next_group) {
ulist_add(tmp, glist->group->qgroupid,
- (unsigned long)glist->group,
+ (uintptr_t)glist->group,
GFP_ATOMIC);
}
}
@@ -1469,13 +1469,17 @@ int btrfs_qgroup_reserve(struct btrfs_root *root, u64 num_bytes)
* be exceeded
*/
ulist = ulist_alloc(GFP_ATOMIC);
- ulist_add(ulist, qgroup->qgroupid, (unsigned long)qgroup, GFP_ATOMIC);
+ if (!ulist) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ ulist_add(ulist, qgroup->qgroupid, (uintptr_t)qgroup, GFP_ATOMIC);
ULIST_ITER_INIT(&uiter);
while ((unode = ulist_next(ulist, &uiter))) {
struct btrfs_qgroup *qg;
struct btrfs_qgroup_list *glist;
- qg = (struct btrfs_qgroup *)unode->aux;
+ qg = (struct btrfs_qgroup *)(uintptr_t)unode->aux;
if ((qg->lim_flags & BTRFS_QGROUP_LIMIT_MAX_RFER) &&
qg->reserved + qg->rfer + num_bytes >
@@ -1489,7 +1493,7 @@ int btrfs_qgroup_reserve(struct btrfs_root *root, u64 num_bytes)
list_for_each_entry(glist, &qg->groups, next_group) {
ulist_add(ulist, glist->group->qgroupid,
- (unsigned long)glist->group, GFP_ATOMIC);
+ (uintptr_t)glist->group, GFP_ATOMIC);
}
}
if (ret)
@@ -1502,7 +1506,7 @@ int btrfs_qgroup_reserve(struct btrfs_root *root, u64 num_bytes)
while ((unode = ulist_next(ulist, &uiter))) {
struct btrfs_qgroup *qg;
- qg = (struct btrfs_qgroup *)unode->aux;
+ qg = (struct btrfs_qgroup *)(uintptr_t)unode->aux;
qg->reserved += num_bytes;
}
@@ -1541,19 +1545,23 @@ void btrfs_qgroup_free(struct btrfs_root *root, u64 num_bytes)
goto out;
ulist = ulist_alloc(GFP_ATOMIC);
- ulist_add(ulist, qgroup->qgroupid, (unsigned long)qgroup, GFP_ATOMIC);
+ if (!ulist) {
+ btrfs_std_error(fs_info, -ENOMEM);
+ goto out;
+ }
+ ulist_add(ulist, qgroup->qgroupid, (uintptr_t)qgroup, GFP_ATOMIC);
ULIST_ITER_INIT(&uiter);
while ((unode = ulist_next(ulist, &uiter))) {
struct btrfs_qgroup *qg;
struct btrfs_qgroup_list *glist;
- qg = (struct btrfs_qgroup *)unode->aux;
+ qg = (struct btrfs_qgroup *)(uintptr_t)unode->aux;
qg->reserved -= num_bytes;
list_for_each_entry(glist, &qg->groups, next_group) {
ulist_add(ulist, glist->group->qgroupid,
- (unsigned long)glist->group, GFP_ATOMIC);
+ (uintptr_t)glist->group, GFP_ATOMIC);
}
}
diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c
index 4da0865..776f0aa 100644
--- a/fs/btrfs/relocation.c
+++ b/fs/btrfs/relocation.c
@@ -3270,8 +3270,8 @@ 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 (IS_ERR_OR_NULL(inode) || is_bad_inode(inode)) {
- if (inode && !IS_ERR(inode))
+ if (IS_ERR(inode) || is_bad_inode(inode)) {
+ if (!IS_ERR(inode))
iput(inode);
return -ENOENT;
}
@@ -3621,7 +3621,7 @@ next:
ret = find_first_extent_bit(&rc->processed_blocks,
key.objectid, &start, &end,
- EXTENT_DIRTY);
+ EXTENT_DIRTY, NULL);
if (ret == 0 && start <= key.objectid) {
btrfs_release_path(path);
@@ -3674,7 +3674,8 @@ int prepare_to_relocate(struct reloc_control *rc)
struct btrfs_trans_handle *trans;
int ret;
- rc->block_rsv = btrfs_alloc_block_rsv(rc->extent_root);
+ rc->block_rsv = btrfs_alloc_block_rsv(rc->extent_root,
+ BTRFS_BLOCK_RSV_TEMP);
if (!rc->block_rsv)
return -ENOMEM;
@@ -4057,7 +4058,7 @@ int btrfs_relocate_block_group(struct btrfs_root *extent_root, u64 group_start)
(unsigned long long)rc->block_group->flags);
btrfs_start_delalloc_inodes(fs_info->tree_root, 0);
- btrfs_wait_ordered_extents(fs_info->tree_root, 0, 0);
+ btrfs_wait_ordered_extents(fs_info->tree_root, 0);
while (1) {
mutex_lock(&fs_info->cleaner_mutex);
diff --git a/fs/btrfs/root-tree.c b/fs/btrfs/root-tree.c
index 10d8e4d..eb923d0 100644
--- a/fs/btrfs/root-tree.c
+++ b/fs/btrfs/root-tree.c
@@ -141,8 +141,10 @@ int btrfs_update_root(struct btrfs_trans_handle *trans, struct btrfs_root
return -ENOMEM;
ret = btrfs_search_slot(trans, root, key, path, 0, 1);
- if (ret < 0)
- goto out_abort;
+ if (ret < 0) {
+ btrfs_abort_transaction(trans, root, ret);
+ goto out;
+ }
if (ret != 0) {
btrfs_print_leaf(root, path->nodes[0]);
@@ -166,16 +168,23 @@ int btrfs_update_root(struct btrfs_trans_handle *trans, struct btrfs_root
btrfs_release_path(path);
ret = btrfs_search_slot(trans, root, key, path,
-1, 1);
- if (ret < 0)
- goto out_abort;
+ if (ret < 0) {
+ btrfs_abort_transaction(trans, root, ret);
+ goto out;
+ }
+
ret = btrfs_del_item(trans, root, path);
- if (ret < 0)
- goto out_abort;
+ if (ret < 0) {
+ btrfs_abort_transaction(trans, root, ret);
+ goto out;
+ }
btrfs_release_path(path);
ret = btrfs_insert_empty_item(trans, root, path,
key, sizeof(*item));
- if (ret < 0)
- goto out_abort;
+ if (ret < 0) {
+ btrfs_abort_transaction(trans, root, ret);
+ goto out;
+ }
l = path->nodes[0];
slot = path->slots[0];
ptr = btrfs_item_ptr_offset(l, slot);
@@ -192,10 +201,6 @@ int btrfs_update_root(struct btrfs_trans_handle *trans, struct btrfs_root
out:
btrfs_free_path(path);
return ret;
-
-out_abort:
- btrfs_abort_transaction(trans, root, ret);
- goto out;
}
int btrfs_insert_root(struct btrfs_trans_handle *trans, struct btrfs_root *root,
diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c
index b223620..27892f6 100644
--- a/fs/btrfs/scrub.c
+++ b/fs/btrfs/scrub.c
@@ -352,13 +352,14 @@ static void scrub_print_warning(const char *errstr, struct scrub_block *sblock)
struct extent_buffer *eb;
struct btrfs_extent_item *ei;
struct scrub_warning swarn;
- u32 item_size;
- int ret;
+ unsigned long ptr = 0;
+ u64 extent_item_pos;
+ u64 flags = 0;
u64 ref_root;
+ u32 item_size;
u8 ref_level;
- unsigned long ptr = 0;
const int bufsize = 4096;
- u64 extent_item_pos;
+ int ret;
path = btrfs_alloc_path();
@@ -375,7 +376,8 @@ static void scrub_print_warning(const char *errstr, struct scrub_block *sblock)
if (!path || !swarn.scratch_buf || !swarn.msg_buf)
goto out;
- ret = extent_from_logical(fs_info, swarn.logical, path, &found_key);
+ ret = extent_from_logical(fs_info, swarn.logical, path, &found_key,
+ &flags);
if (ret < 0)
goto out;
@@ -387,7 +389,7 @@ static void scrub_print_warning(const char *errstr, struct scrub_block *sblock)
item_size = btrfs_item_size_nr(eb, path->slots[0]);
btrfs_release_path(path);
- if (ret & BTRFS_EXTENT_FLAG_TREE_BLOCK) {
+ if (flags & BTRFS_EXTENT_FLAG_TREE_BLOCK) {
do {
ret = tree_backref_for_extent(&ptr, eb, ei, item_size,
&ref_root, &ref_level);
@@ -1029,6 +1031,7 @@ static int scrub_setup_recheck_block(struct scrub_dev *sdev,
spin_lock(&sdev->stat_lock);
sdev->stat.malloc_errors++;
spin_unlock(&sdev->stat_lock);
+ kfree(bbio);
return -ENOMEM;
}
sblock->page_count++;
@@ -1666,21 +1669,6 @@ static void scrub_bio_end_io_worker(struct btrfs_work *work)
scrub_block_put(sblock);
}
- if (sbio->err) {
- /* what is this good for??? */
- 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->page_count; i++) {
- struct bio_vec *bi;
- bi = &sbio->bio->bi_io_vec[i];
- bi->bv_offset = 0;
- bi->bv_len = PAGE_SIZE;
- }
- }
-
bio_put(sbio->bio);
sbio->bio = NULL;
spin_lock(&sdev->list_lock);
diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c
index fb5ffe9..c7beb54 100644
--- a/fs/btrfs/send.c
+++ b/fs/btrfs/send.c
@@ -107,7 +107,6 @@ struct send_ctx {
int cur_inode_new;
int cur_inode_new_gen;
int cur_inode_deleted;
- int cur_inode_first_ref_orphan;
u64 cur_inode_size;
u64 cur_inode_mode;
@@ -126,7 +125,15 @@ struct send_ctx {
struct name_cache_entry {
struct list_head list;
- struct list_head use_list;
+ /*
+ * radix_tree has only 32bit entries but we need to handle 64bit inums.
+ * We use the lower 32bit of the 64bit inum to store it in the tree. If
+ * more then one inum would fall into the same entry, we use radix_list
+ * to store the additional entries. radix_list is also used to store
+ * entries where two entries have the same inum but different
+ * generations.
+ */
+ struct list_head radix_list;
u64 ino;
u64 gen;
u64 parent_ino;
@@ -328,6 +335,7 @@ out:
return ret;
}
+#if 0
static void fs_path_remove(struct fs_path *p)
{
BUG_ON(p->reversed);
@@ -335,6 +343,7 @@ static void fs_path_remove(struct fs_path *p)
p->end--;
*p->end = 0;
}
+#endif
static int fs_path_copy(struct fs_path *p, struct fs_path *from)
{
@@ -377,7 +386,7 @@ static struct btrfs_path *alloc_path_for_send(void)
return path;
}
-static int write_buf(struct send_ctx *sctx, const void *buf, u32 len)
+int write_buf(struct file *filp, const void *buf, u32 len, loff_t *off)
{
int ret;
mm_segment_t old_fs;
@@ -387,8 +396,7 @@ static int write_buf(struct send_ctx *sctx, const void *buf, u32 len)
set_fs(KERNEL_DS);
while (pos < len) {
- ret = vfs_write(sctx->send_filp, (char *)buf + pos, len - pos,
- &sctx->send_off);
+ ret = vfs_write(filp, (char *)buf + pos, len - pos, off);
/* TODO handle that correctly */
/*if (ret == -ERESTARTSYS) {
continue;
@@ -544,7 +552,8 @@ static int send_header(struct send_ctx *sctx)
strcpy(hdr.magic, BTRFS_SEND_STREAM_MAGIC);
hdr.version = cpu_to_le32(BTRFS_SEND_STREAM_VERSION);
- return write_buf(sctx, &hdr, sizeof(hdr));
+ return write_buf(sctx->send_filp, &hdr, sizeof(hdr),
+ &sctx->send_off);
}
/*
@@ -581,7 +590,8 @@ static int send_cmd(struct send_ctx *sctx)
crc = crc32c(0, (unsigned char *)sctx->send_buf, sctx->send_size);
hdr->crc = cpu_to_le32(crc);
- ret = write_buf(sctx, sctx->send_buf, sctx->send_size);
+ ret = write_buf(sctx->send_filp, sctx->send_buf, sctx->send_size,
+ &sctx->send_off);
sctx->total_send_size += sctx->send_size;
sctx->cmd_send_size[le16_to_cpu(hdr->cmd)] += sctx->send_size;
@@ -687,7 +697,8 @@ out:
*/
static int get_inode_info(struct btrfs_root *root,
u64 ino, u64 *size, u64 *gen,
- u64 *mode, u64 *uid, u64 *gid)
+ u64 *mode, u64 *uid, u64 *gid,
+ u64 *rdev)
{
int ret;
struct btrfs_inode_item *ii;
@@ -721,6 +732,8 @@ static int get_inode_info(struct btrfs_root *root,
*uid = btrfs_inode_uid(path->nodes[0], ii);
if (gid)
*gid = btrfs_inode_gid(path->nodes[0], ii);
+ if (rdev)
+ *rdev = btrfs_inode_rdev(path->nodes[0], ii);
out:
btrfs_free_path(path);
@@ -852,7 +865,6 @@ static int iterate_dir_item(struct send_ctx *sctx,
struct extent_buffer *eb;
struct btrfs_item *item;
struct btrfs_dir_item *di;
- struct btrfs_path *tmp_path = NULL;
struct btrfs_key di_key;
char *buf = NULL;
char *buf2 = NULL;
@@ -874,12 +886,6 @@ static int iterate_dir_item(struct send_ctx *sctx,
goto out;
}
- tmp_path = alloc_path_for_send();
- if (!tmp_path) {
- ret = -ENOMEM;
- goto out;
- }
-
eb = path->nodes[0];
slot = path->slots[0];
item = btrfs_item_nr(eb, slot);
@@ -941,7 +947,6 @@ static int iterate_dir_item(struct send_ctx *sctx,
}
out:
- btrfs_free_path(tmp_path);
if (buf_virtual)
vfree(buf);
else
@@ -1026,12 +1031,12 @@ struct backref_ctx {
u64 extent_len;
/* Just to check for bugs in backref resolving */
- int found_in_send_root;
+ int found_itself;
};
static int __clone_root_cmp_bsearch(const void *key, const void *elt)
{
- u64 root = (u64)key;
+ u64 root = (u64)(uintptr_t)key;
struct clone_root *cr = (struct clone_root *)elt;
if (root < cr->root->objectid)
@@ -1055,6 +1060,7 @@ static int __clone_root_cmp_sort(const void *e1, const void *e2)
/*
* Called for every backref that is found for the current extent.
+ * Results are collected in sctx->clone_roots->ino/offset/found_refs
*/
static int __iterate_backrefs(u64 ino, u64 offset, u64 root, void *ctx_)
{
@@ -1064,7 +1070,7 @@ static int __iterate_backrefs(u64 ino, u64 offset, u64 root, void *ctx_)
u64 i_size;
/* First check if the root is in the list of accepted clone sources */
- found = bsearch((void *)root, bctx->sctx->clone_roots,
+ found = bsearch((void *)(uintptr_t)root, bctx->sctx->clone_roots,
bctx->sctx->clone_roots_cnt,
sizeof(struct clone_root),
__clone_root_cmp_bsearch);
@@ -1074,14 +1080,15 @@ static int __iterate_backrefs(u64 ino, u64 offset, u64 root, void *ctx_)
if (found->root == bctx->sctx->send_root &&
ino == bctx->cur_objectid &&
offset == bctx->cur_offset) {
- bctx->found_in_send_root = 1;
+ bctx->found_itself = 1;
}
/*
- * There are inodes that have extents that lie behind it's i_size. Don't
+ * There are inodes that have extents that lie behind its i_size. Don't
* accept clones from these extents.
*/
- ret = get_inode_info(found->root, ino, &i_size, NULL, NULL, NULL, NULL);
+ ret = get_inode_info(found->root, ino, &i_size, NULL, NULL, NULL, NULL,
+ NULL);
if (ret < 0)
return ret;
@@ -1101,16 +1108,12 @@ static int __iterate_backrefs(u64 ino, u64 offset, u64 root, void *ctx_)
*/
if (ino >= bctx->cur_objectid)
return 0;
- /*if (ino > ctx->cur_objectid)
+#if 0
+ if (ino > bctx->cur_objectid)
return 0;
- if (offset + ctx->extent_len > ctx->cur_offset)
- return 0;*/
-
- bctx->found++;
- found->found_refs++;
- found->ino = ino;
- found->offset = offset;
- return 0;
+ if (offset + bctx->extent_len > bctx->cur_offset)
+ return 0;
+#endif
}
bctx->found++;
@@ -1130,6 +1133,12 @@ static int __iterate_backrefs(u64 ino, u64 offset, u64 root, void *ctx_)
}
/*
+ * Given an inode, offset and extent item, it finds a good clone for a clone
+ * instruction. Returns -ENOENT when none could be found. The function makes
+ * sure that the returned clone is usable at the point where sending is at the
+ * moment. This means, that no clones are accepted which lie behind the current
+ * inode+offset.
+ *
* path must point to the extent item when called.
*/
static int find_extent_clone(struct send_ctx *sctx,
@@ -1141,20 +1150,29 @@ static int find_extent_clone(struct send_ctx *sctx,
int ret;
int extent_type;
u64 logical;
+ u64 disk_byte;
u64 num_bytes;
u64 extent_item_pos;
+ u64 flags = 0;
struct btrfs_file_extent_item *fi;
struct extent_buffer *eb = path->nodes[0];
- struct backref_ctx backref_ctx;
+ struct backref_ctx *backref_ctx = NULL;
struct clone_root *cur_clone_root;
struct btrfs_key found_key;
struct btrfs_path *tmp_path;
+ int compressed;
u32 i;
tmp_path = alloc_path_for_send();
if (!tmp_path)
return -ENOMEM;
+ backref_ctx = kmalloc(sizeof(*backref_ctx), GFP_NOFS);
+ if (!backref_ctx) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
if (data_offset >= ino_size) {
/*
* There may be extents that lie behind the file's size.
@@ -1172,22 +1190,23 @@ static int find_extent_clone(struct send_ctx *sctx,
ret = -ENOENT;
goto out;
}
+ compressed = btrfs_file_extent_compression(eb, fi);
num_bytes = btrfs_file_extent_num_bytes(eb, fi);
- logical = btrfs_file_extent_disk_bytenr(eb, fi);
- if (logical == 0) {
+ disk_byte = btrfs_file_extent_disk_bytenr(eb, fi);
+ if (disk_byte == 0) {
ret = -ENOENT;
goto out;
}
- logical += btrfs_file_extent_offset(eb, fi);
+ logical = disk_byte + btrfs_file_extent_offset(eb, fi);
- ret = extent_from_logical(sctx->send_root->fs_info,
- logical, tmp_path, &found_key);
+ ret = extent_from_logical(sctx->send_root->fs_info, disk_byte, tmp_path,
+ &found_key, &flags);
btrfs_release_path(tmp_path);
if (ret < 0)
goto out;
- if (ret & BTRFS_EXTENT_FLAG_TREE_BLOCK) {
+ if (flags & BTRFS_EXTENT_FLAG_TREE_BLOCK) {
ret = -EIO;
goto out;
}
@@ -1202,12 +1221,12 @@ static int find_extent_clone(struct send_ctx *sctx,
cur_clone_root->found_refs = 0;
}
- backref_ctx.sctx = sctx;
- backref_ctx.found = 0;
- backref_ctx.cur_objectid = ino;
- backref_ctx.cur_offset = data_offset;
- backref_ctx.found_in_send_root = 0;
- backref_ctx.extent_len = num_bytes;
+ backref_ctx->sctx = sctx;
+ backref_ctx->found = 0;
+ backref_ctx->cur_objectid = ino;
+ backref_ctx->cur_offset = data_offset;
+ backref_ctx->found_itself = 0;
+ backref_ctx->extent_len = num_bytes;
/*
* The last extent of a file may be too large due to page alignment.
@@ -1215,25 +1234,31 @@ static int find_extent_clone(struct send_ctx *sctx,
* __iterate_backrefs work.
*/
if (data_offset + num_bytes >= ino_size)
- backref_ctx.extent_len = ino_size - data_offset;
+ backref_ctx->extent_len = ino_size - data_offset;
/*
* Now collect all backrefs.
*/
+ if (compressed == BTRFS_COMPRESS_NONE)
+ extent_item_pos = logical - found_key.objectid;
+ else
+ extent_item_pos = 0;
+
extent_item_pos = logical - found_key.objectid;
ret = iterate_extent_inodes(sctx->send_root->fs_info,
found_key.objectid, extent_item_pos, 1,
- __iterate_backrefs, &backref_ctx);
+ __iterate_backrefs, backref_ctx);
+
if (ret < 0)
goto out;
- if (!backref_ctx.found_in_send_root) {
+ if (!backref_ctx->found_itself) {
/* found a bug in backref code? */
ret = -EIO;
printk(KERN_ERR "btrfs: ERROR did not find backref in "
"send_root. inode=%llu, offset=%llu, "
- "logical=%llu\n",
- ino, data_offset, logical);
+ "disk_byte=%llu found extent=%llu\n",
+ ino, data_offset, disk_byte, found_key.objectid);
goto out;
}
@@ -1242,7 +1267,7 @@ verbose_printk(KERN_DEBUG "btrfs: find_extent_clone: data_offset=%llu, "
"num_bytes=%llu, logical=%llu\n",
data_offset, ino, num_bytes, logical);
- if (!backref_ctx.found)
+ if (!backref_ctx->found)
verbose_printk("btrfs: no clones found\n");
cur_clone_root = NULL;
@@ -1253,7 +1278,6 @@ verbose_printk(KERN_DEBUG "btrfs: find_extent_clone: data_offset=%llu, "
else if (sctx->clone_roots[i].root == sctx->send_root)
/* prefer clones from send_root over others */
cur_clone_root = sctx->clone_roots + i;
- break;
}
}
@@ -1267,6 +1291,7 @@ verbose_printk(KERN_DEBUG "btrfs: find_extent_clone: data_offset=%llu, "
out:
btrfs_free_path(tmp_path);
+ kfree(backref_ctx);
return ret;
}
@@ -1307,8 +1332,6 @@ static int read_symlink(struct send_ctx *sctx,
len = btrfs_file_extent_inline_len(path->nodes[0], ei);
ret = fs_path_add_from_extent_buffer(dest, path->nodes[0], off, len);
- if (ret < 0)
- goto out;
out:
btrfs_free_path(path);
@@ -1404,7 +1427,7 @@ static int get_cur_inode_state(struct send_ctx *sctx, u64 ino, u64 gen)
u64 right_gen;
ret = get_inode_info(sctx->send_root, ino, NULL, &left_gen, NULL, NULL,
- NULL);
+ NULL, NULL);
if (ret < 0 && ret != -ENOENT)
goto out;
left_ret = ret;
@@ -1413,16 +1436,16 @@ static int get_cur_inode_state(struct send_ctx *sctx, u64 ino, u64 gen)
right_ret = -ENOENT;
} else {
ret = get_inode_info(sctx->parent_root, ino, NULL, &right_gen,
- NULL, NULL, NULL);
+ NULL, NULL, NULL, NULL);
if (ret < 0 && ret != -ENOENT)
goto out;
right_ret = ret;
}
if (!left_ret && !right_ret) {
- if (left_gen == gen && right_gen == gen)
+ if (left_gen == gen && right_gen == gen) {
ret = inode_state_no_change;
- else if (left_gen == gen) {
+ } else if (left_gen == gen) {
if (ino < sctx->send_progress)
ret = inode_state_did_create;
else
@@ -1516,6 +1539,10 @@ out:
return ret;
}
+/*
+ * Looks up the first btrfs_inode_ref of a given ino. It returns the parent dir,
+ * generation of the parent dir and the name of the dir entry.
+ */
static int get_first_ref(struct send_ctx *sctx,
struct btrfs_root *root, u64 ino,
u64 *dir, u64 *dir_gen, struct fs_path *name)
@@ -1557,7 +1584,7 @@ static int get_first_ref(struct send_ctx *sctx,
btrfs_release_path(path);
ret = get_inode_info(root, found_key.offset, NULL, dir_gen, NULL, NULL,
- NULL);
+ NULL, NULL);
if (ret < 0)
goto out;
@@ -1586,22 +1613,28 @@ static int is_first_ref(struct send_ctx *sctx,
if (ret < 0)
goto out;
- if (name_len != fs_path_len(tmp_name)) {
+ if (dir != tmp_dir || name_len != fs_path_len(tmp_name)) {
ret = 0;
goto out;
}
- ret = memcmp(tmp_name->start, name, name_len);
- if (ret)
- ret = 0;
- else
- ret = 1;
+ ret = !memcmp(tmp_name->start, name, name_len);
out:
fs_path_free(sctx, tmp_name);
return ret;
}
+/*
+ * Used by process_recorded_refs to determine if a new ref would overwrite an
+ * already existing ref. In case it detects an overwrite, it returns the
+ * inode/gen in who_ino/who_gen.
+ * When an overwrite is detected, process_recorded_refs does proper orphanizing
+ * to make sure later references to the overwritten inode are possible.
+ * Orphanizing is however only required for the first ref of an inode.
+ * process_recorded_refs does an additional is_first_ref check to see if
+ * orphanizing is really required.
+ */
static int will_overwrite_ref(struct send_ctx *sctx, u64 dir, u64 dir_gen,
const char *name, int name_len,
u64 *who_ino, u64 *who_gen)
@@ -1626,9 +1659,14 @@ static int will_overwrite_ref(struct send_ctx *sctx, u64 dir, u64 dir_gen,
goto out;
}
+ /*
+ * Check if the overwritten ref was already processed. If yes, the ref
+ * was already unlinked/moved, so we can safely assume that we will not
+ * overwrite anything at this point in time.
+ */
if (other_inode > sctx->send_progress) {
ret = get_inode_info(sctx->parent_root, other_inode, NULL,
- who_gen, NULL, NULL, NULL);
+ who_gen, NULL, NULL, NULL, NULL);
if (ret < 0)
goto out;
@@ -1642,6 +1680,13 @@ out:
return ret;
}
+/*
+ * Checks if the ref was overwritten by an already processed inode. This is
+ * used by __get_cur_name_and_parent to find out if the ref was orphanized and
+ * thus the orphan name needs be used.
+ * process_recorded_refs also uses it to avoid unlinking of refs that were
+ * overwritten.
+ */
static int did_overwrite_ref(struct send_ctx *sctx,
u64 dir, u64 dir_gen,
u64 ino, u64 ino_gen,
@@ -1671,7 +1716,7 @@ static int did_overwrite_ref(struct send_ctx *sctx,
}
ret = get_inode_info(sctx->send_root, ow_inode, NULL, &gen, NULL, NULL,
- NULL);
+ NULL, NULL);
if (ret < 0)
goto out;
@@ -1690,6 +1735,11 @@ out:
return ret;
}
+/*
+ * Same as did_overwrite_ref, but also checks if it is the first ref of an inode
+ * that got overwritten. This is used by process_recorded_refs to determine
+ * if it has to use the path as returned by get_cur_path or the orphan name.
+ */
static int did_overwrite_first_ref(struct send_ctx *sctx, u64 ino, u64 gen)
{
int ret = 0;
@@ -1710,39 +1760,40 @@ static int did_overwrite_first_ref(struct send_ctx *sctx, u64 ino, u64 gen)
ret = did_overwrite_ref(sctx, dir, dir_gen, ino, gen,
name->start, fs_path_len(name));
- if (ret < 0)
- goto out;
out:
fs_path_free(sctx, name);
return ret;
}
+/*
+ * Insert a name cache entry. On 32bit kernels the radix tree index is 32bit,
+ * so we need to do some special handling in case we have clashes. This function
+ * takes care of this with the help of name_cache_entry::radix_list.
+ * In case of error, nce is kfreed.
+ */
static int name_cache_insert(struct send_ctx *sctx,
struct name_cache_entry *nce)
{
int ret = 0;
- struct name_cache_entry **ncea;
-
- ncea = radix_tree_lookup(&sctx->name_cache, nce->ino);
- if (ncea) {
- if (!ncea[0])
- ncea[0] = nce;
- else if (!ncea[1])
- ncea[1] = nce;
- else
- BUG();
- } else {
- ncea = kmalloc(sizeof(void *) * 2, GFP_NOFS);
- if (!ncea)
+ struct list_head *nce_head;
+
+ nce_head = radix_tree_lookup(&sctx->name_cache,
+ (unsigned long)nce->ino);
+ if (!nce_head) {
+ nce_head = kmalloc(sizeof(*nce_head), GFP_NOFS);
+ if (!nce_head)
return -ENOMEM;
+ INIT_LIST_HEAD(nce_head);
- ncea[0] = nce;
- ncea[1] = NULL;
- ret = radix_tree_insert(&sctx->name_cache, nce->ino, ncea);
- if (ret < 0)
+ ret = radix_tree_insert(&sctx->name_cache, nce->ino, nce_head);
+ if (ret < 0) {
+ kfree(nce_head);
+ kfree(nce);
return ret;
+ }
}
+ list_add_tail(&nce->radix_list, nce_head);
list_add_tail(&nce->list, &sctx->name_cache_list);
sctx->name_cache_size++;
@@ -1752,50 +1803,52 @@ static int name_cache_insert(struct send_ctx *sctx,
static void name_cache_delete(struct send_ctx *sctx,
struct name_cache_entry *nce)
{
- struct name_cache_entry **ncea;
-
- ncea = radix_tree_lookup(&sctx->name_cache, nce->ino);
- BUG_ON(!ncea);
-
- if (ncea[0] == nce)
- ncea[0] = NULL;
- else if (ncea[1] == nce)
- ncea[1] = NULL;
- else
- BUG();
+ struct list_head *nce_head;
- if (!ncea[0] && !ncea[1]) {
- radix_tree_delete(&sctx->name_cache, nce->ino);
- kfree(ncea);
- }
+ nce_head = radix_tree_lookup(&sctx->name_cache,
+ (unsigned long)nce->ino);
+ BUG_ON(!nce_head);
+ list_del(&nce->radix_list);
list_del(&nce->list);
-
sctx->name_cache_size--;
+
+ if (list_empty(nce_head)) {
+ radix_tree_delete(&sctx->name_cache, (unsigned long)nce->ino);
+ kfree(nce_head);
+ }
}
static struct name_cache_entry *name_cache_search(struct send_ctx *sctx,
u64 ino, u64 gen)
{
- struct name_cache_entry **ncea;
+ struct list_head *nce_head;
+ struct name_cache_entry *cur;
- ncea = radix_tree_lookup(&sctx->name_cache, ino);
- if (!ncea)
+ nce_head = radix_tree_lookup(&sctx->name_cache, (unsigned long)ino);
+ if (!nce_head)
return NULL;
- if (ncea[0] && ncea[0]->gen == gen)
- return ncea[0];
- else if (ncea[1] && ncea[1]->gen == gen)
- return ncea[1];
+ list_for_each_entry(cur, nce_head, radix_list) {
+ if (cur->ino == ino && cur->gen == gen)
+ return cur;
+ }
return NULL;
}
+/*
+ * Removes the entry from the list and adds it back to the end. This marks the
+ * entry as recently used so that name_cache_clean_unused does not remove it.
+ */
static void name_cache_used(struct send_ctx *sctx, struct name_cache_entry *nce)
{
list_del(&nce->list);
list_add_tail(&nce->list, &sctx->name_cache_list);
}
+/*
+ * Remove some entries from the beginning of name_cache_list.
+ */
static void name_cache_clean_unused(struct send_ctx *sctx)
{
struct name_cache_entry *nce;
@@ -1814,13 +1867,23 @@ static void name_cache_clean_unused(struct send_ctx *sctx)
static void name_cache_free(struct send_ctx *sctx)
{
struct name_cache_entry *nce;
- struct name_cache_entry *tmp;
- list_for_each_entry_safe(nce, tmp, &sctx->name_cache_list, list) {
+ while (!list_empty(&sctx->name_cache_list)) {
+ nce = list_entry(sctx->name_cache_list.next,
+ struct name_cache_entry, list);
name_cache_delete(sctx, nce);
+ kfree(nce);
}
}
+/*
+ * Used by get_cur_path for each ref up to the root.
+ * Returns 0 if it succeeded.
+ * Returns 1 if the inode is not existent or got overwritten. In that case, the
+ * name is an orphan name. This instructs get_cur_path to stop iterating. If 1
+ * is returned, parent_ino/parent_gen are not guaranteed to be valid.
+ * Returns <0 in case of error.
+ */
static int __get_cur_name_and_parent(struct send_ctx *sctx,
u64 ino, u64 gen,
u64 *parent_ino,
@@ -1832,6 +1895,11 @@ static int __get_cur_name_and_parent(struct send_ctx *sctx,
struct btrfs_path *path = NULL;
struct name_cache_entry *nce = NULL;
+ /*
+ * First check if we already did a call to this function with the same
+ * ino/gen. If yes, check if the cache entry is still up-to-date. If yes
+ * return the cached result.
+ */
nce = name_cache_search(sctx, ino, gen);
if (nce) {
if (ino < sctx->send_progress && nce->need_later_update) {
@@ -1854,6 +1922,11 @@ static int __get_cur_name_and_parent(struct send_ctx *sctx,
if (!path)
return -ENOMEM;
+ /*
+ * If the inode is not existent yet, add the orphan name and return 1.
+ * This should only happen for the parent dir that we determine in
+ * __record_new_ref
+ */
ret = is_inode_existent(sctx, ino, gen);
if (ret < 0)
goto out;
@@ -1866,6 +1939,10 @@ static int __get_cur_name_and_parent(struct send_ctx *sctx,
goto out_cache;
}
+ /*
+ * Depending on whether the inode was already processed or not, use
+ * send_root or parent_root for ref lookup.
+ */
if (ino < sctx->send_progress)
ret = get_first_ref(sctx, sctx->send_root, ino,
parent_ino, parent_gen, dest);
@@ -1875,6 +1952,10 @@ static int __get_cur_name_and_parent(struct send_ctx *sctx,
if (ret < 0)
goto out;
+ /*
+ * Check if the ref was overwritten by an inode's ref that was processed
+ * earlier. If yes, treat as orphan and return 1.
+ */
ret = did_overwrite_ref(sctx, *parent_ino, *parent_gen, ino, gen,
dest->start, dest->end - dest->start);
if (ret < 0)
@@ -1888,6 +1969,9 @@ static int __get_cur_name_and_parent(struct send_ctx *sctx,
}
out_cache:
+ /*
+ * Store the result of the lookup in the name cache.
+ */
nce = kmalloc(sizeof(*nce) + fs_path_len(dest) + 1, GFP_NOFS);
if (!nce) {
ret = -ENOMEM;
@@ -1901,7 +1985,6 @@ out_cache:
nce->name_len = fs_path_len(dest);
nce->ret = ret;
strcpy(nce->name, dest->start);
- memset(&nce->use_list, 0, sizeof(nce->use_list));
if (ino < sctx->send_progress)
nce->need_later_update = 0;
@@ -2107,9 +2190,6 @@ static int send_subvol_begin(struct send_ctx *sctx)
read_extent_buffer(leaf, name, (unsigned long)(ref + 1), namelen);
btrfs_release_path(path);
- if (ret < 0)
- goto out;
-
if (parent_root) {
ret = begin_cmd(sctx, BTRFS_SEND_C_SNAPSHOT);
if (ret < 0)
@@ -2276,7 +2356,7 @@ verbose_printk("btrfs: send_utimes %llu\n", ino);
btrfs_inode_mtime(ii));
TLV_PUT_BTRFS_TIMESPEC(sctx, BTRFS_SEND_A_CTIME, eb,
btrfs_inode_ctime(ii));
- /* TODO otime? */
+ /* TODO Add otime support when the otime patches get into upstream */
ret = send_cmd(sctx);
@@ -2292,39 +2372,39 @@ out:
* a valid path yet because we did not process the refs yet. So, the inode
* is created as orphan.
*/
-static int send_create_inode(struct send_ctx *sctx, struct btrfs_path *path,
- struct btrfs_key *key)
+static int send_create_inode(struct send_ctx *sctx, u64 ino)
{
int ret = 0;
- struct extent_buffer *eb = path->nodes[0];
- struct btrfs_inode_item *ii;
struct fs_path *p;
- int slot = path->slots[0];
int cmd;
+ u64 gen;
u64 mode;
+ u64 rdev;
-verbose_printk("btrfs: send_create_inode %llu\n", sctx->cur_ino);
+verbose_printk("btrfs: send_create_inode %llu\n", ino);
p = fs_path_alloc(sctx);
if (!p)
return -ENOMEM;
- ii = btrfs_item_ptr(eb, slot, struct btrfs_inode_item);
- mode = btrfs_inode_mode(eb, ii);
+ ret = get_inode_info(sctx->send_root, ino, NULL, &gen, &mode, NULL,
+ NULL, &rdev);
+ if (ret < 0)
+ goto out;
- if (S_ISREG(mode))
+ if (S_ISREG(mode)) {
cmd = BTRFS_SEND_C_MKFILE;
- else if (S_ISDIR(mode))
+ } else if (S_ISDIR(mode)) {
cmd = BTRFS_SEND_C_MKDIR;
- else if (S_ISLNK(mode))
+ } else if (S_ISLNK(mode)) {
cmd = BTRFS_SEND_C_SYMLINK;
- else if (S_ISCHR(mode) || S_ISBLK(mode))
+ } else if (S_ISCHR(mode) || S_ISBLK(mode)) {
cmd = BTRFS_SEND_C_MKNOD;
- else if (S_ISFIFO(mode))
+ } else if (S_ISFIFO(mode)) {
cmd = BTRFS_SEND_C_MKFIFO;
- else if (S_ISSOCK(mode))
+ } else if (S_ISSOCK(mode)) {
cmd = BTRFS_SEND_C_MKSOCK;
- else {
+ } else {
printk(KERN_WARNING "btrfs: unexpected inode type %o",
(int)(mode & S_IFMT));
ret = -ENOTSUPP;
@@ -2335,22 +2415,22 @@ verbose_printk("btrfs: send_create_inode %llu\n", sctx->cur_ino);
if (ret < 0)
goto out;
- ret = gen_unique_name(sctx, sctx->cur_ino, sctx->cur_inode_gen, p);
+ ret = gen_unique_name(sctx, ino, gen, p);
if (ret < 0)
goto out;
TLV_PUT_PATH(sctx, BTRFS_SEND_A_PATH, p);
- TLV_PUT_U64(sctx, BTRFS_SEND_A_INO, sctx->cur_ino);
+ TLV_PUT_U64(sctx, BTRFS_SEND_A_INO, ino);
if (S_ISLNK(mode)) {
fs_path_reset(p);
- ret = read_symlink(sctx, sctx->send_root, sctx->cur_ino, p);
+ ret = read_symlink(sctx, sctx->send_root, ino, p);
if (ret < 0)
goto out;
TLV_PUT_PATH(sctx, BTRFS_SEND_A_PATH_LINK, p);
} else if (S_ISCHR(mode) || S_ISBLK(mode) ||
S_ISFIFO(mode) || S_ISSOCK(mode)) {
- TLV_PUT_U64(sctx, BTRFS_SEND_A_RDEV, btrfs_inode_rdev(eb, ii));
+ TLV_PUT_U64(sctx, BTRFS_SEND_A_RDEV, rdev);
}
ret = send_cmd(sctx);
@@ -2364,6 +2444,92 @@ out:
return ret;
}
+/*
+ * We need some special handling for inodes that get processed before the parent
+ * directory got created. See process_recorded_refs for details.
+ * This function does the check if we already created the dir out of order.
+ */
+static int did_create_dir(struct send_ctx *sctx, u64 dir)
+{
+ int ret = 0;
+ struct btrfs_path *path = NULL;
+ struct btrfs_key key;
+ struct btrfs_key found_key;
+ struct btrfs_key di_key;
+ struct extent_buffer *eb;
+ struct btrfs_dir_item *di;
+ int slot;
+
+ path = alloc_path_for_send();
+ if (!path) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ key.objectid = dir;
+ key.type = BTRFS_DIR_INDEX_KEY;
+ key.offset = 0;
+ while (1) {
+ ret = btrfs_search_slot_for_read(sctx->send_root, &key, path,
+ 1, 0);
+ if (ret < 0)
+ goto out;
+ if (!ret) {
+ eb = path->nodes[0];
+ slot = path->slots[0];
+ btrfs_item_key_to_cpu(eb, &found_key, slot);
+ }
+ if (ret || found_key.objectid != key.objectid ||
+ found_key.type != key.type) {
+ ret = 0;
+ goto out;
+ }
+
+ di = btrfs_item_ptr(eb, slot, struct btrfs_dir_item);
+ btrfs_dir_item_key_to_cpu(eb, di, &di_key);
+
+ if (di_key.objectid < sctx->send_progress) {
+ ret = 1;
+ goto out;
+ }
+
+ key.offset = found_key.offset + 1;
+ btrfs_release_path(path);
+ }
+
+out:
+ btrfs_free_path(path);
+ return ret;
+}
+
+/*
+ * Only creates the inode if it is:
+ * 1. Not a directory
+ * 2. Or a directory which was not created already due to out of order
+ * directories. See did_create_dir and process_recorded_refs for details.
+ */
+static int send_create_inode_if_needed(struct send_ctx *sctx)
+{
+ int ret;
+
+ if (S_ISDIR(sctx->cur_inode_mode)) {
+ ret = did_create_dir(sctx, sctx->cur_ino);
+ if (ret < 0)
+ goto out;
+ if (ret) {
+ ret = 0;
+ goto out;
+ }
+ }
+
+ ret = send_create_inode(sctx, sctx->cur_ino);
+ if (ret < 0)
+ goto out;
+
+out:
+ return ret;
+}
+
struct recorded_ref {
struct list_head list;
char *dir_path;
@@ -2416,13 +2582,13 @@ static int record_ref(struct list_head *head, u64 dir,
static void __free_recorded_refs(struct send_ctx *sctx, struct list_head *head)
{
struct recorded_ref *cur;
- struct recorded_ref *tmp;
- list_for_each_entry_safe(cur, tmp, head, list) {
+ while (!list_empty(head)) {
+ cur = list_entry(head->next, struct recorded_ref, list);
fs_path_free(sctx, cur->full_path);
+ list_del(&cur->list);
kfree(cur);
}
- INIT_LIST_HEAD(head);
}
static void free_recorded_refs(struct send_ctx *sctx)
@@ -2432,7 +2598,7 @@ static void free_recorded_refs(struct send_ctx *sctx)
}
/*
- * Renames/moves a file/dir to it's orphan name. Used when the first
+ * Renames/moves a file/dir to its orphan name. Used when the first
* ref of an unprocessed inode gets overwritten and for all non empty
* directories.
*/
@@ -2472,6 +2638,12 @@ static int can_rmdir(struct send_ctx *sctx, u64 dir, u64 send_progress)
struct btrfs_key loc;
struct btrfs_dir_item *di;
+ /*
+ * Don't try to rmdir the top/root subvolume dir.
+ */
+ if (dir == BTRFS_FIRST_FREE_OBJECTID)
+ return 0;
+
path = alloc_path_for_send();
if (!path)
return -ENOMEM;
@@ -2513,160 +2685,6 @@ out:
return ret;
}
-struct finish_unordered_dir_ctx {
- struct send_ctx *sctx;
- struct fs_path *cur_path;
- struct fs_path *dir_path;
- u64 dir_ino;
- int need_delete;
- int delete_pass;
-};
-
-int __finish_unordered_dir(int num, struct btrfs_key *di_key,
- const char *name, int name_len,
- const char *data, int data_len,
- u8 type, void *ctx)
-{
- int ret = 0;
- struct finish_unordered_dir_ctx *fctx = ctx;
- struct send_ctx *sctx = fctx->sctx;
- u64 di_gen;
- u64 di_mode;
- int is_orphan = 0;
-
- if (di_key->objectid >= fctx->dir_ino)
- goto out;
-
- fs_path_reset(fctx->cur_path);
-
- ret = get_inode_info(sctx->send_root, di_key->objectid,
- NULL, &di_gen, &di_mode, NULL, NULL);
- if (ret < 0)
- goto out;
-
- ret = is_first_ref(sctx, sctx->send_root, di_key->objectid,
- fctx->dir_ino, name, name_len);
- if (ret < 0)
- goto out;
- if (ret) {
- is_orphan = 1;
- ret = gen_unique_name(sctx, di_key->objectid, di_gen,
- fctx->cur_path);
- } else {
- ret = get_cur_path(sctx, di_key->objectid, di_gen,
- fctx->cur_path);
- }
- if (ret < 0)
- goto out;
-
- ret = fs_path_add(fctx->dir_path, name, name_len);
- if (ret < 0)
- goto out;
-
- if (!fctx->delete_pass) {
- if (S_ISDIR(di_mode)) {
- ret = send_rename(sctx, fctx->cur_path,
- fctx->dir_path);
- } else {
- ret = send_link(sctx, fctx->dir_path,
- fctx->cur_path);
- if (is_orphan)
- fctx->need_delete = 1;
- }
- } else if (!S_ISDIR(di_mode)) {
- ret = send_unlink(sctx, fctx->cur_path);
- } else {
- ret = 0;
- }
-
- fs_path_remove(fctx->dir_path);
-
-out:
- return ret;
-}
-
-/*
- * Go through all dir items and see if we find refs which could not be created
- * in the past because the dir did not exist at that time.
- */
-static int finish_outoforder_dir(struct send_ctx *sctx, u64 dir, u64 dir_gen)
-{
- int ret = 0;
- struct btrfs_path *path = NULL;
- struct btrfs_key key;
- struct btrfs_key found_key;
- struct extent_buffer *eb;
- struct finish_unordered_dir_ctx fctx;
- int slot;
-
- path = alloc_path_for_send();
- if (!path) {
- ret = -ENOMEM;
- goto out;
- }
-
- memset(&fctx, 0, sizeof(fctx));
- fctx.sctx = sctx;
- fctx.cur_path = fs_path_alloc(sctx);
- fctx.dir_path = fs_path_alloc(sctx);
- if (!fctx.cur_path || !fctx.dir_path) {
- ret = -ENOMEM;
- goto out;
- }
- fctx.dir_ino = dir;
-
- ret = get_cur_path(sctx, dir, dir_gen, fctx.dir_path);
- if (ret < 0)
- goto out;
-
- /*
- * We do two passes. The first links in the new refs and the second
- * deletes orphans if required. Deletion of orphans is not required for
- * directory inodes, as we always have only one ref and use rename
- * instead of link for those.
- */
-
-again:
- key.objectid = dir;
- key.type = BTRFS_DIR_ITEM_KEY;
- key.offset = 0;
- while (1) {
- ret = btrfs_search_slot_for_read(sctx->send_root, &key, path,
- 1, 0);
- if (ret < 0)
- goto out;
- eb = path->nodes[0];
- slot = path->slots[0];
- btrfs_item_key_to_cpu(eb, &found_key, slot);
-
- if (found_key.objectid != key.objectid ||
- found_key.type != key.type) {
- btrfs_release_path(path);
- break;
- }
-
- ret = iterate_dir_item(sctx, sctx->send_root, path,
- &found_key, __finish_unordered_dir,
- &fctx);
- if (ret < 0)
- goto out;
-
- key.offset = found_key.offset + 1;
- btrfs_release_path(path);
- }
-
- if (!fctx.delete_pass && fctx.need_delete) {
- fctx.delete_pass = 1;
- goto again;
- }
-
-out:
- btrfs_free_path(path);
- fs_path_free(sctx, fctx.cur_path);
- fs_path_free(sctx, fctx.dir_path);
- return ret;
-}
-
/*
* This does all the move/link/unlink/rmdir magic.
*/
@@ -2674,6 +2692,7 @@ static int process_recorded_refs(struct send_ctx *sctx)
{
int ret = 0;
struct recorded_ref *cur;
+ struct recorded_ref *cur2;
struct ulist *check_dirs = NULL;
struct ulist_iterator uit;
struct ulist_node *un;
@@ -2685,6 +2704,12 @@ static int process_recorded_refs(struct send_ctx *sctx)
verbose_printk("btrfs: process_recorded_refs %llu\n", sctx->cur_ino);
+ /*
+ * This should never happen as the root dir always has the same ref
+ * which is always '..'
+ */
+ BUG_ON(sctx->cur_ino <= BTRFS_FIRST_FREE_OBJECTID);
+
valid_path = fs_path_alloc(sctx);
if (!valid_path) {
ret = -ENOMEM;
@@ -2731,6 +2756,46 @@ verbose_printk("btrfs: process_recorded_refs %llu\n", sctx->cur_ino);
list_for_each_entry(cur, &sctx->new_refs, list) {
/*
+ * We may have refs where the parent directory does not exist
+ * yet. This happens if the parent directories inum is higher
+ * the the current inum. To handle this case, we create the
+ * parent directory out of order. But we need to check if this
+ * did already happen before due to other refs in the same dir.
+ */
+ ret = get_cur_inode_state(sctx, cur->dir, cur->dir_gen);
+ if (ret < 0)
+ goto out;
+ if (ret == inode_state_will_create) {
+ ret = 0;
+ /*
+ * First check if any of the current inodes refs did
+ * already create the dir.
+ */
+ list_for_each_entry(cur2, &sctx->new_refs, list) {
+ if (cur == cur2)
+ break;
+ if (cur2->dir == cur->dir) {
+ ret = 1;
+ break;
+ }
+ }
+
+ /*
+ * If that did not happen, check if a previous inode
+ * did already create the dir.
+ */
+ if (!ret)
+ ret = did_create_dir(sctx, cur->dir);
+ if (ret < 0)
+ goto out;
+ if (!ret) {
+ ret = send_create_inode(sctx, cur->dir);
+ if (ret < 0)
+ goto out;
+ }
+ }
+
+ /*
* Check if this new ref would overwrite the first ref of
* another unprocessed inode. If yes, orphanize the
* overwritten inode. If we find an overwritten ref that is
@@ -2764,7 +2829,7 @@ verbose_printk("btrfs: process_recorded_refs %llu\n", sctx->cur_ino);
* inode, move it and update valid_path. If not, link or move
* it depending on the inode mode.
*/
- if (is_orphan && !sctx->cur_inode_first_ref_orphan) {
+ if (is_orphan) {
ret = send_rename(sctx, valid_path, cur->full_path);
if (ret < 0)
goto out;
@@ -2827,6 +2892,17 @@ verbose_printk("btrfs: process_recorded_refs %llu\n", sctx->cur_ino);
if (ret < 0)
goto out;
}
+ } else if (S_ISDIR(sctx->cur_inode_mode) &&
+ !list_empty(&sctx->deleted_refs)) {
+ /*
+ * We have a moved dir. Add the old parent to check_dirs
+ */
+ cur = list_entry(sctx->deleted_refs.next, struct recorded_ref,
+ list);
+ ret = ulist_add(check_dirs, cur->dir, cur->dir_gen,
+ GFP_NOFS);
+ if (ret < 0)
+ goto out;
} else if (!S_ISDIR(sctx->cur_inode_mode)) {
/*
* We have a non dir inode. Go through all deleted refs and
@@ -2840,35 +2916,9 @@ verbose_printk("btrfs: process_recorded_refs %llu\n", sctx->cur_ino);
if (ret < 0)
goto out;
if (!ret) {
- /*
- * In case the inode was moved to a directory
- * that was not created yet (see
- * __record_new_ref), we can not unlink the ref
- * as it will be needed later when the parent
- * directory is created, so that we can move in
- * the inode to the new dir.
- */
- if (!is_orphan &&
- sctx->cur_inode_first_ref_orphan) {
- ret = orphanize_inode(sctx,
- sctx->cur_ino,
- sctx->cur_inode_gen,
- cur->full_path);
- if (ret < 0)
- goto out;
- ret = gen_unique_name(sctx,
- sctx->cur_ino,
- sctx->cur_inode_gen,
- valid_path);
- if (ret < 0)
- goto out;
- is_orphan = 1;
-
- } else {
- ret = send_unlink(sctx, cur->full_path);
- if (ret < 0)
- goto out;
- }
+ ret = send_unlink(sctx, cur->full_path);
+ if (ret < 0)
+ goto out;
}
ret = ulist_add(check_dirs, cur->dir, cur->dir_gen,
GFP_NOFS);
@@ -2880,12 +2930,11 @@ verbose_printk("btrfs: process_recorded_refs %llu\n", sctx->cur_ino);
* If the inode is still orphan, unlink the orphan. This may
* happen when a previous inode did overwrite the first ref
* of this inode and no new refs were added for the current
- * inode.
- * We can however not delete the orphan in case the inode relies
- * in a directory that was not created yet (see
- * __record_new_ref)
+ * inode. Unlinking does not mean that the inode is deleted in
+ * all cases. There may still be links to this inode in other
+ * places.
*/
- if (is_orphan && !sctx->cur_inode_first_ref_orphan) {
+ if (is_orphan) {
ret = send_unlink(sctx, valid_path);
if (ret < 0)
goto out;
@@ -2900,6 +2949,11 @@ verbose_printk("btrfs: process_recorded_refs %llu\n", sctx->cur_ino);
*/
ULIST_ITER_INIT(&uit);
while ((un = ulist_next(check_dirs, &uit))) {
+ /*
+ * In case we had refs into dirs that were not processed yet,
+ * we don't need to do the utime and rmdir logic for these dirs.
+ * The dir will be processed later.
+ */
if (un->val > sctx->cur_ino)
continue;
@@ -2929,25 +2983,6 @@ verbose_printk("btrfs: process_recorded_refs %llu\n", sctx->cur_ino);
}
}
- /*
- * Current inode is now at it's new position, so we must increase
- * send_progress
- */
- sctx->send_progress = sctx->cur_ino + 1;
-
- /*
- * We may have a directory here that has pending refs which could not
- * be created before (because the dir did not exist before, see
- * __record_new_ref). finish_outoforder_dir will link/move the pending
- * refs.
- */
- if (S_ISDIR(sctx->cur_inode_mode) && sctx->cur_inode_new) {
- ret = finish_outoforder_dir(sctx, sctx->cur_ino,
- sctx->cur_inode_gen);
- if (ret < 0)
- goto out;
- }
-
ret = 0;
out:
@@ -2971,34 +3006,9 @@ static int __record_new_ref(int num, u64 dir, int index,
return -ENOMEM;
ret = get_inode_info(sctx->send_root, dir, NULL, &gen, NULL, NULL,
- NULL);
- if (ret < 0)
- goto out;
-
- /*
- * The parent may be non-existent at this point in time. This happens
- * if the ino of the parent dir is higher then the current ino. In this
- * case, we can not process this ref until the parent dir is finally
- * created. If we reach the parent dir later, process_recorded_refs
- * will go through all dir items and process the refs that could not be
- * processed before. In case this is the first ref, we set
- * cur_inode_first_ref_orphan to 1 to inform process_recorded_refs to
- * keep an orphan of the inode so that it later can be used for
- * link/move
- */
- ret = is_inode_existent(sctx, dir, gen);
+ NULL, NULL);
if (ret < 0)
goto out;
- if (!ret) {
- ret = is_first_ref(sctx, sctx->send_root, sctx->cur_ino, dir,
- name->start, fs_path_len(name));
- if (ret < 0)
- goto out;
- if (ret)
- sctx->cur_inode_first_ref_orphan = 1;
- ret = 0;
- goto out;
- }
ret = get_cur_path(sctx, dir, gen, p);
if (ret < 0)
@@ -3029,7 +3039,7 @@ static int __record_deleted_ref(int num, u64 dir, int index,
return -ENOMEM;
ret = get_inode_info(sctx->parent_root, dir, NULL, &gen, NULL, NULL,
- NULL);
+ NULL, NULL);
if (ret < 0)
goto out;
@@ -3206,33 +3216,28 @@ static int process_all_refs(struct send_ctx *sctx,
key.offset = 0;
while (1) {
ret = btrfs_search_slot_for_read(root, &key, path, 1, 0);
- if (ret < 0) {
- btrfs_release_path(path);
+ if (ret < 0)
goto out;
- }
- if (ret) {
- btrfs_release_path(path);
+ if (ret)
break;
- }
eb = path->nodes[0];
slot = path->slots[0];
btrfs_item_key_to_cpu(eb, &found_key, slot);
if (found_key.objectid != key.objectid ||
- found_key.type != key.type) {
- btrfs_release_path(path);
+ found_key.type != key.type)
break;
- }
- ret = iterate_inode_ref(sctx, sctx->parent_root, path,
- &found_key, 0, cb, sctx);
+ ret = iterate_inode_ref(sctx, root, path, &found_key, 0, cb,
+ sctx);
btrfs_release_path(path);
if (ret < 0)
goto out;
key.offset = found_key.offset + 1;
}
+ btrfs_release_path(path);
ret = process_recorded_refs(sctx);
@@ -3555,7 +3560,7 @@ static int send_write(struct send_ctx *sctx, u64 offset, u32 len)
int ret = 0;
struct fs_path *p;
loff_t pos = offset;
- int readed = 0;
+ int num_read = 0;
mm_segment_t old_fs;
p = fs_path_alloc(sctx);
@@ -3580,8 +3585,8 @@ verbose_printk("btrfs: send_write offset=%llu, len=%d\n", offset, len);
ret = vfs_read(sctx->cur_inode_filp, sctx->read_buf, len, &pos);
if (ret < 0)
goto out;
- readed = ret;
- if (!readed)
+ num_read = ret;
+ if (!num_read)
goto out;
ret = begin_cmd(sctx, BTRFS_SEND_C_WRITE);
@@ -3594,7 +3599,7 @@ verbose_printk("btrfs: send_write offset=%llu, len=%d\n", offset, len);
TLV_PUT_PATH(sctx, BTRFS_SEND_A_PATH, p);
TLV_PUT_U64(sctx, BTRFS_SEND_A_FILE_OFFSET, offset);
- TLV_PUT(sctx, BTRFS_SEND_A_DATA, sctx->read_buf, readed);
+ TLV_PUT(sctx, BTRFS_SEND_A_DATA, sctx->read_buf, num_read);
ret = send_cmd(sctx);
@@ -3604,7 +3609,7 @@ out:
set_fs(old_fs);
if (ret < 0)
return ret;
- return readed;
+ return num_read;
}
/*
@@ -3615,7 +3620,6 @@ static int send_clone(struct send_ctx *sctx,
struct clone_root *clone_root)
{
int ret = 0;
- struct btrfs_root *clone_root2 = clone_root->root;
struct fs_path *p;
u64 gen;
@@ -3640,22 +3644,23 @@ verbose_printk("btrfs: send_clone offset=%llu, len=%d, clone_root=%llu, "
TLV_PUT_U64(sctx, BTRFS_SEND_A_CLONE_LEN, len);
TLV_PUT_PATH(sctx, BTRFS_SEND_A_PATH, p);
- if (clone_root2 == sctx->send_root) {
+ if (clone_root->root == sctx->send_root) {
ret = get_inode_info(sctx->send_root, clone_root->ino, NULL,
- &gen, NULL, NULL, NULL);
+ &gen, NULL, NULL, NULL, NULL);
if (ret < 0)
goto out;
ret = get_cur_path(sctx, clone_root->ino, gen, p);
} else {
- ret = get_inode_path(sctx, clone_root2, clone_root->ino, p);
+ ret = get_inode_path(sctx, clone_root->root,
+ clone_root->ino, p);
}
if (ret < 0)
goto out;
TLV_PUT_UUID(sctx, BTRFS_SEND_A_CLONE_UUID,
- clone_root2->root_item.uuid);
+ clone_root->root->root_item.uuid);
TLV_PUT_U64(sctx, BTRFS_SEND_A_CLONE_CTRANSID,
- clone_root2->root_item.ctransid);
+ clone_root->root->root_item.ctransid);
TLV_PUT_PATH(sctx, BTRFS_SEND_A_CLONE_PATH, p);
TLV_PUT_U64(sctx, BTRFS_SEND_A_CLONE_OFFSET,
clone_root->offset);
@@ -3684,10 +3689,17 @@ static int send_write_or_clone(struct send_ctx *sctx,
ei = btrfs_item_ptr(path->nodes[0], path->slots[0],
struct btrfs_file_extent_item);
type = btrfs_file_extent_type(path->nodes[0], ei);
- if (type == BTRFS_FILE_EXTENT_INLINE)
+ if (type == BTRFS_FILE_EXTENT_INLINE) {
len = btrfs_file_extent_inline_len(path->nodes[0], ei);
- else
+ /*
+ * it is possible the inline item won't cover the whole page,
+ * but there may be items after this page. Make
+ * sure to send the whole thing
+ */
+ len = PAGE_CACHE_ALIGN(len);
+ } else {
len = btrfs_file_extent_num_bytes(path->nodes[0], ei);
+ }
if (offset + len > sctx->cur_inode_size)
len = sctx->cur_inode_size - offset;
@@ -3735,6 +3747,8 @@ static int is_extent_unchanged(struct send_ctx *sctx,
u64 left_offset_fixed;
u64 left_len;
u64 right_len;
+ u64 left_gen;
+ u64 right_gen;
u8 left_type;
u8 right_type;
@@ -3744,17 +3758,17 @@ static int is_extent_unchanged(struct send_ctx *sctx,
eb = left_path->nodes[0];
slot = left_path->slots[0];
-
ei = btrfs_item_ptr(eb, slot, struct btrfs_file_extent_item);
left_type = btrfs_file_extent_type(eb, ei);
- left_disknr = btrfs_file_extent_disk_bytenr(eb, ei);
- left_len = btrfs_file_extent_num_bytes(eb, ei);
- left_offset = btrfs_file_extent_offset(eb, ei);
if (left_type != BTRFS_FILE_EXTENT_REG) {
ret = 0;
goto out;
}
+ left_disknr = btrfs_file_extent_disk_bytenr(eb, ei);
+ left_len = btrfs_file_extent_num_bytes(eb, ei);
+ left_offset = btrfs_file_extent_offset(eb, ei);
+ left_gen = btrfs_file_extent_generation(eb, ei);
/*
* Following comments will refer to these graphics. L is the left
@@ -3810,6 +3824,7 @@ static int is_extent_unchanged(struct send_ctx *sctx,
right_disknr = btrfs_file_extent_disk_bytenr(eb, ei);
right_len = btrfs_file_extent_num_bytes(eb, ei);
right_offset = btrfs_file_extent_offset(eb, ei);
+ right_gen = btrfs_file_extent_generation(eb, ei);
if (right_type != BTRFS_FILE_EXTENT_REG) {
ret = 0;
@@ -3820,7 +3835,7 @@ static int is_extent_unchanged(struct send_ctx *sctx,
* Are we at extent 8? If yes, we know the extent is changed.
* This may only happen on the first iteration.
*/
- if (found_key.offset + right_len < ekey->offset) {
+ if (found_key.offset + right_len <= ekey->offset) {
ret = 0;
goto out;
}
@@ -3837,8 +3852,9 @@ static int is_extent_unchanged(struct send_ctx *sctx,
/*
* Check if we have the same extent.
*/
- if (left_disknr + left_offset_fixed !=
- right_disknr + right_offset) {
+ if (left_disknr != right_disknr ||
+ left_offset_fixed != right_offset ||
+ left_gen != right_gen) {
ret = 0;
goto out;
}
@@ -3977,6 +3993,15 @@ static int process_recorded_refs_if_needed(struct send_ctx *sctx, int at_end)
goto out;
ret = process_recorded_refs(sctx);
+ if (ret < 0)
+ goto out;
+
+ /*
+ * We have processed the refs and thus need to advance send_progress.
+ * Now, calls to get_cur_xxx will take the updated refs of the current
+ * inode into account.
+ */
+ sctx->send_progress = sctx->cur_ino + 1;
out:
return ret;
@@ -4004,7 +4029,7 @@ static int finish_inode_if_needed(struct send_ctx *sctx, int at_end)
goto out;
ret = get_inode_info(sctx->send_root, sctx->cur_ino, NULL, NULL,
- &left_mode, &left_uid, &left_gid);
+ &left_mode, &left_uid, &left_gid, NULL);
if (ret < 0)
goto out;
@@ -4015,7 +4040,7 @@ static int finish_inode_if_needed(struct send_ctx *sctx, int at_end)
} else {
ret = get_inode_info(sctx->parent_root, sctx->cur_ino,
NULL, NULL, &right_mode, &right_uid,
- &right_gid);
+ &right_gid, NULL);
if (ret < 0)
goto out;
@@ -4074,7 +4099,12 @@ static int changed_inode(struct send_ctx *sctx,
sctx->cur_ino = key->objectid;
sctx->cur_inode_new_gen = 0;
- sctx->cur_inode_first_ref_orphan = 0;
+
+ /*
+ * Set send_progress to current inode. This will tell all get_cur_xxx
+ * functions that the current inode's refs are not updated yet. Later,
+ * when process_recorded_refs is finished, it is set to cur_ino + 1.
+ */
sctx->send_progress = sctx->cur_ino;
if (result == BTRFS_COMPARE_TREE_NEW ||
@@ -4098,7 +4128,14 @@ static int changed_inode(struct send_ctx *sctx,
right_gen = btrfs_inode_generation(sctx->right_path->nodes[0],
right_ii);
- if (left_gen != right_gen)
+
+ /*
+ * The cur_ino = root dir case is special here. We can't treat
+ * the inode as deleted+reused because it would generate a
+ * stream that tries to delete/mkdir the root dir.
+ */
+ if (left_gen != right_gen &&
+ sctx->cur_ino != BTRFS_FIRST_FREE_OBJECTID)
sctx->cur_inode_new_gen = 1;
}
@@ -4111,8 +4148,7 @@ static int changed_inode(struct send_ctx *sctx,
sctx->cur_inode_mode = btrfs_inode_mode(
sctx->left_path->nodes[0], left_ii);
if (sctx->cur_ino != BTRFS_FIRST_FREE_OBJECTID)
- ret = send_create_inode(sctx, sctx->left_path,
- sctx->cmp_key);
+ ret = send_create_inode_if_needed(sctx);
} else if (result == BTRFS_COMPARE_TREE_DELETED) {
sctx->cur_inode_gen = right_gen;
sctx->cur_inode_new = 0;
@@ -4122,7 +4158,17 @@ static int changed_inode(struct send_ctx *sctx,
sctx->cur_inode_mode = btrfs_inode_mode(
sctx->right_path->nodes[0], right_ii);
} else if (result == BTRFS_COMPARE_TREE_CHANGED) {
+ /*
+ * We need to do some special handling in case the inode was
+ * reported as changed with a changed generation number. This
+ * means that the original inode was deleted and new inode
+ * reused the same inum. So we have to treat the old inode as
+ * deleted and the new one as new.
+ */
if (sctx->cur_inode_new_gen) {
+ /*
+ * First, process the inode as if it was deleted.
+ */
sctx->cur_inode_gen = right_gen;
sctx->cur_inode_new = 0;
sctx->cur_inode_deleted = 1;
@@ -4135,6 +4181,9 @@ static int changed_inode(struct send_ctx *sctx,
if (ret < 0)
goto out;
+ /*
+ * Now process the inode as if it was new.
+ */
sctx->cur_inode_gen = left_gen;
sctx->cur_inode_new = 1;
sctx->cur_inode_deleted = 0;
@@ -4142,14 +4191,23 @@ static int changed_inode(struct send_ctx *sctx,
sctx->left_path->nodes[0], left_ii);
sctx->cur_inode_mode = btrfs_inode_mode(
sctx->left_path->nodes[0], left_ii);
- ret = send_create_inode(sctx, sctx->left_path,
- sctx->cmp_key);
+ ret = send_create_inode_if_needed(sctx);
if (ret < 0)
goto out;
ret = process_all_refs(sctx, BTRFS_COMPARE_TREE_NEW);
if (ret < 0)
goto out;
+ /*
+ * Advance send_progress now as we did not get into
+ * process_recorded_refs_if_needed in the new_gen case.
+ */
+ sctx->send_progress = sctx->cur_ino + 1;
+
+ /*
+ * Now process all extents and xattrs of the inode as if
+ * they were all new.
+ */
ret = process_all_extents(sctx);
if (ret < 0)
goto out;
@@ -4172,6 +4230,16 @@ out:
return ret;
}
+/*
+ * We have to process new refs before deleted refs, but compare_trees gives us
+ * the new and deleted refs mixed. To fix this, we record the new/deleted refs
+ * first and later process them in process_recorded_refs.
+ * For the cur_inode_new_gen case, we skip recording completely because
+ * changed_inode did already initiate processing of refs. The reason for this is
+ * that in this case, compare_tree actually compares the refs of 2 different
+ * inodes. To fix this, process_all_refs is used in changed_inode to handle all
+ * refs of the right tree as deleted and all refs of the left tree as new.
+ */
static int changed_ref(struct send_ctx *sctx,
enum btrfs_compare_tree_result result)
{
@@ -4192,6 +4260,11 @@ static int changed_ref(struct send_ctx *sctx,
return ret;
}
+/*
+ * Process new/deleted/changed xattrs. We skip processing in the
+ * cur_inode_new_gen case because changed_inode did already initiate processing
+ * of xattrs. The reason is the same as in changed_ref
+ */
static int changed_xattr(struct send_ctx *sctx,
enum btrfs_compare_tree_result result)
{
@@ -4211,6 +4284,11 @@ static int changed_xattr(struct send_ctx *sctx,
return ret;
}
+/*
+ * Process new/deleted/changed extents. We skip processing in the
+ * cur_inode_new_gen case because changed_inode did already initiate processing
+ * of extents. The reason is the same as in changed_ref
+ */
static int changed_extent(struct send_ctx *sctx,
enum btrfs_compare_tree_result result)
{
@@ -4227,7 +4305,10 @@ static int changed_extent(struct send_ctx *sctx,
return ret;
}
-
+/*
+ * Updates compare related fields in sctx and simply forwards to the actual
+ * changed_xxx functions.
+ */
static int changed_cb(struct btrfs_root *left_root,
struct btrfs_root *right_root,
struct btrfs_path *left_path,
@@ -4247,6 +4328,11 @@ static int changed_cb(struct btrfs_root *left_root,
if (ret < 0)
goto out;
+ /* Ignore non-FS objects */
+ if (key->objectid == BTRFS_FREE_INO_OBJECTID ||
+ key->objectid == BTRFS_FREE_SPACE_OBJECTID)
+ goto out;
+
if (key->type == BTRFS_INODE_ITEM_KEY)
ret = changed_inode(sctx, result);
else if (key->type == BTRFS_INODE_REF_KEY)
@@ -4299,7 +4385,8 @@ join_trans:
}
/*
- * Make sure the tree has not changed
+ * Make sure the tree has not changed after re-joining. We detect this
+ * by comparing start_ctransid and ctransid. They should always match.
*/
spin_lock(&send_root->root_times_lock);
ctransid = btrfs_root_ctransid(&send_root->root_item);
diff --git a/fs/btrfs/send.h b/fs/btrfs/send.h
index 9934e94..1bf4f32 100644
--- a/fs/btrfs/send.h
+++ b/fs/btrfs/send.h
@@ -130,4 +130,5 @@ enum {
#ifdef __KERNEL__
long btrfs_ioctl_send(struct file *mnt_file, void __user *arg);
+int write_buf(struct file *filp, const void *buf, u32 len, loff_t *off);
#endif
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index 83d6f9f..915ac14 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -243,12 +243,18 @@ void __btrfs_abort_transaction(struct btrfs_trans_handle *trans,
struct btrfs_root *root, const char *function,
unsigned int line, int errno)
{
- WARN_ONCE(1, KERN_DEBUG "btrfs: Transaction aborted");
+ WARN_ONCE(1, KERN_DEBUG "btrfs: Transaction aborted\n");
trans->aborted = errno;
/* Nothing used. The other threads that have joined this
* transaction may be able to continue. */
if (!trans->blocks_used) {
- btrfs_printk(root->fs_info, "Aborting unused transaction.\n");
+ char nbuf[16];
+ const char *errstr;
+
+ errstr = btrfs_decode_error(root->fs_info, errno, nbuf);
+ btrfs_printk(root->fs_info,
+ "%s:%d: Aborting unused transaction(%s).\n",
+ function, line, errstr);
return;
}
trans->transaction->aborted = errno;
@@ -407,7 +413,15 @@ int btrfs_parse_options(struct btrfs_root *root, char *options)
btrfs_set_opt(info->mount_opt, NODATASUM);
break;
case Opt_nodatacow:
- printk(KERN_INFO "btrfs: setting nodatacow\n");
+ if (!btrfs_test_opt(root, COMPRESS) ||
+ !btrfs_test_opt(root, FORCE_COMPRESS)) {
+ printk(KERN_INFO "btrfs: setting nodatacow, compression disabled\n");
+ } else {
+ printk(KERN_INFO "btrfs: setting nodatacow\n");
+ }
+ info->compress_type = BTRFS_COMPRESS_NONE;
+ btrfs_clear_opt(info->mount_opt, COMPRESS);
+ btrfs_clear_opt(info->mount_opt, FORCE_COMPRESS);
btrfs_set_opt(info->mount_opt, NODATACOW);
btrfs_set_opt(info->mount_opt, NODATASUM);
break;
@@ -422,10 +436,14 @@ int btrfs_parse_options(struct btrfs_root *root, char *options)
compress_type = "zlib";
info->compress_type = BTRFS_COMPRESS_ZLIB;
btrfs_set_opt(info->mount_opt, COMPRESS);
+ btrfs_clear_opt(info->mount_opt, NODATACOW);
+ btrfs_clear_opt(info->mount_opt, NODATASUM);
} else if (strcmp(args[0].from, "lzo") == 0) {
compress_type = "lzo";
info->compress_type = BTRFS_COMPRESS_LZO;
btrfs_set_opt(info->mount_opt, COMPRESS);
+ btrfs_clear_opt(info->mount_opt, NODATACOW);
+ btrfs_clear_opt(info->mount_opt, NODATASUM);
btrfs_set_fs_incompat(info, COMPRESS_LZO);
} else if (strncmp(args[0].from, "no", 2) == 0) {
compress_type = "no";
@@ -543,11 +561,11 @@ int btrfs_parse_options(struct btrfs_root *root, char *options)
btrfs_set_opt(info->mount_opt, ENOSPC_DEBUG);
break;
case Opt_defrag:
- printk(KERN_INFO "btrfs: enabling auto defrag");
+ printk(KERN_INFO "btrfs: enabling auto defrag\n");
btrfs_set_opt(info->mount_opt, AUTO_DEFRAG);
break;
case Opt_recovery:
- printk(KERN_INFO "btrfs: enabling auto recovery");
+ printk(KERN_INFO "btrfs: enabling auto recovery\n");
btrfs_set_opt(info->mount_opt, RECOVERY);
break;
case Opt_skip_balance:
@@ -846,18 +864,15 @@ int btrfs_sync_fs(struct super_block *sb, int wait)
return 0;
}
- btrfs_wait_ordered_extents(root, 0, 0);
-
- spin_lock(&fs_info->trans_lock);
- if (!fs_info->running_transaction) {
- spin_unlock(&fs_info->trans_lock);
- return 0;
- }
- spin_unlock(&fs_info->trans_lock);
+ btrfs_wait_ordered_extents(root, 0);
- trans = btrfs_join_transaction(root);
- if (IS_ERR(trans))
+ trans = btrfs_attach_transaction(root);
+ if (IS_ERR(trans)) {
+ /* no transaction, don't bother */
+ if (PTR_ERR(trans) == -ENOENT)
+ return 0;
return PTR_ERR(trans);
+ }
return btrfs_commit_transaction(trans, root);
}
@@ -1508,17 +1523,21 @@ static long btrfs_control_ioctl(struct file *file, unsigned int cmd,
static int btrfs_freeze(struct super_block *sb)
{
- struct btrfs_fs_info *fs_info = btrfs_sb(sb);
- mutex_lock(&fs_info->transaction_kthread_mutex);
- mutex_lock(&fs_info->cleaner_mutex);
- return 0;
+ struct btrfs_trans_handle *trans;
+ struct btrfs_root *root = btrfs_sb(sb)->tree_root;
+
+ trans = btrfs_attach_transaction(root);
+ if (IS_ERR(trans)) {
+ /* no transaction, don't bother */
+ if (PTR_ERR(trans) == -ENOENT)
+ return 0;
+ return PTR_ERR(trans);
+ }
+ return btrfs_commit_transaction(trans, root);
}
static int btrfs_unfreeze(struct super_block *sb)
{
- struct btrfs_fs_info *fs_info = btrfs_sb(sb);
- mutex_unlock(&fs_info->cleaner_mutex);
- mutex_unlock(&fs_info->transaction_kthread_mutex);
return 0;
}
@@ -1595,7 +1614,7 @@ static int btrfs_interface_init(void)
static void btrfs_interface_exit(void)
{
if (misc_deregister(&btrfs_misc) < 0)
- printk(KERN_INFO "misc_deregister failed for control device");
+ printk(KERN_INFO "btrfs: misc_deregister failed for control device\n");
}
static int __init init_btrfs_fs(void)
@@ -1620,10 +1639,14 @@ static int __init init_btrfs_fs(void)
if (err)
goto free_extent_io;
- err = btrfs_delayed_inode_init();
+ err = ordered_data_init();
if (err)
goto free_extent_map;
+ err = btrfs_delayed_inode_init();
+ if (err)
+ goto free_ordered_data;
+
err = btrfs_interface_init();
if (err)
goto free_delayed_inode;
@@ -1641,6 +1664,8 @@ unregister_ioctl:
btrfs_interface_exit();
free_delayed_inode:
btrfs_delayed_inode_exit();
+free_ordered_data:
+ ordered_data_exit();
free_extent_map:
extent_map_exit();
free_extent_io:
@@ -1657,6 +1682,7 @@ static void __exit exit_btrfs_fs(void)
{
btrfs_destroy_cachep();
btrfs_delayed_inode_exit();
+ ordered_data_exit();
extent_map_exit();
extent_io_exit();
btrfs_interface_exit();
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c
index 27c2600..77db875 100644
--- a/fs/btrfs/transaction.c
+++ b/fs/btrfs/transaction.c
@@ -53,7 +53,7 @@ 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, int nofail)
+static noinline int join_transaction(struct btrfs_root *root, int type)
{
struct btrfs_transaction *cur_trans;
struct btrfs_fs_info *fs_info = root->fs_info;
@@ -67,7 +67,13 @@ loop:
}
if (fs_info->trans_no_join) {
- if (!nofail) {
+ /*
+ * If we are JOIN_NOLOCK we're already committing a current
+ * transaction, we just need a handle to deal with something
+ * when committing the transaction, such as inode cache and
+ * space cache. It is a special case.
+ */
+ if (type != TRANS_JOIN_NOLOCK) {
spin_unlock(&fs_info->trans_lock);
return -EBUSY;
}
@@ -87,6 +93,13 @@ loop:
}
spin_unlock(&fs_info->trans_lock);
+ /*
+ * If we are ATTACH, we just want to catch the current transaction,
+ * and commit it. If there is no transaction, just return ENOENT.
+ */
+ if (type == TRANS_ATTACH)
+ return -ENOENT;
+
cur_trans = kmem_cache_alloc(btrfs_transaction_cachep, GFP_NOFS);
if (!cur_trans)
return -ENOMEM;
@@ -267,13 +280,6 @@ static void wait_current_trans(struct btrfs_root *root)
}
}
-enum btrfs_trans_type {
- TRANS_START,
- TRANS_JOIN,
- TRANS_USERSPACE,
- TRANS_JOIN_NOLOCK,
-};
-
static int may_wait_transaction(struct btrfs_root *root, int type)
{
if (root->fs_info->log_root_recovering)
@@ -290,7 +296,8 @@ static int may_wait_transaction(struct btrfs_root *root, int type)
}
static struct btrfs_trans_handle *start_transaction(struct btrfs_root *root,
- u64 num_items, int type)
+ u64 num_items, int type,
+ int noflush)
{
struct btrfs_trans_handle *h;
struct btrfs_transaction *cur_trans;
@@ -324,9 +331,14 @@ static struct btrfs_trans_handle *start_transaction(struct btrfs_root *root,
}
num_bytes = btrfs_calc_trans_metadata_size(root, num_items);
- ret = btrfs_block_rsv_add(root,
- &root->fs_info->trans_block_rsv,
- num_bytes);
+ if (noflush)
+ ret = btrfs_block_rsv_add_noflush(root,
+ &root->fs_info->trans_block_rsv,
+ num_bytes);
+ else
+ ret = btrfs_block_rsv_add(root,
+ &root->fs_info->trans_block_rsv,
+ num_bytes);
if (ret)
return ERR_PTR(ret);
}
@@ -335,19 +347,34 @@ again:
if (!h)
return ERR_PTR(-ENOMEM);
- sb_start_intwrite(root->fs_info->sb);
+ /*
+ * If we are JOIN_NOLOCK we're already committing a transaction and
+ * waiting on this guy, so we don't need to do the sb_start_intwrite
+ * because we're already holding a ref. We need this because we could
+ * have raced in and did an fsync() on a file which can kick a commit
+ * and then we deadlock with somebody doing a freeze.
+ *
+ * If we are ATTACH, it means we just want to catch the current
+ * transaction and commit it, so we needn't do sb_start_intwrite().
+ */
+ if (type < TRANS_JOIN_NOLOCK)
+ sb_start_intwrite(root->fs_info->sb);
if (may_wait_transaction(root, type))
wait_current_trans(root);
do {
- ret = join_transaction(root, type == TRANS_JOIN_NOLOCK);
+ ret = join_transaction(root, type);
if (ret == -EBUSY)
wait_current_trans(root);
} while (ret == -EBUSY);
if (ret < 0) {
- sb_end_intwrite(root->fs_info->sb);
+ /* We must get the transaction if we are JOIN_NOLOCK. */
+ BUG_ON(type == TRANS_JOIN_NOLOCK);
+
+ if (type < TRANS_JOIN_NOLOCK)
+ sb_end_intwrite(root->fs_info->sb);
kmem_cache_free(btrfs_trans_handle_cachep, h);
return ERR_PTR(ret);
}
@@ -367,7 +394,9 @@ again:
h->aborted = 0;
h->qgroup_reserved = qgroup_reserved;
h->delayed_ref_elem.seq = 0;
+ h->type = type;
INIT_LIST_HEAD(&h->qgroup_ref_list);
+ INIT_LIST_HEAD(&h->new_bgs);
smp_mb();
if (cur_trans->blocked && may_wait_transaction(root, type)) {
@@ -393,21 +422,33 @@ got_it:
struct btrfs_trans_handle *btrfs_start_transaction(struct btrfs_root *root,
int num_items)
{
- return start_transaction(root, num_items, TRANS_START);
+ return start_transaction(root, num_items, TRANS_START, 0);
+}
+
+struct btrfs_trans_handle *btrfs_start_transaction_noflush(
+ struct btrfs_root *root, int num_items)
+{
+ return start_transaction(root, num_items, TRANS_START, 1);
}
+
struct btrfs_trans_handle *btrfs_join_transaction(struct btrfs_root *root)
{
- return start_transaction(root, 0, TRANS_JOIN);
+ return start_transaction(root, 0, TRANS_JOIN, 0);
}
struct btrfs_trans_handle *btrfs_join_transaction_nolock(struct btrfs_root *root)
{
- return start_transaction(root, 0, TRANS_JOIN_NOLOCK);
+ return start_transaction(root, 0, TRANS_JOIN_NOLOCK, 0);
}
struct btrfs_trans_handle *btrfs_start_ioctl_transaction(struct btrfs_root *root)
{
- return start_transaction(root, 0, TRANS_USERSPACE);
+ return start_transaction(root, 0, TRANS_USERSPACE, 0);
+}
+
+struct btrfs_trans_handle *btrfs_attach_transaction(struct btrfs_root *root)
+{
+ return start_transaction(root, 0, TRANS_ATTACH, 0);
}
/* wait for a transaction commit to be fully complete */
@@ -506,11 +547,12 @@ int btrfs_should_end_transaction(struct btrfs_trans_handle *trans,
}
static int __btrfs_end_transaction(struct btrfs_trans_handle *trans,
- struct btrfs_root *root, int throttle, int lock)
+ struct btrfs_root *root, int throttle)
{
struct btrfs_transaction *cur_trans = trans->transaction;
struct btrfs_fs_info *info = root->fs_info;
int count = 0;
+ int lock = (trans->type != TRANS_JOIN_NOLOCK);
int err = 0;
if (--trans->use_count) {
@@ -536,6 +578,9 @@ static int __btrfs_end_transaction(struct btrfs_trans_handle *trans,
trans->qgroup_reserved = 0;
}
+ if (!list_empty(&trans->new_bgs))
+ btrfs_create_pending_block_groups(trans, root);
+
while (count < 2) {
unsigned long cur = trans->delayed_ref_updates;
trans->delayed_ref_updates = 0;
@@ -551,7 +596,8 @@ static int __btrfs_end_transaction(struct btrfs_trans_handle *trans,
btrfs_trans_release_metadata(trans, root);
trans->block_rsv = NULL;
- sb_end_intwrite(root->fs_info->sb);
+ if (!list_empty(&trans->new_bgs))
+ btrfs_create_pending_block_groups(trans, root);
if (lock && !atomic_read(&root->fs_info->open_ioctl_trans) &&
should_end_transaction(trans, root)) {
@@ -573,6 +619,9 @@ static int __btrfs_end_transaction(struct btrfs_trans_handle *trans,
}
}
+ if (trans->type < TRANS_JOIN_NOLOCK)
+ sb_end_intwrite(root->fs_info->sb);
+
WARN_ON(cur_trans != info->running_transaction);
WARN_ON(atomic_read(&cur_trans->num_writers) < 1);
atomic_dec(&cur_trans->num_writers);
@@ -604,7 +653,7 @@ int btrfs_end_transaction(struct btrfs_trans_handle *trans,
{
int ret;
- ret = __btrfs_end_transaction(trans, root, 0, 1);
+ ret = __btrfs_end_transaction(trans, root, 0);
if (ret)
return ret;
return 0;
@@ -615,18 +664,7 @@ int btrfs_end_transaction_throttle(struct btrfs_trans_handle *trans,
{
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)
-{
- int ret;
-
- ret = __btrfs_end_transaction(trans, root, 0, 0);
+ ret = __btrfs_end_transaction(trans, root, 1);
if (ret)
return ret;
return 0;
@@ -635,7 +673,7 @@ int btrfs_end_transaction_nolock(struct btrfs_trans_handle *trans,
int btrfs_end_transaction_dmeta(struct btrfs_trans_handle *trans,
struct btrfs_root *root)
{
- return __btrfs_end_transaction(trans, root, 1, 1);
+ return __btrfs_end_transaction(trans, root, 1);
}
/*
@@ -649,13 +687,15 @@ int btrfs_write_marked_extents(struct btrfs_root *root,
int err = 0;
int werr = 0;
struct address_space *mapping = root->fs_info->btree_inode->i_mapping;
+ struct extent_state *cached_state = NULL;
u64 start = 0;
u64 end;
while (!find_first_extent_bit(dirty_pages, start, &start, &end,
- mark)) {
- convert_extent_bit(dirty_pages, start, end, EXTENT_NEED_WAIT, mark,
- GFP_NOFS);
+ mark, &cached_state)) {
+ convert_extent_bit(dirty_pages, start, end, EXTENT_NEED_WAIT,
+ mark, &cached_state, GFP_NOFS);
+ cached_state = NULL;
err = filemap_fdatawrite_range(mapping, start, end);
if (err)
werr = err;
@@ -679,12 +719,14 @@ int btrfs_wait_marked_extents(struct btrfs_root *root,
int err = 0;
int werr = 0;
struct address_space *mapping = root->fs_info->btree_inode->i_mapping;
+ struct extent_state *cached_state = NULL;
u64 start = 0;
u64 end;
while (!find_first_extent_bit(dirty_pages, start, &start, &end,
- EXTENT_NEED_WAIT)) {
- clear_extent_bits(dirty_pages, start, end, EXTENT_NEED_WAIT, GFP_NOFS);
+ EXTENT_NEED_WAIT, &cached_state)) {
+ clear_extent_bit(dirty_pages, start, end, EXTENT_NEED_WAIT,
+ 0, 0, &cached_state, GFP_NOFS);
err = filemap_fdatawait_range(mapping, start, end);
if (err)
werr = err;
@@ -955,6 +997,8 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
struct btrfs_root *parent_root;
struct btrfs_block_rsv *rsv;
struct inode *parent_inode;
+ struct btrfs_path *path;
+ struct btrfs_dir_item *dir_item;
struct dentry *parent;
struct dentry *dentry;
struct extent_buffer *tmp;
@@ -967,18 +1011,22 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
u64 root_flags;
uuid_le new_uuid;
- rsv = trans->block_rsv;
+ path = btrfs_alloc_path();
+ if (!path) {
+ ret = pending->error = -ENOMEM;
+ goto path_alloc_fail;
+ }
new_root_item = kmalloc(sizeof(*new_root_item), GFP_NOFS);
if (!new_root_item) {
ret = pending->error = -ENOMEM;
- goto fail;
+ goto root_item_alloc_fail;
}
ret = btrfs_find_free_objectid(tree_root, &objectid);
if (ret) {
pending->error = ret;
- goto fail;
+ goto no_free_objectid;
}
btrfs_reloc_pre_snapshot(trans, pending, &to_reserve);
@@ -988,22 +1036,22 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
to_reserve);
if (ret) {
pending->error = ret;
- goto fail;
+ goto no_free_objectid;
}
}
ret = btrfs_qgroup_inherit(trans, fs_info, root->root_key.objectid,
objectid, pending->inherit);
- kfree(pending->inherit);
if (ret) {
pending->error = ret;
- goto fail;
+ goto no_free_objectid;
}
key.objectid = objectid;
key.offset = (u64)-1;
key.type = BTRFS_ROOT_ITEM_KEY;
+ rsv = trans->block_rsv;
trans->block_rsv = &pending->block_rsv;
dentry = pending->dentry;
@@ -1017,24 +1065,21 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
*/
ret = btrfs_set_inode_index(parent_inode, &index);
BUG_ON(ret); /* -ENOMEM */
- ret = btrfs_insert_dir_item(trans, parent_root,
- dentry->d_name.name, dentry->d_name.len,
- parent_inode, &key,
- BTRFS_FT_DIR, index);
- if (ret == -EEXIST) {
+
+ /* check if there is a file/dir which has the same name. */
+ dir_item = btrfs_lookup_dir_item(NULL, parent_root, path,
+ btrfs_ino(parent_inode),
+ dentry->d_name.name,
+ dentry->d_name.len, 0);
+ if (dir_item != NULL && !IS_ERR(dir_item)) {
pending->error = -EEXIST;
- dput(parent);
goto fail;
- } else if (ret) {
- goto abort_trans_dput;
+ } else if (IS_ERR(dir_item)) {
+ ret = PTR_ERR(dir_item);
+ btrfs_abort_transaction(trans, root, ret);
+ goto fail;
}
-
- btrfs_i_size_write(parent_inode, parent_inode->i_size +
- dentry->d_name.len * 2);
- parent_inode->i_mtime = parent_inode->i_ctime = CURRENT_TIME;
- ret = btrfs_update_inode(trans, parent_root, parent_inode);
- if (ret)
- goto abort_trans_dput;
+ btrfs_release_path(path);
/*
* pull in the delayed directory update
@@ -1043,8 +1088,8 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
* snapshot
*/
ret = btrfs_run_delayed_items(trans, root);
- if (ret) { /* Transaction aborted */
- dput(parent);
+ if (ret) { /* Transaction aborted */
+ btrfs_abort_transaction(trans, root, ret);
goto fail;
}
@@ -1079,7 +1124,8 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
if (ret) {
btrfs_tree_unlock(old);
free_extent_buffer(old);
- goto abort_trans_dput;
+ btrfs_abort_transaction(trans, root, ret);
+ goto fail;
}
btrfs_set_lock_blocking(old);
@@ -1088,8 +1134,10 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
/* clean up in any case */
btrfs_tree_unlock(old);
free_extent_buffer(old);
- if (ret)
- goto abort_trans_dput;
+ if (ret) {
+ btrfs_abort_transaction(trans, root, ret);
+ goto fail;
+ }
/* see comments in should_cow_block() */
root->force_cow = 1;
@@ -1101,8 +1149,10 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
ret = btrfs_insert_root(trans, tree_root, &key, new_root_item);
btrfs_tree_unlock(tmp);
free_extent_buffer(tmp);
- if (ret)
- goto abort_trans_dput;
+ if (ret) {
+ btrfs_abort_transaction(trans, root, ret);
+ goto fail;
+ }
/*
* insert root back/forward references
@@ -1111,32 +1161,58 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
parent_root->root_key.objectid,
btrfs_ino(parent_inode), index,
dentry->d_name.name, dentry->d_name.len);
- dput(parent);
- if (ret)
+ if (ret) {
+ btrfs_abort_transaction(trans, root, ret);
goto fail;
+ }
key.offset = (u64)-1;
pending->snap = btrfs_read_fs_root_no_name(root->fs_info, &key);
if (IS_ERR(pending->snap)) {
ret = PTR_ERR(pending->snap);
- goto abort_trans;
+ btrfs_abort_transaction(trans, root, ret);
+ goto fail;
}
ret = btrfs_reloc_post_snapshot(trans, pending);
+ if (ret) {
+ btrfs_abort_transaction(trans, root, ret);
+ goto fail;
+ }
+
+ ret = btrfs_run_delayed_refs(trans, root, (unsigned long)-1);
+ if (ret) {
+ btrfs_abort_transaction(trans, root, ret);
+ goto fail;
+ }
+
+ ret = btrfs_insert_dir_item(trans, parent_root,
+ dentry->d_name.name, dentry->d_name.len,
+ parent_inode, &key,
+ BTRFS_FT_DIR, index);
+ /* We have check then name at the beginning, so it is impossible. */
+ BUG_ON(ret == -EEXIST);
+ if (ret) {
+ btrfs_abort_transaction(trans, root, ret);
+ goto fail;
+ }
+
+ btrfs_i_size_write(parent_inode, parent_inode->i_size +
+ dentry->d_name.len * 2);
+ parent_inode->i_mtime = parent_inode->i_ctime = CURRENT_TIME;
+ ret = btrfs_update_inode(trans, parent_root, parent_inode);
if (ret)
- goto abort_trans;
- ret = 0;
+ btrfs_abort_transaction(trans, root, ret);
fail:
- kfree(new_root_item);
+ dput(parent);
trans->block_rsv = rsv;
+no_free_objectid:
+ kfree(new_root_item);
+root_item_alloc_fail:
+ btrfs_free_path(path);
+path_alloc_fail:
btrfs_block_rsv_release(root, &pending->block_rsv, (u64)-1);
return ret;
-
-abort_trans_dput:
- dput(parent);
-abort_trans:
- btrfs_abort_transaction(trans, root, ret);
- goto fail;
}
/*
@@ -1229,6 +1305,16 @@ static void do_async_commit(struct work_struct *work)
struct btrfs_async_commit *ac =
container_of(work, struct btrfs_async_commit, work.work);
+ /*
+ * We've got freeze protection passed with the transaction.
+ * Tell lockdep about it.
+ */
+ rwsem_acquire_read(
+ &ac->root->fs_info->sb->s_writers.lock_map[SB_FREEZE_FS-1],
+ 0, 1, _THIS_IP_);
+
+ current->journal_info = ac->newtrans;
+
btrfs_commit_transaction(ac->newtrans, ac->root);
kfree(ac);
}
@@ -1258,6 +1344,14 @@ int btrfs_commit_transaction_async(struct btrfs_trans_handle *trans,
atomic_inc(&cur_trans->use_count);
btrfs_end_transaction(trans, root);
+
+ /*
+ * Tell lockdep we've released the freeze rwsem, since the
+ * async commit thread will be the one to unlock it.
+ */
+ rwsem_release(&root->fs_info->sb->s_writers.lock_map[SB_FREEZE_FS-1],
+ 1, _THIS_IP_);
+
schedule_delayed_work(&ac->work, 0);
/* wait for transaction to start and unblock */
@@ -1348,6 +1442,9 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
*/
cur_trans->delayed_refs.flushing = 1;
+ if (!list_empty(&trans->new_bgs))
+ btrfs_create_pending_block_groups(trans, root);
+
ret = btrfs_run_delayed_refs(trans, root, 0);
if (ret)
goto cleanup_transaction;
@@ -1403,7 +1500,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
if (flush_on_commit || snap_pending) {
btrfs_start_delalloc_inodes(root, 1);
- btrfs_wait_ordered_extents(root, 0, 1);
+ btrfs_wait_ordered_extents(root, 1);
}
ret = btrfs_run_delayed_items(trans, root);
@@ -1456,13 +1553,28 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
*/
mutex_lock(&root->fs_info->reloc_mutex);
- ret = btrfs_run_delayed_items(trans, root);
+ /*
+ * We needn't worry about the delayed items because we will
+ * deal with them in create_pending_snapshot(), which is the
+ * core function of the snapshot creation.
+ */
+ ret = create_pending_snapshots(trans, root->fs_info);
if (ret) {
mutex_unlock(&root->fs_info->reloc_mutex);
goto cleanup_transaction;
}
- ret = create_pending_snapshots(trans, root->fs_info);
+ /*
+ * We insert the dir indexes of the snapshots and update the inode
+ * of the snapshots' parents after the snapshot creation, so there
+ * are some delayed items which are not dealt with. Now deal with
+ * them.
+ *
+ * We needn't worry that this operation will corrupt the snapshots,
+ * because all the tree which are snapshoted will be forced to COW
+ * the nodes and leaves.
+ */
+ ret = btrfs_run_delayed_items(trans, root);
if (ret) {
mutex_unlock(&root->fs_info->reloc_mutex);
goto cleanup_transaction;
@@ -1584,7 +1696,8 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
put_transaction(cur_trans);
put_transaction(cur_trans);
- sb_end_intwrite(root->fs_info->sb);
+ if (trans->type < TRANS_JOIN_NOLOCK)
+ sb_end_intwrite(root->fs_info->sb);
trace_btrfs_transaction_commit(root);
diff --git a/fs/btrfs/transaction.h b/fs/btrfs/transaction.h
index e8b8416..8096194 100644
--- a/fs/btrfs/transaction.h
+++ b/fs/btrfs/transaction.h
@@ -47,6 +47,14 @@ struct btrfs_transaction {
int aborted;
};
+enum btrfs_trans_type {
+ TRANS_START,
+ TRANS_JOIN,
+ TRANS_USERSPACE,
+ TRANS_JOIN_NOLOCK,
+ TRANS_ATTACH,
+};
+
struct btrfs_trans_handle {
u64 transid;
u64 bytes_reserved;
@@ -58,8 +66,9 @@ struct btrfs_trans_handle {
struct btrfs_transaction *transaction;
struct btrfs_block_rsv *block_rsv;
struct btrfs_block_rsv *orig_rsv;
- int aborted;
- int adding_csums;
+ short aborted;
+ short adding_csums;
+ enum btrfs_trans_type type;
/*
* this root is only needed to validate that the root passed to
* start_transaction is the same as the one passed to end_transaction.
@@ -68,6 +77,7 @@ struct btrfs_trans_handle {
struct btrfs_root *root;
struct seq_list delayed_ref_elem;
struct list_head qgroup_ref_list;
+ struct list_head new_bgs;
};
struct btrfs_pending_snapshot {
@@ -88,16 +98,18 @@ static inline void btrfs_set_inode_last_trans(struct btrfs_trans_handle *trans,
{
BTRFS_I(inode)->last_trans = trans->transaction->transid;
BTRFS_I(inode)->last_sub_trans = BTRFS_I(inode)->root->log_transid;
+ BTRFS_I(inode)->last_log_commit = BTRFS_I(inode)->root->last_log_commit;
}
int btrfs_end_transaction(struct btrfs_trans_handle *trans,
struct btrfs_root *root);
-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_start_transaction_noflush(
+ struct btrfs_root *root, int num_items);
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_attach_transaction(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,
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c
index c86670f..e9ebb47 100644
--- a/fs/btrfs/tree-log.c
+++ b/fs/btrfs/tree-log.c
@@ -18,13 +18,16 @@
#include <linux/sched.h>
#include <linux/slab.h>
+#include <linux/list_sort.h>
#include "ctree.h"
#include "transaction.h"
#include "disk-io.h"
#include "locking.h"
#include "print-tree.h"
+#include "backref.h"
#include "compat.h"
#include "tree-log.h"
+#include "hash.h"
/* magic values for the inode_only field in btrfs_log_inode:
*
@@ -146,7 +149,7 @@ static int start_log_trans(struct btrfs_trans_handle *trans,
root->log_multiple_pids = true;
}
- root->log_batch++;
+ atomic_inc(&root->log_batch);
atomic_inc(&root->log_writers);
mutex_unlock(&root->log_mutex);
return 0;
@@ -165,7 +168,7 @@ static int start_log_trans(struct btrfs_trans_handle *trans,
err = ret;
}
mutex_unlock(&root->fs_info->tree_log_mutex);
- root->log_batch++;
+ atomic_inc(&root->log_batch);
atomic_inc(&root->log_writers);
mutex_unlock(&root->log_mutex);
return err;
@@ -484,7 +487,6 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans,
int found_type;
u64 mask = root->sectorsize - 1;
u64 extent_end;
- u64 alloc_hint;
u64 start = key->offset;
u64 saved_nbytes;
struct btrfs_file_extent_item *item;
@@ -550,8 +552,7 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans,
saved_nbytes = inode_get_bytes(inode);
/* drop any overlapping extents */
- ret = btrfs_drop_extents(trans, inode, start, extent_end,
- &alloc_hint, 1);
+ ret = btrfs_drop_extents(trans, root, inode, start, extent_end, 1);
BUG_ON(ret);
if (found_type == BTRFS_FILE_EXTENT_REG ||
@@ -744,6 +745,7 @@ out:
*/
static noinline int backref_in_log(struct btrfs_root *log,
struct btrfs_key *key,
+ u64 ref_objectid,
char *name, int namelen)
{
struct btrfs_path *path;
@@ -764,8 +766,17 @@ static noinline int backref_in_log(struct btrfs_root *log,
if (ret != 0)
goto out;
- item_size = btrfs_item_size_nr(path->nodes[0], path->slots[0]);
ptr = btrfs_item_ptr_offset(path->nodes[0], path->slots[0]);
+
+ if (key->type == BTRFS_INODE_EXTREF_KEY) {
+ if (btrfs_find_name_in_ext_backref(path, ref_objectid,
+ name, namelen, NULL))
+ match = 1;
+
+ goto out;
+ }
+
+ item_size = btrfs_item_size_nr(path->nodes[0], path->slots[0]);
ptr_end = ptr + item_size;
while (ptr < ptr_end) {
ref = (struct btrfs_inode_ref *)ptr;
@@ -786,91 +797,42 @@ out:
return match;
}
-
-/*
- * replay one inode back reference item found in the log tree.
- * eb, slot and key refer to the buffer and key found in the log tree.
- * root is the destination we are replaying into, and path is for temp
- * use by this function. (it should be released on return).
- */
-static noinline int add_inode_ref(struct btrfs_trans_handle *trans,
+static inline int __add_inode_ref(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
- struct btrfs_root *log,
struct btrfs_path *path,
- struct extent_buffer *eb, int slot,
- struct btrfs_key *key)
+ struct btrfs_root *log_root,
+ struct inode *dir, struct inode *inode,
+ struct extent_buffer *eb,
+ u64 inode_objectid, u64 parent_objectid,
+ u64 ref_index, char *name, int namelen,
+ int *search_done)
{
- struct btrfs_inode_ref *ref;
- struct btrfs_dir_item *di;
- struct inode *dir;
- struct inode *inode;
- unsigned long ref_ptr;
- unsigned long ref_end;
- char *name;
- int namelen;
int ret;
- int search_done = 0;
-
- /*
- * it is possible that we didn't log all the parent directories
- * for a given inode. If we don't find the dir, just don't
- * copy the back ref in. The link count fixup code will take
- * care of the rest
- */
- dir = read_one_inode(root, key->offset);
- if (!dir)
- return -ENOENT;
-
- inode = read_one_inode(root, key->objectid);
- if (!inode) {
- iput(dir);
- return -EIO;
- }
-
- ref_ptr = btrfs_item_ptr_offset(eb, slot);
- ref_end = ref_ptr + btrfs_item_size_nr(eb, slot);
+ char *victim_name;
+ int victim_name_len;
+ struct extent_buffer *leaf;
+ struct btrfs_dir_item *di;
+ struct btrfs_key search_key;
+ struct btrfs_inode_extref *extref;
again:
- ref = (struct btrfs_inode_ref *)ref_ptr;
-
- namelen = btrfs_inode_ref_name_len(eb, ref);
- name = kmalloc(namelen, GFP_NOFS);
- BUG_ON(!name);
-
- 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, btrfs_ino(dir), btrfs_ino(inode),
- btrfs_inode_ref_index(eb, ref),
- name, namelen)) {
- goto out;
- }
-
- /*
- * look for a conflicting back reference in the metadata.
- * if we find one we have to unlink that name of the file
- * before we add our new link. Later on, we overwrite any
- * existing back reference, and we don't want to create
- * dangling pointers in the directory.
- */
-
- if (search_done)
- goto insert;
-
- ret = btrfs_search_slot(NULL, root, key, path, 0, 0);
+ /* Search old style refs */
+ search_key.objectid = inode_objectid;
+ search_key.type = BTRFS_INODE_REF_KEY;
+ search_key.offset = parent_objectid;
+ ret = btrfs_search_slot(NULL, root, &search_key, path, 0, 0);
if (ret == 0) {
- char *victim_name;
- int victim_name_len;
struct btrfs_inode_ref *victim_ref;
unsigned long ptr;
unsigned long ptr_end;
- struct extent_buffer *leaf = path->nodes[0];
+
+ leaf = path->nodes[0];
/* are we trying to overwrite a back ref for the root directory
* if so, just jump out, we're done
*/
- if (key->objectid == key->offset)
- goto out_nowrite;
+ if (search_key.objectid == search_key.offset)
+ return 1;
/* check all the names in this back reference to see
* if they are in the log. if so, we allow them to stay
@@ -889,7 +851,9 @@ again:
(unsigned long)(victim_ref + 1),
victim_name_len);
- if (!backref_in_log(log, key, victim_name,
+ if (!backref_in_log(log_root, &search_key,
+ parent_objectid,
+ victim_name,
victim_name_len)) {
btrfs_inc_nlink(inode);
btrfs_release_path(path);
@@ -897,9 +861,14 @@ again:
ret = btrfs_unlink_inode(trans, root, dir,
inode, victim_name,
victim_name_len);
+ BUG_ON(ret);
btrfs_run_delayed_items(trans, root);
+ kfree(victim_name);
+ *search_done = 1;
+ goto again;
}
kfree(victim_name);
+
ptr = (unsigned long)(victim_ref + 1) + victim_name_len;
}
BUG_ON(ret);
@@ -908,14 +877,78 @@ again:
* NOTE: we have searched root tree and checked the
* coresponding ref, it does not need to check again.
*/
- search_done = 1;
+ *search_done = 1;
+ }
+ btrfs_release_path(path);
+
+ /* Same search but for extended refs */
+ extref = btrfs_lookup_inode_extref(NULL, root, path, name, namelen,
+ inode_objectid, parent_objectid, 0,
+ 0);
+ if (!IS_ERR_OR_NULL(extref)) {
+ u32 item_size;
+ u32 cur_offset = 0;
+ unsigned long base;
+ struct inode *victim_parent;
+
+ leaf = path->nodes[0];
+
+ item_size = btrfs_item_size_nr(leaf, path->slots[0]);
+ base = btrfs_item_ptr_offset(leaf, path->slots[0]);
+
+ while (cur_offset < item_size) {
+ extref = (struct btrfs_inode_extref *)base + cur_offset;
+
+ victim_name_len = btrfs_inode_extref_name_len(leaf, extref);
+
+ if (btrfs_inode_extref_parent(leaf, extref) != parent_objectid)
+ goto next;
+
+ victim_name = kmalloc(victim_name_len, GFP_NOFS);
+ read_extent_buffer(leaf, victim_name, (unsigned long)&extref->name,
+ victim_name_len);
+
+ search_key.objectid = inode_objectid;
+ search_key.type = BTRFS_INODE_EXTREF_KEY;
+ search_key.offset = btrfs_extref_hash(parent_objectid,
+ victim_name,
+ victim_name_len);
+ ret = 0;
+ if (!backref_in_log(log_root, &search_key,
+ parent_objectid, victim_name,
+ victim_name_len)) {
+ ret = -ENOENT;
+ victim_parent = read_one_inode(root,
+ parent_objectid);
+ if (victim_parent) {
+ btrfs_inc_nlink(inode);
+ btrfs_release_path(path);
+
+ ret = btrfs_unlink_inode(trans, root,
+ victim_parent,
+ inode,
+ victim_name,
+ victim_name_len);
+ btrfs_run_delayed_items(trans, root);
+ }
+ BUG_ON(ret);
+ iput(victim_parent);
+ kfree(victim_name);
+ *search_done = 1;
+ goto again;
+ }
+ kfree(victim_name);
+ BUG_ON(ret);
+next:
+ cur_offset += victim_name_len + sizeof(*extref);
+ }
+ *search_done = 1;
}
btrfs_release_path(path);
/* look for a conflicting sequence number */
di = btrfs_lookup_dir_index_item(trans, root, path, btrfs_ino(dir),
- btrfs_inode_ref_index(eb, ref),
- name, namelen, 0);
+ ref_index, name, namelen, 0);
if (di && !IS_ERR(di)) {
ret = drop_one_dir_item(trans, root, path, dir, di);
BUG_ON(ret);
@@ -931,25 +964,173 @@ again:
}
btrfs_release_path(path);
-insert:
- /* insert our name */
- ret = btrfs_add_link(trans, dir, inode, name, namelen, 0,
- btrfs_inode_ref_index(eb, ref));
- BUG_ON(ret);
+ return 0;
+}
- btrfs_update_inode(trans, root, inode);
+static int extref_get_fields(struct extent_buffer *eb, unsigned long ref_ptr,
+ u32 *namelen, char **name, u64 *index,
+ u64 *parent_objectid)
+{
+ struct btrfs_inode_extref *extref;
-out:
- ref_ptr = (unsigned long)(ref + 1) + namelen;
- kfree(name);
- if (ref_ptr < ref_end)
- goto again;
+ extref = (struct btrfs_inode_extref *)ref_ptr;
+
+ *namelen = btrfs_inode_extref_name_len(eb, extref);
+ *name = kmalloc(*namelen, GFP_NOFS);
+ if (*name == NULL)
+ return -ENOMEM;
+
+ read_extent_buffer(eb, *name, (unsigned long)&extref->name,
+ *namelen);
+
+ *index = btrfs_inode_extref_index(eb, extref);
+ if (parent_objectid)
+ *parent_objectid = btrfs_inode_extref_parent(eb, extref);
+
+ return 0;
+}
+
+static int ref_get_fields(struct extent_buffer *eb, unsigned long ref_ptr,
+ u32 *namelen, char **name, u64 *index)
+{
+ struct btrfs_inode_ref *ref;
+
+ ref = (struct btrfs_inode_ref *)ref_ptr;
+
+ *namelen = btrfs_inode_ref_name_len(eb, ref);
+ *name = kmalloc(*namelen, GFP_NOFS);
+ if (*name == NULL)
+ return -ENOMEM;
+
+ read_extent_buffer(eb, *name, (unsigned long)(ref + 1), *namelen);
+
+ *index = btrfs_inode_ref_index(eb, ref);
+
+ return 0;
+}
+
+/*
+ * replay one inode back reference item found in the log tree.
+ * eb, slot and key refer to the buffer and key found in the log tree.
+ * root is the destination we are replaying into, and path is for temp
+ * use by this function. (it should be released on return).
+ */
+static noinline int add_inode_ref(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root,
+ struct btrfs_root *log,
+ struct btrfs_path *path,
+ struct extent_buffer *eb, int slot,
+ struct btrfs_key *key)
+{
+ struct inode *dir;
+ struct inode *inode;
+ unsigned long ref_ptr;
+ unsigned long ref_end;
+ char *name;
+ int namelen;
+ int ret;
+ int search_done = 0;
+ int log_ref_ver = 0;
+ u64 parent_objectid;
+ u64 inode_objectid;
+ u64 ref_index = 0;
+ int ref_struct_size;
+
+ ref_ptr = btrfs_item_ptr_offset(eb, slot);
+ ref_end = ref_ptr + btrfs_item_size_nr(eb, slot);
+
+ if (key->type == BTRFS_INODE_EXTREF_KEY) {
+ struct btrfs_inode_extref *r;
+
+ ref_struct_size = sizeof(struct btrfs_inode_extref);
+ log_ref_ver = 1;
+ r = (struct btrfs_inode_extref *)ref_ptr;
+ parent_objectid = btrfs_inode_extref_parent(eb, r);
+ } else {
+ ref_struct_size = sizeof(struct btrfs_inode_ref);
+ parent_objectid = key->offset;
+ }
+ inode_objectid = key->objectid;
+
+ /*
+ * it is possible that we didn't log all the parent directories
+ * for a given inode. If we don't find the dir, just don't
+ * copy the back ref in. The link count fixup code will take
+ * care of the rest
+ */
+ dir = read_one_inode(root, parent_objectid);
+ if (!dir)
+ return -ENOENT;
+
+ inode = read_one_inode(root, inode_objectid);
+ if (!inode) {
+ iput(dir);
+ return -EIO;
+ }
+
+ while (ref_ptr < ref_end) {
+ if (log_ref_ver) {
+ ret = extref_get_fields(eb, ref_ptr, &namelen, &name,
+ &ref_index, &parent_objectid);
+ /*
+ * parent object can change from one array
+ * item to another.
+ */
+ if (!dir)
+ dir = read_one_inode(root, parent_objectid);
+ if (!dir)
+ return -ENOENT;
+ } else {
+ ret = ref_get_fields(eb, ref_ptr, &namelen, &name,
+ &ref_index);
+ }
+ if (ret)
+ return ret;
+
+ /* if we already have a perfect match, we're done */
+ if (!inode_in_dir(root, path, btrfs_ino(dir), btrfs_ino(inode),
+ ref_index, name, namelen)) {
+ /*
+ * look for a conflicting back reference in the
+ * metadata. if we find one we have to unlink that name
+ * of the file before we add our new link. Later on, we
+ * overwrite any existing back reference, and we don't
+ * want to create dangling pointers in the directory.
+ */
+
+ if (!search_done) {
+ ret = __add_inode_ref(trans, root, path, log,
+ dir, inode, eb,
+ inode_objectid,
+ parent_objectid,
+ ref_index, name, namelen,
+ &search_done);
+ if (ret == 1)
+ goto out;
+ BUG_ON(ret);
+ }
+
+ /* insert our name */
+ ret = btrfs_add_link(trans, dir, inode, name, namelen,
+ 0, ref_index);
+ BUG_ON(ret);
+
+ btrfs_update_inode(trans, root, inode);
+ }
+
+ ref_ptr = (unsigned long)(ref_ptr + ref_struct_size) + namelen;
+ kfree(name);
+ if (log_ref_ver) {
+ iput(dir);
+ dir = NULL;
+ }
+ }
/* finally write the back reference in the inode */
ret = overwrite_item(trans, root, path, eb, slot, key);
BUG_ON(ret);
-out_nowrite:
+out:
btrfs_release_path(path);
iput(dir);
iput(inode);
@@ -966,25 +1147,55 @@ static int insert_orphan_item(struct btrfs_trans_handle *trans,
return ret;
}
+static int count_inode_extrefs(struct btrfs_root *root,
+ struct inode *inode, struct btrfs_path *path)
+{
+ int ret = 0;
+ int name_len;
+ unsigned int nlink = 0;
+ u32 item_size;
+ u32 cur_offset = 0;
+ u64 inode_objectid = btrfs_ino(inode);
+ u64 offset = 0;
+ unsigned long ptr;
+ struct btrfs_inode_extref *extref;
+ struct extent_buffer *leaf;
-/*
- * There are a few corners where the link count of the file can't
- * be properly maintained during replay. So, instead of adding
- * lots of complexity to the log code, we just scan the backrefs
- * for any file that has been through replay.
- *
- * The scan will update the link count on the inode to reflect the
- * number of back refs found. If it goes down to zero, the iput
- * will free the inode.
- */
-static noinline int fixup_inode_link_count(struct btrfs_trans_handle *trans,
- struct btrfs_root *root,
- struct inode *inode)
+ while (1) {
+ ret = btrfs_find_one_extref(root, inode_objectid, offset, path,
+ &extref, &offset);
+ if (ret)
+ break;
+
+ leaf = path->nodes[0];
+ item_size = btrfs_item_size_nr(leaf, path->slots[0]);
+ ptr = btrfs_item_ptr_offset(leaf, path->slots[0]);
+
+ while (cur_offset < item_size) {
+ extref = (struct btrfs_inode_extref *) (ptr + cur_offset);
+ name_len = btrfs_inode_extref_name_len(leaf, extref);
+
+ nlink++;
+
+ cur_offset += name_len + sizeof(*extref);
+ }
+
+ offset++;
+ btrfs_release_path(path);
+ }
+ btrfs_release_path(path);
+
+ if (ret < 0)
+ return ret;
+ return nlink;
+}
+
+static int count_inode_refs(struct btrfs_root *root,
+ struct inode *inode, struct btrfs_path *path)
{
- struct btrfs_path *path;
int ret;
struct btrfs_key key;
- u64 nlink = 0;
+ unsigned int nlink = 0;
unsigned long ptr;
unsigned long ptr_end;
int name_len;
@@ -994,10 +1205,6 @@ static noinline int fixup_inode_link_count(struct btrfs_trans_handle *trans,
key.type = BTRFS_INODE_REF_KEY;
key.offset = (u64)-1;
- path = btrfs_alloc_path();
- if (!path)
- return -ENOMEM;
-
while (1) {
ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
if (ret < 0)
@@ -1031,6 +1238,50 @@ static noinline int fixup_inode_link_count(struct btrfs_trans_handle *trans,
btrfs_release_path(path);
}
btrfs_release_path(path);
+
+ return nlink;
+}
+
+/*
+ * There are a few corners where the link count of the file can't
+ * be properly maintained during replay. So, instead of adding
+ * lots of complexity to the log code, we just scan the backrefs
+ * for any file that has been through replay.
+ *
+ * The scan will update the link count on the inode to reflect the
+ * number of back refs found. If it goes down to zero, the iput
+ * will free the inode.
+ */
+static noinline int fixup_inode_link_count(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root,
+ struct inode *inode)
+{
+ struct btrfs_path *path;
+ int ret;
+ u64 nlink = 0;
+ u64 ino = btrfs_ino(inode);
+
+ path = btrfs_alloc_path();
+ if (!path)
+ return -ENOMEM;
+
+ ret = count_inode_refs(root, inode, path);
+ if (ret < 0)
+ goto out;
+
+ nlink = ret;
+
+ ret = count_inode_extrefs(root, inode, path);
+ if (ret == -ENOENT)
+ ret = 0;
+
+ if (ret < 0)
+ goto out;
+
+ nlink += ret;
+
+ ret = 0;
+
if (nlink != inode->i_nlink) {
set_nlink(inode, nlink);
btrfs_update_inode(trans, root, inode);
@@ -1046,9 +1297,10 @@ static noinline int fixup_inode_link_count(struct btrfs_trans_handle *trans,
ret = insert_orphan_item(trans, root, ino);
BUG_ON(ret);
}
- btrfs_free_path(path);
- return 0;
+out:
+ btrfs_free_path(path);
+ return ret;
}
static noinline int fixup_inode_link_counts(struct btrfs_trans_handle *trans,
@@ -1695,6 +1947,10 @@ static int replay_one_buffer(struct btrfs_root *log, struct extent_buffer *eb,
ret = add_inode_ref(wc->trans, root, log, path,
eb, i, &key);
BUG_ON(ret && ret != -ENOENT);
+ } else if (key.type == BTRFS_INODE_EXTREF_KEY) {
+ ret = add_inode_ref(wc->trans, root, log, path,
+ eb, i, &key);
+ BUG_ON(ret && ret != -ENOENT);
} else if (key.type == BTRFS_EXTENT_DATA_KEY) {
ret = replay_one_extent(wc->trans, root, path,
eb, i, &key);
@@ -2037,7 +2293,7 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
if (atomic_read(&root->log_commit[(index1 + 1) % 2]))
wait_log_commit(trans, root, root->log_transid - 1);
while (1) {
- unsigned long batch = root->log_batch;
+ int batch = atomic_read(&root->log_batch);
/* when we're on an ssd, just kick the log commit out */
if (!btrfs_test_opt(root, SSD) && root->log_multiple_pids) {
mutex_unlock(&root->log_mutex);
@@ -2045,7 +2301,7 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
mutex_lock(&root->log_mutex);
}
wait_for_writer(trans, root);
- if (batch == root->log_batch)
+ if (batch == atomic_read(&root->log_batch))
break;
}
@@ -2074,7 +2330,6 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
btrfs_set_root_node(&log->root_item, log->node);
- root->log_batch = 0;
root->log_transid++;
log->log_transid = root->log_transid;
root->log_start_pid = 0;
@@ -2087,7 +2342,7 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
mutex_unlock(&root->log_mutex);
mutex_lock(&log_root_tree->log_mutex);
- log_root_tree->log_batch++;
+ atomic_inc(&log_root_tree->log_batch);
atomic_inc(&log_root_tree->log_writers);
mutex_unlock(&log_root_tree->log_mutex);
@@ -2157,7 +2412,6 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
btrfs_set_super_log_root_level(root->fs_info->super_for_commit,
btrfs_header_level(log_root_tree->node));
- log_root_tree->log_batch = 0;
log_root_tree->log_transid++;
smp_mb();
@@ -2171,9 +2425,12 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
* in and cause problems either.
*/
btrfs_scrub_pause_super(root);
- write_ctree_super(trans, root->fs_info->tree_root, 1);
+ ret = write_ctree_super(trans, root->fs_info->tree_root, 1);
btrfs_scrub_continue_super(root);
- ret = 0;
+ if (ret) {
+ btrfs_abort_transaction(trans, root, ret);
+ goto out_wake_log_root;
+ }
mutex_lock(&root->log_mutex);
if (root->last_log_commit < log_transid)
@@ -2209,7 +2466,8 @@ static void free_log_tree(struct btrfs_trans_handle *trans,
while (1) {
ret = find_first_extent_bit(&log->dirty_log_pages,
- 0, &start, &end, EXTENT_DIRTY | EXTENT_NEW);
+ 0, &start, &end, EXTENT_DIRTY | EXTENT_NEW,
+ NULL);
if (ret)
break;
@@ -2646,6 +2904,7 @@ static int drop_objectid_items(struct btrfs_trans_handle *trans,
int ret;
struct btrfs_key key;
struct btrfs_key found_key;
+ int start_slot;
key.objectid = objectid;
key.type = max_key_type;
@@ -2667,8 +2926,18 @@ static int drop_objectid_items(struct btrfs_trans_handle *trans,
if (found_key.objectid != objectid)
break;
- ret = btrfs_del_item(trans, log, path);
- if (ret)
+ found_key.offset = 0;
+ found_key.type = 0;
+ ret = btrfs_bin_search(path->nodes[0], &found_key, 0,
+ &start_slot);
+
+ ret = btrfs_del_items(trans, log, path, start_slot,
+ path->slots[0] - start_slot + 1);
+ /*
+ * If start slot isn't 0 then we don't need to re-search, we've
+ * found the last guy with the objectid in this tree.
+ */
+ if (ret || start_slot != 0)
break;
btrfs_release_path(path);
}
@@ -2678,14 +2947,64 @@ static int drop_objectid_items(struct btrfs_trans_handle *trans,
return ret;
}
+static void fill_inode_item(struct btrfs_trans_handle *trans,
+ struct extent_buffer *leaf,
+ struct btrfs_inode_item *item,
+ struct inode *inode, int log_inode_only)
+{
+ btrfs_set_inode_uid(leaf, item, inode->i_uid);
+ btrfs_set_inode_gid(leaf, item, inode->i_gid);
+ btrfs_set_inode_mode(leaf, item, inode->i_mode);
+ btrfs_set_inode_nlink(leaf, item, inode->i_nlink);
+
+ btrfs_set_timespec_sec(leaf, btrfs_inode_atime(item),
+ inode->i_atime.tv_sec);
+ btrfs_set_timespec_nsec(leaf, btrfs_inode_atime(item),
+ inode->i_atime.tv_nsec);
+
+ btrfs_set_timespec_sec(leaf, btrfs_inode_mtime(item),
+ inode->i_mtime.tv_sec);
+ btrfs_set_timespec_nsec(leaf, btrfs_inode_mtime(item),
+ inode->i_mtime.tv_nsec);
+
+ btrfs_set_timespec_sec(leaf, btrfs_inode_ctime(item),
+ inode->i_ctime.tv_sec);
+ btrfs_set_timespec_nsec(leaf, btrfs_inode_ctime(item),
+ inode->i_ctime.tv_nsec);
+
+ btrfs_set_inode_nbytes(leaf, item, inode_get_bytes(inode));
+
+ btrfs_set_inode_sequence(leaf, item, inode->i_version);
+ 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, 0);
+
+ if (log_inode_only) {
+ /* set the generation to zero so the recover code
+ * can tell the difference between an logging
+ * just to say 'this inode exists' and a logging
+ * to say 'update this inode with these values'
+ */
+ btrfs_set_inode_generation(leaf, item, 0);
+ btrfs_set_inode_size(leaf, item, 0);
+ } else {
+ btrfs_set_inode_generation(leaf, item,
+ BTRFS_I(inode)->generation);
+ btrfs_set_inode_size(leaf, item, inode->i_size);
+ }
+
+}
+
static noinline int copy_items(struct btrfs_trans_handle *trans,
- struct btrfs_root *log,
+ struct inode *inode,
struct btrfs_path *dst_path,
struct extent_buffer *src,
int start_slot, int nr, int inode_only)
{
unsigned long src_offset;
unsigned long dst_offset;
+ struct btrfs_root *log = BTRFS_I(inode)->root->log_root;
struct btrfs_file_extent_item *extent;
struct btrfs_inode_item *inode_item;
int ret;
@@ -2694,6 +3013,7 @@ static noinline int copy_items(struct btrfs_trans_handle *trans,
char *ins_data;
int i;
struct list_head ordered_sums;
+ int skip_csum = BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM;
INIT_LIST_HEAD(&ordered_sums);
@@ -2722,29 +3042,23 @@ static noinline int copy_items(struct btrfs_trans_handle *trans,
src_offset = btrfs_item_ptr_offset(src, start_slot + i);
- copy_extent_buffer(dst_path->nodes[0], src, dst_offset,
- src_offset, ins_sizes[i]);
-
- if (inode_only == LOG_INODE_EXISTS &&
- ins_keys[i].type == BTRFS_INODE_ITEM_KEY) {
+ if (ins_keys[i].type == BTRFS_INODE_ITEM_KEY) {
inode_item = btrfs_item_ptr(dst_path->nodes[0],
dst_path->slots[0],
struct btrfs_inode_item);
- btrfs_set_inode_size(dst_path->nodes[0], inode_item, 0);
-
- /* set the generation to zero so the recover code
- * can tell the difference between an logging
- * just to say 'this inode exists' and a logging
- * to say 'update this inode with these values'
- */
- btrfs_set_inode_generation(dst_path->nodes[0],
- inode_item, 0);
+ fill_inode_item(trans, dst_path->nodes[0], inode_item,
+ inode, inode_only == LOG_INODE_EXISTS);
+ } else {
+ copy_extent_buffer(dst_path->nodes[0], src, dst_offset,
+ src_offset, ins_sizes[i]);
}
+
/* take a reference on file data extents so that truncates
* or deletes of this inode don't have to relog the inode
* again
*/
- if (btrfs_key_type(ins_keys + i) == BTRFS_EXTENT_DATA_KEY) {
+ if (btrfs_key_type(ins_keys + i) == BTRFS_EXTENT_DATA_KEY &&
+ !skip_csum) {
int found_type;
extent = btrfs_item_ptr(src, start_slot + i,
struct btrfs_file_extent_item);
@@ -2753,8 +3067,7 @@ static noinline int copy_items(struct btrfs_trans_handle *trans,
continue;
found_type = btrfs_file_extent_type(src, extent);
- if (found_type == BTRFS_FILE_EXTENT_REG ||
- found_type == BTRFS_FILE_EXTENT_PREALLOC) {
+ if (found_type == BTRFS_FILE_EXTENT_REG) {
u64 ds, dl, cs, cl;
ds = btrfs_file_extent_disk_bytenr(src,
extent);
@@ -2803,6 +3116,239 @@ static noinline int copy_items(struct btrfs_trans_handle *trans,
return ret;
}
+static int extent_cmp(void *priv, struct list_head *a, struct list_head *b)
+{
+ struct extent_map *em1, *em2;
+
+ em1 = list_entry(a, struct extent_map, list);
+ em2 = list_entry(b, struct extent_map, list);
+
+ if (em1->start < em2->start)
+ return -1;
+ else if (em1->start > em2->start)
+ return 1;
+ return 0;
+}
+
+struct log_args {
+ struct extent_buffer *src;
+ u64 next_offset;
+ int start_slot;
+ int nr;
+};
+
+static int log_one_extent(struct btrfs_trans_handle *trans,
+ struct inode *inode, struct btrfs_root *root,
+ struct extent_map *em, struct btrfs_path *path,
+ struct btrfs_path *dst_path, struct log_args *args)
+{
+ struct btrfs_root *log = root->log_root;
+ struct btrfs_file_extent_item *fi;
+ struct btrfs_key key;
+ u64 start = em->mod_start;
+ u64 search_start = start;
+ u64 len = em->mod_len;
+ u64 num_bytes;
+ int nritems;
+ int ret;
+
+ if (BTRFS_I(inode)->logged_trans == trans->transid) {
+ ret = __btrfs_drop_extents(trans, log, inode, dst_path, start,
+ start + len, NULL, 0);
+ if (ret)
+ return ret;
+ }
+
+ while (len) {
+ if (args->nr)
+ goto next_slot;
+again:
+ key.objectid = btrfs_ino(inode);
+ key.type = BTRFS_EXTENT_DATA_KEY;
+ key.offset = search_start;
+
+ ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
+ if (ret < 0)
+ return ret;
+
+ if (ret) {
+ /*
+ * A rare case were we can have an em for a section of a
+ * larger extent so we need to make sure that this em
+ * falls within the extent we've found. If not we just
+ * bail and go back to ye-olde way of doing things but
+ * it happens often enough in testing that we need to do
+ * this dance to make sure.
+ */
+ do {
+ if (path->slots[0] == 0) {
+ btrfs_release_path(path);
+ if (search_start == 0)
+ return -ENOENT;
+ search_start--;
+ goto again;
+ }
+
+ path->slots[0]--;
+ btrfs_item_key_to_cpu(path->nodes[0], &key,
+ path->slots[0]);
+ if (key.objectid != btrfs_ino(inode) ||
+ key.type != BTRFS_EXTENT_DATA_KEY) {
+ btrfs_release_path(path);
+ return -ENOENT;
+ }
+ } while (key.offset > start);
+
+ fi = btrfs_item_ptr(path->nodes[0], path->slots[0],
+ struct btrfs_file_extent_item);
+ num_bytes = btrfs_file_extent_num_bytes(path->nodes[0],
+ fi);
+ if (key.offset + num_bytes <= start) {
+ btrfs_release_path(path);
+ return -ENOENT;
+ }
+ }
+ args->src = path->nodes[0];
+next_slot:
+ btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]);
+ fi = btrfs_item_ptr(args->src, path->slots[0],
+ struct btrfs_file_extent_item);
+ if (args->nr &&
+ args->start_slot + args->nr == path->slots[0]) {
+ args->nr++;
+ } else if (args->nr) {
+ ret = copy_items(trans, inode, dst_path, args->src,
+ args->start_slot, args->nr,
+ LOG_INODE_ALL);
+ if (ret)
+ return ret;
+ args->nr = 1;
+ args->start_slot = path->slots[0];
+ } else if (!args->nr) {
+ args->nr = 1;
+ args->start_slot = path->slots[0];
+ }
+ nritems = btrfs_header_nritems(path->nodes[0]);
+ path->slots[0]++;
+ num_bytes = btrfs_file_extent_num_bytes(args->src, fi);
+ if (len < num_bytes) {
+ /* I _think_ this is ok, envision we write to a
+ * preallocated space that is adjacent to a previously
+ * written preallocated space that gets merged when we
+ * mark this preallocated space written. If we do not
+ * have the adjacent extent in cache then when we copy
+ * this extent it could end up being larger than our EM
+ * thinks it is, which is a-ok, so just set len to 0.
+ */
+ len = 0;
+ } else {
+ len -= num_bytes;
+ }
+ start = key.offset + num_bytes;
+ args->next_offset = start;
+ search_start = start;
+
+ if (path->slots[0] < nritems) {
+ if (len)
+ goto next_slot;
+ break;
+ }
+
+ if (args->nr) {
+ ret = copy_items(trans, inode, dst_path, args->src,
+ args->start_slot, args->nr,
+ LOG_INODE_ALL);
+ if (ret)
+ return ret;
+ args->nr = 0;
+ btrfs_release_path(path);
+ }
+ }
+
+ return 0;
+}
+
+static int btrfs_log_changed_extents(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root,
+ struct inode *inode,
+ struct btrfs_path *path,
+ struct btrfs_path *dst_path)
+{
+ struct log_args args;
+ struct extent_map *em, *n;
+ struct list_head extents;
+ struct extent_map_tree *tree = &BTRFS_I(inode)->extent_tree;
+ u64 test_gen;
+ int ret = 0;
+
+ INIT_LIST_HEAD(&extents);
+
+ memset(&args, 0, sizeof(args));
+
+ write_lock(&tree->lock);
+ test_gen = root->fs_info->last_trans_committed;
+
+ list_for_each_entry_safe(em, n, &tree->modified_extents, list) {
+ list_del_init(&em->list);
+ if (em->generation <= test_gen)
+ continue;
+ /* Need a ref to keep it from getting evicted from cache */
+ atomic_inc(&em->refs);
+ set_bit(EXTENT_FLAG_LOGGING, &em->flags);
+ list_add_tail(&em->list, &extents);
+ }
+
+ list_sort(NULL, &extents, extent_cmp);
+
+ while (!list_empty(&extents)) {
+ em = list_entry(extents.next, struct extent_map, list);
+
+ list_del_init(&em->list);
+ clear_bit(EXTENT_FLAG_LOGGING, &em->flags);
+
+ /*
+ * If we had an error we just need to delete everybody from our
+ * private list.
+ */
+ if (ret) {
+ free_extent_map(em);
+ continue;
+ }
+
+ write_unlock(&tree->lock);
+
+ /*
+ * If the previous EM and the last extent we left off on aren't
+ * sequential then we need to copy the items we have and redo
+ * our search
+ */
+ if (args.nr && em->mod_start != args.next_offset) {
+ ret = copy_items(trans, inode, dst_path, args.src,
+ args.start_slot, args.nr,
+ LOG_INODE_ALL);
+ if (ret) {
+ free_extent_map(em);
+ write_lock(&tree->lock);
+ continue;
+ }
+ btrfs_release_path(path);
+ args.nr = 0;
+ }
+
+ ret = log_one_extent(trans, inode, root, em, path, dst_path, &args);
+ free_extent_map(em);
+ write_lock(&tree->lock);
+ }
+ WARN_ON(!list_empty(&extents));
+ write_unlock(&tree->lock);
+
+ if (!ret && args.nr)
+ ret = copy_items(trans, inode, dst_path, args.src,
+ args.start_slot, args.nr, LOG_INODE_ALL);
+ btrfs_release_path(path);
+ return ret;
+}
+
/* log a single inode in the tree log.
* At least one parent directory for this inode must exist in the tree
* or be logged already.
@@ -2832,6 +3378,7 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans,
int nritems;
int ins_start_slot = 0;
int ins_nr;
+ bool fast_search = false;
u64 ino = btrfs_ino(inode);
log = root->log_root;
@@ -2851,21 +3398,23 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans,
max_key.objectid = ino;
- /* today the code can only do partial logging of directories */
- if (!S_ISDIR(inode->i_mode))
- inode_only = LOG_INODE_ALL;
+ /* today the code can only do partial logging of directories */
if (inode_only == LOG_INODE_EXISTS || S_ISDIR(inode->i_mode))
max_key.type = BTRFS_XATTR_ITEM_KEY;
else
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;
+ /* Only run delayed items if we are a dir or a new file */
+ if (S_ISDIR(inode->i_mode) ||
+ BTRFS_I(inode)->generation > root->fs_info->last_trans_committed) {
+ 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);
@@ -2881,7 +3430,16 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans,
max_key_type = BTRFS_XATTR_ITEM_KEY;
ret = drop_objectid_items(trans, log, path, ino, max_key_type);
} else {
- ret = btrfs_truncate_inode_items(trans, log, inode, 0, 0);
+ if (test_and_clear_bit(BTRFS_INODE_NEEDS_FULL_SYNC,
+ &BTRFS_I(inode)->runtime_flags)) {
+ ret = btrfs_truncate_inode_items(trans, log,
+ inode, 0, 0);
+ } else {
+ fast_search = true;
+ max_key.type = BTRFS_XATTR_ITEM_KEY;
+ ret = drop_objectid_items(trans, log, path, ino,
+ BTRFS_XATTR_ITEM_KEY);
+ }
}
if (ret) {
err = ret;
@@ -2912,7 +3470,7 @@ again:
goto next_slot;
}
- ret = copy_items(trans, log, dst_path, src, ins_start_slot,
+ ret = copy_items(trans, inode, dst_path, src, ins_start_slot,
ins_nr, inode_only);
if (ret) {
err = ret;
@@ -2930,7 +3488,7 @@ next_slot:
goto again;
}
if (ins_nr) {
- ret = copy_items(trans, log, dst_path, src,
+ ret = copy_items(trans, inode, dst_path, src,
ins_start_slot,
ins_nr, inode_only);
if (ret) {
@@ -2951,8 +3509,7 @@ next_slot:
break;
}
if (ins_nr) {
- ret = copy_items(trans, log, dst_path, src,
- ins_start_slot,
+ ret = copy_items(trans, inode, dst_path, src, ins_start_slot,
ins_nr, inode_only);
if (ret) {
err = ret;
@@ -2960,7 +3517,24 @@ next_slot:
}
ins_nr = 0;
}
- WARN_ON(ins_nr);
+
+ if (fast_search) {
+ btrfs_release_path(path);
+ btrfs_release_path(dst_path);
+ ret = btrfs_log_changed_extents(trans, root, inode, path,
+ dst_path);
+ if (ret) {
+ err = ret;
+ goto out_unlock;
+ }
+ } else {
+ struct extent_map_tree *tree = &BTRFS_I(inode)->extent_tree;
+ struct extent_map *em, *n;
+
+ list_for_each_entry_safe(em, n, &tree->modified_extents, list)
+ list_del_init(&em->list);
+ }
+
if (inode_only == LOG_INODE_ALL && S_ISDIR(inode->i_mode)) {
btrfs_release_path(path);
btrfs_release_path(dst_path);
@@ -2971,6 +3545,7 @@ next_slot:
}
}
BTRFS_I(inode)->logged_trans = trans->transid;
+ BTRFS_I(inode)->last_log_commit = BTRFS_I(inode)->last_sub_trans;
out_unlock:
mutex_unlock(&BTRFS_I(inode)->log_mutex);
@@ -3138,7 +3713,7 @@ int btrfs_log_inode_parent(struct btrfs_trans_handle *trans,
end_trans:
dput(old_parent);
if (ret < 0) {
- BUG_ON(ret != -ENOSPC);
+ WARN_ON(ret != -ENOSPC);
root->fs_info->last_trans_log_full_commit = trans->transid;
ret = 1;
}
diff --git a/fs/btrfs/ulist.c b/fs/btrfs/ulist.c
index ab942f4..99be4c1 100644
--- a/fs/btrfs/ulist.c
+++ b/fs/btrfs/ulist.c
@@ -143,14 +143,13 @@ EXPORT_SYMBOL(ulist_free);
* In case of allocation failure -ENOMEM is returned and the ulist stays
* unaltered.
*/
-int ulist_add(struct ulist *ulist, u64 val, unsigned long aux,
- gfp_t gfp_mask)
+int ulist_add(struct ulist *ulist, u64 val, u64 aux, gfp_t gfp_mask)
{
return ulist_add_merge(ulist, val, aux, NULL, gfp_mask);
}
-int ulist_add_merge(struct ulist *ulist, u64 val, unsigned long aux,
- unsigned long *old_aux, gfp_t gfp_mask)
+int ulist_add_merge(struct ulist *ulist, u64 val, u64 aux,
+ u64 *old_aux, gfp_t gfp_mask)
{
int i;
diff --git a/fs/btrfs/ulist.h b/fs/btrfs/ulist.h
index 21bdc8e..21a1963 100644
--- a/fs/btrfs/ulist.h
+++ b/fs/btrfs/ulist.h
@@ -33,7 +33,7 @@ struct ulist_iterator {
*/
struct ulist_node {
u64 val; /* value to store */
- unsigned long aux; /* auxiliary value saved along with the val */
+ u64 aux; /* auxiliary value saved along with the val */
};
struct ulist {
@@ -65,10 +65,9 @@ void ulist_fini(struct ulist *ulist);
void ulist_reinit(struct ulist *ulist);
struct ulist *ulist_alloc(gfp_t gfp_mask);
void ulist_free(struct ulist *ulist);
-int ulist_add(struct ulist *ulist, u64 val, unsigned long aux,
- gfp_t gfp_mask);
-int ulist_add_merge(struct ulist *ulist, u64 val, unsigned long aux,
- unsigned long *old_aux, gfp_t gfp_mask);
+int ulist_add(struct ulist *ulist, u64 val, u64 aux, gfp_t gfp_mask);
+int ulist_add_merge(struct ulist *ulist, u64 val, u64 aux,
+ u64 *old_aux, gfp_t gfp_mask);
struct ulist_node *ulist_next(struct ulist *ulist,
struct ulist_iterator *uiter);
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index 88b969a..029b903 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -639,7 +639,7 @@ static int __btrfs_open_devices(struct btrfs_fs_devices *fs_devices,
bdev = blkdev_get_by_path(device->name->str, flags, holder);
if (IS_ERR(bdev)) {
- printk(KERN_INFO "open %s failed\n", device->name->str);
+ printk(KERN_INFO "btrfs: open %s failed\n", device->name->str);
goto error;
}
filemap_write_and_wait(bdev->bd_inode->i_mapping);
@@ -1475,6 +1475,9 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path)
free_fs_devices(cur_devices);
}
+ root->fs_info->num_tolerated_disk_barrier_failures =
+ btrfs_calc_num_tolerated_disk_barrier_failures(root->fs_info);
+
/*
* at this point, the device is zero sized. We want to
* remove it from the devices list and zero out the old super
@@ -1775,15 +1778,21 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path)
if (seeding_dev) {
ret = init_first_rw_device(trans, root, device);
- if (ret)
+ if (ret) {
+ btrfs_abort_transaction(trans, root, ret);
goto error_trans;
+ }
ret = btrfs_finish_sprout(trans, root);
- if (ret)
+ if (ret) {
+ btrfs_abort_transaction(trans, root, ret);
goto error_trans;
+ }
} else {
ret = btrfs_add_device(trans, root, device);
- if (ret)
+ if (ret) {
+ btrfs_abort_transaction(trans, root, ret);
goto error_trans;
+ }
}
/*
@@ -1793,6 +1802,8 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path)
btrfs_clear_space_info_full(root->fs_info);
unlock_chunks(root);
+ root->fs_info->num_tolerated_disk_barrier_failures =
+ btrfs_calc_num_tolerated_disk_barrier_failures(root->fs_info);
ret = btrfs_commit_transaction(trans, root);
if (seeding_dev) {
@@ -1814,7 +1825,6 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path)
error_trans:
unlock_chunks(root);
- btrfs_abort_transaction(trans, root, ret);
btrfs_end_transaction(trans, root);
rcu_string_free(device->name);
kfree(device);
@@ -2804,6 +2814,26 @@ int btrfs_balance(struct btrfs_balance_control *bctl,
}
}
+ if (bctl->sys.flags & BTRFS_BALANCE_ARGS_CONVERT) {
+ int num_tolerated_disk_barrier_failures;
+ u64 target = bctl->sys.target;
+
+ num_tolerated_disk_barrier_failures =
+ btrfs_calc_num_tolerated_disk_barrier_failures(fs_info);
+ if (num_tolerated_disk_barrier_failures > 0 &&
+ (target &
+ (BTRFS_BLOCK_GROUP_DUP | BTRFS_BLOCK_GROUP_RAID0 |
+ BTRFS_AVAIL_ALLOC_BIT_SINGLE)))
+ num_tolerated_disk_barrier_failures = 0;
+ else if (num_tolerated_disk_barrier_failures > 1 &&
+ (target &
+ (BTRFS_BLOCK_GROUP_RAID1 | BTRFS_BLOCK_GROUP_RAID10)))
+ num_tolerated_disk_barrier_failures = 1;
+
+ fs_info->num_tolerated_disk_barrier_failures =
+ num_tolerated_disk_barrier_failures;
+ }
+
ret = insert_balance_item(fs_info->tree_root, bctl);
if (ret && ret != -EEXIST)
goto out;
@@ -2836,6 +2866,11 @@ int btrfs_balance(struct btrfs_balance_control *bctl,
__cancel_balance(fs_info);
}
+ if (bctl->sys.flags & BTRFS_BALANCE_ARGS_CONVERT) {
+ fs_info->num_tolerated_disk_barrier_failures =
+ btrfs_calc_num_tolerated_disk_barrier_failures(fs_info);
+ }
+
wake_up(&fs_info->balance_wait_q);
return ret;
@@ -3608,12 +3643,16 @@ static noinline int init_first_rw_device(struct btrfs_trans_handle *trans,
ret = __btrfs_alloc_chunk(trans, extent_root, &sys_map,
&sys_chunk_size, &sys_stripe_size,
sys_chunk_offset, alloc_profile);
- if (ret)
- goto abort;
+ if (ret) {
+ btrfs_abort_transaction(trans, root, ret);
+ goto out;
+ }
ret = btrfs_add_device(trans, fs_info->chunk_root, device);
- if (ret)
- goto abort;
+ if (ret) {
+ btrfs_abort_transaction(trans, root, ret);
+ goto out;
+ }
/*
* Modifying chunk tree needs allocating new blocks from both
@@ -3623,19 +3662,19 @@ static noinline int init_first_rw_device(struct btrfs_trans_handle *trans,
*/
ret = __finish_chunk_alloc(trans, extent_root, map, chunk_offset,
chunk_size, stripe_size);
- if (ret)
- goto abort;
+ if (ret) {
+ btrfs_abort_transaction(trans, root, ret);
+ goto out;
+ }
ret = __finish_chunk_alloc(trans, extent_root, sys_map,
sys_chunk_offset, sys_chunk_size,
sys_stripe_size);
if (ret)
- goto abort;
+ btrfs_abort_transaction(trans, root, ret);
- return 0;
+out:
-abort:
- btrfs_abort_transaction(trans, root, ret);
return ret;
}
@@ -3760,7 +3799,7 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,
read_unlock(&em_tree->lock);
if (!em) {
- printk(KERN_CRIT "unable to find logical %llu len %llu\n",
+ printk(KERN_CRIT "btrfs: unable to find logical %llu len %llu\n",
(unsigned long long)logical,
(unsigned long long)*length);
BUG();
@@ -4217,7 +4256,7 @@ int btrfs_map_bio(struct btrfs_root *root, int rw, struct bio *bio,
total_devs = bbio->num_stripes;
if (map_length < length) {
- printk(KERN_CRIT "mapping failed logical %llu bio len %llu "
+ printk(KERN_CRIT "btrfs: mapping failed logical %llu bio len %llu "
"len %llu\n", (unsigned long long)logical,
(unsigned long long)length,
(unsigned long long)map_length);
diff --git a/fs/btrfs/zlib.c b/fs/btrfs/zlib.c
index 92c2065..9acb846 100644
--- a/fs/btrfs/zlib.c
+++ b/fs/btrfs/zlib.c
@@ -97,7 +97,7 @@ static int zlib_compress_pages(struct list_head *ws,
*total_in = 0;
if (Z_OK != zlib_deflateInit(&workspace->def_strm, 3)) {
- printk(KERN_WARNING "deflateInit failed\n");
+ printk(KERN_WARNING "btrfs: deflateInit failed\n");
ret = -1;
goto out;
}
@@ -125,7 +125,7 @@ static int zlib_compress_pages(struct list_head *ws,
while (workspace->def_strm.total_in < len) {
ret = zlib_deflate(&workspace->def_strm, Z_SYNC_FLUSH);
if (ret != Z_OK) {
- printk(KERN_DEBUG "btrfs deflate in loop returned %d\n",
+ printk(KERN_DEBUG "btrfs: deflate in loop returned %d\n",
ret);
zlib_deflateEnd(&workspace->def_strm);
ret = -1;
@@ -252,7 +252,7 @@ static int zlib_decompress_biovec(struct list_head *ws, struct page **pages_in,
}
if (Z_OK != zlib_inflateInit2(&workspace->inf_strm, wbits)) {
- printk(KERN_WARNING "inflateInit failed\n");
+ printk(KERN_WARNING "btrfs: inflateInit failed\n");
return -1;
}
while (workspace->inf_strm.total_in < srclen) {
@@ -336,7 +336,7 @@ static int zlib_decompress(struct list_head *ws, unsigned char *data_in,
}
if (Z_OK != zlib_inflateInit2(&workspace->inf_strm, wbits)) {
- printk(KERN_WARNING "inflateInit failed\n");
+ printk(KERN_WARNING "btrfs: inflateInit failed\n");
return -1;
}
diff --git a/fs/cifs/cifs_unicode.c b/fs/cifs/cifs_unicode.c
index 53cf2aa..71d5d0a 100644
--- a/fs/cifs/cifs_unicode.c
+++ b/fs/cifs/cifs_unicode.c
@@ -203,6 +203,27 @@ cifs_strtoUTF16(__le16 *to, const char *from, int len,
int i;
wchar_t wchar_to; /* needed to quiet sparse */
+ /* special case for utf8 to handle no plane0 chars */
+ if (!strcmp(codepage->charset, "utf8")) {
+ /*
+ * convert utf8 -> utf16, we assume we have enough space
+ * as caller should have assumed conversion does not overflow
+ * in destination len is length in wchar_t units (16bits)
+ */
+ i = utf8s_to_utf16s(from, len, UTF16_LITTLE_ENDIAN,
+ (wchar_t *) to, len);
+
+ /* if success terminate and exit */
+ if (i >= 0)
+ goto success;
+ /*
+ * if fails fall back to UCS encoding as this
+ * function should not return negative values
+ * currently can fail only if source contains
+ * invalid encoded characters
+ */
+ }
+
for (i = 0; len && *from; i++, from += charlen, len -= charlen) {
charlen = codepage->char2uni(from, len, &wchar_to);
if (charlen < 1) {
@@ -215,6 +236,7 @@ cifs_strtoUTF16(__le16 *to, const char *from, int len,
put_unaligned_le16(wchar_to, &to[i]);
}
+success:
put_unaligned_le16(0, &to[i]);
return i;
}
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 2fdbe08..5c670b9 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -67,6 +67,7 @@ enum {
/* Mount options that take no arguments */
Opt_user_xattr, Opt_nouser_xattr,
Opt_forceuid, Opt_noforceuid,
+ Opt_forcegid, Opt_noforcegid,
Opt_noblocksend, Opt_noautotune,
Opt_hard, Opt_soft, Opt_perm, Opt_noperm,
Opt_mapchars, Opt_nomapchars, Opt_sfu,
@@ -117,6 +118,8 @@ static const match_table_t cifs_mount_option_tokens = {
{ Opt_nouser_xattr, "nouser_xattr" },
{ Opt_forceuid, "forceuid" },
{ Opt_noforceuid, "noforceuid" },
+ { Opt_forcegid, "forcegid" },
+ { Opt_noforcegid, "noforcegid" },
{ Opt_noblocksend, "noblocksend" },
{ Opt_noautotune, "noautotune" },
{ Opt_hard, "hard" },
@@ -1195,6 +1198,12 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
case Opt_noforceuid:
override_uid = 0;
break;
+ case Opt_forcegid:
+ override_gid = 1;
+ break;
+ case Opt_noforcegid:
+ override_gid = 0;
+ break;
case Opt_noblocksend:
vol->noblocksnd = 1;
break;
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
index 2126ab1..76d974c 100644
--- a/fs/cifs/transport.c
+++ b/fs/cifs/transport.c
@@ -183,6 +183,12 @@ smb_send_kvec(struct TCP_Server_Info *server, struct kvec *iov, size_t n_vec,
rc = kernel_sendmsg(ssocket, &smb_msg, &iov[first_vec],
n_vec - first_vec, remaining);
if (rc == -ENOSPC || rc == -EAGAIN) {
+ /*
+ * Catch if a low level driver returns -ENOSPC. This
+ * WARN_ON will be removed by 3.10 if no one reports
+ * seeing this.
+ */
+ WARN_ON_ONCE(rc == -ENOSPC);
i++;
if (i >= 14 || (!server->noblocksnd && (i > 2))) {
cERROR(1, "sends on sock %p stuck for 15 "
diff --git a/fs/exec.c b/fs/exec.c
index 4f2bebc..ca43453 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -59,7 +59,6 @@
#include <asm/uaccess.h>
#include <asm/mmu_context.h>
#include <asm/tlb.h>
-#include <asm/exec.h>
#include <trace/events/task.h>
#include "internal.h"
@@ -392,7 +391,7 @@ struct user_arg_ptr {
union {
const char __user *const __user *native;
#ifdef CONFIG_COMPAT
- compat_uptr_t __user *compat;
+ const compat_uptr_t __user *compat;
#endif
} ptr;
};
@@ -1574,9 +1573,9 @@ int do_execve(const char *filename,
}
#ifdef CONFIG_COMPAT
-int compat_do_execve(char *filename,
- compat_uptr_t __user *__argv,
- compat_uptr_t __user *__envp,
+int compat_do_execve(const char *filename,
+ const compat_uptr_t __user *__argv,
+ const compat_uptr_t __user *__envp,
struct pt_regs *regs)
{
struct user_arg_ptr argv = {
@@ -1658,3 +1657,55 @@ int get_dumpable(struct mm_struct *mm)
{
return __get_dumpable(mm->flags);
}
+
+#ifdef __ARCH_WANT_SYS_EXECVE
+SYSCALL_DEFINE3(execve,
+ const char __user *, filename,
+ const char __user *const __user *, argv,
+ const char __user *const __user *, envp)
+{
+ const char *path = getname(filename);
+ int error = PTR_ERR(path);
+ if (!IS_ERR(path)) {
+ error = do_execve(path, argv, envp, current_pt_regs());
+ putname(path);
+ }
+ return error;
+}
+#ifdef CONFIG_COMPAT
+asmlinkage long compat_sys_execve(const char __user * filename,
+ const compat_uptr_t __user * argv,
+ const compat_uptr_t __user * envp)
+{
+ const char *path = getname(filename);
+ int error = PTR_ERR(path);
+ if (!IS_ERR(path)) {
+ error = compat_do_execve(path, argv, envp, current_pt_regs());
+ putname(path);
+ }
+ return error;
+}
+#endif
+#endif
+
+#ifdef __ARCH_WANT_KERNEL_EXECVE
+int kernel_execve(const char *filename,
+ const char *const argv[],
+ const char *const envp[])
+{
+ struct pt_regs *p = current_pt_regs();
+ int ret;
+
+ ret = do_execve(filename,
+ (const char __user *const __user *)argv,
+ (const char __user *const __user *)envp, p);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * We were successful. We won't be returning to our caller, but
+ * instead to user space by manipulating the kernel stack.
+ */
+ ret_from_kernel_execve(p);
+}
+#endif
diff --git a/fs/exofs/ore.c b/fs/exofs/ore.c
index 1585db1..f936cb5 100644
--- a/fs/exofs/ore.c
+++ b/fs/exofs/ore.c
@@ -814,8 +814,8 @@ static int _write_mirror(struct ore_io_state *ios, int cur_comp)
struct bio *bio;
if (per_dev != master_dev) {
- bio = bio_kmalloc(GFP_KERNEL,
- master_dev->bio->bi_max_vecs);
+ bio = bio_clone_kmalloc(master_dev->bio,
+ GFP_KERNEL);
if (unlikely(!bio)) {
ORE_DBGMSG(
"Failed to allocate BIO size=%u\n",
@@ -824,7 +824,6 @@ static int _write_mirror(struct ore_io_state *ios, int cur_comp)
goto out;
}
- __bio_clone(bio, master_dev->bio);
bio->bi_bdev = NULL;
bio->bi_next = NULL;
per_dev->offset = master_dev->offset;
diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c
index 401b6c6..51ea267 100644
--- a/fs/fs-writeback.c
+++ b/fs/fs-writeback.c
@@ -249,7 +249,7 @@ static bool inode_dirtied_after(struct inode *inode, unsigned long t)
}
/*
- * Move expired (dirtied after work->older_than_this) dirty inodes from
+ * Move expired (dirtied before work->older_than_this) dirty inodes from
* @delaying_queue to @dispatch_queue.
*/
static int move_expired_inodes(struct list_head *delaying_queue,
diff --git a/fs/hostfs/hostfs.h b/fs/hostfs/hostfs.h
index 1fe7313..9c88da0 100644
--- a/fs/hostfs/hostfs.h
+++ b/fs/hostfs/hostfs.h
@@ -1,7 +1,7 @@
#ifndef __UM_FS_HOSTFS
#define __UM_FS_HOSTFS
-#include "os.h"
+#include <os.h>
/*
* These are exactly the same definitions as in fs.h, but the names are
diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c
index 6c9f3a9..457addc 100644
--- a/fs/hostfs/hostfs_kern.c
+++ b/fs/hostfs/hostfs_kern.c
@@ -16,8 +16,8 @@
#include <linux/mount.h>
#include <linux/namei.h>
#include "hostfs.h"
-#include "init.h"
-#include "kern.h"
+#include <init.h>
+#include <kern.h>
struct hostfs_inode_info {
int fd;
@@ -848,9 +848,11 @@ int hostfs_setattr(struct dentry *dentry, struct iattr *attr)
attr->ia_size != i_size_read(inode)) {
int error;
- error = vmtruncate(inode, attr->ia_size);
- if (err)
- return err;
+ error = inode_newsize_ok(inode, attr->ia_size);
+ if (error)
+ return error;
+
+ truncate_setsize(inode, attr->ia_size);
}
setattr_copy(inode, attr);
diff --git a/fs/hostfs/hostfs_user.c b/fs/hostfs/hostfs_user.c
index a74ad0d..67838f3 100644
--- a/fs/hostfs/hostfs_user.c
+++ b/fs/hostfs/hostfs_user.c
@@ -15,7 +15,6 @@
#include <sys/types.h>
#include <sys/vfs.h>
#include "hostfs.h"
-#include "os.h"
#include <utime.h>
static void stat64_to_hostfs(const struct stat64 *buf, struct hostfs_stat *p)
diff --git a/fs/hppfs/hppfs.c b/fs/hppfs/hppfs.c
index c1dffe4..78f21f8 100644
--- a/fs/hppfs/hppfs.c
+++ b/fs/hppfs/hppfs.c
@@ -18,7 +18,7 @@
#include <linux/pid_namespace.h>
#include <linux/namei.h>
#include <asm/uaccess.h>
-#include "os.h"
+#include <os.h>
static struct inode *get_inode(struct super_block *, struct dentry *);
@@ -674,7 +674,7 @@ static struct inode *get_inode(struct super_block *sb, struct dentry *dentry)
if (!inode) {
dput(dentry);
- return ERR_PTR(-ENOMEM);
+ return NULL;
}
if (S_ISDIR(dentry->d_inode->i_mode)) {
diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c
index ff48795..d3d8799 100644
--- a/fs/jffs2/super.c
+++ b/fs/jffs2/super.c
@@ -100,6 +100,10 @@ static int jffs2_sync_fs(struct super_block *sb, int wait)
{
struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
+#ifdef CONFIG_JFFS2_FS_WRITEBUFFER
+ cancel_delayed_work_sync(&c->wbuf_dwork);
+#endif
+
mutex_lock(&c->alloc_sem);
jffs2_flush_wbuf_pad(c);
mutex_unlock(&c->alloc_sem);
diff --git a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c
index 6f4529d..a6597d6 100644
--- a/fs/jffs2/wbuf.c
+++ b/fs/jffs2/wbuf.c
@@ -1044,10 +1044,10 @@ int jffs2_check_oob_empty(struct jffs2_sb_info *c,
ops.datbuf = NULL;
ret = mtd_read_oob(c->mtd, jeb->offset, &ops);
- if (ret || ops.oobretlen != ops.ooblen) {
+ if ((ret && !mtd_is_bitflip(ret)) || ops.oobretlen != ops.ooblen) {
pr_err("cannot read OOB for EB at %08x, requested %zd bytes, read %zd bytes, error %d\n",
jeb->offset, ops.ooblen, ops.oobretlen, ret);
- if (!ret)
+ if (!ret || mtd_is_bitflip(ret))
ret = -EIO;
return ret;
}
@@ -1086,10 +1086,10 @@ int jffs2_check_nand_cleanmarker(struct jffs2_sb_info *c,
ops.datbuf = NULL;
ret = mtd_read_oob(c->mtd, jeb->offset, &ops);
- if (ret || ops.oobretlen != ops.ooblen) {
+ if ((ret && !mtd_is_bitflip(ret)) || ops.oobretlen != ops.ooblen) {
pr_err("cannot read OOB for EB at %08x, requested %zd bytes, read %zd bytes, error %d\n",
jeb->offset, ops.ooblen, ops.oobretlen, ret);
- if (!ret)
+ if (!ret || mtd_is_bitflip(ret))
ret = -EIO;
return ret;
}
diff --git a/fs/lockd/mon.c b/fs/lockd/mon.c
index 7ef14b3..e4fb3ba 100644
--- a/fs/lockd/mon.c
+++ b/fs/lockd/mon.c
@@ -7,7 +7,6 @@
*/
#include <linux/types.h>
-#include <linux/utsname.h>
#include <linux/kernel.h>
#include <linux/ktime.h>
#include <linux/slab.h>
@@ -19,6 +18,8 @@
#include <asm/unaligned.h>
+#include "netns.h"
+
#define NLMDBG_FACILITY NLMDBG_MONITOR
#define NSM_PROGRAM 100024
#define NSM_VERSION 1
@@ -40,6 +41,7 @@ struct nsm_args {
u32 proc;
char *mon_name;
+ char *nodename;
};
struct nsm_res {
@@ -70,7 +72,7 @@ static struct rpc_clnt *nsm_create(struct net *net)
};
struct rpc_create_args args = {
.net = net,
- .protocol = XPRT_TRANSPORT_UDP,
+ .protocol = XPRT_TRANSPORT_TCP,
.address = (struct sockaddr *)&sin,
.addrsize = sizeof(sin),
.servername = "rpc.statd",
@@ -83,10 +85,54 @@ static struct rpc_clnt *nsm_create(struct net *net)
return rpc_create(&args);
}
-static int nsm_mon_unmon(struct nsm_handle *nsm, u32 proc, struct nsm_res *res,
- struct net *net)
+static struct rpc_clnt *nsm_client_get(struct net *net)
{
+ static DEFINE_MUTEX(nsm_create_mutex);
struct rpc_clnt *clnt;
+ struct lockd_net *ln = net_generic(net, lockd_net_id);
+
+ spin_lock(&ln->nsm_clnt_lock);
+ if (ln->nsm_users) {
+ ln->nsm_users++;
+ clnt = ln->nsm_clnt;
+ spin_unlock(&ln->nsm_clnt_lock);
+ goto out;
+ }
+ spin_unlock(&ln->nsm_clnt_lock);
+
+ mutex_lock(&nsm_create_mutex);
+ clnt = nsm_create(net);
+ if (!IS_ERR(clnt)) {
+ ln->nsm_clnt = clnt;
+ smp_wmb();
+ ln->nsm_users = 1;
+ }
+ mutex_unlock(&nsm_create_mutex);
+out:
+ return clnt;
+}
+
+static void nsm_client_put(struct net *net)
+{
+ struct lockd_net *ln = net_generic(net, lockd_net_id);
+ struct rpc_clnt *clnt = ln->nsm_clnt;
+ int shutdown = 0;
+
+ spin_lock(&ln->nsm_clnt_lock);
+ if (ln->nsm_users) {
+ if (--ln->nsm_users)
+ ln->nsm_clnt = NULL;
+ shutdown = !ln->nsm_users;
+ }
+ spin_unlock(&ln->nsm_clnt_lock);
+
+ if (shutdown)
+ rpc_shutdown_client(clnt);
+}
+
+static int nsm_mon_unmon(struct nsm_handle *nsm, u32 proc, struct nsm_res *res,
+ struct rpc_clnt *clnt)
+{
int status;
struct nsm_args args = {
.priv = &nsm->sm_priv,
@@ -94,31 +140,24 @@ static int nsm_mon_unmon(struct nsm_handle *nsm, u32 proc, struct nsm_res *res,
.vers = 3,
.proc = NLMPROC_NSM_NOTIFY,
.mon_name = nsm->sm_mon_name,
+ .nodename = clnt->cl_nodename,
};
struct rpc_message msg = {
.rpc_argp = &args,
.rpc_resp = res,
};
- clnt = nsm_create(net);
- if (IS_ERR(clnt)) {
- status = PTR_ERR(clnt);
- dprintk("lockd: failed to create NSM upcall transport, "
- "status=%d\n", status);
- goto out;
- }
+ BUG_ON(clnt == NULL);
memset(res, 0, sizeof(*res));
msg.rpc_proc = &clnt->cl_procinfo[proc];
- status = rpc_call_sync(clnt, &msg, 0);
+ status = rpc_call_sync(clnt, &msg, RPC_TASK_SOFTCONN);
if (status < 0)
dprintk("lockd: NSM upcall RPC failed, status=%d\n",
status);
else
status = 0;
- rpc_shutdown_client(clnt);
- out:
return status;
}
@@ -138,6 +177,7 @@ int nsm_monitor(const struct nlm_host *host)
struct nsm_handle *nsm = host->h_nsmhandle;
struct nsm_res res;
int status;
+ struct rpc_clnt *clnt;
dprintk("lockd: nsm_monitor(%s)\n", nsm->sm_name);
@@ -150,7 +190,15 @@ int nsm_monitor(const struct nlm_host *host)
*/
nsm->sm_mon_name = nsm_use_hostnames ? nsm->sm_name : nsm->sm_addrbuf;
- status = nsm_mon_unmon(nsm, NSMPROC_MON, &res, host->net);
+ clnt = nsm_client_get(host->net);
+ if (IS_ERR(clnt)) {
+ status = PTR_ERR(clnt);
+ dprintk("lockd: failed to create NSM upcall transport, "
+ "status=%d, net=%p\n", status, host->net);
+ return status;
+ }
+
+ status = nsm_mon_unmon(nsm, NSMPROC_MON, &res, clnt);
if (unlikely(res.status != 0))
status = -EIO;
if (unlikely(status < 0)) {
@@ -182,9 +230,11 @@ void nsm_unmonitor(const struct nlm_host *host)
if (atomic_read(&nsm->sm_count) == 1
&& nsm->sm_monitored && !nsm->sm_sticky) {
+ struct lockd_net *ln = net_generic(host->net, lockd_net_id);
+
dprintk("lockd: nsm_unmonitor(%s)\n", nsm->sm_name);
- status = nsm_mon_unmon(nsm, NSMPROC_UNMON, &res, host->net);
+ status = nsm_mon_unmon(nsm, NSMPROC_UNMON, &res, ln->nsm_clnt);
if (res.status != 0)
status = -EIO;
if (status < 0)
@@ -192,6 +242,8 @@ void nsm_unmonitor(const struct nlm_host *host)
nsm->sm_name);
else
nsm->sm_monitored = 0;
+
+ nsm_client_put(host->net);
}
}
@@ -430,7 +482,7 @@ static void encode_my_id(struct xdr_stream *xdr, const struct nsm_args *argp)
{
__be32 *p;
- encode_nsm_string(xdr, utsname()->nodename);
+ encode_nsm_string(xdr, argp->nodename);
p = xdr_reserve_space(xdr, 4 + 4 + 4);
*p++ = cpu_to_be32(argp->prog);
*p++ = cpu_to_be32(argp->vers);
diff --git a/fs/lockd/netns.h b/fs/lockd/netns.h
index 4eee248..5010b55 100644
--- a/fs/lockd/netns.h
+++ b/fs/lockd/netns.h
@@ -12,6 +12,10 @@ struct lockd_net {
struct delayed_work grace_period_end;
struct lock_manager lockd_manager;
struct list_head grace_list;
+
+ spinlock_t nsm_clnt_lock;
+ unsigned int nsm_users;
+ struct rpc_clnt *nsm_clnt;
};
extern int lockd_net_id;
diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c
index 31a63f8..7e35587 100644
--- a/fs/lockd/svc.c
+++ b/fs/lockd/svc.c
@@ -596,6 +596,7 @@ static int lockd_init_net(struct net *net)
INIT_DELAYED_WORK(&ln->grace_period_end, grace_ender);
INIT_LIST_HEAD(&ln->grace_list);
+ spin_lock_init(&ln->nsm_clnt_lock);
return 0;
}
diff --git a/fs/nfs/Kconfig b/fs/nfs/Kconfig
index db7ad719..13ca196 100644
--- a/fs/nfs/Kconfig
+++ b/fs/nfs/Kconfig
@@ -95,8 +95,8 @@ config NFS_SWAP
This option enables swapon to work on files located on NFS mounts.
config NFS_V4_1
- bool "NFS client support for NFSv4.1 (EXPERIMENTAL)"
- depends on NFS_V4 && EXPERIMENTAL
+ bool "NFS client support for NFSv4.1"
+ depends on NFS_V4
select SUNRPC_BACKCHANNEL
help
This option enables support for minor version 1 of the NFSv4 protocol
diff --git a/fs/nfs/blocklayout/blocklayout.c b/fs/nfs/blocklayout/blocklayout.c
index dd392ed..f1027b0 100644
--- a/fs/nfs/blocklayout/blocklayout.c
+++ b/fs/nfs/blocklayout/blocklayout.c
@@ -37,6 +37,7 @@
#include <linux/bio.h> /* struct bio */
#include <linux/buffer_head.h> /* various write calls */
#include <linux/prefetch.h>
+#include <linux/pagevec.h>
#include "../pnfs.h"
#include "../internal.h"
@@ -162,25 +163,39 @@ static struct bio *bl_alloc_init_bio(int npg, sector_t isect,
return bio;
}
-static struct bio *bl_add_page_to_bio(struct bio *bio, int npg, int rw,
+static struct bio *do_add_page_to_bio(struct bio *bio, int npg, int rw,
sector_t isect, struct page *page,
struct pnfs_block_extent *be,
void (*end_io)(struct bio *, int err),
- struct parallel_io *par)
+ struct parallel_io *par,
+ unsigned int offset, int len)
{
+ isect = isect + (offset >> SECTOR_SHIFT);
+ dprintk("%s: npg %d rw %d isect %llu offset %u len %d\n", __func__,
+ npg, rw, (unsigned long long)isect, offset, len);
retry:
if (!bio) {
bio = bl_alloc_init_bio(npg, isect, be, end_io, par);
if (!bio)
return ERR_PTR(-ENOMEM);
}
- if (bio_add_page(bio, page, PAGE_CACHE_SIZE, 0) < PAGE_CACHE_SIZE) {
+ if (bio_add_page(bio, page, len, offset) < len) {
bio = bl_submit_bio(rw, bio);
goto retry;
}
return bio;
}
+static struct bio *bl_add_page_to_bio(struct bio *bio, int npg, int rw,
+ sector_t isect, struct page *page,
+ struct pnfs_block_extent *be,
+ void (*end_io)(struct bio *, int err),
+ struct parallel_io *par)
+{
+ return do_add_page_to_bio(bio, npg, rw, isect, page, be,
+ end_io, par, 0, PAGE_CACHE_SIZE);
+}
+
/* This is basically copied from mpage_end_io_read */
static void bl_end_io_read(struct bio *bio, int err)
{
@@ -228,14 +243,6 @@ bl_end_par_io_read(void *data, int unused)
schedule_work(&rdata->task.u.tk_work);
}
-static bool
-bl_check_alignment(u64 offset, u32 len, unsigned long blkmask)
-{
- if ((offset & blkmask) || (len & blkmask))
- return false;
- return true;
-}
-
static enum pnfs_try_status
bl_read_pagelist(struct nfs_read_data *rdata)
{
@@ -246,15 +253,15 @@ bl_read_pagelist(struct nfs_read_data *rdata)
sector_t isect, extent_length = 0;
struct parallel_io *par;
loff_t f_offset = rdata->args.offset;
+ size_t bytes_left = rdata->args.count;
+ unsigned int pg_offset, pg_len;
struct page **pages = rdata->args.pages;
int pg_index = rdata->args.pgbase >> PAGE_CACHE_SHIFT;
+ const bool is_dio = (header->dreq != NULL);
dprintk("%s enter nr_pages %u offset %lld count %u\n", __func__,
rdata->pages.npages, f_offset, (unsigned int)rdata->args.count);
- if (!bl_check_alignment(f_offset, rdata->args.count, PAGE_CACHE_MASK))
- goto use_mds;
-
par = alloc_parallel(rdata);
if (!par)
goto use_mds;
@@ -284,36 +291,53 @@ bl_read_pagelist(struct nfs_read_data *rdata)
extent_length = min(extent_length, cow_length);
}
}
+
+ if (is_dio) {
+ pg_offset = f_offset & ~PAGE_CACHE_MASK;
+ if (pg_offset + bytes_left > PAGE_CACHE_SIZE)
+ pg_len = PAGE_CACHE_SIZE - pg_offset;
+ else
+ pg_len = bytes_left;
+
+ f_offset += pg_len;
+ bytes_left -= pg_len;
+ isect += (pg_offset >> SECTOR_SHIFT);
+ } else {
+ pg_offset = 0;
+ pg_len = PAGE_CACHE_SIZE;
+ }
+
hole = is_hole(be, isect);
if (hole && !cow_read) {
bio = bl_submit_bio(READ, bio);
/* Fill hole w/ zeroes w/o accessing device */
dprintk("%s Zeroing page for hole\n", __func__);
- zero_user_segment(pages[i], 0, PAGE_CACHE_SIZE);
+ zero_user_segment(pages[i], pg_offset, pg_len);
print_page(pages[i]);
SetPageUptodate(pages[i]);
} else {
struct pnfs_block_extent *be_read;
be_read = (hole && cow_read) ? cow_read : be;
- bio = bl_add_page_to_bio(bio, rdata->pages.npages - i,
+ bio = do_add_page_to_bio(bio, rdata->pages.npages - i,
READ,
isect, pages[i], be_read,
- bl_end_io_read, par);
+ bl_end_io_read, par,
+ pg_offset, pg_len);
if (IS_ERR(bio)) {
header->pnfs_error = PTR_ERR(bio);
bio = NULL;
goto out;
}
}
- isect += PAGE_CACHE_SECTORS;
+ isect += (pg_len >> SECTOR_SHIFT);
extent_length -= PAGE_CACHE_SECTORS;
}
if ((isect << SECTOR_SHIFT) >= header->inode->i_size) {
rdata->res.eof = 1;
- rdata->res.count = header->inode->i_size - f_offset;
+ rdata->res.count = header->inode->i_size - rdata->args.offset;
} else {
- rdata->res.count = (isect << SECTOR_SHIFT) - f_offset;
+ rdata->res.count = (isect << SECTOR_SHIFT) - rdata->args.offset;
}
out:
bl_put_extent(be);
@@ -461,6 +485,106 @@ map_block(struct buffer_head *bh, sector_t isect, struct pnfs_block_extent *be)
return;
}
+static void
+bl_read_single_end_io(struct bio *bio, int error)
+{
+ struct bio_vec *bvec = bio->bi_io_vec + bio->bi_vcnt - 1;
+ struct page *page = bvec->bv_page;
+
+ /* Only one page in bvec */
+ unlock_page(page);
+}
+
+static int
+bl_do_readpage_sync(struct page *page, struct pnfs_block_extent *be,
+ unsigned int offset, unsigned int len)
+{
+ struct bio *bio;
+ struct page *shadow_page;
+ sector_t isect;
+ char *kaddr, *kshadow_addr;
+ int ret = 0;
+
+ dprintk("%s: offset %u len %u\n", __func__, offset, len);
+
+ shadow_page = alloc_page(GFP_NOFS | __GFP_HIGHMEM);
+ if (shadow_page == NULL)
+ return -ENOMEM;
+
+ bio = bio_alloc(GFP_NOIO, 1);
+ if (bio == NULL)
+ return -ENOMEM;
+
+ isect = (page->index << PAGE_CACHE_SECTOR_SHIFT) +
+ (offset / SECTOR_SIZE);
+
+ bio->bi_sector = isect - be->be_f_offset + be->be_v_offset;
+ bio->bi_bdev = be->be_mdev;
+ bio->bi_end_io = bl_read_single_end_io;
+
+ lock_page(shadow_page);
+ if (bio_add_page(bio, shadow_page,
+ SECTOR_SIZE, round_down(offset, SECTOR_SIZE)) == 0) {
+ unlock_page(shadow_page);
+ bio_put(bio);
+ return -EIO;
+ }
+
+ submit_bio(READ, bio);
+ wait_on_page_locked(shadow_page);
+ if (unlikely(!test_bit(BIO_UPTODATE, &bio->bi_flags))) {
+ ret = -EIO;
+ } else {
+ kaddr = kmap_atomic(page);
+ kshadow_addr = kmap_atomic(shadow_page);
+ memcpy(kaddr + offset, kshadow_addr + offset, len);
+ kunmap_atomic(kshadow_addr);
+ kunmap_atomic(kaddr);
+ }
+ __free_page(shadow_page);
+ bio_put(bio);
+
+ return ret;
+}
+
+static int
+bl_read_partial_page_sync(struct page *page, struct pnfs_block_extent *be,
+ unsigned int dirty_offset, unsigned int dirty_len,
+ bool full_page)
+{
+ int ret = 0;
+ unsigned int start, end;
+
+ if (full_page) {
+ start = 0;
+ end = PAGE_CACHE_SIZE;
+ } else {
+ start = round_down(dirty_offset, SECTOR_SIZE);
+ end = round_up(dirty_offset + dirty_len, SECTOR_SIZE);
+ }
+
+ dprintk("%s: offset %u len %d\n", __func__, dirty_offset, dirty_len);
+ if (!be) {
+ zero_user_segments(page, start, dirty_offset,
+ dirty_offset + dirty_len, end);
+ if (start == 0 && end == PAGE_CACHE_SIZE &&
+ trylock_page(page)) {
+ SetPageUptodate(page);
+ unlock_page(page);
+ }
+ return ret;
+ }
+
+ if (start != dirty_offset)
+ ret = bl_do_readpage_sync(page, be, start, dirty_offset - start);
+
+ if (!ret && (dirty_offset + dirty_len < end))
+ ret = bl_do_readpage_sync(page, be, dirty_offset + dirty_len,
+ end - dirty_offset - dirty_len);
+
+ return ret;
+}
+
/* Given an unmapped page, zero it or read in page for COW, page is locked
* by caller.
*/
@@ -494,7 +618,6 @@ init_page_for_write(struct page *page, struct pnfs_block_extent *cow_read)
SetPageUptodate(page);
cleanup:
- bl_put_extent(cow_read);
if (bh)
free_buffer_head(bh);
if (ret) {
@@ -566,6 +689,7 @@ bl_write_pagelist(struct nfs_write_data *wdata, int sync)
struct parallel_io *par = NULL;
loff_t offset = wdata->args.offset;
size_t count = wdata->args.count;
+ unsigned int pg_offset, pg_len, saved_len;
struct page **pages = wdata->args.pages;
struct page *page;
pgoff_t index;
@@ -574,10 +698,13 @@ bl_write_pagelist(struct nfs_write_data *wdata, int sync)
NFS_SERVER(header->inode)->pnfs_blksize >> PAGE_CACHE_SHIFT;
dprintk("%s enter, %Zu@%lld\n", __func__, count, offset);
- /* Check for alignment first */
- if (!bl_check_alignment(offset, count, PAGE_CACHE_MASK))
- goto out_mds;
+ if (header->dreq != NULL &&
+ (!IS_ALIGNED(offset, NFS_SERVER(header->inode)->pnfs_blksize) ||
+ !IS_ALIGNED(count, NFS_SERVER(header->inode)->pnfs_blksize))) {
+ dprintk("pnfsblock nonblock aligned DIO writes. Resend MDS\n");
+ goto out_mds;
+ }
/* At this point, wdata->pages is a (sequential) list of nfs_pages.
* We want to write each, and if there is an error set pnfs_error
* to have it redone using nfs.
@@ -674,10 +801,11 @@ next_page:
if (!extent_length) {
/* We've used up the previous extent */
bl_put_extent(be);
+ bl_put_extent(cow_read);
bio = bl_submit_bio(WRITE, bio);
/* Get the next one */
be = bl_find_get_extent(BLK_LSEG2EXT(header->lseg),
- isect, NULL);
+ isect, &cow_read);
if (!be || !is_writable(be, isect)) {
header->pnfs_error = -EINVAL;
goto out;
@@ -694,7 +822,26 @@ next_page:
extent_length = be->be_length -
(isect - be->be_f_offset);
}
- if (be->be_state == PNFS_BLOCK_INVALID_DATA) {
+
+ dprintk("%s offset %lld count %Zu\n", __func__, offset, count);
+ pg_offset = offset & ~PAGE_CACHE_MASK;
+ if (pg_offset + count > PAGE_CACHE_SIZE)
+ pg_len = PAGE_CACHE_SIZE - pg_offset;
+ else
+ pg_len = count;
+
+ saved_len = pg_len;
+ if (be->be_state == PNFS_BLOCK_INVALID_DATA &&
+ !bl_is_sector_init(be->be_inval, isect)) {
+ ret = bl_read_partial_page_sync(pages[i], cow_read,
+ pg_offset, pg_len, true);
+ if (ret) {
+ dprintk("%s bl_read_partial_page_sync fail %d\n",
+ __func__, ret);
+ header->pnfs_error = ret;
+ goto out;
+ }
+
ret = bl_mark_sectors_init(be->be_inval, isect,
PAGE_CACHE_SECTORS);
if (unlikely(ret)) {
@@ -703,15 +850,35 @@ next_page:
header->pnfs_error = ret;
goto out;
}
+
+ /* Expand to full page write */
+ pg_offset = 0;
+ pg_len = PAGE_CACHE_SIZE;
+ } else if ((pg_offset & (SECTOR_SIZE - 1)) ||
+ (pg_len & (SECTOR_SIZE - 1))){
+ /* ahh, nasty case. We have to do sync full sector
+ * read-modify-write cycles.
+ */
+ unsigned int saved_offset = pg_offset;
+ ret = bl_read_partial_page_sync(pages[i], be, pg_offset,
+ pg_len, false);
+ pg_offset = round_down(pg_offset, SECTOR_SIZE);
+ pg_len = round_up(saved_offset + pg_len, SECTOR_SIZE)
+ - pg_offset;
}
- bio = bl_add_page_to_bio(bio, wdata->pages.npages - i, WRITE,
+
+
+ bio = do_add_page_to_bio(bio, wdata->pages.npages - i, WRITE,
isect, pages[i], be,
- bl_end_io_write, par);
+ bl_end_io_write, par,
+ pg_offset, pg_len);
if (IS_ERR(bio)) {
header->pnfs_error = PTR_ERR(bio);
bio = NULL;
goto out;
}
+ offset += saved_len;
+ count -= saved_len;
isect += PAGE_CACHE_SECTORS;
last_isect = isect;
extent_length -= PAGE_CACHE_SECTORS;
@@ -729,17 +896,16 @@ next_page:
}
write_done:
- wdata->res.count = (last_isect << SECTOR_SHIFT) - (offset);
- if (count < wdata->res.count) {
- wdata->res.count = count;
- }
+ wdata->res.count = wdata->args.count;
out:
bl_put_extent(be);
+ bl_put_extent(cow_read);
bl_submit_bio(WRITE, bio);
put_parallel(par);
return PNFS_ATTEMPTED;
out_mds:
bl_put_extent(be);
+ bl_put_extent(cow_read);
kfree(par);
return PNFS_NOT_ATTEMPTED;
}
@@ -874,7 +1040,7 @@ static void free_blk_mountid(struct block_mount_id *mid)
}
}
-/* This is mostly copied from the filelayout's get_device_info function.
+/* This is mostly copied from the filelayout_get_device_info function.
* It seems much of this should be at the generic pnfs level.
*/
static struct pnfs_block_dev *
@@ -1011,33 +1177,95 @@ bl_clear_layoutdriver(struct nfs_server *server)
return 0;
}
+static bool
+is_aligned_req(struct nfs_page *req, unsigned int alignment)
+{
+ return IS_ALIGNED(req->wb_offset, alignment) &&
+ IS_ALIGNED(req->wb_bytes, alignment);
+}
+
static void
bl_pg_init_read(struct nfs_pageio_descriptor *pgio, struct nfs_page *req)
{
- if (!bl_check_alignment(req->wb_offset, req->wb_bytes, PAGE_CACHE_MASK))
+ if (pgio->pg_dreq != NULL &&
+ !is_aligned_req(req, SECTOR_SIZE))
nfs_pageio_reset_read_mds(pgio);
else
pnfs_generic_pg_init_read(pgio, req);
}
+static bool
+bl_pg_test_read(struct nfs_pageio_descriptor *pgio, struct nfs_page *prev,
+ struct nfs_page *req)
+{
+ if (pgio->pg_dreq != NULL &&
+ !is_aligned_req(req, SECTOR_SIZE))
+ return false;
+
+ return pnfs_generic_pg_test(pgio, prev, req);
+}
+
+/*
+ * Return the number of contiguous bytes for a given inode
+ * starting at page frame idx.
+ */
+static u64 pnfs_num_cont_bytes(struct inode *inode, pgoff_t idx)
+{
+ struct address_space *mapping = inode->i_mapping;
+ pgoff_t end;
+
+ /* Optimize common case that writes from 0 to end of file */
+ end = DIV_ROUND_UP(i_size_read(inode), PAGE_CACHE_SIZE);
+ if (end != NFS_I(inode)->npages) {
+ rcu_read_lock();
+ end = radix_tree_next_hole(&mapping->page_tree, idx + 1, ULONG_MAX);
+ rcu_read_unlock();
+ }
+
+ if (!end)
+ return i_size_read(inode) - (idx << PAGE_CACHE_SHIFT);
+ else
+ return (end - idx) << PAGE_CACHE_SHIFT;
+}
+
static void
bl_pg_init_write(struct nfs_pageio_descriptor *pgio, struct nfs_page *req)
{
- if (!bl_check_alignment(req->wb_offset, req->wb_bytes, PAGE_CACHE_MASK))
+ if (pgio->pg_dreq != NULL &&
+ !is_aligned_req(req, PAGE_CACHE_SIZE)) {
nfs_pageio_reset_write_mds(pgio);
- else
- pnfs_generic_pg_init_write(pgio, req);
+ } else {
+ u64 wb_size;
+ if (pgio->pg_dreq == NULL)
+ wb_size = pnfs_num_cont_bytes(pgio->pg_inode,
+ req->wb_index);
+ else
+ wb_size = nfs_dreq_bytes_left(pgio->pg_dreq);
+
+ pnfs_generic_pg_init_write(pgio, req, wb_size);
+ }
+}
+
+static bool
+bl_pg_test_write(struct nfs_pageio_descriptor *pgio, struct nfs_page *prev,
+ struct nfs_page *req)
+{
+ if (pgio->pg_dreq != NULL &&
+ !is_aligned_req(req, PAGE_CACHE_SIZE))
+ return false;
+
+ return pnfs_generic_pg_test(pgio, prev, req);
}
static const struct nfs_pageio_ops bl_pg_read_ops = {
.pg_init = bl_pg_init_read,
- .pg_test = pnfs_generic_pg_test,
+ .pg_test = bl_pg_test_read,
.pg_doio = pnfs_generic_pg_readpages,
};
static const struct nfs_pageio_ops bl_pg_write_ops = {
.pg_init = bl_pg_init_write,
- .pg_test = pnfs_generic_pg_test,
+ .pg_test = bl_pg_test_write,
.pg_doio = pnfs_generic_pg_writepages,
};
diff --git a/fs/nfs/blocklayout/blocklayout.h b/fs/nfs/blocklayout/blocklayout.h
index 0335069..f4891bd 100644
--- a/fs/nfs/blocklayout/blocklayout.h
+++ b/fs/nfs/blocklayout/blocklayout.h
@@ -41,6 +41,7 @@
#define PAGE_CACHE_SECTORS (PAGE_CACHE_SIZE >> SECTOR_SHIFT)
#define PAGE_CACHE_SECTOR_SHIFT (PAGE_CACHE_SHIFT - SECTOR_SHIFT)
+#define SECTOR_SIZE (1 << SECTOR_SHIFT)
struct block_mount_id {
spinlock_t bm_lock; /* protects list */
@@ -172,7 +173,6 @@ struct bl_msg_hdr {
/* blocklayoutdev.c */
ssize_t bl_pipe_downcall(struct file *, const char __user *, size_t);
void bl_pipe_destroy_msg(struct rpc_pipe_msg *);
-struct block_device *nfs4_blkdev_get(dev_t dev);
int nfs4_blkdev_put(struct block_device *bdev);
struct pnfs_block_dev *nfs4_blk_decode_device(struct nfs_server *server,
struct pnfs_device *dev);
diff --git a/fs/nfs/blocklayout/blocklayoutdev.c b/fs/nfs/blocklayout/blocklayoutdev.c
index c965542..a86c5bd 100644
--- a/fs/nfs/blocklayout/blocklayoutdev.c
+++ b/fs/nfs/blocklayout/blocklayoutdev.c
@@ -53,22 +53,6 @@ static int decode_sector_number(__be32 **rp, sector_t *sp)
return 0;
}
-/* Open a block_device by device number. */
-struct block_device *nfs4_blkdev_get(dev_t dev)
-{
- struct block_device *bd;
-
- dprintk("%s enter\n", __func__);
- bd = blkdev_get_by_dev(dev, FMODE_READ, NULL);
- if (IS_ERR(bd))
- goto fail;
- return bd;
-fail:
- dprintk("%s failed to open device : %ld\n",
- __func__, PTR_ERR(bd));
- return NULL;
-}
-
/*
* Release the block device
*/
@@ -172,11 +156,12 @@ nfs4_blk_decode_device(struct nfs_server *server,
goto out;
}
- bd = nfs4_blkdev_get(MKDEV(reply->major, reply->minor));
+ bd = blkdev_get_by_dev(MKDEV(reply->major, reply->minor),
+ FMODE_READ, NULL);
if (IS_ERR(bd)) {
- rc = PTR_ERR(bd);
- dprintk("%s failed to open device : %d\n", __func__, rc);
- rv = ERR_PTR(rc);
+ dprintk("%s failed to open device : %ld\n", __func__,
+ PTR_ERR(bd));
+ rv = ERR_CAST(bd);
goto out;
}
diff --git a/fs/nfs/blocklayout/extents.c b/fs/nfs/blocklayout/extents.c
index 1f9a603..9c3e117 100644
--- a/fs/nfs/blocklayout/extents.c
+++ b/fs/nfs/blocklayout/extents.c
@@ -683,8 +683,7 @@ encode_pnfs_block_layoutupdate(struct pnfs_block_layout *bl,
p = xdr_encode_hyper(p, lce->bse_length << SECTOR_SHIFT);
p = xdr_encode_hyper(p, 0LL);
*p++ = cpu_to_be32(PNFS_BLOCK_READWRITE_DATA);
- list_del(&lce->bse_node);
- list_add_tail(&lce->bse_node, &bl->bl_committing);
+ list_move_tail(&lce->bse_node, &bl->bl_committing);
bl->bl_count--;
count++;
}
diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c
index 4c8459e..2245bef 100644
--- a/fs/nfs/callback.c
+++ b/fs/nfs/callback.c
@@ -12,6 +12,7 @@
#include <linux/sunrpc/svc.h>
#include <linux/sunrpc/svcsock.h>
#include <linux/nfs_fs.h>
+#include <linux/errno.h>
#include <linux/mutex.h>
#include <linux/freezer.h>
#include <linux/kthread.h>
@@ -23,6 +24,7 @@
#include "nfs4_fs.h"
#include "callback.h"
#include "internal.h"
+#include "netns.h"
#define NFSDBG_FACILITY NFSDBG_CALLBACK
@@ -37,7 +39,32 @@ static struct nfs_callback_data nfs_callback_info[NFS4_MAX_MINOR_VERSION + 1];
static DEFINE_MUTEX(nfs_callback_mutex);
static struct svc_program nfs4_callback_program;
-unsigned short nfs_callback_tcpport6;
+static int nfs4_callback_up_net(struct svc_serv *serv, struct net *net)
+{
+ int ret;
+ struct nfs_net *nn = net_generic(net, nfs_net_id);
+
+ ret = svc_create_xprt(serv, "tcp", net, PF_INET,
+ nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS);
+ if (ret <= 0)
+ goto out_err;
+ nn->nfs_callback_tcpport = ret;
+ dprintk("NFS: Callback listener port = %u (af %u, net %p)\n",
+ nn->nfs_callback_tcpport, PF_INET, net);
+
+ ret = svc_create_xprt(serv, "tcp", net, PF_INET6,
+ nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS);
+ if (ret > 0) {
+ nn->nfs_callback_tcpport6 = ret;
+ dprintk("NFS: Callback listener port = %u (af %u, net %p)\n",
+ nn->nfs_callback_tcpport6, PF_INET6, net);
+ } else if (ret != -EAFNOSUPPORT)
+ goto out_err;
+ return 0;
+
+out_err:
+ return (ret) ? ret : -ENOMEM;
+}
/*
* This is the NFSv4 callback kernel thread.
@@ -78,38 +105,23 @@ nfs4_callback_svc(void *vrqstp)
* Prepare to bring up the NFSv4 callback service
*/
static struct svc_rqst *
-nfs4_callback_up(struct svc_serv *serv, struct rpc_xprt *xprt)
+nfs4_callback_up(struct svc_serv *serv)
{
- int ret;
-
- ret = svc_create_xprt(serv, "tcp", &init_net, PF_INET,
- nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS);
- if (ret <= 0)
- goto out_err;
- nfs_callback_tcpport = ret;
- dprintk("NFS: Callback listener port = %u (af %u)\n",
- nfs_callback_tcpport, PF_INET);
-
- ret = svc_create_xprt(serv, "tcp", &init_net, PF_INET6,
- nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS);
- if (ret > 0) {
- nfs_callback_tcpport6 = ret;
- dprintk("NFS: Callback listener port = %u (af %u)\n",
- nfs_callback_tcpport6, PF_INET6);
- } else if (ret == -EAFNOSUPPORT)
- ret = 0;
- else
- goto out_err;
-
return svc_prepare_thread(serv, &serv->sv_pools[0], NUMA_NO_NODE);
-
-out_err:
- if (ret == 0)
- ret = -ENOMEM;
- return ERR_PTR(ret);
}
#if defined(CONFIG_NFS_V4_1)
+static int nfs41_callback_up_net(struct svc_serv *serv, struct net *net)
+{
+ /*
+ * Create an svc_sock for the back channel service that shares the
+ * fore channel connection.
+ * Returns the input port (0) and sets the svc_serv bc_xprt on success
+ */
+ return svc_create_xprt(serv, "tcp-bc", net, PF_INET, 0,
+ SVC_SOCK_ANONYMOUS);
+}
+
/*
* The callback service for NFSv4.1 callbacks
*/
@@ -149,28 +161,9 @@ nfs41_callback_svc(void *vrqstp)
* Bring up the NFSv4.1 callback service
*/
static struct svc_rqst *
-nfs41_callback_up(struct svc_serv *serv, struct rpc_xprt *xprt)
+nfs41_callback_up(struct svc_serv *serv)
{
struct svc_rqst *rqstp;
- int ret;
-
- /*
- * Create an svc_sock for the back channel service that shares the
- * fore channel connection.
- * Returns the input port (0) and sets the svc_serv bc_xprt on success
- */
- ret = svc_create_xprt(serv, "tcp-bc", &init_net, PF_INET, 0,
- SVC_SOCK_ANONYMOUS);
- if (ret < 0) {
- rqstp = ERR_PTR(ret);
- goto out;
- }
-
- /*
- * Save the svc_serv in the transport so that it can
- * be referenced when the session backchannel is initialized
- */
- xprt->bc_serv = serv;
INIT_LIST_HEAD(&serv->sv_cb_list);
spin_lock_init(&serv->sv_cb_lock);
@@ -180,90 +173,74 @@ nfs41_callback_up(struct svc_serv *serv, struct rpc_xprt *xprt)
svc_xprt_put(serv->sv_bc_xprt);
serv->sv_bc_xprt = NULL;
}
-out:
dprintk("--> %s return %ld\n", __func__,
IS_ERR(rqstp) ? PTR_ERR(rqstp) : 0);
return rqstp;
}
-static inline int nfs_minorversion_callback_svc_setup(u32 minorversion,
- struct svc_serv *serv, struct rpc_xprt *xprt,
+static void nfs_minorversion_callback_svc_setup(struct svc_serv *serv,
struct svc_rqst **rqstpp, int (**callback_svc)(void *vrqstp))
{
- if (minorversion) {
- *rqstpp = nfs41_callback_up(serv, xprt);
- *callback_svc = nfs41_callback_svc;
- }
- return minorversion;
+ *rqstpp = nfs41_callback_up(serv);
+ *callback_svc = nfs41_callback_svc;
}
static inline void nfs_callback_bc_serv(u32 minorversion, struct rpc_xprt *xprt,
- struct nfs_callback_data *cb_info)
+ struct svc_serv *serv)
{
if (minorversion)
- xprt->bc_serv = cb_info->serv;
+ /*
+ * Save the svc_serv in the transport so that it can
+ * be referenced when the session backchannel is initialized
+ */
+ xprt->bc_serv = serv;
}
#else
-static inline int nfs_minorversion_callback_svc_setup(u32 minorversion,
- struct svc_serv *serv, struct rpc_xprt *xprt,
- struct svc_rqst **rqstpp, int (**callback_svc)(void *vrqstp))
+static int nfs41_callback_up_net(struct svc_serv *serv, struct net *net)
{
return 0;
}
+static void nfs_minorversion_callback_svc_setup(struct svc_serv *serv,
+ struct svc_rqst **rqstpp, int (**callback_svc)(void *vrqstp))
+{
+ *rqstpp = ERR_PTR(-ENOTSUPP);
+ *callback_svc = ERR_PTR(-ENOTSUPP);
+}
+
static inline void nfs_callback_bc_serv(u32 minorversion, struct rpc_xprt *xprt,
- struct nfs_callback_data *cb_info)
+ struct svc_serv *serv)
{
}
#endif /* CONFIG_NFS_V4_1 */
-/*
- * Bring up the callback thread if it is not already up.
- */
-int nfs_callback_up(u32 minorversion, struct rpc_xprt *xprt)
+static int nfs_callback_start_svc(int minorversion, struct rpc_xprt *xprt,
+ struct svc_serv *serv)
{
- struct svc_serv *serv = NULL;
struct svc_rqst *rqstp;
int (*callback_svc)(void *vrqstp);
struct nfs_callback_data *cb_info = &nfs_callback_info[minorversion];
char svc_name[12];
- int ret = 0;
- int minorversion_setup;
- struct net *net = &init_net;
+ int ret;
- mutex_lock(&nfs_callback_mutex);
- if (cb_info->users++ || cb_info->task != NULL) {
- nfs_callback_bc_serv(minorversion, xprt, cb_info);
- goto out;
- }
- serv = svc_create(&nfs4_callback_program, NFS4_CALLBACK_BUFSIZE, NULL);
- if (!serv) {
- ret = -ENOMEM;
- goto out_err;
- }
- /* As there is only one thread we need to over-ride the
- * default maximum of 80 connections
- */
- serv->sv_maxconn = 1024;
+ nfs_callback_bc_serv(minorversion, xprt, serv);
- ret = svc_bind(serv, net);
- if (ret < 0) {
- printk(KERN_WARNING "NFS: bind callback service failed\n");
- goto out_err;
- }
+ if (cb_info->task)
+ return 0;
- minorversion_setup = nfs_minorversion_callback_svc_setup(minorversion,
- serv, xprt, &rqstp, &callback_svc);
- if (!minorversion_setup) {
+ switch (minorversion) {
+ case 0:
/* v4.0 callback setup */
- rqstp = nfs4_callback_up(serv, xprt);
+ rqstp = nfs4_callback_up(serv);
callback_svc = nfs4_callback_svc;
+ break;
+ default:
+ nfs_minorversion_callback_svc_setup(serv,
+ &rqstp, &callback_svc);
}
- if (IS_ERR(rqstp)) {
- ret = PTR_ERR(rqstp);
- goto out_err;
- }
+ if (IS_ERR(rqstp))
+ return PTR_ERR(rqstp);
svc_sock_update_bufs(serv);
@@ -276,41 +253,165 @@ int nfs_callback_up(u32 minorversion, struct rpc_xprt *xprt)
svc_exit_thread(cb_info->rqst);
cb_info->rqst = NULL;
cb_info->task = NULL;
- goto out_err;
+ return PTR_ERR(cb_info->task);
+ }
+ dprintk("nfs_callback_up: service started\n");
+ return 0;
+}
+
+static void nfs_callback_down_net(u32 minorversion, struct svc_serv *serv, struct net *net)
+{
+ struct nfs_net *nn = net_generic(net, nfs_net_id);
+
+ if (--nn->cb_users[minorversion])
+ return;
+
+ dprintk("NFS: destroy per-net callback data; net=%p\n", net);
+ svc_shutdown_net(serv, net);
+}
+
+static int nfs_callback_up_net(int minorversion, struct svc_serv *serv, struct net *net)
+{
+ struct nfs_net *nn = net_generic(net, nfs_net_id);
+ int ret;
+
+ if (nn->cb_users[minorversion]++)
+ return 0;
+
+ dprintk("NFS: create per-net callback data; net=%p\n", net);
+
+ ret = svc_bind(serv, net);
+ if (ret < 0) {
+ printk(KERN_WARNING "NFS: bind callback service failed\n");
+ goto err_bind;
+ }
+
+ switch (minorversion) {
+ case 0:
+ ret = nfs4_callback_up_net(serv, net);
+ break;
+ case 1:
+ ret = nfs41_callback_up_net(serv, net);
+ break;
+ default:
+ printk(KERN_ERR "NFS: unknown callback version: %d\n",
+ minorversion);
+ ret = -EINVAL;
+ break;
}
-out:
+
+ if (ret < 0) {
+ printk(KERN_ERR "NFS: callback service start failed\n");
+ goto err_socks;
+ }
+ return 0;
+
+err_socks:
+ svc_rpcb_cleanup(serv, net);
+err_bind:
+ dprintk("NFS: Couldn't create callback socket: err = %d; "
+ "net = %p\n", ret, net);
+ return ret;
+}
+
+static struct svc_serv *nfs_callback_create_svc(int minorversion)
+{
+ struct nfs_callback_data *cb_info = &nfs_callback_info[minorversion];
+ struct svc_serv *serv;
+
+ /*
+ * Check whether we're already up and running.
+ */
+ if (cb_info->task) {
+ /*
+ * Note: increase service usage, because later in case of error
+ * svc_destroy() will be called.
+ */
+ svc_get(cb_info->serv);
+ return cb_info->serv;
+ }
+
+ /*
+ * Sanity check: if there's no task,
+ * we should be the first user ...
+ */
+ if (cb_info->users)
+ printk(KERN_WARNING "nfs_callback_create_svc: no kthread, %d users??\n",
+ cb_info->users);
+
+ serv = svc_create(&nfs4_callback_program, NFS4_CALLBACK_BUFSIZE, NULL);
+ if (!serv) {
+ printk(KERN_ERR "nfs_callback_create_svc: create service failed\n");
+ return ERR_PTR(-ENOMEM);
+ }
+ /* As there is only one thread we need to over-ride the
+ * default maximum of 80 connections
+ */
+ serv->sv_maxconn = 1024;
+ dprintk("nfs_callback_create_svc: service created\n");
+ return serv;
+}
+
+/*
+ * Bring up the callback thread if it is not already up.
+ */
+int nfs_callback_up(u32 minorversion, struct rpc_xprt *xprt)
+{
+ struct svc_serv *serv;
+ struct nfs_callback_data *cb_info = &nfs_callback_info[minorversion];
+ int ret;
+ struct net *net = xprt->xprt_net;
+
+ mutex_lock(&nfs_callback_mutex);
+
+ serv = nfs_callback_create_svc(minorversion);
+ if (IS_ERR(serv)) {
+ ret = PTR_ERR(serv);
+ goto err_create;
+ }
+
+ ret = nfs_callback_up_net(minorversion, serv, net);
+ if (ret < 0)
+ goto err_net;
+
+ ret = nfs_callback_start_svc(minorversion, xprt, serv);
+ if (ret < 0)
+ goto err_start;
+
+ cb_info->users++;
/*
* svc_create creates the svc_serv with sv_nrthreads == 1, and then
* svc_prepare_thread increments that. So we need to call svc_destroy
* on both success and failure so that the refcount is 1 when the
* thread exits.
*/
- if (serv)
- svc_destroy(serv);
+err_net:
+ svc_destroy(serv);
+err_create:
mutex_unlock(&nfs_callback_mutex);
return ret;
-out_err:
- dprintk("NFS: Couldn't create callback socket or server thread; "
- "err = %d\n", ret);
- cb_info->users--;
- if (serv)
- svc_shutdown_net(serv, net);
- goto out;
+
+err_start:
+ nfs_callback_down_net(minorversion, serv, net);
+ dprintk("NFS: Couldn't create server thread; err = %d\n", ret);
+ goto err_net;
}
/*
* Kill the callback thread if it's no longer being used.
*/
-void nfs_callback_down(int minorversion)
+void nfs_callback_down(int minorversion, struct net *net)
{
struct nfs_callback_data *cb_info = &nfs_callback_info[minorversion];
mutex_lock(&nfs_callback_mutex);
+ nfs_callback_down_net(minorversion, cb_info->serv, net);
cb_info->users--;
if (cb_info->users == 0 && cb_info->task != NULL) {
kthread_stop(cb_info->task);
- svc_shutdown_net(cb_info->serv, &init_net);
+ dprintk("nfs_callback_down: service stopped\n");
svc_exit_thread(cb_info->rqst);
+ dprintk("nfs_callback_down: service destroyed\n");
cb_info->serv = NULL;
cb_info->rqst = NULL;
cb_info->task = NULL;
diff --git a/fs/nfs/callback.h b/fs/nfs/callback.h
index b44d7b1..4251c2ae 100644
--- a/fs/nfs/callback.h
+++ b/fs/nfs/callback.h
@@ -194,7 +194,7 @@ extern __be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy,
struct cb_process_state *cps);
#if IS_ENABLED(CONFIG_NFS_V4)
extern int nfs_callback_up(u32 minorversion, struct rpc_xprt *xprt);
-extern void nfs_callback_down(int minorversion);
+extern void nfs_callback_down(int minorversion, struct net *net);
extern int nfs4_validate_delegation_stateid(struct nfs_delegation *delegation,
const nfs4_stateid *stateid);
extern int nfs4_set_callback_sessionid(struct nfs_client *clp);
@@ -209,6 +209,5 @@ extern int nfs4_set_callback_sessionid(struct nfs_client *clp);
extern unsigned int nfs_callback_set_tcpport;
extern unsigned short nfs_callback_tcpport;
-extern unsigned short nfs_callback_tcpport6;
#endif /* __LINUX_FS_NFS_CALLBACK_H */
diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c
index 1b5d809..76b4a7a 100644
--- a/fs/nfs/callback_proc.c
+++ b/fs/nfs/callback_proc.c
@@ -122,7 +122,15 @@ static struct pnfs_layout_hdr * get_layout_by_fh_locked(struct nfs_client *clp,
ino = igrab(lo->plh_inode);
if (!ino)
continue;
- get_layout_hdr(lo);
+ spin_lock(&ino->i_lock);
+ /* Is this layout in the process of being freed? */
+ if (NFS_I(ino)->layout != lo) {
+ spin_unlock(&ino->i_lock);
+ iput(ino);
+ continue;
+ }
+ pnfs_get_layout_hdr(lo);
+ spin_unlock(&ino->i_lock);
return lo;
}
}
@@ -158,7 +166,7 @@ static u32 initiate_file_draining(struct nfs_client *clp,
ino = lo->plh_inode;
spin_lock(&ino->i_lock);
if (test_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags) ||
- mark_matching_lsegs_invalid(lo, &free_me_list,
+ pnfs_mark_matching_lsegs_invalid(lo, &free_me_list,
&args->cbl_range))
rv = NFS4ERR_DELAY;
else
@@ -166,7 +174,7 @@ static u32 initiate_file_draining(struct nfs_client *clp,
pnfs_set_layout_stateid(lo, &args->cbl_stateid, true);
spin_unlock(&ino->i_lock);
pnfs_free_lseg_list(&free_me_list);
- put_layout_hdr(lo);
+ pnfs_put_layout_hdr(lo);
iput(ino);
return rv;
}
@@ -196,9 +204,18 @@ static u32 initiate_bulk_draining(struct nfs_client *clp,
continue;
list_for_each_entry(lo, &server->layouts, plh_layouts) {
- if (!igrab(lo->plh_inode))
+ ino = igrab(lo->plh_inode);
+ if (ino)
+ continue;
+ spin_lock(&ino->i_lock);
+ /* Is this layout in the process of being freed? */
+ if (NFS_I(ino)->layout != lo) {
+ spin_unlock(&ino->i_lock);
+ iput(ino);
continue;
- get_layout_hdr(lo);
+ }
+ pnfs_get_layout_hdr(lo);
+ spin_unlock(&ino->i_lock);
BUG_ON(!list_empty(&lo->plh_bulk_recall));
list_add(&lo->plh_bulk_recall, &recall_list);
}
@@ -211,12 +228,12 @@ 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))
+ if (pnfs_mark_matching_lsegs_invalid(lo, &free_me_list, &range))
rv = NFS4ERR_DELAY;
list_del_init(&lo->plh_bulk_recall);
spin_unlock(&ino->i_lock);
pnfs_free_lseg_list(&free_me_list);
- put_layout_hdr(lo);
+ pnfs_put_layout_hdr(lo);
iput(ino);
}
return rv;
diff --git a/fs/nfs/client.c b/fs/nfs/client.c
index 9969444..8b39a42 100644
--- a/fs/nfs/client.c
+++ b/fs/nfs/client.c
@@ -93,10 +93,10 @@ static struct nfs_subversion *find_nfs_version(unsigned int version)
spin_unlock(&nfs_version_lock);
return nfs;
}
- };
+ }
spin_unlock(&nfs_version_lock);
- return ERR_PTR(-EPROTONOSUPPORT);;
+ return ERR_PTR(-EPROTONOSUPPORT);
}
struct nfs_subversion *get_nfs_version(unsigned int version)
@@ -498,7 +498,8 @@ nfs_get_client(const struct nfs_client_initdata *cl_init,
return nfs_found_client(cl_init, clp);
}
if (new) {
- list_add(&new->cl_share_link, &nn->nfs_client_list);
+ list_add_tail(&new->cl_share_link,
+ &nn->nfs_client_list);
spin_unlock(&nn->nfs_client_lock);
new->cl_flags = cl_init->init_flags;
return rpc_ops->init_client(new, timeparms, ip_addr,
@@ -668,7 +669,8 @@ int nfs_init_server_rpcclient(struct nfs_server *server,
{
struct nfs_client *clp = server->nfs_client;
- server->client = rpc_clone_client(clp->cl_rpcclient);
+ server->client = rpc_clone_client_set_auth(clp->cl_rpcclient,
+ pseudoflavour);
if (IS_ERR(server->client)) {
dprintk("%s: couldn't create rpc_client!\n", __func__);
return PTR_ERR(server->client);
@@ -678,16 +680,6 @@ int nfs_init_server_rpcclient(struct nfs_server *server,
timeo,
sizeof(server->client->cl_timeout_default));
server->client->cl_timeout = &server->client->cl_timeout_default;
-
- if (pseudoflavour != clp->cl_rpcclient->cl_auth->au_flavor) {
- struct rpc_auth *auth;
-
- auth = rpcauth_create(pseudoflavour, server->client);
- if (IS_ERR(auth)) {
- dprintk("%s: couldn't create credcache!\n", __func__);
- return PTR_ERR(auth);
- }
- }
server->client->cl_softrtry = 0;
if (server->flags & NFS_MOUNT_SOFT)
server->client->cl_softrtry = 1;
@@ -761,6 +753,8 @@ static int nfs_init_server(struct nfs_server *server,
data->timeo, data->retrans);
if (data->flags & NFS_MOUNT_NORESVPORT)
set_bit(NFS_CS_NORESVPORT, &cl_init.init_flags);
+ if (server->options & NFS_OPTION_MIGRATION)
+ set_bit(NFS_CS_MIGRATION, &cl_init.init_flags);
/* Allocate or find a client reference we can use */
clp = nfs_get_client(&cl_init, &timeparms, NULL, RPC_AUTH_UNIX);
@@ -855,7 +849,6 @@ static void nfs_server_set_fsinfo(struct nfs_server *server,
if (server->wsize > NFS_MAX_FILE_IO_SIZE)
server->wsize = NFS_MAX_FILE_IO_SIZE;
server->wpages = (server->wsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
- server->pnfs_blksize = fsinfo->blksize;
server->wtmult = nfs_block_bits(fsinfo->wtmult, NULL);
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index 627f108..ce8cb92 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -2072,7 +2072,7 @@ found:
nfs_access_free_entry(entry);
}
-static void nfs_access_add_cache(struct inode *inode, struct nfs_access_entry *set)
+void nfs_access_add_cache(struct inode *inode, struct nfs_access_entry *set)
{
struct nfs_access_entry *cache = kmalloc(sizeof(*cache), GFP_KERNEL);
if (cache == NULL)
@@ -2098,6 +2098,20 @@ static void nfs_access_add_cache(struct inode *inode, struct nfs_access_entry *s
spin_unlock(&nfs_access_lru_lock);
}
}
+EXPORT_SYMBOL_GPL(nfs_access_add_cache);
+
+void nfs_access_set_mask(struct nfs_access_entry *entry, u32 access_result)
+{
+ entry->mask = 0;
+ if (access_result & NFS4_ACCESS_READ)
+ entry->mask |= MAY_READ;
+ if (access_result &
+ (NFS4_ACCESS_MODIFY | NFS4_ACCESS_EXTEND | NFS4_ACCESS_DELETE))
+ entry->mask |= MAY_WRITE;
+ if (access_result & (NFS4_ACCESS_LOOKUP|NFS4_ACCESS_EXECUTE))
+ entry->mask |= MAY_EXEC;
+}
+EXPORT_SYMBOL_GPL(nfs_access_set_mask);
static int nfs_do_access(struct inode *inode, struct rpc_cred *cred, int mask)
{
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c
index 1ba385b..cae26cb 100644
--- a/fs/nfs/direct.c
+++ b/fs/nfs/direct.c
@@ -46,6 +46,7 @@
#include <linux/kref.h>
#include <linux/slab.h>
#include <linux/task_io_accounting_ops.h>
+#include <linux/module.h>
#include <linux/nfs_fs.h>
#include <linux/nfs_page.h>
@@ -78,6 +79,7 @@ struct nfs_direct_req {
atomic_t io_count; /* i/os we're waiting for */
spinlock_t lock; /* protect completion state */
ssize_t count, /* bytes actually processed */
+ bytes_left, /* bytes left to be sent */
error; /* any reported error */
struct completion completion; /* wait for i/o completion */
@@ -190,6 +192,12 @@ static void nfs_direct_req_release(struct nfs_direct_req *dreq)
kref_put(&dreq->kref, nfs_direct_req_free);
}
+ssize_t nfs_dreq_bytes_left(struct nfs_direct_req *dreq)
+{
+ return dreq->bytes_left;
+}
+EXPORT_SYMBOL_GPL(nfs_dreq_bytes_left);
+
/*
* Collects and returns the final error value/byte-count.
*/
@@ -390,6 +398,7 @@ static ssize_t nfs_direct_read_schedule_segment(struct nfs_pageio_descriptor *de
user_addr += req_len;
pos += req_len;
count -= req_len;
+ dreq->bytes_left -= req_len;
}
/* The nfs_page now hold references to these pages */
nfs_direct_release_pages(pagevec, npages);
@@ -450,23 +459,28 @@ static ssize_t nfs_direct_read(struct kiocb *iocb, const struct iovec *iov,
ssize_t result = -ENOMEM;
struct inode *inode = iocb->ki_filp->f_mapping->host;
struct nfs_direct_req *dreq;
+ struct nfs_lock_context *l_ctx;
dreq = nfs_direct_req_alloc();
if (dreq == NULL)
goto out;
dreq->inode = inode;
+ dreq->bytes_left = iov_length(iov, nr_segs);
dreq->ctx = get_nfs_open_context(nfs_file_open_context(iocb->ki_filp));
- dreq->l_ctx = nfs_get_lock_context(dreq->ctx);
- if (dreq->l_ctx == NULL)
+ l_ctx = nfs_get_lock_context(dreq->ctx);
+ if (IS_ERR(l_ctx)) {
+ result = PTR_ERR(l_ctx);
goto out_release;
+ }
+ dreq->l_ctx = l_ctx;
if (!is_sync_kiocb(iocb))
dreq->iocb = iocb;
+ NFS_I(inode)->read_io += iov_length(iov, nr_segs);
result = nfs_direct_read_schedule_iovec(dreq, iov, nr_segs, pos, uio);
if (!result)
result = nfs_direct_wait(dreq);
- NFS_I(inode)->read_io += result;
out_release:
nfs_direct_req_release(dreq);
out:
@@ -706,6 +720,7 @@ static ssize_t nfs_direct_write_schedule_segment(struct nfs_pageio_descriptor *d
user_addr += req_len;
pos += req_len;
count -= req_len;
+ dreq->bytes_left -= req_len;
}
/* The nfs_page now hold references to these pages */
nfs_direct_release_pages(pagevec, npages);
@@ -814,6 +829,7 @@ static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq,
get_dreq(dreq);
atomic_inc(&inode->i_dio_count);
+ NFS_I(dreq->inode)->write_io += iov_length(iov, nr_segs);
for (seg = 0; seg < nr_segs; seg++) {
const struct iovec *vec = &iov[seg];
result = nfs_direct_write_schedule_segment(&desc, vec, pos, uio);
@@ -825,7 +841,6 @@ static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq,
pos += vec->iov_len;
}
nfs_pageio_complete(&desc);
- NFS_I(dreq->inode)->write_io += desc.pg_bytes_written;
/*
* If no bytes were started, return the error, and let the
@@ -849,16 +864,21 @@ static ssize_t nfs_direct_write(struct kiocb *iocb, const struct iovec *iov,
ssize_t result = -ENOMEM;
struct inode *inode = iocb->ki_filp->f_mapping->host;
struct nfs_direct_req *dreq;
+ struct nfs_lock_context *l_ctx;
dreq = nfs_direct_req_alloc();
if (!dreq)
goto out;
dreq->inode = inode;
+ dreq->bytes_left = count;
dreq->ctx = get_nfs_open_context(nfs_file_open_context(iocb->ki_filp));
- dreq->l_ctx = nfs_get_lock_context(dreq->ctx);
- if (dreq->l_ctx == NULL)
+ l_ctx = nfs_get_lock_context(dreq->ctx);
+ if (IS_ERR(l_ctx)) {
+ result = PTR_ERR(l_ctx);
goto out_release;
+ }
+ dreq->l_ctx = l_ctx;
if (!is_sync_kiocb(iocb))
dreq->iocb = iocb;
diff --git a/fs/nfs/file.c b/fs/nfs/file.c
index f692be9..582bb88 100644
--- a/fs/nfs/file.c
+++ b/fs/nfs/file.c
@@ -259,7 +259,7 @@ nfs_file_fsync_commit(struct file *file, loff_t start, loff_t end, int datasync)
struct dentry *dentry = file->f_path.dentry;
struct nfs_open_context *ctx = nfs_file_open_context(file);
struct inode *inode = dentry->d_inode;
- int have_error, status;
+ int have_error, do_resend, status;
int ret = 0;
dprintk("NFS: fsync file(%s/%s) datasync %d\n",
@@ -267,15 +267,23 @@ nfs_file_fsync_commit(struct file *file, loff_t start, loff_t end, int datasync)
datasync);
nfs_inc_stats(inode, NFSIOS_VFSFSYNC);
+ do_resend = test_and_clear_bit(NFS_CONTEXT_RESEND_WRITES, &ctx->flags);
have_error = test_and_clear_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags);
status = nfs_commit_inode(inode, FLUSH_SYNC);
- if (status >= 0 && ret < 0)
- status = ret;
have_error |= test_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags);
- if (have_error)
+ if (have_error) {
ret = xchg(&ctx->error, 0);
- if (!ret && status < 0)
+ if (ret)
+ goto out;
+ }
+ if (status < 0) {
ret = status;
+ goto out;
+ }
+ do_resend |= test_bit(NFS_CONTEXT_RESEND_WRITES, &ctx->flags);
+ if (do_resend)
+ ret = -EAGAIN;
+out:
return ret;
}
EXPORT_SYMBOL_GPL(nfs_file_fsync_commit);
@@ -286,13 +294,22 @@ nfs_file_fsync(struct file *file, loff_t start, loff_t end, int datasync)
int ret;
struct inode *inode = file->f_path.dentry->d_inode;
- ret = filemap_write_and_wait_range(inode->i_mapping, start, end);
- if (ret != 0)
- goto out;
- mutex_lock(&inode->i_mutex);
- ret = nfs_file_fsync_commit(file, start, end, datasync);
- mutex_unlock(&inode->i_mutex);
-out:
+ do {
+ ret = filemap_write_and_wait_range(inode->i_mapping, start, end);
+ if (ret != 0)
+ break;
+ mutex_lock(&inode->i_mutex);
+ ret = nfs_file_fsync_commit(file, start, end, datasync);
+ mutex_unlock(&inode->i_mutex);
+ /*
+ * If nfs_file_fsync_commit detected a server reboot, then
+ * resend all dirty pages that might have been covered by
+ * the NFS_CONTEXT_RESEND_WRITES flag
+ */
+ start = 0;
+ end = LLONG_MAX;
+ } while (ret == -EAGAIN);
+
return ret;
}
diff --git a/fs/nfs/getroot.c b/fs/nfs/getroot.c
index 4654ced..033803c 100644
--- a/fs/nfs/getroot.c
+++ b/fs/nfs/getroot.c
@@ -32,6 +32,8 @@
#include <asm/uaccess.h>
+#include "internal.h"
+
#define NFSDBG_FACILITY NFSDBG_CLIENT
/*
diff --git a/fs/nfs/idmap.c b/fs/nfs/idmap.c
index a850079..9cc4a3f 100644
--- a/fs/nfs/idmap.c
+++ b/fs/nfs/idmap.c
@@ -55,18 +55,19 @@
static const struct cred *id_resolver_cache;
static struct key_type key_type_id_resolver_legacy;
-struct idmap {
- struct rpc_pipe *idmap_pipe;
- struct key_construction *idmap_key_cons;
- struct mutex idmap_mutex;
-};
-
struct idmap_legacy_upcalldata {
struct rpc_pipe_msg pipe_msg;
struct idmap_msg idmap_msg;
+ struct key_construction *key_cons;
struct idmap *idmap;
};
+struct idmap {
+ struct rpc_pipe *idmap_pipe;
+ struct idmap_legacy_upcalldata *idmap_upcall_data;
+ struct mutex idmap_mutex;
+};
+
/**
* nfs_fattr_init_names - initialise the nfs_fattr owner_name/group_name fields
* @fattr: fully initialised struct nfs_fattr
@@ -158,7 +159,7 @@ static int nfs_map_string_to_numeric(const char *name, size_t namelen, __u32 *re
return 0;
memcpy(buf, name, namelen);
buf[namelen] = '\0';
- if (strict_strtoul(buf, 0, &val) != 0)
+ if (kstrtoul(buf, 0, &val) != 0)
return 0;
*res = val;
return 1;
@@ -330,7 +331,6 @@ static ssize_t nfs_idmap_get_key(const char *name, size_t namelen,
ret = nfs_idmap_request_key(&key_type_id_resolver_legacy,
name, namelen, type, data,
data_size, idmap);
- idmap->idmap_key_cons = NULL;
mutex_unlock(&idmap->idmap_mutex);
}
return ret;
@@ -364,7 +364,7 @@ static int nfs_idmap_lookup_id(const char *name, size_t namelen, const char *typ
if (data_size <= 0) {
ret = -EINVAL;
} else {
- ret = strict_strtol(id_str, 10, &id_long);
+ ret = kstrtol(id_str, 10, &id_long);
*id = (__u32)id_long;
}
return ret;
@@ -465,8 +465,6 @@ nfs_idmap_new(struct nfs_client *clp)
struct rpc_pipe *pipe;
int error;
- BUG_ON(clp->cl_idmap != NULL);
-
idmap = kzalloc(sizeof(*idmap), GFP_KERNEL);
if (idmap == NULL)
return -ENOMEM;
@@ -510,7 +508,6 @@ static int __rpc_pipefs_event(struct nfs_client *clp, unsigned long event,
switch (event) {
case RPC_PIPEFS_MOUNT:
- BUG_ON(clp->cl_rpcclient->cl_dentry == NULL);
err = __nfs_idmap_register(clp->cl_rpcclient->cl_dentry,
clp->cl_idmap,
clp->cl_idmap->idmap_pipe);
@@ -632,9 +629,6 @@ static int nfs_idmap_prepare_message(char *desc, struct idmap *idmap,
substring_t substr;
int token, ret;
- memset(im, 0, sizeof(*im));
- memset(msg, 0, sizeof(*msg));
-
im->im_type = IDMAP_TYPE_GROUP;
token = match_token(desc, nfs_idmap_tokens, &substr);
@@ -665,6 +659,35 @@ out:
return ret;
}
+static bool
+nfs_idmap_prepare_pipe_upcall(struct idmap *idmap,
+ struct idmap_legacy_upcalldata *data)
+{
+ if (idmap->idmap_upcall_data != NULL) {
+ WARN_ON_ONCE(1);
+ return false;
+ }
+ idmap->idmap_upcall_data = data;
+ return true;
+}
+
+static void
+nfs_idmap_complete_pipe_upcall_locked(struct idmap *idmap, int ret)
+{
+ struct key_construction *cons = idmap->idmap_upcall_data->key_cons;
+
+ kfree(idmap->idmap_upcall_data);
+ idmap->idmap_upcall_data = NULL;
+ complete_request_key(cons, ret);
+}
+
+static void
+nfs_idmap_abort_pipe_upcall(struct idmap *idmap, int ret)
+{
+ if (idmap->idmap_upcall_data != NULL)
+ nfs_idmap_complete_pipe_upcall_locked(idmap, ret);
+}
+
static int nfs_idmap_legacy_upcall(struct key_construction *cons,
const char *op,
void *aux)
@@ -677,29 +700,28 @@ static int nfs_idmap_legacy_upcall(struct key_construction *cons,
int ret = -ENOMEM;
/* msg and im are freed in idmap_pipe_destroy_msg */
- data = kmalloc(sizeof(*data), GFP_KERNEL);
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
if (!data)
goto out1;
msg = &data->pipe_msg;
im = &data->idmap_msg;
data->idmap = idmap;
+ data->key_cons = cons;
ret = nfs_idmap_prepare_message(key->description, idmap, im, msg);
if (ret < 0)
goto out2;
- BUG_ON(idmap->idmap_key_cons != NULL);
- idmap->idmap_key_cons = cons;
+ ret = -EAGAIN;
+ if (!nfs_idmap_prepare_pipe_upcall(idmap, data))
+ goto out2;
ret = rpc_queue_upcall(idmap->idmap_pipe, msg);
if (ret < 0)
- goto out3;
+ nfs_idmap_abort_pipe_upcall(idmap, ret);
return ret;
-
-out3:
- idmap->idmap_key_cons = NULL;
out2:
kfree(data);
out1:
@@ -714,21 +736,32 @@ static int nfs_idmap_instantiate(struct key *key, struct key *authkey, char *dat
authkey);
}
-static int nfs_idmap_read_message(struct idmap_msg *im, struct key *key, struct key *authkey)
+static int nfs_idmap_read_and_verify_message(struct idmap_msg *im,
+ struct idmap_msg *upcall,
+ struct key *key, struct key *authkey)
{
char id_str[NFS_UINT_MAXLEN];
- int ret = -EINVAL;
+ int ret = -ENOKEY;
+ /* ret = -ENOKEY */
+ if (upcall->im_type != im->im_type || upcall->im_conv != im->im_conv)
+ goto out;
switch (im->im_conv) {
case IDMAP_CONV_NAMETOID:
+ if (strcmp(upcall->im_name, im->im_name) != 0)
+ break;
sprintf(id_str, "%d", im->im_id);
ret = nfs_idmap_instantiate(key, authkey, id_str);
break;
case IDMAP_CONV_IDTONAME:
+ if (upcall->im_id != im->im_id)
+ break;
ret = nfs_idmap_instantiate(key, authkey, im->im_name);
break;
+ default:
+ ret = -EINVAL;
}
-
+out:
return ret;
}
@@ -740,14 +773,16 @@ idmap_pipe_downcall(struct file *filp, const char __user *src, size_t mlen)
struct key_construction *cons;
struct idmap_msg im;
size_t namelen_in;
- int ret;
+ int ret = -ENOKEY;
/* If instantiation is successful, anyone waiting for key construction
* will have been woken up and someone else may now have used
* idmap_key_cons - so after this point we may no longer touch it.
*/
- cons = ACCESS_ONCE(idmap->idmap_key_cons);
- idmap->idmap_key_cons = NULL;
+ if (idmap->idmap_upcall_data == NULL)
+ goto out_noupcall;
+
+ cons = idmap->idmap_upcall_data->key_cons;
if (mlen != sizeof(im)) {
ret = -ENOSPC;
@@ -768,16 +803,19 @@ idmap_pipe_downcall(struct file *filp, const char __user *src, size_t mlen)
if (namelen_in == 0 || namelen_in == IDMAP_NAMESZ) {
ret = -EINVAL;
goto out;
- }
+}
- ret = nfs_idmap_read_message(&im, cons->key, cons->authkey);
+ ret = nfs_idmap_read_and_verify_message(&im,
+ &idmap->idmap_upcall_data->idmap_msg,
+ cons->key, cons->authkey);
if (ret >= 0) {
key_set_timeout(cons->key, nfs_idmap_cache_timeout);
ret = mlen;
}
out:
- complete_request_key(cons, ret);
+ nfs_idmap_complete_pipe_upcall_locked(idmap, ret);
+out_noupcall:
return ret;
}
@@ -788,14 +826,9 @@ idmap_pipe_destroy_msg(struct rpc_pipe_msg *msg)
struct idmap_legacy_upcalldata,
pipe_msg);
struct idmap *idmap = data->idmap;
- struct key_construction *cons;
- if (msg->errno) {
- cons = ACCESS_ONCE(idmap->idmap_key_cons);
- idmap->idmap_key_cons = NULL;
- complete_request_key(cons, msg->errno);
- }
- /* Free memory allocated in nfs_idmap_legacy_upcall() */
- kfree(data);
+
+ if (msg->errno)
+ nfs_idmap_abort_pipe_upcall(idmap, msg->errno);
}
static void
@@ -803,7 +836,8 @@ idmap_release_pipe(struct inode *inode)
{
struct rpc_inode *rpci = RPC_I(inode);
struct idmap *idmap = (struct idmap *)rpci->private;
- idmap->idmap_key_cons = NULL;
+
+ nfs_idmap_abort_pipe_upcall(idmap, -EPIPE);
}
int nfs_map_name_to_uid(const struct nfs_server *server, const char *name, size_t namelen, __u32 *uid)
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index e4c716d..5c7325c 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -547,8 +547,8 @@ EXPORT_SYMBOL_GPL(nfs_getattr);
static void nfs_init_lock_context(struct nfs_lock_context *l_ctx)
{
atomic_set(&l_ctx->count, 1);
- l_ctx->lockowner = current->files;
- l_ctx->pid = current->tgid;
+ l_ctx->lockowner.l_owner = current->files;
+ l_ctx->lockowner.l_pid = current->tgid;
INIT_LIST_HEAD(&l_ctx->list);
}
@@ -557,9 +557,9 @@ static struct nfs_lock_context *__nfs_find_lock_context(struct nfs_open_context
struct nfs_lock_context *pos;
list_for_each_entry(pos, &ctx->lock_context.list, list) {
- if (pos->lockowner != current->files)
+ if (pos->lockowner.l_owner != current->files)
continue;
- if (pos->pid != current->tgid)
+ if (pos->lockowner.l_pid != current->tgid)
continue;
atomic_inc(&pos->count);
return pos;
@@ -578,7 +578,7 @@ struct nfs_lock_context *nfs_get_lock_context(struct nfs_open_context *ctx)
spin_unlock(&inode->i_lock);
new = kmalloc(sizeof(*new), GFP_KERNEL);
if (new == NULL)
- return NULL;
+ return ERR_PTR(-ENOMEM);
nfs_init_lock_context(new);
spin_lock(&inode->i_lock);
res = __nfs_find_lock_context(ctx);
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index 31fdb03..59b133c 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -101,11 +101,11 @@ struct nfs_client_initdata {
*/
struct nfs_parsed_mount_data {
int flags;
- int rsize, wsize;
- int timeo, retrans;
- int acregmin, acregmax,
+ unsigned int rsize, wsize;
+ unsigned int timeo, retrans;
+ unsigned int acregmin, acregmax,
acdirmin, acdirmax;
- int namlen;
+ unsigned int namlen;
unsigned int options;
unsigned int bsize;
unsigned int auth_flavor_len;
@@ -464,6 +464,7 @@ static inline void nfs_inode_dio_wait(struct inode *inode)
{
inode_dio_wait(inode);
}
+extern ssize_t nfs_dreq_bytes_left(struct nfs_direct_req *dreq);
/* nfs4proc.c */
extern void __nfs4_read_done_cb(struct nfs_read_data *);
@@ -483,6 +484,12 @@ extern int _nfs4_call_sync_session(struct rpc_clnt *clnt,
struct nfs4_sequence_args *args,
struct nfs4_sequence_res *res,
int cache_reply);
+extern int nfs40_walk_client_list(struct nfs_client *clp,
+ struct nfs_client **result,
+ struct rpc_cred *cred);
+extern int nfs41_walk_client_list(struct nfs_client *clp,
+ struct nfs_client **result,
+ struct rpc_cred *cred);
/*
* Determine the device name as a string
diff --git a/fs/nfs/netns.h b/fs/nfs/netns.h
index 0539de1..8ee1fab 100644
--- a/fs/nfs/netns.h
+++ b/fs/nfs/netns.h
@@ -5,6 +5,7 @@
#ifndef __NFS_NETNS_H__
#define __NFS_NETNS_H__
+#include <linux/nfs4.h>
#include <net/net_namespace.h>
#include <net/netns/generic.h>
@@ -22,6 +23,9 @@ struct nfs_net {
struct list_head nfs_volume_list;
#if IS_ENABLED(CONFIG_NFS_V4)
struct idr cb_ident_idr; /* Protected by nfs_client_lock */
+ unsigned short nfs_callback_tcpport;
+ unsigned short nfs_callback_tcpport6;
+ int cb_users[NFS4_MAX_MINOR_VERSION + 1];
#endif
spinlock_t nfs_client_lock;
struct timespec boot_time;
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h
index da0618a..a525fde 100644
--- a/fs/nfs/nfs4_fs.h
+++ b/fs/nfs/nfs4_fs.h
@@ -132,8 +132,8 @@ struct nfs4_lock_owner {
struct nfs4_lock_state {
struct list_head ls_locks; /* Other lock stateids */
struct nfs4_state * ls_state; /* Pointer to open state */
-#define NFS_LOCK_INITIALIZED 1
- int ls_flags;
+#define NFS_LOCK_INITIALIZED 0
+ unsigned long ls_flags;
struct nfs_seqid_counter ls_seqid;
nfs4_stateid ls_stateid;
atomic_t ls_count;
@@ -191,6 +191,8 @@ struct nfs4_state_recovery_ops {
int (*establish_clid)(struct nfs_client *, struct rpc_cred *);
struct rpc_cred * (*get_clid_cred)(struct nfs_client *);
int (*reclaim_complete)(struct nfs_client *);
+ int (*detect_trunking)(struct nfs_client *, struct nfs_client **,
+ struct rpc_cred *);
};
struct nfs4_state_maintenance_ops {
@@ -223,7 +225,7 @@ extern int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred);
extern int nfs4_destroy_clientid(struct nfs_client *clp);
extern int nfs4_init_clientid(struct nfs_client *, struct rpc_cred *);
extern int nfs41_init_clientid(struct nfs_client *, struct rpc_cred *);
-extern int nfs4_do_close(struct nfs4_state *state, gfp_t gfp_mask, int wait, bool roc);
+extern int nfs4_do_close(struct nfs4_state *state, gfp_t gfp_mask, int wait);
extern int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle);
extern int nfs4_proc_fs_locations(struct rpc_clnt *, struct inode *, const struct qstr *,
struct nfs4_fs_locations *, struct page *);
@@ -320,9 +322,15 @@ extern void nfs4_renew_state(struct work_struct *);
/* nfs4state.c */
struct rpc_cred *nfs4_get_setclientid_cred(struct nfs_client *clp);
struct rpc_cred *nfs4_get_renew_cred_locked(struct nfs_client *clp);
+int nfs4_discover_server_trunking(struct nfs_client *clp,
+ struct nfs_client **);
+int nfs40_discover_server_trunking(struct nfs_client *clp,
+ struct nfs_client **, struct rpc_cred *);
#if defined(CONFIG_NFS_V4_1)
struct rpc_cred *nfs4_get_machine_cred_locked(struct nfs_client *clp);
struct rpc_cred *nfs4_get_exchange_id_cred(struct nfs_client *clp);
+int nfs41_discover_server_trunking(struct nfs_client *clp,
+ struct nfs_client **, struct rpc_cred *);
extern void nfs4_schedule_session_recovery(struct nfs4_session *, int);
#else
static inline void nfs4_schedule_session_recovery(struct nfs4_session *session, int err)
@@ -351,7 +359,7 @@ extern void nfs41_handle_server_scope(struct nfs_client *,
extern void nfs4_put_lock_state(struct nfs4_lock_state *lsp);
extern int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl);
extern void nfs4_select_rw_stateid(nfs4_stateid *, struct nfs4_state *,
- fmode_t, fl_owner_t, pid_t);
+ fmode_t, const struct nfs_lockowner *);
extern struct nfs_seqid *nfs_alloc_seqid(struct nfs_seqid_counter *counter, gfp_t gfp_mask);
extern int nfs_wait_on_sequence(struct nfs_seqid *seqid, struct rpc_task *task);
@@ -372,6 +380,9 @@ extern bool nfs4_disable_idmapping;
extern unsigned short max_session_slots;
extern unsigned short send_implementation_id;
+#define NFS4_CLIENT_ID_UNIQ_LEN (64)
+extern char nfs4_client_id_uniquifier[NFS4_CLIENT_ID_UNIQ_LEN];
+
/* nfs4sysctl.c */
#ifdef CONFIG_SYSCTL
int nfs4_register_sysctl(void);
diff --git a/fs/nfs/nfs4client.c b/fs/nfs/nfs4client.c
index 24eb663..6bacfde 100644
--- a/fs/nfs/nfs4client.c
+++ b/fs/nfs/nfs4client.c
@@ -84,7 +84,7 @@ error:
static void nfs4_destroy_callback(struct nfs_client *clp)
{
if (__test_and_clear_bit(NFS_CS_CALLBACK, &clp->cl_res_state))
- nfs_callback_down(clp->cl_mvops->minor_version);
+ nfs_callback_down(clp->cl_mvops->minor_version, clp->cl_net);
}
static void nfs4_shutdown_client(struct nfs_client *clp)
@@ -185,6 +185,7 @@ struct nfs_client *nfs4_init_client(struct nfs_client *clp,
rpc_authflavor_t authflavour)
{
char buf[INET6_ADDRSTRLEN + 1];
+ struct nfs_client *old;
int error;
if (clp->cl_cons_state == NFS_CS_READY) {
@@ -230,6 +231,17 @@ struct nfs_client *nfs4_init_client(struct nfs_client *clp,
if (!nfs4_has_session(clp))
nfs_mark_client_ready(clp, NFS_CS_READY);
+
+ error = nfs4_discover_server_trunking(clp, &old);
+ if (error < 0)
+ goto error;
+ if (clp != old) {
+ clp->cl_preserve_clid = true;
+ nfs_put_client(clp);
+ clp = old;
+ atomic_inc(&clp->cl_count);
+ }
+
return clp;
error:
@@ -239,6 +251,248 @@ error:
return ERR_PTR(error);
}
+/*
+ * SETCLIENTID just did a callback update with the callback ident in
+ * "drop," but server trunking discovery claims "drop" and "keep" are
+ * actually the same server. Swap the callback IDs so that "keep"
+ * will continue to use the callback ident the server now knows about,
+ * and so that "keep"'s original callback ident is destroyed when
+ * "drop" is freed.
+ */
+static void nfs4_swap_callback_idents(struct nfs_client *keep,
+ struct nfs_client *drop)
+{
+ struct nfs_net *nn = net_generic(keep->cl_net, nfs_net_id);
+ unsigned int save = keep->cl_cb_ident;
+
+ if (keep->cl_cb_ident == drop->cl_cb_ident)
+ return;
+
+ dprintk("%s: keeping callback ident %u and dropping ident %u\n",
+ __func__, keep->cl_cb_ident, drop->cl_cb_ident);
+
+ spin_lock(&nn->nfs_client_lock);
+
+ idr_replace(&nn->cb_ident_idr, keep, drop->cl_cb_ident);
+ keep->cl_cb_ident = drop->cl_cb_ident;
+
+ idr_replace(&nn->cb_ident_idr, drop, save);
+ drop->cl_cb_ident = save;
+
+ spin_unlock(&nn->nfs_client_lock);
+}
+
+/**
+ * nfs40_walk_client_list - Find server that recognizes a client ID
+ *
+ * @new: nfs_client with client ID to test
+ * @result: OUT: found nfs_client, or new
+ * @cred: credential to use for trunking test
+ *
+ * Returns zero, a negative errno, or a negative NFS4ERR status.
+ * If zero is returned, an nfs_client pointer is planted in "result."
+ *
+ * NB: nfs40_walk_client_list() relies on the new nfs_client being
+ * the last nfs_client on the list.
+ */
+int nfs40_walk_client_list(struct nfs_client *new,
+ struct nfs_client **result,
+ struct rpc_cred *cred)
+{
+ struct nfs_net *nn = net_generic(new->cl_net, nfs_net_id);
+ struct nfs_client *pos, *n, *prev = NULL;
+ struct nfs4_setclientid_res clid = {
+ .clientid = new->cl_clientid,
+ .confirm = new->cl_confirm,
+ };
+ int status;
+
+ spin_lock(&nn->nfs_client_lock);
+ list_for_each_entry_safe(pos, n, &nn->nfs_client_list, cl_share_link) {
+ /* If "pos" isn't marked ready, we can't trust the
+ * remaining fields in "pos" */
+ if (pos->cl_cons_state < NFS_CS_READY)
+ continue;
+
+ if (pos->rpc_ops != new->rpc_ops)
+ continue;
+
+ if (pos->cl_proto != new->cl_proto)
+ continue;
+
+ if (pos->cl_minorversion != new->cl_minorversion)
+ continue;
+
+ if (pos->cl_clientid != new->cl_clientid)
+ continue;
+
+ atomic_inc(&pos->cl_count);
+ spin_unlock(&nn->nfs_client_lock);
+
+ if (prev)
+ nfs_put_client(prev);
+
+ status = nfs4_proc_setclientid_confirm(pos, &clid, cred);
+ if (status == 0) {
+ nfs4_swap_callback_idents(pos, new);
+
+ nfs_put_client(pos);
+ *result = pos;
+ dprintk("NFS: <-- %s using nfs_client = %p ({%d})\n",
+ __func__, pos, atomic_read(&pos->cl_count));
+ return 0;
+ }
+ if (status != -NFS4ERR_STALE_CLIENTID) {
+ nfs_put_client(pos);
+ dprintk("NFS: <-- %s status = %d, no result\n",
+ __func__, status);
+ return status;
+ }
+
+ spin_lock(&nn->nfs_client_lock);
+ prev = pos;
+ }
+
+ /*
+ * No matching nfs_client found. This should be impossible,
+ * because the new nfs_client has already been added to
+ * nfs_client_list by nfs_get_client().
+ *
+ * Don't BUG(), since the caller is holding a mutex.
+ */
+ if (prev)
+ nfs_put_client(prev);
+ spin_unlock(&nn->nfs_client_lock);
+ pr_err("NFS: %s Error: no matching nfs_client found\n", __func__);
+ return -NFS4ERR_STALE_CLIENTID;
+}
+
+#ifdef CONFIG_NFS_V4_1
+/*
+ * Returns true if the client IDs match
+ */
+static bool nfs4_match_clientids(struct nfs_client *a, struct nfs_client *b)
+{
+ if (a->cl_clientid != b->cl_clientid) {
+ dprintk("NFS: --> %s client ID %llx does not match %llx\n",
+ __func__, a->cl_clientid, b->cl_clientid);
+ return false;
+ }
+ dprintk("NFS: --> %s client ID %llx matches %llx\n",
+ __func__, a->cl_clientid, b->cl_clientid);
+ return true;
+}
+
+/*
+ * Returns true if the server owners match
+ */
+static bool
+nfs4_match_serverowners(struct nfs_client *a, struct nfs_client *b)
+{
+ struct nfs41_server_owner *o1 = a->cl_serverowner;
+ struct nfs41_server_owner *o2 = b->cl_serverowner;
+
+ if (o1->minor_id != o2->minor_id) {
+ dprintk("NFS: --> %s server owner minor IDs do not match\n",
+ __func__);
+ return false;
+ }
+
+ if (o1->major_id_sz != o2->major_id_sz)
+ goto out_major_mismatch;
+ if (memcmp(o1->major_id, o2->major_id, o1->major_id_sz) != 0)
+ goto out_major_mismatch;
+
+ dprintk("NFS: --> %s server owners match\n", __func__);
+ return true;
+
+out_major_mismatch:
+ dprintk("NFS: --> %s server owner major IDs do not match\n",
+ __func__);
+ return false;
+}
+
+/**
+ * nfs41_walk_client_list - Find nfs_client that matches a client/server owner
+ *
+ * @new: nfs_client with client ID to test
+ * @result: OUT: found nfs_client, or new
+ * @cred: credential to use for trunking test
+ *
+ * Returns zero, a negative errno, or a negative NFS4ERR status.
+ * If zero is returned, an nfs_client pointer is planted in "result."
+ *
+ * NB: nfs41_walk_client_list() relies on the new nfs_client being
+ * the last nfs_client on the list.
+ */
+int nfs41_walk_client_list(struct nfs_client *new,
+ struct nfs_client **result,
+ struct rpc_cred *cred)
+{
+ struct nfs_net *nn = net_generic(new->cl_net, nfs_net_id);
+ struct nfs_client *pos, *n, *prev = NULL;
+ int error;
+
+ spin_lock(&nn->nfs_client_lock);
+ list_for_each_entry_safe(pos, n, &nn->nfs_client_list, cl_share_link) {
+ /* If "pos" isn't marked ready, we can't trust the
+ * remaining fields in "pos", especially the client
+ * ID and serverowner fields. Wait for CREATE_SESSION
+ * to finish. */
+ if (pos->cl_cons_state < NFS_CS_READY) {
+ atomic_inc(&pos->cl_count);
+ spin_unlock(&nn->nfs_client_lock);
+
+ if (prev)
+ nfs_put_client(prev);
+ prev = pos;
+
+ error = nfs_wait_client_init_complete(pos);
+ if (error < 0) {
+ nfs_put_client(pos);
+ spin_lock(&nn->nfs_client_lock);
+ continue;
+ }
+
+ spin_lock(&nn->nfs_client_lock);
+ }
+
+ if (pos->rpc_ops != new->rpc_ops)
+ continue;
+
+ if (pos->cl_proto != new->cl_proto)
+ continue;
+
+ if (pos->cl_minorversion != new->cl_minorversion)
+ continue;
+
+ if (!nfs4_match_clientids(pos, new))
+ continue;
+
+ if (!nfs4_match_serverowners(pos, new))
+ continue;
+
+ spin_unlock(&nn->nfs_client_lock);
+ dprintk("NFS: <-- %s using nfs_client = %p ({%d})\n",
+ __func__, pos, atomic_read(&pos->cl_count));
+
+ *result = pos;
+ return 0;
+ }
+
+ /*
+ * No matching nfs_client found. This should be impossible,
+ * because the new nfs_client has already been added to
+ * nfs_client_list by nfs_get_client().
+ *
+ * Don't BUG(), since the caller is holding a mutex.
+ */
+ spin_unlock(&nn->nfs_client_lock);
+ pr_err("NFS: %s Error: no matching nfs_client found\n", __func__);
+ return -NFS4ERR_STALE_CLIENTID;
+}
+#endif /* CONFIG_NFS_V4_1 */
+
static void nfs4_destroy_server(struct nfs_server *server)
{
nfs_server_return_all_delegations(server);
diff --git a/fs/nfs/nfs4file.c b/fs/nfs/nfs4file.c
index eb5eb8e..afddd66 100644
--- a/fs/nfs/nfs4file.c
+++ b/fs/nfs/nfs4file.c
@@ -95,16 +95,25 @@ nfs4_file_fsync(struct file *file, loff_t start, loff_t end, int datasync)
int ret;
struct inode *inode = file->f_path.dentry->d_inode;
- ret = filemap_write_and_wait_range(inode->i_mapping, start, end);
- if (ret != 0)
- goto out;
- mutex_lock(&inode->i_mutex);
- ret = nfs_file_fsync_commit(file, start, end, datasync);
- if (!ret && !datasync)
- /* application has asked for meta-data sync */
- ret = pnfs_layoutcommit_inode(inode, true);
- mutex_unlock(&inode->i_mutex);
-out:
+ do {
+ ret = filemap_write_and_wait_range(inode->i_mapping, start, end);
+ if (ret != 0)
+ break;
+ mutex_lock(&inode->i_mutex);
+ ret = nfs_file_fsync_commit(file, start, end, datasync);
+ if (!ret && !datasync)
+ /* application has asked for meta-data sync */
+ ret = pnfs_layoutcommit_inode(inode, true);
+ mutex_unlock(&inode->i_mutex);
+ /*
+ * If nfs_file_fsync_commit detected a server reboot, then
+ * resend all dirty pages that might have been covered by
+ * the NFS_CONTEXT_RESEND_WRITES flag
+ */
+ start = 0;
+ end = LLONG_MAX;
+ } while (ret == -EAGAIN);
+
return ret;
}
diff --git a/fs/nfs/nfs4filelayout.c b/fs/nfs/nfs4filelayout.c
index 53f94d9..52d8472 100644
--- a/fs/nfs/nfs4filelayout.c
+++ b/fs/nfs/nfs4filelayout.c
@@ -190,8 +190,6 @@ static int filelayout_async_handle_error(struct rpc_task *task,
* i/o and all i/o waiting on the slot table to the MDS until
* layout is destroyed and a new valid layout is obtained.
*/
- set_bit(NFS_LAYOUT_INVALID,
- &NFS_I(inode)->layout->plh_flags);
pnfs_destroy_layout(NFS_I(inode));
rpc_wake_up(&tbl->slot_tbl_waitq);
goto reset;
@@ -205,7 +203,7 @@ static int filelayout_async_handle_error(struct rpc_task *task,
case -EPIPE:
dprintk("%s DS connection error %d\n", __func__,
task->tk_status);
- filelayout_mark_devid_invalid(devid);
+ nfs4_mark_deviceid_unavailable(devid);
clear_bit(NFS_INO_LAYOUTCOMMIT, &NFS_I(inode)->flags);
_pnfs_return_layout(inode);
rpc_wake_up(&tbl->slot_tbl_waitq);
@@ -269,6 +267,21 @@ filelayout_set_layoutcommit(struct nfs_write_data *wdata)
(unsigned long) NFS_I(hdr->inode)->layout->plh_lwb);
}
+bool
+filelayout_test_devid_unavailable(struct nfs4_deviceid_node *node)
+{
+ return filelayout_test_devid_invalid(node) ||
+ nfs4_test_deviceid_unavailable(node);
+}
+
+static bool
+filelayout_reset_to_mds(struct pnfs_layout_segment *lseg)
+{
+ struct nfs4_deviceid_node *node = FILELAYOUT_DEVID_NODE(lseg);
+
+ return filelayout_test_devid_unavailable(node);
+}
+
/*
* Call ops for the async read/write cases
* In the case of dense layouts, the offset needs to be reset to its
@@ -453,7 +466,7 @@ static void filelayout_commit_release(void *calldata)
struct nfs_commit_data *data = calldata;
data->completion_ops->completion(data);
- put_lseg(data->lseg);
+ pnfs_put_lseg(data->lseg);
nfs_put_client(data->ds_clp);
nfs_commitdata_release(data);
}
@@ -608,13 +621,13 @@ filelayout_check_layout(struct pnfs_layout_hdr *lo,
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);
+ dsaddr = filelayout_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);
- /* Found deviceid is being reaped */
- if (test_bit(NFS_DEVICEID_INVALID, &dsaddr->id_node.flags))
+ /* Found deviceid is unavailable */
+ if (filelayout_test_devid_unavailable(&dsaddr->id_node))
goto out_put;
fl->dsaddr = dsaddr;
@@ -931,7 +944,7 @@ filelayout_pg_init_write(struct nfs_pageio_descriptor *pgio,
nfs_init_cinfo(&cinfo, pgio->pg_inode, pgio->pg_dreq);
status = filelayout_alloc_commit_info(pgio->pg_lseg, &cinfo, GFP_NOFS);
if (status < 0) {
- put_lseg(pgio->pg_lseg);
+ pnfs_put_lseg(pgio->pg_lseg);
pgio->pg_lseg = NULL;
goto out_mds;
}
@@ -985,7 +998,7 @@ filelayout_clear_request_commit(struct nfs_page *req,
out:
nfs_request_remove_commit_list(req, cinfo);
spin_unlock(cinfo->lock);
- put_lseg(freeme);
+ pnfs_put_lseg(freeme);
}
static struct list_head *
@@ -1018,7 +1031,7 @@ filelayout_choose_commit_list(struct nfs_page *req,
* off due to a rewrite, in which case it will be done in
* filelayout_clear_request_commit
*/
- buckets[i].wlseg = get_lseg(lseg);
+ buckets[i].wlseg = pnfs_get_lseg(lseg);
}
set_bit(PG_COMMIT_TO_DS, &req->wb_flags);
cinfo->ds->nwritten++;
@@ -1128,7 +1141,7 @@ filelayout_scan_ds_commit_list(struct pnfs_commit_bucket *bucket,
if (list_empty(src))
bucket->wlseg = NULL;
else
- get_lseg(bucket->clseg);
+ pnfs_get_lseg(bucket->clseg);
}
return ret;
}
@@ -1159,12 +1172,12 @@ static void filelayout_recover_commit_reqs(struct list_head *dst,
/* NOTE cinfo->lock is NOT held, relying on fact that this is
* only called on single thread per dreq.
- * Can't take the lock because need to do put_lseg
+ * Can't take the lock because need to do pnfs_put_lseg
*/
for (i = 0, b = cinfo->ds->buckets; i < cinfo->ds->nbuckets; i++, b++) {
if (transfer_commit_list(&b->written, dst, cinfo, 0)) {
BUG_ON(!list_empty(&b->written));
- put_lseg(b->wlseg);
+ pnfs_put_lseg(b->wlseg);
b->wlseg = NULL;
}
}
@@ -1200,7 +1213,7 @@ alloc_ds_commits(struct nfs_commit_info *cinfo, struct list_head *list)
if (list_empty(&bucket->committing))
continue;
nfs_retry_commit(&bucket->committing, bucket->clseg, cinfo);
- put_lseg(bucket->clseg);
+ pnfs_put_lseg(bucket->clseg);
bucket->clseg = NULL;
}
/* Caller will clean up entries put on list */
diff --git a/fs/nfs/nfs4filelayout.h b/fs/nfs/nfs4filelayout.h
index 43fe802..dca47d78 100644
--- a/fs/nfs/nfs4filelayout.h
+++ b/fs/nfs/nfs4filelayout.h
@@ -129,23 +129,13 @@ filelayout_mark_devid_invalid(struct nfs4_deviceid_node *node)
}
static inline bool
-filelayout_test_layout_invalid(struct pnfs_layout_hdr *lo)
-{
- return test_bit(NFS_LAYOUT_INVALID, &lo->plh_flags);
-}
-
-static inline bool
filelayout_test_devid_invalid(struct nfs4_deviceid_node *node)
{
return test_bit(NFS_DEVICEID_INVALID, &node->flags);
}
-static inline bool
-filelayout_reset_to_mds(struct pnfs_layout_segment *lseg)
-{
- return filelayout_test_devid_invalid(FILELAYOUT_DEVID_NODE(lseg)) ||
- filelayout_test_layout_invalid(lseg->pls_layout);
-}
+extern bool
+filelayout_test_devid_unavailable(struct nfs4_deviceid_node *node);
extern struct nfs_fh *
nfs4_fl_select_ds_fh(struct pnfs_layout_segment *lseg, u32 j);
@@ -158,7 +148,7 @@ struct nfs4_pnfs_ds *nfs4_fl_prepare_ds(struct pnfs_layout_segment *lseg,
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);
+filelayout_get_device_info(struct inode *inode, struct nfs4_deviceid *dev_id, gfp_t gfp_flags);
void nfs4_ds_disconnect(struct nfs_client *clp);
#endif /* FS_NFS_NFS4FILELAYOUT_H */
diff --git a/fs/nfs/nfs4filelayoutdev.c b/fs/nfs/nfs4filelayoutdev.c
index f81231f..3336d5e 100644
--- a/fs/nfs/nfs4filelayoutdev.c
+++ b/fs/nfs/nfs4filelayoutdev.c
@@ -690,7 +690,7 @@ decode_and_add_device(struct inode *inode, struct pnfs_device *dev, gfp_t gfp_fl
* of available devices, and return it.
*/
struct nfs4_file_layout_dsaddr *
-get_device_info(struct inode *inode, struct nfs4_deviceid *dev_id, gfp_t gfp_flags)
+filelayout_get_device_info(struct inode *inode, struct nfs4_deviceid *dev_id, gfp_t gfp_flags)
{
struct pnfs_device *pdev = NULL;
u32 max_resp_sz;
@@ -804,13 +804,14 @@ nfs4_fl_prepare_ds(struct pnfs_layout_segment *lseg, u32 ds_idx)
struct nfs4_pnfs_ds *ds = dsaddr->ds_list[ds_idx];
struct nfs4_deviceid_node *devid = FILELAYOUT_DEVID_NODE(lseg);
- if (filelayout_test_devid_invalid(devid))
+ if (filelayout_test_devid_unavailable(devid))
return NULL;
if (ds == NULL) {
printk(KERN_ERR "NFS: %s: No data server for offset index %d\n",
__func__, ds_idx);
- goto mark_dev_invalid;
+ filelayout_mark_devid_invalid(devid);
+ return NULL;
}
if (!ds->ds_clp) {
@@ -818,14 +819,12 @@ nfs4_fl_prepare_ds(struct pnfs_layout_segment *lseg, u32 ds_idx)
int err;
err = nfs4_ds_connect(s, ds);
- if (err)
- goto mark_dev_invalid;
+ if (err) {
+ nfs4_mark_deviceid_unavailable(devid);
+ return NULL;
+ }
}
return ds;
-
-mark_dev_invalid:
- filelayout_mark_devid_invalid(devid);
- return NULL;
}
module_param(dataserver_retrans, uint, 0644);
diff --git a/fs/nfs/nfs4namespace.c b/fs/nfs/nfs4namespace.c
index 017b4b0..79fbb61 100644
--- a/fs/nfs/nfs4namespace.c
+++ b/fs/nfs/nfs4namespace.c
@@ -192,25 +192,13 @@ out:
struct rpc_clnt *nfs4_create_sec_client(struct rpc_clnt *clnt, struct inode *inode,
struct qstr *name)
{
- struct rpc_clnt *clone;
- struct rpc_auth *auth;
rpc_authflavor_t flavor;
flavor = nfs4_negotiate_security(inode, name);
if ((int)flavor < 0)
- return ERR_PTR(flavor);
+ return ERR_PTR((int)flavor);
- clone = rpc_clone_client(clnt);
- if (IS_ERR(clone))
- return clone;
-
- auth = rpcauth_create(flavor, clone);
- if (!auth) {
- rpc_shutdown_client(clone);
- clone = ERR_PTR(-EIO);
- }
-
- return clone;
+ return rpc_clone_client_set_auth(clnt, flavor);
}
static struct vfsmount *try_location(struct nfs_clone_mount *mountdata,
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 1e50326..68b21d8 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -104,6 +104,8 @@ static int nfs4_map_errors(int err)
return -EACCES;
case -NFS4ERR_MINOR_VERS_MISMATCH:
return -EPROTONOSUPPORT;
+ case -NFS4ERR_ACCESS:
+ return -EACCES;
default:
dprintk("%s could not handle NFSv4 error %d\n",
__func__, -err);
@@ -150,6 +152,12 @@ static const u32 nfs4_pnfs_open_bitmap[3] = {
FATTR4_WORD2_MDSTHRESHOLD
};
+static const u32 nfs4_open_noattr_bitmap[3] = {
+ FATTR4_WORD0_TYPE
+ | FATTR4_WORD0_CHANGE
+ | FATTR4_WORD0_FILEID,
+};
+
const u32 nfs4_statfs_bitmap[2] = {
FATTR4_WORD0_FILES_AVAIL
| FATTR4_WORD0_FILES_FREE
@@ -832,6 +840,7 @@ static void nfs4_init_opendata_res(struct nfs4_opendata *p)
p->o_res.seqid = p->o_arg.seqid;
p->c_res.seqid = p->c_arg.seqid;
p->o_res.server = p->o_arg.server;
+ p->o_res.access_request = p->o_arg.access;
nfs_fattr_init(&p->f_attr);
nfs_fattr_init_names(&p->f_attr, &p->owner_name, &p->group_name);
}
@@ -860,6 +869,14 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry,
p->o_arg.fh = NFS_FH(dir);
p->o_arg.open_flags = flags;
p->o_arg.fmode = fmode & (FMODE_READ|FMODE_WRITE);
+ /* don't put an ACCESS op in OPEN compound if O_EXCL, because ACCESS
+ * will return permission denied for all bits until close */
+ if (!(flags & O_EXCL)) {
+ /* ask server to check for all possible rights as results
+ * are cached */
+ p->o_arg.access = NFS4_ACCESS_READ | NFS4_ACCESS_MODIFY |
+ NFS4_ACCESS_EXTEND | NFS4_ACCESS_EXECUTE;
+ }
p->o_arg.clientid = server->nfs_client->cl_clientid;
p->o_arg.id.create_time = ktime_to_ns(sp->so_seqid.create_time);
p->o_arg.id.uniquifier = sp->so_seqid.owner_id;
@@ -1115,11 +1132,80 @@ out_return_state:
return state;
}
-static struct nfs4_state *nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data)
+static void
+nfs4_opendata_check_deleg(struct nfs4_opendata *data, struct nfs4_state *state)
+{
+ struct nfs_client *clp = NFS_SERVER(state->inode)->nfs_client;
+ struct nfs_delegation *delegation;
+ int delegation_flags = 0;
+
+ rcu_read_lock();
+ delegation = rcu_dereference(NFS_I(state->inode)->delegation);
+ if (delegation)
+ delegation_flags = delegation->flags;
+ rcu_read_unlock();
+ if (data->o_arg.claim == NFS4_OPEN_CLAIM_DELEGATE_CUR) {
+ pr_err_ratelimited("NFS: Broken NFSv4 server %s is "
+ "returning a delegation for "
+ "OPEN(CLAIM_DELEGATE_CUR)\n",
+ clp->cl_hostname);
+ } else if ((delegation_flags & 1UL<<NFS_DELEGATION_NEED_RECLAIM) == 0)
+ nfs_inode_set_delegation(state->inode,
+ data->owner->so_cred,
+ &data->o_res);
+ else
+ nfs_inode_reclaim_delegation(state->inode,
+ data->owner->so_cred,
+ &data->o_res);
+}
+
+/*
+ * Check the inode attributes against the CLAIM_PREVIOUS returned attributes
+ * and update the nfs4_state.
+ */
+static struct nfs4_state *
+_nfs4_opendata_reclaim_to_nfs4_state(struct nfs4_opendata *data)
+{
+ struct inode *inode = data->state->inode;
+ struct nfs4_state *state = data->state;
+ int ret;
+
+ if (!data->rpc_done) {
+ ret = data->rpc_status;
+ goto err;
+ }
+
+ ret = -ESTALE;
+ if (!(data->f_attr.valid & NFS_ATTR_FATTR_TYPE) ||
+ !(data->f_attr.valid & NFS_ATTR_FATTR_FILEID) ||
+ !(data->f_attr.valid & NFS_ATTR_FATTR_CHANGE))
+ goto err;
+
+ ret = -ENOMEM;
+ state = nfs4_get_open_state(inode, data->owner);
+ if (state == NULL)
+ goto err;
+
+ ret = nfs_refresh_inode(inode, &data->f_attr);
+ if (ret)
+ goto err;
+
+ if (data->o_res.delegation_type != 0)
+ nfs4_opendata_check_deleg(data, state);
+ update_open_stateid(state, &data->o_res.stateid, NULL,
+ data->o_arg.fmode);
+
+ return state;
+err:
+ return ERR_PTR(ret);
+
+}
+
+static struct nfs4_state *
+_nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data)
{
struct inode *inode;
struct nfs4_state *state = NULL;
- struct nfs_delegation *delegation;
int ret;
if (!data->rpc_done) {
@@ -1138,30 +1224,8 @@ static struct nfs4_state *nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data
state = nfs4_get_open_state(inode, data->owner);
if (state == NULL)
goto err_put_inode;
- if (data->o_res.delegation_type != 0) {
- struct nfs_client *clp = NFS_SERVER(inode)->nfs_client;
- int delegation_flags = 0;
-
- rcu_read_lock();
- delegation = rcu_dereference(NFS_I(inode)->delegation);
- if (delegation)
- delegation_flags = delegation->flags;
- rcu_read_unlock();
- if (data->o_arg.claim == NFS4_OPEN_CLAIM_DELEGATE_CUR) {
- pr_err_ratelimited("NFS: Broken NFSv4 server %s is "
- "returning a delegation for "
- "OPEN(CLAIM_DELEGATE_CUR)\n",
- clp->cl_hostname);
- } else if ((delegation_flags & 1UL<<NFS_DELEGATION_NEED_RECLAIM) == 0)
- nfs_inode_set_delegation(state->inode,
- data->owner->so_cred,
- &data->o_res);
- else
- nfs_inode_reclaim_delegation(state->inode,
- data->owner->so_cred,
- &data->o_res);
- }
-
+ if (data->o_res.delegation_type != 0)
+ nfs4_opendata_check_deleg(data, state);
update_open_stateid(state, &data->o_res.stateid, NULL,
data->o_arg.fmode);
iput(inode);
@@ -1173,6 +1237,14 @@ err:
return ERR_PTR(ret);
}
+static struct nfs4_state *
+nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data)
+{
+ if (data->o_arg.claim == NFS4_OPEN_CLAIM_PREVIOUS)
+ return _nfs4_opendata_reclaim_to_nfs4_state(data);
+ return _nfs4_opendata_to_nfs4_state(data);
+}
+
static struct nfs_open_context *nfs4_state_find_open_context(struct nfs4_state *state)
{
struct nfs_inode *nfsi = NFS_I(state->inode);
@@ -1494,6 +1566,7 @@ static void nfs4_open_prepare(struct rpc_task *task, void *calldata)
data->o_arg.clientid = sp->so_server->nfs_client->cl_clientid;
if (data->o_arg.claim == NFS4_OPEN_CLAIM_PREVIOUS) {
task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_NOATTR];
+ data->o_arg.open_bitmap = &nfs4_open_noattr_bitmap[0];
nfs_copy_fh(&data->o_res.fh, data->o_arg.fh);
}
data->timestamp = jiffies;
@@ -1526,7 +1599,8 @@ static void nfs4_open_done(struct rpc_task *task, void *calldata)
return;
if (task->tk_status == 0) {
- switch (data->o_res.f_attr->mode & S_IFMT) {
+ if (data->o_res.f_attr->valid & NFS_ATTR_FATTR_TYPE) {
+ switch (data->o_res.f_attr->mode & S_IFMT) {
case S_IFREG:
break;
case S_IFLNK:
@@ -1537,6 +1611,7 @@ static void nfs4_open_done(struct rpc_task *task, void *calldata)
break;
default:
data->rpc_status = -ENOTDIR;
+ }
}
renew_lease(data->o_res.server, data->timestamp);
if (!(data->o_res.rflags & NFS4_OPEN_RESULT_CONFIRM))
@@ -1643,6 +1718,39 @@ static int _nfs4_recover_proc_open(struct nfs4_opendata *data)
return status;
}
+static int nfs4_opendata_access(struct rpc_cred *cred,
+ struct nfs4_opendata *opendata,
+ struct nfs4_state *state, fmode_t fmode)
+{
+ struct nfs_access_entry cache;
+ u32 mask;
+
+ /* access call failed or for some reason the server doesn't
+ * support any access modes -- defer access call until later */
+ if (opendata->o_res.access_supported == 0)
+ return 0;
+
+ mask = 0;
+ /* don't check MAY_WRITE - a newly created file may not have
+ * write mode bits, but POSIX allows the creating process to write */
+ if (fmode & FMODE_READ)
+ mask |= MAY_READ;
+ if (fmode & FMODE_EXEC)
+ mask |= MAY_EXEC;
+
+ cache.cred = cred;
+ cache.jiffies = jiffies;
+ nfs_access_set_mask(&cache, opendata->o_res.access_result);
+ nfs_access_add_cache(state->inode, &cache);
+
+ if ((mask & ~cache.mask & (MAY_READ | MAY_EXEC)) == 0)
+ return 0;
+
+ /* even though OPEN succeeded, access is denied. Close the file */
+ nfs4_close_state(state, fmode);
+ return -NFS4ERR_ACCESS;
+}
+
/*
* Note: On error, nfs4_proc_open will free the struct nfs4_opendata
*/
@@ -1774,7 +1882,11 @@ static void nfs41_clear_delegation_stateid(struct nfs4_state *state)
* informs us the stateid is unrecognized. */
if (status != -NFS4ERR_BAD_STATEID)
nfs41_free_stateid(server, stateid);
+ nfs_remove_bad_delegation(state->inode);
+ write_seqlock(&state->seqlock);
+ nfs4_stateid_copy(&state->stateid, &state->open_stateid);
+ write_sequnlock(&state->seqlock);
clear_bit(NFS_DELEGATED_STATE, &state->flags);
}
}
@@ -1790,7 +1902,7 @@ static void nfs41_clear_delegation_stateid(struct nfs4_state *state)
static int nfs41_check_open_stateid(struct nfs4_state *state)
{
struct nfs_server *server = NFS_SERVER(state->inode);
- nfs4_stateid *stateid = &state->stateid;
+ nfs4_stateid *stateid = &state->open_stateid;
int status;
/* If a state reset has been done, test_stateid is unneeded */
@@ -1896,6 +2008,10 @@ static int _nfs4_do_open(struct inode *dir,
if (server->caps & NFS_CAP_POSIX_LOCK)
set_bit(NFS_STATE_POSIX_LOCKS, &state->flags);
+ status = nfs4_opendata_access(cred, opendata, state, fmode);
+ if (status != 0)
+ goto err_opendata_put;
+
if (opendata->o_arg.open_flags & O_EXCL) {
nfs4_exclusive_attrset(opendata, sattr);
@@ -1941,7 +2057,7 @@ static struct nfs4_state *nfs4_do_open(struct inode *dir,
struct nfs4_state *res;
int status;
- fmode &= FMODE_READ|FMODE_WRITE;
+ fmode &= FMODE_READ|FMODE_WRITE|FMODE_EXEC;
do {
status = _nfs4_do_open(dir, dentry, fmode, flags, sattr, cred,
&res, ctx_th);
@@ -2013,8 +2129,12 @@ static int _nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
nfs_fattr_init(fattr);
if (state != NULL) {
+ struct nfs_lockowner lockowner = {
+ .l_owner = current->files,
+ .l_pid = current->tgid,
+ };
nfs4_select_rw_stateid(&arg.stateid, state, FMODE_WRITE,
- current->files, current->tgid);
+ &lockowner);
} else if (nfs4_copy_delegation_stateid(&arg.stateid, inode,
FMODE_WRITE)) {
/* Use that stateid */
@@ -2133,6 +2253,7 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data)
{
struct nfs4_closedata *calldata = data;
struct nfs4_state *state = calldata->state;
+ struct inode *inode = calldata->inode;
int call_close = 0;
dprintk("%s: begin!\n", __func__);
@@ -2166,16 +2287,13 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data)
if (calldata->arg.fmode == 0) {
task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CLOSE];
if (calldata->roc &&
- pnfs_roc_drain(calldata->inode, &calldata->roc_barrier)) {
- rpc_sleep_on(&NFS_SERVER(calldata->inode)->roc_rpcwaitq,
- task, NULL);
+ pnfs_roc_drain(inode, &calldata->roc_barrier, task))
goto out;
- }
}
nfs_fattr_init(calldata->res.fattr);
calldata->timestamp = jiffies;
- if (nfs4_setup_sequence(NFS_SERVER(calldata->inode),
+ if (nfs4_setup_sequence(NFS_SERVER(inode),
&calldata->arg.seq_args,
&calldata->res.seq_res,
task))
@@ -2202,7 +2320,7 @@ static const struct rpc_call_ops nfs4_close_ops = {
*
* NOTE: Caller must be holding the sp->so_owner semaphore!
*/
-int nfs4_do_close(struct nfs4_state *state, gfp_t gfp_mask, int wait, bool roc)
+int nfs4_do_close(struct nfs4_state *state, gfp_t gfp_mask, int wait)
{
struct nfs_server *server = NFS_SERVER(state->inode);
struct nfs4_closedata *calldata;
@@ -2238,7 +2356,7 @@ int nfs4_do_close(struct nfs4_state *state, gfp_t gfp_mask, int wait, bool roc)
calldata->res.fattr = &calldata->fattr;
calldata->res.seqid = calldata->arg.seqid;
calldata->res.server = server;
- calldata->roc = roc;
+ calldata->roc = pnfs_roc(state->inode);
nfs_sb_active(calldata->inode->i_sb);
msg.rpc_argp = &calldata->arg;
@@ -2255,8 +2373,6 @@ int nfs4_do_close(struct nfs4_state *state, gfp_t gfp_mask, int wait, bool roc)
out_free_calldata:
kfree(calldata);
out:
- if (roc)
- pnfs_roc_release(state->inode);
nfs4_put_open_state(state);
nfs4_put_state_owner(sp);
return status;
@@ -2399,7 +2515,7 @@ static int nfs4_lookup_root_sec(struct nfs_server *server, struct nfs_fh *fhandl
int ret;
auth = rpcauth_create(flavor, server->client);
- if (!auth) {
+ if (IS_ERR(auth)) {
ret = -EIO;
goto out;
}
@@ -2767,13 +2883,7 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry
status = nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0);
if (!status) {
- entry->mask = 0;
- if (res.access & NFS4_ACCESS_READ)
- entry->mask |= MAY_READ;
- if (res.access & (NFS4_ACCESS_MODIFY | NFS4_ACCESS_EXTEND | NFS4_ACCESS_DELETE))
- entry->mask |= MAY_WRITE;
- if (res.access & (NFS4_ACCESS_LOOKUP|NFS4_ACCESS_EXECUTE))
- entry->mask |= MAY_EXEC;
+ nfs_access_set_mask(entry, res.access);
nfs_refresh_inode(inode, res.fattr);
}
nfs_free_fattr(res.fattr);
@@ -3362,8 +3472,11 @@ static int nfs4_proc_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, s
nfs_fattr_init(fsinfo->fattr);
error = nfs4_do_fsinfo(server, fhandle, fsinfo);
- if (error == 0)
+ if (error == 0) {
+ /* block layout checks this! */
+ server->pnfs_blksize = fsinfo->blksize;
set_pnfs_layoutdriver(server, fhandle, fsinfo->layouttype);
+ }
return error;
}
@@ -4007,6 +4120,36 @@ static void nfs4_init_boot_verifier(const struct nfs_client *clp,
memcpy(bootverf->data, verf, sizeof(bootverf->data));
}
+static unsigned int
+nfs4_init_nonuniform_client_string(const struct nfs_client *clp,
+ char *buf, size_t len)
+{
+ unsigned int result;
+
+ rcu_read_lock();
+ result = scnprintf(buf, len, "Linux NFSv4.0 %s/%s %s",
+ clp->cl_ipaddr,
+ rpc_peeraddr2str(clp->cl_rpcclient,
+ RPC_DISPLAY_ADDR),
+ rpc_peeraddr2str(clp->cl_rpcclient,
+ RPC_DISPLAY_PROTO));
+ rcu_read_unlock();
+ return result;
+}
+
+static unsigned int
+nfs4_init_uniform_client_string(const struct nfs_client *clp,
+ char *buf, size_t len)
+{
+ char *nodename = clp->cl_rpcclient->cl_nodename;
+
+ if (nfs4_client_id_uniquifier[0] != '\0')
+ nodename = nfs4_client_id_uniquifier;
+ return scnprintf(buf, len, "Linux NFSv%u.%u %s",
+ clp->rpc_ops->version, clp->cl_minorversion,
+ nodename);
+}
+
/**
* nfs4_proc_setclientid - Negotiate client ID
* @clp: state data structure
@@ -4037,15 +4180,18 @@ int nfs4_proc_setclientid(struct nfs_client *clp, u32 program,
/* nfs_client_id4 */
nfs4_init_boot_verifier(clp, &sc_verifier);
- rcu_read_lock();
- setclientid.sc_name_len = scnprintf(setclientid.sc_name,
- sizeof(setclientid.sc_name), "%s/%s %s",
- clp->cl_ipaddr,
- rpc_peeraddr2str(clp->cl_rpcclient,
- RPC_DISPLAY_ADDR),
- rpc_peeraddr2str(clp->cl_rpcclient,
- RPC_DISPLAY_PROTO));
+ if (test_bit(NFS_CS_MIGRATION, &clp->cl_flags))
+ setclientid.sc_name_len =
+ nfs4_init_uniform_client_string(clp,
+ setclientid.sc_name,
+ sizeof(setclientid.sc_name));
+ else
+ setclientid.sc_name_len =
+ nfs4_init_nonuniform_client_string(clp,
+ setclientid.sc_name,
+ sizeof(setclientid.sc_name));
/* cb_client4 */
+ rcu_read_lock();
setclientid.sc_netid_len = scnprintf(setclientid.sc_netid,
sizeof(setclientid.sc_netid),
rpc_peeraddr2str(clp->cl_rpcclient,
@@ -4391,7 +4537,7 @@ static void nfs4_locku_prepare(struct rpc_task *task, void *data)
if (nfs_wait_on_sequence(calldata->arg.seqid, task) != 0)
return;
- if ((calldata->lsp->ls_flags & NFS_LOCK_INITIALIZED) == 0) {
+ if (test_bit(NFS_LOCK_INITIALIZED, &calldata->lsp->ls_flags) == 0) {
/* Note: exit _without_ running nfs4_locku_done */
task->tk_action = NULL;
return;
@@ -4585,7 +4731,7 @@ static void nfs4_lock_done(struct rpc_task *task, void *calldata)
}
if (data->rpc_status == 0) {
nfs4_stateid_copy(&data->lsp->ls_stateid, &data->res.stateid);
- data->lsp->ls_flags |= NFS_LOCK_INITIALIZED;
+ set_bit(NFS_LOCK_INITIALIZED, &data->lsp->ls_flags);
renew_lease(NFS_SERVER(data->ctx->dentry->d_inode), data->timestamp);
}
out:
@@ -4632,7 +4778,7 @@ static void nfs4_handle_setlk_error(struct nfs_server *server, struct nfs4_lock_
case -NFS4ERR_BAD_STATEID:
lsp->ls_seqid.flags &= ~NFS_SEQID_CONFIRMED;
if (new_lock_owner != 0 ||
- (lsp->ls_flags & NFS_LOCK_INITIALIZED) != 0)
+ test_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags) != 0)
nfs4_schedule_stateid_recovery(server, lsp->ls_state);
break;
case -NFS4ERR_STALE_STATEID:
@@ -4756,7 +4902,7 @@ static int nfs41_check_expired_locks(struct nfs4_state *state)
struct nfs_server *server = NFS_SERVER(state->inode);
list_for_each_entry(lsp, &state->lock_states, ls_locks) {
- if (lsp->ls_flags & NFS_LOCK_INITIALIZED) {
+ if (test_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags)) {
status = nfs41_test_stateid(server, &lsp->ls_stateid);
if (status != NFS_OK) {
/* Free the stateid unless the server
@@ -4764,7 +4910,7 @@ static int nfs41_check_expired_locks(struct nfs4_state *state)
if (status != -NFS4ERR_BAD_STATEID)
nfs41_free_stateid(server,
&lsp->ls_stateid);
- lsp->ls_flags &= ~NFS_LOCK_INITIALIZED;
+ clear_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags);
ret = status;
}
}
@@ -5267,10 +5413,8 @@ int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred)
};
nfs4_init_boot_verifier(clp, &verifier);
- args.id_len = scnprintf(args.id, sizeof(args.id),
- "%s/%s",
- clp->cl_ipaddr,
- clp->cl_rpcclient->cl_nodename);
+ args.id_len = nfs4_init_uniform_client_string(clp, args.id,
+ sizeof(args.id));
dprintk("NFS call exchange_id auth=%s, '%.*s'\n",
clp->cl_rpcclient->cl_auth->au_ops->au_name,
args.id_len, args.id);
@@ -5391,6 +5535,8 @@ int nfs4_destroy_clientid(struct nfs_client *clp)
goto out;
if (clp->cl_exchange_flags == 0)
goto out;
+ if (clp->cl_preserve_clid)
+ goto out;
cred = nfs4_get_exchange_id_cred(clp);
ret = nfs4_proc_destroy_clientid(clp, cred);
if (cred)
@@ -6196,26 +6342,44 @@ nfs4_layoutget_prepare(struct rpc_task *task, void *calldata)
static void nfs4_layoutget_done(struct rpc_task *task, void *calldata)
{
struct nfs4_layoutget *lgp = calldata;
- struct nfs_server *server = NFS_SERVER(lgp->args.inode);
+ struct inode *inode = lgp->args.inode;
+ struct nfs_server *server = NFS_SERVER(inode);
+ struct pnfs_layout_hdr *lo;
+ struct nfs4_state *state = NULL;
dprintk("--> %s\n", __func__);
if (!nfs4_sequence_done(task, &lgp->res.seq_res))
- return;
+ goto out;
switch (task->tk_status) {
case 0:
- break;
+ goto out;
case -NFS4ERR_LAYOUTTRYLATER:
case -NFS4ERR_RECALLCONFLICT:
task->tk_status = -NFS4ERR_DELAY;
- /* Fall through */
- default:
- if (nfs4_async_handle_error(task, server, NULL) == -EAGAIN) {
- rpc_restart_call_prepare(task);
- return;
+ break;
+ case -NFS4ERR_EXPIRED:
+ case -NFS4ERR_BAD_STATEID:
+ spin_lock(&inode->i_lock);
+ lo = NFS_I(inode)->layout;
+ if (!lo || list_empty(&lo->plh_segs)) {
+ spin_unlock(&inode->i_lock);
+ /* If the open stateid was bad, then recover it. */
+ state = lgp->args.ctx->state;
+ } else {
+ LIST_HEAD(head);
+
+ pnfs_mark_matching_lsegs_invalid(lo, &head, NULL);
+ spin_unlock(&inode->i_lock);
+ /* Mark the bad layout state as invalid, then
+ * retry using the open stateid. */
+ pnfs_free_lseg_list(&head);
}
}
+ if (nfs4_async_handle_error(task, server, state) == -EAGAIN)
+ rpc_restart_call_prepare(task);
+out:
dprintk("<-- %s\n", __func__);
}
@@ -6282,7 +6446,8 @@ static const struct rpc_call_ops nfs4_layoutget_call_ops = {
.rpc_release = nfs4_layoutget_release,
};
-void nfs4_proc_layoutget(struct nfs4_layoutget *lgp, gfp_t gfp_flags)
+struct pnfs_layout_segment *
+nfs4_proc_layoutget(struct nfs4_layoutget *lgp, gfp_t gfp_flags)
{
struct nfs_server *server = NFS_SERVER(lgp->args.inode);
size_t max_pages = max_response_pages(server);
@@ -6299,6 +6464,7 @@ void nfs4_proc_layoutget(struct nfs4_layoutget *lgp, gfp_t gfp_flags)
.callback_data = lgp,
.flags = RPC_TASK_ASYNC,
};
+ struct pnfs_layout_segment *lseg = NULL;
int status = 0;
dprintk("--> %s\n", __func__);
@@ -6306,7 +6472,7 @@ void nfs4_proc_layoutget(struct nfs4_layoutget *lgp, gfp_t gfp_flags)
lgp->args.layout.pages = nfs4_alloc_pages(max_pages, gfp_flags);
if (!lgp->args.layout.pages) {
nfs4_layoutget_release(lgp);
- return;
+ return ERR_PTR(-ENOMEM);
}
lgp->args.layout.pglen = max_pages * PAGE_SIZE;
@@ -6315,15 +6481,17 @@ void nfs4_proc_layoutget(struct nfs4_layoutget *lgp, gfp_t gfp_flags)
nfs41_init_sequence(&lgp->args.seq_args, &lgp->res.seq_res, 0);
task = rpc_run_task(&task_setup_data);
if (IS_ERR(task))
- return;
+ return ERR_CAST(task);
status = nfs4_wait_for_completion_rpc_task(task);
if (status == 0)
status = task->tk_status;
if (status == 0)
- status = pnfs_layout_process(lgp);
+ lseg = pnfs_layout_process(lgp);
rpc_put_task(task);
dprintk("<-- %s status=%d\n", __func__, status);
- return;
+ if (status)
+ return ERR_PTR(status);
+ return lseg;
}
static void
@@ -6342,7 +6510,6 @@ 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 = lrp->args.layout;
dprintk("--> %s\n", __func__);
@@ -6354,20 +6521,21 @@ static void nfs4_layoutreturn_done(struct rpc_task *task, void *calldata)
rpc_restart_call_prepare(task);
return;
}
- spin_lock(&lo->plh_inode->i_lock);
- if (task->tk_status == 0 && lrp->res.lrs_present)
- pnfs_set_layout_stateid(lo, &lrp->res.stateid, true);
- 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;
+ struct pnfs_layout_hdr *lo = lrp->args.layout;
dprintk("--> %s\n", __func__);
- put_layout_hdr(lrp->args.layout);
+ spin_lock(&lo->plh_inode->i_lock);
+ if (lrp->res.lrs_present)
+ pnfs_set_layout_stateid(lo, &lrp->res.stateid, true);
+ lo->plh_block_lgets--;
+ spin_unlock(&lo->plh_inode->i_lock);
+ pnfs_put_layout_hdr(lrp->args.layout);
kfree(calldata);
dprintk("<-- %s\n", __func__);
}
@@ -6541,7 +6709,7 @@ static void nfs4_layoutcommit_release(void *calldata)
list_del_init(&lseg->pls_lc_list);
if (test_and_clear_bit(NFS_LSEG_LAYOUTCOMMIT,
&lseg->pls_flags))
- put_lseg(lseg);
+ pnfs_put_lseg(lseg);
}
clear_bit_unlock(NFS_INO_LAYOUTCOMMITTING, bitlock);
@@ -6800,6 +6968,7 @@ static const struct nfs4_state_recovery_ops nfs40_reboot_recovery_ops = {
.recover_lock = nfs4_lock_reclaim,
.establish_clid = nfs4_init_clientid,
.get_clid_cred = nfs4_get_setclientid_cred,
+ .detect_trunking = nfs40_discover_server_trunking,
};
#if defined(CONFIG_NFS_V4_1)
@@ -6811,6 +6980,7 @@ static const struct nfs4_state_recovery_ops nfs41_reboot_recovery_ops = {
.establish_clid = nfs41_init_clientid,
.get_clid_cred = nfs4_get_exchange_id_cred,
.reclaim_complete = nfs41_proc_reclaim_complete,
+ .detect_trunking = nfs41_discover_server_trunking,
};
#endif /* CONFIG_NFS_V4_1 */
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c
index 55148de..c351e6b 100644
--- a/fs/nfs/nfs4state.c
+++ b/fs/nfs/nfs4state.c
@@ -51,18 +51,21 @@
#include <linux/bitops.h>
#include <linux/jiffies.h>
+#include <linux/sunrpc/clnt.h>
+
#include "nfs4_fs.h"
#include "callback.h"
#include "delegation.h"
#include "internal.h"
#include "pnfs.h"
+#include "netns.h"
#define NFSDBG_FACILITY NFSDBG_STATE
#define OPENOWNER_POOL_SIZE 8
const nfs4_stateid zero_stateid;
-
+static DEFINE_MUTEX(nfs_clid_init_mutex);
static LIST_HEAD(nfs4_clientid_list);
int nfs4_init_clientid(struct nfs_client *clp, struct rpc_cred *cred)
@@ -73,12 +76,13 @@ int nfs4_init_clientid(struct nfs_client *clp, struct rpc_cred *cred)
};
unsigned short port;
int status;
+ struct nfs_net *nn = net_generic(clp->cl_net, nfs_net_id);
if (test_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state))
goto do_confirm;
- port = nfs_callback_tcpport;
+ port = nn->nfs_callback_tcpport;
if (clp->cl_addr.ss_family == AF_INET6)
- port = nfs_callback_tcpport6;
+ port = nn->nfs_callback_tcpport6;
status = nfs4_proc_setclientid(clp, NFS4_CALLBACK, port, cred, &clid);
if (status != 0)
@@ -96,6 +100,56 @@ out:
return status;
}
+/**
+ * nfs40_discover_server_trunking - Detect server IP address trunking (mv0)
+ *
+ * @clp: nfs_client under test
+ * @result: OUT: found nfs_client, or clp
+ * @cred: credential to use for trunking test
+ *
+ * Returns zero, a negative errno, or a negative NFS4ERR status.
+ * If zero is returned, an nfs_client pointer is planted in
+ * "result".
+ *
+ * Note: The returned client may not yet be marked ready.
+ */
+int nfs40_discover_server_trunking(struct nfs_client *clp,
+ struct nfs_client **result,
+ struct rpc_cred *cred)
+{
+ struct nfs4_setclientid_res clid = {
+ .clientid = clp->cl_clientid,
+ .confirm = clp->cl_confirm,
+ };
+ struct nfs_net *nn = net_generic(clp->cl_net, nfs_net_id);
+ unsigned short port;
+ int status;
+
+ port = nn->nfs_callback_tcpport;
+ if (clp->cl_addr.ss_family == AF_INET6)
+ port = nn->nfs_callback_tcpport6;
+
+ status = nfs4_proc_setclientid(clp, NFS4_CALLBACK, port, cred, &clid);
+ if (status != 0)
+ goto out;
+ clp->cl_clientid = clid.clientid;
+ clp->cl_confirm = clid.confirm;
+
+ status = nfs40_walk_client_list(clp, result, cred);
+ switch (status) {
+ case -NFS4ERR_STALE_CLIENTID:
+ set_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state);
+ case 0:
+ /* Sustain the lease, even if it's empty. If the clientid4
+ * goes stale it's of no use for trunking discovery. */
+ nfs4_schedule_state_renewal(*result);
+ break;
+ }
+
+out:
+ return status;
+}
+
struct rpc_cred *nfs4_get_machine_cred_locked(struct nfs_client *clp)
{
struct rpc_cred *cred = NULL;
@@ -275,6 +329,33 @@ out:
return status;
}
+/**
+ * nfs41_discover_server_trunking - Detect server IP address trunking (mv1)
+ *
+ * @clp: nfs_client under test
+ * @result: OUT: found nfs_client, or clp
+ * @cred: credential to use for trunking test
+ *
+ * Returns NFS4_OK, a negative errno, or a negative NFS4ERR status.
+ * If NFS4_OK is returned, an nfs_client pointer is planted in
+ * "result".
+ *
+ * Note: The returned client may not yet be marked ready.
+ */
+int nfs41_discover_server_trunking(struct nfs_client *clp,
+ struct nfs_client **result,
+ struct rpc_cred *cred)
+{
+ int status;
+
+ status = nfs4_proc_exchange_id(clp, cred);
+ if (status != NFS4_OK)
+ return status;
+ set_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state);
+
+ return nfs41_walk_client_list(clp, result, cred);
+}
+
struct rpc_cred *nfs4_get_exchange_id_cred(struct nfs_client *clp)
{
struct rpc_cred *cred;
@@ -729,11 +810,8 @@ static void __nfs4_close(struct nfs4_state *state,
if (!call_close) {
nfs4_put_open_state(state);
nfs4_put_state_owner(owner);
- } else {
- bool roc = pnfs_roc(state->inode);
-
- nfs4_do_close(state, gfp_mask, wait, roc);
- }
+ } else
+ nfs4_do_close(state, gfp_mask, wait);
}
void nfs4_close_state(struct nfs4_state *state, fmode_t fmode)
@@ -865,7 +943,7 @@ void nfs4_put_lock_state(struct nfs4_lock_state *lsp)
if (list_empty(&state->lock_states))
clear_bit(LK_STATE_IN_USE, &state->flags);
spin_unlock(&state->state_lock);
- if (lsp->ls_flags & NFS_LOCK_INITIALIZED) {
+ if (test_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags)) {
if (nfs4_release_lockowner(lsp) == 0)
return;
}
@@ -911,17 +989,25 @@ int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl)
}
static bool nfs4_copy_lock_stateid(nfs4_stateid *dst, struct nfs4_state *state,
- fl_owner_t fl_owner, pid_t fl_pid)
+ const struct nfs_lockowner *lockowner)
{
struct nfs4_lock_state *lsp;
+ fl_owner_t fl_owner;
+ pid_t fl_pid;
bool ret = false;
+
+ if (lockowner == NULL)
+ goto out;
+
if (test_bit(LK_STATE_IN_USE, &state->flags) == 0)
goto out;
+ fl_owner = lockowner->l_owner;
+ fl_pid = lockowner->l_pid;
spin_lock(&state->state_lock);
lsp = __nfs4_find_lock_state(state, fl_owner, fl_pid, NFS4_ANY_LOCK_TYPE);
- if (lsp != NULL && (lsp->ls_flags & NFS_LOCK_INITIALIZED) != 0) {
+ if (lsp != NULL && test_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags) != 0) {
nfs4_stateid_copy(dst, &lsp->ls_stateid);
ret = true;
}
@@ -946,11 +1032,11 @@ static void nfs4_copy_open_stateid(nfs4_stateid *dst, struct nfs4_state *state)
* requests.
*/
void nfs4_select_rw_stateid(nfs4_stateid *dst, struct nfs4_state *state,
- fmode_t fmode, fl_owner_t fl_owner, pid_t fl_pid)
+ fmode_t fmode, const struct nfs_lockowner *lockowner)
{
if (nfs4_copy_delegation_stateid(dst, state->inode, fmode))
return;
- if (nfs4_copy_lock_stateid(dst, state, fl_owner, fl_pid))
+ if (nfs4_copy_lock_stateid(dst, state, lockowner))
return;
nfs4_copy_open_stateid(dst, state);
}
@@ -1289,7 +1375,7 @@ restart:
if (status >= 0) {
spin_lock(&state->state_lock);
list_for_each_entry(lock, &state->lock_states, ls_locks) {
- if (!(lock->ls_flags & NFS_LOCK_INITIALIZED))
+ if (!test_bit(NFS_LOCK_INITIALIZED, &lock->ls_flags))
pr_warn_ratelimited("NFS: "
"%s: Lock reclaim "
"failed!\n", __func__);
@@ -1361,7 +1447,7 @@ static void nfs4_clear_open_state(struct nfs4_state *state)
spin_lock(&state->state_lock);
list_for_each_entry(lock, &state->lock_states, ls_locks) {
lock->ls_seqid.flags = 0;
- lock->ls_flags &= ~NFS_LOCK_INITIALIZED;
+ clear_bit(NFS_LOCK_INITIALIZED, &lock->ls_flags);
}
spin_unlock(&state->state_lock);
}
@@ -1595,8 +1681,8 @@ out:
return nfs4_recovery_handle_error(clp, status);
}
-/* Set NFS4CLNT_LEASE_EXPIRED for all v4.0 errors and for recoverable errors
- * on EXCHANGE_ID for v4.1
+/* Set NFS4CLNT_LEASE_EXPIRED and reclaim reboot state for all v4.0 errors
+ * and for recoverable errors on EXCHANGE_ID for v4.1
*/
static int nfs4_handle_reclaim_lease_error(struct nfs_client *clp, int status)
{
@@ -1606,8 +1692,12 @@ static int nfs4_handle_reclaim_lease_error(struct nfs_client *clp, int status)
return -ESERVERFAULT;
/* Lease confirmation error: retry after purging the lease */
ssleep(1);
+ clear_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state);
+ break;
case -NFS4ERR_STALE_CLIENTID:
clear_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state);
+ nfs4_state_clear_reclaim_reboot(clp);
+ nfs4_state_start_reclaim_reboot(clp);
break;
case -NFS4ERR_CLID_INUSE:
pr_err("NFS: Server %s reports our clientid is in use\n",
@@ -1698,6 +1788,109 @@ static int nfs4_purge_lease(struct nfs_client *clp)
return 0;
}
+/**
+ * nfs4_discover_server_trunking - Detect server IP address trunking
+ *
+ * @clp: nfs_client under test
+ * @result: OUT: found nfs_client, or clp
+ *
+ * Returns zero or a negative errno. If zero is returned,
+ * an nfs_client pointer is planted in "result".
+ *
+ * Note: since we are invoked in process context, and
+ * not from inside the state manager, we cannot use
+ * nfs4_handle_reclaim_lease_error().
+ */
+int nfs4_discover_server_trunking(struct nfs_client *clp,
+ struct nfs_client **result)
+{
+ const struct nfs4_state_recovery_ops *ops =
+ clp->cl_mvops->reboot_recovery_ops;
+ rpc_authflavor_t *flavors, flav, save;
+ struct rpc_clnt *clnt;
+ struct rpc_cred *cred;
+ int i, len, status;
+
+ dprintk("NFS: %s: testing '%s'\n", __func__, clp->cl_hostname);
+
+ len = NFS_MAX_SECFLAVORS;
+ flavors = kcalloc(len, sizeof(*flavors), GFP_KERNEL);
+ if (flavors == NULL) {
+ status = -ENOMEM;
+ goto out;
+ }
+ len = rpcauth_list_flavors(flavors, len);
+ if (len < 0) {
+ status = len;
+ goto out_free;
+ }
+ clnt = clp->cl_rpcclient;
+ save = clnt->cl_auth->au_flavor;
+ i = 0;
+
+ mutex_lock(&nfs_clid_init_mutex);
+ status = -ENOENT;
+again:
+ cred = ops->get_clid_cred(clp);
+ if (cred == NULL)
+ goto out_unlock;
+
+ status = ops->detect_trunking(clp, result, cred);
+ put_rpccred(cred);
+ switch (status) {
+ case 0:
+ break;
+
+ case -EACCES:
+ if (clp->cl_machine_cred == NULL)
+ break;
+ /* Handle case where the user hasn't set up machine creds */
+ nfs4_clear_machine_cred(clp);
+ case -NFS4ERR_DELAY:
+ case -ETIMEDOUT:
+ case -EAGAIN:
+ ssleep(1);
+ dprintk("NFS: %s after status %d, retrying\n",
+ __func__, status);
+ goto again;
+
+ case -NFS4ERR_CLID_INUSE:
+ case -NFS4ERR_WRONGSEC:
+ status = -EPERM;
+ if (i >= len)
+ break;
+
+ flav = flavors[i++];
+ if (flav == save)
+ flav = flavors[i++];
+ clnt = rpc_clone_client_set_auth(clnt, flav);
+ if (IS_ERR(clnt)) {
+ status = PTR_ERR(clnt);
+ break;
+ }
+ clp->cl_rpcclient = clnt;
+ goto again;
+
+ case -NFS4ERR_MINOR_VERS_MISMATCH:
+ status = -EPROTONOSUPPORT;
+ break;
+
+ case -EKEYEXPIRED:
+ nfs4_warn_keyexpired(clp->cl_hostname);
+ case -NFS4ERR_NOT_SAME: /* FixMe: implement recovery
+ * in nfs4_exchange_id */
+ status = -EKEYEXPIRED;
+ }
+
+out_unlock:
+ mutex_unlock(&nfs_clid_init_mutex);
+out_free:
+ kfree(flavors);
+out:
+ dprintk("NFS: %s: status = %d\n", __func__, status);
+ return status;
+}
+
#ifdef CONFIG_NFS_V4_1
void nfs4_schedule_session_recovery(struct nfs4_session *session, int err)
{
@@ -2008,6 +2201,7 @@ out_error:
pr_warn_ratelimited("NFS: state manager%s%s failed on NFSv4 server %s"
" with error %d\n", section_sep, section,
clp->cl_hostname, -status);
+ ssleep(1);
nfs4_end_drain_session(clp);
nfs4_clear_state_manager_bit(clp);
}
diff --git a/fs/nfs/nfs4sysctl.c b/fs/nfs/nfs4sysctl.c
index 5729bc8..2628d92 100644
--- a/fs/nfs/nfs4sysctl.c
+++ b/fs/nfs/nfs4sysctl.c
@@ -9,6 +9,7 @@
#include <linux/nfs_idmap.h>
#include <linux/nfs_fs.h>
+#include "nfs4_fs.h"
#include "callback.h"
static const int nfs_set_port_min = 0;
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
index 8dba6bd..40836ee 100644
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -447,12 +447,14 @@ static int nfs4_stat_to_errno(int);
encode_sequence_maxsz + \
encode_putfh_maxsz + \
encode_open_maxsz + \
+ encode_access_maxsz + \
encode_getfh_maxsz + \
encode_getattr_maxsz)
#define NFS4_dec_open_sz (compound_decode_hdr_maxsz + \
decode_sequence_maxsz + \
decode_putfh_maxsz + \
decode_open_maxsz + \
+ decode_access_maxsz + \
decode_getfh_maxsz + \
decode_getattr_maxsz)
#define NFS4_enc_open_confirm_sz \
@@ -467,11 +469,13 @@ static int nfs4_stat_to_errno(int);
encode_sequence_maxsz + \
encode_putfh_maxsz + \
encode_open_maxsz + \
+ encode_access_maxsz + \
encode_getattr_maxsz)
#define NFS4_dec_open_noattr_sz (compound_decode_hdr_maxsz + \
decode_sequence_maxsz + \
decode_putfh_maxsz + \
decode_open_maxsz + \
+ decode_access_maxsz + \
decode_getattr_maxsz)
#define NFS4_enc_open_downgrade_sz \
(compound_encode_hdr_maxsz + \
@@ -1509,8 +1513,12 @@ static void encode_open_stateid(struct xdr_stream *xdr,
nfs4_stateid stateid;
if (ctx->state != NULL) {
+ const struct nfs_lockowner *lockowner = NULL;
+
+ if (l_ctx != NULL)
+ lockowner = &l_ctx->lockowner;
nfs4_select_rw_stateid(&stateid, ctx->state,
- fmode, l_ctx->lockowner, l_ctx->pid);
+ fmode, lockowner);
if (zero_seqid)
stateid.seqid = 0;
encode_nfs4_stateid(xdr, &stateid);
@@ -2216,6 +2224,8 @@ static void nfs4_xdr_enc_open(struct rpc_rqst *req, struct xdr_stream *xdr,
encode_putfh(xdr, args->fh, &hdr);
encode_open(xdr, args, &hdr);
encode_getfh(xdr, &hdr);
+ if (args->access)
+ encode_access(xdr, args->access, &hdr);
encode_getfattr_open(xdr, args->bitmask, args->open_bitmap, &hdr);
encode_nops(&hdr);
}
@@ -2252,7 +2262,9 @@ static void nfs4_xdr_enc_open_noattr(struct rpc_rqst *req,
encode_sequence(xdr, &args->seq_args, &hdr);
encode_putfh(xdr, args->fh, &hdr);
encode_open(xdr, args, &hdr);
- encode_getfattr(xdr, args->bitmask, &hdr);
+ if (args->access)
+ encode_access(xdr, args->access, &hdr);
+ encode_getfattr_open(xdr, args->bitmask, args->open_bitmap, &hdr);
encode_nops(&hdr);
}
@@ -4095,7 +4107,7 @@ out_overflow:
return -EIO;
}
-static int decode_access(struct xdr_stream *xdr, struct nfs4_accessres *access)
+static int decode_access(struct xdr_stream *xdr, u32 *supported, u32 *access)
{
__be32 *p;
uint32_t supp, acc;
@@ -4109,8 +4121,8 @@ static int decode_access(struct xdr_stream *xdr, struct nfs4_accessres *access)
goto out_overflow;
supp = be32_to_cpup(p++);
acc = be32_to_cpup(p);
- access->supported = supp;
- access->access = acc;
+ *supported = supp;
+ *access = acc;
return 0;
out_overflow:
print_overflow_msg(__func__, xdr);
@@ -5642,7 +5654,8 @@ static int decode_getdeviceinfo(struct xdr_stream *xdr,
* and places the remaining xdr data in xdr_buf->tail
*/
pdev->mincount = be32_to_cpup(p);
- xdr_read_pages(xdr, pdev->mincount); /* include space for the length */
+ if (xdr_read_pages(xdr, pdev->mincount) != pdev->mincount)
+ goto out_overflow;
/* Parse notification bitmap, verifying that it is zero. */
p = xdr_inline_decode(xdr, 4);
@@ -5887,7 +5900,7 @@ static int nfs4_xdr_dec_access(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
status = decode_putfh(xdr);
if (status != 0)
goto out;
- status = decode_access(xdr, res);
+ status = decode_access(xdr, &res->supported, &res->access);
if (status != 0)
goto out;
decode_getfattr(xdr, res->fattr, res->server);
@@ -6228,6 +6241,8 @@ static int nfs4_xdr_dec_open(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
status = decode_getfh(xdr, &res->fh);
if (status)
goto out;
+ if (res->access_request)
+ decode_access(xdr, &res->access_supported, &res->access_result);
decode_getfattr(xdr, res->f_attr, res->server);
out:
return status;
@@ -6276,6 +6291,8 @@ static int nfs4_xdr_dec_open_noattr(struct rpc_rqst *rqstp,
status = decode_open(xdr, res);
if (status)
goto out;
+ if (res->access_request)
+ decode_access(xdr, &res->access_supported, &res->access_result);
decode_getfattr(xdr, res->f_attr, res->server);
out:
return status;
diff --git a/fs/nfs/objlayout/objio_osd.c b/fs/nfs/objlayout/objio_osd.c
index ea6d111..be731e6 100644
--- a/fs/nfs/objlayout/objio_osd.c
+++ b/fs/nfs/objlayout/objio_osd.c
@@ -41,6 +41,7 @@
#include <scsi/osd_ore.h>
#include "objlayout.h"
+#include "../internal.h"
#define NFSDBG_FACILITY NFSDBG_PNFS_LD
@@ -606,8 +607,14 @@ static bool aligned_on_raid_stripe(u64 offset, struct ore_layout *layout,
void objio_init_write(struct nfs_pageio_descriptor *pgio, struct nfs_page *req)
{
unsigned long stripe_end = 0;
+ u64 wb_size;
- pnfs_generic_pg_init_write(pgio, req);
+ if (pgio->pg_dreq == NULL)
+ wb_size = i_size_read(pgio->pg_inode) - req_offset(req);
+ else
+ wb_size = nfs_dreq_bytes_left(pgio->pg_dreq);
+
+ pnfs_generic_pg_init_write(pgio, req, wb_size);
if (unlikely(pgio->pg_lseg == NULL))
return; /* Not pNFS */
diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c
index 311a796..e56e846 100644
--- a/fs/nfs/pagelist.c
+++ b/fs/nfs/pagelist.c
@@ -102,6 +102,7 @@ nfs_create_request(struct nfs_open_context *ctx, struct inode *inode,
unsigned int offset, unsigned int count)
{
struct nfs_page *req;
+ struct nfs_lock_context *l_ctx;
/* try to allocate the request struct */
req = nfs_page_alloc();
@@ -109,11 +110,12 @@ nfs_create_request(struct nfs_open_context *ctx, struct inode *inode,
return ERR_PTR(-ENOMEM);
/* get lock context early so we can deal with alloc failures */
- req->wb_lock_context = nfs_get_lock_context(ctx);
- if (req->wb_lock_context == NULL) {
+ l_ctx = nfs_get_lock_context(ctx);
+ if (IS_ERR(l_ctx)) {
nfs_page_free(req);
- return ERR_PTR(-ENOMEM);
+ return ERR_CAST(l_ctx);
}
+ req->wb_lock_context = l_ctx;
/* Initialize the request struct. Initially, we assume a
* long write-back delay. This will be adjusted in
@@ -290,7 +292,9 @@ static bool nfs_can_coalesce_requests(struct nfs_page *prev,
{
if (req->wb_context->cred != prev->wb_context->cred)
return false;
- if (req->wb_lock_context->lockowner != prev->wb_lock_context->lockowner)
+ if (req->wb_lock_context->lockowner.l_owner != prev->wb_lock_context->lockowner.l_owner)
+ return false;
+ if (req->wb_lock_context->lockowner.l_pid != prev->wb_lock_context->lockowner.l_pid)
return false;
if (req->wb_context->state != prev->wb_context->state)
return false;
diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c
index 2e00fea..fe624c9 100644
--- a/fs/nfs/pnfs.c
+++ b/fs/nfs/pnfs.c
@@ -35,6 +35,7 @@
#include "iostat.h"
#define NFSDBG_FACILITY NFSDBG_PNFS
+#define PNFS_LAYOUTGET_RETRY_TIMEOUT (120*HZ)
/* Locking:
*
@@ -190,7 +191,7 @@ EXPORT_SYMBOL_GPL(pnfs_unregister_layoutdriver);
/* Need to hold i_lock if caller does not already hold reference */
void
-get_layout_hdr(struct pnfs_layout_hdr *lo)
+pnfs_get_layout_hdr(struct pnfs_layout_hdr *lo)
{
atomic_inc(&lo->plh_refcount);
}
@@ -199,43 +200,107 @@ 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);
+ return ld->alloc_layout_hdr(ino, 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;
+ struct nfs_server *server = NFS_SERVER(lo->plh_inode);
+ struct pnfs_layoutdriver_type *ld = server->pnfs_curr_ld;
+
+ if (!list_empty(&lo->plh_layouts)) {
+ struct nfs_client *clp = server->nfs_client;
+
+ spin_lock(&clp->cl_lock);
+ list_del_init(&lo->plh_layouts);
+ spin_unlock(&clp->cl_lock);
+ }
put_rpccred(lo->plh_lc_cred);
- return ld->alloc_layout_hdr ? ld->free_layout_hdr(lo) : kfree(lo);
+ return ld->free_layout_hdr(lo);
}
static void
-destroy_layout_hdr(struct pnfs_layout_hdr *lo)
+pnfs_detach_layout_hdr(struct pnfs_layout_hdr *lo)
{
+ struct nfs_inode *nfsi = NFS_I(lo->plh_inode);
dprintk("%s: freeing layout cache %p\n", __func__, lo);
- BUG_ON(!list_empty(&lo->plh_layouts));
- NFS_I(lo->plh_inode)->layout = NULL;
- pnfs_free_layout_hdr(lo);
+ nfsi->layout = NULL;
+ /* Reset MDS Threshold I/O counters */
+ nfsi->write_io = 0;
+ nfsi->read_io = 0;
+}
+
+void
+pnfs_put_layout_hdr(struct pnfs_layout_hdr *lo)
+{
+ struct inode *inode = lo->plh_inode;
+
+ if (atomic_dec_and_lock(&lo->plh_refcount, &inode->i_lock)) {
+ pnfs_detach_layout_hdr(lo);
+ spin_unlock(&inode->i_lock);
+ pnfs_free_layout_hdr(lo);
+ }
+}
+
+static int
+pnfs_iomode_to_fail_bit(u32 iomode)
+{
+ return iomode == IOMODE_RW ?
+ NFS_LAYOUT_RW_FAILED : NFS_LAYOUT_RO_FAILED;
}
static void
-put_layout_hdr_locked(struct pnfs_layout_hdr *lo)
+pnfs_layout_set_fail_bit(struct pnfs_layout_hdr *lo, int fail_bit)
{
- if (atomic_dec_and_test(&lo->plh_refcount))
- destroy_layout_hdr(lo);
+ lo->plh_retry_timestamp = jiffies;
+ if (test_and_set_bit(fail_bit, &lo->plh_flags))
+ atomic_inc(&lo->plh_refcount);
}
-void
-put_layout_hdr(struct pnfs_layout_hdr *lo)
+static void
+pnfs_layout_clear_fail_bit(struct pnfs_layout_hdr *lo, int fail_bit)
+{
+ if (test_and_clear_bit(fail_bit, &lo->plh_flags))
+ atomic_dec(&lo->plh_refcount);
+}
+
+static void
+pnfs_layout_io_set_failed(struct pnfs_layout_hdr *lo, u32 iomode)
{
struct inode *inode = lo->plh_inode;
+ struct pnfs_layout_range range = {
+ .iomode = iomode,
+ .offset = 0,
+ .length = NFS4_MAX_UINT64,
+ };
+ LIST_HEAD(head);
- if (atomic_dec_and_lock(&lo->plh_refcount, &inode->i_lock)) {
- destroy_layout_hdr(lo);
- spin_unlock(&inode->i_lock);
+ spin_lock(&inode->i_lock);
+ pnfs_layout_set_fail_bit(lo, pnfs_iomode_to_fail_bit(iomode));
+ pnfs_mark_matching_lsegs_invalid(lo, &head, &range);
+ spin_unlock(&inode->i_lock);
+ pnfs_free_lseg_list(&head);
+ dprintk("%s Setting layout IOMODE_%s fail bit\n", __func__,
+ iomode == IOMODE_RW ? "RW" : "READ");
+}
+
+static bool
+pnfs_layout_io_test_failed(struct pnfs_layout_hdr *lo, u32 iomode)
+{
+ unsigned long start, end;
+ int fail_bit = pnfs_iomode_to_fail_bit(iomode);
+
+ if (test_bit(fail_bit, &lo->plh_flags) == 0)
+ return false;
+ end = jiffies;
+ start = end - PNFS_LAYOUTGET_RETRY_TIMEOUT;
+ if (!time_in_range(lo->plh_retry_timestamp, start, end)) {
+ /* It is time to retry the failed layoutgets */
+ pnfs_layout_clear_fail_bit(lo, fail_bit);
+ return false;
}
+ return true;
}
static void
@@ -249,33 +314,32 @@ init_lseg(struct pnfs_layout_hdr *lo, struct pnfs_layout_segment *lseg)
lseg->pls_layout = lo;
}
-static void free_lseg(struct pnfs_layout_segment *lseg)
+static void pnfs_free_lseg(struct pnfs_layout_segment *lseg)
{
struct inode *ino = lseg->pls_layout->plh_inode;
NFS_SERVER(ino)->pnfs_curr_ld->free_lseg(lseg);
- /* Matched by get_layout_hdr in pnfs_insert_layout */
- put_layout_hdr(NFS_I(ino)->layout);
}
static void
-put_lseg_common(struct pnfs_layout_segment *lseg)
+pnfs_layout_remove_lseg(struct pnfs_layout_hdr *lo,
+ struct pnfs_layout_segment *lseg)
{
- struct inode *inode = lseg->pls_layout->plh_inode;
+ struct inode *inode = lo->plh_inode;
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);
- /* Matched by initial refcount set in alloc_init_layout_hdr */
- put_layout_hdr_locked(lseg->pls_layout);
- }
+ /* Matched by pnfs_get_layout_hdr in pnfs_layout_insert_lseg */
+ atomic_dec(&lo->plh_refcount);
+ if (list_empty(&lo->plh_segs))
+ clear_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags);
rpc_wake_up(&NFS_SERVER(inode)->roc_rpcwaitq);
}
void
-put_lseg(struct pnfs_layout_segment *lseg)
+pnfs_put_lseg(struct pnfs_layout_segment *lseg)
{
+ struct pnfs_layout_hdr *lo;
struct inode *inode;
if (!lseg)
@@ -284,17 +348,17 @@ put_lseg(struct pnfs_layout_segment *lseg)
dprintk("%s: lseg %p ref %d valid %d\n", __func__, lseg,
atomic_read(&lseg->pls_refcount),
test_bit(NFS_LSEG_VALID, &lseg->pls_flags));
- inode = lseg->pls_layout->plh_inode;
+ lo = lseg->pls_layout;
+ inode = lo->plh_inode;
if (atomic_dec_and_lock(&lseg->pls_refcount, &inode->i_lock)) {
- LIST_HEAD(free_me);
-
- put_lseg_common(lseg);
- list_add(&lseg->pls_list, &free_me);
+ pnfs_get_layout_hdr(lo);
+ pnfs_layout_remove_lseg(lo, lseg);
spin_unlock(&inode->i_lock);
- pnfs_free_lseg_list(&free_me);
+ pnfs_free_lseg(lseg);
+ pnfs_put_layout_hdr(lo);
}
}
-EXPORT_SYMBOL_GPL(put_lseg);
+EXPORT_SYMBOL_GPL(pnfs_put_lseg);
static inline u64
end_offset(u64 start, u64 len)
@@ -378,7 +442,7 @@ static int mark_lseg_invalid(struct pnfs_layout_segment *lseg,
dprintk("%s: lseg %p ref %d\n", __func__, lseg,
atomic_read(&lseg->pls_refcount));
if (atomic_dec_and_test(&lseg->pls_refcount)) {
- put_lseg_common(lseg);
+ pnfs_layout_remove_lseg(lseg->pls_layout, lseg);
list_add(&lseg->pls_list, tmp_list);
rv = 1;
}
@@ -390,7 +454,7 @@ static int mark_lseg_invalid(struct pnfs_layout_segment *lseg,
* after call.
*/
int
-mark_matching_lsegs_invalid(struct pnfs_layout_hdr *lo,
+pnfs_mark_matching_lsegs_invalid(struct pnfs_layout_hdr *lo,
struct list_head *tmp_list,
struct pnfs_layout_range *recall_range)
{
@@ -399,14 +463,8 @@ mark_matching_lsegs_invalid(struct pnfs_layout_hdr *lo,
dprintk("%s:Begin lo %p\n", __func__, lo);
- if (list_empty(&lo->plh_segs)) {
- /* Reset MDS Threshold I/O counters */
- NFS_I(lo->plh_inode)->write_io = 0;
- NFS_I(lo->plh_inode)->read_io = 0;
- if (!test_and_set_bit(NFS_LAYOUT_DESTROYED, &lo->plh_flags))
- put_layout_hdr_locked(lo);
+ if (list_empty(&lo->plh_segs))
return 0;
- }
list_for_each_entry_safe(lseg, next, &lo->plh_segs, pls_list)
if (!recall_range ||
should_free_lseg(&lseg->pls_range, recall_range)) {
@@ -426,25 +484,13 @@ void
pnfs_free_lseg_list(struct list_head *free_me)
{
struct pnfs_layout_segment *lseg, *tmp;
- struct pnfs_layout_hdr *lo;
if (list_empty(free_me))
return;
- lo = list_first_entry(free_me, struct pnfs_layout_segment,
- pls_list)->pls_layout;
-
- if (test_bit(NFS_LAYOUT_DESTROYED, &lo->plh_flags)) {
- struct nfs_client *clp;
-
- clp = NFS_SERVER(lo->plh_inode)->nfs_client;
- spin_lock(&clp->cl_lock);
- list_del_init(&lo->plh_layouts);
- spin_unlock(&clp->cl_lock);
- }
list_for_each_entry_safe(lseg, tmp, free_me, pls_list) {
list_del(&lseg->pls_list);
- free_lseg(lseg);
+ pnfs_free_lseg(lseg);
}
}
@@ -458,10 +504,15 @@ 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, NULL);
- }
- spin_unlock(&nfsi->vfs_inode.i_lock);
- pnfs_free_lseg_list(&tmp_list);
+ pnfs_mark_matching_lsegs_invalid(lo, &tmp_list, NULL);
+ pnfs_get_layout_hdr(lo);
+ pnfs_layout_clear_fail_bit(lo, NFS_LAYOUT_RO_FAILED);
+ pnfs_layout_clear_fail_bit(lo, NFS_LAYOUT_RW_FAILED);
+ spin_unlock(&nfsi->vfs_inode.i_lock);
+ pnfs_free_lseg_list(&tmp_list);
+ pnfs_put_layout_hdr(lo);
+ } else
+ spin_unlock(&nfsi->vfs_inode.i_lock);
}
EXPORT_SYMBOL_GPL(pnfs_destroy_layout);
@@ -498,46 +549,54 @@ pnfs_destroy_all_layouts(struct nfs_client *clp)
}
}
+/*
+ * Compare 2 layout stateid sequence ids, to see which is newer,
+ * taking into account wraparound issues.
+ */
+static bool pnfs_seqid_is_newer(u32 s1, u32 s2)
+{
+ return (s32)s1 - (s32)s2 > 0;
+}
+
/* update lo->plh_stateid with new if is more recent */
void
pnfs_set_layout_stateid(struct pnfs_layout_hdr *lo, const nfs4_stateid *new,
bool update_barrier)
{
- u32 oldseq, newseq;
+ u32 oldseq, newseq, new_barrier;
+ int empty = list_empty(&lo->plh_segs);
oldseq = be32_to_cpu(lo->plh_stateid.seqid);
newseq = be32_to_cpu(new->seqid);
- if ((int)(newseq - oldseq) > 0) {
+ if (empty || pnfs_seqid_is_newer(newseq, oldseq)) {
nfs4_stateid_copy(&lo->plh_stateid, new);
if (update_barrier) {
- u32 new_barrier = be32_to_cpu(new->seqid);
-
- if ((int)(new_barrier - lo->plh_barrier))
- lo->plh_barrier = new_barrier;
+ new_barrier = be32_to_cpu(new->seqid);
} else {
/* Because of wraparound, we want to keep the barrier
- * "close" to the current seqids. It needs to be
- * within 2**31 to count as "behind", so if it
- * gets too near that limit, give us a litle leeway
- * and bring it to within 2**30.
- * NOTE - and yes, this is all unsigned arithmetic.
+ * "close" to the current seqids.
*/
- if (unlikely((newseq - lo->plh_barrier) > (3 << 29)))
- lo->plh_barrier = newseq - (1 << 30);
+ new_barrier = newseq - atomic_read(&lo->plh_outstanding);
}
+ if (empty || pnfs_seqid_is_newer(new_barrier, lo->plh_barrier))
+ lo->plh_barrier = new_barrier;
}
}
+static bool
+pnfs_layout_stateid_blocked(const struct pnfs_layout_hdr *lo,
+ const nfs4_stateid *stateid)
+{
+ u32 seqid = be32_to_cpu(stateid->seqid);
+
+ return !pnfs_seqid_is_newer(seqid, lo->plh_barrier);
+}
+
/* lget is set to 1 if called from inside send_layoutget call chain */
static bool
-pnfs_layoutgets_blocked(struct pnfs_layout_hdr *lo, nfs4_stateid *stateid,
- int lget)
+pnfs_layoutgets_blocked(const struct pnfs_layout_hdr *lo, int lget)
{
- if ((stateid) &&
- (int)(lo->plh_barrier - be32_to_cpu(stateid->seqid)) >= 0)
- return true;
return lo->plh_block_lgets ||
- test_bit(NFS_LAYOUT_DESTROYED, &lo->plh_flags) ||
test_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags) ||
(list_empty(&lo->plh_segs) &&
(atomic_read(&lo->plh_outstanding) > lget));
@@ -551,7 +610,7 @@ pnfs_choose_layoutget_stateid(nfs4_stateid *dst, struct pnfs_layout_hdr *lo,
dprintk("--> %s\n", __func__);
spin_lock(&lo->plh_inode->i_lock);
- if (pnfs_layoutgets_blocked(lo, NULL, 1)) {
+ if (pnfs_layoutgets_blocked(lo, 1)) {
status = -EAGAIN;
} else if (list_empty(&lo->plh_segs)) {
int seq;
@@ -582,7 +641,7 @@ send_layoutget(struct pnfs_layout_hdr *lo,
struct inode *ino = lo->plh_inode;
struct nfs_server *server = NFS_SERVER(ino);
struct nfs4_layoutget *lgp;
- struct pnfs_layout_segment *lseg = NULL;
+ struct pnfs_layout_segment *lseg;
dprintk("--> %s\n", __func__);
@@ -599,16 +658,22 @@ send_layoutget(struct pnfs_layout_hdr *lo,
lgp->args.type = server->pnfs_curr_ld->id;
lgp->args.inode = ino;
lgp->args.ctx = get_nfs_open_context(ctx);
- lgp->lsegpp = &lseg;
lgp->gfp_flags = gfp_flags;
/* Synchronously retrieve layout information from server and
* store in lseg.
*/
- nfs4_proc_layoutget(lgp, gfp_flags);
- if (!lseg) {
- /* remember that LAYOUTGET failed and suspend trying */
- set_bit(lo_fail_bit(range->iomode), &lo->plh_flags);
+ lseg = nfs4_proc_layoutget(lgp, gfp_flags);
+ if (IS_ERR(lseg)) {
+ switch (PTR_ERR(lseg)) {
+ case -ENOMEM:
+ case -ERESTARTSYS:
+ break;
+ default:
+ /* remember that LAYOUTGET failed and suspend trying */
+ pnfs_layout_io_set_failed(lo, range->iomode);
+ }
+ return NULL;
}
return lseg;
@@ -636,25 +701,24 @@ _pnfs_return_layout(struct inode *ino)
spin_lock(&ino->i_lock);
lo = nfsi->layout;
- if (!lo || pnfs_test_layout_returned(lo)) {
+ if (!lo) {
spin_unlock(&ino->i_lock);
dprintk("NFS: %s no layout to return\n", __func__);
goto out;
}
stateid = nfsi->layout->plh_stateid;
/* Reference matched in nfs4_layoutreturn_release */
- get_layout_hdr(lo);
+ pnfs_get_layout_hdr(lo);
empty = list_empty(&lo->plh_segs);
- mark_matching_lsegs_invalid(lo, &tmp_list, NULL);
+ pnfs_mark_matching_lsegs_invalid(lo, &tmp_list, NULL);
/* Don't send a LAYOUTRETURN if list was initially empty */
if (empty) {
spin_unlock(&ino->i_lock);
- put_layout_hdr(lo);
+ pnfs_put_layout_hdr(lo);
dprintk("NFS: %s no layout segments to return\n", __func__);
goto out;
}
lo->plh_block_lgets++;
- pnfs_mark_layout_returned(lo);
spin_unlock(&ino->i_lock);
pnfs_free_lseg_list(&tmp_list);
@@ -663,10 +727,10 @@ _pnfs_return_layout(struct inode *ino)
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);
- pnfs_clear_layout_returned(lo);
- put_layout_hdr(lo);
+ spin_lock(&ino->i_lock);
+ lo->plh_block_lgets--;
+ spin_unlock(&ino->i_lock);
+ pnfs_put_layout_hdr(lo);
goto out;
}
@@ -703,7 +767,7 @@ bool pnfs_roc(struct inode *ino)
if (!found)
goto out_nolayout;
lo->plh_block_lgets++;
- get_layout_hdr(lo); /* matched in pnfs_roc_release */
+ pnfs_get_layout_hdr(lo); /* matched in pnfs_roc_release */
spin_unlock(&ino->i_lock);
pnfs_free_lseg_list(&tmp_list);
return true;
@@ -720,8 +784,12 @@ void pnfs_roc_release(struct inode *ino)
spin_lock(&ino->i_lock);
lo = NFS_I(ino)->layout;
lo->plh_block_lgets--;
- put_layout_hdr_locked(lo);
- spin_unlock(&ino->i_lock);
+ if (atomic_dec_and_test(&lo->plh_refcount)) {
+ pnfs_detach_layout_hdr(lo);
+ spin_unlock(&ino->i_lock);
+ pnfs_free_layout_hdr(lo);
+ } else
+ spin_unlock(&ino->i_lock);
}
void pnfs_roc_set_barrier(struct inode *ino, u32 barrier)
@@ -730,32 +798,34 @@ void pnfs_roc_set_barrier(struct inode *ino, u32 barrier)
spin_lock(&ino->i_lock);
lo = NFS_I(ino)->layout;
- if ((int)(barrier - lo->plh_barrier) > 0)
+ if (pnfs_seqid_is_newer(barrier, lo->plh_barrier))
lo->plh_barrier = barrier;
spin_unlock(&ino->i_lock);
}
-bool pnfs_roc_drain(struct inode *ino, u32 *barrier)
+bool pnfs_roc_drain(struct inode *ino, u32 *barrier, struct rpc_task *task)
{
struct nfs_inode *nfsi = NFS_I(ino);
+ struct pnfs_layout_hdr *lo;
struct pnfs_layout_segment *lseg;
+ u32 current_seqid;
bool found = false;
spin_lock(&ino->i_lock);
list_for_each_entry(lseg, &nfsi->layout->plh_segs, pls_list)
if (test_bit(NFS_LSEG_ROC, &lseg->pls_flags)) {
+ rpc_sleep_on(&NFS_SERVER(ino)->roc_rpcwaitq, task, NULL);
found = true;
- break;
+ goto out;
}
- if (!found) {
- struct pnfs_layout_hdr *lo = nfsi->layout;
- u32 current_seqid = be32_to_cpu(lo->plh_stateid.seqid);
+ lo = nfsi->layout;
+ current_seqid = be32_to_cpu(lo->plh_stateid.seqid);
- /* Since close does not return a layout stateid for use as
- * a barrier, we choose the worst-case barrier.
- */
- *barrier = current_seqid + atomic_read(&lo->plh_outstanding);
- }
+ /* Since close does not return a layout stateid for use as
+ * a barrier, we choose the worst-case barrier.
+ */
+ *barrier = current_seqid + atomic_read(&lo->plh_outstanding);
+out:
spin_unlock(&ino->i_lock);
return found;
}
@@ -786,14 +856,13 @@ cmp_layout(struct pnfs_layout_range *l1,
}
static void
-pnfs_insert_layout(struct pnfs_layout_hdr *lo,
+pnfs_layout_insert_lseg(struct pnfs_layout_hdr *lo,
struct pnfs_layout_segment *lseg)
{
struct pnfs_layout_segment *lp;
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(&lseg->pls_range, &lp->pls_range) > 0)
continue;
@@ -813,7 +882,7 @@ pnfs_insert_layout(struct pnfs_layout_hdr *lo,
__func__, lseg, lseg->pls_range.iomode,
lseg->pls_range.offset, lseg->pls_range.length);
out:
- get_layout_hdr(lo);
+ pnfs_get_layout_hdr(lo);
dprintk("%s:Return\n", __func__);
}
@@ -847,21 +916,19 @@ pnfs_find_alloc_layout(struct inode *ino,
dprintk("%s Begin ino=%p layout=%p\n", __func__, ino, nfsi->layout);
- assert_spin_locked(&ino->i_lock);
- if (nfsi->layout) {
- if (test_bit(NFS_LAYOUT_DESTROYED, &nfsi->layout->plh_flags))
- return NULL;
- else
- return nfsi->layout;
- }
+ if (nfsi->layout != NULL)
+ goto out_existing;
spin_unlock(&ino->i_lock);
new = alloc_init_layout_hdr(ino, ctx, gfp_flags);
spin_lock(&ino->i_lock);
- if (likely(nfsi->layout == NULL)) /* Won the race? */
+ if (likely(nfsi->layout == NULL)) { /* Won the race? */
nfsi->layout = new;
- else
- pnfs_free_layout_hdr(new);
+ return new;
+ }
+ pnfs_free_layout_hdr(new);
+out_existing:
+ pnfs_get_layout_hdr(nfsi->layout);
return nfsi->layout;
}
@@ -904,11 +971,10 @@ pnfs_find_lseg(struct pnfs_layout_hdr *lo,
dprintk("%s:Begin\n", __func__);
- 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->pls_range, range)) {
- ret = get_lseg(lseg);
+ ret = pnfs_get_lseg(lseg);
break;
}
if (lseg->pls_range.offset > range->offset)
@@ -1013,7 +1079,6 @@ pnfs_update_layout(struct inode *ino,
.length = count,
};
unsigned pg_offset;
- struct nfs_inode *nfsi = NFS_I(ino);
struct nfs_server *server = NFS_SERVER(ino);
struct nfs_client *clp = server->nfs_client;
struct pnfs_layout_hdr *lo;
@@ -1021,16 +1086,16 @@ pnfs_update_layout(struct inode *ino,
bool first = false;
if (!pnfs_enabled_sb(NFS_SERVER(ino)))
- return NULL;
+ goto out;
if (pnfs_within_mdsthreshold(ctx, ino, iomode))
- return NULL;
+ goto out;
spin_lock(&ino->i_lock);
lo = pnfs_find_alloc_layout(ino, ctx, gfp_flags);
if (lo == NULL) {
- dprintk("%s ERROR: can't get pnfs_layout_hdr\n", __func__);
- goto out_unlock;
+ spin_unlock(&ino->i_lock);
+ goto out;
}
/* Do we even need to bother with this? */
@@ -1040,7 +1105,7 @@ pnfs_update_layout(struct inode *ino,
}
/* if LAYOUTGET already failed once we don't try again */
- if (test_bit(lo_fail_bit(iomode), &nfsi->layout->plh_flags))
+ if (pnfs_layout_io_test_failed(lo, iomode))
goto out_unlock;
/* Check to see if the layout for the given range already exists */
@@ -1048,17 +1113,13 @@ pnfs_update_layout(struct inode *ino,
if (lseg)
goto out_unlock;
- if (pnfs_layoutgets_blocked(lo, NULL, 0))
+ if (pnfs_layoutgets_blocked(lo, 0))
goto out_unlock;
atomic_inc(&lo->plh_outstanding);
- get_layout_hdr(lo);
if (list_empty(&lo->plh_segs))
first = true;
- /* Enable LAYOUTRETURNs */
- pnfs_clear_layout_returned(lo);
-
spin_unlock(&ino->i_lock);
if (first) {
/* The lo must be on the clp list if there is any
@@ -1079,24 +1140,26 @@ pnfs_update_layout(struct inode *ino,
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);
- spin_unlock(&clp->cl_lock);
- }
atomic_dec(&lo->plh_outstanding);
- put_layout_hdr(lo);
+out_put_layout_hdr:
+ pnfs_put_layout_hdr(lo);
out:
- dprintk("%s end, state 0x%lx lseg %p\n", __func__,
- nfsi->layout ? nfsi->layout->plh_flags : -1, lseg);
+ dprintk("%s: inode %s/%llu pNFS layout segment %s for "
+ "(%s, offset: %llu, length: %llu)\n",
+ __func__, ino->i_sb->s_id,
+ (unsigned long long)NFS_FILEID(ino),
+ lseg == NULL ? "not found" : "found",
+ iomode==IOMODE_RW ? "read/write" : "read-only",
+ (unsigned long long)pos,
+ (unsigned long long)count);
return lseg;
out_unlock:
spin_unlock(&ino->i_lock);
- goto out;
+ goto out_put_layout_hdr;
}
EXPORT_SYMBOL_GPL(pnfs_update_layout);
-int
+struct pnfs_layout_segment *
pnfs_layout_process(struct nfs4_layoutget *lgp)
{
struct pnfs_layout_hdr *lo = NFS_I(lgp->args.inode)->layout;
@@ -1123,25 +1186,29 @@ pnfs_layout_process(struct nfs4_layoutget *lgp)
goto out_forget_reply;
}
- if (pnfs_layoutgets_blocked(lo, &res->stateid, 1)) {
+ if (pnfs_layoutgets_blocked(lo, 1) ||
+ pnfs_layout_stateid_blocked(lo, &res->stateid)) {
dprintk("%s forget reply due to state\n", __func__);
goto out_forget_reply;
}
+
+ /* Done processing layoutget. Set the layout stateid */
+ pnfs_set_layout_stateid(lo, &res->stateid, false);
+
init_lseg(lo, lseg);
lseg->pls_range = res->range;
- *lgp->lsegpp = get_lseg(lseg);
- pnfs_insert_layout(lo, lseg);
+ pnfs_get_lseg(lseg);
+ pnfs_layout_insert_lseg(lo, lseg);
if (res->return_on_close) {
set_bit(NFS_LSEG_ROC, &lseg->pls_flags);
set_bit(NFS_LAYOUT_ROC, &lo->plh_flags);
}
- /* Done processing layoutget. Set the layout stateid */
- pnfs_set_layout_stateid(lo, &res->stateid, false);
spin_unlock(&ino->i_lock);
+ return lseg;
out:
- return status;
+ return ERR_PTR(status);
out_forget_reply:
spin_unlock(&ino->i_lock);
@@ -1153,16 +1220,24 @@ out_forget_reply:
void
pnfs_generic_pg_init_read(struct nfs_pageio_descriptor *pgio, struct nfs_page *req)
{
+ u64 rd_size = req->wb_bytes;
+
BUG_ON(pgio->pg_lseg != NULL);
if (req->wb_offset != req->wb_pgbase) {
nfs_pageio_reset_read_mds(pgio);
return;
}
+
+ if (pgio->pg_dreq == NULL)
+ rd_size = i_size_read(pgio->pg_inode) - req_offset(req);
+ else
+ rd_size = nfs_dreq_bytes_left(pgio->pg_dreq);
+
pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode,
req->wb_context,
req_offset(req),
- req->wb_bytes,
+ rd_size,
IOMODE_READ,
GFP_KERNEL);
/* If no lseg, fall back to read through mds */
@@ -1173,7 +1248,8 @@ pnfs_generic_pg_init_read(struct nfs_pageio_descriptor *pgio, struct nfs_page *r
EXPORT_SYMBOL_GPL(pnfs_generic_pg_init_read);
void
-pnfs_generic_pg_init_write(struct nfs_pageio_descriptor *pgio, struct nfs_page *req)
+pnfs_generic_pg_init_write(struct nfs_pageio_descriptor *pgio,
+ struct nfs_page *req, u64 wb_size)
{
BUG_ON(pgio->pg_lseg != NULL);
@@ -1181,10 +1257,11 @@ pnfs_generic_pg_init_write(struct nfs_pageio_descriptor *pgio, struct nfs_page *
nfs_pageio_reset_write_mds(pgio);
return;
}
+
pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode,
req->wb_context,
req_offset(req),
- req->wb_bytes,
+ wb_size,
IOMODE_RW,
GFP_NOFS);
/* If no lseg, fall back to write through mds */
@@ -1362,12 +1439,12 @@ pnfs_do_multiple_writes(struct nfs_pageio_descriptor *desc, struct list_head *he
if (trypnfs == PNFS_NOT_ATTEMPTED)
pnfs_write_through_mds(desc, data);
}
- put_lseg(lseg);
+ pnfs_put_lseg(lseg);
}
static void pnfs_writehdr_free(struct nfs_pgio_header *hdr)
{
- put_lseg(hdr->lseg);
+ pnfs_put_lseg(hdr->lseg);
nfs_writehdr_free(hdr);
}
EXPORT_SYMBOL_GPL(pnfs_writehdr_free);
@@ -1382,17 +1459,17 @@ pnfs_generic_pg_writepages(struct nfs_pageio_descriptor *desc)
whdr = nfs_writehdr_alloc();
if (!whdr) {
desc->pg_completion_ops->error_cleanup(&desc->pg_list);
- put_lseg(desc->pg_lseg);
+ pnfs_put_lseg(desc->pg_lseg);
desc->pg_lseg = NULL;
return -ENOMEM;
}
hdr = &whdr->header;
nfs_pgheader_init(desc, hdr, pnfs_writehdr_free);
- hdr->lseg = get_lseg(desc->pg_lseg);
+ hdr->lseg = pnfs_get_lseg(desc->pg_lseg);
atomic_inc(&hdr->refcnt);
ret = nfs_generic_flush(desc, hdr);
if (ret != 0) {
- put_lseg(desc->pg_lseg);
+ pnfs_put_lseg(desc->pg_lseg);
desc->pg_lseg = NULL;
} else
pnfs_do_multiple_writes(desc, &hdr->rpc_list, desc->pg_ioflags);
@@ -1517,12 +1594,12 @@ pnfs_do_multiple_reads(struct nfs_pageio_descriptor *desc, struct list_head *hea
if (trypnfs == PNFS_NOT_ATTEMPTED)
pnfs_read_through_mds(desc, data);
}
- put_lseg(lseg);
+ pnfs_put_lseg(lseg);
}
static void pnfs_readhdr_free(struct nfs_pgio_header *hdr)
{
- put_lseg(hdr->lseg);
+ pnfs_put_lseg(hdr->lseg);
nfs_readhdr_free(hdr);
}
EXPORT_SYMBOL_GPL(pnfs_readhdr_free);
@@ -1538,17 +1615,17 @@ pnfs_generic_pg_readpages(struct nfs_pageio_descriptor *desc)
if (!rhdr) {
desc->pg_completion_ops->error_cleanup(&desc->pg_list);
ret = -ENOMEM;
- put_lseg(desc->pg_lseg);
+ pnfs_put_lseg(desc->pg_lseg);
desc->pg_lseg = NULL;
return ret;
}
hdr = &rhdr->header;
nfs_pgheader_init(desc, hdr, pnfs_readhdr_free);
- hdr->lseg = get_lseg(desc->pg_lseg);
+ hdr->lseg = pnfs_get_lseg(desc->pg_lseg);
atomic_inc(&hdr->refcnt);
ret = nfs_generic_pagein(desc, hdr);
if (ret != 0) {
- put_lseg(desc->pg_lseg);
+ pnfs_put_lseg(desc->pg_lseg);
desc->pg_lseg = NULL;
} else
pnfs_do_multiple_reads(desc, &hdr->rpc_list);
@@ -1574,13 +1651,7 @@ static void pnfs_list_write_lseg(struct inode *inode, struct list_head *listp)
void pnfs_set_lo_fail(struct pnfs_layout_segment *lseg)
{
- if (lseg->pls_range.iomode == IOMODE_RW) {
- dprintk("%s Setting layout IOMODE_RW fail bit\n", __func__);
- set_bit(lo_fail_bit(IOMODE_RW), &lseg->pls_layout->plh_flags);
- } else {
- dprintk("%s Setting layout IOMODE_READ fail bit\n", __func__);
- set_bit(lo_fail_bit(IOMODE_READ), &lseg->pls_layout->plh_flags);
- }
+ pnfs_layout_io_set_failed(lseg->pls_layout, lseg->pls_range.iomode);
}
EXPORT_SYMBOL_GPL(pnfs_set_lo_fail);
@@ -1601,7 +1672,7 @@ pnfs_set_layoutcommit(struct nfs_write_data *wdata)
}
if (!test_and_set_bit(NFS_LSEG_LAYOUTCOMMIT, &hdr->lseg->pls_flags)) {
/* references matched in nfs4_layoutcommit_release */
- get_lseg(hdr->lseg);
+ pnfs_get_lseg(hdr->lseg);
}
if (end_pos > nfsi->layout->plh_lwb)
nfsi->layout->plh_lwb = end_pos;
diff --git a/fs/nfs/pnfs.h b/fs/nfs/pnfs.h
index 745aa1b..2d722db 100644
--- a/fs/nfs/pnfs.h
+++ b/fs/nfs/pnfs.h
@@ -62,9 +62,6 @@ enum {
NFS_LAYOUT_RW_FAILED, /* get rw layout failed stop trying */
NFS_LAYOUT_BULK_RECALL, /* bulk recall affecting layout */
NFS_LAYOUT_ROC, /* some lseg had roc bit set */
- NFS_LAYOUT_DESTROYED, /* no new use of layout allowed */
- NFS_LAYOUT_INVALID, /* layout is being destroyed */
- NFS_LAYOUT_RETURNED, /* layout has already been returned */
};
enum layoutdriver_policy_flags {
@@ -140,6 +137,7 @@ struct pnfs_layout_hdr {
atomic_t plh_outstanding; /* number of RPCs out */
unsigned long plh_block_lgets; /* block LAYOUTGET if >0 */
u32 plh_barrier; /* ignore lower seqids */
+ unsigned long plh_retry_timestamp;
unsigned long plh_flags;
loff_t plh_lwb; /* last write byte for layoutcommit */
struct rpc_cred *plh_lc_cred; /* layoutcommit cred */
@@ -172,12 +170,12 @@ extern int nfs4_proc_getdevicelist(struct nfs_server *server,
struct pnfs_devicelist *devlist);
extern int nfs4_proc_getdeviceinfo(struct nfs_server *server,
struct pnfs_device *dev);
-extern void nfs4_proc_layoutget(struct nfs4_layoutget *lgp, gfp_t gfp_flags);
+extern struct pnfs_layout_segment* nfs4_proc_layoutget(struct nfs4_layoutget *lgp, gfp_t gfp_flags);
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);
+void pnfs_get_layout_hdr(struct pnfs_layout_hdr *lo);
+void pnfs_put_lseg(struct pnfs_layout_segment *lseg);
void pnfs_pageio_init_read(struct nfs_pageio_descriptor *, struct inode *,
const struct nfs_pgio_completion_ops *);
@@ -188,28 +186,29 @@ void set_pnfs_layoutdriver(struct nfs_server *, const struct nfs_fh *, u32);
void unset_pnfs_layoutdriver(struct nfs_server *);
void pnfs_generic_pg_init_read(struct nfs_pageio_descriptor *, struct nfs_page *);
int pnfs_generic_pg_readpages(struct nfs_pageio_descriptor *desc);
-void pnfs_generic_pg_init_write(struct nfs_pageio_descriptor *, struct nfs_page *);
+void pnfs_generic_pg_init_write(struct nfs_pageio_descriptor *pgio,
+ struct nfs_page *req, u64 wb_size);
int pnfs_generic_pg_writepages(struct nfs_pageio_descriptor *desc);
bool pnfs_generic_pg_test(struct nfs_pageio_descriptor *pgio, struct nfs_page *prev, struct nfs_page *req);
void pnfs_set_lo_fail(struct pnfs_layout_segment *lseg);
-int pnfs_layout_process(struct nfs4_layoutget *lgp);
+struct pnfs_layout_segment *pnfs_layout_process(struct nfs4_layoutget *lgp);
void pnfs_free_lseg_list(struct list_head *tmp_list);
void pnfs_destroy_layout(struct nfs_inode *);
void pnfs_destroy_all_layouts(struct nfs_client *);
-void put_layout_hdr(struct pnfs_layout_hdr *lo);
+void pnfs_put_layout_hdr(struct pnfs_layout_hdr *lo);
void pnfs_set_layout_stateid(struct pnfs_layout_hdr *lo,
const nfs4_stateid *new,
bool update_barrier);
int pnfs_choose_layoutget_stateid(nfs4_stateid *dst,
struct pnfs_layout_hdr *lo,
struct nfs4_state *open_state);
-int mark_matching_lsegs_invalid(struct pnfs_layout_hdr *lo,
+int pnfs_mark_matching_lsegs_invalid(struct pnfs_layout_hdr *lo,
struct list_head *tmp_list,
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);
+bool pnfs_roc_drain(struct inode *ino, u32 *barrier, struct rpc_task *task);
void pnfs_set_layoutcommit(struct nfs_write_data *wdata);
void pnfs_cleanup_layoutcommit(struct nfs4_layoutcommit_data *data);
int pnfs_layoutcommit_inode(struct inode *inode, bool sync);
@@ -233,6 +232,7 @@ struct nfs4_threshold *pnfs_mdsthreshold_alloc(void);
/* nfs4_deviceid_flags */
enum {
NFS_DEVICEID_INVALID = 0, /* set when MDS clientid recalled */
+ NFS_DEVICEID_UNAVAILABLE, /* device temporarily unavailable */
};
/* pnfs_dev.c */
@@ -242,6 +242,7 @@ struct nfs4_deviceid_node {
const struct pnfs_layoutdriver_type *ld;
const struct nfs_client *nfs_client;
unsigned long flags;
+ unsigned long timestamp_unavailable;
struct nfs4_deviceid deviceid;
atomic_t ref;
};
@@ -254,34 +255,12 @@ void nfs4_init_deviceid_node(struct nfs4_deviceid_node *,
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_mark_deviceid_unavailable(struct nfs4_deviceid_node *node);
+bool nfs4_test_deviceid_unavailable(struct nfs4_deviceid_node *node);
void nfs4_deviceid_purge_client(const struct nfs_client *);
-static inline void
-pnfs_mark_layout_returned(struct pnfs_layout_hdr *lo)
-{
- set_bit(NFS_LAYOUT_RETURNED, &lo->plh_flags);
-}
-
-static inline void
-pnfs_clear_layout_returned(struct pnfs_layout_hdr *lo)
-{
- clear_bit(NFS_LAYOUT_RETURNED, &lo->plh_flags);
-}
-
-static inline bool
-pnfs_test_layout_returned(struct pnfs_layout_hdr *lo)
-{
- return test_bit(NFS_LAYOUT_RETURNED, &lo->plh_flags);
-}
-
-static inline int lo_fail_bit(u32 iomode)
-{
- return iomode == IOMODE_RW ?
- NFS_LAYOUT_RW_FAILED : NFS_LAYOUT_RO_FAILED;
-}
-
static inline struct pnfs_layout_segment *
-get_lseg(struct pnfs_layout_segment *lseg)
+pnfs_get_lseg(struct pnfs_layout_segment *lseg)
{
if (lseg) {
atomic_inc(&lseg->pls_refcount);
@@ -406,12 +385,12 @@ static inline void pnfs_destroy_layout(struct nfs_inode *nfsi)
}
static inline struct pnfs_layout_segment *
-get_lseg(struct pnfs_layout_segment *lseg)
+pnfs_get_lseg(struct pnfs_layout_segment *lseg)
{
return NULL;
}
-static inline void put_lseg(struct pnfs_layout_segment *lseg)
+static inline void pnfs_put_lseg(struct pnfs_layout_segment *lseg)
{
}
@@ -443,7 +422,7 @@ pnfs_roc_set_barrier(struct inode *ino, u32 barrier)
}
static inline bool
-pnfs_roc_drain(struct inode *ino, u32 *barrier)
+pnfs_roc_drain(struct inode *ino, u32 *barrier, struct rpc_task *task)
{
return false;
}
diff --git a/fs/nfs/pnfs_dev.c b/fs/nfs/pnfs_dev.c
index 73f701f..d35b62e 100644
--- a/fs/nfs/pnfs_dev.c
+++ b/fs/nfs/pnfs_dev.c
@@ -40,6 +40,8 @@
#define NFS4_DEVICE_ID_HASH_SIZE (1 << NFS4_DEVICE_ID_HASH_BITS)
#define NFS4_DEVICE_ID_HASH_MASK (NFS4_DEVICE_ID_HASH_SIZE - 1)
+#define PNFS_DEVICE_RETRY_TIMEOUT (120*HZ)
+
static struct hlist_head nfs4_deviceid_cache[NFS4_DEVICE_ID_HASH_SIZE];
static DEFINE_SPINLOCK(nfs4_deviceid_lock);
@@ -218,6 +220,30 @@ nfs4_put_deviceid_node(struct nfs4_deviceid_node *d)
}
EXPORT_SYMBOL_GPL(nfs4_put_deviceid_node);
+void
+nfs4_mark_deviceid_unavailable(struct nfs4_deviceid_node *node)
+{
+ node->timestamp_unavailable = jiffies;
+ set_bit(NFS_DEVICEID_UNAVAILABLE, &node->flags);
+}
+EXPORT_SYMBOL_GPL(nfs4_mark_deviceid_unavailable);
+
+bool
+nfs4_test_deviceid_unavailable(struct nfs4_deviceid_node *node)
+{
+ if (test_bit(NFS_DEVICEID_UNAVAILABLE, &node->flags)) {
+ unsigned long start, end;
+
+ end = jiffies;
+ start = end - PNFS_DEVICE_RETRY_TIMEOUT;
+ if (time_in_range(node->timestamp_unavailable, start, end))
+ return true;
+ clear_bit(NFS_DEVICEID_UNAVAILABLE, &node->flags);
+ }
+ return false;
+}
+EXPORT_SYMBOL_GPL(nfs4_test_deviceid_unavailable);
+
static void
_deviceid_purge_client(const struct nfs_client *clp, long hash)
{
@@ -276,3 +302,4 @@ nfs4_deviceid_mark_client_invalid(struct nfs_client *clp)
}
rcu_read_unlock();
}
+
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index d2c7f5d..e831bce 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -88,6 +88,7 @@ enum {
Opt_sharecache, Opt_nosharecache,
Opt_resvport, Opt_noresvport,
Opt_fscache, Opt_nofscache,
+ Opt_migration, Opt_nomigration,
/* Mount options that take integer arguments */
Opt_port,
@@ -147,6 +148,8 @@ static const match_table_t nfs_mount_option_tokens = {
{ Opt_noresvport, "noresvport" },
{ Opt_fscache, "fsc" },
{ Opt_nofscache, "nofsc" },
+ { Opt_migration, "migration" },
+ { Opt_nomigration, "nomigration" },
{ Opt_port, "port=%s" },
{ Opt_rsize, "rsize=%s" },
@@ -676,6 +679,9 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss,
if (nfss->options & NFS_OPTION_FSCACHE)
seq_printf(m, ",fsc");
+ if (nfss->options & NFS_OPTION_MIGRATION)
+ seq_printf(m, ",migration");
+
if (nfss->flags & NFS_MOUNT_LOOKUP_CACHE_NONEG) {
if (nfss->flags & NFS_MOUNT_LOOKUP_CACHE_NONE)
seq_printf(m, ",lookupcache=none");
@@ -1106,7 +1112,7 @@ static int nfs_get_option_ul(substring_t args[], unsigned long *option)
string = match_strdup(args);
if (string == NULL)
return -ENOMEM;
- rc = strict_strtoul(string, 10, option);
+ rc = kstrtoul(string, 10, option);
kfree(string);
return rc;
@@ -1243,6 +1249,12 @@ static int nfs_parse_mount_options(char *raw,
kfree(mnt->fscache_uniq);
mnt->fscache_uniq = NULL;
break;
+ case Opt_migration:
+ mnt->options |= NFS_OPTION_MIGRATION;
+ break;
+ case Opt_nomigration:
+ mnt->options &= NFS_OPTION_MIGRATION;
+ break;
/*
* options that take numeric values
@@ -1535,6 +1547,10 @@ static int nfs_parse_mount_options(char *raw,
if (mnt->minorversion && mnt->version != 4)
goto out_minorversion_mismatch;
+ if (mnt->options & NFS_OPTION_MIGRATION &&
+ mnt->version != 4 && mnt->minorversion != 0)
+ goto out_migration_misuse;
+
/*
* verify that any proto=/mountproto= options match the address
* families in the addr=/mountaddr= options.
@@ -1572,6 +1588,10 @@ out_minorversion_mismatch:
printk(KERN_INFO "NFS: mount option vers=%u does not support "
"minorversion=%u\n", mnt->version, mnt->minorversion);
return 0;
+out_migration_misuse:
+ printk(KERN_INFO
+ "NFS: 'migration' not supported for this NFS version\n");
+ return 0;
out_nomem:
printk(KERN_INFO "NFS: not enough memory to parse option\n");
return 0;
@@ -2494,7 +2514,7 @@ EXPORT_SYMBOL_GPL(nfs_kill_super);
/*
* Clone an NFS2/3/4 server record on xdev traversal (FSID-change)
*/
-struct dentry *
+static struct dentry *
nfs_xdev_mount(struct file_system_type *fs_type, int flags,
const char *dev_name, void *raw_data)
{
@@ -2642,6 +2662,7 @@ unsigned int nfs_idmap_cache_timeout = 600;
bool nfs4_disable_idmapping = true;
unsigned short max_session_slots = NFS4_DEF_SLOT_TABLE_SIZE;
unsigned short send_implementation_id = 1;
+char nfs4_client_id_uniquifier[NFS4_CLIENT_ID_UNIQ_LEN] = "";
EXPORT_SYMBOL_GPL(nfs_callback_set_tcpport);
EXPORT_SYMBOL_GPL(nfs_callback_tcpport);
@@ -2649,6 +2670,7 @@ EXPORT_SYMBOL_GPL(nfs_idmap_cache_timeout);
EXPORT_SYMBOL_GPL(nfs4_disable_idmapping);
EXPORT_SYMBOL_GPL(max_session_slots);
EXPORT_SYMBOL_GPL(send_implementation_id);
+EXPORT_SYMBOL_GPL(nfs4_client_id_uniquifier);
#define NFS_CALLBACK_MAXPORTNR (65535U)
@@ -2659,7 +2681,7 @@ static int param_set_portnr(const char *val, const struct kernel_param *kp)
if (!val)
return -EINVAL;
- ret = strict_strtoul(val, 0, &num);
+ ret = kstrtoul(val, 0, &num);
if (ret == -EINVAL || num > NFS_CALLBACK_MAXPORTNR)
return -EINVAL;
*((unsigned int *)kp->arg) = num;
@@ -2674,6 +2696,8 @@ static struct kernel_param_ops param_ops_portnr = {
module_param_named(callback_tcpport, nfs_callback_set_tcpport, portnr, 0644);
module_param(nfs_idmap_cache_timeout, int, 0644);
module_param(nfs4_disable_idmapping, bool, 0644);
+module_param_string(nfs4_unique_id, nfs4_client_id_uniquifier,
+ NFS4_CLIENT_ID_UNIQ_LEN, 0600);
MODULE_PARM_DESC(nfs4_disable_idmapping,
"Turn off NFSv4 idmapping when using 'sec=sys'");
module_param(max_session_slots, ushort, 0644);
@@ -2682,6 +2706,7 @@ MODULE_PARM_DESC(max_session_slots, "Maximum number of outstanding NFSv4.1 "
module_param(send_implementation_id, ushort, 0644);
MODULE_PARM_DESC(send_implementation_id,
"Send implementation ID with NFSv4.1 exchange_id");
+MODULE_PARM_DESC(nfs4_unique_id, "nfs_client_id4 uniquifier string");
MODULE_ALIAS("nfs4");
#endif /* CONFIG_NFS_V4 */
diff --git a/fs/nfs/write.c b/fs/nfs/write.c
index e3b5537..9347ab7 100644
--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -846,6 +846,7 @@ static int nfs_writepage_setup(struct nfs_open_context *ctx, struct page *page,
int nfs_flush_incompatible(struct file *file, struct page *page)
{
struct nfs_open_context *ctx = nfs_file_open_context(file);
+ struct nfs_lock_context *l_ctx;
struct nfs_page *req;
int do_flush, status;
/*
@@ -860,9 +861,12 @@ int nfs_flush_incompatible(struct file *file, struct page *page)
req = nfs_page_find_request(page);
if (req == NULL)
return 0;
- do_flush = req->wb_page != page || req->wb_context != ctx ||
- req->wb_lock_context->lockowner != current->files ||
- req->wb_lock_context->pid != current->tgid;
+ l_ctx = req->wb_lock_context;
+ do_flush = req->wb_page != page || req->wb_context != ctx;
+ if (l_ctx) {
+ do_flush |= l_ctx->lockowner.l_owner != current->files
+ || l_ctx->lockowner.l_pid != current->tgid;
+ }
nfs_release_request(req);
if (!do_flush)
return 0;
@@ -1576,6 +1580,7 @@ static void nfs_commit_release_pages(struct nfs_commit_data *data)
/* We have a mismatch. Write the page again */
dprintk(" mismatch\n");
nfs_mark_request_dirty(req);
+ set_bit(NFS_CONTEXT_RESEND_WRITES, &req->wb_context->flags);
next:
nfs_unlock_and_release_request(req);
}
diff --git a/include/linux/bcma/bcma_driver_chipcommon.h b/include/linux/bcma/bcma_driver_chipcommon.h
index 6ba45d2..1cf1749 100644
--- a/include/linux/bcma/bcma_driver_chipcommon.h
+++ b/include/linux/bcma/bcma_driver_chipcommon.h
@@ -522,6 +522,8 @@ struct bcma_sflash {
u32 blocksize;
u16 numblocks;
u32 size;
+
+ struct mtd_info *mtd;
};
#endif
diff --git a/include/linux/binfmts.h b/include/linux/binfmts.h
index 37935c2..26531f3 100644
--- a/include/linux/binfmts.h
+++ b/include/linux/binfmts.h
@@ -19,6 +19,8 @@ struct pt_regs;
#ifdef __KERNEL__
#include <linux/sched.h>
+#include <linux/unistd.h>
+#include <asm/exec.h>
#define CORENAME_MAX_SIZE 128
@@ -135,5 +137,9 @@ extern void install_exec_creds(struct linux_binprm *bprm);
extern void set_binfmt(struct linux_binfmt *new);
extern void free_bprm(struct linux_binprm *);
+#ifdef __ARCH_WANT_KERNEL_EXECVE
+extern void ret_from_kernel_execve(struct pt_regs *normal) __noreturn;
+#endif
+
#endif /* __KERNEL__ */
#endif /* _LINUX_BINFMTS_H */
diff --git a/include/linux/bio.h b/include/linux/bio.h
index 2643589..820e7aa 100644
--- a/include/linux/bio.h
+++ b/include/linux/bio.h
@@ -212,20 +212,41 @@ extern void bio_pair_release(struct bio_pair *dbio);
extern struct bio_set *bioset_create(unsigned int, unsigned int);
extern void bioset_free(struct bio_set *);
-extern struct bio *bio_alloc(gfp_t, unsigned int);
-extern struct bio *bio_kmalloc(gfp_t, unsigned int);
extern struct bio *bio_alloc_bioset(gfp_t, int, struct bio_set *);
extern void bio_put(struct bio *);
-extern void bio_free(struct bio *, struct bio_set *);
+
+extern void __bio_clone(struct bio *, struct bio *);
+extern struct bio *bio_clone_bioset(struct bio *, gfp_t, struct bio_set *bs);
+
+extern struct bio_set *fs_bio_set;
+
+static inline struct bio *bio_alloc(gfp_t gfp_mask, unsigned int nr_iovecs)
+{
+ return bio_alloc_bioset(gfp_mask, nr_iovecs, fs_bio_set);
+}
+
+static inline struct bio *bio_clone(struct bio *bio, gfp_t gfp_mask)
+{
+ return bio_clone_bioset(bio, gfp_mask, fs_bio_set);
+}
+
+static inline struct bio *bio_kmalloc(gfp_t gfp_mask, unsigned int nr_iovecs)
+{
+ return bio_alloc_bioset(gfp_mask, nr_iovecs, NULL);
+}
+
+static inline struct bio *bio_clone_kmalloc(struct bio *bio, gfp_t gfp_mask)
+{
+ return bio_clone_bioset(bio, gfp_mask, NULL);
+
+}
extern void bio_endio(struct bio *, int);
struct request_queue;
extern int bio_phys_segments(struct request_queue *, struct bio *);
-extern void __bio_clone(struct bio *, struct bio *);
-extern struct bio *bio_clone(struct bio *, gfp_t);
-
extern void bio_init(struct bio *);
+extern void bio_reset(struct bio *);
extern int bio_add_page(struct bio *, struct page *, unsigned int,unsigned int);
extern int bio_add_pc_page(struct request_queue *, struct bio *, struct page *,
@@ -304,8 +325,6 @@ struct biovec_slab {
struct kmem_cache *slab;
};
-extern struct bio_set *fs_bio_set;
-
/*
* a small number of entries is fine, not going to be performance critical.
* basically we just need to survive
@@ -367,9 +386,31 @@ static inline char *__bio_kmap_irq(struct bio *bio, unsigned short idx,
/*
* Check whether this bio carries any data or not. A NULL bio is allowed.
*/
-static inline int bio_has_data(struct bio *bio)
+static inline bool bio_has_data(struct bio *bio)
{
- return bio && bio->bi_io_vec != NULL;
+ if (bio && bio->bi_vcnt)
+ return true;
+
+ return false;
+}
+
+static inline bool bio_is_rw(struct bio *bio)
+{
+ if (!bio_has_data(bio))
+ return false;
+
+ if (bio->bi_rw & REQ_WRITE_SAME)
+ return false;
+
+ return true;
+}
+
+static inline bool bio_mergeable(struct bio *bio)
+{
+ if (bio->bi_rw & REQ_NOMERGE_FLAGS)
+ return false;
+
+ return true;
}
/*
@@ -505,9 +546,8 @@ static inline struct bio *bio_list_get(struct bio_list *bl)
#define bio_integrity(bio) (bio->bi_integrity != NULL)
-extern struct bio_integrity_payload *bio_integrity_alloc_bioset(struct bio *, gfp_t, unsigned int, struct bio_set *);
extern struct bio_integrity_payload *bio_integrity_alloc(struct bio *, gfp_t, unsigned int);
-extern void bio_integrity_free(struct bio *, struct bio_set *);
+extern void bio_integrity_free(struct bio *);
extern int bio_integrity_add_page(struct bio *, struct page *, unsigned int, unsigned int);
extern int bio_integrity_enabled(struct bio *bio);
extern int bio_integrity_set_tag(struct bio *, void *, unsigned int);
@@ -517,7 +557,7 @@ extern void bio_integrity_endio(struct bio *, int);
extern void bio_integrity_advance(struct bio *, unsigned int);
extern void bio_integrity_trim(struct bio *, unsigned int, unsigned int);
extern void bio_integrity_split(struct bio *, struct bio_pair *, int);
-extern int bio_integrity_clone(struct bio *, struct bio *, gfp_t, struct bio_set *);
+extern int bio_integrity_clone(struct bio *, struct bio *, gfp_t);
extern int bioset_integrity_create(struct bio_set *, int);
extern void bioset_integrity_free(struct bio_set *);
extern void bio_integrity_init(void);
@@ -549,13 +589,13 @@ static inline int bio_integrity_prep(struct bio *bio)
return 0;
}
-static inline void bio_integrity_free(struct bio *bio, struct bio_set *bs)
+static inline void bio_integrity_free(struct bio *bio)
{
return;
}
static inline int bio_integrity_clone(struct bio *bio, struct bio *bio_src,
- gfp_t gfp_mask, struct bio_set *bs)
+ gfp_t gfp_mask)
{
return 0;
}
diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h
index 7b7ac9c..cdf1119 100644
--- a/include/linux/blk_types.h
+++ b/include/linux/blk_types.h
@@ -59,12 +59,6 @@ struct bio {
unsigned int bi_seg_front_size;
unsigned int bi_seg_back_size;
- unsigned int bi_max_vecs; /* max bvl_vecs we can hold */
-
- atomic_t bi_cnt; /* pin count */
-
- struct bio_vec *bi_io_vec; /* the actual vec list */
-
bio_end_io_t *bi_end_io;
void *bi_private;
@@ -80,7 +74,17 @@ struct bio {
struct bio_integrity_payload *bi_integrity; /* data integrity */
#endif
- bio_destructor_t *bi_destructor; /* destructor */
+ /*
+ * Everything starting with bi_max_vecs will be preserved by bio_reset()
+ */
+
+ unsigned int bi_max_vecs; /* max bvl_vecs we can hold */
+
+ atomic_t bi_cnt; /* pin count */
+
+ struct bio_vec *bi_io_vec; /* the actual vec list */
+
+ struct bio_set *bi_pool;
/*
* We can inline a number of vecs at the end of the bio, to avoid
@@ -90,6 +94,8 @@ struct bio {
struct bio_vec bi_inline_vecs[0];
};
+#define BIO_RESET_BYTES offsetof(struct bio, bi_max_vecs)
+
/*
* bio flags
*/
@@ -105,6 +111,13 @@ struct bio {
#define BIO_FS_INTEGRITY 9 /* fs owns integrity data, not block layer */
#define BIO_QUIET 10 /* Make BIO Quiet */
#define BIO_MAPPED_INTEGRITY 11/* integrity metadata has been remapped */
+
+/*
+ * Flags starting here get preserved by bio_reset() - this includes
+ * BIO_POOL_IDX()
+ */
+#define BIO_RESET_BITS 12
+
#define bio_flagged(bio, flag) ((bio)->bi_flags & (1 << (flag)))
/*
@@ -134,6 +147,7 @@ enum rq_flag_bits {
__REQ_PRIO, /* boost priority in cfq */
__REQ_DISCARD, /* request to discard sectors */
__REQ_SECURE, /* secure discard (used with __REQ_DISCARD) */
+ __REQ_WRITE_SAME, /* write same block many times */
__REQ_NOIDLE, /* don't anticipate more IO after this one */
__REQ_FUA, /* forced unit access */
@@ -172,15 +186,21 @@ enum rq_flag_bits {
#define REQ_META (1 << __REQ_META)
#define REQ_PRIO (1 << __REQ_PRIO)
#define REQ_DISCARD (1 << __REQ_DISCARD)
+#define REQ_WRITE_SAME (1 << __REQ_WRITE_SAME)
#define REQ_NOIDLE (1 << __REQ_NOIDLE)
#define REQ_FAILFAST_MASK \
(REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT | REQ_FAILFAST_DRIVER)
#define REQ_COMMON_MASK \
(REQ_WRITE | REQ_FAILFAST_MASK | REQ_SYNC | REQ_META | REQ_PRIO | \
- REQ_DISCARD | REQ_NOIDLE | REQ_FLUSH | REQ_FUA | REQ_SECURE)
+ REQ_DISCARD | REQ_WRITE_SAME | REQ_NOIDLE | REQ_FLUSH | REQ_FUA | \
+ REQ_SECURE)
#define REQ_CLONE_MASK REQ_COMMON_MASK
+/* This mask is used for both bio and request merge checking */
+#define REQ_NOMERGE_FLAGS \
+ (REQ_NOMERGE | REQ_STARTED | REQ_SOFTBARRIER | REQ_FLUSH | REQ_FUA)
+
#define REQ_RAHEAD (1 << __REQ_RAHEAD)
#define REQ_THROTTLED (1 << __REQ_THROTTLED)
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 4a2ab7c..1756001 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -270,6 +270,7 @@ struct queue_limits {
unsigned int io_min;
unsigned int io_opt;
unsigned int max_discard_sectors;
+ unsigned int max_write_same_sectors;
unsigned int discard_granularity;
unsigned int discard_alignment;
@@ -540,8 +541,7 @@ static inline void queue_flag_clear(unsigned int flag, struct request_queue *q)
#define blk_account_rq(rq) \
(((rq)->cmd_flags & REQ_STARTED) && \
- ((rq)->cmd_type == REQ_TYPE_FS || \
- ((rq)->cmd_flags & REQ_DISCARD)))
+ ((rq)->cmd_type == REQ_TYPE_FS))
#define blk_pm_request(rq) \
((rq)->cmd_type == REQ_TYPE_PM_SUSPEND || \
@@ -595,17 +595,39 @@ static inline void blk_clear_rl_full(struct request_list *rl, bool sync)
rl->flags &= ~flag;
}
+static inline bool rq_mergeable(struct request *rq)
+{
+ if (rq->cmd_type != REQ_TYPE_FS)
+ return false;
-/*
- * mergeable request must not have _NOMERGE or _BARRIER bit set, nor may
- * it already be started by driver.
- */
-#define RQ_NOMERGE_FLAGS \
- (REQ_NOMERGE | REQ_STARTED | REQ_SOFTBARRIER | REQ_FLUSH | REQ_FUA | REQ_DISCARD)
-#define rq_mergeable(rq) \
- (!((rq)->cmd_flags & RQ_NOMERGE_FLAGS) && \
- (((rq)->cmd_flags & REQ_DISCARD) || \
- (rq)->cmd_type == REQ_TYPE_FS))
+ if (rq->cmd_flags & REQ_NOMERGE_FLAGS)
+ return false;
+
+ return true;
+}
+
+static inline bool blk_check_merge_flags(unsigned int flags1,
+ unsigned int flags2)
+{
+ if ((flags1 & REQ_DISCARD) != (flags2 & REQ_DISCARD))
+ return false;
+
+ if ((flags1 & REQ_SECURE) != (flags2 & REQ_SECURE))
+ return false;
+
+ if ((flags1 & REQ_WRITE_SAME) != (flags2 & REQ_WRITE_SAME))
+ return false;
+
+ return true;
+}
+
+static inline bool blk_write_same_mergeable(struct bio *a, struct bio *b)
+{
+ if (bio_data(a) == bio_data(b))
+ return true;
+
+ return false;
+}
/*
* q->prep_rq_fn return values
@@ -802,6 +824,28 @@ static inline unsigned int blk_rq_cur_sectors(const struct request *rq)
return blk_rq_cur_bytes(rq) >> 9;
}
+static inline unsigned int blk_queue_get_max_sectors(struct request_queue *q,
+ unsigned int cmd_flags)
+{
+ if (unlikely(cmd_flags & REQ_DISCARD))
+ return q->limits.max_discard_sectors;
+
+ if (unlikely(cmd_flags & REQ_WRITE_SAME))
+ return q->limits.max_write_same_sectors;
+
+ return q->limits.max_sectors;
+}
+
+static inline unsigned int blk_rq_get_max_sectors(struct request *rq)
+{
+ struct request_queue *q = rq->q;
+
+ if (unlikely(rq->cmd_type == REQ_TYPE_BLOCK_PC))
+ return q->limits.max_hw_sectors;
+
+ return blk_queue_get_max_sectors(q, rq->cmd_flags);
+}
+
/*
* Request issue related functions.
*/
@@ -857,6 +901,8 @@ extern void blk_queue_max_segments(struct request_queue *, unsigned short);
extern void blk_queue_max_segment_size(struct request_queue *, unsigned int);
extern void blk_queue_max_discard_sectors(struct request_queue *q,
unsigned int max_discard_sectors);
+extern void blk_queue_max_write_same_sectors(struct request_queue *q,
+ unsigned int max_write_same_sectors);
extern void blk_queue_logical_block_size(struct request_queue *, unsigned short);
extern void blk_queue_physical_block_size(struct request_queue *, unsigned int);
extern void blk_queue_alignment_offset(struct request_queue *q,
@@ -987,6 +1033,8 @@ static inline struct request *blk_map_queue_find_tag(struct blk_queue_tag *bqt,
extern int blkdev_issue_flush(struct block_device *, gfp_t, sector_t *);
extern int blkdev_issue_discard(struct block_device *bdev, sector_t sector,
sector_t nr_sects, gfp_t gfp_mask, unsigned long flags);
+extern int blkdev_issue_write_same(struct block_device *bdev, sector_t sector,
+ sector_t nr_sects, gfp_t gfp_mask, struct page *page);
extern int blkdev_issue_zeroout(struct block_device *bdev, sector_t sector,
sector_t nr_sects, gfp_t gfp_mask);
static inline int sb_issue_discard(struct super_block *sb, sector_t block,
@@ -1164,6 +1212,16 @@ static inline unsigned int bdev_discard_zeroes_data(struct block_device *bdev)
return queue_discard_zeroes_data(bdev_get_queue(bdev));
}
+static inline unsigned int bdev_write_same(struct block_device *bdev)
+{
+ struct request_queue *q = bdev_get_queue(bdev);
+
+ if (q)
+ return q->limits.max_write_same_sectors;
+
+ return 0;
+}
+
static inline int queue_dma_alignment(struct request_queue *q)
{
return q ? q->dma_alignment : 511;
diff --git a/include/linux/caif/Kbuild b/include/linux/caif/Kbuild
index a9cf250..e69de29 100644
--- a/include/linux/caif/Kbuild
+++ b/include/linux/caif/Kbuild
@@ -1,2 +0,0 @@
-header-y += caif_socket.h
-header-y += if_caif.h
diff --git a/include/linux/compat.h b/include/linux/compat.h
index 3f53d00..d0ced10 100644
--- a/include/linux/compat.h
+++ b/include/linux/compat.h
@@ -284,8 +284,12 @@ 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(const char *filename, const compat_uptr_t __user *argv,
+ const compat_uptr_t __user *envp, struct pt_regs *regs);
+#ifdef __ARCH_WANT_SYS_EXECVE
+asmlinkage long compat_sys_execve(const char __user *filename, const compat_uptr_t __user *argv,
+ const compat_uptr_t __user *envp);
+#endif
asmlinkage long compat_sys_select(int n, compat_ulong_t __user *inp,
compat_ulong_t __user *outp, compat_ulong_t __user *exp,
diff --git a/include/linux/compiler-gcc4.h b/include/linux/compiler-gcc4.h
index 934bc34..412bc6c 100644
--- a/include/linux/compiler-gcc4.h
+++ b/include/linux/compiler-gcc4.h
@@ -59,7 +59,7 @@
#if __GNUC_MINOR__ > 0
#define __compiletime_object_size(obj) __builtin_object_size(obj, 0)
#endif
-#if __GNUC_MINOR__ >= 4 && !defined(__CHECKER__)
+#if __GNUC_MINOR__ >= 3 && !defined(__CHECKER__)
#define __compiletime_warning(message) __attribute__((warning(message)))
#define __compiletime_error(message) __attribute__((error(message)))
#endif
diff --git a/include/linux/dw_dmac.h b/include/linux/dw_dmac.h
index 2412e02..e1c8c9e 100644
--- a/include/linux/dw_dmac.h
+++ b/include/linux/dw_dmac.h
@@ -19,6 +19,10 @@
* @nr_channels: Number of channels supported by hardware (max 8)
* @is_private: The device channels should be marked as private and not for
* by the general purpose DMA channel allocator.
+ * @block_size: Maximum block size supported by the controller
+ * @nr_masters: Number of AHB masters supported by the controller
+ * @data_width: Maximum data width supported by hardware per AHB master
+ * (0 - 8bits, 1 - 16bits, ..., 5 - 256bits)
*/
struct dw_dma_platform_data {
unsigned int nr_channels;
@@ -29,6 +33,9 @@ struct dw_dma_platform_data {
#define CHAN_PRIORITY_ASCENDING 0 /* chan0 highest */
#define CHAN_PRIORITY_DESCENDING 1 /* chan7 highest */
unsigned char chan_priority;
+ unsigned short block_size;
+ unsigned char nr_masters;
+ unsigned char data_width[4];
};
/* bursts size */
diff --git a/include/linux/edma.h b/include/linux/edma.h
new file mode 100644
index 0000000..a1307e7
--- /dev/null
+++ b/include/linux/edma.h
@@ -0,0 +1,29 @@
+/*
+ * TI EDMA DMA engine driver
+ *
+ * Copyright 2012 Texas Instruments
+ *
+ * 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 "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#ifndef __LINUX_EDMA_H
+#define __LINUX_EDMA_H
+
+struct dma_chan;
+
+#if defined(CONFIG_TI_EDMA) || defined(CONFIG_TI_EDMA_MODULE)
+bool edma_filter_fn(struct dma_chan *, void *);
+#else
+static inline bool edma_filter_fn(struct dma_chan *chan, void *param)
+{
+ return false;
+}
+#endif
+
+#endif
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 9baf827..8ef2fc9 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -335,6 +335,7 @@ struct inodes_stat_t {
#define BLKDISCARDZEROES _IO(0x12,124)
#define BLKSECDISCARD _IO(0x12,125)
#define BLKROTATIONAL _IO(0x12,126)
+#define BLKZEROOUT _IO(0x12,127)
#define BMAP_IOCTL 1 /* obsolete - kept for compatibility */
#define FIBMAP _IO(0x00,1) /* bmap access */
@@ -415,6 +416,7 @@ struct inodes_stat_t {
#include <linux/migrate_mode.h>
#include <linux/uidgid.h>
#include <linux/lockdep.h>
+#include <linux/percpu-rwsem.h>
#include <asm/byteorder.h>
@@ -724,6 +726,8 @@ struct block_device {
int bd_fsfreeze_count;
/* Mutex for freeze */
struct mutex bd_fsfreeze_mutex;
+ /* A semaphore that prevents I/O while block size is being changed */
+ struct percpu_rw_semaphore bd_block_size_semaphore;
};
/*
@@ -2569,6 +2573,8 @@ extern int generic_segment_checks(const struct iovec *iov,
unsigned long *nr_segs, size_t *count, int access_flags);
/* fs/block_dev.c */
+extern ssize_t blkdev_aio_read(struct kiocb *iocb, const struct iovec *iov,
+ unsigned long nr_segs, loff_t pos);
extern ssize_t blkdev_aio_write(struct kiocb *iocb, const struct iovec *iov,
unsigned long nr_segs, loff_t pos);
extern int blkdev_fsync(struct file *filp, loff_t start, loff_t end,
diff --git a/include/linux/i2c-algo-pca.h b/include/linux/i2c-algo-pca.h
index 1364d62..a3c3ecd 100644
--- a/include/linux/i2c-algo-pca.h
+++ b/include/linux/i2c-algo-pca.h
@@ -62,6 +62,7 @@ struct i2c_algo_pca_data {
* 330000, 288000, 217000, 146000, 88000, 59000, 44000, 36000
* For PCA9665, use the frequency you want here. */
unsigned int i2c_clock;
+ unsigned int chip;
};
int i2c_pca_add_bus(struct i2c_adapter *);
diff --git a/include/linux/i2c-omap.h b/include/linux/i2c-omap.h
index 92a0dc7..df804ba 100644
--- a/include/linux/i2c-omap.h
+++ b/include/linux/i2c-omap.h
@@ -34,7 +34,6 @@ struct omap_i2c_bus_platform_data {
u32 clkrate;
u32 rev;
u32 flags;
- void (*set_mpu_wkup_lat)(struct device *dev, long set);
};
#endif
diff --git a/include/linux/i2c/i2c-rcar.h b/include/linux/i2c/i2c-rcar.h
new file mode 100644
index 0000000..496f5c2
--- /dev/null
+++ b/include/linux/i2c/i2c-rcar.h
@@ -0,0 +1,10 @@
+#ifndef __I2C_R_CAR_H__
+#define __I2C_R_CAR_H__
+
+#include <linux/platform_device.h>
+
+struct i2c_rcar_platform_data {
+ u32 bus_speed;
+};
+
+#endif /* __I2C_R_CAR_H__ */
diff --git a/include/linux/if_vlan.h b/include/linux/if_vlan.h
index e6ff12d..c0ff748 100644
--- a/include/linux/if_vlan.h
+++ b/include/linux/if_vlan.h
@@ -80,6 +80,8 @@ static inline int is_vlan_dev(struct net_device *dev)
}
#define vlan_tx_tag_present(__skb) ((__skb)->vlan_tci & VLAN_TAG_PRESENT)
+#define vlan_tx_nonzero_tag_present(__skb) \
+ (vlan_tx_tag_present(__skb) && ((__skb)->vlan_tci & VLAN_VID_MASK))
#define vlan_tx_tag_get(__skb) ((__skb)->vlan_tci & ~VLAN_TAG_PRESENT)
#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
@@ -89,7 +91,7 @@ extern struct net_device *__vlan_find_dev_deep(struct net_device *real_dev,
extern struct net_device *vlan_dev_real_dev(const struct net_device *dev);
extern u16 vlan_dev_vlan_id(const struct net_device *dev);
-extern bool vlan_do_receive(struct sk_buff **skb, bool last_handler);
+extern bool vlan_do_receive(struct sk_buff **skb);
extern struct sk_buff *vlan_untag(struct sk_buff *skb);
extern int vlan_vid_add(struct net_device *dev, unsigned short vid);
@@ -120,10 +122,8 @@ static inline u16 vlan_dev_vlan_id(const struct net_device *dev)
return 0;
}
-static inline bool vlan_do_receive(struct sk_buff **skb, bool last_handler)
+static inline bool vlan_do_receive(struct sk_buff **skb)
{
- if (((*skb)->vlan_tci & VLAN_VID_MASK) && last_handler)
- (*skb)->pkt_type = PACKET_OTHERHOST;
return false;
}
diff --git a/include/linux/isdn/Kbuild b/include/linux/isdn/Kbuild
index 991cdb2..e69de29 100644
--- a/include/linux/isdn/Kbuild
+++ b/include/linux/isdn/Kbuild
@@ -1 +0,0 @@
-header-y += capicmd.h
diff --git a/include/linux/leds-lp5523.h b/include/linux/leds-lp5523.h
index 2694289..727877f 100644
--- a/include/linux/leds-lp5523.h
+++ b/include/linux/leds-lp5523.h
@@ -26,6 +26,7 @@
/* See Documentation/leds/leds-lp5523.txt */
struct lp5523_led_config {
+ const char *name;
u8 chan_nr;
u8 led_current; /* mA x10, 0 if led is not connected */
u8 max_current;
diff --git a/include/linux/leds.h b/include/linux/leds.h
index c6f8dad..6e53bb3 100644
--- a/include/linux/leds.h
+++ b/include/linux/leds.h
@@ -16,6 +16,7 @@
#include <linux/spinlock.h>
#include <linux/rwsem.h>
#include <linux/timer.h>
+#include <linux/workqueue.h>
struct device;
/*
@@ -69,6 +70,9 @@ struct led_classdev {
struct timer_list blink_timer;
int blink_brightness;
+ struct work_struct set_brightness_work;
+ int delayed_set_value;
+
#ifdef CONFIG_LEDS_TRIGGERS
/* Protects the trigger data below */
struct rw_semaphore trigger_lock;
diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h
index fd0e6d5..11ddc7f 100644
--- a/include/linux/memcontrol.h
+++ b/include/linux/memcontrol.h
@@ -396,7 +396,7 @@ enum {
};
struct sock;
-#ifdef CONFIG_MEMCG_KMEM
+#if defined(CONFIG_INET) && defined(CONFIG_MEMCG_KMEM)
void sock_update_memcg(struct sock *sk);
void sock_release_memcg(struct sock *sk);
#else
@@ -406,6 +406,6 @@ static inline void sock_update_memcg(struct sock *sk)
static inline void sock_release_memcg(struct sock *sk)
{
}
-#endif /* CONFIG_MEMCG_KMEM */
+#endif /* CONFIG_INET && CONFIG_MEMCG_KMEM */
#endif /* _LINUX_MEMCONTROL_H */
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index 4b27f9f..943550df 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -57,6 +57,7 @@ struct mmc_ext_csd {
unsigned int sa_timeout; /* Units: 100ns */
unsigned int generic_cmd6_time; /* Units: 10ms */
unsigned int power_off_longtime; /* Units: ms */
+ u8 power_off_notification; /* state */
unsigned int hs_max_dtr;
#define MMC_HIGH_26_MAX_DTR 26000000
#define MMC_HIGH_52_MAX_DTR 52000000
@@ -76,10 +77,13 @@ struct mmc_ext_csd {
bool hpi_en; /* HPI enablebit */
bool hpi; /* HPI support bit */
unsigned int hpi_cmd; /* cmd used as HPI */
+ bool bkops; /* background support bit */
+ bool bkops_en; /* background enable bit */
unsigned int data_sector_size; /* 512 bytes or 4KB */
unsigned int data_tag_unit_size; /* DATA TAG UNIT size */
unsigned int boot_ro_lock; /* ro lock support */
bool boot_ro_lockable;
+ u8 raw_exception_status; /* 53 */
u8 raw_partition_support; /* 160 */
u8 raw_erased_mem_count; /* 181 */
u8 raw_ext_csd_structure; /* 194 */
@@ -93,6 +97,7 @@ struct mmc_ext_csd {
u8 raw_sec_erase_mult; /* 230 */
u8 raw_sec_feature_support;/* 231 */
u8 raw_trim_mult; /* 232 */
+ u8 raw_bkops_status; /* 246 */
u8 raw_sectors[4]; /* 212 - 4 bytes */
unsigned int feature_support;
@@ -225,7 +230,7 @@ struct mmc_card {
#define MMC_CARD_SDXC (1<<6) /* card is SDXC */
#define MMC_CARD_REMOVED (1<<7) /* card has been removed */
#define MMC_STATE_HIGHSPEED_200 (1<<8) /* card is in HS200 mode */
-#define MMC_STATE_SLEEP (1<<9) /* card is in sleep state */
+#define MMC_STATE_DOING_BKOPS (1<<10) /* card is doing BKOPS */
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 */
@@ -241,11 +246,6 @@ struct mmc_card {
#define MMC_QUIRK_LONG_READ_TIME (1<<9) /* Data read time > CSD says */
#define MMC_QUIRK_SEC_ERASE_TRIM_BROKEN (1<<10) /* Skip secure for erase/trim */
/* byte mode */
- unsigned int poweroff_notify_state; /* eMMC4.5 notify feature */
-#define MMC_NO_POWER_NOTIFICATION 0
-#define MMC_POWERED_ON 1
-#define MMC_POWEROFF_SHORT 2
-#define MMC_POWEROFF_LONG 3
unsigned int erase_size; /* erase size in sectors */
unsigned int erase_shift; /* if erase unit is power 2 */
@@ -392,7 +392,7 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data)
#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_removed(c) ((c) && ((c)->state & MMC_CARD_REMOVED))
-#define mmc_card_is_sleep(c) ((c)->state & MMC_STATE_SLEEP)
+#define mmc_card_doing_bkops(c) ((c)->state & MMC_STATE_DOING_BKOPS)
#define mmc_card_set_present(c) ((c)->state |= MMC_STATE_PRESENT)
#define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY)
@@ -404,9 +404,9 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data)
#define mmc_sd_card_set_uhs(c) ((c)->state |= MMC_STATE_ULTRAHIGHSPEED)
#define mmc_card_set_ext_capacity(c) ((c)->state |= MMC_CARD_SDXC)
#define mmc_card_set_removed(c) ((c)->state |= MMC_CARD_REMOVED)
-#define mmc_card_set_sleep(c) ((c)->state |= MMC_STATE_SLEEP)
+#define mmc_card_set_doing_bkops(c) ((c)->state |= MMC_STATE_DOING_BKOPS)
+#define mmc_card_clr_doing_bkops(c) ((c)->state &= ~MMC_STATE_DOING_BKOPS)
-#define mmc_card_clr_sleep(c) ((c)->state &= ~MMC_STATE_SLEEP)
/*
* Quirk add/remove for MMC products.
*/
diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h
index 1b431c7..9b9cdaf 100644
--- a/include/linux/mmc/core.h
+++ b/include/linux/mmc/core.h
@@ -134,6 +134,8 @@ struct mmc_host;
struct mmc_card;
struct mmc_async_req;
+extern int mmc_stop_bkops(struct mmc_card *);
+extern int mmc_read_bkops_status(struct mmc_card *);
extern struct mmc_async_req *mmc_start_req(struct mmc_host *,
struct mmc_async_req *, int *);
extern int mmc_interrupt_hpi(struct mmc_card *);
@@ -142,6 +144,8 @@ 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 void mmc_start_bkops(struct mmc_card *card, bool from_exception);
+extern int __mmc_switch(struct mmc_card *, u8, u8, u8, unsigned int, bool);
extern int mmc_switch(struct mmc_card *, u8, u8, u8, unsigned int);
#define MMC_ERASE_ARG 0x00000000
diff --git a/include/linux/mmc/dw_mmc.h b/include/linux/mmc/dw_mmc.h
index 7a7ebd3..7c6a113 100644
--- a/include/linux/mmc/dw_mmc.h
+++ b/include/linux/mmc/dw_mmc.h
@@ -78,6 +78,10 @@ struct mmc_data;
* @data_offset: Set the offset of DATA register according to VERID.
* @dev: Device associated with the MMC controller.
* @pdata: Platform data associated with the MMC controller.
+ * @drv_data: Driver specific data for identified variant of the controller
+ * @priv: Implementation defined private data.
+ * @biu_clk: Pointer to bus interface unit clock instance.
+ * @ciu_clk: Pointer to card interface unit clock instance.
* @slot: Slots sharing this MMC controller.
* @fifo_depth: depth of FIFO.
* @data_shift: log2 of FIFO item size.
@@ -156,8 +160,12 @@ struct dw_mci {
u32 fifoth_val;
u16 verid;
u16 data_offset;
- struct device dev;
+ struct device *dev;
struct dw_mci_board *pdata;
+ struct dw_mci_drv_data *drv_data;
+ void *priv;
+ struct clk *biu_clk;
+ struct clk *ciu_clk;
struct dw_mci_slot *slot[MAX_MCI_SLOTS];
/* FIFO push and pull */
@@ -201,7 +209,8 @@ struct dw_mci_dma_ops {
#define DW_MCI_QUIRK_HIGHSPEED BIT(2)
/* Unreliable card detection */
#define DW_MCI_QUIRK_BROKEN_CARD_DETECTION BIT(3)
-
+/* Write Protect detection not available */
+#define DW_MCI_QUIRK_NO_WRITE_PROTECT BIT(4)
struct dma_pdata;
@@ -218,7 +227,7 @@ struct dw_mci_board {
u32 num_slots;
u32 quirks; /* Workaround / Quirk flags */
- unsigned int bus_hz; /* Bus speed */
+ unsigned int bus_hz; /* Clock speed at the cclk_in pad */
unsigned int caps; /* Capabilities */
unsigned int caps2; /* More capabilities */
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index f578a71..7abb0e1 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -259,10 +259,6 @@ struct mmc_host {
#define MMC_CAP2_RO_ACTIVE_HIGH (1 << 11) /* Write-protect signal active high */
mmc_pm_flag_t pm_caps; /* supported pm features */
- unsigned int power_notify_type;
-#define MMC_HOST_PW_NOTIFY_NONE 0
-#define MMC_HOST_PW_NOTIFY_SHORT 1
-#define MMC_HOST_PW_NOTIFY_LONG 2
#ifdef CONFIG_MMC_CLKGATE
int clk_requests; /* internal reference counter */
@@ -300,6 +296,7 @@ struct mmc_host {
#endif
int rescan_disable; /* disable card detection */
+ int rescan_entered; /* used with nonremovable devices */
struct mmc_card *card; /* device attached to this host */
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
index d425cab..01e4b39 100644
--- a/include/linux/mmc/mmc.h
+++ b/include/linux/mmc/mmc.h
@@ -139,6 +139,7 @@ static inline bool mmc_op_multi(u32 opcode)
#define R1_CURRENT_STATE(x) ((x & 0x00001E00) >> 9) /* sx, b (4 bits) */
#define R1_READY_FOR_DATA (1 << 8) /* sx, a */
#define R1_SWITCH_ERROR (1 << 7) /* sx, c */
+#define R1_EXCEPTION_EVENT (1 << 6) /* sx, a */
#define R1_APP_CMD (1 << 5) /* sr, c */
#define R1_STATE_IDLE 0
@@ -274,12 +275,15 @@ struct _mmc_csd {
#define EXT_CSD_FLUSH_CACHE 32 /* W */
#define EXT_CSD_CACHE_CTRL 33 /* R/W */
#define EXT_CSD_POWER_OFF_NOTIFICATION 34 /* R/W */
+#define EXT_CSD_EXP_EVENTS_STATUS 54 /* RO */
#define EXT_CSD_DATA_SECTOR_SIZE 61 /* R */
#define EXT_CSD_GP_SIZE_MULT 143 /* R/W */
#define EXT_CSD_PARTITION_ATTRIBUTE 156 /* R/W */
#define EXT_CSD_PARTITION_SUPPORT 160 /* RO */
#define EXT_CSD_HPI_MGMT 161 /* R/W */
#define EXT_CSD_RST_N_FUNCTION 162 /* R/W */
+#define EXT_CSD_BKOPS_EN 163 /* R/W */
+#define EXT_CSD_BKOPS_START 164 /* W */
#define EXT_CSD_SANITIZE_START 165 /* W */
#define EXT_CSD_WR_REL_PARAM 166 /* RO */
#define EXT_CSD_BOOT_WP 173 /* R/W */
@@ -313,11 +317,13 @@ struct _mmc_csd {
#define EXT_CSD_PWR_CL_200_360 237 /* RO */
#define EXT_CSD_PWR_CL_DDR_52_195 238 /* RO */
#define EXT_CSD_PWR_CL_DDR_52_360 239 /* RO */
+#define EXT_CSD_BKOPS_STATUS 246 /* RO */
#define EXT_CSD_POWER_OFF_LONG_TIME 247 /* RO */
#define EXT_CSD_GENERIC_CMD6_TIME 248 /* RO */
#define EXT_CSD_CACHE_SIZE 249 /* RO, 4 bytes */
#define EXT_CSD_TAG_UNIT_SIZE 498 /* RO */
#define EXT_CSD_DATA_TAG_SUPPORT 499 /* RO */
+#define EXT_CSD_BKOPS_SUPPORT 502 /* RO */
#define EXT_CSD_HPI_FEATURES 503 /* RO */
/*
@@ -378,6 +384,19 @@ struct _mmc_csd {
#define EXT_CSD_PWR_CL_8BIT_SHIFT 4
#define EXT_CSD_PWR_CL_4BIT_SHIFT 0
/*
+ * EXCEPTION_EVENT_STATUS field
+ */
+#define EXT_CSD_URGENT_BKOPS BIT(0)
+#define EXT_CSD_DYNCAP_NEEDED BIT(1)
+#define EXT_CSD_SYSPOOL_EXHAUSTED BIT(2)
+#define EXT_CSD_PACKED_FAILURE BIT(3)
+
+/*
+ * BKOPS status level
+ */
+#define EXT_CSD_BKOPS_LEVEL_2 0x2
+
+/*
* MMC_SWITCH access modes
*/
diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h
index ac83b10..fa8529a 100644
--- a/include/linux/mmc/sdhci.h
+++ b/include/linux/mmc/sdhci.h
@@ -97,7 +97,8 @@ struct sdhci_host {
const struct sdhci_ops *ops; /* Low level hw interface */
- struct regulator *vmmc; /* Power regulator */
+ struct regulator *vmmc; /* Power regulator (vmmc) */
+ struct regulator *vqmmc; /* Signaling regulator (vccq) */
/* Internal data */
struct mmc_host *mmc; /* MMC structure */
diff --git a/include/linux/mtd/bbm.h b/include/linux/mtd/bbm.h
index 650ef35..211ff67 100644
--- a/include/linux/mtd/bbm.h
+++ b/include/linux/mtd/bbm.h
@@ -78,8 +78,6 @@ struct nand_bbt_descr {
#define NAND_BBT_LASTBLOCK 0x00000010
/* The bbt is at the given page, else we must scan for the bbt */
#define NAND_BBT_ABSPAGE 0x00000020
-/* The bbt is at the given page, else we must scan for the bbt */
-#define NAND_BBT_SEARCH 0x00000040
/* bbt is stored per chip on multichip devices */
#define NAND_BBT_PERCHIP 0x00000080
/* bbt has a version counter at offset veroffs */
@@ -110,7 +108,10 @@ struct nand_bbt_descr {
* OOB area. This option is passed to the default bad block table function.
*/
#define NAND_BBT_USE_FLASH 0x00020000
-/* Do not store flash based bad block table in OOB area; store it in-band */
+/*
+ * Do not store flash based bad block table marker in the OOB area; store it
+ * in-band.
+ */
#define NAND_BBT_NO_OOB 0x00040000
/*
* Do not write new bad block markers to OOB; useful, e.g., when ECC covers
diff --git a/include/linux/mtd/lpc32xx_mlc.h b/include/linux/mtd/lpc32xx_mlc.h
new file mode 100644
index 0000000..d91b1e3
--- /dev/null
+++ b/include/linux/mtd/lpc32xx_mlc.h
@@ -0,0 +1,20 @@
+/*
+ * Platform data for LPC32xx SoC MLC NAND controller
+ *
+ * Copyright © 2012 Roland Stigge
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __LINUX_MTD_LPC32XX_MLC_H
+#define __LINUX_MTD_LPC32XX_MLC_H
+
+#include <linux/dmaengine.h>
+
+struct lpc32xx_mlc_platform_data {
+ bool (*dma_filter)(struct dma_chan *chan, void *filter_param);
+};
+
+#endif /* __LINUX_MTD_LPC32XX_MLC_H */
diff --git a/include/linux/mtd/lpc32xx_slc.h b/include/linux/mtd/lpc32xx_slc.h
new file mode 100644
index 0000000..1169548
--- /dev/null
+++ b/include/linux/mtd/lpc32xx_slc.h
@@ -0,0 +1,20 @@
+/*
+ * Platform data for LPC32xx SoC SLC NAND controller
+ *
+ * Copyright © 2012 Roland Stigge
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __LINUX_MTD_LPC32XX_SLC_H
+#define __LINUX_MTD_LPC32XX_SLC_H
+
+#include <linux/dmaengine.h>
+
+struct lpc32xx_slc_platform_data {
+ bool (*dma_filter)(struct dma_chan *chan, void *filter_param);
+};
+
+#endif /* __LINUX_MTD_LPC32XX_SLC_H */
diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h
index 63dadc0..81d61e7 100644
--- a/include/linux/mtd/mtd.h
+++ b/include/linux/mtd/mtd.h
@@ -265,14 +265,7 @@ int mtd_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen,
int mtd_panic_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen,
const u_char *buf);
-static inline int mtd_read_oob(struct mtd_info *mtd, loff_t from,
- struct mtd_oob_ops *ops)
-{
- ops->retlen = ops->oobretlen = 0;
- if (!mtd->_read_oob)
- return -EOPNOTSUPP;
- return mtd->_read_oob(mtd, from, ops);
-}
+int mtd_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops);
static inline int mtd_write_oob(struct mtd_info *mtd, loff_t to,
struct mtd_oob_ops *ops)
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index 57977c6..24e9159 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -56,7 +56,7 @@ extern int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len);
* is supported now. If you add a chip with bigger oobsize/page
* adjust this accordingly.
*/
-#define NAND_MAX_OOBSIZE 576
+#define NAND_MAX_OOBSIZE 640
#define NAND_MAX_PAGESIZE 8192
/*
@@ -92,6 +92,8 @@ extern int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len);
#define NAND_CMD_READID 0x90
#define NAND_CMD_ERASE2 0xd0
#define NAND_CMD_PARAM 0xec
+#define NAND_CMD_GET_FEATURES 0xee
+#define NAND_CMD_SET_FEATURES 0xef
#define NAND_CMD_RESET 0xff
#define NAND_CMD_LOCK 0x2a
@@ -185,12 +187,6 @@ typedef enum {
* This happens with the Renesas AG-AND chips, possibly others.
*/
#define BBT_AUTO_REFRESH 0x00000080
-/*
- * Chip does not require ready check on read. True
- * for all large page devices, as they do not support
- * autoincrement.
- */
-#define NAND_NO_READRDY 0x00000100
/* Chip does not allow subpage writes */
#define NAND_NO_SUBPAGE_WRITE 0x00000200
@@ -200,6 +196,9 @@ typedef enum {
/* Device behaves just like nand, but is readonly */
#define NAND_ROM 0x00000800
+/* Device supports subpage reads */
+#define NAND_SUBPAGE_READ 0x00001000
+
/* Options valid for Samsung large page devices */
#define NAND_SAMSUNG_LP_OPTIONS \
(NAND_NO_PADDING | NAND_CACHEPRG | NAND_COPYBACK)
@@ -208,12 +207,7 @@ typedef enum {
#define NAND_MUST_PAD(chip) (!(chip->options & NAND_NO_PADDING))
#define NAND_HAS_CACHEPROG(chip) ((chip->options & NAND_CACHEPRG))
#define NAND_HAS_COPYBACK(chip) ((chip->options & NAND_COPYBACK))
-/* Large page NAND with SOFT_ECC should support subpage reads */
-#define NAND_SUBPAGE_READ(chip) ((chip->ecc.mode == NAND_ECC_SOFT) \
- && (chip->page_shift > 9))
-
-/* Mask to zero out the chip options, which come from the id table */
-#define NAND_CHIPOPTIONS_MSK 0x0000ffff
+#define NAND_HAS_SUBPAGE_READ(chip) ((chip->options & NAND_SUBPAGE_READ))
/* Non chip related options */
/* This option skips the bbt scan during initialization. */
@@ -237,6 +231,21 @@ typedef enum {
/* Keep gcc happy */
struct nand_chip;
+/* ONFI timing mode, used in both asynchronous and synchronous mode */
+#define ONFI_TIMING_MODE_0 (1 << 0)
+#define ONFI_TIMING_MODE_1 (1 << 1)
+#define ONFI_TIMING_MODE_2 (1 << 2)
+#define ONFI_TIMING_MODE_3 (1 << 3)
+#define ONFI_TIMING_MODE_4 (1 << 4)
+#define ONFI_TIMING_MODE_5 (1 << 5)
+#define ONFI_TIMING_MODE_UNKNOWN (1 << 6)
+
+/* ONFI feature address */
+#define ONFI_FEATURE_ADDR_TIMING_MODE 0x1
+
+/* ONFI subfeature parameters length */
+#define ONFI_SUBFEATURE_PARAM_LEN 4
+
struct nand_onfi_params {
/* rev info and features block */
/* 'O' 'N' 'F' 'I' */
@@ -334,8 +343,10 @@ struct nand_hw_control {
* @read_page_raw: function to read a raw page without ECC
* @write_page_raw: function to write a raw page without ECC
* @read_page: function to read a page according to the ECC generator
- * requirements.
- * @read_subpage: function to read parts of the page covered by ECC.
+ * requirements; returns maximum number of bitflips corrected in
+ * any single ECC step, 0 if bitflips uncorrectable, -EIO hw error
+ * @read_subpage: function to read parts of the page covered by ECC;
+ * returns same as read_page()
* @write_page: function to write a page according to the ECC generator
* requirements.
* @write_oob_raw: function to write chip OOB data without ECC
@@ -361,13 +372,13 @@ struct nand_ecc_ctrl {
uint8_t *calc_ecc);
int (*read_page_raw)(struct mtd_info *mtd, struct nand_chip *chip,
uint8_t *buf, int oob_required, int page);
- void (*write_page_raw)(struct mtd_info *mtd, struct nand_chip *chip,
+ int (*write_page_raw)(struct mtd_info *mtd, struct nand_chip *chip,
const uint8_t *buf, int oob_required);
int (*read_page)(struct mtd_info *mtd, struct nand_chip *chip,
uint8_t *buf, int oob_required, int page);
int (*read_subpage)(struct mtd_info *mtd, struct nand_chip *chip,
uint32_t offs, uint32_t len, uint8_t *buf);
- void (*write_page)(struct mtd_info *mtd, struct nand_chip *chip,
+ int (*write_page)(struct mtd_info *mtd, struct nand_chip *chip,
const uint8_t *buf, int oob_required);
int (*write_oob_raw)(struct mtd_info *mtd, struct nand_chip *chip,
int page);
@@ -403,8 +414,6 @@ struct nand_buffers {
* @read_word: [REPLACEABLE] read one word from the chip
* @write_buf: [REPLACEABLE] write data from the buffer to the chip
* @read_buf: [REPLACEABLE] read data from the chip into the buffer
- * @verify_buf: [REPLACEABLE] verify buffer contents against the chip
- * data.
* @select_chip: [REPLACEABLE] select chip nr
* @block_bad: [REPLACEABLE] check, if the block is bad
* @block_markbad: [REPLACEABLE] mark the block bad
@@ -462,6 +471,8 @@ struct nand_buffers {
* non 0 if ONFI supported.
* @onfi_params: [INTERN] holds the ONFI page parameter when ONFI is
* supported, 0 otherwise.
+ * @onfi_set_features [REPLACEABLE] set the features for ONFI nand
+ * @onfi_get_features [REPLACEABLE] get the features for ONFI nand
* @ecclayout: [REPLACEABLE] the default ECC placement scheme
* @bbt: [INTERN] bad block table pointer
* @bbt_td: [REPLACEABLE] bad block table descriptor for flash
@@ -487,7 +498,6 @@ struct nand_chip {
u16 (*read_word)(struct mtd_info *mtd);
void (*write_buf)(struct mtd_info *mtd, const uint8_t *buf, int len);
void (*read_buf)(struct mtd_info *mtd, uint8_t *buf, int len);
- int (*verify_buf)(struct mtd_info *mtd, const uint8_t *buf, int len);
void (*select_chip)(struct mtd_info *mtd, int chip);
int (*block_bad)(struct mtd_info *mtd, loff_t ofs, int getchip);
int (*block_markbad)(struct mtd_info *mtd, loff_t ofs);
@@ -505,6 +515,10 @@ struct nand_chip {
int (*write_page)(struct mtd_info *mtd, struct nand_chip *chip,
const uint8_t *buf, int oob_required, int page,
int cached, int raw);
+ int (*onfi_set_features)(struct mtd_info *mtd, struct nand_chip *chip,
+ int feature_addr, uint8_t *subfeature_para);
+ int (*onfi_get_features)(struct mtd_info *mtd, struct nand_chip *chip,
+ int feature_addr, uint8_t *subfeature_para);
int chip_delay;
unsigned int options;
@@ -559,6 +573,7 @@ struct nand_chip {
#define NAND_MFR_MICRON 0x2c
#define NAND_MFR_AMD 0x01
#define NAND_MFR_MACRONIX 0xc2
+#define NAND_MFR_EON 0x92
/**
* struct nand_flash_dev - NAND Flash Device ID Structure
@@ -641,6 +656,7 @@ struct platform_device;
* ALE/CLE/nCE. Also used to write command and address
* @write_buf: platform specific function for write buffer
* @read_buf: platform specific function for read buffer
+ * @read_byte: platform specific function to read one byte from chip
* @priv: private data to transport driver specific settings
*
* All fields are optional and depend on the hardware driver requirements
@@ -677,4 +693,20 @@ struct platform_nand_chip *get_platform_nandchip(struct mtd_info *mtd)
return chip->priv;
}
+/* return the supported asynchronous timing mode. */
+static inline int onfi_get_async_timing_mode(struct nand_chip *chip)
+{
+ if (!chip->onfi_version)
+ return ONFI_TIMING_MODE_UNKNOWN;
+ return le16_to_cpu(chip->onfi_params.async_timing_mode);
+}
+
+/* return the supported synchronous timing mode. */
+static inline int onfi_get_sync_timing_mode(struct nand_chip *chip)
+{
+ if (!chip->onfi_version)
+ return ONFI_TIMING_MODE_UNKNOWN;
+ return le16_to_cpu(chip->onfi_params.src_sync_timing_mode);
+}
+
#endif /* __LINUX_MTD_NAND_H */
diff --git a/include/linux/mtd/sh_flctl.h b/include/linux/mtd/sh_flctl.h
index a38e1fa..01e4b15 100644
--- a/include/linux/mtd/sh_flctl.h
+++ b/include/linux/mtd/sh_flctl.h
@@ -49,7 +49,6 @@
#define FLERRADR(f) (f->reg + 0x98)
/* FLCMNCR control bits */
-#define ECCPOS2 (0x1 << 25)
#define _4ECCCNTEN (0x1 << 24)
#define _4ECCEN (0x1 << 23)
#define _4ECCCORRECT (0x1 << 22)
@@ -59,9 +58,6 @@
#define QTSEL_E (0x1 << 17)
#define ENDIAN (0x1 << 16) /* 1 = little endian */
#define FCKSEL_E (0x1 << 15)
-#define ECCPOS_00 (0x00 << 12)
-#define ECCPOS_01 (0x01 << 12)
-#define ECCPOS_02 (0x02 << 12)
#define ACM_SACCES_MODE (0x01 << 10)
#define NANWF_E (0x1 << 9)
#define SE_D (0x1 << 8) /* Spare area disable */
@@ -107,6 +103,14 @@
#define DOCMD2_E (0x1 << 17) /* 2nd cmd stage execute */
#define DOCMD1_E (0x1 << 16) /* 1st cmd stage execute */
+/* FLINTDMACR control bits */
+#define ESTERINTE (0x1 << 24) /* ECC error interrupt enable */
+#define AC1CLR (0x1 << 19) /* ECC FIFO clear */
+#define AC0CLR (0x1 << 18) /* Data FIFO clear */
+#define ECERB (0x1 << 9) /* ECC error */
+#define STERB (0x1 << 8) /* Status error */
+#define STERINTE (0x1 << 4) /* Status error enable */
+
/* FLTRCR control bits */
#define TRSTRT (0x1 << 0) /* translation start */
#define TREND (0x1 << 1) /* translation end */
@@ -125,9 +129,15 @@
#define _4ECCEND (0x1 << 1) /* 4 symbols end */
#define _4ECCEXST (0x1 << 0) /* 4 symbols exist */
-#define INIT_FL4ECCRESULT_VAL 0x03FF03FF
#define LOOP_TIMEOUT_MAX 0x00010000
+enum flctl_ecc_res_t {
+ FL_SUCCESS,
+ FL_REPAIRABLE,
+ FL_ERROR,
+ FL_TIMEOUT
+};
+
struct sh_flctl {
struct mtd_info mtd;
struct nand_chip chip;
@@ -145,8 +155,7 @@ struct sh_flctl {
uint32_t erase_ADRCNT; /* bits of FLCMDCR in ERASE1 cmd */
uint32_t rw_ADRCNT; /* bits of FLCMDCR in READ WRITE cmd */
uint32_t flcmncr_base; /* base value of FLCMNCR */
-
- int hwecc_cant_correct[4];
+ uint32_t flintdmacr_base; /* irq enable bits */
unsigned page_size:1; /* NAND page size (0 = 512, 1 = 2048) */
unsigned hwecc:1; /* Hardware ECC (0 = disabled, 1 = enabled) */
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 01646aa..561c8bc 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -1497,19 +1497,25 @@ struct napi_gro_cb {
/* This indicates where we are processing relative to skb->data. */
int data_offset;
- /* This is non-zero if the packet may be of the same flow. */
- int same_flow;
-
/* This is non-zero if the packet cannot be merged with the new skb. */
int flush;
/* Number of segments aggregated. */
- int count;
+ u16 count;
+
+ /* This is non-zero if the packet may be of the same flow. */
+ u8 same_flow;
/* Free the skb? */
- int free;
+ u8 free;
#define NAPI_GRO_FREE 1
#define NAPI_GRO_FREE_STOLEN_HEAD 2
+
+ /* jiffies when first packet was created/queued */
+ unsigned long age;
+
+ /* Used in ipv6_gro_receive() */
+ int proto;
};
#define NAPI_GRO_CB(skb) ((struct napi_gro_cb *)(skb)->cb)
@@ -1663,7 +1669,6 @@ extern int netpoll_trap(void);
#endif
extern int skb_gro_receive(struct sk_buff **head,
struct sk_buff *skb);
-extern void skb_gro_reset_offset(struct sk_buff *skb);
static inline unsigned int skb_gro_offset(const struct sk_buff *skb)
{
@@ -2157,7 +2162,7 @@ extern gro_result_t dev_gro_receive(struct napi_struct *napi,
extern gro_result_t napi_skb_finish(gro_result_t ret, struct sk_buff *skb);
extern gro_result_t napi_gro_receive(struct napi_struct *napi,
struct sk_buff *skb);
-extern void napi_gro_flush(struct napi_struct *napi);
+extern void napi_gro_flush(struct napi_struct *napi, bool flush_old);
extern struct sk_buff * napi_get_frags(struct napi_struct *napi);
extern gro_result_t napi_frags_finish(struct napi_struct *napi,
struct sk_buff *skb,
diff --git a/include/linux/netfilter/Kbuild b/include/linux/netfilter/Kbuild
index 874ae8f..b332202 100644
--- a/include/linux/netfilter/Kbuild
+++ b/include/linux/netfilter/Kbuild
@@ -1,78 +1 @@
header-y += ipset/
-
-header-y += nf_conntrack_common.h
-header-y += nf_conntrack_ftp.h
-header-y += nf_conntrack_sctp.h
-header-y += nf_conntrack_tcp.h
-header-y += nf_conntrack_tuple_common.h
-header-y += nf_nat.h
-header-y += nfnetlink.h
-header-y += nfnetlink_acct.h
-header-y += nfnetlink_compat.h
-header-y += nfnetlink_conntrack.h
-header-y += nfnetlink_cthelper.h
-header-y += nfnetlink_cttimeout.h
-header-y += nfnetlink_log.h
-header-y += nfnetlink_queue.h
-header-y += x_tables.h
-header-y += xt_AUDIT.h
-header-y += xt_CHECKSUM.h
-header-y += xt_CLASSIFY.h
-header-y += xt_CONNMARK.h
-header-y += xt_CONNSECMARK.h
-header-y += xt_CT.h
-header-y += xt_DSCP.h
-header-y += xt_IDLETIMER.h
-header-y += xt_LED.h
-header-y += xt_LOG.h
-header-y += xt_MARK.h
-header-y += xt_nfacct.h
-header-y += xt_NFLOG.h
-header-y += xt_NFQUEUE.h
-header-y += xt_RATEEST.h
-header-y += xt_SECMARK.h
-header-y += xt_TCPMSS.h
-header-y += xt_TCPOPTSTRIP.h
-header-y += xt_TEE.h
-header-y += xt_TPROXY.h
-header-y += xt_addrtype.h
-header-y += xt_cluster.h
-header-y += xt_comment.h
-header-y += xt_connbytes.h
-header-y += xt_connlimit.h
-header-y += xt_connmark.h
-header-y += xt_conntrack.h
-header-y += xt_cpu.h
-header-y += xt_dccp.h
-header-y += xt_devgroup.h
-header-y += xt_dscp.h
-header-y += xt_ecn.h
-header-y += xt_esp.h
-header-y += xt_hashlimit.h
-header-y += xt_helper.h
-header-y += xt_iprange.h
-header-y += xt_ipvs.h
-header-y += xt_length.h
-header-y += xt_limit.h
-header-y += xt_mac.h
-header-y += xt_mark.h
-header-y += xt_multiport.h
-header-y += xt_osf.h
-header-y += xt_owner.h
-header-y += xt_physdev.h
-header-y += xt_pkttype.h
-header-y += xt_policy.h
-header-y += xt_quota.h
-header-y += xt_rateest.h
-header-y += xt_realm.h
-header-y += xt_recent.h
-header-y += xt_set.h
-header-y += xt_sctp.h
-header-y += xt_socket.h
-header-y += xt_state.h
-header-y += xt_statistic.h
-header-y += xt_string.h
-header-y += xt_tcpmss.h
-header-y += xt_tcpudp.h
-header-y += xt_time.h
-header-y += xt_u32.h
diff --git a/include/linux/netfilter/ipset/Kbuild b/include/linux/netfilter/ipset/Kbuild
index 601fe71..e69de29 100644
--- a/include/linux/netfilter/ipset/Kbuild
+++ b/include/linux/netfilter/ipset/Kbuild
@@ -1,4 +0,0 @@
-header-y += ip_set.h
-header-y += ip_set_bitmap.h
-header-y += ip_set_hash.h
-header-y += ip_set_list.h
diff --git a/include/linux/netfilter/ipset/ip_set.h b/include/linux/netfilter/ipset/ip_set.h
index 528697b..7958e84 100644
--- a/include/linux/netfilter/ipset/ip_set.h
+++ b/include/linux/netfilter/ipset/ip_set.h
@@ -1,6 +1,3 @@
-#ifndef _IP_SET_H
-#define _IP_SET_H
-
/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
* Patrick Schaaf <bof@bof.de>
* Martin Josefsson <gandalf@wlug.westbo.se>
@@ -10,199 +7,9 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
+#ifndef _IP_SET_H
+#define _IP_SET_H
-#include <linux/types.h>
-
-/* The protocol version */
-#define IPSET_PROTOCOL 6
-
-/* The max length of strings including NUL: set and type identifiers */
-#define IPSET_MAXNAMELEN 32
-
-/* Message types and commands */
-enum ipset_cmd {
- IPSET_CMD_NONE,
- IPSET_CMD_PROTOCOL, /* 1: Return protocol version */
- IPSET_CMD_CREATE, /* 2: Create a new (empty) set */
- IPSET_CMD_DESTROY, /* 3: Destroy a (empty) set */
- IPSET_CMD_FLUSH, /* 4: Remove all elements from a set */
- IPSET_CMD_RENAME, /* 5: Rename a set */
- IPSET_CMD_SWAP, /* 6: Swap two sets */
- IPSET_CMD_LIST, /* 7: List sets */
- IPSET_CMD_SAVE, /* 8: Save sets */
- IPSET_CMD_ADD, /* 9: Add an element to a set */
- IPSET_CMD_DEL, /* 10: Delete an element from a set */
- IPSET_CMD_TEST, /* 11: Test an element in a set */
- IPSET_CMD_HEADER, /* 12: Get set header data only */
- IPSET_CMD_TYPE, /* 13: Get set type */
- IPSET_MSG_MAX, /* Netlink message commands */
-
- /* Commands in userspace: */
- IPSET_CMD_RESTORE = IPSET_MSG_MAX, /* 14: Enter restore mode */
- IPSET_CMD_HELP, /* 15: Get help */
- IPSET_CMD_VERSION, /* 16: Get program version */
- IPSET_CMD_QUIT, /* 17: Quit from interactive mode */
-
- IPSET_CMD_MAX,
-
- IPSET_CMD_COMMIT = IPSET_CMD_MAX, /* 18: Commit buffered commands */
-};
-
-/* Attributes at command level */
-enum {
- IPSET_ATTR_UNSPEC,
- IPSET_ATTR_PROTOCOL, /* 1: Protocol version */
- IPSET_ATTR_SETNAME, /* 2: Name of the set */
- IPSET_ATTR_TYPENAME, /* 3: Typename */
- IPSET_ATTR_SETNAME2 = IPSET_ATTR_TYPENAME, /* Setname at rename/swap */
- IPSET_ATTR_REVISION, /* 4: Settype revision */
- IPSET_ATTR_FAMILY, /* 5: Settype family */
- IPSET_ATTR_FLAGS, /* 6: Flags at command level */
- IPSET_ATTR_DATA, /* 7: Nested attributes */
- IPSET_ATTR_ADT, /* 8: Multiple data containers */
- IPSET_ATTR_LINENO, /* 9: Restore lineno */
- IPSET_ATTR_PROTOCOL_MIN, /* 10: Minimal supported version number */
- IPSET_ATTR_REVISION_MIN = IPSET_ATTR_PROTOCOL_MIN, /* type rev min */
- __IPSET_ATTR_CMD_MAX,
-};
-#define IPSET_ATTR_CMD_MAX (__IPSET_ATTR_CMD_MAX - 1)
-
-/* CADT specific attributes */
-enum {
- IPSET_ATTR_IP = IPSET_ATTR_UNSPEC + 1,
- IPSET_ATTR_IP_FROM = IPSET_ATTR_IP,
- IPSET_ATTR_IP_TO, /* 2 */
- IPSET_ATTR_CIDR, /* 3 */
- IPSET_ATTR_PORT, /* 4 */
- IPSET_ATTR_PORT_FROM = IPSET_ATTR_PORT,
- IPSET_ATTR_PORT_TO, /* 5 */
- IPSET_ATTR_TIMEOUT, /* 6 */
- IPSET_ATTR_PROTO, /* 7 */
- IPSET_ATTR_CADT_FLAGS, /* 8 */
- IPSET_ATTR_CADT_LINENO = IPSET_ATTR_LINENO, /* 9 */
- /* Reserve empty slots */
- IPSET_ATTR_CADT_MAX = 16,
- /* Create-only specific attributes */
- IPSET_ATTR_GC,
- IPSET_ATTR_HASHSIZE,
- IPSET_ATTR_MAXELEM,
- IPSET_ATTR_NETMASK,
- IPSET_ATTR_PROBES,
- IPSET_ATTR_RESIZE,
- IPSET_ATTR_SIZE,
- /* Kernel-only */
- IPSET_ATTR_ELEMENTS,
- IPSET_ATTR_REFERENCES,
- IPSET_ATTR_MEMSIZE,
-
- __IPSET_ATTR_CREATE_MAX,
-};
-#define IPSET_ATTR_CREATE_MAX (__IPSET_ATTR_CREATE_MAX - 1)
-
-/* ADT specific attributes */
-enum {
- IPSET_ATTR_ETHER = IPSET_ATTR_CADT_MAX + 1,
- IPSET_ATTR_NAME,
- IPSET_ATTR_NAMEREF,
- IPSET_ATTR_IP2,
- IPSET_ATTR_CIDR2,
- IPSET_ATTR_IP2_TO,
- IPSET_ATTR_IFACE,
- __IPSET_ATTR_ADT_MAX,
-};
-#define IPSET_ATTR_ADT_MAX (__IPSET_ATTR_ADT_MAX - 1)
-
-/* IP specific attributes */
-enum {
- IPSET_ATTR_IPADDR_IPV4 = IPSET_ATTR_UNSPEC + 1,
- IPSET_ATTR_IPADDR_IPV6,
- __IPSET_ATTR_IPADDR_MAX,
-};
-#define IPSET_ATTR_IPADDR_MAX (__IPSET_ATTR_IPADDR_MAX - 1)
-
-/* Error codes */
-enum ipset_errno {
- IPSET_ERR_PRIVATE = 4096,
- IPSET_ERR_PROTOCOL,
- IPSET_ERR_FIND_TYPE,
- IPSET_ERR_MAX_SETS,
- IPSET_ERR_BUSY,
- IPSET_ERR_EXIST_SETNAME2,
- IPSET_ERR_TYPE_MISMATCH,
- IPSET_ERR_EXIST,
- IPSET_ERR_INVALID_CIDR,
- IPSET_ERR_INVALID_NETMASK,
- IPSET_ERR_INVALID_FAMILY,
- IPSET_ERR_TIMEOUT,
- IPSET_ERR_REFERENCED,
- IPSET_ERR_IPADDR_IPV4,
- IPSET_ERR_IPADDR_IPV6,
-
- /* Type specific error codes */
- IPSET_ERR_TYPE_SPECIFIC = 4352,
-};
-
-/* Flags at command level */
-enum ipset_cmd_flags {
- IPSET_FLAG_BIT_EXIST = 0,
- IPSET_FLAG_EXIST = (1 << IPSET_FLAG_BIT_EXIST),
- IPSET_FLAG_BIT_LIST_SETNAME = 1,
- IPSET_FLAG_LIST_SETNAME = (1 << IPSET_FLAG_BIT_LIST_SETNAME),
- IPSET_FLAG_BIT_LIST_HEADER = 2,
- IPSET_FLAG_LIST_HEADER = (1 << IPSET_FLAG_BIT_LIST_HEADER),
- IPSET_FLAG_CMD_MAX = 15, /* Lower half */
-};
-
-/* Flags at CADT attribute level */
-enum ipset_cadt_flags {
- IPSET_FLAG_BIT_BEFORE = 0,
- IPSET_FLAG_BEFORE = (1 << IPSET_FLAG_BIT_BEFORE),
- IPSET_FLAG_BIT_PHYSDEV = 1,
- IPSET_FLAG_PHYSDEV = (1 << IPSET_FLAG_BIT_PHYSDEV),
- IPSET_FLAG_BIT_NOMATCH = 2,
- IPSET_FLAG_NOMATCH = (1 << IPSET_FLAG_BIT_NOMATCH),
- IPSET_FLAG_CADT_MAX = 15, /* Upper half */
-};
-
-/* Commands with settype-specific attributes */
-enum ipset_adt {
- IPSET_ADD,
- IPSET_DEL,
- IPSET_TEST,
- IPSET_ADT_MAX,
- IPSET_CREATE = IPSET_ADT_MAX,
- IPSET_CADT_MAX,
-};
-
-/* Sets are identified by an index in kernel space. Tweak with ip_set_id_t
- * and IPSET_INVALID_ID if you want to increase the max number of sets.
- */
-typedef __u16 ip_set_id_t;
-
-#define IPSET_INVALID_ID 65535
-
-enum ip_set_dim {
- IPSET_DIM_ZERO = 0,
- IPSET_DIM_ONE,
- IPSET_DIM_TWO,
- IPSET_DIM_THREE,
- /* Max dimension in elements.
- * If changed, new revision of iptables match/target is required.
- */
- IPSET_DIM_MAX = 6,
- IPSET_BIT_RETURN_NOMATCH = 7,
-};
-
-/* Option flags for kernel operations */
-enum ip_set_kopt {
- IPSET_INV_MATCH = (1 << IPSET_DIM_ZERO),
- IPSET_DIM_ONE_SRC = (1 << IPSET_DIM_ONE),
- IPSET_DIM_TWO_SRC = (1 << IPSET_DIM_TWO),
- IPSET_DIM_THREE_SRC = (1 << IPSET_DIM_THREE),
- IPSET_RETURN_NOMATCH = (1 << IPSET_BIT_RETURN_NOMATCH),
-};
-
-#ifdef __KERNEL__
#include <linux/ip.h>
#include <linux/ipv6.h>
#include <linux/netlink.h>
@@ -211,6 +18,7 @@ enum ip_set_kopt {
#include <linux/stringify.h>
#include <linux/vmalloc.h>
#include <net/netlink.h>
+#include <uapi/linux/netfilter/ipset/ip_set.h>
#define _IP_SET_MODULE_DESC(a, b, c) \
MODULE_DESCRIPTION(a " type of IP sets, revisions " b "-" c)
@@ -476,31 +284,4 @@ bitmap_bytes(u32 a, u32 b)
return 4 * ((((b - a + 8) / 8) + 3) / 4);
}
-#endif /* __KERNEL__ */
-
-/* Interface to iptables/ip6tables */
-
-#define SO_IP_SET 83
-
-union ip_set_name_index {
- char name[IPSET_MAXNAMELEN];
- ip_set_id_t index;
-};
-
-#define IP_SET_OP_GET_BYNAME 0x00000006 /* Get set index by name */
-struct ip_set_req_get_set {
- unsigned int op;
- unsigned int version;
- union ip_set_name_index set;
-};
-
-#define IP_SET_OP_GET_BYINDEX 0x00000007 /* Get set name by index */
-/* Uses ip_set_req_get_set */
-
-#define IP_SET_OP_VERSION 0x00000100 /* Ask kernel version */
-struct ip_set_req_version {
- unsigned int op;
- unsigned int version;
-};
-
#endif /*_IP_SET_H */
diff --git a/include/linux/netfilter/ipset/ip_set_bitmap.h b/include/linux/netfilter/ipset/ip_set_bitmap.h
index 61a9e87..1a30646 100644
--- a/include/linux/netfilter/ipset/ip_set_bitmap.h
+++ b/include/linux/netfilter/ipset/ip_set_bitmap.h
@@ -1,15 +1,8 @@
#ifndef __IP_SET_BITMAP_H
#define __IP_SET_BITMAP_H
-/* Bitmap type specific error codes */
-enum {
- /* The element is out of the range of the set */
- IPSET_ERR_BITMAP_RANGE = IPSET_ERR_TYPE_SPECIFIC,
- /* The range exceeds the size limit of the set type */
- IPSET_ERR_BITMAP_RANGE_SIZE,
-};
+#include <uapi/linux/netfilter/ipset/ip_set_bitmap.h>
-#ifdef __KERNEL__
#define IPSET_BITMAP_MAX_RANGE 0x0000FFFF
/* Common functions */
@@ -26,6 +19,4 @@ range_to_mask(u32 from, u32 to, u8 *bits)
return mask;
}
-#endif /* __KERNEL__ */
-
#endif /* __IP_SET_BITMAP_H */
diff --git a/include/linux/netfilter/ipset/ip_set_hash.h b/include/linux/netfilter/ipset/ip_set_hash.h
index e2a9fae..f98ddfb 100644
--- a/include/linux/netfilter/ipset/ip_set_hash.h
+++ b/include/linux/netfilter/ipset/ip_set_hash.h
@@ -1,23 +1,8 @@
#ifndef __IP_SET_HASH_H
#define __IP_SET_HASH_H
-/* Hash type specific error codes */
-enum {
- /* Hash is full */
- IPSET_ERR_HASH_FULL = IPSET_ERR_TYPE_SPECIFIC,
- /* Null-valued element */
- IPSET_ERR_HASH_ELEM,
- /* Invalid protocol */
- IPSET_ERR_INVALID_PROTO,
- /* Protocol missing but must be specified */
- IPSET_ERR_MISSING_PROTO,
- /* Range not supported */
- IPSET_ERR_HASH_RANGE_UNSUPPORTED,
- /* Invalid range */
- IPSET_ERR_HASH_RANGE,
-};
+#include <uapi/linux/netfilter/ipset/ip_set_hash.h>
-#ifdef __KERNEL__
#define IPSET_DEFAULT_HASHSIZE 1024
#define IPSET_MIMINAL_HASHSIZE 64
@@ -25,6 +10,4 @@ enum {
#define IPSET_DEFAULT_PROBES 4
#define IPSET_DEFAULT_RESIZE 100
-#endif /* __KERNEL__ */
-
#endif /* __IP_SET_HASH_H */
diff --git a/include/linux/netfilter/ipset/ip_set_list.h b/include/linux/netfilter/ipset/ip_set_list.h
index 40a63f3..68c2aea 100644
--- a/include/linux/netfilter/ipset/ip_set_list.h
+++ b/include/linux/netfilter/ipset/ip_set_list.h
@@ -1,27 +1,10 @@
#ifndef __IP_SET_LIST_H
#define __IP_SET_LIST_H
-/* List type specific error codes */
-enum {
- /* Set name to be added/deleted/tested does not exist. */
- IPSET_ERR_NAME = IPSET_ERR_TYPE_SPECIFIC,
- /* list:set type is not permitted to add */
- IPSET_ERR_LOOP,
- /* Missing reference set */
- IPSET_ERR_BEFORE,
- /* Reference set does not exist */
- IPSET_ERR_NAMEREF,
- /* Set is full */
- IPSET_ERR_LIST_FULL,
- /* Reference set is not added to the set */
- IPSET_ERR_REF_EXIST,
-};
+#include <uapi/linux/netfilter/ipset/ip_set_list.h>
-#ifdef __KERNEL__
#define IP_SET_LIST_DEFAULT_SIZE 8
#define IP_SET_LIST_MIN_SIZE 4
-#endif /* __KERNEL__ */
-
#endif /* __IP_SET_LIST_H */
diff --git a/include/linux/netfilter/nf_conntrack_common.h b/include/linux/netfilter/nf_conntrack_common.h
index d146872..127d0b9 100644
--- a/include/linux/netfilter/nf_conntrack_common.h
+++ b/include/linux/netfilter/nf_conntrack_common.h
@@ -1,119 +1,8 @@
#ifndef _NF_CONNTRACK_COMMON_H
#define _NF_CONNTRACK_COMMON_H
-/* Connection state tracking for netfilter. This is separated from,
- but required by, the NAT layer; it can also be used by an iptables
- extension. */
-enum ip_conntrack_info {
- /* Part of an established connection (either direction). */
- IP_CT_ESTABLISHED,
- /* Like NEW, but related to an existing connection, or ICMP error
- (in either direction). */
- IP_CT_RELATED,
+#include <uapi/linux/netfilter/nf_conntrack_common.h>
- /* Started a new connection to track (only
- IP_CT_DIR_ORIGINAL); may be a retransmission. */
- IP_CT_NEW,
-
- /* >= 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
-};
-
-/* Bitset representing status of connection. */
-enum ip_conntrack_status {
- /* It's an expected connection: bit 0 set. This bit never changed */
- IPS_EXPECTED_BIT = 0,
- IPS_EXPECTED = (1 << IPS_EXPECTED_BIT),
-
- /* We've seen packets both ways: bit 1 set. Can be set, not unset. */
- IPS_SEEN_REPLY_BIT = 1,
- IPS_SEEN_REPLY = (1 << IPS_SEEN_REPLY_BIT),
-
- /* Conntrack should never be early-expired. */
- IPS_ASSURED_BIT = 2,
- IPS_ASSURED = (1 << IPS_ASSURED_BIT),
-
- /* Connection is confirmed: originating packet has left box */
- IPS_CONFIRMED_BIT = 3,
- IPS_CONFIRMED = (1 << IPS_CONFIRMED_BIT),
-
- /* Connection needs src nat in orig dir. This bit never changed. */
- IPS_SRC_NAT_BIT = 4,
- IPS_SRC_NAT = (1 << IPS_SRC_NAT_BIT),
-
- /* Connection needs dst nat in orig dir. This bit never changed. */
- IPS_DST_NAT_BIT = 5,
- IPS_DST_NAT = (1 << IPS_DST_NAT_BIT),
-
- /* Both together. */
- IPS_NAT_MASK = (IPS_DST_NAT | IPS_SRC_NAT),
-
- /* Connection needs TCP sequence adjusted. */
- IPS_SEQ_ADJUST_BIT = 6,
- IPS_SEQ_ADJUST = (1 << IPS_SEQ_ADJUST_BIT),
-
- /* NAT initialization bits. */
- IPS_SRC_NAT_DONE_BIT = 7,
- IPS_SRC_NAT_DONE = (1 << IPS_SRC_NAT_DONE_BIT),
-
- IPS_DST_NAT_DONE_BIT = 8,
- IPS_DST_NAT_DONE = (1 << IPS_DST_NAT_DONE_BIT),
-
- /* Both together */
- IPS_NAT_DONE_MASK = (IPS_DST_NAT_DONE | IPS_SRC_NAT_DONE),
-
- /* Connection is dying (removed from lists), can not be unset. */
- IPS_DYING_BIT = 9,
- IPS_DYING = (1 << IPS_DYING_BIT),
-
- /* Connection has fixed timeout. */
- IPS_FIXED_TIMEOUT_BIT = 10,
- IPS_FIXED_TIMEOUT = (1 << IPS_FIXED_TIMEOUT_BIT),
-
- /* Conntrack is a template */
- IPS_TEMPLATE_BIT = 11,
- IPS_TEMPLATE = (1 << IPS_TEMPLATE_BIT),
-
- /* Conntrack is a fake untracked entry */
- IPS_UNTRACKED_BIT = 12,
- IPS_UNTRACKED = (1 << IPS_UNTRACKED_BIT),
-
- /* Conntrack got a helper explicitly attached via CT target. */
- IPS_HELPER_BIT = 13,
- IPS_HELPER = (1 << IPS_HELPER_BIT),
-};
-
-/* Connection tracking event types */
-enum ip_conntrack_events {
- IPCT_NEW, /* new conntrack */
- IPCT_RELATED, /* related conntrack */
- IPCT_DESTROY, /* destroyed conntrack */
- IPCT_REPLY, /* connection has seen two-way traffic */
- IPCT_ASSURED, /* connection status has changed to assured */
- IPCT_PROTOINFO, /* protocol information has changed */
- IPCT_HELPER, /* new helper has been set */
- IPCT_MARK, /* new mark has been set */
- IPCT_NATSEQADJ, /* NAT is doing sequence adjustment */
- IPCT_SECMARK, /* new security mark has been set */
-};
-
-enum ip_conntrack_expect_events {
- IPEXP_NEW, /* new expectation */
- IPEXP_DESTROY, /* destroyed expectation */
-};
-
-/* expectation flags */
-#define NF_CT_EXPECT_PERMANENT 0x1
-#define NF_CT_EXPECT_INACTIVE 0x2
-#define NF_CT_EXPECT_USERSPACE 0x4
-
-#ifdef __KERNEL__
struct ip_conntrack_stat {
unsigned int searched;
unsigned int found;
@@ -136,6 +25,4 @@ struct ip_conntrack_stat {
/* call to create an explicit dependency on nf_conntrack. */
extern void need_conntrack(void);
-#endif /* __KERNEL__ */
-
#endif /* _NF_CONNTRACK_COMMON_H */
diff --git a/include/linux/netfilter/nf_conntrack_ftp.h b/include/linux/netfilter/nf_conntrack_ftp.h
index 8faf3f7..5f818b0 100644
--- a/include/linux/netfilter/nf_conntrack_ftp.h
+++ b/include/linux/netfilter/nf_conntrack_ftp.h
@@ -1,20 +1,8 @@
#ifndef _NF_CONNTRACK_FTP_H
#define _NF_CONNTRACK_FTP_H
-/* FTP tracking. */
-/* This enum is exposed to userspace */
-enum nf_ct_ftp_type {
- /* PORT command from client */
- NF_CT_FTP_PORT,
- /* PASV response from server */
- NF_CT_FTP_PASV,
- /* EPRT command from client */
- NF_CT_FTP_EPRT,
- /* EPSV response from server */
- NF_CT_FTP_EPSV,
-};
+#include <uapi/linux/netfilter/nf_conntrack_ftp.h>
-#ifdef __KERNEL__
#define FTP_PORT 21
@@ -42,6 +30,4 @@ extern unsigned int (*nf_nat_ftp_hook)(struct sk_buff *skb,
unsigned int matchoff,
unsigned int matchlen,
struct nf_conntrack_expect *exp);
-#endif /* __KERNEL__ */
-
#endif /* _NF_CONNTRACK_FTP_H */
diff --git a/include/linux/netfilter/nf_conntrack_tcp.h b/include/linux/netfilter/nf_conntrack_tcp.h
index e59868a..22db961 100644
--- a/include/linux/netfilter/nf_conntrack_tcp.h
+++ b/include/linux/netfilter/nf_conntrack_tcp.h
@@ -1,53 +1,8 @@
#ifndef _NF_CONNTRACK_TCP_H
#define _NF_CONNTRACK_TCP_H
-/* TCP tracking. */
-#include <linux/types.h>
+#include <uapi/linux/netfilter/nf_conntrack_tcp.h>
-/* This is exposed to userspace (ctnetlink) */
-enum tcp_conntrack {
- TCP_CONNTRACK_NONE,
- TCP_CONNTRACK_SYN_SENT,
- TCP_CONNTRACK_SYN_RECV,
- TCP_CONNTRACK_ESTABLISHED,
- TCP_CONNTRACK_FIN_WAIT,
- TCP_CONNTRACK_CLOSE_WAIT,
- TCP_CONNTRACK_LAST_ACK,
- TCP_CONNTRACK_TIME_WAIT,
- TCP_CONNTRACK_CLOSE,
- TCP_CONNTRACK_LISTEN, /* obsolete */
-#define TCP_CONNTRACK_SYN_SENT2 TCP_CONNTRACK_LISTEN
- TCP_CONNTRACK_MAX,
- TCP_CONNTRACK_IGNORE,
- TCP_CONNTRACK_RETRANS,
- TCP_CONNTRACK_UNACK,
- TCP_CONNTRACK_TIMEOUT_MAX
-};
-
-/* Window scaling is advertised by the sender */
-#define IP_CT_TCP_FLAG_WINDOW_SCALE 0x01
-
-/* SACK is permitted by the sender */
-#define IP_CT_TCP_FLAG_SACK_PERM 0x02
-
-/* This sender sent FIN first */
-#define IP_CT_TCP_FLAG_CLOSE_INIT 0x04
-
-/* Be liberal in window checking */
-#define IP_CT_TCP_FLAG_BE_LIBERAL 0x08
-
-/* Has unacknowledged data */
-#define IP_CT_TCP_FLAG_DATA_UNACKNOWLEDGED 0x10
-
-/* The field td_maxack has been set */
-#define IP_CT_TCP_FLAG_MAXACK_SET 0x20
-
-struct nf_ct_tcp_flags {
- __u8 flags;
- __u8 mask;
-};
-
-#ifdef __KERNEL__
struct ip_ct_tcp_state {
u_int32_t td_end; /* max of seq + len */
@@ -74,6 +29,4 @@ struct ip_ct_tcp {
u_int8_t last_flags; /* Last flags set */
};
-#endif /* __KERNEL__ */
-
#endif /* _NF_CONNTRACK_TCP_H */
diff --git a/include/linux/netfilter/nfnetlink.h b/include/linux/netfilter/nfnetlink.h
index 18341cd..4966dde 100644
--- a/include/linux/netfilter/nfnetlink.h
+++ b/include/linux/netfilter/nfnetlink.h
@@ -1,63 +1,11 @@
#ifndef _NFNETLINK_H
#define _NFNETLINK_H
-#include <linux/types.h>
-#include <linux/netfilter/nfnetlink_compat.h>
-enum nfnetlink_groups {
- NFNLGRP_NONE,
-#define NFNLGRP_NONE NFNLGRP_NONE
- NFNLGRP_CONNTRACK_NEW,
-#define NFNLGRP_CONNTRACK_NEW NFNLGRP_CONNTRACK_NEW
- NFNLGRP_CONNTRACK_UPDATE,
-#define NFNLGRP_CONNTRACK_UPDATE NFNLGRP_CONNTRACK_UPDATE
- NFNLGRP_CONNTRACK_DESTROY,
-#define NFNLGRP_CONNTRACK_DESTROY NFNLGRP_CONNTRACK_DESTROY
- NFNLGRP_CONNTRACK_EXP_NEW,
-#define NFNLGRP_CONNTRACK_EXP_NEW NFNLGRP_CONNTRACK_EXP_NEW
- NFNLGRP_CONNTRACK_EXP_UPDATE,
-#define NFNLGRP_CONNTRACK_EXP_UPDATE NFNLGRP_CONNTRACK_EXP_UPDATE
- NFNLGRP_CONNTRACK_EXP_DESTROY,
-#define NFNLGRP_CONNTRACK_EXP_DESTROY NFNLGRP_CONNTRACK_EXP_DESTROY
- __NFNLGRP_MAX,
-};
-#define NFNLGRP_MAX (__NFNLGRP_MAX - 1)
-
-/* General form of address family dependent message.
- */
-struct nfgenmsg {
- __u8 nfgen_family; /* AF_xxx */
- __u8 version; /* nfnetlink version */
- __be16 res_id; /* resource id */
-};
-
-#define NFNETLINK_V0 0
-
-/* netfilter netlink message types are split in two pieces:
- * 8 bit subsystem, 8bit operation.
- */
-
-#define NFNL_SUBSYS_ID(x) ((x & 0xff00) >> 8)
-#define NFNL_MSG_TYPE(x) (x & 0x00ff)
-
-/* No enum here, otherwise __stringify() trick of MODULE_ALIAS_NFNL_SUBSYS()
- * won't work anymore */
-#define NFNL_SUBSYS_NONE 0
-#define NFNL_SUBSYS_CTNETLINK 1
-#define NFNL_SUBSYS_CTNETLINK_EXP 2
-#define NFNL_SUBSYS_QUEUE 3
-#define NFNL_SUBSYS_ULOG 4
-#define NFNL_SUBSYS_OSF 5
-#define NFNL_SUBSYS_IPSET 6
-#define NFNL_SUBSYS_ACCT 7
-#define NFNL_SUBSYS_CTNETLINK_TIMEOUT 8
-#define NFNL_SUBSYS_CTHELPER 9
-#define NFNL_SUBSYS_COUNT 10
-
-#ifdef __KERNEL__
#include <linux/netlink.h>
#include <linux/capability.h>
#include <net/netlink.h>
+#include <uapi/linux/netfilter/nfnetlink.h>
struct nfnl_callback {
int (*call)(struct sock *nl, struct sk_buff *skb,
@@ -92,5 +40,4 @@ extern void nfnl_unlock(void);
#define MODULE_ALIAS_NFNL_SUBSYS(subsys) \
MODULE_ALIAS("nfnetlink-subsys-" __stringify(subsys))
-#endif /* __KERNEL__ */
#endif /* _NFNETLINK_H */
diff --git a/include/linux/netfilter/nfnetlink_acct.h b/include/linux/netfilter/nfnetlink_acct.h
index 7c4279b..bb4bbc9 100644
--- a/include/linux/netfilter/nfnetlink_acct.h
+++ b/include/linux/netfilter/nfnetlink_acct.h
@@ -1,29 +1,8 @@
#ifndef _NFNL_ACCT_H_
#define _NFNL_ACCT_H_
-#ifndef NFACCT_NAME_MAX
-#define NFACCT_NAME_MAX 32
-#endif
+#include <uapi/linux/netfilter/nfnetlink_acct.h>
-enum nfnl_acct_msg_types {
- NFNL_MSG_ACCT_NEW,
- NFNL_MSG_ACCT_GET,
- NFNL_MSG_ACCT_GET_CTRZERO,
- NFNL_MSG_ACCT_DEL,
- NFNL_MSG_ACCT_MAX
-};
-
-enum nfnl_acct_type {
- NFACCT_UNSPEC,
- NFACCT_NAME,
- NFACCT_PKTS,
- NFACCT_BYTES,
- NFACCT_USE,
- __NFACCT_MAX
-};
-#define NFACCT_MAX (__NFACCT_MAX - 1)
-
-#ifdef __KERNEL__
struct nf_acct;
@@ -31,6 +10,4 @@ extern struct nf_acct *nfnl_acct_find_get(const char *filter_name);
extern void nfnl_acct_put(struct nf_acct *acct);
extern void nfnl_acct_update(const struct sk_buff *skb, struct nf_acct *nfacct);
-#endif /* __KERNEL__ */
-
#endif /* _NFNL_ACCT_H */
diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h
index 8d674a7..dd49566 100644
--- a/include/linux/netfilter/x_tables.h
+++ b/include/linux/netfilter/x_tables.h
@@ -1,191 +1,9 @@
#ifndef _X_TABLES_H
#define _X_TABLES_H
-#include <linux/kernel.h>
-#include <linux/types.h>
-#define XT_FUNCTION_MAXNAMELEN 30
-#define XT_EXTENSION_MAXNAMELEN 29
-#define XT_TABLE_MAXNAMELEN 32
-
-struct xt_entry_match {
- union {
- struct {
- __u16 match_size;
-
- /* Used by userspace */
- char name[XT_EXTENSION_MAXNAMELEN];
- __u8 revision;
- } user;
- struct {
- __u16 match_size;
-
- /* Used inside the kernel */
- struct xt_match *match;
- } kernel;
-
- /* Total length */
- __u16 match_size;
- } u;
-
- unsigned char data[0];
-};
-
-struct xt_entry_target {
- union {
- struct {
- __u16 target_size;
-
- /* Used by userspace */
- char name[XT_EXTENSION_MAXNAMELEN];
- __u8 revision;
- } user;
- struct {
- __u16 target_size;
-
- /* Used inside the kernel */
- struct xt_target *target;
- } kernel;
-
- /* Total length */
- __u16 target_size;
- } u;
-
- unsigned char data[0];
-};
-
-#define XT_TARGET_INIT(__name, __size) \
-{ \
- .target.u.user = { \
- .target_size = XT_ALIGN(__size), \
- .name = __name, \
- }, \
-}
-
-struct xt_standard_target {
- struct xt_entry_target target;
- int verdict;
-};
-
-struct xt_error_target {
- struct xt_entry_target target;
- char errorname[XT_FUNCTION_MAXNAMELEN];
-};
-
-/* The argument to IPT_SO_GET_REVISION_*. Returns highest revision
- * kernel supports, if >= revision. */
-struct xt_get_revision {
- char name[XT_EXTENSION_MAXNAMELEN];
- __u8 revision;
-};
-
-/* CONTINUE verdict for targets */
-#define XT_CONTINUE 0xFFFFFFFF
-
-/* For standard target */
-#define XT_RETURN (-NF_REPEAT - 1)
-
-/* this is a dummy structure to find out the alignment requirement for a struct
- * containing all the fundamental data types that are used in ipt_entry,
- * ip6t_entry and arpt_entry. This sucks, and it is a hack. It will be my
- * personal pleasure to remove it -HW
- */
-struct _xt_align {
- __u8 u8;
- __u16 u16;
- __u32 u32;
- __u64 u64;
-};
-
-#define XT_ALIGN(s) __ALIGN_KERNEL((s), __alignof__(struct _xt_align))
-
-/* Standard return verdict, or do jump. */
-#define XT_STANDARD_TARGET ""
-/* Error verdict. */
-#define XT_ERROR_TARGET "ERROR"
-
-#define SET_COUNTER(c,b,p) do { (c).bcnt = (b); (c).pcnt = (p); } while(0)
-#define ADD_COUNTER(c,b,p) do { (c).bcnt += (b); (c).pcnt += (p); } while(0)
-
-struct xt_counters {
- __u64 pcnt, bcnt; /* Packet and byte counters */
-};
-
-/* The argument to IPT_SO_ADD_COUNTERS. */
-struct xt_counters_info {
- /* Which table. */
- char name[XT_TABLE_MAXNAMELEN];
-
- unsigned int num_counters;
-
- /* The counters (actually `number' of these). */
- struct xt_counters counters[0];
-};
-
-#define XT_INV_PROTO 0x40 /* Invert the sense of PROTO. */
-
-#ifndef __KERNEL__
-/* fn returns 0 to continue iteration */
-#define XT_MATCH_ITERATE(type, e, fn, args...) \
-({ \
- unsigned int __i; \
- int __ret = 0; \
- struct xt_entry_match *__m; \
- \
- for (__i = sizeof(type); \
- __i < (e)->target_offset; \
- __i += __m->u.match_size) { \
- __m = (void *)e + __i; \
- \
- __ret = fn(__m , ## args); \
- if (__ret != 0) \
- break; \
- } \
- __ret; \
-})
-
-/* fn returns 0 to continue iteration */
-#define XT_ENTRY_ITERATE_CONTINUE(type, entries, size, n, fn, args...) \
-({ \
- unsigned int __i, __n; \
- int __ret = 0; \
- type *__entry; \
- \
- for (__i = 0, __n = 0; __i < (size); \
- __i += __entry->next_offset, __n++) { \
- __entry = (void *)(entries) + __i; \
- if (__n < n) \
- continue; \
- \
- __ret = fn(__entry , ## args); \
- if (__ret != 0) \
- break; \
- } \
- __ret; \
-})
-
-/* fn returns 0 to continue iteration */
-#define XT_ENTRY_ITERATE(type, entries, size, fn, args...) \
- XT_ENTRY_ITERATE_CONTINUE(type, entries, size, 0, fn, args)
-
-#endif /* !__KERNEL__ */
-
-/* pos is normally a struct ipt_entry/ip6t_entry/etc. */
-#define xt_entry_foreach(pos, ehead, esize) \
- for ((pos) = (typeof(pos))(ehead); \
- (pos) < (typeof(pos))((char *)(ehead) + (esize)); \
- (pos) = (typeof(pos))((char *)(pos) + (pos)->next_offset))
-
-/* can only be xt_entry_match, so no use of typeof here */
-#define xt_ematch_foreach(pos, entry) \
- for ((pos) = (struct xt_entry_match *)entry->elems; \
- (pos) < (struct xt_entry_match *)((char *)(entry) + \
- (entry)->target_offset); \
- (pos) = (struct xt_entry_match *)((char *)(pos) + \
- (pos)->u.match_size))
-
-#ifdef __KERNEL__
#include <linux/netdevice.h>
+#include <uapi/linux/netfilter/x_tables.h>
/**
* struct xt_action_param - parameters for matches/targets
@@ -617,6 +435,4 @@ extern int xt_compat_target_to_user(const struct xt_entry_target *t,
void __user **dstptr, unsigned int *size);
#endif /* CONFIG_COMPAT */
-#endif /* __KERNEL__ */
-
#endif /* _X_TABLES_H */
diff --git a/include/linux/netfilter/xt_hashlimit.h b/include/linux/netfilter/xt_hashlimit.h
index c42e52f..074790c 100644
--- a/include/linux/netfilter/xt_hashlimit.h
+++ b/include/linux/netfilter/xt_hashlimit.h
@@ -1,78 +1,9 @@
#ifndef _XT_HASHLIMIT_H
#define _XT_HASHLIMIT_H
-#include <linux/types.h>
+#include <uapi/linux/netfilter/xt_hashlimit.h>
-/* timings are in milliseconds. */
-#define XT_HASHLIMIT_SCALE 10000
-/* 1/10,000 sec period => max of 10,000/sec. Min rate is then 429490
- * seconds, or one packet every 59 hours.
- */
-
-/* packet length accounting is done in 16-byte steps */
-#define XT_HASHLIMIT_BYTE_SHIFT 4
-
-/* details of this structure hidden by the implementation */
-struct xt_hashlimit_htable;
-
-enum {
- XT_HASHLIMIT_HASH_DIP = 1 << 0,
- XT_HASHLIMIT_HASH_DPT = 1 << 1,
- XT_HASHLIMIT_HASH_SIP = 1 << 2,
- XT_HASHLIMIT_HASH_SPT = 1 << 3,
- XT_HASHLIMIT_INVERT = 1 << 4,
- XT_HASHLIMIT_BYTES = 1 << 5,
-};
-#ifdef __KERNEL__
#define XT_HASHLIMIT_ALL (XT_HASHLIMIT_HASH_DIP | XT_HASHLIMIT_HASH_DPT | \
XT_HASHLIMIT_HASH_SIP | XT_HASHLIMIT_HASH_SPT | \
XT_HASHLIMIT_INVERT | XT_HASHLIMIT_BYTES)
-#endif
-
-struct hashlimit_cfg {
- __u32 mode; /* bitmask of XT_HASHLIMIT_HASH_* */
- __u32 avg; /* Average secs between packets * scale */
- __u32 burst; /* Period multiplier for upper limit. */
-
- /* user specified */
- __u32 size; /* how many buckets */
- __u32 max; /* max number of entries */
- __u32 gc_interval; /* gc interval */
- __u32 expire; /* when do entries expire? */
-};
-
-struct xt_hashlimit_info {
- char name [IFNAMSIZ]; /* name */
- struct hashlimit_cfg cfg;
-
- /* Used internally by the kernel */
- struct xt_hashlimit_htable *hinfo;
- union {
- void *ptr;
- struct xt_hashlimit_info *master;
- } u;
-};
-
-struct hashlimit_cfg1 {
- __u32 mode; /* bitmask of XT_HASHLIMIT_HASH_* */
- __u32 avg; /* Average secs between packets * scale */
- __u32 burst; /* Period multiplier for upper limit. */
-
- /* user specified */
- __u32 size; /* how many buckets */
- __u32 max; /* max number of entries */
- __u32 gc_interval; /* gc interval */
- __u32 expire; /* when do entries expire? */
-
- __u8 srcmask, dstmask;
-};
-
-struct xt_hashlimit_mtinfo1 {
- char name[IFNAMSIZ];
- struct hashlimit_cfg1 cfg;
-
- /* Used internally by the kernel */
- struct xt_hashlimit_htable *hinfo __attribute__((aligned(8)));
-};
-
#endif /*_XT_HASHLIMIT_H*/
diff --git a/include/linux/netfilter/xt_physdev.h b/include/linux/netfilter/xt_physdev.h
index 8555e39..5b5e417 100644
--- a/include/linux/netfilter/xt_physdev.h
+++ b/include/linux/netfilter/xt_physdev.h
@@ -1,26 +1,7 @@
#ifndef _XT_PHYSDEV_H
#define _XT_PHYSDEV_H
-#include <linux/types.h>
-
-#ifdef __KERNEL__
#include <linux/if.h>
-#endif
-
-#define XT_PHYSDEV_OP_IN 0x01
-#define XT_PHYSDEV_OP_OUT 0x02
-#define XT_PHYSDEV_OP_BRIDGED 0x04
-#define XT_PHYSDEV_OP_ISIN 0x08
-#define XT_PHYSDEV_OP_ISOUT 0x10
-#define XT_PHYSDEV_OP_MASK (0x20 - 1)
-
-struct xt_physdev_info {
- char physindev[IFNAMSIZ];
- char in_mask[IFNAMSIZ];
- char physoutdev[IFNAMSIZ];
- char out_mask[IFNAMSIZ];
- __u8 invert;
- __u8 bitmask;
-};
+#include <uapi/linux/netfilter/xt_physdev.h>
#endif /*_XT_PHYSDEV_H*/
diff --git a/include/linux/netfilter_arp/Kbuild b/include/linux/netfilter_arp/Kbuild
index b27439c..e69de29 100644
--- a/include/linux/netfilter_arp/Kbuild
+++ b/include/linux/netfilter_arp/Kbuild
@@ -1,2 +0,0 @@
-header-y += arp_tables.h
-header-y += arpt_mangle.h
diff --git a/include/linux/netfilter_arp/arp_tables.h b/include/linux/netfilter_arp/arp_tables.h
index e08565d..cfb7191 100644
--- a/include/linux/netfilter_arp/arp_tables.h
+++ b/include/linux/netfilter_arp/arp_tables.h
@@ -5,211 +5,14 @@
* network byte order.
* flags are stored in host byte order (of course).
*/
-
#ifndef _ARPTABLES_H
#define _ARPTABLES_H
-#ifdef __KERNEL__
#include <linux/if.h>
#include <linux/in.h>
#include <linux/if_arp.h>
#include <linux/skbuff.h>
-#endif
-#include <linux/types.h>
-#include <linux/compiler.h>
-#include <linux/netfilter_arp.h>
-
-#include <linux/netfilter/x_tables.h>
-
-#ifndef __KERNEL__
-#define ARPT_FUNCTION_MAXNAMELEN XT_FUNCTION_MAXNAMELEN
-#define ARPT_TABLE_MAXNAMELEN XT_TABLE_MAXNAMELEN
-#define arpt_entry_target xt_entry_target
-#define arpt_standard_target xt_standard_target
-#define arpt_error_target xt_error_target
-#define ARPT_CONTINUE XT_CONTINUE
-#define ARPT_RETURN XT_RETURN
-#define arpt_counters_info xt_counters_info
-#define arpt_counters xt_counters
-#define ARPT_STANDARD_TARGET XT_STANDARD_TARGET
-#define ARPT_ERROR_TARGET XT_ERROR_TARGET
-#define ARPT_ENTRY_ITERATE(entries, size, fn, args...) \
- XT_ENTRY_ITERATE(struct arpt_entry, entries, size, fn, ## args)
-#endif
-
-#define ARPT_DEV_ADDR_LEN_MAX 16
-
-struct arpt_devaddr_info {
- char addr[ARPT_DEV_ADDR_LEN_MAX];
- char mask[ARPT_DEV_ADDR_LEN_MAX];
-};
-
-/* Yes, Virginia, you have to zero the padding. */
-struct arpt_arp {
- /* Source and target IP addr */
- struct in_addr src, tgt;
- /* Mask for src and target IP addr */
- struct in_addr smsk, tmsk;
-
- /* Device hw address length, src+target device addresses */
- __u8 arhln, arhln_mask;
- struct arpt_devaddr_info src_devaddr;
- struct arpt_devaddr_info tgt_devaddr;
-
- /* ARP operation code. */
- __be16 arpop, arpop_mask;
-
- /* ARP hardware address and protocol address format. */
- __be16 arhrd, arhrd_mask;
- __be16 arpro, arpro_mask;
-
- /* The protocol address length is only accepted if it is 4
- * so there is no use in offering a way to do filtering on it.
- */
-
- char iniface[IFNAMSIZ], outiface[IFNAMSIZ];
- unsigned char iniface_mask[IFNAMSIZ], outiface_mask[IFNAMSIZ];
-
- /* Flags word */
- __u8 flags;
- /* Inverse flags */
- __u16 invflags;
-};
-
-/* Values for "flag" field in struct arpt_ip (general arp structure).
- * No flags defined yet.
- */
-#define ARPT_F_MASK 0x00 /* All possible flag bits mask. */
-
-/* Values for "inv" field in struct arpt_arp. */
-#define ARPT_INV_VIA_IN 0x0001 /* Invert the sense of IN IFACE. */
-#define ARPT_INV_VIA_OUT 0x0002 /* Invert the sense of OUT IFACE */
-#define ARPT_INV_SRCIP 0x0004 /* Invert the sense of SRC IP. */
-#define ARPT_INV_TGTIP 0x0008 /* Invert the sense of TGT IP. */
-#define ARPT_INV_SRCDEVADDR 0x0010 /* Invert the sense of SRC DEV ADDR. */
-#define ARPT_INV_TGTDEVADDR 0x0020 /* Invert the sense of TGT DEV ADDR. */
-#define ARPT_INV_ARPOP 0x0040 /* Invert the sense of ARP OP. */
-#define ARPT_INV_ARPHRD 0x0080 /* Invert the sense of ARP HRD. */
-#define ARPT_INV_ARPPRO 0x0100 /* Invert the sense of ARP PRO. */
-#define ARPT_INV_ARPHLN 0x0200 /* Invert the sense of ARP HLN. */
-#define ARPT_INV_MASK 0x03FF /* All possible flag bits mask. */
-
-/* This structure defines each of the firewall rules. Consists of 3
- parts which are 1) general ARP header stuff 2) match specific
- stuff 3) the target to perform if the rule matches */
-struct arpt_entry
-{
- struct arpt_arp arp;
-
- /* Size of arpt_entry + matches */
- __u16 target_offset;
- /* Size of arpt_entry + matches + target */
- __u16 next_offset;
-
- /* Back pointer */
- unsigned int comefrom;
-
- /* Packet and byte counters. */
- struct xt_counters counters;
-
- /* The matches (if any), then the target. */
- unsigned char elems[0];
-};
-
-/*
- * New IP firewall options for [gs]etsockopt at the RAW IP level.
- * Unlike BSD Linux inherits IP options so you don't have to use a raw
- * socket for this. Instead we check rights in the calls.
- *
- * ATTENTION: check linux/in.h before adding new number here.
- */
-#define ARPT_BASE_CTL 96
-
-#define ARPT_SO_SET_REPLACE (ARPT_BASE_CTL)
-#define ARPT_SO_SET_ADD_COUNTERS (ARPT_BASE_CTL + 1)
-#define ARPT_SO_SET_MAX ARPT_SO_SET_ADD_COUNTERS
-
-#define ARPT_SO_GET_INFO (ARPT_BASE_CTL)
-#define ARPT_SO_GET_ENTRIES (ARPT_BASE_CTL + 1)
-/* #define ARPT_SO_GET_REVISION_MATCH (APRT_BASE_CTL + 2) */
-#define ARPT_SO_GET_REVISION_TARGET (ARPT_BASE_CTL + 3)
-#define ARPT_SO_GET_MAX (ARPT_SO_GET_REVISION_TARGET)
-
-/* The argument to ARPT_SO_GET_INFO */
-struct arpt_getinfo {
- /* Which table: caller fills this in. */
- char name[XT_TABLE_MAXNAMELEN];
-
- /* Kernel fills these in. */
- /* Which hook entry points are valid: bitmask */
- unsigned int valid_hooks;
-
- /* Hook entry points: one per netfilter hook. */
- unsigned int hook_entry[NF_ARP_NUMHOOKS];
-
- /* Underflow points. */
- unsigned int underflow[NF_ARP_NUMHOOKS];
-
- /* Number of entries */
- unsigned int num_entries;
-
- /* Size of entries. */
- unsigned int size;
-};
-
-/* The argument to ARPT_SO_SET_REPLACE. */
-struct arpt_replace {
- /* Which table. */
- char name[XT_TABLE_MAXNAMELEN];
-
- /* Which hook entry points are valid: bitmask. You can't
- change this. */
- unsigned int valid_hooks;
-
- /* Number of entries */
- unsigned int num_entries;
-
- /* Total size of new entries */
- unsigned int size;
-
- /* Hook entry points. */
- unsigned int hook_entry[NF_ARP_NUMHOOKS];
-
- /* Underflow points. */
- unsigned int underflow[NF_ARP_NUMHOOKS];
-
- /* Information about old entries: */
- /* Number of counters (must be equal to current number of entries). */
- unsigned int num_counters;
- /* The old entries' counters. */
- struct xt_counters __user *counters;
-
- /* The entries (hang off end: not really an array). */
- struct arpt_entry entries[0];
-};
-
-/* The argument to ARPT_SO_GET_ENTRIES. */
-struct arpt_get_entries {
- /* Which table: user fills this in. */
- char name[XT_TABLE_MAXNAMELEN];
-
- /* User fills this in: total entry size. */
- unsigned int size;
-
- /* The entries. */
- struct arpt_entry entrytable[0];
-};
-
-/* Helper functions */
-static __inline__ struct xt_entry_target *arpt_get_target(struct arpt_entry *e)
-{
- return (void *)e + e->target_offset;
-}
-
-/*
- * Main firewall chains definitions and global var's definitions.
- */
-#ifdef __KERNEL__
+#include <uapi/linux/netfilter_arp/arp_tables.h>
/* Standard entry. */
struct arpt_standard {
@@ -274,5 +77,4 @@ compat_arpt_get_target(struct compat_arpt_entry *e)
}
#endif /* CONFIG_COMPAT */
-#endif /*__KERNEL__*/
#endif /* _ARPTABLES_H */
diff --git a/include/linux/netfilter_bridge/Kbuild b/include/linux/netfilter_bridge/Kbuild
index e48f1a3..e69de29 100644
--- a/include/linux/netfilter_bridge/Kbuild
+++ b/include/linux/netfilter_bridge/Kbuild
@@ -1,18 +0,0 @@
-header-y += ebt_802_3.h
-header-y += ebt_among.h
-header-y += ebt_arp.h
-header-y += ebt_arpreply.h
-header-y += ebt_ip.h
-header-y += ebt_ip6.h
-header-y += ebt_limit.h
-header-y += ebt_log.h
-header-y += ebt_mark_m.h
-header-y += ebt_mark_t.h
-header-y += ebt_nat.h
-header-y += ebt_nflog.h
-header-y += ebt_pkttype.h
-header-y += ebt_redirect.h
-header-y += ebt_stp.h
-header-y += ebt_ulog.h
-header-y += ebt_vlan.h
-header-y += ebtables.h
diff --git a/include/linux/netfilter_bridge/ebt_802_3.h b/include/linux/netfilter_bridge/ebt_802_3.h
index be5be15..e17e8bf 100644
--- a/include/linux/netfilter_bridge/ebt_802_3.h
+++ b/include/linux/netfilter_bridge/ebt_802_3.h
@@ -1,70 +1,11 @@
#ifndef __LINUX_BRIDGE_EBT_802_3_H
#define __LINUX_BRIDGE_EBT_802_3_H
-#include <linux/types.h>
-
-#define EBT_802_3_SAP 0x01
-#define EBT_802_3_TYPE 0x02
-
-#define EBT_802_3_MATCH "802_3"
-
-/*
- * If frame has DSAP/SSAP value 0xaa you must check the SNAP type
- * to discover what kind of packet we're carrying.
- */
-#define CHECK_TYPE 0xaa
-
-/*
- * Control field may be one or two bytes. If the first byte has
- * the value 0x03 then the entire length is one byte, otherwise it is two.
- * One byte controls are used in Unnumbered Information frames.
- * Two byte controls are used in Numbered Information frames.
- */
-#define IS_UI 0x03
-
-#define EBT_802_3_MASK (EBT_802_3_SAP | EBT_802_3_TYPE | EBT_802_3)
-
-/* ui has one byte ctrl, ni has two */
-struct hdr_ui {
- __u8 dsap;
- __u8 ssap;
- __u8 ctrl;
- __u8 orig[3];
- __be16 type;
-};
-
-struct hdr_ni {
- __u8 dsap;
- __u8 ssap;
- __be16 ctrl;
- __u8 orig[3];
- __be16 type;
-};
-
-struct ebt_802_3_hdr {
- __u8 daddr[6];
- __u8 saddr[6];
- __be16 len;
- union {
- struct hdr_ui ui;
- struct hdr_ni ni;
- } llc;
-};
-
-#ifdef __KERNEL__
#include <linux/skbuff.h>
+#include <uapi/linux/netfilter_bridge/ebt_802_3.h>
static inline struct ebt_802_3_hdr *ebt_802_3_hdr(const struct sk_buff *skb)
{
return (struct ebt_802_3_hdr *)skb_mac_header(skb);
}
#endif
-
-struct ebt_802_3_info {
- __u8 sap;
- __be16 type;
- __u8 bitmask;
- __u8 invflags;
-};
-
-#endif
diff --git a/include/linux/netfilter_bridge/ebtables.h b/include/linux/netfilter_bridge/ebtables.h
index 4dd5bd6..34e7a2b 100644
--- a/include/linux/netfilter_bridge/ebtables.h
+++ b/include/linux/netfilter_bridge/ebtables.h
@@ -9,191 +9,11 @@
* This code is stongly inspired on the iptables code which is
* Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
*/
-
#ifndef __LINUX_BRIDGE_EFF_H
#define __LINUX_BRIDGE_EFF_H
-#include <linux/if.h>
-#include <linux/netfilter_bridge.h>
-#include <linux/if_ether.h>
-
-#define EBT_TABLE_MAXNAMELEN 32
-#define EBT_CHAIN_MAXNAMELEN EBT_TABLE_MAXNAMELEN
-#define EBT_FUNCTION_MAXNAMELEN EBT_TABLE_MAXNAMELEN
-
-/* verdicts >0 are "branches" */
-#define EBT_ACCEPT -1
-#define EBT_DROP -2
-#define EBT_CONTINUE -3
-#define EBT_RETURN -4
-#define NUM_STANDARD_TARGETS 4
-/* ebtables target modules store the verdict inside an int. We can
- * reclaim a part of this int for backwards compatible extensions.
- * The 4 lsb are more than enough to store the verdict. */
-#define EBT_VERDICT_BITS 0x0000000F
-
-struct xt_match;
-struct xt_target;
-
-struct ebt_counter {
- uint64_t pcnt;
- uint64_t bcnt;
-};
-struct ebt_replace {
- char name[EBT_TABLE_MAXNAMELEN];
- unsigned int valid_hooks;
- /* nr of rules in the table */
- unsigned int nentries;
- /* total size of the entries */
- unsigned int entries_size;
- /* start of the chains */
- struct ebt_entries __user *hook_entry[NF_BR_NUMHOOKS];
- /* nr of counters userspace expects back */
- unsigned int num_counters;
- /* where the kernel will put the old counters */
- struct ebt_counter __user *counters;
- char __user *entries;
-};
+#include <uapi/linux/netfilter_bridge/ebtables.h>
-struct ebt_replace_kernel {
- char name[EBT_TABLE_MAXNAMELEN];
- unsigned int valid_hooks;
- /* nr of rules in the table */
- unsigned int nentries;
- /* total size of the entries */
- unsigned int entries_size;
- /* start of the chains */
- struct ebt_entries *hook_entry[NF_BR_NUMHOOKS];
- /* nr of counters userspace expects back */
- unsigned int num_counters;
- /* where the kernel will put the old counters */
- struct ebt_counter *counters;
- char *entries;
-};
-
-struct ebt_entries {
- /* this field is always set to zero
- * See EBT_ENTRY_OR_ENTRIES.
- * Must be same size as ebt_entry.bitmask */
- unsigned int distinguisher;
- /* the chain name */
- char name[EBT_CHAIN_MAXNAMELEN];
- /* counter offset for this chain */
- unsigned int counter_offset;
- /* one standard (accept, drop, return) per hook */
- int policy;
- /* nr. of entries */
- unsigned int nentries;
- /* entry list */
- char data[0] __attribute__ ((aligned (__alignof__(struct ebt_replace))));
-};
-
-/* used for the bitmask of struct ebt_entry */
-
-/* This is a hack to make a difference between an ebt_entry struct and an
- * ebt_entries struct when traversing the entries from start to end.
- * Using this simplifies the code a lot, while still being able to use
- * ebt_entries.
- * Contrary, iptables doesn't use something like ebt_entries and therefore uses
- * different techniques for naming the policy and such. So, iptables doesn't
- * need a hack like this.
- */
-#define EBT_ENTRY_OR_ENTRIES 0x01
-/* these are the normal masks */
-#define EBT_NOPROTO 0x02
-#define EBT_802_3 0x04
-#define EBT_SOURCEMAC 0x08
-#define EBT_DESTMAC 0x10
-#define EBT_F_MASK (EBT_NOPROTO | EBT_802_3 | EBT_SOURCEMAC | EBT_DESTMAC \
- | EBT_ENTRY_OR_ENTRIES)
-
-#define EBT_IPROTO 0x01
-#define EBT_IIN 0x02
-#define EBT_IOUT 0x04
-#define EBT_ISOURCE 0x8
-#define EBT_IDEST 0x10
-#define EBT_ILOGICALIN 0x20
-#define EBT_ILOGICALOUT 0x40
-#define EBT_INV_MASK (EBT_IPROTO | EBT_IIN | EBT_IOUT | EBT_ILOGICALIN \
- | EBT_ILOGICALOUT | EBT_ISOURCE | EBT_IDEST)
-
-struct ebt_entry_match {
- union {
- char name[EBT_FUNCTION_MAXNAMELEN];
- struct xt_match *match;
- } u;
- /* size of data */
- unsigned int match_size;
- unsigned char data[0] __attribute__ ((aligned (__alignof__(struct ebt_replace))));
-};
-
-struct ebt_entry_watcher {
- union {
- char name[EBT_FUNCTION_MAXNAMELEN];
- struct xt_target *watcher;
- } u;
- /* size of data */
- unsigned int watcher_size;
- unsigned char data[0] __attribute__ ((aligned (__alignof__(struct ebt_replace))));
-};
-
-struct ebt_entry_target {
- union {
- char name[EBT_FUNCTION_MAXNAMELEN];
- struct xt_target *target;
- } u;
- /* size of data */
- unsigned int target_size;
- unsigned char data[0] __attribute__ ((aligned (__alignof__(struct ebt_replace))));
-};
-
-#define EBT_STANDARD_TARGET "standard"
-struct ebt_standard_target {
- struct ebt_entry_target target;
- int verdict;
-};
-
-/* one entry */
-struct ebt_entry {
- /* this needs to be the first field */
- unsigned int bitmask;
- unsigned int invflags;
- __be16 ethproto;
- /* the physical in-dev */
- char in[IFNAMSIZ];
- /* the logical in-dev */
- char logical_in[IFNAMSIZ];
- /* the physical out-dev */
- char out[IFNAMSIZ];
- /* the logical out-dev */
- char logical_out[IFNAMSIZ];
- unsigned char sourcemac[ETH_ALEN];
- unsigned char sourcemsk[ETH_ALEN];
- unsigned char destmac[ETH_ALEN];
- unsigned char destmsk[ETH_ALEN];
- /* sizeof ebt_entry + matches */
- unsigned int watchers_offset;
- /* sizeof ebt_entry + matches + watchers */
- unsigned int target_offset;
- /* sizeof ebt_entry + matches + watchers + target */
- unsigned int next_offset;
- unsigned char elems[0] __attribute__ ((aligned (__alignof__(struct ebt_replace))));
-};
-
-/* {g,s}etsockopt numbers */
-#define EBT_BASE_CTL 128
-
-#define EBT_SO_SET_ENTRIES (EBT_BASE_CTL)
-#define EBT_SO_SET_COUNTERS (EBT_SO_SET_ENTRIES+1)
-#define EBT_SO_SET_MAX (EBT_SO_SET_COUNTERS+1)
-
-#define EBT_SO_GET_INFO (EBT_BASE_CTL)
-#define EBT_SO_GET_ENTRIES (EBT_SO_GET_INFO+1)
-#define EBT_SO_GET_INIT_INFO (EBT_SO_GET_ENTRIES+1)
-#define EBT_SO_GET_INIT_ENTRIES (EBT_SO_GET_INIT_INFO+1)
-#define EBT_SO_GET_MAX (EBT_SO_GET_INIT_ENTRIES+1)
-
-#ifdef __KERNEL__
/* return values for match() functions */
#define EBT_MATCH 0
@@ -304,77 +124,4 @@ extern unsigned int ebt_do_table(unsigned int hook, struct sk_buff *skb,
/* True if the target is not a standard target */
#define INVALID_TARGET (info->target < -NUM_STANDARD_TARGETS || info->target >= 0)
-#endif /* __KERNEL__ */
-
-/* blatently stolen from ip_tables.h
- * fn returns 0 to continue iteration */
-#define EBT_MATCH_ITERATE(e, fn, args...) \
-({ \
- unsigned int __i; \
- int __ret = 0; \
- struct ebt_entry_match *__match; \
- \
- for (__i = sizeof(struct ebt_entry); \
- __i < (e)->watchers_offset; \
- __i += __match->match_size + \
- sizeof(struct ebt_entry_match)) { \
- __match = (void *)(e) + __i; \
- \
- __ret = fn(__match , ## args); \
- if (__ret != 0) \
- break; \
- } \
- if (__ret == 0) { \
- if (__i != (e)->watchers_offset) \
- __ret = -EINVAL; \
- } \
- __ret; \
-})
-
-#define EBT_WATCHER_ITERATE(e, fn, args...) \
-({ \
- unsigned int __i; \
- int __ret = 0; \
- struct ebt_entry_watcher *__watcher; \
- \
- for (__i = e->watchers_offset; \
- __i < (e)->target_offset; \
- __i += __watcher->watcher_size + \
- sizeof(struct ebt_entry_watcher)) { \
- __watcher = (void *)(e) + __i; \
- \
- __ret = fn(__watcher , ## args); \
- if (__ret != 0) \
- break; \
- } \
- if (__ret == 0) { \
- if (__i != (e)->target_offset) \
- __ret = -EINVAL; \
- } \
- __ret; \
-})
-
-#define EBT_ENTRY_ITERATE(entries, size, fn, args...) \
-({ \
- unsigned int __i; \
- int __ret = 0; \
- struct ebt_entry *__entry; \
- \
- for (__i = 0; __i < (size);) { \
- __entry = (void *)(entries) + __i; \
- __ret = fn(__entry , ## args); \
- if (__ret != 0) \
- break; \
- if (__entry->bitmask != 0) \
- __i += __entry->next_offset; \
- else \
- __i += sizeof(struct ebt_entries); \
- } \
- if (__ret == 0) { \
- if (__i != (size)) \
- __ret = -EINVAL; \
- } \
- __ret; \
-})
-
#endif
diff --git a/include/linux/netfilter_ipv4/Kbuild b/include/linux/netfilter_ipv4/Kbuild
index 8ba0c5b..e69de29 100644
--- a/include/linux/netfilter_ipv4/Kbuild
+++ b/include/linux/netfilter_ipv4/Kbuild
@@ -1,10 +0,0 @@
-header-y += ip_tables.h
-header-y += ipt_CLUSTERIP.h
-header-y += ipt_ECN.h
-header-y += ipt_LOG.h
-header-y += ipt_REJECT.h
-header-y += ipt_TTL.h
-header-y += ipt_ULOG.h
-header-y += ipt_ah.h
-header-y += ipt_ecn.h
-header-y += ipt_ttl.h
diff --git a/include/linux/netfilter_ipv4/ip_tables.h b/include/linux/netfilter_ipv4/ip_tables.h
index db79231..901e84d 100644
--- a/include/linux/netfilter_ipv4/ip_tables.h
+++ b/include/linux/netfilter_ipv4/ip_tables.h
@@ -11,230 +11,17 @@
* flags are stored in host byte order (of course).
* Port numbers are stored in HOST byte order.
*/
-
#ifndef _IPTABLES_H
#define _IPTABLES_H
-#ifdef __KERNEL__
#include <linux/if.h>
#include <linux/in.h>
#include <linux/ip.h>
#include <linux/skbuff.h>
-#endif
-#include <linux/types.h>
-#include <linux/compiler.h>
-#include <linux/netfilter_ipv4.h>
-
-#include <linux/netfilter/x_tables.h>
-
-#ifndef __KERNEL__
-#define IPT_FUNCTION_MAXNAMELEN XT_FUNCTION_MAXNAMELEN
-#define IPT_TABLE_MAXNAMELEN XT_TABLE_MAXNAMELEN
-#define ipt_match xt_match
-#define ipt_target xt_target
-#define ipt_table xt_table
-#define ipt_get_revision xt_get_revision
-#define ipt_entry_match xt_entry_match
-#define ipt_entry_target xt_entry_target
-#define ipt_standard_target xt_standard_target
-#define ipt_error_target xt_error_target
-#define ipt_counters xt_counters
-#define IPT_CONTINUE XT_CONTINUE
-#define IPT_RETURN XT_RETURN
-
-/* This group is older than old (iptables < v1.4.0-rc1~89) */
-#include <linux/netfilter/xt_tcpudp.h>
-#define ipt_udp xt_udp
-#define ipt_tcp xt_tcp
-#define IPT_TCP_INV_SRCPT XT_TCP_INV_SRCPT
-#define IPT_TCP_INV_DSTPT XT_TCP_INV_DSTPT
-#define IPT_TCP_INV_FLAGS XT_TCP_INV_FLAGS
-#define IPT_TCP_INV_OPTION XT_TCP_INV_OPTION
-#define IPT_TCP_INV_MASK XT_TCP_INV_MASK
-#define IPT_UDP_INV_SRCPT XT_UDP_INV_SRCPT
-#define IPT_UDP_INV_DSTPT XT_UDP_INV_DSTPT
-#define IPT_UDP_INV_MASK XT_UDP_INV_MASK
-
-/* The argument to IPT_SO_ADD_COUNTERS. */
-#define ipt_counters_info xt_counters_info
-/* Standard return verdict, or do jump. */
-#define IPT_STANDARD_TARGET XT_STANDARD_TARGET
-/* Error verdict. */
-#define IPT_ERROR_TARGET XT_ERROR_TARGET
-
-/* fn returns 0 to continue iteration */
-#define IPT_MATCH_ITERATE(e, fn, args...) \
- XT_MATCH_ITERATE(struct ipt_entry, e, fn, ## args)
-
-/* fn returns 0 to continue iteration */
-#define IPT_ENTRY_ITERATE(entries, size, fn, args...) \
- XT_ENTRY_ITERATE(struct ipt_entry, entries, size, fn, ## args)
-#endif
-
-/* Yes, Virginia, you have to zero the padding. */
-struct ipt_ip {
- /* Source and destination IP addr */
- struct in_addr src, dst;
- /* Mask for src and dest IP addr */
- struct in_addr smsk, dmsk;
- char iniface[IFNAMSIZ], outiface[IFNAMSIZ];
- unsigned char iniface_mask[IFNAMSIZ], outiface_mask[IFNAMSIZ];
-
- /* Protocol, 0 = ANY */
- __u16 proto;
-
- /* Flags word */
- __u8 flags;
- /* Inverse flags */
- __u8 invflags;
-};
-
-/* Values for "flag" field in struct ipt_ip (general ip structure). */
-#define IPT_F_FRAG 0x01 /* Set if rule is a fragment rule */
-#define IPT_F_GOTO 0x02 /* Set if jump is a goto */
-#define IPT_F_MASK 0x03 /* All possible flag bits mask. */
-
-/* Values for "inv" field in struct ipt_ip. */
-#define IPT_INV_VIA_IN 0x01 /* Invert the sense of IN IFACE. */
-#define IPT_INV_VIA_OUT 0x02 /* Invert the sense of OUT IFACE */
-#define IPT_INV_TOS 0x04 /* Invert the sense of TOS. */
-#define IPT_INV_SRCIP 0x08 /* Invert the sense of SRC IP. */
-#define IPT_INV_DSTIP 0x10 /* Invert the sense of DST OP. */
-#define IPT_INV_FRAG 0x20 /* Invert the sense of FRAG. */
-#define IPT_INV_PROTO XT_INV_PROTO
-#define IPT_INV_MASK 0x7F /* All possible flag bits mask. */
-
-/* This structure defines each of the firewall rules. Consists of 3
- parts which are 1) general IP header stuff 2) match specific
- stuff 3) the target to perform if the rule matches */
-struct ipt_entry {
- struct ipt_ip ip;
-
- /* Mark with fields that we care about. */
- unsigned int nfcache;
-
- /* Size of ipt_entry + matches */
- __u16 target_offset;
- /* Size of ipt_entry + matches + target */
- __u16 next_offset;
-
- /* Back pointer */
- unsigned int comefrom;
-
- /* Packet and byte counters. */
- struct xt_counters counters;
-
- /* The matches (if any), then the target. */
- unsigned char elems[0];
-};
-
-/*
- * New IP firewall options for [gs]etsockopt at the RAW IP level.
- * Unlike BSD Linux inherits IP options so you don't have to use a raw
- * socket for this. Instead we check rights in the calls.
- *
- * ATTENTION: check linux/in.h before adding new number here.
- */
-#define IPT_BASE_CTL 64
-
-#define IPT_SO_SET_REPLACE (IPT_BASE_CTL)
-#define IPT_SO_SET_ADD_COUNTERS (IPT_BASE_CTL + 1)
-#define IPT_SO_SET_MAX IPT_SO_SET_ADD_COUNTERS
-
-#define IPT_SO_GET_INFO (IPT_BASE_CTL)
-#define IPT_SO_GET_ENTRIES (IPT_BASE_CTL + 1)
-#define IPT_SO_GET_REVISION_MATCH (IPT_BASE_CTL + 2)
-#define IPT_SO_GET_REVISION_TARGET (IPT_BASE_CTL + 3)
-#define IPT_SO_GET_MAX IPT_SO_GET_REVISION_TARGET
-
-/* ICMP matching stuff */
-struct ipt_icmp {
- __u8 type; /* type to match */
- __u8 code[2]; /* range of code */
- __u8 invflags; /* Inverse flags */
-};
-
-/* Values for "inv" field for struct ipt_icmp. */
-#define IPT_ICMP_INV 0x01 /* Invert the sense of type/code test */
-
-/* The argument to IPT_SO_GET_INFO */
-struct ipt_getinfo {
- /* Which table: caller fills this in. */
- char name[XT_TABLE_MAXNAMELEN];
-
- /* Kernel fills these in. */
- /* Which hook entry points are valid: bitmask */
- unsigned int valid_hooks;
-
- /* Hook entry points: one per netfilter hook. */
- unsigned int hook_entry[NF_INET_NUMHOOKS];
-
- /* Underflow points. */
- unsigned int underflow[NF_INET_NUMHOOKS];
-
- /* Number of entries */
- unsigned int num_entries;
-
- /* Size of entries. */
- unsigned int size;
-};
-
-/* The argument to IPT_SO_SET_REPLACE. */
-struct ipt_replace {
- /* Which table. */
- char name[XT_TABLE_MAXNAMELEN];
-
- /* Which hook entry points are valid: bitmask. You can't
- change this. */
- unsigned int valid_hooks;
-
- /* Number of entries */
- unsigned int num_entries;
-
- /* Total size of new entries */
- unsigned int size;
-
- /* Hook entry points. */
- unsigned int hook_entry[NF_INET_NUMHOOKS];
-
- /* Underflow points. */
- unsigned int underflow[NF_INET_NUMHOOKS];
-
- /* Information about old entries: */
- /* Number of counters (must be equal to current number of entries). */
- unsigned int num_counters;
- /* The old entries' counters. */
- struct xt_counters __user *counters;
-
- /* The entries (hang off end: not really an array). */
- struct ipt_entry entries[0];
-};
-
-/* The argument to IPT_SO_GET_ENTRIES. */
-struct ipt_get_entries {
- /* Which table: user fills this in. */
- char name[XT_TABLE_MAXNAMELEN];
-
- /* User fills this in: total entry size. */
- unsigned int size;
-
- /* The entries. */
- struct ipt_entry entrytable[0];
-};
-
-/* Helper functions */
-static __inline__ struct xt_entry_target *
-ipt_get_target(struct ipt_entry *e)
-{
- return (void *)e + e->target_offset;
-}
-
-/*
- * Main firewall chains definitions and global var's definitions.
- */
-#ifdef __KERNEL__
#include <linux/init.h>
+#include <uapi/linux/netfilter_ipv4/ip_tables.h>
+
extern void ipt_init(void) __init;
extern struct xt_table *ipt_register_table(struct net *net,
@@ -303,5 +90,4 @@ compat_ipt_get_target(struct compat_ipt_entry *e)
}
#endif /* CONFIG_COMPAT */
-#endif /*__KERNEL__*/
#endif /* _IPTABLES_H */
diff --git a/include/linux/netfilter_ipv6/Kbuild b/include/linux/netfilter_ipv6/Kbuild
index b88c005..e69de29 100644
--- a/include/linux/netfilter_ipv6/Kbuild
+++ b/include/linux/netfilter_ipv6/Kbuild
@@ -1,12 +0,0 @@
-header-y += ip6_tables.h
-header-y += ip6t_HL.h
-header-y += ip6t_LOG.h
-header-y += ip6t_NPT.h
-header-y += ip6t_REJECT.h
-header-y += ip6t_ah.h
-header-y += ip6t_frag.h
-header-y += ip6t_hl.h
-header-y += ip6t_ipv6header.h
-header-y += ip6t_mh.h
-header-y += ip6t_opts.h
-header-y += ip6t_rt.h
diff --git a/include/linux/netfilter_ipv6/ip6_tables.h b/include/linux/netfilter_ipv6/ip6_tables.h
index 08c2cbb..5f84c62 100644
--- a/include/linux/netfilter_ipv6/ip6_tables.h
+++ b/include/linux/netfilter_ipv6/ip6_tables.h
@@ -11,268 +11,17 @@
* flags are stored in host byte order (of course).
* Port numbers are stored in HOST byte order.
*/
-
#ifndef _IP6_TABLES_H
#define _IP6_TABLES_H
-#ifdef __KERNEL__
#include <linux/if.h>
#include <linux/in6.h>
#include <linux/ipv6.h>
#include <linux/skbuff.h>
-#endif
-#include <linux/types.h>
-#include <linux/compiler.h>
-#include <linux/netfilter_ipv6.h>
-
-#include <linux/netfilter/x_tables.h>
-
-#ifndef __KERNEL__
-#define IP6T_FUNCTION_MAXNAMELEN XT_FUNCTION_MAXNAMELEN
-#define IP6T_TABLE_MAXNAMELEN XT_TABLE_MAXNAMELEN
-#define ip6t_match xt_match
-#define ip6t_target xt_target
-#define ip6t_table xt_table
-#define ip6t_get_revision xt_get_revision
-#define ip6t_entry_match xt_entry_match
-#define ip6t_entry_target xt_entry_target
-#define ip6t_standard_target xt_standard_target
-#define ip6t_error_target xt_error_target
-#define ip6t_counters xt_counters
-#define IP6T_CONTINUE XT_CONTINUE
-#define IP6T_RETURN XT_RETURN
-
-/* Pre-iptables-1.4.0 */
-#include <linux/netfilter/xt_tcpudp.h>
-#define ip6t_tcp xt_tcp
-#define ip6t_udp xt_udp
-#define IP6T_TCP_INV_SRCPT XT_TCP_INV_SRCPT
-#define IP6T_TCP_INV_DSTPT XT_TCP_INV_DSTPT
-#define IP6T_TCP_INV_FLAGS XT_TCP_INV_FLAGS
-#define IP6T_TCP_INV_OPTION XT_TCP_INV_OPTION
-#define IP6T_TCP_INV_MASK XT_TCP_INV_MASK
-#define IP6T_UDP_INV_SRCPT XT_UDP_INV_SRCPT
-#define IP6T_UDP_INV_DSTPT XT_UDP_INV_DSTPT
-#define IP6T_UDP_INV_MASK XT_UDP_INV_MASK
-
-#define ip6t_counters_info xt_counters_info
-#define IP6T_STANDARD_TARGET XT_STANDARD_TARGET
-#define IP6T_ERROR_TARGET XT_ERROR_TARGET
-#define IP6T_MATCH_ITERATE(e, fn, args...) \
- XT_MATCH_ITERATE(struct ip6t_entry, e, fn, ## args)
-#define IP6T_ENTRY_ITERATE(entries, size, fn, args...) \
- XT_ENTRY_ITERATE(struct ip6t_entry, entries, size, fn, ## args)
-#endif
-
-/* Yes, Virginia, you have to zero the padding. */
-struct ip6t_ip6 {
- /* Source and destination IP6 addr */
- struct in6_addr src, dst;
- /* Mask for src and dest IP6 addr */
- struct in6_addr smsk, dmsk;
- char iniface[IFNAMSIZ], outiface[IFNAMSIZ];
- unsigned char iniface_mask[IFNAMSIZ], outiface_mask[IFNAMSIZ];
-
- /* Upper protocol number
- * - The allowed value is 0 (any) or protocol number of last parsable
- * header, which is 50 (ESP), 59 (No Next Header), 135 (MH), or
- * the non IPv6 extension headers.
- * - The protocol numbers of IPv6 extension headers except of ESP and
- * MH do not match any packets.
- * - You also need to set IP6T_FLAGS_PROTO to "flags" to check protocol.
- */
- __u16 proto;
- /* TOS to match iff flags & IP6T_F_TOS */
- __u8 tos;
-
- /* Flags word */
- __u8 flags;
- /* Inverse flags */
- __u8 invflags;
-};
-
-/* Values for "flag" field in struct ip6t_ip6 (general ip6 structure). */
-#define IP6T_F_PROTO 0x01 /* Set if rule cares about upper
- protocols */
-#define IP6T_F_TOS 0x02 /* Match the TOS. */
-#define IP6T_F_GOTO 0x04 /* Set if jump is a goto */
-#define IP6T_F_MASK 0x07 /* All possible flag bits mask. */
-
-/* Values for "inv" field in struct ip6t_ip6. */
-#define IP6T_INV_VIA_IN 0x01 /* Invert the sense of IN IFACE. */
-#define IP6T_INV_VIA_OUT 0x02 /* Invert the sense of OUT IFACE */
-#define IP6T_INV_TOS 0x04 /* Invert the sense of TOS. */
-#define IP6T_INV_SRCIP 0x08 /* Invert the sense of SRC IP. */
-#define IP6T_INV_DSTIP 0x10 /* Invert the sense of DST OP. */
-#define IP6T_INV_FRAG 0x20 /* Invert the sense of FRAG. */
-#define IP6T_INV_PROTO XT_INV_PROTO
-#define IP6T_INV_MASK 0x7F /* All possible flag bits mask. */
-
-/* This structure defines each of the firewall rules. Consists of 3
- parts which are 1) general IP header stuff 2) match specific
- stuff 3) the target to perform if the rule matches */
-struct ip6t_entry {
- struct ip6t_ip6 ipv6;
-
- /* Mark with fields that we care about. */
- unsigned int nfcache;
-
- /* Size of ipt_entry + matches */
- __u16 target_offset;
- /* Size of ipt_entry + matches + target */
- __u16 next_offset;
-
- /* Back pointer */
- unsigned int comefrom;
-
- /* Packet and byte counters. */
- struct xt_counters counters;
-
- /* The matches (if any), then the target. */
- unsigned char elems[0];
-};
-
-/* Standard entry */
-struct ip6t_standard {
- struct ip6t_entry entry;
- struct xt_standard_target target;
-};
-
-struct ip6t_error {
- struct ip6t_entry entry;
- struct xt_error_target target;
-};
-
-#define IP6T_ENTRY_INIT(__size) \
-{ \
- .target_offset = sizeof(struct ip6t_entry), \
- .next_offset = (__size), \
-}
-
-#define IP6T_STANDARD_INIT(__verdict) \
-{ \
- .entry = IP6T_ENTRY_INIT(sizeof(struct ip6t_standard)), \
- .target = XT_TARGET_INIT(XT_STANDARD_TARGET, \
- sizeof(struct xt_standard_target)), \
- .target.verdict = -(__verdict) - 1, \
-}
-
-#define IP6T_ERROR_INIT \
-{ \
- .entry = IP6T_ENTRY_INIT(sizeof(struct ip6t_error)), \
- .target = XT_TARGET_INIT(XT_ERROR_TARGET, \
- sizeof(struct xt_error_target)), \
- .target.errorname = "ERROR", \
-}
-
-/*
- * New IP firewall options for [gs]etsockopt at the RAW IP level.
- * Unlike BSD Linux inherits IP options so you don't have to use
- * a raw socket for this. Instead we check rights in the calls.
- *
- * ATTENTION: check linux/in6.h before adding new number here.
- */
-#define IP6T_BASE_CTL 64
-
-#define IP6T_SO_SET_REPLACE (IP6T_BASE_CTL)
-#define IP6T_SO_SET_ADD_COUNTERS (IP6T_BASE_CTL + 1)
-#define IP6T_SO_SET_MAX IP6T_SO_SET_ADD_COUNTERS
-
-#define IP6T_SO_GET_INFO (IP6T_BASE_CTL)
-#define IP6T_SO_GET_ENTRIES (IP6T_BASE_CTL + 1)
-#define IP6T_SO_GET_REVISION_MATCH (IP6T_BASE_CTL + 4)
-#define IP6T_SO_GET_REVISION_TARGET (IP6T_BASE_CTL + 5)
-#define IP6T_SO_GET_MAX IP6T_SO_GET_REVISION_TARGET
-
-/* ICMP matching stuff */
-struct ip6t_icmp {
- __u8 type; /* type to match */
- __u8 code[2]; /* range of code */
- __u8 invflags; /* Inverse flags */
-};
-
-/* Values for "inv" field for struct ipt_icmp. */
-#define IP6T_ICMP_INV 0x01 /* Invert the sense of type/code test */
-
-/* The argument to IP6T_SO_GET_INFO */
-struct ip6t_getinfo {
- /* Which table: caller fills this in. */
- char name[XT_TABLE_MAXNAMELEN];
-
- /* Kernel fills these in. */
- /* Which hook entry points are valid: bitmask */
- unsigned int valid_hooks;
-
- /* Hook entry points: one per netfilter hook. */
- unsigned int hook_entry[NF_INET_NUMHOOKS];
-
- /* Underflow points. */
- unsigned int underflow[NF_INET_NUMHOOKS];
-
- /* Number of entries */
- unsigned int num_entries;
-
- /* Size of entries. */
- unsigned int size;
-};
-
-/* The argument to IP6T_SO_SET_REPLACE. */
-struct ip6t_replace {
- /* Which table. */
- char name[XT_TABLE_MAXNAMELEN];
-
- /* Which hook entry points are valid: bitmask. You can't
- change this. */
- unsigned int valid_hooks;
-
- /* Number of entries */
- unsigned int num_entries;
-
- /* Total size of new entries */
- unsigned int size;
-
- /* Hook entry points. */
- unsigned int hook_entry[NF_INET_NUMHOOKS];
-
- /* Underflow points. */
- unsigned int underflow[NF_INET_NUMHOOKS];
-
- /* Information about old entries: */
- /* Number of counters (must be equal to current number of entries). */
- unsigned int num_counters;
- /* The old entries' counters. */
- struct xt_counters __user *counters;
-
- /* The entries (hang off end: not really an array). */
- struct ip6t_entry entries[0];
-};
-
-/* The argument to IP6T_SO_GET_ENTRIES. */
-struct ip6t_get_entries {
- /* Which table: user fills this in. */
- char name[XT_TABLE_MAXNAMELEN];
-
- /* User fills this in: total entry size. */
- unsigned int size;
-
- /* The entries. */
- struct ip6t_entry entrytable[0];
-};
-
-/* Helper functions */
-static __inline__ struct xt_entry_target *
-ip6t_get_target(struct ip6t_entry *e)
-{
- return (void *)e + e->target_offset;
-}
-
-/*
- * Main firewall chains definitions and global var's definitions.
- */
-
-#ifdef __KERNEL__
#include <linux/init.h>
+#include <uapi/linux/netfilter_ipv6/ip6_tables.h>
+
extern void ip6t_init(void) __init;
extern void *ip6t_alloc_initial_table(const struct xt_table *);
@@ -327,5 +76,4 @@ compat_ip6t_get_target(struct compat_ip6t_entry *e)
}
#endif /* CONFIG_COMPAT */
-#endif /*__KERNEL__*/
#endif /* _IP6_TABLES_H */
diff --git a/include/linux/netlink.h b/include/linux/netlink.h
index f80c56a..6d3af05c 100644
--- a/include/linux/netlink.h
+++ b/include/linux/netlink.h
@@ -245,6 +245,8 @@ struct netlink_callback {
struct netlink_callback *cb);
int (*done)(struct netlink_callback *cb);
void *data;
+ /* the module that dump function belong to */
+ struct module *module;
u16 family;
u16 min_dump_alloc;
unsigned int prev_seq, seq;
@@ -262,14 +264,24 @@ __nlmsg_put(struct sk_buff *skb, u32 portid, u32 seq, int type, int len, int fla
struct netlink_dump_control {
int (*dump)(struct sk_buff *skb, struct netlink_callback *);
- int (*done)(struct netlink_callback*);
+ int (*done)(struct netlink_callback *);
void *data;
+ struct module *module;
u16 min_dump_alloc;
};
-extern int netlink_dump_start(struct sock *ssk, struct sk_buff *skb,
- const struct nlmsghdr *nlh,
- struct netlink_dump_control *control);
+extern int __netlink_dump_start(struct sock *ssk, struct sk_buff *skb,
+ const struct nlmsghdr *nlh,
+ struct netlink_dump_control *control);
+static inline int netlink_dump_start(struct sock *ssk, struct sk_buff *skb,
+ const struct nlmsghdr *nlh,
+ struct netlink_dump_control *control)
+{
+ if (!control->module)
+ control->module = THIS_MODULE;
+
+ return __netlink_dump_start(ssk, skb, nlh, control);
+}
#endif /* __KERNEL__ */
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
index 4b03f56..334a2f5 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -81,12 +81,16 @@ struct nfs_access_entry {
int mask;
};
+struct nfs_lockowner {
+ fl_owner_t l_owner;
+ pid_t l_pid;
+};
+
struct nfs_lock_context {
atomic_t count;
struct list_head list;
struct nfs_open_context *open_context;
- fl_owner_t lockowner;
- pid_t pid;
+ struct nfs_lockowner lockowner;
};
struct nfs4_state;
@@ -99,6 +103,7 @@ struct nfs_open_context {
unsigned long flags;
#define NFS_CONTEXT_ERROR_WRITE (0)
+#define NFS_CONTEXT_RESEND_WRITES (1)
int error;
struct list_head list;
@@ -355,6 +360,8 @@ extern int nfs_refresh_inode(struct inode *, struct nfs_fattr *);
extern int nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr);
extern int nfs_post_op_update_inode_force_wcc(struct inode *inode, struct nfs_fattr *fattr);
extern int nfs_getattr(struct vfsmount *, struct dentry *, struct kstat *);
+extern void nfs_access_add_cache(struct inode *, struct nfs_access_entry *);
+extern void nfs_access_set_mask(struct nfs_access_entry *, u32);
extern int nfs_permission(struct inode *, int);
extern int nfs_open(struct inode *, struct file *);
extern int nfs_release(struct inode *, struct file *);
diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h
index 310c63c..a9e76ee 100644
--- a/include/linux/nfs_fs_sb.h
+++ b/include/linux/nfs_fs_sb.h
@@ -39,6 +39,7 @@ struct nfs_client {
unsigned long cl_flags; /* behavior switches */
#define NFS_CS_NORESVPORT 0 /* - use ephemeral src port */
#define NFS_CS_DISCRTRY 1 /* - disconnect on RPC retry */
+#define NFS_CS_MIGRATION 2 /* - transparent state migr */
struct sockaddr_storage cl_addr; /* server identifier */
size_t cl_addrlen;
char * cl_hostname; /* hostname of server */
@@ -81,6 +82,7 @@ struct nfs_client {
/* The flags used for obtaining the clientid during EXCHANGE_ID */
u32 cl_exchange_flags;
struct nfs4_session *cl_session; /* shared session */
+ bool cl_preserve_clid;
struct nfs41_server_owner *cl_serverowner;
struct nfs41_server_scope *cl_serverscope;
struct nfs41_impl_id *cl_implid;
@@ -125,6 +127,7 @@ struct nfs_server {
unsigned int namelen;
unsigned int options; /* extra options enabled by mount */
#define NFS_OPTION_FSCACHE 0x00000001 /* - local caching enabled */
+#define NFS_OPTION_MIGRATION 0x00000002 /* - NFSv4 migration enabled */
struct nfs_fsid fsid;
__u64 maxfilesize; /* maximum file size */
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index be9cf3c..a73ea89 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -251,7 +251,6 @@ struct nfs4_layoutget_res {
struct nfs4_layoutget {
struct nfs4_layoutget_args args;
struct nfs4_layoutget_res res;
- struct pnfs_layout_segment **lsegpp;
gfp_t gfp_flags;
};
@@ -335,6 +334,7 @@ struct nfs_openargs {
struct nfs_seqid * seqid;
int open_flags;
fmode_t fmode;
+ u32 access;
__u64 clientid;
struct stateowner_id id;
union {
@@ -369,6 +369,9 @@ struct nfs_openres {
struct nfs4_string *owner;
struct nfs4_string *group_owner;
struct nfs4_sequence_res seq_res;
+ __u32 access_request;
+ __u32 access_supported;
+ __u32 access_result;
};
/*
diff --git a/include/linux/pageblock-flags.h b/include/linux/pageblock-flags.h
index eed27f4..be655e4 100644
--- a/include/linux/pageblock-flags.h
+++ b/include/linux/pageblock-flags.h
@@ -71,13 +71,13 @@ void set_pageblock_flags_group(struct page *page, unsigned long flags,
#ifdef CONFIG_COMPACTION
#define get_pageblock_skip(page) \
get_pageblock_flags_group(page, PB_migrate_skip, \
- PB_migrate_skip + 1)
+ PB_migrate_skip)
#define clear_pageblock_skip(page) \
set_pageblock_flags_group(page, 0, PB_migrate_skip, \
- PB_migrate_skip + 1)
+ PB_migrate_skip)
#define set_pageblock_skip(page) \
set_pageblock_flags_group(page, 1, PB_migrate_skip, \
- PB_migrate_skip + 1)
+ PB_migrate_skip)
#endif /* CONFIG_COMPACTION */
#define get_pageblock_flags(page) \
diff --git a/include/linux/percpu-rwsem.h b/include/linux/percpu-rwsem.h
new file mode 100644
index 0000000..cf80f7e
--- /dev/null
+++ b/include/linux/percpu-rwsem.h
@@ -0,0 +1,89 @@
+#ifndef _LINUX_PERCPU_RWSEM_H
+#define _LINUX_PERCPU_RWSEM_H
+
+#include <linux/mutex.h>
+#include <linux/percpu.h>
+#include <linux/rcupdate.h>
+#include <linux/delay.h>
+
+struct percpu_rw_semaphore {
+ unsigned __percpu *counters;
+ bool locked;
+ struct mutex mtx;
+};
+
+static inline void percpu_down_read(struct percpu_rw_semaphore *p)
+{
+ rcu_read_lock();
+ if (unlikely(p->locked)) {
+ rcu_read_unlock();
+ mutex_lock(&p->mtx);
+ this_cpu_inc(*p->counters);
+ mutex_unlock(&p->mtx);
+ return;
+ }
+ this_cpu_inc(*p->counters);
+ rcu_read_unlock();
+}
+
+static inline void percpu_up_read(struct percpu_rw_semaphore *p)
+{
+ /*
+ * On X86, write operation in this_cpu_dec serves as a memory unlock
+ * barrier (i.e. memory accesses may be moved before the write, but
+ * no memory accesses are moved past the write).
+ * On other architectures this may not be the case, so we need smp_mb()
+ * there.
+ */
+#if defined(CONFIG_X86) && (!defined(CONFIG_X86_PPRO_FENCE) && !defined(CONFIG_X86_OOSTORE))
+ barrier();
+#else
+ smp_mb();
+#endif
+ this_cpu_dec(*p->counters);
+}
+
+static inline unsigned __percpu_count(unsigned __percpu *counters)
+{
+ unsigned total = 0;
+ int cpu;
+
+ for_each_possible_cpu(cpu)
+ total += ACCESS_ONCE(*per_cpu_ptr(counters, cpu));
+
+ return total;
+}
+
+static inline void percpu_down_write(struct percpu_rw_semaphore *p)
+{
+ mutex_lock(&p->mtx);
+ p->locked = true;
+ synchronize_rcu();
+ while (__percpu_count(p->counters))
+ msleep(1);
+ smp_rmb(); /* paired with smp_mb() in percpu_sem_up_read() */
+}
+
+static inline void percpu_up_write(struct percpu_rw_semaphore *p)
+{
+ p->locked = false;
+ mutex_unlock(&p->mtx);
+}
+
+static inline int percpu_init_rwsem(struct percpu_rw_semaphore *p)
+{
+ p->counters = alloc_percpu(unsigned);
+ if (unlikely(!p->counters))
+ return -ENOMEM;
+ p->locked = false;
+ mutex_init(&p->mtx);
+ return 0;
+}
+
+static inline void percpu_free_rwsem(struct percpu_rw_semaphore *p)
+{
+ free_percpu(p->counters);
+ p->counters = NULL; /* catch use after free bugs */
+}
+
+#endif
diff --git a/include/linux/platform_data/i2c-nomadik.h b/include/linux/platform_data/i2c-nomadik.h
index c2303c3..3a8be9c 100644
--- a/include/linux/platform_data/i2c-nomadik.h
+++ b/include/linux/platform_data/i2c-nomadik.h
@@ -28,7 +28,7 @@ enum i2c_freq_mode {
* @sm: speed mode
*/
struct nmk_i2c_controller {
- unsigned long clk_freq;
+ u32 clk_freq;
unsigned short slsu;
unsigned char tft;
unsigned char rft;
diff --git a/include/linux/platform_data/leds-lm3556.h b/include/linux/platform_data/leds-lm3556.h
deleted file mode 100644
index 4b4e7d6..0000000
--- a/include/linux/platform_data/leds-lm3556.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Simple driver for Texas Instruments LM3556 LED Flash driver chip (Rev0x03)
- * Copyright (C) 2012 Texas Instruments
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- */
-
-#ifndef __LINUX_LM3556_H
-#define __LINUX_LM3556_H
-
-#define LM3556_NAME "leds-lm3556"
-
-enum lm3556_pin_polarity {
- PIN_LOW_ACTIVE = 0,
- PIN_HIGH_ACTIVE,
-};
-
-enum lm3556_pin_enable {
- PIN_DISABLED = 0,
- PIN_ENABLED,
-};
-
-enum lm3556_strobe_usuage {
- STROBE_EDGE_DETECT = 0,
- STROBE_LEVEL_DETECT,
-};
-
-enum lm3556_indic_mode {
- INDIC_MODE_INTERNAL = 0,
- INDIC_MODE_EXTERNAL,
-};
-
-struct lm3556_platform_data {
- enum lm3556_pin_enable torch_pin_en;
- enum lm3556_pin_polarity torch_pin_polarity;
-
- enum lm3556_strobe_usuage strobe_usuage;
- enum lm3556_pin_enable strobe_pin_en;
- enum lm3556_pin_polarity strobe_pin_polarity;
-
- enum lm3556_pin_enable tx_pin_en;
- enum lm3556_pin_polarity tx_pin_polarity;
-
- enum lm3556_indic_mode indicator_mode;
-};
-
-#endif /* __LINUX_LM3556_H */
diff --git a/include/linux/platform_data/leds-lm355x.h b/include/linux/platform_data/leds-lm355x.h
new file mode 100644
index 0000000..b88724b
--- /dev/null
+++ b/include/linux/platform_data/leds-lm355x.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2012 Texas Instruments
+ *
+ * License Terms: GNU General Public License v2
+ *
+ * Simple driver for Texas Instruments LM355x LED driver chip
+ *
+ * Author: G.Shark Jeong <gshark.jeong@gmail.com>
+ * Daniel Jeong <daniel.jeong@ti.com>
+ */
+
+#define LM355x_NAME "leds-lm355x"
+#define LM3554_NAME "leds-lm3554"
+#define LM3556_NAME "leds-lm3556"
+
+/* lm3554 : strobe def. on */
+enum lm355x_strobe {
+ LM355x_PIN_STROBE_DISABLE = 0x00,
+ LM355x_PIN_STROBE_ENABLE = 0x01,
+};
+
+enum lm355x_torch {
+ LM355x_PIN_TORCH_DISABLE = 0,
+ LM3554_PIN_TORCH_ENABLE = 0x80,
+ LM3556_PIN_TORCH_ENABLE = 0x10,
+};
+
+enum lm355x_tx2 {
+ LM355x_PIN_TX_DISABLE = 0,
+ LM3554_PIN_TX_ENABLE = 0x20,
+ LM3556_PIN_TX_ENABLE = 0x40,
+};
+
+enum lm355x_ntc {
+ LM355x_PIN_NTC_DISABLE = 0,
+ LM3554_PIN_NTC_ENABLE = 0x08,
+ LM3556_PIN_NTC_ENABLE = 0x80,
+};
+
+enum lm355x_pmode {
+ LM355x_PMODE_DISABLE = 0,
+ LM355x_PMODE_ENABLE = 0x04,
+};
+
+/*
+ * struct lm3554_platform_data
+ * @pin_strobe: strobe input
+ * @pin_torch : input pin
+ * lm3554-tx1/torch/gpio1
+ * lm3556-torch
+ * @pin_tx2 : input pin
+ * lm3554-envm/tx2/gpio2
+ * lm3556-tx pin
+ * @ntc_pin : output pin
+ * lm3554-ledi/ntc
+ * lm3556-temp pin
+ * @pass_mode : pass mode
+ */
+struct lm355x_platform_data {
+ enum lm355x_strobe pin_strobe;
+ enum lm355x_torch pin_tx1;
+ enum lm355x_tx2 pin_tx2;
+ enum lm355x_ntc ntc_pin;
+
+ enum lm355x_pmode pass_mode;
+};
diff --git a/include/linux/platform_data/leds-lm3642.h b/include/linux/platform_data/leds-lm3642.h
new file mode 100644
index 0000000..72d6ee6
--- /dev/null
+++ b/include/linux/platform_data/leds-lm3642.h
@@ -0,0 +1,38 @@
+/*
+* Copyright (C) 2012 Texas Instruments
+*
+* License Terms: GNU General Public License v2
+*
+* Simple driver for Texas Instruments LM3642 LED driver chip
+*
+* Author: G.Shark Jeong <gshark.jeong@gmail.com>
+* Daniel Jeong <daniel.jeong@ti.com>
+*/
+
+#ifndef __LINUX_LM3642_H
+#define __LINUX_LM3642_H
+
+#define LM3642_NAME "leds-lm3642"
+
+enum lm3642_torch_pin_enable {
+ LM3642_TORCH_PIN_DISABLE = 0x00,
+ LM3642_TORCH_PIN_ENABLE = 0x10,
+};
+
+enum lm3642_strobe_pin_enable {
+ LM3642_STROBE_PIN_DISABLE = 0x00,
+ LM3642_STROBE_PIN_ENABLE = 0x20,
+};
+
+enum lm3642_tx_pin_enable {
+ LM3642_TX_PIN_DISABLE = 0x00,
+ LM3642_TX_PIN_ENABLE = 0x40,
+};
+
+struct lm3642_platform_data {
+ enum lm3642_torch_pin_enable torch_pin;
+ enum lm3642_strobe_pin_enable strobe_pin;
+ enum lm3642_tx_pin_enable tx_pin;
+};
+
+#endif /* __LINUX_LM3642_H */
diff --git a/include/linux/platform_data/leds-pca9633.h b/include/linux/platform_data/leds-pca9633.h
new file mode 100644
index 0000000..c5bf29b
--- /dev/null
+++ b/include/linux/platform_data/leds-pca9633.h
@@ -0,0 +1,35 @@
+/*
+ * PCA9633 LED chip driver.
+ *
+ * Copyright 2012 bct electronic 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.
+ *
+ * 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
+ */
+
+#ifndef __LINUX_PCA9633_H
+#define __LINUX_PCA9633_H
+#include <linux/leds.h>
+
+enum pca9633_outdrv {
+ PCA9633_OPEN_DRAIN,
+ PCA9633_TOTEM_POLE, /* aka push-pull */
+};
+
+struct pca9633_platform_data {
+ struct led_platform_data leds;
+ enum pca9633_outdrv outdrv;
+};
+
+#endif /* __LINUX_PCA9633_H*/
diff --git a/include/linux/platform_data/mmp_dma.h b/include/linux/platform_data/mmp_dma.h
new file mode 100644
index 0000000..2a330ec
--- /dev/null
+++ b/include/linux/platform_data/mmp_dma.h
@@ -0,0 +1,19 @@
+/*
+ * MMP Platform DMA Management
+ *
+ * Copyright (c) 2011 Marvell Semiconductors Inc.
+ *
+ * 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 MMP_DMA_H
+#define MMP_DMA_H
+
+struct mmp_dma_platdata {
+ int dma_channels;
+};
+
+#endif /* MMP_DMA_H */
diff --git a/include/linux/platform_data/pxa_sdhci.h b/include/linux/platform_data/pxa_sdhci.h
index 51ad099..59acd98 100644
--- a/include/linux/platform_data/pxa_sdhci.h
+++ b/include/linux/platform_data/pxa_sdhci.h
@@ -49,6 +49,7 @@ struct sdhci_pxa_platdata {
bool ext_cd_gpio_invert;
unsigned int max_speed;
unsigned int host_caps;
+ unsigned int host_caps2;
unsigned int quirks;
unsigned int pm_caps;
};
diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h
index 3db698a..1d24ffa 100644
--- a/include/linux/ptrace.h
+++ b/include/linux/ptrace.h
@@ -401,6 +401,10 @@ static inline void user_single_step_siginfo(struct task_struct *tsk,
#define arch_ptrace_stop(code, info) do { } while (0)
#endif
+#ifndef current_pt_regs
+#define current_pt_regs() task_pt_regs(current)
+#endif
+
extern int task_current_syscall(struct task_struct *target, long *callno,
unsigned long args[6], unsigned int maxargs,
unsigned long *sp, unsigned long *pc);
diff --git a/include/linux/pwm.h b/include/linux/pwm.h
index 21d076c..112b314 100644
--- a/include/linux/pwm.h
+++ b/include/linux/pwm.h
@@ -1,11 +1,13 @@
#ifndef __LINUX_PWM_H
#define __LINUX_PWM_H
+#include <linux/err.h>
#include <linux/of.h>
struct pwm_device;
struct seq_file;
+#if IS_ENABLED(CONFIG_PWM) || IS_ENABLED(CONFIG_HAVE_PWM)
/*
* pwm_request - request a PWM device
*/
@@ -30,10 +32,47 @@ int pwm_enable(struct pwm_device *pwm);
* pwm_disable - stop a PWM output toggling
*/
void pwm_disable(struct pwm_device *pwm);
+#else
+static inline struct pwm_device *pwm_request(int pwm_id, const char *label)
+{
+ return ERR_PTR(-ENODEV);
+}
+
+static inline void pwm_free(struct pwm_device *pwm)
+{
+}
+
+static inline int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
+{
+ return -EINVAL;
+}
+
+static inline int pwm_enable(struct pwm_device *pwm)
+{
+ return -EINVAL;
+}
+
+static inline void pwm_disable(struct pwm_device *pwm)
+{
+}
+#endif
-#ifdef CONFIG_PWM
struct pwm_chip;
+/**
+ * enum pwm_polarity - polarity of a PWM signal
+ * @PWM_POLARITY_NORMAL: a high signal for the duration of the duty-
+ * cycle, followed by a low signal for the remainder of the pulse
+ * period
+ * @PWM_POLARITY_INVERSED: a low signal for the duration of the duty-
+ * cycle, followed by a high signal for the remainder of the pulse
+ * period
+ */
+enum pwm_polarity {
+ PWM_POLARITY_NORMAL,
+ PWM_POLARITY_INVERSED,
+};
+
enum {
PWMF_REQUESTED = 1 << 0,
PWMF_ENABLED = 1 << 1,
@@ -61,11 +100,17 @@ static inline unsigned int pwm_get_period(struct pwm_device *pwm)
return pwm ? pwm->period : 0;
}
+/*
+ * pwm_set_polarity - configure the polarity of a PWM signal
+ */
+int pwm_set_polarity(struct pwm_device *pwm, enum pwm_polarity polarity);
+
/**
* struct pwm_ops - PWM controller operations
* @request: optional hook for requesting a PWM
* @free: optional hook for freeing a PWM
* @config: configure duty cycles and period length for this PWM
+ * @set_polarity: configure the polarity of this PWM
* @enable: enable PWM output toggling
* @disable: disable PWM output toggling
* @dbg_show: optional routine to show contents in debugfs
@@ -79,6 +124,9 @@ struct pwm_ops {
int (*config)(struct pwm_chip *chip,
struct pwm_device *pwm,
int duty_ns, int period_ns);
+ int (*set_polarity)(struct pwm_chip *chip,
+ struct pwm_device *pwm,
+ enum pwm_polarity polarity);
int (*enable)(struct pwm_chip *chip,
struct pwm_device *pwm);
void (*disable)(struct pwm_chip *chip,
@@ -113,6 +161,7 @@ struct pwm_chip {
unsigned int of_pwm_n_cells;
};
+#if IS_ENABLED(CONFIG_PWM)
int pwm_set_chip_data(struct pwm_device *pwm, void *data);
void *pwm_get_chip_data(struct pwm_device *pwm);
@@ -125,6 +174,57 @@ struct pwm_device *pwm_request_from_chip(struct pwm_chip *chip,
struct pwm_device *pwm_get(struct device *dev, const char *consumer);
void pwm_put(struct pwm_device *pwm);
+struct pwm_device *devm_pwm_get(struct device *dev, const char *consumer);
+void devm_pwm_put(struct device *dev, struct pwm_device *pwm);
+#else
+static inline int pwm_set_chip_data(struct pwm_device *pwm, void *data)
+{
+ return -EINVAL;
+}
+
+static inline void *pwm_get_chip_data(struct pwm_device *pwm)
+{
+ return NULL;
+}
+
+static inline int pwmchip_add(struct pwm_chip *chip)
+{
+ return -EINVAL;
+}
+
+static inline int pwmchip_remove(struct pwm_chip *chip)
+{
+ return -EINVAL;
+}
+
+static inline struct pwm_device *pwm_request_from_chip(struct pwm_chip *chip,
+ unsigned int index,
+ const char *label)
+{
+ return ERR_PTR(-ENODEV);
+}
+
+static inline struct pwm_device *pwm_get(struct device *dev,
+ const char *consumer)
+{
+ return ERR_PTR(-ENODEV);
+}
+
+static inline void pwm_put(struct pwm_device *pwm)
+{
+}
+
+static inline struct pwm_device *devm_pwm_get(struct device *dev,
+ const char *consumer)
+{
+ return ERR_PTR(-ENODEV);
+}
+
+static inline void devm_pwm_put(struct device *dev, struct pwm_device *pwm)
+{
+}
+#endif
+
struct pwm_lookup {
struct list_head list;
const char *provider;
@@ -141,8 +241,12 @@ struct pwm_lookup {
.con_id = _con_id, \
}
+#if IS_ENABLED(CONFIG_PWM)
void pwm_add_table(struct pwm_lookup *table, size_t num);
-
+#else
+static inline void pwm_add_table(struct pwm_lookup *table, size_t num)
+{
+}
#endif
#endif /* __LINUX_PWM_H */
diff --git a/include/linux/rio.h b/include/linux/rio.h
index d2dff22..4187da5 100644
--- a/include/linux/rio.h
+++ b/include/linux/rio.h
@@ -63,7 +63,7 @@
*
* 0 RapidIO inbound doorbells
* 1 RapidIO inbound mailboxes
- * 1 RapidIO outbound mailboxes
+ * 2 RapidIO outbound mailboxes
*/
#define RIO_DOORBELL_RESOURCE 0
#define RIO_INB_MBOX_RESOURCE 1
@@ -266,7 +266,6 @@ struct rio_mport {
struct rio_id_table {
u16 start; /* logical minimal id */
- u16 next; /* hint for find */
u32 max; /* max number of IDs in table */
spinlock_t lock;
unsigned long *table;
diff --git a/include/linux/scatterlist.h b/include/linux/scatterlist.h
index 7b600da..4bd6c06 100644
--- a/include/linux/scatterlist.h
+++ b/include/linux/scatterlist.h
@@ -201,6 +201,7 @@ static inline void *sg_virt(struct scatterlist *sg)
return page_address(sg_page(sg)) + sg->offset;
}
+int sg_nents(struct scatterlist *sg);
struct scatterlist *sg_next(struct scatterlist *);
struct scatterlist *sg_last(struct scatterlist *s, unsigned int);
void sg_init_table(struct scatterlist *, unsigned int);
diff --git a/include/linux/sched.h b/include/linux/sched.h
index c2070e9..a83ca58 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -2332,6 +2332,9 @@ extern int do_execve(const char *,
const char __user * const __user *, struct pt_regs *);
extern long do_fork(unsigned long, unsigned long, struct pt_regs *, unsigned long, int __user *, int __user *);
struct task_struct *fork_idle(int);
+#ifdef CONFIG_GENERIC_KERNEL_THREAD
+extern pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
+#endif
extern void set_task_comm(struct task_struct *tsk, char *from);
extern char *get_task_comm(char *to, struct task_struct *tsk);
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index b33a3a1..6a2c34e 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -589,9 +589,6 @@ static inline struct sk_buff *alloc_skb_fclone(unsigned int size,
return __alloc_skb(size, priority, SKB_ALLOC_FCLONE, NUMA_NO_NODE);
}
-extern void skb_recycle(struct sk_buff *skb);
-extern bool skb_recycle_check(struct sk_buff *skb, int skb_size);
-
extern struct sk_buff *skb_morph(struct sk_buff *dst, struct sk_buff *src);
extern int skb_copy_ubufs(struct sk_buff *skb, gfp_t gfp_mask);
extern struct sk_buff *skb_clone(struct sk_buff *skb,
@@ -2645,27 +2642,6 @@ static inline void skb_checksum_none_assert(const struct sk_buff *skb)
bool skb_partial_csum_set(struct sk_buff *skb, u16 start, u16 off);
-static inline bool skb_is_recycleable(const struct sk_buff *skb, int skb_size)
-{
- if (irqs_disabled())
- return false;
-
- if (skb_shinfo(skb)->tx_flags & SKBTX_DEV_ZEROCOPY)
- return false;
-
- if (skb_is_nonlinear(skb) || skb->fclone != SKB_FCLONE_UNAVAILABLE)
- return false;
-
- skb_size = SKB_DATA_ALIGN(skb_size + NET_SKB_PAD);
- if (skb_end_offset(skb) < skb_size)
- return false;
-
- if (skb_shared(skb) || skb_cloned(skb))
- return false;
-
- return true;
-}
-
/**
* skb_head_is_locked - Determine if the skb->head is locked down
* @skb: skb to check
diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h
index 523547e..34206b8 100644
--- a/include/linux/sunrpc/clnt.h
+++ b/include/linux/sunrpc/clnt.h
@@ -130,6 +130,8 @@ struct rpc_clnt *rpc_bind_new_program(struct rpc_clnt *,
const struct rpc_program *, u32);
void rpc_task_reset_client(struct rpc_task *task, struct rpc_clnt *clnt);
struct rpc_clnt *rpc_clone_client(struct rpc_clnt *);
+struct rpc_clnt *rpc_clone_client_set_auth(struct rpc_clnt *,
+ rpc_authflavor_t);
void rpc_shutdown_client(struct rpc_clnt *);
void rpc_release_client(struct rpc_clnt *);
void rpc_task_release_client(struct rpc_task *);
diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h
index bf8c49f..951cb9b 100644
--- a/include/linux/sunrpc/xprt.h
+++ b/include/linux/sunrpc/xprt.h
@@ -173,8 +173,7 @@ struct rpc_xprt {
unsigned int min_reqs; /* min number of slots */
atomic_t num_reqs; /* total slots */
unsigned long state; /* transport state */
- unsigned char shutdown : 1, /* being shut down */
- resvport : 1; /* use a reserved port */
+ unsigned char resvport : 1; /* use a reserved port */
unsigned int swapper; /* we're swapping over this
transport */
unsigned int bind_index; /* bind function index */
diff --git a/include/linux/tc_act/Kbuild b/include/linux/tc_act/Kbuild
index 67b501c3..e69de29 100644
--- a/include/linux/tc_act/Kbuild
+++ b/include/linux/tc_act/Kbuild
@@ -1,7 +0,0 @@
-header-y += tc_gact.h
-header-y += tc_ipt.h
-header-y += tc_mirred.h
-header-y += tc_pedit.h
-header-y += tc_nat.h
-header-y += tc_skbedit.h
-header-y += tc_csum.h
diff --git a/include/linux/tc_ematch/Kbuild b/include/linux/tc_ematch/Kbuild
index 4a58a1c..e69de29 100644
--- a/include/linux/tc_ematch/Kbuild
+++ b/include/linux/tc_ematch/Kbuild
@@ -1,4 +0,0 @@
-header-y += tc_em_cmp.h
-header-y += tc_em_meta.h
-header-y += tc_em_nbyte.h
-header-y += tc_em_text.h
diff --git a/include/mtd/Kbuild b/include/mtd/Kbuild
index 192f8fb..e69de29 100644
--- a/include/mtd/Kbuild
+++ b/include/mtd/Kbuild
@@ -1,5 +0,0 @@
-header-y += inftl-user.h
-header-y += mtd-abi.h
-header-y += mtd-user.h
-header-y += nftl-user.h
-header-y += ubi-user.h
diff --git a/include/net/flow.h b/include/net/flow.h
index e1dd508..628e11b 100644
--- a/include/net/flow.h
+++ b/include/net/flow.h
@@ -21,6 +21,7 @@ struct flowi_common {
__u8 flowic_flags;
#define FLOWI_FLAG_ANYSRC 0x01
#define FLOWI_FLAG_CAN_SLEEP 0x02
+#define FLOWI_FLAG_KNOWN_NH 0x04
__u32 flowic_secid;
};
diff --git a/include/net/route.h b/include/net/route.h
index da22243..bc40b63 100644
--- a/include/net/route.h
+++ b/include/net/route.h
@@ -48,7 +48,8 @@ struct rtable {
int rt_genid;
unsigned int rt_flags;
__u16 rt_type;
- __u16 rt_is_input;
+ __u8 rt_is_input;
+ __u8 rt_uses_gateway;
int rt_iif;
diff --git a/include/rdma/rdma_netlink.h b/include/rdma/rdma_netlink.h
index 3c5363a..bd3d8b2 100644
--- a/include/rdma/rdma_netlink.h
+++ b/include/rdma/rdma_netlink.h
@@ -39,6 +39,7 @@ struct rdma_cm_id_stats {
struct ibnl_client_cbs {
int (*dump)(struct sk_buff *skb, struct netlink_callback *nlcb);
+ struct module *module;
};
int ibnl_init(void);
diff --git a/include/target/target_core_backend.h b/include/target/target_core_backend.h
index 941c84bf..2acd540 100644
--- a/include/target/target_core_backend.h
+++ b/include/target/target_core_backend.h
@@ -13,9 +13,6 @@ struct se_subsystem_api {
u8 transport_type;
- unsigned int fua_write_emulated : 1;
- unsigned int write_cache_emulated : 1;
-
int (*attach_hba)(struct se_hba *, u32);
void (*detach_hba)(struct se_hba *);
int (*pmode_enable_hba)(struct se_hba *, unsigned long);
diff --git a/include/target/target_core_fabric.h b/include/target/target_core_fabric.h
index 69fb3cfd..81ddb4a 100644
--- a/include/target/target_core_fabric.h
+++ b/include/target/target_core_fabric.h
@@ -62,8 +62,6 @@ struct target_core_fabric_ops {
int (*queue_data_in)(struct se_cmd *);
int (*queue_status)(struct se_cmd *);
int (*queue_tm_rsp)(struct se_cmd *);
- u16 (*set_fabric_sense_len)(struct se_cmd *, u32);
- u16 (*get_fabric_sense_len)(void);
/*
* fabric module calls for target_core_fabric_configfs.c
*/
@@ -102,6 +100,9 @@ void transport_init_se_cmd(struct se_cmd *, struct target_core_fabric_ops *,
struct se_session *, u32, int, int, unsigned char *);
int transport_lookup_cmd_lun(struct se_cmd *, u32);
int target_setup_cmd_from_cdb(struct se_cmd *, unsigned char *);
+int target_submit_cmd_map_sgls(struct se_cmd *, struct se_session *,
+ unsigned char *, unsigned char *, u32, u32, int, int, int,
+ struct scatterlist *, u32, struct scatterlist *, u32);
int target_submit_cmd(struct se_cmd *, struct se_session *, unsigned char *,
unsigned char *, u32, u32, int, int, int);
int target_submit_tmr(struct se_cmd *se_cmd, struct se_session *se_sess,
diff --git a/include/trace/events/btrfs.h b/include/trace/events/btrfs.h
index 91b91e8..54fab04 100644
--- a/include/trace/events/btrfs.h
+++ b/include/trace/events/btrfs.h
@@ -445,6 +445,7 @@ TRACE_EVENT(btrfs_delayed_tree_ref,
__field( u64, ref_root )
__field( int, level )
__field( int, type )
+ __field( u64, seq )
),
TP_fast_assign(
@@ -455,17 +456,19 @@ TRACE_EVENT(btrfs_delayed_tree_ref,
__entry->ref_root = full_ref->root;
__entry->level = full_ref->level;
__entry->type = ref->type;
+ __entry->seq = ref->seq;
),
TP_printk("bytenr = %llu, num_bytes = %llu, action = %s, "
"parent = %llu(%s), ref_root = %llu(%s), level = %d, "
- "type = %s",
+ "type = %s, seq = %llu",
(unsigned long long)__entry->bytenr,
(unsigned long long)__entry->num_bytes,
show_ref_action(__entry->action),
show_root_type(__entry->parent),
show_root_type(__entry->ref_root),
- __entry->level, show_ref_type(__entry->type))
+ __entry->level, show_ref_type(__entry->type),
+ (unsigned long long)__entry->seq)
);
TRACE_EVENT(btrfs_delayed_data_ref,
@@ -485,6 +488,7 @@ TRACE_EVENT(btrfs_delayed_data_ref,
__field( u64, owner )
__field( u64, offset )
__field( int, type )
+ __field( u64, seq )
),
TP_fast_assign(
@@ -496,11 +500,12 @@ TRACE_EVENT(btrfs_delayed_data_ref,
__entry->owner = full_ref->objectid;
__entry->offset = full_ref->offset;
__entry->type = ref->type;
+ __entry->seq = ref->seq;
),
TP_printk("bytenr = %llu, num_bytes = %llu, action = %s, "
"parent = %llu(%s), ref_root = %llu(%s), owner = %llu, "
- "offset = %llu, type = %s",
+ "offset = %llu, type = %s, seq = %llu",
(unsigned long long)__entry->bytenr,
(unsigned long long)__entry->num_bytes,
show_ref_action(__entry->action),
@@ -508,7 +513,8 @@ TRACE_EVENT(btrfs_delayed_data_ref,
show_root_type(__entry->ref_root),
(unsigned long long)__entry->owner,
(unsigned long long)__entry->offset,
- show_ref_type(__entry->type))
+ show_ref_type(__entry->type),
+ (unsigned long long)__entry->seq)
);
TRACE_EVENT(btrfs_delayed_ref_head,
diff --git a/include/uapi/linux/caif/Kbuild b/include/uapi/linux/caif/Kbuild
index aafaa5a..4339661 100644
--- a/include/uapi/linux/caif/Kbuild
+++ b/include/uapi/linux/caif/Kbuild
@@ -1 +1,3 @@
# UAPI Header export list
+header-y += caif_socket.h
+header-y += if_caif.h
diff --git a/include/linux/caif/caif_socket.h b/include/uapi/linux/caif/caif_socket.h
index 3f3bac6..3f3bac6 100644
--- a/include/linux/caif/caif_socket.h
+++ b/include/uapi/linux/caif/caif_socket.h
diff --git a/include/linux/caif/if_caif.h b/include/uapi/linux/caif/if_caif.h
index 5e7eed4..5e7eed4 100644
--- a/include/linux/caif/if_caif.h
+++ b/include/uapi/linux/caif/if_caif.h
diff --git a/include/uapi/linux/isdn/Kbuild b/include/uapi/linux/isdn/Kbuild
index aafaa5a..89e5285 100644
--- a/include/uapi/linux/isdn/Kbuild
+++ b/include/uapi/linux/isdn/Kbuild
@@ -1 +1,2 @@
# UAPI Header export list
+header-y += capicmd.h
diff --git a/include/linux/isdn/capicmd.h b/include/uapi/linux/isdn/capicmd.h
index b58635f..b58635f 100644
--- a/include/linux/isdn/capicmd.h
+++ b/include/uapi/linux/isdn/capicmd.h
diff --git a/include/uapi/linux/netfilter/Kbuild b/include/uapi/linux/netfilter/Kbuild
index 4afbace..08f555f 100644
--- a/include/uapi/linux/netfilter/Kbuild
+++ b/include/uapi/linux/netfilter/Kbuild
@@ -1,2 +1,78 @@
# UAPI Header export list
header-y += ipset/
+header-y += nf_conntrack_common.h
+header-y += nf_conntrack_ftp.h
+header-y += nf_conntrack_sctp.h
+header-y += nf_conntrack_tcp.h
+header-y += nf_conntrack_tuple_common.h
+header-y += nf_nat.h
+header-y += nfnetlink.h
+header-y += nfnetlink_acct.h
+header-y += nfnetlink_compat.h
+header-y += nfnetlink_conntrack.h
+header-y += nfnetlink_cthelper.h
+header-y += nfnetlink_cttimeout.h
+header-y += nfnetlink_log.h
+header-y += nfnetlink_queue.h
+header-y += x_tables.h
+header-y += xt_AUDIT.h
+header-y += xt_CHECKSUM.h
+header-y += xt_CLASSIFY.h
+header-y += xt_CONNMARK.h
+header-y += xt_CONNSECMARK.h
+header-y += xt_CT.h
+header-y += xt_DSCP.h
+header-y += xt_IDLETIMER.h
+header-y += xt_LED.h
+header-y += xt_LOG.h
+header-y += xt_MARK.h
+header-y += xt_NFLOG.h
+header-y += xt_NFQUEUE.h
+header-y += xt_RATEEST.h
+header-y += xt_SECMARK.h
+header-y += xt_TCPMSS.h
+header-y += xt_TCPOPTSTRIP.h
+header-y += xt_TEE.h
+header-y += xt_TPROXY.h
+header-y += xt_addrtype.h
+header-y += xt_cluster.h
+header-y += xt_comment.h
+header-y += xt_connbytes.h
+header-y += xt_connlimit.h
+header-y += xt_connmark.h
+header-y += xt_conntrack.h
+header-y += xt_cpu.h
+header-y += xt_dccp.h
+header-y += xt_devgroup.h
+header-y += xt_dscp.h
+header-y += xt_ecn.h
+header-y += xt_esp.h
+header-y += xt_hashlimit.h
+header-y += xt_helper.h
+header-y += xt_iprange.h
+header-y += xt_ipvs.h
+header-y += xt_length.h
+header-y += xt_limit.h
+header-y += xt_mac.h
+header-y += xt_mark.h
+header-y += xt_multiport.h
+header-y += xt_nfacct.h
+header-y += xt_osf.h
+header-y += xt_owner.h
+header-y += xt_physdev.h
+header-y += xt_pkttype.h
+header-y += xt_policy.h
+header-y += xt_quota.h
+header-y += xt_rateest.h
+header-y += xt_realm.h
+header-y += xt_recent.h
+header-y += xt_sctp.h
+header-y += xt_set.h
+header-y += xt_socket.h
+header-y += xt_state.h
+header-y += xt_statistic.h
+header-y += xt_string.h
+header-y += xt_tcpmss.h
+header-y += xt_tcpudp.h
+header-y += xt_time.h
+header-y += xt_u32.h
diff --git a/include/uapi/linux/netfilter/ipset/Kbuild b/include/uapi/linux/netfilter/ipset/Kbuild
index aafaa5a..d268042 100644
--- a/include/uapi/linux/netfilter/ipset/Kbuild
+++ b/include/uapi/linux/netfilter/ipset/Kbuild
@@ -1 +1,5 @@
# UAPI Header export list
+header-y += ip_set.h
+header-y += ip_set_bitmap.h
+header-y += ip_set_hash.h
+header-y += ip_set_list.h
diff --git a/include/uapi/linux/netfilter/ipset/ip_set.h b/include/uapi/linux/netfilter/ipset/ip_set.h
new file mode 100644
index 0000000..fbee428
--- /dev/null
+++ b/include/uapi/linux/netfilter/ipset/ip_set.h
@@ -0,0 +1,231 @@
+/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
+ * Patrick Schaaf <bof@bof.de>
+ * Martin Josefsson <gandalf@wlug.westbo.se>
+ * Copyright (C) 2003-2011 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
+ *
+ * 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 _UAPI_IP_SET_H
+#define _UAPI_IP_SET_H
+
+
+#include <linux/types.h>
+
+/* The protocol version */
+#define IPSET_PROTOCOL 6
+
+/* The max length of strings including NUL: set and type identifiers */
+#define IPSET_MAXNAMELEN 32
+
+/* Message types and commands */
+enum ipset_cmd {
+ IPSET_CMD_NONE,
+ IPSET_CMD_PROTOCOL, /* 1: Return protocol version */
+ IPSET_CMD_CREATE, /* 2: Create a new (empty) set */
+ IPSET_CMD_DESTROY, /* 3: Destroy a (empty) set */
+ IPSET_CMD_FLUSH, /* 4: Remove all elements from a set */
+ IPSET_CMD_RENAME, /* 5: Rename a set */
+ IPSET_CMD_SWAP, /* 6: Swap two sets */
+ IPSET_CMD_LIST, /* 7: List sets */
+ IPSET_CMD_SAVE, /* 8: Save sets */
+ IPSET_CMD_ADD, /* 9: Add an element to a set */
+ IPSET_CMD_DEL, /* 10: Delete an element from a set */
+ IPSET_CMD_TEST, /* 11: Test an element in a set */
+ IPSET_CMD_HEADER, /* 12: Get set header data only */
+ IPSET_CMD_TYPE, /* 13: Get set type */
+ IPSET_MSG_MAX, /* Netlink message commands */
+
+ /* Commands in userspace: */
+ IPSET_CMD_RESTORE = IPSET_MSG_MAX, /* 14: Enter restore mode */
+ IPSET_CMD_HELP, /* 15: Get help */
+ IPSET_CMD_VERSION, /* 16: Get program version */
+ IPSET_CMD_QUIT, /* 17: Quit from interactive mode */
+
+ IPSET_CMD_MAX,
+
+ IPSET_CMD_COMMIT = IPSET_CMD_MAX, /* 18: Commit buffered commands */
+};
+
+/* Attributes at command level */
+enum {
+ IPSET_ATTR_UNSPEC,
+ IPSET_ATTR_PROTOCOL, /* 1: Protocol version */
+ IPSET_ATTR_SETNAME, /* 2: Name of the set */
+ IPSET_ATTR_TYPENAME, /* 3: Typename */
+ IPSET_ATTR_SETNAME2 = IPSET_ATTR_TYPENAME, /* Setname at rename/swap */
+ IPSET_ATTR_REVISION, /* 4: Settype revision */
+ IPSET_ATTR_FAMILY, /* 5: Settype family */
+ IPSET_ATTR_FLAGS, /* 6: Flags at command level */
+ IPSET_ATTR_DATA, /* 7: Nested attributes */
+ IPSET_ATTR_ADT, /* 8: Multiple data containers */
+ IPSET_ATTR_LINENO, /* 9: Restore lineno */
+ IPSET_ATTR_PROTOCOL_MIN, /* 10: Minimal supported version number */
+ IPSET_ATTR_REVISION_MIN = IPSET_ATTR_PROTOCOL_MIN, /* type rev min */
+ __IPSET_ATTR_CMD_MAX,
+};
+#define IPSET_ATTR_CMD_MAX (__IPSET_ATTR_CMD_MAX - 1)
+
+/* CADT specific attributes */
+enum {
+ IPSET_ATTR_IP = IPSET_ATTR_UNSPEC + 1,
+ IPSET_ATTR_IP_FROM = IPSET_ATTR_IP,
+ IPSET_ATTR_IP_TO, /* 2 */
+ IPSET_ATTR_CIDR, /* 3 */
+ IPSET_ATTR_PORT, /* 4 */
+ IPSET_ATTR_PORT_FROM = IPSET_ATTR_PORT,
+ IPSET_ATTR_PORT_TO, /* 5 */
+ IPSET_ATTR_TIMEOUT, /* 6 */
+ IPSET_ATTR_PROTO, /* 7 */
+ IPSET_ATTR_CADT_FLAGS, /* 8 */
+ IPSET_ATTR_CADT_LINENO = IPSET_ATTR_LINENO, /* 9 */
+ /* Reserve empty slots */
+ IPSET_ATTR_CADT_MAX = 16,
+ /* Create-only specific attributes */
+ IPSET_ATTR_GC,
+ IPSET_ATTR_HASHSIZE,
+ IPSET_ATTR_MAXELEM,
+ IPSET_ATTR_NETMASK,
+ IPSET_ATTR_PROBES,
+ IPSET_ATTR_RESIZE,
+ IPSET_ATTR_SIZE,
+ /* Kernel-only */
+ IPSET_ATTR_ELEMENTS,
+ IPSET_ATTR_REFERENCES,
+ IPSET_ATTR_MEMSIZE,
+
+ __IPSET_ATTR_CREATE_MAX,
+};
+#define IPSET_ATTR_CREATE_MAX (__IPSET_ATTR_CREATE_MAX - 1)
+
+/* ADT specific attributes */
+enum {
+ IPSET_ATTR_ETHER = IPSET_ATTR_CADT_MAX + 1,
+ IPSET_ATTR_NAME,
+ IPSET_ATTR_NAMEREF,
+ IPSET_ATTR_IP2,
+ IPSET_ATTR_CIDR2,
+ IPSET_ATTR_IP2_TO,
+ IPSET_ATTR_IFACE,
+ __IPSET_ATTR_ADT_MAX,
+};
+#define IPSET_ATTR_ADT_MAX (__IPSET_ATTR_ADT_MAX - 1)
+
+/* IP specific attributes */
+enum {
+ IPSET_ATTR_IPADDR_IPV4 = IPSET_ATTR_UNSPEC + 1,
+ IPSET_ATTR_IPADDR_IPV6,
+ __IPSET_ATTR_IPADDR_MAX,
+};
+#define IPSET_ATTR_IPADDR_MAX (__IPSET_ATTR_IPADDR_MAX - 1)
+
+/* Error codes */
+enum ipset_errno {
+ IPSET_ERR_PRIVATE = 4096,
+ IPSET_ERR_PROTOCOL,
+ IPSET_ERR_FIND_TYPE,
+ IPSET_ERR_MAX_SETS,
+ IPSET_ERR_BUSY,
+ IPSET_ERR_EXIST_SETNAME2,
+ IPSET_ERR_TYPE_MISMATCH,
+ IPSET_ERR_EXIST,
+ IPSET_ERR_INVALID_CIDR,
+ IPSET_ERR_INVALID_NETMASK,
+ IPSET_ERR_INVALID_FAMILY,
+ IPSET_ERR_TIMEOUT,
+ IPSET_ERR_REFERENCED,
+ IPSET_ERR_IPADDR_IPV4,
+ IPSET_ERR_IPADDR_IPV6,
+
+ /* Type specific error codes */
+ IPSET_ERR_TYPE_SPECIFIC = 4352,
+};
+
+/* Flags at command level */
+enum ipset_cmd_flags {
+ IPSET_FLAG_BIT_EXIST = 0,
+ IPSET_FLAG_EXIST = (1 << IPSET_FLAG_BIT_EXIST),
+ IPSET_FLAG_BIT_LIST_SETNAME = 1,
+ IPSET_FLAG_LIST_SETNAME = (1 << IPSET_FLAG_BIT_LIST_SETNAME),
+ IPSET_FLAG_BIT_LIST_HEADER = 2,
+ IPSET_FLAG_LIST_HEADER = (1 << IPSET_FLAG_BIT_LIST_HEADER),
+ IPSET_FLAG_CMD_MAX = 15, /* Lower half */
+};
+
+/* Flags at CADT attribute level */
+enum ipset_cadt_flags {
+ IPSET_FLAG_BIT_BEFORE = 0,
+ IPSET_FLAG_BEFORE = (1 << IPSET_FLAG_BIT_BEFORE),
+ IPSET_FLAG_BIT_PHYSDEV = 1,
+ IPSET_FLAG_PHYSDEV = (1 << IPSET_FLAG_BIT_PHYSDEV),
+ IPSET_FLAG_BIT_NOMATCH = 2,
+ IPSET_FLAG_NOMATCH = (1 << IPSET_FLAG_BIT_NOMATCH),
+ IPSET_FLAG_CADT_MAX = 15, /* Upper half */
+};
+
+/* Commands with settype-specific attributes */
+enum ipset_adt {
+ IPSET_ADD,
+ IPSET_DEL,
+ IPSET_TEST,
+ IPSET_ADT_MAX,
+ IPSET_CREATE = IPSET_ADT_MAX,
+ IPSET_CADT_MAX,
+};
+
+/* Sets are identified by an index in kernel space. Tweak with ip_set_id_t
+ * and IPSET_INVALID_ID if you want to increase the max number of sets.
+ */
+typedef __u16 ip_set_id_t;
+
+#define IPSET_INVALID_ID 65535
+
+enum ip_set_dim {
+ IPSET_DIM_ZERO = 0,
+ IPSET_DIM_ONE,
+ IPSET_DIM_TWO,
+ IPSET_DIM_THREE,
+ /* Max dimension in elements.
+ * If changed, new revision of iptables match/target is required.
+ */
+ IPSET_DIM_MAX = 6,
+ IPSET_BIT_RETURN_NOMATCH = 7,
+};
+
+/* Option flags for kernel operations */
+enum ip_set_kopt {
+ IPSET_INV_MATCH = (1 << IPSET_DIM_ZERO),
+ IPSET_DIM_ONE_SRC = (1 << IPSET_DIM_ONE),
+ IPSET_DIM_TWO_SRC = (1 << IPSET_DIM_TWO),
+ IPSET_DIM_THREE_SRC = (1 << IPSET_DIM_THREE),
+ IPSET_RETURN_NOMATCH = (1 << IPSET_BIT_RETURN_NOMATCH),
+};
+
+
+/* Interface to iptables/ip6tables */
+
+#define SO_IP_SET 83
+
+union ip_set_name_index {
+ char name[IPSET_MAXNAMELEN];
+ ip_set_id_t index;
+};
+
+#define IP_SET_OP_GET_BYNAME 0x00000006 /* Get set index by name */
+struct ip_set_req_get_set {
+ unsigned int op;
+ unsigned int version;
+ union ip_set_name_index set;
+};
+
+#define IP_SET_OP_GET_BYINDEX 0x00000007 /* Get set name by index */
+/* Uses ip_set_req_get_set */
+
+#define IP_SET_OP_VERSION 0x00000100 /* Ask kernel version */
+struct ip_set_req_version {
+ unsigned int op;
+ unsigned int version;
+};
+
+#endif /* _UAPI_IP_SET_H */
diff --git a/include/uapi/linux/netfilter/ipset/ip_set_bitmap.h b/include/uapi/linux/netfilter/ipset/ip_set_bitmap.h
new file mode 100644
index 0000000..6a2c038
--- /dev/null
+++ b/include/uapi/linux/netfilter/ipset/ip_set_bitmap.h
@@ -0,0 +1,13 @@
+#ifndef _UAPI__IP_SET_BITMAP_H
+#define _UAPI__IP_SET_BITMAP_H
+
+/* Bitmap type specific error codes */
+enum {
+ /* The element is out of the range of the set */
+ IPSET_ERR_BITMAP_RANGE = IPSET_ERR_TYPE_SPECIFIC,
+ /* The range exceeds the size limit of the set type */
+ IPSET_ERR_BITMAP_RANGE_SIZE,
+};
+
+
+#endif /* _UAPI__IP_SET_BITMAP_H */
diff --git a/include/uapi/linux/netfilter/ipset/ip_set_hash.h b/include/uapi/linux/netfilter/ipset/ip_set_hash.h
new file mode 100644
index 0000000..352eecc
--- /dev/null
+++ b/include/uapi/linux/netfilter/ipset/ip_set_hash.h
@@ -0,0 +1,21 @@
+#ifndef _UAPI__IP_SET_HASH_H
+#define _UAPI__IP_SET_HASH_H
+
+/* Hash type specific error codes */
+enum {
+ /* Hash is full */
+ IPSET_ERR_HASH_FULL = IPSET_ERR_TYPE_SPECIFIC,
+ /* Null-valued element */
+ IPSET_ERR_HASH_ELEM,
+ /* Invalid protocol */
+ IPSET_ERR_INVALID_PROTO,
+ /* Protocol missing but must be specified */
+ IPSET_ERR_MISSING_PROTO,
+ /* Range not supported */
+ IPSET_ERR_HASH_RANGE_UNSUPPORTED,
+ /* Invalid range */
+ IPSET_ERR_HASH_RANGE,
+};
+
+
+#endif /* _UAPI__IP_SET_HASH_H */
diff --git a/include/uapi/linux/netfilter/ipset/ip_set_list.h b/include/uapi/linux/netfilter/ipset/ip_set_list.h
new file mode 100644
index 0000000..a44efaa
--- /dev/null
+++ b/include/uapi/linux/netfilter/ipset/ip_set_list.h
@@ -0,0 +1,21 @@
+#ifndef _UAPI__IP_SET_LIST_H
+#define _UAPI__IP_SET_LIST_H
+
+/* List type specific error codes */
+enum {
+ /* Set name to be added/deleted/tested does not exist. */
+ IPSET_ERR_NAME = IPSET_ERR_TYPE_SPECIFIC,
+ /* list:set type is not permitted to add */
+ IPSET_ERR_LOOP,
+ /* Missing reference set */
+ IPSET_ERR_BEFORE,
+ /* Reference set does not exist */
+ IPSET_ERR_NAMEREF,
+ /* Set is full */
+ IPSET_ERR_LIST_FULL,
+ /* Reference set is not added to the set */
+ IPSET_ERR_REF_EXIST,
+};
+
+
+#endif /* _UAPI__IP_SET_LIST_H */
diff --git a/include/uapi/linux/netfilter/nf_conntrack_common.h b/include/uapi/linux/netfilter/nf_conntrack_common.h
new file mode 100644
index 0000000..1644cdd
--- /dev/null
+++ b/include/uapi/linux/netfilter/nf_conntrack_common.h
@@ -0,0 +1,117 @@
+#ifndef _UAPI_NF_CONNTRACK_COMMON_H
+#define _UAPI_NF_CONNTRACK_COMMON_H
+/* Connection state tracking for netfilter. This is separated from,
+ but required by, the NAT layer; it can also be used by an iptables
+ extension. */
+enum ip_conntrack_info {
+ /* Part of an established connection (either direction). */
+ IP_CT_ESTABLISHED,
+
+ /* Like NEW, but related to an existing connection, or ICMP error
+ (in either direction). */
+ IP_CT_RELATED,
+
+ /* Started a new connection to track (only
+ IP_CT_DIR_ORIGINAL); may be a retransmission. */
+ IP_CT_NEW,
+
+ /* >= 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
+};
+
+/* Bitset representing status of connection. */
+enum ip_conntrack_status {
+ /* It's an expected connection: bit 0 set. This bit never changed */
+ IPS_EXPECTED_BIT = 0,
+ IPS_EXPECTED = (1 << IPS_EXPECTED_BIT),
+
+ /* We've seen packets both ways: bit 1 set. Can be set, not unset. */
+ IPS_SEEN_REPLY_BIT = 1,
+ IPS_SEEN_REPLY = (1 << IPS_SEEN_REPLY_BIT),
+
+ /* Conntrack should never be early-expired. */
+ IPS_ASSURED_BIT = 2,
+ IPS_ASSURED = (1 << IPS_ASSURED_BIT),
+
+ /* Connection is confirmed: originating packet has left box */
+ IPS_CONFIRMED_BIT = 3,
+ IPS_CONFIRMED = (1 << IPS_CONFIRMED_BIT),
+
+ /* Connection needs src nat in orig dir. This bit never changed. */
+ IPS_SRC_NAT_BIT = 4,
+ IPS_SRC_NAT = (1 << IPS_SRC_NAT_BIT),
+
+ /* Connection needs dst nat in orig dir. This bit never changed. */
+ IPS_DST_NAT_BIT = 5,
+ IPS_DST_NAT = (1 << IPS_DST_NAT_BIT),
+
+ /* Both together. */
+ IPS_NAT_MASK = (IPS_DST_NAT | IPS_SRC_NAT),
+
+ /* Connection needs TCP sequence adjusted. */
+ IPS_SEQ_ADJUST_BIT = 6,
+ IPS_SEQ_ADJUST = (1 << IPS_SEQ_ADJUST_BIT),
+
+ /* NAT initialization bits. */
+ IPS_SRC_NAT_DONE_BIT = 7,
+ IPS_SRC_NAT_DONE = (1 << IPS_SRC_NAT_DONE_BIT),
+
+ IPS_DST_NAT_DONE_BIT = 8,
+ IPS_DST_NAT_DONE = (1 << IPS_DST_NAT_DONE_BIT),
+
+ /* Both together */
+ IPS_NAT_DONE_MASK = (IPS_DST_NAT_DONE | IPS_SRC_NAT_DONE),
+
+ /* Connection is dying (removed from lists), can not be unset. */
+ IPS_DYING_BIT = 9,
+ IPS_DYING = (1 << IPS_DYING_BIT),
+
+ /* Connection has fixed timeout. */
+ IPS_FIXED_TIMEOUT_BIT = 10,
+ IPS_FIXED_TIMEOUT = (1 << IPS_FIXED_TIMEOUT_BIT),
+
+ /* Conntrack is a template */
+ IPS_TEMPLATE_BIT = 11,
+ IPS_TEMPLATE = (1 << IPS_TEMPLATE_BIT),
+
+ /* Conntrack is a fake untracked entry */
+ IPS_UNTRACKED_BIT = 12,
+ IPS_UNTRACKED = (1 << IPS_UNTRACKED_BIT),
+
+ /* Conntrack got a helper explicitly attached via CT target. */
+ IPS_HELPER_BIT = 13,
+ IPS_HELPER = (1 << IPS_HELPER_BIT),
+};
+
+/* Connection tracking event types */
+enum ip_conntrack_events {
+ IPCT_NEW, /* new conntrack */
+ IPCT_RELATED, /* related conntrack */
+ IPCT_DESTROY, /* destroyed conntrack */
+ IPCT_REPLY, /* connection has seen two-way traffic */
+ IPCT_ASSURED, /* connection status has changed to assured */
+ IPCT_PROTOINFO, /* protocol information has changed */
+ IPCT_HELPER, /* new helper has been set */
+ IPCT_MARK, /* new mark has been set */
+ IPCT_NATSEQADJ, /* NAT is doing sequence adjustment */
+ IPCT_SECMARK, /* new security mark has been set */
+};
+
+enum ip_conntrack_expect_events {
+ IPEXP_NEW, /* new expectation */
+ IPEXP_DESTROY, /* destroyed expectation */
+};
+
+/* expectation flags */
+#define NF_CT_EXPECT_PERMANENT 0x1
+#define NF_CT_EXPECT_INACTIVE 0x2
+#define NF_CT_EXPECT_USERSPACE 0x4
+
+
+#endif /* _UAPI_NF_CONNTRACK_COMMON_H */
diff --git a/include/uapi/linux/netfilter/nf_conntrack_ftp.h b/include/uapi/linux/netfilter/nf_conntrack_ftp.h
new file mode 100644
index 0000000..1030315
--- /dev/null
+++ b/include/uapi/linux/netfilter/nf_conntrack_ftp.h
@@ -0,0 +1,18 @@
+#ifndef _UAPI_NF_CONNTRACK_FTP_H
+#define _UAPI_NF_CONNTRACK_FTP_H
+/* FTP tracking. */
+
+/* This enum is exposed to userspace */
+enum nf_ct_ftp_type {
+ /* PORT command from client */
+ NF_CT_FTP_PORT,
+ /* PASV response from server */
+ NF_CT_FTP_PASV,
+ /* EPRT command from client */
+ NF_CT_FTP_EPRT,
+ /* EPSV response from server */
+ NF_CT_FTP_EPSV,
+};
+
+
+#endif /* _UAPI_NF_CONNTRACK_FTP_H */
diff --git a/include/linux/netfilter/nf_conntrack_sctp.h b/include/uapi/linux/netfilter/nf_conntrack_sctp.h
index ceeefe6..ceeefe6 100644
--- a/include/linux/netfilter/nf_conntrack_sctp.h
+++ b/include/uapi/linux/netfilter/nf_conntrack_sctp.h
diff --git a/include/uapi/linux/netfilter/nf_conntrack_tcp.h b/include/uapi/linux/netfilter/nf_conntrack_tcp.h
new file mode 100644
index 0000000..9993a42
--- /dev/null
+++ b/include/uapi/linux/netfilter/nf_conntrack_tcp.h
@@ -0,0 +1,51 @@
+#ifndef _UAPI_NF_CONNTRACK_TCP_H
+#define _UAPI_NF_CONNTRACK_TCP_H
+/* TCP tracking. */
+
+#include <linux/types.h>
+
+/* This is exposed to userspace (ctnetlink) */
+enum tcp_conntrack {
+ TCP_CONNTRACK_NONE,
+ TCP_CONNTRACK_SYN_SENT,
+ TCP_CONNTRACK_SYN_RECV,
+ TCP_CONNTRACK_ESTABLISHED,
+ TCP_CONNTRACK_FIN_WAIT,
+ TCP_CONNTRACK_CLOSE_WAIT,
+ TCP_CONNTRACK_LAST_ACK,
+ TCP_CONNTRACK_TIME_WAIT,
+ TCP_CONNTRACK_CLOSE,
+ TCP_CONNTRACK_LISTEN, /* obsolete */
+#define TCP_CONNTRACK_SYN_SENT2 TCP_CONNTRACK_LISTEN
+ TCP_CONNTRACK_MAX,
+ TCP_CONNTRACK_IGNORE,
+ TCP_CONNTRACK_RETRANS,
+ TCP_CONNTRACK_UNACK,
+ TCP_CONNTRACK_TIMEOUT_MAX
+};
+
+/* Window scaling is advertised by the sender */
+#define IP_CT_TCP_FLAG_WINDOW_SCALE 0x01
+
+/* SACK is permitted by the sender */
+#define IP_CT_TCP_FLAG_SACK_PERM 0x02
+
+/* This sender sent FIN first */
+#define IP_CT_TCP_FLAG_CLOSE_INIT 0x04
+
+/* Be liberal in window checking */
+#define IP_CT_TCP_FLAG_BE_LIBERAL 0x08
+
+/* Has unacknowledged data */
+#define IP_CT_TCP_FLAG_DATA_UNACKNOWLEDGED 0x10
+
+/* The field td_maxack has been set */
+#define IP_CT_TCP_FLAG_MAXACK_SET 0x20
+
+struct nf_ct_tcp_flags {
+ __u8 flags;
+ __u8 mask;
+};
+
+
+#endif /* _UAPI_NF_CONNTRACK_TCP_H */
diff --git a/include/linux/netfilter/nf_conntrack_tuple_common.h b/include/uapi/linux/netfilter/nf_conntrack_tuple_common.h
index 2f6bbc5..2f6bbc5 100644
--- a/include/linux/netfilter/nf_conntrack_tuple_common.h
+++ b/include/uapi/linux/netfilter/nf_conntrack_tuple_common.h
diff --git a/include/linux/netfilter/nf_nat.h b/include/uapi/linux/netfilter/nf_nat.h
index bf0cc37..bf0cc37 100644
--- a/include/linux/netfilter/nf_nat.h
+++ b/include/uapi/linux/netfilter/nf_nat.h
diff --git a/include/uapi/linux/netfilter/nfnetlink.h b/include/uapi/linux/netfilter/nfnetlink.h
new file mode 100644
index 0000000..4a4efaf
--- /dev/null
+++ b/include/uapi/linux/netfilter/nfnetlink.h
@@ -0,0 +1,56 @@
+#ifndef _UAPI_NFNETLINK_H
+#define _UAPI_NFNETLINK_H
+#include <linux/types.h>
+#include <linux/netfilter/nfnetlink_compat.h>
+
+enum nfnetlink_groups {
+ NFNLGRP_NONE,
+#define NFNLGRP_NONE NFNLGRP_NONE
+ NFNLGRP_CONNTRACK_NEW,
+#define NFNLGRP_CONNTRACK_NEW NFNLGRP_CONNTRACK_NEW
+ NFNLGRP_CONNTRACK_UPDATE,
+#define NFNLGRP_CONNTRACK_UPDATE NFNLGRP_CONNTRACK_UPDATE
+ NFNLGRP_CONNTRACK_DESTROY,
+#define NFNLGRP_CONNTRACK_DESTROY NFNLGRP_CONNTRACK_DESTROY
+ NFNLGRP_CONNTRACK_EXP_NEW,
+#define NFNLGRP_CONNTRACK_EXP_NEW NFNLGRP_CONNTRACK_EXP_NEW
+ NFNLGRP_CONNTRACK_EXP_UPDATE,
+#define NFNLGRP_CONNTRACK_EXP_UPDATE NFNLGRP_CONNTRACK_EXP_UPDATE
+ NFNLGRP_CONNTRACK_EXP_DESTROY,
+#define NFNLGRP_CONNTRACK_EXP_DESTROY NFNLGRP_CONNTRACK_EXP_DESTROY
+ __NFNLGRP_MAX,
+};
+#define NFNLGRP_MAX (__NFNLGRP_MAX - 1)
+
+/* General form of address family dependent message.
+ */
+struct nfgenmsg {
+ __u8 nfgen_family; /* AF_xxx */
+ __u8 version; /* nfnetlink version */
+ __be16 res_id; /* resource id */
+};
+
+#define NFNETLINK_V0 0
+
+/* netfilter netlink message types are split in two pieces:
+ * 8 bit subsystem, 8bit operation.
+ */
+
+#define NFNL_SUBSYS_ID(x) ((x & 0xff00) >> 8)
+#define NFNL_MSG_TYPE(x) (x & 0x00ff)
+
+/* No enum here, otherwise __stringify() trick of MODULE_ALIAS_NFNL_SUBSYS()
+ * won't work anymore */
+#define NFNL_SUBSYS_NONE 0
+#define NFNL_SUBSYS_CTNETLINK 1
+#define NFNL_SUBSYS_CTNETLINK_EXP 2
+#define NFNL_SUBSYS_QUEUE 3
+#define NFNL_SUBSYS_ULOG 4
+#define NFNL_SUBSYS_OSF 5
+#define NFNL_SUBSYS_IPSET 6
+#define NFNL_SUBSYS_ACCT 7
+#define NFNL_SUBSYS_CTNETLINK_TIMEOUT 8
+#define NFNL_SUBSYS_CTHELPER 9
+#define NFNL_SUBSYS_COUNT 10
+
+#endif /* _UAPI_NFNETLINK_H */
diff --git a/include/uapi/linux/netfilter/nfnetlink_acct.h b/include/uapi/linux/netfilter/nfnetlink_acct.h
new file mode 100644
index 0000000..c7b6269
--- /dev/null
+++ b/include/uapi/linux/netfilter/nfnetlink_acct.h
@@ -0,0 +1,27 @@
+#ifndef _UAPI_NFNL_ACCT_H_
+#define _UAPI_NFNL_ACCT_H_
+
+#ifndef NFACCT_NAME_MAX
+#define NFACCT_NAME_MAX 32
+#endif
+
+enum nfnl_acct_msg_types {
+ NFNL_MSG_ACCT_NEW,
+ NFNL_MSG_ACCT_GET,
+ NFNL_MSG_ACCT_GET_CTRZERO,
+ NFNL_MSG_ACCT_DEL,
+ NFNL_MSG_ACCT_MAX
+};
+
+enum nfnl_acct_type {
+ NFACCT_UNSPEC,
+ NFACCT_NAME,
+ NFACCT_PKTS,
+ NFACCT_BYTES,
+ NFACCT_USE,
+ __NFACCT_MAX
+};
+#define NFACCT_MAX (__NFACCT_MAX - 1)
+
+
+#endif /* _UAPI_NFNL_ACCT_H_ */
diff --git a/include/linux/netfilter/nfnetlink_compat.h b/include/uapi/linux/netfilter/nfnetlink_compat.h
index ffb9503..ffb9503 100644
--- a/include/linux/netfilter/nfnetlink_compat.h
+++ b/include/uapi/linux/netfilter/nfnetlink_compat.h
diff --git a/include/linux/netfilter/nfnetlink_conntrack.h b/include/uapi/linux/netfilter/nfnetlink_conntrack.h
index 43bfe3e..43bfe3e 100644
--- a/include/linux/netfilter/nfnetlink_conntrack.h
+++ b/include/uapi/linux/netfilter/nfnetlink_conntrack.h
diff --git a/include/linux/netfilter/nfnetlink_cthelper.h b/include/uapi/linux/netfilter/nfnetlink_cthelper.h
index 33659f6..33659f6 100644
--- a/include/linux/netfilter/nfnetlink_cthelper.h
+++ b/include/uapi/linux/netfilter/nfnetlink_cthelper.h
diff --git a/include/linux/netfilter/nfnetlink_cttimeout.h b/include/uapi/linux/netfilter/nfnetlink_cttimeout.h
index a2810a7..a2810a7 100644
--- a/include/linux/netfilter/nfnetlink_cttimeout.h
+++ b/include/uapi/linux/netfilter/nfnetlink_cttimeout.h
diff --git a/include/linux/netfilter/nfnetlink_log.h b/include/uapi/linux/netfilter/nfnetlink_log.h
index 90c2c95..90c2c95 100644
--- a/include/linux/netfilter/nfnetlink_log.h
+++ b/include/uapi/linux/netfilter/nfnetlink_log.h
diff --git a/include/linux/netfilter/nfnetlink_queue.h b/include/uapi/linux/netfilter/nfnetlink_queue.h
index 70ec8c2..70ec8c2 100644
--- a/include/linux/netfilter/nfnetlink_queue.h
+++ b/include/uapi/linux/netfilter/nfnetlink_queue.h
diff --git a/include/uapi/linux/netfilter/x_tables.h b/include/uapi/linux/netfilter/x_tables.h
new file mode 100644
index 0000000..c36969b
--- /dev/null
+++ b/include/uapi/linux/netfilter/x_tables.h
@@ -0,0 +1,187 @@
+#ifndef _UAPI_X_TABLES_H
+#define _UAPI_X_TABLES_H
+#include <linux/kernel.h>
+#include <linux/types.h>
+
+#define XT_FUNCTION_MAXNAMELEN 30
+#define XT_EXTENSION_MAXNAMELEN 29
+#define XT_TABLE_MAXNAMELEN 32
+
+struct xt_entry_match {
+ union {
+ struct {
+ __u16 match_size;
+
+ /* Used by userspace */
+ char name[XT_EXTENSION_MAXNAMELEN];
+ __u8 revision;
+ } user;
+ struct {
+ __u16 match_size;
+
+ /* Used inside the kernel */
+ struct xt_match *match;
+ } kernel;
+
+ /* Total length */
+ __u16 match_size;
+ } u;
+
+ unsigned char data[0];
+};
+
+struct xt_entry_target {
+ union {
+ struct {
+ __u16 target_size;
+
+ /* Used by userspace */
+ char name[XT_EXTENSION_MAXNAMELEN];
+ __u8 revision;
+ } user;
+ struct {
+ __u16 target_size;
+
+ /* Used inside the kernel */
+ struct xt_target *target;
+ } kernel;
+
+ /* Total length */
+ __u16 target_size;
+ } u;
+
+ unsigned char data[0];
+};
+
+#define XT_TARGET_INIT(__name, __size) \
+{ \
+ .target.u.user = { \
+ .target_size = XT_ALIGN(__size), \
+ .name = __name, \
+ }, \
+}
+
+struct xt_standard_target {
+ struct xt_entry_target target;
+ int verdict;
+};
+
+struct xt_error_target {
+ struct xt_entry_target target;
+ char errorname[XT_FUNCTION_MAXNAMELEN];
+};
+
+/* The argument to IPT_SO_GET_REVISION_*. Returns highest revision
+ * kernel supports, if >= revision. */
+struct xt_get_revision {
+ char name[XT_EXTENSION_MAXNAMELEN];
+ __u8 revision;
+};
+
+/* CONTINUE verdict for targets */
+#define XT_CONTINUE 0xFFFFFFFF
+
+/* For standard target */
+#define XT_RETURN (-NF_REPEAT - 1)
+
+/* this is a dummy structure to find out the alignment requirement for a struct
+ * containing all the fundamental data types that are used in ipt_entry,
+ * ip6t_entry and arpt_entry. This sucks, and it is a hack. It will be my
+ * personal pleasure to remove it -HW
+ */
+struct _xt_align {
+ __u8 u8;
+ __u16 u16;
+ __u32 u32;
+ __u64 u64;
+};
+
+#define XT_ALIGN(s) __ALIGN_KERNEL((s), __alignof__(struct _xt_align))
+
+/* Standard return verdict, or do jump. */
+#define XT_STANDARD_TARGET ""
+/* Error verdict. */
+#define XT_ERROR_TARGET "ERROR"
+
+#define SET_COUNTER(c,b,p) do { (c).bcnt = (b); (c).pcnt = (p); } while(0)
+#define ADD_COUNTER(c,b,p) do { (c).bcnt += (b); (c).pcnt += (p); } while(0)
+
+struct xt_counters {
+ __u64 pcnt, bcnt; /* Packet and byte counters */
+};
+
+/* The argument to IPT_SO_ADD_COUNTERS. */
+struct xt_counters_info {
+ /* Which table. */
+ char name[XT_TABLE_MAXNAMELEN];
+
+ unsigned int num_counters;
+
+ /* The counters (actually `number' of these). */
+ struct xt_counters counters[0];
+};
+
+#define XT_INV_PROTO 0x40 /* Invert the sense of PROTO. */
+
+#ifndef __KERNEL__
+/* fn returns 0 to continue iteration */
+#define XT_MATCH_ITERATE(type, e, fn, args...) \
+({ \
+ unsigned int __i; \
+ int __ret = 0; \
+ struct xt_entry_match *__m; \
+ \
+ for (__i = sizeof(type); \
+ __i < (e)->target_offset; \
+ __i += __m->u.match_size) { \
+ __m = (void *)e + __i; \
+ \
+ __ret = fn(__m , ## args); \
+ if (__ret != 0) \
+ break; \
+ } \
+ __ret; \
+})
+
+/* fn returns 0 to continue iteration */
+#define XT_ENTRY_ITERATE_CONTINUE(type, entries, size, n, fn, args...) \
+({ \
+ unsigned int __i, __n; \
+ int __ret = 0; \
+ type *__entry; \
+ \
+ for (__i = 0, __n = 0; __i < (size); \
+ __i += __entry->next_offset, __n++) { \
+ __entry = (void *)(entries) + __i; \
+ if (__n < n) \
+ continue; \
+ \
+ __ret = fn(__entry , ## args); \
+ if (__ret != 0) \
+ break; \
+ } \
+ __ret; \
+})
+
+/* fn returns 0 to continue iteration */
+#define XT_ENTRY_ITERATE(type, entries, size, fn, args...) \
+ XT_ENTRY_ITERATE_CONTINUE(type, entries, size, 0, fn, args)
+
+#endif /* !__KERNEL__ */
+
+/* pos is normally a struct ipt_entry/ip6t_entry/etc. */
+#define xt_entry_foreach(pos, ehead, esize) \
+ for ((pos) = (typeof(pos))(ehead); \
+ (pos) < (typeof(pos))((char *)(ehead) + (esize)); \
+ (pos) = (typeof(pos))((char *)(pos) + (pos)->next_offset))
+
+/* can only be xt_entry_match, so no use of typeof here */
+#define xt_ematch_foreach(pos, entry) \
+ for ((pos) = (struct xt_entry_match *)entry->elems; \
+ (pos) < (struct xt_entry_match *)((char *)(entry) + \
+ (entry)->target_offset); \
+ (pos) = (struct xt_entry_match *)((char *)(pos) + \
+ (pos)->u.match_size))
+
+
+#endif /* _UAPI_X_TABLES_H */
diff --git a/include/linux/netfilter/xt_AUDIT.h b/include/uapi/linux/netfilter/xt_AUDIT.h
index 38751d2..38751d2 100644
--- a/include/linux/netfilter/xt_AUDIT.h
+++ b/include/uapi/linux/netfilter/xt_AUDIT.h
diff --git a/include/linux/netfilter/xt_CHECKSUM.h b/include/uapi/linux/netfilter/xt_CHECKSUM.h
index 9a2e466..9a2e466 100644
--- a/include/linux/netfilter/xt_CHECKSUM.h
+++ b/include/uapi/linux/netfilter/xt_CHECKSUM.h
diff --git a/include/linux/netfilter/xt_CLASSIFY.h b/include/uapi/linux/netfilter/xt_CLASSIFY.h
index a813bf1..a813bf1 100644
--- a/include/linux/netfilter/xt_CLASSIFY.h
+++ b/include/uapi/linux/netfilter/xt_CLASSIFY.h
diff --git a/include/linux/netfilter/xt_CONNMARK.h b/include/uapi/linux/netfilter/xt_CONNMARK.h
index 2f2e48e..2f2e48e 100644
--- a/include/linux/netfilter/xt_CONNMARK.h
+++ b/include/uapi/linux/netfilter/xt_CONNMARK.h
diff --git a/include/linux/netfilter/xt_CONNSECMARK.h b/include/uapi/linux/netfilter/xt_CONNSECMARK.h
index b973ff8..b973ff8 100644
--- a/include/linux/netfilter/xt_CONNSECMARK.h
+++ b/include/uapi/linux/netfilter/xt_CONNSECMARK.h
diff --git a/include/linux/netfilter/xt_CT.h b/include/uapi/linux/netfilter/xt_CT.h
index a064b8a..a064b8a 100644
--- a/include/linux/netfilter/xt_CT.h
+++ b/include/uapi/linux/netfilter/xt_CT.h
diff --git a/include/linux/netfilter/xt_DSCP.h b/include/uapi/linux/netfilter/xt_DSCP.h
index 648e0b3..648e0b3 100644
--- a/include/linux/netfilter/xt_DSCP.h
+++ b/include/uapi/linux/netfilter/xt_DSCP.h
diff --git a/include/linux/netfilter/xt_IDLETIMER.h b/include/uapi/linux/netfilter/xt_IDLETIMER.h
index 208ae93..208ae93 100644
--- a/include/linux/netfilter/xt_IDLETIMER.h
+++ b/include/uapi/linux/netfilter/xt_IDLETIMER.h
diff --git a/include/linux/netfilter/xt_LED.h b/include/uapi/linux/netfilter/xt_LED.h
index f5509e7..f5509e7 100644
--- a/include/linux/netfilter/xt_LED.h
+++ b/include/uapi/linux/netfilter/xt_LED.h
diff --git a/include/linux/netfilter/xt_LOG.h b/include/uapi/linux/netfilter/xt_LOG.h
index cac0790..cac0790 100644
--- a/include/linux/netfilter/xt_LOG.h
+++ b/include/uapi/linux/netfilter/xt_LOG.h
diff --git a/include/linux/netfilter/xt_MARK.h b/include/uapi/linux/netfilter/xt_MARK.h
index 41c456d..41c456d 100644
--- a/include/linux/netfilter/xt_MARK.h
+++ b/include/uapi/linux/netfilter/xt_MARK.h
diff --git a/include/linux/netfilter/xt_NFLOG.h b/include/uapi/linux/netfilter/xt_NFLOG.h
index 87b5831..87b5831 100644
--- a/include/linux/netfilter/xt_NFLOG.h
+++ b/include/uapi/linux/netfilter/xt_NFLOG.h
diff --git a/include/linux/netfilter/xt_NFQUEUE.h b/include/uapi/linux/netfilter/xt_NFQUEUE.h
index 9eafdbb..9eafdbb 100644
--- a/include/linux/netfilter/xt_NFQUEUE.h
+++ b/include/uapi/linux/netfilter/xt_NFQUEUE.h
diff --git a/include/linux/netfilter/xt_RATEEST.h b/include/uapi/linux/netfilter/xt_RATEEST.h
index 6605e20..6605e20 100644
--- a/include/linux/netfilter/xt_RATEEST.h
+++ b/include/uapi/linux/netfilter/xt_RATEEST.h
diff --git a/include/linux/netfilter/xt_SECMARK.h b/include/uapi/linux/netfilter/xt_SECMARK.h
index 989092b..989092b 100644
--- a/include/linux/netfilter/xt_SECMARK.h
+++ b/include/uapi/linux/netfilter/xt_SECMARK.h
diff --git a/include/linux/netfilter/xt_TCPMSS.h b/include/uapi/linux/netfilter/xt_TCPMSS.h
index 9a6960a..9a6960a 100644
--- a/include/linux/netfilter/xt_TCPMSS.h
+++ b/include/uapi/linux/netfilter/xt_TCPMSS.h
diff --git a/include/linux/netfilter/xt_TCPOPTSTRIP.h b/include/uapi/linux/netfilter/xt_TCPOPTSTRIP.h
index 7157318..7157318 100644
--- a/include/linux/netfilter/xt_TCPOPTSTRIP.h
+++ b/include/uapi/linux/netfilter/xt_TCPOPTSTRIP.h
diff --git a/include/linux/netfilter/xt_TEE.h b/include/uapi/linux/netfilter/xt_TEE.h
index 5c21d5c..5c21d5c 100644
--- a/include/linux/netfilter/xt_TEE.h
+++ b/include/uapi/linux/netfilter/xt_TEE.h
diff --git a/include/linux/netfilter/xt_TPROXY.h b/include/uapi/linux/netfilter/xt_TPROXY.h
index 902043c..902043c 100644
--- a/include/linux/netfilter/xt_TPROXY.h
+++ b/include/uapi/linux/netfilter/xt_TPROXY.h
diff --git a/include/linux/netfilter/xt_addrtype.h b/include/uapi/linux/netfilter/xt_addrtype.h
index b156baa..b156baa 100644
--- a/include/linux/netfilter/xt_addrtype.h
+++ b/include/uapi/linux/netfilter/xt_addrtype.h
diff --git a/include/linux/netfilter/xt_cluster.h b/include/uapi/linux/netfilter/xt_cluster.h
index 9b883c8..9b883c8 100644
--- a/include/linux/netfilter/xt_cluster.h
+++ b/include/uapi/linux/netfilter/xt_cluster.h
diff --git a/include/linux/netfilter/xt_comment.h b/include/uapi/linux/netfilter/xt_comment.h
index 0ea5e79..0ea5e79 100644
--- a/include/linux/netfilter/xt_comment.h
+++ b/include/uapi/linux/netfilter/xt_comment.h
diff --git a/include/linux/netfilter/xt_connbytes.h b/include/uapi/linux/netfilter/xt_connbytes.h
index f1d6c15..f1d6c15 100644
--- a/include/linux/netfilter/xt_connbytes.h
+++ b/include/uapi/linux/netfilter/xt_connbytes.h
diff --git a/include/linux/netfilter/xt_connlimit.h b/include/uapi/linux/netfilter/xt_connlimit.h
index f165609..f165609 100644
--- a/include/linux/netfilter/xt_connlimit.h
+++ b/include/uapi/linux/netfilter/xt_connlimit.h
diff --git a/include/linux/netfilter/xt_connmark.h b/include/uapi/linux/netfilter/xt_connmark.h
index efc17a8..efc17a8 100644
--- a/include/linux/netfilter/xt_connmark.h
+++ b/include/uapi/linux/netfilter/xt_connmark.h
diff --git a/include/linux/netfilter/xt_conntrack.h b/include/uapi/linux/netfilter/xt_conntrack.h
index e3c041d..e3c041d 100644
--- a/include/linux/netfilter/xt_conntrack.h
+++ b/include/uapi/linux/netfilter/xt_conntrack.h
diff --git a/include/linux/netfilter/xt_cpu.h b/include/uapi/linux/netfilter/xt_cpu.h
index 93c7f11..93c7f11 100644
--- a/include/linux/netfilter/xt_cpu.h
+++ b/include/uapi/linux/netfilter/xt_cpu.h
diff --git a/include/linux/netfilter/xt_dccp.h b/include/uapi/linux/netfilter/xt_dccp.h
index a579e1b..a579e1b 100644
--- a/include/linux/netfilter/xt_dccp.h
+++ b/include/uapi/linux/netfilter/xt_dccp.h
diff --git a/include/linux/netfilter/xt_devgroup.h b/include/uapi/linux/netfilter/xt_devgroup.h
index 1babde0..1babde0 100644
--- a/include/linux/netfilter/xt_devgroup.h
+++ b/include/uapi/linux/netfilter/xt_devgroup.h
diff --git a/include/linux/netfilter/xt_dscp.h b/include/uapi/linux/netfilter/xt_dscp.h
index 15f8932..15f8932 100644
--- a/include/linux/netfilter/xt_dscp.h
+++ b/include/uapi/linux/netfilter/xt_dscp.h
diff --git a/include/linux/netfilter/xt_ecn.h b/include/uapi/linux/netfilter/xt_ecn.h
index 7158fca..7158fca 100644
--- a/include/linux/netfilter/xt_ecn.h
+++ b/include/uapi/linux/netfilter/xt_ecn.h
diff --git a/include/linux/netfilter/xt_esp.h b/include/uapi/linux/netfilter/xt_esp.h
index ee68824..ee68824 100644
--- a/include/linux/netfilter/xt_esp.h
+++ b/include/uapi/linux/netfilter/xt_esp.h
diff --git a/include/uapi/linux/netfilter/xt_hashlimit.h b/include/uapi/linux/netfilter/xt_hashlimit.h
new file mode 100644
index 0000000..cbfc43d
--- /dev/null
+++ b/include/uapi/linux/netfilter/xt_hashlimit.h
@@ -0,0 +1,73 @@
+#ifndef _UAPI_XT_HASHLIMIT_H
+#define _UAPI_XT_HASHLIMIT_H
+
+#include <linux/types.h>
+
+/* timings are in milliseconds. */
+#define XT_HASHLIMIT_SCALE 10000
+/* 1/10,000 sec period => max of 10,000/sec. Min rate is then 429490
+ * seconds, or one packet every 59 hours.
+ */
+
+/* packet length accounting is done in 16-byte steps */
+#define XT_HASHLIMIT_BYTE_SHIFT 4
+
+/* details of this structure hidden by the implementation */
+struct xt_hashlimit_htable;
+
+enum {
+ XT_HASHLIMIT_HASH_DIP = 1 << 0,
+ XT_HASHLIMIT_HASH_DPT = 1 << 1,
+ XT_HASHLIMIT_HASH_SIP = 1 << 2,
+ XT_HASHLIMIT_HASH_SPT = 1 << 3,
+ XT_HASHLIMIT_INVERT = 1 << 4,
+ XT_HASHLIMIT_BYTES = 1 << 5,
+};
+
+struct hashlimit_cfg {
+ __u32 mode; /* bitmask of XT_HASHLIMIT_HASH_* */
+ __u32 avg; /* Average secs between packets * scale */
+ __u32 burst; /* Period multiplier for upper limit. */
+
+ /* user specified */
+ __u32 size; /* how many buckets */
+ __u32 max; /* max number of entries */
+ __u32 gc_interval; /* gc interval */
+ __u32 expire; /* when do entries expire? */
+};
+
+struct xt_hashlimit_info {
+ char name [IFNAMSIZ]; /* name */
+ struct hashlimit_cfg cfg;
+
+ /* Used internally by the kernel */
+ struct xt_hashlimit_htable *hinfo;
+ union {
+ void *ptr;
+ struct xt_hashlimit_info *master;
+ } u;
+};
+
+struct hashlimit_cfg1 {
+ __u32 mode; /* bitmask of XT_HASHLIMIT_HASH_* */
+ __u32 avg; /* Average secs between packets * scale */
+ __u32 burst; /* Period multiplier for upper limit. */
+
+ /* user specified */
+ __u32 size; /* how many buckets */
+ __u32 max; /* max number of entries */
+ __u32 gc_interval; /* gc interval */
+ __u32 expire; /* when do entries expire? */
+
+ __u8 srcmask, dstmask;
+};
+
+struct xt_hashlimit_mtinfo1 {
+ char name[IFNAMSIZ];
+ struct hashlimit_cfg1 cfg;
+
+ /* Used internally by the kernel */
+ struct xt_hashlimit_htable *hinfo __attribute__((aligned(8)));
+};
+
+#endif /* _UAPI_XT_HASHLIMIT_H */
diff --git a/include/linux/netfilter/xt_helper.h b/include/uapi/linux/netfilter/xt_helper.h
index 6b42763..6b42763 100644
--- a/include/linux/netfilter/xt_helper.h
+++ b/include/uapi/linux/netfilter/xt_helper.h
diff --git a/include/linux/netfilter/xt_iprange.h b/include/uapi/linux/netfilter/xt_iprange.h
index 25fd7cf..25fd7cf 100644
--- a/include/linux/netfilter/xt_iprange.h
+++ b/include/uapi/linux/netfilter/xt_iprange.h
diff --git a/include/linux/netfilter/xt_ipvs.h b/include/uapi/linux/netfilter/xt_ipvs.h
index eff34ac..eff34ac 100644
--- a/include/linux/netfilter/xt_ipvs.h
+++ b/include/uapi/linux/netfilter/xt_ipvs.h
diff --git a/include/linux/netfilter/xt_length.h b/include/uapi/linux/netfilter/xt_length.h
index b82ed7c..b82ed7c 100644
--- a/include/linux/netfilter/xt_length.h
+++ b/include/uapi/linux/netfilter/xt_length.h
diff --git a/include/linux/netfilter/xt_limit.h b/include/uapi/linux/netfilter/xt_limit.h
index bb47fc4..bb47fc4 100644
--- a/include/linux/netfilter/xt_limit.h
+++ b/include/uapi/linux/netfilter/xt_limit.h
diff --git a/include/linux/netfilter/xt_mac.h b/include/uapi/linux/netfilter/xt_mac.h
index b892cdc..b892cdc 100644
--- a/include/linux/netfilter/xt_mac.h
+++ b/include/uapi/linux/netfilter/xt_mac.h
diff --git a/include/linux/netfilter/xt_mark.h b/include/uapi/linux/netfilter/xt_mark.h
index ecadc40..ecadc40 100644
--- a/include/linux/netfilter/xt_mark.h
+++ b/include/uapi/linux/netfilter/xt_mark.h
diff --git a/include/linux/netfilter/xt_multiport.h b/include/uapi/linux/netfilter/xt_multiport.h
index 5b7e72d..5b7e72d 100644
--- a/include/linux/netfilter/xt_multiport.h
+++ b/include/uapi/linux/netfilter/xt_multiport.h
diff --git a/include/linux/netfilter/xt_nfacct.h b/include/uapi/linux/netfilter/xt_nfacct.h
index 3e19c8a..3e19c8a 100644
--- a/include/linux/netfilter/xt_nfacct.h
+++ b/include/uapi/linux/netfilter/xt_nfacct.h
diff --git a/include/linux/netfilter/xt_osf.h b/include/uapi/linux/netfilter/xt_osf.h
index 18afa49..18afa49 100644
--- a/include/linux/netfilter/xt_osf.h
+++ b/include/uapi/linux/netfilter/xt_osf.h
diff --git a/include/linux/netfilter/xt_owner.h b/include/uapi/linux/netfilter/xt_owner.h
index 2081761..2081761 100644
--- a/include/linux/netfilter/xt_owner.h
+++ b/include/uapi/linux/netfilter/xt_owner.h
diff --git a/include/uapi/linux/netfilter/xt_physdev.h b/include/uapi/linux/netfilter/xt_physdev.h
new file mode 100644
index 0000000..db7a298
--- /dev/null
+++ b/include/uapi/linux/netfilter/xt_physdev.h
@@ -0,0 +1,23 @@
+#ifndef _UAPI_XT_PHYSDEV_H
+#define _UAPI_XT_PHYSDEV_H
+
+#include <linux/types.h>
+
+
+#define XT_PHYSDEV_OP_IN 0x01
+#define XT_PHYSDEV_OP_OUT 0x02
+#define XT_PHYSDEV_OP_BRIDGED 0x04
+#define XT_PHYSDEV_OP_ISIN 0x08
+#define XT_PHYSDEV_OP_ISOUT 0x10
+#define XT_PHYSDEV_OP_MASK (0x20 - 1)
+
+struct xt_physdev_info {
+ char physindev[IFNAMSIZ];
+ char in_mask[IFNAMSIZ];
+ char physoutdev[IFNAMSIZ];
+ char out_mask[IFNAMSIZ];
+ __u8 invert;
+ __u8 bitmask;
+};
+
+#endif /* _UAPI_XT_PHYSDEV_H */
diff --git a/include/linux/netfilter/xt_pkttype.h b/include/uapi/linux/netfilter/xt_pkttype.h
index f265cf5..f265cf5 100644
--- a/include/linux/netfilter/xt_pkttype.h
+++ b/include/uapi/linux/netfilter/xt_pkttype.h
diff --git a/include/linux/netfilter/xt_policy.h b/include/uapi/linux/netfilter/xt_policy.h
index be8ead0..be8ead0 100644
--- a/include/linux/netfilter/xt_policy.h
+++ b/include/uapi/linux/netfilter/xt_policy.h
diff --git a/include/linux/netfilter/xt_quota.h b/include/uapi/linux/netfilter/xt_quota.h
index 9314723..9314723 100644
--- a/include/linux/netfilter/xt_quota.h
+++ b/include/uapi/linux/netfilter/xt_quota.h
diff --git a/include/linux/netfilter/xt_rateest.h b/include/uapi/linux/netfilter/xt_rateest.h
index d40a619..d40a619 100644
--- a/include/linux/netfilter/xt_rateest.h
+++ b/include/uapi/linux/netfilter/xt_rateest.h
diff --git a/include/linux/netfilter/xt_realm.h b/include/uapi/linux/netfilter/xt_realm.h
index d4a82ee..d4a82ee 100644
--- a/include/linux/netfilter/xt_realm.h
+++ b/include/uapi/linux/netfilter/xt_realm.h
diff --git a/include/linux/netfilter/xt_recent.h b/include/uapi/linux/netfilter/xt_recent.h
index 6ef36c1..6ef36c1 100644
--- a/include/linux/netfilter/xt_recent.h
+++ b/include/uapi/linux/netfilter/xt_recent.h
diff --git a/include/linux/netfilter/xt_sctp.h b/include/uapi/linux/netfilter/xt_sctp.h
index 29287be..29287be 100644
--- a/include/linux/netfilter/xt_sctp.h
+++ b/include/uapi/linux/netfilter/xt_sctp.h
diff --git a/include/linux/netfilter/xt_set.h b/include/uapi/linux/netfilter/xt_set.h
index e3a9978..e3a9978 100644
--- a/include/linux/netfilter/xt_set.h
+++ b/include/uapi/linux/netfilter/xt_set.h
diff --git a/include/linux/netfilter/xt_socket.h b/include/uapi/linux/netfilter/xt_socket.h
index 26d7217..26d7217 100644
--- a/include/linux/netfilter/xt_socket.h
+++ b/include/uapi/linux/netfilter/xt_socket.h
diff --git a/include/linux/netfilter/xt_state.h b/include/uapi/linux/netfilter/xt_state.h
index 7b32de8..7b32de8 100644
--- a/include/linux/netfilter/xt_state.h
+++ b/include/uapi/linux/netfilter/xt_state.h
diff --git a/include/linux/netfilter/xt_statistic.h b/include/uapi/linux/netfilter/xt_statistic.h
index 4e983ef..4e983ef 100644
--- a/include/linux/netfilter/xt_statistic.h
+++ b/include/uapi/linux/netfilter/xt_statistic.h
diff --git a/include/linux/netfilter/xt_string.h b/include/uapi/linux/netfilter/xt_string.h
index 235347c..235347c 100644
--- a/include/linux/netfilter/xt_string.h
+++ b/include/uapi/linux/netfilter/xt_string.h
diff --git a/include/linux/netfilter/xt_tcpmss.h b/include/uapi/linux/netfilter/xt_tcpmss.h
index fbac56b..fbac56b 100644
--- a/include/linux/netfilter/xt_tcpmss.h
+++ b/include/uapi/linux/netfilter/xt_tcpmss.h
diff --git a/include/linux/netfilter/xt_tcpudp.h b/include/uapi/linux/netfilter/xt_tcpudp.h
index 38aa7b3..38aa7b3 100644
--- a/include/linux/netfilter/xt_tcpudp.h
+++ b/include/uapi/linux/netfilter/xt_tcpudp.h
diff --git a/include/linux/netfilter/xt_time.h b/include/uapi/linux/netfilter/xt_time.h
index 0958860..0958860 100644
--- a/include/linux/netfilter/xt_time.h
+++ b/include/uapi/linux/netfilter/xt_time.h
diff --git a/include/linux/netfilter/xt_u32.h b/include/uapi/linux/netfilter/xt_u32.h
index 04d1bfe..04d1bfe 100644
--- a/include/linux/netfilter/xt_u32.h
+++ b/include/uapi/linux/netfilter/xt_u32.h
diff --git a/include/uapi/linux/netfilter_arp/Kbuild b/include/uapi/linux/netfilter_arp/Kbuild
index aafaa5a..62d5637 100644
--- a/include/uapi/linux/netfilter_arp/Kbuild
+++ b/include/uapi/linux/netfilter_arp/Kbuild
@@ -1 +1,3 @@
# UAPI Header export list
+header-y += arp_tables.h
+header-y += arpt_mangle.h
diff --git a/include/uapi/linux/netfilter_arp/arp_tables.h b/include/uapi/linux/netfilter_arp/arp_tables.h
new file mode 100644
index 0000000..a5a86a4
--- /dev/null
+++ b/include/uapi/linux/netfilter_arp/arp_tables.h
@@ -0,0 +1,206 @@
+/*
+ * Format of an ARP firewall descriptor
+ *
+ * src, tgt, src_mask, tgt_mask, arpop, arpop_mask are always stored in
+ * network byte order.
+ * flags are stored in host byte order (of course).
+ */
+
+#ifndef _UAPI_ARPTABLES_H
+#define _UAPI_ARPTABLES_H
+
+#include <linux/types.h>
+#include <linux/compiler.h>
+#include <linux/netfilter_arp.h>
+
+#include <linux/netfilter/x_tables.h>
+
+#ifndef __KERNEL__
+#define ARPT_FUNCTION_MAXNAMELEN XT_FUNCTION_MAXNAMELEN
+#define ARPT_TABLE_MAXNAMELEN XT_TABLE_MAXNAMELEN
+#define arpt_entry_target xt_entry_target
+#define arpt_standard_target xt_standard_target
+#define arpt_error_target xt_error_target
+#define ARPT_CONTINUE XT_CONTINUE
+#define ARPT_RETURN XT_RETURN
+#define arpt_counters_info xt_counters_info
+#define arpt_counters xt_counters
+#define ARPT_STANDARD_TARGET XT_STANDARD_TARGET
+#define ARPT_ERROR_TARGET XT_ERROR_TARGET
+#define ARPT_ENTRY_ITERATE(entries, size, fn, args...) \
+ XT_ENTRY_ITERATE(struct arpt_entry, entries, size, fn, ## args)
+#endif
+
+#define ARPT_DEV_ADDR_LEN_MAX 16
+
+struct arpt_devaddr_info {
+ char addr[ARPT_DEV_ADDR_LEN_MAX];
+ char mask[ARPT_DEV_ADDR_LEN_MAX];
+};
+
+/* Yes, Virginia, you have to zero the padding. */
+struct arpt_arp {
+ /* Source and target IP addr */
+ struct in_addr src, tgt;
+ /* Mask for src and target IP addr */
+ struct in_addr smsk, tmsk;
+
+ /* Device hw address length, src+target device addresses */
+ __u8 arhln, arhln_mask;
+ struct arpt_devaddr_info src_devaddr;
+ struct arpt_devaddr_info tgt_devaddr;
+
+ /* ARP operation code. */
+ __be16 arpop, arpop_mask;
+
+ /* ARP hardware address and protocol address format. */
+ __be16 arhrd, arhrd_mask;
+ __be16 arpro, arpro_mask;
+
+ /* The protocol address length is only accepted if it is 4
+ * so there is no use in offering a way to do filtering on it.
+ */
+
+ char iniface[IFNAMSIZ], outiface[IFNAMSIZ];
+ unsigned char iniface_mask[IFNAMSIZ], outiface_mask[IFNAMSIZ];
+
+ /* Flags word */
+ __u8 flags;
+ /* Inverse flags */
+ __u16 invflags;
+};
+
+/* Values for "flag" field in struct arpt_ip (general arp structure).
+ * No flags defined yet.
+ */
+#define ARPT_F_MASK 0x00 /* All possible flag bits mask. */
+
+/* Values for "inv" field in struct arpt_arp. */
+#define ARPT_INV_VIA_IN 0x0001 /* Invert the sense of IN IFACE. */
+#define ARPT_INV_VIA_OUT 0x0002 /* Invert the sense of OUT IFACE */
+#define ARPT_INV_SRCIP 0x0004 /* Invert the sense of SRC IP. */
+#define ARPT_INV_TGTIP 0x0008 /* Invert the sense of TGT IP. */
+#define ARPT_INV_SRCDEVADDR 0x0010 /* Invert the sense of SRC DEV ADDR. */
+#define ARPT_INV_TGTDEVADDR 0x0020 /* Invert the sense of TGT DEV ADDR. */
+#define ARPT_INV_ARPOP 0x0040 /* Invert the sense of ARP OP. */
+#define ARPT_INV_ARPHRD 0x0080 /* Invert the sense of ARP HRD. */
+#define ARPT_INV_ARPPRO 0x0100 /* Invert the sense of ARP PRO. */
+#define ARPT_INV_ARPHLN 0x0200 /* Invert the sense of ARP HLN. */
+#define ARPT_INV_MASK 0x03FF /* All possible flag bits mask. */
+
+/* This structure defines each of the firewall rules. Consists of 3
+ parts which are 1) general ARP header stuff 2) match specific
+ stuff 3) the target to perform if the rule matches */
+struct arpt_entry
+{
+ struct arpt_arp arp;
+
+ /* Size of arpt_entry + matches */
+ __u16 target_offset;
+ /* Size of arpt_entry + matches + target */
+ __u16 next_offset;
+
+ /* Back pointer */
+ unsigned int comefrom;
+
+ /* Packet and byte counters. */
+ struct xt_counters counters;
+
+ /* The matches (if any), then the target. */
+ unsigned char elems[0];
+};
+
+/*
+ * New IP firewall options for [gs]etsockopt at the RAW IP level.
+ * Unlike BSD Linux inherits IP options so you don't have to use a raw
+ * socket for this. Instead we check rights in the calls.
+ *
+ * ATTENTION: check linux/in.h before adding new number here.
+ */
+#define ARPT_BASE_CTL 96
+
+#define ARPT_SO_SET_REPLACE (ARPT_BASE_CTL)
+#define ARPT_SO_SET_ADD_COUNTERS (ARPT_BASE_CTL + 1)
+#define ARPT_SO_SET_MAX ARPT_SO_SET_ADD_COUNTERS
+
+#define ARPT_SO_GET_INFO (ARPT_BASE_CTL)
+#define ARPT_SO_GET_ENTRIES (ARPT_BASE_CTL + 1)
+/* #define ARPT_SO_GET_REVISION_MATCH (APRT_BASE_CTL + 2) */
+#define ARPT_SO_GET_REVISION_TARGET (ARPT_BASE_CTL + 3)
+#define ARPT_SO_GET_MAX (ARPT_SO_GET_REVISION_TARGET)
+
+/* The argument to ARPT_SO_GET_INFO */
+struct arpt_getinfo {
+ /* Which table: caller fills this in. */
+ char name[XT_TABLE_MAXNAMELEN];
+
+ /* Kernel fills these in. */
+ /* Which hook entry points are valid: bitmask */
+ unsigned int valid_hooks;
+
+ /* Hook entry points: one per netfilter hook. */
+ unsigned int hook_entry[NF_ARP_NUMHOOKS];
+
+ /* Underflow points. */
+ unsigned int underflow[NF_ARP_NUMHOOKS];
+
+ /* Number of entries */
+ unsigned int num_entries;
+
+ /* Size of entries. */
+ unsigned int size;
+};
+
+/* The argument to ARPT_SO_SET_REPLACE. */
+struct arpt_replace {
+ /* Which table. */
+ char name[XT_TABLE_MAXNAMELEN];
+
+ /* Which hook entry points are valid: bitmask. You can't
+ change this. */
+ unsigned int valid_hooks;
+
+ /* Number of entries */
+ unsigned int num_entries;
+
+ /* Total size of new entries */
+ unsigned int size;
+
+ /* Hook entry points. */
+ unsigned int hook_entry[NF_ARP_NUMHOOKS];
+
+ /* Underflow points. */
+ unsigned int underflow[NF_ARP_NUMHOOKS];
+
+ /* Information about old entries: */
+ /* Number of counters (must be equal to current number of entries). */
+ unsigned int num_counters;
+ /* The old entries' counters. */
+ struct xt_counters __user *counters;
+
+ /* The entries (hang off end: not really an array). */
+ struct arpt_entry entries[0];
+};
+
+/* The argument to ARPT_SO_GET_ENTRIES. */
+struct arpt_get_entries {
+ /* Which table: user fills this in. */
+ char name[XT_TABLE_MAXNAMELEN];
+
+ /* User fills this in: total entry size. */
+ unsigned int size;
+
+ /* The entries. */
+ struct arpt_entry entrytable[0];
+};
+
+/* Helper functions */
+static __inline__ struct xt_entry_target *arpt_get_target(struct arpt_entry *e)
+{
+ return (void *)e + e->target_offset;
+}
+
+/*
+ * Main firewall chains definitions and global var's definitions.
+ */
+#endif /* _UAPI_ARPTABLES_H */
diff --git a/include/linux/netfilter_arp/arpt_mangle.h b/include/uapi/linux/netfilter_arp/arpt_mangle.h
index 250f502..250f502 100644
--- a/include/linux/netfilter_arp/arpt_mangle.h
+++ b/include/uapi/linux/netfilter_arp/arpt_mangle.h
diff --git a/include/uapi/linux/netfilter_bridge/Kbuild b/include/uapi/linux/netfilter_bridge/Kbuild
index aafaa5a..348717c 100644
--- a/include/uapi/linux/netfilter_bridge/Kbuild
+++ b/include/uapi/linux/netfilter_bridge/Kbuild
@@ -1 +1,19 @@
# UAPI Header export list
+header-y += ebt_802_3.h
+header-y += ebt_among.h
+header-y += ebt_arp.h
+header-y += ebt_arpreply.h
+header-y += ebt_ip.h
+header-y += ebt_ip6.h
+header-y += ebt_limit.h
+header-y += ebt_log.h
+header-y += ebt_mark_m.h
+header-y += ebt_mark_t.h
+header-y += ebt_nat.h
+header-y += ebt_nflog.h
+header-y += ebt_pkttype.h
+header-y += ebt_redirect.h
+header-y += ebt_stp.h
+header-y += ebt_ulog.h
+header-y += ebt_vlan.h
+header-y += ebtables.h
diff --git a/include/uapi/linux/netfilter_bridge/ebt_802_3.h b/include/uapi/linux/netfilter_bridge/ebt_802_3.h
new file mode 100644
index 0000000..5bf8491
--- /dev/null
+++ b/include/uapi/linux/netfilter_bridge/ebt_802_3.h
@@ -0,0 +1,62 @@
+#ifndef _UAPI__LINUX_BRIDGE_EBT_802_3_H
+#define _UAPI__LINUX_BRIDGE_EBT_802_3_H
+
+#include <linux/types.h>
+
+#define EBT_802_3_SAP 0x01
+#define EBT_802_3_TYPE 0x02
+
+#define EBT_802_3_MATCH "802_3"
+
+/*
+ * If frame has DSAP/SSAP value 0xaa you must check the SNAP type
+ * to discover what kind of packet we're carrying.
+ */
+#define CHECK_TYPE 0xaa
+
+/*
+ * Control field may be one or two bytes. If the first byte has
+ * the value 0x03 then the entire length is one byte, otherwise it is two.
+ * One byte controls are used in Unnumbered Information frames.
+ * Two byte controls are used in Numbered Information frames.
+ */
+#define IS_UI 0x03
+
+#define EBT_802_3_MASK (EBT_802_3_SAP | EBT_802_3_TYPE | EBT_802_3)
+
+/* ui has one byte ctrl, ni has two */
+struct hdr_ui {
+ __u8 dsap;
+ __u8 ssap;
+ __u8 ctrl;
+ __u8 orig[3];
+ __be16 type;
+};
+
+struct hdr_ni {
+ __u8 dsap;
+ __u8 ssap;
+ __be16 ctrl;
+ __u8 orig[3];
+ __be16 type;
+};
+
+struct ebt_802_3_hdr {
+ __u8 daddr[6];
+ __u8 saddr[6];
+ __be16 len;
+ union {
+ struct hdr_ui ui;
+ struct hdr_ni ni;
+ } llc;
+};
+
+
+struct ebt_802_3_info {
+ __u8 sap;
+ __be16 type;
+ __u8 bitmask;
+ __u8 invflags;
+};
+
+#endif /* _UAPI__LINUX_BRIDGE_EBT_802_3_H */
diff --git a/include/linux/netfilter_bridge/ebt_among.h b/include/uapi/linux/netfilter_bridge/ebt_among.h
index bd4e3ad..bd4e3ad 100644
--- a/include/linux/netfilter_bridge/ebt_among.h
+++ b/include/uapi/linux/netfilter_bridge/ebt_among.h
diff --git a/include/linux/netfilter_bridge/ebt_arp.h b/include/uapi/linux/netfilter_bridge/ebt_arp.h
index 522f3e4..522f3e4 100644
--- a/include/linux/netfilter_bridge/ebt_arp.h
+++ b/include/uapi/linux/netfilter_bridge/ebt_arp.h
diff --git a/include/linux/netfilter_bridge/ebt_arpreply.h b/include/uapi/linux/netfilter_bridge/ebt_arpreply.h
index 7e77896..7e77896 100644
--- a/include/linux/netfilter_bridge/ebt_arpreply.h
+++ b/include/uapi/linux/netfilter_bridge/ebt_arpreply.h
diff --git a/include/linux/netfilter_bridge/ebt_ip.h b/include/uapi/linux/netfilter_bridge/ebt_ip.h
index c4bbc41..c4bbc41 100644
--- a/include/linux/netfilter_bridge/ebt_ip.h
+++ b/include/uapi/linux/netfilter_bridge/ebt_ip.h
diff --git a/include/linux/netfilter_bridge/ebt_ip6.h b/include/uapi/linux/netfilter_bridge/ebt_ip6.h
index 42b8896..42b8896 100644
--- a/include/linux/netfilter_bridge/ebt_ip6.h
+++ b/include/uapi/linux/netfilter_bridge/ebt_ip6.h
diff --git a/include/linux/netfilter_bridge/ebt_limit.h b/include/uapi/linux/netfilter_bridge/ebt_limit.h
index 66d80b3..66d80b3 100644
--- a/include/linux/netfilter_bridge/ebt_limit.h
+++ b/include/uapi/linux/netfilter_bridge/ebt_limit.h
diff --git a/include/linux/netfilter_bridge/ebt_log.h b/include/uapi/linux/netfilter_bridge/ebt_log.h
index 7e7f1d1..7e7f1d1 100644
--- a/include/linux/netfilter_bridge/ebt_log.h
+++ b/include/uapi/linux/netfilter_bridge/ebt_log.h
diff --git a/include/linux/netfilter_bridge/ebt_mark_m.h b/include/uapi/linux/netfilter_bridge/ebt_mark_m.h
index 410f9e5..410f9e5 100644
--- a/include/linux/netfilter_bridge/ebt_mark_m.h
+++ b/include/uapi/linux/netfilter_bridge/ebt_mark_m.h
diff --git a/include/linux/netfilter_bridge/ebt_mark_t.h b/include/uapi/linux/netfilter_bridge/ebt_mark_t.h
index 7d5a268..7d5a268 100644
--- a/include/linux/netfilter_bridge/ebt_mark_t.h
+++ b/include/uapi/linux/netfilter_bridge/ebt_mark_t.h
diff --git a/include/linux/netfilter_bridge/ebt_nat.h b/include/uapi/linux/netfilter_bridge/ebt_nat.h
index 5e74e3b..5e74e3b 100644
--- a/include/linux/netfilter_bridge/ebt_nat.h
+++ b/include/uapi/linux/netfilter_bridge/ebt_nat.h
diff --git a/include/linux/netfilter_bridge/ebt_nflog.h b/include/uapi/linux/netfilter_bridge/ebt_nflog.h
index df829fc..df829fc 100644
--- a/include/linux/netfilter_bridge/ebt_nflog.h
+++ b/include/uapi/linux/netfilter_bridge/ebt_nflog.h
diff --git a/include/linux/netfilter_bridge/ebt_pkttype.h b/include/uapi/linux/netfilter_bridge/ebt_pkttype.h
index c241bad..c241bad 100644
--- a/include/linux/netfilter_bridge/ebt_pkttype.h
+++ b/include/uapi/linux/netfilter_bridge/ebt_pkttype.h
diff --git a/include/linux/netfilter_bridge/ebt_redirect.h b/include/uapi/linux/netfilter_bridge/ebt_redirect.h
index dd9622c..dd9622c 100644
--- a/include/linux/netfilter_bridge/ebt_redirect.h
+++ b/include/uapi/linux/netfilter_bridge/ebt_redirect.h
diff --git a/include/linux/netfilter_bridge/ebt_stp.h b/include/uapi/linux/netfilter_bridge/ebt_stp.h
index 1025b9f..1025b9f 100644
--- a/include/linux/netfilter_bridge/ebt_stp.h
+++ b/include/uapi/linux/netfilter_bridge/ebt_stp.h
diff --git a/include/linux/netfilter_bridge/ebt_ulog.h b/include/uapi/linux/netfilter_bridge/ebt_ulog.h
index 89a6bec..89a6bec 100644
--- a/include/linux/netfilter_bridge/ebt_ulog.h
+++ b/include/uapi/linux/netfilter_bridge/ebt_ulog.h
diff --git a/include/linux/netfilter_bridge/ebt_vlan.h b/include/uapi/linux/netfilter_bridge/ebt_vlan.h
index 967d1d5..967d1d5 100644
--- a/include/linux/netfilter_bridge/ebt_vlan.h
+++ b/include/uapi/linux/netfilter_bridge/ebt_vlan.h
diff --git a/include/uapi/linux/netfilter_bridge/ebtables.h b/include/uapi/linux/netfilter_bridge/ebtables.h
new file mode 100644
index 0000000..ba99336
--- /dev/null
+++ b/include/uapi/linux/netfilter_bridge/ebtables.h
@@ -0,0 +1,268 @@
+/*
+ * ebtables
+ *
+ * Authors:
+ * Bart De Schuymer <bdschuym@pandora.be>
+ *
+ * ebtables.c,v 2.0, April, 2002
+ *
+ * This code is stongly inspired on the iptables code which is
+ * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
+ */
+
+#ifndef _UAPI__LINUX_BRIDGE_EFF_H
+#define _UAPI__LINUX_BRIDGE_EFF_H
+#include <linux/if.h>
+#include <linux/netfilter_bridge.h>
+#include <linux/if_ether.h>
+
+#define EBT_TABLE_MAXNAMELEN 32
+#define EBT_CHAIN_MAXNAMELEN EBT_TABLE_MAXNAMELEN
+#define EBT_FUNCTION_MAXNAMELEN EBT_TABLE_MAXNAMELEN
+
+/* verdicts >0 are "branches" */
+#define EBT_ACCEPT -1
+#define EBT_DROP -2
+#define EBT_CONTINUE -3
+#define EBT_RETURN -4
+#define NUM_STANDARD_TARGETS 4
+/* ebtables target modules store the verdict inside an int. We can
+ * reclaim a part of this int for backwards compatible extensions.
+ * The 4 lsb are more than enough to store the verdict. */
+#define EBT_VERDICT_BITS 0x0000000F
+
+struct xt_match;
+struct xt_target;
+
+struct ebt_counter {
+ uint64_t pcnt;
+ uint64_t bcnt;
+};
+
+struct ebt_replace {
+ char name[EBT_TABLE_MAXNAMELEN];
+ unsigned int valid_hooks;
+ /* nr of rules in the table */
+ unsigned int nentries;
+ /* total size of the entries */
+ unsigned int entries_size;
+ /* start of the chains */
+ struct ebt_entries __user *hook_entry[NF_BR_NUMHOOKS];
+ /* nr of counters userspace expects back */
+ unsigned int num_counters;
+ /* where the kernel will put the old counters */
+ struct ebt_counter __user *counters;
+ char __user *entries;
+};
+
+struct ebt_replace_kernel {
+ char name[EBT_TABLE_MAXNAMELEN];
+ unsigned int valid_hooks;
+ /* nr of rules in the table */
+ unsigned int nentries;
+ /* total size of the entries */
+ unsigned int entries_size;
+ /* start of the chains */
+ struct ebt_entries *hook_entry[NF_BR_NUMHOOKS];
+ /* nr of counters userspace expects back */
+ unsigned int num_counters;
+ /* where the kernel will put the old counters */
+ struct ebt_counter *counters;
+ char *entries;
+};
+
+struct ebt_entries {
+ /* this field is always set to zero
+ * See EBT_ENTRY_OR_ENTRIES.
+ * Must be same size as ebt_entry.bitmask */
+ unsigned int distinguisher;
+ /* the chain name */
+ char name[EBT_CHAIN_MAXNAMELEN];
+ /* counter offset for this chain */
+ unsigned int counter_offset;
+ /* one standard (accept, drop, return) per hook */
+ int policy;
+ /* nr. of entries */
+ unsigned int nentries;
+ /* entry list */
+ char data[0] __attribute__ ((aligned (__alignof__(struct ebt_replace))));
+};
+
+/* used for the bitmask of struct ebt_entry */
+
+/* This is a hack to make a difference between an ebt_entry struct and an
+ * ebt_entries struct when traversing the entries from start to end.
+ * Using this simplifies the code a lot, while still being able to use
+ * ebt_entries.
+ * Contrary, iptables doesn't use something like ebt_entries and therefore uses
+ * different techniques for naming the policy and such. So, iptables doesn't
+ * need a hack like this.
+ */
+#define EBT_ENTRY_OR_ENTRIES 0x01
+/* these are the normal masks */
+#define EBT_NOPROTO 0x02
+#define EBT_802_3 0x04
+#define EBT_SOURCEMAC 0x08
+#define EBT_DESTMAC 0x10
+#define EBT_F_MASK (EBT_NOPROTO | EBT_802_3 | EBT_SOURCEMAC | EBT_DESTMAC \
+ | EBT_ENTRY_OR_ENTRIES)
+
+#define EBT_IPROTO 0x01
+#define EBT_IIN 0x02
+#define EBT_IOUT 0x04
+#define EBT_ISOURCE 0x8
+#define EBT_IDEST 0x10
+#define EBT_ILOGICALIN 0x20
+#define EBT_ILOGICALOUT 0x40
+#define EBT_INV_MASK (EBT_IPROTO | EBT_IIN | EBT_IOUT | EBT_ILOGICALIN \
+ | EBT_ILOGICALOUT | EBT_ISOURCE | EBT_IDEST)
+
+struct ebt_entry_match {
+ union {
+ char name[EBT_FUNCTION_MAXNAMELEN];
+ struct xt_match *match;
+ } u;
+ /* size of data */
+ unsigned int match_size;
+ unsigned char data[0] __attribute__ ((aligned (__alignof__(struct ebt_replace))));
+};
+
+struct ebt_entry_watcher {
+ union {
+ char name[EBT_FUNCTION_MAXNAMELEN];
+ struct xt_target *watcher;
+ } u;
+ /* size of data */
+ unsigned int watcher_size;
+ unsigned char data[0] __attribute__ ((aligned (__alignof__(struct ebt_replace))));
+};
+
+struct ebt_entry_target {
+ union {
+ char name[EBT_FUNCTION_MAXNAMELEN];
+ struct xt_target *target;
+ } u;
+ /* size of data */
+ unsigned int target_size;
+ unsigned char data[0] __attribute__ ((aligned (__alignof__(struct ebt_replace))));
+};
+
+#define EBT_STANDARD_TARGET "standard"
+struct ebt_standard_target {
+ struct ebt_entry_target target;
+ int verdict;
+};
+
+/* one entry */
+struct ebt_entry {
+ /* this needs to be the first field */
+ unsigned int bitmask;
+ unsigned int invflags;
+ __be16 ethproto;
+ /* the physical in-dev */
+ char in[IFNAMSIZ];
+ /* the logical in-dev */
+ char logical_in[IFNAMSIZ];
+ /* the physical out-dev */
+ char out[IFNAMSIZ];
+ /* the logical out-dev */
+ char logical_out[IFNAMSIZ];
+ unsigned char sourcemac[ETH_ALEN];
+ unsigned char sourcemsk[ETH_ALEN];
+ unsigned char destmac[ETH_ALEN];
+ unsigned char destmsk[ETH_ALEN];
+ /* sizeof ebt_entry + matches */
+ unsigned int watchers_offset;
+ /* sizeof ebt_entry + matches + watchers */
+ unsigned int target_offset;
+ /* sizeof ebt_entry + matches + watchers + target */
+ unsigned int next_offset;
+ unsigned char elems[0] __attribute__ ((aligned (__alignof__(struct ebt_replace))));
+};
+
+/* {g,s}etsockopt numbers */
+#define EBT_BASE_CTL 128
+
+#define EBT_SO_SET_ENTRIES (EBT_BASE_CTL)
+#define EBT_SO_SET_COUNTERS (EBT_SO_SET_ENTRIES+1)
+#define EBT_SO_SET_MAX (EBT_SO_SET_COUNTERS+1)
+
+#define EBT_SO_GET_INFO (EBT_BASE_CTL)
+#define EBT_SO_GET_ENTRIES (EBT_SO_GET_INFO+1)
+#define EBT_SO_GET_INIT_INFO (EBT_SO_GET_ENTRIES+1)
+#define EBT_SO_GET_INIT_ENTRIES (EBT_SO_GET_INIT_INFO+1)
+#define EBT_SO_GET_MAX (EBT_SO_GET_INIT_ENTRIES+1)
+
+
+/* blatently stolen from ip_tables.h
+ * fn returns 0 to continue iteration */
+#define EBT_MATCH_ITERATE(e, fn, args...) \
+({ \
+ unsigned int __i; \
+ int __ret = 0; \
+ struct ebt_entry_match *__match; \
+ \
+ for (__i = sizeof(struct ebt_entry); \
+ __i < (e)->watchers_offset; \
+ __i += __match->match_size + \
+ sizeof(struct ebt_entry_match)) { \
+ __match = (void *)(e) + __i; \
+ \
+ __ret = fn(__match , ## args); \
+ if (__ret != 0) \
+ break; \
+ } \
+ if (__ret == 0) { \
+ if (__i != (e)->watchers_offset) \
+ __ret = -EINVAL; \
+ } \
+ __ret; \
+})
+
+#define EBT_WATCHER_ITERATE(e, fn, args...) \
+({ \
+ unsigned int __i; \
+ int __ret = 0; \
+ struct ebt_entry_watcher *__watcher; \
+ \
+ for (__i = e->watchers_offset; \
+ __i < (e)->target_offset; \
+ __i += __watcher->watcher_size + \
+ sizeof(struct ebt_entry_watcher)) { \
+ __watcher = (void *)(e) + __i; \
+ \
+ __ret = fn(__watcher , ## args); \
+ if (__ret != 0) \
+ break; \
+ } \
+ if (__ret == 0) { \
+ if (__i != (e)->target_offset) \
+ __ret = -EINVAL; \
+ } \
+ __ret; \
+})
+
+#define EBT_ENTRY_ITERATE(entries, size, fn, args...) \
+({ \
+ unsigned int __i; \
+ int __ret = 0; \
+ struct ebt_entry *__entry; \
+ \
+ for (__i = 0; __i < (size);) { \
+ __entry = (void *)(entries) + __i; \
+ __ret = fn(__entry , ## args); \
+ if (__ret != 0) \
+ break; \
+ if (__entry->bitmask != 0) \
+ __i += __entry->next_offset; \
+ else \
+ __i += sizeof(struct ebt_entries); \
+ } \
+ if (__ret == 0) { \
+ if (__i != (size)) \
+ __ret = -EINVAL; \
+ } \
+ __ret; \
+})
+
+#endif /* _UAPI__LINUX_BRIDGE_EFF_H */
diff --git a/include/uapi/linux/netfilter_ipv4/Kbuild b/include/uapi/linux/netfilter_ipv4/Kbuild
index aafaa5a..fb00843 100644
--- a/include/uapi/linux/netfilter_ipv4/Kbuild
+++ b/include/uapi/linux/netfilter_ipv4/Kbuild
@@ -1 +1,11 @@
# UAPI Header export list
+header-y += ip_tables.h
+header-y += ipt_CLUSTERIP.h
+header-y += ipt_ECN.h
+header-y += ipt_LOG.h
+header-y += ipt_REJECT.h
+header-y += ipt_TTL.h
+header-y += ipt_ULOG.h
+header-y += ipt_ah.h
+header-y += ipt_ecn.h
+header-y += ipt_ttl.h
diff --git a/include/uapi/linux/netfilter_ipv4/ip_tables.h b/include/uapi/linux/netfilter_ipv4/ip_tables.h
new file mode 100644
index 0000000..f1e6ef2
--- /dev/null
+++ b/include/uapi/linux/netfilter_ipv4/ip_tables.h
@@ -0,0 +1,229 @@
+/*
+ * 25-Jul-1998 Major changes to allow for ip chain table
+ *
+ * 3-Jan-2000 Named tables to allow packet selection for different uses.
+ */
+
+/*
+ * Format of an IP firewall descriptor
+ *
+ * src, dst, src_mask, dst_mask are always stored in network byte order.
+ * flags are stored in host byte order (of course).
+ * Port numbers are stored in HOST byte order.
+ */
+
+#ifndef _UAPI_IPTABLES_H
+#define _UAPI_IPTABLES_H
+
+#include <linux/types.h>
+#include <linux/compiler.h>
+#include <linux/netfilter_ipv4.h>
+
+#include <linux/netfilter/x_tables.h>
+
+#ifndef __KERNEL__
+#define IPT_FUNCTION_MAXNAMELEN XT_FUNCTION_MAXNAMELEN
+#define IPT_TABLE_MAXNAMELEN XT_TABLE_MAXNAMELEN
+#define ipt_match xt_match
+#define ipt_target xt_target
+#define ipt_table xt_table
+#define ipt_get_revision xt_get_revision
+#define ipt_entry_match xt_entry_match
+#define ipt_entry_target xt_entry_target
+#define ipt_standard_target xt_standard_target
+#define ipt_error_target xt_error_target
+#define ipt_counters xt_counters
+#define IPT_CONTINUE XT_CONTINUE
+#define IPT_RETURN XT_RETURN
+
+/* This group is older than old (iptables < v1.4.0-rc1~89) */
+#include <linux/netfilter/xt_tcpudp.h>
+#define ipt_udp xt_udp
+#define ipt_tcp xt_tcp
+#define IPT_TCP_INV_SRCPT XT_TCP_INV_SRCPT
+#define IPT_TCP_INV_DSTPT XT_TCP_INV_DSTPT
+#define IPT_TCP_INV_FLAGS XT_TCP_INV_FLAGS
+#define IPT_TCP_INV_OPTION XT_TCP_INV_OPTION
+#define IPT_TCP_INV_MASK XT_TCP_INV_MASK
+#define IPT_UDP_INV_SRCPT XT_UDP_INV_SRCPT
+#define IPT_UDP_INV_DSTPT XT_UDP_INV_DSTPT
+#define IPT_UDP_INV_MASK XT_UDP_INV_MASK
+
+/* The argument to IPT_SO_ADD_COUNTERS. */
+#define ipt_counters_info xt_counters_info
+/* Standard return verdict, or do jump. */
+#define IPT_STANDARD_TARGET XT_STANDARD_TARGET
+/* Error verdict. */
+#define IPT_ERROR_TARGET XT_ERROR_TARGET
+
+/* fn returns 0 to continue iteration */
+#define IPT_MATCH_ITERATE(e, fn, args...) \
+ XT_MATCH_ITERATE(struct ipt_entry, e, fn, ## args)
+
+/* fn returns 0 to continue iteration */
+#define IPT_ENTRY_ITERATE(entries, size, fn, args...) \
+ XT_ENTRY_ITERATE(struct ipt_entry, entries, size, fn, ## args)
+#endif
+
+/* Yes, Virginia, you have to zero the padding. */
+struct ipt_ip {
+ /* Source and destination IP addr */
+ struct in_addr src, dst;
+ /* Mask for src and dest IP addr */
+ struct in_addr smsk, dmsk;
+ char iniface[IFNAMSIZ], outiface[IFNAMSIZ];
+ unsigned char iniface_mask[IFNAMSIZ], outiface_mask[IFNAMSIZ];
+
+ /* Protocol, 0 = ANY */
+ __u16 proto;
+
+ /* Flags word */
+ __u8 flags;
+ /* Inverse flags */
+ __u8 invflags;
+};
+
+/* Values for "flag" field in struct ipt_ip (general ip structure). */
+#define IPT_F_FRAG 0x01 /* Set if rule is a fragment rule */
+#define IPT_F_GOTO 0x02 /* Set if jump is a goto */
+#define IPT_F_MASK 0x03 /* All possible flag bits mask. */
+
+/* Values for "inv" field in struct ipt_ip. */
+#define IPT_INV_VIA_IN 0x01 /* Invert the sense of IN IFACE. */
+#define IPT_INV_VIA_OUT 0x02 /* Invert the sense of OUT IFACE */
+#define IPT_INV_TOS 0x04 /* Invert the sense of TOS. */
+#define IPT_INV_SRCIP 0x08 /* Invert the sense of SRC IP. */
+#define IPT_INV_DSTIP 0x10 /* Invert the sense of DST OP. */
+#define IPT_INV_FRAG 0x20 /* Invert the sense of FRAG. */
+#define IPT_INV_PROTO XT_INV_PROTO
+#define IPT_INV_MASK 0x7F /* All possible flag bits mask. */
+
+/* This structure defines each of the firewall rules. Consists of 3
+ parts which are 1) general IP header stuff 2) match specific
+ stuff 3) the target to perform if the rule matches */
+struct ipt_entry {
+ struct ipt_ip ip;
+
+ /* Mark with fields that we care about. */
+ unsigned int nfcache;
+
+ /* Size of ipt_entry + matches */
+ __u16 target_offset;
+ /* Size of ipt_entry + matches + target */
+ __u16 next_offset;
+
+ /* Back pointer */
+ unsigned int comefrom;
+
+ /* Packet and byte counters. */
+ struct xt_counters counters;
+
+ /* The matches (if any), then the target. */
+ unsigned char elems[0];
+};
+
+/*
+ * New IP firewall options for [gs]etsockopt at the RAW IP level.
+ * Unlike BSD Linux inherits IP options so you don't have to use a raw
+ * socket for this. Instead we check rights in the calls.
+ *
+ * ATTENTION: check linux/in.h before adding new number here.
+ */
+#define IPT_BASE_CTL 64
+
+#define IPT_SO_SET_REPLACE (IPT_BASE_CTL)
+#define IPT_SO_SET_ADD_COUNTERS (IPT_BASE_CTL + 1)
+#define IPT_SO_SET_MAX IPT_SO_SET_ADD_COUNTERS
+
+#define IPT_SO_GET_INFO (IPT_BASE_CTL)
+#define IPT_SO_GET_ENTRIES (IPT_BASE_CTL + 1)
+#define IPT_SO_GET_REVISION_MATCH (IPT_BASE_CTL + 2)
+#define IPT_SO_GET_REVISION_TARGET (IPT_BASE_CTL + 3)
+#define IPT_SO_GET_MAX IPT_SO_GET_REVISION_TARGET
+
+/* ICMP matching stuff */
+struct ipt_icmp {
+ __u8 type; /* type to match */
+ __u8 code[2]; /* range of code */
+ __u8 invflags; /* Inverse flags */
+};
+
+/* Values for "inv" field for struct ipt_icmp. */
+#define IPT_ICMP_INV 0x01 /* Invert the sense of type/code test */
+
+/* The argument to IPT_SO_GET_INFO */
+struct ipt_getinfo {
+ /* Which table: caller fills this in. */
+ char name[XT_TABLE_MAXNAMELEN];
+
+ /* Kernel fills these in. */
+ /* Which hook entry points are valid: bitmask */
+ unsigned int valid_hooks;
+
+ /* Hook entry points: one per netfilter hook. */
+ unsigned int hook_entry[NF_INET_NUMHOOKS];
+
+ /* Underflow points. */
+ unsigned int underflow[NF_INET_NUMHOOKS];
+
+ /* Number of entries */
+ unsigned int num_entries;
+
+ /* Size of entries. */
+ unsigned int size;
+};
+
+/* The argument to IPT_SO_SET_REPLACE. */
+struct ipt_replace {
+ /* Which table. */
+ char name[XT_TABLE_MAXNAMELEN];
+
+ /* Which hook entry points are valid: bitmask. You can't
+ change this. */
+ unsigned int valid_hooks;
+
+ /* Number of entries */
+ unsigned int num_entries;
+
+ /* Total size of new entries */
+ unsigned int size;
+
+ /* Hook entry points. */
+ unsigned int hook_entry[NF_INET_NUMHOOKS];
+
+ /* Underflow points. */
+ unsigned int underflow[NF_INET_NUMHOOKS];
+
+ /* Information about old entries: */
+ /* Number of counters (must be equal to current number of entries). */
+ unsigned int num_counters;
+ /* The old entries' counters. */
+ struct xt_counters __user *counters;
+
+ /* The entries (hang off end: not really an array). */
+ struct ipt_entry entries[0];
+};
+
+/* The argument to IPT_SO_GET_ENTRIES. */
+struct ipt_get_entries {
+ /* Which table: user fills this in. */
+ char name[XT_TABLE_MAXNAMELEN];
+
+ /* User fills this in: total entry size. */
+ unsigned int size;
+
+ /* The entries. */
+ struct ipt_entry entrytable[0];
+};
+
+/* Helper functions */
+static __inline__ struct xt_entry_target *
+ipt_get_target(struct ipt_entry *e)
+{
+ return (void *)e + e->target_offset;
+}
+
+/*
+ * Main firewall chains definitions and global var's definitions.
+ */
+#endif /* _UAPI_IPTABLES_H */
diff --git a/include/linux/netfilter_ipv4/ipt_CLUSTERIP.h b/include/uapi/linux/netfilter_ipv4/ipt_CLUSTERIP.h
index c6a204c..c6a204c 100644
--- a/include/linux/netfilter_ipv4/ipt_CLUSTERIP.h
+++ b/include/uapi/linux/netfilter_ipv4/ipt_CLUSTERIP.h
diff --git a/include/linux/netfilter_ipv4/ipt_ECN.h b/include/uapi/linux/netfilter_ipv4/ipt_ECN.h
index bb88d53..bb88d53 100644
--- a/include/linux/netfilter_ipv4/ipt_ECN.h
+++ b/include/uapi/linux/netfilter_ipv4/ipt_ECN.h
diff --git a/include/linux/netfilter_ipv4/ipt_LOG.h b/include/uapi/linux/netfilter_ipv4/ipt_LOG.h
index 5d81520..5d81520 100644
--- a/include/linux/netfilter_ipv4/ipt_LOG.h
+++ b/include/uapi/linux/netfilter_ipv4/ipt_LOG.h
diff --git a/include/linux/netfilter_ipv4/ipt_REJECT.h b/include/uapi/linux/netfilter_ipv4/ipt_REJECT.h
index 4293a1a..4293a1a 100644
--- a/include/linux/netfilter_ipv4/ipt_REJECT.h
+++ b/include/uapi/linux/netfilter_ipv4/ipt_REJECT.h
diff --git a/include/linux/netfilter_ipv4/ipt_TTL.h b/include/uapi/linux/netfilter_ipv4/ipt_TTL.h
index f6ac169..f6ac169 100644
--- a/include/linux/netfilter_ipv4/ipt_TTL.h
+++ b/include/uapi/linux/netfilter_ipv4/ipt_TTL.h
diff --git a/include/linux/netfilter_ipv4/ipt_ULOG.h b/include/uapi/linux/netfilter_ipv4/ipt_ULOG.h
index 417aad2..417aad2 100644
--- a/include/linux/netfilter_ipv4/ipt_ULOG.h
+++ b/include/uapi/linux/netfilter_ipv4/ipt_ULOG.h
diff --git a/include/linux/netfilter_ipv4/ipt_ah.h b/include/uapi/linux/netfilter_ipv4/ipt_ah.h
index 4e02bb0..4e02bb0 100644
--- a/include/linux/netfilter_ipv4/ipt_ah.h
+++ b/include/uapi/linux/netfilter_ipv4/ipt_ah.h
diff --git a/include/linux/netfilter_ipv4/ipt_ecn.h b/include/uapi/linux/netfilter_ipv4/ipt_ecn.h
index 0e0c063..0e0c063 100644
--- a/include/linux/netfilter_ipv4/ipt_ecn.h
+++ b/include/uapi/linux/netfilter_ipv4/ipt_ecn.h
diff --git a/include/linux/netfilter_ipv4/ipt_ttl.h b/include/uapi/linux/netfilter_ipv4/ipt_ttl.h
index 37bee44..37bee44 100644
--- a/include/linux/netfilter_ipv4/ipt_ttl.h
+++ b/include/uapi/linux/netfilter_ipv4/ipt_ttl.h
diff --git a/include/uapi/linux/netfilter_ipv6/Kbuild b/include/uapi/linux/netfilter_ipv6/Kbuild
index aafaa5a..75a668c 100644
--- a/include/uapi/linux/netfilter_ipv6/Kbuild
+++ b/include/uapi/linux/netfilter_ipv6/Kbuild
@@ -1 +1,13 @@
# UAPI Header export list
+header-y += ip6_tables.h
+header-y += ip6t_HL.h
+header-y += ip6t_LOG.h
+header-y += ip6t_NPT.h
+header-y += ip6t_REJECT.h
+header-y += ip6t_ah.h
+header-y += ip6t_frag.h
+header-y += ip6t_hl.h
+header-y += ip6t_ipv6header.h
+header-y += ip6t_mh.h
+header-y += ip6t_opts.h
+header-y += ip6t_rt.h
diff --git a/include/uapi/linux/netfilter_ipv6/ip6_tables.h b/include/uapi/linux/netfilter_ipv6/ip6_tables.h
new file mode 100644
index 0000000..bf1ef65
--- /dev/null
+++ b/include/uapi/linux/netfilter_ipv6/ip6_tables.h
@@ -0,0 +1,267 @@
+/*
+ * 25-Jul-1998 Major changes to allow for ip chain table
+ *
+ * 3-Jan-2000 Named tables to allow packet selection for different uses.
+ */
+
+/*
+ * Format of an IP6 firewall descriptor
+ *
+ * src, dst, src_mask, dst_mask are always stored in network byte order.
+ * flags are stored in host byte order (of course).
+ * Port numbers are stored in HOST byte order.
+ */
+
+#ifndef _UAPI_IP6_TABLES_H
+#define _UAPI_IP6_TABLES_H
+
+#include <linux/types.h>
+#include <linux/compiler.h>
+#include <linux/netfilter_ipv6.h>
+
+#include <linux/netfilter/x_tables.h>
+
+#ifndef __KERNEL__
+#define IP6T_FUNCTION_MAXNAMELEN XT_FUNCTION_MAXNAMELEN
+#define IP6T_TABLE_MAXNAMELEN XT_TABLE_MAXNAMELEN
+#define ip6t_match xt_match
+#define ip6t_target xt_target
+#define ip6t_table xt_table
+#define ip6t_get_revision xt_get_revision
+#define ip6t_entry_match xt_entry_match
+#define ip6t_entry_target xt_entry_target
+#define ip6t_standard_target xt_standard_target
+#define ip6t_error_target xt_error_target
+#define ip6t_counters xt_counters
+#define IP6T_CONTINUE XT_CONTINUE
+#define IP6T_RETURN XT_RETURN
+
+/* Pre-iptables-1.4.0 */
+#include <linux/netfilter/xt_tcpudp.h>
+#define ip6t_tcp xt_tcp
+#define ip6t_udp xt_udp
+#define IP6T_TCP_INV_SRCPT XT_TCP_INV_SRCPT
+#define IP6T_TCP_INV_DSTPT XT_TCP_INV_DSTPT
+#define IP6T_TCP_INV_FLAGS XT_TCP_INV_FLAGS
+#define IP6T_TCP_INV_OPTION XT_TCP_INV_OPTION
+#define IP6T_TCP_INV_MASK XT_TCP_INV_MASK
+#define IP6T_UDP_INV_SRCPT XT_UDP_INV_SRCPT
+#define IP6T_UDP_INV_DSTPT XT_UDP_INV_DSTPT
+#define IP6T_UDP_INV_MASK XT_UDP_INV_MASK
+
+#define ip6t_counters_info xt_counters_info
+#define IP6T_STANDARD_TARGET XT_STANDARD_TARGET
+#define IP6T_ERROR_TARGET XT_ERROR_TARGET
+#define IP6T_MATCH_ITERATE(e, fn, args...) \
+ XT_MATCH_ITERATE(struct ip6t_entry, e, fn, ## args)
+#define IP6T_ENTRY_ITERATE(entries, size, fn, args...) \
+ XT_ENTRY_ITERATE(struct ip6t_entry, entries, size, fn, ## args)
+#endif
+
+/* Yes, Virginia, you have to zero the padding. */
+struct ip6t_ip6 {
+ /* Source and destination IP6 addr */
+ struct in6_addr src, dst;
+ /* Mask for src and dest IP6 addr */
+ struct in6_addr smsk, dmsk;
+ char iniface[IFNAMSIZ], outiface[IFNAMSIZ];
+ unsigned char iniface_mask[IFNAMSIZ], outiface_mask[IFNAMSIZ];
+
+ /* Upper protocol number
+ * - The allowed value is 0 (any) or protocol number of last parsable
+ * header, which is 50 (ESP), 59 (No Next Header), 135 (MH), or
+ * the non IPv6 extension headers.
+ * - The protocol numbers of IPv6 extension headers except of ESP and
+ * MH do not match any packets.
+ * - You also need to set IP6T_FLAGS_PROTO to "flags" to check protocol.
+ */
+ __u16 proto;
+ /* TOS to match iff flags & IP6T_F_TOS */
+ __u8 tos;
+
+ /* Flags word */
+ __u8 flags;
+ /* Inverse flags */
+ __u8 invflags;
+};
+
+/* Values for "flag" field in struct ip6t_ip6 (general ip6 structure). */
+#define IP6T_F_PROTO 0x01 /* Set if rule cares about upper
+ protocols */
+#define IP6T_F_TOS 0x02 /* Match the TOS. */
+#define IP6T_F_GOTO 0x04 /* Set if jump is a goto */
+#define IP6T_F_MASK 0x07 /* All possible flag bits mask. */
+
+/* Values for "inv" field in struct ip6t_ip6. */
+#define IP6T_INV_VIA_IN 0x01 /* Invert the sense of IN IFACE. */
+#define IP6T_INV_VIA_OUT 0x02 /* Invert the sense of OUT IFACE */
+#define IP6T_INV_TOS 0x04 /* Invert the sense of TOS. */
+#define IP6T_INV_SRCIP 0x08 /* Invert the sense of SRC IP. */
+#define IP6T_INV_DSTIP 0x10 /* Invert the sense of DST OP. */
+#define IP6T_INV_FRAG 0x20 /* Invert the sense of FRAG. */
+#define IP6T_INV_PROTO XT_INV_PROTO
+#define IP6T_INV_MASK 0x7F /* All possible flag bits mask. */
+
+/* This structure defines each of the firewall rules. Consists of 3
+ parts which are 1) general IP header stuff 2) match specific
+ stuff 3) the target to perform if the rule matches */
+struct ip6t_entry {
+ struct ip6t_ip6 ipv6;
+
+ /* Mark with fields that we care about. */
+ unsigned int nfcache;
+
+ /* Size of ipt_entry + matches */
+ __u16 target_offset;
+ /* Size of ipt_entry + matches + target */
+ __u16 next_offset;
+
+ /* Back pointer */
+ unsigned int comefrom;
+
+ /* Packet and byte counters. */
+ struct xt_counters counters;
+
+ /* The matches (if any), then the target. */
+ unsigned char elems[0];
+};
+
+/* Standard entry */
+struct ip6t_standard {
+ struct ip6t_entry entry;
+ struct xt_standard_target target;
+};
+
+struct ip6t_error {
+ struct ip6t_entry entry;
+ struct xt_error_target target;
+};
+
+#define IP6T_ENTRY_INIT(__size) \
+{ \
+ .target_offset = sizeof(struct ip6t_entry), \
+ .next_offset = (__size), \
+}
+
+#define IP6T_STANDARD_INIT(__verdict) \
+{ \
+ .entry = IP6T_ENTRY_INIT(sizeof(struct ip6t_standard)), \
+ .target = XT_TARGET_INIT(XT_STANDARD_TARGET, \
+ sizeof(struct xt_standard_target)), \
+ .target.verdict = -(__verdict) - 1, \
+}
+
+#define IP6T_ERROR_INIT \
+{ \
+ .entry = IP6T_ENTRY_INIT(sizeof(struct ip6t_error)), \
+ .target = XT_TARGET_INIT(XT_ERROR_TARGET, \
+ sizeof(struct xt_error_target)), \
+ .target.errorname = "ERROR", \
+}
+
+/*
+ * New IP firewall options for [gs]etsockopt at the RAW IP level.
+ * Unlike BSD Linux inherits IP options so you don't have to use
+ * a raw socket for this. Instead we check rights in the calls.
+ *
+ * ATTENTION: check linux/in6.h before adding new number here.
+ */
+#define IP6T_BASE_CTL 64
+
+#define IP6T_SO_SET_REPLACE (IP6T_BASE_CTL)
+#define IP6T_SO_SET_ADD_COUNTERS (IP6T_BASE_CTL + 1)
+#define IP6T_SO_SET_MAX IP6T_SO_SET_ADD_COUNTERS
+
+#define IP6T_SO_GET_INFO (IP6T_BASE_CTL)
+#define IP6T_SO_GET_ENTRIES (IP6T_BASE_CTL + 1)
+#define IP6T_SO_GET_REVISION_MATCH (IP6T_BASE_CTL + 4)
+#define IP6T_SO_GET_REVISION_TARGET (IP6T_BASE_CTL + 5)
+#define IP6T_SO_GET_MAX IP6T_SO_GET_REVISION_TARGET
+
+/* ICMP matching stuff */
+struct ip6t_icmp {
+ __u8 type; /* type to match */
+ __u8 code[2]; /* range of code */
+ __u8 invflags; /* Inverse flags */
+};
+
+/* Values for "inv" field for struct ipt_icmp. */
+#define IP6T_ICMP_INV 0x01 /* Invert the sense of type/code test */
+
+/* The argument to IP6T_SO_GET_INFO */
+struct ip6t_getinfo {
+ /* Which table: caller fills this in. */
+ char name[XT_TABLE_MAXNAMELEN];
+
+ /* Kernel fills these in. */
+ /* Which hook entry points are valid: bitmask */
+ unsigned int valid_hooks;
+
+ /* Hook entry points: one per netfilter hook. */
+ unsigned int hook_entry[NF_INET_NUMHOOKS];
+
+ /* Underflow points. */
+ unsigned int underflow[NF_INET_NUMHOOKS];
+
+ /* Number of entries */
+ unsigned int num_entries;
+
+ /* Size of entries. */
+ unsigned int size;
+};
+
+/* The argument to IP6T_SO_SET_REPLACE. */
+struct ip6t_replace {
+ /* Which table. */
+ char name[XT_TABLE_MAXNAMELEN];
+
+ /* Which hook entry points are valid: bitmask. You can't
+ change this. */
+ unsigned int valid_hooks;
+
+ /* Number of entries */
+ unsigned int num_entries;
+
+ /* Total size of new entries */
+ unsigned int size;
+
+ /* Hook entry points. */
+ unsigned int hook_entry[NF_INET_NUMHOOKS];
+
+ /* Underflow points. */
+ unsigned int underflow[NF_INET_NUMHOOKS];
+
+ /* Information about old entries: */
+ /* Number of counters (must be equal to current number of entries). */
+ unsigned int num_counters;
+ /* The old entries' counters. */
+ struct xt_counters __user *counters;
+
+ /* The entries (hang off end: not really an array). */
+ struct ip6t_entry entries[0];
+};
+
+/* The argument to IP6T_SO_GET_ENTRIES. */
+struct ip6t_get_entries {
+ /* Which table: user fills this in. */
+ char name[XT_TABLE_MAXNAMELEN];
+
+ /* User fills this in: total entry size. */
+ unsigned int size;
+
+ /* The entries. */
+ struct ip6t_entry entrytable[0];
+};
+
+/* Helper functions */
+static __inline__ struct xt_entry_target *
+ip6t_get_target(struct ip6t_entry *e)
+{
+ return (void *)e + e->target_offset;
+}
+
+/*
+ * Main firewall chains definitions and global var's definitions.
+ */
+
+#endif /* _UAPI_IP6_TABLES_H */
diff --git a/include/linux/netfilter_ipv6/ip6t_HL.h b/include/uapi/linux/netfilter_ipv6/ip6t_HL.h
index ebd8ead..ebd8ead 100644
--- a/include/linux/netfilter_ipv6/ip6t_HL.h
+++ b/include/uapi/linux/netfilter_ipv6/ip6t_HL.h
diff --git a/include/linux/netfilter_ipv6/ip6t_LOG.h b/include/uapi/linux/netfilter_ipv6/ip6t_LOG.h
index 3dd0bc4..3dd0bc4 100644
--- a/include/linux/netfilter_ipv6/ip6t_LOG.h
+++ b/include/uapi/linux/netfilter_ipv6/ip6t_LOG.h
diff --git a/include/linux/netfilter_ipv6/ip6t_NPT.h b/include/uapi/linux/netfilter_ipv6/ip6t_NPT.h
index f763355..f763355 100644
--- a/include/linux/netfilter_ipv6/ip6t_NPT.h
+++ b/include/uapi/linux/netfilter_ipv6/ip6t_NPT.h
diff --git a/include/linux/netfilter_ipv6/ip6t_REJECT.h b/include/uapi/linux/netfilter_ipv6/ip6t_REJECT.h
index 205ed62..205ed62 100644
--- a/include/linux/netfilter_ipv6/ip6t_REJECT.h
+++ b/include/uapi/linux/netfilter_ipv6/ip6t_REJECT.h
diff --git a/include/linux/netfilter_ipv6/ip6t_ah.h b/include/uapi/linux/netfilter_ipv6/ip6t_ah.h
index 5da2b65..5da2b65 100644
--- a/include/linux/netfilter_ipv6/ip6t_ah.h
+++ b/include/uapi/linux/netfilter_ipv6/ip6t_ah.h
diff --git a/include/linux/netfilter_ipv6/ip6t_frag.h b/include/uapi/linux/netfilter_ipv6/ip6t_frag.h
index b47f61b..b47f61b 100644
--- a/include/linux/netfilter_ipv6/ip6t_frag.h
+++ b/include/uapi/linux/netfilter_ipv6/ip6t_frag.h
diff --git a/include/linux/netfilter_ipv6/ip6t_hl.h b/include/uapi/linux/netfilter_ipv6/ip6t_hl.h
index 6e76dbc..6e76dbc 100644
--- a/include/linux/netfilter_ipv6/ip6t_hl.h
+++ b/include/uapi/linux/netfilter_ipv6/ip6t_hl.h
diff --git a/include/linux/netfilter_ipv6/ip6t_ipv6header.h b/include/uapi/linux/netfilter_ipv6/ip6t_ipv6header.h
index efae3a2..efae3a2 100644
--- a/include/linux/netfilter_ipv6/ip6t_ipv6header.h
+++ b/include/uapi/linux/netfilter_ipv6/ip6t_ipv6header.h
diff --git a/include/linux/netfilter_ipv6/ip6t_mh.h b/include/uapi/linux/netfilter_ipv6/ip6t_mh.h
index a7729a5..a7729a5 100644
--- a/include/linux/netfilter_ipv6/ip6t_mh.h
+++ b/include/uapi/linux/netfilter_ipv6/ip6t_mh.h
diff --git a/include/linux/netfilter_ipv6/ip6t_opts.h b/include/uapi/linux/netfilter_ipv6/ip6t_opts.h
index 17d419a..17d419a 100644
--- a/include/linux/netfilter_ipv6/ip6t_opts.h
+++ b/include/uapi/linux/netfilter_ipv6/ip6t_opts.h
diff --git a/include/linux/netfilter_ipv6/ip6t_rt.h b/include/uapi/linux/netfilter_ipv6/ip6t_rt.h
index 7605a5f..7605a5f 100644
--- a/include/linux/netfilter_ipv6/ip6t_rt.h
+++ b/include/uapi/linux/netfilter_ipv6/ip6t_rt.h
diff --git a/include/uapi/linux/tc_act/Kbuild b/include/uapi/linux/tc_act/Kbuild
index aafaa5a..0623ec4 100644
--- a/include/uapi/linux/tc_act/Kbuild
+++ b/include/uapi/linux/tc_act/Kbuild
@@ -1 +1,8 @@
# UAPI Header export list
+header-y += tc_csum.h
+header-y += tc_gact.h
+header-y += tc_ipt.h
+header-y += tc_mirred.h
+header-y += tc_nat.h
+header-y += tc_pedit.h
+header-y += tc_skbedit.h
diff --git a/include/linux/tc_act/tc_csum.h b/include/uapi/linux/tc_act/tc_csum.h
index a047c49..a047c49 100644
--- a/include/linux/tc_act/tc_csum.h
+++ b/include/uapi/linux/tc_act/tc_csum.h
diff --git a/include/linux/tc_act/tc_gact.h b/include/uapi/linux/tc_act/tc_gact.h
index f7bf94e..f7bf94e 100644
--- a/include/linux/tc_act/tc_gact.h
+++ b/include/uapi/linux/tc_act/tc_gact.h
diff --git a/include/linux/tc_act/tc_ipt.h b/include/uapi/linux/tc_act/tc_ipt.h
index a233556..a233556 100644
--- a/include/linux/tc_act/tc_ipt.h
+++ b/include/uapi/linux/tc_act/tc_ipt.h
diff --git a/include/linux/tc_act/tc_mirred.h b/include/uapi/linux/tc_act/tc_mirred.h
index 7561750..7561750 100644
--- a/include/linux/tc_act/tc_mirred.h
+++ b/include/uapi/linux/tc_act/tc_mirred.h
diff --git a/include/linux/tc_act/tc_nat.h b/include/uapi/linux/tc_act/tc_nat.h
index 6663aeb..6663aeb 100644
--- a/include/linux/tc_act/tc_nat.h
+++ b/include/uapi/linux/tc_act/tc_nat.h
diff --git a/include/linux/tc_act/tc_pedit.h b/include/uapi/linux/tc_act/tc_pedit.h
index 716cfab..716cfab 100644
--- a/include/linux/tc_act/tc_pedit.h
+++ b/include/uapi/linux/tc_act/tc_pedit.h
diff --git a/include/linux/tc_act/tc_skbedit.h b/include/uapi/linux/tc_act/tc_skbedit.h
index 7a2e910..7a2e910 100644
--- a/include/linux/tc_act/tc_skbedit.h
+++ b/include/uapi/linux/tc_act/tc_skbedit.h
diff --git a/include/uapi/linux/tc_ematch/Kbuild b/include/uapi/linux/tc_ematch/Kbuild
index aafaa5a..53fca39 100644
--- a/include/uapi/linux/tc_ematch/Kbuild
+++ b/include/uapi/linux/tc_ematch/Kbuild
@@ -1 +1,5 @@
# UAPI Header export list
+header-y += tc_em_cmp.h
+header-y += tc_em_meta.h
+header-y += tc_em_nbyte.h
+header-y += tc_em_text.h
diff --git a/include/linux/tc_ematch/tc_em_cmp.h b/include/uapi/linux/tc_ematch/tc_em_cmp.h
index f34bb1b..f34bb1b 100644
--- a/include/linux/tc_ematch/tc_em_cmp.h
+++ b/include/uapi/linux/tc_ematch/tc_em_cmp.h
diff --git a/include/linux/tc_ematch/tc_em_meta.h b/include/uapi/linux/tc_ematch/tc_em_meta.h
index b11f8ce..b11f8ce 100644
--- a/include/linux/tc_ematch/tc_em_meta.h
+++ b/include/uapi/linux/tc_ematch/tc_em_meta.h
diff --git a/include/linux/tc_ematch/tc_em_nbyte.h b/include/uapi/linux/tc_ematch/tc_em_nbyte.h
index 7172cfb..7172cfb 100644
--- a/include/linux/tc_ematch/tc_em_nbyte.h
+++ b/include/uapi/linux/tc_ematch/tc_em_nbyte.h
diff --git a/include/linux/tc_ematch/tc_em_text.h b/include/uapi/linux/tc_ematch/tc_em_text.h
index 5aac404..5aac404 100644
--- a/include/linux/tc_ematch/tc_em_text.h
+++ b/include/uapi/linux/tc_ematch/tc_em_text.h
diff --git a/include/uapi/mtd/Kbuild b/include/uapi/mtd/Kbuild
index aafaa5a..5a691e1 100644
--- a/include/uapi/mtd/Kbuild
+++ b/include/uapi/mtd/Kbuild
@@ -1 +1,6 @@
# UAPI Header export list
+header-y += inftl-user.h
+header-y += mtd-abi.h
+header-y += mtd-user.h
+header-y += nftl-user.h
+header-y += ubi-user.h
diff --git a/include/mtd/inftl-user.h b/include/uapi/mtd/inftl-user.h
index 8376bd1..8376bd1 100644
--- a/include/mtd/inftl-user.h
+++ b/include/uapi/mtd/inftl-user.h
diff --git a/include/mtd/mtd-abi.h b/include/uapi/mtd/mtd-abi.h
index 36eace0..36eace0 100644
--- a/include/mtd/mtd-abi.h
+++ b/include/uapi/mtd/mtd-abi.h
diff --git a/include/mtd/mtd-user.h b/include/uapi/mtd/mtd-user.h
index 83327c8..83327c8 100644
--- a/include/mtd/mtd-user.h
+++ b/include/uapi/mtd/mtd-user.h
diff --git a/include/mtd/nftl-user.h b/include/uapi/mtd/nftl-user.h
index bdeabd8..bdeabd8 100644
--- a/include/mtd/nftl-user.h
+++ b/include/uapi/mtd/nftl-user.h
diff --git a/include/mtd/ubi-user.h b/include/uapi/mtd/ubi-user.h
index 53cae1e..53cae1e 100644
--- a/include/mtd/ubi-user.h
+++ b/include/uapi/mtd/ubi-user.h
diff --git a/include/video/omapdss.h b/include/video/omapdss.h
index a6267a2..3729173 100644
--- a/include/video/omapdss.h
+++ b/include/video/omapdss.h
@@ -48,10 +48,10 @@
#define DISPC_IRQ_FRAMEDONEWB (1 << 23)
#define DISPC_IRQ_FRAMEDONETV (1 << 24)
#define DISPC_IRQ_WBBUFFEROVERFLOW (1 << 25)
-#define DISPC_IRQ_FRAMEDONE3 (1 << 26)
-#define DISPC_IRQ_VSYNC3 (1 << 27)
-#define DISPC_IRQ_ACBIAS_COUNT_STAT3 (1 << 28)
-#define DISPC_IRQ_SYNC_LOST3 (1 << 29)
+#define DISPC_IRQ_SYNC_LOST3 (1 << 27)
+#define DISPC_IRQ_VSYNC3 (1 << 28)
+#define DISPC_IRQ_ACBIAS_COUNT_STAT3 (1 << 29)
+#define DISPC_IRQ_FRAMEDONE3 (1 << 30)
struct omap_dss_device;
struct omap_overlay_manager;
@@ -73,6 +73,7 @@ enum omap_plane {
OMAP_DSS_VIDEO1 = 1,
OMAP_DSS_VIDEO2 = 2,
OMAP_DSS_VIDEO3 = 3,
+ OMAP_DSS_WB = 4,
};
enum omap_channel {
@@ -186,6 +187,8 @@ enum omap_overlay_caps {
OMAP_DSS_OVL_CAP_GLOBAL_ALPHA = 1 << 1,
OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA = 1 << 2,
OMAP_DSS_OVL_CAP_ZORDER = 1 << 3,
+ OMAP_DSS_OVL_CAP_POS = 1 << 4,
+ OMAP_DSS_OVL_CAP_REPLICATION = 1 << 5,
};
enum omap_overlay_manager_caps {
@@ -207,6 +210,16 @@ enum omap_hdmi_flags {
OMAP_HDMI_SDA_SCL_EXTERNAL_PULLUP = 1 << 0,
};
+enum omap_dss_output_id {
+ OMAP_DSS_OUTPUT_DPI = 1 << 0,
+ OMAP_DSS_OUTPUT_DBI = 1 << 1,
+ OMAP_DSS_OUTPUT_SDI = 1 << 2,
+ OMAP_DSS_OUTPUT_DSI1 = 1 << 3,
+ OMAP_DSS_OUTPUT_DSI2 = 1 << 4,
+ OMAP_DSS_OUTPUT_VENC = 1 << 5,
+ OMAP_DSS_OUTPUT_HDMI = 1 << 6,
+};
+
/* RFBI */
struct rfbi_timings {
@@ -243,7 +256,7 @@ void rfbi_bus_unlock(void);
/* DSI */
-struct omap_dss_dsi_videomode_data {
+struct omap_dss_dsi_videomode_timings {
/* DSI video mode blanking data */
/* Unit: byte clock cycles */
u16 hsa;
@@ -424,6 +437,8 @@ struct omap_overlay {
struct omap_overlay_info *info);
int (*wait_for_go)(struct omap_overlay *ovl);
+
+ struct omap_dss_device *(*get_device)(struct omap_overlay *ovl);
};
struct omap_overlay_manager_info {
@@ -448,9 +463,10 @@ struct omap_overlay_manager {
enum omap_overlay_manager_caps caps;
struct list_head overlays;
enum omap_display_type supported_displays;
+ enum omap_dss_output_id supported_outputs;
/* dynamic fields */
- struct omap_dss_device *device;
+ struct omap_dss_output *output;
/*
* The following functions do not block:
@@ -463,9 +479,9 @@ struct omap_overlay_manager {
* interrupt context
*/
- int (*set_device)(struct omap_overlay_manager *mgr,
- struct omap_dss_device *dssdev);
- int (*unset_device)(struct omap_overlay_manager *mgr);
+ int (*set_output)(struct omap_overlay_manager *mgr,
+ struct omap_dss_output *output);
+ int (*unset_output)(struct omap_overlay_manager *mgr);
int (*set_manager_info)(struct omap_overlay_manager *mgr,
struct omap_overlay_manager_info *info);
@@ -475,6 +491,8 @@ struct omap_overlay_manager {
int (*apply)(struct omap_overlay_manager *mgr);
int (*wait_for_go)(struct omap_overlay_manager *mgr);
int (*wait_for_vsync)(struct omap_overlay_manager *mgr);
+
+ struct omap_dss_device *(*get_device)(struct omap_overlay_manager *mgr);
};
/* 22 pins means 1 clk lane and 10 data lanes */
@@ -492,6 +510,37 @@ struct omap_dsi_pin_config {
int pins[OMAP_DSS_MAX_DSI_PINS];
};
+struct omap_dss_writeback_info {
+ u32 paddr;
+ u32 p_uv_addr;
+ u16 buf_width;
+ u16 width;
+ u16 height;
+ enum omap_color_mode color_mode;
+ u8 rotation;
+ enum omap_dss_rotation_type rotation_type;
+ bool mirror;
+ u8 pre_mult_alpha;
+};
+
+struct omap_dss_output {
+ struct list_head list;
+
+ /* display type supported by the output */
+ enum omap_display_type type;
+
+ /* output instance */
+ enum omap_dss_output_id id;
+
+ /* output's platform device pointer */
+ struct platform_device *pdev;
+
+ /* dynamic fields */
+ struct omap_overlay_manager *manager;
+
+ struct omap_dss_device *device;
+};
+
struct omap_dss_device {
struct device dev;
@@ -564,7 +613,7 @@ struct omap_dss_device {
enum omap_dss_dsi_pixel_format dsi_pix_fmt;
enum omap_dss_dsi_mode dsi_mode;
- struct omap_dss_dsi_videomode_data dsi_vm_data;
+ struct omap_dss_dsi_videomode_timings dsi_vm_timings;
} panel;
struct {
@@ -590,7 +639,7 @@ struct omap_dss_device {
enum omap_display_caps caps;
- struct omap_overlay_manager *manager;
+ struct omap_dss_output *output;
enum omap_dss_display_state state;
@@ -605,6 +654,8 @@ struct omap_dss_device {
struct omap_dss_hdmi_data
{
+ int ct_cp_hpd_gpio;
+ int ls_oe_gpio;
int hpd_gpio;
};
@@ -699,6 +750,11 @@ struct omap_overlay_manager *omap_dss_get_overlay_manager(int num);
int omap_dss_get_num_overlays(void);
struct omap_overlay *omap_dss_get_overlay(int num);
+struct omap_dss_output *omap_dss_get_output(enum omap_dss_output_id id);
+int omapdss_output_set_device(struct omap_dss_output *out,
+ struct omap_dss_device *dssdev);
+int omapdss_output_unset_device(struct omap_dss_output *out);
+
void omapdss_default_get_resolution(struct omap_dss_device *dssdev,
u16 *xres, u16 *yres);
int omapdss_default_get_recommended_bpp(struct omap_dss_device *dssdev);
@@ -719,6 +775,15 @@ int omap_dispc_wait_for_irq_interruptible_timeout(u32 irqmask,
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);
+void omapdss_dsi_set_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings);
+void omapdss_dsi_set_size(struct omap_dss_device *dssdev, u16 w, u16 h);
+void omapdss_dsi_set_pixel_format(struct omap_dss_device *dssdev,
+ enum omap_dss_dsi_pixel_format fmt);
+void omapdss_dsi_set_operation_mode(struct omap_dss_device *dssdev,
+ enum omap_dss_dsi_mode mode);
+void omapdss_dsi_set_videomode_timings(struct omap_dss_device *dssdev,
+ struct omap_dss_dsi_videomode_timings *timings);
int omap_dsi_update(struct omap_dss_device *dssdev, int channel,
void (*callback)(int, void *), void *data);
@@ -727,6 +792,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_configure_pins(struct omap_dss_device *dssdev,
const struct omap_dsi_pin_config *pin_cfg);
+int omapdss_dsi_set_clocks(struct omap_dss_device *dssdev,
+ unsigned long ddr_clk, unsigned long lp_clk);
int omapdss_dsi_display_enable(struct omap_dss_device *dssdev);
void omapdss_dsi_display_disable(struct omap_dss_device *dssdev,
@@ -734,22 +801,29 @@ void omapdss_dsi_display_disable(struct omap_dss_device *dssdev,
int omapdss_dpi_display_enable(struct omap_dss_device *dssdev);
void omapdss_dpi_display_disable(struct omap_dss_device *dssdev);
-void dpi_set_timings(struct omap_dss_device *dssdev,
- struct omap_video_timings *timings);
+void omapdss_dpi_set_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings);
int dpi_check_timings(struct omap_dss_device *dssdev,
struct omap_video_timings *timings);
+void omapdss_dpi_set_data_lines(struct omap_dss_device *dssdev, int data_lines);
int omapdss_sdi_display_enable(struct omap_dss_device *dssdev);
void omapdss_sdi_display_disable(struct omap_dss_device *dssdev);
+void omapdss_sdi_set_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings);
+void omapdss_sdi_set_datapairs(struct omap_dss_device *dssdev, int datapairs);
int omapdss_rfbi_display_enable(struct omap_dss_device *dssdev);
void omapdss_rfbi_display_disable(struct omap_dss_device *dssdev);
-int omap_rfbi_prepare_update(struct omap_dss_device *dssdev,
- u16 *x, u16 *y, u16 *w, u16 *h);
-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 omap_rfbi_update(struct omap_dss_device *dssdev, void (*callback)(void *),
+ void *data);
+int omap_rfbi_configure(struct omap_dss_device *dssdev);
+void omapdss_rfbi_set_size(struct omap_dss_device *dssdev, u16 w, u16 h);
+void omapdss_rfbi_set_pixel_size(struct omap_dss_device *dssdev,
+ int pixel_size);
+void omapdss_rfbi_set_data_lines(struct omap_dss_device *dssdev,
int data_lines);
+void omapdss_rfbi_set_interface_timings(struct omap_dss_device *dssdev,
+ struct rfbi_timings *timings);
#endif
diff --git a/arch/arm/plat-samsung/include/plat/regs-fb.h b/include/video/samsung_fimd.h
index 9a78012..7ae6c07 100644
--- a/arch/arm/plat-samsung/include/plat/regs-fb.h
+++ b/include/video/samsung_fimd.h
@@ -1,13 +1,13 @@
-/* arch/arm/plat-samsung/include/plat/regs-fb.h
+/* include/video/samsung_fimd.h
*
* Copyright 2008 Openmoko, Inc.
* Copyright 2008 Simtec Electronics
* http://armlinux.simtec.co.uk/
* Ben Dooks <ben@simtec.co.uk>
*
- * S3C Platform - new-style framebuffer register definitions
+ * S3C Platform - new-style fimd and framebuffer register definitions
*
- * This is the register set for the new style framebuffer interface
+ * This is the register set for the fimd and new style framebuffer interface
* found from the S3C2443 onwards into the S3C2416, S3C2450 and the
* S3C64XX series such as the S3C6400 and S3C6410.
*
@@ -15,19 +15,11 @@
* whichever architecture is selected, it only contains the core of the
* register set. See <mach/regs-fb.h> to get the specifics.
*
- * Note, we changed to using regs-fb.h as it avoids any clashes with
- * the original regs-lcd.h so out of the way of regs-lcd.h as well as
- * indicating the newer block is much more than just an LCD interface.
- *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
-/* Please do not include this file directly, use <mach/regs-fb.h> to
- * ensure all the localised SoC support is included as necessary.
-*/
-
/* VIDCON0 */
#define VIDCON0 (0x00)
@@ -401,3 +393,141 @@
#define BLENDCON_NEW_8BIT_ALPHA_VALUE (1 << 0)
#define BLENDCON_NEW_4BIT_ALPHA_VALUE (0 << 0)
+#define S3C_FB_MAX_WIN (5) /* number of hardware windows available. */
+#define VIDCON1_FSTATUS_EVEN (1 << 15)
+
+/* Video timing controls */
+#define VIDTCON0 (0x10)
+#define VIDTCON1 (0x14)
+#define VIDTCON2 (0x18)
+
+/* Window position controls */
+
+#define WINCON(_win) (0x20 + ((_win) * 4))
+
+/* OSD1 and OSD4 do not have register D */
+
+#define VIDOSD_BASE (0x40)
+
+#define VIDINTCON0 (0x130)
+
+/* WINCONx */
+
+#define WINCONx_CSCWIDTH_MASK (0x3 << 26)
+#define WINCONx_CSCWIDTH_SHIFT (26)
+#define WINCONx_CSCWIDTH_WIDE (0x0 << 26)
+#define WINCONx_CSCWIDTH_NARROW (0x3 << 26)
+
+#define WINCONx_ENLOCAL (1 << 22)
+#define WINCONx_BUFSTATUS (1 << 21)
+#define WINCONx_BUFSEL (1 << 20)
+#define WINCONx_BUFAUTOEN (1 << 19)
+#define WINCONx_YCbCr (1 << 13)
+
+#define WINCON1_LOCALSEL_CAMIF (1 << 23)
+
+#define WINCON2_LOCALSEL_CAMIF (1 << 23)
+#define WINCON2_BLD_PIX (1 << 6)
+
+#define WINCON2_ALPHA_SEL (1 << 1)
+#define WINCON2_BPPMODE_MASK (0xf << 2)
+#define WINCON2_BPPMODE_SHIFT (2)
+#define WINCON2_BPPMODE_1BPP (0x0 << 2)
+#define WINCON2_BPPMODE_2BPP (0x1 << 2)
+#define WINCON2_BPPMODE_4BPP (0x2 << 2)
+#define WINCON2_BPPMODE_8BPP_1232 (0x4 << 2)
+#define WINCON2_BPPMODE_16BPP_565 (0x5 << 2)
+#define WINCON2_BPPMODE_16BPP_A1555 (0x6 << 2)
+#define WINCON2_BPPMODE_16BPP_I1555 (0x7 << 2)
+#define WINCON2_BPPMODE_18BPP_666 (0x8 << 2)
+#define WINCON2_BPPMODE_18BPP_A1665 (0x9 << 2)
+#define WINCON2_BPPMODE_19BPP_A1666 (0xa << 2)
+#define WINCON2_BPPMODE_24BPP_888 (0xb << 2)
+#define WINCON2_BPPMODE_24BPP_A1887 (0xc << 2)
+#define WINCON2_BPPMODE_25BPP_A1888 (0xd << 2)
+#define WINCON2_BPPMODE_28BPP_A4888 (0xd << 2)
+
+#define WINCON3_BLD_PIX (1 << 6)
+
+#define WINCON3_ALPHA_SEL (1 << 1)
+#define WINCON3_BPPMODE_MASK (0xf << 2)
+#define WINCON3_BPPMODE_SHIFT (2)
+#define WINCON3_BPPMODE_1BPP (0x0 << 2)
+#define WINCON3_BPPMODE_2BPP (0x1 << 2)
+#define WINCON3_BPPMODE_4BPP (0x2 << 2)
+#define WINCON3_BPPMODE_16BPP_565 (0x5 << 2)
+#define WINCON3_BPPMODE_16BPP_A1555 (0x6 << 2)
+#define WINCON3_BPPMODE_16BPP_I1555 (0x7 << 2)
+#define WINCON3_BPPMODE_18BPP_666 (0x8 << 2)
+#define WINCON3_BPPMODE_18BPP_A1665 (0x9 << 2)
+#define WINCON3_BPPMODE_19BPP_A1666 (0xa << 2)
+#define WINCON3_BPPMODE_24BPP_888 (0xb << 2)
+#define WINCON3_BPPMODE_24BPP_A1887 (0xc << 2)
+#define WINCON3_BPPMODE_25BPP_A1888 (0xd << 2)
+#define WINCON3_BPPMODE_28BPP_A4888 (0xd << 2)
+
+#define VIDINTCON0_FIFIOSEL_WINDOW2 (0x10 << 5)
+#define VIDINTCON0_FIFIOSEL_WINDOW3 (0x20 << 5)
+#define VIDINTCON0_FIFIOSEL_WINDOW4 (0x40 << 5)
+
+#define DITHMODE (0x170)
+#define WINxMAP(_win) (0x180 + ((_win) * 4))
+
+
+#define DITHMODE_R_POS_MASK (0x3 << 5)
+#define DITHMODE_R_POS_SHIFT (5)
+#define DITHMODE_R_POS_8BIT (0x0 << 5)
+#define DITHMODE_R_POS_6BIT (0x1 << 5)
+#define DITHMODE_R_POS_5BIT (0x2 << 5)
+
+#define DITHMODE_G_POS_MASK (0x3 << 3)
+#define DITHMODE_G_POS_SHIFT (3)
+#define DITHMODE_G_POS_8BIT (0x0 << 3)
+#define DITHMODE_G_POS_6BIT (0x1 << 3)
+#define DITHMODE_G_POS_5BIT (0x2 << 3)
+
+#define DITHMODE_B_POS_MASK (0x3 << 1)
+#define DITHMODE_B_POS_SHIFT (1)
+#define DITHMODE_B_POS_8BIT (0x0 << 1)
+#define DITHMODE_B_POS_6BIT (0x1 << 1)
+#define DITHMODE_B_POS_5BIT (0x2 << 1)
+
+#define DITHMODE_DITH_EN (1 << 0)
+
+#define WPALCON (0x1A0)
+
+/* Palette control */
+/* Note for S5PC100: you can still use those macros on WPALCON (aka WPALCON_L),
+ * but make sure that WPALCON_H W2PAL-W4PAL entries are zeroed out */
+#define WPALCON_W4PAL_16BPP_A555 (1 << 8)
+#define WPALCON_W3PAL_16BPP_A555 (1 << 7)
+#define WPALCON_W2PAL_16BPP_A555 (1 << 6)
+
+
+/* Notes on per-window bpp settings
+ *
+ * Value Win0 Win1 Win2 Win3 Win 4
+ * 0000 1(P) 1(P) 1(P) 1(P) 1(P)
+ * 0001 2(P) 2(P) 2(P) 2(P) 2(P)
+ * 0010 4(P) 4(P) 4(P) 4(P) -none-
+ * 0011 8(P) 8(P) -none- -none- -none-
+ * 0100 -none- 8(A232) 8(A232) -none- -none-
+ * 0101 16(565) 16(565) 16(565) 16(565) 16(565)
+ * 0110 -none- 16(A555) 16(A555) 16(A555) 16(A555)
+ * 0111 16(I555) 16(I565) 16(I555) 16(I555) 16(I555)
+ * 1000 18(666) 18(666) 18(666) 18(666) 18(666)
+ * 1001 -none- 18(A665) 18(A665) 18(A665) 16(A665)
+ * 1010 -none- 19(A666) 19(A666) 19(A666) 19(A666)
+ * 1011 24(888) 24(888) 24(888) 24(888) 24(888)
+ * 1100 -none- 24(A887) 24(A887) 24(A887) 24(A887)
+ * 1101 -none- 25(A888) 25(A888) 25(A888) 25(A888)
+ * 1110 -none- -none- -none- -none- -none-
+ * 1111 -none- -none- -none- -none- -none-
+*/
+
+/* FIMD Version 8 register offset definitions */
+#define FIMD_V8_VIDTCON0 (0x20010)
+#define FIMD_V8_VIDTCON1 (0x20014)
+#define FIMD_V8_VIDTCON2 (0x20018)
+#define FIMD_V8_VIDTCON3 (0x2001C)
+#define FIMD_V8_VIDCON1 (0x20004)
diff --git a/kernel/fork.c b/kernel/fork.c
index 1cd7d581..8b20ab7 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -1584,7 +1584,7 @@ long do_fork(unsigned long clone_flags,
* requested, no event is reported; otherwise, report if the event
* for the type of forking is enabled.
*/
- if (likely(user_mode(regs)) && !(clone_flags & CLONE_UNTRACED)) {
+ if (!(clone_flags & CLONE_UNTRACED) && likely(user_mode(regs))) {
if (clone_flags & CLONE_VFORK)
trace = PTRACE_EVENT_VFORK;
else if ((clone_flags & CSIGNAL) != SIGCHLD)
@@ -1634,6 +1634,17 @@ long do_fork(unsigned long clone_flags,
return nr;
}
+#ifdef CONFIG_GENERIC_KERNEL_THREAD
+/*
+ * Create a kernel thread.
+ */
+pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
+{
+ return do_fork(flags|CLONE_VM|CLONE_UNTRACED, (unsigned long)fn, NULL,
+ (unsigned long)arg, NULL, NULL);
+}
+#endif
+
#ifndef ARCH_MIN_MMSTRUCT_ALIGN
#define ARCH_MIN_MMSTRUCT_ALIGN 0
#endif
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index c177472..bd7c394 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -505,7 +505,7 @@ static inline void init_hrtick(void)
#ifdef CONFIG_SMP
#ifndef tsk_is_polling
-#define tsk_is_polling(t) test_tsk_thread_flag(t, TIF_POLLING_NRFLAG)
+#define tsk_is_polling(t) 0
#endif
void resched_task(struct task_struct *p)
diff --git a/lib/kasprintf.c b/lib/kasprintf.c
index ae0de80..32f1215 100644
--- a/lib/kasprintf.c
+++ b/lib/kasprintf.c
@@ -21,7 +21,7 @@ char *kvasprintf(gfp_t gfp, const char *fmt, va_list ap)
len = vsnprintf(NULL, 0, fmt, aq);
va_end(aq);
- p = kmalloc(len+1, gfp);
+ p = kmalloc_track_caller(len+1, gfp);
if (!p)
return NULL;
diff --git a/lib/scatterlist.c b/lib/scatterlist.c
index e76d85c..3675452b 100644
--- a/lib/scatterlist.c
+++ b/lib/scatterlist.c
@@ -39,6 +39,25 @@ struct scatterlist *sg_next(struct scatterlist *sg)
EXPORT_SYMBOL(sg_next);
/**
+ * sg_nents - return total count of entries in scatterlist
+ * @sg: The scatterlist
+ *
+ * Description:
+ * Allows to know how many entries are in sg, taking into acount
+ * chaining as well
+ *
+ **/
+int sg_nents(struct scatterlist *sg)
+{
+ int nents;
+ for (nents = 0; sg; sg = sg_next(sg))
+ nents++;
+ return nents;
+}
+EXPORT_SYMBOL(sg_nents);
+
+
+/**
* sg_last - return the last scatterlist entry in a list
* @sgl: First entry in the scatterlist
* @nents: Number of entries in the scatterlist
diff --git a/mm/backing-dev.c b/mm/backing-dev.c
index b41823c..d3ca2b3 100644
--- a/mm/backing-dev.c
+++ b/mm/backing-dev.c
@@ -158,16 +158,16 @@ static ssize_t read_ahead_kb_store(struct device *dev,
const char *buf, size_t count)
{
struct backing_dev_info *bdi = dev_get_drvdata(dev);
- char *end;
unsigned long read_ahead_kb;
- ssize_t ret = -EINVAL;
+ ssize_t ret;
- read_ahead_kb = simple_strtoul(buf, &end, 10);
- if (*buf && (end[0] == '\0' || (end[0] == '\n' && end[1] == '\0'))) {
- bdi->ra_pages = read_ahead_kb >> (PAGE_SHIFT - 10);
- ret = count;
- }
- return ret;
+ ret = kstrtoul(buf, 10, &read_ahead_kb);
+ if (ret < 0)
+ return ret;
+
+ bdi->ra_pages = read_ahead_kb >> (PAGE_SHIFT - 10);
+
+ return count;
}
#define K(pages) ((pages) << (PAGE_SHIFT - 10))
@@ -187,16 +187,17 @@ static ssize_t min_ratio_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct backing_dev_info *bdi = dev_get_drvdata(dev);
- char *end;
unsigned int ratio;
- ssize_t ret = -EINVAL;
+ ssize_t ret;
+
+ ret = kstrtouint(buf, 10, &ratio);
+ if (ret < 0)
+ return ret;
+
+ ret = bdi_set_min_ratio(bdi, ratio);
+ if (!ret)
+ ret = count;
- ratio = simple_strtoul(buf, &end, 10);
- if (*buf && (end[0] == '\0' || (end[0] == '\n' && end[1] == '\0'))) {
- ret = bdi_set_min_ratio(bdi, ratio);
- if (!ret)
- ret = count;
- }
return ret;
}
BDI_SHOW(min_ratio, bdi->min_ratio)
@@ -205,16 +206,17 @@ static ssize_t max_ratio_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct backing_dev_info *bdi = dev_get_drvdata(dev);
- char *end;
unsigned int ratio;
- ssize_t ret = -EINVAL;
+ ssize_t ret;
+
+ ret = kstrtouint(buf, 10, &ratio);
+ if (ret < 0)
+ return ret;
+
+ ret = bdi_set_max_ratio(bdi, ratio);
+ if (!ret)
+ ret = count;
- ratio = simple_strtoul(buf, &end, 10);
- if (*buf && (end[0] == '\0' || (end[0] == '\n' && end[1] == '\0'))) {
- ret = bdi_set_max_ratio(bdi, ratio);
- if (!ret)
- ret = count;
- }
return ret;
}
BDI_SHOW(max_ratio, bdi->max_ratio)
diff --git a/mm/page-writeback.c b/mm/page-writeback.c
index 5ad5ce2..830893b 100644
--- a/mm/page-writeback.c
+++ b/mm/page-writeback.c
@@ -1602,10 +1602,18 @@ void writeback_set_ratelimit(void)
}
static int __cpuinit
-ratelimit_handler(struct notifier_block *self, unsigned long u, void *v)
+ratelimit_handler(struct notifier_block *self, unsigned long action,
+ void *hcpu)
{
- writeback_set_ratelimit();
- return NOTIFY_DONE;
+
+ switch (action & ~CPU_TASKS_FROZEN) {
+ case CPU_ONLINE:
+ case CPU_DEAD:
+ writeback_set_ratelimit();
+ return NOTIFY_OK;
+ default:
+ return NOTIFY_DONE;
+ }
}
static struct notifier_block __cpuinitdata ratelimit_nb = {
diff --git a/net/8021q/vlan_core.c b/net/8021q/vlan_core.c
index add69d0..fbbf1fa 100644
--- a/net/8021q/vlan_core.c
+++ b/net/8021q/vlan_core.c
@@ -5,7 +5,7 @@
#include <linux/export.h>
#include "vlan.h"
-bool vlan_do_receive(struct sk_buff **skbp, bool last_handler)
+bool vlan_do_receive(struct sk_buff **skbp)
{
struct sk_buff *skb = *skbp;
u16 vlan_id = skb->vlan_tci & VLAN_VID_MASK;
@@ -13,14 +13,8 @@ bool vlan_do_receive(struct sk_buff **skbp, bool last_handler)
struct vlan_pcpu_stats *rx_stats;
vlan_dev = vlan_find_dev(skb->dev, vlan_id);
- if (!vlan_dev) {
- /* Only the last call to vlan_do_receive() should change
- * pkt_type to PACKET_OTHERHOST
- */
- if (vlan_id && last_handler)
- skb->pkt_type = PACKET_OTHERHOST;
+ if (!vlan_dev)
return false;
- }
skb = *skbp = skb_share_check(skb, GFP_ATOMIC);
if (unlikely(!skb))
diff --git a/net/9p/client.c b/net/9p/client.c
index 8260f13..34d4176 100644
--- a/net/9p/client.c
+++ b/net/9p/client.c
@@ -76,6 +76,20 @@ inline int p9_is_proto_dotu(struct p9_client *clnt)
}
EXPORT_SYMBOL(p9_is_proto_dotu);
+/*
+ * Some error codes are taken directly from the server replies,
+ * make sure they are valid.
+ */
+static int safe_errno(int err)
+{
+ if ((err > 0) || (err < -MAX_ERRNO)) {
+ p9_debug(P9_DEBUG_ERROR, "Invalid error code %d\n", err);
+ return -EPROTO;
+ }
+ return err;
+}
+
+
/* Interpret mount option for protocol version */
static int get_protocol_version(char *s)
{
@@ -782,7 +796,7 @@ again:
return req;
reterr:
p9_free_req(c, req);
- return ERR_PTR(err);
+ return ERR_PTR(safe_errno(err));
}
/**
@@ -865,7 +879,7 @@ static struct p9_req_t *p9_client_zc_rpc(struct p9_client *c, int8_t type,
return req;
reterr:
p9_free_req(c, req);
- return ERR_PTR(err);
+ return ERR_PTR(safe_errno(err));
}
static struct p9_fid *p9_fid_create(struct p9_client *clnt)
diff --git a/net/9p/trans_fd.c b/net/9p/trans_fd.c
index 15656b8..02efb25 100644
--- a/net/9p/trans_fd.c
+++ b/net/9p/trans_fd.c
@@ -316,8 +316,7 @@ static void p9_read_work(struct work_struct *work)
m->rsize - m->rpos);
p9_debug(P9_DEBUG_TRANS, "mux %p got %d bytes\n", m, err);
if (err == -EAGAIN) {
- clear_bit(Rworksched, &m->wsched);
- return;
+ goto end_clear;
}
if (err <= 0)
@@ -379,19 +378,20 @@ static void p9_read_work(struct work_struct *work)
m->req = NULL;
}
+end_clear:
+ clear_bit(Rworksched, &m->wsched);
+
if (!list_empty(&m->req_list)) {
if (test_and_clear_bit(Rpending, &m->wsched))
n = POLLIN;
else
n = p9_fd_poll(m->client, NULL);
- if (n & POLLIN) {
+ if ((n & POLLIN) && !test_and_set_bit(Rworksched, &m->wsched)) {
p9_debug(P9_DEBUG_TRANS, "sched read work %p\n", m);
schedule_work(&m->rq);
- } else
- clear_bit(Rworksched, &m->wsched);
- } else
- clear_bit(Rworksched, &m->wsched);
+ }
+ }
return;
error:
@@ -453,12 +453,13 @@ static void p9_write_work(struct work_struct *work)
}
if (!m->wsize) {
+ spin_lock(&m->client->lock);
if (list_empty(&m->unsent_req_list)) {
clear_bit(Wworksched, &m->wsched);
+ spin_unlock(&m->client->lock);
return;
}
- spin_lock(&m->client->lock);
req = list_entry(m->unsent_req_list.next, struct p9_req_t,
req_list);
req->status = REQ_STATUS_SENT;
@@ -476,10 +477,9 @@ static void p9_write_work(struct work_struct *work)
clear_bit(Wpending, &m->wsched);
err = p9_fd_write(m->client, m->wbuf + m->wpos, m->wsize - m->wpos);
p9_debug(P9_DEBUG_TRANS, "mux %p sent %d bytes\n", m, err);
- if (err == -EAGAIN) {
- clear_bit(Wworksched, &m->wsched);
- return;
- }
+ if (err == -EAGAIN)
+ goto end_clear;
+
if (err < 0)
goto error;
@@ -492,19 +492,21 @@ static void p9_write_work(struct work_struct *work)
if (m->wpos == m->wsize)
m->wpos = m->wsize = 0;
- if (m->wsize == 0 && !list_empty(&m->unsent_req_list)) {
+end_clear:
+ clear_bit(Wworksched, &m->wsched);
+
+ if (m->wsize || !list_empty(&m->unsent_req_list)) {
if (test_and_clear_bit(Wpending, &m->wsched))
n = POLLOUT;
else
n = p9_fd_poll(m->client, NULL);
- if (n & POLLOUT) {
+ if ((n & POLLOUT) &&
+ !test_and_set_bit(Wworksched, &m->wsched)) {
p9_debug(P9_DEBUG_TRANS, "sched write work %p\n", m);
schedule_work(&m->wq);
- } else
- clear_bit(Wworksched, &m->wsched);
- } else
- clear_bit(Wworksched, &m->wsched);
+ }
+ }
return;
diff --git a/net/core/dev.c b/net/core/dev.c
index 1e0a184..09cb3f6 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -3300,18 +3300,18 @@ ncls:
&& !skb_pfmemalloc_protocol(skb))
goto drop;
- rx_handler = rcu_dereference(skb->dev->rx_handler);
if (vlan_tx_tag_present(skb)) {
if (pt_prev) {
ret = deliver_skb(skb, pt_prev, orig_dev);
pt_prev = NULL;
}
- if (vlan_do_receive(&skb, !rx_handler))
+ if (vlan_do_receive(&skb))
goto another_round;
else if (unlikely(!skb))
goto unlock;
}
+ rx_handler = rcu_dereference(skb->dev->rx_handler);
if (rx_handler) {
if (pt_prev) {
ret = deliver_skb(skb, pt_prev, orig_dev);
@@ -3331,6 +3331,9 @@ ncls:
}
}
+ if (vlan_tx_nonzero_tag_present(skb))
+ skb->pkt_type = PACKET_OTHERHOST;
+
/* deliver only exact match when indicated */
null_or_dev = deliver_exact ? skb->dev : NULL;
@@ -3471,17 +3474,31 @@ out:
return netif_receive_skb(skb);
}
-inline void napi_gro_flush(struct napi_struct *napi)
+/* napi->gro_list contains packets ordered by age.
+ * youngest packets at the head of it.
+ * Complete skbs in reverse order to reduce latencies.
+ */
+void napi_gro_flush(struct napi_struct *napi, bool flush_old)
{
- struct sk_buff *skb, *next;
+ struct sk_buff *skb, *prev = NULL;
- for (skb = napi->gro_list; skb; skb = next) {
- next = skb->next;
+ /* scan list and build reverse chain */
+ for (skb = napi->gro_list; skb != NULL; skb = skb->next) {
+ skb->prev = prev;
+ prev = skb;
+ }
+
+ for (skb = prev; skb; skb = prev) {
skb->next = NULL;
+
+ if (flush_old && NAPI_GRO_CB(skb)->age == jiffies)
+ return;
+
+ prev = skb->prev;
napi_gro_complete(skb);
+ napi->gro_count--;
}
- napi->gro_count = 0;
napi->gro_list = NULL;
}
EXPORT_SYMBOL(napi_gro_flush);
@@ -3542,6 +3559,7 @@ enum gro_result dev_gro_receive(struct napi_struct *napi, struct sk_buff *skb)
napi->gro_count++;
NAPI_GRO_CB(skb)->count = 1;
+ NAPI_GRO_CB(skb)->age = jiffies;
skb_shinfo(skb)->gso_size = skb_gro_len(skb);
skb->next = napi->gro_list;
napi->gro_list = skb;
@@ -3631,20 +3649,22 @@ gro_result_t napi_skb_finish(gro_result_t ret, struct sk_buff *skb)
}
EXPORT_SYMBOL(napi_skb_finish);
-void skb_gro_reset_offset(struct sk_buff *skb)
+static void skb_gro_reset_offset(struct sk_buff *skb)
{
+ const struct skb_shared_info *pinfo = skb_shinfo(skb);
+ const skb_frag_t *frag0 = &pinfo->frags[0];
+
NAPI_GRO_CB(skb)->data_offset = 0;
NAPI_GRO_CB(skb)->frag0 = NULL;
NAPI_GRO_CB(skb)->frag0_len = 0;
if (skb->mac_header == skb->tail &&
- !PageHighMem(skb_frag_page(&skb_shinfo(skb)->frags[0]))) {
- NAPI_GRO_CB(skb)->frag0 =
- skb_frag_address(&skb_shinfo(skb)->frags[0]);
- NAPI_GRO_CB(skb)->frag0_len = skb_frag_size(&skb_shinfo(skb)->frags[0]);
+ pinfo->nr_frags &&
+ !PageHighMem(skb_frag_page(frag0))) {
+ NAPI_GRO_CB(skb)->frag0 = skb_frag_address(frag0);
+ NAPI_GRO_CB(skb)->frag0_len = skb_frag_size(frag0);
}
}
-EXPORT_SYMBOL(skb_gro_reset_offset);
gro_result_t napi_gro_receive(struct napi_struct *napi, struct sk_buff *skb)
{
@@ -3876,7 +3896,7 @@ void napi_complete(struct napi_struct *n)
if (unlikely(test_bit(NAPI_STATE_NPSVC, &n->state)))
return;
- napi_gro_flush(n);
+ napi_gro_flush(n, false);
local_irq_save(flags);
__napi_complete(n);
local_irq_restore(flags);
@@ -3981,8 +4001,17 @@ static void net_rx_action(struct softirq_action *h)
local_irq_enable();
napi_complete(n);
local_irq_disable();
- } else
+ } else {
+ if (n->gro_list) {
+ /* flush too old packets
+ * If HZ < 1000, flush all packets.
+ */
+ local_irq_enable();
+ napi_gro_flush(n, HZ >= 1000);
+ local_irq_disable();
+ }
list_move_tail(&n->poll_list, &sd->poll_list);
+ }
}
netpoll_poll_unlock(have);
diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index baca771..2257148 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -1301,8 +1301,6 @@ int neigh_resolve_output(struct neighbour *neigh, struct sk_buff *skb)
if (!dst)
goto discard;
- __skb_pull(skb, skb_network_offset(skb));
-
if (!neigh_event_send(neigh, skb)) {
int err;
struct net_device *dev = neigh->dev;
@@ -1312,6 +1310,7 @@ int neigh_resolve_output(struct neighbour *neigh, struct sk_buff *skb)
neigh_hh_init(neigh, dst);
do {
+ __skb_pull(skb, skb_network_offset(skb));
seq = read_seqbegin(&neigh->ha_lock);
err = dev_hard_header(skb, dev, ntohs(skb->protocol),
neigh->ha, NULL, skb->len);
@@ -1342,9 +1341,8 @@ int neigh_connected_output(struct neighbour *neigh, struct sk_buff *skb)
unsigned int seq;
int err;
- __skb_pull(skb, skb_network_offset(skb));
-
do {
+ __skb_pull(skb, skb_network_offset(skb));
seq = read_seqbegin(&neigh->ha_lock);
err = dev_hard_header(skb, dev, ntohs(skb->protocol),
neigh->ha, NULL, skb->len);
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index cdc2859..6e04b1f 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -655,53 +655,6 @@ void consume_skb(struct sk_buff *skb)
}
EXPORT_SYMBOL(consume_skb);
-/**
- * skb_recycle - clean up an skb for reuse
- * @skb: buffer
- *
- * Recycles the skb to be reused as a receive buffer. This
- * function does any necessary reference count dropping, and
- * cleans up the skbuff as if it just came from __alloc_skb().
- */
-void skb_recycle(struct sk_buff *skb)
-{
- struct skb_shared_info *shinfo;
-
- skb_release_head_state(skb);
-
- shinfo = skb_shinfo(skb);
- memset(shinfo, 0, offsetof(struct skb_shared_info, dataref));
- atomic_set(&shinfo->dataref, 1);
-
- memset(skb, 0, offsetof(struct sk_buff, tail));
- skb->data = skb->head + NET_SKB_PAD;
- skb_reset_tail_pointer(skb);
-}
-EXPORT_SYMBOL(skb_recycle);
-
-/**
- * skb_recycle_check - check if skb can be reused for receive
- * @skb: buffer
- * @skb_size: minimum receive buffer size
- *
- * Checks that the skb passed in is not shared or cloned, and
- * that it is linear and its head portion at least as large as
- * skb_size so that it can be recycled as a receive buffer.
- * If these conditions are met, this function does any necessary
- * reference count dropping and cleans up the skbuff as if it
- * just came from __alloc_skb().
- */
-bool skb_recycle_check(struct sk_buff *skb, int skb_size)
-{
- if (!skb_is_recycleable(skb, skb_size))
- return false;
-
- skb_recycle(skb);
-
- return true;
-}
-EXPORT_SYMBOL(skb_recycle_check);
-
static void __copy_skb_header(struct sk_buff *new, const struct sk_buff *old)
{
new->tstamp = old->tstamp;
diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c
index 68c93d1..825c608 100644
--- a/net/ipv4/fib_frontend.c
+++ b/net/ipv4/fib_frontend.c
@@ -322,7 +322,8 @@ int fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst,
{
int r = secpath_exists(skb) ? 0 : IN_DEV_RPFILTER(idev);
- if (!r && !fib_num_tclassid_users(dev_net(dev))) {
+ if (!r && !fib_num_tclassid_users(dev_net(dev)) &&
+ (dev->ifindex != oif || !IN_DEV_TX_REDIRECTS(idev))) {
*itag = 0;
return 0;
}
diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c
index 2677530..71b125c 100644
--- a/net/ipv4/fib_semantics.c
+++ b/net/ipv4/fib_semantics.c
@@ -840,6 +840,8 @@ struct fib_info *fib_create_info(struct fib_config *cfg)
change_nexthops(fi) {
nexthop_nh->nh_parent = fi;
nexthop_nh->nh_pcpu_rth_output = alloc_percpu(struct rtable __rcu *);
+ if (!nexthop_nh->nh_pcpu_rth_output)
+ goto failure;
} endfor_nexthops(fi)
if (cfg->fc_mx) {
diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c
index f0c5b9c..d34ce29 100644
--- a/net/ipv4/inet_connection_sock.c
+++ b/net/ipv4/inet_connection_sock.c
@@ -406,7 +406,7 @@ struct dst_entry *inet_csk_route_req(struct sock *sk,
rt = ip_route_output_flow(net, fl4, sk);
if (IS_ERR(rt))
goto no_route;
- if (opt && opt->opt.is_strictroute && rt->rt_gateway)
+ if (opt && opt->opt.is_strictroute && rt->rt_uses_gateway)
goto route_err;
return &rt->dst;
@@ -442,7 +442,7 @@ struct dst_entry *inet_csk_route_child_sock(struct sock *sk,
rt = ip_route_output_flow(net, fl4, sk);
if (IS_ERR(rt))
goto no_route;
- if (opt && opt->opt.is_strictroute && rt->rt_gateway)
+ if (opt && opt->opt.is_strictroute && rt->rt_uses_gateway)
goto route_err;
rcu_read_unlock();
return &rt->dst;
diff --git a/net/ipv4/ip_forward.c b/net/ipv4/ip_forward.c
index ab09b12..694de3b 100644
--- a/net/ipv4/ip_forward.c
+++ b/net/ipv4/ip_forward.c
@@ -85,7 +85,7 @@ int ip_forward(struct sk_buff *skb)
rt = skb_rtable(skb);
- if (opt->is_strictroute && opt->nexthop != rt->rt_gateway)
+ if (opt->is_strictroute && rt->rt_uses_gateway)
goto sr_failed;
if (unlikely(skb->len > dst_mtu(&rt->dst) && !skb_is_gso(skb) &&
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index 24a29a3..6537a40 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -193,7 +193,7 @@ static inline int ip_finish_output2(struct sk_buff *skb)
}
rcu_read_lock_bh();
- nexthop = rt->rt_gateway ? rt->rt_gateway : ip_hdr(skb)->daddr;
+ nexthop = (__force u32) rt_nexthop(rt, ip_hdr(skb)->daddr);
neigh = __ipv4_neigh_lookup_noref(dev, nexthop);
if (unlikely(!neigh))
neigh = __neigh_create(&arp_tbl, &nexthop, dev, false);
@@ -371,7 +371,7 @@ int ip_queue_xmit(struct sk_buff *skb, struct flowi *fl)
skb_dst_set_noref(skb, &rt->dst);
packet_routed:
- if (inet_opt && inet_opt->opt.is_strictroute && rt->rt_gateway)
+ if (inet_opt && inet_opt->opt.is_strictroute && rt->rt_uses_gateway)
goto no_route;
/* OK, we know where to send it, allocate and build IP header. */
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index ff62206..1a0da8d 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -802,7 +802,8 @@ void ip_rt_send_redirect(struct sk_buff *skb)
net = dev_net(rt->dst.dev);
peer = inet_getpeer_v4(net->ipv4.peers, ip_hdr(skb)->saddr, 1);
if (!peer) {
- icmp_send(skb, ICMP_REDIRECT, ICMP_REDIR_HOST, rt->rt_gateway);
+ icmp_send(skb, ICMP_REDIRECT, ICMP_REDIR_HOST,
+ rt_nexthop(rt, ip_hdr(skb)->daddr));
return;
}
@@ -827,7 +828,9 @@ void ip_rt_send_redirect(struct sk_buff *skb)
time_after(jiffies,
(peer->rate_last +
(ip_rt_redirect_load << peer->rate_tokens)))) {
- icmp_send(skb, ICMP_REDIRECT, ICMP_REDIR_HOST, rt->rt_gateway);
+ __be32 gw = rt_nexthop(rt, ip_hdr(skb)->daddr);
+
+ icmp_send(skb, ICMP_REDIRECT, ICMP_REDIR_HOST, gw);
peer->rate_last = jiffies;
++peer->rate_tokens;
#ifdef CONFIG_IP_ROUTE_VERBOSE
@@ -835,7 +838,7 @@ void ip_rt_send_redirect(struct sk_buff *skb)
peer->rate_tokens == ip_rt_redirect_number)
net_warn_ratelimited("host %pI4/if%d ignores redirects for %pI4 to %pI4\n",
&ip_hdr(skb)->saddr, inet_iif(skb),
- &ip_hdr(skb)->daddr, &rt->rt_gateway);
+ &ip_hdr(skb)->daddr, &gw);
#endif
}
out_put_peer:
@@ -904,22 +907,32 @@ out: kfree_skb(skb);
return 0;
}
-static u32 __ip_rt_update_pmtu(struct rtable *rt, struct flowi4 *fl4, u32 mtu)
+static void __ip_rt_update_pmtu(struct rtable *rt, struct flowi4 *fl4, u32 mtu)
{
+ struct dst_entry *dst = &rt->dst;
struct fib_result res;
+ if (dst->dev->mtu < mtu)
+ return;
+
if (mtu < ip_rt_min_pmtu)
mtu = ip_rt_min_pmtu;
+ if (!rt->rt_pmtu) {
+ dst->obsolete = DST_OBSOLETE_KILL;
+ } else {
+ rt->rt_pmtu = mtu;
+ dst->expires = max(1UL, jiffies + ip_rt_mtu_expires);
+ }
+
rcu_read_lock();
- if (fib_lookup(dev_net(rt->dst.dev), fl4, &res) == 0) {
+ if (fib_lookup(dev_net(dst->dev), fl4, &res) == 0) {
struct fib_nh *nh = &FIB_RES_NH(res);
update_or_create_fnhe(nh, fl4->daddr, 0, mtu,
jiffies + ip_rt_mtu_expires);
}
rcu_read_unlock();
- return mtu;
}
static void ip_rt_update_pmtu(struct dst_entry *dst, struct sock *sk,
@@ -929,14 +942,7 @@ static void ip_rt_update_pmtu(struct dst_entry *dst, struct sock *sk,
struct flowi4 fl4;
ip_rt_build_flow_key(&fl4, sk, skb);
- mtu = __ip_rt_update_pmtu(rt, &fl4, mtu);
-
- if (!rt->rt_pmtu) {
- dst->obsolete = DST_OBSOLETE_KILL;
- } else {
- rt->rt_pmtu = mtu;
- rt->dst.expires = max(1UL, jiffies + ip_rt_mtu_expires);
- }
+ __ip_rt_update_pmtu(rt, &fl4, mtu);
}
void ipv4_update_pmtu(struct sk_buff *skb, struct net *net, u32 mtu,
@@ -1120,7 +1126,7 @@ static unsigned int ipv4_mtu(const struct dst_entry *dst)
mtu = dst->dev->mtu;
if (unlikely(dst_metric_locked(dst, RTAX_MTU))) {
- if (rt->rt_gateway && mtu > 576)
+ if (rt->rt_uses_gateway && mtu > 576)
mtu = 576;
}
@@ -1171,7 +1177,9 @@ static bool rt_bind_exception(struct rtable *rt, struct fib_nh_exception *fnhe,
if (fnhe->fnhe_gw) {
rt->rt_flags |= RTCF_REDIRECTED;
rt->rt_gateway = fnhe->fnhe_gw;
- }
+ rt->rt_uses_gateway = 1;
+ } else if (!rt->rt_gateway)
+ rt->rt_gateway = daddr;
orig = rcu_dereference(fnhe->fnhe_rth);
rcu_assign_pointer(fnhe->fnhe_rth, rt);
@@ -1180,13 +1188,6 @@ static bool rt_bind_exception(struct rtable *rt, struct fib_nh_exception *fnhe,
fnhe->fnhe_stamp = jiffies;
ret = true;
- } else {
- /* Routes we intend to cache in nexthop exception have
- * the DST_NOCACHE bit clear. However, if we are
- * unsuccessful at storing this route into the cache
- * we really need to set it.
- */
- rt->dst.flags |= DST_NOCACHE;
}
spin_unlock_bh(&fnhe_lock);
@@ -1201,8 +1202,6 @@ static bool rt_cache_route(struct fib_nh *nh, struct rtable *rt)
if (rt_is_input_route(rt)) {
p = (struct rtable **)&nh->nh_rth_input;
} else {
- if (!nh->nh_pcpu_rth_output)
- goto nocache;
p = (struct rtable **)__this_cpu_ptr(nh->nh_pcpu_rth_output);
}
orig = *p;
@@ -1211,16 +1210,8 @@ static bool rt_cache_route(struct fib_nh *nh, struct rtable *rt)
if (prev == orig) {
if (orig)
rt_free(orig);
- } else {
- /* Routes we intend to cache in the FIB nexthop have
- * the DST_NOCACHE bit clear. However, if we are
- * unsuccessful at storing this route into the cache
- * we really need to set it.
- */
-nocache:
- rt->dst.flags |= DST_NOCACHE;
+ } else
ret = false;
- }
return ret;
}
@@ -1281,8 +1272,10 @@ static void rt_set_nexthop(struct rtable *rt, __be32 daddr,
if (fi) {
struct fib_nh *nh = &FIB_RES_NH(*res);
- if (nh->nh_gw && nh->nh_scope == RT_SCOPE_LINK)
+ if (nh->nh_gw && nh->nh_scope == RT_SCOPE_LINK) {
rt->rt_gateway = nh->nh_gw;
+ rt->rt_uses_gateway = 1;
+ }
dst_init_metrics(&rt->dst, fi->fib_metrics, true);
#ifdef CONFIG_IP_ROUTE_CLASSID
rt->dst.tclassid = nh->nh_tclassid;
@@ -1291,8 +1284,18 @@ static void rt_set_nexthop(struct rtable *rt, __be32 daddr,
cached = rt_bind_exception(rt, fnhe, daddr);
else if (!(rt->dst.flags & DST_NOCACHE))
cached = rt_cache_route(nh, rt);
- }
- if (unlikely(!cached))
+ if (unlikely(!cached)) {
+ /* Routes we intend to cache in nexthop exception or
+ * FIB nexthop have the DST_NOCACHE bit clear.
+ * However, if we are unsuccessful at storing this
+ * route into the cache we really need to set it.
+ */
+ rt->dst.flags |= DST_NOCACHE;
+ if (!rt->rt_gateway)
+ rt->rt_gateway = daddr;
+ rt_add_uncached_list(rt);
+ }
+ } else
rt_add_uncached_list(rt);
#ifdef CONFIG_IP_ROUTE_CLASSID
@@ -1360,6 +1363,7 @@ static int ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr,
rth->rt_iif = 0;
rth->rt_pmtu = 0;
rth->rt_gateway = 0;
+ rth->rt_uses_gateway = 0;
INIT_LIST_HEAD(&rth->rt_uncached);
if (our) {
rth->dst.input= ip_local_deliver;
@@ -1429,7 +1433,6 @@ static int __mkroute_input(struct sk_buff *skb,
return -EINVAL;
}
-
err = fib_validate_source(skb, saddr, daddr, tos, FIB_RES_OIF(*res),
in_dev->dev, in_dev, &itag);
if (err < 0) {
@@ -1439,10 +1442,13 @@ static int __mkroute_input(struct sk_buff *skb,
goto cleanup;
}
- if (out_dev == in_dev && err &&
+ do_cache = res->fi && !itag;
+ if (out_dev == in_dev && err && IN_DEV_TX_REDIRECTS(out_dev) &&
(IN_DEV_SHARED_MEDIA(out_dev) ||
- inet_addr_onlink(out_dev, saddr, FIB_RES_GW(*res))))
+ inet_addr_onlink(out_dev, saddr, FIB_RES_GW(*res)))) {
flags |= RTCF_DOREDIRECT;
+ do_cache = false;
+ }
if (skb->protocol != htons(ETH_P_IP)) {
/* Not IP (i.e. ARP). Do not create route, if it is
@@ -1459,15 +1465,11 @@ static int __mkroute_input(struct sk_buff *skb,
}
}
- do_cache = false;
- if (res->fi) {
- if (!itag) {
- rth = rcu_dereference(FIB_RES_NH(*res).nh_rth_input);
- if (rt_cache_valid(rth)) {
- skb_dst_set_noref(skb, &rth->dst);
- goto out;
- }
- do_cache = true;
+ if (do_cache) {
+ rth = rcu_dereference(FIB_RES_NH(*res).nh_rth_input);
+ if (rt_cache_valid(rth)) {
+ skb_dst_set_noref(skb, &rth->dst);
+ goto out;
}
}
@@ -1486,6 +1488,7 @@ static int __mkroute_input(struct sk_buff *skb,
rth->rt_iif = 0;
rth->rt_pmtu = 0;
rth->rt_gateway = 0;
+ rth->rt_uses_gateway = 0;
INIT_LIST_HEAD(&rth->rt_uncached);
rth->dst.input = ip_forward;
@@ -1656,6 +1659,7 @@ local_input:
rth->rt_iif = 0;
rth->rt_pmtu = 0;
rth->rt_gateway = 0;
+ rth->rt_uses_gateway = 0;
INIT_LIST_HEAD(&rth->rt_uncached);
if (res.type == RTN_UNREACHABLE) {
rth->dst.input= ip_error;
@@ -1758,6 +1762,7 @@ static struct rtable *__mkroute_output(const struct fib_result *res,
struct in_device *in_dev;
u16 type = res->type;
struct rtable *rth;
+ bool do_cache;
in_dev = __in_dev_get_rcu(dev_out);
if (!in_dev)
@@ -1794,24 +1799,36 @@ static struct rtable *__mkroute_output(const struct fib_result *res,
}
fnhe = NULL;
+ do_cache = fi != NULL;
if (fi) {
struct rtable __rcu **prth;
+ struct fib_nh *nh = &FIB_RES_NH(*res);
- fnhe = find_exception(&FIB_RES_NH(*res), fl4->daddr);
+ fnhe = find_exception(nh, fl4->daddr);
if (fnhe)
prth = &fnhe->fnhe_rth;
- else
- prth = __this_cpu_ptr(FIB_RES_NH(*res).nh_pcpu_rth_output);
+ else {
+ if (unlikely(fl4->flowi4_flags &
+ FLOWI_FLAG_KNOWN_NH &&
+ !(nh->nh_gw &&
+ nh->nh_scope == RT_SCOPE_LINK))) {
+ do_cache = false;
+ goto add;
+ }
+ prth = __this_cpu_ptr(nh->nh_pcpu_rth_output);
+ }
rth = rcu_dereference(*prth);
if (rt_cache_valid(rth)) {
dst_hold(&rth->dst);
return rth;
}
}
+
+add:
rth = rt_dst_alloc(dev_out,
IN_DEV_CONF_GET(in_dev, NOPOLICY),
IN_DEV_CONF_GET(in_dev, NOXFRM),
- fi);
+ do_cache);
if (!rth)
return ERR_PTR(-ENOBUFS);
@@ -1824,6 +1841,7 @@ static struct rtable *__mkroute_output(const struct fib_result *res,
rth->rt_iif = orig_oif ? : 0;
rth->rt_pmtu = 0;
rth->rt_gateway = 0;
+ rth->rt_uses_gateway = 0;
INIT_LIST_HEAD(&rth->rt_uncached);
RT_CACHE_STAT_INC(out_slow_tot);
@@ -2102,6 +2120,7 @@ struct dst_entry *ipv4_blackhole_route(struct net *net, struct dst_entry *dst_or
rt->rt_flags = ort->rt_flags;
rt->rt_type = ort->rt_type;
rt->rt_gateway = ort->rt_gateway;
+ rt->rt_uses_gateway = ort->rt_uses_gateway;
INIT_LIST_HEAD(&rt->rt_uncached);
@@ -2180,12 +2199,22 @@ static int rt_fill_info(struct net *net, __be32 dst, __be32 src,
if (nla_put_be32(skb, RTA_PREFSRC, fl4->saddr))
goto nla_put_failure;
}
- if (rt->rt_gateway &&
+ if (rt->rt_uses_gateway &&
nla_put_be32(skb, RTA_GATEWAY, rt->rt_gateway))
goto nla_put_failure;
+ expires = rt->dst.expires;
+ if (expires) {
+ unsigned long now = jiffies;
+
+ if (time_before(now, expires))
+ expires -= now;
+ else
+ expires = 0;
+ }
+
memcpy(metrics, dst_metrics_ptr(&rt->dst), sizeof(metrics));
- if (rt->rt_pmtu)
+ if (rt->rt_pmtu && expires)
metrics[RTAX_MTU - 1] = rt->rt_pmtu;
if (rtnetlink_put_metrics(skb, metrics) < 0)
goto nla_put_failure;
@@ -2195,13 +2224,6 @@ static int rt_fill_info(struct net *net, __be32 dst, __be32 src,
goto nla_put_failure;
error = rt->dst.error;
- expires = rt->dst.expires;
- if (expires) {
- if (time_before(jiffies, expires))
- expires -= jiffies;
- else
- expires = 0;
- }
if (rt_is_input_route(rt)) {
if (nla_put_u32(skb, RTA_IIF, rt->rt_iif))
diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c
index 681ea2f..05c5ab8 100644
--- a/net/ipv4/xfrm4_policy.c
+++ b/net/ipv4/xfrm4_policy.c
@@ -91,6 +91,7 @@ static int xfrm4_fill_dst(struct xfrm_dst *xdst, struct net_device *dev,
RTCF_LOCAL);
xdst->u.rt.rt_type = rt->rt_type;
xdst->u.rt.rt_gateway = rt->rt_gateway;
+ xdst->u.rt.rt_uses_gateway = rt->rt_uses_gateway;
xdst->u.rt.rt_pmtu = rt->rt_pmtu;
INIT_LIST_HEAD(&xdst->u.rt.rt_uncached);
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index e22e6d8..a974247 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -822,13 +822,6 @@ out:
return segs;
}
-struct ipv6_gro_cb {
- struct napi_gro_cb napi;
- int proto;
-};
-
-#define IPV6_GRO_CB(skb) ((struct ipv6_gro_cb *)(skb)->cb)
-
static struct sk_buff **ipv6_gro_receive(struct sk_buff **head,
struct sk_buff *skb)
{
@@ -874,28 +867,31 @@ static struct sk_buff **ipv6_gro_receive(struct sk_buff **head,
iph = ipv6_hdr(skb);
}
- IPV6_GRO_CB(skb)->proto = proto;
+ NAPI_GRO_CB(skb)->proto = proto;
flush--;
nlen = skb_network_header_len(skb);
for (p = *head; p; p = p->next) {
- struct ipv6hdr *iph2;
+ const struct ipv6hdr *iph2;
+ __be32 first_word; /* <Version:4><Traffic_Class:8><Flow_Label:20> */
if (!NAPI_GRO_CB(p)->same_flow)
continue;
iph2 = ipv6_hdr(p);
+ first_word = *(__be32 *)iph ^ *(__be32 *)iph2 ;
- /* All fields must match except length. */
+ /* All fields must match except length and Traffic Class. */
if (nlen != skb_network_header_len(p) ||
- memcmp(iph, iph2, offsetof(struct ipv6hdr, payload_len)) ||
+ (first_word & htonl(0xF00FFFFF)) ||
memcmp(&iph->nexthdr, &iph2->nexthdr,
nlen - offsetof(struct ipv6hdr, nexthdr))) {
NAPI_GRO_CB(p)->same_flow = 0;
continue;
}
-
+ /* flush if Traffic Class fields are different */
+ NAPI_GRO_CB(p)->flush |= !!(first_word & htonl(0x0FF00000));
NAPI_GRO_CB(p)->flush |= flush;
}
@@ -927,7 +923,7 @@ static int ipv6_gro_complete(struct sk_buff *skb)
sizeof(*iph));
rcu_read_lock();
- ops = rcu_dereference(inet6_protos[IPV6_GRO_CB(skb)->proto]);
+ ops = rcu_dereference(inet6_protos[NAPI_GRO_CB(skb)->proto]);
if (WARN_ON(!ops || !ops->gro_complete))
goto out_unlock;
diff --git a/net/netfilter/ipvs/ip_vs_xmit.c b/net/netfilter/ipvs/ip_vs_xmit.c
index 56f6d5d..cc4c809 100644
--- a/net/netfilter/ipvs/ip_vs_xmit.c
+++ b/net/netfilter/ipvs/ip_vs_xmit.c
@@ -50,6 +50,7 @@ enum {
* local
*/
IP_VS_RT_MODE_CONNECT = 8, /* Always bind route to saddr */
+ IP_VS_RT_MODE_KNOWN_NH = 16,/* Route via remote addr */
};
/*
@@ -113,6 +114,8 @@ static struct rtable *do_output_route4(struct net *net, __be32 daddr,
fl4.daddr = daddr;
fl4.saddr = (rt_mode & IP_VS_RT_MODE_CONNECT) ? *saddr : 0;
fl4.flowi4_tos = rtos;
+ fl4.flowi4_flags = (rt_mode & IP_VS_RT_MODE_KNOWN_NH) ?
+ FLOWI_FLAG_KNOWN_NH : 0;
retry:
rt = ip_route_output_key(net, &fl4);
@@ -1061,7 +1064,8 @@ ip_vs_dr_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
if (!(rt = __ip_vs_get_out_rt(skb, cp->dest, cp->daddr.ip,
RT_TOS(iph->tos),
IP_VS_RT_MODE_LOCAL |
- IP_VS_RT_MODE_NON_LOCAL, NULL)))
+ IP_VS_RT_MODE_NON_LOCAL |
+ IP_VS_RT_MODE_KNOWN_NH, NULL)))
goto tx_error_icmp;
if (rt->rt_flags & RTCF_LOCAL) {
ip_rt_put(rt);
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index 0f2e3ad..01e944a 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -169,6 +169,8 @@ static void netlink_sock_destruct(struct sock *sk)
if (nlk->cb) {
if (nlk->cb->done)
nlk->cb->done(nlk->cb);
+
+ module_put(nlk->cb->module);
netlink_destroy_callback(nlk->cb);
}
@@ -1758,6 +1760,7 @@ static int netlink_dump(struct sock *sk)
nlk->cb = NULL;
mutex_unlock(nlk->cb_mutex);
+ module_put(cb->module);
netlink_consume_callback(cb);
return 0;
@@ -1767,9 +1770,9 @@ errout_skb:
return err;
}
-int netlink_dump_start(struct sock *ssk, struct sk_buff *skb,
- const struct nlmsghdr *nlh,
- struct netlink_dump_control *control)
+int __netlink_dump_start(struct sock *ssk, struct sk_buff *skb,
+ const struct nlmsghdr *nlh,
+ struct netlink_dump_control *control)
{
struct netlink_callback *cb;
struct sock *sk;
@@ -1784,6 +1787,7 @@ int netlink_dump_start(struct sock *ssk, struct sk_buff *skb,
cb->done = control->done;
cb->nlh = nlh;
cb->data = control->data;
+ cb->module = control->module;
cb->min_dump_alloc = control->min_dump_alloc;
atomic_inc(&skb->users);
cb->skb = skb;
@@ -1794,19 +1798,28 @@ int netlink_dump_start(struct sock *ssk, struct sk_buff *skb,
return -ECONNREFUSED;
}
nlk = nlk_sk(sk);
- /* A dump is in progress... */
+
mutex_lock(nlk->cb_mutex);
+ /* A dump is in progress... */
if (nlk->cb) {
mutex_unlock(nlk->cb_mutex);
netlink_destroy_callback(cb);
- sock_put(sk);
- return -EBUSY;
+ ret = -EBUSY;
+ goto out;
}
+ /* add reference of module which cb->dump belongs to */
+ if (!try_module_get(cb->module)) {
+ mutex_unlock(nlk->cb_mutex);
+ netlink_destroy_callback(cb);
+ ret = -EPROTONOSUPPORT;
+ goto out;
+ }
+
nlk->cb = cb;
mutex_unlock(nlk->cb_mutex);
ret = netlink_dump(sk);
-
+out:
sock_put(sk);
if (ret)
@@ -1817,7 +1830,7 @@ int netlink_dump_start(struct sock *ssk, struct sk_buff *skb,
*/
return -EINTR;
}
-EXPORT_SYMBOL(netlink_dump_start);
+EXPORT_SYMBOL(__netlink_dump_start);
void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err)
{
diff --git a/net/rds/send.c b/net/rds/send.c
index 96531d4..88eace5 100644
--- a/net/rds/send.c
+++ b/net/rds/send.c
@@ -1122,7 +1122,7 @@ rds_send_pong(struct rds_connection *conn, __be16 dport)
rds_stats_inc(s_send_pong);
if (!test_bit(RDS_LL_SEND_FULL, &conn->c_flags))
- rds_send_xmit(conn);
+ queue_delayed_work(rds_wq, &conn->c_send_w, 0);
rds_message_put(rm);
return 0;
diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c
index 34c5220..909dc0c 100644
--- a/net/sunrpc/auth_gss/auth_gss.c
+++ b/net/sunrpc/auth_gss/auth_gss.c
@@ -239,7 +239,7 @@ gss_fill_context(const void *p, const void *end, struct gss_cl_ctx *ctx, struct
}
return q;
err:
- dprintk("RPC: gss_fill_context returning %ld\n", -PTR_ERR(p));
+ dprintk("RPC: %s returning %ld\n", __func__, -PTR_ERR(p));
return p;
}
@@ -301,10 +301,10 @@ __gss_find_upcall(struct rpc_pipe *pipe, uid_t uid)
if (pos->uid != uid)
continue;
atomic_inc(&pos->count);
- dprintk("RPC: gss_find_upcall found msg %p\n", pos);
+ dprintk("RPC: %s found msg %p\n", __func__, pos);
return pos;
}
- dprintk("RPC: gss_find_upcall found nothing\n");
+ dprintk("RPC: %s found nothing\n", __func__);
return NULL;
}
@@ -507,8 +507,8 @@ gss_refresh_upcall(struct rpc_task *task)
struct rpc_pipe *pipe;
int err = 0;
- dprintk("RPC: %5u gss_refresh_upcall for uid %u\n", task->tk_pid,
- cred->cr_uid);
+ dprintk("RPC: %5u %s for uid %u\n",
+ task->tk_pid, __func__, cred->cr_uid);
gss_msg = gss_setup_upcall(task->tk_client, gss_auth, cred);
if (PTR_ERR(gss_msg) == -EAGAIN) {
/* XXX: warning on the first, under the assumption we
@@ -539,8 +539,8 @@ gss_refresh_upcall(struct rpc_task *task)
spin_unlock(&pipe->lock);
gss_release_msg(gss_msg);
out:
- dprintk("RPC: %5u gss_refresh_upcall for uid %u result %d\n",
- task->tk_pid, cred->cr_uid, err);
+ dprintk("RPC: %5u %s for uid %u result %d\n",
+ task->tk_pid, __func__, cred->cr_uid, err);
return err;
}
@@ -553,7 +553,7 @@ gss_create_upcall(struct gss_auth *gss_auth, struct gss_cred *gss_cred)
DEFINE_WAIT(wait);
int err = 0;
- dprintk("RPC: gss_upcall for uid %u\n", cred->cr_uid);
+ dprintk("RPC: %s for uid %u\n", __func__, cred->cr_uid);
retry:
gss_msg = gss_setup_upcall(gss_auth->client, gss_auth, cred);
if (PTR_ERR(gss_msg) == -EAGAIN) {
@@ -594,8 +594,8 @@ out_intr:
finish_wait(&gss_msg->waitqueue, &wait);
gss_release_msg(gss_msg);
out:
- dprintk("RPC: gss_create_upcall for uid %u result %d\n",
- cred->cr_uid, err);
+ dprintk("RPC: %s for uid %u result %d\n",
+ __func__, cred->cr_uid, err);
return err;
}
@@ -681,7 +681,7 @@ err_put_ctx:
err:
kfree(buf);
out:
- dprintk("RPC: gss_pipe_downcall returning %Zd\n", err);
+ dprintk("RPC: %s returning %Zd\n", __func__, err);
return err;
}
@@ -747,8 +747,8 @@ gss_pipe_destroy_msg(struct rpc_pipe_msg *msg)
struct gss_upcall_msg *gss_msg = container_of(msg, struct gss_upcall_msg, msg);
if (msg->errno < 0) {
- dprintk("RPC: gss_pipe_destroy_msg releasing msg %p\n",
- gss_msg);
+ dprintk("RPC: %s releasing msg %p\n",
+ __func__, gss_msg);
atomic_inc(&gss_msg->count);
gss_unhash_msg(gss_msg);
if (msg->errno == -ETIMEDOUT)
@@ -976,7 +976,7 @@ gss_destroying_context(struct rpc_cred *cred)
static void
gss_do_free_ctx(struct gss_cl_ctx *ctx)
{
- dprintk("RPC: gss_free_ctx\n");
+ dprintk("RPC: %s\n", __func__);
gss_delete_sec_context(&ctx->gc_gss_ctx);
kfree(ctx->gc_wire_ctx.data);
@@ -999,7 +999,7 @@ gss_free_ctx(struct gss_cl_ctx *ctx)
static void
gss_free_cred(struct gss_cred *gss_cred)
{
- dprintk("RPC: gss_free_cred %p\n", gss_cred);
+ dprintk("RPC: %s cred=%p\n", __func__, gss_cred);
kfree(gss_cred);
}
@@ -1049,8 +1049,8 @@ gss_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags)
struct gss_cred *cred = NULL;
int err = -ENOMEM;
- dprintk("RPC: gss_create_cred for uid %d, flavor %d\n",
- acred->uid, auth->au_flavor);
+ dprintk("RPC: %s for uid %d, flavor %d\n",
+ __func__, acred->uid, auth->au_flavor);
if (!(cred = kzalloc(sizeof(*cred), GFP_NOFS)))
goto out_err;
@@ -1069,7 +1069,7 @@ gss_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags)
return &cred->gc_base;
out_err:
- dprintk("RPC: gss_create_cred failed with error %d\n", err);
+ dprintk("RPC: %s failed with error %d\n", __func__, err);
return ERR_PTR(err);
}
@@ -1127,7 +1127,7 @@ gss_marshal(struct rpc_task *task, __be32 *p)
struct kvec iov;
struct xdr_buf verf_buf;
- dprintk("RPC: %5u gss_marshal\n", task->tk_pid);
+ dprintk("RPC: %5u %s\n", task->tk_pid, __func__);
*p++ = htonl(RPC_AUTH_GSS);
cred_len = p++;
@@ -1253,7 +1253,7 @@ gss_validate(struct rpc_task *task, __be32 *p)
u32 flav,len;
u32 maj_stat;
- dprintk("RPC: %5u gss_validate\n", task->tk_pid);
+ dprintk("RPC: %5u %s\n", task->tk_pid, __func__);
flav = ntohl(*p++);
if ((len = ntohl(*p++)) > RPC_MAX_AUTH_SIZE)
@@ -1271,20 +1271,20 @@ gss_validate(struct rpc_task *task, __be32 *p)
if (maj_stat == GSS_S_CONTEXT_EXPIRED)
clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags);
if (maj_stat) {
- dprintk("RPC: %5u gss_validate: gss_verify_mic returned "
- "error 0x%08x\n", task->tk_pid, maj_stat);
+ dprintk("RPC: %5u %s: gss_verify_mic returned error 0x%08x\n",
+ task->tk_pid, __func__, maj_stat);
goto out_bad;
}
/* We leave it to unwrap to calculate au_rslack. For now we just
* calculate the length of the verifier: */
cred->cr_auth->au_verfsize = XDR_QUADLEN(len) + 2;
gss_put_ctx(ctx);
- dprintk("RPC: %5u gss_validate: gss_verify_mic succeeded.\n",
- task->tk_pid);
+ dprintk("RPC: %5u %s: gss_verify_mic succeeded.\n",
+ task->tk_pid, __func__);
return p + XDR_QUADLEN(len);
out_bad:
gss_put_ctx(ctx);
- dprintk("RPC: %5u gss_validate failed.\n", task->tk_pid);
+ dprintk("RPC: %5u %s failed.\n", task->tk_pid, __func__);
return NULL;
}
@@ -1466,7 +1466,7 @@ gss_wrap_req(struct rpc_task *task,
struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred);
int status = -EIO;
- dprintk("RPC: %5u gss_wrap_req\n", task->tk_pid);
+ dprintk("RPC: %5u %s\n", task->tk_pid, __func__);
if (ctx->gc_proc != RPC_GSS_PROC_DATA) {
/* The spec seems a little ambiguous here, but I think that not
* wrapping context destruction requests makes the most sense.
@@ -1489,7 +1489,7 @@ gss_wrap_req(struct rpc_task *task,
}
out:
gss_put_ctx(ctx);
- dprintk("RPC: %5u gss_wrap_req returning %d\n", task->tk_pid, status);
+ dprintk("RPC: %5u %s returning %d\n", task->tk_pid, __func__, status);
return status;
}
@@ -1604,8 +1604,8 @@ out_decode:
status = gss_unwrap_req_decode(decode, rqstp, p, obj);
out:
gss_put_ctx(ctx);
- dprintk("RPC: %5u gss_unwrap_resp returning %d\n", task->tk_pid,
- status);
+ dprintk("RPC: %5u %s returning %d\n",
+ task->tk_pid, __func__, status);
return status;
}
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
index fa48c60..cdc7564b 100644
--- a/net/sunrpc/clnt.c
+++ b/net/sunrpc/clnt.c
@@ -490,61 +490,86 @@ EXPORT_SYMBOL_GPL(rpc_create);
* same transport while varying parameters such as the authentication
* flavour.
*/
-struct rpc_clnt *
-rpc_clone_client(struct rpc_clnt *clnt)
+static struct rpc_clnt *__rpc_clone_client(struct rpc_create_args *args,
+ struct rpc_clnt *clnt)
{
- struct rpc_clnt *new;
struct rpc_xprt *xprt;
- int err = -ENOMEM;
+ struct rpc_clnt *new;
+ int err;
- new = kmemdup(clnt, sizeof(*new), GFP_KERNEL);
- if (!new)
- goto out_no_clnt;
- new->cl_parent = clnt;
- /* Turn off autobind on clones */
- new->cl_autobind = 0;
- INIT_LIST_HEAD(&new->cl_tasks);
- spin_lock_init(&new->cl_lock);
- rpc_init_rtt(&new->cl_rtt_default, clnt->cl_timeout->to_initval);
- new->cl_metrics = rpc_alloc_iostats(clnt);
- if (new->cl_metrics == NULL)
- goto out_no_stats;
- if (clnt->cl_principal) {
- new->cl_principal = kstrdup(clnt->cl_principal, GFP_KERNEL);
- if (new->cl_principal == NULL)
- goto out_no_principal;
- }
+ err = -ENOMEM;
rcu_read_lock();
xprt = xprt_get(rcu_dereference(clnt->cl_xprt));
rcu_read_unlock();
if (xprt == NULL)
- goto out_no_transport;
- rcu_assign_pointer(new->cl_xprt, xprt);
- atomic_set(&new->cl_count, 1);
- err = rpc_setup_pipedir(new, clnt->cl_program->pipe_dir_name);
- if (err != 0)
- goto out_no_path;
- rpc_clnt_set_nodename(new, utsname()->nodename);
- if (new->cl_auth)
- atomic_inc(&new->cl_auth->au_count);
+ goto out_err;
+ args->servername = xprt->servername;
+
+ new = rpc_new_client(args, xprt);
+ if (IS_ERR(new)) {
+ err = PTR_ERR(new);
+ goto out_put;
+ }
+
atomic_inc(&clnt->cl_count);
- rpc_register_client(new);
- rpciod_up();
+ new->cl_parent = clnt;
+
+ /* Turn off autobind on clones */
+ new->cl_autobind = 0;
+ new->cl_softrtry = clnt->cl_softrtry;
+ new->cl_discrtry = clnt->cl_discrtry;
+ new->cl_chatty = clnt->cl_chatty;
return new;
-out_no_path:
+
+out_put:
xprt_put(xprt);
-out_no_transport:
- kfree(new->cl_principal);
-out_no_principal:
- rpc_free_iostats(new->cl_metrics);
-out_no_stats:
- kfree(new);
-out_no_clnt:
+out_err:
dprintk("RPC: %s: returned error %d\n", __func__, err);
return ERR_PTR(err);
}
+
+/**
+ * rpc_clone_client - Clone an RPC client structure
+ *
+ * @clnt: RPC client whose parameters are copied
+ *
+ * Returns a fresh RPC client or an ERR_PTR.
+ */
+struct rpc_clnt *rpc_clone_client(struct rpc_clnt *clnt)
+{
+ struct rpc_create_args args = {
+ .program = clnt->cl_program,
+ .prognumber = clnt->cl_prog,
+ .version = clnt->cl_vers,
+ .authflavor = clnt->cl_auth->au_flavor,
+ .client_name = clnt->cl_principal,
+ };
+ return __rpc_clone_client(&args, clnt);
+}
EXPORT_SYMBOL_GPL(rpc_clone_client);
+/**
+ * rpc_clone_client_set_auth - Clone an RPC client structure and set its auth
+ *
+ * @clnt: RPC client whose parameters are copied
+ * @auth: security flavor for new client
+ *
+ * Returns a fresh RPC client or an ERR_PTR.
+ */
+struct rpc_clnt *
+rpc_clone_client_set_auth(struct rpc_clnt *clnt, rpc_authflavor_t flavor)
+{
+ struct rpc_create_args args = {
+ .program = clnt->cl_program,
+ .prognumber = clnt->cl_prog,
+ .version = clnt->cl_vers,
+ .authflavor = flavor,
+ .client_name = clnt->cl_principal,
+ };
+ return __rpc_clone_client(&args, clnt);
+}
+EXPORT_SYMBOL_GPL(rpc_clone_client_set_auth);
+
/*
* Kill all tasks for the given client.
* XXX: kill their descendants as well?
diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c
index 21fde99..80f5dd2 100644
--- a/net/sunrpc/rpc_pipe.c
+++ b/net/sunrpc/rpc_pipe.c
@@ -1119,8 +1119,8 @@ rpc_fill_super(struct super_block *sb, void *data, int silent)
return -ENOMEM;
if (rpc_populate(root, files, RPCAUTH_lockd, RPCAUTH_RootEOF, NULL))
return -ENOMEM;
- dprintk("RPC: sending pipefs MOUNT notification for net %p%s\n", net,
- NET_NAME(net));
+ dprintk("RPC: sending pipefs MOUNT notification for net %p%s\n",
+ net, NET_NAME(net));
sn->pipefs_sb = sb;
err = blocking_notifier_call_chain(&rpc_pipefs_notifier_list,
RPC_PIPEFS_MOUNT,
@@ -1155,8 +1155,8 @@ static void rpc_kill_sb(struct super_block *sb)
sn->pipefs_sb = NULL;
mutex_unlock(&sn->pipefs_sb_lock);
put_net(net);
- dprintk("RPC: sending pipefs UMOUNT notification for net %p%s\n", net,
- NET_NAME(net));
+ dprintk("RPC: sending pipefs UMOUNT notification for net %p%s\n",
+ net, NET_NAME(net));
blocking_notifier_call_chain(&rpc_pipefs_notifier_list,
RPC_PIPEFS_UMOUNT,
sb);
diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c
index 128494ec..6357fcb 100644
--- a/net/sunrpc/sched.c
+++ b/net/sunrpc/sched.c
@@ -1022,7 +1022,7 @@ static int rpciod_start(void)
* Create the rpciod thread and wait for it to start.
*/
dprintk("RPC: creating workqueue rpciod\n");
- wq = alloc_workqueue("rpciod", WQ_MEM_RECLAIM, 0);
+ wq = alloc_workqueue("rpciod", WQ_MEM_RECLAIM, 1);
rpciod_workqueue = wq;
return rpciod_workqueue != NULL;
}
diff --git a/net/sunrpc/xdr.c b/net/sunrpc/xdr.c
index 0afba1b..08f50af 100644
--- a/net/sunrpc/xdr.c
+++ b/net/sunrpc/xdr.c
@@ -730,19 +730,24 @@ static unsigned int xdr_align_pages(struct xdr_stream *xdr, unsigned int len)
if (xdr->nwords == 0)
return 0;
- if (nwords > xdr->nwords) {
- nwords = xdr->nwords;
- len = nwords << 2;
- }
/* Realign pages to current pointer position */
iov = buf->head;
- if (iov->iov_len > cur)
+ if (iov->iov_len > cur) {
xdr_shrink_bufhead(buf, iov->iov_len - cur);
+ xdr->nwords = XDR_QUADLEN(buf->len - cur);
+ }
- /* Truncate page data and move it into the tail */
- if (buf->page_len > len)
+ if (nwords > xdr->nwords) {
+ nwords = xdr->nwords;
+ len = nwords << 2;
+ }
+ if (buf->page_len <= len)
+ len = buf->page_len;
+ else if (nwords < xdr->nwords) {
+ /* Truncate page data and move it into the tail */
xdr_shrink_pagelen(buf, buf->page_len - len);
- xdr->nwords = XDR_QUADLEN(buf->len - cur);
+ xdr->nwords = XDR_QUADLEN(buf->len - cur);
+ }
return len;
}
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c
index 5d7f61d..bd462a5 100644
--- a/net/sunrpc/xprt.c
+++ b/net/sunrpc/xprt.c
@@ -231,7 +231,7 @@ EXPORT_SYMBOL_GPL(xprt_reserve_xprt);
static void xprt_clear_locked(struct rpc_xprt *xprt)
{
xprt->snd_task = NULL;
- if (!test_bit(XPRT_CLOSE_WAIT, &xprt->state) || xprt->shutdown) {
+ if (!test_bit(XPRT_CLOSE_WAIT, &xprt->state)) {
smp_mb__before_clear_bit();
clear_bit(XPRT_LOCKED, &xprt->state);
smp_mb__after_clear_bit();
@@ -504,9 +504,6 @@ EXPORT_SYMBOL_GPL(xprt_wait_for_buffer_space);
*/
void xprt_write_space(struct rpc_xprt *xprt)
{
- if (unlikely(xprt->shutdown))
- return;
-
spin_lock_bh(&xprt->transport_lock);
if (xprt->snd_task) {
dprintk("RPC: write space: waking waiting task on "
@@ -679,7 +676,7 @@ xprt_init_autodisconnect(unsigned long data)
struct rpc_xprt *xprt = (struct rpc_xprt *)data;
spin_lock(&xprt->transport_lock);
- if (!list_empty(&xprt->recv) || xprt->shutdown)
+ if (!list_empty(&xprt->recv))
goto out_abort;
if (test_and_set_bit(XPRT_LOCKED, &xprt->state))
goto out_abort;
@@ -1262,7 +1259,6 @@ out:
static void xprt_destroy(struct rpc_xprt *xprt)
{
dprintk("RPC: destroying transport %p\n", xprt);
- xprt->shutdown = 1;
del_timer_sync(&xprt->timer);
rpc_destroy_wait_queue(&xprt->binding);
diff --git a/net/sunrpc/xprtrdma/transport.c b/net/sunrpc/xprtrdma/transport.c
index 5d9202d..c9aa7a3 100644
--- a/net/sunrpc/xprtrdma/transport.c
+++ b/net/sunrpc/xprtrdma/transport.c
@@ -199,21 +199,15 @@ xprt_rdma_connect_worker(struct work_struct *work)
struct rpc_xprt *xprt = &r_xprt->xprt;
int rc = 0;
- if (!xprt->shutdown) {
- current->flags |= PF_FSTRANS;
- xprt_clear_connected(xprt);
-
- dprintk("RPC: %s: %sconnect\n", __func__,
- r_xprt->rx_ep.rep_connected != 0 ? "re" : "");
- rc = rpcrdma_ep_connect(&r_xprt->rx_ep, &r_xprt->rx_ia);
- if (rc)
- goto out;
- }
- goto out_clear;
+ current->flags |= PF_FSTRANS;
+ xprt_clear_connected(xprt);
+
+ dprintk("RPC: %s: %sconnect\n", __func__,
+ r_xprt->rx_ep.rep_connected != 0 ? "re" : "");
+ rc = rpcrdma_ep_connect(&r_xprt->rx_ep, &r_xprt->rx_ia);
+ if (rc)
+ xprt_wake_pending_tasks(xprt, rc);
-out:
- xprt_wake_pending_tasks(xprt, rc);
-out_clear:
dprintk("RPC: %s: exit\n", __func__);
xprt_clear_connecting(xprt);
current->flags &= ~PF_FSTRANS;
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c
index a35b8e5..aaaadfb 100644
--- a/net/sunrpc/xprtsock.c
+++ b/net/sunrpc/xprtsock.c
@@ -917,9 +917,6 @@ static void xs_local_data_ready(struct sock *sk, int len)
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);
@@ -981,9 +978,6 @@ static void xs_udp_data_ready(struct sock *sk, int len)
if ((skb = skb_recv_datagram(sk, 0, 1, &err)) == NULL)
goto out;
- if (xprt->shutdown)
- goto dropit;
-
repsize = skb->len - sizeof(struct udphdr);
if (repsize < 4) {
dprintk("RPC: impossible RPC reply size %d!\n", repsize);
@@ -1025,6 +1019,16 @@ static void xs_udp_data_ready(struct sock *sk, int len)
read_unlock_bh(&sk->sk_callback_lock);
}
+/*
+ * Helper function to force a TCP close if the server is sending
+ * junk and/or it has put us in CLOSE_WAIT
+ */
+static void xs_tcp_force_close(struct rpc_xprt *xprt)
+{
+ set_bit(XPRT_CONNECTION_CLOSE, &xprt->state);
+ xprt_force_disconnect(xprt);
+}
+
static inline void xs_tcp_read_fraghdr(struct rpc_xprt *xprt, struct xdr_skb_reader *desc)
{
struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt);
@@ -1051,7 +1055,7 @@ static inline void xs_tcp_read_fraghdr(struct rpc_xprt *xprt, struct xdr_skb_rea
/* Sanity check of the record length */
if (unlikely(transport->tcp_reclen < 8)) {
dprintk("RPC: invalid TCP record fragment length\n");
- xprt_force_disconnect(xprt);
+ xs_tcp_force_close(xprt);
return;
}
dprintk("RPC: reading TCP record fragment of length %d\n",
@@ -1132,7 +1136,7 @@ static inline void xs_tcp_read_calldir(struct sock_xprt *transport,
break;
default:
dprintk("RPC: invalid request message type\n");
- xprt_force_disconnect(&transport->xprt);
+ xs_tcp_force_close(&transport->xprt);
}
xs_tcp_check_fraghdr(transport);
}
@@ -1402,9 +1406,6 @@ static void xs_tcp_data_ready(struct sock *sk, int bytes)
read_lock_bh(&sk->sk_callback_lock);
if (!(xprt = xprt_from_sock(sk)))
goto out;
- if (xprt->shutdown)
- goto out;
-
/* Any data means we had a useful conversation, so
* the we don't need to delay the next reconnect
*/
@@ -1455,6 +1456,8 @@ static void xs_tcp_cancel_linger_timeout(struct rpc_xprt *xprt)
static void xs_sock_mark_closed(struct rpc_xprt *xprt)
{
smp_mb__before_clear_bit();
+ clear_bit(XPRT_CONNECTION_ABORT, &xprt->state);
+ clear_bit(XPRT_CONNECTION_CLOSE, &xprt->state);
clear_bit(XPRT_CLOSE_WAIT, &xprt->state);
clear_bit(XPRT_CLOSING, &xprt->state);
smp_mb__after_clear_bit();
@@ -1512,8 +1515,8 @@ static void xs_tcp_state_change(struct sock *sk)
break;
case TCP_CLOSE_WAIT:
/* The server initiated a shutdown of the socket */
- xprt_force_disconnect(xprt);
xprt->connect_cookie++;
+ xs_tcp_force_close(xprt);
case TCP_CLOSING:
/*
* If the server closed down the connection, make sure that
@@ -1889,9 +1892,6 @@ static void xs_local_setup_socket(struct work_struct *work)
struct socket *sock;
int status = -EIO;
- if (xprt->shutdown)
- goto out;
-
current->flags |= PF_FSTRANS;
clear_bit(XPRT_CONNECTION_ABORT, &xprt->state);
@@ -2008,9 +2008,6 @@ static void xs_udp_setup_socket(struct work_struct *work)
struct socket *sock = transport->sock;
int status = -EIO;
- if (xprt->shutdown)
- goto out;
-
current->flags |= PF_FSTRANS;
/* Start by resetting any existing state */
@@ -2156,9 +2153,6 @@ static void xs_tcp_setup_socket(struct work_struct *work)
struct rpc_xprt *xprt = &transport->xprt;
int status = -EIO;
- if (xprt->shutdown)
- goto out;
-
current->flags |= PF_FSTRANS;
if (!sock) {
@@ -2199,8 +2193,7 @@ static void xs_tcp_setup_socket(struct work_struct *work)
/* We're probably in TIME_WAIT. Get rid of existing socket,
* and retry
*/
- set_bit(XPRT_CONNECTION_CLOSE, &xprt->state);
- xprt_force_disconnect(xprt);
+ xs_tcp_force_close(xprt);
break;
case -ECONNREFUSED:
case -ECONNRESET:
@@ -2528,6 +2521,7 @@ static struct rpc_xprt_ops xs_tcp_ops = {
static struct rpc_xprt_ops bc_tcp_ops = {
.reserve_xprt = xprt_reserve_xprt,
.release_xprt = xprt_release_xprt,
+ .alloc_slot = xprt_alloc_slot,
.rpcbind = xs_local_rpcbind,
.buf_alloc = bc_malloc,
.buf_free = bc_free,
diff --git a/scripts/Makefile.modinst b/scripts/Makefile.modinst
index efa5d94..3d13d3a 100644
--- a/scripts/Makefile.modinst
+++ b/scripts/Makefile.modinst
@@ -9,7 +9,7 @@ include scripts/Kbuild.include
#
-__modules := $(sort $(shell grep -h '\.ko' /dev/null $(wildcard $(MODVERDIR)/*.mod)))
+__modules := $(sort $(shell grep -h '\.ko$$' /dev/null $(wildcard $(MODVERDIR)/*.mod)))
modules := $(patsubst %.o,%.ko,$(wildcard $(__modules:.ko=.o)))
PHONY += $(modules)
diff --git a/scripts/Makefile.modpost b/scripts/Makefile.modpost
index 08dce14..a1cb022 100644
--- a/scripts/Makefile.modpost
+++ b/scripts/Makefile.modpost
@@ -60,7 +60,7 @@ kernelsymfile := $(objtree)/Module.symvers
modulesymfile := $(firstword $(KBUILD_EXTMOD))/Module.symvers
# Step 1), find all modules listed in $(MODVERDIR)/
-__modules := $(sort $(shell grep -h '\.ko' /dev/null $(wildcard $(MODVERDIR)/*.mod)))
+__modules := $(sort $(shell grep -h '\.ko$$' /dev/null $(wildcard $(MODVERDIR)/*.mod)))
modules := $(patsubst %.o,%.ko, $(wildcard $(__modules:.ko=.o)))
# Stop after building .o files if NOFINAL is set. Makes compile tests quicker
diff --git a/scripts/coccicheck b/scripts/coccicheck
index 823e972..1a49d1c 100755
--- a/scripts/coccicheck
+++ b/scripts/coccicheck
@@ -95,6 +95,9 @@ coccinelle () {
$SPATCH -D report $FLAGS -sp_file $COCCI $OPT $OPTIONS -no_show_diff || \
$SPATCH -D context $FLAGS -sp_file $COCCI $OPT $OPTIONS || \
$SPATCH -D org $FLAGS -sp_file $COCCI $OPT $OPTIONS -no_show_diff || exit 1
+ elif [ "$MODE" = "rep+ctxt" ] ; then
+ $SPATCH -D report $FLAGS -sp_file $COCCI $OPT $OPTIONS -no_show_diff && \
+ $SPATCH -D context $FLAGS -sp_file $COCCI $OPT $OPTIONS || exit 1
else
$SPATCH -D $MODE $FLAGS -sp_file $COCCI $OPT $OPTIONS || exit 1
fi
diff --git a/scripts/coccinelle/api/ptr_ret.cocci b/scripts/coccinelle/api/ptr_ret.cocci
index cbfd08c..15f076f 100644
--- a/scripts/coccinelle/api/ptr_ret.cocci
+++ b/scripts/coccinelle/api/ptr_ret.cocci
@@ -30,6 +30,13 @@ expression ptr;
- if (IS_ERR(ptr)) return PTR_ERR(ptr); return 0;
+ return PTR_RET(ptr);
+@depends on patch@
+expression ptr;
+@@
+
+- (IS_ERR(ptr) ? PTR_ERR(ptr) : 0)
++ PTR_RET(ptr)
+
@r1 depends on !patch@
expression ptr;
position p1;
@@ -44,6 +51,13 @@ position p2;
* if@p2 (IS_ERR(ptr)) return PTR_ERR(ptr); return 0;
+@r3 depends on !patch@
+expression ptr;
+position p3;
+@@
+
+* IS_ERR@p3(ptr) ? PTR_ERR(ptr) : 0
+
@script:python depends on org@
p << r1.p1;
@@
@@ -57,6 +71,12 @@ p << r2.p2;
coccilib.org.print_todo(p[0], "WARNING: PTR_RET can be used")
+@script:python depends on org@
+p << r3.p3;
+@@
+
+coccilib.org.print_todo(p[0], "WARNING: PTR_RET can be used")
+
@script:python depends on report@
p << r1.p1;
@@
@@ -68,3 +88,9 @@ p << r2.p2;
@@
coccilib.report.print_report(p[0], "WARNING: PTR_RET can be used")
+
+@script:python depends on report@
+p << r3.p3;
+@@
+
+coccilib.report.print_report(p[0], "WARNING: PTR_RET can be used")
diff --git a/scripts/coccinelle/tests/odd_ptr_err.cocci b/scripts/coccinelle/tests/odd_ptr_err.cocci
new file mode 100644
index 0000000..e8dd8a6
--- /dev/null
+++ b/scripts/coccinelle/tests/odd_ptr_err.cocci
@@ -0,0 +1,65 @@
+/// PTR_ERR should access the value just tested by IS_ERR
+//# There can be false positives in the patch case, where it is the call
+//# IS_ERR that is wrong.
+///
+// Confidence: High
+// Copyright: (C) 2012 Julia Lawall, INRIA. GPLv2.
+// Copyright: (C) 2012 Gilles Muller, INRIA. GPLv2.
+// URL: http://coccinelle.lip6.fr/
+// Comments:
+// Options: -no_includes -include_headers
+
+virtual patch
+virtual context
+virtual org
+virtual report
+
+@depends on patch@
+expression e,e1;
+@@
+
+(
+if (IS_ERR(e)) { ... PTR_ERR(e) ... }
+|
+if (IS_ERR(e=e1)) { ... PTR_ERR(e) ... }
+|
+if (IS_ERR(e))
+ { ...
+ PTR_ERR(
+- e1
++ e
+ )
+ ... }
+)
+
+@r depends on !patch@
+expression e,e1;
+position p1,p2;
+@@
+
+(
+if (IS_ERR(e)) { ... PTR_ERR(e) ... }
+|
+if (IS_ERR(e=e1)) { ... PTR_ERR(e) ... }
+|
+*if (IS_ERR@p1(e))
+ { ...
+* PTR_ERR@p2(e1)
+ ... }
+)
+
+@script:python depends on org@
+p1 << r.p1;
+p2 << r.p2;
+@@
+
+cocci.print_main("inconsistent IS_ERR and PTR_ERR",p1)
+cocci.print_secs("PTR_ERR",p2)
+
+@script:python depends on report@
+p1 << r.p1;
+p2 << r.p2;
+@@
+
+msg = "inconsistent IS_ERR and PTR_ERR, PTR_ERR on line %s" % (p2[0].line)
+coccilib.report.print_report(p1[0],msg)
diff --git a/scripts/kconfig/Makefile b/scripts/kconfig/Makefile
index 77d5399..3091794 100644
--- a/scripts/kconfig/Makefile
+++ b/scripts/kconfig/Makefile
@@ -76,11 +76,17 @@ PHONY += allnoconfig allyesconfig allmodconfig alldefconfig randconfig
allnoconfig allyesconfig allmodconfig alldefconfig randconfig: $(obj)/conf
$< --$@ $(Kconfig)
-PHONY += listnewconfig oldnoconfig savedefconfig defconfig
+PHONY += listnewconfig olddefconfig oldnoconfig savedefconfig defconfig
-listnewconfig oldnoconfig: $(obj)/conf
+listnewconfig olddefconfig: $(obj)/conf
$< --$@ $(Kconfig)
+# oldnoconfig is an alias of olddefconfig, because people already are dependent
+# on its behavior(sets new symbols to their default value but not 'n') with the
+# counter-intuitive name.
+oldnoconfig: $(obj)/conf
+ $< --olddefconfig $(Kconfig)
+
savedefconfig: $(obj)/conf
$< --$@=defconfig $(Kconfig)
@@ -114,7 +120,7 @@ help:
@echo ' alldefconfig - New config with all symbols set to default'
@echo ' randconfig - New config with random answer to all options'
@echo ' listnewconfig - List new options'
- @echo ' oldnoconfig - Same as silentoldconfig but sets new symbols to their default value'
+ @echo ' olddefconfig - Same as silentoldconfig but sets new symbols to their default value'
# lxdialog stuff
check-lxdialog := $(srctree)/$(src)/lxdialog/check-lxdialog.sh
diff --git a/scripts/kconfig/conf.c b/scripts/kconfig/conf.c
index 0dc4a2c..4da3b4a 100644
--- a/scripts/kconfig/conf.c
+++ b/scripts/kconfig/conf.c
@@ -32,7 +32,7 @@ enum input_mode {
defconfig,
savedefconfig,
listnewconfig,
- oldnoconfig,
+ olddefconfig,
} input_mode = oldaskconfig;
static int indent = 1;
@@ -365,7 +365,7 @@ static void conf(struct menu *menu)
case P_MENU:
if ((input_mode == silentoldconfig ||
input_mode == listnewconfig ||
- input_mode == oldnoconfig) &&
+ input_mode == olddefconfig) &&
rootEntry != menu) {
check_conf(menu);
return;
@@ -429,7 +429,7 @@ static void check_conf(struct menu *menu)
if (sym->name && !sym_is_choice_value(sym)) {
printf("%s%s\n", CONFIG_, sym->name);
}
- } else if (input_mode != oldnoconfig) {
+ } else if (input_mode != olddefconfig) {
if (!conf_cnt++)
printf(_("*\n* Restart config...\n*\n"));
rootEntry = menu_get_parent_menu(menu);
@@ -454,7 +454,13 @@ static struct option long_opts[] = {
{"alldefconfig", no_argument, NULL, alldefconfig},
{"randconfig", no_argument, NULL, randconfig},
{"listnewconfig", no_argument, NULL, listnewconfig},
- {"oldnoconfig", no_argument, NULL, oldnoconfig},
+ {"olddefconfig", no_argument, NULL, olddefconfig},
+ /*
+ * oldnoconfig is an alias of olddefconfig, because people already
+ * are dependent on its behavior(sets new symbols to their default
+ * value but not 'n') with the counter-intuitive name.
+ */
+ {"oldnoconfig", no_argument, NULL, olddefconfig},
{NULL, 0, NULL, 0}
};
@@ -467,7 +473,8 @@ static void conf_usage(const char *progname)
printf(" --oldaskconfig Start a new configuration using a line-oriented program\n");
printf(" --oldconfig Update a configuration using a provided .config as base\n");
printf(" --silentoldconfig Same as oldconfig, but quietly, additionally update deps\n");
- printf(" --oldnoconfig Same as silentoldconfig but set new symbols to no\n");
+ printf(" --olddefconfig Same as silentoldconfig but sets new symbols to their default value\n");
+ printf(" --oldnoconfig An alias of olddefconfig\n");
printf(" --defconfig <file> New config with default defined in <file>\n");
printf(" --savedefconfig <file> Save the minimal current configuration to <file>\n");
printf(" --allnoconfig New config where all options are answered with no\n");
@@ -520,7 +527,7 @@ int main(int ac, char **av)
case allmodconfig:
case alldefconfig:
case listnewconfig:
- case oldnoconfig:
+ case olddefconfig:
break;
case '?':
conf_usage(progname);
@@ -565,7 +572,7 @@ int main(int ac, char **av)
case oldaskconfig:
case oldconfig:
case listnewconfig:
- case oldnoconfig:
+ case olddefconfig:
conf_read(NULL);
break;
case allnoconfig:
@@ -645,7 +652,7 @@ int main(int ac, char **av)
/* fall through */
case oldconfig:
case listnewconfig:
- case oldnoconfig:
+ case olddefconfig:
case silentoldconfig:
/* Update until a loop caused no more changes */
do {
@@ -653,7 +660,7 @@ int main(int ac, char **av)
check_conf(&rootmenu);
} while (conf_cnt &&
(input_mode != listnewconfig &&
- input_mode != oldnoconfig));
+ input_mode != olddefconfig));
break;
}
diff --git a/scripts/kconfig/expr.h b/scripts/kconfig/expr.h
index d4ecce8..bd2e098 100644
--- a/scripts/kconfig/expr.h
+++ b/scripts/kconfig/expr.h
@@ -12,6 +12,7 @@ extern "C" {
#include <assert.h>
#include <stdio.h>
+#include <sys/queue.h>
#ifndef __cplusplus
#include <stdbool.h>
#endif
@@ -173,6 +174,16 @@ struct menu {
#define MENU_CHANGED 0x0001
#define MENU_ROOT 0x0002
+struct jump_key {
+ CIRCLEQ_ENTRY(jump_key) entries;
+ size_t offset;
+ struct menu *target;
+ int index;
+};
+CIRCLEQ_HEAD(jk_head, jump_key);
+
+#define JUMP_NB 9
+
extern struct file *file_list;
extern struct file *current_file;
struct file *lookup_file(const char *name);
diff --git a/scripts/kconfig/lkc_proto.h b/scripts/kconfig/lkc_proto.h
index 47fe9c3..1d1c085 100644
--- a/scripts/kconfig/lkc_proto.h
+++ b/scripts/kconfig/lkc_proto.h
@@ -21,8 +21,10 @@ P(menu_get_root_menu,struct menu *,(struct menu *menu));
P(menu_get_parent_menu,struct menu *,(struct menu *menu));
P(menu_has_help,bool,(struct menu *menu));
P(menu_get_help,const char *,(struct menu *menu));
-P(get_symbol_str, void, (struct gstr *r, struct symbol *sym));
-P(get_relations_str, struct gstr, (struct symbol **sym_arr));
+P(get_symbol_str, void, (struct gstr *r, struct symbol *sym, struct jk_head
+ *head));
+P(get_relations_str, struct gstr, (struct symbol **sym_arr, struct jk_head
+ *head));
P(menu_get_ext_help,void,(struct menu *menu, struct gstr *help));
/* symbol.c */
diff --git a/scripts/kconfig/lxdialog/dialog.h b/scripts/kconfig/lxdialog/dialog.h
index b5211fc..ee17a52 100644
--- a/scripts/kconfig/lxdialog/dialog.h
+++ b/scripts/kconfig/lxdialog/dialog.h
@@ -144,6 +144,7 @@ struct dialog_info {
*/
extern struct dialog_info dlg;
extern char dialog_input_result[];
+extern int saved_x, saved_y; /* Needed in signal handler in mconf.c */
/*
* Function prototypes
@@ -209,7 +210,13 @@ int first_alpha(const char *string, const char *exempt);
int dialog_yesno(const char *title, const char *prompt, int height, int width);
int dialog_msgbox(const char *title, const char *prompt, int height,
int width, int pause);
-int dialog_textbox(const char *title, const char *file, int height, int width);
+
+
+typedef void (*update_text_fn)(char *buf, size_t start, size_t end, void
+ *_data);
+int dialog_textbox(const char *title, char *tbuf, int initial_height,
+ int initial_width, int *keys, int *_vscroll, int *_hscroll,
+ update_text_fn update_text, void *data);
int dialog_menu(const char *title, const char *prompt,
const void *selected, int *s_scroll);
int dialog_checklist(const char *title, const char *prompt, int height,
diff --git a/scripts/kconfig/lxdialog/textbox.c b/scripts/kconfig/lxdialog/textbox.c
index 4e5de60..a48bb93 100644
--- a/scripts/kconfig/lxdialog/textbox.c
+++ b/scripts/kconfig/lxdialog/textbox.c
@@ -22,23 +22,25 @@
#include "dialog.h"
static void back_lines(int n);
-static void print_page(WINDOW * win, int height, int width);
-static void print_line(WINDOW * win, int row, int width);
+static void print_page(WINDOW *win, int height, int width, update_text_fn
+ update_text, void *data);
+static void print_line(WINDOW *win, int row, int width);
static char *get_line(void);
static void print_position(WINDOW * win);
static int hscroll;
static int begin_reached, end_reached, page_length;
-static const char *buf;
-static const char *page;
+static char *buf;
+static char *page;
/*
* refresh window content
*/
static void refresh_text_box(WINDOW *dialog, WINDOW *box, int boxh, int boxw,
- int cur_y, int cur_x)
+ int cur_y, int cur_x, update_text_fn update_text,
+ void *data)
{
- print_page(box, boxh, boxw);
+ print_page(box, boxh, boxw, update_text, data);
print_position(dialog);
wmove(dialog, cur_y, cur_x); /* Restore cursor position */
wrefresh(dialog);
@@ -47,14 +49,18 @@ static void refresh_text_box(WINDOW *dialog, WINDOW *box, int boxh, int boxw,
/*
* Display text from a file in a dialog box.
+ *
+ * keys is a null-terminated array
+ * update_text() may not add or remove any '\n' or '\0' in tbuf
*/
-int dialog_textbox(const char *title, const char *tbuf,
- int initial_height, int initial_width)
+int dialog_textbox(const char *title, char *tbuf, int initial_height,
+ int initial_width, int *keys, int *_vscroll, int *_hscroll,
+ update_text_fn update_text, void *data)
{
int i, x, y, cur_x, cur_y, key = 0;
int height, width, boxh, boxw;
- int passed_end;
WINDOW *dialog, *box;
+ bool done = false;
begin_reached = 1;
end_reached = 0;
@@ -63,6 +69,15 @@ int dialog_textbox(const char *title, const char *tbuf,
buf = tbuf;
page = buf; /* page is pointer to start of page to be displayed */
+ if (_vscroll && *_vscroll) {
+ begin_reached = 0;
+
+ for (i = 0; i < *_vscroll; i++)
+ get_line();
+ }
+ if (_hscroll)
+ hscroll = *_hscroll;
+
do_resize:
getmaxyx(stdscr, height, width);
if (height < 8 || width < 8)
@@ -120,9 +135,10 @@ do_resize:
/* Print first page of text */
attr_clear(box, boxh, boxw, dlg.dialog.atr);
- refresh_text_box(dialog, box, boxh, boxw, cur_y, cur_x);
+ refresh_text_box(dialog, box, boxh, boxw, cur_y, cur_x, update_text,
+ data);
- while ((key != KEY_ESC) && (key != '\n')) {
+ while (!done) {
key = wgetch(dialog);
switch (key) {
case 'E': /* Exit */
@@ -130,16 +146,17 @@ do_resize:
case 'X':
case 'x':
case 'q':
- delwin(box);
- delwin(dialog);
- return 0;
+ case '\n':
+ done = true;
+ break;
case 'g': /* First page */
case KEY_HOME:
if (!begin_reached) {
begin_reached = 1;
page = buf;
refresh_text_box(dialog, box, boxh, boxw,
- cur_y, cur_x);
+ cur_y, cur_x, update_text,
+ data);
}
break;
case 'G': /* Last page */
@@ -149,45 +166,18 @@ do_resize:
/* point to last char in buf */
page = buf + strlen(buf);
back_lines(boxh);
- refresh_text_box(dialog, box, boxh, boxw,
- cur_y, cur_x);
+ refresh_text_box(dialog, box, boxh, boxw, cur_y,
+ cur_x, update_text, data);
break;
case 'K': /* Previous line */
case 'k':
case KEY_UP:
- if (!begin_reached) {
- back_lines(page_length + 1);
-
- /* We don't call print_page() here but use
- * scrolling to ensure faster screen update.
- * However, 'end_reached' and 'page_length'
- * should still be updated, and 'page' should
- * point to start of next page. This is done
- * by calling get_line() in the following
- * 'for' loop. */
- scrollok(box, TRUE);
- wscrl(box, -1); /* Scroll box region down one line */
- scrollok(box, FALSE);
- page_length = 0;
- passed_end = 0;
- for (i = 0; i < boxh; i++) {
- if (!i) {
- /* print first line of page */
- print_line(box, 0, boxw);
- wnoutrefresh(box);
- } else
- /* Called to update 'end_reached' and 'page' */
- get_line();
- if (!passed_end)
- page_length++;
- if (end_reached && !passed_end)
- passed_end = 1;
- }
+ if (begin_reached)
+ break;
- print_position(dialog);
- wmove(dialog, cur_y, cur_x); /* Restore cursor position */
- wrefresh(dialog);
- }
+ back_lines(page_length + 1);
+ refresh_text_box(dialog, box, boxh, boxw, cur_y,
+ cur_x, update_text, data);
break;
case 'B': /* Previous page */
case 'b':
@@ -196,23 +186,18 @@ do_resize:
if (begin_reached)
break;
back_lines(page_length + boxh);
- refresh_text_box(dialog, box, boxh, boxw,
- cur_y, cur_x);
+ refresh_text_box(dialog, box, boxh, boxw, cur_y,
+ cur_x, update_text, data);
break;
case 'J': /* Next line */
case 'j':
case KEY_DOWN:
- if (!end_reached) {
- begin_reached = 0;
- scrollok(box, TRUE);
- scroll(box); /* Scroll box region up one line */
- scrollok(box, FALSE);
- print_line(box, boxh - 1, boxw);
- wnoutrefresh(box);
- print_position(dialog);
- wmove(dialog, cur_y, cur_x); /* Restore cursor position */
- wrefresh(dialog);
- }
+ if (end_reached)
+ break;
+
+ back_lines(page_length - 1);
+ refresh_text_box(dialog, box, boxh, boxw, cur_y,
+ cur_x, update_text, data);
break;
case KEY_NPAGE: /* Next page */
case ' ':
@@ -221,8 +206,8 @@ do_resize:
break;
begin_reached = 0;
- refresh_text_box(dialog, box, boxh, boxw,
- cur_y, cur_x);
+ refresh_text_box(dialog, box, boxh, boxw, cur_y,
+ cur_x, update_text, data);
break;
case '0': /* Beginning of line */
case 'H': /* Scroll left */
@@ -237,8 +222,8 @@ do_resize:
hscroll--;
/* Reprint current page to scroll horizontally */
back_lines(page_length);
- refresh_text_box(dialog, box, boxh, boxw,
- cur_y, cur_x);
+ refresh_text_box(dialog, box, boxh, boxw, cur_y,
+ cur_x, update_text, data);
break;
case 'L': /* Scroll right */
case 'l':
@@ -248,11 +233,12 @@ do_resize:
hscroll++;
/* Reprint current page to scroll horizontally */
back_lines(page_length);
- refresh_text_box(dialog, box, boxh, boxw,
- cur_y, cur_x);
+ refresh_text_box(dialog, box, boxh, boxw, cur_y,
+ cur_x, update_text, data);
break;
case KEY_ESC:
- key = on_key_esc(dialog);
+ if (on_key_esc(dialog) == KEY_ESC)
+ done = true;
break;
case KEY_RESIZE:
back_lines(height);
@@ -260,11 +246,31 @@ do_resize:
delwin(dialog);
on_key_resize();
goto do_resize;
+ default:
+ for (i = 0; keys[i]; i++) {
+ if (key == keys[i]) {
+ done = true;
+ break;
+ }
+ }
}
}
delwin(box);
delwin(dialog);
- return key; /* ESC pressed */
+ if (_vscroll) {
+ const char *s;
+
+ s = buf;
+ *_vscroll = 0;
+ back_lines(page_length);
+ while (s < page && (s = strchr(s, '\n'))) {
+ (*_vscroll)++;
+ s++;
+ }
+ }
+ if (_hscroll)
+ *_hscroll = hscroll;
+ return key;
}
/*
@@ -301,12 +307,23 @@ static void back_lines(int n)
}
/*
- * Print a new page of text. Called by dialog_textbox().
+ * Print a new page of text.
*/
-static void print_page(WINDOW * win, int height, int width)
+static void print_page(WINDOW *win, int height, int width, update_text_fn
+ update_text, void *data)
{
int i, passed_end = 0;
+ if (update_text) {
+ char *end;
+
+ for (i = 0; i < height; i++)
+ get_line();
+ end = page;
+ back_lines(height);
+ update_text(buf, page - buf, end - buf, data);
+ }
+
page_length = 0;
for (i = 0; i < height; i++) {
print_line(win, i, width);
@@ -319,7 +336,7 @@ static void print_page(WINDOW * win, int height, int width)
}
/*
- * Print a new line of text. Called by dialog_textbox() and print_page().
+ * Print a new line of text.
*/
static void print_line(WINDOW * win, int row, int width)
{
@@ -357,10 +374,8 @@ static char *get_line(void)
end_reached = 0;
while (*page != '\n') {
if (*page == '\0') {
- if (!end_reached) {
- end_reached = 1;
- break;
- }
+ end_reached = 1;
+ break;
} else if (i < MAX_LEN)
line[i++] = *(page++);
else {
@@ -373,7 +388,7 @@ static char *get_line(void)
if (i <= MAX_LEN)
line[i] = '\0';
if (!end_reached)
- page++; /* move pass '\n' */
+ page++; /* move past '\n' */
return line;
}
diff --git a/scripts/kconfig/lxdialog/util.c b/scripts/kconfig/lxdialog/util.c
index f2375ad..109d531 100644
--- a/scripts/kconfig/lxdialog/util.c
+++ b/scripts/kconfig/lxdialog/util.c
@@ -23,6 +23,9 @@
#include "dialog.h"
+/* Needed in signal handler in mconf.c */
+int saved_x, saved_y;
+
struct dialog_info dlg;
static void set_mono_theme(void)
@@ -273,6 +276,10 @@ int init_dialog(const char *backtitle)
int height, width;
initscr(); /* Init curses */
+
+ /* Get current cursor position for signal handler in mconf.c */
+ getyx(stdscr, saved_y, saved_x);
+
getmaxyx(stdscr, height, width);
if (height < 19 || width < 80) {
endwin();
diff --git a/scripts/kconfig/mconf.c b/scripts/kconfig/mconf.c
index f584a28..48f6744 100644
--- a/scripts/kconfig/mconf.c
+++ b/scripts/kconfig/mconf.c
@@ -236,16 +236,19 @@ search_help[] = N_(
"Result:\n"
"-----------------------------------------------------------------\n"
"Symbol: FOO [=m]\n"
+ "Type : tristate\n"
"Prompt: Foo bus is used to drive the bar HW\n"
- "Defined at drivers/pci/Kconfig:47\n"
- "Depends on: X86_LOCAL_APIC && X86_IO_APIC || IA64\n"
- "Location:\n"
- " -> Bus options (PCI, PCMCIA, EISA, ISA)\n"
- " -> PCI support (PCI [=y])\n"
- " -> PCI access mode (<choice> [=y])\n"
- "Selects: LIBCRC32\n"
- "Selected by: BAR\n"
+ " Defined at drivers/pci/Kconfig:47\n"
+ " Depends on: X86_LOCAL_APIC && X86_IO_APIC || IA64\n"
+ " Location:\n"
+ " -> Bus options (PCI, PCMCIA, EISA, ISA)\n"
+ " -> PCI support (PCI [=y])\n"
+ "(1) -> PCI access mode (<choice> [=y])\n"
+ " Selects: LIBCRC32\n"
+ " Selected by: BAR\n"
"-----------------------------------------------------------------\n"
+ "o The line 'Type:' shows the type of the configuration option for\n"
+ " this symbol (boolean, tristate, string, ...)\n"
"o The line 'Prompt:' shows the text used in the menu structure for\n"
" this symbol\n"
"o The 'Defined at' line tell at what file / line number the symbol\n"
@@ -254,8 +257,12 @@ search_help[] = N_(
" this symbol to be visible in the menu (selectable)\n"
"o The 'Location:' lines tell where in the menu structure this symbol\n"
" is located\n"
- " A location followed by a [=y] indicate that this is a selectable\n"
- " menu item - and current value is displayed inside brackets.\n"
+ " A location followed by a [=y] indicates that this is a\n"
+ " selectable menu item - and the current value is displayed inside\n"
+ " brackets.\n"
+ " Press the key in the (#) prefix to jump directly to that\n"
+ " location. You will be returned to the current search results\n"
+ " after exiting this new menu.\n"
"o The 'Selects:' line tell what symbol will be automatically\n"
" selected if this symbol is selected (y or m)\n"
"o The 'Selected by' line tell what symbol has selected this symbol\n"
@@ -273,13 +280,15 @@ static struct menu *current_menu;
static int child_count;
static int single_menu_mode;
static int show_all_options;
-static int saved_x, saved_y;
-static void conf(struct menu *menu);
+static void conf(struct menu *menu, struct menu *active_menu);
static void conf_choice(struct menu *menu);
static void conf_string(struct menu *menu);
static void conf_load(void);
static void conf_save(void);
+static int show_textbox_ext(const char *title, char *text, int r, int c,
+ int *keys, int *vscroll, int *hscroll,
+ update_text_fn update_text, void *data);
static void show_textbox(const char *title, const char *text, int r, int c);
static void show_helptext(const char *title, const char *text);
static void show_help(struct menu *menu);
@@ -302,12 +311,47 @@ static void set_config_filename(const char *config_filename)
}
+struct search_data {
+ struct jk_head *head;
+ struct menu **targets;
+ int *keys;
+};
+
+static void update_text(char *buf, size_t start, size_t end, void *_data)
+{
+ struct search_data *data = _data;
+ struct jump_key *pos;
+ int k = 0;
+
+ CIRCLEQ_FOREACH(pos, data->head, entries) {
+ if (pos->offset >= start && pos->offset < end) {
+ char header[4];
+
+ if (k < JUMP_NB) {
+ int key = '0' + (pos->index % JUMP_NB) + 1;
+
+ sprintf(header, "(%c)", key);
+ data->keys[k] = key;
+ data->targets[k] = pos->target;
+ k++;
+ } else {
+ sprintf(header, " ");
+ }
+
+ memcpy(buf + pos->offset, header, sizeof(header) - 1);
+ }
+ }
+ data->keys[k] = 0;
+}
+
static void search_conf(void)
{
struct symbol **sym_arr;
struct gstr res;
char *dialog_input;
- int dres;
+ int dres, vscroll = 0, hscroll = 0;
+ bool again;
+
again:
dialog_clear();
dres = dialog_inputbox(_("Search Configuration Parameter"),
@@ -330,10 +374,30 @@ again:
dialog_input += strlen(CONFIG_);
sym_arr = sym_re_search(dialog_input);
- res = get_relations_str(sym_arr);
+ do {
+ struct jk_head head = CIRCLEQ_HEAD_INITIALIZER(head);
+ struct menu *targets[JUMP_NB];
+ int keys[JUMP_NB + 1], i;
+ struct search_data data = {
+ .head = &head,
+ .targets = targets,
+ .keys = keys,
+ };
+
+ res = get_relations_str(sym_arr, &head);
+ dres = show_textbox_ext(_("Search Results"), (char *)
+ str_get(&res), 0, 0, keys, &vscroll,
+ &hscroll, &update_text, (void *)
+ &data);
+ again = false;
+ for (i = 0; i < JUMP_NB && keys[i]; i++)
+ if (dres == keys[i]) {
+ conf(targets[i]->parent, targets[i]);
+ again = true;
+ }
+ str_free(&res);
+ } while (again);
free(sym_arr);
- show_textbox(_("Search Results"), str_get(&res), 0, 0);
- str_free(&res);
}
static void build_conf(struct menu *menu)
@@ -514,12 +578,11 @@ conf_childs:
indent -= doint;
}
-static void conf(struct menu *menu)
+static void conf(struct menu *menu, struct menu *active_menu)
{
struct menu *submenu;
const char *prompt = menu_get_prompt(menu);
struct symbol *sym;
- struct menu *active_menu = NULL;
int res;
int s_scroll = 0;
@@ -562,13 +625,13 @@ static void conf(struct menu *menu)
if (single_menu_mode)
submenu->data = (void *) (long) !submenu->data;
else
- conf(submenu);
+ conf(submenu, NULL);
break;
case 't':
if (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)
conf_choice(submenu);
else if (submenu->prompt->type == P_MENU)
- conf(submenu);
+ conf(submenu, NULL);
break;
case 's':
conf_string(submenu);
@@ -607,7 +670,7 @@ static void conf(struct menu *menu)
if (item_is_tag('t'))
sym_toggle_tristate_value(sym);
else if (item_is_tag('m'))
- conf(submenu);
+ conf(submenu, NULL);
break;
case 7:
search_conf();
@@ -619,10 +682,19 @@ static void conf(struct menu *menu)
}
}
-static void show_textbox(const char *title, const char *text, int r, int c)
+static int show_textbox_ext(const char *title, char *text, int r, int c, int
+ *keys, int *vscroll, int *hscroll, update_text_fn
+ update_text, void *data)
{
dialog_clear();
- dialog_textbox(title, text, r, c);
+ return dialog_textbox(title, text, r, c, keys, vscroll, hscroll,
+ update_text, data);
+}
+
+static void show_textbox(const char *title, const char *text, int r, int c)
+{
+ show_textbox_ext(title, (char *) text, r, c, (int []) {0}, NULL, NULL,
+ NULL, NULL);
}
static void show_helptext(const char *title, const char *text)
@@ -862,9 +934,6 @@ int main(int ac, char **av)
single_menu_mode = 1;
}
- initscr();
-
- getyx(stdscr, saved_y, saved_x);
if (init_dialog(NULL)) {
fprintf(stderr, N_("Your display is too small to run Menuconfig!\n"));
fprintf(stderr, N_("It must be at least 19 lines by 80 columns.\n"));
@@ -873,7 +942,7 @@ int main(int ac, char **av)
set_config_filename(conf_get_configname());
do {
- conf(&rootmenu);
+ conf(&rootmenu, NULL);
res = handle_exit();
} while (res == KEY_ESC);
diff --git a/scripts/kconfig/menu.c b/scripts/kconfig/menu.c
index 8c2a97e..a3cade6 100644
--- a/scripts/kconfig/menu.c
+++ b/scripts/kconfig/menu.c
@@ -507,10 +507,12 @@ const char *menu_get_help(struct menu *menu)
return "";
}
-static void get_prompt_str(struct gstr *r, struct property *prop)
+static void get_prompt_str(struct gstr *r, struct property *prop,
+ struct jk_head *head)
{
int i, j;
- struct menu *submenu[8], *menu;
+ struct menu *submenu[8], *menu, *location = NULL;
+ struct jump_key *jump;
str_printf(r, _("Prompt: %s\n"), _(prop->text));
str_printf(r, _(" Defined at %s:%d\n"), prop->menu->file->name,
@@ -521,13 +523,43 @@ static void get_prompt_str(struct gstr *r, struct property *prop)
str_append(r, "\n");
}
menu = prop->menu->parent;
- for (i = 0; menu != &rootmenu && i < 8; menu = menu->parent)
+ for (i = 0; menu != &rootmenu && i < 8; menu = menu->parent) {
+ bool accessible = menu_is_visible(menu);
+
submenu[i++] = menu;
+ if (location == NULL && accessible)
+ location = menu;
+ }
+ if (head && location) {
+ jump = malloc(sizeof(struct jump_key));
+
+ if (menu_is_visible(prop->menu)) {
+ /*
+ * There is not enough room to put the hint at the
+ * beginning of the "Prompt" line. Put the hint on the
+ * last "Location" line even when it would belong on
+ * the former.
+ */
+ jump->target = prop->menu;
+ } else
+ jump->target = location;
+
+ if (CIRCLEQ_EMPTY(head))
+ jump->index = 0;
+ else
+ jump->index = CIRCLEQ_LAST(head)->index + 1;
+
+ CIRCLEQ_INSERT_TAIL(head, jump, entries);
+ }
+
if (i > 0) {
str_printf(r, _(" Location:\n"));
for (j = 4; --i >= 0; j += 2) {
menu = submenu[i];
- str_printf(r, "%*c-> %s", j, ' ', _(menu_get_prompt(menu)));
+ if (head && location && menu == location)
+ jump->offset = r->len - 1;
+ str_printf(r, "%*c-> %s", j, ' ',
+ _(menu_get_prompt(menu)));
if (menu->sym) {
str_printf(r, " (%s [=%s])", menu->sym->name ?
menu->sym->name : _("<choice>"),
@@ -538,7 +570,10 @@ static void get_prompt_str(struct gstr *r, struct property *prop)
}
}
-void get_symbol_str(struct gstr *r, struct symbol *sym)
+/*
+ * head is optional and may be NULL
+ */
+void get_symbol_str(struct gstr *r, struct symbol *sym, struct jk_head *head)
{
bool hit;
struct property *prop;
@@ -557,7 +592,7 @@ void get_symbol_str(struct gstr *r, struct symbol *sym)
}
}
for_all_prompts(sym, prop)
- get_prompt_str(r, prop);
+ get_prompt_str(r, prop, head);
hit = false;
for_all_properties(sym, prop, P_SELECT) {
if (!hit) {
@@ -577,14 +612,14 @@ void get_symbol_str(struct gstr *r, struct symbol *sym)
str_append(r, "\n\n");
}
-struct gstr get_relations_str(struct symbol **sym_arr)
+struct gstr get_relations_str(struct symbol **sym_arr, struct jk_head *head)
{
struct symbol *sym;
struct gstr res = str_new();
int i;
for (i = 0; sym_arr && (sym = sym_arr[i]); i++)
- get_symbol_str(&res, sym);
+ get_symbol_str(&res, sym, head);
if (!i)
str_append(&res, _("No matches found.\n"));
return res;
@@ -603,5 +638,5 @@ void menu_get_ext_help(struct menu *menu, struct gstr *help)
}
str_printf(help, "%s\n", _(help_text));
if (sym)
- get_symbol_str(help, sym);
+ get_symbol_str(help, sym, NULL);
}
diff --git a/scripts/kconfig/nconf.c b/scripts/kconfig/nconf.c
index 1704a85..87d4b15 100644
--- a/scripts/kconfig/nconf.c
+++ b/scripts/kconfig/nconf.c
@@ -721,7 +721,7 @@ again:
dialog_input += strlen(CONFIG_);
sym_arr = sym_re_search(dialog_input);
- res = get_relations_str(sym_arr);
+ res = get_relations_str(sym_arr, NULL);
free(sym_arr);
show_scroll_win(main_window,
_("Search Results"), str_get(&res));
diff --git a/scripts/kernel-doc b/scripts/kernel-doc
index 01e8a8e..46e7aff 100755
--- a/scripts/kernel-doc
+++ b/scripts/kernel-doc
@@ -6,6 +6,7 @@ use strict;
## Copyright (C) 2000, 1 Tim Waugh <twaugh@redhat.com> ##
## Copyright (C) 2001 Simon Huggins ##
## Copyright (C) 2005-2012 Randy Dunlap ##
+## Copyright (C) 2012 Dan Luedtke ##
## ##
## #define enhancements by Armin Kuster <akuster@mvista.com> ##
## Copyright (c) 2000 MontaVista Software, Inc. ##
@@ -35,6 +36,8 @@ use strict;
# Small fixes (like spaces vs. \s in regex)
# -- Tim Jansen <tim@tjansen.de>
+# 25/07/2012 - Added support for HTML5
+# -- Dan Luedtke <mail@danrl.de>
#
# This will read a 'c' file and scan for embedded comments in the
@@ -44,12 +47,16 @@ use strict;
# Note: This only supports 'c'.
# usage:
-# kernel-doc [ -docbook | -html | -text | -man | -list ] [ -no-doc-sections ]
-# [ -function funcname [ -function funcname ...] ] c file(s)s > outputfile
+# kernel-doc [ -docbook | -html | -html5 | -text | -man | -list ]
+# [ -no-doc-sections ]
+# [ -function funcname [ -function funcname ...] ]
+# c file(s)s > outputfile
# or
-# [ -nofunction funcname [ -function funcname ...] ] c file(s)s > outputfile
+# [ -nofunction funcname [ -function funcname ...] ]
+# c file(s)s > outputfile
#
-# Set output format using one of -docbook -html -text or -man. Default is man.
+# Set output format using one of -docbook -html -html5 -text or -man.
+# Default is man.
# The -list format is for internal use by docproc.
#
# -no-doc-sections
@@ -182,6 +189,14 @@ my $local_lt = "\\\\\\\\lt:";
my $local_gt = "\\\\\\\\gt:";
my $blankline_html = $local_lt . "p" . $local_gt; # was "<p>"
+# html version 5
+my %highlights_html5 = ( $type_constant, "<span class=\"const\">\$1</span>",
+ $type_func, "<span class=\"func\">\$1</span>",
+ $type_struct_xml, "<span class=\"struct\">\$1</span>",
+ $type_env, "<span class=\"env\">\$1</span>",
+ $type_param, "<span class=\"param\">\$1</span>" );
+my $blankline_html5 = $local_lt . "br /" . $local_gt;
+
# XML, docbook format
my %highlights_xml = ( "([^=])\\\"([^\\\"<]+)\\\"", "\$1<quote>\$2</quote>",
$type_constant, "<constant>\$1</constant>",
@@ -311,6 +326,10 @@ while ($ARGV[0] =~ m/^-(.*)/) {
$output_mode = "html";
%highlights = %highlights_html;
$blankline = $blankline_html;
+ } elsif ($cmd eq "-html5") {
+ $output_mode = "html5";
+ %highlights = %highlights_html5;
+ $blankline = $blankline_html5;
} elsif ($cmd eq "-man") {
$output_mode = "man";
%highlights = %highlights_man;
@@ -353,10 +372,11 @@ while ($ARGV[0] =~ m/^-(.*)/) {
# continue execution near EOF;
sub usage {
- print "Usage: $0 [ -v ] [ -docbook | -html | -text | -man | -list ]\n";
+ print "Usage: $0 [ -docbook | -html | -html5 | -text | -man | -list ]\n";
print " [ -no-doc-sections ]\n";
print " [ -function funcname [ -function funcname ...] ]\n";
print " [ -nofunction funcname [ -nofunction funcname ...] ]\n";
+ print " [ -v ]\n";
print " c source file(s) > outputfile\n";
print " -v : verbose output, more warnings & other info listed\n";
exit 1;
@@ -450,7 +470,8 @@ sub output_highlight {
# confess "output_highlight got called with no args?\n";
# }
- if ($output_mode eq "html" || $output_mode eq "xml") {
+ if ($output_mode eq "html" || $output_mode eq "html5" ||
+ $output_mode eq "xml") {
$contents = local_unescape($contents);
# convert data read & converted thru xml_escape() into &xyz; format:
$contents =~ s/\\\\\\/\&/g;
@@ -460,6 +481,11 @@ sub output_highlight {
die $@ if $@;
# print STDERR "contents af:$contents\n";
+# strip whitespaces when generating html5
+ if ($output_mode eq "html5") {
+ $contents =~ s/^\s+//;
+ $contents =~ s/\s+$//;
+ }
foreach $line (split "\n", $contents) {
if (! $output_preformatted) {
$line =~ s/^\s*//;
@@ -480,7 +506,7 @@ sub output_highlight {
}
}
-#output sections in html
+# output sections in html
sub output_section_html(%) {
my %args = %{$_[0]};
my $section;
@@ -640,6 +666,239 @@ sub output_blockhead_html(%) {
print "<hr>\n";
}
+# output sections in html5
+sub output_section_html5(%) {
+ my %args = %{$_[0]};
+ my $section;
+
+ foreach $section (@{$args{'sectionlist'}}) {
+ print "<section>\n";
+ print "<h1>$section</h1>\n";
+ print "<p>\n";
+ output_highlight($args{'sections'}{$section});
+ print "</p>\n";
+ print "</section>\n";
+ }
+}
+
+# output enum in html5
+sub output_enum_html5(%) {
+ my %args = %{$_[0]};
+ my ($parameter);
+ my $count;
+ my $html5id;
+
+ $html5id = $args{'enum'};
+ $html5id =~ s/[^a-zA-Z0-9\-]+/_/g;
+ print "<article class=\"enum\" id=\"enum:". $html5id . "\">";
+ print "<h1>enum " . $args{'enum'} . "</h1>\n";
+ print "<ol class=\"code\">\n";
+ print "<li>";
+ print "<span class=\"keyword\">enum</span> ";
+ print "<span class=\"identifier\">" . $args{'enum'} . "</span> {";
+ print "</li>\n";
+ $count = 0;
+ foreach $parameter (@{$args{'parameterlist'}}) {
+ print "<li class=\"indent\">";
+ print "<span class=\"param\">" . $parameter . "</span>";
+ if ($count != $#{$args{'parameterlist'}}) {
+ $count++;
+ print ",";
+ }
+ print "</li>\n";
+ }
+ print "<li>};</li>\n";
+ print "</ol>\n";
+
+ print "<section>\n";
+ print "<h1>Constants</h1>\n";
+ print "<dl>\n";
+ foreach $parameter (@{$args{'parameterlist'}}) {
+ print "<dt>" . $parameter . "</dt>\n";
+ print "<dd>";
+ output_highlight($args{'parameterdescs'}{$parameter});
+ print "</dd>\n";
+ }
+ print "</dl>\n";
+ print "</section>\n";
+ output_section_html5(@_);
+ print "</article>\n";
+}
+
+# output typedef in html5
+sub output_typedef_html5(%) {
+ my %args = %{$_[0]};
+ my ($parameter);
+ my $count;
+ my $html5id;
+
+ $html5id = $args{'typedef'};
+ $html5id =~ s/[^a-zA-Z0-9\-]+/_/g;
+ print "<article class=\"typedef\" id=\"typedef:" . $html5id . "\">\n";
+ print "<h1>typedef " . $args{'typedef'} . "</h1>\n";
+
+ print "<ol class=\"code\">\n";
+ print "<li>";
+ print "<span class=\"keyword\">typedef</span> ";
+ print "<span class=\"identifier\">" . $args{'typedef'} . "</span>";
+ print "</li>\n";
+ print "</ol>\n";
+ output_section_html5(@_);
+ print "</article>\n";
+}
+
+# output struct in html5
+sub output_struct_html5(%) {
+ my %args = %{$_[0]};
+ my ($parameter);
+ my $html5id;
+
+ $html5id = $args{'struct'};
+ $html5id =~ s/[^a-zA-Z0-9\-]+/_/g;
+ print "<article class=\"struct\" id=\"struct:" . $html5id . "\">\n";
+ print "<hgroup>\n";
+ print "<h1>" . $args{'type'} . " " . $args{'struct'} . "</h1>";
+ print "<h2>". $args{'purpose'} . "</h2>\n";
+ print "</hgroup>\n";
+ print "<ol class=\"code\">\n";
+ print "<li>";
+ print "<span class=\"type\">" . $args{'type'} . "</span> ";
+ print "<span class=\"identifier\">" . $args{'struct'} . "</span> {";
+ print "</li>\n";
+ foreach $parameter (@{$args{'parameterlist'}}) {
+ print "<li class=\"indent\">";
+ if ($parameter =~ /^#/) {
+ print "<span class=\"param\">" . $parameter ."</span>\n";
+ print "</li>\n";
+ next;
+ }
+ my $parameter_name = $parameter;
+ $parameter_name =~ s/\[.*//;
+
+ ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
+ $type = $args{'parametertypes'}{$parameter};
+ if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) {
+ # pointer-to-function
+ print "<span class=\"type\">$1</span> ";
+ print "<span class=\"param\">$parameter</span>";
+ print "<span class=\"type\">)</span> ";
+ print "(<span class=\"args\">$2</span>);";
+ } elsif ($type =~ m/^(.*?)\s*(:.*)/) {
+ # bitfield
+ print "<span class=\"type\">$1</span> ";
+ print "<span class=\"param\">$parameter</span>";
+ print "<span class=\"bits\">$2</span>;";
+ } else {
+ print "<span class=\"type\">$type</span> ";
+ print "<span class=\"param\">$parameter</span>;";
+ }
+ print "</li>\n";
+ }
+ print "<li>};</li>\n";
+ print "</ol>\n";
+
+ print "<section>\n";
+ print "<h1>Members</h1>\n";
+ print "<dl>\n";
+ foreach $parameter (@{$args{'parameterlist'}}) {
+ ($parameter =~ /^#/) && next;
+
+ my $parameter_name = $parameter;
+ $parameter_name =~ s/\[.*//;
+
+ ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
+ print "<dt>" . $parameter . "</dt>\n";
+ print "<dd>";
+ output_highlight($args{'parameterdescs'}{$parameter_name});
+ print "</dd>\n";
+ }
+ print "</dl>\n";
+ print "</section>\n";
+ output_section_html5(@_);
+ print "</article>\n";
+}
+
+# output function in html5
+sub output_function_html5(%) {
+ my %args = %{$_[0]};
+ my ($parameter, $section);
+ my $count;
+ my $html5id;
+
+ $html5id = $args{'function'};
+ $html5id =~ s/[^a-zA-Z0-9\-]+/_/g;
+ print "<article class=\"function\" id=\"func:". $html5id . "\">\n";
+ print "<hgroup>\n";
+ print "<h1>" . $args{'function'} . "</h1>";
+ print "<h2>" . $args{'purpose'} . "</h2>\n";
+ print "</hgroup>\n";
+ print "<ol class=\"code\">\n";
+ print "<li>";
+ print "<span class=\"type\">" . $args{'functiontype'} . "</span> ";
+ print "<span class=\"identifier\">" . $args{'function'} . "</span> (";
+ print "</li>";
+ $count = 0;
+ foreach $parameter (@{$args{'parameterlist'}}) {
+ print "<li class=\"indent\">";
+ $type = $args{'parametertypes'}{$parameter};
+ if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) {
+ # pointer-to-function
+ print "<span class=\"type\">$1</span> ";
+ print "<span class=\"param\">$parameter</span>";
+ print "<span class=\"type\">)</span> ";
+ print "(<span class=\"args\">$2</span>)";
+ } else {
+ print "<span class=\"type\">$type</span> ";
+ print "<span class=\"param\">$parameter</span>";
+ }
+ if ($count != $#{$args{'parameterlist'}}) {
+ $count++;
+ print ",";
+ }
+ print "</li>\n";
+ }
+ print "<li>)</li>\n";
+ print "</ol>\n";
+
+ print "<section>\n";
+ print "<h1>Arguments</h1>\n";
+ print "<p>\n";
+ print "<dl>\n";
+ foreach $parameter (@{$args{'parameterlist'}}) {
+ my $parameter_name = $parameter;
+ $parameter_name =~ s/\[.*//;
+
+ ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
+ print "<dt>" . $parameter . "</dt>\n";
+ print "<dd>";
+ output_highlight($args{'parameterdescs'}{$parameter_name});
+ print "</dd>\n";
+ }
+ print "</dl>\n";
+ print "</section>\n";
+ output_section_html5(@_);
+ print "</article>\n";
+}
+
+# output DOC: block header in html5
+sub output_blockhead_html5(%) {
+ my %args = %{$_[0]};
+ my ($parameter, $section);
+ my $count;
+ my $html5id;
+
+ foreach $section (@{$args{'sectionlist'}}) {
+ $html5id = $section;
+ $html5id =~ s/[^a-zA-Z0-9\-]+/_/g;
+ print "<article class=\"doc\" id=\"doc:". $html5id . "\">\n";
+ print "<h1>$section</h1>\n";
+ print "<p>\n";
+ output_highlight($args{'sections'}{$section});
+ print "</p>\n";
+ }
+ print "</article>\n";
+}
+
sub output_section_xml(%) {
my %args = %{$_[0]};
my $section;
diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
index 00f7512a..0d93856 100644
--- a/scripts/mod/modpost.c
+++ b/scripts/mod/modpost.c
@@ -821,6 +821,7 @@ static const char *section_white_list[] =
".debug*",
".zdebug*", /* Compressed debug sections. */
".GCC-command-line", /* mn10300 */
+ ".GCC.command.line", /* record-gcc-switches, non mn10300 */
".mdebug*", /* alpha, score, mips etc. */
".pdr", /* alpha, score, mips etc. */
".stab*",
diff --git a/scripts/package/buildtar b/scripts/package/buildtar
index d0d748e..62d8234 100644
--- a/scripts/package/buildtar
+++ b/scripts/package/buildtar
@@ -28,15 +28,15 @@ case "${1}" in
file_ext=""
;;
targz-pkg)
- compress="gzip -c9"
+ compress="gzip"
file_ext=".gz"
;;
tarbz2-pkg)
- compress="bzip2 -c9"
+ compress="bzip2"
file_ext=".bz2"
;;
tarxz-pkg)
- compress="xz -c9"
+ compress="xz"
file_ext=".xz"
;;
*)
diff --git a/scripts/tags.sh b/scripts/tags.sh
index cff8faa..79fdafb 100755
--- a/scripts/tags.sh
+++ b/scripts/tags.sh
@@ -154,7 +154,9 @@ exuberant()
--regex-c++='/__CLEARPAGEFLAG_NOOP\(([^,)]*).*/__ClearPage\1/' \
--regex-c++='/TESTCLEARFLAG_FALSE\(([^,)]*).*/TestClearPage\1/' \
--regex-c++='/__TESTCLEARFLAG_FALSE\(([^,)]*).*/__TestClearPage\1/' \
- --regex-c++='/_PE\(([^,)]*).*/PEVENT_ERRNO__\1/'
+ --regex-c++='/_PE\(([^,)]*).*/PEVENT_ERRNO__\1/' \
+ --regex-c='/PCI_OP_READ\(([a-z]*[a-z]).*[1-4]\)/pci_bus_read_config_\1/' \
+ --regex-c='/PCI_OP_WRITE\(([a-z]*[a-z]).*[1-4]\)/pci_bus_write_config_\1/'
all_kconfigs | xargs $1 -a \
--langdef=kconfig --language-force=kconfig \
@@ -197,7 +199,9 @@ emacs()
--regex='/__CLEARPAGEFLAG_NOOP\(([^,)]*).*/__ClearPage\1/' \
--regex='/TESTCLEARFLAG_FALSE\(([^,)]*).*/TestClearPage\1/' \
--regex='/__TESTCLEARFLAG_FALSE\(([^,)]*).*/__TestClearPage\1/' \
- --regex='/_PE\(([^,)]*).*/PEVENT_ERRNO__\1/'
+ --regex='/_PE\(([^,)]*).*/PEVENT_ERRNO__\1/' \
+ --regex='/PCI_OP_READ\(([a-z]*[a-z]).*[1-4]\)/pci_bus_read_config_\1/' \
+ --regex='/PCI_OP_WRITE\(([a-z]*[a-z]).*[1-4]\)/pci_bus_write_config_\1/'
all_kconfigs | xargs $1 -a \
--regex='/^[ \t]*\(\(menu\)*config\)[ \t]+\([a-zA-Z0-9_]+\)/\3/'
diff --git a/sound/oss/waveartist.c b/sound/oss/waveartist.c
index 24c430f..672af8b 100644
--- a/sound/oss/waveartist.c
+++ b/sound/oss/waveartist.c
@@ -1482,9 +1482,9 @@ vnc_mute_spkr(wavnc_info *devc)
{
unsigned long flags;
- spin_lock_irqsave(&nw_gpio_lock, flags);
+ raw_spin_lock_irqsave(&nw_gpio_lock, flags);
nw_cpld_modify(CPLD_UNMUTE, devc->spkr_mute_state ? 0 : CPLD_UNMUTE);
- spin_unlock_irqrestore(&nw_gpio_lock, flags);
+ raw_spin_unlock_irqrestore(&nw_gpio_lock, flags);
}
static void
diff --git a/tools/perf/util/include/linux/rbtree.h b/tools/perf/util/include/linux/rbtree.h
index 9bcdc84..2a030c5 100644
--- a/tools/perf/util/include/linux/rbtree.h
+++ b/tools/perf/util/include/linux/rbtree.h
@@ -1,3 +1,2 @@
#include <stdbool.h>
-#include <stdbool.h>
#include "../../../../include/linux/rbtree.h"
diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl
index c05bcd2..b51d787 100755
--- a/tools/testing/ktest/ktest.pl
+++ b/tools/testing/ktest/ktest.pl
@@ -1873,10 +1873,10 @@ sub make_oldconfig {
apply_min_config;
}
- if (!run_command "$make oldnoconfig") {
- # Perhaps oldnoconfig doesn't exist in this version of the kernel
+ if (!run_command "$make olddefconfig") {
+ # Perhaps olddefconfig doesn't exist in this version of the kernel
# try a yes '' | oldconfig
- doprint "oldnoconfig failed, trying yes '' | make oldconfig\n";
+ doprint "olddefconfig failed, trying yes '' | make oldconfig\n";
run_command "yes '' | $make oldconfig" or
dodie "failed make config oldconfig";
}
@@ -1929,7 +1929,7 @@ sub build {
# old config can ask questions
if ($type eq "oldconfig") {
- $type = "oldnoconfig";
+ $type = "olddefconfig";
# allow for empty configs
run_command "touch $output_config";
@@ -1959,7 +1959,7 @@ sub build {
load_force_config($minconfig);
}
- if ($type ne "oldnoconfig") {
+ if ($type ne "olddefconfig") {
run_command "$make $type" or
dodie "failed make config";
}
@@ -2458,8 +2458,7 @@ my %config_set;
# config_off holds the set of configs that the bad config had disabled.
# We need to record them and set them in the .config when running
-# oldnoconfig, because oldnoconfig does not turn off new symbols, but
-# instead just keeps the defaults.
+# olddefconfig, because olddefconfig keeps the defaults.
my %config_off;
# config_off_tmp holds a set of configs to turn off for now
@@ -3250,7 +3249,7 @@ sub test_this_config {
}
# Remove this config from the list of configs
- # do a make oldnoconfig and then read the resulting
+ # do a make olddefconfig and then read the resulting
# .config to make sure it is missing the config that
# we had before
my %configs = %min_configs;
OpenPOWER on IntegriCloud