OSDN Git Service

Merge tag 'v3.11-rc1' into h8300
authorYoshinori Sato <ysato@users.sourceforge.jp>
Tue, 16 Jul 2013 05:41:06 +0000 (14:41 +0900)
committerYoshinori Sato <ysato@users.sourceforge.jp>
Tue, 16 Jul 2013 05:41:06 +0000 (14:41 +0900)
Linux 3.11-rc1

Conflicts:
arch/h8300/include/uapi/asm/socket.h

1560 files changed:
Documentation/ABI/stable/sysfs-driver-ib_srp
Documentation/ABI/stable/sysfs-module
Documentation/ABI/testing/sysfs-bus-event_source-devices-events
Documentation/ABI/testing/sysfs-class-pwm [new file with mode: 0644]
Documentation/ABI/testing/sysfs-devices-edac
Documentation/ABI/testing/sysfs-driver-intel-rapid-start [new file with mode: 0644]
Documentation/DocBook/media/v4l/compat.xml
Documentation/DocBook/media/v4l/v4l2.xml
Documentation/DocBook/media/v4l/vidioc-dbg-g-chip-ident.xml [deleted file]
Documentation/DocBook/media/v4l/vidioc-dbg-g-chip-info.xml
Documentation/DocBook/media/v4l/vidioc-dbg-g-register.xml
Documentation/DocBook/media/v4l/vidioc-querystd.xml
Documentation/cgroups/blkio-controller.txt
Documentation/coccinelle.txt
Documentation/device-mapper/switch.txt [new file with mode: 0644]
Documentation/devicetree/bindings/arm/global_timer.txt [new file with mode: 0644]
Documentation/devicetree/bindings/gpio/men-a021-wdt.txt [new file with mode: 0644]
Documentation/devicetree/bindings/input/ads7846.txt [new file with mode: 0644]
Documentation/devicetree/bindings/input/touchscreen/ti-tsc-adc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/iommu/arm,smmu.txt [new file with mode: 0644]
Documentation/devicetree/bindings/media/exynos-fimc-lite.txt
Documentation/devicetree/bindings/media/i2c/mt9p031.txt [new file with mode: 0644]
Documentation/devicetree/bindings/media/i2c/tvp514x.txt [new file with mode: 0644]
Documentation/devicetree/bindings/media/samsung-fimc.txt
Documentation/devicetree/bindings/media/samsung-mipi-csis.txt
Documentation/devicetree/bindings/media/sh_mobile_ceu.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mfd/max8998.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mfd/twl4030-power.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mmc/mmc.txt
Documentation/devicetree/bindings/mmc/rockchip-dw-mshc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mmc/synopsis-dw-mshc.txt
Documentation/devicetree/bindings/power_supply/lp8727_charger.txt [new file with mode: 0644]
Documentation/devicetree/bindings/pwm/nxp,pca9685-pwm.txt [new file with mode: 0644]
Documentation/devicetree/bindings/regulator/max8997-regulator.txt
Documentation/devicetree/bindings/regulator/s5m8767-regulator.txt
Documentation/devicetree/bindings/regulator/twl-regulator.txt
Documentation/devicetree/bindings/thermal/ti_soc_thermal.txt [moved from drivers/staging/ti-soc-thermal/ti_soc_thermal.txt with 79% similarity]
Documentation/devicetree/bindings/timer/marvell,orion-timer.txt [new file with mode: 0644]
Documentation/devicetree/bindings/usb/twlxxxx-usb.txt
Documentation/devicetree/bindings/watchdog/brcm,bcm2835-pm-wdog.txt
Documentation/filesystems/xfs.txt
Documentation/kbuild/kconfig.txt
Documentation/kernel-parameters.txt
Documentation/media-framework.txt
Documentation/parisc/registers
Documentation/pwm.txt
Documentation/sysctl/net.txt
Documentation/thermal/x86_pkg_temperature_thermal [new file with mode: 0644]
Documentation/trace/events.txt
Documentation/trace/ftrace.txt
Documentation/vfio.txt
Documentation/video4linux/CARDLIST.bttv
Documentation/video4linux/CARDLIST.saa7134
Documentation/video4linux/CARDLIST.tuner
Documentation/video4linux/fimc.txt
Documentation/video4linux/v4l2-framework.txt
Documentation/vm/zswap.txt [new file with mode: 0644]
Documentation/watchdog/watchdog-parameters.txt
Documentation/zh_CN/video4linux/v4l2-framework.txt
MAINTAINERS
Makefile
arch/alpha/include/uapi/asm/fcntl.h
arch/alpha/include/uapi/asm/socket.h
arch/arc/boot/dts/abilis_tb100.dtsi
arch/arc/boot/dts/abilis_tb101.dtsi
arch/arc/boot/dts/abilis_tb10x.dtsi
arch/arc/boot/dts/angel4.dts
arch/arc/configs/fpga_defconfig
arch/arc/plat-arcfpga/include/plat/irq.h
arch/arc/plat-arcfpga/include/plat/memmap.h
arch/arc/plat-tb10x/Kconfig
arch/arm/Kconfig
arch/arm/Kconfig.debug
arch/arm/boot/dts/am335x-evm.dts
arch/arm/boot/dts/am33xx.dtsi
arch/arm/boot/dts/tegra20-seaboard.dts
arch/arm/boot/dts/tegra20-trimslice.dts
arch/arm/boot/dts/tegra20-whistler.dts
arch/arm/configs/bcm_defconfig
arch/arm/configs/multi_v7_defconfig
arch/arm/configs/omap2plus_defconfig
arch/arm/configs/spear13xx_defconfig
arch/arm/configs/u8500_defconfig
arch/arm/include/asm/smp_scu.h
arch/arm/kernel/head-common.S
arch/arm/kernel/smp_twd.c
arch/arm/mach-davinci/board-dm365-evm.c
arch/arm/mach-dove/include/mach/bridge-regs.h
arch/arm/mach-exynos/Kconfig
arch/arm/mach-ixp4xx/dsmg600-setup.c
arch/arm/mach-ixp4xx/include/mach/timex.h
arch/arm/mach-ixp4xx/omixp-setup.c
arch/arm/mach-kirkwood/include/mach/bridge-regs.h
arch/arm/mach-omap2/Kconfig
arch/arm/mach-omap2/Makefile
arch/arm/mach-omap2/board-igep0020.c
arch/arm/mach-omap2/board-rx51-video.c
arch/arm/mach-omap2/devices.c
arch/arm/mach-omap2/fb.c
arch/arm/mach-omap2/gpmc.c
arch/arm/mach-omap2/io.c
arch/arm/mach-omap2/pmu.c
arch/arm/mach-omap2/sleep44xx.S
arch/arm/mach-omap2/timer.c
arch/arm/mach-orion5x/include/mach/bridge-regs.h
arch/arm/mach-s5pv210/mach-aquila.c
arch/arm/mach-s5pv210/mach-goni.c
arch/arm/mach-shmobile/setup-emev2.c
arch/arm/mach-shmobile/setup-r8a73a4.c
arch/arm/mach-zynq/common.c
arch/arm/mm/init.c
arch/arm/mm/mmap.c
arch/arm/mm/mmu.c
arch/arm64/Kconfig
arch/arm64/kernel/asm-offsets.c
arch/arm64/kvm/Kconfig [new file with mode: 0644]
arch/arm64/mm/mmap.c
arch/avr32/include/uapi/asm/socket.h
arch/blackfin/Kconfig
arch/blackfin/include/asm/bfin_spi3.h [moved from arch/blackfin/include/asm/bfin6xx_spi.h with 99% similarity]
arch/blackfin/kernel/kgdb.c
arch/blackfin/mach-bf561/smp.c
arch/blackfin/mach-bf609/boards/ezkit.c
arch/blackfin/mach-common/smp.c
arch/cris/include/uapi/asm/socket.h
arch/frv/include/uapi/asm/socket.h
arch/ia64/hp/sim/boot/fw-emu.c
arch/ia64/include/uapi/asm/socket.h
arch/m32r/include/uapi/asm/socket.h
arch/metag/include/asm/checksum.h
arch/microblaze/configs/mmu_defconfig
arch/microblaze/include/asm/unistd.h
arch/microblaze/include/uapi/asm/unistd.h
arch/microblaze/kernel/kgdb.c
arch/mips/Kbuild.platforms
arch/mips/Kconfig
arch/mips/Makefile
arch/mips/ath79/mach-ap136.c
arch/mips/bcm63xx/Kconfig
arch/mips/bcm63xx/boards/board_bcm963xx.c
arch/mips/bcm63xx/clk.c
arch/mips/bcm63xx/cpu.c
arch/mips/bcm63xx/dev-flash.c
arch/mips/bcm63xx/dev-spi.c
arch/mips/bcm63xx/dev-uart.c
arch/mips/bcm63xx/irq.c
arch/mips/bcm63xx/nvram.c
arch/mips/bcm63xx/prom.c
arch/mips/bcm63xx/reset.c
arch/mips/bcm63xx/setup.c
arch/mips/boot/compressed/Makefile
arch/mips/boot/compressed/uart-16550.c
arch/mips/cavium-octeon/Kconfig
arch/mips/cavium-octeon/Makefile
arch/mips/cavium-octeon/Platform
arch/mips/cavium-octeon/executive/cvmx-helper-board.c
arch/mips/cavium-octeon/octeon-platform.c
arch/mips/cavium-octeon/serial.c [deleted file]
arch/mips/cavium-octeon/setup.c
arch/mips/configs/cavium_octeon_defconfig
arch/mips/configs/wrppmc_defconfig [deleted file]
arch/mips/dec/Makefile
arch/mips/dec/promcon.c [deleted file]
arch/mips/fw/cfe/cfe_api.c
arch/mips/include/asm/cop2.h
arch/mips/include/asm/cpu-features.h
arch/mips/include/asm/cpu.h
arch/mips/include/asm/fw/cfe/cfe_api.h
arch/mips/include/asm/gic.h
arch/mips/include/asm/io.h
arch/mips/include/asm/kspd.h [deleted file]
arch/mips/include/asm/mach-ar7/spaces.h
arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h
arch/mips/include/asm/mach-bcm63xx/bcm63xx_gpio.h
arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h
arch/mips/include/asm/mach-bcm63xx/board_bcm963xx.h
arch/mips/include/asm/mach-bcm63xx/ioremap.h
arch/mips/include/asm/mach-cavium-octeon/dma-coherence.h
arch/mips/include/asm/mach-cavium-octeon/kernel-entry-init.h
arch/mips/include/asm/mach-cavium-octeon/spaces.h [new file with mode: 0644]
arch/mips/include/asm/mach-generic/dma-coherence.h
arch/mips/include/asm/mach-generic/kernel-entry-init.h
arch/mips/include/asm/mach-ip27/kernel-entry-init.h
arch/mips/include/asm/mach-ip28/spaces.h
arch/mips/include/asm/mach-pmcs-msp71xx/gpio.h [deleted file]
arch/mips/include/asm/mach-wrppmc/mach-gt64120.h [deleted file]
arch/mips/include/asm/mach-wrppmc/war.h [deleted file]
arch/mips/include/asm/mips-boards/generic.h
arch/mips/include/asm/mipsregs.h
arch/mips/include/asm/mmu_context.h
arch/mips/include/asm/netlogic/common.h
arch/mips/include/asm/netlogic/xlp-hal/pic.h
arch/mips/include/asm/netlogic/xlp-hal/xlp.h
arch/mips/include/asm/netlogic/xlr/fmn.h
arch/mips/include/asm/octeon/cvmx-bootinfo.h
arch/mips/include/asm/page.h
arch/mips/include/asm/pci.h
arch/mips/include/asm/processor.h
arch/mips/include/asm/stackframe.h
arch/mips/include/asm/stackprotector.h [new file with mode: 0644]
arch/mips/include/asm/switch_to.h
arch/mips/include/asm/thread_info.h
arch/mips/include/asm/xtalk/xtalk.h
arch/mips/include/uapi/asm/fcntl.h
arch/mips/include/uapi/asm/inst.h
arch/mips/include/uapi/asm/msgbuf.h
arch/mips/include/uapi/asm/resource.h
arch/mips/include/uapi/asm/siginfo.h
arch/mips/include/uapi/asm/socket.h
arch/mips/include/uapi/asm/swab.h
arch/mips/kernel/asm-offsets.c
arch/mips/kernel/branch.c
arch/mips/kernel/cpu-bugs64.c
arch/mips/kernel/cpu-probe.c
arch/mips/kernel/head.S
arch/mips/kernel/irq-gic.c
arch/mips/kernel/mcount.S
arch/mips/kernel/octeon_switch.S
arch/mips/kernel/proc.c
arch/mips/kernel/process.c
arch/mips/kernel/prom.c
arch/mips/kernel/ptrace.c
arch/mips/kernel/r2300_switch.S
arch/mips/kernel/r4k_switch.S
arch/mips/kernel/rtlx.c
arch/mips/kernel/scall32-o32.S
arch/mips/kernel/scall64-64.S
arch/mips/kernel/scall64-n32.S
arch/mips/kernel/scall64-o32.S
arch/mips/kernel/signal.c
arch/mips/kernel/smp-bmips.c
arch/mips/kernel/traps.c
arch/mips/kernel/unaligned.c
arch/mips/kernel/watch.c
arch/mips/lantiq/prom.c
arch/mips/lasat/sysctl.c
arch/mips/loongson/common/cs5536/cs5536_isa.c
arch/mips/math-emu/cp1emu.c
arch/mips/mm/Makefile
arch/mips/mm/cerr-sb1.c
arch/mips/mm/dma-default.c
arch/mips/mm/fault.c
arch/mips/mm/mmap.c
arch/mips/mm/page.c
arch/mips/mm/tlb-funcs.S [new file with mode: 0644]
arch/mips/mm/tlbex.c
arch/mips/mti-malta/Makefile
arch/mips/mti-malta/malta-int.c
arch/mips/mti-malta/malta-reset.c
arch/mips/mti-sead3/sead3-reset.c
arch/mips/netlogic/Kconfig
arch/mips/netlogic/common/Makefile
arch/mips/netlogic/common/irq.c
arch/mips/netlogic/common/nlm-dma.c [new file with mode: 0644]
arch/mips/netlogic/common/reset.S [new file with mode: 0644]
arch/mips/netlogic/common/smp.c
arch/mips/netlogic/common/smpboot.S
arch/mips/netlogic/xlp/Makefile
arch/mips/netlogic/xlp/cop2-ex.c [new file with mode: 0644]
arch/mips/netlogic/xlp/dt.c [new file with mode: 0644]
arch/mips/netlogic/xlp/setup.c
arch/mips/netlogic/xlp/wakeup.c
arch/mips/netlogic/xlr/fmn.c
arch/mips/netlogic/xlr/setup.c
arch/mips/netlogic/xlr/wakeup.c
arch/mips/pci/Makefile
arch/mips/pci/fixup-wrppmc.c [deleted file]
arch/mips/pci/pci-bcm63xx.c
arch/mips/pci/pci-ip27.c
arch/mips/pci/pci-malta.c [moved from arch/mips/mti-malta/malta-pci.c with 100% similarity]
arch/mips/pmcs-msp71xx/Makefile
arch/mips/pmcs-msp71xx/gpio.c [deleted file]
arch/mips/pmcs-msp71xx/gpio_extended.c [deleted file]
arch/mips/powertv/asic/asic_devices.c
arch/mips/ralink/of.c
arch/mips/sgi-ip27/Makefile
arch/mips/sgi-ip27/ip27-irq-pci.c [new file with mode: 0644]
arch/mips/sgi-ip27/ip27-irq.c
arch/mips/sibyte/Kconfig
arch/mips/sibyte/Platform
arch/mips/sibyte/common/Makefile
arch/mips/sibyte/common/bus_watcher.c [moved from arch/mips/sibyte/sb1250/bus_watcher.c with 94% similarity]
arch/mips/sibyte/common/sb_tbprof.c
arch/mips/sibyte/sb1250/Makefile
arch/mips/sni/pcimt.c
arch/mips/sni/pcit.c
arch/mips/wrppmc/Makefile [deleted file]
arch/mips/wrppmc/Platform [deleted file]
arch/mips/wrppmc/irq.c [deleted file]
arch/mips/wrppmc/pci.c [deleted file]
arch/mips/wrppmc/reset.c [deleted file]
arch/mips/wrppmc/serial.c [deleted file]
arch/mips/wrppmc/setup.c [deleted file]
arch/mips/wrppmc/time.c [deleted file]
arch/mn10300/include/uapi/asm/socket.h
arch/parisc/Makefile
arch/parisc/defpalo.conf
arch/parisc/include/asm/special_insns.h
arch/parisc/include/asm/tlbflush.h
arch/parisc/include/uapi/asm/fcntl.h
arch/parisc/include/uapi/asm/socket.h
arch/parisc/install.sh
arch/parisc/kernel/cache.c
arch/parisc/kernel/processor.c
arch/parisc/lib/memcpy.c
arch/powerpc/include/uapi/asm/socket.h
arch/powerpc/mm/mmap.c
arch/powerpc/perf/power7-pmu.c
arch/s390/include/uapi/asm/socket.h
arch/s390/mm/mmap.c
arch/sparc/include/asm/leon.h
arch/sparc/include/uapi/asm/fcntl.h
arch/sparc/include/uapi/asm/socket.h
arch/sparc/kernel/asm-offsets.c
arch/sparc/kernel/ds.c
arch/sparc/kernel/sys_sparc_64.c
arch/sparc/mm/hypersparc.S
arch/sparc/mm/swift.S
arch/sparc/mm/tsunami.S
arch/sparc/mm/viking.S
arch/tile/mm/mmap.c
arch/x86/ia32/ia32_aout.c
arch/x86/include/asm/mce.h
arch/x86/kernel/cpu/mcheck/therm_throt.c
arch/x86/kernel/cpu/perf_event_amd_iommu.c
arch/x86/kernel/nmi.c
arch/x86/kernel/smp.c
arch/x86/kvm/vmx.c
arch/x86/mm/mmap.c
arch/xtensa/Kconfig
arch/xtensa/Kconfig.debug
arch/xtensa/boot/.gitignore [new file with mode: 0644]
arch/xtensa/boot/boot-elf/.gitignore [new file with mode: 0644]
arch/xtensa/boot/lib/.gitignore [new file with mode: 0644]
arch/xtensa/boot/lib/Makefile
arch/xtensa/include/asm/bootparam.h
arch/xtensa/include/asm/cmpxchg.h
arch/xtensa/include/asm/delay.h
arch/xtensa/include/asm/ftrace.h
arch/xtensa/include/asm/pgtable.h
arch/xtensa/include/asm/platform.h
arch/xtensa/include/asm/timex.h
arch/xtensa/include/uapi/asm/socket.h
arch/xtensa/kernel/.gitignore [new file with mode: 0644]
arch/xtensa/kernel/Makefile
arch/xtensa/kernel/entry.S
arch/xtensa/kernel/head.S
arch/xtensa/kernel/mcount.S [new file with mode: 0644]
arch/xtensa/kernel/pci.c
arch/xtensa/kernel/platform.c
arch/xtensa/kernel/setup.c
arch/xtensa/kernel/time.c
arch/xtensa/kernel/xtensa_ksyms.c
arch/xtensa/mm/tlb.c
arch/xtensa/platforms/iss/network.c
arch/xtensa/platforms/iss/simdisk.c
arch/xtensa/platforms/xtfpga/setup.c
arch/xtensa/variants/s6000/delay.c
block/blk-cgroup.c
block/blk-cgroup.h
block/blk-tag.c
block/blk-throttle.c
block/cfq-iosched.c
block/deadline-iosched.c
block/elevator.c
block/noop-iosched.c
drivers/Kconfig
drivers/Makefile
drivers/acpi/device_pm.c
drivers/acpi/dock.c
drivers/acpi/fan.c
drivers/acpi/power.c
drivers/acpi/scan.c
drivers/ata/Kconfig
drivers/base/dma-buf.c
drivers/block/xsysace.c
drivers/char/hw_random/Kconfig
drivers/clocksource/Kconfig
drivers/clocksource/Makefile
drivers/clocksource/arm_global_timer.c [new file with mode: 0644]
drivers/clocksource/time-orion.c [new file with mode: 0644]
drivers/cpufreq/cpufreq.c
drivers/edac/Kconfig
drivers/firewire/core-device.c
drivers/firewire/net.c
drivers/firewire/sbp2.c
drivers/gpu/drm/drm_edid_load.c
drivers/hwmon/lm63.c
drivers/hwmon/lm90.c
drivers/i2c/busses/Kconfig
drivers/ide/delkin_cb.c
drivers/ide/gayle.c
drivers/ide/ide-taskfile.c
drivers/ide/tx4938ide.c
drivers/ide/tx4939ide.c
drivers/iio/adc/ti_am335x_adc.c
drivers/infiniband/Kconfig
drivers/infiniband/Makefile
drivers/infiniband/core/addr.c
drivers/infiniband/core/cma.c
drivers/infiniband/core/sa_query.c
drivers/infiniband/core/sysfs.c
drivers/infiniband/core/ucma.c
drivers/infiniband/core/uverbs_cmd.c
drivers/infiniband/hw/cxgb3/iwch_qp.c
drivers/infiniband/hw/ehca/ehca_main.c
drivers/infiniband/hw/mlx5/Kconfig [new file with mode: 0644]
drivers/infiniband/hw/mlx5/Makefile [new file with mode: 0644]
drivers/infiniband/hw/mlx5/ah.c [new file with mode: 0644]
drivers/infiniband/hw/mlx5/cq.c [new file with mode: 0644]
drivers/infiniband/hw/mlx5/doorbell.c [new file with mode: 0644]
drivers/infiniband/hw/mlx5/mad.c [new file with mode: 0644]
drivers/infiniband/hw/mlx5/main.c [new file with mode: 0644]
drivers/infiniband/hw/mlx5/mem.c [new file with mode: 0644]
drivers/infiniband/hw/mlx5/mlx5_ib.h [new file with mode: 0644]
drivers/infiniband/hw/mlx5/mr.c [new file with mode: 0644]
drivers/infiniband/hw/mlx5/qp.c [new file with mode: 0644]
drivers/infiniband/hw/mlx5/srq.c [new file with mode: 0644]
drivers/infiniband/hw/mlx5/user.h [new file with mode: 0644]
drivers/infiniband/hw/ocrdma/ocrdma.h
drivers/infiniband/hw/ocrdma/ocrdma_hw.c
drivers/infiniband/hw/ocrdma/ocrdma_main.c
drivers/infiniband/hw/ocrdma/ocrdma_sli.h
drivers/infiniband/hw/ocrdma/ocrdma_verbs.c
drivers/infiniband/hw/qib/Kconfig
drivers/infiniband/hw/qib/Makefile
drivers/infiniband/hw/qib/qib.h
drivers/infiniband/hw/qib/qib_common.h
drivers/infiniband/hw/qib/qib_cq.c
drivers/infiniband/hw/qib/qib_debugfs.c [new file with mode: 0644]
drivers/infiniband/hw/qib/qib_debugfs.h [new file with mode: 0644]
drivers/infiniband/hw/qib/qib_driver.c
drivers/infiniband/hw/qib/qib_file_ops.c
drivers/infiniband/hw/qib/qib_iba6120.c
drivers/infiniband/hw/qib/qib_iba7220.c
drivers/infiniband/hw/qib/qib_iba7322.c
drivers/infiniband/hw/qib/qib_init.c
drivers/infiniband/hw/qib/qib_qp.c
drivers/infiniband/hw/qib/qib_sdma.c
drivers/infiniband/hw/qib/qib_verbs.c
drivers/infiniband/hw/qib/qib_verbs.h
drivers/infiniband/ulp/isert/ib_isert.c
drivers/infiniband/ulp/isert/ib_isert.h
drivers/infiniband/ulp/srp/ib_srp.c
drivers/infiniband/ulp/srp/ib_srp.h
drivers/infiniband/ulp/srpt/ib_srpt.c
drivers/input/keyboard/nspire-keypad.c
drivers/input/mouse/elantech.c
drivers/input/touchscreen/ads7846.c
drivers/input/touchscreen/cyttsp4_core.h
drivers/input/touchscreen/cyttsp4_spi.c
drivers/input/touchscreen/cyttsp_core.h
drivers/input/touchscreen/cyttsp_i2c_common.c
drivers/input/touchscreen/cyttsp_spi.c
drivers/input/touchscreen/ti_am335x_tsc.c
drivers/iommu/Kconfig
drivers/iommu/Makefile
drivers/iommu/amd_iommu.c
drivers/iommu/arm-smmu.c [new file with mode: 0644]
drivers/iommu/dmar.c
drivers/iommu/intel-iommu.c
drivers/iommu/intel_irq_remapping.c
drivers/iommu/iommu.c
drivers/iommu/omap-iommu.c
drivers/iommu/omap-iopgtable.h
drivers/iommu/omap-iovmm.c
drivers/irqchip/Makefile
drivers/irqchip/irq-moxart.c [new file with mode: 0644]
drivers/irqchip/irq-nvic.c
drivers/irqchip/irq-sun4i.c
drivers/irqchip/irq-vt8500.c
drivers/md/Kconfig
drivers/md/Makefile
drivers/md/dm-bufio.c
drivers/md/dm-cache-target.c
drivers/md/dm-flakey.c
drivers/md/dm-ioctl.c
drivers/md/dm-mpath.c
drivers/md/dm-switch.c [new file with mode: 0644]
drivers/md/dm-table.c
drivers/md/dm-verity.c
drivers/md/dm.c
drivers/media/common/saa7146/saa7146_video.c
drivers/media/common/siano/smscoreapi.c
drivers/media/common/siano/smsdvb-main.c
drivers/media/common/tveeprom.c
drivers/media/dvb-core/dmxdev.c
drivers/media/dvb-core/dvb-usb-ids.h
drivers/media/dvb-frontends/au8522_decoder.c
drivers/media/dvb-frontends/dib8000.c
drivers/media/dvb-frontends/drxk.h
drivers/media/dvb-frontends/drxk_hard.c
drivers/media/dvb-frontends/drxk_hard.h
drivers/media/dvb-frontends/stb0899_algo.c
drivers/media/dvb-frontends/stb0899_drv.c
drivers/media/dvb-frontends/stb0899_drv.h
drivers/media/firewire/firedtv-fw.c
drivers/media/i2c/Kconfig
drivers/media/i2c/Makefile
drivers/media/i2c/ad9389b.c
drivers/media/i2c/adp1653.c
drivers/media/i2c/adv7170.c
drivers/media/i2c/adv7175.c
drivers/media/i2c/adv7180.c
drivers/media/i2c/adv7183.c
drivers/media/i2c/adv7343.c
drivers/media/i2c/adv7393.c
drivers/media/i2c/adv7604.c
drivers/media/i2c/ak881x.c
drivers/media/i2c/as3645a.c
drivers/media/i2c/bt819.c
drivers/media/i2c/bt856.c
drivers/media/i2c/bt866.c
drivers/media/i2c/cs5345.c
drivers/media/i2c/cs53l32a.c
drivers/media/i2c/cx25840/cx25840-core.c
drivers/media/i2c/cx25840/cx25840-core.h
drivers/media/i2c/cx25840/cx25840-ir.c
drivers/media/i2c/ir-kbd-i2c.c
drivers/media/i2c/ks0127.c
drivers/media/i2c/m52790.c
drivers/media/i2c/m5mols/m5mols_core.c
drivers/media/i2c/ml86v7667.c [new file with mode: 0644]
drivers/media/i2c/msp3400-driver.c
drivers/media/i2c/mt9m032.c
drivers/media/i2c/mt9p031.c
drivers/media/i2c/mt9t001.c
drivers/media/i2c/mt9v011.c
drivers/media/i2c/mt9v032.c
drivers/media/i2c/noon010pc30.c
drivers/media/i2c/ov7640.c
drivers/media/i2c/ov7670.c
drivers/media/i2c/s5c73m3/s5c73m3-core.c
drivers/media/i2c/s5c73m3/s5c73m3-spi.c
drivers/media/i2c/s5k6aa.c
drivers/media/i2c/saa6588.c
drivers/media/i2c/saa7110.c
drivers/media/i2c/saa7115.c
drivers/media/i2c/saa7127.c
drivers/media/i2c/saa717x.c
drivers/media/i2c/saa7185.c
drivers/media/i2c/saa7191.c
drivers/media/i2c/smiapp/smiapp-core.c
drivers/media/i2c/soc_camera/imx074.c
drivers/media/i2c/soc_camera/mt9m001.c
drivers/media/i2c/soc_camera/mt9m111.c
drivers/media/i2c/soc_camera/mt9t031.c
drivers/media/i2c/soc_camera/mt9t112.c
drivers/media/i2c/soc_camera/mt9v022.c
drivers/media/i2c/soc_camera/ov2640.c
drivers/media/i2c/soc_camera/ov5642.c
drivers/media/i2c/soc_camera/ov6650.c
drivers/media/i2c/soc_camera/ov772x.c
drivers/media/i2c/soc_camera/ov9640.c
drivers/media/i2c/soc_camera/ov9640.h
drivers/media/i2c/soc_camera/ov9740.c
drivers/media/i2c/soc_camera/rj54n1cb0c.c
drivers/media/i2c/soc_camera/tw9910.c
drivers/media/i2c/sony-btf-mpx.c
drivers/media/i2c/sr030pc30.c
drivers/media/i2c/tda7432.c
drivers/media/i2c/tda9840.c
drivers/media/i2c/tea6415c.c
drivers/media/i2c/tea6420.c
drivers/media/i2c/ths7303.c
drivers/media/i2c/ths8200.c [new file with mode: 0644]
drivers/media/i2c/ths8200_regs.h [new file with mode: 0644]
drivers/media/i2c/tlv320aic23b.c
drivers/media/i2c/tvaudio.c
drivers/media/i2c/tvp514x.c
drivers/media/i2c/tvp5150.c
drivers/media/i2c/tvp7002.c
drivers/media/i2c/tw2804.c
drivers/media/i2c/tw9903.c
drivers/media/i2c/tw9906.c
drivers/media/i2c/uda1342.c
drivers/media/i2c/upd64031a.c
drivers/media/i2c/upd64083.c
drivers/media/i2c/vp27smpx.c
drivers/media/i2c/vpx3220.c
drivers/media/i2c/vs6624.c
drivers/media/i2c/wm8739.c
drivers/media/i2c/wm8775.c
drivers/media/media-device.c
drivers/media/media-entity.c
drivers/media/parport/bw-qcam.c
drivers/media/pci/Kconfig
drivers/media/pci/b2c2/flexcop-pci.c
drivers/media/pci/bt8xx/bttv-cards.c
drivers/media/pci/bt8xx/bttv-driver.c
drivers/media/pci/bt8xx/bttv.h
drivers/media/pci/cx18/cx18-av-core.c
drivers/media/pci/cx18/cx18-av-core.h
drivers/media/pci/cx18/cx18-ioctl.c
drivers/media/pci/cx23885/cx23885-417.c
drivers/media/pci/cx23885/cx23885-ioctl.c
drivers/media/pci/cx23885/cx23885-ioctl.h
drivers/media/pci/cx23885/cx23885-video.c
drivers/media/pci/cx23885/cx23888-ir.c
drivers/media/pci/cx88/cx88-cards.c
drivers/media/pci/cx88/cx88-core.c
drivers/media/pci/cx88/cx88-video.c
drivers/media/pci/cx88/cx88.h
drivers/media/pci/dm1105/dm1105.c
drivers/media/pci/ivtv/ivtv-driver.c
drivers/media/pci/ivtv/ivtv-ioctl.c
drivers/media/pci/mantis/hopper_cards.c
drivers/media/pci/mantis/mantis_cards.c
drivers/media/pci/mantis/mantis_vp1041.c
drivers/media/pci/pluto2/pluto2.c
drivers/media/pci/pt1/pt1.c
drivers/media/pci/saa7134/saa6752hs.c
drivers/media/pci/saa7134/saa7134-empress.c
drivers/media/pci/saa7134/saa7134-video.c
drivers/media/pci/saa7134/saa7134.h
drivers/media/pci/saa7146/mxb.c
drivers/media/pci/saa7164/saa7164-core.c
drivers/media/pci/saa7164/saa7164-encoder.c
drivers/media/pci/saa7164/saa7164-vbi.c
drivers/media/pci/saa7164/saa7164.h
drivers/media/pci/sta2x11/sta2x11_vip.c
drivers/media/pci/ttpci/budget-av.c
drivers/media/pci/ttpci/budget-ci.c
drivers/media/pci/zoran/zoran_card.c
drivers/media/pci/zoran/zoran_driver.c
drivers/media/platform/Kconfig
drivers/media/platform/blackfin/bfin_capture.c
drivers/media/platform/blackfin/ppi.c
drivers/media/platform/coda.c
drivers/media/platform/coda.h
drivers/media/platform/davinci/vpbe_display.c
drivers/media/platform/davinci/vpbe_osd.c
drivers/media/platform/davinci/vpif.c
drivers/media/platform/davinci/vpif_capture.c
drivers/media/platform/davinci/vpif_capture.h
drivers/media/platform/davinci/vpif_display.c
drivers/media/platform/davinci/vpif_display.h
drivers/media/platform/exynos-gsc/gsc-core.c
drivers/media/platform/exynos4-is/Kconfig
drivers/media/platform/exynos4-is/Makefile
drivers/media/platform/exynos4-is/common.c [new file with mode: 0644]
drivers/media/platform/exynos4-is/common.h [new file with mode: 0644]
drivers/media/platform/exynos4-is/fimc-capture.c
drivers/media/platform/exynos4-is/fimc-core.c
drivers/media/platform/exynos4-is/fimc-core.h
drivers/media/platform/exynos4-is/fimc-is-i2c.c
drivers/media/platform/exynos4-is/fimc-is-param.c
drivers/media/platform/exynos4-is/fimc-is-regs.c
drivers/media/platform/exynos4-is/fimc-is.c
drivers/media/platform/exynos4-is/fimc-is.h
drivers/media/platform/exynos4-is/fimc-isp.c
drivers/media/platform/exynos4-is/fimc-isp.h
drivers/media/platform/exynos4-is/fimc-lite-reg.c
drivers/media/platform/exynos4-is/fimc-lite-reg.h
drivers/media/platform/exynos4-is/fimc-lite.c
drivers/media/platform/exynos4-is/fimc-lite.h
drivers/media/platform/exynos4-is/fimc-m2m.c
drivers/media/platform/exynos4-is/fimc-reg.c
drivers/media/platform/exynos4-is/media-dev.c
drivers/media/platform/exynos4-is/media-dev.h
drivers/media/platform/exynos4-is/mipi-csis.c
drivers/media/platform/fsl-viu.c
drivers/media/platform/indycam.c
drivers/media/platform/m2m-deinterlace.c
drivers/media/platform/marvell-ccic/cafe-driver.c
drivers/media/platform/marvell-ccic/mcam-core.c
drivers/media/platform/marvell-ccic/mcam-core.h
drivers/media/platform/marvell-ccic/mmp-driver.c
drivers/media/platform/mem2mem_testdev.c
drivers/media/platform/mx2_emmaprp.c
drivers/media/platform/omap/omap_vout.c
drivers/media/platform/omap24xxcam.c
drivers/media/platform/omap24xxcam.h
drivers/media/platform/omap3isp/isp.c
drivers/media/platform/omap3isp/ispccdc.c
drivers/media/platform/omap3isp/ispccp2.c
drivers/media/platform/omap3isp/ispcsi2.c
drivers/media/platform/omap3isp/ispqueue.h
drivers/media/platform/omap3isp/ispvideo.c
drivers/media/platform/s3c-camif/camif-capture.c
drivers/media/platform/s3c-camif/camif-core.c
drivers/media/platform/s3c-camif/camif-regs.c
drivers/media/platform/s5p-mfc/s5p_mfc.c
drivers/media/platform/s5p-tv/hdmi_drv.c
drivers/media/platform/s5p-tv/mixer_drv.c
drivers/media/platform/s5p-tv/mixer_video.c
drivers/media/platform/s5p-tv/sdo_drv.c
drivers/media/platform/s5p-tv/sii9234_drv.c
drivers/media/platform/sh_veu.c
drivers/media/platform/sh_vou.c
drivers/media/platform/soc_camera/Kconfig
drivers/media/platform/soc_camera/Makefile
drivers/media/platform/soc_camera/atmel-isi.c
drivers/media/platform/soc_camera/mx1_camera.c
drivers/media/platform/soc_camera/mx2_camera.c
drivers/media/platform/soc_camera/mx3_camera.c
drivers/media/platform/soc_camera/omap1_camera.c
drivers/media/platform/soc_camera/pxa_camera.c
drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c
drivers/media/platform/soc_camera/sh_mobile_csi2.c
drivers/media/platform/soc_camera/soc_camera.c
drivers/media/platform/soc_camera/soc_camera_platform.c
drivers/media/platform/soc_camera/soc_scale_crop.c [new file with mode: 0644]
drivers/media/platform/soc_camera/soc_scale_crop.h [new file with mode: 0644]
drivers/media/platform/timblogiw.c
drivers/media/platform/via-camera.c
drivers/media/radio/radio-keene.c
drivers/media/radio/radio-sf16fmi.c
drivers/media/radio/radio-si476x.c
drivers/media/radio/radio-tea5764.c
drivers/media/radio/radio-timb.c
drivers/media/radio/saa7706h.c
drivers/media/radio/tef6862.c
drivers/media/radio/wl128x/fmdrv.h
drivers/media/radio/wl128x/fmdrv_common.c
drivers/media/radio/wl128x/fmdrv_v4l2.c
drivers/media/rc/gpio-ir-recv.c
drivers/media/rc/keymaps/Makefile
drivers/media/rc/keymaps/rc-delock-61959.c [new file with mode: 0644]
drivers/media/tuners/r820t.c
drivers/media/usb/Kconfig
drivers/media/usb/Makefile
drivers/media/usb/au0828/au0828-video.c
drivers/media/usb/cx231xx/cx231xx-417.c
drivers/media/usb/cx231xx/cx231xx-avcore.c
drivers/media/usb/cx231xx/cx231xx-cards.c
drivers/media/usb/cx231xx/cx231xx-vbi.c
drivers/media/usb/cx231xx/cx231xx-video.c
drivers/media/usb/cx231xx/cx231xx.h
drivers/media/usb/dvb-usb-v2/af9035.c
drivers/media/usb/dvb-usb-v2/af9035.h
drivers/media/usb/dvb-usb-v2/dvb_usb.h
drivers/media/usb/dvb-usb-v2/it913x.c
drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.c
drivers/media/usb/dvb-usb-v2/mxl111sf.c
drivers/media/usb/dvb-usb-v2/rtl28xxu.c
drivers/media/usb/dvb-usb-v2/rtl28xxu.h
drivers/media/usb/dvb-usb/az6027.c
drivers/media/usb/dvb-usb/pctv452e.c
drivers/media/usb/em28xx/em28xx-cards.c
drivers/media/usb/em28xx/em28xx-core.c
drivers/media/usb/em28xx/em28xx-dvb.c
drivers/media/usb/em28xx/em28xx-input.c
drivers/media/usb/em28xx/em28xx-reg.h
drivers/media/usb/em28xx/em28xx-video.c
drivers/media/usb/em28xx/em28xx.h
drivers/media/usb/gspca/gspca.c
drivers/media/usb/gspca/gspca.h
drivers/media/usb/gspca/pac7302.c
drivers/media/usb/gspca/sn9c20x.c
drivers/media/usb/hdpvr/Kconfig
drivers/media/usb/hdpvr/hdpvr-control.c
drivers/media/usb/hdpvr/hdpvr-core.c
drivers/media/usb/hdpvr/hdpvr-video.c
drivers/media/usb/hdpvr/hdpvr.h
drivers/media/usb/pvrusb2/pvrusb2-hdw.c
drivers/media/usb/pvrusb2/pvrusb2-hdw.h
drivers/media/usb/pvrusb2/pvrusb2-io.c
drivers/media/usb/pvrusb2/pvrusb2-v4l2.c
drivers/media/usb/sn9c102/sn9c102.h
drivers/media/usb/sn9c102/sn9c102_core.c
drivers/media/usb/stk1160/stk1160-v4l.c
drivers/media/usb/tm6000/tm6000-cards.c
drivers/media/usb/tm6000/tm6000-video.c
drivers/media/usb/ttusb-budget/dvb-ttusb-budget.c
drivers/media/usb/usbtv/Kconfig [new file with mode: 0644]
drivers/media/usb/usbtv/Makefile [new file with mode: 0644]
drivers/media/usb/usbtv/usbtv.c [new file with mode: 0644]
drivers/media/usb/usbvision/usbvision-video.c
drivers/media/usb/uvc/Kconfig
drivers/media/usb/uvc/uvc_driver.c
drivers/media/usb/uvc/uvc_status.c
drivers/media/usb/uvc/uvc_v4l2.c
drivers/media/usb/uvc/uvcvideo.h
drivers/media/v4l2-core/Makefile
drivers/media/v4l2-core/v4l2-async.c [new file with mode: 0644]
drivers/media/v4l2-core/v4l2-clk.c [new file with mode: 0644]
drivers/media/v4l2-core/v4l2-common.c
drivers/media/v4l2-core/v4l2-compat-ioctl32.c
drivers/media/v4l2-core/v4l2-dev.c
drivers/media/v4l2-core/v4l2-device.c
drivers/media/v4l2-core/v4l2-ioctl.c
drivers/media/v4l2-core/videobuf-dma-contig.c
drivers/media/v4l2-core/videobuf-dma-sg.c
drivers/media/v4l2-core/videobuf-vmalloc.c
drivers/media/v4l2-core/videobuf2-core.c
drivers/mfd/88pm800.c
drivers/mfd/88pm805.c
drivers/mfd/88pm80x.c
drivers/mfd/88pm860x-core.c
drivers/mfd/Kconfig
drivers/mfd/Makefile
drivers/mfd/aat2870-core.c
drivers/mfd/ab3100-core.c
drivers/mfd/ab3100-otp.c
drivers/mfd/ab8500-core.c
drivers/mfd/ab8500-debugfs.c
drivers/mfd/ab8500-gpadc.c
drivers/mfd/abx500-core.c
drivers/mfd/adp5520.c
drivers/mfd/arizona-core.c
drivers/mfd/arizona-i2c.c
drivers/mfd/arizona-irq.c
drivers/mfd/arizona.h
drivers/mfd/asic3.c
drivers/mfd/cros_ec.c
drivers/mfd/davinci_voicecodec.c
drivers/mfd/dbx500-prcmu-regs.h
drivers/mfd/htc-egpio.c
drivers/mfd/htc-i2cpld.c
drivers/mfd/htc-pasic3.c
drivers/mfd/intel_msic.c
drivers/mfd/janz-cmodio.c
drivers/mfd/jz4740-adc.c
drivers/mfd/kempld-core.c [new file with mode: 0644]
drivers/mfd/lpc_ich.c
drivers/mfd/max77686.c
drivers/mfd/max8925-i2c.c
drivers/mfd/max8998-irq.c
drivers/mfd/max8998.c
drivers/mfd/mcp-sa11x0.c
drivers/mfd/palmas.c
drivers/mfd/rtl8411.c
drivers/mfd/rtsx_pcr.c
drivers/mfd/rtsx_pcr.h
drivers/mfd/sec-core.c
drivers/mfd/ssbi.c [moved from drivers/ssbi/ssbi.c with 100% similarity]
drivers/mfd/t7l66xb.c
drivers/mfd/tc6387xb.c
drivers/mfd/tc6393xb.c
drivers/mfd/ti_am335x_tscadc.c
drivers/mfd/tps65912-core.c
drivers/mfd/tps65912-i2c.c
drivers/mfd/tps65912-spi.c
drivers/mfd/twl-core.c
drivers/mfd/twl4030-audio.c
drivers/mfd/twl4030-irq.c
drivers/mfd/twl4030-madc.c
drivers/mfd/twl4030-power.c
drivers/mfd/vexpress-sysreg.c
drivers/mfd/wm8994-core.c
drivers/mfd/wm8994-irq.c
drivers/mfd/wm8997-tables.c [new file with mode: 0644]
drivers/mmc/card/block.c
drivers/mmc/card/mmc_test.c
drivers/mmc/card/queue.c
drivers/mmc/core/bus.c
drivers/mmc/core/core.c
drivers/mmc/core/core.h
drivers/mmc/core/debugfs.c
drivers/mmc/core/host.c
drivers/mmc/core/mmc.c
drivers/mmc/core/mmc_ops.c
drivers/mmc/core/mmc_ops.h
drivers/mmc/core/sd.c
drivers/mmc/core/sdio.c
drivers/mmc/host/Kconfig
drivers/mmc/host/Makefile
drivers/mmc/host/android-goldfish.c
drivers/mmc/host/atmel-mci.c
drivers/mmc/host/au1xmmc.c
drivers/mmc/host/bfin_sdh.c
drivers/mmc/host/cb710-mmc.c
drivers/mmc/host/cb710-mmc.h
drivers/mmc/host/davinci_mmc.c
drivers/mmc/host/dw_mmc-exynos.c
drivers/mmc/host/dw_mmc-pci.c
drivers/mmc/host/dw_mmc-pltfm.c
drivers/mmc/host/dw_mmc-socfpga.c [new file with mode: 0644]
drivers/mmc/host/dw_mmc.c
drivers/mmc/host/dw_mmc.h
drivers/mmc/host/jz4740_mmc.c
drivers/mmc/host/mvsdio.c
drivers/mmc/host/mxcmmc.c
drivers/mmc/host/mxs-mmc.c
drivers/mmc/host/omap.c
drivers/mmc/host/omap_hsmmc.c
drivers/mmc/host/pxamci.c
drivers/mmc/host/rtsx_pci_sdmmc.c
drivers/mmc/host/sdhci-acpi.c
drivers/mmc/host/sdhci-bcm-kona.c [new file with mode: 0644]
drivers/mmc/host/sdhci-bcm2835.c
drivers/mmc/host/sdhci-cns3xxx.c
drivers/mmc/host/sdhci-dove.c
drivers/mmc/host/sdhci-esdhc-imx.c
drivers/mmc/host/sdhci-esdhc.h
drivers/mmc/host/sdhci-of-esdhc.c
drivers/mmc/host/sdhci-of-hlwd.c
drivers/mmc/host/sdhci-pci.c
drivers/mmc/host/sdhci-pltfm.c
drivers/mmc/host/sdhci-pltfm.h
drivers/mmc/host/sdhci-pxav2.c
drivers/mmc/host/sdhci-pxav3.c
drivers/mmc/host/sdhci-s3c.c
drivers/mmc/host/sdhci-sirf.c
drivers/mmc/host/sdhci-spear.c
drivers/mmc/host/sdhci-tegra.c
drivers/mmc/host/sdhci.c
drivers/mmc/host/sdhci.h
drivers/mmc/host/sh_mmcif.c
drivers/mmc/host/sh_mobile_sdhi.c
drivers/mmc/host/tmio_mmc.c
drivers/mmc/host/tmio_mmc.h
drivers/mmc/host/tmio_mmc_dma.c
drivers/mmc/host/tmio_mmc_pio.c
drivers/mmc/host/wmt-sdmmc.c
drivers/net/can/c_can/c_can_platform.c
drivers/net/dummy.c
drivers/net/ethernet/atheros/alx/main.c
drivers/net/ethernet/atheros/atl1e/atl1e_main.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
drivers/net/ethernet/cadence/at91_ether.c
drivers/net/ethernet/intel/ixgbe/ixgbe.h
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
drivers/net/ethernet/mellanox/Kconfig
drivers/net/ethernet/mellanox/Makefile
drivers/net/ethernet/mellanox/mlx4/en_netdev.c
drivers/net/ethernet/mellanox/mlx4/en_rx.c
drivers/net/ethernet/mellanox/mlx5/core/Kconfig [new file with mode: 0644]
drivers/net/ethernet/mellanox/mlx5/core/Makefile [new file with mode: 0644]
drivers/net/ethernet/mellanox/mlx5/core/alloc.c [new file with mode: 0644]
drivers/net/ethernet/mellanox/mlx5/core/cmd.c [new file with mode: 0644]
drivers/net/ethernet/mellanox/mlx5/core/cq.c [new file with mode: 0644]
drivers/net/ethernet/mellanox/mlx5/core/debugfs.c [new file with mode: 0644]
drivers/net/ethernet/mellanox/mlx5/core/eq.c [new file with mode: 0644]
drivers/net/ethernet/mellanox/mlx5/core/fw.c [new file with mode: 0644]
drivers/net/ethernet/mellanox/mlx5/core/health.c [new file with mode: 0644]
drivers/net/ethernet/mellanox/mlx5/core/mad.c [new file with mode: 0644]
drivers/net/ethernet/mellanox/mlx5/core/main.c [new file with mode: 0644]
drivers/net/ethernet/mellanox/mlx5/core/mcg.c [new file with mode: 0644]
drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h [new file with mode: 0644]
drivers/net/ethernet/mellanox/mlx5/core/mr.c [new file with mode: 0644]
drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c [new file with mode: 0644]
drivers/net/ethernet/mellanox/mlx5/core/pd.c [new file with mode: 0644]
drivers/net/ethernet/mellanox/mlx5/core/port.c [new file with mode: 0644]
drivers/net/ethernet/mellanox/mlx5/core/qp.c [new file with mode: 0644]
drivers/net/ethernet/mellanox/mlx5/core/srq.c [new file with mode: 0644]
drivers/net/ethernet/mellanox/mlx5/core/uar.c [new file with mode: 0644]
drivers/net/ethernet/octeon/Kconfig
drivers/net/ethernet/realtek/r8169.c
drivers/net/ethernet/renesas/Kconfig
drivers/net/ethernet/sun/sunvnet.c
drivers/net/ethernet/via/via-rhine.c
drivers/net/ieee802154/mrf24j40.c
drivers/net/ifb.c
drivers/net/macvtap.c
drivers/net/phy/Kconfig
drivers/net/phy/at803x.c
drivers/net/tun.c
drivers/net/usb/Makefile
drivers/net/usb/cdc_ether.c
drivers/net/usb/r8152.c
drivers/net/usb/r815x.c [new file with mode: 0644]
drivers/net/virtio_net.c
drivers/net/vxlan.c
drivers/parisc/lba_pci.c
drivers/platform/x86/Kconfig
drivers/platform/x86/Makefile
drivers/platform/x86/asus-laptop.c
drivers/platform/x86/asus-nb-wmi.c
drivers/platform/x86/asus-wmi.c
drivers/platform/x86/dell-laptop.c
drivers/platform/x86/hp-wmi.c
drivers/platform/x86/intel-rst.c [new file with mode: 0644]
drivers/platform/x86/intel-smartconnect.c [new file with mode: 0644]
drivers/platform/x86/intel_ips.c
drivers/platform/x86/intel_pmic_gpio.c
drivers/platform/x86/msi-laptop.c
drivers/power/88pm860x_battery.c
drivers/power/88pm860x_charger.c
drivers/power/ab8500_btemp.c
drivers/power/ab8500_charger.c
drivers/power/ab8500_fg.c
drivers/power/abx500_chargalg.c
drivers/power/bq27x00_battery.c
drivers/power/charger-manager.c
drivers/power/generic-adc-battery.c
drivers/power/gpio-charger.c
drivers/power/intel_mid_battery.c
drivers/power/jz4740-battery.c
drivers/power/lp8727_charger.c
drivers/power/pcf50633-charger.c
drivers/power/pm2301_charger.c
drivers/power/power_supply_core.c
drivers/power/reset/Kconfig
drivers/power/rx51_battery.c
drivers/power/sbs-battery.c
drivers/power/tps65090-charger.c
drivers/power/twl4030_charger.c
drivers/pwm/Kconfig
drivers/pwm/Makefile
drivers/pwm/core.c
drivers/pwm/pwm-atmel-tcb.c
drivers/pwm/pwm-bfin.c
drivers/pwm/pwm-imx.c
drivers/pwm/pwm-lpc32xx.c
drivers/pwm/pwm-mxs.c
drivers/pwm/pwm-pca9685.c [new file with mode: 0644]
drivers/pwm/pwm-puv3.c
drivers/pwm/pwm-renesas-tpu.c [new file with mode: 0644]
drivers/pwm/pwm-spear.c
drivers/pwm/pwm-tegra.c
drivers/pwm/pwm-tiehrpwm.c
drivers/pwm/sysfs.c [new file with mode: 0644]
drivers/rapidio/switches/idt_gen2.c
drivers/regulator/max8998.c
drivers/regulator/palmas-regulator.c
drivers/regulator/s2mps11.c
drivers/regulator/twl-regulator.c
drivers/remoteproc/remoteproc_core.c
drivers/remoteproc/remoteproc_debugfs.c
drivers/remoteproc/remoteproc_internal.h
drivers/rtc/rtc-max8998.c
drivers/scsi/constants.c
drivers/scsi/fcoe/fcoe.c
drivers/scsi/fcoe/fcoe_ctlr.c
drivers/scsi/fcoe/fcoe_sysfs.c
drivers/scsi/fcoe/fcoe_transport.c
drivers/scsi/libfc/fc_exch.c
drivers/scsi/libfc/fc_rport.c
drivers/scsi/megaraid/megaraid_sas_base.c
drivers/scsi/megaraid/megaraid_sas_fp.c
drivers/scsi/mpt3sas/Kconfig
drivers/scsi/mpt3sas/mpi/mpi2.h
drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h
drivers/scsi/mpt3sas/mpi/mpi2_init.h
drivers/scsi/mpt3sas/mpi/mpi2_ioc.h
drivers/scsi/mpt3sas/mpi/mpi2_raid.h
drivers/scsi/mpt3sas/mpi/mpi2_sas.h
drivers/scsi/mpt3sas/mpi/mpi2_tool.h
drivers/scsi/mpt3sas/mpi/mpi2_type.h
drivers/scsi/mpt3sas/mpt3sas_base.c
drivers/scsi/mpt3sas/mpt3sas_base.h
drivers/scsi/mpt3sas/mpt3sas_config.c
drivers/scsi/mpt3sas/mpt3sas_ctl.c
drivers/scsi/mpt3sas/mpt3sas_ctl.h
drivers/scsi/mpt3sas/mpt3sas_debug.h
drivers/scsi/mpt3sas/mpt3sas_scsih.c
drivers/scsi/mpt3sas/mpt3sas_transport.c
drivers/scsi/mpt3sas/mpt3sas_trigger_diag.c
drivers/scsi/mpt3sas/mpt3sas_trigger_diag.h
drivers/scsi/pm8001/pm8001_init.c
drivers/scsi/qla2xxx/qla_attr.c
drivers/scsi/qla2xxx/qla_bsg.c
drivers/scsi/qla2xxx/qla_dbg.c
drivers/scsi/qla2xxx/qla_def.h
drivers/scsi/qla2xxx/qla_gbl.h
drivers/scsi/qla2xxx/qla_gs.c
drivers/scsi/qla2xxx/qla_init.c
drivers/scsi/qla2xxx/qla_inline.h
drivers/scsi/qla2xxx/qla_iocb.c
drivers/scsi/qla2xxx/qla_isr.c
drivers/scsi/qla2xxx/qla_mbx.c
drivers/scsi/qla2xxx/qla_mr.c
drivers/scsi/qla2xxx/qla_mr.h
drivers/scsi/qla2xxx/qla_os.c
drivers/scsi/qla2xxx/qla_target.c
drivers/scsi/qla2xxx/tcm_qla2xxx.c
drivers/scsi/scsi_debug.c
drivers/scsi/scsi_lib.c
drivers/scsi/storvsc_drv.c
drivers/spi/Kconfig
drivers/ssb/Kconfig
drivers/ssbi/Kconfig [deleted file]
drivers/ssbi/Makefile [deleted file]
drivers/staging/Kconfig
drivers/staging/Makefile
drivers/staging/fwserial/fwserial.c
drivers/staging/media/davinci_vpfe/dm365_ipipe.c
drivers/staging/media/davinci_vpfe/dm365_ipipeif.c
drivers/staging/media/davinci_vpfe/dm365_isif.c
drivers/staging/media/davinci_vpfe/dm365_resizer.c
drivers/staging/media/davinci_vpfe/vpfe_video.c
drivers/staging/media/dt3155v4l/dt3155v4l.c
drivers/staging/media/go7007/go7007-usb.c
drivers/staging/media/lirc/lirc_imon.c
drivers/staging/media/solo6x10/solo6x10-tw28.c
drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c
drivers/staging/octeon/Kconfig
drivers/target/iscsi/iscsi_target.c
drivers/target/iscsi/iscsi_target.h
drivers/target/iscsi/iscsi_target_configfs.c
drivers/target/iscsi/iscsi_target_core.h
drivers/target/iscsi/iscsi_target_erl0.c
drivers/target/iscsi/iscsi_target_erl1.c
drivers/target/iscsi/iscsi_target_nego.c
drivers/target/iscsi/iscsi_target_parameters.c
drivers/target/iscsi/iscsi_target_util.c
drivers/target/iscsi/iscsi_target_util.h
drivers/target/loopback/tcm_loop.c
drivers/target/sbp/sbp_target.c
drivers/target/target_core_configfs.c
drivers/target/target_core_device.c
drivers/target/target_core_fabric_configfs.c
drivers/target/target_core_pr.c
drivers/target/target_core_pr.h
drivers/target/target_core_rd.c
drivers/target/target_core_sbc.c
drivers/target/target_core_tmr.c
drivers/target/target_core_transport.c
drivers/target/tcm_fc/tcm_fc.h
drivers/target/tcm_fc/tfc_cmd.c
drivers/thermal/Kconfig
drivers/thermal/Makefile
drivers/thermal/armada_thermal.c
drivers/thermal/cpu_cooling.c
drivers/thermal/dove_thermal.c
drivers/thermal/exynos_thermal.c
drivers/thermal/kirkwood_thermal.c
drivers/thermal/rcar_thermal.c
drivers/thermal/spear_thermal.c
drivers/thermal/thermal_core.c
drivers/thermal/ti-soc-thermal/Kconfig [moved from drivers/staging/ti-soc-thermal/Kconfig with 81% similarity]
drivers/thermal/ti-soc-thermal/Makefile [moved from drivers/staging/ti-soc-thermal/Makefile with 80% similarity]
drivers/thermal/ti-soc-thermal/TODO [moved from drivers/staging/ti-soc-thermal/TODO with 100% similarity]
drivers/thermal/ti-soc-thermal/dra752-bandgap.h [new file with mode: 0644]
drivers/thermal/ti-soc-thermal/dra752-thermal-data.c [new file with mode: 0644]
drivers/thermal/ti-soc-thermal/omap4-thermal-data.c [moved from drivers/staging/ti-soc-thermal/omap4-thermal-data.c with 100% similarity]
drivers/thermal/ti-soc-thermal/omap4xxx-bandgap.h [moved from drivers/staging/ti-soc-thermal/omap4xxx-bandgap.h with 100% similarity]
drivers/thermal/ti-soc-thermal/omap5-thermal-data.c [moved from drivers/staging/ti-soc-thermal/omap5-thermal-data.c with 100% similarity]
drivers/thermal/ti-soc-thermal/omap5xxx-bandgap.h [moved from drivers/staging/ti-soc-thermal/omap5xxx-bandgap.h with 100% similarity]
drivers/thermal/ti-soc-thermal/ti-bandgap.c [moved from drivers/staging/ti-soc-thermal/ti-bandgap.c with 98% similarity]
drivers/thermal/ti-soc-thermal/ti-bandgap.h [moved from drivers/staging/ti-soc-thermal/ti-bandgap.h with 99% similarity]
drivers/thermal/ti-soc-thermal/ti-thermal-common.c [moved from drivers/staging/ti-soc-thermal/ti-thermal-common.c with 97% similarity]
drivers/thermal/ti-soc-thermal/ti-thermal.h [moved from drivers/staging/ti-soc-thermal/ti-thermal.h with 95% similarity]
drivers/thermal/x86_pkg_temp_thermal.c [new file with mode: 0644]
drivers/tty/serial/8250/8250_dw.c
drivers/usb/gadget/f_uvc.c
drivers/usb/gadget/tcm_usb_gadget.c
drivers/usb/gadget/uvc.h
drivers/usb/host/Kconfig
drivers/usb/phy/phy-twl6030-usb.c
drivers/vfio/vfio.c
drivers/vfio/vfio_iommu_type1.c
drivers/vhost/Kconfig
drivers/vhost/Makefile
drivers/vhost/net.c
drivers/vhost/scsi.c
drivers/vhost/test.c
drivers/vhost/vhost.c
drivers/vhost/vhost.h
drivers/video/logo/logo_linux_clut224.ppm
drivers/virtio/virtio_balloon.c
drivers/virtio/virtio_pci.c
drivers/watchdog/Kconfig
drivers/watchdog/Makefile
drivers/watchdog/at32ap700x_wdt.c
drivers/watchdog/bcm2835_wdt.c [new file with mode: 0644]
drivers/watchdog/bcm63xx_wdt.c
drivers/watchdog/cpwd.c
drivers/watchdog/da9052_wdt.c
drivers/watchdog/da9055_wdt.c
drivers/watchdog/dw_wdt.c
drivers/watchdog/hpwdt.c
drivers/watchdog/imx2_wdt.c
drivers/watchdog/jz4740_wdt.c
drivers/watchdog/kempld_wdt.c [new file with mode: 0644]
drivers/watchdog/mena21_wdt.c [new file with mode: 0644]
drivers/watchdog/mpcore_wdt.c [deleted file]
drivers/watchdog/mtx-1_wdt.c
drivers/watchdog/mv64x60_wdt.c
drivers/watchdog/nuc900_wdt.c
drivers/watchdog/of_xilinx_wdt.c
drivers/watchdog/orion_wdt.c
drivers/watchdog/pnx4008_wdt.c
drivers/watchdog/rc32434_wdt.c
drivers/watchdog/riowd.c
drivers/watchdog/s3c2410_wdt.c
drivers/watchdog/sb_wdog.c
drivers/watchdog/shwdt.c
drivers/watchdog/softdog.c
drivers/watchdog/sp805_wdt.c
drivers/watchdog/ts72xx_wdt.c
drivers/watchdog/twl4030_wdt.c
drivers/watchdog/watchdog_dev.c
drivers/watchdog/wdrtas.c
drivers/watchdog/wm831x_wdt.c
fs/9p/Kconfig
fs/9p/Makefile
fs/9p/vfs_inode.c
fs/9p/xattr.c
fs/9p/xattr.h
fs/9p/xattr_security.c [new file with mode: 0644]
fs/9p/xattr_trusted.c [new file with mode: 0644]
fs/binfmt_aout.c
fs/binfmt_elf.c
fs/block_dev.c
fs/cifs/cifsencrypt.c
fs/cifs/cifsglob.h
fs/cifs/cifsproto.h
fs/cifs/connect.c
fs/cifs/dir.c
fs/cifs/file.c
fs/cifs/inode.c
fs/cifs/smb1ops.c
fs/cifs/smb2file.c
fs/cifs/smb2inode.c
fs/cifs/smb2ops.c
fs/cifs/smb2pdu.c
fs/cifs/smb2pdu.h
fs/cifs/smb2proto.h
fs/cifs/smb2transport.c
fs/configfs/dir.c
fs/ecryptfs/crypto.c
fs/ecryptfs/file.c
fs/ecryptfs/main.c
fs/ecryptfs/messaging.c
fs/efivarfs/inode.c
fs/file_table.c
fs/jfs/jfs_dmap.c
fs/jfs/jfs_dtree.c
fs/jfs/jfs_extent.c
fs/jfs/jfs_imap.c
fs/jfs/jfs_metapage.c
fs/jfs/jfs_superblock.h
fs/jfs/jfs_txnmgr.c
fs/jfs/jfs_xtree.c
fs/jfs/namei.c
fs/jfs/resize.c
fs/jfs/super.c
fs/jfs/xattr.c
fs/libfs.c
fs/namei.c
fs/nfs/dir.c
fs/nfs/inode.c
fs/nfs/write.c
fs/nfsd/Kconfig
fs/nfsd/nfs4proc.c
fs/nfsd/nfs4state.c
fs/nfsd/nfs4xdr.c
fs/nfsd/nfsd.h
fs/nfsd/nfssvc.c
fs/nfsd/state.h
fs/nfsd/vfs.c
fs/nfsd/vfs.h
fs/nfsd/xdr4.h
fs/open.c
fs/select.c
fs/xfs/xfs_attr_leaf.c
fs/xfs/xfs_bmap.c
fs/xfs/xfs_bmap.h
fs/xfs/xfs_dinode.h
fs/xfs/xfs_dir2_block.c
fs/xfs/xfs_dquot.c
fs/xfs/xfs_dquot.h
fs/xfs/xfs_icache.c
fs/xfs/xfs_inode.c
fs/xfs/xfs_inode.h
fs/xfs/xfs_ioctl.c
fs/xfs/xfs_iops.c
fs/xfs/xfs_itable.c
fs/xfs/xfs_qm.c
fs/xfs/xfs_qm.h
fs/xfs/xfs_qm_bhv.c
fs/xfs/xfs_qm_syscalls.c
fs/xfs/xfs_quota.h
fs/xfs/xfs_symlink.c
fs/xfs/xfs_trans_dquot.c
fs/xfs/xfs_vnodeops.c
include/linux/bio.h
include/linux/cgroup.h
include/linux/cpu_cooling.h
include/linux/cpufreq.h
include/linux/device-mapper.h
include/linux/elevator.h
include/linux/firewire.h
include/linux/fs.h
include/linux/ftrace.h
include/linux/i2c/twl.h
include/linux/input/ti_am335x_tsc.h [deleted file]
include/linux/llist.h
include/linux/mfd/88pm80x.h
include/linux/mfd/abx500/ab8500.h
include/linux/mfd/arizona/core.h
include/linux/mfd/davinci_voicecodec.h
include/linux/mfd/kempld.h [new file with mode: 0644]
include/linux/mfd/max8998-private.h
include/linux/mfd/max8998.h
include/linux/mfd/palmas.h
include/linux/mfd/rtsx_pci.h
include/linux/mfd/samsung/core.h
include/linux/mfd/samsung/s2mps11.h
include/linux/mfd/ti_am335x_tscadc.h
include/linux/mfd/tmio.h
include/linux/mfd/wm8994/core.h
include/linux/mfd/wm8994/pdata.h
include/linux/mlx5/cmd.h [new file with mode: 0644]
include/linux/mlx5/cq.h [new file with mode: 0644]
include/linux/mlx5/device.h [new file with mode: 0644]
include/linux/mlx5/doorbell.h [new file with mode: 0644]
include/linux/mlx5/driver.h [new file with mode: 0644]
include/linux/mlx5/qp.h [new file with mode: 0644]
include/linux/mlx5/srq.h [new file with mode: 0644]
include/linux/mm_types.h
include/linux/mmc/card.h
include/linux/mmc/core.h
include/linux/mmc/host.h
include/linux/mmc/sdhci.h
include/linux/moduleparam.h
include/linux/mutex.h
include/linux/netdevice.h
include/linux/nfs_fs.h
include/linux/nmi.h
include/linux/platform_data/mmc-esdhc-imx.h
include/linux/platform_data/pwm-renesas-tpu.h [new file with mode: 0644]
include/linux/platform_data/remoteproc-omap.h
include/linux/platform_data/ti_am335x_adc.h [deleted file]
include/linux/power_supply.h
include/linux/pwm.h
include/linux/reservation.h
include/linux/sched.h
include/linux/slab.h
include/linux/slob_def.h
include/linux/socket.h
include/linux/splice.h
include/linux/sunrpc/cache.h
include/linux/sunrpc/gss_api.h
include/linux/sunrpc/rpc_pipe_fs.h
include/linux/sunrpc/svcauth.h
include/linux/virtio_ring.h
include/linux/ww_mutex.h [new file with mode: 0644]
include/linux/zbud.h [new file with mode: 0644]
include/media/davinci/vpbe_osd.h
include/media/media-device.h
include/media/media-entity.h
include/media/rc-map.h
include/media/s5p_fimc.h
include/media/sh_mobile_ceu.h
include/media/sh_mobile_csi2.h
include/media/soc_camera.h
include/media/ths7303.h
include/media/tveeprom.h
include/media/tvp7002.h
include/media/v4l2-async.h [new file with mode: 0644]
include/media/v4l2-chip-ident.h [deleted file]
include/media/v4l2-clk.h [new file with mode: 0644]
include/media/v4l2-common.h
include/media/v4l2-dev.h
include/media/v4l2-int-device.h
include/media/v4l2-ioctl.h
include/media/v4l2-subdev.h
include/net/9p/transport.h
include/net/busy_poll.h [moved from include/net/ll_poll.h with 83% similarity]
include/rdma/ib.h [new file with mode: 0644]
include/rdma/ib_addr.h
include/rdma/ib_sa.h
include/rdma/ib_verbs.h
include/rdma/rdma_cm.h
include/target/iscsi/iscsi_transport.h
include/target/target_core_base.h
include/target/target_core_configfs.h
include/target/target_core_fabric.h
include/target/target_core_fabric_configfs.h
include/trace/events/target.h [new file with mode: 0644]
include/trace/syscall.h
include/uapi/asm-generic/fcntl.h
include/uapi/asm-generic/socket.h
include/uapi/linux/Kbuild
include/uapi/linux/bcm933xx_hcs.h [new file with mode: 0644]
include/uapi/linux/dm-ioctl.h
include/uapi/linux/v4l2-controls.h
include/uapi/linux/vfio.h
include/uapi/linux/videodev2.h
include/uapi/linux/virtio_config.h
include/uapi/rdma/rdma_user_cm.h
init/Kconfig
kernel/cgroup.c
kernel/events/core.c
kernel/fork.c
kernel/irq/generic-chip.c
kernel/irq/irqdomain.c
kernel/module.c
kernel/mutex.c
kernel/panic.c
kernel/params.c
kernel/printk.c
kernel/sched/core.c
kernel/sysctl.c
kernel/time/tick-broadcast.c
kernel/time/tick-sched.c
kernel/trace/ftrace.c
kernel/trace/trace.c
kernel/trace/trace.h
kernel/trace/trace_events.c
kernel/trace/trace_events_filter.c
kernel/trace/trace_functions.c
kernel/trace/trace_irqsoff.c
kernel/trace/trace_kprobe.c
kernel/trace/trace_selftest.c
kernel/trace/trace_syscalls.c
kernel/trace/trace_uprobe.c
kernel/watchdog.c
lib/Kconfig.debug
lib/llist.c
lib/locking-selftest.c
mm/Kconfig
mm/Makefile
mm/mmap.c
mm/nommu.c
mm/slab.c
mm/slab.h
mm/slab_common.c
mm/slob.c
mm/slub.c
mm/util.c
mm/zbud.c [new file with mode: 0644]
mm/zswap.c [new file with mode: 0644]
net/9p/client.c
net/9p/trans_common.c
net/9p/trans_fd.c
net/9p/trans_rdma.c
net/core/datagram.c
net/core/dev.c
net/core/skbuff.c
net/core/sock.c
net/core/sysctl_net_core.c
net/dns_resolver/dns_key.c
net/ipv4/gre_offload.c
net/ipv4/inet_hashtables.c
net/ipv4/ip_tunnel.c
net/ipv4/tcp.c
net/ipv4/tcp_ipv4.c
net/ipv4/tcp_output.c
net/ipv4/udp.c
net/ipv6/ip6_fib.c
net/ipv6/route.c
net/ipv6/tcp_ipv6.c
net/ipv6/udp.c
net/sched/sch_qfq.c
net/socket.c
net/sunrpc/auth_gss/gss_mech_switch.c
net/sunrpc/auth_gss/svcauth_gss.c
net/sunrpc/cache.c
net/sunrpc/clnt.c
net/sunrpc/rpc_pipe.c
net/sunrpc/svcauth_unix.c
net/sunrpc/svcsock.c
net/sunrpc/xprtsock.c
net/tipc/ib_media.c
scripts/Makefile.headersinst
scripts/Makefile.lib
scripts/coccicheck
scripts/coccinelle/api/alloc/drop_kmalloc_cast.cocci
scripts/coccinelle/api/alloc/kzalloc-simple.cocci
scripts/coccinelle/api/d_find_alias.cocci
scripts/coccinelle/api/devm_request_and_ioremap.cocci
scripts/coccinelle/api/kstrdup.cocci
scripts/coccinelle/api/memdup.cocci
scripts/coccinelle/api/memdup_user.cocci
scripts/coccinelle/api/ptr_ret.cocci
scripts/coccinelle/api/simple_open.cocci
scripts/coccinelle/free/devm_free.cocci
scripts/coccinelle/free/kfree.cocci
scripts/coccinelle/free/kfreeaddr.cocci [new file with mode: 0644]
scripts/coccinelle/free/pci_free_consistent.cocci [new file with mode: 0644]
scripts/coccinelle/iterators/fen.cocci
scripts/coccinelle/iterators/itnull.cocci
scripts/coccinelle/iterators/list_entry_update.cocci
scripts/coccinelle/iterators/use_after_iter.cocci
scripts/coccinelle/locks/call_kern.cocci
scripts/coccinelle/locks/double_lock.cocci
scripts/coccinelle/locks/flags.cocci
scripts/coccinelle/locks/mini_lock.cocci
scripts/coccinelle/misc/boolinit.cocci
scripts/coccinelle/misc/cstptr.cocci
scripts/coccinelle/misc/doubleinit.cocci
scripts/coccinelle/misc/ifaddr.cocci
scripts/coccinelle/misc/ifcol.cocci
scripts/coccinelle/misc/noderef.cocci
scripts/coccinelle/misc/orplus.cocci
scripts/coccinelle/misc/warn.cocci
scripts/coccinelle/null/eno.cocci
scripts/coccinelle/null/kmerr.cocci
scripts/coccinelle/tests/doublebitand.cocci
scripts/coccinelle/tests/doubletest.cocci
scripts/coccinelle/tests/odd_ptr_err.cocci
scripts/config
scripts/headers_install.sh
scripts/kconfig/conf.c
scripts/kconfig/confdata.c
scripts/kconfig/expr.h
scripts/kconfig/lkc.h
scripts/kconfig/lkc_proto.h
scripts/kconfig/lxdialog/checklist.c
scripts/kconfig/lxdialog/dialog.h
scripts/kconfig/lxdialog/inputbox.c
scripts/kconfig/lxdialog/menubox.c
scripts/kconfig/lxdialog/textbox.c
scripts/kconfig/lxdialog/util.c
scripts/kconfig/lxdialog/yesno.c
scripts/kconfig/mconf.c
scripts/kconfig/menu.c
scripts/kconfig/nconf.c
scripts/kconfig/nconf.gui.c
scripts/kconfig/symbol.c
scripts/mod/Makefile
scripts/mod/file2alias.c
scripts/package/mkspec
scripts/setlocalversion
security/capability.c
sound/firewire/isight.c
sound/firewire/scs1x.c
sound/firewire/speakers.c
sound/pci/hda/patch_analog.c
sound/pci/hda/patch_realtek.c
sound/soc/codecs/wm8962.c
sound/soc/fsl/imx-sgtl5000.c
sound/soc/mxs/mxs-saif.c
sound/soc/omap/rx51.c
sound/soc/samsung/i2s.c
sound/soc/samsung/s3c-i2s-v2.c
sound/usb/quirks.c
tools/include/tools/be_byteshift.h
tools/include/tools/le_byteshift.h
tools/lguest/Makefile
tools/lguest/lguest.c
tools/lib/lk/Makefile
tools/perf/Documentation/Makefile
tools/perf/Documentation/examples.txt
tools/perf/Documentation/perf-record.txt
tools/perf/Makefile
tools/perf/bench/mem-memcpy.c
tools/perf/bench/mem-memset.c
tools/perf/builtin-diff.c
tools/perf/builtin-kmem.c
tools/perf/builtin-lock.c
tools/perf/builtin-record.c
tools/perf/builtin-report.c
tools/perf/builtin-sched.c
tools/perf/builtin-stat.c
tools/perf/builtin-timechart.c
tools/perf/builtin-top.c
tools/perf/config/Makefile
tools/perf/config/utilities.mak
tools/perf/scripts/perl/Perf-Trace-Util/Context.xs
tools/perf/util/PERF-VERSION-GEN
tools/perf/util/dso.c
tools/perf/util/dso.h
tools/perf/util/evlist.c
tools/perf/util/evsel.c
tools/perf/util/header.c
tools/perf/util/parse-events.c
tools/perf/util/symbol.c
tools/perf/util/util.h
tools/perf/util/vdso.c
tools/power/cpupower/Makefile
tools/power/cpupower/man/cpupower-monitor.1
tools/power/cpupower/utils/builtin.h
tools/power/cpupower/utils/cpuidle-info.c
tools/power/cpupower/utils/cpuidle-set.c [new file with mode: 0644]
tools/power/cpupower/utils/cpupower.c
tools/power/cpupower/utils/helpers/sysfs.c
tools/power/cpupower/utils/helpers/sysfs.h
tools/power/cpupower/utils/idle_monitor/hsw_ext_idle.c [new file with mode: 0644]
tools/power/cpupower/utils/idle_monitor/idle_monitors.def
tools/power/cpupower/utils/idle_monitor/snb_idle.c
tools/scripts/Makefile.include
tools/virtio/linux/module.h
tools/virtio/linux/virtio.h

index 481aae9..5c53d28 100644 (file)
@@ -54,6 +54,13 @@ Description: Interface for making ib_srp connect to a new target.
                  ib_srp. Specifying a value that exceeds cmd_sg_entries is
                  only safe with partial memory descriptor list support enabled
                  (allow_ext_sg=1).
+               * comp_vector, a number in the range 0..n-1 specifying the
+                 MSI-X completion vector. Some HCA's allocate multiple (n)
+                 MSI-X vectors per HCA port. If the IRQ affinity masks of
+                 these interrupts have been configured such that each MSI-X
+                 interrupt is handled by a different CPU then the comp_vector
+                 parameter can be used to spread the SRP completion workload
+                 over multiple CPU's.
 
 What:          /sys/class/infiniband_srp/srp-<hca>-<port_number>/ibdev
 Date:          January 2, 2006
index a0dd21c..6272ae5 100644 (file)
@@ -4,9 +4,13 @@ Description:
 
        /sys/module/MODULENAME
                The name of the module that is in the kernel.  This
-               module name will show up either if the module is built
-               directly into the kernel, or if it is loaded as a
-               dynamic module.
+               module name will always show up if the module is loaded as a
+               dynamic module.  If it is built directly into the kernel, it
+               will only show up if it has a version or at least one
+               parameter.
+
+               Note: The conditions of creation in the built-in case are not
+               by design and may be removed in the future.
 
        /sys/module/MODULENAME/parameters
                This directory contains individual files that are each
index 8b25ffb..3c1cc24 100644 (file)
@@ -29,7 +29,7 @@ Description:  Generic performance monitoring events
 
 What:          /sys/devices/cpu/events/PM_1PLUS_PPC_CMPL
                /sys/devices/cpu/events/PM_BRU_FIN
-               /sys/devices/cpu/events/PM_BRU_MPRED
+               /sys/devices/cpu/events/PM_BR_MPRED
                /sys/devices/cpu/events/PM_CMPLU_STALL
                /sys/devices/cpu/events/PM_CMPLU_STALL_BRU
                /sys/devices/cpu/events/PM_CMPLU_STALL_DCACHE_MISS
diff --git a/Documentation/ABI/testing/sysfs-class-pwm b/Documentation/ABI/testing/sysfs-class-pwm
new file mode 100644 (file)
index 0000000..c479d77
--- /dev/null
@@ -0,0 +1,79 @@
+What:          /sys/class/pwm/
+Date:          May 2013
+KernelVersion: 3.11
+Contact:       H Hartley Sweeten <hsweeten@visionengravers.com>
+Description:
+               The pwm/ class sub-directory belongs to the Generic PWM
+               Framework and provides a sysfs interface for using PWM
+               channels.
+
+What:          /sys/class/pwm/pwmchipN/
+Date:          May 2013
+KernelVersion: 3.11
+Contact:       H Hartley Sweeten <hsweeten@visionengravers.com>
+Description:
+               A /sys/class/pwm/pwmchipN directory is created for each
+               probed PWM controller/chip where N is the base of the
+               PWM chip.
+
+What:          /sys/class/pwm/pwmchipN/npwm
+Date:          May 2013
+KernelVersion: 3.11
+Contact:       H Hartley Sweeten <hsweeten@visionengravers.com>
+Description:
+               The number of PWM channels supported by the PWM chip.
+
+What:          /sys/class/pwm/pwmchipN/export
+Date:          May 2013
+KernelVersion: 3.11
+Contact:       H Hartley Sweeten <hsweeten@visionengravers.com>
+Description:
+               Exports a PWM channel from the PWM chip for sysfs control.
+               Value is between 0 and /sys/class/pwm/pwmchipN/npwm - 1.
+
+What:          /sys/class/pwm/pwmchipN/unexport
+Date:          May 2013
+KernelVersion: 3.11
+Contact:       H Hartley Sweeten <hsweeten@visionengravers.com>
+Description:
+               Unexports a PWM channel.
+
+What:          /sys/class/pwm/pwmchipN/pwmX
+Date:          May 2013
+KernelVersion: 3.11
+Contact:       H Hartley Sweeten <hsweeten@visionengravers.com>
+Description:
+               A /sys/class/pwm/pwmchipN/pwmX directory is created for
+               each exported PWM channel where X is the exported PWM
+               channel number.
+
+What:          /sys/class/pwm/pwmchipN/pwmX/period
+Date:          May 2013
+KernelVersion: 3.11
+Contact:       H Hartley Sweeten <hsweeten@visionengravers.com>
+Description:
+               Sets the PWM signal period in nanoseconds.
+
+What:          /sys/class/pwm/pwmchipN/pwmX/duty_cycle
+Date:          May 2013
+KernelVersion: 3.11
+Contact:       H Hartley Sweeten <hsweeten@visionengravers.com>
+Description:
+               Sets the PWM signal duty cycle in nanoseconds.
+
+What:          /sys/class/pwm/pwmchipN/pwmX/polarity
+Date:          May 2013
+KernelVersion: 3.11
+Contact:       H Hartley Sweeten <hsweeten@visionengravers.com>
+Description:
+               Sets the output polarity of the PWM signal to "normal" or
+               "inversed".
+
+What:          /sys/class/pwm/pwmchipN/pwmX/enable
+Date:          May 2013
+KernelVersion: 3.11
+Contact:       H Hartley Sweeten <hsweeten@visionengravers.com>
+Description:
+               Enable/disable the PWM signal.
+               0 is disabled
+               1 is enabled
index 30ee78a..6568e00 100644 (file)
@@ -77,7 +77,7 @@ Description:  Read/Write attribute file that controls memory scrubbing.
 
 What:          /sys/devices/system/edac/mc/mc*/max_location
 Date:          April 2012
-Contact:       Mauro Carvalho Chehab <mchehab@redhat.com>
+Contact:       Mauro Carvalho Chehab <m.chehab@samsung.com>
                linux-edac@vger.kernel.org
 Description:   This attribute file displays the information about the last
                available memory slot in this memory controller. It is used by
@@ -85,7 +85,7 @@ Description:  This attribute file displays the information about the last
 
 What:          /sys/devices/system/edac/mc/mc*/(dimm|rank)*/size
 Date:          April 2012
-Contact:       Mauro Carvalho Chehab <mchehab@redhat.com>
+Contact:       Mauro Carvalho Chehab <m.chehab@samsung.com>
                linux-edac@vger.kernel.org
 Description:   This attribute file will display the size of dimm or rank.
                For dimm*/size, this is the size, in MB of the DIMM memory
@@ -96,14 +96,14 @@ Description:        This attribute file will display the size of dimm or rank.
 
 What:          /sys/devices/system/edac/mc/mc*/(dimm|rank)*/dimm_dev_type
 Date:          April 2012
-Contact:       Mauro Carvalho Chehab <mchehab@redhat.com>
+Contact:       Mauro Carvalho Chehab <m.chehab@samsung.com>
                linux-edac@vger.kernel.org
 Description:   This attribute file will display what type of DRAM device is
                being utilized on this DIMM (x1, x2, x4, x8, ...).
 
 What:          /sys/devices/system/edac/mc/mc*/(dimm|rank)*/dimm_edac_mode
 Date:          April 2012
-Contact:       Mauro Carvalho Chehab <mchehab@redhat.com>
+Contact:       Mauro Carvalho Chehab <m.chehab@samsung.com>
                linux-edac@vger.kernel.org
 Description:   This attribute file will display what type of Error detection
                and correction is being utilized. For example: S4ECD4ED would
@@ -111,7 +111,7 @@ Description:        This attribute file will display what type of Error detection
 
 What:          /sys/devices/system/edac/mc/mc*/(dimm|rank)*/dimm_label
 Date:          April 2012
-Contact:       Mauro Carvalho Chehab <mchehab@redhat.com>
+Contact:       Mauro Carvalho Chehab <m.chehab@samsung.com>
                linux-edac@vger.kernel.org
 Description:   This control file allows this DIMM to have a label assigned
                to it. With this label in the module, when errors occur
@@ -126,14 +126,14 @@ Description:      This control file allows this DIMM to have a label assigned
 
 What:          /sys/devices/system/edac/mc/mc*/(dimm|rank)*/dimm_location
 Date:          April 2012
-Contact:       Mauro Carvalho Chehab <mchehab@redhat.com>
+Contact:       Mauro Carvalho Chehab <m.chehab@samsung.com>
                linux-edac@vger.kernel.org
 Description:   This attribute file will display the location (csrow/channel,
                branch/channel/slot or channel/slot) of the dimm or rank.
 
 What:          /sys/devices/system/edac/mc/mc*/(dimm|rank)*/dimm_mem_type
 Date:          April 2012
-Contact:       Mauro Carvalho Chehab <mchehab@redhat.com>
+Contact:       Mauro Carvalho Chehab <m.chehab@samsung.com>
                linux-edac@vger.kernel.org
 Description:   This attribute file will display what type of memory is
                currently on this csrow. Normally, either buffered or
diff --git a/Documentation/ABI/testing/sysfs-driver-intel-rapid-start b/Documentation/ABI/testing/sysfs-driver-intel-rapid-start
new file mode 100644 (file)
index 0000000..5a7d2e2
--- /dev/null
@@ -0,0 +1,21 @@
+What:          /sys/bus/acpi/intel-rapid-start/wakeup_events
+Date:          July 2, 2013
+KernelVersion: 3.11
+Contact:       Matthew Garrett <mjg59@srcf.ucam.org>
+Description:   An integer representing a set of wakeup events as follows:
+               1: Wake to enter hibernation when the wakeup timer expires
+               2: Wake to enter hibernation when the battery reaches a
+               critical level
+
+               These values are ORed together. For example, a value of 3
+               indicates that the system will wake to enter hibernation when
+               either the wakeup timer expires or the battery reaches a
+               critical level.
+
+What:          /sys/bus/acpi/intel-rapid-start/wakeup_time
+Date:          July 2, 2013
+KernelVersion: 3.11
+Contact:       Matthew Garrett <mjg59@srcf.ucam.org>
+Description:   An integer representing the length of time the system will
+               remain asleep before waking up to enter hibernation.
+               This value is in minutes.
index f43542a..0c7195e 100644 (file)
@@ -2254,7 +2254,7 @@ video encoding.</para>
       <orderedlist>
        <listitem>
          <para>The <constant>VIDIOC_G_CHIP_IDENT</constant> ioctl was renamed
-to <constant>VIDIOC_G_CHIP_IDENT_OLD</constant> and &VIDIOC-DBG-G-CHIP-IDENT;
+to <constant>VIDIOC_G_CHIP_IDENT_OLD</constant> and <constant>VIDIOC_DBG_G_CHIP_IDENT</constant>
 was introduced in its place. The old struct <structname>v4l2_chip_ident</structname>
 was renamed to <structname id="v4l2-chip-ident-old">v4l2_chip_ident_old</structname>.</para>
        </listitem>
@@ -2513,6 +2513,16 @@ that used it. It was originally scheduled for removal in 2.6.35.
       </orderedlist>
     </section>
 
+    <section>
+      <title>V4L2 in Linux 3.11</title>
+      <orderedlist>
+        <listitem>
+         <para>Remove obsolete <constant>VIDIOC_DBG_G_CHIP_IDENT</constant> ioctl.
+         </para>
+        </listitem>
+      </orderedlist>
+    </section>
+
     <section id="other">
       <title>Relation of V4L2 to other Linux multimedia APIs</title>
 
@@ -2596,7 +2606,7 @@ and may change in the future.</para>
 ioctls.</para>
         </listitem>
         <listitem>
-         <para>&VIDIOC-DBG-G-CHIP-IDENT; ioctl.</para>
+         <para>&VIDIOC-DBG-G-CHIP-INFO; ioctl.</para>
         </listitem>
         <listitem>
          <para>&VIDIOC-ENUM-DV-TIMINGS;, &VIDIOC-QUERY-DV-TIMINGS; and
index bfe823d..8469fe1 100644 (file)
@@ -141,6 +141,14 @@ structs, ioctls) must be noted in more detail in the history chapter
 applications. -->
 
       <revision>
+       <revnumber>3.11</revnumber>
+       <date>2013-05-26</date>
+       <authorinitials>hv</authorinitials>
+       <revremark>Remove obsolete VIDIOC_DBG_G_CHIP_IDENT ioctl.
+       </revremark>
+      </revision>
+
+      <revision>
        <revnumber>3.10</revnumber>
        <date>2013-03-25</date>
        <authorinitials>hv</authorinitials>
@@ -493,7 +501,7 @@ and discussions on the V4L mailing list.</revremark>
 </partinfo>
 
 <title>Video for Linux Two API Specification</title>
- <subtitle>Revision 3.10</subtitle>
+ <subtitle>Revision 3.11</subtitle>
 
   <chapter id="common">
     &sub-common;
@@ -547,7 +555,6 @@ and discussions on the V4L mailing list.</revremark>
     <!-- All ioctls go here. -->
     &sub-create-bufs;
     &sub-cropcap;
-    &sub-dbg-g-chip-ident;
     &sub-dbg-g-chip-info;
     &sub-dbg-g-register;
     &sub-decoder-cmd;
diff --git a/Documentation/DocBook/media/v4l/vidioc-dbg-g-chip-ident.xml b/Documentation/DocBook/media/v4l/vidioc-dbg-g-chip-ident.xml
deleted file mode 100644 (file)
index 921e185..0000000
+++ /dev/null
@@ -1,271 +0,0 @@
-<refentry id="vidioc-dbg-g-chip-ident">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_DBG_G_CHIP_IDENT</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_DBG_G_CHIP_IDENT</refname>
-    <refpurpose>Identify the chips on a TV card</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>struct v4l2_dbg_chip_ident
-*<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-
-    <variablelist>
-      <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>&fd;</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>request</parameter></term>
-       <listitem>
-         <para>VIDIOC_DBG_G_CHIP_IDENT</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <note>
-      <title>Experimental</title>
-
-      <para>This is an <link
-linkend="experimental">experimental</link> interface and may change in
-the future.</para>
-    </note>
-
-    <para>For driver debugging purposes this ioctl allows test
-applications to query the driver about the chips present on the TV
-card. Regular applications must not use it. When you found a chip
-specific bug, please contact the linux-media mailing list (&v4l-ml;)
-so it can be fixed.</para>
-
-    <para>To query the driver applications must initialize the
-<structfield>match.type</structfield> and
-<structfield>match.addr</structfield> or <structfield>match.name</structfield>
-fields of a &v4l2-dbg-chip-ident;
-and call <constant>VIDIOC_DBG_G_CHIP_IDENT</constant> with a pointer to
-this structure. On success the driver stores information about the
-selected chip in the <structfield>ident</structfield> and
-<structfield>revision</structfield> fields. On failure the structure
-remains unchanged.</para>
-
-    <para>When <structfield>match.type</structfield> is
-<constant>V4L2_CHIP_MATCH_HOST</constant>,
-<structfield>match.addr</structfield> selects the nth non-&i2c; chip
-on the TV card. You can enumerate all chips by starting at zero and
-incrementing <structfield>match.addr</structfield> by one until
-<constant>VIDIOC_DBG_G_CHIP_IDENT</constant> fails with an &EINVAL;.
-The number zero always selects the host chip, &eg; the chip connected
-to the PCI or USB bus.</para>
-
-    <para>When <structfield>match.type</structfield> is
-<constant>V4L2_CHIP_MATCH_I2C_DRIVER</constant>,
-<structfield>match.name</structfield> contains the I2C driver name.
-For instance
-<constant>"saa7127"</constant> will match any chip
-supported by the saa7127 driver, regardless of its &i2c; bus address.
-When multiple chips supported by the same driver are present, the
-ioctl will return <constant>V4L2_IDENT_AMBIGUOUS</constant> in the
-<structfield>ident</structfield> field.</para>
-
-    <para>When <structfield>match.type</structfield> is
-<constant>V4L2_CHIP_MATCH_I2C_ADDR</constant>,
-<structfield>match.addr</structfield> selects a chip by its 7 bit
-&i2c; bus address.</para>
-
-    <para>When <structfield>match.type</structfield> is
-<constant>V4L2_CHIP_MATCH_AC97</constant>,
-<structfield>match.addr</structfield> selects the nth AC97 chip
-on the TV card. You can enumerate all chips by starting at zero and
-incrementing <structfield>match.addr</structfield> by one until
-<constant>VIDIOC_DBG_G_CHIP_IDENT</constant> fails with an &EINVAL;.</para>
-
-    <para>On success, the <structfield>ident</structfield> field will
-contain a chip ID from the Linux
-<filename>media/v4l2-chip-ident.h</filename> header file, and the
-<structfield>revision</structfield> field will contain a driver
-specific value, or zero if no particular revision is associated with
-this chip.</para>
-
-    <para>When the driver could not identify the selected chip,
-<structfield>ident</structfield> will contain
-<constant>V4L2_IDENT_UNKNOWN</constant>. When no chip matched
-the ioctl will succeed but the
-<structfield>ident</structfield> field will contain
-<constant>V4L2_IDENT_NONE</constant>. If multiple chips matched,
-<structfield>ident</structfield> will contain
-<constant>V4L2_IDENT_AMBIGUOUS</constant>. In all these cases the
-<structfield>revision</structfield> field remains unchanged.</para>
-
-    <para>This ioctl is optional, not all drivers may support it. It
-was introduced in Linux 2.6.21, but the API was changed to the
-one described here in 2.6.29.</para>
-
-    <para>We recommended the <application>v4l2-dbg</application>
-utility over calling this ioctl directly. It is available from the
-LinuxTV v4l-dvb repository; see <ulink
-url="http://linuxtv.org/repo/">http://linuxtv.org/repo/</ulink> for
-access instructions.</para>
-
-    <!-- Note for convenience vidioc-dbg-g-register.sgml
-        contains a duplicate of this table. -->
-    <table pgwide="1" frame="none" id="ident-v4l2-dbg-match">
-      <title>struct <structname>v4l2_dbg_match</structname></title>
-      <tgroup cols="4">
-       &cs-ustr;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>type</structfield></entry>
-           <entry>See <xref linkend="ident-chip-match-types" /> for a list of
-possible types.</entry>
-         </row>
-         <row>
-           <entry>union</entry>
-           <entry>(anonymous)</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>__u32</entry>
-           <entry><structfield>addr</structfield></entry>
-           <entry>Match a chip by this number, interpreted according
-to the <structfield>type</structfield> field.</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>char</entry>
-           <entry><structfield>name[32]</structfield></entry>
-           <entry>Match a chip by this name, interpreted according
-to the <structfield>type</structfield> field.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="v4l2-dbg-chip-ident">
-      <title>struct <structname>v4l2_dbg_chip_ident</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>struct v4l2_dbg_match</entry>
-           <entry><structfield>match</structfield></entry>
-           <entry>How to match the chip, see <xref linkend="ident-v4l2-dbg-match" />.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>ident</structfield></entry>
-           <entry>A chip identifier as defined in the Linux
-<filename>media/v4l2-chip-ident.h</filename> header file, or one of
-the values from <xref linkend="chip-ids" />.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>revision</structfield></entry>
-           <entry>A chip revision, chip and driver specific.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <!-- Note for convenience vidioc-dbg-g-register.sgml
-        contains a duplicate of this table. -->
-    <table pgwide="1" frame="none" id="ident-chip-match-types">
-      <title>Chip Match Types</title>
-      <tgroup cols="3">
-       &cs-def;
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_CHIP_MATCH_BRIDGE</constant></entry>
-           <entry>0</entry>
-           <entry>Match the nth chip on the card, zero for the
-           bridge chip. Does not match sub-devices.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CHIP_MATCH_I2C_DRIVER</constant></entry>
-           <entry>1</entry>
-           <entry>Match an &i2c; chip by its driver name.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CHIP_MATCH_I2C_ADDR</constant></entry>
-           <entry>2</entry>
-           <entry>Match a chip by its 7 bit &i2c; bus address.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CHIP_MATCH_AC97</constant></entry>
-           <entry>3</entry>
-           <entry>Match the nth anciliary AC97 chip.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CHIP_MATCH_SUBDEV</constant></entry>
-           <entry>4</entry>
-           <entry>Match the nth sub-device. Can't be used with this ioctl.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <!-- This is an anonymous enum in media/v4l2-chip-ident.h. -->
-    <table pgwide="1" frame="none" id="chip-ids">
-      <title>Chip Identifiers</title>
-      <tgroup cols="3">
-       &cs-def;
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_IDENT_NONE</constant></entry>
-           <entry>0</entry>
-           <entry>No chip matched.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_IDENT_AMBIGUOUS</constant></entry>
-           <entry>1</entry>
-           <entry>Multiple chips matched.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_IDENT_UNKNOWN</constant></entry>
-           <entry>2</entry>
-           <entry>A chip is present at this address, but the driver
-could not identify it.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The <structfield>match_type</structfield> is invalid.</para>
-       </listitem>
-      </varlistentry>
-     </variablelist>
-  </refsect1>
-</refentry>
index e1cece6..4c4603c 100644 (file)
@@ -73,8 +73,7 @@ fields of a &v4l2-dbg-chip-info;
 and call <constant>VIDIOC_DBG_G_CHIP_INFO</constant> with a pointer to
 this structure. On success the driver stores information about the
 selected chip in the <structfield>name</structfield> and
-<structfield>flags</structfield> fields. On failure the structure
-remains unchanged.</para>
+<structfield>flags</structfield> fields.</para>
 
     <para>When <structfield>match.type</structfield> is
 <constant>V4L2_CHIP_MATCH_BRIDGE</constant>,
@@ -132,7 +131,7 @@ to the <structfield>type</structfield> field.</entry>
            <entry>char</entry>
            <entry><structfield>name[32]</structfield></entry>
            <entry>Match a chip by this name, interpreted according
-to the <structfield>type</structfield> field.</entry>
+to the <structfield>type</structfield> field. Currently unused.</entry>
          </row>
        </tbody>
       </tgroup>
@@ -183,21 +182,6 @@ is set, then the driver supports reading registers from the device. If
            bridge chip. Does not match sub-devices.</entry>
          </row>
          <row>
-           <entry><constant>V4L2_CHIP_MATCH_I2C_DRIVER</constant></entry>
-           <entry>1</entry>
-           <entry>Match an &i2c; chip by its driver name. Can't be used with this ioctl.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CHIP_MATCH_I2C_ADDR</constant></entry>
-           <entry>2</entry>
-           <entry>Match a chip by its 7 bit &i2c; bus address. Can't be used with this ioctl.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CHIP_MATCH_AC97</constant></entry>
-           <entry>3</entry>
-           <entry>Match the nth anciliary AC97 chip. Can't be used with this ioctl.</entry>
-         </row>
-         <row>
            <entry><constant>V4L2_CHIP_MATCH_SUBDEV</constant></entry>
            <entry>4</entry>
            <entry>Match the nth sub-device.</entry>
index d13bac9..3d038e7 100644 (file)
@@ -76,7 +76,7 @@ compiled with the <constant>CONFIG_VIDEO_ADV_DEBUG</constant> option
 to enable these ioctls.</para>
 
     <para>To write a register applications must initialize all fields
-of a &v4l2-dbg-register; and call
+of a &v4l2-dbg-register; except for <structfield>size</structfield> and call
 <constant>VIDIOC_DBG_S_REGISTER</constant> with a pointer to this
 structure. The <structfield>match.type</structfield> and
 <structfield>match.addr</structfield> or <structfield>match.name</structfield>
@@ -91,8 +91,8 @@ written into the register.</para>
 <structfield>reg</structfield> fields, and call
 <constant>VIDIOC_DBG_G_REGISTER</constant> with a pointer to this
 structure. On success the driver stores the register value in the
-<structfield>val</structfield> field. On failure the structure remains
-unchanged.</para>
+<structfield>val</structfield> field and the size (in bytes) of the
+value in <structfield>size</structfield>.</para>
 
     <para>When <structfield>match.type</structfield> is
 <constant>V4L2_CHIP_MATCH_BRIDGE</constant>,
@@ -102,39 +102,9 @@ chip connected to the PCI or USB bus. You can find out which chips are
 present with the &VIDIOC-DBG-G-CHIP-INFO; ioctl.</para>
 
     <para>When <structfield>match.type</structfield> is
-<constant>V4L2_CHIP_MATCH_I2C_DRIVER</constant>,
-<structfield>match.name</structfield> contains the I2C driver name.
-For instance
-<constant>"saa7127"</constant> will match any chip
-supported by the saa7127 driver, regardless of its &i2c; bus address.
-When multiple chips supported by the same driver are present, the
-effect of these ioctls is undefined. Again with the
-&VIDIOC-DBG-G-CHIP-INFO; ioctl you can find out which &i2c; chips are
-present.</para>
-
-    <para>When <structfield>match.type</structfield> is
-<constant>V4L2_CHIP_MATCH_I2C_ADDR</constant>,
-<structfield>match.addr</structfield> selects a chip by its 7 bit &i2c;
-bus address.</para>
-
-    <para>When <structfield>match.type</structfield> is
-<constant>V4L2_CHIP_MATCH_AC97</constant>,
-<structfield>match.addr</structfield> selects the nth AC97 chip
-on the TV card.</para>
-
-    <para>When <structfield>match.type</structfield> is
 <constant>V4L2_CHIP_MATCH_SUBDEV</constant>,
 <structfield>match.addr</structfield> selects the nth sub-device.</para>
 
-    <note>
-      <title>Success not guaranteed</title>
-
-      <para>Due to a flaw in the Linux &i2c; bus driver these ioctls may
-return successfully without actually reading or writing a register. To
-catch the most likely failure we recommend a &VIDIOC-DBG-G-CHIP-INFO;
-call confirming the presence of the selected &i2c; chip.</para>
-    </note>
-
     <para>These ioctls are optional, not all drivers may support them.
 However when a driver supports these ioctls it must also support
 &VIDIOC-DBG-G-CHIP-INFO;. Conversely it may support
@@ -150,7 +120,7 @@ LinuxTV v4l-dvb repository; see <ulink
 url="http://linuxtv.org/repo/">http://linuxtv.org/repo/</ulink> for
 access instructions.</para>
 
-    <!-- Note for convenience vidioc-dbg-g-chip-ident.sgml
+    <!-- Note for convenience vidioc-dbg-g-chip-info.sgml
         contains a duplicate of this table. -->
     <table pgwide="1" frame="none" id="v4l2-dbg-match">
       <title>struct <structname>v4l2_dbg_match</structname></title>
@@ -160,7 +130,7 @@ access instructions.</para>
          <row>
            <entry>__u32</entry>
            <entry><structfield>type</structfield></entry>
-           <entry>See <xref linkend="ident-chip-match-types" /> for a list of
+           <entry>See <xref linkend="chip-match-types" /> for a list of
 possible types.</entry>
          </row>
          <row>
@@ -179,7 +149,7 @@ to the <structfield>type</structfield> field.</entry>
            <entry>char</entry>
            <entry><structfield>name[32]</structfield></entry>
            <entry>Match a chip by this name, interpreted according
-to the <structfield>type</structfield> field.</entry>
+to the <structfield>type</structfield> field. Currently unused.</entry>
          </row>
        </tbody>
       </tgroup>
@@ -199,6 +169,11 @@ to the <structfield>type</structfield> field.</entry>
            <entry>How to match the chip, see <xref linkend="v4l2-dbg-match" />.</entry>
          </row>
          <row>
+           <entry>__u32</entry>
+           <entry><structfield>size</structfield></entry>
+           <entry>The register size in bytes.</entry>
+         </row>
+         <row>
            <entry>__u64</entry>
            <entry><structfield>reg</structfield></entry>
            <entry>A register number.</entry>
@@ -213,7 +188,7 @@ register.</entry>
       </tgroup>
     </table>
 
-    <!-- Note for convenience vidioc-dbg-g-chip-ident.sgml
+    <!-- Note for convenience vidioc-dbg-g-chip-info.sgml
         contains a duplicate of this table. -->
     <table pgwide="1" frame="none" id="chip-match-types">
       <title>Chip Match Types</title>
@@ -227,21 +202,6 @@ register.</entry>
            bridge chip. Does not match sub-devices.</entry>
          </row>
          <row>
-           <entry><constant>V4L2_CHIP_MATCH_I2C_DRIVER</constant></entry>
-           <entry>1</entry>
-           <entry>Match an &i2c; chip by its driver name.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CHIP_MATCH_I2C_ADDR</constant></entry>
-           <entry>2</entry>
-           <entry>Match a chip by its 7 bit &i2c; bus address.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CHIP_MATCH_AC97</constant></entry>
-           <entry>3</entry>
-           <entry>Match the nth anciliary AC97 chip.</entry>
-         </row>
-         <row>
            <entry><constant>V4L2_CHIP_MATCH_SUBDEV</constant></entry>
            <entry>4</entry>
            <entry>Match the nth sub-device.</entry>
index fe80a18..2223485 100644 (file)
@@ -54,7 +54,8 @@ standard automatically. To do so, applications call <constant>
 VIDIOC_QUERYSTD</constant> with a pointer to a &v4l2-std-id; type. The
 driver stores here a set of candidates, this can be a single flag or a
 set of supported standards if for example the hardware can only
-distinguish between 50 and 60 Hz systems. When detection is not
+distinguish between 50 and 60 Hz systems. If no signal was detected,
+then the driver will return V4L2_STD_UNKNOWN. When detection is not
 possible or fails, the set must contain all standards supported by the
 current video input or output.</para>
 
index da272c8..cd556b9 100644 (file)
@@ -94,11 +94,13 @@ Throttling/Upper Limit policy
 
 Hierarchical Cgroups
 ====================
-- Currently only CFQ supports hierarchical groups. For throttling,
-  cgroup interface does allow creation of hierarchical cgroups and
-  internally it treats them as flat hierarchy.
 
-  If somebody created a hierarchy like as follows.
+Both CFQ and throttling implement hierarchy support; however,
+throttling's hierarchy support is enabled iff "sane_behavior" is
+enabled from cgroup side, which currently is a development option and
+not publicly available.
+
+If somebody created a hierarchy like as follows.
 
                        root
                        /  \
@@ -106,21 +108,20 @@ Hierarchical Cgroups
                        |
                     test3
 
-  CFQ will handle the hierarchy correctly but and throttling will
-  practically treat all groups at same level. For details on CFQ
-  hierarchy support, refer to Documentation/block/cfq-iosched.txt.
-  Throttling will treat the hierarchy as if it looks like the
-  following.
+CFQ by default and throttling with "sane_behavior" will handle the
+hierarchy correctly.  For details on CFQ hierarchy support, refer to
+Documentation/block/cfq-iosched.txt.  For throttling, all limits apply
+to the whole subtree while all statistics are local to the IOs
+directly generated by tasks in that cgroup.
+
+Throttling without "sane_behavior" enabled from cgroup side will
+practically treat all groups at same level as if it looks like the
+following.
 
                                pivot
                             /  /   \  \
                        root  test1 test2  test3
 
-  Nesting cgroups, while allowed, isn't officially supported and blkio
-  genereates warning when cgroups nest. Once throttling implements
-  hierarchy support, hierarchy will be supported and the warning will
-  be removed.
-
 Various user visible config options
 ===================================
 CONFIG_BLK_CGROUP
index 18de785..7f773d5 100644 (file)
@@ -6,15 +6,17 @@ Copyright 2010 Gilles Muller <Gilles.Muller@lip6.fr>
  Getting Coccinelle
 ~~~~~~~~~~~~~~~~~~~~
 
-The semantic patches included in the kernel use the 'virtual rule'
-feature which was introduced in Coccinelle version 0.1.11.
+The semantic patches included in the kernel use features and options
+which are provided by Coccinelle version 1.0.0-rc11 and above.
+Using earlier versions will fail as the option names used by
+the Coccinelle files and coccicheck have been updated.
 
-Coccinelle (>=0.2.0) is available through the package manager
+Coccinelle is available through the package manager
 of many distributions, e.g. :
 
- - Debian (>=squeeze)
- - Fedora (>=13)
- - Ubuntu (>=10.04 Lucid Lynx)
+ - Debian
+ - Fedora
+ - Ubuntu
  - OpenSUSE
  - Arch Linux
  - NetBSD
@@ -36,11 +38,6 @@ as a regular user, and install it with
 
         sudo make install
 
-The semantic patches in the kernel will work best with Coccinelle version
-0.2.4 or later.  Using earlier versions may incur some parse errors in the
-semantic patch code, but any results that are obtained should still be
-correct.
-
  Using Coccinelle on the Linux kernel
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
@@ -48,7 +45,7 @@ A Coccinelle-specific target is defined in the top level
 Makefile. This target is named 'coccicheck' and calls the 'coccicheck'
 front-end in the 'scripts' directory.
 
-Four modes are defined: patch, report, context, and org. The mode to
+Four basic modes are defined: patch, report, context, and org. The mode to
 use is specified by setting the MODE variable with 'MODE=<mode>'.
 
 'patch' proposes a fix, when possible.
@@ -62,18 +59,24 @@ diff-like style.Lines of interest are indicated with '-'.
 'org' generates a report in the Org mode format of Emacs.
 
 Note that not all semantic patches implement all modes. For easy use
-of Coccinelle, the default mode is "chain" which tries the previous
-modes in the order above until one succeeds.
+of Coccinelle, the default mode is "report".
+
+Two other modes provide some common combinations of these modes.
 
-To make a report for every semantic patch, run the following command:
+'chain' tries the previous modes in the order above until one succeeds.
 
-       make coccicheck MODE=report
+'rep+ctxt' runs successively the report mode and the context mode.
+          It should be used with the C option (described later)
+          which checks the code on a file basis.
 
-NB: The 'report' mode is the default one.
+Examples:
+       To make a report for every semantic patch, run the following command:
 
-To produce patches, run:
+               make coccicheck MODE=report
 
-       make coccicheck MODE=patch
+       To produce patches, run:
+
+               make coccicheck MODE=patch
 
 
 The coccicheck target applies every semantic patch available in the
@@ -91,6 +94,11 @@ To enable verbose messages set the V= variable, for example:
 
    make coccicheck MODE=report V=1
 
+By default, coccicheck tries to run as parallel as possible. To change
+the parallelism, set the J= variable. For example, to run across 4 CPUs:
+
+   make coccicheck MODE=report J=4
+
 
  Using Coccinelle with a single semantic patch
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -124,26 +132,33 @@ To check only newly edited code, use the value 2 for the C flag, i.e.
 
     make C=2 CHECK="scripts/coccicheck"
 
+In these modes, which works on a file basis, there is no information
+about semantic patches displayed, and no commit message proposed.
+
 This runs every semantic patch in scripts/coccinelle by default. The
 COCCI variable may additionally be used to only apply a single
 semantic patch as shown in the previous section.
 
-The "chain" mode is the default. You can select another one with the
+The "report" mode is the default. You can select another one with the
 MODE variable explained above.
 
-In this mode, there is no information about semantic patches
-displayed, and no commit message proposed.
-
  Additional flags
 ~~~~~~~~~~~~~~~~~~
 
 Additional flags can be passed to spatch through the SPFLAGS
 variable.
 
-    make SPFLAGS=--use_glimpse coccicheck
+    make SPFLAGS=--use-glimpse coccicheck
+    make SPFLAGS=--use-idutils coccicheck
 
 See spatch --help to learn more about spatch options.
 
+Note that the '--use-glimpse' and '--use-idutils' options
+require external tools for indexing the code. None of them is
+thus active by default. However, by indexing the code with
+one of these tools, and according to the cocci file used,
+spatch could proceed the entire code base more quickly.
+
  Proposing new semantic patches
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
diff --git a/Documentation/device-mapper/switch.txt b/Documentation/device-mapper/switch.txt
new file mode 100644 (file)
index 0000000..2fa7493
--- /dev/null
@@ -0,0 +1,126 @@
+dm-switch
+=========
+
+The device-mapper switch target creates a device that supports an
+arbitrary mapping of fixed-size regions of I/O across a fixed set of
+paths.  The path used for any specific region can be switched
+dynamically by sending the target a message.
+
+It maps I/O to underlying block devices efficiently when there is a large
+number of fixed-sized address regions but there is no simple pattern
+that would allow for a compact representation of the mapping such as
+dm-stripe.
+
+Background
+----------
+
+Dell EqualLogic and some other iSCSI storage arrays use a distributed
+frameless architecture.  In this architecture, the storage group
+consists of a number of distinct storage arrays ("members") each having
+independent controllers, disk storage and network adapters.  When a LUN
+is created it is spread across multiple members.  The details of the
+spreading are hidden from initiators connected to this storage system.
+The storage group exposes a single target discovery portal, no matter
+how many members are being used.  When iSCSI sessions are created, each
+session is connected to an eth port on a single member.  Data to a LUN
+can be sent on any iSCSI session, and if the blocks being accessed are
+stored on another member the I/O will be forwarded as required.  This
+forwarding is invisible to the initiator.  The storage layout is also
+dynamic, and the blocks stored on disk may be moved from member to
+member as needed to balance the load.
+
+This architecture simplifies the management and configuration of both
+the storage group and initiators.  In a multipathing configuration, it
+is possible to set up multiple iSCSI sessions to use multiple network
+interfaces on both the host and target to take advantage of the
+increased network bandwidth.  An initiator could use a simple round
+robin algorithm to send I/O across all paths and let the storage array
+members forward it as necessary, but there is a performance advantage to
+sending data directly to the correct member.
+
+A device-mapper table already lets you map different regions of a
+device onto different targets.  However in this architecture the LUN is
+spread with an address region size on the order of 10s of MBs, which
+means the resulting table could have more than a million entries and
+consume far too much memory.
+
+Using this device-mapper switch target we can now build a two-layer
+device hierarchy:
+
+    Upper Tier – Determine which array member the I/O should be sent to.
+    Lower Tier – Load balance amongst paths to a particular member.
+
+The lower tier consists of a single dm multipath device for each member.
+Each of these multipath devices contains the set of paths directly to
+the array member in one priority group, and leverages existing path
+selectors to load balance amongst these paths.  We also build a
+non-preferred priority group containing paths to other array members for
+failover reasons.
+
+The upper tier consists of a single dm-switch device.  This device uses
+a bitmap to look up the location of the I/O and choose the appropriate
+lower tier device to route the I/O.  By using a bitmap we are able to
+use 4 bits for each address range in a 16 member group (which is very
+large for us).  This is a much denser representation than the dm table
+b-tree can achieve.
+
+Construction Parameters
+=======================
+
+    <num_paths> <region_size> <num_optional_args> [<optional_args>...]
+    [<dev_path> <offset>]+
+
+<num_paths>
+    The number of paths across which to distribute the I/O.
+
+<region_size>
+    The number of 512-byte sectors in a region. Each region can be redirected
+    to any of the available paths.
+
+<num_optional_args>
+    The number of optional arguments. Currently, no optional arguments
+    are supported and so this must be zero.
+
+<dev_path>
+    The block device that represents a specific path to the device.
+
+<offset>
+    The offset of the start of data on the specific <dev_path> (in units
+    of 512-byte sectors). This number is added to the sector number when
+    forwarding the request to the specific path. Typically it is zero.
+
+Messages
+========
+
+set_region_mappings <index>:<path_nr> [<index>]:<path_nr> [<index>]:<path_nr>...
+
+Modify the region table by specifying which regions are redirected to
+which paths.
+
+<index>
+    The region number (region size was specified in constructor parameters).
+    If index is omitted, the next region (previous index + 1) is used.
+    Expressed in hexadecimal (WITHOUT any prefix like 0x).
+
+<path_nr>
+    The path number in the range 0 ... (<num_paths> - 1).
+    Expressed in hexadecimal (WITHOUT any prefix like 0x).
+
+Status
+======
+
+No status line is reported.
+
+Example
+=======
+
+Assume that you have volumes vg1/switch0 vg1/switch1 vg1/switch2 with
+the same size.
+
+Create a switch device with 64kB region size:
+    dmsetup create switch --table "0 `blockdev --getsize /dev/vg1/switch0`
+       switch 3 128 0 /dev/vg1/switch0 0 /dev/vg1/switch1 0 /dev/vg1/switch2 0"
+
+Set mappings for the first 7 entries to point to devices switch0, switch1,
+switch2, switch0, switch1, switch2, switch1:
+    dmsetup message switch 0 set_region_mappings 0:0 :1 :2 :0 :1 :2 :1
diff --git a/Documentation/devicetree/bindings/arm/global_timer.txt b/Documentation/devicetree/bindings/arm/global_timer.txt
new file mode 100644 (file)
index 0000000..1e54898
--- /dev/null
@@ -0,0 +1,24 @@
+
+* ARM Global Timer
+       Cortex-A9 are often associated with a per-core Global timer.
+
+** Timer node required properties:
+
+- compatible : Should be "arm,cortex-a9-global-timer"
+               Driver supports versions r2p0 and above.
+
+- interrupts : One interrupt to each core
+
+- reg : Specify the base address and the size of the GT timer
+       register window.
+
+- clocks : Should be phandle to a clock.
+
+Example:
+
+       timer@2c000600 {
+               compatible = "arm,cortex-a9-global-timer";
+               reg = <0x2c000600 0x20>;
+               interrupts = <1 13 0xf01>;
+               clocks = <&arm_periph_clk>;
+       };
diff --git a/Documentation/devicetree/bindings/gpio/men-a021-wdt.txt b/Documentation/devicetree/bindings/gpio/men-a021-wdt.txt
new file mode 100644 (file)
index 0000000..370dee3
--- /dev/null
@@ -0,0 +1,25 @@
+Bindings for MEN A21 Watchdog device connected to GPIO lines
+
+Required properties:
+- compatible: "men,a021-wdt"
+- gpios: Specifies the pins that control the Watchdog, order:
+  1: Watchdog enable
+  2: Watchdog fast-mode
+  3: Watchdog trigger
+  4: Watchdog reset cause bit 0
+  5: Watchdog reset cause bit 1
+  6: Watchdog reset cause bit 2
+
+Optional properties:
+- None
+
+Example:
+       watchdog {
+               compatible ="men,a021-wdt";
+               gpios = <&gpio3 9  1    /* WD_EN */
+                        &gpio3 10 1    /* WD_FAST */
+                        &gpio3 11 1    /* WD_TRIG */
+                        &gpio3 6  1    /* RST_CAUSE[0] */
+                        &gpio3 7  1    /* RST_CAUSE[1] */
+                        &gpio3 8  1>;  /* RST_CAUSE[2] */
+       };
diff --git a/Documentation/devicetree/bindings/input/ads7846.txt b/Documentation/devicetree/bindings/input/ads7846.txt
new file mode 100644 (file)
index 0000000..5f7619c
--- /dev/null
@@ -0,0 +1,91 @@
+Device tree bindings for TI's ADS7843, ADS7845, ADS7846, ADS7873, TSC2046
+SPI driven touch screen controllers.
+
+The node for this driver must be a child node of a SPI controller, hence
+all mandatory properties described in
+
+       Documentation/devicetree/bindings/spi/spi-bus.txt
+
+must be specified.
+
+Additional required properties:
+
+       compatible              Must be one of the following, depending on the
+                               model:
+                                       "ti,tsc2046"
+                                       "ti,ads7843"
+                                       "ti,ads7845"
+                                       "ti,ads7846"
+                                       "ti,ads7873"
+
+       interrupt-parent
+       interrupts              An interrupt node describing the IRQ line the chip's
+                               !PENIRQ pin is connected to.
+       vcc-supply              A regulator node for the supply voltage.
+
+
+Optional properties:
+
+       ti,vref-delay-usecs             vref supply delay in usecs, 0 for
+                                       external vref (u16).
+       ti,vref-mv                      The VREF voltage, in millivolts (u16).
+       ti,keep-vref-on                 set to keep vref on for differential
+                                       measurements as well
+       ti,swap-xy                      swap x and y axis
+       ti,settle-delay-usec            Settling time of the analog signals;
+                                       a function of Vcc and the capacitance
+                                       on the X/Y drivers.  If set to non-zero,
+                                       two samples are taken with settle_delay
+                                       us apart, and the second one is used.
+                                       ~150 uSec with 0.01uF caps (u16).
+       ti,penirq-recheck-delay-usecs   If set to non-zero, after samples are
+                                       taken this delay is applied and penirq
+                                       is rechecked, to help avoid false
+                                       events.  This value is affected by the
+                                       material used to build the touch layer
+                                       (u16).
+       ti,x-plate-ohms                 Resistance of the X-plate,
+                                       in Ohms (u16).
+       ti,y-plate-ohms                 Resistance of the Y-plate,
+                                       in Ohms (u16).
+       ti,x-min                        Minimum value on the X axis (u16).
+       ti,y-min                        Minimum value on the Y axis (u16).
+       ti,x-max                        Maximum value on the X axis (u16).
+       ti,y-max                        Minimum value on the Y axis (u16).
+       ti,pressure-min                 Minimum reported pressure value
+                                       (threshold) - u16.
+       ti,pressure-max                 Maximum reported pressure value (u16).
+       ti,debounce-max                 Max number of additional readings per
+                                       sample (u16).
+       ti,debounce-tol                 Tolerance used for filtering (u16).
+       ti,debounce-rep                 Additional consecutive good readings
+                                       required after the first two (u16).
+       ti,pendown-gpio-debounce        Platform specific debounce time for the
+                                       pendown-gpio (u32).
+       pendown-gpio                    GPIO handle describing the pin the !PENIRQ
+                                       line is connected to.
+       linux,wakeup                    use any event on touchscreen as wakeup event.
+
+
+Example for a TSC2046 chip connected to an McSPI controller of an OMAP SoC::
+
+       spi_controller {
+               tsc2046@0 {
+                       reg = <0>;      /* CS0 */
+                       compatible = "ti,tsc2046";
+                       interrupt-parent = <&gpio1>;
+                       interrupts = <8 0>;     /* BOOT6 / GPIO 8 */
+                       spi-max-frequency = <1000000>;
+                       pendown-gpio = <&gpio1 8 0>;
+                       vcc-supply = <&reg_vcc3>;
+
+                       ti,x-min = /bits/ 16 <0>;
+                       ti,x-max = /bits/ 16 <8000>;
+                       ti,y-min = /bits/ 16 <0>;
+                       ti,y-max = /bits/ 16 <4800>;
+                       ti,x-plate-ohms = /bits/ 16 <40>;
+                       ti,pressure-max = /bits/ 16 <255>;
+
+                       linux,wakeup;
+               };
+       };
diff --git a/Documentation/devicetree/bindings/input/touchscreen/ti-tsc-adc.txt b/Documentation/devicetree/bindings/input/touchscreen/ti-tsc-adc.txt
new file mode 100644 (file)
index 0000000..491c97b
--- /dev/null
@@ -0,0 +1,44 @@
+* TI - TSC ADC (Touschscreen and analog digital converter)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Required properties:
+- child "tsc"
+       ti,wires: Wires refer to application modes i.e. 4/5/8 wire touchscreen
+                 support on the platform.
+       ti,x-plate-resistance: X plate resistance
+       ti,coordiante-readouts: The sequencer supports a total of 16
+                               programmable steps each step is used to
+                               read a single coordinate. A single
+                                readout is enough but multiple reads can
+                               increase the quality.
+                               A value of 5 means, 5 reads for X, 5 for
+                               Y and 2 for Z (always). This utilises 12
+                               of the 16 software steps available. The
+                               remaining 4 can be used by the ADC.
+       ti,wire-config: Different boards could have a different order for
+                       connecting wires on touchscreen. We need to provide an
+                       8 bit number where in the 1st four bits represent the
+                       analog lines and the next 4 bits represent positive/
+                       negative terminal on that input line. Notations to
+                       represent the input lines and terminals resoectively
+                       is as follows:
+                       AIN0 = 0, AIN1 = 1 and so on till AIN7 = 7.
+                       XP  = 0, XN = 1, YP = 2, YN = 3.
+- child "adc"
+       ti,adc-channels: List of analog inputs available for ADC.
+                        AIN0 = 0, AIN1 = 1 and so on till AIN7 = 7.
+
+Example:
+       tscadc: tscadc@44e0d000 {
+               compatible = "ti,am3359-tscadc";
+               tsc {
+                       ti,wires = <4>;
+                       ti,x-plate-resistance = <200>;
+                       ti,coordiante-readouts = <5>;
+                       ti,wire-config = <0x00 0x11 0x22 0x33>;
+               };
+
+               adc {
+                       ti,adc-channels = <4 5 6 7>;
+               };
+       }
diff --git a/Documentation/devicetree/bindings/iommu/arm,smmu.txt b/Documentation/devicetree/bindings/iommu/arm,smmu.txt
new file mode 100644 (file)
index 0000000..e34c6cd
--- /dev/null
@@ -0,0 +1,70 @@
+* ARM System MMU Architecture Implementation
+
+ARM SoCs may contain an implementation of the ARM System Memory
+Management Unit Architecture, which can be used to provide 1 or 2 stages
+of address translation to bus masters external to the CPU.
+
+The SMMU may also raise interrupts in response to various fault
+conditions.
+
+** System MMU required properties:
+
+- compatible    : Should be one of:
+
+                        "arm,smmu-v1"
+                        "arm,smmu-v2"
+                        "arm,mmu-400"
+                        "arm,mmu-500"
+
+                  depending on the particular implementation and/or the
+                  version of the architecture implemented.
+
+- reg           : Base address and size of the SMMU.
+
+- #global-interrupts : The number of global interrupts exposed by the
+                       device.
+
+- interrupts    : Interrupt list, with the first #global-irqs entries
+                  corresponding to the global interrupts and any
+                  following entries corresponding to context interrupts,
+                  specified in order of their indexing by the SMMU.
+
+                  For SMMUv2 implementations, there must be exactly one
+                  interrupt per context bank. In the case of a single,
+                  combined interrupt, it must be listed multiple times.
+
+- mmu-masters   : A list of phandles to device nodes representing bus
+                  masters for which the SMMU can provide a translation
+                  and their corresponding StreamIDs (see example below).
+                  Each device node linked from this list must have a
+                  "#stream-id-cells" property, indicating the number of
+                  StreamIDs associated with it.
+
+** System MMU optional properties:
+
+- smmu-parent   : When multiple SMMUs are chained together, this
+                  property can be used to provide a phandle to the
+                  parent SMMU (that is the next SMMU on the path going
+                  from the mmu-masters towards memory) node for this
+                  SMMU.
+
+Example:
+
+        smmu {
+                compatible = "arm,smmu-v1";
+                reg = <0xba5e0000 0x10000>;
+                #global-interrupts = <2>;
+                interrupts = <0 32 4>,
+                             <0 33 4>,
+                             <0 34 4>, /* This is the first context interrupt */
+                             <0 35 4>,
+                             <0 36 4>,
+                             <0 37 4>;
+
+                /*
+                 * Two DMA controllers, the first with two StreamIDs (0xd01d
+                 * and 0xd01e) and the second with only one (0xd11c).
+                 */
+                mmu-masters = <&dma0 0xd01d 0xd01e>,
+                              <&dma1 0xd11c>;
+        };
index de9f6b7..0bf6fb7 100644 (file)
@@ -2,8 +2,10 @@ Exynos4x12/Exynos5 SoC series camera host interface (FIMC-LITE)
 
 Required properties:
 
-- compatible   : should be "samsung,exynos4212-fimc-lite" for Exynos4212 and
-                 Exynos4412 SoCs;
+- compatible   : should be one of:
+                 "samsung,exynos4212-fimc-lite" for Exynos4212/4412 SoCs,
+                 "samsung,exynos5250-fimc-lite" for Exynos5250 compatible
+                  devices;
 - reg          : physical base address and size of the device memory mapped
                  registers;
 - interrupts   : should contain FIMC-LITE interrupt;
diff --git a/Documentation/devicetree/bindings/media/i2c/mt9p031.txt b/Documentation/devicetree/bindings/media/i2c/mt9p031.txt
new file mode 100644 (file)
index 0000000..cb60443
--- /dev/null
@@ -0,0 +1,40 @@
+* Aptina 1/2.5-Inch 5Mp CMOS Digital Image Sensor
+
+The Aptina MT9P031 is a 1/2.5-inch CMOS active pixel digital image sensor with
+an active array size of 2592H x 1944V. It is programmable through a simple
+two-wire serial interface.
+
+Required Properties:
+- compatible: value should be either one among the following
+       (a) "aptina,mt9p031" for mt9p031 sensor
+       (b) "aptina,mt9p031m" for mt9p031m sensor
+
+- input-clock-frequency: Input clock frequency.
+
+- pixel-clock-frequency: Pixel clock frequency.
+
+Optional Properties:
+- reset-gpios: Chip reset GPIO
+
+For further reading on port node refer to
+Documentation/devicetree/bindings/media/video-interfaces.txt.
+
+Example:
+
+       i2c0@1c22000 {
+               ...
+               ...
+               mt9p031@5d {
+                       compatible = "aptina,mt9p031";
+                       reg = <0x5d>;
+                       reset-gpios = <&gpio3 30 0>;
+
+                       port {
+                               mt9p031_1: endpoint {
+                                       input-clock-frequency = <6000000>;
+                                       pixel-clock-frequency = <96000000>;
+                               };
+                       };
+               };
+               ...
+       };
diff --git a/Documentation/devicetree/bindings/media/i2c/tvp514x.txt b/Documentation/devicetree/bindings/media/i2c/tvp514x.txt
new file mode 100644 (file)
index 0000000..46752cc
--- /dev/null
@@ -0,0 +1,44 @@
+* Texas Instruments TVP514x video decoder
+
+The TVP5146/TVP5146m2/TVP5147/TVP5147m1 device is high quality, single-chip
+digital video decoder that digitizes and decodes all popular baseband analog
+video formats into digital video component. The tvp514x decoder supports analog-
+to-digital (A/D) conversion of component RGB and YPbPr signals as well as A/D
+conversion and decoding of NTSC, PAL and SECAM composite and S-video into
+component YCbCr.
+
+Required Properties :
+- compatible : value should be either one among the following
+       (a) "ti,tvp5146" for tvp5146 decoder.
+       (b) "ti,tvp5146m2" for tvp5146m2 decoder.
+       (c) "ti,tvp5147" for tvp5147 decoder.
+       (d) "ti,tvp5147m1" for tvp5147m1 decoder.
+
+- hsync-active: HSYNC Polarity configuration for endpoint.
+
+- vsync-active: VSYNC Polarity configuration for endpoint.
+
+- pclk-sample: Clock polarity of the endpoint.
+
+For further reading on port node refer to Documentation/devicetree/bindings/
+media/video-interfaces.txt.
+
+Example:
+
+       i2c0@1c22000 {
+               ...
+               ...
+               tvp514x@5c {
+                       compatible = "ti,tvp5146";
+                       reg = <0x5c>;
+
+                       port {
+                               tvp514x_1: endpoint {
+                                       hsync-active = <1>;
+                                       vsync-active = <1>;
+                                       pclk-sample = <0>;
+                               };
+                       };
+               };
+               ...
+       };
index 51c776b..96312f6 100644 (file)
@@ -127,22 +127,22 @@ Example:
                                };
                        };
                };
-       };
 
-       /* MIPI CSI-2 bus IF sensor */
-       s5c73m3: sensor@0x1a {
-               compatible = "samsung,s5c73m3";
-               reg = <0x1a>;
-               vddio-supply = <...>;
+               /* MIPI CSI-2 bus IF sensor */
+               s5c73m3: sensor@0x1a {
+                       compatible = "samsung,s5c73m3";
+                       reg = <0x1a>;
+                       vddio-supply = <...>;
 
-               clock-frequency = <24000000>;
-               clocks = <...>;
-               clock-names = "mclk";
+                       clock-frequency = <24000000>;
+                       clocks = <...>;
+                       clock-names = "mclk";
 
-               port {
-                       s5c73m3_1: endpoint {
-                               data-lanes = <1 2 3 4>;
-                               remote-endpoint = <&csis0_ep>;
+                       port {
+                               s5c73m3_1: endpoint {
+                                       data-lanes = <1 2 3 4>;
+                                       remote-endpoint = <&csis0_ep>;
+                               };
                        };
                };
        };
index 5f8e28e..be45f0b 100644 (file)
@@ -5,8 +5,8 @@ Required properties:
 
 - compatible     : "samsung,s5pv210-csis" for S5PV210 (S5PC110),
                    "samsung,exynos4210-csis" for Exynos4210 (S5PC210),
-                   "samsung,exynos4212-csis" for Exynos4212/Exynos4412
-                   SoC series;
+                   "samsung,exynos4212-csis" for Exynos4212/Exynos4412,
+                   "samsung,exynos5250-csis" for Exynos5250;
 - reg            : offset and length of the register set for the device;
 - interrupts      : should contain MIPI CSIS interrupt; the format of the
                    interrupt specifier depends on the interrupt controller;
diff --git a/Documentation/devicetree/bindings/media/sh_mobile_ceu.txt b/Documentation/devicetree/bindings/media/sh_mobile_ceu.txt
new file mode 100644 (file)
index 0000000..1ce4e46
--- /dev/null
@@ -0,0 +1,18 @@
+Bindings, specific for the sh_mobile_ceu_camera.c driver:
+ - compatible: Should be "renesas,sh-mobile-ceu"
+ - reg: register base and size
+ - interrupts: the interrupt number
+ - interrupt-parent: the interrupt controller
+ - renesas,max-width: maximum image width, supported on this SoC
+ - renesas,max-height: maximum image height, supported on this SoC
+
+Example:
+
+ceu0: ceu@0xfe910000 {
+       compatible = "renesas,sh-mobile-ceu";
+       reg = <0xfe910000 0xa0>;
+       interrupt-parent = <&intcs>;
+       interrupts = <0x880>;
+       renesas,max-width = <8188>;
+       renesas,max-height = <8188>;
+};
diff --git a/Documentation/devicetree/bindings/mfd/max8998.txt b/Documentation/devicetree/bindings/mfd/max8998.txt
new file mode 100644 (file)
index 0000000..23a3650
--- /dev/null
@@ -0,0 +1,119 @@
+* Maxim MAX8998, National/TI LP3974 multi-function device
+
+The Maxim MAX8998 is a multi-function device which includes voltage/current
+regulators, real time clock, battery charging controller and several
+other sub-blocks. It is interfaced using an I2C interface. Each sub-block
+is addressed by the host system using different i2c slave address.
+
+PMIC sub-block
+--------------
+
+The PMIC sub-block contains a number of voltage and current regulators,
+with controllable parameters and dynamic voltage scaling capability.
+In addition, it includes a real time clock and battery charging controller
+as well. It is accessible at I2C address 0x66.
+
+Required properties:
+- compatible: Should be one of the following:
+    - "maxim,max8998" for Maxim MAX8998
+    - "national,lp3974" or "ti,lp3974" for National/TI LP3974.
+- reg: Specifies the i2c slave address of the pmic block. It should be 0x66.
+
+Optional properties:
+- interrupt-parent: Specifies the phandle of the interrupt controller to which
+  the interrupts from MAX8998 are routed to.
+- interrupts: Interrupt specifiers for two interrupt sources.
+  - First interrupt specifier is for main interrupt.
+  - Second interrupt specifier is for power-on/-off interrupt.
+- max8998,pmic-buck1-dvs-gpios: GPIO specifiers for two host gpios used
+  for buck 1 dvs. The format of the gpio specifier depends on the gpio
+  controller.
+- max8998,pmic-buck2-dvs-gpio: GPIO specifier for host gpio used
+  for buck 2 dvs. The format of the gpio specifier depends on the gpio
+  controller.
+- max8998,pmic-buck1-default-dvs-idx: Default voltage setting selected from
+  the possible 4 options selectable by the dvs gpios. The value of this
+  property should be 0, 1, 2 or 3. If not specified or out of range,
+  a default value of 0 is taken.
+- max8998,pmic-buck2-default-dvs-idx: Default voltage setting selected from
+  the possible 2 options selectable by the dvs gpios. The value of this
+  property should be 0 or 1. If not specified or out of range, a default
+  value of 0 is taken.
+- max8998,pmic-buck-voltage-lock: If present, disallows changing of
+  preprogrammed buck dvfs voltages.
+
+Additional properties required if max8998,pmic-buck1-dvs-gpios is defined:
+- max8998,pmic-buck1-dvs-voltage: An array of 4 voltage values in microvolts
+  for buck1 regulator that can be selected using dvs gpio.
+
+Additional properties required if max8998,pmic-buck2-dvs-gpio is defined:
+- max8998,pmic-buck2-dvs-voltage: An array of 2 voltage values in microvolts
+  for buck2 regulator that can be selected using dvs gpio.
+
+Regulators: All the regulators of MAX8998 to be instantiated shall be
+listed in a child node named 'regulators'. Each regulator is represented
+by a child node of the 'regulators' node.
+
+       regulator-name {
+               /* standard regulator bindings here */
+       };
+
+Following regulators of the MAX8998 PMIC block are supported. Note that
+the 'n' in regulator name, as in LDOn or BUCKn, represents the LDO or BUCK
+number as described in MAX8998 datasheet.
+
+       - LDOn
+                 - valid values for n are 2 to 17
+                 - Example: LDO2, LDO10, LDO17
+       - BUCKn
+                 - valid values for n are 1 to 4.
+                 - Example: BUCK1, BUCK2, BUCK3, BUCK4
+
+       - ENVICHG: Battery Charging Current Monitor Output. This is a fixed
+                  voltage type regulator
+
+       - ESAFEOUT1: (ldo19)
+       - ESAFEOUT2: (ld020)
+
+Standard regulator bindings are used inside regulator subnodes. Check
+  Documentation/devicetree/bindings/regulator/regulator.txt
+for more details.
+
+Example:
+
+       pmic@66 {
+               compatible = "maxim,max8998-pmic";
+               reg = <0x66>;
+               interrupt-parent = <&wakeup_eint>;
+               interrupts = <4 0>, <3 0>;
+
+               /* Buck 1 DVS settings */
+               max8998,pmic-buck1-default-dvs-idx = <0>;
+               max8998,pmic-buck1-dvs-gpios = <&gpx0 0 1 0 0>, /* SET1 */
+                                              <&gpx0 1 1 0 0>; /* SET2 */
+               max8998,pmic-buck1-dvs-voltage = <1350000>, <1300000>,
+                                                <1000000>, <950000>;
+
+               /* Buck 2 DVS settings */
+               max8998,pmic-buck2-default-dvs-idx = <0>;
+               max8998,pmic-buck2-dvs-gpio = <&gpx0 0 3 0 0>; /* SET3 */
+               max8998,pmic-buck2-dvs-voltage = <1350000>, <1300000>;
+
+               /* Regulators to instantiate */
+               regulators {
+                       ldo2_reg: LDO2 {
+                               regulator-name = "VDD_ALIVE_1.1V";
+                               regulator-min-microvolt = <1100000>;
+                               regulator-max-microvolt = <1100000>;
+                               regulator-always-on;
+                       };
+
+                       buck1_reg: BUCK1 {
+                               regulator-name = "VDD_ARM_1.2V";
+                               regulator-min-microvolt = <950000>;
+                               regulator-max-microvolt = <1350000>;
+                               regulator-always-on;
+                               regulator-boot-on;
+                       };
+               };
+       };
diff --git a/Documentation/devicetree/bindings/mfd/twl4030-power.txt b/Documentation/devicetree/bindings/mfd/twl4030-power.txt
new file mode 100644 (file)
index 0000000..8e15ec3
--- /dev/null
@@ -0,0 +1,28 @@
+Texas Instruments TWL family (twl4030) reset and power management module
+
+The power management module inside the TWL family provides several facilities
+to control the power resources, including power scripts. For now, the
+binding only supports the complete shutdown of the system after poweroff.
+
+Required properties:
+- compatible : must be "ti,twl4030-power"
+
+Optional properties:
+- ti,use_poweroff: With this flag, the chip will initiates an ACTIVE-to-OFF or
+                  SLEEP-to-OFF transition when the system poweroffs.
+
+Example:
+&i2c1 {
+       clock-frequency = <2600000>;
+
+       twl: twl@48 {
+               reg = <0x48>;
+               interrupts = <7>; /* SYS_NIRQ cascaded to intc */
+               interrupt-parent = <&intc>;
+
+               twl_power: power {
+                       compatible = "ti,twl4030-power";
+                       ti,use_poweroff;
+               };
+       };
+};
index 85aada2..458b57f 100644 (file)
@@ -28,6 +28,7 @@ Optional properties:
 - cap-mmc-highspeed: MMC high-speed timing is supported
 - cap-power-off-card: powering off the card is safe
 - cap-sdio-irq: enable SDIO IRQ signalling on this interface
+- full-pwr-cycle: full power cycle of the card is supported
 
 *NOTE* on CD and WP polarity. To use common for all SD/MMC host controllers line
 polarity properties, we have to fix the meaning of the "normal" and "inverted"
diff --git a/Documentation/devicetree/bindings/mmc/rockchip-dw-mshc.txt b/Documentation/devicetree/bindings/mmc/rockchip-dw-mshc.txt
new file mode 100644 (file)
index 0000000..8a3d91d
--- /dev/null
@@ -0,0 +1,23 @@
+* Rockchip 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 synopsis-dw-mshc.txt and the properties used by the Rockchip specific
+extensions to the Synopsis Designware Mobile Storage Host Controller.
+
+Required Properties:
+
+* compatible: should be
+       - "rockchip,rk2928-dw-mshc": for Rockchip RK2928 and following
+
+Example:
+
+       rkdwmmc0@12200000 {
+               compatible = "rockchip,rk2928-dw-mshc";
+               reg = <0x12200000 0x1000>;
+               interrupts = <0 75 0>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+       };
index 1180d78..cdcebea 100644 (file)
@@ -39,6 +39,19 @@ Required Properties:
 
 Optional properties:
 
+* clocks: from common clock binding: handle to biu and ciu clocks for the
+  bus interface unit clock and the card interface unit clock.
+
+* clock-names: from common clock binding: Shall be "biu" and "ciu".
+  If the biu clock is missing we'll simply skip enabling it.  If the
+  ciu clock is missing we'll just assume that the clock is running at
+  clock-frequency.  It is an error to omit both the ciu clock and the
+  clock-frequency.
+
+* clock-frequency: should be the frequency (in Hz) of the ciu clock.  If this
+  is specified and the ciu clock is specified then we'll try to set the ciu
+  clock to this at probe time.
+
 * 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
@@ -55,6 +68,9 @@ Optional properties:
 
 * broken-cd: as documented in mmc core bindings.
 
+* vmmc-supply: The phandle to the regulator to use for vmmc.  If this is
+  specified we'll defer probe until we can find this regulator.
+
 Aliases:
 
 - All the MSHC controller nodes should be represented in the aliases node using
@@ -67,6 +83,8 @@ board specific portions as listed below.
 
        dwmmc0@12200000 {
                compatible = "snps,dw-mshc";
+               clocks = <&clock 351>, <&clock 132>;
+               clock-names = "biu", "ciu";
                reg = <0x12200000 0x1000>;
                interrupts = <0 75 0>;
                #address-cells = <1>;
@@ -74,11 +92,13 @@ board specific portions as listed below.
        };
 
        dwmmc0@12200000 {
+               clock-frequency = <400000000>;
                num-slots = <1>;
                supports-highspeed;
                broken-cd;
                fifo-depth = <0x80>;
                card-detect-delay = <200>;
+               vmmc-supply = <&buck8>;
 
                slot@0 {
                        reg = <0>;
diff --git a/Documentation/devicetree/bindings/power_supply/lp8727_charger.txt b/Documentation/devicetree/bindings/power_supply/lp8727_charger.txt
new file mode 100644 (file)
index 0000000..2246bc5
--- /dev/null
@@ -0,0 +1,44 @@
+Binding for TI/National Semiconductor LP8727 Charger
+
+Required properties:
+- compatible: "ti,lp8727"
+- reg: I2C slave address 27h
+
+Optional properties:
+- interrupt-parent: interrupt controller node (see interrupt binding[0])
+- interrupts: interrupt specifier (see interrupt binding[0])
+- debounce-ms: interrupt debounce time. (u32)
+
+AC and USB charging parameters
+- charger-type: "ac" or "usb" (string)
+- eoc-level: value of 'enum lp8727_eoc_level' (u8)
+- charging-current: value of 'enum lp8727_ichg' (u8)
+
+[0]: Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
+
+Example)
+
+lp8727@27 {
+       compatible = "ti,lp8727";
+       reg = <0x27>;
+
+       /* GPIO 134 is used for LP8728 interrupt pin */
+       interrupt-parent = <&gpio5>;    /* base = 128 */
+       interrupts = <6 0x2>;           /* offset = 6, falling edge type */
+
+       debounce-ms = <300>;
+
+       /* AC charger: 5% EOC and 500mA charging current */
+       ac {
+               charger-type = "ac";
+               eoc-level = /bits/ 8 <0>;
+               charging-current = /bits/ 8 <4>;
+       };
+
+       /* USB charger: 10% EOC and 400mA charging current */
+       usb {
+               charger-type = "usb";
+               eoc-level = /bits/ 8 <1>;
+               charging-current = /bits/ 8 <2>;
+       };
+};
diff --git a/Documentation/devicetree/bindings/pwm/nxp,pca9685-pwm.txt b/Documentation/devicetree/bindings/pwm/nxp,pca9685-pwm.txt
new file mode 100644 (file)
index 0000000..1e3dfe7
--- /dev/null
@@ -0,0 +1,27 @@
+NXP PCA9685 16-channel 12-bit PWM LED controller
+================================================
+
+Required properties:
+  - compatible: "nxp,pca9685-pwm"
+  - #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.
+    The index 16 is the ALLCALL channel, that sets all PWM channels at the same
+    time.
+
+Optional properties:
+  - invert (bool): boolean to enable inverted logic
+  - open-drain (bool): boolean to configure outputs with open-drain structure;
+                      if omitted use totem-pole structure
+
+Example:
+
+For LEDs that are directly connected to the PCA, the following setting is
+applicable:
+
+pca: pca@41 {
+       compatible = "nxp,pca9685-pwm";
+       #pwm-cells = <2>;
+       reg = <0x41>;
+       invert;
+       open-drain;
+};
index 9e5e51d..5c186a7 100644 (file)
@@ -1,6 +1,6 @@
 * Maxim MAX8997 Voltage and Current Regulator
 
-The Maxim MAX8997 is a multi-function device which includes volatage and
+The Maxim MAX8997 is a multi-function device which includes voltage and
 current regulators, rtc, charger controller and other sub-blocks. It is
 interfaced to the host controller using a i2c interface. Each sub-block is
 addressed by the host system using different i2c slave address. This document
index a35ff99..d1660a9 100644 (file)
@@ -1,6 +1,6 @@
 * Samsung S5M8767 Voltage and Current Regulator
 
-The Samsung S5M8767 is a multi-function device which includes volatage and
+The Samsung S5M8767 is a multi-function device which includes voltage and
 current regulators, rtc, charger controller and other sub-blocks. It is
 interfaced to the host controller using a i2c interface. Each sub-block is
 addressed by the host system using different i2c slave address. This document
@@ -103,13 +103,13 @@ Example:
 
                s5m8767,pmic-buck-default-dvs-idx = <0>;
 
-               s5m8767,pmic-buck-dvs-gpios = <&gpx0 0 1 0 0>, /* DVS1 */
-                                                <&gpx0 1 1 0 0>, /* DVS2 */
-                                                <&gpx0 2 1 0 0>; /* DVS3 */
+               s5m8767,pmic-buck-dvs-gpios = <&gpx0 0 0>, /* DVS1 */
+                                                <&gpx0 1 0>, /* DVS2 */
+                                                <&gpx0 2 0>; /* DVS3 */
 
-               s5m8767,pmic-buck-ds-gpios = <&gpx2 3 1 0 0>, /* SET1 */
-                                               <&gpx2 4 1 0 0>, /* SET2 */
-                                               <&gpx2 5 1 0 0>; /* SET3 */
+               s5m8767,pmic-buck-ds-gpios = <&gpx2 3 0>, /* SET1 */
+                                               <&gpx2 4 0>, /* SET2 */
+                                               <&gpx2 5 0>; /* SET3 */
 
                s5m8767,pmic-buck2-dvs-voltage = <1350000>, <1300000>,
                                                 <1250000>, <1200000>,
index 658749b..75b0c16 100644 (file)
@@ -18,20 +18,20 @@ For twl6030 regulators/LDOs
   - "ti,twl6030-vdd1" for VDD1 SMPS
   - "ti,twl6030-vdd2" for VDD2 SMPS
   - "ti,twl6030-vdd3" for VDD3 SMPS
-For twl6025 regulators/LDOs
+For twl6032 regulators/LDOs
 - compatible:
-  - "ti,twl6025-ldo1" for LDO1 LDO
-  - "ti,twl6025-ldo2" for LDO2 LDO
-  - "ti,twl6025-ldo3" for LDO3 LDO
-  - "ti,twl6025-ldo4" for LDO4 LDO
-  - "ti,twl6025-ldo5" for LDO5 LDO
-  - "ti,twl6025-ldo6" for LDO6 LDO
-  - "ti,twl6025-ldo7" for LDO7 LDO
-  - "ti,twl6025-ldoln" for LDOLN LDO
-  - "ti,twl6025-ldousb" for LDOUSB LDO
-  - "ti,twl6025-smps3" for SMPS3 SMPS
-  - "ti,twl6025-smps4" for SMPS4 SMPS
-  - "ti,twl6025-vio" for VIO SMPS
+  - "ti,twl6032-ldo1" for LDO1 LDO
+  - "ti,twl6032-ldo2" for LDO2 LDO
+  - "ti,twl6032-ldo3" for LDO3 LDO
+  - "ti,twl6032-ldo4" for LDO4 LDO
+  - "ti,twl6032-ldo5" for LDO5 LDO
+  - "ti,twl6032-ldo6" for LDO6 LDO
+  - "ti,twl6032-ldo7" for LDO7 LDO
+  - "ti,twl6032-ldoln" for LDOLN LDO
+  - "ti,twl6032-ldousb" for LDOUSB LDO
+  - "ti,twl6032-smps3" for SMPS3 SMPS
+  - "ti,twl6032-smps4" for SMPS4 SMPS
+  - "ti,twl6032-vio" for VIO SMPS
 For twl4030 regulators/LDOs
 - compatible:
   - "ti,twl4030-vaux1" for VAUX1 LDO
@@ -17,8 +17,9 @@ Required properties:
 - interrupts : this entry should indicate which interrupt line
 the talert signal is routed to;
 Specific:
-- ti,tshut-gpio : this entry should be used to inform which GPIO
-line the tshut signal is routed to;
+- gpios : this entry should be used to inform which GPIO
+line the tshut signal is routed to. The informed GPIO will
+be treated as an IRQ;
 - regs : this entry must also be specified and it is specific
 to each bandgap version, because the mapping may change from
 soc to soc, apart of depending on available features.
@@ -37,7 +38,7 @@ bandgap {
                0x4a002378 0x18>;
        compatible = "ti,omap4460-bandgap";
        interrupts = <0 126 4>; /* talert */
-       ti,tshut-gpio = <86>;
+       gpios = <&gpio3 22 0>; /* tshut */
 };
 
 OMAP4470:
@@ -47,7 +48,7 @@ bandgap {
                0x4a002378 0x18>;
        compatible = "ti,omap4470-bandgap";
        interrupts = <0 126 4>; /* talert */
-       ti,tshut-gpio = <86>;
+       gpios = <&gpio3 22 0>; /* tshut */
 };
 
 OMAP5430:
@@ -59,3 +60,15 @@ bandgap {
        compatible = "ti,omap5430-bandgap";
        interrupts = <0 126 4>; /* talert */
 };
+
+DRA752:
+bandgap {
+       reg = <0x4a0021e0 0xc
+               0x4a00232c 0xc
+               0x4a002380 0x2c
+               0x4a0023C0 0x3c
+               0x4a002564 0x8
+               0x4a002574 0x50>;
+       compatible = "ti,dra752-bandgap";
+       interrupts = <0 126 4>; /* talert */
+};
diff --git a/Documentation/devicetree/bindings/timer/marvell,orion-timer.txt b/Documentation/devicetree/bindings/timer/marvell,orion-timer.txt
new file mode 100644 (file)
index 0000000..62bb826
--- /dev/null
@@ -0,0 +1,17 @@
+Marvell Orion SoC timer
+
+Required properties:
+- compatible: shall be "marvell,orion-timer"
+- reg: base address of the timer register starting with TIMERS CONTROL register
+- interrupt-parent: phandle of the bridge interrupt controller
+- interrupts: should contain the interrupts for Timer0 and Timer1
+- clocks: phandle of timer reference clock (tclk)
+
+Example:
+       timer: timer {
+               compatible = "marvell,orion-timer";
+               reg = <0x20300 0x20>;
+               interrupt-parent = <&bridge_intc>;
+               interrupts = <1>, <2>;
+               clocks = <&core_clk 0>;
+       };
index 36b9aed..0aee0ad 100644 (file)
@@ -8,7 +8,7 @@ TWL6030 USB COMPARATOR
    usb interrupt number that raises VBUS interrupts when the controller has to
    act as device
  - usb-supply : phandle to the regulator device tree node. It should be vusb
-   if it is twl6030 or ldousb if it is twl6025 subclass.
+   if it is twl6030 or ldousb if it is twl6032 subclass.
 
 twl6030-usb {
        compatible = "ti,twl6030-usb";
index d209366..f801d71 100644 (file)
@@ -5,9 +5,14 @@ Required properties:
 - compatible : should be "brcm,bcm2835-pm-wdt"
 - reg : Specifies base physical address and size of the registers.
 
+Optional properties:
+
+- timeout-sec   : Contains the watchdog timeout in seconds
+
 Example:
 
 watchdog {
        compatible = "brcm,bcm2835-pm-wdt";
        reg = <0x7e100000 0x28>;
+       timeout-sec = <10>;
 };
index 83577f0..12525b1 100644 (file)
@@ -18,6 +18,8 @@ Mount Options
 =============
 
 When mounting an XFS filesystem, the following options are accepted.
+For boolean mount options, the names with the (*) suffix is the
+default behaviour.
 
   allocsize=size
        Sets the buffered I/O end-of-file preallocation size when
@@ -25,97 +27,128 @@ When mounting an XFS filesystem, the following options are accepted.
        Valid values for this option are page size (typically 4KiB)
        through to 1GiB, inclusive, in power-of-2 increments.
 
-  attr2/noattr2
-       The options enable/disable (default is disabled for backward
-       compatibility on-disk) an "opportunistic" improvement to be
-       made in the way inline extended attributes are stored on-disk.
-       When the new form is used for the first time (by setting or
-       removing extended attributes) the on-disk superblock feature
-       bit field will be updated to reflect this format being in use.
+       The default behaviour is for dynamic end-of-file
+       preallocation size, which uses a set of heuristics to
+       optimise the preallocation size based on the current
+       allocation patterns within the file and the access patterns
+       to the file. Specifying a fixed allocsize value turns off
+       the dynamic behaviour.
+
+  attr2
+  noattr2
+       The options enable/disable an "opportunistic" improvement to
+       be made in the way inline extended attributes are stored
+       on-disk.  When the new form is used for the first time when
+       attr2 is selected (either when setting or removing extended
+       attributes) the on-disk superblock feature bit field will be
+       updated to reflect this format being in use.
+
+       The default behaviour is determined by the on-disk feature
+       bit indicating that attr2 behaviour is active. If either
+       mount option it set, then that becomes the new default used
+       by the filesystem.
 
        CRC enabled filesystems always use the attr2 format, and so
        will reject the noattr2 mount option if it is set.
 
-  barrier
-       Enables the use of block layer write barriers for writes into
-       the journal and unwritten extent conversion.  This allows for
-       drive level write caching to be enabled, for devices that
-       support write barriers.
+  barrier (*)
+  nobarrier
+       Enables/disables the use of block layer write barriers for
+       writes into the journal and for data integrity operations.
+       This allows for drive level write caching to be enabled, for
+       devices that support write barriers.
 
   discard
-       Issue command to let the block device reclaim space freed by the
-       filesystem.  This is useful for SSD devices, thinly provisioned
-       LUNs and virtual machine images, but may have a performance
-       impact.
-
-  dmapi
-       Enable the DMAPI (Data Management API) event callouts.
-       Use with the "mtpt" option.
-
-  grpid/bsdgroups and nogrpid/sysvgroups
-       These options define what group ID a newly created file gets.
-       When grpid is set, it takes the group ID of the directory in
-       which it is created; otherwise (the default) it takes the fsgid
-       of the current process, unless the directory has the setgid bit
-       set, in which case it takes the gid from the parent directory,
-       and also gets the setgid bit set if it is a directory itself.
-
-  ihashsize=value
-       In memory inode hashes have been removed, so this option has
-       no function as of August 2007. Option is deprecated.
-
-  ikeep/noikeep
-       When ikeep is specified, XFS does not delete empty inode clusters
-       and keeps them around on disk. ikeep is the traditional XFS
-       behaviour. When noikeep is specified, empty inode clusters
-       are returned to the free space pool. The default is noikeep for
-       non-DMAPI mounts, while ikeep is the default when DMAPI is in use.
-
-  inode64
-       Indicates that XFS is allowed to create inodes at any location
-       in the filesystem, including those which will result in inode
-       numbers occupying more than 32 bits of significance.  This is
-       the default allocation option. Applications which do not handle
-       inode numbers bigger than 32 bits, should use inode32 option.
+  nodiscard (*)
+       Enable/disable the issuing of commands to let the block
+       device reclaim space freed by the filesystem.  This is
+       useful for SSD devices, thinly provisioned LUNs and virtual
+       machine images, but may have a performance impact.
+
+       Note: It is currently recommended that you use the fstrim
+       application to discard unused blocks rather than the discard
+       mount option because the performance impact of this option
+       is quite severe.
+
+  grpid/bsdgroups
+  nogrpid/sysvgroups (*)
+       These options define what group ID a newly created file
+       gets.  When grpid is set, it takes the group ID of the
+       directory in which it is created; otherwise it takes the
+       fsgid of the current process, unless the directory has the
+       setgid bit set, in which case it takes the gid from the
+       parent directory, and also gets the setgid bit set if it is
+       a directory itself.
+
+  filestreams
+       Make the data allocator use the filestreams allocation mode
+       across the entire filesystem rather than just on directories
+       configured to use it.
+
+  ikeep
+  noikeep (*)
+       When ikeep is specified, XFS does not delete empty inode
+       clusters and keeps them around on disk.  When noikeep is
+       specified, empty inode clusters are returned to the free
+       space pool.
 
   inode32
-       Indicates that XFS is limited to create inodes at locations which
-       will not result in inode numbers with more than 32 bits of
-       significance. This is provided for backwards compatibility, since
-       64 bits inode numbers might cause problems for some applications
-       that cannot handle large inode numbers.
-
-  largeio/nolargeio
+  inode64 (*)
+       When inode32 is specified, it indicates that XFS limits
+       inode creation to locations which will not result in inode
+       numbers with more than 32 bits of significance.
+
+       When inode64 is specified, it indicates that XFS is allowed
+       to create inodes at any location in the filesystem,
+       including those which will result in inode numbers occupying
+       more than 32 bits of significance. 
+
+       inode32 is provided for backwards compatibility with older
+       systems and applications, since 64 bits inode numbers might
+       cause problems for some applications that cannot handle
+       large inode numbers.  If applications are in use which do
+       not handle inode numbers bigger than 32 bits, the inode32
+       option should be specified.
+
+
+  largeio
+  nolargeio (*)
        If "nolargeio" is specified, the optimal I/O reported in
-       st_blksize by stat(2) will be as small as possible to allow user
-       applications to avoid inefficient read/modify/write I/O.
-       If "largeio" specified, a filesystem that has a "swidth" specified
-       will return the "swidth" value (in bytes) in st_blksize. If the
-       filesystem does not have a "swidth" specified but does specify
-       an "allocsize" then "allocsize" (in bytes) will be returned
-       instead.
-       If neither of these two options are specified, then filesystem
-       will behave as if "nolargeio" was specified.
+       st_blksize by stat(2) will be as small as possible to allow
+       user applications to avoid inefficient read/modify/write
+       I/O.  This is typically the page size of the machine, as
+       this is the granularity of the page cache.
+
+       If "largeio" specified, a filesystem that was created with a
+       "swidth" specified will return the "swidth" value (in bytes)
+       in st_blksize. If the filesystem does not have a "swidth"
+       specified but does specify an "allocsize" then "allocsize"
+       (in bytes) will be returned instead. Otherwise the behaviour
+       is the same as if "nolargeio" was specified.
 
   logbufs=value
-       Set the number of in-memory log buffers.  Valid numbers range
-       from 2-8 inclusive.
-       The default value is 8 buffers for filesystems with a
-       blocksize of 64KiB, 4 buffers for filesystems with a blocksize
-       of 32KiB, 3 buffers for filesystems with a blocksize of 16KiB
-       and 2 buffers for all other configurations.  Increasing the
-       number of buffers may increase performance on some workloads
-       at the cost of the memory used for the additional log buffers
-       and their associated control structures.
+       Set the number of in-memory log buffers.  Valid numbers
+       range from 2-8 inclusive.
+
+       The default value is 8 buffers.
+
+       If the memory cost of 8 log buffers is too high on small
+       systems, then it may be reduced at some cost to performance
+       on metadata intensive workloads. The logbsize option below
+       controls the size of each buffer and so is also relevent to
+       this case.
 
   logbsize=value
-       Set the size of each in-memory log buffer.
-       Size may be specified in bytes, or in kilobytes with a "k" suffix.
-       Valid sizes for version 1 and version 2 logs are 16384 (16k) and
-       32768 (32k).  Valid sizes for version 2 logs also include
-       65536 (64k), 131072 (128k) and 262144 (256k).
-       The default value for machines with more than 32MiB of memory
-       is 32768, machines with less memory use 16384 by default.
+       Set the size of each in-memory log buffer.  The size may be
+       specified in bytes, or in kilobytes with a "k" suffix.
+       Valid sizes for version 1 and version 2 logs are 16384 (16k)
+       and 32768 (32k).  Valid sizes for version 2 logs also
+       include 65536 (64k), 131072 (128k) and 262144 (256k). The
+       logbsize must be an integer multiple of the log
+       stripe unit configured at mkfs time.
+
+       The default value for for version 1 logs is 32768, while the
+       default value for version 2 logs is MAX(32768, log_sunit).
 
   logdev=device and rtdev=device
        Use an external log (metadata journal) and/or real-time device.
@@ -124,16 +157,11 @@ When mounting an XFS filesystem, the following options are accepted.
        optional, and the log section can be separate from the data
        section or contained within it.
 
-  mtpt=mountpoint
-       Use with the "dmapi" option.  The value specified here will be
-       included in the DMAPI mount event, and should be the path of
-       the actual mountpoint that is used.
-
   noalign
-       Data allocations will not be aligned at stripe unit boundaries.
-
-  noatime
-       Access timestamps are not updated when a file is read.
+       Data allocations will not be aligned at stripe unit
+       boundaries. This is only relevant to filesystems created
+       with non-zero data alignment parameters (sunit, swidth) by
+       mkfs.
 
   norecovery
        The filesystem will be mounted without running log recovery.
@@ -144,8 +172,14 @@ When mounting an XFS filesystem, the following options are accepted.
        the mount will fail.
 
   nouuid
-       Don't check for double mounted file systems using the file system uuid.
-       This is useful to mount LVM snapshot volumes.
+       Don't check for double mounted file systems using the file
+       system uuid.  This is useful to mount LVM snapshot volumes,
+       and often used in combination with "norecovery" for mounting
+       read-only snapshots.
+
+  noquota
+       Forcibly turns off all quota accounting and enforcement
+       within the filesystem.
 
   uquota/usrquota/uqnoenforce/quota
        User disk quota accounting enabled, and limits (optionally)
@@ -160,24 +194,64 @@ When mounting an XFS filesystem, the following options are accepted.
        enforced.  Refer to xfs_quota(8) for further details.
 
   sunit=value and swidth=value
-       Used to specify the stripe unit and width for a RAID device or
-       a stripe volume.  "value" must be specified in 512-byte block
-       units.
-       If this option is not specified and the filesystem was made on
-       a stripe volume or the stripe width or unit were specified for
-       the RAID device at mkfs time, then the mount system call will
-       restore the value from the superblock.  For filesystems that
-       are made directly on RAID devices, these options can be used
-       to override the information in the superblock if the underlying
-       disk layout changes after the filesystem has been created.
-       The "swidth" option is required if the "sunit" option has been
-       specified, and must be a multiple of the "sunit" value.
+       Used to specify the stripe unit and width for a RAID device
+       or a stripe volume.  "value" must be specified in 512-byte
+       block units. These options are only relevant to filesystems
+       that were created with non-zero data alignment parameters.
+
+       The sunit and swidth parameters specified must be compatible
+       with the existing filesystem alignment characteristics.  In
+       general, that means the only valid changes to sunit are
+       increasing it by a power-of-2 multiple. Valid swidth values
+       are any integer multiple of a valid sunit value.
+
+       Typically the only time these mount options are necessary if
+       after an underlying RAID device has had it's geometry
+       modified, such as adding a new disk to a RAID5 lun and
+       reshaping it.
 
   swalloc
        Data allocations will be rounded up to stripe width boundaries
        when the current end of file is being extended and the file
        size is larger than the stripe width size.
 
+  wsync
+       When specified, all filesystem namespace operations are
+       executed synchronously. This ensures that when the namespace
+       operation (create, unlink, etc) completes, the change to the
+       namespace is on stable storage. This is useful in HA setups
+       where failover must not result in clients seeing
+       inconsistent namespace presentation during or after a
+       failover event.
+
+
+Deprecated Mount Options
+========================
+
+  delaylog/nodelaylog
+       Delayed logging is the only logging method that XFS supports
+       now, so these mount options are now ignored.
+
+       Due for removal in 3.12.
+
+  ihashsize=value
+       In memory inode hashes have been removed, so this option has
+       no function as of August 2007. Option is deprecated.
+
+       Due for removal in 3.12.
+
+  irixsgid
+       This behaviour is now controlled by a sysctl, so the mount
+       option is ignored.
+
+       Due for removal in 3.12.
+
+  osyncisdsync
+  osyncisosync
+       O_SYNC and O_DSYNC are fully supported, so there is no need
+       for these options any more.
+
+       Due for removal in 3.12.
 
 sysctls
 =======
@@ -189,15 +263,20 @@ The following sysctls are available for the XFS filesystem:
        in /proc/fs/xfs/stat.  It then immediately resets to "0".
 
   fs.xfs.xfssyncd_centisecs    (Min: 100  Default: 3000  Max: 720000)
-       The interval at which the xfssyncd thread flushes metadata
-       out to disk.  This thread will flush log activity out, and
-       do some processing on unlinked inodes.
+       The interval at which the filesystem flushes metadata
+       out to disk and runs internal cache cleanup routines.
 
-  fs.xfs.xfsbufd_centisecs     (Min: 50  Default: 100  Max: 3000)
-       The interval at which xfsbufd scans the dirty metadata buffers list.
+  fs.xfs.filestream_centisecs  (Min: 1  Default: 3000  Max: 360000)
+       The interval at which the filesystem ages filestreams cache
+       references and returns timed-out AGs back to the free stream
+       pool.
 
-  fs.xfs.age_buffer_centisecs  (Min: 100  Default: 1500  Max: 720000)
-       The age at which xfsbufd flushes dirty metadata buffers to disk.
+  fs.xfs.speculative_prealloc_lifetime
+               (Units: seconds   Min: 1  Default: 300  Max: 86400)
+       The interval at which the background scanning for inodes
+       with unused speculative preallocation runs. The scan
+       removes unused preallocation from clean inodes and releases
+       the unused space back to the free pool.
 
   fs.xfs.error_level           (Min: 0  Default: 3  Max: 11)
        A volume knob for error reporting when internal errors occur.
@@ -254,9 +333,31 @@ The following sysctls are available for the XFS filesystem:
        by the xfs_io(8) chattr command on a directory to be
        inherited by files in that directory.
 
+  fs.xfs.inherit_nodefrag      (Min: 0  Default: 1  Max: 1)
+       Setting this to "1" will cause the "nodefrag" flag set
+       by the xfs_io(8) chattr command on a directory to be
+       inherited by files in that directory.
+
   fs.xfs.rotorstep             (Min: 1  Default: 1  Max: 256)
        In "inode32" allocation mode, this option determines how many
        files the allocator attempts to allocate in the same allocation
        group before moving to the next allocation group.  The intent
        is to control the rate at which the allocator moves between
        allocation groups when allocating extents for new files.
+
+Deprecated Sysctls
+==================
+
+  fs.xfs.xfsbufd_centisecs     (Min: 50  Default: 100  Max: 3000)
+       Dirty metadata is now tracked by the log subsystem and
+       flushing is driven by log space and idling demands. The
+       xfsbufd no longer exists, so this syctl does nothing.
+
+       Due for removal in 3.14.
+
+  fs.xfs.age_buffer_centisecs  (Min: 100  Default: 1500  Max: 720000)
+       Dirty metadata is now tracked by the log subsystem and
+       flushing is driven by log space and idling demands. The
+       xfsbufd no longer exists, so this syctl does nothing.
+
+       Due for removal in 3.14.
index 213859e..e349f29 100644 (file)
@@ -174,6 +174,19 @@ Searching in menuconfig:
 
                /^hotplug
 
+       When searching, symbols are sorted thus:
+         - exact match first: an exact match is when the search matches
+           the complete symbol name;
+         - alphabetical order: when two symbols do not match exactly,
+           they are sorted in alphabetical order (in the user's current
+           locale).
+       For example: ^ATH.K matches:
+           ATH5K ATH9K ATH5K_AHB ATH5K_DEBUG [...] ATH6KL ATH6KL_DEBUG
+           [...] ATH9K_AHB ATH9K_BTCOEX_SUPPORT ATH9K_COMMON [...]
+       of which only ATH5K and ATH9K match exactly and so are sorted
+       first (and in alphabetical order), then come all other symbols,
+       sorted in alphabetical order.
+
 ______________________________________________________________________
 User interface options for 'menuconfig'
 
index 75236f1..15356ac 100644 (file)
@@ -3081,6 +3081,19 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                        See also Documentation/trace/ftrace.txt "trace options"
                        section.
 
+       traceoff_on_warning
+                       [FTRACE] enable this option to disable tracing when a
+                       warning is hit. This turns off "tracing_on". Tracing can
+                       be enabled again by echoing '1' into the "tracing_on"
+                       file located in /sys/kernel/debug/tracing/
+
+                       This option is useful, as it disables the trace before
+                       the WARNING dump is called, which prevents the trace to
+                       be filled with content caused by the warning output.
+
+                       This option can also be set at run time via the sysctl
+                       option:  kernel/traceoff_on_warning
+
        transparent_hugepage=
                        [KNL]
                        Format: [always|madvise|never]
index eeced24..f552a75 100644 (file)
@@ -265,7 +265,7 @@ connected to another pad through an enabled link
        media_entity_find_link(struct media_pad *source,
                               struct media_pad *sink);
 
-       media_entity_remote_source(struct media_pad *pad);
+       media_entity_remote_pad(struct media_pad *pad);
 
 Refer to the kerneldoc documentation for more information.
 
index dd3cadd..10c7d17 100644 (file)
@@ -78,6 +78,14 @@ Shadow Registers             used by interruption handler code
 TOC enable bit                 1
 
 =========================================================================
+
+The PA-RISC architecture defines 7 registers as "shadow registers".
+Those are used in RETURN FROM INTERRUPTION AND RESTORE instruction to reduce
+the state save and restore time by eliminating the need for general register
+(GR) saves and restores in interruption handlers.
+Shadow registers are the GRs 1, 8, 9, 16, 17, 24, and 25.
+
+=========================================================================
 Register usage notes, originally from John Marvin, with some additional
 notes from Randolph Chung.
 
index 7d2b4c9..1039b68 100644 (file)
@@ -45,6 +45,43 @@ int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns);
 
 To start/stop toggling the PWM output use pwm_enable()/pwm_disable().
 
+Using PWMs with the sysfs interface
+-----------------------------------
+
+If CONFIG_SYSFS is enabled in your kernel configuration a simple sysfs
+interface is provided to use the PWMs from userspace. It is exposed at
+/sys/class/pwm/. Each probed PWM controller/chip will be exported as
+pwmchipN, where N is the base of the PWM chip. Inside the directory you
+will find:
+
+npwm - The number of PWM channels this chip supports (read-only).
+
+export - Exports a PWM channel for use with sysfs (write-only).
+
+unexport - Unexports a PWM channel from sysfs (write-only).
+
+The PWM channels are numbered using a per-chip index from 0 to npwm-1.
+
+When a PWM channel is exported a pwmX directory will be created in the
+pwmchipN directory it is associated with, where X is the number of the
+channel that was exported. The following properties will then be available:
+
+period - The total period of the PWM signal (read/write).
+       Value is in nanoseconds and is the sum of the active and inactive
+       time of the PWM.
+
+duty_cycle - The active time of the PWM signal (read/write).
+       Value is in nanoseconds and must be less than the period.
+
+polarity - Changes the polarity of the PWM signal (read/write).
+       Writes to this property only work if the PWM chip supports changing
+       the polarity. The polarity can only be changed if the PWM is not
+       enabled. Value is the string "normal" or "inversed".
+
+enable - Enable/disable the PWM signal (read/write).
+       0 - disabled
+       1 - enabled
+
 Implementing a PWM driver
 -------------------------
 
index d69e14c..1c15043 100644 (file)
@@ -50,26 +50,27 @@ The maximum number of packets that kernel can handle on a NAPI interrupt,
 it's a Per-CPU variable.
 Default: 64
 
-low_latency_read
+busy_read
 ----------------
 Low latency busy poll timeout for socket reads. (needs CONFIG_NET_LL_RX_POLL)
 Approximate time in us to busy loop waiting for packets on the device queue.
-This sets the default value of the SO_LL socket option.
-Can be set or overridden per socket by setting socket option SO_LL, which is
-the preferred method of enabling.
-If you need to enable the feature globally via sysctl, a value of 50 is recommended.
+This sets the default value of the SO_BUSY_POLL socket option.
+Can be set or overridden per socket by setting socket option SO_BUSY_POLL,
+which is the preferred method of enabling. If you need to enable the feature
+globally via sysctl, a value of 50 is recommended.
 Will increase power usage.
 Default: 0 (off)
 
-low_latency_poll
+busy_poll
 ----------------
 Low latency busy poll timeout for poll and select. (needs CONFIG_NET_LL_RX_POLL)
 Approximate time in us to busy loop waiting for events.
 Recommended value depends on the number of sockets you poll on.
 For several sockets 50, for several hundreds 100.
 For more than that you probably want to use epoll.
-Note that only sockets with SO_LL set will be busy polled, so you want to either
-selectively set SO_LL on those sockets or set sysctl.net.low_latency_read globally.
+Note that only sockets with SO_BUSY_POLL set will be busy polled,
+so you want to either selectively set SO_BUSY_POLL on those sockets or set
+sysctl.net.busy_read globally.
 Will increase power usage.
 Default: 0 (off)
 
diff --git a/Documentation/thermal/x86_pkg_temperature_thermal b/Documentation/thermal/x86_pkg_temperature_thermal
new file mode 100644 (file)
index 0000000..17a3a4c
--- /dev/null
@@ -0,0 +1,47 @@
+Kernel driver: x86_pkg_temp_thermal
+===================
+
+Supported chips:
+* x86: with package level thermal management
+(Verify using: CPUID.06H:EAX[bit 6] =1)
+
+Authors: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
+
+Reference
+---
+Intel® 64 and IA-32 Architectures Software Developer’s Manual (Jan, 2013):
+Chapter 14.6: PACKAGE LEVEL THERMAL MANAGEMENT
+
+Description
+---------
+
+This driver register CPU digital temperature package level sensor as a thermal
+zone with maximum two user mode configurable trip points. Number of trip points
+depends on the capability of the package. Once the trip point is violated,
+user mode can receive notification via thermal notification mechanism and can
+take any action to control temperature.
+
+
+Threshold management
+--------------------
+Each package will register as a thermal zone under /sys/class/thermal.
+Example:
+/sys/class/thermal/thermal_zone1
+
+This contains two trip points:
+- trip_point_0_temp
+- trip_point_1_temp
+
+User can set any temperature between 0 to TJ-Max temperature. Temperature units
+are in milli-degree Celsius. Refer to "Documentation/thermal/sysfs-api.txt" for
+thermal sys-fs details.
+
+Any value other than 0 in these trip points, can trigger thermal notifications.
+Setting 0, stops sending thermal notifications.
+
+Thermal notifications: To get kobject-uevent notifications, set the thermal zone
+policy to "user_space". For example: echo -n "user_space" > policy
+
+
+
+
index bb24c2a..37732a2 100644 (file)
@@ -183,13 +183,22 @@ The relational-operators depend on the type of the field being tested:
 
 The operators available for numeric fields are:
 
-==, !=, <, <=, >, >=
+==, !=, <, <=, >, >=, &
 
 And for string fields they are:
 
-==, !=
+==, !=, ~
 
-Currently, only exact string matches are supported.
+The glob (~) only accepts a wild card character (*) at the start and or
+end of the string. For example:
+
+  prev_comm ~ "*sh"
+  prev_comm ~ "sh*"
+  prev_comm ~ "*sh*"
+
+But does not allow for it to be within the string:
+
+  prev_comm ~ "ba*sh"   <-- is invalid
 
 5.2 Setting filters
 -------------------
index bfe8c29..b937c6e 100644 (file)
@@ -2430,6 +2430,19 @@ The following commands are supported:
    echo '!schedule:disable_event:sched:sched_switch' > \
         set_ftrace_filter
 
+- dump
+  When the function is hit, it will dump the contents of the ftrace
+  ring buffer to the console. This is useful if you need to debug
+  something, and want to dump the trace when a certain function
+  is hit. Perhaps its a function that is called before a tripple
+  fault happens and does not allow you to get a regular dump.
+
+- cpudump
+  When the function is hit, it will dump the contents of the ftrace
+  ring buffer for the current CPU to the console. Unlike the "dump"
+  command, it only prints out the contents of the ring buffer for the
+  CPU that executed the function that triggered the dump.
+
 trace_pipe
 ----------
 
index c55533c..d7993dc 100644 (file)
@@ -172,12 +172,12 @@ group and can access them as follows:
        struct vfio_device_info device_info = { .argsz = sizeof(device_info) };
 
        /* Create a new container */
-       container = open("/dev/vfio/vfio, O_RDWR);
+       container = open("/dev/vfio/vfio", O_RDWR);
 
        if (ioctl(container, VFIO_GET_API_VERSION) != VFIO_API_VERSION)
                /* Unknown API version */
 
-       if (!ioctl(container, VFIO_CHECK_EXTENSION, VFIO_X86_IOMMU))
+       if (!ioctl(container, VFIO_CHECK_EXTENSION, VFIO_TYPE1_IOMMU))
                /* Doesn't support the IOMMU driver we want. */
 
        /* Open the group */
@@ -193,7 +193,7 @@ group and can access them as follows:
        ioctl(group, VFIO_GROUP_SET_CONTAINER, &container);
 
        /* Enable the IOMMU model we want */
-       ioctl(container, VFIO_SET_IOMMU, VFIO_X86_IOMMU)
+       ioctl(container, VFIO_SET_IOMMU, VFIO_TYPE1_IOMMU)
 
        /* Get addition IOMMU info */
        ioctl(container, VFIO_IOMMU_GET_INFO, &iommu_info);
index 581f666..f144750 100644 (file)
 159 -> ProVideo PV183                                      [1830:1540,1831:1540,1832:1540,1833:1540,1834:1540,1835:1540,1836:1540,1837:1540]
 160 -> Tongwei Video Technology TD-3116                    [f200:3116]
 161 -> Aposonic W-DVR                                      [0279:0228]
+162 -> Adlink MPG24
+163 -> Bt848 Capture 14MHz
+164 -> CyberVision CV06 (SV)
index b3ad683..8df17d0 100644 (file)
 189 -> Kworld PC150-U                           [17de:a134]
 190 -> Asus My Cinema PS3-100                   [1043:48cd]
 191 -> Hawell HW-9004V1
+192 -> AverMedia AverTV Satellite Hybrid+FM A706 [1461:2055]
index 5b83a3f..ac88621 100644 (file)
@@ -86,6 +86,6 @@ tuner=85 - Philips FQ1236 MK5
 tuner=86 - Tena TNF5337 MFD
 tuner=87 - Xceive 4000 tuner
 tuner=88 - Xceive 5000C tuner
-tuner=89 - Sony PAL+SECAM (BTF-PG472Z)
-tuner=90 - Sony NTSC-M-JP (BTF-PK467Z)
-tuner=91 - Sony NTSC-M (BTF-PB463Z)
+tuner=89 - Sony BTF-PG472Z PAL/SECAM
+tuner=90 - Sony BTF-PK467Z NTSC-M-JP
+tuner=91 - Sony BTF-PB463Z NTSC-M
index 25f4d34..e51f1b5 100644 (file)
@@ -1,6 +1,6 @@
 Samsung S5P/EXYNOS4 FIMC driver
 
-Copyright (C) 2012 Samsung Electronics Co., Ltd.
+Copyright (C) 2012 - 2013 Samsung Electronics Co., Ltd.
 ---------------------------------------------------------------------------
 
 The FIMC (Fully Interactive Mobile Camera) device available in Samsung
@@ -10,7 +10,7 @@ data from LCD controller (FIMD) through the SoC internal writeback data
 path.  There are multiple FIMC instances in the SoCs (up to 4), having
 slightly different capabilities, like pixel alignment constraints, rotator
 availability, LCD writeback support, etc. The driver is located at
-drivers/media/platform/s5p-fimc directory.
+drivers/media/platform/exynos4-is directory.
 
 1. Supported SoCs
 =================
@@ -36,21 +36,21 @@ Not currently supported:
 =====================
 
 - media device driver
-  drivers/media/platform/s5p-fimc/fimc-mdevice.[ch]
+  drivers/media/platform/exynos4-is/media-dev.[ch]
 
  - camera capture video device driver
-  drivers/media/platform/s5p-fimc/fimc-capture.c
+  drivers/media/platform/exynos4-is/fimc-capture.c
 
  - MIPI-CSI2 receiver subdev
-  drivers/media/platform/s5p-fimc/mipi-csis.[ch]
+  drivers/media/platform/exynos4-is/mipi-csis.[ch]
 
  - video post-processor (mem-to-mem)
-  drivers/media/platform/s5p-fimc/fimc-core.c
+  drivers/media/platform/exynos4-is/fimc-core.c
 
  - common files
-  drivers/media/platform/s5p-fimc/fimc-core.h
-  drivers/media/platform/s5p-fimc/fimc-reg.h
-  drivers/media/platform/s5p-fimc/regs-fimc.h
+  drivers/media/platform/exynos4-is/fimc-core.h
+  drivers/media/platform/exynos4-is/fimc-reg.h
+  drivers/media/platform/exynos4-is/regs-fimc.h
 
 4. User space interfaces
 ========================
@@ -143,7 +143,8 @@ or retrieve the information from /dev/media? with help of the media-ctl tool:
 6. Platform support
 ===================
 
-The machine code (plat-s5p and arch/arm/mach-*) must select following options
+The machine code (arch/arm/plat-samsung and arch/arm/mach-*) must select
+following options:
 
 CONFIG_S5P_DEV_FIMC0       mandatory
 CONFIG_S5P_DEV_FIMC1  \
index a300b28..6c4866b 100644 (file)
@@ -246,7 +246,6 @@ may be NULL if the subdev driver does not support anything from that category.
 It looks like this:
 
 struct v4l2_subdev_core_ops {
-       int (*g_chip_ident)(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip);
        int (*log_status)(struct v4l2_subdev *sd);
        int (*init)(struct v4l2_subdev *sd, u32 val);
        ...
@@ -326,8 +325,27 @@ that width, height and the media bus pixel code are equal on both source and
 sink of the link. Subdev drivers are also free to use this function to
 perform the checks mentioned above in addition to their own checks.
 
-A device (bridge) driver needs to register the v4l2_subdev with the
-v4l2_device:
+There are currently two ways to register subdevices with the V4L2 core. The
+first (traditional) possibility is to have subdevices registered by bridge
+drivers. This can be done when the bridge driver has the complete information
+about subdevices connected to it and knows exactly when to register them. This
+is typically the case for internal subdevices, like video data processing units
+within SoCs or complex PCI(e) boards, camera sensors in USB cameras or connected
+to SoCs, which pass information about them to bridge drivers, usually in their
+platform data.
+
+There are however also situations where subdevices have to be registered
+asynchronously to bridge devices. An example of such a configuration is a Device
+Tree based system where information about subdevices is made available to the
+system independently from the bridge devices, e.g. when subdevices are defined
+in DT as I2C device nodes. The API used in this second case is described further
+below.
+
+Using one or the other registration method only affects the probing process, the
+run-time bridge-subdevice interaction is in both cases the same.
+
+In the synchronous case a device (bridge) driver needs to register the
+v4l2_subdev with the v4l2_device:
 
        int err = v4l2_device_register_subdev(v4l2_dev, sd);
 
@@ -346,24 +364,24 @@ Afterwards the subdev module can be unloaded and sd->dev == NULL.
 
 You can call an ops function either directly:
 
-       err = sd->ops->core->g_chip_ident(sd, &chip);
+       err = sd->ops->core->g_std(sd, &norm);
 
 but it is better and easier to use this macro:
 
-       err = v4l2_subdev_call(sd, core, g_chip_ident, &chip);
+       err = v4l2_subdev_call(sd, core, g_std, &norm);
 
 The macro will to the right NULL pointer checks and returns -ENODEV if subdev
-is NULL, -ENOIOCTLCMD if either subdev->core or subdev->core->g_chip_ident is
-NULL, or the actual result of the subdev->ops->core->g_chip_ident ops.
+is NULL, -ENOIOCTLCMD if either subdev->core or subdev->core->g_std is
+NULL, or the actual result of the subdev->ops->core->g_std ops.
 
 It is also possible to call all or a subset of the sub-devices:
 
-       v4l2_device_call_all(v4l2_dev, 0, core, g_chip_ident, &chip);
+       v4l2_device_call_all(v4l2_dev, 0, core, g_std, &norm);
 
 Any subdev that does not support this ops is skipped and error results are
 ignored. If you want to check for errors use this:
 
-       err = v4l2_device_call_until_err(v4l2_dev, 0, core, g_chip_ident, &chip);
+       err = v4l2_device_call_until_err(v4l2_dev, 0, core, g_std, &norm);
 
 Any error except -ENOIOCTLCMD will exit the loop with that error. If no
 errors (except -ENOIOCTLCMD) occurred, then 0 is returned.
@@ -394,6 +412,30 @@ controlled through GPIO pins. This distinction is only relevant when setting
 up the device, but once the subdev is registered it is completely transparent.
 
 
+In the asynchronous case subdevice probing can be invoked independently of the
+bridge driver availability. The subdevice driver then has to verify whether all
+the requirements for a successful probing are satisfied. This can include a
+check for a master clock availability. If any of the conditions aren't satisfied
+the driver might decide to return -EPROBE_DEFER to request further reprobing
+attempts. Once all conditions are met the subdevice shall be registered using
+the v4l2_async_register_subdev() function. Unregistration is performed using
+the v4l2_async_unregister_subdev() call. Subdevices registered this way are
+stored in a global list of subdevices, ready to be picked up by bridge drivers.
+
+Bridge drivers in turn have to register a notifier object with an array of
+subdevice descriptors that the bridge device needs for its operation. This is
+performed using the v4l2_async_notifier_register() call. To unregister the
+notifier the driver has to call v4l2_async_notifier_unregister(). The former of
+the two functions takes two arguments: a pointer to struct v4l2_device and a
+pointer to struct v4l2_async_notifier. The latter contains a pointer to an array
+of pointers to subdevice descriptors of type struct v4l2_async_subdev type. The
+V4L2 core will then use these descriptors to match asynchronously registered
+subdevices to them. If a match is detected the .bound() notifier callback is
+called. After all subdevices have been located the .complete() callback is
+called. When a subdevice is removed from the system the .unbind() method is
+called. All three callbacks are optional.
+
+
 V4L2 sub-device userspace API
 -----------------------------
 
@@ -575,9 +617,13 @@ of the video device exits.
 The default video_device_release() callback just calls kfree to free the
 allocated memory.
 
+There is also a video_device_release_empty() function that does nothing
+(is empty) and can be used if the struct is embedded and there is nothing
+to do when it is released.
+
 You should also set these fields:
 
-- v4l2_dev: set to the v4l2_device parent device.
+- v4l2_dev: must be set to the v4l2_device parent device.
 
 - name: set to something descriptive and unique.
 
@@ -614,15 +660,16 @@ You should also set these fields:
   If you want to have a separate priority state per (group of) device node(s),
   then you can point it to your own struct v4l2_prio_state.
 
-- parent: you only set this if v4l2_device was registered with NULL as
+- dev_parent: you only set this if v4l2_device was registered with NULL as
   the parent device struct. This only happens in cases where one hardware
   device has multiple PCI devices that all share the same v4l2_device core.
 
   The cx88 driver is an example of this: one core v4l2_device struct, but
-  it is used by both an raw video PCI device (cx8800) and a MPEG PCI device
-  (cx8802). Since the v4l2_device cannot be associated with a particular
-  PCI device it is setup without a parent device. But when the struct
-  video_device is setup you do know which parent PCI device to use.
+  it is used by both a raw video PCI device (cx8800) and a MPEG PCI device
+  (cx8802). Since the v4l2_device cannot be associated with two PCI devices
+  at the same time it is setup without a parent device. But when the struct
+  video_device is initialized you *do* know which parent PCI device to use and
+  so you set dev_device to the correct PCI device.
 
 - flags: optional. Set to V4L2_FL_USE_FH_PRIO if you want to let the framework
   handle the VIDIOC_G/S_PRIORITY ioctls. This requires that you use struct
@@ -1061,3 +1108,29 @@ available event type is 'class base + 1'.
 
 An example on how the V4L2 events may be used can be found in the OMAP
 3 ISP driver (drivers/media/platform/omap3isp).
+
+
+V4L2 clocks
+-----------
+
+Many subdevices, like camera sensors, TV decoders and encoders, need a clock
+signal to be supplied by the system. Often this clock is supplied by the
+respective bridge device. The Linux kernel provides a Common Clock Framework for
+this purpose. However, it is not (yet) available on all architectures. Besides,
+the nature of the multi-functional (clock, data + synchronisation, I2C control)
+connection of subdevices to the system might impose special requirements on the
+clock API usage. E.g. V4L2 has to support clock provider driver unregistration
+while a subdevice driver is holding a reference to the clock. For these reasons
+a V4L2 clock helper API has been developed and is provided to bridge and
+subdevice drivers.
+
+The API consists of two parts: two functions to register and unregister a V4L2
+clock source: v4l2_clk_register() and v4l2_clk_unregister() and calls to control
+a clock object, similar to the respective generic clock API calls:
+v4l2_clk_get(), v4l2_clk_put(), v4l2_clk_enable(), v4l2_clk_disable(),
+v4l2_clk_get_rate(), and v4l2_clk_set_rate(). Clock suppliers have to provide
+clock operations that will be called when clock users invoke respective API
+methods.
+
+It is expected that once the CCF becomes available on all relevant
+architectures this API will be removed.
diff --git a/Documentation/vm/zswap.txt b/Documentation/vm/zswap.txt
new file mode 100644 (file)
index 0000000..7e492d8
--- /dev/null
@@ -0,0 +1,68 @@
+Overview:
+
+Zswap is a lightweight compressed cache for swap pages. It takes pages that are
+in the process of being swapped out and attempts to compress them into a
+dynamically allocated RAM-based memory pool.  zswap basically trades CPU cycles
+for potentially reduced swap I/O.  This trade-off can also result in a
+significant performance improvement if reads from the compressed cache are
+faster than reads from a swap device.
+
+NOTE: Zswap is a new feature as of v3.11 and interacts heavily with memory
+reclaim.  This interaction has not be fully explored on the large set of
+potential configurations and workloads that exist.  For this reason, zswap
+is a work in progress and should be considered experimental.
+
+Some potential benefits:
+* Desktop/laptop users with limited RAM capacities can mitigate the
+    performance impact of swapping.
+* Overcommitted guests that share a common I/O resource can
+    dramatically reduce their swap I/O pressure, avoiding heavy handed I/O
+    throttling by the hypervisor. This allows more work to get done with less
+    impact to the guest workload and guests sharing the I/O subsystem
+* Users with SSDs as swap devices can extend the life of the device by
+    drastically reducing life-shortening writes.
+
+Zswap evicts pages from compressed cache on an LRU basis to the backing swap
+device when the compressed pool reaches it size limit.  This requirement had
+been identified in prior community discussions.
+
+To enabled zswap, the "enabled" attribute must be set to 1 at boot time.  e.g.
+zswap.enabled=1
+
+Design:
+
+Zswap receives pages for compression through the Frontswap API and is able to
+evict pages from its own compressed pool on an LRU basis and write them back to
+the backing swap device in the case that the compressed pool is full.
+
+Zswap makes use of zbud for the managing the compressed memory pool.  Each
+allocation in zbud is not directly accessible by address.  Rather, a handle is
+return by the allocation routine and that handle must be mapped before being
+accessed.  The compressed memory pool grows on demand and shrinks as compressed
+pages are freed.  The pool is not preallocated.
+
+When a swap page is passed from frontswap to zswap, zswap maintains a mapping
+of the swap entry, a combination of the swap type and swap offset, to the zbud
+handle that references that compressed swap page.  This mapping is achieved
+with a red-black tree per swap type.  The swap offset is the search key for the
+tree nodes.
+
+During a page fault on a PTE that is a swap entry, frontswap calls the zswap
+load function to decompress the page into the page allocated by the page fault
+handler.
+
+Once there are no PTEs referencing a swap page stored in zswap (i.e. the count
+in the swap_map goes to 0) the swap code calls the zswap invalidate function,
+via frontswap, to free the compressed entry.
+
+Zswap seeks to be simple in its policies.  Sysfs attributes allow for one user
+controlled policies:
+* max_pool_percent - The maximum percentage of memory that the compressed
+    pool can occupy.
+
+Zswap allows the compressor to be selected at kernel boot time by setting the
+“compressor” attribute.  The default compressor is lzo.  e.g.
+zswap.compressor=deflate
+
+A debugfs interface is provided for various statistic about pool size, number
+of pages stored, and various counters for the reasons pages are rejected.
index 04fddba..f9492fe 100644 (file)
@@ -194,14 +194,6 @@ reset: Watchdog Interrupt/Reset Mode. 0 = interrupt, 1 = reset
 nowayout: Watchdog cannot be stopped once started
        (default=kernel config parameter)
 -------------------------------------------------
-mpcore_wdt:
-mpcore_margin: MPcore timer margin in seconds.
-       (0 < mpcore_margin < 65536, default=60)
-nowayout: Watchdog cannot be stopped once started
-       (default=kernel config parameter)
-mpcore_noboot: MPcore watchdog action, set to 1 to ignore reboots,
-       0 to reboot (default=0
--------------------------------------------------
 mv64x60_wdt:
 nowayout: Watchdog cannot be stopped once started
        (default=kernel config parameter)
index 44c1d93..0da95db 100644 (file)
@@ -247,7 +247,6 @@ i2c_client 结构体,i2c_set_clientdata() 函数可用于保存一个 v4l2_sub
 这些结构体定义如下:
 
 struct v4l2_subdev_core_ops {
-       int (*g_chip_ident)(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip);
        int (*log_status)(struct v4l2_subdev *sd);
        int (*init)(struct v4l2_subdev *sd, u32 val);
        ...
@@ -337,24 +336,24 @@ subdev->dev 域就指向了 v4l2_device。
 
 注册之设备后,可通过以下方式直接调用其操作函数:
 
-       err = sd->ops->core->g_chip_ident(sd, &chip);
+       err = sd->ops->core->g_std(sd, &norm);
 
 但使用如下宏会比较容易且合适:
 
-       err = v4l2_subdev_call(sd, core, g_chip_ident, &chip);
+       err = v4l2_subdev_call(sd, core, g_std, &norm);
 
 这个宏将会做 NULL 指针检查,如果 subdev 为 NULL,则返回-ENODEV;如果
-subdev->core 或 subdev->core->g_chip_ident 为 NULL,则返回 -ENOIOCTLCMD;
-否则将返回 subdev->ops->core->g_chip_ident ops 调用的实际结果。
+subdev->core 或 subdev->core->g_std 为 NULL,则返回 -ENOIOCTLCMD;
+否则将返回 subdev->ops->core->g_std ops 调用的实际结果。
 
 有时也可能同时调用所有或一系列子设备的某个操作函数:
 
-       v4l2_device_call_all(v4l2_dev, 0, core, g_chip_ident, &chip);
+       v4l2_device_call_all(v4l2_dev, 0, core, g_std, &norm);
 
 任何不支持此操作的子设备都会被跳过,并忽略错误返回值。但如果你需要
 检查出错码,则可使用如下函数:
 
-       err = v4l2_device_call_until_err(v4l2_dev, 0, core, g_chip_ident, &chip);
+       err = v4l2_device_call_until_err(v4l2_dev, 0, core, g_std, &norm);
 
 除 -ENOIOCTLCMD 外的任何错误都会跳出循环并返回错误值。如果(除 -ENOIOCTLCMD
 外)没有错误发生,则返回 0。
index 0e6875d..1615b6e 100644 (file)
@@ -752,7 +752,7 @@ S:  Maintained
 F:     arch/arm/mach-highbank/
 
 ARM/CAVIUM NETWORKS CNS3XXX MACHINE SUPPORT
-M:     Anton Vorontsov <avorontsov@mvista.com>
+M:     Anton Vorontsov <anton@enomsg.org>
 S:     Maintained
 F:     arch/arm/mach-cns3xxx/
 T:     git git://git.infradead.org/users/cbou/linux-cns3xxx.git
@@ -1165,15 +1165,6 @@ L:       linux-media@vger.kernel.org
 S:     Maintained
 F:     drivers/media/platform/s5p-g2d/
 
-ARM/SAMSUNG S5P SERIES FIMC SUPPORT
-M:     Kyungmin Park <kyungmin.park@samsung.com>
-M:     Sylwester Nawrocki <s.nawrocki@samsung.com>
-L:     linux-arm-kernel@lists.infradead.org
-L:     linux-media@vger.kernel.org
-S:     Maintained
-F:     arch/arm/plat-samsung/include/plat/*fimc*
-F:     drivers/media/platform/s5p-fimc/
-
 ARM/SAMSUNG S5P SERIES Multi Format Codec (MFC) SUPPORT
 M:     Kyungmin Park <kyungmin.park@samsung.com>
 M:     Kamil Debski <k.debski@samsung.com>
@@ -1333,6 +1324,12 @@ S:       Supported
 F:     arch/arm/mach-zynq/
 F:     drivers/cpuidle/cpuidle-zynq.c
 
+ARM SMMU DRIVER
+M:     Will Deacon <will.deacon@arm.com>
+L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+S:     Maintained
+F:     drivers/iommu/arm-smmu.c
+
 ARM64 PORT (AARCH64 ARCHITECTURE)
 M:     Catalin Marinas <catalin.marinas@arm.com>
 M:     Will Deacon <will.deacon@arm.com>
@@ -1589,7 +1586,7 @@ F:        include/net/ax25.h
 F:     net/ax25/
 
 AZ6007 DVB DRIVER
-M:     Mauro Carvalho Chehab <mchehab@redhat.com>
+M:     Mauro Carvalho Chehab <m.chehab@samsung.com>
 L:     linux-media@vger.kernel.org
 W:     http://linuxtv.org
 T:     git git://linuxtv.org/media_tree.git
@@ -1874,7 +1871,7 @@ F:        Documentation/filesystems/btrfs.txt
 F:     fs/btrfs/
 
 BTTV VIDEO4LINUX DRIVER
-M:     Mauro Carvalho Chehab <mchehab@redhat.com>
+M:     Mauro Carvalho Chehab <m.chehab@samsung.com>
 L:     linux-media@vger.kernel.org
 W:     http://linuxtv.org
 T:     git git://linuxtv.org/media_tree.git
@@ -2129,9 +2126,12 @@ COCCINELLE/Semantic Patches (SmPL)
 M:     Julia Lawall <Julia.Lawall@lip6.fr>
 M:     Gilles Muller <Gilles.Muller@lip6.fr>
 M:     Nicolas Palix <nicolas.palix@imag.fr>
+M:     Michal Marek <mmarek@suse.cz>
 L:     cocci@systeme.lip6.fr (moderated for non-subscribers)
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mmarek/kbuild.git misc
 W:     http://coccinelle.lip6.fr/
 S:     Supported
+F:     Documentation/coccinelle.txt
 F:     scripts/coccinelle/
 F:     scripts/coccicheck
 
@@ -2359,7 +2359,7 @@ F:        drivers/media/common/cx2341x*
 F:     include/media/cx2341x*
 
 CX88 VIDEO4LINUX DRIVER
-M:     Mauro Carvalho Chehab <mchehab@redhat.com>
+M:     Mauro Carvalho Chehab <m.chehab@samsung.com>
 L:     linux-media@vger.kernel.org
 W:     http://linuxtv.org
 T:     git git://linuxtv.org/media_tree.git
@@ -2565,6 +2565,7 @@ S:        Maintained
 
 DEVICE-MAPPER  (LVM)
 M:     Alasdair Kergon <agk@redhat.com>
+M:     Mike Snitzer <snitzer@redhat.com>
 M:     dm-devel@redhat.com
 L:     dm-devel@redhat.com
 W:     http://sources.redhat.com/dm
@@ -2576,6 +2577,7 @@ F:        drivers/md/dm*
 F:     drivers/md/persistent-data/
 F:     include/linux/device-mapper.h
 F:     include/linux/dm-*.h
+F:     include/uapi/linux/dm-*.h
 
 DIOLAN U2C-12 I2C DRIVER
 M:     Guenter Roeck <linux@roeck-us.net>
@@ -2979,7 +2981,7 @@ S:        Maintained
 F:     drivers/edac/e7xxx_edac.c
 
 EDAC-GHES
-M:     Mauro Carvalho Chehab <mchehab@redhat.com>
+M:     Mauro Carvalho Chehab <m.chehab@samsung.com>
 L:     linux-edac@vger.kernel.org
 W:     bluesmoke.sourceforge.net
 S:     Maintained
@@ -3007,21 +3009,21 @@ S:      Maintained
 F:     drivers/edac/i5000_edac.c
 
 EDAC-I5400
-M:     Mauro Carvalho Chehab <mchehab@redhat.com>
+M:     Mauro Carvalho Chehab <m.chehab@samsung.com>
 L:     linux-edac@vger.kernel.org
 W:     bluesmoke.sourceforge.net
 S:     Maintained
 F:     drivers/edac/i5400_edac.c
 
 EDAC-I7300
-M:     Mauro Carvalho Chehab <mchehab@redhat.com>
+M:     Mauro Carvalho Chehab <m.chehab@samsung.com>
 L:     linux-edac@vger.kernel.org
 W:     bluesmoke.sourceforge.net
 S:     Maintained
 F:     drivers/edac/i7300_edac.c
 
 EDAC-I7CORE
-M:     Mauro Carvalho Chehab <mchehab@redhat.com>
+M:     Mauro Carvalho Chehab <m.chehab@samsung.com>
 L:     linux-edac@vger.kernel.org
 W:     bluesmoke.sourceforge.net
 S:     Maintained
@@ -3050,7 +3052,7 @@ S:        Maintained
 F:     drivers/edac/r82600_edac.c
 
 EDAC-SBRIDGE
-M:     Mauro Carvalho Chehab <mchehab@redhat.com>
+M:     Mauro Carvalho Chehab <m.chehab@samsung.com>
 L:     linux-edac@vger.kernel.org
 W:     bluesmoke.sourceforge.net
 S:     Maintained
@@ -3110,7 +3112,7 @@ S:        Maintained
 F:     drivers/net/ethernet/ibm/ehea/
 
 EM28XX VIDEO4LINUX DRIVER
-M:     Mauro Carvalho Chehab <mchehab@redhat.com>
+M:     Mauro Carvalho Chehab <m.chehab@samsung.com>
 L:     linux-media@vger.kernel.org
 W:     http://linuxtv.org
 T:     git git://linuxtv.org/media_tree.git
@@ -5306,7 +5308,7 @@ S:        Maintained
 F:     drivers/media/radio/radio-maxiradio*
 
 MEDIA INPUT INFRASTRUCTURE (V4L/DVB)
-M:     Mauro Carvalho Chehab <mchehab@redhat.com>
+M:     Mauro Carvalho Chehab <m.chehab@samsung.com>
 P:     LinuxTV.org Project
 L:     linux-media@vger.kernel.org
 W:     http://linuxtv.org
@@ -5385,6 +5387,12 @@ F:       drivers/mtd/
 F:     include/linux/mtd/
 F:     include/uapi/mtd/
 
+MEN A21 WATCHDOG DRIVER
+M:     Johannes Thumshirn <johannes.thumshirn@men.de>
+L:     linux-watchdog@vger.kernel.org
+S:     Supported
+F:     drivers/watchdog/mena21_wdt.c
+
 METAG ARCHITECTURE
 M:     James Hogan <james.hogan@imgtec.com>
 S:     Supported
@@ -5428,6 +5436,28 @@ W:       http://linuxtv.org
 S:     Odd Fixes
 F:     drivers/media/radio/radio-miropcm20*
 
+Mellanox MLX5 core VPI driver
+M:     Eli Cohen <eli@mellanox.com>
+L:     netdev@vger.kernel.org
+L:     linux-rdma@vger.kernel.org
+W:     http://www.mellanox.com
+Q:     http://patchwork.ozlabs.org/project/netdev/list/
+Q:     http://patchwork.kernel.org/project/linux-rdma/list/
+T:     git://openfabrics.org/~eli/connect-ib.git
+S:     Supported
+F:     drivers/net/ethernet/mellanox/mlx5/core/
+F:     include/linux/mlx5/
+
+Mellanox MLX5 IB driver
+M:      Eli Cohen <eli@mellanox.com>
+L:      linux-rdma@vger.kernel.org
+W:      http://www.mellanox.com
+Q:      http://patchwork.kernel.org/project/linux-rdma/list/
+T:      git://openfabrics.org/~eli/connect-ib.git
+S:      Supported
+F:      include/linux/mlx5/
+F:      drivers/infiniband/hw/mlx5/
+
 MODULE SUPPORT
 M:     Rusty Russell <rusty@rustcorp.com.au>
 S:     Maintained
@@ -5500,9 +5530,12 @@ F:       include/media/mt9v032.h
 
 MULTIFUNCTION DEVICES (MFD)
 M:     Samuel Ortiz <sameo@linux.intel.com>
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/sameo/mfd-2.6.git
+M:     Lee Jones <lee.jones@linaro.org>
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/sameo/mfd-next.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/sameo/mfd-fixes.git
 S:     Supported
 F:     drivers/mfd/
+F:     include/linux/mfd/
 
 MULTIMEDIA CARD (MMC), SECURE DIGITAL (SD) AND SDIO SUBSYSTEM
 M:     Chris Ball <cjb@laptop.org>
@@ -6403,7 +6436,7 @@ F:        include/linux/timer*
 F:     kernel/*timer*
 
 POWER SUPPLY CLASS/SUBSYSTEM and DRIVERS
-M:     Anton Vorontsov <cbou@mail.ru>
+M:     Anton Vorontsov <anton@enomsg.org>
 M:     David Woodhouse <dwmw2@infradead.org>
 T:     git git://git.infradead.org/battery-2.6.git
 S:     Maintained
@@ -6513,7 +6546,7 @@ S:        Maintained
 F:     drivers/block/ps3vram.c
 
 PSTORE FILESYSTEM
-M:     Anton Vorontsov <cbouatmailru@gmail.com>
+M:     Anton Vorontsov <anton@enomsg.org>
 M:     Colin Cross <ccross@android.com>
 M:     Kees Cook <keescook@chromium.org>
 M:     Tony Luck <tony.luck@intel.com>
@@ -6565,8 +6598,8 @@ S:        Maintained
 F:     drivers/media/usb/pwc/*
 
 PWM SUBSYSTEM
-M:     Thierry Reding <thierry.reding@avionic-design.de>
-L:     linux-kernel@vger.kernel.org
+M:     Thierry Reding <thierry.reding@gmail.com>
+L:     linux-pwm@vger.kernel.org
 S:     Maintained
 W:     http://gitorious.org/linux-pwm
 T:     git git://gitorious.org/linux-pwm/linux-pwm.git
@@ -6648,10 +6681,12 @@ F:      Documentation/networking/LICENSE.qla3xxx
 F:     drivers/net/ethernet/qlogic/qla3xxx.*
 
 QLOGIC QLCNIC (1/10)Gb ETHERNET DRIVER
+M:     Himanshu Madhani <himanshu.madhani@qlogic.com>
 M:     Rajesh Borundia <rajesh.borundia@qlogic.com>
 M:     Shahed Shaikh <shahed.shaikh@qlogic.com>
 M:     Jitendra Kalsaria <jitendra.kalsaria@qlogic.com>
 M:     Sony Chacko <sony.chacko@qlogic.com>
+M:     Sucheta Chakraborty <sucheta.chakraborty@qlogic.com>
 M:     linux-driver@qlogic.com
 L:     netdev@vger.kernel.org
 S:     Supported
@@ -6999,7 +7034,7 @@ S:        Odd Fixes
 F:     drivers/media/i2c/saa6588*
 
 SAA7134 VIDEO4LINUX DRIVER
-M:     Mauro Carvalho Chehab <mchehab@redhat.com>
+M:     Mauro Carvalho Chehab <m.chehab@samsung.com>
 L:     linux-media@vger.kernel.org
 W:     http://linuxtv.org
 T:     git git://linuxtv.org/media_tree.git
@@ -7044,6 +7079,15 @@ F:       drivers/regulator/s5m*.c
 F:     drivers/rtc/rtc-sec.c
 F:     include/linux/mfd/samsung/
 
+SAMSUNG S5P/EXYNOS4 SOC SERIES CAMERA SUBSYSTEM DRIVERS
+M:     Kyungmin Park <kyungmin.park@samsung.com>
+M:     Sylwester Nawrocki <s.nawrocki@samsung.com>
+L:     linux-media@vger.kernel.org
+Q:     https://patchwork.linuxtv.org/project/linux-media/list/
+S:     Supported
+F:     drivers/media/platform/exynos4-is/
+F:     include/media/s5p_fimc.h
+
 SAMSUNG S3C24XX/S3C64XX SOC SERIES CAMIF DRIVER
 M:     Sylwester Nawrocki <sylvester.nawrocki@gmail.com>
 L:     linux-media@vger.kernel.org
@@ -7211,7 +7255,7 @@ F:        drivers/mmc/host/sdhci.*
 F:     drivers/mmc/host/sdhci-pltfm.[ch]
 
 SECURE DIGITAL HOST CONTROLLER INTERFACE, OPEN FIRMWARE BINDINGS (SDHCI-OF)
-M:     Anton Vorontsov <avorontsov@ru.mvista.com>
+M:     Anton Vorontsov <anton@enomsg.org>
 L:     linuxppc-dev@lists.ozlabs.org
 L:     linux-mmc@vger.kernel.org
 S:     Maintained
@@ -7361,7 +7405,7 @@ S:        Odd Fixes
 F:     drivers/media/radio/radio-si4713.h
 
 SIANO DVB DRIVER
-M:     Mauro Carvalho Chehab <mchehab@redhat.com>
+M:     Mauro Carvalho Chehab <m.chehab@samsung.com>
 L:     linux-media@vger.kernel.org
 W:     http://linuxtv.org
 T:     git git://linuxtv.org/media_tree.git
@@ -8066,7 +8110,7 @@ S:        Maintained
 F:     drivers/media/i2c/tda9840*
 
 TEA5761 TUNER DRIVER
-M:     Mauro Carvalho Chehab <mchehab@redhat.com>
+M:     Mauro Carvalho Chehab <m.chehab@samsung.com>
 L:     linux-media@vger.kernel.org
 W:     http://linuxtv.org
 T:     git git://linuxtv.org/media_tree.git
@@ -8074,7 +8118,7 @@ S:        Odd fixes
 F:     drivers/media/tuners/tea5761.*
 
 TEA5767 TUNER DRIVER
-M:     Mauro Carvalho Chehab <mchehab@redhat.com>
+M:     Mauro Carvalho Chehab <m.chehab@samsung.com>
 L:     linux-media@vger.kernel.org
 W:     http://linuxtv.org
 T:     git git://linuxtv.org/media_tree.git
@@ -8147,6 +8191,7 @@ M:      Zhang Rui <rui.zhang@intel.com>
 M:      Eduardo Valentin <eduardo.valentin@ti.com>
 L:      linux-pm@vger.kernel.org
 T:      git git://git.kernel.org/pub/scm/linux/kernel/git/rzhang/linux.git
+T:      git git://git.kernel.org/pub/scm/linux/kernel/git/evalenti/linux-soc-thermal.git
 Q:      https://patchwork.kernel.org/project/linux-pm/list/
 S:      Supported
 F:      drivers/thermal/
@@ -8171,8 +8216,8 @@ F:        drivers/platform/x86/thinkpad_acpi.c
 TI BANDGAP AND THERMAL DRIVER
 M:     Eduardo Valentin <eduardo.valentin@ti.com>
 L:     linux-pm@vger.kernel.org
-S:     Maintained
-F:     drivers/staging/omap-thermal/
+S:     Supported
+F:     drivers/thermal/ti-soc-thermal/
 
 TI FLASH MEDIA INTERFACE DRIVER
 M:     Alex Dubov <oakad@yahoo.com>
@@ -8312,7 +8357,7 @@ F:        include/linux/shmem_fs.h
 F:     mm/shmem.c
 
 TM6000 VIDEO4LINUX DRIVER
-M:     Mauro Carvalho Chehab <mchehab@redhat.com>
+M:     Mauro Carvalho Chehab <m.chehab@samsung.com>
 L:     linux-media@vger.kernel.org
 W:     http://linuxtv.org
 T:     git git://linuxtv.org/media_tree.git
@@ -8881,6 +8926,7 @@ M:        "Michael S. Tsirkin" <mst@redhat.com>
 L:     virtualization@lists.linux-foundation.org
 S:     Maintained
 F:     drivers/virtio/
+F:     tools/virtio/
 F:     drivers/net/virtio_net.c
 F:     drivers/block/virtio_blk.c
 F:     include/linux/virtio_*.h
@@ -8976,7 +9022,7 @@ M:        Liam Girdwood <lgirdwood@gmail.com>
 M:     Mark Brown <broonie@kernel.org>
 W:     http://opensource.wolfsonmicro.com/node/15
 W:     http://www.slimlogic.co.uk/?p=48
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/lrg/regulator.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator.git
 S:     Supported
 F:     drivers/regulator/
 F:     include/linux/regulator/
@@ -9168,7 +9214,7 @@ S:        Maintained
 F:     arch/x86/kernel/cpu/mcheck/*
 
 XC2028/3028 TUNER DRIVER
-M:     Mauro Carvalho Chehab <mchehab@redhat.com>
+M:     Mauro Carvalho Chehab <m.chehab@samsung.com>
 L:     linux-media@vger.kernel.org
 W:     http://linuxtv.org
 T:     git git://linuxtv.org/media_tree.git
index 170ed7c..9262ba8 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,8 +1,8 @@
 VERSION = 3
-PATCHLEVEL = 10
+PATCHLEVEL = 11
 SUBLEVEL = 0
-EXTRAVERSION =
-NAME = Unicycling Gorilla
+EXTRAVERSION = -rc1
+NAME = Linux for Workgroups
 
 # *DOCUMENTATION*
 # To see a list of typical targets execute "make help"
@@ -1116,6 +1116,7 @@ help:
        @echo  '  gtags           - Generate GNU GLOBAL index'
        @echo  '  kernelrelease   - Output the release version string'
        @echo  '  kernelversion   - Output the version stored in Makefile'
+       @echo  '  image_name      - Output the image name'
        @echo  '  headers_install - Install sanitised kernel headers to INSTALL_HDR_PATH'; \
         echo  '                    (default: $(INSTALL_HDR_PATH))'; \
         echo  ''
@@ -1310,7 +1311,7 @@ export_report:
 endif #ifeq ($(config-targets),1)
 endif #ifeq ($(mixed-targets),1)
 
-PHONY += checkstack kernelrelease kernelversion
+PHONY += checkstack kernelrelease kernelversion image_name
 
 # UML needs a little special treatment here.  It wants to use the host
 # toolchain, so needs $(SUBARCH) passed to checkstack.pl.  Everyone
@@ -1331,6 +1332,9 @@ kernelrelease:
 kernelversion:
        @echo $(KERNELVERSION)
 
+image_name:
+       @echo $(KBUILD_IMAGE)
+
 # Clear a bunch of variables before executing the submake
 tools/: FORCE
        $(Q)mkdir -p $(objtree)/tools
index dfdadb0..09f49a6 100644 (file)
@@ -32,7 +32,7 @@
 #define O_SYNC         (__O_SYNC|O_DSYNC)
 
 #define O_PATH         040000000
-#define O_TMPFILE      0100000000
+#define __O_TMPFILE    0100000000
 
 #define F_GETLK                7
 #define F_SETLK                8
index 4885825..467de01 100644 (file)
@@ -81,6 +81,6 @@
 
 #define SO_SELECT_ERR_QUEUE    45
 
-#define SO_LL                  46
+#define SO_BUSY_POLL                   46
 
 #endif /* _UAPI_ASM_SOCKET_H */
index 941ad11..d9f8249 100644 (file)
 
 /include/ "abilis_tb10x.dtsi"
 
-/* interrupt specifiers
- * --------------------
- * 0: rising, 1: low, 2: high, 3: falling,
- */
 
 / {
        clock-frequency         = <500000000>;  /* 500 MHZ */
                        interrupt-controller;
                        #interrupt-cells = <1>;
                        interrupt-parent = <&tb10x_ictl>;
-                       interrupts = <27 1>;
+                       interrupts = <27 2>;
                        reg = <0xFF140000 0x1000>;
                        gpio-controller;
                        #gpio-cells = <1>;
                        interrupt-controller;
                        #interrupt-cells = <1>;
                        interrupt-parent = <&tb10x_ictl>;
-                       interrupts = <27 1>;
+                       interrupts = <27 2>;
                        reg = <0xFF141000 0x1000>;
                        gpio-controller;
                        #gpio-cells = <1>;
                        interrupt-controller;
                        #interrupt-cells = <1>;
                        interrupt-parent = <&tb10x_ictl>;
-                       interrupts = <27 1>;
+                       interrupts = <27 2>;
                        reg = <0xFF142000 0x1000>;
                        gpio-controller;
                        #gpio-cells = <1>;
                        interrupt-controller;
                        #interrupt-cells = <1>;
                        interrupt-parent = <&tb10x_ictl>;
-                       interrupts = <27 1>;
+                       interrupts = <27 2>;
                        reg = <0xFF143000 0x1000>;
                        gpio-controller;
                        #gpio-cells = <1>;
                        interrupt-controller;
                        #interrupt-cells = <1>;
                        interrupt-parent = <&tb10x_ictl>;
-                       interrupts = <27 1>;
+                       interrupts = <27 2>;
                        reg = <0xFF144000 0x1000>;
                        gpio-controller;
                        #gpio-cells = <1>;
                        interrupt-controller;
                        #interrupt-cells = <1>;
                        interrupt-parent = <&tb10x_ictl>;
-                       interrupts = <27 1>;
+                       interrupts = <27 2>;
                        reg = <0xFF145000 0x1000>;
                        gpio-controller;
                        #gpio-cells = <1>;
                        interrupt-controller;
                        #interrupt-cells = <1>;
                        interrupt-parent = <&tb10x_ictl>;
-                       interrupts = <27 1>;
+                       interrupts = <27 2>;
                        reg = <0xFF146000 0x1000>;
                        gpio-controller;
                        #gpio-cells = <1>;
                        interrupt-controller;
                        #interrupt-cells = <1>;
                        interrupt-parent = <&tb10x_ictl>;
-                       interrupts = <27 1>;
+                       interrupts = <27 2>;
                        reg = <0xFF147000 0x1000>;
                        gpio-controller;
                        #gpio-cells = <1>;
                        interrupt-controller;
                        #interrupt-cells = <1>;
                        interrupt-parent = <&tb10x_ictl>;
-                       interrupts = <27 1>;
+                       interrupts = <27 2>;
                        reg = <0xFF148000 0x1000>;
                        gpio-controller;
                        #gpio-cells = <1>;
                        interrupt-controller;
                        #interrupt-cells = <1>;
                        interrupt-parent = <&tb10x_ictl>;
-                       interrupts = <27 1>;
+                       interrupts = <27 2>;
                        reg = <0xFF149000 0x1000>;
                        gpio-controller;
                        #gpio-cells = <1>;
                        interrupt-controller;
                        #interrupt-cells = <1>;
                        interrupt-parent = <&tb10x_ictl>;
-                       interrupts = <27 1>;
+                       interrupts = <27 2>;
                        reg = <0xFF14A000 0x1000>;
                        gpio-controller;
                        #gpio-cells = <1>;
                        interrupt-controller;
                        #interrupt-cells = <1>;
                        interrupt-parent = <&tb10x_ictl>;
-                       interrupts = <27 1>;
+                       interrupts = <27 2>;
                        reg = <0xFF14B000 0x1000>;
                        gpio-controller;
                        #gpio-cells = <1>;
                        interrupt-controller;
                        #interrupt-cells = <1>;
                        interrupt-parent = <&tb10x_ictl>;
-                       interrupts = <27 1>;
+                       interrupts = <27 2>;
                        reg = <0xFF14C000 0x1000>;
                        gpio-controller;
                        #gpio-cells = <1>;
                        interrupt-controller;
                        #interrupt-cells = <1>;
                        interrupt-parent = <&tb10x_ictl>;
-                       interrupts = <27 1>;
+                       interrupts = <27 2>;
                        reg = <0xFF14D000 0x1000>;
                        gpio-controller;
                        #gpio-cells = <1>;
index fd25c21..da8ca79 100644 (file)
 
 /include/ "abilis_tb10x.dtsi"
 
-/* interrupt specifiers
- * --------------------
- * 0: rising, 1: low, 2: high, 3: falling,
- */
 
 / {
        clock-frequency         = <500000000>;  /* 500 MHZ */
                        interrupt-controller;
                        #interrupt-cells = <1>;
                        interrupt-parent = <&tb10x_ictl>;
-                       interrupts = <27 1>;
+                       interrupts = <27 2>;
                        reg = <0xFF140000 0x1000>;
                        gpio-controller;
                        #gpio-cells = <1>;
                        interrupt-controller;
                        #interrupt-cells = <1>;
                        interrupt-parent = <&tb10x_ictl>;
-                       interrupts = <27 1>;
+                       interrupts = <27 2>;
                        reg = <0xFF141000 0x1000>;
                        gpio-controller;
                        #gpio-cells = <1>;
                        interrupt-controller;
                        #interrupt-cells = <1>;
                        interrupt-parent = <&tb10x_ictl>;
-                       interrupts = <27 1>;
+                       interrupts = <27 2>;
                        reg = <0xFF142000 0x1000>;
                        gpio-controller;
                        #gpio-cells = <1>;
                        interrupt-controller;
                        #interrupt-cells = <1>;
                        interrupt-parent = <&tb10x_ictl>;
-                       interrupts = <27 1>;
+                       interrupts = <27 2>;
                        reg = <0xFF143000 0x1000>;
                        gpio-controller;
                        #gpio-cells = <1>;
                        interrupt-controller;
                        #interrupt-cells = <1>;
                        interrupt-parent = <&tb10x_ictl>;
-                       interrupts = <27 1>;
+                       interrupts = <27 2>;
                        reg = <0xFF144000 0x1000>;
                        gpio-controller;
                        #gpio-cells = <1>;
                        interrupt-controller;
                        #interrupt-cells = <1>;
                        interrupt-parent = <&tb10x_ictl>;
-                       interrupts = <27 1>;
+                       interrupts = <27 2>;
                        reg = <0xFF145000 0x1000>;
                        gpio-controller;
                        #gpio-cells = <1>;
                        interrupt-controller;
                        #interrupt-cells = <1>;
                        interrupt-parent = <&tb10x_ictl>;
-                       interrupts = <27 1>;
+                       interrupts = <27 2>;
                        reg = <0xFF146000 0x1000>;
                        gpio-controller;
                        #gpio-cells = <1>;
                        interrupt-controller;
                        #interrupt-cells = <1>;
                        interrupt-parent = <&tb10x_ictl>;
-                       interrupts = <27 1>;
+                       interrupts = <27 2>;
                        reg = <0xFF147000 0x1000>;
                        gpio-controller;
                        #gpio-cells = <1>;
                        interrupt-controller;
                        #interrupt-cells = <1>;
                        interrupt-parent = <&tb10x_ictl>;
-                       interrupts = <27 1>;
+                       interrupts = <27 2>;
                        reg = <0xFF148000 0x1000>;
                        gpio-controller;
                        #gpio-cells = <1>;
                        interrupt-controller;
                        #interrupt-cells = <1>;
                        interrupt-parent = <&tb10x_ictl>;
-                       interrupts = <27 1>;
+                       interrupts = <27 2>;
                        reg = <0xFF149000 0x1000>;
                        gpio-controller;
                        #gpio-cells = <1>;
                        interrupt-controller;
                        #interrupt-cells = <1>;
                        interrupt-parent = <&tb10x_ictl>;
-                       interrupts = <27 1>;
+                       interrupts = <27 2>;
                        reg = <0xFF14A000 0x1000>;
                        gpio-controller;
                        #gpio-cells = <1>;
                        interrupt-controller;
                        #interrupt-cells = <1>;
                        interrupt-parent = <&tb10x_ictl>;
-                       interrupts = <27 1>;
+                       interrupts = <27 2>;
                        reg = <0xFF14B000 0x1000>;
                        gpio-controller;
                        #gpio-cells = <1>;
                        interrupt-controller;
                        #interrupt-cells = <1>;
                        interrupt-parent = <&tb10x_ictl>;
-                       interrupts = <27 1>;
+                       interrupts = <27 2>;
                        reg = <0xFF14C000 0x1000>;
                        gpio-controller;
                        #gpio-cells = <1>;
                        interrupt-controller;
                        #interrupt-cells = <1>;
                        interrupt-parent = <&tb10x_ictl>;
-                       interrupts = <27 1>;
+                       interrupts = <27 2>;
                        reg = <0xFF14D000 0x1000>;
                        gpio-controller;
                        #gpio-cells = <1>;
index b97e305..edf56f4 100644 (file)
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
-/* interrupt specifiers
- * --------------------
- * 0: rising, 1: low, 2: high, 3: falling,
- */
 
 / {
        compatible              = "abilis,arc-tb10x";
@@ -78,7 +74,7 @@
                        #interrupt-cells = <1>;
                };
                tb10x_ictl: pic@fe002000 {
-                       compatible = "abilis,tb10x_ictl";
+                       compatible = "abilis,tb10x-ictl";
                        reg = <0xFE002000 0x20>;
                        interrupt-controller;
                        #interrupt-cells = <2>;
@@ -91,7 +87,7 @@
                        compatible = "snps,dw-apb-uart";
                        reg = <0xFF100000 0x100>;
                        clock-frequency = <166666666>;
-                       interrupts = <25 1>;
+                       interrupts = <25 8>;
                        reg-shift = <2>;
                        reg-io-width = <4>;
                        interrupt-parent = <&tb10x_ictl>;
                        compatible = "snps,dwmac-3.70a","snps,dwmac";
                        reg = <0xFE100000 0x1058>;
                        interrupt-parent = <&tb10x_ictl>;
-                       interrupts = <6 1>;
+                       interrupts = <6 8>;
                        interrupt-names = "macirq";
                        clocks = <&ahb_clk>;
                        clock-names = "stmmaceth";
                        compatible = "snps,dma-spear1340";
                        reg = <0xFE000000 0x400>;
                        interrupt-parent = <&tb10x_ictl>;
-                       interrupts = <14 1>;
+                       interrupts = <14 8>;
                        dma-channels = <6>;
                        dma-requests = <0>;
                        dma-masters = <1>;
                        compatible = "snps,designware-i2c";
                        reg = <0xFF120000 0x1000>;
                        interrupt-parent = <&tb10x_ictl>;
-                       interrupts = <12 1>;
+                       interrupts = <12 8>;
                        clocks = <&ahb_clk>;
                };
                i2c1: i2c@FF121000 {
                        compatible = "snps,designware-i2c";
                        reg = <0xFF121000 0x1000>;
                        interrupt-parent = <&tb10x_ictl>;
-                       interrupts = <12 1>;
+                       interrupts = <12 8>;
                        clocks = <&ahb_clk>;
                };
                i2c2: i2c@FF122000 {
                        compatible = "snps,designware-i2c";
                        reg = <0xFF122000 0x1000>;
                        interrupt-parent = <&tb10x_ictl>;
-                       interrupts = <12 1>;
+                       interrupts = <12 8>;
                        clocks = <&ahb_clk>;
                };
                i2c3: i2c@FF123000 {
                        compatible = "snps,designware-i2c";
                        reg = <0xFF123000 0x1000>;
                        interrupt-parent = <&tb10x_ictl>;
-                       interrupts = <12 1>;
+                       interrupts = <12 8>;
                        clocks = <&ahb_clk>;
                };
                i2c4: i2c@FF124000 {
                        compatible = "snps,designware-i2c";
                        reg = <0xFF124000 0x1000>;
                        interrupt-parent = <&tb10x_ictl>;
-                       interrupts = <12 1>;
+                       interrupts = <12 8>;
                        clocks = <&ahb_clk>;
                };
 
                        num-cs = <1>;
                        reg = <0xFE010000 0x20>;
                        interrupt-parent = <&tb10x_ictl>;
-                       interrupts = <26 1>;
+                       interrupts = <26 8>;
                        clocks = <&ahb_clk>;
                };
                spi1: spi@0xFE011000 {
                        num-cs = <2>;
                        reg = <0xFE011000 0x20>;
                        interrupt-parent = <&tb10x_ictl>;
-                       interrupts = <10 1>;
+                       interrupts = <10 8>;
                        clocks = <&ahb_clk>;
                };
 
                        compatible = "abilis,tb100-tsm";
                        reg = <0xff316000 0x400>;
                        interrupt-parent = <&tb10x_ictl>;
-                       interrupts = <17 1>;
+                       interrupts = <17 8>;
                        output-clkdiv = <4>;
                        global-packet-delay = <0x21>;
                        port-packet-delay = <0>;
                                        "cpuctrl",
                                        "a6it_int_force";
                        interrupt-parent = <&tb10x_ictl>;
-                       interrupts = <20 1>, <19 1>;
+                       interrupts = <20 2>, <19 2>;
                        interrupt-names = "cmd_irq", "event_irq";
                };
                tb10x_mdsc0: tb10x-mdscr@FF300000 {
                        compatible = "abilis,tb100-wfb";
                        reg = <0xff319000 0x1000>;
                        interrupt-parent = <&tb10x_ictl>;
-                       interrupts = <16 1>;
+                       interrupts = <16 8>;
                };
        };
 };
index bae4f93..4fb2d6f 100644 (file)
                        current-speed = <115200>;
                        status = "okay";
                };
+
+               ethernet@c0fc2000 {
+                       compatible = "snps,arc-emac";
+                       reg = <0xc0fc2000 0x3c>;
+                       interrupts = <6>;
+                       mac-address = [ 00 11 22 33 44 55 ];
+                       clock-frequency = <80000000>;
+                       max-speed = <100>;
+                       phy = <&phy0>;
+
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       phy0: ethernet-phy@0 {
+                               reg = <1>;
+                       };
+               };
        };
 };
index c109af3..4ca50f1 100644 (file)
@@ -38,6 +38,9 @@ CONFIG_INET=y
 # CONFIG_PREVENT_FIRMWARE_BUILD is not set
 # CONFIG_FIRMWARE_IN_KERNEL is not set
 # CONFIG_BLK_DEV is not set
+CONFIG_NETDEVICES=y
+CONFIG_ARC_EMAC=y
+CONFIG_LXT_PHY=y
 # CONFIG_INPUT_MOUSEDEV_PSAUX is not set
 # CONFIG_INPUT_KEYBOARD is not set
 # CONFIG_INPUT_MOUSE is not set
index 41e3356..6adbc53 100644 (file)
@@ -16,8 +16,6 @@
 #define UART1_IRQ      10
 #define UART2_IRQ      11
 
-#define VMAC_IRQ       6
-
 #define IDE_IRQ                13
 #define PCI_IRQ                14
 #define PS2_IRQ                15
index 1663f33..5c78e61 100644 (file)
@@ -15,8 +15,6 @@
 #define UART0_BASE              0xC0FC1000
 #define UART1_BASE              0xC0FC1100
 
-#define VMAC_REG_BASEADDR       0xC0FC2000
-
 #define IDE_CONTROLLER_BASE     0xC0FC9000
 
 #define AHB_PCI_HOST_BRG_BASE   0xC0FD0000
index 1d34521..1ab386b 100644 (file)
@@ -22,6 +22,7 @@ menuconfig ARC_PLAT_TB10X
        select PINCTRL
        select PINMUX
        select ARCH_REQUIRE_GPIOLIB
+       select TB10X_IRQC
        help
          Support for platforms based on the TB10x home media gateway SOC by
          Abilis Systems. TB10x is based on the ARC700 CPU architecture.
index 9a20661..9169822 100644 (file)
@@ -1302,7 +1302,7 @@ config ARM_ERRATA_754327
 
 config ARM_ERRATA_364296
        bool "ARM errata: Possible cache data corruption with hit-under-miss enabled"
-       depends on CPU_V6 && !SMP
+       depends on CPU_V6
        help
          This options enables the workaround for the 364296 ARM1136
          r0p2 erratum (possible cache data corruption with
index 5b7be8d..e401a76 100644 (file)
@@ -510,6 +510,16 @@ choice
                  Say Y here if you want the debug print routines to direct
                  their output to the uart1 port on SiRFmarco devices.
 
+       config DEBUG_STI_UART
+               depends on ARCH_STI
+               bool "Use StiH415/416 ASC for low-level debug"
+               help
+                 Say Y here if you want kernel low-level debugging support
+                 on StiH415/416 based platforms like B2000, B2020.
+                 It support UART2 and SBC_UART1.
+
+                 If unsure, say N.
+
        config DEBUG_U300_UART
                bool "Kernel low-level debugging messages via U300 UART0"
                depends on ARCH_U300
@@ -564,16 +574,6 @@ choice
                  This option selects UART0 on VIA/Wondermedia System-on-a-chip
                  devices, including VT8500, WM8505, WM8650 and WM8850.
 
-       config DEBUG_STI_UART
-               depends on ARCH_STI
-               bool "Use StiH415/416 ASC for low-level debug"
-               help
-                 Say Y here if you want kernel low-level debugging support
-                 on StiH415/416 based platforms like B2000, B2020.
-                 It support UART2 and SBC_UART1.
-
-                 If unsure, say N.
-
        config DEBUG_LL_UART_NONE
                bool "No low-level debugging UART"
                depends on !ARCH_MULTIPLATFORM
index 904ba83..3aee1a4 100644 (file)
        phy_id = <&davinci_mdio>, <1>;
        phy-mode = "rgmii-txid";
 };
+
+&tscadc {
+       status = "okay";
+       tsc {
+               ti,wires = <4>;
+               ti,x-plate-resistance = <200>;
+               ti,coordiante-readouts = <5>;
+               ti,wire-config = <0x00 0x11 0x22 0x33>;
+       };
+
+       adc {
+               ti,adc-channels = <4 5 6 7>;
+       };
+};
index 0d4df90..38b446b 100644 (file)
                        status = "disabled";
                };
 
+               tscadc: tscadc@44e0d000 {
+                       compatible = "ti,am3359-tscadc";
+                       reg = <0x44e0d000 0x1000>;
+                       interrupt-parent = <&intc>;
+                       interrupts = <16>;
+                       ti,hwmods = "adc_tsc";
+                       status = "disabled";
+
+                       tsc {
+                               compatible = "ti,am3359-tsc";
+                       };
+                       am335x_adc: adc {
+                               #io-channel-cells = <1>;
+                               compatible = "ti,am3359-adc";
+                       };
+               };
+
                gpmc: gpmc@50000000 {
                        compatible = "ti,am3352-gpmc";
                        ti,hwmods = "gpmc";
index ab177b4..365760b 100644 (file)
                        regulator-name = "vdd_vbus_wup1";
                        regulator-min-microvolt = <5000000>;
                        regulator-max-microvolt = <5000000>;
+                       enable-active-high;
                        gpio = <&gpio 24 0>; /* PD0 */
                };
        };
index 1701599..ed4b901 100644 (file)
                        regulator-name = "usb1_vbus";
                        regulator-min-microvolt = <5000000>;
                        regulator-max-microvolt = <5000000>;
+                       enable-active-high;
                        gpio = <&gpio 170 0>; /* PV2 */
                };
        };
index ea078ab..ab67c94 100644 (file)
                        regulator-name = "vbus1";
                        regulator-min-microvolt = <5000000>;
                        regulator-max-microvolt = <5000000>;
+                       enable-active-high;
                        gpio = <&tca6416 0 0>; /* GPIO_PMU0 */
                };
 
                        regulator-name = "vbus3";
                        regulator-min-microvolt = <5000000>;
                        regulator-max-microvolt = <5000000>;
+                       enable-active-high;
                        gpio = <&tca6416 1 0>; /* GPIO_PMU1 */
                };
        };
index e3bf2d6..65edf6d 100644 (file)
@@ -78,6 +78,13 @@ CONFIG_BACKLIGHT_LCD_SUPPORT=y
 CONFIG_LCD_CLASS_DEVICE=y
 CONFIG_BACKLIGHT_CLASS_DEVICE=y
 # CONFIG_USB_SUPPORT is not set
+CONFIG_MMC=y
+CONFIG_MMC_UNSAFE_RESUME=y
+CONFIG_MMC_BLOCK_MINORS=32
+CONFIG_MMC_TEST=y
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_PLTFM=y
+CONFIG_MMC_SDHCI_BCM_KONA=y
 CONFIG_NEW_LEDS=y
 CONFIG_LEDS_CLASS=y
 CONFIG_LEDS_TRIGGERS=y
index 340d550..fe0bdc3 100644 (file)
-CONFIG_EXPERIMENTAL=y
+CONFIG_IRQ_DOMAIN_DEBUG=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_ARCH_MVEBU=y
 CONFIG_MACH_ARMADA_370=y
-CONFIG_ARCH_SIRF=y
 CONFIG_MACH_ARMADA_XP=y
+CONFIG_ARCH_BCM=y
+CONFIG_GPIO_PCA953X=y
 CONFIG_ARCH_HIGHBANK=y
+CONFIG_ARCH_KEYSTONE=y
+CONFIG_ARCH_MXC=y
+CONFIG_MACH_IMX51_DT=y
+CONFIG_SOC_IMX53=y
+CONFIG_SOC_IMX6Q=y
+CONFIG_SOC_IMX6SL=y
+CONFIG_SOC_VF610=y
+CONFIG_ARCH_OMAP3=y
+CONFIG_ARCH_OMAP4=y
+CONFIG_SOC_OMAP5=y
+CONFIG_SOC_AM33XX=y
+CONFIG_SOC_AM43XX=y
+CONFIG_ARCH_ROCKCHIP=y
 CONFIG_ARCH_SOCFPGA=y
-CONFIG_ARCH_SUNXI=y
-CONFIG_ARCH_WM8850=y
-# CONFIG_ARCH_VEXPRESS_CORTEX_A5_A9_ERRATA is not set
-CONFIG_ARCH_ZYNQ=y
-CONFIG_ARM_ERRATA_754322=y
 CONFIG_PLAT_SPEAR=y
 CONFIG_ARCH_SPEAR13XX=y
 CONFIG_MACH_SPEAR1310=y
 CONFIG_MACH_SPEAR1340=y
+CONFIG_ARCH_STI=y
+CONFIG_ARCH_SUNXI=y
+CONFIG_ARCH_SIRF=y
+CONFIG_ARCH_TEGRA=y
+CONFIG_ARCH_TEGRA_2x_SOC=y
+CONFIG_ARCH_TEGRA_3x_SOC=y
+CONFIG_ARCH_TEGRA_114_SOC=y
+CONFIG_TEGRA_PCI=y
+CONFIG_TEGRA_EMC_SCALING_ENABLE=y
+CONFIG_ARCH_U8500=y
+CONFIG_MACH_SNOWBALL=y
+CONFIG_MACH_UX500_DT=y
+CONFIG_ARCH_VEXPRESS=y
+CONFIG_ARCH_VEXPRESS_CA9X4=y
+CONFIG_ARCH_VIRT=y
+CONFIG_ARCH_WM8850=y
+CONFIG_ARCH_ZYNQ=y
 CONFIG_SMP=y
-CONFIG_ARM_ARCH_TIMER=y
-CONFIG_AEABI=y
-CONFIG_HIGHMEM=y
 CONFIG_HIGHPTE=y
 CONFIG_ARM_APPENDED_DTB=y
-CONFIG_VFP=y
-CONFIG_NEON=y
 CONFIG_NET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
 CONFIG_BLK_DEV_SD=y
 CONFIG_ATA=y
+CONFIG_SATA_AHCI_PLATFORM=y
 CONFIG_SATA_HIGHBANK=y
 CONFIG_SATA_MV=y
-CONFIG_SATA_AHCI_PLATFORM=y
 CONFIG_NETDEVICES=y
 CONFIG_SUN4I_EMAC=y
 CONFIG_NET_CALXEDA_XGMAC=y
 CONFIG_SMSC911X=y
 CONFIG_STMMAC_ETH=y
-CONFIG_SERIO_AMBAKMI=y
 CONFIG_MDIO_SUN4I=y
+CONFIG_KEYBOARD_SPEAR=y
+CONFIG_SERIO_AMBAKMI=y
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_8250_DW=y
-CONFIG_KEYBOARD_SPEAR=y
 CONFIG_SERIAL_AMBA_PL011=y
 CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
-CONFIG_SERIAL_OF_PLATFORM=y
 CONFIG_SERIAL_SIRFSOC=y
 CONFIG_SERIAL_SIRFSOC_CONSOLE=y
+CONFIG_SERIAL_TEGRA=y
+CONFIG_SERIAL_IMX=y
+CONFIG_SERIAL_IMX_CONSOLE=y
 CONFIG_SERIAL_VT8500=y
 CONFIG_SERIAL_VT8500_CONSOLE=y
+CONFIG_SERIAL_OF_PLATFORM=y
+CONFIG_SERIAL_OMAP=y
+CONFIG_SERIAL_OMAP_CONSOLE=y
 CONFIG_SERIAL_XILINX_PS_UART=y
 CONFIG_SERIAL_XILINX_PS_UART_CONSOLE=y
-CONFIG_IPMI_HANDLER=y
-CONFIG_IPMI_SI=y
-CONFIG_I2C=y
+CONFIG_SERIAL_FSL_LPUART=y
+CONFIG_SERIAL_FSL_LPUART_CONSOLE=y
 CONFIG_I2C_DESIGNWARE_PLATFORM=y
 CONFIG_I2C_SIRF=y
+CONFIG_I2C_TEGRA=y
 CONFIG_SPI=y
 CONFIG_SPI_PL022=y
 CONFIG_SPI_SIRF=y
-CONFIG_GPIO_PL061=y
-CONFIG_FB=y
+CONFIG_SPI_TEGRA114=y
+CONFIG_SPI_TEGRA20_SLINK=y
+CONFIG_PINCTRL_SINGLE=y
+CONFIG_GPIO_GENERIC_PLATFORM=y
+CONFIG_GPIO_TWL4030=y
+CONFIG_REGULATOR_GPIO=y
+CONFIG_REGULATOR_AB8500=y
+CONFIG_REGULATOR_TPS51632=y
+CONFIG_REGULATOR_TPS62360=y
+CONFIG_REGULATOR_TWL4030=y
+CONFIG_REGULATOR_VEXPRESS=y
+CONFIG_DRM=y
+CONFIG_TEGRA_HOST1X=y
+CONFIG_DRM_TEGRA=y
 CONFIG_FB_ARMCLCD=y
 CONFIG_FB_WM8505=y
-CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_FB_SIMPLE=y
 CONFIG_USB=y
+CONFIG_USB_XHCI_HCD=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_MXC=y
+CONFIG_USB_EHCI_TEGRA=y
+CONFIG_USB_EHCI_HCD_PLATFORM=y
 CONFIG_USB_ISP1760_HCD=y
 CONFIG_USB_STORAGE=y
+CONFIG_AB8500_USB=y
+CONFIG_NOP_USB_XCEIV=y
+CONFIG_OMAP_USB2=y
+CONFIG_OMAP_USB3=y
+CONFIG_SAMSUNG_USB2PHY=y
+CONFIG_SAMSUNG_USB3PHY=y
+CONFIG_USB_GPIO_VBUS=y
+CONFIG_USB_ISP1301=y
+CONFIG_USB_MXS_PHY=y
 CONFIG_MMC=y
 CONFIG_MMC_ARMMMCI=y
 CONFIG_MMC_SDHCI=y
 CONFIG_MMC_SDHCI_PLTFM=y
+CONFIG_MMC_SDHCI_TEGRA=y
 CONFIG_MMC_SDHCI_SPEAR=y
-CONFIG_MMC_WMT=y
+CONFIG_MMC_OMAP=y
+CONFIG_MMC_OMAP_HS=y
 CONFIG_EDAC=y
 CONFIG_EDAC_MM_EDAC=y
 CONFIG_EDAC_HIGHBANK_MC=y
 CONFIG_EDAC_HIGHBANK_L2=y
 CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_TWL4030=y
 CONFIG_RTC_DRV_PL031=y
 CONFIG_RTC_DRV_VT8500=y
-CONFIG_PWM=y
-CONFIG_PWM_VT8500=y
+CONFIG_RTC_DRV_TEGRA=y
 CONFIG_DMADEVICES=y
-CONFIG_PL330_DMA=y
-CONFIG_SIRF_DMA=y
 CONFIG_DW_DMAC=y
+CONFIG_TEGRA20_APB_DMA=y
+CONFIG_STE_DMA40=y
+CONFIG_SIRF_DMA=y
+CONFIG_TI_EDMA=y
+CONFIG_PL330_DMA=y
+CONFIG_IMX_SDMA=y
+CONFIG_IMX_DMA=y
+CONFIG_MXS_DMA=y
+CONFIG_DMA_OMAP=y
+CONFIG_PWM=y
+CONFIG_PWM_VT8500=y
+CONFIG_EXT4_FS=y
+CONFIG_TMPFS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3_ACL=y
+CONFIG_NFS_V4=y
+CONFIG_ROOT_NFS=y
+CONFIG_PRINTK_TIME=y
+CONFIG_DEBUG_FS=y
+CONFIG_DEBUG_KERNEL=y
+CONFIG_LOCKUP_DETECTOR=y
index a24c024..5339e6a 100644 (file)
@@ -22,6 +22,10 @@ CONFIG_MODULE_SRCVERSION_ALL=y
 # CONFIG_BLK_DEV_BSG is not set
 CONFIG_ARCH_MULTI_V6=y
 CONFIG_ARCH_OMAP2PLUS=y
+CONFIG_ARCH_OMAP2=y
+CONFIG_ARCH_OMAP3=y
+CONFIG_ARCH_OMAP4=y
+CONFIG_SOC_AM33XX=y
 CONFIG_OMAP_RESET_CLOCKS=y
 CONFIG_OMAP_MUX_DEBUG=y
 CONFIG_ARCH_VEXPRESS_CA9X4=y
@@ -34,6 +38,8 @@ CONFIG_NR_CPUS=2
 CONFIG_LEDS=y
 CONFIG_ZBOOT_ROM_TEXT=0x0
 CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_ARM_APPENDED_DTB=y
+CONFIG_ARM_ATAG_DTB_COMPAT=y
 CONFIG_CMDLINE="root=/dev/mmcblk0p2 rootwait console=ttyO2,115200"
 CONFIG_KEXEC=y
 CONFIG_FPE_NWFPE=y
@@ -152,6 +158,13 @@ CONFIG_W1=y
 CONFIG_POWER_SUPPLY=y
 CONFIG_SENSORS_LM75=m
 CONFIG_WATCHDOG=y
+CONFIG_THERMAL=y
+CONFIG_THERMAL_HWMON=y
+CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y
+CONFIG_THERMAL_GOV_FAIR_SHARE=y
+CONFIG_THERMAL_GOV_STEP_WISE=y
+CONFIG_THERMAL_GOV_USER_SPACE=y
+CONFIG_CPU_THERMAL=y
 CONFIG_OMAP_WATCHDOG=y
 CONFIG_TWL4030_WATCHDOG=y
 CONFIG_MFD_TPS65217=y
@@ -238,7 +251,13 @@ CONFIG_RTC_DRV_TWL92330=y
 CONFIG_RTC_DRV_TWL4030=y
 CONFIG_RTC_DRV_OMAP=y
 CONFIG_DMADEVICES=y
+CONFIG_TI_EDMA=y
 CONFIG_DMA_OMAP=y
+CONFIG_TI_SOC_THERMAL=y
+CONFIG_TI_THERMAL=y
+CONFIG_OMAP4_THERMAL=y
+CONFIG_OMAP5_THERMAL=y
+CONFIG_DRA752_THERMAL=y
 CONFIG_EXT2_FS=y
 CONFIG_EXT3_FS=y
 # CONFIG_EXT3_FS_XATTR is not set
index 1fdb826..82eaa55 100644 (file)
@@ -61,7 +61,6 @@ CONFIG_GPIO_SYSFS=y
 CONFIG_GPIO_PL061=y
 # CONFIG_HWMON is not set
 CONFIG_WATCHDOG=y
-CONFIG_MPCORE_WATCHDOG=y
 # CONFIG_HID_SUPPORT is not set
 CONFIG_USB=y
 # CONFIG_USB_DEVICE_CLASS is not set
index c037aa1..a0025dc 100644 (file)
@@ -1,6 +1,8 @@
-CONFIG_EXPERIMENTAL=y
+CONFIG_HIGHMEM=y
 # CONFIG_SWAP is not set
 CONFIG_SYSVIPC=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_KALLSYMS_ALL=y
 CONFIG_MODULES=y
@@ -9,10 +11,7 @@ CONFIG_MODULE_UNLOAD=y
 CONFIG_ARCH_U8500=y
 CONFIG_MACH_HREFV60=y
 CONFIG_MACH_SNOWBALL=y
-CONFIG_MACH_U5500=y
 CONFIG_MACH_UX500_DT=y
-CONFIG_NO_HZ=y
-CONFIG_HIGH_RES_TIMERS=y
 CONFIG_SMP=y
 CONFIG_NR_CPUS=2
 CONFIG_PREEMPT=y
@@ -20,6 +19,7 @@ CONFIG_AEABI=y
 CONFIG_CMDLINE="root=/dev/ram0 console=ttyAMA2,115200n8"
 CONFIG_CPU_FREQ=y
 CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
+CONFIG_CPU_IDLE=y
 CONFIG_VFP=y
 CONFIG_NEON=y
 CONFIG_PM_RUNTIME=y
@@ -36,7 +36,6 @@ CONFIG_CAIF=y
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_SIZE=65536
-CONFIG_AB8500_PWM=y
 CONFIG_SENSORS_BH1780=y
 CONFIG_NETDEVICES=y
 CONFIG_SMSC911X=y
@@ -60,35 +59,39 @@ CONFIG_VT_HW_CONSOLE_BINDING=y
 CONFIG_SERIAL_AMBA_PL011=y
 CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
 CONFIG_HW_RANDOM=y
-CONFIG_HW_RANDOM_NOMADIK=y
 CONFIG_SPI=y
 CONFIG_SPI_PL022=y
 CONFIG_GPIO_STMPE=y
 CONFIG_GPIO_TC3589X=y
-# CONFIG_POWER_SUPPLY is not set
-# CONFIG_AB8500_BM is not set
-# CONFIG_AB8500_BATTERY_THERM_ON_BATCTRL is not set
 CONFIG_THERMAL=y
 CONFIG_CPU_THERMAL=y
+CONFIG_WATCHDOG=y
 CONFIG_MFD_STMPE=y
 CONFIG_MFD_TC3589X=y
-CONFIG_AB5500_CORE=y
-CONFIG_AB8500_CORE=y
-CONFIG_REGULATOR=y
-CONFIG_REGULATOR_AB8500=y
-CONFIG_REGULATOR_FIXED_VOLTAGE=y
 CONFIG_REGULATOR_GPIO=y
-# CONFIG_HID_SUPPORT is not set
-CONFIG_USB_GADGET=y
+CONFIG_REGULATOR_AB8500=y
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_SOC=y
+CONFIG_SND_SOC_UX500=y
+CONFIG_SND_SOC_UX500_MACH_MOP500=y
+CONFIG_USB=y
+CONFIG_USB_MUSB_HDRC=y
+CONFIG_USB_MUSB_UX500=y
+CONFIG_USB_PHY=y
 CONFIG_AB8500_USB=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_GADGET_MUSB_HDRC=y
+CONFIG_USB_ETH=m
 CONFIG_MMC=y
-CONFIG_MMC_CLKGATE=y
+CONFIG_MMC_UNSAFE_RESUME=y
+# CONFIG_MMC_BLOCK_BOUNCE is not set
 CONFIG_MMC_ARMMMCI=y
 CONFIG_NEW_LEDS=y
 CONFIG_LEDS_CLASS=y
 CONFIG_LEDS_LM3530=y
-CONFIG_LEDS_LP5521=y
 CONFIG_LEDS_GPIO=y
+CONFIG_LEDS_LP5521=y
 CONFIG_LEDS_TRIGGERS=y
 CONFIG_LEDS_TRIGGER_HEARTBEAT=y
 CONFIG_RTC_CLASS=y
@@ -108,7 +111,6 @@ CONFIG_EXT4_FS=y
 CONFIG_VFAT_FS=y
 CONFIG_TMPFS=y
 CONFIG_TMPFS_POSIX_ACL=y
-CONFIG_CONFIGFS_FS=m
 # CONFIG_MISC_FILESYSTEMS is not set
 CONFIG_NFS_FS=y
 CONFIG_ROOT_NFS=y
@@ -122,3 +124,7 @@ CONFIG_DEBUG_KERNEL=y
 CONFIG_DEBUG_INFO=y
 # CONFIG_FTRACE is not set
 CONFIG_DEBUG_USER=y
+CONFIG_CRYPTO_DEV_UX500=y
+CONFIG_CRYPTO_DEV_UX500_CRYP=y
+CONFIG_CRYPTO_DEV_UX500_HASH=y
+CONFIG_CRYPTO_DEV_UX500_DEBUG=y
index 18d1693..0393fba 100644 (file)
@@ -23,10 +23,21 @@ static inline unsigned long scu_a9_get_base(void)
        return pa;
 }
 
+#ifdef CONFIG_HAVE_ARM_SCU
 unsigned int scu_get_core_count(void __iomem *);
 int scu_power_mode(void __iomem *, unsigned int);
+#else
+static inline unsigned int scu_get_core_count(void __iomem *scu_base)
+{
+       return 0;
+}
+static inline int scu_power_mode(void __iomem *scu_base, unsigned int mode)
+{
+       return -EINVAL;
+}
+#endif
 
-#ifdef CONFIG_SMP
+#if defined(CONFIG_SMP) && defined(CONFIG_HAVE_ARM_SCU)
 void scu_enable(void __iomem *scu_base);
 #else
 static inline void scu_enable(void __iomem *scu_base) {}
index 5b391a6..76ab5ca 100644 (file)
@@ -133,6 +133,9 @@ ENTRY(lookup_processor_type)
        ldmfd   sp!, {r4 - r6, r9, pc}
 ENDPROC(lookup_processor_type)
 
+       __FINIT
+       .text
+
 /*
  * Read processor ID register (CP#15, CR0), and look up in the linker-built
  * supported processor list.  Note that we can't use the absolute addresses
index 90525d9..f6fd1d4 100644 (file)
@@ -120,7 +120,7 @@ static int twd_rate_change(struct notifier_block *nb,
         * changing cpu.
         */
        if (flags == POST_RATE_CHANGE)
-               smp_call_function(twd_update_frequency,
+               on_each_cpu(twd_update_frequency,
                                  (void *)&cnd->new_rate, 1);
 
        return NOTIFY_OK;
index fd38c8d..afbc439 100644 (file)
@@ -509,7 +509,6 @@ struct ths7303_platform_data ths7303_pdata = {
        .ch_1 = 3,
        .ch_2 = 3,
        .ch_3 = 3,
-       .init_enable = 1,
 };
 
 static struct amp_config_info vpbe_amp = {
index 99f259e..5362df3 100644 (file)
@@ -26,6 +26,7 @@
 #define SYSTEM_SOFT_RESET      (BRIDGE_VIRT_BASE + 0x010c)
 #define  SOFT_RESET            0x00000001
 
+#define BRIDGE_CAUSE           (BRIDGE_VIRT_BASE + 0x0110)
 #define  BRIDGE_INT_TIMER1_CLR (~0x0004)
 
 #define IRQ_VIRT_BASE          (BRIDGE_VIRT_BASE + 0x0200)
index f5f65b5..855d4a7 100644 (file)
@@ -38,7 +38,7 @@ config CPU_EXYNOS4210
        depends on ARCH_EXYNOS4
        select ARM_CPU_SUSPEND if PM
        select PINCTRL_EXYNOS
-       select PM_GENERIC_DOMAINS
+       select PM_GENERIC_DOMAINS if PM
        select S5P_PM if PM
        select S5P_SLEEP if PM
        select SAMSUNG_DMADEV
index 686ef34..63de1b3 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/i2c-gpio.h>
 
 #include <mach/hardware.h>
+
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/flash.h>
index c9e930f..0396d89 100644 (file)
@@ -3,7 +3,7 @@
  * 
  */
 
-#include <mach/hardware.h>
+#include <mach/ixp4xx-regs.h>
 
 /*
  * We use IXP425 General purpose timer for our timer needs, it runs at 
index 46a89f5..75ef03d 100644 (file)
@@ -27,6 +27,8 @@
 #include <asm/mach/arch.h>
 #include <asm/mach/flash.h>
 
+#include <mach/hardware.h>
+
 static struct resource omixp_flash_resources[] = {
        {
                .flags  = IORESOURCE_MEM,
index d4cbe5e..91242c9 100644 (file)
 #define CPU_RESET              0x00000002
 
 #define RSTOUTn_MASK           (BRIDGE_VIRT_BASE + 0x0108)
-#define WDT_RESET_OUT_EN       0x00000002
 #define SOFT_RESET_OUT_EN      0x00000004
 
 #define SYSTEM_SOFT_RESET      (BRIDGE_VIRT_BASE + 0x010c)
 #define SOFT_RESET             0x00000001
 
 #define BRIDGE_CAUSE           (BRIDGE_VIRT_BASE + 0x0110)
-#define WDT_INT_REQ            0x0008
 
 #define BRIDGE_INT_TIMER1_CLR  (~0x0004)
 
index c7b32a9..627fa7e 100644 (file)
@@ -1,63 +1,10 @@
 config ARCH_OMAP
        bool
 
-config ARCH_OMAP2PLUS
-       bool "TI OMAP2/3/4/5 SoCs with device tree support" if (ARCH_MULTI_V6 || ARCH_MULTI_V7)
-       select ARCH_HAS_CPUFREQ
-       select ARCH_HAS_BANDGAP
-       select ARCH_HAS_HOLES_MEMORYMODEL
-       select ARCH_OMAP
-       select ARCH_REQUIRE_GPIOLIB
-       select CLKDEV_LOOKUP
-       select CLKSRC_MMIO
-       select GENERIC_CLOCKEVENTS
-       select GENERIC_IRQ_CHIP
-       select HAVE_CLK
-       select OMAP_DM_TIMER
-       select PINCTRL
-       select PROC_DEVICETREE if PROC_FS
-       select SOC_BUS
-       select SPARSE_IRQ
-       select TI_PRIV_EDMA
-       select USE_OF
-       help
-         Systems based on OMAP2, OMAP3, OMAP4 or OMAP5
-
-
-if ARCH_OMAP2PLUS
-
-menu "TI OMAP2/3/4 Specific Features"
-
-config ARCH_OMAP2PLUS_TYPICAL
-       bool "Typical OMAP configuration"
-       default y
-       select AEABI
-       select HIGHMEM
-       select I2C
-       select I2C_OMAP
-       select MENELAUS if ARCH_OMAP2
-       select NEON if ARCH_OMAP3 || ARCH_OMAP4 || SOC_OMAP5
-       select PM_RUNTIME
-       select REGULATOR
-       select TWL4030_CORE if ARCH_OMAP3 || ARCH_OMAP4
-       select TWL4030_POWER if ARCH_OMAP3 || ARCH_OMAP4
-       select VFP
-       help
-         Compile a kernel suitable for booting most boards
-
-config SOC_HAS_OMAP2_SDRC
-       bool "OMAP2 SDRAM Controller support"
-
-config SOC_HAS_REALTIME_COUNTER
-       bool "Real time free running counter"
-       depends on SOC_OMAP5
-       default y
-
 config ARCH_OMAP2
        bool "TI OMAP2"
-       depends on ARCH_OMAP2PLUS
        depends on ARCH_MULTI_V6
-       default y
+       select ARCH_OMAP2PLUS
        select CPU_V6
        select MULTI_IRQ_HANDLER
        select SOC_HAS_OMAP2_SDRC
@@ -65,9 +12,8 @@ config ARCH_OMAP2
 
 config ARCH_OMAP3
        bool "TI OMAP3"
-       depends on ARCH_OMAP2PLUS
        depends on ARCH_MULTI_V7
-       default y
+       select ARCH_OMAP2PLUS
        select ARCH_HAS_OPP
        select ARM_CPU_SUSPEND if PM
        select CPU_V7
@@ -81,9 +27,8 @@ config ARCH_OMAP3
 
 config ARCH_OMAP4
        bool "TI OMAP4"
-       default y
-       depends on ARCH_OMAP2PLUS
        depends on ARCH_MULTI_V7
+       select ARCH_OMAP2PLUS
        select ARCH_HAS_OPP
        select ARCH_NEEDS_CPU_IDLE_COUPLED if SMP
        select ARM_CPU_SUSPEND if PM
@@ -108,12 +53,87 @@ config ARCH_OMAP4
 config SOC_OMAP5
        bool "TI OMAP5"
        depends on ARCH_MULTI_V7
+       select ARCH_OMAP2PLUS
        select ARM_CPU_SUSPEND if PM
        select ARM_GIC
        select CPU_V7
+       select HAVE_ARM_SCU if SMP
+       select HAVE_ARM_TWD if LOCAL_TIMERS
        select HAVE_SMP
        select COMMON_CLK
        select HAVE_ARM_ARCH_TIMER
+       select ARM_ERRATA_798181
+
+config SOC_AM33XX
+       bool "AM33XX support"
+       depends on ARCH_MULTI_V7
+       select ARCH_OMAP2PLUS
+       select ARM_CPU_SUSPEND if PM
+       select CPU_V7
+       select MULTI_IRQ_HANDLER
+       select COMMON_CLK
+
+config SOC_AM43XX
+       bool "TI AM43x"
+       depends on ARCH_MULTI_V7
+       select CPU_V7
+       select ARCH_OMAP2PLUS
+       select MULTI_IRQ_HANDLER
+       select ARM_GIC
+       select COMMON_CLK
+       select MACH_OMAP_GENERIC
+
+config ARCH_OMAP2PLUS
+       bool
+       select ARCH_HAS_BANDGAP
+       select ARCH_HAS_CPUFREQ
+       select ARCH_HAS_HOLES_MEMORYMODEL
+       select ARCH_OMAP
+       select ARCH_REQUIRE_GPIOLIB
+       select CLKDEV_LOOKUP
+       select CLKSRC_MMIO
+       select GENERIC_CLOCKEVENTS
+       select GENERIC_IRQ_CHIP
+       select HAVE_CLK
+       select OMAP_DM_TIMER
+       select PINCTRL
+       select PROC_DEVICETREE if PROC_FS
+       select SOC_BUS
+       select SPARSE_IRQ
+       select TI_PRIV_EDMA
+       select USE_OF
+       help
+         Systems based on OMAP2, OMAP3, OMAP4 or OMAP5
+
+
+if ARCH_OMAP2PLUS
+
+menu "TI OMAP2/3/4 Specific Features"
+
+config ARCH_OMAP2PLUS_TYPICAL
+       bool "Typical OMAP configuration"
+       default y
+       select AEABI
+       select HIGHMEM
+       select I2C
+       select I2C_OMAP
+       select MENELAUS if ARCH_OMAP2
+       select NEON if ARCH_OMAP3 || ARCH_OMAP4 || SOC_OMAP5
+       select PM_RUNTIME
+       select REGULATOR
+       select TWL4030_CORE if ARCH_OMAP3 || ARCH_OMAP4
+       select TWL4030_POWER if ARCH_OMAP3 || ARCH_OMAP4
+       select VFP
+       help
+         Compile a kernel suitable for booting most boards
+
+config SOC_HAS_OMAP2_SDRC
+       bool "OMAP2 SDRAM Controller support"
+
+config SOC_HAS_REALTIME_COUNTER
+       bool "Real time free running counter"
+       depends on SOC_OMAP5
+       default y
 
 comment "OMAP Core Type"
        depends on ARCH_OMAP2
@@ -142,23 +162,6 @@ config SOC_TI81XX
        depends on ARCH_OMAP3
        default y
 
-config SOC_AM33XX
-       bool "AM33XX support"
-       depends on ARCH_MULTI_V7
-       default y
-       select ARM_CPU_SUSPEND if PM
-       select CPU_V7
-       select MULTI_IRQ_HANDLER
-       select COMMON_CLK
-
-config SOC_AM43XX
-       bool "TI AM43x"
-       select CPU_V7
-       select MULTI_IRQ_HANDLER
-       select ARM_GIC
-       select COMMON_CLK
-       select MACH_OMAP_GENERIC
-
 config OMAP_PACKAGE_ZAF
        bool
 
index ea5a27f..d4f6715 100644 (file)
@@ -95,10 +95,6 @@ obj-$(CONFIG_POWER_AVS_OMAP_CLASS3)    += smartreflex-class3.o
 AFLAGS_sleep24xx.o                     :=-Wa,-march=armv6
 AFLAGS_sleep34xx.o                     :=-Wa,-march=armv7-a$(plus_sec)
 
-ifeq ($(CONFIG_PM_VERBOSE),y)
-CFLAGS_pm_bus.o                                += -DDEBUG
-endif
-
 endif
 
 ifeq ($(CONFIG_CPU_IDLE),y)
index b54562d..87e65dd 100644 (file)
@@ -553,6 +553,37 @@ static struct usbhs_omap_platform_data igep3_usbhs_bdata __initdata = {
 
 #ifdef CONFIG_OMAP_MUX
 static struct omap_board_mux board_mux[] __initdata = {
+       /* Display Sub System */
+       OMAP3_MUX(DSS_PCLK, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
+       OMAP3_MUX(DSS_HSYNC, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
+       OMAP3_MUX(DSS_VSYNC, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
+       OMAP3_MUX(DSS_ACBIAS, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
+       OMAP3_MUX(DSS_DATA0, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
+       OMAP3_MUX(DSS_DATA1, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
+       OMAP3_MUX(DSS_DATA2, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
+       OMAP3_MUX(DSS_DATA3, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
+       OMAP3_MUX(DSS_DATA4, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
+       OMAP3_MUX(DSS_DATA5, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
+       OMAP3_MUX(DSS_DATA6, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
+       OMAP3_MUX(DSS_DATA7, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
+       OMAP3_MUX(DSS_DATA8, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
+       OMAP3_MUX(DSS_DATA9, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
+       OMAP3_MUX(DSS_DATA10, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
+       OMAP3_MUX(DSS_DATA11, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
+       OMAP3_MUX(DSS_DATA12, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
+       OMAP3_MUX(DSS_DATA13, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
+       OMAP3_MUX(DSS_DATA14, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
+       OMAP3_MUX(DSS_DATA15, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
+       OMAP3_MUX(DSS_DATA16, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
+       OMAP3_MUX(DSS_DATA17, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
+       OMAP3_MUX(DSS_DATA18, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
+       OMAP3_MUX(DSS_DATA19, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
+       OMAP3_MUX(DSS_DATA20, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
+       OMAP3_MUX(DSS_DATA21, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
+       OMAP3_MUX(DSS_DATA22, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
+       OMAP3_MUX(DSS_DATA23, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
+       /* TFP410 PanelBus DVI Transmitte (GPIO_170) */
+       OMAP3_MUX(HDQ_SIO, OMAP_MUX_MODE4 | OMAP_PIN_OUTPUT),
        /* SMSC9221 LAN Controller ETH IRQ (GPIO_176) */
        OMAP3_MUX(MCSPI1_CS2, OMAP_MUX_MODE4 | OMAP_PIN_INPUT),
        { .reg_offset = OMAP_MUX_TERMINATOR },
index bd74f9f..bdd1e3a 100644 (file)
@@ -61,7 +61,7 @@ static struct omap_dss_board_info rx51_dss_board_info = {
 
 static int __init rx51_video_init(void)
 {
-       if (!machine_is_nokia_rx51())
+       if (!machine_is_nokia_rx51() && !of_machine_is_compatible("nokia,omap3-n900"))
                return 0;
 
        if (omap_mux_init_gpio(RX51_LCD_RESET_GPIO, OMAP_PIN_OUTPUT)) {
index aef96e4..3c1279f 100644 (file)
@@ -15,7 +15,6 @@
 #include <linux/io.h>
 #include <linux/clk.h>
 #include <linux/err.h>
-#include <linux/gpio.h>
 #include <linux/slab.h>
 #include <linux/of.h>
 #include <linux/pinctrl/machine.h>
@@ -66,7 +65,7 @@ static int __init omap3_l3_init(void)
 
        WARN(IS_ERR(pdev), "could not build omap_device for %s\n", oh_name);
 
-       return IS_ERR(pdev) ? PTR_ERR(pdev) : 0;
+       return PTR_RET(pdev);
 }
 omap_postcore_initcall(omap3_l3_init);
 
@@ -100,7 +99,7 @@ static int __init omap4_l3_init(void)
 
        WARN(IS_ERR(pdev), "could not build omap_device for %s\n", oh_name);
 
-       return IS_ERR(pdev) ? PTR_ERR(pdev) : 0;
+       return PTR_RET(pdev);
 }
 omap_postcore_initcall(omap4_l3_init);
 
index 190ae49..2ca33cc 100644 (file)
@@ -83,10 +83,7 @@ static int __init omap_init_vrfb(void)
        pdev = platform_device_register_resndata(NULL, "omapvrfb", -1,
                        res, num_res, NULL, 0);
 
-       if (IS_ERR(pdev))
-               return PTR_ERR(pdev);
-       else
-               return 0;
+       return PTR_RET(pdev);
 }
 
 omap_arch_initcall(omap_init_vrfb);
index 1c7969e..f3fdd6a 100644 (file)
@@ -1734,7 +1734,7 @@ static int __init omap_gpmc_init(void)
        pdev = omap_device_build(DEVICE_NAME, -1, oh, NULL, 0);
        WARN(IS_ERR(pdev), "could not build omap_device for %s\n", oh_name);
 
-       return IS_ERR(pdev) ? PTR_ERR(pdev) : 0;
+       return PTR_RET(pdev);
 }
 omap_postcore_initcall(omap_gpmc_init);
 
index fe3253a..4a3f06f 100644 (file)
@@ -394,7 +394,7 @@ static void __init omap_hwmod_init_postsetup(void)
        omap_pm_if_early_init();
 }
 
-static void __init omap_common_late_init(void)
+static void __init __maybe_unused omap_common_late_init(void)
 {
        omap_mux_late_init();
        omap2_common_pm_late_init();
index 9ace8ea..33c8846 100644 (file)
@@ -54,10 +54,7 @@ static int __init omap2_init_pmu(unsigned oh_num, char *oh_names[])
        WARN(IS_ERR(omap_pmu_dev), "Can't build omap_device for %s.\n",
             dev_name);
 
-       if (IS_ERR(omap_pmu_dev))
-               return PTR_ERR(omap_pmu_dev);
-
-       return 0;
+       return PTR_RET(omap_pmu_dev);
 }
 
 static int __init omap_init_pmu(void)
index 88ff83a..9086ce0 100644 (file)
@@ -34,6 +34,8 @@ ppa_zero_params:
 ppa_por_params:
        .word           1, 0
 
+#ifdef CONFIG_ARCH_OMAP4
+
 /*
  * =============================
  * == CPU suspend finisher ==
@@ -326,7 +328,9 @@ skip_l2en:
 
        b       cpu_resume                      @ Jump to generic resume
 ENDPROC(omap4_cpu_resume)
-#endif
+#endif /* CONFIG_ARCH_OMAP4 */
+
+#endif /* defined(CONFIG_SMP) && defined(CONFIG_PM) */
 
 #ifndef CONFIG_OMAP4_ERRATA_I688
 ENTRY(omap_bus_sync)
index 29ac667..b37e1fc 100644 (file)
@@ -220,7 +220,7 @@ static int __init omap_dm_timer_init_one(struct omap_dm_timer *timer,
                                         int posted)
 {
        char name[10]; /* 10 = sizeof("gptXX_Xck0") */
-       const char *oh_name;
+       const char *oh_name = NULL;
        struct device_node *np;
        struct omap_hwmod *oh;
        struct resource irq, mem;
index 461fd69..f727d03 100644 (file)
@@ -18,7 +18,6 @@
 #define CPU_CTRL               (ORION5X_BRIDGE_VIRT_BASE + 0x104)
 
 #define RSTOUTn_MASK           (ORION5X_BRIDGE_VIRT_BASE + 0x108)
-#define WDT_RESET_OUT_EN       0x0002
 
 #define CPU_SOFT_RESET         (ORION5X_BRIDGE_VIRT_BASE + 0x10c)
 
@@ -26,8 +25,6 @@
 
 #define POWER_MNG_CTRL_REG     (ORION5X_BRIDGE_VIRT_BASE + 0x11C)
 
-#define WDT_INT_REQ            0x0008
-
 #define BRIDGE_INT_TIMER1_CLR  (~0x0004)
 
 #define MAIN_IRQ_CAUSE         (ORION5X_BRIDGE_VIRT_BASE + 0x200)
index ed2b854..ad40ab0 100644 (file)
@@ -377,12 +377,8 @@ static struct max8998_platform_data aquila_max8998_pdata = {
        .buck1_set1     = S5PV210_GPH0(3),
        .buck1_set2     = S5PV210_GPH0(4),
        .buck2_set3     = S5PV210_GPH0(5),
-       .buck1_voltage1 = 1200000,
-       .buck1_voltage2 = 1200000,
-       .buck1_voltage3 = 1200000,
-       .buck1_voltage4 = 1200000,
-       .buck2_voltage1 = 1200000,
-       .buck2_voltage2 = 1200000,
+       .buck1_voltage  = { 1200000, 1200000, 1200000, 1200000 },
+       .buck2_voltage  = { 1200000, 1200000 },
 };
 #endif
 
index 30b24ad..e5cd9fb 100644 (file)
@@ -580,12 +580,8 @@ static struct max8998_platform_data goni_max8998_pdata = {
        .buck1_set1     = S5PV210_GPH0(3),
        .buck1_set2     = S5PV210_GPH0(4),
        .buck2_set3     = S5PV210_GPH0(5),
-       .buck1_voltage1 = 1200000,
-       .buck1_voltage2 = 1200000,
-       .buck1_voltage3 = 1200000,
-       .buck1_voltage4 = 1200000,
-       .buck2_voltage1 = 1200000,
-       .buck2_voltage2 = 1200000,
+       .buck1_voltage  = { 1200000, 1200000, 1200000, 1200000 },
+       .buck2_voltage  = { 1200000, 1200000 },
 };
 #endif
 
index 899a86c..1ccddd2 100644 (file)
@@ -287,14 +287,14 @@ static struct gpio_em_config gio3_config = {
 static struct resource gio3_resources[] = {
        [0] = {
                .name   = "GIO_096",
-               .start  = 0xe0050100,
-               .end    = 0xe005012b,
+               .start  = 0xe0050180,
+               .end    = 0xe00501ab,
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
                .name   = "GIO_096",
-               .start  = 0xe0050140,
-               .end    = 0xe005015f,
+               .start  = 0xe00501c0,
+               .end    = 0xe00501df,
                .flags  = IORESOURCE_MEM,
        },
        [2] = {
index c5a75a7..7f45c2e 100644 (file)
@@ -62,7 +62,7 @@ enum { SCIFA0, SCIFA1, SCIFB0, SCIFB1, SCIFB2, SCIFB3 };
 static const struct plat_sci_port scif[] = {
        SCIFA_DATA(SCIFA0, 0xe6c40000, gic_spi(144)), /* SCIFA0 */
        SCIFA_DATA(SCIFA1, 0xe6c50000, gic_spi(145)), /* SCIFA1 */
-       SCIFB_DATA(SCIFB0, 0xe6c50000, gic_spi(145)), /* SCIFB0 */
+       SCIFB_DATA(SCIFB0, 0xe6c20000, gic_spi(148)), /* SCIFB0 */
        SCIFB_DATA(SCIFB1, 0xe6c30000, gic_spi(149)), /* SCIFB1 */
        SCIFB_DATA(SCIFB2, 0xe6ce0000, gic_spi(150)), /* SCIFB2 */
        SCIFB_DATA(SCIFB3, 0xe6cf0000, gic_spi(151)), /* SCIFB3 */
index 4130e65..5b799c2 100644 (file)
@@ -101,7 +101,7 @@ static const char * const zynq_dt_match[] = {
        NULL
 };
 
-MACHINE_START(XILINX_EP107, "Xilinx Zynq Platform")
+DT_MACHINE_START(XILINX_EP107, "Xilinx Zynq Platform")
        .smp            = smp_ops(zynq_smp_ops),
        .map_io         = zynq_map_io,
        .init_machine   = zynq_init_machine,
index 6833cbe..15225d8 100644 (file)
@@ -597,7 +597,7 @@ void __init mem_init(void)
 
 #ifdef CONFIG_SA1111
        /* now that our DMA memory is actually so designated, we can free it */
-       free_reserved_area(__va(PHYS_PFN_OFFSET), swapper_pg_dir, -1, NULL);
+       free_reserved_area(__va(PHYS_OFFSET), swapper_pg_dir, -1, NULL);
 #endif
 
        free_highpages();
index 10062ce..0c63562 100644 (file)
@@ -181,11 +181,9 @@ void arch_pick_mmap_layout(struct mm_struct *mm)
        if (mmap_is_legacy()) {
                mm->mmap_base = TASK_UNMAPPED_BASE + random_factor;
                mm->get_unmapped_area = arch_get_unmapped_area;
-               mm->unmap_area = arch_unmap_area;
        } else {
                mm->mmap_base = mmap_base(random_factor);
                mm->get_unmapped_area = arch_get_unmapped_area_topdown;
-               mm->unmap_area = arch_unmap_area_topdown;
        }
 }
 
index d7229d2..4f56617 100644 (file)
@@ -950,7 +950,7 @@ void __init debug_ll_io_init(void)
        map.virtual &= PAGE_MASK;
        map.length = PAGE_SIZE;
        map.type = MT_DEVICE;
-       create_mapping(&map);
+       iotable_init(&map, 1);
 }
 #endif
 
index 4143d9b..9737e97 100644 (file)
@@ -270,6 +270,8 @@ source "drivers/Kconfig"
 
 source "fs/Kconfig"
 
+source "arch/arm64/kvm/Kconfig"
+
 source "arch/arm64/Kconfig.debug"
 
 source "security/Kconfig"
index 49c162c..666e231 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/dma-mapping.h>
+#include <linux/kvm_host.h>
 #include <asm/thread_info.h>
 #include <asm/memory.h>
 #include <asm/cputable.h>
diff --git a/arch/arm64/kvm/Kconfig b/arch/arm64/kvm/Kconfig
new file mode 100644 (file)
index 0000000..21e9082
--- /dev/null
@@ -0,0 +1,51 @@
+#
+# KVM configuration
+#
+
+source "virt/kvm/Kconfig"
+
+menuconfig VIRTUALIZATION
+       bool "Virtualization"
+       ---help---
+         Say Y here to get to see options for using your Linux host to run
+         other operating systems inside virtual machines (guests).
+         This option alone does not add any kernel code.
+
+         If you say N, all options in this submenu will be skipped and
+         disabled.
+
+if VIRTUALIZATION
+
+config KVM
+       bool "Kernel-based Virtual Machine (KVM) support"
+       select MMU_NOTIFIER
+       select PREEMPT_NOTIFIERS
+       select ANON_INODES
+       select KVM_MMIO
+       select KVM_ARM_HOST
+       select KVM_ARM_VGIC
+       select KVM_ARM_TIMER
+       ---help---
+         Support hosting virtualized guest machines.
+
+         If unsure, say N.
+
+config KVM_ARM_HOST
+       bool
+       ---help---
+         Provides host support for ARM processors.
+
+config KVM_ARM_VGIC
+       bool
+       depends on KVM_ARM_HOST && OF
+       select HAVE_KVM_IRQCHIP
+       ---help---
+         Adds support for a hardware assisted, in-kernel GIC emulation.
+
+config KVM_ARM_TIMER
+       bool
+       depends on KVM_ARM_VGIC
+       ---help---
+         Adds support for the Architected Timers in virtual machines.
+
+endif # VIRTUALIZATION
index 7c7be78..8ed6cb1 100644 (file)
@@ -90,11 +90,9 @@ void arch_pick_mmap_layout(struct mm_struct *mm)
        if (mmap_is_legacy()) {
                mm->mmap_base = TASK_UNMAPPED_BASE;
                mm->get_unmapped_area = arch_get_unmapped_area;
-               mm->unmap_area = arch_unmap_area;
        } else {
                mm->mmap_base = mmap_base();
                mm->get_unmapped_area = arch_get_unmapped_area_topdown;
-               mm->unmap_area = arch_unmap_area_topdown;
        }
 }
 EXPORT_SYMBOL_GPL(arch_pick_mmap_layout);
index 79b6179..11c4259 100644 (file)
@@ -74,6 +74,6 @@
 
 #define SO_SELECT_ERR_QUEUE    45
 
-#define SO_LL                  46
+#define SO_BUSY_POLL           46
 
 #endif /* __ASM_AVR32_SOCKET_H */
index 08c7ac6..3b6abc5 100644 (file)
@@ -283,7 +283,7 @@ config BF_REV_0_0
 
 config BF_REV_0_1
        bool "0.1"
-       depends on (BF51x || BF52x || (BF54x && !BF54xM))
+       depends on (BF51x || BF52x || (BF54x && !BF54xM) || BF60x)
 
 config BF_REV_0_2
        bool "0.2"
similarity index 99%
rename from arch/blackfin/include/asm/bfin6xx_spi.h
rename to arch/blackfin/include/asm/bfin_spi3.h
index 89370b6..0957e65 100644 (file)
@@ -240,7 +240,7 @@ struct bfin_spi_regs {
 #define MAX_CTRL_CS          8  /* cs in spi controller */
 
 /* device.platform_data for SSP controller devices */
-struct bfin6xx_spi_master {
+struct bfin_spi3_master {
        u16 num_chipselect;
        u16 pin_req[7];
 };
@@ -248,7 +248,7 @@ struct bfin6xx_spi_master {
 /* spi_board_info.controller_data for SPI slave devices,
  * copied to spi_device.platform_data ... mostly for dma tuning
  */
-struct bfin6xx_spi_chip {
+struct bfin_spi3_chip {
        u32 control;
        u16 cs_chg_udelay; /* Some devices require 16-bit delays */
        u32 tx_dummy_val; /* tx value for rx only transfer */
index b882ce2..fa53fae 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/ptrace.h>              /* for linux pt_regs struct */
 #include <linux/kgdb.h>
 #include <linux/uaccess.h>
+#include <asm/irq_regs.h>
 
 void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs)
 {
index ab1c617..c77a23b 100644 (file)
@@ -69,7 +69,6 @@ void __cpuinit platform_secondary_init(unsigned int cpu)
        SSYNC();
 
        /* We are done with local CPU inits, unblock the boot CPU. */
-       set_cpu_online(cpu, true);
        spin_lock(&boot_lock);
        spin_unlock(&boot_lock);
 }
@@ -91,7 +90,9 @@ int __cpuinit platform_boot_secondary(unsigned int cpu, struct task_struct *idle
                SSYNC();
        }
 
-       timeout = jiffies + 1 * HZ;
+       timeout = jiffies + HZ;
+       /* release the lock and let coreb run */
+       spin_unlock(&boot_lock);
        while (time_before(jiffies, timeout)) {
                if (cpu_online(cpu))
                        break;
@@ -100,8 +101,6 @@ int __cpuinit platform_boot_secondary(unsigned int cpu, struct task_struct *idle
        }
 
        if (cpu_online(cpu)) {
-               /* release the lock and let coreb run */
-               spin_unlock(&boot_lock);
                return 0;
        } else
                panic("CPU%u: processor failed to boot\n", cpu);
index bba40ae..0bc4723 100644 (file)
@@ -17,7 +17,7 @@
 #include <linux/i2c.h>
 #include <linux/interrupt.h>
 #include <linux/usb/musb.h>
-#include <asm/bfin6xx_spi.h>
+#include <asm/bfin_spi3.h>
 #include <asm/dma.h>
 #include <asm/gpio.h>
 #include <asm/nand.h>
@@ -108,7 +108,6 @@ static struct platform_device bfin_rotary_device = {
 static unsigned short pins[] = P_RMII0;
 
 static struct stmmac_mdio_bus_data phy_private_data = {
-       .bus_id = 0,
        .phy_mask = 1,
 };
 
@@ -745,13 +744,13 @@ static struct flash_platform_data bfin_spi_flash_data = {
        .type = "w25q32",
 };
 
-static struct bfin6xx_spi_chip spi_flash_chip_info = {
+static struct bfin_spi3_chip spi_flash_chip_info = {
        .enable_dma = true,         /* use dma transfer with this chip*/
 };
 #endif
 
 #if defined(CONFIG_SPI_SPIDEV) || defined(CONFIG_SPI_SPIDEV_MODULE)
-static struct bfin6xx_spi_chip spidev_chip_info = {
+static struct bfin_spi3_chip spidev_chip_info = {
        .enable_dma = true,
 };
 #endif
@@ -1296,7 +1295,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = {
        },
 #endif
 };
-#if defined(CONFIG_SPI_BFIN6XX) || defined(CONFIG_SPI_BFIN6XX_MODULE)
+#if IS_ENABLED(CONFIG_SPI_BFIN_V3)
 /* SPI (0) */
 static struct resource bfin_spi0_resource[] = {
        {
@@ -1337,13 +1336,13 @@ static struct resource bfin_spi1_resource[] = {
 };
 
 /* SPI controller data */
-static struct bfin6xx_spi_master bf60x_spi_master_info0 = {
+static struct bfin_spi3_master bf60x_spi_master_info0 = {
        .num_chipselect = MAX_CTRL_CS + MAX_BLACKFIN_GPIOS,
        .pin_req = {P_SPI0_SCK, P_SPI0_MISO, P_SPI0_MOSI, 0},
 };
 
 static struct platform_device bf60x_spi_master0 = {
-       .name = "bfin-spi",
+       .name = "bfin-spi3",
        .id = 0, /* Bus number */
        .num_resources = ARRAY_SIZE(bfin_spi0_resource),
        .resource = bfin_spi0_resource,
@@ -1352,13 +1351,13 @@ static struct platform_device bf60x_spi_master0 = {
        },
 };
 
-static struct bfin6xx_spi_master bf60x_spi_master_info1 = {
+static struct bfin_spi3_master bf60x_spi_master_info1 = {
        .num_chipselect = MAX_CTRL_CS + MAX_BLACKFIN_GPIOS,
        .pin_req = {P_SPI1_SCK, P_SPI1_MISO, P_SPI1_MOSI, 0},
 };
 
 static struct platform_device bf60x_spi_master1 = {
-       .name = "bfin-spi",
+       .name = "bfin-spi3",
        .id = 1, /* Bus number */
        .num_resources = ARRAY_SIZE(bfin_spi1_resource),
        .resource = bfin_spi1_resource,
@@ -1534,7 +1533,7 @@ static struct platform_device *ezkit_devices[] __initdata = {
        &bfin_sdh_device,
 #endif
 
-#if defined(CONFIG_SPI_BFIN6XX) || defined(CONFIG_SPI_BFIN6XX_MODULE)
+#if IS_ENABLED(CONFIG_SPI_BFIN_V3)
        &bf60x_spi_master0,
        &bf60x_spi_master1,
 #endif
index 1bc2ce6..961d839 100644 (file)
@@ -49,6 +49,7 @@ unsigned long blackfin_iflush_l1_entry[NR_CPUS];
 struct blackfin_initial_pda __cpuinitdata initial_pda_coreb;
 
 enum ipi_message_type {
+       BFIN_IPI_NONE,
        BFIN_IPI_TIMER,
        BFIN_IPI_RESCHEDULE,
        BFIN_IPI_CALL_FUNC,
@@ -72,8 +73,8 @@ static DEFINE_SPINLOCK(stop_lock);
 
 /* Simple FIFO buffer, overflow leads to panic */
 struct ipi_data {
-       unsigned long count;
-       unsigned long bits;
+       atomic_t count;
+       atomic_t bits;
 };
 
 static DEFINE_PER_CPU(struct ipi_data, bfin_ipi);
@@ -146,7 +147,6 @@ static irqreturn_t ipi_handler_int1(int irq, void *dev_instance)
        platform_clear_ipi(cpu, IRQ_SUPPLE_1);
 
        bfin_ipi_data = &__get_cpu_var(bfin_ipi);
-       smp_mb();
        while ((pending = xchg(&bfin_ipi_data->bits, 0)) != 0) {
                msg = 0;
                do {
@@ -170,9 +170,8 @@ static irqreturn_t ipi_handler_int1(int irq, void *dev_instance)
                                ipi_cpu_stop(cpu);
                                break;
                        }
+                       atomic_dec(&bfin_ipi_data->count);
                } while (msg < BITS_PER_LONG);
-
-               smp_mb();
        }
        return IRQ_HANDLED;
 }
@@ -195,12 +194,10 @@ void send_ipi(const struct cpumask *cpumask, enum ipi_message_type msg)
        unsigned long flags;
 
        local_irq_save(flags);
-       smp_mb();
        for_each_cpu(cpu, cpumask) {
                bfin_ipi_data = &per_cpu(bfin_ipi, cpu);
-               smp_mb();
-               set_bit(msg, &bfin_ipi_data->bits);
-               bfin_ipi_data->count++;
+               atomic_set_mask((1 << msg), &bfin_ipi_data->bits);
+               atomic_inc(&bfin_ipi_data->count);
                platform_send_ipi_cpu(cpu, IRQ_SUPPLE_1);
        }
 
@@ -319,7 +316,6 @@ void __cpuinit secondary_start_kernel(void)
        setup_secondary(cpu);
 
        platform_secondary_init(cpu);
-
        /* setup local core timer */
        bfin_local_timer_setup();
 
@@ -335,6 +331,8 @@ void __cpuinit secondary_start_kernel(void)
         */
        calibrate_delay();
 
+       /* We are done with local CPU inits, unblock the boot CPU. */
+       set_cpu_online(cpu, true);
        cpu_startup_entry(CPUHP_ONLINE);
 }
 
index 47b1ec5..eb723e5 100644 (file)
@@ -76,7 +76,7 @@
 
 #define SO_SELECT_ERR_QUEUE    45
 
-#define SO_LL                  46
+#define SO_BUSY_POLL           46
 
 #endif /* _ASM_SOCKET_H */
 
index dbc0852..f0cb1c3 100644 (file)
@@ -74,7 +74,7 @@
 
 #define SO_SELECT_ERR_QUEUE    45
 
-#define SO_LL                  46
+#define SO_BUSY_POLL           46
 
 #endif /* _ASM_SOCKET_H */
 
index 271f412..87bf9ad 100644 (file)
@@ -290,16 +290,16 @@ sys_fw_init (const char *args, int arglen)
        efi_runtime->hdr.signature = EFI_RUNTIME_SERVICES_SIGNATURE;
        efi_runtime->hdr.revision = EFI_RUNTIME_SERVICES_REVISION;
        efi_runtime->hdr.headersize = sizeof(efi_runtime->hdr);
-       efi_runtime->get_time = __pa(&fw_efi_get_time);
-       efi_runtime->set_time = __pa(&efi_unimplemented);
-       efi_runtime->get_wakeup_time = __pa(&efi_unimplemented);
-       efi_runtime->set_wakeup_time = __pa(&efi_unimplemented);
-       efi_runtime->set_virtual_address_map = __pa(&efi_unimplemented);
-       efi_runtime->get_variable = __pa(&efi_unimplemented);
-       efi_runtime->get_next_variable = __pa(&efi_unimplemented);
-       efi_runtime->set_variable = __pa(&efi_unimplemented);
-       efi_runtime->get_next_high_mono_count = __pa(&efi_unimplemented);
-       efi_runtime->reset_system = __pa(&efi_reset_system);
+       efi_runtime->get_time = (void *)__pa(&fw_efi_get_time);
+       efi_runtime->set_time = (void *)__pa(&efi_unimplemented);
+       efi_runtime->get_wakeup_time = (void *)__pa(&efi_unimplemented);
+       efi_runtime->set_wakeup_time = (void *)__pa(&efi_unimplemented);
+       efi_runtime->set_virtual_address_map = (void *)__pa(&efi_unimplemented);
+       efi_runtime->get_variable = (void *)__pa(&efi_unimplemented);
+       efi_runtime->get_next_variable = (void *)__pa(&efi_unimplemented);
+       efi_runtime->set_variable = (void *)__pa(&efi_unimplemented);
+       efi_runtime->get_next_high_mono_count = (void *)__pa(&efi_unimplemented);
+       efi_runtime->reset_system = (void *)__pa(&efi_reset_system);
 
        efi_tables->guid = SAL_SYSTEM_TABLE_GUID;
        efi_tables->table = __pa(sal_systab);
index d3358b7..556d070 100644 (file)
@@ -83,6 +83,6 @@
 
 #define SO_SELECT_ERR_QUEUE    45
 
-#define SO_LL                  46
+#define SO_BUSY_POLL           46
 
 #endif /* _ASM_IA64_SOCKET_H */
index 44aaf46..24be7c8 100644 (file)
@@ -74,6 +74,6 @@
 
 #define SO_SELECT_ERR_QUEUE    45
 
-#define SO_LL                  46
+#define SO_BUSY_POLL           46
 
 #endif /* _ASM_M32R_SOCKET_H */
index 999bf76..08dd1cc 100644 (file)
@@ -64,7 +64,8 @@ static inline __wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr,
                                        __wsum sum)
 {
        unsigned long len_proto = (proto + len) << 8;
-       asm ("ADD    %0, %0, %1\n"
+       asm ("ADDS   %0, %0, %1\n"
+            "ADDCS  %0, %0, #1\n"
             "ADDS   %0, %0, %2\n"
             "ADDCS  %0, %0, #1\n"
             "ADDS   %0, %0, %3\n"
index 3649a8b..deaf45a 100644 (file)
@@ -1,4 +1,3 @@
-CONFIG_EXPERIMENTAL=y
 CONFIG_SYSVIPC=y
 CONFIG_POSIX_MQUEUE=y
 CONFIG_FHANDLE=y
@@ -81,6 +80,9 @@ CONFIG_DETECT_HUNG_TASK=y
 CONFIG_DEBUG_SLAB=y
 CONFIG_DEBUG_SPINLOCK=y
 CONFIG_DEBUG_INFO=y
+CONFIG_KGDB=y
+CONFIG_KGDB_TESTS=y
+CONFIG_KGDB_KDB=y
 CONFIG_EARLY_PRINTK=y
 CONFIG_KEYS=y
 CONFIG_ENCRYPTED_KEYS=y
index 6dece2d..b14232b 100644 (file)
@@ -38,4 +38,7 @@
 #define __ARCH_WANT_SYS_FORK
 
 #endif /* __ASSEMBLY__ */
+
+#define __NR_syscalls         381
+
 #endif /* _ASM_MICROBLAZE_UNISTD_H */
index 5f7fe75..20043b6 100644 (file)
 #define __NR_kcmp              379
 #define __NR_finit_module      380
 
-#define __NR_syscalls          381
-
 #endif /* _UAPI_ASM_MICROBLAZE_UNISTD_H */
index 8adc924..09a5e82 100644 (file)
@@ -141,7 +141,7 @@ void kgdb_arch_exit(void)
 /*
  * Global data
  */
-const struct kgdb_arch arch_kgdb_ops = {
+struct kgdb_arch arch_kgdb_ops = {
 #ifdef __MICROBLAZEEL__
        .gdb_bpt_instr = {0x18, 0x00, 0x0c, 0xba}, /* brki r16, 0x18 */
 #else
index 4b597d9..d9d81c2 100644 (file)
@@ -30,7 +30,6 @@ platforms += sibyte
 platforms += sni
 platforms += txx9
 platforms += vr41xx
-platforms += wrppmc
 
 # include the platform specific files
 include $(patsubst %, $(srctree)/arch/mips/%/Platform, $(platforms))
index beeff43..4758a8f 100644 (file)
@@ -1,6 +1,7 @@
 config MIPS
        bool
        default y
+       select HAVE_CONTEXT_TRACKING
        select HAVE_GENERIC_DMA_COHERENT
        select HAVE_IDE
        select HAVE_OPROFILE
@@ -27,6 +28,7 @@ config MIPS
        select HAVE_GENERIC_HARDIRQS
        select GENERIC_IRQ_PROBE
        select GENERIC_IRQ_SHOW
+       select GENERIC_PCI_IOMAP
        select HAVE_ARCH_JUMP_LABEL
        select ARCH_WANT_IPC_PARSE_VERSION
        select IRQ_FORCED_THREADING
@@ -46,9 +48,6 @@ config MIPS
 
 menu "Machine selection"
 
-config ZONE_DMA
-       bool
-
 choice
        prompt "System type"
        default SGI_IP22
@@ -124,11 +123,14 @@ config BCM47XX
 
 config BCM63XX
        bool "Broadcom BCM63XX based boards"
+       select BOOT_RAW
        select CEVT_R4K
        select CSRC_R4K
        select DMA_NONCOHERENT
        select IRQ_CPU
        select SYS_HAS_CPU_MIPS32_R1
+       select SYS_HAS_CPU_BMIPS4350 if !BCM63XX_CPU_6338 && !BCM63XX_CPU_6345 && !BCM63XX_CPU_6348
+       select NR_CPUS_DEFAULT_2
        select SYS_SUPPORTS_32BIT_KERNEL
        select SYS_SUPPORTS_BIG_ENDIAN
        select SYS_HAS_EARLY_PRINTK
@@ -341,7 +343,6 @@ config MIPS_SEAD3
        select DMA_NONCOHERENT
        select IRQ_CPU
        select IRQ_GIC
-       select MIPS_CPU_SCACHE
        select MIPS_MSC
        select SYS_HAS_CPU_MIPS32_R1
        select SYS_HAS_CPU_MIPS32_R2
@@ -420,7 +421,6 @@ config POWERTV
        select CSRC_POWERTV
        select DMA_NONCOHERENT
        select HW_HAS_PCI
-       select SYS_HAS_EARLY_PRINTK
        select SYS_HAS_CPU_MIPS32_R2
        select SYS_SUPPORTS_32BIT_KERNEL
        select SYS_SUPPORTS_BIG_ENDIAN
@@ -713,46 +713,8 @@ config MIKROTIK_RB532
          Support the Mikrotik(tm) RouterBoard 532 series,
          based on the IDT RC32434 SoC.
 
-config WR_PPMC
-       bool "Wind River PPMC board"
-       select CEVT_R4K
-       select CSRC_R4K
-       select IRQ_CPU
-       select BOOT_ELF32
-       select DMA_NONCOHERENT
-       select HW_HAS_PCI
-       select PCI_GT64XXX_PCI0
-       select SWAP_IO_SPACE
-       select SYS_HAS_CPU_MIPS32_R1
-       select SYS_HAS_CPU_MIPS32_R2
-       select SYS_HAS_CPU_MIPS64_R1
-       select SYS_HAS_CPU_NEVADA
-       select SYS_HAS_CPU_RM7000
-       select SYS_SUPPORTS_32BIT_KERNEL
-       select SYS_SUPPORTS_64BIT_KERNEL
-       select SYS_SUPPORTS_BIG_ENDIAN
-       select SYS_SUPPORTS_LITTLE_ENDIAN
-       help
-         This enables support for the Wind River MIPS32 4KC PPMC evaluation
-         board, which is based on GT64120 bridge chip.
-
-config CAVIUM_OCTEON_SIMULATOR
-       bool "Cavium Networks Octeon Simulator"
-       select CEVT_R4K
-       select 64BIT_PHYS_ADDR
-       select DMA_COHERENT
-       select SYS_SUPPORTS_64BIT_KERNEL
-       select SYS_SUPPORTS_BIG_ENDIAN
-       select SYS_SUPPORTS_HOTPLUG_CPU
-       select SYS_HAS_CPU_CAVIUM_OCTEON
-       select HOLES_IN_ZONE
-       help
-         The Octeon simulator is software performance model of the Cavium
-         Octeon Processor. It supports simulating Octeon processors on x86
-         hardware.
-
-config CAVIUM_OCTEON_REFERENCE_BOARD
-       bool "Cavium Networks Octeon reference board"
+config CAVIUM_OCTEON_SOC
+       bool "Cavium Networks Octeon SoC based boards"
        select CEVT_R4K
        select 64BIT_PHYS_ADDR
        select DMA_COHERENT
@@ -806,6 +768,8 @@ config NLM_XLR_BOARD
        select SYS_HAS_EARLY_PRINTK
        select USB_ARCH_HAS_OHCI if USB_SUPPORT
        select USB_ARCH_HAS_EHCI if USB_SUPPORT
+       select SYS_SUPPORTS_ZBOOT
+       select SYS_SUPPORTS_ZBOOT_UART16550
        help
          Support for systems based on Netlogic XLR and XLS processors.
          Say Y here if you have a XLR or XLS based board.
@@ -832,6 +796,8 @@ config NLM_XLP_BOARD
        select SYNC_R4K
        select SYS_HAS_EARLY_PRINTK
        select USE_OF
+       select SYS_SUPPORTS_ZBOOT
+       select SYS_SUPPORTS_ZBOOT_UART16550
        help
          This board is based on Netlogic XLP Processor.
          Say Y here if you have a XLP based board.
@@ -1031,7 +997,6 @@ config CPU_BIG_ENDIAN
 config CPU_LITTLE_ENDIAN
        bool "Little endian"
        depends on SYS_SUPPORTS_LITTLE_ENDIAN
-       help
 
 endchoice
 
@@ -1964,7 +1929,7 @@ config MIPS_MT_FPAFF
 
 config MIPS_VPE_LOADER
        bool "VPE loader support."
-       depends on SYS_SUPPORTS_MULTITHREADING
+       depends on SYS_SUPPORTS_MULTITHREADING && MODULES
        select CPU_MIPSR2_IRQ_VI
        select CPU_MIPSR2_IRQ_EI
        select MIPS_MT
@@ -2382,6 +2347,19 @@ config SECCOMP
 
          If unsure, say Y. Only embedded should say N here.
 
+config CC_STACKPROTECTOR
+       bool "Enable -fstack-protector buffer overflow detection (EXPERIMENTAL)"
+       help
+         This option turns on the -fstack-protector GCC feature. This
+         feature puts, at the beginning of functions, a canary value on
+         the stack just before the return address, and validates
+         the value just before actually returning.  Stack based buffer
+         overflows (that need to overwrite this return address) now also
+         overwrite the canary, which gets detected and the attack is then
+         neutralized via a kernel panic.
+
+         This feature requires gcc version 4.2 or above.
+
 config USE_OF
        bool
        select OF
@@ -2413,7 +2391,6 @@ config PCI
        bool "Support for PCI controller"
        depends on HW_HAS_PCI
        select PCI_DOMAINS
-       select GENERIC_PCI_IOMAP
        select NO_GENERIC_PCI_IOPORT_MAP
        help
          Find out whether you have a PCI motherboard. PCI is the name of a
@@ -2479,6 +2456,9 @@ config I8253
        select CLKEVT_I8253
        select MIPS_EXTERNAL_TIMER
 
+config ZONE_DMA
+       bool
+
 config ZONE_DMA32
        bool
 
index dd58a04..37f9ef3 100644 (file)
@@ -227,6 +227,10 @@ KBUILD_CPPFLAGS += -DDATAOFFSET=$(if $(dataoffset-y),$(dataoffset-y),0)
 
 LDFLAGS                        += -m $(ld-emul)
 
+ifdef CONFIG_CC_STACKPROTECTOR
+  KBUILD_CFLAGS += -fstack-protector
+endif
+
 ifdef CONFIG_MIPS
 CHECKFLAGS += $(shell $(CC) $(KBUILD_CFLAGS) -dM -E -x c /dev/null | \
        egrep -vw '__GNUC_(|MINOR_|PATCHLEVEL_)_' | \
index 479dd4b..07eac58 100644 (file)
@@ -132,7 +132,7 @@ static void __init ap136_pci_init(u8 *eeprom)
        ath79_register_pci();
 }
 #else
-static inline void ap136_pci_init(void) {}
+static inline void ap136_pci_init(u8 *eeprom) {}
 #endif /* CONFIG_PCI */
 
 static void __init ap136_setup(void)
index 5639662..b78306c 100644 (file)
@@ -1,6 +1,10 @@
 menu "CPU support"
        depends on BCM63XX
 
+config BCM63XX_CPU_3368
+       bool "support 3368 CPU"
+       select HW_HAS_PCI
+
 config BCM63XX_CPU_6328
        bool "support 6328 CPU"
        select HW_HAS_PCI
@@ -8,14 +12,9 @@ config BCM63XX_CPU_6328
 config BCM63XX_CPU_6338
        bool "support 6338 CPU"
        select HW_HAS_PCI
-       select USB_ARCH_HAS_OHCI
-       select USB_OHCI_BIG_ENDIAN_DESC
-       select USB_OHCI_BIG_ENDIAN_MMIO
 
 config BCM63XX_CPU_6345
        bool "support 6345 CPU"
-       select USB_OHCI_BIG_ENDIAN_DESC
-       select USB_OHCI_BIG_ENDIAN_MMIO
 
 config BCM63XX_CPU_6348
        bool "support 6348 CPU"
index 9c0ddaf..5b974eb 100644 (file)
 #include <bcm63xx_dev_usb_usbd.h>
 #include <board_bcm963xx.h>
 
+#include <uapi/linux/bcm933xx_hcs.h>
+
 #define PFX    "board_bcm963xx: "
 
+#define HCS_OFFSET_128K                        0x20000
+
 static struct board_info board;
 
 /*
+ * known 3368 boards
+ */
+#ifdef CONFIG_BCM63XX_CPU_3368
+static struct board_info __initdata board_cvg834g = {
+       .name                           = "CVG834G_E15R3921",
+       .expected_cpu_id                = 0x3368,
+
+       .has_uart0                      = 1,
+       .has_uart1                      = 1,
+
+       .has_enet0                      = 1,
+       .has_pci                        = 1,
+
+       .enet0 = {
+               .has_phy                = 1,
+               .use_internal_phy       = 1,
+       },
+
+       .leds = {
+               {
+                       .name           = "CVG834G:green:power",
+                       .gpio           = 37,
+                       .default_trigger= "default-on",
+               },
+       },
+
+       .ephy_reset_gpio                = 36,
+       .ephy_reset_gpio_flags          = GPIOF_INIT_HIGH,
+};
+#endif
+
+/*
  * known 6328 boards
  */
 #ifdef CONFIG_BCM63XX_CPU_6328
@@ -639,6 +675,9 @@ static struct board_info __initdata board_DWVS0 = {
  * all boards
  */
 static const struct board_info __initconst *bcm963xx_boards[] = {
+#ifdef CONFIG_BCM63XX_CPU_3368
+       &board_cvg834g,
+#endif
 #ifdef CONFIG_BCM63XX_CPU_6328
        &board_96328avng,
 #endif
@@ -722,8 +761,9 @@ void __init board_prom_init(void)
        unsigned int i;
        u8 *boot_addr, *cfe;
        char cfe_version[32];
-       char *board_name;
+       char *board_name = NULL;
        u32 val;
+       struct bcm_hcs *hcs;
 
        /* read base address of boot chip select (0)
         * 6328/6362 do not have MPI but boot from a fixed address
@@ -747,7 +787,12 @@ void __init board_prom_init(void)
 
        bcm63xx_nvram_init(boot_addr + BCM963XX_NVRAM_OFFSET);
 
-       board_name = bcm63xx_nvram_get_name();
+       if (BCMCPU_IS_3368()) {
+               hcs = (struct bcm_hcs *)boot_addr;
+               board_name = hcs->filename;
+       } else {
+               board_name = bcm63xx_nvram_get_name();
+       }
        /* find board by name */
        for (i = 0; i < ARRAY_SIZE(bcm963xx_boards); i++) {
                if (strncmp(board_name, bcm963xx_boards[i]->name, 16))
@@ -877,5 +922,9 @@ int __init board_register_devices(void)
 
        platform_device_register(&bcm63xx_gpio_leds);
 
+       if (board.ephy_reset_gpio && board.ephy_reset_gpio_flags)
+               gpio_request_one(board.ephy_reset_gpio,
+                               board.ephy_reset_gpio_flags, "ephy-reset");
+
        return 0;
 }
index c726a97..43da4ae 100644 (file)
@@ -84,7 +84,7 @@ static void enetx_set(struct clk *clk, int enable)
        else
                clk_disable_unlocked(&clk_enet_misc);
 
-       if (BCMCPU_IS_6358()) {
+       if (BCMCPU_IS_3368() || BCMCPU_IS_6358()) {
                u32 mask;
 
                if (clk->id == 0)
@@ -110,9 +110,8 @@ static struct clk clk_enet1 = {
  */
 static void ephy_set(struct clk *clk, int enable)
 {
-       if (!BCMCPU_IS_6358())
-               return;
-       bcm_hwclock_set(CKCTL_6358_EPHY_EN, enable);
+       if (BCMCPU_IS_3368() || BCMCPU_IS_6358())
+               bcm_hwclock_set(CKCTL_6358_EPHY_EN, enable);
 }
 
 
@@ -155,9 +154,10 @@ static struct clk clk_enetsw = {
  */
 static void pcm_set(struct clk *clk, int enable)
 {
-       if (!BCMCPU_IS_6358())
-               return;
-       bcm_hwclock_set(CKCTL_6358_PCM_EN, enable);
+       if (BCMCPU_IS_3368())
+               bcm_hwclock_set(CKCTL_3368_PCM_EN, enable);
+       if (BCMCPU_IS_6358())
+               bcm_hwclock_set(CKCTL_6358_PCM_EN, enable);
 }
 
 static struct clk clk_pcm = {
@@ -211,7 +211,7 @@ static void spi_set(struct clk *clk, int enable)
                mask = CKCTL_6338_SPI_EN;
        else if (BCMCPU_IS_6348())
                mask = CKCTL_6348_SPI_EN;
-       else if (BCMCPU_IS_6358())
+       else if (BCMCPU_IS_3368() || BCMCPU_IS_6358())
                mask = CKCTL_6358_SPI_EN;
        else if (BCMCPU_IS_6362())
                mask = CKCTL_6362_SPI_EN;
@@ -318,6 +318,18 @@ unsigned long clk_get_rate(struct clk *clk)
 
 EXPORT_SYMBOL(clk_get_rate);
 
+int clk_set_rate(struct clk *clk, unsigned long rate)
+{
+       return 0;
+}
+EXPORT_SYMBOL_GPL(clk_set_rate);
+
+long clk_round_rate(struct clk *clk, unsigned long rate)
+{
+       return 0;
+}
+EXPORT_SYMBOL_GPL(clk_round_rate);
+
 struct clk *clk_get(struct device *dev, const char *id)
 {
        if (!strcmp(id, "enet0"))
@@ -338,7 +350,7 @@ struct clk *clk_get(struct device *dev, const char *id)
                return &clk_xtm;
        if (!strcmp(id, "periph"))
                return &clk_periph;
-       if (BCMCPU_IS_6358() && !strcmp(id, "pcm"))
+       if ((BCMCPU_IS_3368() || BCMCPU_IS_6358()) && !strcmp(id, "pcm"))
                return &clk_pcm;
        if ((BCMCPU_IS_6362() || BCMCPU_IS_6368()) && !strcmp(id, "ipsec"))
                return &clk_ipsec;
index 79fe32d..7e17374 100644 (file)
@@ -29,6 +29,14 @@ static u8 bcm63xx_cpu_rev;
 static unsigned int bcm63xx_cpu_freq;
 static unsigned int bcm63xx_memory_size;
 
+static const unsigned long bcm3368_regs_base[] = {
+       __GEN_CPU_REGS_TABLE(3368)
+};
+
+static const int bcm3368_irqs[] = {
+       __GEN_CPU_IRQ_TABLE(3368)
+};
+
 static const unsigned long bcm6328_regs_base[] = {
        __GEN_CPU_REGS_TABLE(6328)
 };
@@ -116,6 +124,9 @@ unsigned int bcm63xx_get_memory_size(void)
 static unsigned int detect_cpu_clock(void)
 {
        switch (bcm63xx_get_cpu_id()) {
+       case BCM3368_CPU_ID:
+               return 300000000;
+
        case BCM6328_CPU_ID:
        {
                unsigned int tmp, mips_pll_fcvo;
@@ -266,7 +277,7 @@ static unsigned int detect_memory_size(void)
                banks = (val & SDRAM_CFG_BANK_MASK) ? 2 : 1;
        }
 
-       if (BCMCPU_IS_6358() || BCMCPU_IS_6368()) {
+       if (BCMCPU_IS_3368() || BCMCPU_IS_6358() || BCMCPU_IS_6368()) {
                val = bcm_memc_readl(MEMC_CFG_REG);
                rows = (val & MEMC_CFG_ROW_MASK) >> MEMC_CFG_ROW_SHIFT;
                cols = (val & MEMC_CFG_COL_MASK) >> MEMC_CFG_COL_SHIFT;
@@ -302,10 +313,17 @@ void __init bcm63xx_cpu_init(void)
                chipid_reg = BCM_6345_PERF_BASE;
                break;
        case CPU_BMIPS4350:
-               if ((read_c0_prid() & 0xf0) == 0x10)
+               switch ((read_c0_prid() & 0xff)) {
+               case 0x04:
+                       chipid_reg = BCM_3368_PERF_BASE;
+                       break;
+               case 0x10:
                        chipid_reg = BCM_6345_PERF_BASE;
-               else
+                       break;
+               default:
                        chipid_reg = BCM_6368_PERF_BASE;
+                       break;
+               }
                break;
        }
 
@@ -322,6 +340,10 @@ void __init bcm63xx_cpu_init(void)
        bcm63xx_cpu_rev = (tmp & REV_REVID_MASK) >> REV_REVID_SHIFT;
 
        switch (bcm63xx_cpu_id) {
+       case BCM3368_CPU_ID:
+               bcm63xx_regs_base = bcm3368_regs_base;
+               bcm63xx_irqs = bcm3368_irqs;
+               break;
        case BCM6328_CPU_ID:
                bcm63xx_regs_base = bcm6328_regs_base;
                bcm63xx_irqs = bcm6328_irqs;
index 588d1ec..172dd83 100644 (file)
@@ -71,6 +71,7 @@ static int __init bcm63xx_detect_flash_type(void)
        case BCM6348_CPU_ID:
                /* no way to auto detect so assume parallel */
                return BCM63XX_FLASH_TYPE_PARALLEL;
+       case BCM3368_CPU_ID:
        case BCM6358_CPU_ID:
                val = bcm_gpio_readl(GPIO_STRAPBUS_REG);
                if (val & STRAPBUS_6358_BOOT_SEL_PARALLEL)
index 3065bb6..d12daed 100644 (file)
@@ -37,7 +37,8 @@ static __init void bcm63xx_spi_regs_init(void)
 {
        if (BCMCPU_IS_6338() || BCMCPU_IS_6348())
                bcm63xx_regs_spi = bcm6348_regs_spi;
-       if (BCMCPU_IS_6358() || BCMCPU_IS_6362() || BCMCPU_IS_6368())
+       if (BCMCPU_IS_3368() || BCMCPU_IS_6358() ||
+               BCMCPU_IS_6362() || BCMCPU_IS_6368())
                bcm63xx_regs_spi = bcm6358_regs_spi;
 }
 #else
@@ -87,7 +88,8 @@ int __init bcm63xx_spi_register(void)
                spi_pdata.msg_ctl_width = SPI_6348_MSG_CTL_WIDTH;
        }
 
-       if (BCMCPU_IS_6358() || BCMCPU_IS_6362() || BCMCPU_IS_6368()) {
+       if (BCMCPU_IS_3368() || BCMCPU_IS_6358() || BCMCPU_IS_6362() ||
+               BCMCPU_IS_6368()) {
                spi_resources[0].end += BCM_6358_RSET_SPI_SIZE - 1;
                spi_pdata.fifo_size = SPI_6358_MSG_DATA_SIZE;
                spi_pdata.msg_type_shift = SPI_6358_MSG_TYPE_SHIFT;
index d6e42c6..3bc7f3b 100644 (file)
@@ -54,7 +54,8 @@ int __init bcm63xx_uart_register(unsigned int id)
        if (id >= ARRAY_SIZE(bcm63xx_uart_devices))
                return -ENODEV;
 
-       if (id == 1 && (!BCMCPU_IS_6358() && !BCMCPU_IS_6368()))
+       if (id == 1 && (!BCMCPU_IS_3368() && !BCMCPU_IS_6358() &&
+               !BCMCPU_IS_6368()))
                return -ENODEV;
 
        if (id == 0) {
index c0ab388..1525f8a 100644 (file)
@@ -27,6 +27,17 @@ static void __internal_irq_unmask_32(unsigned int irq) __maybe_unused;
 static void __internal_irq_unmask_64(unsigned int irq) __maybe_unused;
 
 #ifndef BCMCPU_RUNTIME_DETECT
+#ifdef CONFIG_BCM63XX_CPU_3368
+#define irq_stat_reg           PERF_IRQSTAT_3368_REG
+#define irq_mask_reg           PERF_IRQMASK_3368_REG
+#define irq_bits               32
+#define is_ext_irq_cascaded    0
+#define ext_irq_start          0
+#define ext_irq_end            0
+#define ext_irq_count          4
+#define ext_irq_cfg_reg1       PERF_EXTIRQ_CFG_REG_3368
+#define ext_irq_cfg_reg2       0
+#endif
 #ifdef CONFIG_BCM63XX_CPU_6328
 #define irq_stat_reg           PERF_IRQSTAT_6328_REG
 #define irq_mask_reg           PERF_IRQMASK_6328_REG
@@ -140,6 +151,13 @@ static void bcm63xx_init_irq(void)
        irq_mask_addr = bcm63xx_regset_address(RSET_PERF);
 
        switch (bcm63xx_get_cpu_id()) {
+       case BCM3368_CPU_ID:
+               irq_stat_addr += PERF_IRQSTAT_3368_REG;
+               irq_mask_addr += PERF_IRQMASK_3368_REG;
+               irq_bits = 32;
+               ext_irq_count = 4;
+               ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_3368;
+               break;
        case BCM6328_CPU_ID:
                irq_stat_addr += PERF_IRQSTAT_6328_REG;
                irq_mask_addr += PERF_IRQMASK_6328_REG;
@@ -294,6 +312,10 @@ asmlinkage void plat_irq_dispatch(void)
 
                if (cause & CAUSEF_IP7)
                        do_IRQ(7);
+               if (cause & CAUSEF_IP0)
+                       do_IRQ(0);
+               if (cause & CAUSEF_IP1)
+                       do_IRQ(1);
                if (cause & CAUSEF_IP2)
                        dispatch_internal();
                if (!is_ext_irq_cascaded) {
@@ -475,6 +497,7 @@ static int bcm63xx_external_irq_set_type(struct irq_data *d,
                        reg &= ~EXTIRQ_CFG_BOTHEDGE_6348(irq);
                break;
 
+       case BCM3368_CPU_ID:
        case BCM6328_CPU_ID:
        case BCM6338_CPU_ID:
        case BCM6345_CPU_ID:
index a4b8864..e652e57 100644 (file)
@@ -42,6 +42,7 @@ void __init bcm63xx_nvram_init(void *addr)
 {
        unsigned int check_len;
        u32 crc, expected_crc;
+       u8 hcs_mac_addr[ETH_ALEN] = { 0x00, 0x10, 0x18, 0xff, 0xff, 0xff };
 
        /* extract nvram data */
        memcpy(&nvram, addr, sizeof(nvram));
@@ -62,6 +63,15 @@ void __init bcm63xx_nvram_init(void *addr)
        if (crc != expected_crc)
                pr_warn("nvram checksum failed, contents may be invalid (expected %08x, got %08x)\n",
                        expected_crc, crc);
+
+       /* Cable modems have a different NVRAM which is embedded in the eCos
+        * firmware and not easily extractible, give at least a MAC address
+        * pool.
+        */
+       if (BCMCPU_IS_3368()) {
+               memcpy(nvram.mac_addr_base, hcs_mac_addr, ETH_ALEN);
+               nvram.mac_addr_count = 2;
+       }
 }
 
 u8 *bcm63xx_nvram_get_name(void)
index fd69808..8ac4e09 100644 (file)
@@ -8,7 +8,11 @@
 
 #include <linux/init.h>
 #include <linux/bootmem.h>
+#include <linux/smp.h>
 #include <asm/bootinfo.h>
+#include <asm/bmips.h>
+#include <asm/smp-ops.h>
+#include <asm/mipsregs.h>
 #include <bcm63xx_board.h>
 #include <bcm63xx_cpu.h>
 #include <bcm63xx_io.h>
@@ -26,7 +30,9 @@ void __init prom_init(void)
        bcm_wdt_writel(WDT_STOP_2, WDT_CTL_REG);
 
        /* disable all hardware blocks clock for now */
-       if (BCMCPU_IS_6328())
+       if (BCMCPU_IS_3368())
+               mask = CKCTL_3368_ALL_SAFE_EN;
+       else if (BCMCPU_IS_6328())
                mask = CKCTL_6328_ALL_SAFE_EN;
        else if (BCMCPU_IS_6338())
                mask = CKCTL_6338_ALL_SAFE_EN;
@@ -52,6 +58,47 @@ void __init prom_init(void)
 
        /* do low level board init */
        board_prom_init();
+
+       if (IS_ENABLED(CONFIG_CPU_BMIPS4350) && IS_ENABLED(CONFIG_SMP)) {
+               /* set up SMP */
+               register_smp_ops(&bmips_smp_ops);
+
+               /*
+                * BCM6328 might not have its second CPU enabled, while BCM6358
+                * needs special handling for its shared TLB, so disable SMP
+                * for now.
+                */
+               if (BCMCPU_IS_6328()) {
+                       reg = bcm_readl(BCM_6328_OTP_BASE +
+                                       OTP_USER_BITS_6328_REG(3));
+
+                       if (reg & OTP_6328_REG3_TP1_DISABLED)
+                               bmips_smp_enabled = 0;
+               } else if (BCMCPU_IS_6358()) {
+                       bmips_smp_enabled = 0;
+               }
+
+               if (!bmips_smp_enabled)
+                       return;
+
+               /*
+                * The bootloader has set up the CPU1 reset vector at
+                * 0xa000_0200.
+                * This conflicts with the special interrupt vector (IV).
+                * The bootloader has also set up CPU1 to respond to the wrong
+                * IPI interrupt.
+                * Here we will start up CPU1 in the background and ask it to
+                * reconfigure itself then go back to sleep.
+                */
+               memcpy((void *)0xa0000200, &bmips_smp_movevec, 0x20);
+               __sync();
+               set_c0_cause(C_SW0);
+               cpumask_set_cpu(1, &bmips_booted_mask);
+
+               /*
+                * FIXME: we really should have some sort of hazard barrier here
+                */
+       }
 }
 
 void __init prom_free_prom_memory(void)
index 317931c..acbeb1f 100644 (file)
        [BCM63XX_RESET_PCIE]            = BCM## __cpu ##_RESET_PCIE,    \
        [BCM63XX_RESET_PCIE_EXT]        = BCM## __cpu ##_RESET_PCIE_EXT,
 
+#define BCM3368_RESET_SPI      SOFTRESET_3368_SPI_MASK
+#define BCM3368_RESET_ENET     SOFTRESET_3368_ENET_MASK
+#define BCM3368_RESET_USBH     0
+#define BCM3368_RESET_USBD     SOFTRESET_3368_USBS_MASK
+#define BCM3368_RESET_DSL      0
+#define BCM3368_RESET_SAR      0
+#define BCM3368_RESET_EPHY     SOFTRESET_3368_EPHY_MASK
+#define BCM3368_RESET_ENETSW   0
+#define BCM3368_RESET_PCM      SOFTRESET_3368_PCM_MASK
+#define BCM3368_RESET_MPI      SOFTRESET_3368_MPI_MASK
+#define BCM3368_RESET_PCIE     0
+#define BCM3368_RESET_PCIE_EXT 0
+
 #define BCM6328_RESET_SPI      SOFTRESET_6328_SPI_MASK
 #define BCM6328_RESET_ENET     0
 #define BCM6328_RESET_USBH     SOFTRESET_6328_USBH_MASK
 /*
  * core reset bits
  */
+static const u32 bcm3368_reset_bits[] = {
+       __GEN_RESET_BITS_TABLE(3368)
+};
+
 static const u32 bcm6328_reset_bits[] = {
        __GEN_RESET_BITS_TABLE(6328)
 };
@@ -146,7 +163,10 @@ static int reset_reg;
 
 static int __init bcm63xx_reset_bits_init(void)
 {
-       if (BCMCPU_IS_6328()) {
+       if (BCMCPU_IS_3368()) {
+               reset_reg = PERF_SOFTRESET_6358_REG;
+               bcm63xx_reset_bits = bcm3368_reset_bits;
+       } else if (BCMCPU_IS_6328()) {
                reset_reg = PERF_SOFTRESET_6328_REG;
                bcm63xx_reset_bits = bcm6328_reset_bits;
        } else if (BCMCPU_IS_6338()) {
@@ -170,6 +190,13 @@ static int __init bcm63xx_reset_bits_init(void)
 }
 #else
 
+#ifdef CONFIG_BCM63XX_CPU_3368
+static const u32 bcm63xx_reset_bits[] = {
+       __GEN_RESET_BITS_TABLE(3368)
+};
+#define reset_reg PERF_SOFTRESET_6358_REG
+#endif
+
 #ifdef CONFIG_BCM63XX_CPU_6328
 static const u32 bcm63xx_reset_bits[] = {
        __GEN_RESET_BITS_TABLE(6328)
index 24a2444..6660c7d 100644 (file)
@@ -68,6 +68,9 @@ void bcm63xx_machine_reboot(void)
 
        /* mask and clear all external irq */
        switch (bcm63xx_get_cpu_id()) {
+       case BCM3368_CPU_ID:
+               perf_regs[0] = PERF_EXTIRQ_CFG_REG_3368;
+               break;
        case BCM6328_CPU_ID:
                perf_regs[0] = PERF_EXTIRQ_CFG_REG_6328;
                break;
index bbaa1d4..bb1dbf4 100644 (file)
@@ -18,6 +18,8 @@ BOOT_HEAP_SIZE := 0x400000
 # Disable Function Tracer
 KBUILD_CFLAGS := $(shell echo $(KBUILD_CFLAGS) | sed -e "s/-pg//")
 
+KBUILD_CFLAGS := $(filter-out -fstack-protector, $(KBUILD_CFLAGS))
+
 KBUILD_CFLAGS := $(LINUXINCLUDE) $(KBUILD_CFLAGS) -D__KERNEL__ \
        -DBOOT_HEAP_SIZE=$(BOOT_HEAP_SIZE) -D"VMLINUX_LOAD_ADDRESS_ULL=$(VMLINUX_LOAD_ADDRESS)ull"
 
index 1c7b739..c01d343 100644 (file)
 #define PORT(offset) (UART0_BASE + (4 * offset))
 #endif
 
+#ifdef CONFIG_CPU_XLR
+#define UART0_BASE  0x1EF14000
+#define PORT(offset) (CKSEG1ADDR(UART0_BASE) + (4 * offset))
+#define IOTYPE unsigned int
+#endif
+
+#ifdef CONFIG_CPU_XLP
+#define UART0_BASE  0x18030100
+#define PORT(offset) (CKSEG1ADDR(UART0_BASE) + (4 * offset))
+#define IOTYPE unsigned int
+#endif
+
+#ifndef IOTYPE
+#define IOTYPE char
+#endif
+
 #ifndef PORT
 #error please define the serial port address for your own machine
 #endif
 
 static inline unsigned int serial_in(int offset)
 {
-       return *((char *)PORT(offset));
+       return *((volatile IOTYPE *)PORT(offset)) & 0xFF;
 }
 
 static inline void serial_out(int offset, int value)
 {
-       *((char *)PORT(offset)) = value;
+       *((volatile IOTYPE *)PORT(offset)) = value & 0xFF;
 }
 
 void putc(char c)
 {
-       int timeout = 1024;
+       int timeout = 1000000;
 
        while (((serial_in(UART_LSR) & UART_LSR_THRE) == 0) && (timeout-- > 0))
                ;
index 75a6df7..227705d 100644 (file)
@@ -10,6 +10,10 @@ config CAVIUM_CN63XXP1
          non-CN63XXP1 hardware, so it is recommended to select "n"
          unless it is known the workarounds are needed.
 
+endif # CPU_CAVIUM_OCTEON
+
+if CAVIUM_OCTEON_SOC
+
 config CAVIUM_OCTEON_2ND_KERNEL
        bool "Build the kernel to be used as a 2nd kernel on the same chip"
        default "n"
@@ -19,17 +23,6 @@ config CAVIUM_OCTEON_2ND_KERNEL
          with this option to be run at the same time as one built without this
          option.
 
-config CAVIUM_OCTEON_HW_FIX_UNALIGNED
-       bool "Enable hardware fixups of unaligned loads and stores"
-       default "y"
-       help
-         Configure the Octeon hardware to automatically fix unaligned loads
-         and stores. Normally unaligned accesses are fixed using a kernel
-         exception handler. This option enables the hardware automatic fixups,
-         which requires only an extra 3 cycles. Disable this option if you
-         are running code that relies on address exceptions on unaligned
-         accesses.
-
 config CAVIUM_OCTEON_CVMSEG_SIZE
        int "Number of L1 cache lines reserved for CVMSEG memory"
        range 0 54
@@ -103,4 +96,4 @@ config OCTEON_ILM
          To compile this driver as a module, choose M here.  The module
          will be called octeon-ilm
 
-endif # CPU_CAVIUM_OCTEON
+endif # CAVIUM_OCTEON_SOC
index 3595aff..4e95204 100644 (file)
 CFLAGS_octeon-platform.o = -I$(src)/../../../scripts/dtc/libfdt
 CFLAGS_setup.o = -I$(src)/../../../scripts/dtc/libfdt
 
-obj-y := cpu.o setup.o serial.o octeon-platform.o octeon-irq.o csrc-octeon.o
-obj-y += dma-octeon.o flash_setup.o
+obj-y := cpu.o setup.o octeon-platform.o octeon-irq.o csrc-octeon.o
+obj-y += dma-octeon.o
 obj-y += octeon-memcpy.o
 obj-y += executive/
 
+obj-$(CONFIG_MTD)                    += flash_setup.o
 obj-$(CONFIG_SMP)                    += smp.o
 obj-$(CONFIG_OCTEON_ILM)             += oct_ilm.o
 
index 1e43ccf..8a301cb 100644 (file)
@@ -1,11 +1,11 @@
 #
 # Cavium Octeon
 #
-platform-$(CONFIG_CPU_CAVIUM_OCTEON)   += cavium-octeon/
-cflags-$(CONFIG_CPU_CAVIUM_OCTEON)     +=                              \
+platform-$(CONFIG_CAVIUM_OCTEON_SOC)   += cavium-octeon/
+cflags-$(CONFIG_CAVIUM_OCTEON_SOC)     +=                              \
                -I$(srctree)/arch/mips/include/asm/mach-cavium-octeon
 ifdef CONFIG_CAVIUM_OCTEON_2ND_KERNEL
-load-$(CONFIG_CPU_CAVIUM_OCTEON)       += 0xffffffff84100000
+load-$(CONFIG_CAVIUM_OCTEON_SOC)       += 0xffffffff84100000
 else
-load-$(CONFIG_CPU_CAVIUM_OCTEON)       += 0xffffffff81100000
+load-$(CONFIG_CAVIUM_OCTEON_SOC)       += 0xffffffff81100000
 endif
index 7c64977..0a1283c 100644 (file)
@@ -181,6 +181,11 @@ int cvmx_helper_board_get_mii_address(int ipd_port)
                        return ipd_port - 16 + 4;
                else
                        return -1;
+       case CVMX_BOARD_TYPE_UBNT_E100:
+               if (ipd_port >= 0 && ipd_port <= 2)
+                       return 7 - ipd_port;
+               else
+                       return -1;
        }
 
        /* Some unknown board. Somebody forgot to update this function... */
@@ -706,6 +711,14 @@ int __cvmx_helper_board_hardware_enable(int interface)
                                }
                        }
                }
+       } else if (cvmx_sysinfo_get()->board_type ==
+                       CVMX_BOARD_TYPE_UBNT_E100) {
+               cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(0, interface), 0);
+               cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(0, interface), 0x10);
+               cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(1, interface), 0);
+               cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(1, interface), 0x10);
+               cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(2, interface), 0);
+               cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(2, interface), 0x10);
        }
        return 0;
 }
index 389512e..7b746e7 100644 (file)
@@ -490,8 +490,15 @@ int __init octeon_prune_device_tree(void)
 
                if (alias_prop) {
                        uart = fdt_path_offset(initial_boot_params, alias_prop);
-                       if (uart_mask & (1 << i))
+                       if (uart_mask & (1 << i)) {
+                               __be32 f;
+
+                               f = cpu_to_be32(octeon_get_io_clock_rate());
+                               fdt_setprop_inplace(initial_boot_params,
+                                                   uart, "clock-frequency",
+                                                   &f, sizeof(f));
                                continue;
+                       }
                        pr_debug("Deleting uart%d\n", i);
                        fdt_nop_node(initial_boot_params, uart);
                        fdt_nop_property(initial_boot_params, aliases,
diff --git a/arch/mips/cavium-octeon/serial.c b/arch/mips/cavium-octeon/serial.c
deleted file mode 100644 (file)
index f393f65..0000000
+++ /dev/null
@@ -1,109 +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) 2004-2007 Cavium Networks
- */
-#include <linux/console.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/serial.h>
-#include <linux/serial_8250.h>
-#include <linux/serial_reg.h>
-#include <linux/tty.h>
-#include <linux/irq.h>
-
-#include <asm/time.h>
-
-#include <asm/octeon/octeon.h>
-
-#define DEBUG_UART 1
-
-unsigned int octeon_serial_in(struct uart_port *up, int offset)
-{
-       int rv = cvmx_read_csr((uint64_t)(up->membase + (offset << 3)));
-       if (offset == UART_IIR && (rv & 0xf) == 7) {
-               /* Busy interrupt, read the USR (39) and try again. */
-               cvmx_read_csr((uint64_t)(up->membase + (39 << 3)));
-               rv = cvmx_read_csr((uint64_t)(up->membase + (offset << 3)));
-       }
-       return rv;
-}
-
-void octeon_serial_out(struct uart_port *up, int offset, int value)
-{
-       /*
-        * If bits 6 or 7 of the OCTEON UART's LCR are set, it quits
-        * working.
-        */
-       if (offset == UART_LCR)
-               value &= 0x9f;
-       cvmx_write_csr((uint64_t)(up->membase + (offset << 3)), (u8)value);
-}
-
-static int octeon_serial_probe(struct platform_device *pdev)
-{
-       int irq, res;
-       struct resource *res_mem;
-       struct uart_8250_port up;
-
-       /* All adaptors have an irq.  */
-       irq = platform_get_irq(pdev, 0);
-       if (irq < 0)
-               return irq;
-
-       memset(&up, 0, sizeof(up));
-
-       up.port.flags = ASYNC_SKIP_TEST | UPF_SHARE_IRQ | UPF_FIXED_TYPE;
-       up.port.type = PORT_OCTEON;
-       up.port.iotype = UPIO_MEM;
-       up.port.regshift = 3;
-       up.port.dev = &pdev->dev;
-
-       if (octeon_is_simulation())
-               /* Make simulator output fast*/
-               up.port.uartclk = 115200 * 16;
-       else
-               up.port.uartclk = octeon_get_io_clock_rate();
-
-       up.port.serial_in = octeon_serial_in;
-       up.port.serial_out = octeon_serial_out;
-       up.port.irq = irq;
-
-       res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (res_mem == NULL) {
-               dev_err(&pdev->dev, "found no memory resource\n");
-               return -ENXIO;
-       }
-       up.port.mapbase = res_mem->start;
-       up.port.membase = ioremap(res_mem->start, resource_size(res_mem));
-
-       res = serial8250_register_8250_port(&up);
-
-       return res >= 0 ? 0 : res;
-}
-
-static struct of_device_id octeon_serial_match[] = {
-       {
-               .compatible = "cavium,octeon-3860-uart",
-       },
-       {},
-};
-MODULE_DEVICE_TABLE(of, octeon_serial_match);
-
-static struct platform_driver octeon_serial_driver = {
-       .probe          = octeon_serial_probe,
-       .driver         = {
-               .owner  = THIS_MODULE,
-               .name   = "octeon_serial",
-               .of_match_table = octeon_serial_match,
-       },
-};
-
-static int __init octeon_serial_init(void)
-{
-       return platform_driver_register(&octeon_serial_driver);
-}
-late_initcall(octeon_serial_init);
index 01b1b3f..48b08eb 100644 (file)
@@ -7,6 +7,7 @@
  * Copyright (C) 2008, 2009 Wind River Systems
  *   written by Ralf Baechle <ralf@linux-mips.org>
  */
+#include <linux/compiler.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/console.h>
 #include <asm/octeon/pci-octeon.h>
 #include <asm/octeon/cvmx-mio-defs.h>
 
-#ifdef CONFIG_CAVIUM_DECODE_RSL
-extern void cvmx_interrupt_rsl_decode(void);
-extern int __cvmx_interrupt_ecc_report_single_bit_errors;
-extern void cvmx_interrupt_rsl_enable(void);
-#endif
-
 extern struct plat_smp_ops octeon_smp_ops;
 
 #ifdef CONFIG_PCI
@@ -463,18 +458,6 @@ static void octeon_halt(void)
 }
 
 /**
- * Handle all the error condition interrupts that might occur.
- *
- */
-#ifdef CONFIG_CAVIUM_DECODE_RSL
-static irqreturn_t octeon_rlm_interrupt(int cpl, void *dev_id)
-{
-       cvmx_interrupt_rsl_decode();
-       return IRQ_HANDLED;
-}
-#endif
-
-/**
  * Return a string representing the system type
  *
  * Returns
@@ -712,7 +695,7 @@ void __init prom_init(void)
        if (cvmx_read_csr(CVMX_L2D_FUS3) & (3ull << 34)) {
                pr_info("Skipping L2 locking due to reduced L2 cache size\n");
        } else {
-               uint32_t ebase = read_c0_ebase() & 0x3ffff000;
+               uint32_t __maybe_unused ebase = read_c0_ebase() & 0x3ffff000;
 #ifdef CONFIG_CAVIUM_OCTEON_LOCK_L2_TLB
                /* TLB refill */
                cvmx_l2c_lock_mem_region(ebase, 0x100);
@@ -996,7 +979,7 @@ void __init plat_mem_setup(void)
        cvmx_bootmem_unlock();
        /* Add the memory region for the kernel. */
        kernel_start = (unsigned long) _text;
-       kernel_size = ALIGN(_end - _text, 0x100000);
+       kernel_size = _end - _text;
 
        /* Adjust for physical offset. */
        kernel_start &= ~0xffffffff80000000ULL;
@@ -1064,15 +1047,6 @@ void prom_free_prom_memory(void)
                        panic("Core-14449 WAR not in place (%04x).\n"
                              "Please build kernel with proper options (CONFIG_CAVIUM_CN63XXP1).", insn);
        }
-#ifdef CONFIG_CAVIUM_DECODE_RSL
-       cvmx_interrupt_rsl_enable();
-
-       /* Add an interrupt handler for general failures. */
-       if (request_irq(OCTEON_IRQ_RML, octeon_rlm_interrupt, IRQF_SHARED,
-                       "RML/RSL", octeon_rlm_interrupt)) {
-               panic("Unable to request_irq(OCTEON_IRQ_RML)");
-       }
-#endif
 }
 
 int octeon_prune_device_tree(void);
index 014ba4b..dace582 100644 (file)
@@ -1,13 +1,11 @@
-CONFIG_CAVIUM_OCTEON_REFERENCE_BOARD=y
+CONFIG_CAVIUM_OCTEON_SOC=y
 CONFIG_CAVIUM_CN63XXP1=y
 CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE=2
-CONFIG_SPARSEMEM_MANUAL=y
 CONFIG_TRANSPARENT_HUGEPAGE=y
 CONFIG_SMP=y
 CONFIG_NR_CPUS=32
 CONFIG_HZ_100=y
 CONFIG_PREEMPT=y
-CONFIG_EXPERIMENTAL=y
 CONFIG_SYSVIPC=y
 CONFIG_POSIX_MQUEUE=y
 CONFIG_BSD_PROCESS_ACCT=y
@@ -50,7 +48,6 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 # CONFIG_FW_LOADER is not set
 CONFIG_MTD=y
 # CONFIG_MTD_OF_PARTS is not set
-CONFIG_MTD_CHAR=y
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_CFI=y
 CONFIG_MTD_CFI_AMDSTD=y
@@ -114,6 +111,7 @@ CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_8250_NR_UARTS=2
 CONFIG_SERIAL_8250_RUNTIME_UARTS=2
+CONFIG_SERIAL_8250_DW=y
 # CONFIG_HW_RANDOM is not set
 CONFIG_I2C=y
 CONFIG_I2C_OCTEON=y
diff --git a/arch/mips/configs/wrppmc_defconfig b/arch/mips/configs/wrppmc_defconfig
deleted file mode 100644 (file)
index 44a451b..0000000
+++ /dev/null
@@ -1,97 +0,0 @@
-CONFIG_WR_PPMC=y
-CONFIG_HZ_1000=y
-CONFIG_EXPERIMENTAL=y
-# CONFIG_SWAP is not set
-CONFIG_SYSVIPC=y
-CONFIG_BSD_PROCESS_ACCT=y
-CONFIG_LOG_BUF_SHIFT=14
-CONFIG_BLK_DEV_INITRD=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EXPERT=y
-CONFIG_KALLSYMS_EXTRA_PASS=y
-# CONFIG_EPOLL is not set
-CONFIG_SLAB=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-CONFIG_MODVERSIONS=y
-CONFIG_MODULE_SRCVERSION_ALL=y
-CONFIG_PCI=y
-CONFIG_HOTPLUG_PCI=y
-CONFIG_BINFMT_MISC=y
-CONFIG_PM=y
-CONFIG_NET=y
-CONFIG_PACKET=y
-CONFIG_UNIX=y
-CONFIG_XFRM_MIGRATE=y
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-CONFIG_IP_PNP_BOOTP=y
-CONFIG_IP_PNP_RARP=y
-CONFIG_IP_MROUTE=y
-CONFIG_ARPD=y
-CONFIG_INET_XFRM_MODE_TRANSPORT=m
-CONFIG_INET_XFRM_MODE_TUNNEL=m
-CONFIG_INET_XFRM_MODE_BEET=m
-CONFIG_TCP_MD5SIG=y
-# CONFIG_IPV6 is not set
-CONFIG_NETWORK_SECMARK=y
-CONFIG_FW_LOADER=m
-CONFIG_BLK_DEV_RAM=y
-CONFIG_SGI_IOC4=m
-CONFIG_NETDEVICES=y
-CONFIG_PHYLIB=y
-CONFIG_VITESSE_PHY=m
-CONFIG_SMSC_PHY=m
-CONFIG_NET_ETHERNET=y
-CONFIG_NET_PCI=y
-CONFIG_E100=y
-CONFIG_QLA3XXX=m
-CONFIG_CHELSIO_T3=m
-CONFIG_NETXEN_NIC=m
-# CONFIG_INPUT is not set
-# CONFIG_SERIO is not set
-# CONFIG_VT is not set
-CONFIG_SERIAL_8250=y
-CONFIG_SERIAL_8250_CONSOLE=y
-CONFIG_SERIAL_8250_NR_UARTS=1
-CONFIG_SERIAL_8250_RUNTIME_UARTS=1
-# CONFIG_HW_RANDOM is not set
-CONFIG_PROC_KCORE=y
-CONFIG_TMPFS=y
-CONFIG_TMPFS_POSIX_ACL=y
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
-CONFIG_ROOT_NFS=y
-CONFIG_DLM=m
-CONFIG_CMDLINE_BOOL=y
-CONFIG_CMDLINE="console=ttyS0,115200n8"
-CONFIG_CRYPTO_NULL=m
-CONFIG_CRYPTO_CBC=m
-CONFIG_CRYPTO_ECB=m
-CONFIG_CRYPTO_LRW=m
-CONFIG_CRYPTO_PCBC=m
-CONFIG_CRYPTO_XCBC=m
-CONFIG_CRYPTO_MD4=m
-CONFIG_CRYPTO_MICHAEL_MIC=m
-CONFIG_CRYPTO_SHA256=m
-CONFIG_CRYPTO_SHA512=m
-CONFIG_CRYPTO_TGR192=m
-CONFIG_CRYPTO_WP512=m
-CONFIG_CRYPTO_ANUBIS=m
-CONFIG_CRYPTO_ARC4=m
-CONFIG_CRYPTO_BLOWFISH=m
-CONFIG_CRYPTO_CAMELLIA=m
-CONFIG_CRYPTO_CAST5=m
-CONFIG_CRYPTO_CAST6=m
-CONFIG_CRYPTO_DES=m
-CONFIG_CRYPTO_FCRYPT=m
-CONFIG_CRYPTO_KHAZAD=m
-CONFIG_CRYPTO_SERPENT=m
-CONFIG_CRYPTO_TEA=m
-CONFIG_CRYPTO_TWOFISH=m
-CONFIG_CRYPTO_DEFLATE=m
-CONFIG_CRC_CCITT=y
-CONFIG_CRC16=y
-CONFIG_LIBCRC32C=y
index 9eb2f9c..3d5d2c5 100644 (file)
@@ -5,6 +5,5 @@
 obj-y          := ecc-berr.o int-handler.o ioasic-irq.o kn01-berr.o \
                   kn02-irq.o kn02xa-berr.o reset.o setup.o time.o
 
-obj-$(CONFIG_PROM_CONSOLE)     += promcon.o
 obj-$(CONFIG_TC)               += tc.o
 obj-$(CONFIG_CPU_HAS_WB)       += wbflush.o
diff --git a/arch/mips/dec/promcon.c b/arch/mips/dec/promcon.c
deleted file mode 100644 (file)
index c239c25..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Wrap-around code for a console using the
- * DECstation PROM io-routines.
- *
- * Copyright (c) 1998 Harald Koerfgen
- */
-
-#include <linux/tty.h>
-#include <linux/ptrace.h>
-#include <linux/init.h>
-#include <linux/console.h>
-#include <linux/fs.h>
-
-#include <asm/dec/prom.h>
-
-static void prom_console_write(struct console *co, const char *s,
-                              unsigned count)
-{
-       unsigned i;
-
-       /*
-        *    Now, do each character
-        */
-       for (i = 0; i < count; i++) {
-               if (*s == 10)
-                       prom_printf("%c", 13);
-               prom_printf("%c", *s++);
-       }
-}
-
-static int __init prom_console_setup(struct console *co, char *options)
-{
-       return 0;
-}
-
-static struct console sercons = {
-       .name   = "ttyS",
-       .write  = prom_console_write,
-       .setup  = prom_console_setup,
-       .flags  = CON_PRINTBUFFER,
-       .index  = -1,
-};
-
-/*
- *    Register console.
- */
-
-static int __init prom_console_init(void)
-{
-       register_console(&sercons);
-
-       return 0;
-}
-console_initcall(prom_console_init);
index d06dc5a..cf84f01 100644 (file)
@@ -406,12 +406,12 @@ int cfe_setenv(char *name, char *val)
        return xiocb.xiocb_status;
 }
 
-int cfe_write(int handle, unsigned char *buffer, int length)
+int cfe_write(int handle, const char *buffer, int length)
 {
        return cfe_writeblk(handle, 0, buffer, length);
 }
 
-int cfe_writeblk(int handle, s64 offset, unsigned char *buffer, int length)
+int cfe_writeblk(int handle, s64 offset, const char *buffer, int length)
 {
        struct cfe_xiocb xiocb;
 
index 3532e2c..c1516cc 100644 (file)
 
 #include <linux/notifier.h>
 
+#if defined(CONFIG_CPU_CAVIUM_OCTEON)
+
+extern void octeon_cop2_save(struct octeon_cop2_state *);
+extern void octeon_cop2_restore(struct octeon_cop2_state *);
+
+#define cop2_save(r)           octeon_cop2_save(r)
+#define cop2_restore(r)                octeon_cop2_restore(r)
+
+#define cop2_present           1
+#define cop2_lazy_restore      1
+
+#elif defined(CONFIG_CPU_XLP)
+
+extern void nlm_cop2_save(struct nlm_cop2_state *);
+extern void nlm_cop2_restore(struct nlm_cop2_state *);
+#define cop2_save(r)           nlm_cop2_save(r)
+#define cop2_restore(r)                nlm_cop2_restore(r)
+
+#define cop2_present           1
+#define cop2_lazy_restore      0
+
+#else
+
+#define cop2_present           0
+#define cop2_lazy_restore      0
+#define cop2_save(r)
+#define cop2_restore(r)
+#endif
+
 enum cu2_ops {
        CU2_EXCEPTION,
        CU2_LWC2_OP,
index e5ec8fc..1dc0860 100644 (file)
 #ifndef cpu_has_tlb
 #define cpu_has_tlb            (cpu_data[0].options & MIPS_CPU_TLB)
 #endif
+
+/*
+ * For the moment we don't consider R6000 and R8000 so we can assume that
+ * anything that doesn't support R4000-style exceptions and interrupts is
+ * R3000-like.  Users should still treat these two macro definitions as
+ * opaque.
+ */
+#ifndef cpu_has_3kex
+#define cpu_has_3kex           (!cpu_has_4kex)
+#endif
 #ifndef cpu_has_4kex
 #define cpu_has_4kex           (cpu_data[0].options & MIPS_CPU_4KEX)
 #endif
 #define cpu_has_mips16         (cpu_data[0].ases & MIPS_ASE_MIPS16)
 #endif
 #ifndef cpu_has_mdmx
-#define cpu_has_mdmx          (cpu_data[0].ases & MIPS_ASE_MDMX)
+#define cpu_has_mdmx           (cpu_data[0].ases & MIPS_ASE_MDMX)
 #endif
 #ifndef cpu_has_mips3d
-#define cpu_has_mips3d        (cpu_data[0].ases & MIPS_ASE_MIPS3D)
+#define cpu_has_mips3d         (cpu_data[0].ases & MIPS_ASE_MIPS3D)
 #endif
 #ifndef cpu_has_smartmips
-#define cpu_has_smartmips      (cpu_data[0].ases & MIPS_ASE_SMARTMIPS)
+#define cpu_has_smartmips      (cpu_data[0].ases & MIPS_ASE_SMARTMIPS)
 #endif
 #ifndef cpu_has_rixi
 #define cpu_has_rixi           (cpu_data[0].options & MIPS_CPU_RIXI)
 #endif
 #ifndef cpu_has_mmips
-#define cpu_has_mmips          (cpu_data[0].options & MIPS_CPU_MICROMIPS)
+# ifdef CONFIG_SYS_SUPPORTS_MICROMIPS
+#  define cpu_has_mmips                (cpu_data[0].options & MIPS_CPU_MICROMIPS)
+# else
+#  define cpu_has_mmips                0
+# endif
 #endif
 #ifndef cpu_has_vtag_icache
 #define cpu_has_vtag_icache    (cpu_data[0].icache.flags & MIPS_CACHE_VTAG)
 #define cpu_has_ic_fills_f_dc  (cpu_data[0].icache.flags & MIPS_CACHE_IC_F_DC)
 #endif
 #ifndef cpu_has_pindexed_dcache
-#define cpu_has_pindexed_dcache (cpu_data[0].dcache.flags & MIPS_CACHE_PINDEX)
+#define cpu_has_pindexed_dcache        (cpu_data[0].dcache.flags & MIPS_CACHE_PINDEX)
 #endif
 #ifndef cpu_has_local_ebase
 #define cpu_has_local_ebase    1
 #endif
 #endif
 
-# define cpu_has_mips_1                (cpu_data[0].isa_level & MIPS_CPU_ISA_I)
 #ifndef cpu_has_mips_2
 # define cpu_has_mips_2                (cpu_data[0].isa_level & MIPS_CPU_ISA_II)
 #endif
 #ifndef cpu_has_mips_5
 # define cpu_has_mips_5                (cpu_data[0].isa_level & MIPS_CPU_ISA_V)
 #endif
-# ifndef cpu_has_mips32r1
+#ifndef cpu_has_mips32r1
 # define cpu_has_mips32r1      (cpu_data[0].isa_level & MIPS_CPU_ISA_M32R1)
-# endif
-# ifndef cpu_has_mips32r2
+#endif
+#ifndef cpu_has_mips32r2
 # define cpu_has_mips32r2      (cpu_data[0].isa_level & MIPS_CPU_ISA_M32R2)
-# endif
-# ifndef cpu_has_mips64r1
+#endif
+#ifndef cpu_has_mips64r1
 # define cpu_has_mips64r1      (cpu_data[0].isa_level & MIPS_CPU_ISA_M64R1)
-# endif
-# ifndef cpu_has_mips64r2
+#endif
+#ifndef cpu_has_mips64r2
 # define cpu_has_mips64r2      (cpu_data[0].isa_level & MIPS_CPU_ISA_M64R2)
-# endif
+#endif
 
 /*
  * Shortcuts ...
  * has CLO and CLZ but not DCLO nor DCLZ.  For 64-bit kernels
  * cpu_has_clo_clz also indicates the availability of DCLO and DCLZ.
  */
-# ifndef cpu_has_clo_clz
-# define cpu_has_clo_clz       cpu_has_mips_r
-# endif
+#ifndef cpu_has_clo_clz
+#define cpu_has_clo_clz        cpu_has_mips_r
+#endif
 
 #ifndef cpu_has_dsp
 #define cpu_has_dsp            (cpu_data[0].ases & MIPS_ASE_DSP)
 # define cpu_has_64bits                (cpu_data[0].isa_level & MIPS_CPU_ISA_64BIT)
 # endif
 # ifndef cpu_has_64bit_zero_reg
-# define cpu_has_64bit_zero_reg (cpu_data[0].isa_level & MIPS_CPU_ISA_64BIT)
+# define cpu_has_64bit_zero_reg        (cpu_data[0].isa_level & MIPS_CPU_ISA_64BIT)
 # endif
 # ifndef cpu_has_64bit_gp_regs
 # define cpu_has_64bit_gp_regs         0
index dd86ab2..632bbe5 100644 (file)
@@ -282,18 +282,17 @@ enum cpu_type_enum {
  * ISA Level encodings
  *
  */
-#define MIPS_CPU_ISA_I         0x00000001
-#define MIPS_CPU_ISA_II                0x00000002
-#define MIPS_CPU_ISA_III       0x00000004
-#define MIPS_CPU_ISA_IV                0x00000008
-#define MIPS_CPU_ISA_V         0x00000010
-#define MIPS_CPU_ISA_M32R1     0x00000020
-#define MIPS_CPU_ISA_M32R2     0x00000040
-#define MIPS_CPU_ISA_M64R1     0x00000080
-#define MIPS_CPU_ISA_M64R2     0x00000100
-
-#define MIPS_CPU_ISA_32BIT (MIPS_CPU_ISA_I | MIPS_CPU_ISA_II | \
-       MIPS_CPU_ISA_M32R1 | MIPS_CPU_ISA_M32R2)
+#define MIPS_CPU_ISA_II                0x00000001
+#define MIPS_CPU_ISA_III       0x00000002
+#define MIPS_CPU_ISA_IV                0x00000004
+#define MIPS_CPU_ISA_V         0x00000008
+#define MIPS_CPU_ISA_M32R1     0x00000010
+#define MIPS_CPU_ISA_M32R2     0x00000020
+#define MIPS_CPU_ISA_M64R1     0x00000040
+#define MIPS_CPU_ISA_M64R2     0x00000080
+
+#define MIPS_CPU_ISA_32BIT (MIPS_CPU_ISA_II | MIPS_CPU_ISA_M32R1 | \
+       MIPS_CPU_ISA_M32R2)
 #define MIPS_CPU_ISA_64BIT (MIPS_CPU_ISA_III | MIPS_CPU_ISA_IV | \
        MIPS_CPU_ISA_V | MIPS_CPU_ISA_M64R1 | MIPS_CPU_ISA_M64R2)
 
index 1734755..a0ea69e 100644 (file)
@@ -115,8 +115,8 @@ int cfe_read(int handle, unsigned char *buffer, int length);
 int cfe_readblk(int handle, int64_t offset, unsigned char *buffer,
                int length);
 int cfe_setenv(char *name, char *val);
-int cfe_write(int handle, unsigned char *buffer, int length);
-int cfe_writeblk(int handle, int64_t offset, unsigned char *buffer,
+int cfe_write(int handle, const char *buffer, int length);
+int cfe_writeblk(int handle, int64_t offset, const char *buffer,
                 int length);
 
 #endif                         /* CFE_API_H */
index 7153b32..b2e3e93 100644 (file)
@@ -347,7 +347,7 @@ struct gic_shared_intr_map {
 #define GIC_CPU_INT2           2 /* .                */
 #define GIC_CPU_INT3           3 /* .                */
 #define GIC_CPU_INT4           4 /* .                */
-#define GIC_CPU_INT5           5 /* Core Interrupt 5 */
+#define GIC_CPU_INT5           5 /* Core Interrupt 7 */
 
 /* Local GIC interrupts. */
 #define GIC_INT_TMR            (GIC_CPU_INT5)
index b7e5985..3321dd5 100644 (file)
@@ -170,6 +170,11 @@ static inline void * isa_bus_to_virt(unsigned long address)
 extern void __iomem * __ioremap(phys_t offset, phys_t size, unsigned long flags);
 extern void __iounmap(const volatile void __iomem *addr);
 
+#ifndef CONFIG_PCI
+struct pci_dev;
+static inline void pci_iounmap(struct pci_dev *dev, void __iomem *addr) {}
+#endif
+
 static inline void __iomem * __ioremap_mode(phys_t offset, unsigned long size,
        unsigned long flags)
 {
@@ -449,6 +454,11 @@ __BUILDIO(q, u64)
 #define readl_relaxed                  readl
 #define readq_relaxed                  readq
 
+#define writeb_relaxed                 writeb
+#define writew_relaxed                 writew
+#define writel_relaxed                 writel
+#define writeq_relaxed                 writeq
+
 #define readb_be(addr)                                                 \
        __raw_readb((__force unsigned *)(addr))
 #define readw_be(addr)                                                 \
diff --git a/arch/mips/include/asm/kspd.h b/arch/mips/include/asm/kspd.h
deleted file mode 100644 (file)
index ec68329..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2005 MIPS Technologies, Inc.  All rights reserved.
- *
- *  This program is free software; you can distribute 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 it will be useful, but WITHOUT
- *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- *  for more details.
- *
- *  You should have received a copy of the GNU General Public License along
- *  with this program; if not, write to the Free Software Foundation, Inc.,
- *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
- *
- */
-
-#ifndef _ASM_KSPD_H
-#define _ASM_KSPD_H
-
-struct kspd_notifications {
-       void (*kspd_sp_exit)(int sp_id);
-
-       struct list_head list;
-};
-
-static inline void kspd_notify(struct kspd_notifications *notify)
-{
-}
-
-#endif
index ac28f27..660ab64 100644 (file)
  * This handles the memory map.
  * We handle pages at KSEG0 for kernels with 32 bit address space.
  */
-#define PAGE_OFFSET            0x94000000UL
-#define PHYS_OFFSET            0x14000000UL
+#define PAGE_OFFSET    _AC(0x94000000, UL)
+#define PHYS_OFFSET    _AC(0x14000000, UL)
+
+#define UNCAC_BASE     _AC(0xb4000000, UL)     /* 0xa0000000 + PHYS_OFFSET */
+#define IO_BASE                UNCAC_BASE
 
 #include <asm/mach-generic/spaces.h>
 
index e6e65dc..19f9134 100644 (file)
@@ -9,6 +9,7 @@
  * compile time if only one CPU support is enabled (idea stolen from
  * arm mach-types)
  */
+#define BCM3368_CPU_ID         0x3368
 #define BCM6328_CPU_ID         0x6328
 #define BCM6338_CPU_ID         0x6338
 #define BCM6345_CPU_ID         0x6345
@@ -22,6 +23,19 @@ u16 __bcm63xx_get_cpu_id(void);
 u8 bcm63xx_get_cpu_rev(void);
 unsigned int bcm63xx_get_cpu_freq(void);
 
+#ifdef CONFIG_BCM63XX_CPU_3368
+# ifdef bcm63xx_get_cpu_id
+#  undef bcm63xx_get_cpu_id
+#  define bcm63xx_get_cpu_id() __bcm63xx_get_cpu_id()
+#  define BCMCPU_RUNTIME_DETECT
+# else
+#  define bcm63xx_get_cpu_id() BCM3368_CPU_ID
+# endif
+# define BCMCPU_IS_3368()      (bcm63xx_get_cpu_id() == BCM3368_CPU_ID)
+#else
+# define BCMCPU_IS_3368()      (0)
+#endif
+
 #ifdef CONFIG_BCM63XX_CPU_6328
 # ifdef bcm63xx_get_cpu_id
 #  undef bcm63xx_get_cpu_id
@@ -194,6 +208,53 @@ enum bcm63xx_regs_set {
 #define RSET_RNG_SIZE                  20
 
 /*
+ * 3368 register sets base address
+ */
+#define BCM_3368_DSL_LMEM_BASE         (0xdeadbeef)
+#define BCM_3368_PERF_BASE             (0xfff8c000)
+#define BCM_3368_TIMER_BASE            (0xfff8c040)
+#define BCM_3368_WDT_BASE              (0xfff8c080)
+#define BCM_3368_UART0_BASE            (0xfff8c100)
+#define BCM_3368_UART1_BASE            (0xfff8c120)
+#define BCM_3368_GPIO_BASE             (0xfff8c080)
+#define BCM_3368_SPI_BASE              (0xfff8c800)
+#define BCM_3368_HSSPI_BASE            (0xdeadbeef)
+#define BCM_3368_UDC0_BASE             (0xdeadbeef)
+#define BCM_3368_USBDMA_BASE           (0xdeadbeef)
+#define BCM_3368_OHCI0_BASE            (0xdeadbeef)
+#define BCM_3368_OHCI_PRIV_BASE                (0xdeadbeef)
+#define BCM_3368_USBH_PRIV_BASE                (0xdeadbeef)
+#define BCM_3368_USBD_BASE             (0xdeadbeef)
+#define BCM_3368_MPI_BASE              (0xfff80000)
+#define BCM_3368_PCMCIA_BASE           (0xfff80054)
+#define BCM_3368_PCIE_BASE             (0xdeadbeef)
+#define BCM_3368_SDRAM_REGS_BASE       (0xdeadbeef)
+#define BCM_3368_DSL_BASE              (0xdeadbeef)
+#define BCM_3368_UBUS_BASE             (0xdeadbeef)
+#define BCM_3368_ENET0_BASE            (0xfff98000)
+#define BCM_3368_ENET1_BASE            (0xfff98800)
+#define BCM_3368_ENETDMA_BASE          (0xfff99800)
+#define BCM_3368_ENETDMAC_BASE         (0xfff99900)
+#define BCM_3368_ENETDMAS_BASE         (0xfff99a00)
+#define BCM_3368_ENETSW_BASE           (0xdeadbeef)
+#define BCM_3368_EHCI0_BASE            (0xdeadbeef)
+#define BCM_3368_SDRAM_BASE            (0xdeadbeef)
+#define BCM_3368_MEMC_BASE             (0xfff84000)
+#define BCM_3368_DDR_BASE              (0xdeadbeef)
+#define BCM_3368_M2M_BASE              (0xdeadbeef)
+#define BCM_3368_ATM_BASE              (0xdeadbeef)
+#define BCM_3368_XTM_BASE              (0xdeadbeef)
+#define BCM_3368_XTMDMA_BASE           (0xdeadbeef)
+#define BCM_3368_XTMDMAC_BASE          (0xdeadbeef)
+#define BCM_3368_XTMDMAS_BASE          (0xdeadbeef)
+#define BCM_3368_PCM_BASE              (0xfff9c200)
+#define BCM_3368_PCMDMA_BASE           (0xdeadbeef)
+#define BCM_3368_PCMDMAC_BASE          (0xdeadbeef)
+#define BCM_3368_PCMDMAS_BASE          (0xdeadbeef)
+#define BCM_3368_RNG_BASE              (0xdeadbeef)
+#define BCM_3368_MISC_BASE             (0xdeadbeef)
+
+/*
  * 6328 register sets base address
  */
 #define BCM_6328_DSL_LMEM_BASE         (0xdeadbeef)
@@ -238,6 +299,8 @@ enum bcm63xx_regs_set {
 #define BCM_6328_PCMDMAS_BASE          (0xdeadbeef)
 #define BCM_6328_RNG_BASE              (0xdeadbeef)
 #define BCM_6328_MISC_BASE             (0xb0001800)
+#define BCM_6328_OTP_BASE              (0xb0000600)
+
 /*
  * 6338 register sets base address
  */
@@ -623,6 +686,9 @@ static inline unsigned long bcm63xx_regset_address(enum bcm63xx_regs_set set)
 #ifdef BCMCPU_RUNTIME_DETECT
        return bcm63xx_regs_base[set];
 #else
+#ifdef CONFIG_BCM63XX_CPU_3368
+       __GEN_RSET(3368)
+#endif
 #ifdef CONFIG_BCM63XX_CPU_6328
        __GEN_RSET(6328)
 #endif
@@ -690,6 +756,52 @@ enum bcm63xx_irq {
 };
 
 /*
+ * 3368 irqs
+ */
+#define BCM_3368_TIMER_IRQ             (IRQ_INTERNAL_BASE + 0)
+#define BCM_3368_SPI_IRQ               (IRQ_INTERNAL_BASE + 1)
+#define BCM_3368_UART0_IRQ             (IRQ_INTERNAL_BASE + 2)
+#define BCM_3368_UART1_IRQ             (IRQ_INTERNAL_BASE + 3)
+#define BCM_3368_DSL_IRQ               0
+#define BCM_3368_UDC0_IRQ              0
+#define BCM_3368_OHCI0_IRQ             0
+#define BCM_3368_ENET0_IRQ             (IRQ_INTERNAL_BASE + 8)
+#define BCM_3368_ENET1_IRQ             (IRQ_INTERNAL_BASE + 6)
+#define BCM_3368_ENET_PHY_IRQ          (IRQ_INTERNAL_BASE + 9)
+#define BCM_3368_ENET0_RXDMA_IRQ       (IRQ_INTERNAL_BASE + 15)
+#define BCM_3368_ENET0_TXDMA_IRQ       (IRQ_INTERNAL_BASE + 16)
+#define BCM_3368_HSSPI_IRQ             0
+#define BCM_3368_EHCI0_IRQ             0
+#define BCM_3368_USBD_IRQ              0
+#define BCM_3368_USBD_RXDMA0_IRQ       0
+#define BCM_3368_USBD_TXDMA0_IRQ       0
+#define BCM_3368_USBD_RXDMA1_IRQ       0
+#define BCM_3368_USBD_TXDMA1_IRQ       0
+#define BCM_3368_USBD_RXDMA2_IRQ       0
+#define BCM_3368_USBD_TXDMA2_IRQ       0
+#define BCM_3368_ENET1_RXDMA_IRQ        (IRQ_INTERNAL_BASE + 17)
+#define BCM_3368_ENET1_TXDMA_IRQ        (IRQ_INTERNAL_BASE + 18)
+#define BCM_3368_PCI_IRQ               (IRQ_INTERNAL_BASE + 31)
+#define BCM_3368_PCMCIA_IRQ            0
+#define BCM_3368_ATM_IRQ               0
+#define BCM_3368_ENETSW_RXDMA0_IRQ     0
+#define BCM_3368_ENETSW_RXDMA1_IRQ     0
+#define BCM_3368_ENETSW_RXDMA2_IRQ     0
+#define BCM_3368_ENETSW_RXDMA3_IRQ     0
+#define BCM_3368_ENETSW_TXDMA0_IRQ     0
+#define BCM_3368_ENETSW_TXDMA1_IRQ     0
+#define BCM_3368_ENETSW_TXDMA2_IRQ     0
+#define BCM_3368_ENETSW_TXDMA3_IRQ     0
+#define BCM_3368_XTM_IRQ               0
+#define BCM_3368_XTM_DMA0_IRQ          0
+
+#define BCM_3368_EXT_IRQ0              (IRQ_INTERNAL_BASE + 25)
+#define BCM_3368_EXT_IRQ1              (IRQ_INTERNAL_BASE + 26)
+#define BCM_3368_EXT_IRQ2              (IRQ_INTERNAL_BASE + 27)
+#define BCM_3368_EXT_IRQ3              (IRQ_INTERNAL_BASE + 28)
+
+
+/*
  * 6328 irqs
  */
 #define BCM_6328_HIGH_IRQ_BASE         (IRQ_INTERNAL_BASE + 32)
index 35baa1a..565ff36 100644 (file)
@@ -11,6 +11,7 @@ static inline unsigned long bcm63xx_gpio_count(void)
        switch (bcm63xx_get_cpu_id()) {
        case BCM6328_CPU_ID:
                return 32;
+       case BCM3368_CPU_ID:
        case BCM6358_CPU_ID:
                return 40;
        case BCM6338_CPU_ID:
index eff7ca7..9875db3 100644 (file)
 /* Clock Control register */
 #define PERF_CKCTL_REG                 0x4
 
+#define CKCTL_3368_MAC_EN              (1 << 3)
+#define CKCTL_3368_TC_EN               (1 << 5)
+#define CKCTL_3368_US_TOP_EN           (1 << 6)
+#define CKCTL_3368_DS_TOP_EN           (1 << 7)
+#define CKCTL_3368_APM_EN              (1 << 8)
+#define CKCTL_3368_SPI_EN              (1 << 9)
+#define CKCTL_3368_USBS_EN             (1 << 10)
+#define CKCTL_3368_BMU_EN              (1 << 11)
+#define CKCTL_3368_PCM_EN              (1 << 12)
+#define CKCTL_3368_NTP_EN              (1 << 13)
+#define CKCTL_3368_ACP_B_EN            (1 << 14)
+#define CKCTL_3368_ACP_A_EN            (1 << 15)
+#define CKCTL_3368_EMUSB_EN            (1 << 17)
+#define CKCTL_3368_ENET0_EN            (1 << 18)
+#define CKCTL_3368_ENET1_EN            (1 << 19)
+#define CKCTL_3368_USBU_EN             (1 << 20)
+#define CKCTL_3368_EPHY_EN             (1 << 21)
+
+#define CKCTL_3368_ALL_SAFE_EN         (CKCTL_3368_MAC_EN | \
+                                        CKCTL_3368_TC_EN | \
+                                        CKCTL_3368_US_TOP_EN | \
+                                        CKCTL_3368_DS_TOP_EN | \
+                                        CKCTL_3368_APM_EN | \
+                                        CKCTL_3368_SPI_EN | \
+                                        CKCTL_3368_USBS_EN | \
+                                        CKCTL_3368_BMU_EN | \
+                                        CKCTL_3368_PCM_EN | \
+                                        CKCTL_3368_NTP_EN | \
+                                        CKCTL_3368_ACP_B_EN | \
+                                        CKCTL_3368_ACP_A_EN | \
+                                        CKCTL_3368_EMUSB_EN | \
+                                        CKCTL_3368_USBU_EN)
+
 #define CKCTL_6328_PHYMIPS_EN          (1 << 0)
 #define CKCTL_6328_ADSL_QPROC_EN       (1 << 1)
 #define CKCTL_6328_ADSL_AFE_EN         (1 << 2)
 #define SYS_PLL_SOFT_RESET             0x1
 
 /* Interrupt Mask register */
+#define PERF_IRQMASK_3368_REG          0xc
 #define PERF_IRQMASK_6328_REG          0x20
 #define PERF_IRQMASK_6338_REG          0xc
 #define PERF_IRQMASK_6345_REG          0xc
 #define PERF_IRQMASK_6368_REG          0x20
 
 /* Interrupt Status register */
+#define PERF_IRQSTAT_3368_REG          0x10
 #define PERF_IRQSTAT_6328_REG          0x28
 #define PERF_IRQSTAT_6338_REG          0x10
 #define PERF_IRQSTAT_6345_REG          0x10
 #define PERF_IRQSTAT_6368_REG          0x28
 
 /* External Interrupt Configuration register */
+#define PERF_EXTIRQ_CFG_REG_3368       0x14
 #define PERF_EXTIRQ_CFG_REG_6328       0x18
 #define PERF_EXTIRQ_CFG_REG_6338       0x14
 #define PERF_EXTIRQ_CFG_REG_6345       0x14
 #define PERF_SOFTRESET_6362_REG                0x10
 #define PERF_SOFTRESET_6368_REG                0x10
 
+#define SOFTRESET_3368_SPI_MASK                (1 << 0)
+#define SOFTRESET_3368_ENET_MASK       (1 << 2)
+#define SOFTRESET_3368_MPI_MASK                (1 << 3)
+#define SOFTRESET_3368_EPHY_MASK       (1 << 6)
+#define SOFTRESET_3368_USBS_MASK       (1 << 11)
+#define SOFTRESET_3368_PCM_MASK                (1 << 13)
+
 #define SOFTRESET_6328_SPI_MASK                (1 << 0)
 #define SOFTRESET_6328_EPHY_MASK       (1 << 1)
 #define SOFTRESET_6328_SAR_MASK                (1 << 2)
 #define SPI_6348_RX_DATA               0x80
 #define SPI_6348_RX_DATA_SIZE          0x3f
 
-/* BCM 6358/6262/6368 SPI core */
+/* BCM 3368/6358/6262/6368 SPI core */
 #define SPI_6358_MSG_CTL               0x00    /* 16-bits register */
 #define SPI_6358_MSG_CTL_WIDTH         16
 #define SPI_6358_MSG_DATA              0x02
 
 #define PCIE_DEVICE_OFFSET             0x8000
 
+/*************************************************************************
+ * _REG relative to RSET_OTP
+ *************************************************************************/
+
+#define OTP_USER_BITS_6328_REG(i)      (0x20 + (i) * 4)
+#define   OTP_6328_REG3_TP1_DISABLED   BIT(9)
+
 #endif /* BCM63XX_REGS_H_ */
index d9aee1a..b86a0ef 100644 (file)
@@ -47,6 +47,12 @@ struct board_info {
 
        /* GPIO LEDs */
        struct gpio_led leds[5];
+
+       /* External PHY reset GPIO */
+       unsigned int ephy_reset_gpio;
+
+       /* External PHY reset GPIO flags from gpio.h */
+       unsigned long ephy_reset_gpio_flags;
 };
 
 #endif /* ! BOARD_BCM963XX_H_ */
index 94e3011..ff15e3b 100644 (file)
@@ -11,6 +11,10 @@ static inline phys_t fixup_bigphys_addr(phys_t phys_addr, phys_t size)
 static inline int is_bcm63xx_internal_registers(phys_t offset)
 {
        switch (bcm63xx_get_cpu_id()) {
+       case BCM3368_CPU_ID:
+               if (offset >= 0xfff80000)
+                       return 1;
+               break;
        case BCM6338_CPU_ID:
        case BCM6345_CPU_ID:
        case BCM6348_CPU_ID:
index be8fb42..47fb247 100644 (file)
@@ -13,6 +13,8 @@
 #ifndef __ASM_MACH_CAVIUM_OCTEON_DMA_COHERENCE_H
 #define __ASM_MACH_CAVIUM_OCTEON_DMA_COHERENCE_H
 
+#include <linux/bug.h>
+
 struct device;
 
 extern void octeon_pci_dma_init(void);
@@ -21,18 +23,21 @@ static inline dma_addr_t plat_map_dma_mem(struct device *dev, void *addr,
        size_t size)
 {
        BUG();
+       return 0;
 }
 
 static inline dma_addr_t plat_map_dma_mem_page(struct device *dev,
        struct page *page)
 {
        BUG();
+       return 0;
 }
 
 static inline unsigned long plat_dma_addr_to_phys(struct device *dev,
        dma_addr_t dma_addr)
 {
        BUG();
+       return 0;
 }
 
 static inline void plat_unmap_dma_mem(struct device *dev, dma_addr_t dma_addr,
@@ -44,6 +49,7 @@ static inline void plat_unmap_dma_mem(struct device *dev, dma_addr_t dma_addr,
 static inline int plat_dma_supported(struct device *dev, u64 mask)
 {
        BUG();
+       return 0;
 }
 
 static inline void plat_extra_sync_for_device(struct device *dev)
@@ -60,6 +66,7 @@ static inline int plat_dma_mapping_error(struct device *dev,
                                         dma_addr_t dma_addr)
 {
        BUG();
+       return 0;
 }
 
 dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr);
index 1e7dbb1..1668ee5 100644 (file)
        ori     v0, CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE
        dmtc0   v0, CP0_CVMMEMCTL_REG   # Write the cavium mem control register
        dmfc0   v0, CP0_CVMCTL_REG      # Read the cavium control register
-#ifdef CONFIG_CAVIUM_OCTEON_HW_FIX_UNALIGNED
        # Disable unaligned load/store support but leave HW fixup enabled
+       # Needed for octeon specific memcpy
        or  v0, v0, 0x5001
        xor v0, v0, 0x1001
-#else
-       # Disable unaligned load/store and HW fixup support
-       or  v0, v0, 0x5001
-       xor v0, v0, 0x5001
-#endif
        # Read the processor ID register
        mfc0 v1, CP0_PRID_REG
        # Disable instruction prefetching (Octeon Pass1 errata)
diff --git a/arch/mips/include/asm/mach-cavium-octeon/spaces.h b/arch/mips/include/asm/mach-cavium-octeon/spaces.h
new file mode 100644 (file)
index 0000000..daa91ac
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * 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) 2012 Cavium, Inc.
+ */
+#ifndef _ASM_MACH_CAVIUM_OCTEON_SPACES_H
+#define _ASM_MACH_CAVIUM_OCTEON_SPACES_H
+
+#include <linux/const.h>
+
+#ifdef CONFIG_64BIT
+/* They are all the same and some OCTEON II cores cannot handle 0xa8.. */
+#define CAC_BASE               _AC(0x8000000000000000, UL)
+#define UNCAC_BASE             _AC(0x8000000000000000, UL)
+#define IO_BASE                        _AC(0x8000000000000000, UL)
+
+
+#endif /* CONFIG_64BIT */
+
+#include <asm/mach-generic/spaces.h>
+
+#endif /* _ASM_MACH_CAVIUM_OCTEON_SPACES_H */
index fe23034..74cb992 100644 (file)
@@ -66,4 +66,16 @@ static inline int plat_device_is_coherent(struct device *dev)
 #endif
 }
 
+#ifdef CONFIG_SWIOTLB
+static inline dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr)
+{
+       return paddr;
+}
+
+static inline phys_addr_t dma_to_phys(struct device *dev, dma_addr_t daddr)
+{
+       return daddr;
+}
+#endif
+
 #endif /* __ASM_MACH_GENERIC_DMA_COHERENCE_H */
index 7e66505..13b0751 100644 (file)
@@ -12,8 +12,8 @@
 /* Intentionally empty macro, used in head.S. Override in
  * arch/mips/mach-xxx/kernel-entry-init.h when necessary.
  */
-.macro kernel_entry_setup
-.endm
+       .macro  kernel_entry_setup
+       .endm
 
 /*
  * Do SMP slave processor setup necessary before we can savely execute C code.
index a323efb..b087cb8 100644 (file)
        .endm
 
 /*
+ * TLB bits
+ */
+#define PAGE_GLOBAL            (1 << 6)
+#define PAGE_VALID             (1 << 7)
+#define PAGE_DIRTY             (1 << 8)
+#define CACHE_CACHABLE_COW     (5 << 9)
+
+       /*
+        * inputs are the text nasid in t1, data nasid in t2.
+        */
+       .macro MAPPED_KERNEL_SETUP_TLB
+#ifdef CONFIG_MAPPED_KERNEL
+       /*
+        * This needs to read the nasid - assume 0 for now.
+        * Drop in 0xffffffffc0000000 in tlbhi, 0+VG in tlblo_0,
+        * 0+DVG in tlblo_1.
+        */
+       dli     t0, 0xffffffffc0000000
+       dmtc0   t0, CP0_ENTRYHI
+       li      t0, 0x1c000             # Offset of text into node memory
+       dsll    t1, NASID_SHFT          # Shift text nasid into place
+       dsll    t2, NASID_SHFT          # Same for data nasid
+       or      t1, t1, t0              # Physical load address of kernel text
+       or      t2, t2, t0              # Physical load address of kernel data
+       dsrl    t1, 12                  # 4K pfn
+       dsrl    t2, 12                  # 4K pfn
+       dsll    t1, 6                   # Get pfn into place
+       dsll    t2, 6                   # Get pfn into place
+       li      t0, ((PAGE_GLOBAL | PAGE_VALID | CACHE_CACHABLE_COW) >> 6)
+       or      t0, t0, t1
+       mtc0    t0, CP0_ENTRYLO0        # physaddr, VG, cach exlwr
+       li      t0, ((PAGE_GLOBAL | PAGE_VALID |  PAGE_DIRTY | CACHE_CACHABLE_COW) >> 6)
+       or      t0, t0, t2
+       mtc0    t0, CP0_ENTRYLO1        # physaddr, DVG, cach exlwr
+       li      t0, 0x1ffe000           # MAPPED_KERN_TLBMASK, TLBPGMASK_16M
+       mtc0    t0, CP0_PAGEMASK
+       li      t0, 0                   # KMAP_INX
+       mtc0    t0, CP0_INDEX
+       li      t0, 1
+       mtc0    t0, CP0_WIRED
+       tlbwi
+#else
+       mtc0    zero, CP0_WIRED
+#endif
+       .endm
+
+/*
  * Intentionally empty macro, used in head.S. Override in
  * arch/mips/mach-xxx/kernel-entry-init.h when necessary.
  */
index 5edf05d..5d6a764 100644 (file)
 #ifndef _ASM_MACH_IP28_SPACES_H
 #define _ASM_MACH_IP28_SPACES_H
 
-#define CAC_BASE               0xa800000000000000
+#define CAC_BASE       _AC(0xa800000000000000, UL)
 
-#define HIGHMEM_START          (~0UL)
+#define HIGHMEM_START  (~0UL)
 
-#define PHYS_OFFSET            _AC(0x20000000, UL)
+#define PHYS_OFFSET    _AC(0x20000000, UL)
+
+#define UNCAC_BASE     _AC(0xc0000000, UL)     /* 0xa0000000 + PHYS_OFFSET */
+#define IO_BASE                UNCAC_BASE
 
 #include <asm/mach-generic/spaces.h>
 
diff --git a/arch/mips/include/asm/mach-pmcs-msp71xx/gpio.h b/arch/mips/include/asm/mach-pmcs-msp71xx/gpio.h
deleted file mode 100644 (file)
index ebdbab9..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * include/asm-mips/pmc-sierra/msp71xx/gpio.h
- *
- * 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.
- *
- * @author Patrick Glass <patrickglass@gmail.com>
- */
-
-#ifndef __PMC_MSP71XX_GPIO_H
-#define __PMC_MSP71XX_GPIO_H
-
-/* Max number of gpio's is 28 on chip plus 3 banks of I2C IO Expanders */
-#define ARCH_NR_GPIOS (28 + (3 * 8))
-
-/* new generic GPIO API - see Documentation/gpio.txt */
-#include <asm-generic/gpio.h>
-
-#define gpio_get_value __gpio_get_value
-#define gpio_set_value __gpio_set_value
-#define gpio_cansleep  __gpio_cansleep
-
-/* Setup calls for the gpio and gpio extended */
-extern void msp71xx_init_gpio(void);
-extern void msp71xx_init_gpio_extended(void);
-extern int msp71xx_set_output_drive(unsigned gpio, int value);
-
-/* Custom output drive functionss */
-static inline int gpio_set_output_drive(unsigned gpio, int value)
-{
-       return msp71xx_set_output_drive(gpio, value);
-}
-
-/* IRQ's are not supported for gpio lines */
-static inline int gpio_to_irq(unsigned gpio)
-{
-       return -EINVAL;
-}
-
-static inline int irq_to_gpio(unsigned irq)
-{
-       return -EINVAL;
-}
-
-#endif /* __PMC_MSP71XX_GPIO_H */
diff --git a/arch/mips/include/asm/mach-wrppmc/mach-gt64120.h b/arch/mips/include/asm/mach-wrppmc/mach-gt64120.h
deleted file mode 100644 (file)
index 00fa368..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * This is a direct copy of the ev96100.h file, with a global
- * search and replace. The numbers are the same.
- *
- * The reason I'm duplicating this is so that the 64120/96100
- * defines won't be confusing in the source code.
- */
-#ifndef __ASM_MIPS_GT64120_H
-#define __ASM_MIPS_GT64120_H
-
-/*
- * This is the CPU physical memory map of PPMC Board:
- *
- *    0x00000000-0x03FFFFFF     - 64MB SDRAM (SCS[0]#)
- *    0x1C000000-0x1C000000     - LED (CS0)
- *    0x1C800000-0x1C800007     - UART 16550 port (CS1)
- *    0x1F000000-0x1F000000     - MailBox (CS3)
- *    0x1FC00000-0x20000000     - 4MB Flash (BOOT CS)
- */
-
-#define WRPPMC_SDRAM_SCS0_BASE 0x00000000
-#define WRPPMC_SDRAM_SCS0_SIZE 0x04000000
-
-#define WRPPMC_UART16550_BASE  0x1C800000
-#define WRPPMC_UART16550_CLOCK 3686400 /* 3.68MHZ */
-
-#define WRPPMC_LED_BASE                0x1C000000
-#define WRPPMC_MBOX_BASE       0x1F000000
-
-#define WRPPMC_BOOTROM_BASE    0x1FC00000
-#define WRPPMC_BOOTROM_SIZE    0x00400000 /* 4M Flash */
-
-#define WRPPMC_MIPS_TIMER_IRQ  7 /* MIPS compare/count timer interrupt */
-#define WRPPMC_UART16550_IRQ   6
-#define WRPPMC_PCI_INTA_IRQ    3
-
-/*
- * PCI Bus I/O and Memory resources allocation
- *
- * NOTE: We only have PCI_0 hose interface
- */
-#define GT_PCI_MEM_BASE 0x13000000UL
-#define GT_PCI_MEM_SIZE 0x02000000UL
-#define GT_PCI_IO_BASE 0x11000000UL
-#define GT_PCI_IO_SIZE 0x02000000UL
-
-/*
- * PCI interrupts will come in on either the INTA or INTD interrupt lines,
- * which are mapped to the #2 and #5 interrupt pins of the MIPS.  On our
- * boards, they all either come in on IntD or they all come in on IntA, they
- * aren't mixed. There can be numerous PCI interrupts, so we keep a list of the
- * "requested" interrupt numbers and go through the list whenever we get an
- * IntA/D.
- *
- * Interrupts < 8 are directly wired to the processor; PCI INTA is 8 and
- * INTD is 11.
- */
-#define GT_TIMER       4
-#define GT_INTA                2
-#define GT_INTD                5
-
-#ifndef __ASSEMBLY__
-
-/*
- * GT64120 internal register space base address
- */
-extern unsigned long gt64120_base;
-
-#define GT64120_BASE   (gt64120_base)
-
-/* define WRPPMC_EARLY_DEBUG to enable early output something to UART */
-#undef WRPPMC_EARLY_DEBUG
-
-#ifdef WRPPMC_EARLY_DEBUG
-extern void wrppmc_led_on(int mask);
-extern void wrppmc_led_off(int mask);
-extern void wrppmc_early_printk(const char *fmt, ...);
-#else
-#define wrppmc_early_printk(fmt, ...) do {} while (0)
-#endif /* WRPPMC_EARLY_DEBUG */
-
-#endif /* __ASSEMBLY__ */
-#endif /* __ASM_MIPS_GT64120_H */
diff --git a/arch/mips/include/asm/mach-wrppmc/war.h b/arch/mips/include/asm/mach-wrppmc/war.h
deleted file mode 100644 (file)
index e86084c..0000000
+++ /dev/null
@@ -1,24 +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) 2002, 2004, 2007 by Ralf Baechle <ralf@linux-mips.org>
- */
-#ifndef __ASM_MIPS_MACH_WRPPMC_WAR_H
-#define __ASM_MIPS_MACH_WRPPMC_WAR_H
-
-#define R4600_V1_INDEX_ICACHEOP_WAR    0
-#define R4600_V1_HIT_CACHEOP_WAR       0
-#define R4600_V2_HIT_CACHEOP_WAR       0
-#define R5432_CP0_INTERRUPT_WAR                0
-#define BCM1250_M3_WAR                 0
-#define SIBYTE_1956_WAR                        0
-#define MIPS4K_ICACHE_REFILL_WAR       0
-#define MIPS_CACHE_SYNC_WAR            0
-#define TX49XX_ICACHE_INDEX_INV_WAR    0
-#define ICACHE_REFILLS_WORKAROUND_WAR  1
-#define R10000_LLSC_WAR                        0
-#define MIPS34K_MISSED_ITLB_WAR                0
-
-#endif /* __ASM_MIPS_MACH_WRPPMC_WAR_H */
index bd9746f..4861681 100644 (file)
 #define ASCII_DISPLAY_POS_BASE    0x1f000418
 
 /*
- * Reset register.
- */
-#define SOFTRES_REG      0x1f000500
-#define GORESET                  0x42
-
-/*
  * Revision register.
  */
 #define MIPS_REVISION_REG                 0x1fc00010
index 87e6207..fed1c3e 100644 (file)
 #define MIPS_CONF3_RXI         (_ULCAST_(1) << 12)
 #define MIPS_CONF3_ULRI                (_ULCAST_(1) << 13)
 #define MIPS_CONF3_ISA         (_ULCAST_(3) << 14)
-#define MIPS_CONF3_ISA_OE      (_ULCAST_(3) << 16)
+#define MIPS_CONF3_ISA_OE      (_ULCAST_(1) << 16)
 #define MIPS_CONF3_VZ          (_ULCAST_(1) << 23)
 
 #define MIPS_CONF4_MMUSIZEEXT  (_ULCAST_(255) << 0)
index 516e6e9..3b29079 100644 (file)
 
 #define TLBMISS_HANDLER_SETUP_PGD(pgd)                                 \
 do {                                                                   \
-       void (*tlbmiss_handler_setup_pgd)(unsigned long);               \
-       extern u32 tlbmiss_handler_setup_pgd_array[16];                 \
-                                                                       \
-       tlbmiss_handler_setup_pgd =                                     \
-               (__typeof__(tlbmiss_handler_setup_pgd)) tlbmiss_handler_setup_pgd_array; \
+       extern void tlbmiss_handler_setup_pgd(unsigned long);           \
        tlbmiss_handler_setup_pgd((unsigned long)(pgd));                \
 } while (0)
 
index aef560a..bb68c33 100644 (file)
  * Common SMP definitions
  */
 #define RESET_VEC_PHYS         0x1fc00000
+#define RESET_VEC_SIZE         8192            /* 8KB reset code and data */
 #define RESET_DATA_PHYS                (RESET_VEC_PHYS + (1<<10))
+
+/* Offsets of parameters in the RESET_DATA_PHYS area */
 #define BOOT_THREAD_MODE       0
 #define BOOT_NMI_LOCK          4
 #define BOOT_NMI_HANDLER       8
 
+/* CPU ready flags for each CPU */
+#define BOOT_CPU_READY         2048
+
 #ifndef __ASSEMBLY__
 #include <linux/cpumask.h>
 #include <linux/spinlock.h>
@@ -59,23 +65,32 @@ int nlm_wakeup_secondary_cpus(void);
 void nlm_rmiboot_preboot(void);
 void nlm_percpu_init(int hwcpuid);
 
+static inline void *
+nlm_get_boot_data(int offset)
+{
+       return (void *)(CKSEG1ADDR(RESET_DATA_PHYS) + offset);
+}
+
 static inline void
 nlm_set_nmi_handler(void *handler)
 {
-       char *reset_data;
+       void *nmih = nlm_get_boot_data(BOOT_NMI_HANDLER);
 
-       reset_data = (char *)CKSEG1ADDR(RESET_DATA_PHYS);
-       *(int64_t *)(reset_data + BOOT_NMI_HANDLER) = (long)handler;
+       *(int64_t *)nmih = (long)handler;
 }
 
 /*
  * Misc.
  */
+void nlm_init_boot_cpu(void);
 unsigned int nlm_get_cpu_frequency(void);
 void nlm_node_init(int node);
 extern struct plat_smp_ops nlm_smp_ops;
 extern char nlm_reset_entry[], nlm_reset_entry_end[];
 
+/* SWIOTLB */
+extern struct dma_map_ops nlm_swiotlb_dma_ops;
+
 extern unsigned int nlm_threads_per_core;
 extern cpumask_t nlm_cpumask;
 
index a981f46..4b5108d 100644 (file)
@@ -315,7 +315,7 @@ nlm_pic_send_ipi(uint64_t base, int hwt, int irq, int nmi)
 {
        uint64_t ipi;
 
-       ipi = (nmi << 31) | (irq << 20);
+       ipi = ((uint64_t)nmi << 31) | (irq << 20);
        ipi |= ((hwt >> 4) << 16) | (1 << (hwt & 0xf)); /* cpuset and mask */
        nlm_write_pic_reg(base, PIC_IPI_CTL, ipi);
 }
index 7e47209..f4ea0f7 100644 (file)
@@ -59,6 +59,7 @@ void xlp_wakeup_secondary_cpus(void);
 
 void xlp_mmu_init(void);
 void nlm_hal_init(void);
+void *xlp_dt_init(void *fdtp);
 
 #endif /* !__ASSEMBLY__ */
 #endif /* _ASM_NLM_XLP_H */
index 2a78929..5604db3 100644 (file)
 #define nlm_write_c2_cc14(s, v)                __write_32bit_c2_register($30, s, v)
 #define nlm_write_c2_cc15(s, v)                __write_32bit_c2_register($31, s, v)
 
+#define nlm_read_c2_status0()          __read_32bit_c2_register($2, 0)
+#define nlm_write_c2_status0(v)                __write_32bit_c2_register($2, 0, v)
+#define nlm_read_c2_status1()          __read_32bit_c2_register($2, 1)
+#define nlm_write_c2_status1(v)                __write_32bit_c2_register($2, 1, v)
 #define nlm_read_c2_status(sel)                __read_32bit_c2_register($2, 0)
 #define nlm_read_c2_config()           __read_32bit_c2_register($3, 0)
 #define nlm_write_c2_config(v)         __write_32bit_c2_register($3, 0, v)
@@ -237,7 +241,7 @@ static inline void nlm_msgwait(unsigned int mask)
 /*
  * Disable interrupts and enable COP2 access
  */
-static inline uint32_t nlm_cop2_enable(void)
+static inline uint32_t nlm_cop2_enable_irqsave(void)
 {
        uint32_t sr = read_c0_status();
 
@@ -245,7 +249,7 @@ static inline uint32_t nlm_cop2_enable(void)
        return sr;
 }
 
-static inline void nlm_cop2_restore(uint32_t sr)
+static inline void nlm_cop2_disable_irqrestore(uint32_t sr)
 {
        write_c0_status(sr);
 }
@@ -296,7 +300,7 @@ static inline int nlm_fmn_send(unsigned int size, unsigned int code,
         */
        for (i = 0; i < 8; i++) {
                nlm_msgsnd(dest);
-               status = nlm_read_c2_status(0);
+               status = nlm_read_c2_status0();
                if ((status & 0x2) == 1)
                        pr_info("Send pending fail!\n");
                if ((status & 0x4) == 0)
@@ -316,7 +320,7 @@ static inline int nlm_fmn_receive(int bucket, int *size, int *code, int *stid,
 
        /* wait for load pending to clear */
        do {
-               status = nlm_read_c2_status(1);
+               status = nlm_read_c2_status0();
        } while ((status & 0x08) != 0);
 
        /* receive error bits */
index 284fa8d..7b7818d 100644 (file)
@@ -227,6 +227,7 @@ enum cvmx_board_types_enum {
         * use any numbers in this range.
         */
        CVMX_BOARD_TYPE_CUST_PRIVATE_MIN = 20001,
+       CVMX_BOARD_TYPE_UBNT_E100 = 20002,
        CVMX_BOARD_TYPE_CUST_PRIVATE_MAX = 30000,
 
        /* The remaining range is reserved for future use. */
@@ -325,6 +326,7 @@ static inline const char *cvmx_board_type_to_string(enum
 
                    /* Customer private range */
                ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_PRIVATE_MIN)
+               ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_UBNT_E100)
                ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_PRIVATE_MAX)
        }
        return "Unsupported Board";
index f59552f..f6be474 100644 (file)
@@ -205,10 +205,8 @@ extern int __virt_addr_valid(const volatile void *kaddr);
 #define VM_DATA_DEFAULT_FLAGS  (VM_READ | VM_WRITE | VM_EXEC | \
                                 VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
 
-#define UNCAC_ADDR(addr)       ((addr) - PAGE_OFFSET + UNCAC_BASE +    \
-                                                               PHYS_OFFSET)
-#define CAC_ADDR(addr)         ((addr) - UNCAC_BASE + PAGE_OFFSET -    \
-                                                               PHYS_OFFSET)
+#define UNCAC_ADDR(addr)       ((addr) - PAGE_OFFSET + UNCAC_BASE)
+#define CAC_ADDR(addr)         ((addr) - UNCAC_BASE + PAGE_OFFSET)
 
 #include <asm-generic/memory_model.h>
 #include <asm-generic/getorder.h>
index b8e24fd..fa8e0aa 100644 (file)
@@ -52,7 +52,6 @@ struct pci_controller {
 /*
  * Used by boards to register their PCI busses before the actual scanning.
  */
-extern struct pci_controller * alloc_pci_controller(void);
 extern void register_pci_controller(struct pci_controller *hose);
 
 /*
index 1470b7b..3605b84 100644 (file)
@@ -137,7 +137,7 @@ union mips_watch_reg_state {
        struct mips3264_watch_reg_state mips3264;
 };
 
-#ifdef CONFIG_CPU_CAVIUM_OCTEON
+#if defined(CONFIG_CPU_CAVIUM_OCTEON)
 
 struct octeon_cop2_state {
        /* DMFC2 rt, 0x0201 */
@@ -182,13 +182,26 @@ struct octeon_cop2_state {
        /* DMFC2 rt, 0x025A; DMFC2 rt, 0x025B - Pass2 */
        unsigned long   cop2_gfm_result[2];
 };
-#define INIT_OCTEON_COP2 {0,}
+#define COP2_INIT                                              \
+       .cp2                    = {0,},
 
 struct octeon_cvmseg_state {
        unsigned long cvmseg[CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE]
                            [cpu_dcache_line_size() / sizeof(unsigned long)];
 };
 
+#elif defined(CONFIG_CPU_XLP)
+struct nlm_cop2_state {
+       u64     rx[4];
+       u64     tx[4];
+       u32     tx_msg_status;
+       u32     rx_msg_status;
+};
+
+#define COP2_INIT                                              \
+       .cp2                    = {{0}, {0}, 0, 0},
+#else
+#define COP2_INIT
 #endif
 
 typedef struct {
@@ -231,8 +244,11 @@ struct thread_struct {
        unsigned long cp0_baduaddr;     /* Last kernel fault accessing USEG */
        unsigned long error_code;
 #ifdef CONFIG_CPU_CAVIUM_OCTEON
-    struct octeon_cop2_state cp2 __attribute__ ((__aligned__(128)));
-    struct octeon_cvmseg_state cvmseg __attribute__ ((__aligned__(128)));
+       struct octeon_cop2_state cp2 __attribute__ ((__aligned__(128)));
+       struct octeon_cvmseg_state cvmseg __attribute__ ((__aligned__(128)));
+#endif
+#ifdef CONFIG_CPU_XLP
+       struct nlm_cop2_state cp2;
 #endif
        struct mips_abi *abi;
 };
@@ -245,13 +261,6 @@ struct thread_struct {
 #define FPAFF_INIT
 #endif /* CONFIG_MIPS_MT_FPAFF */
 
-#ifdef CONFIG_CPU_CAVIUM_OCTEON
-#define OCTEON_INIT                                            \
-       .cp2                    = INIT_OCTEON_COP2,
-#else
-#define OCTEON_INIT
-#endif /* CONFIG_CPU_CAVIUM_OCTEON */
-
 #define INIT_THREAD  {                                         \
        /*                                                      \
         * Saved main processor registers                       \
@@ -300,9 +309,9 @@ struct thread_struct {
        .cp0_baduaddr           = 0,                            \
        .error_code             = 0,                            \
        /*                                                      \
-        * Cavium Octeon specifics (null if not Octeon)         \
+        * Platform specific cop2 registers(null if no COP2)    \
         */                                                     \
-       OCTEON_INIT                                             \
+       COP2_INIT                                               \
 }
 
 struct task_struct;
index a89d1b1..23fc95e 100644 (file)
 #ifndef CONFIG_CPU_HAS_SMARTMIPS
                LONG_S  v1, PT_LO(sp)
 #endif
+#ifdef CONFIG_CPU_CAVIUM_OCTEON
+               /*
+                * The Octeon multiplier state is affected by general
+                * multiply instructions. It must be saved before and
+                * kernel code might corrupt it
+                */
+               jal     octeon_mult_save
+#endif
                .endm
 
                .macro  SAVE_STATIC
                ori     $28, sp, _THREAD_MASK
                xori    $28, _THREAD_MASK
 #ifdef CONFIG_CPU_CAVIUM_OCTEON
-               .set    mips64
-               pref    0, 0($28)       /* Prefetch the current pointer */
-               pref    0, PT_R31(sp)   /* Prefetch the $31(ra) */
-               /* The Octeon multiplier state is affected by general multiply
-                   instructions. It must be saved before and kernel code might
-                   corrupt it */
-               jal     octeon_mult_save
-               LONG_L  v1, 0($28)  /* Load the current pointer */
-                        /* Restore $31(ra) that was changed by the jal */
-               LONG_L  ra, PT_R31(sp)
-               pref    0, 0(v1)    /* Prefetch the current thread */
+               .set    mips64
+               pref    0, 0($28)       /* Prefetch the current pointer */
 #endif
                .set    pop
                .endm
                .endm
 
                .macro  RESTORE_TEMP
+#ifdef CONFIG_CPU_CAVIUM_OCTEON
+               /* Restore the Octeon multiplier state */
+               jal     octeon_mult_restore
+#endif
 #ifdef CONFIG_CPU_HAS_SMARTMIPS
                LONG_L  $24, PT_ACX(sp)
                mtlhx   $24
                DVPE    5                               # dvpe a1
                jal     mips_ihb
 #endif /* CONFIG_MIPS_MT_SMTC */
-#ifdef CONFIG_CPU_CAVIUM_OCTEON
-               /* Restore the Octeon multiplier state */
-               jal     octeon_mult_restore
-#endif
                mfc0    a0, CP0_STATUS
                ori     a0, STATMASK
                xori    a0, STATMASK
diff --git a/arch/mips/include/asm/stackprotector.h b/arch/mips/include/asm/stackprotector.h
new file mode 100644 (file)
index 0000000..eb9b103
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * GCC stack protector support.
+ *
+ * (This is directly adopted from the ARM implementation)
+ *
+ * Stack protector works by putting predefined pattern at the start of
+ * the stack frame and verifying that it hasn't been overwritten when
+ * returning from the function.  The pattern is called stack canary
+ * and gcc expects it to be defined by a global variable called
+ * "__stack_chk_guard" on MIPS.  This unfortunately means that on SMP
+ * we cannot have a different canary value per task.
+ */
+
+#ifndef _ASM_STACKPROTECTOR_H
+#define _ASM_STACKPROTECTOR_H 1
+
+#include <linux/random.h>
+#include <linux/version.h>
+
+extern unsigned long __stack_chk_guard;
+
+/*
+ * Initialize the stackprotector canary value.
+ *
+ * NOTE: this must only be called from functions that never return,
+ * and it must always be inlined.
+ */
+static __always_inline void boot_init_stack_canary(void)
+{
+       unsigned long canary;
+
+       /* Try to get a semi random initial value. */
+       get_random_bytes(&canary, sizeof(canary));
+       canary ^= LINUX_VERSION_CODE;
+
+       current->stack_canary = canary;
+       __stack_chk_guard = current->stack_canary;
+}
+
+#endif /* _ASM_STACKPROTECTOR_H */
index fd16bcb..eb0af15 100644 (file)
@@ -15,6 +15,7 @@
 #include <asm/cpu-features.h>
 #include <asm/watch.h>
 #include <asm/dsp.h>
+#include <asm/cop2.h>
 
 struct task_struct;
 
@@ -66,10 +67,18 @@ do {                                                                        \
 
 #define switch_to(prev, next, last)                                    \
 do {                                                                   \
-       u32 __usedfpu;                                                  \
+       u32 __usedfpu, __c0_stat;                                       \
        __mips_mt_fpaff_switch_to(prev);                                \
        if (cpu_has_dsp)                                                \
                __save_dsp(prev);                                       \
+       if (cop2_present && (KSTK_STATUS(prev) & ST0_CU2)) {            \
+               if (cop2_lazy_restore)                                  \
+                       KSTK_STATUS(prev) &= ~ST0_CU2;                  \
+               __c0_stat = read_c0_status();                           \
+               write_c0_status(__c0_stat | ST0_CU2);                   \
+               cop2_save(&prev->thread.cp2);                           \
+               write_c0_status(__c0_stat & ~ST0_CU2);                  \
+       }                                                               \
        __clear_software_ll_bit();                                      \
        __usedfpu = test_and_clear_tsk_thread_flag(prev, TIF_USEDFPU);  \
        (last) = resume(prev, next, task_thread_info(next), __usedfpu); \
@@ -77,6 +86,14 @@ do {                                                                 \
 
 #define finish_arch_switch(prev)                                       \
 do {                                                                   \
+       u32 __c0_stat;                                                  \
+       if (cop2_present && !cop2_lazy_restore &&                       \
+                       (KSTK_STATUS(current) & ST0_CU2)) {             \
+               __c0_stat = read_c0_status();                           \
+               write_c0_status(__c0_stat | ST0_CU2);                   \
+               cop2_restore(&current->thread.cp2);                     \
+               write_c0_status(__c0_stat & ~ST0_CU2);                  \
+       }                                                               \
        if (cpu_has_dsp)                                                \
                __restore_dsp(current);                                 \
        if (cpu_has_userlocal)                                          \
index 895320e..61215a3 100644 (file)
@@ -109,6 +109,7 @@ static inline struct thread_info *current_thread_info(void)
 #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_MEMDIE             18      /* is terminating due to OOM killer */
+#define TIF_NOHZ               19      /* in adaptive nohz mode */
 #define TIF_FIXADE             20      /* Fix address errors in software */
 #define TIF_LOGADE             21      /* Log address errors to syslog */
 #define TIF_32BIT_REGS         22      /* also implies 16/32 fprs */
@@ -124,6 +125,7 @@ static inline struct thread_info *current_thread_info(void)
 #define _TIF_SECCOMP           (1<<TIF_SECCOMP)
 #define _TIF_NOTIFY_RESUME     (1<<TIF_NOTIFY_RESUME)
 #define _TIF_USEDFPU           (1<<TIF_USEDFPU)
+#define _TIF_NOHZ              (1<<TIF_NOHZ)
 #define _TIF_FIXADE            (1<<TIF_FIXADE)
 #define _TIF_LOGADE            (1<<TIF_LOGADE)
 #define _TIF_32BIT_REGS                (1<<TIF_32BIT_REGS)
@@ -131,14 +133,19 @@ static inline struct thread_info *current_thread_info(void)
 #define _TIF_FPUBOUND          (1<<TIF_FPUBOUND)
 #define _TIF_LOAD_WATCH                (1<<TIF_LOAD_WATCH)
 
+#define _TIF_WORK_SYSCALL_ENTRY        (_TIF_NOHZ | _TIF_SYSCALL_TRACE |       \
+                                _TIF_SYSCALL_AUDIT)
+
 /* work to do in syscall_trace_leave() */
-#define _TIF_WORK_SYSCALL_EXIT (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT)
+#define _TIF_WORK_SYSCALL_EXIT (_TIF_NOHZ | _TIF_SYSCALL_TRACE |       \
+                                _TIF_SYSCALL_AUDIT)
 
 /* work to do on interrupt/exception return */
 #define _TIF_WORK_MASK         \
        (_TIF_SIGPENDING | _TIF_NEED_RESCHED | _TIF_NOTIFY_RESUME)
 /* work to do on any return to u-space */
-#define _TIF_ALLWORK_MASK      (_TIF_WORK_MASK | _TIF_WORK_SYSCALL_EXIT)
+#define _TIF_ALLWORK_MASK      (_TIF_NOHZ | _TIF_WORK_MASK |           \
+                                _TIF_WORK_SYSCALL_EXIT)
 
 #endif /* __KERNEL__ */
 
index 680e7ef..26d2ed1 100644 (file)
@@ -47,6 +47,15 @@ typedef struct xtalk_piomap_s *xtalk_piomap_t;
 #define XIO_PORT(x)    ((xwidgetnum_t)(((x)&XIO_PORT_BITS) >> XIO_PORT_SHIFT))
 #define XIO_PACK(p, o) ((((uint64_t)(p))<<XIO_PORT_SHIFT) | ((o)&XIO_ADDR_BITS))
 
+#ifdef CONFIG_PCI
+extern int bridge_probe(nasid_t nasid, int widget, int masterwid);
+#else
+static inline int bridge_probe(nasid_t nasid, int widget, int masterwid)
+{
+       return 0;
+}
+#endif
+
 #endif /* !__ASSEMBLY__ */
 
 #endif /* _ASM_XTALK_XTALK_H */
index 0bda78f..6ca432f 100644 (file)
@@ -5,9 +5,10 @@
  *
  * Copyright (C) 1995, 96, 97, 98, 99, 2003, 05 Ralf Baechle
  */
-#ifndef _ASM_FCNTL_H
-#define _ASM_FCNTL_H
+#ifndef _UAPI_ASM_FCNTL_H
+#define _UAPI_ASM_FCNTL_H
 
+#include <asm/sgidefs.h>
 
 #define O_APPEND       0x0008
 #define O_DSYNC                0x0010  /* used to be O_SYNC, see below */
  * contain all the same fields as struct flock.
  */
 
-#ifdef CONFIG_32BIT
+#if _MIPS_SIM != _MIPS_SIM_ABI64
+
 #include <linux/types.h>
 
 struct flock {
        short   l_type;
        short   l_whence;
-       off_t   l_start;
-       off_t   l_len;
+       __kernel_off_t  l_start;
+       __kernel_off_t  l_len;
        long    l_sysid;
        __kernel_pid_t l_pid;
        long    pad[4];
@@ -70,8 +72,8 @@ struct flock {
 
 #define HAVE_ARCH_STRUCT_FLOCK
 
-#endif /* CONFIG_32BIT */
+#endif /* _MIPS_SIM == _MIPS_SIM_ABI32 */
 
 #include <asm-generic/fcntl.h>
 
-#endif /* _ASM_FCNTL_H */
+#endif /* _UAPI_ASM_FCNTL_H */
index 0f4aec2..e5a676e 100644 (file)
@@ -409,10 +409,11 @@ enum mm_32f_73_minor_op {
 enum mm_16c_minor_op {
        mm_lwm16_op = 0x04,
        mm_swm16_op = 0x05,
-       mm_jr16_op = 0x18,
-       mm_jrc_op = 0x1a,
-       mm_jalr16_op = 0x1c,
-       mm_jalrs16_op = 0x1e,
+       mm_jr16_op = 0x0c,
+       mm_jrc_op = 0x0d,
+       mm_jalr16_op = 0x0e,
+       mm_jalrs16_op = 0x0f,
+       mm_jraddiusp_op = 0x18,
 };
 
 /*
index 0d6c7f1..df849e8 100644 (file)
 
 struct msqid64_ds {
        struct ipc64_perm msg_perm;
-#if defined(CONFIG_32BIT) && !defined(CONFIG_CPU_LITTLE_ENDIAN)
+#if !defined(__mips64) && defined(__MIPSEB__)
        unsigned long   __unused1;
 #endif
        __kernel_time_t msg_stime;      /* last msgsnd time */
-#if defined(CONFIG_32BIT) && defined(CONFIG_CPU_LITTLE_ENDIAN)
+#if !defined(__mips64) && defined(__MIPSEL__)
        unsigned long   __unused1;
 #endif
-#if defined(CONFIG_32BIT) && !defined(CONFIG_CPU_LITTLE_ENDIAN)
+#if !defined(__mips64) && defined(__MIPSEB__)
        unsigned long   __unused2;
 #endif
        __kernel_time_t msg_rtime;      /* last msgrcv time */
-#if defined(CONFIG_32BIT) && defined(CONFIG_CPU_LITTLE_ENDIAN)
+#if !defined(__mips64) && defined(__MIPSEL__)
        unsigned long   __unused2;
 #endif
-#if defined(CONFIG_32BIT) && !defined(CONFIG_CPU_LITTLE_ENDIAN)
+#if !defined(__mips64) && defined(__MIPSEB__)
        unsigned long   __unused3;
 #endif
        __kernel_time_t msg_ctime;      /* last change time */
-#if defined(CONFIG_32BIT) && defined(CONFIG_CPU_LITTLE_ENDIAN)
+#if !defined(__mips64) && defined(__MIPSEL__)
        unsigned long   __unused3;
 #endif
        unsigned long  msg_cbytes;      /* current number of bytes on queue */
index 87cb308..b26439d 100644 (file)
@@ -26,7 +26,7 @@
  * but we keep the old value on MIPS32,
  * for compatibility:
  */
-#ifdef CONFIG_32BIT
+#ifndef __mips64
 # define RLIM_INFINITY         0x7fffffffUL
 #endif
 
index 6a87141..b7a2306 100644 (file)
@@ -25,10 +25,10 @@ struct siginfo;
 /*
  * Careful to keep union _sifields from shifting ...
  */
-#ifdef CONFIG_32BIT
+#if __SIZEOF_LONG__ == 4
 #define __ARCH_SI_PREAMBLE_SIZE (3 * sizeof(int))
 #endif
-#ifdef CONFIG_64BIT
+#if __SIZEOF_LONG__ == 8
 #define __ARCH_SI_PREAMBLE_SIZE (4 * sizeof(int))
 #endif
 
index 6a07992..61c01f0 100644 (file)
@@ -92,6 +92,6 @@
 
 #define SO_SELECT_ERR_QUEUE    45
 
-#define SO_LL                  46
+#define SO_BUSY_POLL           46
 
 #endif /* _UAPI_ASM_SOCKET_H */
index 97c2f81..ac9a8f9 100644 (file)
@@ -13,7 +13,7 @@
 
 #define __SWAB_64_THRU_32__
 
-#ifdef CONFIG_CPU_MIPSR2
+#if defined(__mips_isa_rev) && (__mips_isa_rev >= 2)
 
 static inline __attribute_const__ __u16 __arch_swab16(__u16 x)
 {
@@ -39,10 +39,10 @@ static inline __attribute_const__ __u32 __arch_swab32(__u32 x)
 #define __arch_swab32 __arch_swab32
 
 /*
- * Having already checked for CONFIG_CPU_MIPSR2, enable the
- * optimized version for 64-bit kernel on r2 CPUs.
+ * Having already checked for MIPS R2, enable the optimized version for
+ * 64-bit kernel on r2 CPUs.
  */
-#ifdef CONFIG_64BIT
+#ifdef __mips64
 static inline __attribute_const__ __u64 __arch_swab64(__u64 x)
 {
        __asm__(
@@ -54,6 +54,6 @@ static inline __attribute_const__ __u64 __arch_swab64(__u64 x)
        return x;
 }
 #define __arch_swab64 __arch_swab64
-#endif /* CONFIG_64BIT */
-#endif /* CONFIG_CPU_MIPSR2 */
+#endif /* __mips64 */
+#endif /* MIPS R2 or newer  */
 #endif /* _ASM_SWAB_H */
index 0845091..0c2e853 100644 (file)
@@ -82,6 +82,9 @@ void output_task_defines(void)
        OFFSET(TASK_FLAGS, task_struct, flags);
        OFFSET(TASK_MM, task_struct, mm);
        OFFSET(TASK_PID, task_struct, pid);
+#if defined(CONFIG_CC_STACKPROTECTOR)
+       OFFSET(TASK_STACK_CANARY, task_struct, stack_canary);
+#endif
        DEFINE(TASK_STRUCT_SIZE, sizeof(struct task_struct));
        BLANK();
 }
index 46c2ad0..4d78bf4 100644 (file)
@@ -467,5 +467,4 @@ unaligned:
        printk("%s: unaligned epc - sending SIGBUS.\n", current->comm);
        force_sig(SIGBUS, current);
        return -EFAULT;
-
 }
index de3c25f..0c61df2 100644 (file)
@@ -6,6 +6,7 @@
  * as published by the Free Software Foundation; either version
  * 2 of the License, or (at your option) any later version.
  */
+#include <linux/context_tracking.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/ptrace.h>
@@ -171,8 +172,12 @@ static volatile int daddi_ov __cpuinitdata;
 
 asmlinkage void __init do_daddi_ov(struct pt_regs *regs)
 {
+       enum ctx_state prev_state;
+
+       prev_state = exception_enter();
        daddi_ov = 1;
        regs->cp0_epc += 4;
+       exception_exit(prev_state);
 }
 
 static inline void check_daddi(void)
index c6568bf..c7b1b3c 100644 (file)
@@ -146,8 +146,7 @@ static void __cpuinit set_isa(struct cpuinfo_mips *c, unsigned int isa)
        case MIPS_CPU_ISA_IV:
                c->isa_level |= MIPS_CPU_ISA_IV;
        case MIPS_CPU_ISA_III:
-               c->isa_level |= MIPS_CPU_ISA_I | MIPS_CPU_ISA_II |
-                               MIPS_CPU_ISA_III;
+               c->isa_level |= MIPS_CPU_ISA_II | MIPS_CPU_ISA_III;
                break;
 
        case MIPS_CPU_ISA_M32R2:
@@ -156,8 +155,6 @@ static void __cpuinit set_isa(struct cpuinfo_mips *c, unsigned int isa)
                c->isa_level |= MIPS_CPU_ISA_M32R1;
        case MIPS_CPU_ISA_II:
                c->isa_level |= MIPS_CPU_ISA_II;
-       case MIPS_CPU_ISA_I:
-               c->isa_level |= MIPS_CPU_ISA_I;
                break;
        }
 }
@@ -272,9 +269,6 @@ static inline unsigned int decode_config3(struct cpuinfo_mips *c)
                c->options |= MIPS_CPU_ULRI;
        if (config3 & MIPS_CONF3_ISA)
                c->options |= MIPS_CPU_MICROMIPS;
-#ifdef CONFIG_CPU_MICROMIPS
-       write_c0_config3(read_c0_config3() | MIPS_CONF3_ISA_OE);
-#endif
        if (config3 & MIPS_CONF3_VZ)
                c->ases |= MIPS_ASE_VZ;
 
@@ -332,7 +326,6 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu)
        case PRID_IMP_R2000:
                c->cputype = CPU_R2000;
                __cpu_name[cpu] = "R2000";
-               set_isa(c, MIPS_CPU_ISA_I);
                c->options = MIPS_CPU_TLB | MIPS_CPU_3K_CACHE |
                             MIPS_CPU_NOFPUEX;
                if (__cpu_has_fpu())
@@ -352,7 +345,6 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu)
                        c->cputype = CPU_R3000;
                        __cpu_name[cpu] = "R3000";
                }
-               set_isa(c, MIPS_CPU_ISA_I);
                c->options = MIPS_CPU_TLB | MIPS_CPU_3K_CACHE |
                             MIPS_CPU_NOFPUEX;
                if (__cpu_has_fpu())
@@ -455,7 +447,6 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu)
                break;
        #endif
        case PRID_IMP_TX39:
-               set_isa(c, MIPS_CPU_ISA_I);
                c->options = MIPS_CPU_TLB | MIPS_CPU_TX39_CACHE;
 
                if ((c->processor_id & 0xf0) == (PRID_REV_TX3927 & 0xf0)) {
@@ -959,6 +950,7 @@ static inline void cpu_probe_netlogic(struct cpuinfo_mips *c, int cpu)
                set_isa(c, MIPS_CPU_ISA_M64R1);
                c->tlbsize = ((read_c0_config1() >> 25) & 0x3f) + 1;
        }
+       c->kscratch_mask = 0xf;
 }
 
 #ifdef CONFIG_64BIT
index c61cdae..0999123 100644 (file)
 #include <kernel-entry-init.h>
 
        /*
-        * inputs are the text nasid in t1, data nasid in t2.
-        */
-       .macro MAPPED_KERNEL_SETUP_TLB
-#ifdef CONFIG_MAPPED_KERNEL
-       /*
-        * This needs to read the nasid - assume 0 for now.
-        * Drop in 0xffffffffc0000000 in tlbhi, 0+VG in tlblo_0,
-        * 0+DVG in tlblo_1.
-        */
-       dli     t0, 0xffffffffc0000000
-       dmtc0   t0, CP0_ENTRYHI
-       li      t0, 0x1c000             # Offset of text into node memory
-       dsll    t1, NASID_SHFT          # Shift text nasid into place
-       dsll    t2, NASID_SHFT          # Same for data nasid
-       or      t1, t1, t0              # Physical load address of kernel text
-       or      t2, t2, t0              # Physical load address of kernel data
-       dsrl    t1, 12                  # 4K pfn
-       dsrl    t2, 12                  # 4K pfn
-       dsll    t1, 6                   # Get pfn into place
-       dsll    t2, 6                   # Get pfn into place
-       li      t0, ((_PAGE_GLOBAL|_PAGE_VALID| _CACHE_CACHABLE_COW) >> 6)
-       or      t0, t0, t1
-       mtc0    t0, CP0_ENTRYLO0        # physaddr, VG, cach exlwr
-       li      t0, ((_PAGE_GLOBAL|_PAGE_VALID| _PAGE_DIRTY|_CACHE_CACHABLE_COW) >> 6)
-       or      t0, t0, t2
-       mtc0    t0, CP0_ENTRYLO1        # physaddr, DVG, cach exlwr
-       li      t0, 0x1ffe000           # MAPPED_KERN_TLBMASK, TLBPGMASK_16M
-       mtc0    t0, CP0_PAGEMASK
-       li      t0, 0                   # KMAP_INX
-       mtc0    t0, CP0_INDEX
-       li      t0, 1
-       mtc0    t0, CP0_WIRED
-       tlbwi
-#else
-       mtc0    zero, CP0_WIRED
-#endif
-       .endm
-
-       /*
         * For the moment disable interrupts, mark the kernel mode and
         * set ST0_KX so that the CPU does not spit fire when using
         * 64-bit addresses.  A full initialization of the CPU's status
index c01b307..5b5ddb2 100644 (file)
@@ -219,16 +219,15 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *cpumask,
 
        /* Assumption : cpumask refers to a single CPU */
        spin_lock_irqsave(&gic_lock, flags);
-       for (;;) {
-               /* Re-route this IRQ */
-               GIC_SH_MAP_TO_VPE_SMASK(irq, first_cpu(tmp));
 
-               /* Update the pcpu_masks */
-               for (i = 0; i < NR_CPUS; i++)
-                       clear_bit(irq, pcpu_masks[i].pcpu_mask);
-               set_bit(irq, pcpu_masks[first_cpu(tmp)].pcpu_mask);
+       /* Re-route this IRQ */
+       GIC_SH_MAP_TO_VPE_SMASK(irq, first_cpu(tmp));
+
+       /* Update the pcpu_masks */
+       for (i = 0; i < NR_CPUS; i++)
+               clear_bit(irq, pcpu_masks[i].pcpu_mask);
+       set_bit(irq, pcpu_masks[first_cpu(tmp)].pcpu_mask);
 
-       }
        cpumask_copy(d->affinity, cpumask);
        spin_unlock_irqrestore(&gic_lock, flags);
 
index 33d0671..a03e93c 100644 (file)
@@ -168,15 +168,11 @@ NESTED(ftrace_graph_caller, PT_SIZE, ra)
 #endif
 
        /* arg3: Get frame pointer of current stack */
-#ifdef CONFIG_FRAME_POINTER
-       move    a2, fp
-#else /* ! CONFIG_FRAME_POINTER */
 #ifdef CONFIG_64BIT
        PTR_LA  a2, PT_SIZE(sp)
 #else
        PTR_LA  a2, (PT_SIZE+8)(sp)
 #endif
-#endif
 
        jal     prepare_ftrace_return
         nop
index 0e23343..4204d76 100644 (file)
        cpu_save_nonscratch a0
        LONG_S  ra, THREAD_REG31(a0)
 
-       /* check if we need to save COP2 registers */
-       PTR_L   t2, TASK_THREAD_INFO(a0)
-       LONG_L  t0, ST_OFF(t2)
-       bbit0   t0, 30, 1f
-
-       /* Disable COP2 in the stored process state */
-       li      t1, ST0_CU2
-       xor     t0, t1
-       LONG_S  t0, ST_OFF(t2)
-
-       /* Enable COP2 so we can save it */
-       mfc0    t0, CP0_STATUS
-       or      t0, t1
-       mtc0    t0, CP0_STATUS
-
-       /* Save COP2 */
-       daddu   a0, THREAD_CP2
-       jal octeon_cop2_save
-       dsubu   a0, THREAD_CP2
-
-       /* Disable COP2 now that we are done */
-       mfc0    t0, CP0_STATUS
-       li      t1, ST0_CU2
-       xor     t0, t1
-       mtc0    t0, CP0_STATUS
-
-1:
 #if CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE > 0
        /* Check if we need to store CVMSEG state */
        mfc0    t0, $11,7       /* CvmMemCtl */
        mtc0    t0, $11,7       /* CvmMemCtl */
 #endif
 3:
+
+#if defined(CONFIG_CC_STACKPROTECTOR) && !defined(CONFIG_SMP)
+       PTR_L   t8, __stack_chk_guard
+       LONG_L  t9, TASK_STACK_CANARY(a1)
+       LONG_S  t9, 0(t8)
+#endif
+
        /*
         * The order of restoring the registers takes care of the race
         * updating $28, $29 and kernelsp without disabling ints.
index acb3437..8c58d8a 100644 (file)
@@ -66,9 +66,7 @@ static int show_cpuinfo(struct seq_file *m, void *v)
                seq_printf(m, "]\n");
        }
        if (cpu_has_mips_r) {
-               seq_printf(m, "isa\t\t\t:");
-               if (cpu_has_mips_1)
-                       seq_printf(m, "%s", " mips1");
+               seq_printf(m, "isa\t\t\t: mips1");
                if (cpu_has_mips_2)
                        seq_printf(m, "%s", " mips2");
                if (cpu_has_mips_3)
index c6a041d..ddc7610 100644 (file)
@@ -201,9 +201,12 @@ int dump_task_fpu(struct task_struct *t, elf_fpregset_t *fpr)
        return 1;
 }
 
-/*
- *
- */
+#ifdef CONFIG_CC_STACKPROTECTOR
+#include <linux/stackprotector.h>
+unsigned long __stack_chk_guard __read_mostly;
+EXPORT_SYMBOL(__stack_chk_guard);
+#endif
+
 struct mips_frame_info {
        void            *func;
        unsigned long   func_size;
index 5712bb5..7e95404 100644 (file)
@@ -30,7 +30,7 @@ __init void mips_set_machine_name(const char *name)
        if (name == NULL)
                return;
 
-       strncpy(mips_machine_name, name, sizeof(mips_machine_name));
+       strlcpy(mips_machine_name, name, sizeof(mips_machine_name));
        pr_info("MIPS: machine is %s\n", mips_get_machine_name());
 }
 
index 9c6299c..8ae1ebe 100644 (file)
@@ -15,6 +15,7 @@
  * binaries.
  */
 #include <linux/compiler.h>
+#include <linux/context_tracking.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
@@ -534,6 +535,8 @@ static inline int audit_arch(void)
  */
 asmlinkage void syscall_trace_enter(struct pt_regs *regs)
 {
+       user_exit();
+
        /* do the secure computing check first */
        secure_computing_strict(regs->regs[2]);
 
@@ -570,6 +573,13 @@ out:
  */
 asmlinkage void syscall_trace_leave(struct pt_regs *regs)
 {
+        /*
+        * We may come here right after calling schedule_user()
+        * or do_notify_resume(), in which case we can be in RCU
+        * user mode.
+        */
+       user_exit();
+
        audit_syscall_exit(regs);
 
        if (!(current->ptrace & PT_PTRACED))
@@ -592,4 +602,6 @@ asmlinkage void syscall_trace_leave(struct pt_regs *regs)
                send_sig(current->exit_code, current, 1);
                current->exit_code = 0;
        }
+
+       user_enter();
 }
index 5266c6e..38af83f 100644 (file)
@@ -65,6 +65,13 @@ LEAF(resume)
        fpu_save_single a0, t0                  # clobbers t0
 
 1:
+
+#if defined(CONFIG_CC_STACKPROTECTOR) && !defined(CONFIG_SMP)
+       PTR_L   t8, __stack_chk_guard
+       LONG_L  t9, TASK_STACK_CANARY(a1)
+       LONG_S  t9, 0(t8)
+#endif
+
        /*
         * The order of restoring the registers takes care of the race
         * updating $28, $29 and kernelsp without disabling ints.
index 5e51219..921238a 100644 (file)
                                                # clobbers t1
 1:
 
+#if defined(CONFIG_CC_STACKPROTECTOR) && !defined(CONFIG_SMP)
+       PTR_L   t8, __stack_chk_guard
+       LONG_L  t9, TASK_STACK_CANARY(a1)
+       LONG_S  t9, 0(t8)
+#endif
+
        /*
         * The order of restoring the registers takes care of the race
         * updating $28, $29 and kernelsp without disabling ints.
index 6fa198d..d763f11 100644 (file)
@@ -437,7 +437,6 @@ static ssize_t file_write(struct file *file, const char __user * buffer,
                          size_t count, loff_t * ppos)
 {
        int minor = iminor(file_inode(file));
-       struct rtlx_channel *rt = &rtlx->channel[minor];
 
        /* any space left... */
        if (!rtlx_write_poll(minor)) {
index e9127ec..e774bb1 100644 (file)
@@ -52,7 +52,7 @@ NESTED(handle_sys, PT_SIZE, sp)
 
 stack_done:
        lw      t0, TI_FLAGS($28)       # syscall tracing enabled?
-       li      t1, _TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT
+       li      t1, _TIF_WORK_SYSCALL_ENTRY
        and     t0, t1
        bnez    t0, syscall_trace_entry # -> yes
 
index 97a5909..be6627e 100644 (file)
@@ -54,7 +54,7 @@ NESTED(handle_sys64, PT_SIZE, sp)
 
        sd      a3, PT_R26(sp)          # save a3 for syscall restarting
 
-       li      t1, _TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT
+       li      t1, _TIF_WORK_SYSCALL_ENTRY
        LONG_L  t0, TI_FLAGS($28)       # syscall tracing enabled?
        and     t0, t1, t0
        bnez    t0, syscall_trace_entry
index edcb659..cab1507 100644 (file)
@@ -47,7 +47,7 @@ NESTED(handle_sysn32, PT_SIZE, sp)
 
        sd      a3, PT_R26(sp)          # save a3 for syscall restarting
 
-       li      t1, _TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT
+       li      t1, _TIF_WORK_SYSCALL_ENTRY
        LONG_L  t0, TI_FLAGS($28)       # syscall tracing enabled?
        and     t0, t1, t0
        bnez    t0, n32_syscall_trace_entry
index 74f485d..37605dc 100644 (file)
@@ -81,7 +81,7 @@ NESTED(handle_sys, PT_SIZE, sp)
        PTR     4b, bad_stack
        .previous
 
-       li      t1, _TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT
+       li      t1, _TIF_WORK_SYSCALL_ENTRY
        LONG_L  t0, TI_FLAGS($28)       # syscall tracing enabled?
        and     t0, t1, t0
        bnez    t0, trace_a_syscall
index fd3ef2c..2f285ab 100644 (file)
@@ -8,6 +8,7 @@
  * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
  */
 #include <linux/cache.h>
+#include <linux/context_tracking.h>
 #include <linux/irqflags.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
@@ -573,6 +574,8 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, void *unused,
 {
        local_irq_enable();
 
+       user_exit();
+
        /* deal with pending signal delivery */
        if (thread_info_flags & _TIF_SIGPENDING)
                do_signal(regs);
@@ -581,6 +584,8 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, void *unused,
                clear_thread_flag(TIF_NOTIFY_RESUME);
                tracehook_notify_resume(regs);
        }
+
+       user_enter();
 }
 
 #ifdef CONFIG_SMP
index 8e393b8..aea6c08 100644 (file)
@@ -63,7 +63,7 @@ static irqreturn_t bmips_ipi_interrupt(int irq, void *dev_id);
 
 static void __init bmips_smp_setup(void)
 {
-       int i;
+       int i, cpu = 1, boot_cpu = 0;
 
 #if defined(CONFIG_CPU_BMIPS4350) || defined(CONFIG_CPU_BMIPS4380)
        /* arbitration priority */
@@ -72,13 +72,22 @@ static void __init bmips_smp_setup(void)
        /* NBK and weak order flags */
        set_c0_brcm_config_0(0x30000);
 
+       /* Find out if we are running on TP0 or TP1 */
+       boot_cpu = !!(read_c0_brcm_cmt_local() & (1 << 31));
+
        /*
         * MIPS interrupts 0,1 (SW INT 0,1) cross over to the other thread
         * MIPS interrupt 2 (HW INT 0) is the CPU0 L1 controller output
         * MIPS interrupt 3 (HW INT 1) is the CPU1 L1 controller output
+        *
+        * If booting from TP1, leave the existing CMT interrupt routing
+        * such that TP0 responds to SW1 and TP1 responds to SW0.
         */
-       change_c0_brcm_cmt_intr(0xf8018000,
-               (0x02 << 27) | (0x03 << 15));
+       if (boot_cpu == 0)
+               change_c0_brcm_cmt_intr(0xf8018000,
+                                       (0x02 << 27) | (0x03 << 15));
+       else
+               change_c0_brcm_cmt_intr(0xf8018000, (0x1d << 27));
 
        /* single core, 2 threads (2 pipelines) */
        max_cpus = 2;
@@ -106,9 +115,15 @@ static void __init bmips_smp_setup(void)
        if (!board_ebase_setup)
                board_ebase_setup = &bmips_ebase_setup;
 
+       __cpu_number_map[boot_cpu] = 0;
+       __cpu_logical_map[0] = boot_cpu;
+
        for (i = 0; i < max_cpus; i++) {
-               __cpu_number_map[i] = 1;
-               __cpu_logical_map[i] = 1;
+               if (i != boot_cpu) {
+                       __cpu_number_map[i] = cpu;
+                       __cpu_logical_map[cpu] = i;
+                       cpu++;
+               }
                set_cpu_possible(i, 1);
                set_cpu_present(i, 1);
        }
@@ -157,7 +172,9 @@ static void bmips_boot_secondary(int cpu, struct task_struct *idle)
                bmips_send_ipi_single(cpu, 0);
        else {
 #if defined(CONFIG_CPU_BMIPS4350) || defined(CONFIG_CPU_BMIPS4380)
-               set_c0_brcm_cmt_ctrl(0x01);
+               /* Reset slave TP1 if booting from TP0 */
+               if (cpu_logical_map(cpu) == 0)
+                       set_c0_brcm_cmt_ctrl(0x01);
 #elif defined(CONFIG_CPU_BMIPS5000)
                if (cpu & 0x01)
                        write_c0_brcm_action(ACTION_BOOT_THREAD(cpu));
index a75ae40..0903d70 100644 (file)
@@ -13,6 +13,7 @@
  */
 #include <linux/bug.h>
 #include <linux/compiler.h>
+#include <linux/context_tracking.h>
 #include <linux/kexec.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
@@ -264,7 +265,7 @@ static void __show_regs(const struct pt_regs *regs)
 
        printk("Status: %08x    ", (uint32_t) regs->cp0_status);
 
-       if (current_cpu_data.isa_level == MIPS_CPU_ISA_I) {
+       if (cpu_has_3kex) {
                if (regs->cp0_status & ST0_KUO)
                        printk("KUo ");
                if (regs->cp0_status & ST0_IEO)
@@ -277,7 +278,7 @@ static void __show_regs(const struct pt_regs *regs)
                        printk("KUc ");
                if (regs->cp0_status & ST0_IEC)
                        printk("IEc ");
-       } else {
+       } else if (cpu_has_4kex) {
                if (regs->cp0_status & ST0_KX)
                        printk("KX ");
                if (regs->cp0_status & ST0_SX)
@@ -423,7 +424,9 @@ asmlinkage void do_be(struct pt_regs *regs)
        const struct exception_table_entry *fixup = NULL;
        int data = regs->cp0_cause & 4;
        int action = MIPS_BE_FATAL;
+       enum ctx_state prev_state;
 
+       prev_state = exception_enter();
        /* XXX For now.  Fixme, this searches the wrong table ...  */
        if (data && !user_mode(regs))
                fixup = search_dbe_tables(exception_epc(regs));
@@ -436,11 +439,11 @@ asmlinkage void do_be(struct pt_regs *regs)
 
        switch (action) {
        case MIPS_BE_DISCARD:
-               return;
+               goto out;
        case MIPS_BE_FIXUP:
                if (fixup) {
                        regs->cp0_epc = fixup->nextinsn;
-                       return;
+                       goto out;
                }
                break;
        default:
@@ -455,10 +458,13 @@ asmlinkage void do_be(struct pt_regs *regs)
               field, regs->cp0_epc, field, regs->regs[31]);
        if (notify_die(DIE_OOPS, "bus error", regs, 0, regs_to_trapnr(regs), SIGBUS)
            == NOTIFY_STOP)
-               return;
+               goto out;
 
        die_if_kernel("Oops", regs);
        force_sig(SIGBUS, current);
+
+out:
+       exception_exit(prev_state);
 }
 
 /*
@@ -673,8 +679,10 @@ static int simulate_sync(struct pt_regs *regs, unsigned int opcode)
 
 asmlinkage void do_ov(struct pt_regs *regs)
 {
+       enum ctx_state prev_state;
        siginfo_t info;
 
+       prev_state = exception_enter();
        die_if_kernel("Integer overflow", regs);
 
        info.si_code = FPE_INTOVF;
@@ -682,6 +690,7 @@ asmlinkage void do_ov(struct pt_regs *regs)
        info.si_errno = 0;
        info.si_addr = (void __user *) regs->cp0_epc;
        force_sig_info(SIGFPE, &info, current);
+       exception_exit(prev_state);
 }
 
 int process_fpemu_return(int sig, void __user *fault_addr)
@@ -713,11 +722,13 @@ int process_fpemu_return(int sig, void __user *fault_addr)
  */
 asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31)
 {
+       enum ctx_state prev_state;
        siginfo_t info = {0};
 
+       prev_state = exception_enter();
        if (notify_die(DIE_FP, "FP exception", regs, 0, regs_to_trapnr(regs), SIGFPE)
            == NOTIFY_STOP)
-               return;
+               goto out;
        die_if_kernel("FP exception in kernel code", regs);
 
        if (fcr31 & FPU_CSR_UNI_X) {
@@ -753,7 +764,7 @@ asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31)
                /* If something went wrong, signal */
                process_fpemu_return(sig, fault_addr);
 
-               return;
+               goto out;
        } else if (fcr31 & FPU_CSR_INV_X)
                info.si_code = FPE_FLTINV;
        else if (fcr31 & FPU_CSR_DIV_X)
@@ -770,6 +781,9 @@ asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31)
        info.si_errno = 0;
        info.si_addr = (void __user *) regs->cp0_epc;
        force_sig_info(SIGFPE, &info, current);
+
+out:
+       exception_exit(prev_state);
 }
 
 static void do_trap_or_bp(struct pt_regs *regs, unsigned int code,
@@ -835,9 +849,11 @@ static void do_trap_or_bp(struct pt_regs *regs, unsigned int code,
 asmlinkage void do_bp(struct pt_regs *regs)
 {
        unsigned int opcode, bcode;
+       enum ctx_state prev_state;
        unsigned long epc;
        u16 instr[2];
 
+       prev_state = exception_enter();
        if (get_isa16_mode(regs->cp0_epc)) {
                /* Calculate EPC. */
                epc = exception_epc(regs);
@@ -852,7 +868,7 @@ asmlinkage void do_bp(struct pt_regs *regs)
                                goto out_sigsegv;
                    bcode = (instr[0] >> 6) & 0x3f;
                    do_trap_or_bp(regs, bcode, "Break");
-                   return;
+                   goto out;
                }
        } else {
                if (__get_user(opcode, (unsigned int __user *) exception_epc(regs)))
@@ -876,12 +892,12 @@ asmlinkage void do_bp(struct pt_regs *regs)
        switch (bcode) {
        case BRK_KPROBE_BP:
                if (notify_die(DIE_BREAK, "debug", regs, bcode, regs_to_trapnr(regs), SIGTRAP) == NOTIFY_STOP)
-                       return;
+                       goto out;
                else
                        break;
        case BRK_KPROBE_SSTEPBP:
                if (notify_die(DIE_SSTEPBP, "single_step", regs, bcode, regs_to_trapnr(regs), SIGTRAP) == NOTIFY_STOP)
-                       return;
+                       goto out;
                else
                        break;
        default:
@@ -889,18 +905,24 @@ asmlinkage void do_bp(struct pt_regs *regs)
        }
 
        do_trap_or_bp(regs, bcode, "Break");
+
+out:
+       exception_exit(prev_state);
        return;
 
 out_sigsegv:
        force_sig(SIGSEGV, current);
+       goto out;
 }
 
 asmlinkage void do_tr(struct pt_regs *regs)
 {
        u32 opcode, tcode = 0;
+       enum ctx_state prev_state;
        u16 instr[2];
        unsigned long epc = msk_isa16_mode(exception_epc(regs));
 
+       prev_state = exception_enter();
        if (get_isa16_mode(regs->cp0_epc)) {
                if (__get_user(instr[0], (u16 __user *)(epc + 0)) ||
                    __get_user(instr[1], (u16 __user *)(epc + 2)))
@@ -918,10 +940,14 @@ asmlinkage void do_tr(struct pt_regs *regs)
        }
 
        do_trap_or_bp(regs, tcode, "Trap");
+
+out:
+       exception_exit(prev_state);
        return;
 
 out_sigsegv:
        force_sig(SIGSEGV, current);
+       goto out;
 }
 
 asmlinkage void do_ri(struct pt_regs *regs)
@@ -929,17 +955,19 @@ asmlinkage void do_ri(struct pt_regs *regs)
        unsigned int __user *epc = (unsigned int __user *)exception_epc(regs);
        unsigned long old_epc = regs->cp0_epc;
        unsigned long old31 = regs->regs[31];
+       enum ctx_state prev_state;
        unsigned int opcode = 0;
        int status = -1;
 
+       prev_state = exception_enter();
        if (notify_die(DIE_RI, "RI Fault", regs, 0, regs_to_trapnr(regs), SIGILL)
            == NOTIFY_STOP)
-               return;
+               goto out;
 
        die_if_kernel("Reserved instruction in kernel code", regs);
 
        if (unlikely(compute_return_epc(regs) < 0))
-               return;
+               goto out;
 
        if (get_isa16_mode(regs->cp0_epc)) {
                unsigned short mmop[2] = { 0 };
@@ -974,6 +1002,9 @@ asmlinkage void do_ri(struct pt_regs *regs)
                regs->regs[31] = old31;
                force_sig(status, current);
        }
+
+out:
+       exception_exit(prev_state);
 }
 
 /*
@@ -1025,21 +1056,16 @@ static int default_cu2_call(struct notifier_block *nfb, unsigned long action,
 {
        struct pt_regs *regs = data;
 
-       switch (action) {
-       default:
-               die_if_kernel("Unhandled kernel unaligned access or invalid "
+       die_if_kernel("COP2: Unhandled kernel unaligned access or invalid "
                              "instruction", regs);
-               /* Fall through  */
-
-       case CU2_EXCEPTION:
-               force_sig(SIGILL, current);
-       }
+       force_sig(SIGILL, current);
 
        return NOTIFY_OK;
 }
 
 asmlinkage void do_cpu(struct pt_regs *regs)
 {
+       enum ctx_state prev_state;
        unsigned int __user *epc;
        unsigned long old_epc, old31;
        unsigned int opcode;
@@ -1047,10 +1073,12 @@ asmlinkage void do_cpu(struct pt_regs *regs)
        int status;
        unsigned long __maybe_unused flags;
 
-       die_if_kernel("do_cpu invoked from kernel context!", regs);
-
+       prev_state = exception_enter();
        cpid = (regs->cp0_cause >> CAUSEB_CE) & 3;
 
+       if (cpid != 2)
+               die_if_kernel("do_cpu invoked from kernel context!", regs);
+
        switch (cpid) {
        case 0:
                epc = (unsigned int __user *)exception_epc(regs);
@@ -1060,7 +1088,7 @@ asmlinkage void do_cpu(struct pt_regs *regs)
                status = -1;
 
                if (unlikely(compute_return_epc(regs) < 0))
-                       return;
+                       goto out;
 
                if (get_isa16_mode(regs->cp0_epc)) {
                        unsigned short mmop[2] = { 0 };
@@ -1093,7 +1121,7 @@ asmlinkage void do_cpu(struct pt_regs *regs)
                        force_sig(status, current);
                }
 
-               return;
+               goto out;
 
        case 3:
                /*
@@ -1131,19 +1159,26 @@ asmlinkage void do_cpu(struct pt_regs *regs)
                                mt_ase_fp_affinity();
                }
 
-               return;
+               goto out;
 
        case 2:
                raw_notifier_call_chain(&cu2_chain, CU2_EXCEPTION, regs);
-               return;
+               goto out;
        }
 
        force_sig(SIGILL, current);
+
+out:
+       exception_exit(prev_state);
 }
 
 asmlinkage void do_mdmx(struct pt_regs *regs)
 {
+       enum ctx_state prev_state;
+
+       prev_state = exception_enter();
        force_sig(SIGILL, current);
+       exception_exit(prev_state);
 }
 
 /*
@@ -1151,8 +1186,10 @@ asmlinkage void do_mdmx(struct pt_regs *regs)
  */
 asmlinkage void do_watch(struct pt_regs *regs)
 {
+       enum ctx_state prev_state;
        u32 cause;
 
+       prev_state = exception_enter();
        /*
         * Clear WP (bit 22) bit of cause register so we don't loop
         * forever.
@@ -1174,13 +1211,16 @@ asmlinkage void do_watch(struct pt_regs *regs)
                mips_clear_watch_registers();
                local_irq_enable();
        }
+       exception_exit(prev_state);
 }
 
 asmlinkage void do_mcheck(struct pt_regs *regs)
 {
        const int field = 2 * sizeof(unsigned long);
        int multi_match = regs->cp0_status & ST0_TS;
+       enum ctx_state prev_state;
 
+       prev_state = exception_enter();
        show_regs(regs);
 
        if (multi_match) {
@@ -1202,6 +1242,7 @@ asmlinkage void do_mcheck(struct pt_regs *regs)
        panic("Caught Machine Check exception - %scaused by multiple "
              "matching entries in the TLB.",
              (multi_match) ? "" : "not ");
+       exception_exit(prev_state);
 }
 
 asmlinkage void do_mt(struct pt_regs *regs)
@@ -1627,7 +1668,6 @@ void *set_vi_handler(int n, vi_handler_t addr)
 }
 
 extern void tlb_init(void);
-extern void flush_tlb_handlers(void);
 
 /*
  * Timer interrupt
@@ -1837,6 +1877,15 @@ void __init trap_init(void)
                        ebase += (read_c0_ebase() & 0x3ffff000);
        }
 
+       if (cpu_has_mmips) {
+               unsigned int config3 = read_c0_config3();
+
+               if (IS_ENABLED(CONFIG_CPU_MICROMIPS))
+                       write_c0_config3(config3 | MIPS_CONF3_ISA_OE);
+               else
+                       write_c0_config3(config3 & ~MIPS_CONF3_ISA_OE);
+       }
+
        if (board_ebase_setup)
                board_ebase_setup();
        per_cpu_trap_init(true);
@@ -1956,7 +2005,6 @@ void __init trap_init(void)
                set_handler(0x080, &except_vec3_generic, 0x80);
 
        local_flush_icache_range(ebase, ebase + 0x400);
-       flush_tlb_handlers();
 
        sort_extable(__start___dbe_table, __stop___dbe_table);
 
index 203d885..c369a5d 100644 (file)
@@ -72,6 +72,7 @@
  *      A store crossing a page boundary might be executed only partially.
  *      Undo the partial store in this case.
  */
+#include <linux/context_tracking.h>
 #include <linux/mm.h>
 #include <linux/signal.h>
 #include <linux/smp.h>
@@ -684,7 +685,8 @@ const int reg16to32[] = { 16, 17, 2, 3, 4, 5, 6, 7 };
 /* Recode table from 16-bit STORE register notation to 32-bit GPR. */
 const int reg16to32st[] = { 0, 17, 2, 3, 4, 5, 6, 7 };
 
-void emulate_load_store_microMIPS(struct pt_regs *regs, void __user * addr)
+static void emulate_load_store_microMIPS(struct pt_regs *regs,
+                                        void __user *addr)
 {
        unsigned long value;
        unsigned int res;
@@ -1548,11 +1550,14 @@ sigill:
            ("Unhandled kernel unaligned access or invalid instruction", regs);
        force_sig(SIGILL, current);
 }
+
 asmlinkage void do_ade(struct pt_regs *regs)
 {
+       enum ctx_state prev_state;
        unsigned int __user *pc;
        mm_segment_t seg;
 
+       prev_state = exception_enter();
        perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS,
                        1, regs, regs->cp0_badvaddr);
        /*
@@ -1628,6 +1633,7 @@ sigbus:
        /*
         * XXX On return from the signal handler we should advance the epc
         */
+       exception_exit(prev_state);
 }
 
 #ifdef CONFIG_DEBUG_FS
index 7726f61..cbdc4de 100644 (file)
@@ -111,6 +111,7 @@ __cpuinit void mips_probe_watch_registers(struct cpuinfo_mips *c)
         * disable the register.
         */
        write_c0_watchlo0(7);
+       back_to_back_c0_hazard();
        t = read_c0_watchlo0();
        write_c0_watchlo0(0);
        c->watch_reg_masks[0] = t & 7;
@@ -121,12 +122,14 @@ __cpuinit void mips_probe_watch_registers(struct cpuinfo_mips *c)
        c->watch_reg_use_cnt = 1;
        t = read_c0_watchhi0();
        write_c0_watchhi0(t | 0xff8);
+       back_to_back_c0_hazard();
        t = read_c0_watchhi0();
        c->watch_reg_masks[0] |= (t & 0xff8);
        if ((t & 0x80000000) == 0)
                return;
 
        write_c0_watchlo1(7);
+       back_to_back_c0_hazard();
        t = read_c0_watchlo1();
        write_c0_watchlo1(0);
        c->watch_reg_masks[1] = t & 7;
@@ -135,12 +138,14 @@ __cpuinit void mips_probe_watch_registers(struct cpuinfo_mips *c)
        c->watch_reg_use_cnt = 2;
        t = read_c0_watchhi1();
        write_c0_watchhi1(t | 0xff8);
+       back_to_back_c0_hazard();
        t = read_c0_watchhi1();
        c->watch_reg_masks[1] |= (t & 0xff8);
        if ((t & 0x80000000) == 0)
                return;
 
        write_c0_watchlo2(7);
+       back_to_back_c0_hazard();
        t = read_c0_watchlo2();
        write_c0_watchlo2(0);
        c->watch_reg_masks[2] = t & 7;
@@ -149,12 +154,14 @@ __cpuinit void mips_probe_watch_registers(struct cpuinfo_mips *c)
        c->watch_reg_use_cnt = 3;
        t = read_c0_watchhi2();
        write_c0_watchhi2(t | 0xff8);
+       back_to_back_c0_hazard();
        t = read_c0_watchhi2();
        c->watch_reg_masks[2] |= (t & 0xff8);
        if ((t & 0x80000000) == 0)
                return;
 
        write_c0_watchlo3(7);
+       back_to_back_c0_hazard();
        t = read_c0_watchlo3();
        write_c0_watchlo3(0);
        c->watch_reg_masks[3] = t & 7;
@@ -163,6 +170,7 @@ __cpuinit void mips_probe_watch_registers(struct cpuinfo_mips *c)
        c->watch_reg_use_cnt = 4;
        t = read_c0_watchhi3();
        write_c0_watchhi3(t | 0xff8);
+       back_to_back_c0_hazard();
        t = read_c0_watchhi3();
        c->watch_reg_masks[3] |= (t & 0xff8);
        if ((t & 0x80000000) == 0)
index 9f9e875..49c4603 100644 (file)
@@ -112,7 +112,7 @@ int __init plat_of_setup(void)
        if (!of_have_populated_dt())
                panic("device tree not present");
 
-       strncpy(of_ids[0].compatible, soc_info.compatible,
+       strlcpy(of_ids[0].compatible, soc_info.compatible,
                sizeof(of_ids[0].compatible));
        strncpy(of_ids[1].compatible, "simple-bus",
                sizeof(of_ids[1].compatible));
index f27694f..3b7f65c 100644 (file)
@@ -39,7 +39,7 @@
 
 
 /* And the same for proc */
-int proc_dolasatstring(ctl_table *table, int write,
+int proc_dolasatstring(struct ctl_table *table, int write,
                       void *buffer, size_t *lenp, loff_t *ppos)
 {
        int r;
@@ -54,7 +54,7 @@ int proc_dolasatstring(ctl_table *table, int write,
 }
 
 /* proc function to write EEPROM after changing int entry */
-int proc_dolasatint(ctl_table *table, int write,
+int proc_dolasatint(struct ctl_table *table, int write,
                       void *buffer, size_t *lenp, loff_t *ppos)
 {
        int r;
@@ -72,7 +72,7 @@ int proc_dolasatint(ctl_table *table, int write,
 static int rtctmp;
 
 /* proc function to read/write RealTime Clock */
-int proc_dolasatrtc(ctl_table *table, int write,
+int proc_dolasatrtc(struct ctl_table *table, int write,
                       void *buffer, size_t *lenp, loff_t *ppos)
 {
        struct timespec ts;
@@ -97,7 +97,7 @@ int proc_dolasatrtc(ctl_table *table, int write,
 #endif
 
 #ifdef CONFIG_INET
-int proc_lasat_ip(ctl_table *table, int write,
+int proc_lasat_ip(struct ctl_table *table, int write,
                       void *buffer, size_t *lenp, loff_t *ppos)
 {
        unsigned int ip;
@@ -157,7 +157,7 @@ int proc_lasat_ip(ctl_table *table, int write,
 }
 #endif
 
-int proc_lasat_prid(ctl_table *table, int write,
+int proc_lasat_prid(struct ctl_table *table, int write,
                       void *buffer, size_t *lenp, loff_t *ppos)
 {
        int r;
@@ -176,7 +176,7 @@ int proc_lasat_prid(ctl_table *table, int write,
 
 extern int lasat_boot_to_service;
 
-static ctl_table lasat_table[] = {
+static struct ctl_table lasat_table[] = {
        {
                .procname       = "cpu-hz",
                .data           = &lasat_board_info.li_cpu_hz,
@@ -262,7 +262,7 @@ static ctl_table lasat_table[] = {
        {}
 };
 
-static ctl_table lasat_root_table[] = {
+static struct ctl_table lasat_root_table[] = {
        {
                .procname       = "lasat",
                .mode           =  0555,
index a6eb2e8..924be39 100644 (file)
@@ -13,6 +13,7 @@
  * option) any later version.
  */
 
+#include <linux/pci.h>
 #include <cs5536/cs5536.h>
 #include <cs5536/cs5536_pci.h>
 
@@ -314,3 +315,16 @@ u32 pci_isa_read_reg(int reg)
 
        return conf_data;
 }
+
+/*
+ * The mfgpt timer interrupt is running early, so we must keep the south bridge
+ * mmio always enabled. Otherwise we may race with the PCI configuration which
+ * may temporarily disable it. When that happens and the timer interrupt fires,
+ * we are not able to clear it and the system will hang.
+ */
+static void cs5536_isa_mmio_always_on(struct pci_dev *dev)
+{
+       dev->mmio_always_on = 1;
+}
+DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA,
+       PCI_CLASS_BRIDGE_ISA, 8, cs5536_isa_mmio_always_on);
index f037719..e773659 100644 (file)
@@ -471,6 +471,9 @@ int mm_isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
        unsigned int fcr31;
        unsigned int bit;
 
+       if (!cpu_has_mmips)
+               return 0;
+
        switch (insn.mm_i_format.opcode) {
        case mm_pool32a_op:
                if ((insn.mm_i_format.simmediate & MM_POOL32A_MINOR_MASK) ==
index e87aae1..7f4f93a 100644 (file)
@@ -4,7 +4,7 @@
 
 obj-y                          += cache.o dma-default.o extable.o fault.o \
                                   gup.o init.o mmap.o page.o page-funcs.o \
-                                  tlbex.o tlbex-fault.o uasm-mips.o
+                                  tlbex.o tlbex-fault.o tlb-funcs.o uasm-mips.o
 
 obj-$(CONFIG_32BIT)            += ioremap.o pgtable-32.o
 obj-$(CONFIG_64BIT)            += pgtable-64.o
index 576add3..ee5c1ff 100644 (file)
@@ -182,11 +182,7 @@ asmlinkage void sb1_cache_error(void)
 
 #ifdef CONFIG_SIBYTE_BW_TRACE
        /* Freeze the trace buffer now */
-#if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80)
-       csr_out32(M_BCM1480_SCD_TRACE_CFG_FREEZE, IOADDR(A_SCD_TRACE_CFG));
-#else
        csr_out32(M_SCD_TRACE_CFG_FREEZE, IOADDR(A_SCD_TRACE_CFG));
-#endif
        printk("Trace buffer frozen\n");
 #endif
 
index caf92ec..aaccf1c 100644 (file)
@@ -246,6 +246,9 @@ static int mips_dma_map_sg(struct device *dev, struct scatterlist *sg,
                if (!plat_device_is_coherent(dev))
                        __dma_sync(sg_page(sg), sg->offset, sg->length,
                                   direction);
+#ifdef CONFIG_NEED_SG_DMA_LENGTH
+               sg->dma_length = sg->length;
+#endif
                sg->dma_address = plat_map_dma_mem_page(dev, sg_page(sg)) +
                                  sg->offset;
        }
index 0fead53..85df1cd 100644 (file)
@@ -5,6 +5,7 @@
  *
  * Copyright (C) 1995 - 2000 by Ralf Baechle
  */
+#include <linux/context_tracking.h>
 #include <linux/signal.h>
 #include <linux/sched.h>
 #include <linux/interrupt.h>
@@ -32,8 +33,8 @@
  * and the problem, and then passes it off to one of the appropriate
  * routines.
  */
-asmlinkage void __kprobes do_page_fault(struct pt_regs *regs, unsigned long write,
-                             unsigned long address)
+static void __kprobes __do_page_fault(struct pt_regs *regs, unsigned long write,
+       unsigned long address)
 {
        struct vm_area_struct * vma = NULL;
        struct task_struct *tsk = current;
@@ -312,3 +313,13 @@ vmalloc_fault:
        }
 #endif
 }
+
+asmlinkage void __kprobes do_page_fault(struct pt_regs *regs,
+       unsigned long write, unsigned long address)
+{
+       enum ctx_state prev_state;
+
+       prev_state = exception_enter();
+       __do_page_fault(regs, write, address);
+       exception_exit(prev_state);
+}
index 7e5fe27..f1baadd 100644 (file)
@@ -158,11 +158,9 @@ void arch_pick_mmap_layout(struct mm_struct *mm)
        if (mmap_is_legacy()) {
                mm->mmap_base = TASK_UNMAPPED_BASE + random_factor;
                mm->get_unmapped_area = arch_get_unmapped_area;
-               mm->unmap_area = arch_unmap_area;
        } else {
                mm->mmap_base = mmap_base(random_factor);
                mm->get_unmapped_area = arch_get_unmapped_area_topdown;
-               mm->unmap_area = arch_unmap_area_topdown;
        }
 }
 
index 4eb8dcf..2c0bd58 100644 (file)
@@ -232,7 +232,7 @@ static inline void __cpuinit build_clear_pref(u32 **buf, int off)
 
                        uasm_i_cache(buf, Create_Dirty_Excl_D, off, A0);
                }
-               }
+       }
 }
 
 extern u32 __clear_page_start;
diff --git a/arch/mips/mm/tlb-funcs.S b/arch/mips/mm/tlb-funcs.S
new file mode 100644 (file)
index 0000000..30a494d
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ *
+ * Micro-assembler generated tlb handler functions.
+ *
+ * Copyright (C) 2013  Broadcom Corporation.
+ *
+ * Based on mm/page-funcs.c
+ * Copyright (C) 2012  MIPS Technologies, Inc.
+ * Copyright (C) 2012  Ralf Baechle <ralf@linux-mips.org>
+ */
+#include <asm/asm.h>
+#include <asm/regdef.h>
+
+#define FASTPATH_SIZE  128
+
+LEAF(tlbmiss_handler_setup_pgd)
+       .space          16 * 4
+END(tlbmiss_handler_setup_pgd)
+EXPORT(tlbmiss_handler_setup_pgd_end)
+
+LEAF(handle_tlbm)
+       .space          FASTPATH_SIZE * 4
+END(handle_tlbm)
+EXPORT(handle_tlbm_end)
+
+LEAF(handle_tlbs)
+       .space          FASTPATH_SIZE * 4
+END(handle_tlbs)
+EXPORT(handle_tlbs_end)
+
+LEAF(handle_tlbl)
+       .space          FASTPATH_SIZE * 4
+END(handle_tlbl)
+EXPORT(handle_tlbl_end)
index afeef93..9ab0f90 100644 (file)
@@ -305,6 +305,17 @@ static int check_for_high_segbits __cpuinitdata;
 
 static unsigned int kscratch_used_mask __cpuinitdata;
 
+static inline int __maybe_unused c0_kscratch(void)
+{
+       switch (current_cpu_type()) {
+       case CPU_XLP:
+       case CPU_XLR:
+               return 22;
+       default:
+               return 31;
+       }
+}
+
 static int __cpuinit allocate_kscratch(void)
 {
        int r;
@@ -334,9 +345,9 @@ static struct work_registers __cpuinit build_get_work_registers(u32 **p)
        int smp_processor_id_sel;
        int smp_processor_id_shift;
 
-       if (scratch_reg > 0) {
+       if (scratch_reg >= 0) {
                /* Save in CPU local C0_KScratch? */
-               UASM_i_MTC0(p, 1, 31, scratch_reg);
+               UASM_i_MTC0(p, 1, c0_kscratch(), scratch_reg);
                r.r1 = K0;
                r.r2 = K1;
                r.r3 = 1;
@@ -384,8 +395,8 @@ static struct work_registers __cpuinit build_get_work_registers(u32 **p)
 
 static void __cpuinit build_restore_work_registers(u32 **p)
 {
-       if (scratch_reg > 0) {
-               UASM_i_MFC0(p, 1, 31, scratch_reg);
+       if (scratch_reg >= 0) {
+               UASM_i_MFC0(p, 1, c0_kscratch(), scratch_reg);
                return;
        }
        /* K0 already points to save area, restore $1 and $2  */
@@ -673,8 +684,8 @@ static __cpuinit void build_restore_pagemask(u32 **p,
                        uasm_i_mtc0(p, 0, C0_PAGEMASK);
                        uasm_il_b(p, r, lid);
                }
-               if (scratch_reg > 0)
-                       UASM_i_MFC0(p, 1, 31, scratch_reg);
+               if (scratch_reg >= 0)
+                       UASM_i_MFC0(p, 1, c0_kscratch(), scratch_reg);
                else
                        UASM_i_LW(p, 1, scratchpad_offset(0), 0);
        } else {
@@ -817,7 +828,7 @@ build_get_pmde64(u32 **p, struct uasm_label **l, struct uasm_reloc **r,
 #ifdef CONFIG_MIPS_PGD_C0_CONTEXT
        if (pgd_reg != -1) {
                /* pgd is in pgd_reg */
-               UASM_i_MFC0(p, ptr, 31, pgd_reg);
+               UASM_i_MFC0(p, ptr, c0_kscratch(), pgd_reg);
        } else {
                /*
                 * &pgd << 11 stored in CONTEXT [23..63].
@@ -929,8 +940,8 @@ build_get_pgd_vmalloc64(u32 **p, struct uasm_label **l, struct uasm_reloc **r,
                uasm_i_jr(p, ptr);
 
                if (mode == refill_scratch) {
-                       if (scratch_reg > 0)
-                               UASM_i_MFC0(p, 1, 31, scratch_reg);
+                       if (scratch_reg >= 0)
+                               UASM_i_MFC0(p, 1, c0_kscratch(), scratch_reg);
                        else
                                UASM_i_LW(p, 1, scratchpad_offset(0), 0);
                } else {
@@ -961,7 +972,7 @@ build_get_pgde32(u32 **p, unsigned int tmp, unsigned int ptr)
        uasm_i_srl(p, ptr, ptr, 19);
 #else
        /*
-        * smp_processor_id() << 3 is stored in CONTEXT.
+        * smp_processor_id() << 2 is stored in CONTEXT.
         */
        uasm_i_mfc0(p, ptr, C0_CONTEXT);
        UASM_i_LA_mostly(p, tmp, pgdc);
@@ -1096,7 +1107,7 @@ struct mips_huge_tlb_info {
 static struct mips_huge_tlb_info __cpuinit
 build_fast_tlb_refill_handler (u32 **p, struct uasm_label **l,
                               struct uasm_reloc **r, unsigned int tmp,
-                              unsigned int ptr, int c0_scratch)
+                              unsigned int ptr, int c0_scratch_reg)
 {
        struct mips_huge_tlb_info rv;
        unsigned int even, odd;
@@ -1110,12 +1121,12 @@ build_fast_tlb_refill_handler (u32 **p, struct uasm_label **l,
                UASM_i_MFC0(p, tmp, C0_BADVADDR);
 
                if (pgd_reg != -1)
-                       UASM_i_MFC0(p, ptr, 31, pgd_reg);
+                       UASM_i_MFC0(p, ptr, c0_kscratch(), pgd_reg);
                else
                        UASM_i_MFC0(p, ptr, C0_CONTEXT);
 
-               if (c0_scratch >= 0)
-                       UASM_i_MTC0(p, scratch, 31, c0_scratch);
+               if (c0_scratch_reg >= 0)
+                       UASM_i_MTC0(p, scratch, c0_kscratch(), c0_scratch_reg);
                else
                        UASM_i_SW(p, scratch, scratchpad_offset(0), 0);
 
@@ -1130,14 +1141,14 @@ build_fast_tlb_refill_handler (u32 **p, struct uasm_label **l,
                }
        } else {
                if (pgd_reg != -1)
-                       UASM_i_MFC0(p, ptr, 31, pgd_reg);
+                       UASM_i_MFC0(p, ptr, c0_kscratch(), pgd_reg);
                else
                        UASM_i_MFC0(p, ptr, C0_CONTEXT);
 
                UASM_i_MFC0(p, tmp, C0_BADVADDR);
 
-               if (c0_scratch >= 0)
-                       UASM_i_MTC0(p, scratch, 31, c0_scratch);
+               if (c0_scratch_reg >= 0)
+                       UASM_i_MTC0(p, scratch, c0_kscratch(), c0_scratch_reg);
                else
                        UASM_i_SW(p, scratch, scratchpad_offset(0), 0);
 
@@ -1242,8 +1253,8 @@ build_fast_tlb_refill_handler (u32 **p, struct uasm_label **l,
        }
        UASM_i_MTC0(p, odd, C0_ENTRYLO1); /* load it */
 
-       if (c0_scratch >= 0) {
-               UASM_i_MFC0(p, scratch, 31, c0_scratch);
+       if (c0_scratch_reg >= 0) {
+               UASM_i_MFC0(p, scratch, c0_kscratch(), c0_scratch_reg);
                build_tlb_write_entry(p, l, r, tlb_random);
                uasm_l_leave(l, *p);
                rv.restore_scratch = 1;
@@ -1286,7 +1297,7 @@ static void __cpuinit build_r4000_tlb_refill_handler(void)
        memset(relocs, 0, sizeof(relocs));
        memset(final_handler, 0, sizeof(final_handler));
 
-       if ((scratch_reg > 0 || scratchpad_available()) && use_bbit_insns()) {
+       if ((scratch_reg >= 0 || scratchpad_available()) && use_bbit_insns()) {
                htlb_info = build_fast_tlb_refill_handler(&p, &l, &r, K0, K1,
                                                          scratch_reg);
                vmalloc_mode = refill_scratch;
@@ -1444,27 +1455,25 @@ static void __cpuinit build_r4000_tlb_refill_handler(void)
        dump_handler("r4000_tlb_refill", (u32 *)ebase, 64);
 }
 
-/*
- * 128 instructions for the fastpath handler is generous and should
- * never be exceeded.
- */
-#define FASTPATH_SIZE 128
+extern u32 handle_tlbl[], handle_tlbl_end[];
+extern u32 handle_tlbs[], handle_tlbs_end[];
+extern u32 handle_tlbm[], handle_tlbm_end[];
 
-u32 handle_tlbl[FASTPATH_SIZE] __cacheline_aligned;
-u32 handle_tlbs[FASTPATH_SIZE] __cacheline_aligned;
-u32 handle_tlbm[FASTPATH_SIZE] __cacheline_aligned;
 #ifdef CONFIG_MIPS_PGD_C0_CONTEXT
-u32 tlbmiss_handler_setup_pgd_array[16] __cacheline_aligned;
+extern u32 tlbmiss_handler_setup_pgd[], tlbmiss_handler_setup_pgd_end[];
 
 static void __cpuinit build_r4000_setup_pgd(void)
 {
        const int a0 = 4;
        const int a1 = 5;
        u32 *p = tlbmiss_handler_setup_pgd_array;
+       const int tlbmiss_handler_setup_pgd_size =
+               tlbmiss_handler_setup_pgd_end - tlbmiss_handler_setup_pgd;
        struct uasm_label *l = labels;
        struct uasm_reloc *r = relocs;
 
-       memset(tlbmiss_handler_setup_pgd_array, 0, sizeof(tlbmiss_handler_setup_pgd_array));
+       memset(tlbmiss_handler_setup_pgd, 0, tlbmiss_handler_setup_pgd_size *
+                                       sizeof(tlbmiss_handler_setup_pgd[0]));
        memset(labels, 0, sizeof(labels));
        memset(relocs, 0, sizeof(relocs));
 
@@ -1490,17 +1499,17 @@ static void __cpuinit build_r4000_setup_pgd(void)
        } else {
                /* PGD in c0_KScratch */
                uasm_i_jr(&p, 31);
-               UASM_i_MTC0(&p, a0, 31, pgd_reg);
+               UASM_i_MTC0(&p, a0, c0_kscratch(), pgd_reg);
        }
-       if (p - tlbmiss_handler_setup_pgd_array > ARRAY_SIZE(tlbmiss_handler_setup_pgd_array))
-               panic("tlbmiss_handler_setup_pgd_array space exceeded");
+       if (p >= tlbmiss_handler_setup_pgd_end)
+               panic("tlbmiss_handler_setup_pgd space exceeded");
+
        uasm_resolve_relocs(relocs, labels);
-       pr_debug("Wrote tlbmiss_handler_setup_pgd_array (%u instructions).\n",
-                (unsigned int)(p - tlbmiss_handler_setup_pgd_array));
+       pr_debug("Wrote tlbmiss_handler_setup_pgd (%u instructions).\n",
+                (unsigned int)(p - tlbmiss_handler_setup_pgd));
 
-       dump_handler("tlbmiss_handler",
-                    tlbmiss_handler_setup_pgd_array,
-                    ARRAY_SIZE(tlbmiss_handler_setup_pgd_array));
+       dump_handler("tlbmiss_handler", tlbmiss_handler_setup_pgd,
+                                       tlbmiss_handler_setup_pgd_size);
 }
 #endif
 
@@ -1745,10 +1754,11 @@ build_r3000_tlbchange_handler_head(u32 **p, unsigned int pte,
 static void __cpuinit build_r3000_tlb_load_handler(void)
 {
        u32 *p = handle_tlbl;
+       const int handle_tlbl_size = handle_tlbl_end - handle_tlbl;
        struct uasm_label *l = labels;
        struct uasm_reloc *r = relocs;
 
-       memset(handle_tlbl, 0, sizeof(handle_tlbl));
+       memset(handle_tlbl, 0, handle_tlbl_size * sizeof(handle_tlbl[0]));
        memset(labels, 0, sizeof(labels));
        memset(relocs, 0, sizeof(relocs));
 
@@ -1762,23 +1772,24 @@ static void __cpuinit build_r3000_tlb_load_handler(void)
        uasm_i_j(&p, (unsigned long)tlb_do_page_fault_0 & 0x0fffffff);
        uasm_i_nop(&p);
 
-       if ((p - handle_tlbl) > FASTPATH_SIZE)
+       if (p >= handle_tlbl_end)
                panic("TLB load handler fastpath space exceeded");
 
        uasm_resolve_relocs(relocs, labels);
        pr_debug("Wrote TLB load handler fastpath (%u instructions).\n",
                 (unsigned int)(p - handle_tlbl));
 
-       dump_handler("r3000_tlb_load", handle_tlbl, ARRAY_SIZE(handle_tlbl));
+       dump_handler("r3000_tlb_load", handle_tlbl, handle_tlbl_size);
 }
 
 static void __cpuinit build_r3000_tlb_store_handler(void)
 {
        u32 *p = handle_tlbs;
+       const int handle_tlbs_size = handle_tlbs_end - handle_tlbs;
        struct uasm_label *l = labels;
        struct uasm_reloc *r = relocs;
 
-       memset(handle_tlbs, 0, sizeof(handle_tlbs));
+       memset(handle_tlbs, 0, handle_tlbs_size * sizeof(handle_tlbs[0]));
        memset(labels, 0, sizeof(labels));
        memset(relocs, 0, sizeof(relocs));
 
@@ -1792,23 +1803,24 @@ static void __cpuinit build_r3000_tlb_store_handler(void)
        uasm_i_j(&p, (unsigned long)tlb_do_page_fault_1 & 0x0fffffff);
        uasm_i_nop(&p);
 
-       if ((p - handle_tlbs) > FASTPATH_SIZE)
+       if (p >= handle_tlbs)
                panic("TLB store handler fastpath space exceeded");
 
        uasm_resolve_relocs(relocs, labels);
        pr_debug("Wrote TLB store handler fastpath (%u instructions).\n",
                 (unsigned int)(p - handle_tlbs));
 
-       dump_handler("r3000_tlb_store", handle_tlbs, ARRAY_SIZE(handle_tlbs));
+       dump_handler("r3000_tlb_store", handle_tlbs, handle_tlbs_size);
 }
 
 static void __cpuinit build_r3000_tlb_modify_handler(void)
 {
        u32 *p = handle_tlbm;
+       const int handle_tlbm_size = handle_tlbm_end - handle_tlbm;
        struct uasm_label *l = labels;
        struct uasm_reloc *r = relocs;
 
-       memset(handle_tlbm, 0, sizeof(handle_tlbm));
+       memset(handle_tlbm, 0, handle_tlbm_size * sizeof(handle_tlbm[0]));
        memset(labels, 0, sizeof(labels));
        memset(relocs, 0, sizeof(relocs));
 
@@ -1822,14 +1834,14 @@ static void __cpuinit build_r3000_tlb_modify_handler(void)
        uasm_i_j(&p, (unsigned long)tlb_do_page_fault_1 & 0x0fffffff);
        uasm_i_nop(&p);
 
-       if ((p - handle_tlbm) > FASTPATH_SIZE)
+       if (p >= handle_tlbm_end)
                panic("TLB modify handler fastpath space exceeded");
 
        uasm_resolve_relocs(relocs, labels);
        pr_debug("Wrote TLB modify handler fastpath (%u instructions).\n",
                 (unsigned int)(p - handle_tlbm));
 
-       dump_handler("r3000_tlb_modify", handle_tlbm, ARRAY_SIZE(handle_tlbm));
+       dump_handler("r3000_tlb_modify", handle_tlbm, handle_tlbm_size);
 }
 #endif /* CONFIG_MIPS_PGD_C0_CONTEXT */
 
@@ -1893,11 +1905,12 @@ build_r4000_tlbchange_handler_tail(u32 **p, struct uasm_label **l,
 static void __cpuinit build_r4000_tlb_load_handler(void)
 {
        u32 *p = handle_tlbl;
+       const int handle_tlbl_size = handle_tlbl_end - handle_tlbl;
        struct uasm_label *l = labels;
        struct uasm_reloc *r = relocs;
        struct work_registers wr;
 
-       memset(handle_tlbl, 0, sizeof(handle_tlbl));
+       memset(handle_tlbl, 0, handle_tlbl_size * sizeof(handle_tlbl[0]));
        memset(labels, 0, sizeof(labels));
        memset(relocs, 0, sizeof(relocs));
 
@@ -1935,6 +1948,19 @@ static void __cpuinit build_r4000_tlb_load_handler(void)
                uasm_i_nop(&p);
 
                uasm_i_tlbr(&p);
+
+               switch (current_cpu_type()) {
+               default:
+                       if (cpu_has_mips_r2) {
+                               uasm_i_ehb(&p);
+
+               case CPU_CAVIUM_OCTEON:
+               case CPU_CAVIUM_OCTEON_PLUS:
+               case CPU_CAVIUM_OCTEON2:
+                               break;
+                       }
+               }
+
                /* Examine  entrylo 0 or 1 based on ptr. */
                if (use_bbit_insns()) {
                        uasm_i_bbit0(&p, wr.r2, ilog2(sizeof(pte_t)), 8);
@@ -1989,6 +2015,19 @@ static void __cpuinit build_r4000_tlb_load_handler(void)
                uasm_i_nop(&p);
 
                uasm_i_tlbr(&p);
+
+               switch (current_cpu_type()) {
+               default:
+                       if (cpu_has_mips_r2) {
+                               uasm_i_ehb(&p);
+
+               case CPU_CAVIUM_OCTEON:
+               case CPU_CAVIUM_OCTEON_PLUS:
+               case CPU_CAVIUM_OCTEON2:
+                               break;
+                       }
+               }
+
                /* Examine  entrylo 0 or 1 based on ptr. */
                if (use_bbit_insns()) {
                        uasm_i_bbit0(&p, wr.r2, ilog2(sizeof(pte_t)), 8);
@@ -2036,24 +2075,25 @@ static void __cpuinit build_r4000_tlb_load_handler(void)
        uasm_i_j(&p, (unsigned long)tlb_do_page_fault_0 & 0x0fffffff);
        uasm_i_nop(&p);
 
-       if ((p - handle_tlbl) > FASTPATH_SIZE)
+       if (p >= handle_tlbl_end)
                panic("TLB load handler fastpath space exceeded");
 
        uasm_resolve_relocs(relocs, labels);
        pr_debug("Wrote TLB load handler fastpath (%u instructions).\n",
                 (unsigned int)(p - handle_tlbl));
 
-       dump_handler("r4000_tlb_load", handle_tlbl, ARRAY_SIZE(handle_tlbl));
+       dump_handler("r4000_tlb_load", handle_tlbl, handle_tlbl_size);
 }
 
 static void __cpuinit build_r4000_tlb_store_handler(void)
 {
        u32 *p = handle_tlbs;
+       const int handle_tlbs_size = handle_tlbs_end - handle_tlbs;
        struct uasm_label *l = labels;
        struct uasm_reloc *r = relocs;
        struct work_registers wr;
 
-       memset(handle_tlbs, 0, sizeof(handle_tlbs));
+       memset(handle_tlbs, 0, handle_tlbs_size * sizeof(handle_tlbs[0]));
        memset(labels, 0, sizeof(labels));
        memset(relocs, 0, sizeof(relocs));
 
@@ -2090,24 +2130,25 @@ static void __cpuinit build_r4000_tlb_store_handler(void)
        uasm_i_j(&p, (unsigned long)tlb_do_page_fault_1 & 0x0fffffff);
        uasm_i_nop(&p);
 
-       if ((p - handle_tlbs) > FASTPATH_SIZE)
+       if (p >= handle_tlbs_end)
                panic("TLB store handler fastpath space exceeded");
 
        uasm_resolve_relocs(relocs, labels);
        pr_debug("Wrote TLB store handler fastpath (%u instructions).\n",
                 (unsigned int)(p - handle_tlbs));
 
-       dump_handler("r4000_tlb_store", handle_tlbs, ARRAY_SIZE(handle_tlbs));
+       dump_handler("r4000_tlb_store", handle_tlbs, handle_tlbs_size);
 }
 
 static void __cpuinit build_r4000_tlb_modify_handler(void)
 {
        u32 *p = handle_tlbm;
+       const int handle_tlbm_size = handle_tlbm_end - handle_tlbm;
        struct uasm_label *l = labels;
        struct uasm_reloc *r = relocs;
        struct work_registers wr;
 
-       memset(handle_tlbm, 0, sizeof(handle_tlbm));
+       memset(handle_tlbm, 0, handle_tlbm_size * sizeof(handle_tlbm[0]));
        memset(labels, 0, sizeof(labels));
        memset(relocs, 0, sizeof(relocs));
 
@@ -2145,14 +2186,28 @@ static void __cpuinit build_r4000_tlb_modify_handler(void)
        uasm_i_j(&p, (unsigned long)tlb_do_page_fault_1 & 0x0fffffff);
        uasm_i_nop(&p);
 
-       if ((p - handle_tlbm) > FASTPATH_SIZE)
+       if (p >= handle_tlbm_end)
                panic("TLB modify handler fastpath space exceeded");
 
        uasm_resolve_relocs(relocs, labels);
        pr_debug("Wrote TLB modify handler fastpath (%u instructions).\n",
                 (unsigned int)(p - handle_tlbm));
 
-       dump_handler("r4000_tlb_modify", handle_tlbm, ARRAY_SIZE(handle_tlbm));
+       dump_handler("r4000_tlb_modify", handle_tlbm, handle_tlbm_size);
+}
+
+static void __cpuinit flush_tlb_handlers(void)
+{
+       local_flush_icache_range((unsigned long)handle_tlbl,
+                          (unsigned long)handle_tlbl_end);
+       local_flush_icache_range((unsigned long)handle_tlbs,
+                          (unsigned long)handle_tlbs_end);
+       local_flush_icache_range((unsigned long)handle_tlbm,
+                          (unsigned long)handle_tlbm_end);
+#ifdef CONFIG_MIPS_PGD_C0_CONTEXT
+       local_flush_icache_range((unsigned long)tlbmiss_handler_setup_pgd,
+                          (unsigned long)tlbmiss_handler_setup_pgd_end);
+#endif
 }
 
 void __cpuinit build_tlb_refill_handler(void)
@@ -2187,6 +2242,7 @@ void __cpuinit build_tlb_refill_handler(void)
                        build_r3000_tlb_load_handler();
                        build_r3000_tlb_store_handler();
                        build_r3000_tlb_modify_handler();
+                       flush_tlb_handlers();
                        run_once++;
                }
 #else
@@ -2214,23 +2270,10 @@ void __cpuinit build_tlb_refill_handler(void)
                        build_r4000_tlb_modify_handler();
                        if (!cpu_has_local_ebase)
                                build_r4000_tlb_refill_handler();
+                       flush_tlb_handlers();
                        run_once++;
                }
                if (cpu_has_local_ebase)
                        build_r4000_tlb_refill_handler();
        }
 }
-
-void __cpuinit flush_tlb_handlers(void)
-{
-       local_flush_icache_range((unsigned long)handle_tlbl,
-                          (unsigned long)handle_tlbl + sizeof(handle_tlbl));
-       local_flush_icache_range((unsigned long)handle_tlbs,
-                          (unsigned long)handle_tlbs + sizeof(handle_tlbs));
-       local_flush_icache_range((unsigned long)handle_tlbm,
-                          (unsigned long)handle_tlbm + sizeof(handle_tlbm));
-#ifdef CONFIG_MIPS_PGD_C0_CONTEXT
-       local_flush_icache_range((unsigned long)tlbmiss_handler_setup_pgd_array,
-                          (unsigned long)tlbmiss_handler_setup_pgd_array + sizeof(handle_tlbm));
-#endif
-}
index 0388fc8..72fdedb 100644 (file)
@@ -10,7 +10,6 @@ obj-y                         := malta-amon.o malta-display.o malta-init.o \
                                   malta-reset.o malta-setup.o malta-time.o
 
 obj-$(CONFIG_EARLY_PRINTK)     += malta-console.o
-obj-$(CONFIG_PCI)              += malta-pci.o
 
 # FIXME FIXME FIXME
 obj-$(CONFIG_MIPS_MT_SMTC)     += malta-smtc.o
index 0a1339a..c69da37 100644 (file)
@@ -422,8 +422,10 @@ static struct gic_intr_map gic_intr_map[GIC_NUM_INTRS] = {
  */
 int __init gcmp_probe(unsigned long addr, unsigned long size)
 {
-       if (mips_revision_sconid != MIPS_REVISION_SCON_ROCIT) {
+       if ((mips_revision_sconid != MIPS_REVISION_SCON_ROCIT)  &&
+           (mips_revision_sconid != MIPS_REVISION_SCON_GT64120)) {
                gcmp_present = 0;
+               pr_debug("GCMP NOT present\n");
                return gcmp_present;
        }
 
index 3294205..d627d4b 100644 (file)
@@ -1,33 +1,18 @@
 /*
+ * 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.
+ *
  * Carsten Langgaard, carstenl@mips.com
  * Copyright (C) 1999,2000 MIPS Technologies, Inc.  All rights reserved.
- *
- * ########################################################################
- *
- *  This program is free software; you can distribute 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 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.
- *
- * ########################################################################
- *
- * Reset the MIPS boards.
- *
  */
-#include <linux/init.h>
+#include <linux/io.h>
 #include <linux/pm.h>
 
-#include <asm/io.h>
 #include <asm/reboot.h>
-#include <asm/mips-boards/generic.h>
+
+#define SOFTRES_REG    0x1f000500
+#define GORESET                0x42
 
 static void mips_machine_restart(char *command)
 {
@@ -45,7 +30,6 @@ static void mips_machine_halt(void)
        __raw_writel(GORESET, softres_reg);
 }
 
-
 static int __init mips_reboot_setup(void)
 {
        _machine_restart = mips_machine_restart;
@@ -54,5 +38,4 @@ static int __init mips_reboot_setup(void)
 
        return 0;
 }
-
 arch_initcall(mips_reboot_setup);
index 20475c5..e6fb244 100644 (file)
@@ -9,7 +9,9 @@
 #include <linux/pm.h>
 
 #include <asm/reboot.h>
-#include <asm/mips-boards/generic.h>
+
+#define SOFTRES_REG    0x1f000050
+#define GORESET                0x4d
 
 static void mips_machine_restart(char *command)
 {
@@ -35,5 +37,4 @@ static int __init mips_reboot_setup(void)
 
        return 0;
 }
-
 arch_initcall(mips_reboot_setup);
index e0873a3..2447bf9 100644 (file)
@@ -51,4 +51,15 @@ endif
 config NLM_COMMON
        bool
 
+config IOMMU_HELPER
+       bool
+
+config NEED_SG_DMA_LENGTH
+       bool
+
+config SWIOTLB
+       def_bool y
+       select NEED_SG_DMA_LENGTH
+       select IOMMU_HELPER
+
 endif
index 291372a..362739d 100644 (file)
@@ -1,3 +1,5 @@
 obj-y                          += irq.o time.o
+obj-y                          += nlm-dma.o
+obj-y                          += reset.o
 obj-$(CONFIG_SMP)              += smp.o smpboot.o
 obj-$(CONFIG_EARLY_PRINTK)     += earlycons.o
index 9f84c60..73facb2 100644 (file)
@@ -253,13 +253,12 @@ asmlinkage void plat_irq_dispatch(void)
 
        node = nlm_nodeid();
        eirr = read_c0_eirr_and_eimr();
-
-       i = __ilog2_u64(eirr);
-       if (i == -1)
+       if (eirr == 0)
                return;
 
+       i = __ffs64(eirr);
        /* per-CPU IRQs don't need translation */
-       if (eirr & PERCPU_IRQ_MASK) {
+       if (i < PIC_IRQ_BASE) {
                do_IRQ(i);
                return;
        }
diff --git a/arch/mips/netlogic/common/nlm-dma.c b/arch/mips/netlogic/common/nlm-dma.c
new file mode 100644 (file)
index 0000000..f3d4ae8
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+*  Copyright (C) 2003-2013 Broadcom Corporation
+*  All Rights Reserved
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the Broadcom
+ * license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BROADCOM ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL BROADCOM OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <linux/dma-mapping.h>
+#include <linux/scatterlist.h>
+#include <linux/bootmem.h>
+#include <linux/export.h>
+#include <linux/swiotlb.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+
+#include <asm/bootinfo.h>
+
+static char *nlm_swiotlb;
+
+static void *nlm_dma_alloc_coherent(struct device *dev, size_t size,
+       dma_addr_t *dma_handle, gfp_t gfp, struct dma_attrs *attrs)
+{
+       void *ret;
+
+       if (dma_alloc_from_coherent(dev, size, dma_handle, &ret))
+               return ret;
+
+       /* ignore region specifiers */
+       gfp &= ~(__GFP_DMA | __GFP_DMA32 | __GFP_HIGHMEM);
+
+#ifdef CONFIG_ZONE_DMA32
+       if (dev->coherent_dma_mask <= DMA_BIT_MASK(32))
+               gfp |= __GFP_DMA32;
+#endif
+
+       /* Don't invoke OOM killer */
+       gfp |= __GFP_NORETRY;
+
+       return swiotlb_alloc_coherent(dev, size, dma_handle, gfp);
+}
+
+static void nlm_dma_free_coherent(struct device *dev, size_t size,
+       void *vaddr, dma_addr_t dma_handle, struct dma_attrs *attrs)
+{
+       int order = get_order(size);
+
+       if (dma_release_from_coherent(dev, order, vaddr))
+               return;
+
+       swiotlb_free_coherent(dev, size, vaddr, dma_handle);
+}
+
+struct dma_map_ops nlm_swiotlb_dma_ops = {
+       .alloc = nlm_dma_alloc_coherent,
+       .free = nlm_dma_free_coherent,
+       .map_page = swiotlb_map_page,
+       .unmap_page = swiotlb_unmap_page,
+       .map_sg = swiotlb_map_sg_attrs,
+       .unmap_sg = swiotlb_unmap_sg_attrs,
+       .sync_single_for_cpu = swiotlb_sync_single_for_cpu,
+       .sync_single_for_device = swiotlb_sync_single_for_device,
+       .sync_sg_for_cpu = swiotlb_sync_sg_for_cpu,
+       .sync_sg_for_device = swiotlb_sync_sg_for_device,
+       .mapping_error = swiotlb_dma_mapping_error,
+       .dma_supported = swiotlb_dma_supported
+};
+
+void __init plat_swiotlb_setup(void)
+{
+       size_t swiotlbsize;
+       unsigned long swiotlb_nslabs;
+
+       swiotlbsize = 1 << 20; /* 1 MB for now */
+       swiotlb_nslabs = swiotlbsize >> IO_TLB_SHIFT;
+       swiotlb_nslabs = ALIGN(swiotlb_nslabs, IO_TLB_SEGSIZE);
+       swiotlbsize = swiotlb_nslabs << IO_TLB_SHIFT;
+
+       nlm_swiotlb = alloc_bootmem_low_pages(swiotlbsize);
+       swiotlb_init_with_tbl(nlm_swiotlb, swiotlb_nslabs, 1);
+}
diff --git a/arch/mips/netlogic/common/reset.S b/arch/mips/netlogic/common/reset.S
new file mode 100644 (file)
index 0000000..adb1828
--- /dev/null
@@ -0,0 +1,230 @@
+/*
+ * Copyright 2003-2013 Broadcom Corporation.
+ * All Rights Reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the Broadcom
+ * license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BROADCOM ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL BROADCOM OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/init.h>
+
+#include <asm/asm.h>
+#include <asm/asm-offsets.h>
+#include <asm/regdef.h>
+#include <asm/mipsregs.h>
+#include <asm/stackframe.h>
+#include <asm/asmmacro.h>
+#include <asm/addrspace.h>
+
+#include <asm/netlogic/common.h>
+
+#include <asm/netlogic/xlp-hal/iomap.h>
+#include <asm/netlogic/xlp-hal/xlp.h>
+#include <asm/netlogic/xlp-hal/sys.h>
+#include <asm/netlogic/xlp-hal/cpucontrol.h>
+
+#define CP0_EBASE      $15
+#define SYS_CPU_COHERENT_BASE(node)    CKSEG1ADDR(XLP_DEFAULT_IO_BASE) + \
+                       XLP_IO_SYS_OFFSET(node) + XLP_IO_PCI_HDRSZ + \
+                       SYS_CPU_NONCOHERENT_MODE * 4
+
+/* Enable XLP features and workarounds in the LSU */
+.macro xlp_config_lsu
+       li      t0, LSU_DEFEATURE
+       mfcr    t1, t0
+
+       lui     t2, 0xc080      /* SUE, Enable Unaligned Access, L2HPE */
+       or      t1, t1, t2
+       mtcr    t1, t0
+
+       li      t0, ICU_DEFEATURE
+       mfcr    t1, t0
+       ori     t1, 0x1000      /* Enable Icache partitioning */
+       mtcr    t1, t0
+
+       li      t0, SCHED_DEFEATURE
+       lui     t1, 0x0100      /* Disable BRU accepting ALU ops */
+       mtcr    t1, t0
+.endm
+
+/*
+ * Low level flush for L1D cache on XLP, the normal cache ops does
+ * not do the complete and correct cache flush.
+ */
+.macro xlp_flush_l1_dcache
+       li      t0, LSU_DEBUG_DATA0
+       li      t1, LSU_DEBUG_ADDR
+       li      t2, 0           /* index */
+       li      t3, 0x1000      /* loop count */
+1:
+       sll     v0, t2, 5
+       mtcr    zero, t0
+       ori     v1, v0, 0x3     /* way0 | write_enable | write_active */
+       mtcr    v1, t1
+2:
+       mfcr    v1, t1
+       andi    v1, 0x1         /* wait for write_active == 0 */
+       bnez    v1, 2b
+       nop
+       mtcr    zero, t0
+       ori     v1, v0, 0x7     /* way1 | write_enable | write_active */
+       mtcr    v1, t1
+3:
+       mfcr    v1, t1
+       andi    v1, 0x1         /* wait for write_active == 0 */
+       bnez    v1, 3b
+       nop
+       addi    t2, 1
+       bne     t3, t2, 1b
+       nop
+.endm
+
+/*
+ * nlm_reset_entry will be copied to the reset entry point for
+ * XLR and XLP. The XLP cores start here when they are woken up. This
+ * is also the NMI entry point.
+ *
+ * We use scratch reg 6/7 to save k0/k1 and check for NMI first.
+ *
+ * The data corresponding to reset/NMI is stored at RESET_DATA_PHYS
+ * location, this will have the thread mask (used when core is woken up)
+ * and the current NMI handler in case we reached here for an NMI.
+ *
+ * When a core or thread is newly woken up, it marks itself ready and
+ * loops in a 'wait'. When the CPU really needs waking up, we send an NMI
+ * IPI to it, with the NMI handler set to prom_boot_secondary_cpus
+ */
+       .set    noreorder
+       .set    noat
+       .set    arch=xlr        /* for mfcr/mtcr, XLR is sufficient */
+
+FEXPORT(nlm_reset_entry)
+       dmtc0   k0, $22, 6
+       dmtc0   k1, $22, 7
+       mfc0    k0, CP0_STATUS
+       li      k1, 0x80000
+       and     k1, k0, k1
+       beqz    k1, 1f          /* go to real reset entry */
+       nop
+       li      k1, CKSEG1ADDR(RESET_DATA_PHYS) /* NMI */
+       ld      k0, BOOT_NMI_HANDLER(k1)
+       jr      k0
+       nop
+
+1:     /* Entry point on core wakeup */
+       mfc0    t0, CP0_EBASE, 1
+       mfc0    t1, CP0_EBASE, 1
+       srl     t1, 5
+       andi    t1, 0x3                 /* t1 <- node */
+       li      t2, 0x40000
+       mul     t3, t2, t1              /* t3 = node * 0x40000 */
+       srl     t0, t0, 2
+       and     t0, t0, 0x7             /* t0 <- core */
+       li      t1, 0x1
+       sll     t0, t1, t0
+       nor     t0, t0, zero            /* t0 <- ~(1 << core) */
+       li      t2, SYS_CPU_COHERENT_BASE(0)
+       add     t2, t2, t3              /* t2 <- SYS offset for node */
+       lw      t1, 0(t2)
+       and     t1, t1, t0
+       sw      t1, 0(t2)
+
+       /* read back to ensure complete */
+       lw      t1, 0(t2)
+       sync
+
+       /* Configure LSU on Non-0 Cores. */
+       xlp_config_lsu
+       /* FALL THROUGH */
+
+/*
+ * Wake up sibling threads from the initial thread in
+ * a core.
+ */
+EXPORT(nlm_boot_siblings)
+       /* core L1D flush before enable threads */
+       xlp_flush_l1_dcache
+       /* Enable hw threads by writing to MAP_THREADMODE of the core */
+       li      t0, CKSEG1ADDR(RESET_DATA_PHYS)
+       lw      t1, BOOT_THREAD_MODE(t0)        /* t1 <- thread mode */
+       li      t0, ((CPU_BLOCKID_MAP << 8) | MAP_THREADMODE)
+       mfcr    t2, t0
+       or      t2, t2, t1
+       mtcr    t2, t0
+
+       /*
+        * The new hardware thread starts at the next instruction
+        * For all the cases other than core 0 thread 0, we will
+       * jump to the secondary wait function.
+       */
+       mfc0    v0, CP0_EBASE, 1
+       andi    v0, 0x3ff               /* v0 <- node/core */
+
+       beqz    v0, 4f          /* boot cpu (cpuid == 0)? */
+       nop
+
+       /* setup status reg */
+       move    t1, zero
+#ifdef CONFIG_64BIT
+       ori     t1, ST0_KX
+#endif
+       mtc0    t1, CP0_STATUS
+
+       /* mark CPU ready, careful here, previous mtcr trashed registers */
+       li      t3, CKSEG1ADDR(RESET_DATA_PHYS)
+       ADDIU   t1, t3, BOOT_CPU_READY
+       sll     v1, v0, 2
+       PTR_ADDU t1, v1
+       li      t2, 1
+       sw      t2, 0(t1)
+       /* Wait until NMI hits */
+3:     wait
+       b       3b
+       nop
+
+       /*
+        * For the boot CPU, we have to restore registers and
+        * return
+        */
+4:     dmfc0   t0, $4, 2       /* restore SP from UserLocal */
+       li      t1, 0xfadebeef
+       dmtc0   t1, $4, 2       /* restore SP from UserLocal */
+       PTR_SUBU sp, t0, PT_SIZE
+       RESTORE_ALL
+       jr      ra
+       nop
+EXPORT(nlm_reset_entry_end)
+
+LEAF(nlm_init_boot_cpu)
+#ifdef CONFIG_CPU_XLP
+       xlp_config_lsu
+#endif
+       jr      ra
+       nop
+END(nlm_init_boot_cpu)
index ffba524..885d293 100644 (file)
@@ -145,7 +145,6 @@ void nlm_cpus_done(void)
  * Boot all other cpus in the system, initialize them, and bring them into
  * the boot function
  */
-int nlm_cpu_ready[NR_CPUS];
 unsigned long nlm_next_gp;
 unsigned long nlm_next_sp;
 static cpumask_t phys_cpu_present_mask;
@@ -168,6 +167,7 @@ void __init nlm_smp_setup(void)
 {
        unsigned int boot_cpu;
        int num_cpus, i, ncore;
+       volatile u32 *cpu_ready = nlm_get_boot_data(BOOT_CPU_READY);
        char buf[64];
 
        boot_cpu = hard_smp_processor_id();
@@ -181,10 +181,10 @@ void __init nlm_smp_setup(void)
        num_cpus = 1;
        for (i = 0; i < NR_CPUS; i++) {
                /*
-                * nlm_cpu_ready array is not set for the boot_cpu,
+                * cpu_ready array is not set for the boot_cpu,
                 * it is only set for ASPs (see smpboot.S)
                 */
-               if (nlm_cpu_ready[i]) {
+               if (cpu_ready[i]) {
                        cpumask_set_cpu(i, &phys_cpu_present_mask);
                        __cpu_number_map[i] = num_cpus;
                        __cpu_logical_map[num_cpus] = i;
@@ -254,21 +254,15 @@ unsupp:
 
 int __cpuinit nlm_wakeup_secondary_cpus(void)
 {
-       unsigned long reset_vec;
-       char *reset_data;
+       u32 *reset_data;
        int threadmode;
 
-       /* Update reset entry point with CPU init code */
-       reset_vec = CKSEG1ADDR(RESET_VEC_PHYS);
-       memcpy((void *)reset_vec, (void *)nlm_reset_entry,
-                       (nlm_reset_entry_end - nlm_reset_entry));
-
        /* verify the mask and setup core config variables */
        threadmode = nlm_parse_cpumask(&nlm_cpumask);
 
        /* Setup CPU init parameters */
-       reset_data = (char *)CKSEG1ADDR(RESET_DATA_PHYS);
-       *(int *)(reset_data + BOOT_THREAD_MODE) = threadmode;
+       reset_data = nlm_get_boot_data(BOOT_THREAD_MODE);
+       *reset_data = threadmode;
 
 #ifdef CONFIG_CPU_XLP
        xlp_wakeup_secondary_cpus();
index 0265174..528c46c 100644 (file)
 #include <asm/netlogic/xlp-hal/cpucontrol.h>
 
 #define CP0_EBASE      $15
-#define SYS_CPU_COHERENT_BASE(node)    CKSEG1ADDR(XLP_DEFAULT_IO_BASE) + \
-                       XLP_IO_SYS_OFFSET(node) + XLP_IO_PCI_HDRSZ + \
-                       SYS_CPU_NONCOHERENT_MODE * 4
-
-#define XLP_AX_WORKAROUND      /* enable Ax silicon workarounds */
-
-/* Enable XLP features and workarounds in the LSU */
-.macro xlp_config_lsu
-       li      t0, LSU_DEFEATURE
-       mfcr    t1, t0
-
-       lui     t2, 0xc080      /* SUE, Enable Unaligned Access, L2HPE */
-       or      t1, t1, t2
-#ifdef XLP_AX_WORKAROUND
-       li      t2, ~0xe        /* S1RCM */
-       and     t1, t1, t2
-#endif
-       mtcr    t1, t0
-
-       li      t0, ICU_DEFEATURE
-       mfcr    t1, t0
-       ori     t1, 0x1000      /* Enable Icache partitioning */
-       mtcr    t1, t0
-
-
-#ifdef XLP_AX_WORKAROUND
-       li      t0, SCHED_DEFEATURE
-       lui     t1, 0x0100      /* Disable BRU accepting ALU ops */
-       mtcr    t1, t0
-#endif
-.endm
-
-/*
- * This is the code that will be copied to the reset entry point for
- * XLR and XLP. The XLP cores start here when they are woken up. This
- * is also the NMI entry point.
- */
-.macro xlp_flush_l1_dcache
-       li      t0, LSU_DEBUG_DATA0
-       li      t1, LSU_DEBUG_ADDR
-       li      t2, 0           /* index */
-       li      t3, 0x1000      /* loop count */
-1:
-       sll     v0, t2, 5
-       mtcr    zero, t0
-       ori     v1, v0, 0x3     /* way0 | write_enable | write_active */
-       mtcr    v1, t1
-2:
-       mfcr    v1, t1
-       andi    v1, 0x1         /* wait for write_active == 0 */
-       bnez    v1, 2b
-       nop
-       mtcr    zero, t0
-       ori     v1, v0, 0x7     /* way1 | write_enable | write_active */
-       mtcr    v1, t1
-3:
-       mfcr    v1, t1
-       andi    v1, 0x1         /* wait for write_active == 0 */
-       bnez    v1, 3b
-       nop
-       addi    t2, 1
-       bne     t3, t2, 1b
-       nop
-.endm
-
-/*
- * The cores can come start when they are woken up. This is also the NMI
- * entry, so check that first.
- *
- * The data corresponding to reset/NMI is stored at RESET_DATA_PHYS
- * location, this will have the thread mask (used when core is woken up)
- * and the current NMI handler in case we reached here for an NMI.
- *
- * When a core or thread is newly woken up, it loops in a 'wait'. When
- * the CPU really needs waking up, we send an NMI to it, with the NMI
- * handler set to prom_boot_secondary_cpus
- */
 
        .set    noreorder
        .set    noat
-       .set    arch=xlr        /* for mfcr/mtcr, XLR is sufficient */
-
-FEXPORT(nlm_reset_entry)
-       dmtc0   k0, $22, 6
-       dmtc0   k1, $22, 7
-       mfc0    k0, CP0_STATUS
-       li      k1, 0x80000
-       and     k1, k0, k1
-       beqz    k1, 1f          /* go to real reset entry */
-       nop
-       li      k1, CKSEG1ADDR(RESET_DATA_PHYS) /* NMI */
-       ld      k0, BOOT_NMI_HANDLER(k1)
-       jr      k0
-       nop
-
-1:     /* Entry point on core wakeup */
-       mfc0    t0, CP0_EBASE, 1
-       mfc0    t1, CP0_EBASE, 1
-       srl     t1, 5
-       andi    t1, 0x3                 /* t1 <- node */
-       li      t2, 0x40000
-       mul     t3, t2, t1              /* t3 = node * 0x40000 */
-       srl     t0, t0, 2
-       and     t0, t0, 0x7             /* t0 <- core */
-       li      t1, 0x1
-       sll     t0, t1, t0
-       nor     t0, t0, zero            /* t0 <- ~(1 << core) */
-       li      t2, SYS_CPU_COHERENT_BASE(0)
-       add     t2, t2, t3              /* t2 <- SYS offset for node */
-       lw      t1, 0(t2)
-       and     t1, t1, t0
-       sw      t1, 0(t2)
-
-       /* read back to ensure complete */
-       lw      t1, 0(t2)
-       sync
-
-       /* Configure LSU on Non-0 Cores. */
-       xlp_config_lsu
-       /* FALL THROUGH */
-
-/*
- * Wake up sibling threads from the initial thread in
- * a core.
- */
-EXPORT(nlm_boot_siblings)
-       /* core L1D flush before enable threads */
-       xlp_flush_l1_dcache
-       /* Enable hw threads by writing to MAP_THREADMODE of the core */
-       li      t0, CKSEG1ADDR(RESET_DATA_PHYS)
-       lw      t1, BOOT_THREAD_MODE(t0)        /* t1 <- thread mode */
-       li      t0, ((CPU_BLOCKID_MAP << 8) | MAP_THREADMODE)
-       mfcr    t2, t0
-       or      t2, t2, t1
-       mtcr    t2, t0
-
-       /*
-        * The new hardware thread starts at the next instruction
-        * For all the cases other than core 0 thread 0, we will
-       * jump to the secondary wait function.
-       */
-       mfc0    v0, CP0_EBASE, 1
-       andi    v0, 0x3ff               /* v0 <- node/core */
-
-       /* Init MMU in the first thread after changing THREAD_MODE
-        * register (Ax Errata?)
-        */
-       andi    v1, v0, 0x3             /* v1 <- thread id */
-       bnez    v1, 2f
-       nop
-
-       li      t0, MMU_SETUP
-       li      t1, 0
-       mtcr    t1, t0
-       _ehb
-
-2:     beqz    v0, 4f          /* boot cpu (cpuid == 0)? */
-       nop
-
-       /* setup status reg */
-       move    t1, zero
-#ifdef CONFIG_64BIT
-       ori     t1, ST0_KX
-#endif
-       mtc0    t1, CP0_STATUS
-       /* mark CPU ready */
-       PTR_LA  t1, nlm_cpu_ready
-       sll     v1, v0, 2
-       PTR_ADDU t1, v1
-       li      t2, 1
-       sw      t2, 0(t1)
-       /* Wait until NMI hits */
-3:     wait
-       j       3b
-       nop
-
-       /*
-        * For the boot CPU, we have to restore registers and
-        * return
-        */
-4:     dmfc0   t0, $4, 2       /* restore SP from UserLocal */
-       li      t1, 0xfadebeef
-       dmtc0   t1, $4, 2       /* restore SP from UserLocal */
-       PTR_SUBU sp, t0, PT_SIZE
-       RESTORE_ALL
-       jr   ra
-       nop
-EXPORT(nlm_reset_entry_end)
+       .set    arch=xlr                /* for mfcr/mtcr, XLR is sufficient */
 
 FEXPORT(xlp_boot_core0_siblings)       /* "Master" cpu starts from here */
-       xlp_config_lsu
        dmtc0   sp, $4, 2               /* SP saved in UserLocal */
        SAVE_ALL
        sync
@@ -294,8 +109,9 @@ NESTED(nlm_rmiboot_preboot, 16, sp)
        andi    t2, t0, 0x3     /* thread num */
        sll     t0, 2           /* offset in cpu array */
 
-       PTR_LA  t1, nlm_cpu_ready /* mark CPU ready */
-       PTR_ADDU t1, t0
+       li      t3, CKSEG1ADDR(RESET_DATA_PHYS)
+       ADDIU   t1, t3, BOOT_CPU_READY
+       ADDU    t1, t0
        li      t3, 1
        sw      t3, 0(t1)
 
@@ -321,7 +137,7 @@ NESTED(nlm_rmiboot_preboot, 16, sp)
        mtcr    t1, t0          /* update core control */
 
 1:     wait
-       j       1b
+       b       1b
        nop
 END(nlm_rmiboot_preboot)
        __FINIT
index a84d6ed..85ac4a8 100644 (file)
@@ -1,3 +1,3 @@
-obj-y                          += setup.o nlm_hal.o
+obj-y                          += setup.o nlm_hal.o cop2-ex.o dt.o
 obj-$(CONFIG_SMP)              += wakeup.o
 obj-$(CONFIG_USB)              += usb-init.o
diff --git a/arch/mips/netlogic/xlp/cop2-ex.c b/arch/mips/netlogic/xlp/cop2-ex.c
new file mode 100644 (file)
index 0000000..52bc5de
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * 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) 2013 Broadcom Corporation.
+ *
+ * based on arch/mips/cavium-octeon/cpu.c
+ * Copyright (C) 2009 Wind River Systems,
+ *   written by Ralf Baechle <ralf@linux-mips.org>
+ */
+#include <linux/init.h>
+#include <linux/irqflags.h>
+#include <linux/notifier.h>
+#include <linux/prefetch.h>
+#include <linux/sched.h>
+
+#include <asm/cop2.h>
+#include <asm/current.h>
+#include <asm/mipsregs.h>
+#include <asm/page.h>
+
+#include <asm/netlogic/mips-extns.h>
+
+/*
+ * 64 bit ops are done in inline assembly to support 32 bit
+ * compilation
+ */
+void nlm_cop2_save(struct nlm_cop2_state *r)
+{
+       asm volatile(
+               ".set   push\n"
+               ".set   noat\n"
+               "dmfc2  $1, $0, 0\n"
+               "sd     $1, 0(%1)\n"
+               "dmfc2  $1, $0, 1\n"
+               "sd     $1, 8(%1)\n"
+               "dmfc2  $1, $0, 2\n"
+               "sd     $1, 16(%1)\n"
+               "dmfc2  $1, $0, 3\n"
+               "sd     $1, 24(%1)\n"
+               "dmfc2  $1, $1, 0\n"
+               "sd     $1, 0(%2)\n"
+               "dmfc2  $1, $1, 1\n"
+               "sd     $1, 8(%2)\n"
+               "dmfc2  $1, $1, 2\n"
+               "sd     $1, 16(%2)\n"
+               "dmfc2  $1, $1, 3\n"
+               "sd     $1, 24(%2)\n"
+               ".set   pop\n"
+               : "=m"(*r)
+               : "r"(r->tx), "r"(r->rx));
+
+       r->tx_msg_status = __read_32bit_c2_register($2, 0);
+       r->rx_msg_status = __read_32bit_c2_register($3, 0) & 0x0fffffff;
+}
+
+void nlm_cop2_restore(struct nlm_cop2_state *r)
+{
+       u32 rstat;
+
+       asm volatile(
+               ".set   push\n"
+               ".set   noat\n"
+               "ld     $1, 0(%1)\n"
+               "dmtc2  $1, $0, 0\n"
+               "ld     $1, 8(%1)\n"
+               "dmtc2  $1, $0, 1\n"
+               "ld     $1, 16(%1)\n"
+               "dmtc2  $1, $0, 2\n"
+               "ld     $1, 24(%1)\n"
+               "dmtc2  $1, $0, 3\n"
+               "ld     $1, 0(%2)\n"
+               "dmtc2  $1, $1, 0\n"
+               "ld     $1, 8(%2)\n"
+               "dmtc2  $1, $1, 1\n"
+               "ld     $1, 16(%2)\n"
+               "dmtc2  $1, $1, 2\n"
+               "ld     $1, 24(%2)\n"
+               "dmtc2  $1, $1, 3\n"
+               ".set   pop\n"
+               : : "m"(*r), "r"(r->tx), "r"(r->rx));
+
+       __write_32bit_c2_register($2, 0, r->tx_msg_status);
+       rstat = __read_32bit_c2_register($3, 0) & 0xf0000000u;
+       __write_32bit_c2_register($3, 0, r->rx_msg_status | rstat);
+}
+
+static int nlm_cu2_call(struct notifier_block *nfb, unsigned long action,
+       void *data)
+{
+       unsigned long flags;
+       unsigned int status;
+
+       switch (action) {
+       case CU2_EXCEPTION:
+               if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
+                       break;
+               local_irq_save(flags);
+               KSTK_STATUS(current) |= ST0_CU2;
+               status = read_c0_status();
+               write_c0_status(status | ST0_CU2);
+               nlm_cop2_restore(&(current->thread.cp2));
+               write_c0_status(status & ~ST0_CU2);
+               local_irq_restore(flags);
+               pr_info("COP2 access enabled for pid %d (%s)\n",
+                                       current->pid, current->comm);
+               return NOTIFY_BAD;      /* Don't call default notifier */
+       }
+
+       return NOTIFY_OK;               /* Let default notifier send signals */
+}
+
+static int __init nlm_cu2_setup(void)
+{
+       return cu2_notifier(nlm_cu2_call, 0);
+}
+early_initcall(nlm_cu2_setup);
diff --git a/arch/mips/netlogic/xlp/dt.c b/arch/mips/netlogic/xlp/dt.c
new file mode 100644 (file)
index 0000000..a15cdbb
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2003-2013 Broadcom Corporation.
+ * All Rights Reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the Broadcom
+ * license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BROADCOM ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL BROADCOM OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/kernel.h>
+#include <linux/bootmem.h>
+
+#include <linux/of_fdt.h>
+#include <linux/of_platform.h>
+#include <linux/of_device.h>
+
+extern u32 __dtb_xlp_evp_begin[], __dtb_xlp_svp_begin[], __dtb_start[];
+
+void __init *xlp_dt_init(void *fdtp)
+{
+       if (!fdtp) {
+               switch (current_cpu_data.processor_id & 0xff00) {
+#ifdef CONFIG_DT_XLP_SVP
+               case PRID_IMP_NETLOGIC_XLP3XX:
+                       fdtp = __dtb_xlp_svp_begin;
+                       break;
+#endif
+#ifdef CONFIG_DT_XLP_EVP
+               case PRID_IMP_NETLOGIC_XLP8XX:
+                       fdtp = __dtb_xlp_evp_begin;
+                       break;
+#endif
+               default:
+                       /* Pick a built-in if any, and hope for the best */
+                       fdtp = __dtb_start;
+                       break;
+               }
+       }
+       initial_boot_params = fdtp;
+       return fdtp;
+}
+
+void __init device_tree_init(void)
+{
+       unsigned long base, size;
+
+       if (!initial_boot_params)
+               return;
+
+       base = virt_to_phys((void *)initial_boot_params);
+       size = be32_to_cpu(initial_boot_params->totalsize);
+
+       /* Before we do anything, lets reserve the dt blob */
+       reserve_bootmem(base, size, BOOTMEM_DEFAULT);
+
+       unflatten_device_tree();
+
+       /* free the space reserved for the dt blob */
+       free_bootmem(base, size);
+}
+
+static struct of_device_id __initdata xlp_ids[] = {
+       { .compatible = "simple-bus", },
+       {},
+};
+
+int __init xlp8xx_ds_publish_devices(void)
+{
+       if (!of_have_populated_dt())
+               return 0;
+       return of_platform_bus_probe(NULL, xlp_ids, NULL);
+}
+
+device_initcall(xlp8xx_ds_publish_devices);
index eaa99d2..7b638f7 100644 (file)
  */
 
 #include <linux/kernel.h>
-#include <linux/serial_8250.h>
-#include <linux/pm.h>
-#include <linux/bootmem.h>
+#include <linux/of_fdt.h>
 
 #include <asm/idle.h>
 #include <asm/reboot.h>
 #include <asm/time.h>
 #include <asm/bootinfo.h>
 
-#include <linux/of_fdt.h>
-#include <linux/of_platform.h>
-#include <linux/of_device.h>
-
 #include <asm/netlogic/haldefs.h>
 #include <asm/netlogic/common.h>
 
@@ -57,7 +51,6 @@ uint64_t nlm_io_base;
 struct nlm_soc_info nlm_nodes[NLM_NR_NODES];
 cpumask_t nlm_cpumask = CPU_MASK_CPU0;
 unsigned int nlm_threads_per_core;
-extern u32 __dtb_xlp_evp_begin[], __dtb_xlp_svp_begin[], __dtb_start[];
 
 static void nlm_linux_exit(void)
 {
@@ -68,41 +61,28 @@ static void nlm_linux_exit(void)
                cpu_wait();
 }
 
-void __init plat_mem_setup(void)
+static void nlm_fixup_mem(void)
 {
-       void *fdtp;
+       const int pref_backup = 512;
+       int i;
+
+       for (i = 0; i < boot_mem_map.nr_map; i++) {
+               if (boot_mem_map.map[i].type != BOOT_MEM_RAM)
+                       continue;
+               boot_mem_map.map[i].size -= pref_backup;
+       }
+}
 
+void __init plat_mem_setup(void)
+{
        panic_timeout   = 5;
        _machine_restart = (void (*)(char *))nlm_linux_exit;
        _machine_halt   = nlm_linux_exit;
        pm_power_off    = nlm_linux_exit;
 
-       /*
-        * If no FDT pointer is passed in, use the built-in FDT.
-        * device_tree_init() does not handle CKSEG0 pointers in
-        * 64-bit, so convert pointer.
-        */
-       fdtp = (void *)(long)fw_arg0;
-       if (!fdtp) {
-               switch (current_cpu_data.processor_id & 0xff00) {
-#ifdef CONFIG_DT_XLP_SVP
-               case PRID_IMP_NETLOGIC_XLP3XX:
-                       fdtp = __dtb_xlp_svp_begin;
-                       break;
-#endif
-#ifdef CONFIG_DT_XLP_EVP
-               case PRID_IMP_NETLOGIC_XLP8XX:
-                       fdtp = __dtb_xlp_evp_begin;
-                       break;
-#endif
-               default:
-                       /* Pick a built-in if any, and hope for the best */
-                       fdtp = __dtb_start;
-                       break;
-               }
-       }
-       fdtp = phys_to_virt(__pa(fdtp));
-       early_init_devtree(fdtp);
+       /* memory and bootargs from DT */
+       early_init_devtree(initial_boot_params);
+       nlm_fixup_mem();
 }
 
 const char *get_system_type(void)
@@ -131,9 +111,19 @@ void nlm_percpu_init(int hwcpuid)
 
 void __init prom_init(void)
 {
+       void *reset_vec;
+
        nlm_io_base = CKSEG1ADDR(XLP_DEFAULT_IO_BASE);
+       nlm_init_boot_cpu();
        xlp_mmu_init();
        nlm_node_init(0);
+       xlp_dt_init((void *)(long)fw_arg0);
+
+       /* Update reset entry point with CPU init code */
+       reset_vec = (void *)CKSEG1ADDR(RESET_VEC_PHYS);
+       memset(reset_vec, 0, RESET_VEC_SIZE);
+       memcpy(reset_vec, (void *)nlm_reset_entry,
+                       (nlm_reset_entry_end - nlm_reset_entry));
 
 #ifdef CONFIG_SMP
        cpumask_setall(&nlm_cpumask);
@@ -145,36 +135,3 @@ void __init prom_init(void)
        register_smp_ops(&nlm_smp_ops);
 #endif
 }
-
-void __init device_tree_init(void)
-{
-       unsigned long base, size;
-
-       if (!initial_boot_params)
-               return;
-
-       base = virt_to_phys((void *)initial_boot_params);
-       size = be32_to_cpu(initial_boot_params->totalsize);
-
-       /* Before we do anything, lets reserve the dt blob */
-       reserve_bootmem(base, size, BOOTMEM_DEFAULT);
-
-       unflatten_device_tree();
-
-       /* free the space reserved for the dt blob */
-       free_bootmem(base, size);
-}
-
-static struct of_device_id __initdata xlp_ids[] = {
-       { .compatible = "simple-bus", },
-       {},
-};
-
-int __init xlp8xx_ds_publish_devices(void)
-{
-       if (!of_have_populated_dt())
-               return 0;
-       return of_platform_bus_probe(NULL, xlp_ids, NULL);
-}
-
-device_initcall(xlp8xx_ds_publish_devices);
index abb3e08..0cce37c 100644 (file)
@@ -77,12 +77,28 @@ static int xlp_wakeup_core(uint64_t sysbase, int node, int core)
        return count != 0;
 }
 
+static int wait_for_cpus(int cpu, int bootcpu)
+{
+       volatile uint32_t *cpu_ready = nlm_get_boot_data(BOOT_CPU_READY);
+       int i, count, notready;
+
+       count = 0x20000000;
+       do {
+               notready = nlm_threads_per_core;
+               for (i = 0; i < nlm_threads_per_core; i++)
+                       if (cpu_ready[cpu + i] || cpu == bootcpu)
+                               --notready;
+       } while (notready != 0 && --count > 0);
+
+       return count != 0;
+}
+
 static void xlp_enable_secondary_cores(const cpumask_t *wakeup_mask)
 {
        struct nlm_soc_info *nodep;
        uint64_t syspcibase;
        uint32_t syscoremask;
-       int core, n, cpu, count, val;
+       int core, n, cpu;
 
        for (n = 0; n < NLM_NR_NODES; n++) {
                syspcibase = nlm_get_sys_pcibase(n);
@@ -122,11 +138,8 @@ static void xlp_enable_secondary_cores(const cpumask_t *wakeup_mask)
                        /* core is up */
                        nodep->coremask |= 1u << core;
 
-                       /* spin until the first hw thread sets its ready */
-                       count = 0x20000000;
-                       do {
-                               val = *(volatile int *)&nlm_cpu_ready[cpu];
-                       } while (val == 0 && --count > 0);
+                       /* spin until the hw threads sets their ready */
+                       wait_for_cpus(cpu, 0);
                }
        }
 }
@@ -138,6 +151,7 @@ void xlp_wakeup_secondary_cpus()
         * first wakeup core 0 threads
         */
        xlp_boot_core0_siblings();
+       wait_for_cpus(0, 0);
 
        /* now get other cores out of reset */
        xlp_enable_secondary_cores(&nlm_cpumask);
index 4d74f03..d428e84 100644 (file)
@@ -74,13 +74,13 @@ static irqreturn_t fmn_message_handler(int irq, void *data)
        struct nlm_fmn_msg msg;
        uint32_t mflags, bkt_status;
 
-       mflags = nlm_cop2_enable();
+       mflags = nlm_cop2_enable_irqsave();
        /* Disable message ring interrupt */
        nlm_fmn_setup_intr(irq, 0);
        while (1) {
                /* 8 bkts per core, [24:31] each bit represents one bucket
                 * Bit is Zero if bucket is not empty */
-               bkt_status = (nlm_read_c2_status() >> 24) & 0xff;
+               bkt_status = (nlm_read_c2_status0() >> 24) & 0xff;
                if (bkt_status == 0xff)
                        break;
                for (bucket = 0; bucket < 8; bucket++) {
@@ -97,16 +97,16 @@ static irqreturn_t fmn_message_handler(int irq, void *data)
                                pr_warn("No msgring handler for stnid %d\n",
                                                src_stnid);
                        else {
-                               nlm_cop2_restore(mflags);
+                               nlm_cop2_disable_irqrestore(mflags);
                                hndlr->action(bucket, src_stnid, size, code,
                                        &msg, hndlr->arg);
-                               mflags = nlm_cop2_enable();
+                               mflags = nlm_cop2_enable_irqsave();
                        }
                }
        };
        /* Enable message ring intr, to any thread in core */
        nlm_fmn_setup_intr(irq, (1 << nlm_threads_per_core) - 1);
-       nlm_cop2_restore(mflags);
+       nlm_cop2_disable_irqrestore(mflags);
        return IRQ_HANDLED;
 }
 
@@ -128,7 +128,7 @@ void xlr_percpu_fmn_init(void)
 
        bucket_sizes = xlr_board_fmn_config.bucket_size;
        cpu_fmn_info = &xlr_board_fmn_config.cpu[id];
-       flags = nlm_cop2_enable();
+       flags = nlm_cop2_enable_irqsave();
 
        /* Setup bucket sizes for the core. */
        nlm_write_c2_bucksize(0, bucket_sizes[id * 8 + 0]);
@@ -166,7 +166,7 @@ void xlr_percpu_fmn_init(void)
 
        /* enable FMN interrupts on this CPU */
        nlm_fmn_setup_intr(IRQ_FMN, (1 << nlm_threads_per_core) - 1);
-       nlm_cop2_restore(flags);
+       nlm_cop2_disable_irqrestore(flags);
 }
 
 
@@ -198,7 +198,7 @@ void nlm_setup_fmn_irq(void)
        /* setup irq only once */
        setup_irq(IRQ_FMN, &fmn_irqaction);
 
-       flags = nlm_cop2_enable();
+       flags = nlm_cop2_enable_irqsave();
        nlm_fmn_setup_intr(IRQ_FMN, (1 << nlm_threads_per_core) - 1);
-       nlm_cop2_restore(flags);
+       nlm_cop2_disable_irqrestore(flags);
 }
index 89c8c10..214d123 100644 (file)
@@ -196,6 +196,7 @@ void __init prom_init(void)
 {
        int *argv, *envp;               /* passed as 32 bit ptrs */
        struct psb_info *prom_infop;
+       void *reset_vec;
 #ifdef CONFIG_SMP
        int i;
 #endif
@@ -208,6 +209,12 @@ void __init prom_init(void)
        nlm_prom_info = *prom_infop;
        nlm_init_node();
 
+       /* Update reset entry point with CPU init code */
+       reset_vec = (void *)CKSEG1ADDR(RESET_VEC_PHYS);
+       memset(reset_vec, 0, RESET_VEC_SIZE);
+       memcpy(reset_vec, (void *)nlm_reset_entry,
+                       (nlm_reset_entry_end - nlm_reset_entry));
+
        nlm_early_serial_setup();
        build_arcs_cmdline(argv);
        prom_add_memory();
index 3ebf741..c06e4c9 100644 (file)
@@ -53,6 +53,7 @@ int __cpuinit xlr_wakeup_secondary_cpus(void)
 {
        struct nlm_soc_info *nodep;
        unsigned int i, j, boot_cpu;
+       volatile u32 *cpu_ready = nlm_get_boot_data(BOOT_CPU_READY);
 
        /*
         *  In case of RMI boot, hit with NMI to get the cores
@@ -71,7 +72,7 @@ int __cpuinit xlr_wakeup_secondary_cpus(void)
        nodep->coremask = 1;
        for (i = 1; i < NLM_CORES_PER_NODE; i++) {
                for (j = 1000000; j > 0; j--) {
-                       if (nlm_cpu_ready[i * NLM_THREADS_PER_CORE])
+                       if (cpu_ready[i * NLM_THREADS_PER_CORE])
                                break;
                        udelay(10);
                }
index 2cb1d31..c382042 100644 (file)
@@ -29,7 +29,7 @@ obj-$(CONFIG_LASAT)           += pci-lasat.o
 obj-$(CONFIG_MIPS_COBALT)      += fixup-cobalt.o
 obj-$(CONFIG_LEMOTE_FULOONG2E) += fixup-fuloong2e.o ops-loongson2.o
 obj-$(CONFIG_LEMOTE_MACH2F)    += fixup-lemote2f.o ops-loongson2.o
-obj-$(CONFIG_MIPS_MALTA)       += fixup-malta.o
+obj-$(CONFIG_MIPS_MALTA)       += fixup-malta.o pci-malta.o
 obj-$(CONFIG_PMC_MSP7120_GW)   += fixup-pmcmsp.o ops-pmcmsp.o
 obj-$(CONFIG_PMC_MSP7120_EVAL) += fixup-pmcmsp.o ops-pmcmsp.o
 obj-$(CONFIG_PMC_MSP7120_FPGA) += fixup-pmcmsp.o ops-pmcmsp.o
@@ -52,12 +52,11 @@ obj-$(CONFIG_TOSHIBA_RBTX4927)      += fixup-rbtx4927.o
 obj-$(CONFIG_TOSHIBA_RBTX4938) += fixup-rbtx4938.o
 obj-$(CONFIG_VICTOR_MPC30X)    += fixup-mpc30x.o
 obj-$(CONFIG_ZAO_CAPCELLA)     += fixup-capcella.o
-obj-$(CONFIG_WR_PPMC)          += fixup-wrppmc.o
 obj-$(CONFIG_MIKROTIK_RB532)   += pci-rc32434.o ops-rc32434.o fixup-rc32434.o
-obj-$(CONFIG_CPU_CAVIUM_OCTEON) += pci-octeon.o pcie-octeon.o
+obj-$(CONFIG_CAVIUM_OCTEON_SOC) += pci-octeon.o pcie-octeon.o
 obj-$(CONFIG_CPU_XLR)          += pci-xlr.o
 obj-$(CONFIG_CPU_XLP)          += pci-xlp.o
 
 ifdef CONFIG_PCI_MSI
-obj-$(CONFIG_CPU_CAVIUM_OCTEON) += msi-octeon.o
+obj-$(CONFIG_CAVIUM_OCTEON_SOC) += msi-octeon.o
 endif
diff --git a/arch/mips/pci/fixup-wrppmc.c b/arch/mips/pci/fixup-wrppmc.c
deleted file mode 100644 (file)
index 29737ed..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * fixup-wrppmc.c: PPMC board specific PCI fixup
- *
- * 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) 2006, Wind River Inc. Rongkai.zhan (rongkai.zhan@windriver.com)
- */
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <asm/gt64120.h>
-
-/* PCI interrupt pins */
-#define PCI_INTA               1
-#define PCI_INTB               2
-#define PCI_INTC               3
-#define PCI_INTD               4
-
-#define PCI_SLOT_MAXNR 32 /* Each PCI bus has 32 physical slots */
-
-static char pci_irq_tab[PCI_SLOT_MAXNR][5] __initdata = {
-       /* 0    INTA   INTB   INTC   INTD */
-       [0] = {0, 0, 0, 0, 0},          /* Slot 0: GT64120 PCI bridge */
-       [6] = {0, WRPPMC_PCI_INTA_IRQ, 0, 0, 0},
-};
-
-int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
-{
-       return pci_irq_tab[slot][pin];
-}
-
-/* Do platform specific device initialization at pci_enable_device() time */
-int pcibios_plat_dev_init(struct pci_dev *dev)
-{
-       return 0;
-}
index 2eb9542..151d9b5 100644 (file)
@@ -266,7 +266,7 @@ static int __init bcm63xx_register_pci(void)
        /* setup PCI to local bus access, used by PCI device to target
         * local RAM while bus mastering */
        bcm63xx_int_cfg_writel(0, PCI_BASE_ADDRESS_3);
-       if (BCMCPU_IS_6358() || BCMCPU_IS_6368())
+       if (BCMCPU_IS_3368() || BCMCPU_IS_6358() || BCMCPU_IS_6368())
                val = MPI_SP0_REMAP_ENABLE_MASK;
        else
                val = 0;
@@ -338,6 +338,7 @@ static int __init bcm63xx_pci_init(void)
        case BCM6328_CPU_ID:
        case BCM6362_CPU_ID:
                return bcm63xx_register_pcie();
+       case BCM3368_CPU_ID:
        case BCM6348_CPU_ID:
        case BCM6358_CPU_ID:
        case BCM6368_CPU_ID:
index 6eb65e4..7b2ac81 100644 (file)
@@ -217,6 +217,7 @@ static void pci_fixup_ioc3(struct pci_dev *d)
        pci_disable_swapping(d);
 }
 
+#ifdef CONFIG_NUMA
 int pcibus_to_node(struct pci_bus *bus)
 {
        struct bridge_controller *bc = BRIDGE_CONTROLLER(bus);
@@ -224,6 +225,7 @@ int pcibus_to_node(struct pci_bus *bus)
        return bc->nasid;
 }
 EXPORT_SYMBOL(pcibus_to_node);
+#endif /* CONFIG_NUMA */
 
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IOC3,
        pci_fixup_ioc3);
index cefba77..9201c8b 100644 (file)
@@ -3,7 +3,6 @@
 #
 obj-y += msp_prom.o msp_setup.o msp_irq.o \
         msp_time.o msp_serial.o msp_elb.o
-obj-$(CONFIG_HAVE_GPIO_LIB) += gpio.o gpio_extended.o
 obj-$(CONFIG_PMC_MSP7120_GW) += msp_hwbutton.o
 obj-$(CONFIG_IRQ_MSP_SLP) += msp_irq_slp.o
 obj-$(CONFIG_IRQ_MSP_CIC) += msp_irq_cic.o msp_irq_per.o
diff --git a/arch/mips/pmcs-msp71xx/gpio.c b/arch/mips/pmcs-msp71xx/gpio.c
deleted file mode 100644 (file)
index aaccbe5..0000000
+++ /dev/null
@@ -1,216 +0,0 @@
-/*
- * Generic PMC MSP71xx GPIO handling. These base gpio are controlled by two
- * types of registers. The data register sets the output level when in output
- * mode and when in input mode will contain the value at the input. The config
- * register sets the various modes for each gpio.
- *
- * 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.
- *
- * @author Patrick Glass <patrickglass@gmail.com>
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/gpio.h>
-#include <linux/spinlock.h>
-#include <linux/io.h>
-
-#define MSP71XX_CFG_OFFSET(gpio)       (4 * (gpio))
-#define CONF_MASK                      0x0F
-#define MSP71XX_GPIO_INPUT             0x01
-#define MSP71XX_GPIO_OUTPUT            0x08
-
-#define MSP71XX_GPIO_BASE              0x0B8400000L
-
-#define to_msp71xx_gpio_chip(c) container_of(c, struct msp71xx_gpio_chip, chip)
-
-static spinlock_t gpio_lock;
-
-/*
- * struct msp71xx_gpio_chip - container for gpio chip and registers
- * @chip: chip structure for the specified gpio bank
- * @data_reg: register for reading and writing the gpio pin value
- * @config_reg: register to set the mode for the gpio pin bank
- * @out_drive_reg: register to set the output drive mode for the gpio pin bank
- */
-struct msp71xx_gpio_chip {
-       struct gpio_chip chip;
-       void __iomem *data_reg;
-       void __iomem *config_reg;
-       void __iomem *out_drive_reg;
-};
-
-/*
- * msp71xx_gpio_get() - return the chip's gpio value
- * @chip: chip structure which controls the specified gpio
- * @offset: gpio whose value will be returned
- *
- * It will return 0 if gpio value is low and other if high.
- */
-static int msp71xx_gpio_get(struct gpio_chip *chip, unsigned offset)
-{
-       struct msp71xx_gpio_chip *msp_chip = to_msp71xx_gpio_chip(chip);
-
-       return __raw_readl(msp_chip->data_reg) & (1 << offset);
-}
-
-/*
- * msp71xx_gpio_set() - set the output value for the gpio
- * @chip: chip structure who controls the specified gpio
- * @offset: gpio whose value will be assigned
- * @value: logic level to assign to the gpio initially
- *
- * This will set the gpio bit specified to the desired value. It will set the
- * gpio pin low if value is 0 otherwise it will be high.
- */
-static void msp71xx_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
-{
-       struct msp71xx_gpio_chip *msp_chip = to_msp71xx_gpio_chip(chip);
-       unsigned long flags;
-       u32 data;
-
-       spin_lock_irqsave(&gpio_lock, flags);
-
-       data = __raw_readl(msp_chip->data_reg);
-       if (value)
-               data |= (1 << offset);
-       else
-               data &= ~(1 << offset);
-       __raw_writel(data, msp_chip->data_reg);
-
-       spin_unlock_irqrestore(&gpio_lock, flags);
-}
-
-/*
- * msp71xx_set_gpio_mode() - declare the mode for a gpio
- * @chip: chip structure which controls the specified gpio
- * @offset: gpio whose value will be assigned
- * @mode: desired configuration for the gpio (see datasheet)
- *
- * It will set the gpio pin config to the @mode value passed in.
- */
-static int msp71xx_set_gpio_mode(struct gpio_chip *chip,
-                                unsigned offset, int mode)
-{
-       struct msp71xx_gpio_chip *msp_chip = to_msp71xx_gpio_chip(chip);
-       const unsigned bit_offset = MSP71XX_CFG_OFFSET(offset);
-       unsigned long flags;
-       u32 cfg;
-
-       spin_lock_irqsave(&gpio_lock, flags);
-
-       cfg = __raw_readl(msp_chip->config_reg);
-       cfg &= ~(CONF_MASK << bit_offset);
-       cfg |= (mode << bit_offset);
-       __raw_writel(cfg, msp_chip->config_reg);
-
-       spin_unlock_irqrestore(&gpio_lock, flags);
-
-       return 0;
-}
-
-/*
- * msp71xx_direction_output() - declare the direction mode for a gpio
- * @chip: chip structure which controls the specified gpio
- * @offset: gpio whose value will be assigned
- * @value: logic level to assign to the gpio initially
- *
- * This call will set the mode for the @gpio to output. It will set the
- * gpio pin low if value is 0 otherwise it will be high.
- */
-static int msp71xx_direction_output(struct gpio_chip *chip,
-                                   unsigned offset, int value)
-{
-       msp71xx_gpio_set(chip, offset, value);
-
-       return msp71xx_set_gpio_mode(chip, offset, MSP71XX_GPIO_OUTPUT);
-}
-
-/*
- * msp71xx_direction_input() - declare the direction mode for a gpio
- * @chip: chip structure which controls the specified gpio
- * @offset: gpio whose to which the value will be assigned
- *
- * This call will set the mode for the @gpio to input.
- */
-static int msp71xx_direction_input(struct gpio_chip *chip, unsigned offset)
-{
-       return msp71xx_set_gpio_mode(chip, offset, MSP71XX_GPIO_INPUT);
-}
-
-/*
- * msp71xx_set_output_drive() - declare the output drive for the gpio line
- * @gpio: gpio pin whose output drive you wish to modify
- * @value: zero for active drain 1 for open drain drive
- *
- * This call will set the output drive mode for the @gpio to output.
- */
-int msp71xx_set_output_drive(unsigned gpio, int value)
-{
-       unsigned long flags;
-       u32 data;
-
-       if (gpio > 15 || gpio < 0)
-               return -EINVAL;
-
-       spin_lock_irqsave(&gpio_lock, flags);
-
-       data = __raw_readl((void __iomem *)(MSP71XX_GPIO_BASE + 0x190));
-       if (value)
-               data |= (1 << gpio);
-       else
-               data &= ~(1 << gpio);
-       __raw_writel(data, (void __iomem *)(MSP71XX_GPIO_BASE + 0x190));
-
-       spin_unlock_irqrestore(&gpio_lock, flags);
-
-       return 0;
-}
-EXPORT_SYMBOL(msp71xx_set_output_drive);
-
-#define MSP71XX_GPIO_BANK(name, dr, cr, base_gpio, num_gpio) \
-{ \
-       .chip = { \
-               .label            = name, \
-               .direction_input  = msp71xx_direction_input, \
-               .direction_output = msp71xx_direction_output, \
-               .get              = msp71xx_gpio_get, \
-               .set              = msp71xx_gpio_set, \
-               .base             = base_gpio, \
-               .ngpio            = num_gpio \
-       }, \
-       .data_reg       = (void __iomem *)(MSP71XX_GPIO_BASE + dr), \
-       .config_reg     = (void __iomem *)(MSP71XX_GPIO_BASE + cr), \
-       .out_drive_reg  = (void __iomem *)(MSP71XX_GPIO_BASE + 0x190), \
-}
-
-/*
- * struct msp71xx_gpio_banks[] - container array of gpio banks
- * @chip: chip structure for the specified gpio bank
- * @data_reg: register for reading and writing the gpio pin value
- * @config_reg: register to set the mode for the gpio pin bank
- *
- * This array structure defines the gpio banks for the PMC MIPS Processor.
- * We specify the bank name, the data register, the config register, base
- * starting gpio number, and the number of gpios exposed by the bank.
- */
-static struct msp71xx_gpio_chip msp71xx_gpio_banks[] = {
-
-       MSP71XX_GPIO_BANK("GPIO_1_0", 0x170, 0x180, 0, 2),
-       MSP71XX_GPIO_BANK("GPIO_5_2", 0x174, 0x184, 2, 4),
-       MSP71XX_GPIO_BANK("GPIO_9_6", 0x178, 0x188, 6, 4),
-       MSP71XX_GPIO_BANK("GPIO_15_10", 0x17C, 0x18C, 10, 6),
-};
-
-void __init msp71xx_init_gpio(void)
-{
-       int i;
-
-       spin_lock_init(&gpio_lock);
-
-       for (i = 0; i < ARRAY_SIZE(msp71xx_gpio_banks); i++)
-               gpiochip_add(&msp71xx_gpio_banks[i].chip);
-}
diff --git a/arch/mips/pmcs-msp71xx/gpio_extended.c b/arch/mips/pmcs-msp71xx/gpio_extended.c
deleted file mode 100644 (file)
index 2a99f36..0000000
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * Generic PMC MSP71xx EXTENDED (EXD) GPIO handling. The extended gpio is
- * a set of hardware registers that have no need for explicit locking as
- * it is handled by unique method of writing individual set/clr bits.
- *
- * 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.
- *
- * @author Patrick Glass <patrickglass@gmail.com>
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/gpio.h>
-#include <linux/io.h>
-
-#define MSP71XX_DATA_OFFSET(gpio)      (2 * (gpio))
-#define MSP71XX_READ_OFFSET(gpio)      (MSP71XX_DATA_OFFSET(gpio) + 1)
-#define MSP71XX_CFG_OUT_OFFSET(gpio)   (MSP71XX_DATA_OFFSET(gpio) + 16)
-#define MSP71XX_CFG_IN_OFFSET(gpio)    (MSP71XX_CFG_OUT_OFFSET(gpio) + 1)
-
-#define MSP71XX_EXD_GPIO_BASE  0x0BC000000L
-
-#define to_msp71xx_exd_gpio_chip(c) \
-                       container_of(c, struct msp71xx_exd_gpio_chip, chip)
-
-/*
- * struct msp71xx_exd_gpio_chip - container for gpio chip and registers
- * @chip: chip structure for the specified gpio bank
- * @reg: register for control and data of gpio pin
- */
-struct msp71xx_exd_gpio_chip {
-       struct gpio_chip chip;
-       void __iomem *reg;
-};
-
-/*
- * msp71xx_exd_gpio_get() - return the chip's gpio value
- * @chip: chip structure which controls the specified gpio
- * @offset: gpio whose value will be returned
- *
- * It will return 0 if gpio value is low and other if high.
- */
-static int msp71xx_exd_gpio_get(struct gpio_chip *chip, unsigned offset)
-{
-       struct msp71xx_exd_gpio_chip *msp71xx_chip =
-           to_msp71xx_exd_gpio_chip(chip);
-       const unsigned bit = MSP71XX_READ_OFFSET(offset);
-
-       return __raw_readl(msp71xx_chip->reg) & (1 << bit);
-}
-
-/*
- * msp71xx_exd_gpio_set() - set the output value for the gpio
- * @chip: chip structure who controls the specified gpio
- * @offset: gpio whose value will be assigned
- * @value: logic level to assign to the gpio initially
- *
- * This will set the gpio bit specified to the desired value. It will set the
- * gpio pin low if value is 0 otherwise it will be high.
- */
-static void msp71xx_exd_gpio_set(struct gpio_chip *chip,
-                                unsigned offset, int value)
-{
-       struct msp71xx_exd_gpio_chip *msp71xx_chip =
-           to_msp71xx_exd_gpio_chip(chip);
-       const unsigned bit = MSP71XX_DATA_OFFSET(offset);
-
-       __raw_writel(1 << (bit + (value ? 1 : 0)), msp71xx_chip->reg);
-}
-
-/*
- * msp71xx_exd_direction_output() - declare the direction mode for a gpio
- * @chip: chip structure which controls the specified gpio
- * @offset: gpio whose value will be assigned
- * @value: logic level to assign to the gpio initially
- *
- * This call will set the mode for the @gpio to output. It will set the
- * gpio pin low if value is 0 otherwise it will be high.
- */
-static int msp71xx_exd_direction_output(struct gpio_chip *chip,
-                                       unsigned offset, int value)
-{
-       struct msp71xx_exd_gpio_chip *msp71xx_chip =
-           to_msp71xx_exd_gpio_chip(chip);
-
-       msp71xx_exd_gpio_set(chip, offset, value);
-       __raw_writel(1 << MSP71XX_CFG_OUT_OFFSET(offset), msp71xx_chip->reg);
-       return 0;
-}
-
-/*
- * msp71xx_exd_direction_input() - declare the direction mode for a gpio
- * @chip: chip structure which controls the specified gpio
- * @offset: gpio whose to which the value will be assigned
- *
- * This call will set the mode for the @gpio to input.
- */
-static int msp71xx_exd_direction_input(struct gpio_chip *chip, unsigned offset)
-{
-       struct msp71xx_exd_gpio_chip *msp71xx_chip =
-           to_msp71xx_exd_gpio_chip(chip);
-
-       __raw_writel(1 << MSP71XX_CFG_IN_OFFSET(offset), msp71xx_chip->reg);
-       return 0;
-}
-
-#define MSP71XX_EXD_GPIO_BANK(name, exd_reg, base_gpio, num_gpio) \
-{ \
-       .chip = { \
-               .label            = name, \
-               .direction_input  = msp71xx_exd_direction_input, \
-               .direction_output = msp71xx_exd_direction_output, \
-               .get              = msp71xx_exd_gpio_get, \
-               .set              = msp71xx_exd_gpio_set, \
-               .base             = base_gpio, \
-               .ngpio            = num_gpio, \
-       }, \
-       .reg    = (void __iomem *)(MSP71XX_EXD_GPIO_BASE + exd_reg), \
-}
-
-/*
- * struct msp71xx_exd_gpio_banks[] - container array of gpio banks
- * @chip: chip structure for the specified gpio bank
- * @reg: register for reading and writing the gpio pin value
- *
- * This array structure defines the extended gpio banks for the
- * PMC MIPS Processor. We specify the bank name, the data/config
- * register,the base starting gpio number, and the number of
- * gpios exposed by the bank of gpios.
- */
-static struct msp71xx_exd_gpio_chip msp71xx_exd_gpio_banks[] = {
-
-       MSP71XX_EXD_GPIO_BANK("GPIO_23_16", 0x188, 16, 8),
-       MSP71XX_EXD_GPIO_BANK("GPIO_27_24", 0x18C, 24, 4),
-};
-
-void __init msp71xx_init_gpio_extended(void)
-{
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(msp71xx_exd_gpio_banks); i++)
-               gpiochip_add(&msp71xx_exd_gpio_banks[i].chip);
-}
index d38b095..9f64c23 100644 (file)
@@ -529,17 +529,8 @@ EXPORT_SYMBOL(asic_resource_get);
  */
 void platform_release_memory(void *ptr, int size)
 {
-       unsigned long addr;
-       unsigned long end;
-
-       addr = ((unsigned long)ptr + (PAGE_SIZE - 1)) & PAGE_MASK;
-       end = ((unsigned long)ptr + size) & PAGE_MASK;
-
-       for (; addr < end; addr += PAGE_SIZE) {
-               ClearPageReserved(virt_to_page(__va(addr)));
-               init_page_count(virt_to_page(__va(addr)));
-               free_page((unsigned long)__va(addr));
-       }
+       free_reserved_area((unsigned long)ptr, (unsigned long)(ptr + size),
+                          -1, NULL);
 }
 EXPORT_SYMBOL(platform_release_memory);
 
index 6b5f340..f25ea5b 100644 (file)
@@ -104,7 +104,7 @@ static int __init plat_of_setup(void)
        if (!of_have_populated_dt())
                panic("device tree not present");
 
-       strncpy(of_ids[0].compatible, soc_info.compatible, len);
+       strlcpy(of_ids[0].compatible, soc_info.compatible, len);
        strncpy(of_ids[1].compatible, "palmbus", len);
 
        if (of_platform_populate(NULL, of_ids, NULL, NULL))
index 1f29e76..da8f681 100644 (file)
@@ -7,4 +7,5 @@ obj-y   := ip27-berr.o ip27-irq.o ip27-init.o ip27-klconfig.o ip27-klnuma.o \
           ip27-xtalk.o
 
 obj-$(CONFIG_EARLY_PRINTK)     += ip27-console.o
+obj-$(CONFIG_PCI)              += ip27-irq-pci.o
 obj-$(CONFIG_SMP)              += ip27-smp.o
diff --git a/arch/mips/sgi-ip27/ip27-irq-pci.c b/arch/mips/sgi-ip27/ip27-irq-pci.c
new file mode 100644 (file)
index 0000000..ec22ec5
--- /dev/null
@@ -0,0 +1,266 @@
+/*
+ * ip27-irq.c: Highlevel interrupt handling for IP27 architecture.
+ *
+ * Copyright (C) 1999, 2000 Ralf Baechle (ralf@gnu.org)
+ * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
+ * Copyright (C) 1999 - 2001 Kanoj Sarcar
+ */
+
+#undef DEBUG
+
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/timex.h>
+#include <linux/smp.h>
+#include <linux/random.h>
+#include <linux/kernel.h>
+#include <linux/kernel_stat.h>
+#include <linux/delay.h>
+#include <linux/bitops.h>
+
+#include <asm/bootinfo.h>
+#include <asm/io.h>
+#include <asm/mipsregs.h>
+
+#include <asm/processor.h>
+#include <asm/pci/bridge.h>
+#include <asm/sn/addrs.h>
+#include <asm/sn/agent.h>
+#include <asm/sn/arch.h>
+#include <asm/sn/hub.h>
+#include <asm/sn/intr.h>
+
+/*
+ * Linux has a controller-independent x86 interrupt architecture.
+ * every controller has a 'controller-template', that is used
+ * by the main code to do the right thing. Each driver-visible
+ * interrupt source is transparently wired to the appropriate
+ * controller. Thus drivers need not be aware of the
+ * interrupt-controller.
+ *
+ * Various interrupt controllers we handle: 8259 PIC, SMP IO-APIC,
+ * PIIX4's internal 8259 PIC and SGI's Visual Workstation Cobalt (IO-)APIC.
+ * (IO-APICs assumed to be messaging to Pentium local-APICs)
+ *
+ * the code is designed to be easily extended with new/different
+ * interrupt controllers, without having to do assembly magic.
+ */
+
+extern struct bridge_controller *irq_to_bridge[];
+extern int irq_to_slot[];
+
+/*
+ * use these macros to get the encoded nasid and widget id
+ * from the irq value
+ */
+#define IRQ_TO_BRIDGE(i)               irq_to_bridge[(i)]
+#define SLOT_FROM_PCI_IRQ(i)           irq_to_slot[i]
+
+static inline int alloc_level(int cpu, int irq)
+{
+       struct hub_data *hub = hub_data(cpu_to_node(cpu));
+       struct slice_data *si = cpu_data[cpu].data;
+       int level;
+
+       level = find_first_zero_bit(hub->irq_alloc_mask, LEVELS_PER_SLICE);
+       if (level >= LEVELS_PER_SLICE)
+               panic("Cpu %d flooded with devices", cpu);
+
+       __set_bit(level, hub->irq_alloc_mask);
+       si->level_to_irq[level] = irq;
+
+       return level;
+}
+
+static inline int find_level(cpuid_t *cpunum, int irq)
+{
+       int cpu, i;
+
+       for_each_online_cpu(cpu) {
+               struct slice_data *si = cpu_data[cpu].data;
+
+               for (i = BASE_PCI_IRQ; i < LEVELS_PER_SLICE; i++)
+                       if (si->level_to_irq[i] == irq) {
+                               *cpunum = cpu;
+
+                               return i;
+                       }
+       }
+
+       panic("Could not identify cpu/level for irq %d", irq);
+}
+
+static int intr_connect_level(int cpu, int bit)
+{
+       nasid_t nasid = COMPACT_TO_NASID_NODEID(cpu_to_node(cpu));
+       struct slice_data *si = cpu_data[cpu].data;
+
+       set_bit(bit, si->irq_enable_mask);
+
+       if (!cputoslice(cpu)) {
+               REMOTE_HUB_S(nasid, PI_INT_MASK0_A, si->irq_enable_mask[0]);
+               REMOTE_HUB_S(nasid, PI_INT_MASK1_A, si->irq_enable_mask[1]);
+       } else {
+               REMOTE_HUB_S(nasid, PI_INT_MASK0_B, si->irq_enable_mask[0]);
+               REMOTE_HUB_S(nasid, PI_INT_MASK1_B, si->irq_enable_mask[1]);
+       }
+
+       return 0;
+}
+
+static int intr_disconnect_level(int cpu, int bit)
+{
+       nasid_t nasid = COMPACT_TO_NASID_NODEID(cpu_to_node(cpu));
+       struct slice_data *si = cpu_data[cpu].data;
+
+       clear_bit(bit, si->irq_enable_mask);
+
+       if (!cputoslice(cpu)) {
+               REMOTE_HUB_S(nasid, PI_INT_MASK0_A, si->irq_enable_mask[0]);
+               REMOTE_HUB_S(nasid, PI_INT_MASK1_A, si->irq_enable_mask[1]);
+       } else {
+               REMOTE_HUB_S(nasid, PI_INT_MASK0_B, si->irq_enable_mask[0]);
+               REMOTE_HUB_S(nasid, PI_INT_MASK1_B, si->irq_enable_mask[1]);
+       }
+
+       return 0;
+}
+
+/* Startup one of the (PCI ...) IRQs routes over a bridge.  */
+static unsigned int startup_bridge_irq(struct irq_data *d)
+{
+       struct bridge_controller *bc;
+       bridgereg_t device;
+       bridge_t *bridge;
+       int pin, swlevel;
+       cpuid_t cpu;
+
+       pin = SLOT_FROM_PCI_IRQ(d->irq);
+       bc = IRQ_TO_BRIDGE(d->irq);
+       bridge = bc->base;
+
+       pr_debug("bridge_startup(): irq= 0x%x  pin=%d\n", d->irq, pin);
+       /*
+        * "map" irq to a swlevel greater than 6 since the first 6 bits
+        * of INT_PEND0 are taken
+        */
+       swlevel = find_level(&cpu, d->irq);
+       bridge->b_int_addr[pin].addr = (0x20000 | swlevel | (bc->nasid << 8));
+       bridge->b_int_enable |= (1 << pin);
+       bridge->b_int_enable |= 0x7ffffe00;     /* more stuff in int_enable */
+
+       /*
+        * Enable sending of an interrupt clear packt to the hub on a high to
+        * low transition of the interrupt pin.
+        *
+        * IRIX sets additional bits in the address which are documented as
+        * reserved in the bridge docs.
+        */
+       bridge->b_int_mode |= (1UL << pin);
+
+       /*
+        * We assume the bridge to have a 1:1 mapping between devices
+        * (slots) and intr pins.
+        */
+       device = bridge->b_int_device;
+       device &= ~(7 << (pin*3));
+       device |= (pin << (pin*3));
+       bridge->b_int_device = device;
+
+       bridge->b_wid_tflush;
+
+       intr_connect_level(cpu, swlevel);
+
+       return 0;       /* Never anything pending.  */
+}
+
+/* Shutdown one of the (PCI ...) IRQs routes over a bridge.  */
+static void shutdown_bridge_irq(struct irq_data *d)
+{
+       struct bridge_controller *bc = IRQ_TO_BRIDGE(d->irq);
+       bridge_t *bridge = bc->base;
+       int pin, swlevel;
+       cpuid_t cpu;
+
+       pr_debug("bridge_shutdown: irq 0x%x\n", d->irq);
+       pin = SLOT_FROM_PCI_IRQ(d->irq);
+
+       /*
+        * map irq to a swlevel greater than 6 since the first 6 bits
+        * of INT_PEND0 are taken
+        */
+       swlevel = find_level(&cpu, d->irq);
+       intr_disconnect_level(cpu, swlevel);
+
+       bridge->b_int_enable &= ~(1 << pin);
+       bridge->b_wid_tflush;
+}
+
+static inline void enable_bridge_irq(struct irq_data *d)
+{
+       cpuid_t cpu;
+       int swlevel;
+
+       swlevel = find_level(&cpu, d->irq);     /* Criminal offence */
+       intr_connect_level(cpu, swlevel);
+}
+
+static inline void disable_bridge_irq(struct irq_data *d)
+{
+       cpuid_t cpu;
+       int swlevel;
+
+       swlevel = find_level(&cpu, d->irq);     /* Criminal offence */
+       intr_disconnect_level(cpu, swlevel);
+}
+
+static struct irq_chip bridge_irq_type = {
+       .name           = "bridge",
+       .irq_startup    = startup_bridge_irq,
+       .irq_shutdown   = shutdown_bridge_irq,
+       .irq_mask       = disable_bridge_irq,
+       .irq_unmask     = enable_bridge_irq,
+};
+
+void register_bridge_irq(unsigned int irq)
+{
+       irq_set_chip_and_handler(irq, &bridge_irq_type, handle_level_irq);
+}
+
+int request_bridge_irq(struct bridge_controller *bc)
+{
+       int irq = allocate_irqno();
+       int swlevel, cpu;
+       nasid_t nasid;
+
+       if (irq < 0)
+               return irq;
+
+       /*
+        * "map" irq to a swlevel greater than 6 since the first 6 bits
+        * of INT_PEND0 are taken
+        */
+       cpu = bc->irq_cpu;
+       swlevel = alloc_level(cpu, irq);
+       if (unlikely(swlevel < 0)) {
+               free_irqno(irq);
+
+               return -EAGAIN;
+       }
+
+       /* Make sure it's not already pending when we connect it. */
+       nasid = COMPACT_TO_NASID_NODEID(cpu_to_node(cpu));
+       REMOTE_HUB_CLR_INTR(nasid, swlevel);
+
+       intr_connect_level(cpu, swlevel);
+
+       register_bridge_irq(irq);
+
+       return irq;
+}
index 2315cfe..3fbaef9 100644 (file)
@@ -29,7 +29,6 @@
 #include <asm/mipsregs.h>
 
 #include <asm/processor.h>
-#include <asm/pci/bridge.h>
 #include <asm/sn/addrs.h>
 #include <asm/sn/agent.h>
 #include <asm/sn/arch.h>
 
 extern asmlinkage void ip27_irq(void);
 
-extern struct bridge_controller *irq_to_bridge[];
-extern int irq_to_slot[];
-
-/*
- * use these macros to get the encoded nasid and widget id
- * from the irq value
- */
-#define IRQ_TO_BRIDGE(i)               irq_to_bridge[(i)]
-#define SLOT_FROM_PCI_IRQ(i)           irq_to_slot[i]
-
-static inline int alloc_level(int cpu, int irq)
-{
-       struct hub_data *hub = hub_data(cpu_to_node(cpu));
-       struct slice_data *si = cpu_data[cpu].data;
-       int level;
-
-       level = find_first_zero_bit(hub->irq_alloc_mask, LEVELS_PER_SLICE);
-       if (level >= LEVELS_PER_SLICE)
-               panic("Cpu %d flooded with devices", cpu);
-
-       __set_bit(level, hub->irq_alloc_mask);
-       si->level_to_irq[level] = irq;
-
-       return level;
-}
-
-static inline int find_level(cpuid_t *cpunum, int irq)
-{
-       int cpu, i;
-
-       for_each_online_cpu(cpu) {
-               struct slice_data *si = cpu_data[cpu].data;
-
-               for (i = BASE_PCI_IRQ; i < LEVELS_PER_SLICE; i++)
-                       if (si->level_to_irq[i] == irq) {
-                               *cpunum = cpu;
-
-                               return i;
-                       }
-       }
-
-       panic("Could not identify cpu/level for irq %d", irq);
-}
-
 /*
  * Find first bit set
  */
@@ -204,175 +159,6 @@ static void ip27_hub_error(void)
        panic("CPU %d got a hub error interrupt", smp_processor_id());
 }
 
-static int intr_connect_level(int cpu, int bit)
-{
-       nasid_t nasid = COMPACT_TO_NASID_NODEID(cpu_to_node(cpu));
-       struct slice_data *si = cpu_data[cpu].data;
-
-       set_bit(bit, si->irq_enable_mask);
-
-       if (!cputoslice(cpu)) {
-               REMOTE_HUB_S(nasid, PI_INT_MASK0_A, si->irq_enable_mask[0]);
-               REMOTE_HUB_S(nasid, PI_INT_MASK1_A, si->irq_enable_mask[1]);
-       } else {
-               REMOTE_HUB_S(nasid, PI_INT_MASK0_B, si->irq_enable_mask[0]);
-               REMOTE_HUB_S(nasid, PI_INT_MASK1_B, si->irq_enable_mask[1]);
-       }
-
-       return 0;
-}
-
-static int intr_disconnect_level(int cpu, int bit)
-{
-       nasid_t nasid = COMPACT_TO_NASID_NODEID(cpu_to_node(cpu));
-       struct slice_data *si = cpu_data[cpu].data;
-
-       clear_bit(bit, si->irq_enable_mask);
-
-       if (!cputoslice(cpu)) {
-               REMOTE_HUB_S(nasid, PI_INT_MASK0_A, si->irq_enable_mask[0]);
-               REMOTE_HUB_S(nasid, PI_INT_MASK1_A, si->irq_enable_mask[1]);
-       } else {
-               REMOTE_HUB_S(nasid, PI_INT_MASK0_B, si->irq_enable_mask[0]);
-               REMOTE_HUB_S(nasid, PI_INT_MASK1_B, si->irq_enable_mask[1]);
-       }
-
-       return 0;
-}
-
-/* Startup one of the (PCI ...) IRQs routes over a bridge.  */
-static unsigned int startup_bridge_irq(struct irq_data *d)
-{
-       struct bridge_controller *bc;
-       bridgereg_t device;
-       bridge_t *bridge;
-       int pin, swlevel;
-       cpuid_t cpu;
-
-       pin = SLOT_FROM_PCI_IRQ(d->irq);
-       bc = IRQ_TO_BRIDGE(d->irq);
-       bridge = bc->base;
-
-       pr_debug("bridge_startup(): irq= 0x%x  pin=%d\n", d->irq, pin);
-       /*
-        * "map" irq to a swlevel greater than 6 since the first 6 bits
-        * of INT_PEND0 are taken
-        */
-       swlevel = find_level(&cpu, d->irq);
-       bridge->b_int_addr[pin].addr = (0x20000 | swlevel | (bc->nasid << 8));
-       bridge->b_int_enable |= (1 << pin);
-       bridge->b_int_enable |= 0x7ffffe00;     /* more stuff in int_enable */
-
-       /*
-        * Enable sending of an interrupt clear packt to the hub on a high to
-        * low transition of the interrupt pin.
-        *
-        * IRIX sets additional bits in the address which are documented as
-        * reserved in the bridge docs.
-        */
-       bridge->b_int_mode |= (1UL << pin);
-
-       /*
-        * We assume the bridge to have a 1:1 mapping between devices
-        * (slots) and intr pins.
-        */
-       device = bridge->b_int_device;
-       device &= ~(7 << (pin*3));
-       device |= (pin << (pin*3));
-       bridge->b_int_device = device;
-
-       bridge->b_wid_tflush;
-
-       intr_connect_level(cpu, swlevel);
-
-       return 0;       /* Never anything pending.  */
-}
-
-/* Shutdown one of the (PCI ...) IRQs routes over a bridge.  */
-static void shutdown_bridge_irq(struct irq_data *d)
-{
-       struct bridge_controller *bc = IRQ_TO_BRIDGE(d->irq);
-       bridge_t *bridge = bc->base;
-       int pin, swlevel;
-       cpuid_t cpu;
-
-       pr_debug("bridge_shutdown: irq 0x%x\n", d->irq);
-       pin = SLOT_FROM_PCI_IRQ(d->irq);
-
-       /*
-        * map irq to a swlevel greater than 6 since the first 6 bits
-        * of INT_PEND0 are taken
-        */
-       swlevel = find_level(&cpu, d->irq);
-       intr_disconnect_level(cpu, swlevel);
-
-       bridge->b_int_enable &= ~(1 << pin);
-       bridge->b_wid_tflush;
-}
-
-static inline void enable_bridge_irq(struct irq_data *d)
-{
-       cpuid_t cpu;
-       int swlevel;
-
-       swlevel = find_level(&cpu, d->irq);     /* Criminal offence */
-       intr_connect_level(cpu, swlevel);
-}
-
-static inline void disable_bridge_irq(struct irq_data *d)
-{
-       cpuid_t cpu;
-       int swlevel;
-
-       swlevel = find_level(&cpu, d->irq);     /* Criminal offence */
-       intr_disconnect_level(cpu, swlevel);
-}
-
-static struct irq_chip bridge_irq_type = {
-       .name           = "bridge",
-       .irq_startup    = startup_bridge_irq,
-       .irq_shutdown   = shutdown_bridge_irq,
-       .irq_mask       = disable_bridge_irq,
-       .irq_unmask     = enable_bridge_irq,
-};
-
-void register_bridge_irq(unsigned int irq)
-{
-       irq_set_chip_and_handler(irq, &bridge_irq_type, handle_level_irq);
-}
-
-int request_bridge_irq(struct bridge_controller *bc)
-{
-       int irq = allocate_irqno();
-       int swlevel, cpu;
-       nasid_t nasid;
-
-       if (irq < 0)
-               return irq;
-
-       /*
-        * "map" irq to a swlevel greater than 6 since the first 6 bits
-        * of INT_PEND0 are taken
-        */
-       cpu = bc->irq_cpu;
-       swlevel = alloc_level(cpu, irq);
-       if (unlikely(swlevel < 0)) {
-               free_irqno(irq);
-
-               return -EAGAIN;
-       }
-
-       /* Make sure it's not already pending when we connect it. */
-       nasid = COMPACT_TO_NASID_NODEID(cpu_to_node(cpu));
-       REMOTE_HUB_CLR_INTR(nasid, swlevel);
-
-       intr_connect_level(cpu, swlevel);
-
-       register_bridge_irq(irq);
-
-       return irq;
-}
-
 asmlinkage void plat_irq_dispatch(void)
 {
        unsigned long pending = read_c0_cause() & read_c0_status();
index 01cc1a7..5fbd360 100644 (file)
@@ -147,7 +147,8 @@ config SIBYTE_CFE_CONSOLE
 
 config SIBYTE_BUS_WATCHER
        bool "Support for Bus Watcher statistics"
-       depends on SIBYTE_SB1xxx_SOC
+       depends on SIBYTE_SB1xxx_SOC && \
+               (SIBYTE_BCM112X || SIBYTE_SB1250)
        help
          Handle and keep statistics on the bus error interrupts (COR_ECC,
          BAD_ECC, IO_BUS).
index d03a075..af11733 100644 (file)
@@ -13,7 +13,6 @@ cflags-$(CONFIG_SIBYTE_BCM112X) +=                                    \
                -I$(srctree)/arch/mips/include/asm/mach-sibyte          \
                -DSIBYTE_HDR_FEATURES=SIBYTE_HDR_FMASK_1250_112x_ALL
 
-platform-$(CONFIG_SIBYTE_SB1250)       += sibyte/
 cflags-$(CONFIG_SIBYTE_SB1250) +=                                      \
                -I$(srctree)/arch/mips/include/asm/mach-sibyte          \
                -DSIBYTE_HDR_FEATURES=SIBYTE_HDR_FMASK_1250_112x_ALL
@@ -31,7 +30,8 @@ cflags-$(CONFIG_SIBYTE_BCM1x80) +=                                    \
 # Sibyte BCM91120C (CRhine) board
 # Sibyte BCM91125C (CRhone) board
 # Sibyte BCM91125E (Rhone) board
-# Sibyte SWARM board
+# Sibyte BCM91250A (SWARM) board
+# Sibyte BCM91250C2 (LittleSur) board
 # Sibyte BCM91x80 (BigSur) board
 #
 load-$(CONFIG_SIBYTE_CARMEL)   := 0xffffffff80100000
@@ -41,3 +41,4 @@ load-$(CONFIG_SIBYTE_RHONE)   := 0xffffffff80100000
 load-$(CONFIG_SIBYTE_SENTOSA)  := 0xffffffff80100000
 load-$(CONFIG_SIBYTE_SWARM)    := 0xffffffff80100000
 load-$(CONFIG_SIBYTE_BIGSUR)   := 0xffffffff80100000
+load-$(CONFIG_SIBYTE_LITTLESUR) := 0xffffffff80100000
index 36aa700..b3d6bf2 100644 (file)
@@ -1,3 +1,4 @@
 obj-y := cfe.o
+obj-$(CONFIG_SIBYTE_BUS_WATCHER)       += bus_watcher.o
 obj-$(CONFIG_SIBYTE_CFE_CONSOLE)       += cfe_console.o
 obj-$(CONFIG_SIBYTE_TBPROF)            += sb_tbprof.o
similarity index 94%
rename from arch/mips/sibyte/sb1250/bus_watcher.c
rename to arch/mips/sibyte/common/bus_watcher.c
index 8871e33..5581844 100644 (file)
@@ -37,6 +37,9 @@
 #include <asm/sibyte/sb1250_regs.h>
 #include <asm/sibyte/sb1250_int.h>
 #include <asm/sibyte/sb1250_scd.h>
+#if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80)
+#include <asm/sibyte/bcm1480_regs.h>
+#endif
 
 
 struct bw_stats_struct {
@@ -81,9 +84,15 @@ void check_bus_watcher(void)
 #ifdef CONFIG_SB1_PASS_1_WORKAROUNDS
        /* Destructive read, clears register and interrupt */
        status = csr_in32(IOADDR(A_SCD_BUS_ERR_STATUS));
-#else
+#elif defined(CONFIG_SIBYTE_BCM112X) || defined(CONFIG_SIBYTE_SB1250)
        /* Use non-destructive register */
        status = csr_in32(IOADDR(A_SCD_BUS_ERR_STATUS_DEBUG));
+#elif defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80)
+       /* Use non-destructive register */
+       /* Same as 1250 except BUS_ERR_STATUS_DEBUG is in a different place. */
+       status = csr_in32(IOADDR(A_BCM1480_BUS_ERR_STATUS_DEBUG));
+#else
+#error bus watcher being built for unknown Sibyte SOC!
 #endif
        if (!(status & 0x7fffffff)) {
                printk("Using last values reaped by bus watcher driver\n");
@@ -175,9 +184,6 @@ static irqreturn_t sibyte_bw_int(int irq, void *data)
 #ifdef CONFIG_SIBYTE_BW_TRACE
        int i;
 #endif
-#ifndef CONFIG_PROC_FS
-       char bw_buf[1024];
-#endif
 
 #ifdef CONFIG_SIBYTE_BW_TRACE
        csr_out32(M_SCD_TRACE_CFG_FREEZE, IOADDR(A_SCD_TRACE_CFG));
index 2188b39..059e28c 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/types.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
+#include <linux/sched.h>
 #include <linux/vmalloc.h>
 #include <linux/fs.h>
 #include <linux/errno.h>
index d3d969d..cdc4c56 100644 (file)
@@ -1,4 +1,3 @@
 obj-y := setup.o irq.o time.o
 
 obj-$(CONFIG_SMP)                      += smp.o
-obj-$(CONFIG_SIBYTE_BUS_WATCHER)       += bus_watcher.o
index cec4b8c..12336c2 100644 (file)
@@ -185,6 +185,7 @@ static void __init sni_pcimt_resource_init(void)
 
 extern struct pci_ops sni_pcimt_ops;
 
+#ifdef CONFIG_PCI
 static struct pci_controller sni_controller = {
        .pci_ops        = &sni_pcimt_ops,
        .mem_resource   = &sni_mem_resource,
@@ -193,6 +194,7 @@ static struct pci_controller sni_controller = {
        .io_offset      = 0x00000000UL,
        .io_map_base    = SNI_PORT_BASE
 };
+#endif
 
 static void enable_pcimt_irq(struct irq_data *d)
 {
index 7cddd03..05bb516 100644 (file)
@@ -128,13 +128,6 @@ static struct resource pcit_io_resources[] = {
        }
 };
 
-static struct resource sni_mem_resource = {
-       .start  = 0x18000000UL,
-       .end    = 0x1fbfffffUL,
-       .name   = "PCIT PCI MEM",
-       .flags  = IORESOURCE_MEM
-};
-
 static void __init sni_pcit_resource_init(void)
 {
        int i;
@@ -147,6 +140,14 @@ static void __init sni_pcit_resource_init(void)
 
 extern struct pci_ops sni_pcit_ops;
 
+#ifdef CONFIG_PCI
+static struct resource sni_mem_resource = {
+       .start  = 0x18000000UL,
+       .end    = 0x1fbfffffUL,
+       .name   = "PCIT PCI MEM",
+       .flags  = IORESOURCE_MEM
+};
+
 static struct pci_controller sni_pcit_controller = {
        .pci_ops        = &sni_pcit_ops,
        .mem_resource   = &sni_mem_resource,
@@ -155,6 +156,7 @@ static struct pci_controller sni_pcit_controller = {
        .io_offset      = 0x00000000UL,
        .io_map_base    = SNI_PORT_BASE
 };
+#endif /* CONFIG_PCI */
 
 static void enable_pcit_irq(struct irq_data *d)
 {
diff --git a/arch/mips/wrppmc/Makefile b/arch/mips/wrppmc/Makefile
deleted file mode 100644 (file)
index 307cc69..0000000
+++ /dev/null
@@ -1,12 +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 2006 Wind River System, Inc.
-# Author: Rongkai.Zhan <rongkai.zhan@windriver.com>
-#
-# Makefile for the Wind River MIPS 4Kc PPMC Eval Board
-#
-
-obj-y += irq.o pci.o reset.o serial.o setup.o time.o
diff --git a/arch/mips/wrppmc/Platform b/arch/mips/wrppmc/Platform
deleted file mode 100644 (file)
index dc78b25..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-#
-# Wind River PPMC Board (4KC + GT64120)
-#
-platform-$(CONFIG_WR_PPMC)     += wrppmc/
-cflags-$(CONFIG_WR_PPMC)       +=                                      \
-               -I$(srctree)/arch/mips/include/asm/mach-wrppmc
-load-$(CONFIG_WR_PPMC)         += 0xffffffff80100000
diff --git a/arch/mips/wrppmc/irq.c b/arch/mips/wrppmc/irq.c
deleted file mode 100644 (file)
index f237bf4..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * irq.c: GT64120 Interrupt Controller
- *
- * Copyright (C) 2006, Wind River System Inc.
- * Author: Rongkai.Zhan, <rongkai.zhan@windriver.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/hardirq.h>
-#include <linux/init.h>
-#include <linux/irq.h>
-
-#include <asm/gt64120.h>
-#include <asm/irq_cpu.h>
-#include <asm/mipsregs.h>
-
-asmlinkage void plat_irq_dispatch(void)
-{
-       unsigned int pending = read_c0_status() & read_c0_cause() & ST0_IM;
-
-       if (pending & STATUSF_IP7)
-               do_IRQ(WRPPMC_MIPS_TIMER_IRQ);  /* CPU Compare/Count internal timer */
-       else if (pending & STATUSF_IP6)
-               do_IRQ(WRPPMC_UART16550_IRQ);   /* UART 16550 port */
-       else if (pending & STATUSF_IP3)
-               do_IRQ(WRPPMC_PCI_INTA_IRQ);    /* PCI INT_A */
-       else
-               spurious_interrupt();
-}
-
-/**
- * Initialize GT64120 Interrupt Controller
- */
-void gt64120_init_pic(void)
-{
-       /* clear CPU Interrupt Cause Registers */
-       GT_WRITE(GT_INTRCAUSE_OFS, (0x1F << 21));
-       GT_WRITE(GT_HINTRCAUSE_OFS, 0x00);
-
-       /* Disable all interrupts from GT64120 bridge chip */
-       GT_WRITE(GT_INTRMASK_OFS, 0x00);
-       GT_WRITE(GT_HINTRMASK_OFS, 0x00);
-       GT_WRITE(GT_PCI0_ICMASK_OFS, 0x00);
-       GT_WRITE(GT_PCI0_HICMASK_OFS, 0x00);
-}
-
-void __init arch_init_irq(void)
-{
-       /* IRQ 0 - 7 are for MIPS common irq_cpu controller */
-       mips_cpu_irq_init();
-
-       gt64120_init_pic();
-}
diff --git a/arch/mips/wrppmc/pci.c b/arch/mips/wrppmc/pci.c
deleted file mode 100644 (file)
index 8b8a0e1..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * pci.c: GT64120 PCI support.
- *
- * Copyright (C) 2006, Wind River System Inc. Rongkai.Zhan <rongkai.zhan@windriver.com>
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-#include <linux/init.h>
-#include <linux/ioport.h>
-#include <linux/types.h>
-#include <linux/pci.h>
-
-#include <asm/gt64120.h>
-
-extern struct pci_ops gt64xxx_pci0_ops;
-
-static struct resource pci0_io_resource = {
-       .name  = "pci_0 io",
-       .start = GT_PCI_IO_BASE,
-       .end   = GT_PCI_IO_BASE + GT_PCI_IO_SIZE - 1,
-       .flags = IORESOURCE_IO,
-};
-
-static struct resource pci0_mem_resource = {
-       .name  = "pci_0 memory",
-       .start = GT_PCI_MEM_BASE,
-       .end   = GT_PCI_MEM_BASE + GT_PCI_MEM_SIZE - 1,
-       .flags = IORESOURCE_MEM,
-};
-
-static struct pci_controller hose_0 = {
-       .pci_ops        = &gt64xxx_pci0_ops,
-       .io_resource    = &pci0_io_resource,
-       .mem_resource   = &pci0_mem_resource,
-};
-
-static int __init gt64120_pci_init(void)
-{
-       (void) GT_READ(GT_PCI0_CMD_OFS);        /* Huh??? -- Ralf  */
-       (void) GT_READ(GT_PCI0_BARE_OFS);
-
-       /* reset the whole PCI I/O space range */
-       ioport_resource.start = GT_PCI_IO_BASE;
-       ioport_resource.end = GT_PCI_IO_BASE + GT_PCI_IO_SIZE - 1;
-
-       register_pci_controller(&hose_0);
-       return 0;
-}
-
-arch_initcall(gt64120_pci_init);
diff --git a/arch/mips/wrppmc/reset.c b/arch/mips/wrppmc/reset.c
deleted file mode 100644 (file)
index 80beb18..0000000
+++ /dev/null
@@ -1,41 +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) 1997 Ralf Baechle
- */
-#include <linux/irqflags.h>
-#include <linux/kernel.h>
-
-#include <asm/cacheflush.h>
-#include <asm/idle.h>
-#include <asm/mipsregs.h>
-#include <asm/processor.h>
-
-void wrppmc_machine_restart(char *command)
-{
-       /*
-        * Ouch, we're still alive ... This time we take the silver bullet ...
-        * ... and find that we leave the hardware in a state in which the
-        * kernel in the flush locks up somewhen during of after the PCI
-        * detection stuff.
-        */
-       local_irq_disable();
-       set_c0_status(ST0_BEV | ST0_ERL);
-       change_c0_config(CONF_CM_CMASK, CONF_CM_UNCACHED);
-       flush_cache_all();
-       write_c0_wired(0);
-       __asm__ __volatile__("jr\t%0"::"r"(0xbfc00000));
-}
-
-void wrppmc_machine_halt(void)
-{
-       local_irq_disable();
-
-       printk(KERN_NOTICE "You can safely turn off the power\n");
-       while (1) {
-               if (cpu_wait)
-                       cpu_wait();
-       }
-}
diff --git a/arch/mips/wrppmc/serial.c b/arch/mips/wrppmc/serial.c
deleted file mode 100644 (file)
index 83f0f7d..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- *  Registration of WRPPMC UART platform device.
- *
- *  Copyright (C) 2007 Yoichi Yuasa <yuasa@linux-mips.org>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- */
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/ioport.h>
-#include <linux/platform_device.h>
-#include <linux/serial_8250.h>
-
-#include <asm/gt64120.h>
-
-static struct resource wrppmc_uart_resource[] __initdata = {
-       {
-               .start  = WRPPMC_UART16550_BASE,
-               .end    = WRPPMC_UART16550_BASE + 7,
-               .flags  = IORESOURCE_MEM,
-       },
-       {
-               .start  = WRPPMC_UART16550_IRQ,
-               .end    = WRPPMC_UART16550_IRQ,
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-static struct plat_serial8250_port wrppmc_serial8250_port[] = {
-       {
-               .irq            = WRPPMC_UART16550_IRQ,
-               .uartclk        = WRPPMC_UART16550_CLOCK,
-               .iotype         = UPIO_MEM,
-               .flags          = UPF_IOREMAP | UPF_SKIP_TEST,
-               .mapbase        = WRPPMC_UART16550_BASE,
-       },
-       {},
-};
-
-static __init int wrppmc_uart_add(void)
-{
-       struct platform_device *pdev;
-       int retval;
-
-       pdev = platform_device_alloc("serial8250", -1);
-       if (!pdev)
-               return -ENOMEM;
-
-       pdev->id = PLAT8250_DEV_PLATFORM;
-       pdev->dev.platform_data = wrppmc_serial8250_port;
-
-       retval = platform_device_add_resources(pdev, wrppmc_uart_resource,
-                                       ARRAY_SIZE(wrppmc_uart_resource));
-       if (retval)
-               goto err_free_device;
-
-       retval = platform_device_add(pdev);
-       if (retval)
-               goto err_free_device;
-
-       return 0;
-
-err_free_device:
-       platform_device_put(pdev);
-
-       return retval;
-}
-device_initcall(wrppmc_uart_add);
diff --git a/arch/mips/wrppmc/setup.c b/arch/mips/wrppmc/setup.c
deleted file mode 100644 (file)
index ca65c84..0000000
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * setup.c: Setup pointers to hardware dependent routines.
- *
- * 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) 1996, 1997, 2004 by Ralf Baechle (ralf@linux-mips.org)
- * Copyright (C) 2006, Wind River System Inc. Rongkai.zhan <rongkai.zhan@windriver.com>
- */
-#include <linux/init.h>
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/pm.h>
-
-#include <asm/io.h>
-#include <asm/bootinfo.h>
-#include <asm/reboot.h>
-#include <asm/time.h>
-#include <asm/gt64120.h>
-
-unsigned long gt64120_base = KSEG1ADDR(0x14000000);
-
-#ifdef WRPPMC_EARLY_DEBUG
-
-static volatile unsigned char * wrppmc_led = \
-       (volatile unsigned char *)KSEG1ADDR(WRPPMC_LED_BASE);
-
-/*
- * PPMC LED control register:
- * -) bit[0] controls DS1 LED (1 - OFF, 0 - ON)
- * -) bit[1] controls DS2 LED (1 - OFF, 0 - ON)
- * -) bit[2] controls DS4 LED (1 - OFF, 0 - ON)
- */
-void wrppmc_led_on(int mask)
-{
-       unsigned char value = *wrppmc_led;
-
-       value &= (0xF8 | mask);
-       *wrppmc_led = value;
-}
-
-/* If mask = 0, turn off all LEDs */
-void wrppmc_led_off(int mask)
-{
-       unsigned char value = *wrppmc_led;
-
-       value |= (0x7 & mask);
-       *wrppmc_led = value;
-}
-
-/*
- * We assume that bootloader has initialized UART16550 correctly
- */
-void __init wrppmc_early_putc(char ch)
-{
-       static volatile unsigned char *wrppmc_uart = \
-               (volatile unsigned char *)KSEG1ADDR(WRPPMC_UART16550_BASE);
-       unsigned char value;
-
-       /* Wait until Transmit-Holding-Register is empty */
-       while (1) {
-               value = *(wrppmc_uart + 5);
-               if (value & 0x20)
-                       break;
-       }
-
-       *wrppmc_uart = ch;
-}
-
-void __init wrppmc_early_printk(const char *fmt, ...)
-{
-       static char pbuf[256] = {'\0', };
-       char *ch = pbuf;
-       va_list args;
-       unsigned int i;
-
-       memset(pbuf, 0, 256);
-       va_start(args, fmt);
-       i = vsprintf(pbuf, fmt, args);
-       va_end(args);
-
-       /* Print the string */
-       while (*ch != '\0') {
-               wrppmc_early_putc(*ch);
-               /* if print '\n', also print '\r' */
-               if (*ch++ == '\n')
-                       wrppmc_early_putc('\r');
-       }
-}
-#endif /* WRPPMC_EARLY_DEBUG */
-
-void __init prom_free_prom_memory(void)
-{
-}
-
-void __init plat_mem_setup(void)
-{
-       extern void wrppmc_machine_restart(char *command);
-       extern void wrppmc_machine_halt(void);
-
-       _machine_restart = wrppmc_machine_restart;
-       _machine_halt    = wrppmc_machine_halt;
-       pm_power_off     = wrppmc_machine_halt;
-
-       /* This makes the operations of 'in/out[bwl]' to the
-        * physical address ( < KSEG0) can work via KSEG1
-        */
-       set_io_port_base(KSEG1);
-}
-
-const char *get_system_type(void)
-{
-       return "Wind River PPMC (GT64120)";
-}
-
-/*
- * Initializes basic routines and structures pointers, memory size (as
- * given by the bios and saves the command line.
- */
-void __init prom_init(void)
-{
-       add_memory_region(WRPPMC_SDRAM_SCS0_BASE, WRPPMC_SDRAM_SCS0_SIZE, BOOT_MEM_RAM);
-       add_memory_region(WRPPMC_BOOTROM_BASE, WRPPMC_BOOTROM_SIZE, BOOT_MEM_ROM_DATA);
-
-       wrppmc_early_printk("prom_init: GT64120 SDRAM Bank 0: 0x%x - 0x%08lx\n",
-                       WRPPMC_SDRAM_SCS0_BASE, (WRPPMC_SDRAM_SCS0_BASE + WRPPMC_SDRAM_SCS0_SIZE));
-}
diff --git a/arch/mips/wrppmc/time.c b/arch/mips/wrppmc/time.c
deleted file mode 100644 (file)
index 668dbd5..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * time.c: MIPS CPU Count/Compare timer hookup
- *
- * Author: Mark.Zhan, <rongkai.zhan@windriver.com>
- *
- * 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) 1996, 1997, 2004 by Ralf Baechle (ralf@linux-mips.org)
- * Copyright (C) 2006, Wind River System Inc.
- */
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-
-#include <asm/gt64120.h>
-#include <asm/time.h>
-
-#define WRPPMC_CPU_CLK_FREQ 40000000 /* 40MHZ */
-
-/*
- * Estimate CPU frequency.  Sets mips_hpt_frequency as a side-effect
- *
- * NOTE: We disable all GT64120 timers, and use MIPS processor internal
- * timer as the source of kernel clock tick.
- */
-void __init plat_time_init(void)
-{
-       /* Disable GT64120 timers */
-       GT_WRITE(GT_TC_CONTROL_OFS, 0x00);
-       GT_WRITE(GT_TC0_OFS, 0x00);
-       GT_WRITE(GT_TC1_OFS, 0x00);
-       GT_WRITE(GT_TC2_OFS, 0x00);
-       GT_WRITE(GT_TC3_OFS, 0x00);
-
-       /* Use MIPS compare/count internal timer */
-       mips_hpt_frequency = WRPPMC_CPU_CLK_FREQ;
-}
index db80fd3..e2a2b20 100644 (file)
@@ -74,6 +74,6 @@
 
 #define SO_SELECT_ERR_QUEUE    45
 
-#define SO_LL                  46
+#define SO_BUSY_POLL           46
 
 #endif /* _ASM_SOCKET_H */
index 96ec398..e02f665 100644 (file)
@@ -17,6 +17,8 @@
 # Mike Shaver, Helge Deller and Martin K. Petersen
 #
 
+KBUILD_IMAGE := vmlinuz
+
 KBUILD_DEFCONFIG := default_defconfig
 
 NM             = sh $(srctree)/arch/parisc/nm
@@ -92,7 +94,7 @@ PALOCONF := $(shell if [ -f $(src)/palo.conf ]; then echo $(src)/palo.conf; \
        else echo $(obj)/palo.conf; \
        fi)
 
-palo: vmlinux
+palo: vmlinuz
        @if test ! -x "$(PALO)"; then \
                echo 'ERROR: Please install palo first (apt-get install palo)';\
                echo 'or build it from source and install it somewhere in your $$PATH';\
@@ -107,10 +109,14 @@ palo: vmlinux
        fi
        $(PALO) -f $(PALOCONF)
 
-# Shorthands for known targets not supported by parisc, use vmlinux as default
-Image zImage bzImage: vmlinux
+# Shorthands for known targets not supported by parisc, use vmlinux/vmlinuz as default
+Image: vmlinux
+zImage bzImage: vmlinuz
+
+vmlinuz: vmlinux
+       @gzip -cf -9 $< > $@
 
-install: vmlinux
+install: vmlinuz
        sh $(src)/arch/parisc/install.sh \
                        $(KERNELRELEASE) $< System.map "$(INSTALL_PATH)"
 
@@ -119,6 +125,7 @@ MRPROPER_FILES      += palo.conf
 
 define archhelp
        @echo  '* vmlinux       - Uncompressed kernel image (./vmlinux)'
+       @echo  '  vmlinuz       - Compressed kernel image (./vmlinuz)'
        @echo  '  palo          - Bootable image (./lifimage)'
        @echo  '  install       - Install kernel using'
        @echo  '                  (your) ~/bin/$(INSTALLKERNEL) or'
index 4e1ae25..208ff3b 100644 (file)
@@ -4,7 +4,7 @@
 # Most people using 'make palo' want a bootable file, usable for
 # network or tape booting for example.
 --init-tape=lifimage
---recoverykernel=vmlinux
+--recoverykernel=vmlinuz
 
 ########## Pick your ROOT here! ##########
 # You need at least one 'root='!
 # If you want a root ramdisk, use the next 2 lines
 #   (Edit the ramdisk image name!!!!)
 --ramdisk=ram-disk-image-file
---commandline=0/vmlinux HOME=/ root=/dev/ram initrd=0/ramdisk
+--commandline=0/vmlinuz HOME=/ root=/dev/ram initrd=0/ramdisk panic_timeout=60 panic=-1
 
 # If you want NFS root, use the following command line (Edit the HOSTNAME!!!)
-#--commandline=0/vmlinux HOME=/ root=/dev/nfs nfsroot=HOSTNAME ip=bootp
+#--commandline=0/vmlinuz HOME=/ root=/dev/nfs nfsroot=HOSTNAME ip=bootp
 
 # If you have root on a disk partition, use this (Edit the partition name!!!)
-#--commandline=0/vmlinux HOME=/ root=/dev/sda1
+#--commandline=0/vmlinuz HOME=/ root=/dev/sda1
index d306b75..e150930 100644 (file)
@@ -32,9 +32,12 @@ static inline void set_eiem(unsigned long val)
        cr;                             \
 })
 
-#define mtsp(gr, cr) \
-       __asm__ __volatile__("mtsp %0,%1" \
+#define mtsp(val, cr) \
+       { if (__builtin_constant_p(val) && ((val) == 0)) \
+        __asm__ __volatile__("mtsp %%r0,%0" : : "i" (cr) : "memory"); \
+       else \
+        __asm__ __volatile__("mtsp %0,%1" \
                : /* no outputs */ \
-               : "r" (gr), "i" (cr) : "memory")
+               : "r" (val), "i" (cr) : "memory"); }
 
 #endif /* __PARISC_SPECIAL_INSNS_H */
index 5273da9..9d086a5 100644 (file)
@@ -63,13 +63,14 @@ static inline void flush_tlb_mm(struct mm_struct *mm)
 static inline void flush_tlb_page(struct vm_area_struct *vma,
        unsigned long addr)
 {
-       unsigned long flags;
+       unsigned long flags, sid;
 
        /* For one page, it's not worth testing the split_tlb variable */
 
        mb();
-       mtsp(vma->vm_mm->context,1);
+       sid = vma->vm_mm->context;
        purge_tlb_start(flags);
+       mtsp(sid, 1);
        pdtlb(addr);
        pitlb(addr);
        purge_tlb_end(flags);
index cc61c47..34a46cb 100644 (file)
@@ -20,7 +20,7 @@
 #define O_INVISIBLE    004000000 /* invisible I/O, for DMAPI/XDSM */
 
 #define O_PATH         020000000
-#define O_TMPFILE      040000000
+#define __O_TMPFILE    040000000
 
 #define F_GETLK64      8
 #define F_SETLK64      9
index f866fff..71700e6 100644 (file)
@@ -73,7 +73,7 @@
 
 #define SO_SELECT_ERR_QUEUE    0x4026
 
-#define SO_LL                  0x4027
+#define SO_BUSY_POLL           0x4027
 
 /* O_NONBLOCK clashes with the bits used for socket types.  Therefore we
  * have to define SOCK_NONBLOCK to a different value here.
index e593fc8..4da682b 100644 (file)
@@ -26,13 +26,13 @@ if [ -x /sbin/${INSTALLKERNEL} ]; then exec /sbin/${INSTALLKERNEL} "$@"; fi
 
 # Default install
 
-if [ -f $4/vmlinux ]; then
-       mv $4/vmlinux $4/vmlinux.old
+if [ -f $4/vmlinuz ]; then
+       mv $4/vmlinuz $4/vmlinuz.old
 fi
 
 if [ -f $4/System.map ]; then
        mv $4/System.map $4/System.old
 fi
 
-cat $2 > $4/vmlinux
+cat $2 > $4/vmlinuz
 cp $3 $4/System.map
index 65fb4cb..2e65aa5 100644 (file)
@@ -440,8 +440,8 @@ void __flush_tlb_range(unsigned long sid, unsigned long start,
        else {
                unsigned long flags;
 
-               mtsp(sid, 1);
                purge_tlb_start(flags);
+               mtsp(sid, 1);
                if (split_tlb) {
                        while (npages--) {
                                pdtlb(start);
index c8fb61e..8a96c8a 100644 (file)
@@ -371,10 +371,23 @@ show_cpuinfo (struct seq_file *m, void *v)
 
                seq_printf(m, "capabilities\t:");
                if (boot_cpu_data.pdc.capabilities & PDC_MODEL_OS32)
-                       seq_printf(m, " os32");
+                       seq_puts(m, " os32");
                if (boot_cpu_data.pdc.capabilities & PDC_MODEL_OS64)
-                       seq_printf(m, " os64");
-               seq_printf(m, "\n");
+                       seq_puts(m, " os64");
+               if (boot_cpu_data.pdc.capabilities & PDC_MODEL_IOPDIR_FDC)
+                       seq_puts(m, " iopdir_fdc");
+               switch (boot_cpu_data.pdc.capabilities & PDC_MODEL_NVA_MASK) {
+               case PDC_MODEL_NVA_SUPPORTED:
+                       seq_puts(m, " nva_supported");
+                       break;
+               case PDC_MODEL_NVA_SLOW:
+                       seq_puts(m, " nva_slow");
+                       break;
+               case PDC_MODEL_NVA_UNSUPPORTED:
+                       seq_puts(m, " needs_equivalent_aliasing");
+                       break;
+               }
+               seq_printf(m, " (0x%02lx)\n", boot_cpu_data.pdc.capabilities);
 
                seq_printf(m, "model\t\t: %s\n"
                                "model name\t: %s\n",
index a49cc81..ac4370b 100644 (file)
@@ -2,6 +2,7 @@
  *    Optimized memory copy routines.
  *
  *    Copyright (C) 2004 Randolph Chung <tausq@debian.org>
+ *    Copyright (C) 2013 Helge Deller <deller@gmx.de>
  *
  *    This program is free software; you can redistribute it and/or modify
  *    it under the terms of the GNU General Public License as published by
@@ -153,17 +154,21 @@ static inline void prefetch_dst(const void *addr)
 #define prefetch_dst(addr) do { } while(0)
 #endif
 
+#define PA_MEMCPY_OK           0
+#define PA_MEMCPY_LOAD_ERROR   1
+#define PA_MEMCPY_STORE_ERROR  2
+
 /* Copy from a not-aligned src to an aligned dst, using shifts. Handles 4 words
  * per loop.  This code is derived from glibc. 
  */
-static inline unsigned long copy_dstaligned(unsigned long dst, unsigned long src, unsigned long len, unsigned long o_dst, unsigned long o_src, unsigned long o_len)
+static inline unsigned long copy_dstaligned(unsigned long dst,
+                                       unsigned long src, unsigned long len)
 {
        /* gcc complains that a2 and a3 may be uninitialized, but actually
         * they cannot be.  Initialize a2/a3 to shut gcc up.
         */
        register unsigned int a0, a1, a2 = 0, a3 = 0;
        int sh_1, sh_2;
-       struct exception_data *d;
 
        /* prefetch_src((const void *)src); */
 
@@ -197,7 +202,7 @@ static inline unsigned long copy_dstaligned(unsigned long dst, unsigned long src
                        goto do2;
                case 0:
                        if (len == 0)
-                               return 0;
+                               return PA_MEMCPY_OK;
                        /* a3 = ((unsigned int *) src)[0];
                           a0 = ((unsigned int *) src)[1]; */
                        ldw(s_space, 0, src, a3, cda_ldw_exc);
@@ -256,42 +261,35 @@ do0:
        preserve_branch(handle_load_error);
        preserve_branch(handle_store_error);
 
-       return 0;
+       return PA_MEMCPY_OK;
 
 handle_load_error:
        __asm__ __volatile__ ("cda_ldw_exc:\n");
-       d = &__get_cpu_var(exception_data);
-       DPRINTF("cda_ldw_exc: o_len=%lu fault_addr=%lu o_src=%lu ret=%lu\n",
-               o_len, d->fault_addr, o_src, o_len - d->fault_addr + o_src);
-       return o_len * 4 - d->fault_addr + o_src;
+       return PA_MEMCPY_LOAD_ERROR;
 
 handle_store_error:
        __asm__ __volatile__ ("cda_stw_exc:\n");
-       d = &__get_cpu_var(exception_data);
-       DPRINTF("cda_stw_exc: o_len=%lu fault_addr=%lu o_dst=%lu ret=%lu\n",
-               o_len, d->fault_addr, o_dst, o_len - d->fault_addr + o_dst);
-       return o_len * 4 - d->fault_addr + o_dst;
+       return PA_MEMCPY_STORE_ERROR;
 }
 
 
-/* Returns 0 for success, otherwise, returns number of bytes not transferred. */
-static unsigned long pa_memcpy(void *dstp, const void *srcp, unsigned long len)
+/* Returns PA_MEMCPY_OK, PA_MEMCPY_LOAD_ERROR or PA_MEMCPY_STORE_ERROR.
+ * In case of an access fault the faulty address can be read from the per_cpu
+ * exception data struct. */
+static unsigned long pa_memcpy_internal(void *dstp, const void *srcp,
+                                       unsigned long len)
 {
        register unsigned long src, dst, t1, t2, t3;
        register unsigned char *pcs, *pcd;
        register unsigned int *pws, *pwd;
        register double *pds, *pdd;
-       unsigned long ret = 0;
-       unsigned long o_dst, o_src, o_len;
-       struct exception_data *d;
+       unsigned long ret;
 
        src = (unsigned long)srcp;
        dst = (unsigned long)dstp;
        pcs = (unsigned char *)srcp;
        pcd = (unsigned char *)dstp;
 
-       o_dst = dst; o_src = src; o_len = len;
-
        /* prefetch_src((const void *)srcp); */
 
        if (len < THRESHOLD)
@@ -401,7 +399,7 @@ byte_copy:
                len--;
        }
 
-       return 0;
+       return PA_MEMCPY_OK;
 
 unaligned_copy:
        /* possibly we are aligned on a word, but not on a double... */
@@ -438,8 +436,7 @@ unaligned_copy:
                src = (unsigned long)pcs;
        }
 
-       ret = copy_dstaligned(dst, src, len / sizeof(unsigned int), 
-               o_dst, o_src, o_len);
+       ret = copy_dstaligned(dst, src, len / sizeof(unsigned int));
        if (ret)
                return ret;
 
@@ -454,17 +451,41 @@ unaligned_copy:
 
 handle_load_error:
        __asm__ __volatile__ ("pmc_load_exc:\n");
-       d = &__get_cpu_var(exception_data);
-       DPRINTF("pmc_load_exc: o_len=%lu fault_addr=%lu o_src=%lu ret=%lu\n",
-               o_len, d->fault_addr, o_src, o_len - d->fault_addr + o_src);
-       return o_len - d->fault_addr + o_src;
+       return PA_MEMCPY_LOAD_ERROR;
 
 handle_store_error:
        __asm__ __volatile__ ("pmc_store_exc:\n");
+       return PA_MEMCPY_STORE_ERROR;
+}
+
+
+/* Returns 0 for success, otherwise, returns number of bytes not transferred. */
+static unsigned long pa_memcpy(void *dstp, const void *srcp, unsigned long len)
+{
+       unsigned long ret, fault_addr, reference;
+       struct exception_data *d;
+
+       ret = pa_memcpy_internal(dstp, srcp, len);
+       if (likely(ret == PA_MEMCPY_OK))
+               return 0;
+
+       /* if a load or store fault occured we can get the faulty addr */
        d = &__get_cpu_var(exception_data);
-       DPRINTF("pmc_store_exc: o_len=%lu fault_addr=%lu o_dst=%lu ret=%lu\n",
-               o_len, d->fault_addr, o_dst, o_len - d->fault_addr + o_dst);
-       return o_len - d->fault_addr + o_dst;
+       fault_addr = d->fault_addr;
+
+       /* error in load or store? */
+       if (ret == PA_MEMCPY_LOAD_ERROR)
+               reference = (unsigned long) srcp;
+       else
+               reference = (unsigned long) dstp;
+
+       DPRINTF("pa_memcpy: fault type = %lu, len=%lu fault_addr=%lu ref=%lu\n",
+               ret, len, fault_addr, reference);
+
+       if (fault_addr >= reference)
+               return len - (fault_addr - reference);
+       else
+               return len;
 }
 
 #ifdef __KERNEL__
index 405fb09..a6d7446 100644 (file)
@@ -81,6 +81,6 @@
 
 #define SO_SELECT_ERR_QUEUE    45
 
-#define SO_LL                  46
+#define SO_BUSY_POLL           46
 
 #endif /* _ASM_POWERPC_SOCKET_H */
index 67a42ed..cb8bdbe 100644 (file)
@@ -92,10 +92,8 @@ void arch_pick_mmap_layout(struct mm_struct *mm)
        if (mmap_is_legacy()) {
                mm->mmap_base = TASK_UNMAPPED_BASE;
                mm->get_unmapped_area = arch_get_unmapped_area;
-               mm->unmap_area = arch_unmap_area;
        } else {
                mm->mmap_base = mmap_base();
                mm->get_unmapped_area = arch_get_unmapped_area_topdown;
-               mm->unmap_area = arch_unmap_area_topdown;
        }
 }
index 13c3f0e..d1821b8 100644 (file)
@@ -60,7 +60,7 @@
 #define        PME_PM_LD_REF_L1                0xc880
 #define        PME_PM_LD_MISS_L1               0x400f0
 #define        PME_PM_BRU_FIN                  0x10068
-#define        PME_PM_BRU_MPRED                0x400f6
+#define        PME_PM_BR_MPRED                 0x400f6
 
 #define PME_PM_CMPLU_STALL_FXU                 0x20014
 #define PME_PM_CMPLU_STALL_DIV                 0x40014
@@ -349,7 +349,7 @@ static int power7_generic_events[] = {
        [PERF_COUNT_HW_CACHE_REFERENCES] =              PME_PM_LD_REF_L1,
        [PERF_COUNT_HW_CACHE_MISSES] =                  PME_PM_LD_MISS_L1,
        [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] =           PME_PM_BRU_FIN,
-       [PERF_COUNT_HW_BRANCH_MISSES] =                 PME_PM_BRU_MPRED,
+       [PERF_COUNT_HW_BRANCH_MISSES] =                 PME_PM_BR_MPRED,
 };
 
 #define C(x)   PERF_COUNT_HW_CACHE_##x
@@ -405,7 +405,7 @@ GENERIC_EVENT_ATTR(instructions,            INST_CMPL);
 GENERIC_EVENT_ATTR(cache-references,           LD_REF_L1);
 GENERIC_EVENT_ATTR(cache-misses,               LD_MISS_L1);
 GENERIC_EVENT_ATTR(branch-instructions,                BRU_FIN);
-GENERIC_EVENT_ATTR(branch-misses,              BRU_MPRED);
+GENERIC_EVENT_ATTR(branch-misses,              BR_MPRED);
 
 POWER_EVENT_ATTR(CYC,                          CYC);
 POWER_EVENT_ATTR(GCT_NOSLOT_CYC,               GCT_NOSLOT_CYC);
@@ -414,7 +414,7 @@ POWER_EVENT_ATTR(INST_CMPL,                 INST_CMPL);
 POWER_EVENT_ATTR(LD_REF_L1,                    LD_REF_L1);
 POWER_EVENT_ATTR(LD_MISS_L1,                   LD_MISS_L1);
 POWER_EVENT_ATTR(BRU_FIN,                      BRU_FIN)
-POWER_EVENT_ATTR(BRU_MPRED,                    BRU_MPRED);
+POWER_EVENT_ATTR(BR_MPRED,                     BR_MPRED);
 
 POWER_EVENT_ATTR(CMPLU_STALL_FXU,              CMPLU_STALL_FXU);
 POWER_EVENT_ATTR(CMPLU_STALL_DIV,              CMPLU_STALL_DIV);
@@ -449,7 +449,7 @@ static struct attribute *power7_events_attr[] = {
        GENERIC_EVENT_PTR(LD_REF_L1),
        GENERIC_EVENT_PTR(LD_MISS_L1),
        GENERIC_EVENT_PTR(BRU_FIN),
-       GENERIC_EVENT_PTR(BRU_MPRED),
+       GENERIC_EVENT_PTR(BR_MPRED),
 
        POWER_EVENT_PTR(CYC),
        POWER_EVENT_PTR(GCT_NOSLOT_CYC),
@@ -458,7 +458,7 @@ static struct attribute *power7_events_attr[] = {
        POWER_EVENT_PTR(LD_REF_L1),
        POWER_EVENT_PTR(LD_MISS_L1),
        POWER_EVENT_PTR(BRU_FIN),
-       POWER_EVENT_PTR(BRU_MPRED),
+       POWER_EVENT_PTR(BR_MPRED),
 
        POWER_EVENT_PTR(CMPLU_STALL_FXU),
        POWER_EVENT_PTR(CMPLU_STALL_DIV),
index 0c5105f..9249449 100644 (file)
@@ -80,6 +80,6 @@
 
 #define SO_SELECT_ERR_QUEUE    45
 
-#define SO_LL                  46
+#define SO_BUSY_POLL           46
 
 #endif /* _ASM_SOCKET_H */
index 06bafec..4002329 100644 (file)
@@ -91,11 +91,9 @@ void arch_pick_mmap_layout(struct mm_struct *mm)
        if (mmap_is_legacy()) {
                mm->mmap_base = TASK_UNMAPPED_BASE;
                mm->get_unmapped_area = arch_get_unmapped_area;
-               mm->unmap_area = arch_unmap_area;
        } else {
                mm->mmap_base = mmap_base();
                mm->get_unmapped_area = arch_get_unmapped_area_topdown;
-               mm->unmap_area = arch_unmap_area_topdown;
        }
 }
 
@@ -176,11 +174,9 @@ void arch_pick_mmap_layout(struct mm_struct *mm)
        if (mmap_is_legacy()) {
                mm->mmap_base = TASK_UNMAPPED_BASE;
                mm->get_unmapped_area = s390_get_unmapped_area;
-               mm->unmap_area = arch_unmap_area;
        } else {
                mm->mmap_base = mmap_base();
                mm->get_unmapped_area = s390_get_unmapped_area_topdown;
-               mm->unmap_area = arch_unmap_area_topdown;
        }
 }
 
index b836e92..c2f6ff6 100644 (file)
@@ -108,7 +108,7 @@ static inline int sparc_leon3_snooping_enabled(void)
 {
        u32 cctrl;
        __asm__ __volatile__("lda [%%g0] 2, %0\n\t" : "=r"(cctrl));
-        return (cctrl >> 23) & 1;
+       return ((cctrl >> 23) & 1) && ((cctrl >> 17) & 1);
 };
 
 static inline void sparc_leon3_disable_cache(void)
index d73e5e0..7e8ace5 100644 (file)
@@ -35,7 +35,7 @@
 #define O_SYNC         (__O_SYNC|O_DSYNC)
 
 #define O_PATH         0x1000000
-#define O_TMPFILE      0x2000000
+#define __O_TMPFILE    0x2000000
 
 #define F_GETOWN       5       /*  for sockets. */
 #define F_SETOWN       6       /*  for sockets. */
index b46c3fa..4e1d66c 100644 (file)
@@ -70,7 +70,7 @@
 
 #define SO_SELECT_ERR_QUEUE    0x0029
 
-#define SO_LL                  0x0030
+#define SO_BUSY_POLL           0x0030
 
 /* Security levels - as per NRL IPv6 - don't actually do anything */
 #define SO_SECURITY_AUTHENTICATION             0x5001
index 961b87f..f76389a 100644 (file)
@@ -49,6 +49,8 @@ int foo(void)
        DEFINE(AOFF_task_thread, offsetof(struct task_struct, thread));
        BLANK();
        DEFINE(AOFF_mm_context, offsetof(struct mm_struct, context));
+       BLANK();
+       DEFINE(VMA_VM_MM,    offsetof(struct vm_area_struct, vm_mm));
 
        /* DEFINE(NUM_USER_SEGMENTS, TASK_SIZE>>28); */
        return 0;
index 5ef48da..11d460f 100644 (file)
@@ -783,6 +783,16 @@ void ldom_set_var(const char *var, const char *value)
                char  *base, *p;
                int msg_len, loops;
 
+               if (strlen(var) + strlen(value) + 2 >
+                   sizeof(pkt) - sizeof(pkt.header)) {
+                       printk(KERN_ERR PFX
+                               "contents length: %zu, which more than max: %lu,"
+                               "so could not set (%s) variable to (%s).\n",
+                               strlen(var) + strlen(value) + 2,
+                               sizeof(pkt) - sizeof(pkt.header), var, value);
+                       return;
+               }
+
                memset(&pkt, 0, sizeof(pkt));
                pkt.header.data.tag.type = DS_DATA;
                pkt.header.data.handle = cp->handle;
index 2daaaa6..51561b8 100644 (file)
@@ -290,7 +290,6 @@ void arch_pick_mmap_layout(struct mm_struct *mm)
            sysctl_legacy_va_layout) {
                mm->mmap_base = TASK_UNMAPPED_BASE + random_factor;
                mm->get_unmapped_area = arch_get_unmapped_area;
-               mm->unmap_area = arch_unmap_area;
        } else {
                /* We know it's 32-bit */
                unsigned long task_size = STACK_TOP32;
@@ -302,7 +301,6 @@ void arch_pick_mmap_layout(struct mm_struct *mm)
 
                mm->mmap_base = PAGE_ALIGN(task_size - gap - random_factor);
                mm->get_unmapped_area = arch_get_unmapped_area_topdown;
-               mm->unmap_area = arch_unmap_area_topdown;
        }
 }
 
index 44aad32..969f964 100644 (file)
@@ -74,7 +74,7 @@ hypersparc_flush_cache_mm_out:
 
        /* The things we do for performance... */
 hypersparc_flush_cache_range:
-       ld      [%o0 + 0x0], %o0                /* XXX vma->vm_mm, GROSS XXX */
+       ld      [%o0 + VMA_VM_MM], %o0
 #ifndef CONFIG_SMP
        ld      [%o0 + AOFF_mm_context], %g1
        cmp     %g1, -1
@@ -163,7 +163,7 @@ hypersparc_flush_cache_range_out:
         */
        /* Verified, my ass... */
 hypersparc_flush_cache_page:
-       ld      [%o0 + 0x0], %o0                /* XXX vma->vm_mm, GROSS XXX */
+       ld      [%o0 + VMA_VM_MM], %o0
        ld      [%o0 + AOFF_mm_context], %g2
 #ifndef CONFIG_SMP
        cmp     %g2, -1
@@ -284,7 +284,7 @@ hypersparc_flush_tlb_mm_out:
         sta    %g5, [%g1] ASI_M_MMUREGS
 
 hypersparc_flush_tlb_range:
-       ld      [%o0 + 0x00], %o0       /* XXX vma->vm_mm GROSS XXX */
+       ld      [%o0 + VMA_VM_MM], %o0
        mov     SRMMU_CTX_REG, %g1
        ld      [%o0 + AOFF_mm_context], %o3
        lda     [%g1] ASI_M_MMUREGS, %g5
@@ -307,7 +307,7 @@ hypersparc_flush_tlb_range_out:
         sta    %g5, [%g1] ASI_M_MMUREGS
 
 hypersparc_flush_tlb_page:
-       ld      [%o0 + 0x00], %o0       /* XXX vma->vm_mm GROSS XXX */
+       ld      [%o0 + VMA_VM_MM], %o0
        mov     SRMMU_CTX_REG, %g1
        ld      [%o0 + AOFF_mm_context], %o3
        andn    %o1, (PAGE_SIZE - 1), %o1
index c801c39..5d2b88d 100644 (file)
@@ -105,7 +105,7 @@ swift_flush_cache_mm_out:
 
        .globl  swift_flush_cache_range
 swift_flush_cache_range:
-       ld      [%o0 + 0x0], %o0                /* XXX vma->vm_mm, GROSS XXX */
+       ld      [%o0 + VMA_VM_MM], %o0
        sub     %o2, %o1, %o2
        sethi   %hi(4096), %o3
        cmp     %o2, %o3
@@ -116,7 +116,7 @@ swift_flush_cache_range:
 
        .globl  swift_flush_cache_page
 swift_flush_cache_page:
-       ld      [%o0 + 0x0], %o0                /* XXX vma->vm_mm, GROSS XXX */
+       ld      [%o0 + VMA_VM_MM], %o0
 70:
        ld      [%o0 + AOFF_mm_context], %g2
        cmp     %g2, -1
@@ -219,7 +219,7 @@ swift_flush_sig_insns:
        .globl  swift_flush_tlb_range
        .globl  swift_flush_tlb_all
 swift_flush_tlb_range:
-       ld      [%o0 + 0x00], %o0       /* XXX vma->vm_mm GROSS XXX */
+       ld      [%o0 + VMA_VM_MM], %o0
 swift_flush_tlb_mm:
        ld      [%o0 + AOFF_mm_context], %g2
        cmp     %g2, -1
@@ -233,7 +233,7 @@ swift_flush_tlb_all_out:
 
        .globl  swift_flush_tlb_page
 swift_flush_tlb_page:
-       ld      [%o0 + 0x00], %o0       /* XXX vma->vm_mm GROSS XXX */
+       ld      [%o0 + VMA_VM_MM], %o0
        mov     SRMMU_CTX_REG, %g1
        ld      [%o0 + AOFF_mm_context], %o3
        andn    %o1, (PAGE_SIZE - 1), %o1
index 4e55e8f..bf10a34 100644 (file)
@@ -24,7 +24,7 @@
        /* Sliiick... */
 tsunami_flush_cache_page:
 tsunami_flush_cache_range:
-       ld      [%o0 + 0x0], %o0        /* XXX vma->vm_mm, GROSS XXX */
+       ld      [%o0 + VMA_VM_MM], %o0
 tsunami_flush_cache_mm:
        ld      [%o0 + AOFF_mm_context], %g2
        cmp     %g2, -1
@@ -46,7 +46,7 @@ tsunami_flush_sig_insns:
 
        /* More slick stuff... */
 tsunami_flush_tlb_range:
-       ld      [%o0 + 0x00], %o0       /* XXX vma->vm_mm GROSS XXX */
+       ld      [%o0 + VMA_VM_MM], %o0
 tsunami_flush_tlb_mm:
        ld      [%o0 + AOFF_mm_context], %g2
        cmp     %g2, -1
@@ -65,7 +65,7 @@ tsunami_flush_tlb_out:
 
        /* This one can be done in a fine grained manner... */
 tsunami_flush_tlb_page:
-       ld      [%o0 + 0x00], %o0       /* XXX vma->vm_mm GROSS XXX */
+       ld      [%o0 + VMA_VM_MM], %o0
        mov     SRMMU_CTX_REG, %g1
        ld      [%o0 + AOFF_mm_context], %o3
        andn    %o1, (PAGE_SIZE - 1), %o1
index bf8ee06..852257f 100644 (file)
@@ -108,7 +108,7 @@ viking_mxcc_flush_page:
 viking_flush_cache_page:
 viking_flush_cache_range:
 #ifndef CONFIG_SMP
-       ld      [%o0 + 0x0], %o0                /* XXX vma->vm_mm, GROSS XXX */
+       ld      [%o0 + VMA_VM_MM], %o0
 #endif
 viking_flush_cache_mm:
 #ifndef CONFIG_SMP
@@ -148,7 +148,7 @@ viking_flush_tlb_mm:
 #endif
 
 viking_flush_tlb_range:
-       ld      [%o0 + 0x00], %o0       /* XXX vma->vm_mm GROSS XXX */
+       ld      [%o0 + VMA_VM_MM], %o0
        mov     SRMMU_CTX_REG, %g1
        ld      [%o0 + AOFF_mm_context], %o3
        lda     [%g1] ASI_M_MMUREGS, %g5
@@ -173,7 +173,7 @@ viking_flush_tlb_range:
 #endif
 
 viking_flush_tlb_page:
-       ld      [%o0 + 0x00], %o0       /* XXX vma->vm_mm GROSS XXX */
+       ld      [%o0 + VMA_VM_MM], %o0
        mov     SRMMU_CTX_REG, %g1
        ld      [%o0 + AOFF_mm_context], %o3
        lda     [%g1] ASI_M_MMUREGS, %g5
@@ -239,7 +239,7 @@ sun4dsmp_flush_tlb_range:
        tst     %g5
        bne     3f
         mov    SRMMU_CTX_REG, %g1
-       ld      [%o0 + 0x00], %o0       /* XXX vma->vm_mm GROSS XXX */
+       ld      [%o0 + VMA_VM_MM], %o0
        ld      [%o0 + AOFF_mm_context], %o3
        lda     [%g1] ASI_M_MMUREGS, %g5
        sethi   %hi(~((1 << SRMMU_PGDIR_SHIFT) - 1)), %o4
@@ -265,7 +265,7 @@ sun4dsmp_flush_tlb_page:
        tst     %g5
        bne     2f
         mov    SRMMU_CTX_REG, %g1
-       ld      [%o0 + 0x00], %o0       /* XXX vma->vm_mm GROSS XXX */
+       ld      [%o0 + VMA_VM_MM], %o0
        ld      [%o0 + AOFF_mm_context], %o3
        lda     [%g1] ASI_M_MMUREGS, %g5
        and     %o1, PAGE_MASK, %o1
index f96f4ce..d67d91e 100644 (file)
@@ -66,10 +66,8 @@ void arch_pick_mmap_layout(struct mm_struct *mm)
        if (!is_32bit || rlimit(RLIMIT_STACK) == RLIM_INFINITY) {
                mm->mmap_base = TASK_UNMAPPED_BASE;
                mm->get_unmapped_area = arch_get_unmapped_area;
-               mm->unmap_area = arch_unmap_area;
        } else {
                mm->mmap_base = mmap_base(mm);
                mm->get_unmapped_area = arch_get_unmapped_area_topdown;
-               mm->unmap_area = arch_unmap_area_topdown;
        }
 }
index 805078e..fbeba82 100644 (file)
@@ -308,8 +308,6 @@ static int load_aout_binary(struct linux_binprm *bprm)
                (current->mm->start_data = N_DATADDR(ex));
        current->mm->brk = ex.a_bss +
                (current->mm->start_brk = N_BSSADDR(ex));
-       current->mm->free_area_cache = TASK_UNMAPPED_BASE;
-       current->mm->cached_hole_size = 0;
 
        retval = setup_arg_pages(bprm, IA32_STACK_TOP, EXSTACK_DEFAULT);
        if (retval < 0) {
index 6b52980..29e3093 100644 (file)
@@ -214,6 +214,13 @@ void mce_log_therm_throt_event(__u64 status);
 /* Interrupt Handler for core thermal thresholds */
 extern int (*platform_thermal_notify)(__u64 msr_val);
 
+/* Interrupt Handler for package thermal thresholds */
+extern int (*platform_thermal_package_notify)(__u64 msr_val);
+
+/* Callback support of rate control, return true, if
+ * callback has rate control */
+extern bool (*platform_thermal_package_rate_control)(void);
+
 #ifdef CONFIG_X86_THERMAL_VECTOR
 extern void mcheck_intel_therm_init(void);
 #else
index 98f2083..41e8e00 100644 (file)
@@ -55,12 +55,24 @@ struct thermal_state {
        struct _thermal_state package_power_limit;
        struct _thermal_state core_thresh0;
        struct _thermal_state core_thresh1;
+       struct _thermal_state pkg_thresh0;
+       struct _thermal_state pkg_thresh1;
 };
 
 /* Callback to handle core threshold interrupts */
 int (*platform_thermal_notify)(__u64 msr_val);
 EXPORT_SYMBOL(platform_thermal_notify);
 
+/* Callback to handle core package threshold_interrupts */
+int (*platform_thermal_package_notify)(__u64 msr_val);
+EXPORT_SYMBOL_GPL(platform_thermal_package_notify);
+
+/* Callback support of rate control, return true, if
+ * callback has rate control */
+bool (*platform_thermal_package_rate_control)(void);
+EXPORT_SYMBOL_GPL(platform_thermal_package_rate_control);
+
+
 static DEFINE_PER_CPU(struct thermal_state, thermal_state);
 
 static atomic_t therm_throt_en = ATOMIC_INIT(0);
@@ -195,19 +207,25 @@ static int therm_throt_process(bool new_event, int event, int level)
        return 0;
 }
 
-static int thresh_event_valid(int event)
+static int thresh_event_valid(int level, int event)
 {
        struct _thermal_state *state;
        unsigned int this_cpu = smp_processor_id();
        struct thermal_state *pstate = &per_cpu(thermal_state, this_cpu);
        u64 now = get_jiffies_64();
 
-       state = (event == 0) ? &pstate->core_thresh0 : &pstate->core_thresh1;
+       if (level == PACKAGE_LEVEL)
+               state = (event == 0) ? &pstate->pkg_thresh0 :
+                                               &pstate->pkg_thresh1;
+       else
+               state = (event == 0) ? &pstate->core_thresh0 :
+                                               &pstate->core_thresh1;
 
        if (time_before64(now, state->next_check))
                return 0;
 
        state->next_check = now + CHECK_INTERVAL;
+
        return 1;
 }
 
@@ -322,6 +340,39 @@ device_initcall(thermal_throttle_init_device);
 
 #endif /* CONFIG_SYSFS */
 
+static void notify_package_thresholds(__u64 msr_val)
+{
+       bool notify_thres_0 = false;
+       bool notify_thres_1 = false;
+
+       if (!platform_thermal_package_notify)
+               return;
+
+       /* lower threshold check */
+       if (msr_val & THERM_LOG_THRESHOLD0)
+               notify_thres_0 = true;
+       /* higher threshold check */
+       if (msr_val & THERM_LOG_THRESHOLD1)
+               notify_thres_1 = true;
+
+       if (!notify_thres_0 && !notify_thres_1)
+               return;
+
+       if (platform_thermal_package_rate_control &&
+               platform_thermal_package_rate_control()) {
+               /* Rate control is implemented in callback */
+               platform_thermal_package_notify(msr_val);
+               return;
+       }
+
+       /* lower threshold reached */
+       if (notify_thres_0 && thresh_event_valid(PACKAGE_LEVEL, 0))
+               platform_thermal_package_notify(msr_val);
+       /* higher threshold reached */
+       if (notify_thres_1 && thresh_event_valid(PACKAGE_LEVEL, 1))
+               platform_thermal_package_notify(msr_val);
+}
+
 static void notify_thresholds(__u64 msr_val)
 {
        /* check whether the interrupt handler is defined;
@@ -331,10 +382,12 @@ static void notify_thresholds(__u64 msr_val)
                return;
 
        /* lower threshold reached */
-       if ((msr_val & THERM_LOG_THRESHOLD0) && thresh_event_valid(0))
+       if ((msr_val & THERM_LOG_THRESHOLD0) &&
+                       thresh_event_valid(CORE_LEVEL, 0))
                platform_thermal_notify(msr_val);
        /* higher threshold reached */
-       if ((msr_val & THERM_LOG_THRESHOLD1) && thresh_event_valid(1))
+       if ((msr_val & THERM_LOG_THRESHOLD1) &&
+                       thresh_event_valid(CORE_LEVEL, 1))
                platform_thermal_notify(msr_val);
 }
 
@@ -360,6 +413,8 @@ static void intel_thermal_interrupt(void)
 
        if (this_cpu_has(X86_FEATURE_PTS)) {
                rdmsrl(MSR_IA32_PACKAGE_THERM_STATUS, msr_val);
+               /* check violations of package thermal thresholds */
+               notify_package_thresholds(msr_val);
                therm_throt_process(msr_val & PACKAGE_THERM_STATUS_PROCHOT,
                                        THERMAL_THROTTLING_EVENT,
                                        PACKAGE_LEVEL);
index 0db655e..639d128 100644 (file)
@@ -491,10 +491,8 @@ static struct perf_amd_iommu __perf_iommu = {
 static __init int amd_iommu_pc_init(void)
 {
        /* Make sure the IOMMU PC resource is available */
-       if (!amd_iommu_pc_supported()) {
-               pr_err("perf: amd_iommu PMU not installed. No support!\n");
+       if (!amd_iommu_pc_supported())
                return -ENODEV;
-       }
 
        _init_perf_amd_iommu(&__perf_iommu, "amd_iommu");
 
index 0920212..ba77ebc 100644 (file)
@@ -111,7 +111,7 @@ static int __kprobes nmi_handle(unsigned int type, struct pt_regs *regs, bool b2
         */
        list_for_each_entry_rcu(a, &desc->head, list) {
                u64 before, delta, whole_msecs;
-               int decimal_msecs, thishandled;
+               int remainder_ns, decimal_msecs, thishandled;
 
                before = local_clock();
                thishandled = a->handler(type, regs);
@@ -123,8 +123,9 @@ static int __kprobes nmi_handle(unsigned int type, struct pt_regs *regs, bool b2
                        continue;
 
                nmi_longest_ns = delta;
-               whole_msecs = do_div(delta, (1000 * 1000));
-               decimal_msecs = do_div(delta, 1000) % 1000;
+               whole_msecs = delta;
+               remainder_ns = do_div(whole_msecs, (1000 * 1000));
+               decimal_msecs = remainder_ns / 1000;
                printk_ratelimited(KERN_INFO
                        "INFO: NMI handler (%ps) took too long to run: "
                        "%lld.%03d msecs\n", a->handler, whole_msecs,
index f4fe0b8..cdaa347 100644 (file)
@@ -265,23 +265,30 @@ void smp_reschedule_interrupt(struct pt_regs *regs)
         */
 }
 
-void smp_trace_reschedule_interrupt(struct pt_regs *regs)
+static inline void smp_entering_irq(void)
 {
        ack_APIC_irq();
+       irq_enter();
+}
+
+void smp_trace_reschedule_interrupt(struct pt_regs *regs)
+{
+       /*
+        * Need to call irq_enter() before calling the trace point.
+        * __smp_reschedule_interrupt() calls irq_enter/exit() too (in
+        * scheduler_ipi(). This is OK, since those functions are allowed
+        * to nest.
+        */
+       smp_entering_irq();
        trace_reschedule_entry(RESCHEDULE_VECTOR);
        __smp_reschedule_interrupt();
        trace_reschedule_exit(RESCHEDULE_VECTOR);
+       exiting_irq();
        /*
         * KVM uses this interrupt to force a cpu out of guest mode
         */
 }
 
-static inline void call_function_entering_irq(void)
-{
-       ack_APIC_irq();
-       irq_enter();
-}
-
 static inline void __smp_call_function_interrupt(void)
 {
        generic_smp_call_function_interrupt();
@@ -290,14 +297,14 @@ static inline void __smp_call_function_interrupt(void)
 
 void smp_call_function_interrupt(struct pt_regs *regs)
 {
-       call_function_entering_irq();
+       smp_entering_irq();
        __smp_call_function_interrupt();
        exiting_irq();
 }
 
 void smp_trace_call_function_interrupt(struct pt_regs *regs)
 {
-       call_function_entering_irq();
+       smp_entering_irq();
        trace_call_function_entry(CALL_FUNCTION_VECTOR);
        __smp_call_function_interrupt();
        trace_call_function_exit(CALL_FUNCTION_VECTOR);
@@ -312,14 +319,14 @@ static inline void __smp_call_function_single_interrupt(void)
 
 void smp_call_function_single_interrupt(struct pt_regs *regs)
 {
-       call_function_entering_irq();
+       smp_entering_irq();
        __smp_call_function_single_interrupt();
        exiting_irq();
 }
 
 void smp_trace_call_function_single_interrupt(struct pt_regs *regs)
 {
-       call_function_entering_irq();
+       smp_entering_irq();
        trace_call_function_single_entry(CALL_FUNCTION_SINGLE_VECTOR);
        __smp_call_function_single_interrupt();
        trace_call_function_single_exit(CALL_FUNCTION_SINGLE_VECTOR);
index a7e1855..064d0be 100644 (file)
@@ -3404,15 +3404,22 @@ static void vmx_get_segment(struct kvm_vcpu *vcpu,
        var->limit = vmx_read_guest_seg_limit(vmx, seg);
        var->selector = vmx_read_guest_seg_selector(vmx, seg);
        ar = vmx_read_guest_seg_ar(vmx, seg);
+       var->unusable = (ar >> 16) & 1;
        var->type = ar & 15;
        var->s = (ar >> 4) & 1;
        var->dpl = (ar >> 5) & 3;
-       var->present = (ar >> 7) & 1;
+       /*
+        * Some userspaces do not preserve unusable property. Since usable
+        * segment has to be present according to VMX spec we can use present
+        * property to amend userspace bug by making unusable segment always
+        * nonpresent. vmx_segment_access_rights() already marks nonpresent
+        * segment as unusable.
+        */
+       var->present = !var->unusable;
        var->avl = (ar >> 12) & 1;
        var->l = (ar >> 13) & 1;
        var->db = (ar >> 14) & 1;
        var->g = (ar >> 15) & 1;
-       var->unusable = (ar >> 16) & 1;
 }
 
 static u64 vmx_get_segment_base(struct kvm_vcpu *vcpu, int seg)
index 845df68..62c29a5 100644 (file)
@@ -115,10 +115,8 @@ void arch_pick_mmap_layout(struct mm_struct *mm)
        if (mmap_is_legacy()) {
                mm->mmap_base = mmap_legacy_base();
                mm->get_unmapped_area = arch_get_unmapped_area;
-               mm->unmap_area = arch_unmap_area;
        } else {
                mm->mmap_base = mmap_base();
                mm->get_unmapped_area = arch_get_unmapped_area_topdown;
-               mm->unmap_area = arch_unmap_area_topdown;
        }
 }
index 0a1b95f..7ea6451 100644 (file)
@@ -6,10 +6,12 @@ config XTENSA
        select ARCH_WANT_FRAME_POINTERS
        select HAVE_IDE
        select GENERIC_ATOMIC64
+       select GENERIC_CLOCKEVENTS
        select HAVE_GENERIC_HARDIRQS
        select VIRT_TO_BUS
        select GENERIC_IRQ_SHOW
        select GENERIC_CPU_DEVICES
+       select GENERIC_SCHED_CLOCK
        select MODULES_USE_ELF_RELA
        select GENERIC_PCI_IOMAP
        select ARCH_WANT_IPC_PARSE_VERSION
@@ -17,6 +19,7 @@ config XTENSA
        select CLONE_BACKWARDS
        select IRQ_DOMAIN
        select HAVE_OPROFILE
+       select HAVE_FUNCTION_TRACER
        help
          Xtensa processors are 32-bit RISC machines designed by Tensilica
          primarily for embedded systems.  These processors are both
index a34010e..af7da74 100644 (file)
@@ -2,6 +2,16 @@ menu "Kernel hacking"
 
 source "lib/Kconfig.debug"
 
+config DEBUG_TLB_SANITY
+       bool "Debug TLB sanity"
+       depends on DEBUG_KERNEL
+       help
+         Enable this to turn on TLB sanity check on each entry to userspace.
+         This check can spot missing TLB invalidation/wrong PTE permissions/
+         premature page freeing.
+
+         If unsure, say N.
+
 config LD_NO_RELAX
        bool "Disable linker relaxation"
        default n
diff --git a/arch/xtensa/boot/.gitignore b/arch/xtensa/boot/.gitignore
new file mode 100644 (file)
index 0000000..be76559
--- /dev/null
@@ -0,0 +1,3 @@
+uImage
+zImage.redboot
+*.dtb
diff --git a/arch/xtensa/boot/boot-elf/.gitignore b/arch/xtensa/boot/boot-elf/.gitignore
new file mode 100644 (file)
index 0000000..5ff8fbb
--- /dev/null
@@ -0,0 +1 @@
+boot.lds
diff --git a/arch/xtensa/boot/lib/.gitignore b/arch/xtensa/boot/lib/.gitignore
new file mode 100644 (file)
index 0000000..1629a61
--- /dev/null
@@ -0,0 +1,3 @@
+inffast.c
+inflate.c
+inftrees.c
index ad8952e..6868f2c 100644 (file)
@@ -7,6 +7,13 @@ zlib   := inffast.c inflate.c inftrees.c
 lib-y  += $(zlib:.c=.o) zmem.o
 
 ccflags-y      := -Ilib/zlib_inflate
+ifdef CONFIG_FUNCTION_TRACER
+CFLAGS_REMOVE_inflate.o = -pg
+CFLAGS_REMOVE_zmem.o = -pg
+CFLAGS_REMOVE_inftrees.o = -pg
+CFLAGS_REMOVE_inffast.o = -pg
+endif
+
 
 quiet_cmd_copy_zlib = COPY    $@
       cmd_copy_zlib = cat $< > $@
index 0c25799..23392c5 100644 (file)
@@ -20,7 +20,7 @@
 #define BP_TAG_COMMAND_LINE    0x1001  /* command line (0-terminated string)*/
 #define BP_TAG_INITRD          0x1002  /* ramdisk addr and size (bp_meminfo) */
 #define BP_TAG_MEMORY          0x1003  /* memory addr and size (bp_meminfo) */
-#define BP_TAG_SERIAL_BAUSRATE 0x1004  /* baud rate of current console. */
+#define BP_TAG_SERIAL_BAUDRATE 0x1004  /* baud rate of current console. */
 #define BP_TAG_SERIAL_PORT     0x1005  /* serial device of current console */
 #define BP_TAG_FDT             0x1006  /* flat device tree addr */
 
index d9ab131..370b26f 100644 (file)
@@ -93,6 +93,7 @@ static inline unsigned long __cmpxchg_local(volatile void *ptr,
        ((__typeof__(*(ptr)))__cmpxchg_local_generic((ptr), (unsigned long)(o),\
                        (unsigned long)(n), sizeof(*(ptr))))
 #define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n))
+#define cmpxchg64(ptr, o, n)    cmpxchg64_local((ptr), (o), (n))
 
 /*
  * xchg_u32
index 61fc5fa..3899610 100644 (file)
@@ -12,7 +12,7 @@
 #ifndef _XTENSA_DELAY_H
 #define _XTENSA_DELAY_H
 
-#include <asm/processor.h>
+#include <asm/timex.h>
 #include <asm/param.h>
 
 extern unsigned long loops_per_jiffy;
@@ -24,24 +24,17 @@ static inline void __delay(unsigned long loops)
                              : "=r" (loops) : "0" (loops));
 }
 
-static __inline__ u32 xtensa_get_ccount(void)
-{
-       u32 ccount;
-       asm volatile ("rsr %0, ccount\n" : "=r" (ccount));
-       return ccount;
-}
-
 /* For SMP/NUMA systems, change boot_cpu_data to something like
  * local_cpu_data->... where local_cpu_data points to the current
  * cpu. */
 
 static __inline__ void udelay (unsigned long usecs)
 {
-       unsigned long start = xtensa_get_ccount();
+       unsigned long start = get_ccount();
        unsigned long cycles = usecs * (loops_per_jiffy / (1000000UL / HZ));
 
        /* Note: all variables are unsigned (can wrap around)! */
-       while (((unsigned long)xtensa_get_ccount()) - start < cycles)
+       while (((unsigned long)get_ccount()) - start < cycles)
                ;
 }
 
index 36dc7a6..73cc3f4 100644 (file)
@@ -13,6 +13,7 @@
 #include <asm/processor.h>
 
 #define HAVE_ARCH_CALLER_ADDR
+#ifndef __ASSEMBLY__
 #define CALLER_ADDR0 ({ unsigned long a0, a1; \
                __asm__ __volatile__ ( \
                        "mov %0, a0\n" \
@@ -24,10 +25,22 @@ extern unsigned long return_address(unsigned level);
 #define CALLER_ADDR1 return_address(1)
 #define CALLER_ADDR2 return_address(2)
 #define CALLER_ADDR3 return_address(3)
-#else
+#else /* CONFIG_FRAME_POINTER */
 #define CALLER_ADDR1 (0)
 #define CALLER_ADDR2 (0)
 #define CALLER_ADDR3 (0)
-#endif
+#endif /* CONFIG_FRAME_POINTER */
+#endif /* __ASSEMBLY__ */
+
+#ifdef CONFIG_FUNCTION_TRACER
+
+#define MCOUNT_ADDR ((unsigned long)(_mcount))
+#define MCOUNT_INSN_SIZE 3
+
+#ifndef __ASSEMBLY__
+extern void _mcount(void);
+#define mcount _mcount
+#endif /* __ASSEMBLY__ */
+#endif /* CONFIG_FUNCTION_TRACER */
 
 #endif /* _XTENSA_FTRACE_H */
index 8f017eb..0fdf5d0 100644 (file)
@@ -5,7 +5,7 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  *
- * Copyright (C) 2001 - 2007 Tensilica Inc.
+ * Copyright (C) 2001 - 2013 Tensilica Inc.
  */
 
 #ifndef _XTENSA_PGTABLE_H
  * Virtual memory area. We keep a distance to other memory regions to be
  * on the safe side. We also use this area for cache aliasing.
  */
-
 #define VMALLOC_START          0xC0000000
 #define VMALLOC_END            0xC7FEFFFF
 #define TLBTEMP_BASE_1         0xC7FF0000
 #define TLBTEMP_BASE_2         0xC7FF8000
 
 /*
- * Xtensa Linux config PTE layout (when present):
- *     31-12:  PPN
- *     11-6:   Software
- *     5-4:    RING
- *     3-0:    CA
+ * For the Xtensa architecture, the PTE layout is as follows:
+ *
+ *             31------12  11  10-9   8-6  5-4  3-2  1-0
+ *             +-----------------------------------------+
+ *             |           |   Software   |   HARDWARE   |
+ *             |    PPN    |          ADW | RI |Attribute|
+ *             +-----------------------------------------+
+ *   pte_none  |             MBZ          | 01 | 11 | 00 |
+ *             +-----------------------------------------+
+ *   present   |    PPN    | 0 | 00 | ADW | RI | CA | wx |
+ *             +- - - - - - - - - - - - - - - - - - - - -+
+ *   (PAGE_NONE)|    PPN    | 0 | 00 | ADW | 01 | 11 | 11 |
+ *             +-----------------------------------------+
+ *   swap      |     index     |   type   | 01 | 11 | 00 |
+ *             +- - - - - - - - - - - - - - - - - - - - -+
+ *   file      |        file offset       | 01 | 11 | 10 |
+ *             +-----------------------------------------+
+ *
+ * For T1050 hardware and earlier the layout differs for present and (PAGE_NONE)
+ *             +-----------------------------------------+
+ *   present   |    PPN    | 0 | 00 | ADW | RI | CA | w1 |
+ *             +-----------------------------------------+
+ *   (PAGE_NONE)|    PPN    | 0 | 00 | ADW | 01 | 01 | 00 |
+ *             +-----------------------------------------+
  *
- * Similar to the Alpha and MIPS ports, we need to keep track of the ref
- * and mod bits in software.  We have a software "you can read
- * from this page" bit, and a hardware one which actually lets the
- * process read from the page.  On the same token we have a software
- * writable bit and the real hardware one which actually lets the
- * process write to the page.
+ *  Legend:
+ *   PPN        Physical Page Number
+ *   ADW       software: accessed (young) / dirty / writable
+ *   RI         ring (0=privileged, 1=user, 2 and 3 are unused)
+ *   CA                cache attribute: 00 bypass, 01 writeback, 10 writethrough
+ *             (11 is invalid and used to mark pages that are not present)
+ *   w         page is writable (hw)
+ *   x         page is executable (hw)
+ *   index      swap offset / PAGE_SIZE (bit 11-31: 21 bits -> 8 GB)
+ *             (note that the index is always non-zero)
+ *   type       swap type (5 bits -> 32 types)
+ *   file offset 26-bit offset into the file, in increments of PAGE_SIZE
  *
- * See further below for PTE layout for swapped-out pages.
+ *  Notes:
+ *   - (PROT_NONE) is a special case of 'present' but causes an exception for
+ *     any access (read, write, and execute).
+ *   - 'multihit-exception' has the highest priority of all MMU exceptions,
+ *     so the ring must be set to 'RING_USER' even for 'non-present' pages.
+ *   - on older hardware, the exectuable flag was not supported and
+ *     used as a 'valid' flag, so it needs to be always set.
+ *   - we need to keep track of certain flags in software (dirty and young)
+ *     to do this, we use write exceptions and have a separate software w-flag.
+ *   - attribute value 1101 (and 1111 on T1050 and earlier) is reserved
  */
 
+#define _PAGE_ATTRIB_MASK      0xf
+
 #define _PAGE_HW_EXEC          (1<<0)  /* hardware: page is executable */
 #define _PAGE_HW_WRITE         (1<<1)  /* hardware: page is writable */
 
-#define _PAGE_FILE             (1<<1)  /* non-linear mapping, if !present */
-#define _PAGE_PROTNONE         (3<<0)  /* special case for VM_PROT_NONE */
-
-/* None of these cache modes include MP coherency:  */
 #define _PAGE_CA_BYPASS                (0<<2)  /* bypass, non-speculative */
 #define _PAGE_CA_WB            (1<<2)  /* write-back */
 #define _PAGE_CA_WT            (2<<2)  /* write-through */
 #define _PAGE_CA_MASK          (3<<2)
-#define _PAGE_INVALID          (3<<2)
+#define _PAGE_CA_INVALID       (3<<2)
+
+/* We use invalid attribute values to distinguish special pte entries */
+#if XCHAL_HW_VERSION_MAJOR < 2000
+#define _PAGE_HW_VALID         0x01    /* older HW needed this bit set */
+#define _PAGE_NONE             0x04
+#else
+#define _PAGE_HW_VALID         0x00
+#define _PAGE_NONE             0x0f
+#endif
+#define _PAGE_FILE             (1<<1)  /* file mapped page, only if !present */
 
 #define _PAGE_USER             (1<<4)  /* user access (ring=1) */
 
 #define _PAGE_DIRTY            (1<<7)  /* software: page dirty */
 #define _PAGE_ACCESSED         (1<<8)  /* software: page accessed (read) */
 
-/* On older HW revisions, we always have to set bit 0 */
-#if XCHAL_HW_VERSION_MAJOR < 2000
-# define _PAGE_VALID           (1<<0)
-#else
-# define _PAGE_VALID           0
-#endif
-
-#define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY)
-#define _PAGE_PRESENT  (_PAGE_VALID | _PAGE_CA_WB | _PAGE_ACCESSED)
-
 #ifdef CONFIG_MMU
 
-#define PAGE_NONE         __pgprot(_PAGE_INVALID | _PAGE_USER | _PAGE_PROTNONE)
+#define _PAGE_CHG_MASK    (PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY)
+#define _PAGE_PRESENT     (_PAGE_HW_VALID | _PAGE_CA_WB | _PAGE_ACCESSED)
+
+#define PAGE_NONE         __pgprot(_PAGE_NONE | _PAGE_USER)
 #define PAGE_COPY         __pgprot(_PAGE_PRESENT | _PAGE_USER)
 #define PAGE_COPY_EXEC    __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_HW_EXEC)
 #define PAGE_READONLY     __pgprot(_PAGE_PRESENT | _PAGE_USER)
 #define PAGE_KERNEL_EXEC   __pgprot(_PAGE_PRESENT|_PAGE_HW_WRITE|_PAGE_HW_EXEC)
 
 #if (DCACHE_WAY_SIZE > PAGE_SIZE)
-# define _PAGE_DIRECTORY (_PAGE_VALID | _PAGE_ACCESSED)
+# define _PAGE_DIRECTORY   (_PAGE_HW_VALID | _PAGE_ACCESSED | _PAGE_CA_BYPASS)
 #else
-# define _PAGE_DIRECTORY (_PAGE_VALID | _PAGE_ACCESSED | _PAGE_CA_WB)
+# define _PAGE_DIRECTORY   (_PAGE_HW_VALID | _PAGE_ACCESSED | _PAGE_CA_WB)
 #endif
 
 #else /* no mmu */
@@ -202,12 +236,16 @@ static inline void pgtable_cache_init(void) { }
 /*
  * pte status.
  */
-#define pte_none(pte)   (pte_val(pte) == _PAGE_INVALID)
-#define pte_present(pte)                                               \
-       (((pte_val(pte) & _PAGE_CA_MASK) != _PAGE_INVALID)              \
-        || ((pte_val(pte) & _PAGE_PROTNONE) == _PAGE_PROTNONE))
+# define pte_none(pte)  (pte_val(pte) == (_PAGE_CA_INVALID | _PAGE_USER))
+#if XCHAL_HW_VERSION_MAJOR < 2000
+# define pte_present(pte) ((pte_val(pte) & _PAGE_CA_MASK) != _PAGE_CA_INVALID)
+#else
+# define pte_present(pte)                                              \
+       (((pte_val(pte) & _PAGE_CA_MASK) != _PAGE_CA_INVALID)           \
+        || ((pte_val(pte) & _PAGE_ATTRIB_MASK) == _PAGE_NONE))
+#endif
 #define pte_clear(mm,addr,ptep)                                                \
-       do { update_pte(ptep, __pte(_PAGE_INVALID)); } while(0)
+       do { update_pte(ptep, __pte(_PAGE_CA_INVALID | _PAGE_USER)); } while (0)
 
 #define pmd_none(pmd)   (!pmd_val(pmd))
 #define pmd_present(pmd) (pmd_val(pmd) & PAGE_MASK)
@@ -328,35 +366,23 @@ ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
 
 
 /*
- * Encode and decode a swap entry.
- *
- * Format of swap pte:
- *  bit           0       MBZ
- *  bit           1       page-file (must be zero)
- *  bits   2 -  3  page hw access mode (must be 11: _PAGE_INVALID)
- *  bits   4 -  5  ring protection (must be 01: _PAGE_USER)
- *  bits   6 - 10  swap type (5 bits -> 32 types)
- *  bits  11 - 31  swap offset / PAGE_SIZE (21 bits -> 8GB)
- * Format of file pte:
- *  bit           0       MBZ
- *  bit           1       page-file (must be one: _PAGE_FILE)
- *  bits   2 -  3  page hw access mode (must be 11: _PAGE_INVALID)
- *  bits   4 -  5  ring protection (must be 01: _PAGE_USER)
- *  bits   6 - 31  file offset / PAGE_SIZE
+ * Encode and decode a swap and file entry.
  */
+#define SWP_TYPE_BITS          5
+#define MAX_SWAPFILES_CHECK() BUILD_BUG_ON(MAX_SWAPFILES_SHIFT > SWP_TYPE_BITS)
 
 #define __swp_type(entry)      (((entry).val >> 6) & 0x1f)
 #define __swp_offset(entry)    ((entry).val >> 11)
 #define __swp_entry(type,offs) \
-       ((swp_entry_t) {((type) << 6) | ((offs) << 11) | _PAGE_INVALID})
+       ((swp_entry_t){((type) << 6) | ((offs) << 11) | \
+        _PAGE_CA_INVALID | _PAGE_USER})
 #define __pte_to_swp_entry(pte)        ((swp_entry_t) { pte_val(pte) })
 #define __swp_entry_to_pte(x)  ((pte_t) { (x).val })
 
-#define PTE_FILE_MAX_BITS      28
-#define pte_to_pgoff(pte)      (pte_val(pte) >> 4)
+#define PTE_FILE_MAX_BITS      26
+#define pte_to_pgoff(pte)      (pte_val(pte) >> 6)
 #define pgoff_to_pte(off)      \
-       ((pte_t) { ((off) << 4) | _PAGE_INVALID | _PAGE_FILE })
+       ((pte_t) { ((off) << 6) | _PAGE_CA_INVALID | _PAGE_FILE | _PAGE_USER })
 
 #endif /*  !defined (__ASSEMBLY__) */
 
index ec098b6..32e98f2 100644 (file)
@@ -30,11 +30,6 @@ extern void platform_init(bp_tag_t*);
 extern void platform_setup (char **);
 
 /*
- * platform_init_irq is called from init_IRQ.
- */
-extern void platform_init_irq (void);
-
-/*
  * platform_restart is called to restart the system.
  */
 extern void platform_restart (void);
index 3d35e5d..69f9017 100644 (file)
 # error "Bad timer number for Linux configurations!"
 #endif
 
-#define LINUX_TIMER_MASK        (1L << LINUX_TIMER_INT)
-
-#define CLOCK_TICK_RATE        1193180 /* (everyone is using this value) */
-#define CLOCK_TICK_FACTOR       20 /* Factor of both 10^6 and CLOCK_TICK_RATE */
-
 #ifdef CONFIG_XTENSA_CALIBRATE_CCOUNT
-extern unsigned long ccount_per_jiffy;
-extern unsigned long nsec_per_ccount;
-#define CCOUNT_PER_JIFFY ccount_per_jiffy
-#define NSEC_PER_CCOUNT  nsec_per_ccount
+extern unsigned long ccount_freq;
+#define CCOUNT_PER_JIFFY (ccount_freq / HZ)
 #else
 #define CCOUNT_PER_JIFFY (CONFIG_XTENSA_CPU_CLOCK*(1000000UL/HZ))
-#define NSEC_PER_CCOUNT (1000UL / CONFIG_XTENSA_CPU_CLOCK)
 #endif
 
 
index b21ace4..c114483 100644 (file)
@@ -85,6 +85,6 @@
 
 #define SO_SELECT_ERR_QUEUE    45
 
-#define SO_LL                  46
+#define SO_BUSY_POLL           46
 
 #endif /* _XTENSA_SOCKET_H */
diff --git a/arch/xtensa/kernel/.gitignore b/arch/xtensa/kernel/.gitignore
new file mode 100644 (file)
index 0000000..c5f676c
--- /dev/null
@@ -0,0 +1 @@
+vmlinux.lds
index 1e7fc87..f90265e 100644 (file)
@@ -11,6 +11,7 @@ obj-y := align.o coprocessor.o entry.o irq.o pci-dma.o platform.o process.o \
 obj-$(CONFIG_KGDB) += xtensa-stub.o
 obj-$(CONFIG_PCI) += pci.o
 obj-$(CONFIG_MODULES) += xtensa_ksyms.o module.o
+obj-$(CONFIG_FUNCTION_TRACER) += mcount.o
 
 AFLAGS_head.o += -mtext-section-literals
 
index 5082507..9298742 100644 (file)
@@ -458,7 +458,7 @@ common_exception_return:
 
        _bbsi.l a4, TIF_NEED_RESCHED, 3f
        _bbsi.l a4, TIF_NOTIFY_RESUME, 2f
-       _bbci.l a4, TIF_SIGPENDING, 4f
+       _bbci.l a4, TIF_SIGPENDING, 5f
 
 2:     l32i    a4, a1, PT_DEPC
        bgeui   a4, VALID_DOUBLE_EXCEPTION_ADDRESS, 4f
@@ -476,6 +476,13 @@ common_exception_return:
        callx4  a4
        j       1b
 
+5:
+#ifdef CONFIG_DEBUG_TLB_SANITY
+       l32i    a4, a1, PT_DEPC
+       bgeui   a4, VALID_DOUBLE_EXCEPTION_ADDRESS, 4f
+       movi    a4, check_tlb_sanity
+       callx4  a4
+#endif
 4:     /* Restore optional registers. */
 
        load_xtregs_opt a1 a2 a4 a5 a6 a7 PT_XTREGS_OPT
@@ -1792,10 +1799,15 @@ ENTRY(fast_store_prohibited)
        l32i    a0, a0, 0
        beqz    a0, 2f
 
-       /* Note that we assume _PAGE_WRITABLE_BIT is only set if pte is valid.*/
+       /*
+        * Note that we test _PAGE_WRITABLE_BIT only if PTE is present
+        * and is not PAGE_NONE. See pgtable.h for possible PTE layouts.
+        */
 
        _PTE_OFFSET(a0, a1, a4)
        l32i    a4, a0, 0               # read pteval
+       movi    a1, _PAGE_CA_INVALID
+       ball    a4, a1, 2f
        bbci.l  a4, _PAGE_WRITABLE_BIT, 2f
 
        movi    a1, _PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_HW_WRITE
index ef12c0e..7d740eb 100644 (file)
@@ -68,6 +68,15 @@ _SetupMMU:
 
 #ifdef CONFIG_INITIALIZE_XTENSA_MMU_INSIDE_VMLINUX
        initialize_mmu
+#if defined(CONFIG_MMU) && XCHAL_HAVE_PTP_MMU && XCHAL_HAVE_SPANNING_WAY
+       rsr     a2, excsave1
+       movi    a3, 0x08000000
+       bgeu    a2, a3, 1f
+       movi    a3, 0xd0000000
+       add     a2, a2, a3
+       wsr     a2, excsave1
+1:
+#endif
 #endif
        .end    no-absolute-literals
 
diff --git a/arch/xtensa/kernel/mcount.S b/arch/xtensa/kernel/mcount.S
new file mode 100644 (file)
index 0000000..0eeda2e
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * arch/xtensa/kernel/mcount.S
+ *
+ * Xtensa specific mcount support
+ *
+ * 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) 2013 Tensilica Inc.
+ */
+
+#include <linux/linkage.h>
+#include <asm/ftrace.h>
+
+/*
+ * Entry condition:
+ *
+ *   a2:       a0 of the caller
+ */
+
+ENTRY(_mcount)
+
+       entry   a1, 16
+
+       movi    a4, ftrace_trace_function
+       l32i    a4, a4, 0
+       movi    a3, ftrace_stub
+       bne     a3, a4, 1f
+       retw
+
+1:     xor     a7, a2, a1
+       movi    a3, 0x3fffffff
+       and     a7, a7, a3
+       xor     a7, a7, a1
+
+       xor     a6, a0, a1
+       and     a6, a6, a3
+       xor     a6, a6, a1
+       addi    a6, a6, -MCOUNT_INSN_SIZE
+       callx4  a4
+
+       retw
+
+ENDPROC(_mcount)
+
+ENTRY(ftrace_stub)
+       entry   a1, 16
+       retw
+ENDPROC(ftrace_stub)
index 126c188..5b34033 100644 (file)
@@ -77,9 +77,9 @@ pcibios_align_resource(void *data, const struct resource *res,
 
        if (res->flags & IORESOURCE_IO) {
                if (size > 0x100) {
-                       printk(KERN_ERR "PCI: I/O Region %s/%d too large"
-                              " (%ld bytes)\n", pci_name(dev),
-                              dev->resource - res, size);
+                       pr_err("PCI: I/O Region %s/%d too large (%u bytes)\n",
+                                       pci_name(dev), dev->resource - res,
+                                       size);
                }
 
                if (start & 0x300)
@@ -174,7 +174,7 @@ static int __init pcibios_init(void)
        struct pci_controller *pci_ctrl;
        struct list_head resources;
        struct pci_bus *bus;
-       int next_busno = 0, i;
+       int next_busno = 0;
 
        printk("PCI: Probing PCI hardware\n");
 
@@ -197,7 +197,7 @@ static int __init pcibios_init(void)
 
 subsys_initcall(pcibios_init);
 
-void __init pcibios_fixup_bus(struct pci_bus *bus)
+void pcibios_fixup_bus(struct pci_bus *bus)
 {
        if (bus->parent) {
                /* This is a subordinate bridge */
index 2bd6c35..1cf0082 100644 (file)
@@ -29,7 +29,6 @@
  */
 
 _F(void, setup, (char** cmd), { });
-_F(void, init_irq, (void), { });
 _F(void, restart, (void), { while(1); });
 _F(void, halt, (void), { while(1); });
 _F(void, power_off, (void), { while(1); });
@@ -42,6 +41,6 @@ _F(void, pcibios_init, (void), { });
 _F(void, calibrate_ccount, (void),
 {
        pr_err("ERROR: Cannot calibrate cpu frequency! Assuming 10MHz.\n");
-       ccount_per_jiffy = 10 * (1000000UL/HZ);
+       ccount_freq = 10 * 1000000UL;
 });
 #endif
index 6dd25ec..42a8bba 100644 (file)
@@ -152,8 +152,8 @@ static int __init parse_tag_initrd(const bp_tag_t* tag)
 {
        meminfo_t* mi;
        mi = (meminfo_t*)(tag->data);
-       initrd_start = (void*)(mi->start);
-       initrd_end = (void*)(mi->end);
+       initrd_start = __va(mi->start);
+       initrd_end = __va(mi->end);
 
        return 0;
 }
@@ -164,7 +164,7 @@ __tagtable(BP_TAG_INITRD, parse_tag_initrd);
 
 static int __init parse_tag_fdt(const bp_tag_t *tag)
 {
-       dtb_start = (void *)(tag->data[0]);
+       dtb_start = __va(tag->data[0]);
        return 0;
 }
 
@@ -256,7 +256,7 @@ void __init early_init_devtree(void *params)
 static void __init copy_devtree(void)
 {
        void *alloc = early_init_dt_alloc_memory_arch(
-                       be32_to_cpu(initial_boot_params->totalsize), 0);
+                       be32_to_cpu(initial_boot_params->totalsize), 8);
        if (alloc) {
                memcpy(alloc, initial_boot_params,
                                be32_to_cpu(initial_boot_params->totalsize));
index ffb4741..bdbb173 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/sched.h>
 #include <linux/time.h>
 #include <linux/clocksource.h>
+#include <linux/clockchips.h>
 #include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/profile.h>
 #include <linux/delay.h>
 #include <linux/irqdomain.h>
+#include <linux/sched_clock.h>
 
 #include <asm/timex.h>
 #include <asm/platform.h>
 
 #ifdef CONFIG_XTENSA_CALIBRATE_CCOUNT
-unsigned long ccount_per_jiffy;                /* per 1/HZ */
-unsigned long nsec_per_ccount;         /* nsec per ccount increment */
+unsigned long ccount_freq;             /* ccount Hz */
 #endif
 
 static cycle_t ccount_read(struct clocksource *cs)
@@ -37,6 +38,11 @@ static cycle_t ccount_read(struct clocksource *cs)
        return (cycle_t)get_ccount();
 }
 
+static u32 notrace ccount_sched_clock_read(void)
+{
+       return get_ccount();
+}
+
 static struct clocksource ccount_clocksource = {
        .name = "ccount",
        .rating = 200,
@@ -44,29 +50,98 @@ static struct clocksource ccount_clocksource = {
        .mask = CLOCKSOURCE_MASK(32),
 };
 
+static int ccount_timer_set_next_event(unsigned long delta,
+               struct clock_event_device *dev);
+static void ccount_timer_set_mode(enum clock_event_mode mode,
+               struct clock_event_device *evt);
+static struct ccount_timer_t {
+       struct clock_event_device evt;
+       int irq_enabled;
+} ccount_timer = {
+       .evt = {
+               .name           = "ccount_clockevent",
+               .features       = CLOCK_EVT_FEAT_ONESHOT,
+               .rating         = 300,
+               .set_next_event = ccount_timer_set_next_event,
+               .set_mode       = ccount_timer_set_mode,
+       },
+};
+
+static int ccount_timer_set_next_event(unsigned long delta,
+               struct clock_event_device *dev)
+{
+       unsigned long flags, next;
+       int ret = 0;
+
+       local_irq_save(flags);
+       next = get_ccount() + delta;
+       set_linux_timer(next);
+       if (next - get_ccount() > delta)
+               ret = -ETIME;
+       local_irq_restore(flags);
+
+       return ret;
+}
+
+static void ccount_timer_set_mode(enum clock_event_mode mode,
+               struct clock_event_device *evt)
+{
+       struct ccount_timer_t *timer =
+               container_of(evt, struct ccount_timer_t, evt);
+
+       /*
+        * There is no way to disable the timer interrupt at the device level,
+        * only at the intenable register itself. Since enable_irq/disable_irq
+        * calls are nested, we need to make sure that these calls are
+        * balanced.
+        */
+       switch (mode) {
+       case CLOCK_EVT_MODE_SHUTDOWN:
+       case CLOCK_EVT_MODE_UNUSED:
+               if (timer->irq_enabled) {
+                       disable_irq(evt->irq);
+                       timer->irq_enabled = 0;
+               }
+               break;
+       case CLOCK_EVT_MODE_RESUME:
+       case CLOCK_EVT_MODE_ONESHOT:
+               if (!timer->irq_enabled) {
+                       enable_irq(evt->irq);
+                       timer->irq_enabled = 1;
+               }
+       default:
+               break;
+       }
+}
+
 static irqreturn_t timer_interrupt(int irq, void *dev_id);
 static struct irqaction timer_irqaction = {
        .handler =      timer_interrupt,
-       .flags =        IRQF_DISABLED,
+       .flags =        IRQF_TIMER,
        .name =         "timer",
+       .dev_id =       &ccount_timer,
 };
 
 void __init time_init(void)
 {
-       unsigned int irq;
 #ifdef CONFIG_XTENSA_CALIBRATE_CCOUNT
        printk("Calibrating CPU frequency ");
        platform_calibrate_ccount();
-       printk("%d.%02d MHz\n", (int)ccount_per_jiffy/(1000000/HZ),
-                       (int)(ccount_per_jiffy/(10000/HZ))%100);
+       printk("%d.%02d MHz\n", (int)ccount_freq/1000000,
+                       (int)(ccount_freq/10000)%100);
 #endif
        clocksource_register_hz(&ccount_clocksource, CCOUNT_PER_JIFFY * HZ);
 
-       /* Initialize the linux timer interrupt. */
+       ccount_timer.evt.cpumask = cpumask_of(0);
+       ccount_timer.evt.irq = irq_create_mapping(NULL, LINUX_TIMER_INT);
+       if (WARN(!ccount_timer.evt.irq, "error: can't map timer irq"))
+               return;
+       clockevents_config_and_register(&ccount_timer.evt, ccount_freq, 0xf,
+                       0xffffffff);
+       setup_irq(ccount_timer.evt.irq, &timer_irqaction);
+       ccount_timer.irq_enabled = 1;
 
-       irq = irq_create_mapping(NULL, LINUX_TIMER_INT);
-       setup_irq(irq, &timer_irqaction);
-       set_linux_timer(get_ccount() + CCOUNT_PER_JIFFY);
+       setup_sched_clock(ccount_sched_clock_read, 32, ccount_freq);
 }
 
 /*
@@ -75,36 +150,14 @@ void __init time_init(void)
 
 irqreturn_t timer_interrupt (int irq, void *dev_id)
 {
+       struct ccount_timer_t *timer = dev_id;
+       struct clock_event_device *evt = &timer->evt;
 
-       unsigned long next;
-
-       next = get_linux_timer();
-
-again:
-       while ((signed long)(get_ccount() - next) > 0) {
-
-               profile_tick(CPU_PROFILING);
-#ifndef CONFIG_SMP
-               update_process_times(user_mode(get_irq_regs()));
-#endif
-
-               xtime_update(1); /* Linux handler in kernel/time/timekeeping */
-
-               /* Note that writing CCOMPARE clears the interrupt. */
-
-               next += CCOUNT_PER_JIFFY;
-               set_linux_timer(next);
-       }
+       evt->event_handler(evt);
 
        /* Allow platform to do something useful (Wdog). */
-
        platform_heartbeat();
 
-       /* Make sure we didn't miss any tick... */
-
-       if ((signed long)(get_ccount() - next) > 0)
-               goto again;
-
        return IRQ_HANDLED;
 }
 
index 42c53c8..d8507f8 100644 (file)
@@ -124,3 +124,7 @@ extern long common_exception_return;
 extern long _spill_registers;
 EXPORT_SYMBOL(common_exception_return);
 EXPORT_SYMBOL(_spill_registers);
+
+#ifdef CONFIG_FUNCTION_TRACER
+EXPORT_SYMBOL(_mcount);
+#endif
index 5411aa6..ca9d236 100644 (file)
@@ -64,7 +64,7 @@ void flush_tlb_mm(struct mm_struct *mm)
 {
        if (mm == current->active_mm) {
                unsigned long flags;
-               local_save_flags(flags);
+               local_irq_save(flags);
                __get_new_mmu_context(mm);
                __load_mmu_context(mm);
                local_irq_restore(flags);
@@ -94,7 +94,7 @@ void flush_tlb_range (struct vm_area_struct *vma,
        printk("[tlbrange<%02lx,%08lx,%08lx>]\n",
                        (unsigned long)mm->context, start, end);
 #endif
-       local_save_flags(flags);
+       local_irq_save(flags);
 
        if (end-start + (PAGE_SIZE-1) <= _TLB_ENTRIES << PAGE_SHIFT) {
                int oldpid = get_rasid_register();
@@ -128,9 +128,10 @@ void flush_tlb_page (struct vm_area_struct *vma, unsigned long page)
        if(mm->context == NO_CONTEXT)
                return;
 
-       local_save_flags(flags);
+       local_irq_save(flags);
 
        oldpid = get_rasid_register();
+       set_rasid_register(ASID_INSERT(mm->context));
 
        if (vma->vm_flags & VM_EXEC)
                invalidate_itlb_mapping(page);
@@ -140,3 +141,116 @@ void flush_tlb_page (struct vm_area_struct *vma, unsigned long page)
 
        local_irq_restore(flags);
 }
+
+#ifdef CONFIG_DEBUG_TLB_SANITY
+
+static unsigned get_pte_for_vaddr(unsigned vaddr)
+{
+       struct task_struct *task = get_current();
+       struct mm_struct *mm = task->mm;
+       pgd_t *pgd;
+       pmd_t *pmd;
+       pte_t *pte;
+
+       if (!mm)
+               mm = task->active_mm;
+       pgd = pgd_offset(mm, vaddr);
+       if (pgd_none_or_clear_bad(pgd))
+               return 0;
+       pmd = pmd_offset(pgd, vaddr);
+       if (pmd_none_or_clear_bad(pmd))
+               return 0;
+       pte = pte_offset_map(pmd, vaddr);
+       if (!pte)
+               return 0;
+       return pte_val(*pte);
+}
+
+enum {
+       TLB_SUSPICIOUS  = 1,
+       TLB_INSANE      = 2,
+};
+
+static void tlb_insane(void)
+{
+       BUG_ON(1);
+}
+
+static void tlb_suspicious(void)
+{
+       WARN_ON(1);
+}
+
+/*
+ * Check that TLB entries with kernel ASID (1) have kernel VMA (>= TASK_SIZE),
+ * and TLB entries with user ASID (>=4) have VMA < TASK_SIZE.
+ *
+ * Check that valid TLB entries either have the same PA as the PTE, or PTE is
+ * marked as non-present. Non-present PTE and the page with non-zero refcount
+ * and zero mapcount is normal for batched TLB flush operation. Zero refcount
+ * means that the page was freed prematurely. Non-zero mapcount is unusual,
+ * but does not necessary means an error, thus marked as suspicious.
+ */
+static int check_tlb_entry(unsigned w, unsigned e, bool dtlb)
+{
+       unsigned tlbidx = w | (e << PAGE_SHIFT);
+       unsigned r0 = dtlb ?
+               read_dtlb_virtual(tlbidx) : read_itlb_virtual(tlbidx);
+       unsigned vpn = (r0 & PAGE_MASK) | (e << PAGE_SHIFT);
+       unsigned pte = get_pte_for_vaddr(vpn);
+       unsigned mm_asid = (get_rasid_register() >> 8) & ASID_MASK;
+       unsigned tlb_asid = r0 & ASID_MASK;
+       bool kernel = tlb_asid == 1;
+       int rc = 0;
+
+       if (tlb_asid > 0 && ((vpn < TASK_SIZE) == kernel)) {
+               pr_err("%cTLB: way: %u, entry: %u, VPN %08x in %s PTE\n",
+                               dtlb ? 'D' : 'I', w, e, vpn,
+                               kernel ? "kernel" : "user");
+               rc |= TLB_INSANE;
+       }
+
+       if (tlb_asid == mm_asid) {
+               unsigned r1 = dtlb ? read_dtlb_translation(tlbidx) :
+                       read_itlb_translation(tlbidx);
+               if ((pte ^ r1) & PAGE_MASK) {
+                       pr_err("%cTLB: way: %u, entry: %u, mapping: %08x->%08x, PTE: %08x\n",
+                                       dtlb ? 'D' : 'I', w, e, r0, r1, pte);
+                       if (pte == 0 || !pte_present(__pte(pte))) {
+                               struct page *p = pfn_to_page(r1 >> PAGE_SHIFT);
+                               pr_err("page refcount: %d, mapcount: %d\n",
+                                               page_count(p),
+                                               page_mapcount(p));
+                               if (!page_count(p))
+                                       rc |= TLB_INSANE;
+                               else if (page_mapped(p))
+                                       rc |= TLB_SUSPICIOUS;
+                       } else {
+                               rc |= TLB_INSANE;
+                       }
+               }
+       }
+       return rc;
+}
+
+void check_tlb_sanity(void)
+{
+       unsigned long flags;
+       unsigned w, e;
+       int bug = 0;
+
+       local_irq_save(flags);
+       for (w = 0; w < DTLB_ARF_WAYS; ++w)
+               for (e = 0; e < (1 << XCHAL_DTLB_ARF_ENTRIES_LOG2); ++e)
+                       bug |= check_tlb_entry(w, e, true);
+       for (w = 0; w < ITLB_ARF_WAYS; ++w)
+               for (e = 0; e < (1 << XCHAL_ITLB_ARF_ENTRIES_LOG2); ++e)
+                       bug |= check_tlb_entry(w, e, false);
+       if (bug & TLB_INSANE)
+               tlb_insane();
+       if (bug & TLB_SUSPICIOUS)
+               tlb_suspicious();
+       local_irq_restore(flags);
+}
+
+#endif /* CONFIG_DEBUG_TLB_SANITY */
index 7d0fea6..56f88b7 100644 (file)
@@ -700,7 +700,7 @@ struct iss_net_init {
 
 #define ERR KERN_ERR "iss_net_setup: "
 
-static int iss_net_setup(char *str)
+static int __init iss_net_setup(char *str)
 {
        struct iss_net_private *device = NULL;
        struct iss_net_init *new;
index c0edb35..8c6e819 100644 (file)
@@ -108,13 +108,13 @@ static int simdisk_xfer_bio(struct simdisk *dev, struct bio *bio)
        sector_t sector = bio->bi_sector;
 
        bio_for_each_segment(bvec, bio, i) {
-               char *buffer = __bio_kmap_atomic(bio, i, KM_USER0);
+               char *buffer = __bio_kmap_atomic(bio, i);
                unsigned len = bvec->bv_len >> SECTOR_SHIFT;
 
                simdisk_transfer(dev, sector, len, buffer,
                                bio_data_dir(bio) == WRITE);
                sector += len;
-               __bio_kunmap_atomic(bio, KM_USER0);
+               __bio_kunmap_atomic(bio);
        }
        return 0;
 }
index 96ef8ee..74bb74f 100644 (file)
@@ -163,7 +163,7 @@ void platform_heartbeat(void)
 
 #ifdef CONFIG_XTENSA_CALIBRATE_CCOUNT
 
-void platform_calibrate_ccount(void)
+void __init platform_calibrate_ccount(void)
 {
        long clk_freq = 0;
 #ifdef CONFIG_OF
@@ -179,8 +179,7 @@ void platform_calibrate_ccount(void)
        if (!clk_freq)
                clk_freq = *(long *)XTFPGA_CLKFRQ_VADDR;
 
-       ccount_per_jiffy = clk_freq / HZ;
-       nsec_per_ccount = 1000000000UL / clk_freq;
+       ccount_freq = clk_freq;
 }
 
 #endif
index 54b2b57..3915456 100644 (file)
@@ -1,4 +1,3 @@
-#include <asm/delay.h>
 #include <asm/timex.h>
 #include <asm/io.h>
 #include <variant/hardware.h>
@@ -17,11 +16,10 @@ void platform_calibrate_ccount(void)
                "1:     l32i %0, %2, 0 ;"
                "       beq %0, %1, 1b ;"
                : "=&a"(u) : "a"(t), "a"(tstamp));
-               b = xtensa_get_ccount();
+               b = get_ccount();
                if (i == LOOPS)
                        a = b;
        } while (--i >= 0);
        b -= a;
-       nsec_per_ccount = (LOOPS * 10000) / b;
-       ccount_per_jiffy = b * (100000UL / (LOOPS * HZ));
+       ccount_freq = b * (100000UL / LOOPS);
 }
index e8918ff..290792a 100644 (file)
@@ -32,26 +32,6 @@ EXPORT_SYMBOL_GPL(blkcg_root);
 
 static struct blkcg_policy *blkcg_policy[BLKCG_MAX_POLS];
 
-static struct blkcg_gq *__blkg_lookup(struct blkcg *blkcg,
-                                     struct request_queue *q, bool update_hint);
-
-/**
- * blkg_for_each_descendant_pre - pre-order walk of a blkg's descendants
- * @d_blkg: loop cursor pointing to the current descendant
- * @pos_cgrp: used for iteration
- * @p_blkg: target blkg to walk descendants of
- *
- * Walk @c_blkg through the descendants of @p_blkg.  Must be used with RCU
- * read locked.  If called under either blkcg or queue lock, the iteration
- * is guaranteed to include all and only online blkgs.  The caller may
- * update @pos_cgrp by calling cgroup_rightmost_descendant() to skip
- * subtree.
- */
-#define blkg_for_each_descendant_pre(d_blkg, pos_cgrp, p_blkg)         \
-       cgroup_for_each_descendant_pre((pos_cgrp), (p_blkg)->blkcg->css.cgroup) \
-               if (((d_blkg) = __blkg_lookup(cgroup_to_blkcg(pos_cgrp), \
-                                             (p_blkg)->q, false)))
-
 static bool blkcg_policy_enabled(struct request_queue *q,
                                 const struct blkcg_policy *pol)
 {
@@ -71,18 +51,8 @@ static void blkg_free(struct blkcg_gq *blkg)
        if (!blkg)
                return;
 
-       for (i = 0; i < BLKCG_MAX_POLS; i++) {
-               struct blkcg_policy *pol = blkcg_policy[i];
-               struct blkg_policy_data *pd = blkg->pd[i];
-
-               if (!pd)
-                       continue;
-
-               if (pol && pol->pd_exit_fn)
-                       pol->pd_exit_fn(blkg);
-
-               kfree(pd);
-       }
+       for (i = 0; i < BLKCG_MAX_POLS; i++)
+               kfree(blkg->pd[i]);
 
        blk_exit_rl(&blkg->rl);
        kfree(blkg);
@@ -134,10 +104,6 @@ static struct blkcg_gq *blkg_alloc(struct blkcg *blkcg, struct request_queue *q,
                blkg->pd[i] = pd;
                pd->blkg = blkg;
                pd->plid = i;
-
-               /* invoke per-policy init */
-               if (pol->pd_init_fn)
-                       pol->pd_init_fn(blkg);
        }
 
        return blkg;
@@ -158,8 +124,8 @@ err_free:
  * @q's bypass state.  If @update_hint is %true, the caller should be
  * holding @q->queue_lock and lookup hint is updated on success.
  */
-static struct blkcg_gq *__blkg_lookup(struct blkcg *blkcg,
-                                     struct request_queue *q, bool update_hint)
+struct blkcg_gq *__blkg_lookup(struct blkcg *blkcg, struct request_queue *q,
+                              bool update_hint)
 {
        struct blkcg_gq *blkg;
 
@@ -234,16 +200,25 @@ static struct blkcg_gq *blkg_create(struct blkcg *blkcg,
        }
        blkg = new_blkg;
 
-       /* link parent and insert */
+       /* link parent */
        if (blkcg_parent(blkcg)) {
                blkg->parent = __blkg_lookup(blkcg_parent(blkcg), q, false);
                if (WARN_ON_ONCE(!blkg->parent)) {
-                       blkg = ERR_PTR(-EINVAL);
+                       ret = -EINVAL;
                        goto err_put_css;
                }
                blkg_get(blkg->parent);
        }
 
+       /* invoke per-policy init */
+       for (i = 0; i < BLKCG_MAX_POLS; i++) {
+               struct blkcg_policy *pol = blkcg_policy[i];
+
+               if (blkg->pd[i] && pol->pd_init_fn)
+                       pol->pd_init_fn(blkg);
+       }
+
+       /* insert */
        spin_lock(&blkcg->lock);
        ret = radix_tree_insert(&blkcg->blkg_tree, q->id, blkg);
        if (likely(!ret)) {
@@ -394,30 +369,38 @@ static void blkg_destroy_all(struct request_queue *q)
        q->root_rl.blkg = NULL;
 }
 
-static void blkg_rcu_free(struct rcu_head *rcu_head)
+/*
+ * A group is RCU protected, but having an rcu lock does not mean that one
+ * can access all the fields of blkg and assume these are valid.  For
+ * example, don't try to follow throtl_data and request queue links.
+ *
+ * Having a reference to blkg under an rcu allows accesses to only values
+ * local to groups like group stats and group rate limits.
+ */
+void __blkg_release_rcu(struct rcu_head *rcu_head)
 {
-       blkg_free(container_of(rcu_head, struct blkcg_gq, rcu_head));
-}
+       struct blkcg_gq *blkg = container_of(rcu_head, struct blkcg_gq, rcu_head);
+       int i;
+
+       /* tell policies that this one is being freed */
+       for (i = 0; i < BLKCG_MAX_POLS; i++) {
+               struct blkcg_policy *pol = blkcg_policy[i];
+
+               if (blkg->pd[i] && pol->pd_exit_fn)
+                       pol->pd_exit_fn(blkg);
+       }
 
-void __blkg_release(struct blkcg_gq *blkg)
-{
        /* release the blkcg and parent blkg refs this blkg has been holding */
        css_put(&blkg->blkcg->css);
-       if (blkg->parent)
+       if (blkg->parent) {
+               spin_lock_irq(blkg->q->queue_lock);
                blkg_put(blkg->parent);
+               spin_unlock_irq(blkg->q->queue_lock);
+       }
 
-       /*
-        * A group is freed in rcu manner. But having an rcu lock does not
-        * mean that one can access all the fields of blkg and assume these
-        * are valid. For example, don't try to follow throtl_data and
-        * request queue links.
-        *
-        * Having a reference to blkg under an rcu allows acess to only
-        * values local to groups like group stats and group rate limits
-        */
-       call_rcu(&blkg->rcu_head, blkg_rcu_free);
+       blkg_free(blkg);
 }
-EXPORT_SYMBOL_GPL(__blkg_release);
+EXPORT_SYMBOL_GPL(__blkg_release_rcu);
 
 /*
  * The next function used by blk_queue_for_each_rl().  It's a bit tricky
@@ -928,14 +911,6 @@ struct cgroup_subsys blkio_subsys = {
        .subsys_id = blkio_subsys_id,
        .base_cftypes = blkcg_files,
        .module = THIS_MODULE,
-
-       /*
-        * blkio subsystem is utterly broken in terms of hierarchy support.
-        * It treats all cgroups equally regardless of where they're
-        * located in the hierarchy - all cgroups are treated as if they're
-        * right below the root.  Fix it and remove the following.
-        */
-       .broken_hierarchy = true,
 };
 EXPORT_SYMBOL_GPL(blkio_subsys);
 
index 4e595ee..8056c03 100644 (file)
@@ -266,7 +266,7 @@ static inline void blkg_get(struct blkcg_gq *blkg)
        blkg->refcnt++;
 }
 
-void __blkg_release(struct blkcg_gq *blkg);
+void __blkg_release_rcu(struct rcu_head *rcu);
 
 /**
  * blkg_put - put a blkg reference
@@ -279,9 +279,43 @@ static inline void blkg_put(struct blkcg_gq *blkg)
        lockdep_assert_held(blkg->q->queue_lock);
        WARN_ON_ONCE(blkg->refcnt <= 0);
        if (!--blkg->refcnt)
-               __blkg_release(blkg);
+               call_rcu(&blkg->rcu_head, __blkg_release_rcu);
 }
 
+struct blkcg_gq *__blkg_lookup(struct blkcg *blkcg, struct request_queue *q,
+                              bool update_hint);
+
+/**
+ * blkg_for_each_descendant_pre - pre-order walk of a blkg's descendants
+ * @d_blkg: loop cursor pointing to the current descendant
+ * @pos_cgrp: used for iteration
+ * @p_blkg: target blkg to walk descendants of
+ *
+ * Walk @c_blkg through the descendants of @p_blkg.  Must be used with RCU
+ * read locked.  If called under either blkcg or queue lock, the iteration
+ * is guaranteed to include all and only online blkgs.  The caller may
+ * update @pos_cgrp by calling cgroup_rightmost_descendant() to skip
+ * subtree.
+ */
+#define blkg_for_each_descendant_pre(d_blkg, pos_cgrp, p_blkg)         \
+       cgroup_for_each_descendant_pre((pos_cgrp), (p_blkg)->blkcg->css.cgroup) \
+               if (((d_blkg) = __blkg_lookup(cgroup_to_blkcg(pos_cgrp), \
+                                             (p_blkg)->q, false)))
+
+/**
+ * blkg_for_each_descendant_post - post-order walk of a blkg's descendants
+ * @d_blkg: loop cursor pointing to the current descendant
+ * @pos_cgrp: used for iteration
+ * @p_blkg: target blkg to walk descendants of
+ *
+ * Similar to blkg_for_each_descendant_pre() but performs post-order
+ * traversal instead.  Synchronization rules are the same.
+ */
+#define blkg_for_each_descendant_post(d_blkg, pos_cgrp, p_blkg)                \
+       cgroup_for_each_descendant_post((pos_cgrp), (p_blkg)->blkcg->css.cgroup) \
+               if (((d_blkg) = __blkg_lookup(cgroup_to_blkcg(pos_cgrp), \
+                                             (p_blkg)->q, false)))
+
 /**
  * blk_get_rl - get request_list to use
  * @q: request_queue of interest
index cc345e1..3f33d86 100644 (file)
@@ -348,9 +348,16 @@ int blk_queue_start_tag(struct request_queue *q, struct request *rq)
         */
        max_depth = bqt->max_depth;
        if (!rq_is_sync(rq) && max_depth > 1) {
-               max_depth -= 2;
-               if (!max_depth)
+               switch (max_depth) {
+               case 2:
                        max_depth = 1;
+                       break;
+               case 3:
+                       max_depth = 2;
+                       break;
+               default:
+                       max_depth -= 2;
+               }
                if (q->in_flight[BLK_RW_ASYNC] > max_depth)
                        return 1;
        }
index 3114622..08a32df 100644 (file)
@@ -25,18 +25,61 @@ static struct blkcg_policy blkcg_policy_throtl;
 
 /* A workqueue to queue throttle related work */
 static struct workqueue_struct *kthrotld_workqueue;
-static void throtl_schedule_delayed_work(struct throtl_data *td,
-                               unsigned long delay);
-
-struct throtl_rb_root {
-       struct rb_root rb;
-       struct rb_node *left;
-       unsigned int count;
-       unsigned long min_disptime;
+
+/*
+ * To implement hierarchical throttling, throtl_grps form a tree and bios
+ * are dispatched upwards level by level until they reach the top and get
+ * issued.  When dispatching bios from the children and local group at each
+ * level, if the bios are dispatched into a single bio_list, there's a risk
+ * of a local or child group which can queue many bios at once filling up
+ * the list starving others.
+ *
+ * To avoid such starvation, dispatched bios are queued separately
+ * according to where they came from.  When they are again dispatched to
+ * the parent, they're popped in round-robin order so that no single source
+ * hogs the dispatch window.
+ *
+ * throtl_qnode is used to keep the queued bios separated by their sources.
+ * Bios are queued to throtl_qnode which in turn is queued to
+ * throtl_service_queue and then dispatched in round-robin order.
+ *
+ * It's also used to track the reference counts on blkg's.  A qnode always
+ * belongs to a throtl_grp and gets queued on itself or the parent, so
+ * incrementing the reference of the associated throtl_grp when a qnode is
+ * queued and decrementing when dequeued is enough to keep the whole blkg
+ * tree pinned while bios are in flight.
+ */
+struct throtl_qnode {
+       struct list_head        node;           /* service_queue->queued[] */
+       struct bio_list         bios;           /* queued bios */
+       struct throtl_grp       *tg;            /* tg this qnode belongs to */
 };
 
-#define THROTL_RB_ROOT (struct throtl_rb_root) { .rb = RB_ROOT, .left = NULL, \
-                       .count = 0, .min_disptime = 0}
+struct throtl_service_queue {
+       struct throtl_service_queue *parent_sq; /* the parent service_queue */
+
+       /*
+        * Bios queued directly to this service_queue or dispatched from
+        * children throtl_grp's.
+        */
+       struct list_head        queued[2];      /* throtl_qnode [READ/WRITE] */
+       unsigned int            nr_queued[2];   /* number of queued bios */
+
+       /*
+        * RB tree of active children throtl_grp's, which are sorted by
+        * their ->disptime.
+        */
+       struct rb_root          pending_tree;   /* RB tree of active tgs */
+       struct rb_node          *first_pending; /* first node in the tree */
+       unsigned int            nr_pending;     /* # queued in the tree */
+       unsigned long           first_pending_disptime; /* disptime of the first tg */
+       struct timer_list       pending_timer;  /* fires on first_pending_disptime */
+};
+
+enum tg_state_flags {
+       THROTL_TG_PENDING       = 1 << 0,       /* on parent's pending tree */
+       THROTL_TG_WAS_EMPTY     = 1 << 1,       /* bio_lists[] became non-empty */
+};
 
 #define rb_entry_tg(node)      rb_entry((node), struct throtl_grp, rb_node)
 
@@ -52,9 +95,26 @@ struct throtl_grp {
        /* must be the first member */
        struct blkg_policy_data pd;
 
-       /* active throtl group service_tree member */
+       /* active throtl group service_queue member */
        struct rb_node rb_node;
 
+       /* throtl_data this group belongs to */
+       struct throtl_data *td;
+
+       /* this group's service queue */
+       struct throtl_service_queue service_queue;
+
+       /*
+        * qnode_on_self is used when bios are directly queued to this
+        * throtl_grp so that local bios compete fairly with bios
+        * dispatched from children.  qnode_on_parent is used when bios are
+        * dispatched from this throtl_grp into its parent and will compete
+        * with the sibling qnode_on_parents and the parent's
+        * qnode_on_self.
+        */
+       struct throtl_qnode qnode_on_self[2];
+       struct throtl_qnode qnode_on_parent[2];
+
        /*
         * Dispatch time in jiffies. This is the estimated time when group
         * will unthrottle and is ready to dispatch more bio. It is used as
@@ -64,11 +124,8 @@ struct throtl_grp {
 
        unsigned int flags;
 
-       /* Two lists for READ and WRITE */
-       struct bio_list bio_lists[2];
-
-       /* Number of queued bios on READ and WRITE lists */
-       unsigned int nr_queued[2];
+       /* are there any throtl rules between this group and td? */
+       bool has_rules[2];
 
        /* bytes per second rate limits */
        uint64_t bps[2];
@@ -85,9 +142,6 @@ struct throtl_grp {
        unsigned long slice_start[2];
        unsigned long slice_end[2];
 
-       /* Some throttle limits got updated for the group */
-       int limits_changed;
-
        /* Per cpu stats pointer */
        struct tg_stats_cpu __percpu *stats_cpu;
 
@@ -98,7 +152,7 @@ struct throtl_grp {
 struct throtl_data
 {
        /* service tree for active throtl groups */
-       struct throtl_rb_root tg_service_tree;
+       struct throtl_service_queue service_queue;
 
        struct request_queue *queue;
 
@@ -111,9 +165,7 @@ struct throtl_data
        unsigned int nr_undestroyed_grps;
 
        /* Work for dispatching throttled bios */
-       struct delayed_work throtl_work;
-
-       int limits_changed;
+       struct work_struct dispatch_work;
 };
 
 /* list and work item to allocate percpu group stats */
@@ -123,6 +175,8 @@ static LIST_HEAD(tg_stats_alloc_list);
 static void tg_stats_alloc_fn(struct work_struct *);
 static DECLARE_DELAYED_WORK(tg_stats_alloc_work, tg_stats_alloc_fn);
 
+static void throtl_pending_timer_fn(unsigned long arg);
+
 static inline struct throtl_grp *pd_to_tg(struct blkg_policy_data *pd)
 {
        return pd ? container_of(pd, struct throtl_grp, pd) : NULL;
@@ -143,41 +197,65 @@ static inline struct throtl_grp *td_root_tg(struct throtl_data *td)
        return blkg_to_tg(td->queue->root_blkg);
 }
 
-enum tg_state_flags {
-       THROTL_TG_FLAG_on_rr = 0,       /* on round-robin busy list */
-};
-
-#define THROTL_TG_FNS(name)                                            \
-static inline void throtl_mark_tg_##name(struct throtl_grp *tg)                \
-{                                                                      \
-       (tg)->flags |= (1 << THROTL_TG_FLAG_##name);                    \
-}                                                                      \
-static inline void throtl_clear_tg_##name(struct throtl_grp *tg)       \
-{                                                                      \
-       (tg)->flags &= ~(1 << THROTL_TG_FLAG_##name);                   \
-}                                                                      \
-static inline int throtl_tg_##name(const struct throtl_grp *tg)                \
-{                                                                      \
-       return ((tg)->flags & (1 << THROTL_TG_FLAG_##name)) != 0;       \
+/**
+ * sq_to_tg - return the throl_grp the specified service queue belongs to
+ * @sq: the throtl_service_queue of interest
+ *
+ * Return the throtl_grp @sq belongs to.  If @sq is the top-level one
+ * embedded in throtl_data, %NULL is returned.
+ */
+static struct throtl_grp *sq_to_tg(struct throtl_service_queue *sq)
+{
+       if (sq && sq->parent_sq)
+               return container_of(sq, struct throtl_grp, service_queue);
+       else
+               return NULL;
 }
 
-THROTL_TG_FNS(on_rr);
+/**
+ * sq_to_td - return throtl_data the specified service queue belongs to
+ * @sq: the throtl_service_queue of interest
+ *
+ * A service_queue can be embeded in either a throtl_grp or throtl_data.
+ * Determine the associated throtl_data accordingly and return it.
+ */
+static struct throtl_data *sq_to_td(struct throtl_service_queue *sq)
+{
+       struct throtl_grp *tg = sq_to_tg(sq);
 
-#define throtl_log_tg(td, tg, fmt, args...)    do {                    \
-       char __pbuf[128];                                               \
+       if (tg)
+               return tg->td;
+       else
+               return container_of(sq, struct throtl_data, service_queue);
+}
+
+/**
+ * throtl_log - log debug message via blktrace
+ * @sq: the service_queue being reported
+ * @fmt: printf format string
+ * @args: printf args
+ *
+ * The messages are prefixed with "throtl BLKG_NAME" if @sq belongs to a
+ * throtl_grp; otherwise, just "throtl".
+ *
+ * TODO: this should be made a function and name formatting should happen
+ * after testing whether blktrace is enabled.
+ */
+#define throtl_log(sq, fmt, args...)   do {                            \
+       struct throtl_grp *__tg = sq_to_tg((sq));                       \
+       struct throtl_data *__td = sq_to_td((sq));                      \
+                                                                       \
+       (void)__td;                                                     \
+       if ((__tg)) {                                                   \
+               char __pbuf[128];                                       \
                                                                        \
-       blkg_path(tg_to_blkg(tg), __pbuf, sizeof(__pbuf));              \
-       blk_add_trace_msg((td)->queue, "throtl %s " fmt, __pbuf, ##args); \
+               blkg_path(tg_to_blkg(__tg), __pbuf, sizeof(__pbuf));    \
+               blk_add_trace_msg(__td->queue, "throtl %s " fmt, __pbuf, ##args); \
+       } else {                                                        \
+               blk_add_trace_msg(__td->queue, "throtl " fmt, ##args);  \
+       }                                                               \
 } while (0)
 
-#define throtl_log(td, fmt, args...)   \
-       blk_add_trace_msg((td)->queue, "throtl " fmt, ##args)
-
-static inline unsigned int total_nr_queued(struct throtl_data *td)
-{
-       return td->nr_queued[0] + td->nr_queued[1];
-}
-
 /*
  * Worker for allocating per cpu stat for tgs. This is scheduled on the
  * system_wq once there are some groups on the alloc_list waiting for
@@ -215,15 +293,141 @@ alloc_stats:
                goto alloc_stats;
 }
 
+static void throtl_qnode_init(struct throtl_qnode *qn, struct throtl_grp *tg)
+{
+       INIT_LIST_HEAD(&qn->node);
+       bio_list_init(&qn->bios);
+       qn->tg = tg;
+}
+
+/**
+ * throtl_qnode_add_bio - add a bio to a throtl_qnode and activate it
+ * @bio: bio being added
+ * @qn: qnode to add bio to
+ * @queued: the service_queue->queued[] list @qn belongs to
+ *
+ * Add @bio to @qn and put @qn on @queued if it's not already on.
+ * @qn->tg's reference count is bumped when @qn is activated.  See the
+ * comment on top of throtl_qnode definition for details.
+ */
+static void throtl_qnode_add_bio(struct bio *bio, struct throtl_qnode *qn,
+                                struct list_head *queued)
+{
+       bio_list_add(&qn->bios, bio);
+       if (list_empty(&qn->node)) {
+               list_add_tail(&qn->node, queued);
+               blkg_get(tg_to_blkg(qn->tg));
+       }
+}
+
+/**
+ * throtl_peek_queued - peek the first bio on a qnode list
+ * @queued: the qnode list to peek
+ */
+static struct bio *throtl_peek_queued(struct list_head *queued)
+{
+       struct throtl_qnode *qn = list_first_entry(queued, struct throtl_qnode, node);
+       struct bio *bio;
+
+       if (list_empty(queued))
+               return NULL;
+
+       bio = bio_list_peek(&qn->bios);
+       WARN_ON_ONCE(!bio);
+       return bio;
+}
+
+/**
+ * throtl_pop_queued - pop the first bio form a qnode list
+ * @queued: the qnode list to pop a bio from
+ * @tg_to_put: optional out argument for throtl_grp to put
+ *
+ * Pop the first bio from the qnode list @queued.  After popping, the first
+ * qnode is removed from @queued if empty or moved to the end of @queued so
+ * that the popping order is round-robin.
+ *
+ * When the first qnode is removed, its associated throtl_grp should be put
+ * too.  If @tg_to_put is NULL, this function automatically puts it;
+ * otherwise, *@tg_to_put is set to the throtl_grp to put and the caller is
+ * responsible for putting it.
+ */
+static struct bio *throtl_pop_queued(struct list_head *queued,
+                                    struct throtl_grp **tg_to_put)
+{
+       struct throtl_qnode *qn = list_first_entry(queued, struct throtl_qnode, node);
+       struct bio *bio;
+
+       if (list_empty(queued))
+               return NULL;
+
+       bio = bio_list_pop(&qn->bios);
+       WARN_ON_ONCE(!bio);
+
+       if (bio_list_empty(&qn->bios)) {
+               list_del_init(&qn->node);
+               if (tg_to_put)
+                       *tg_to_put = qn->tg;
+               else
+                       blkg_put(tg_to_blkg(qn->tg));
+       } else {
+               list_move_tail(&qn->node, queued);
+       }
+
+       return bio;
+}
+
+/* init a service_queue, assumes the caller zeroed it */
+static void throtl_service_queue_init(struct throtl_service_queue *sq,
+                                     struct throtl_service_queue *parent_sq)
+{
+       INIT_LIST_HEAD(&sq->queued[0]);
+       INIT_LIST_HEAD(&sq->queued[1]);
+       sq->pending_tree = RB_ROOT;
+       sq->parent_sq = parent_sq;
+       setup_timer(&sq->pending_timer, throtl_pending_timer_fn,
+                   (unsigned long)sq);
+}
+
+static void throtl_service_queue_exit(struct throtl_service_queue *sq)
+{
+       del_timer_sync(&sq->pending_timer);
+}
+
 static void throtl_pd_init(struct blkcg_gq *blkg)
 {
        struct throtl_grp *tg = blkg_to_tg(blkg);
+       struct throtl_data *td = blkg->q->td;
+       struct throtl_service_queue *parent_sq;
        unsigned long flags;
+       int rw;
+
+       /*
+        * If sane_hierarchy is enabled, we switch to properly hierarchical
+        * behavior where limits on a given throtl_grp are applied to the
+        * whole subtree rather than just the group itself.  e.g. If 16M
+        * read_bps limit is set on the root group, the whole system can't
+        * exceed 16M for the device.
+        *
+        * If sane_hierarchy is not enabled, the broken flat hierarchy
+        * behavior is retained where all throtl_grps are treated as if
+        * they're all separate root groups right below throtl_data.
+        * Limits of a group don't interact with limits of other groups
+        * regardless of the position of the group in the hierarchy.
+        */
+       parent_sq = &td->service_queue;
+
+       if (cgroup_sane_behavior(blkg->blkcg->css.cgroup) && blkg->parent)
+               parent_sq = &blkg_to_tg(blkg->parent)->service_queue;
+
+       throtl_service_queue_init(&tg->service_queue, parent_sq);
+
+       for (rw = READ; rw <= WRITE; rw++) {
+               throtl_qnode_init(&tg->qnode_on_self[rw], tg);
+               throtl_qnode_init(&tg->qnode_on_parent[rw], tg);
+       }
 
        RB_CLEAR_NODE(&tg->rb_node);
-       bio_list_init(&tg->bio_lists[0]);
-       bio_list_init(&tg->bio_lists[1]);
-       tg->limits_changed = false;
+       tg->td = td;
 
        tg->bps[READ] = -1;
        tg->bps[WRITE] = -1;
@@ -241,6 +445,30 @@ static void throtl_pd_init(struct blkcg_gq *blkg)
        spin_unlock_irqrestore(&tg_stats_alloc_lock, flags);
 }
 
+/*
+ * Set has_rules[] if @tg or any of its parents have limits configured.
+ * This doesn't require walking up to the top of the hierarchy as the
+ * parent's has_rules[] is guaranteed to be correct.
+ */
+static void tg_update_has_rules(struct throtl_grp *tg)
+{
+       struct throtl_grp *parent_tg = sq_to_tg(tg->service_queue.parent_sq);
+       int rw;
+
+       for (rw = READ; rw <= WRITE; rw++)
+               tg->has_rules[rw] = (parent_tg && parent_tg->has_rules[rw]) ||
+                                   (tg->bps[rw] != -1 || tg->iops[rw] != -1);
+}
+
+static void throtl_pd_online(struct blkcg_gq *blkg)
+{
+       /*
+        * We don't want new groups to escape the limits of its ancestors.
+        * Update has_rules[] after a new group is brought online.
+        */
+       tg_update_has_rules(blkg_to_tg(blkg));
+}
+
 static void throtl_pd_exit(struct blkcg_gq *blkg)
 {
        struct throtl_grp *tg = blkg_to_tg(blkg);
@@ -251,6 +479,8 @@ static void throtl_pd_exit(struct blkcg_gq *blkg)
        spin_unlock_irqrestore(&tg_stats_alloc_lock, flags);
 
        free_percpu(tg->stats_cpu);
+
+       throtl_service_queue_exit(&tg->service_queue);
 }
 
 static void throtl_pd_reset_stats(struct blkcg_gq *blkg)
@@ -309,17 +539,18 @@ static struct throtl_grp *throtl_lookup_create_tg(struct throtl_data *td,
        return tg;
 }
 
-static struct throtl_grp *throtl_rb_first(struct throtl_rb_root *root)
+static struct throtl_grp *
+throtl_rb_first(struct throtl_service_queue *parent_sq)
 {
        /* Service tree is empty */
-       if (!root->count)
+       if (!parent_sq->nr_pending)
                return NULL;
 
-       if (!root->left)
-               root->left = rb_first(&root->rb);
+       if (!parent_sq->first_pending)
+               parent_sq->first_pending = rb_first(&parent_sq->pending_tree);
 
-       if (root->left)
-               return rb_entry_tg(root->left);
+       if (parent_sq->first_pending)
+               return rb_entry_tg(parent_sq->first_pending);
 
        return NULL;
 }
@@ -330,29 +561,30 @@ static void rb_erase_init(struct rb_node *n, struct rb_root *root)
        RB_CLEAR_NODE(n);
 }
 
-static void throtl_rb_erase(struct rb_node *n, struct throtl_rb_root *root)
+static void throtl_rb_erase(struct rb_node *n,
+                           struct throtl_service_queue *parent_sq)
 {
-       if (root->left == n)
-               root->left = NULL;
-       rb_erase_init(n, &root->rb);
-       --root->count;
+       if (parent_sq->first_pending == n)
+               parent_sq->first_pending = NULL;
+       rb_erase_init(n, &parent_sq->pending_tree);
+       --parent_sq->nr_pending;
 }
 
-static void update_min_dispatch_time(struct throtl_rb_root *st)
+static void update_min_dispatch_time(struct throtl_service_queue *parent_sq)
 {
        struct throtl_grp *tg;
 
-       tg = throtl_rb_first(st);
+       tg = throtl_rb_first(parent_sq);
        if (!tg)
                return;
 
-       st->min_disptime = tg->disptime;
+       parent_sq->first_pending_disptime = tg->disptime;
 }
 
-static void
-tg_service_tree_add(struct throtl_rb_root *st, struct throtl_grp *tg)
+static void tg_service_queue_add(struct throtl_grp *tg)
 {
-       struct rb_node **node = &st->rb.rb_node;
+       struct throtl_service_queue *parent_sq = tg->service_queue.parent_sq;
+       struct rb_node **node = &parent_sq->pending_tree.rb_node;
        struct rb_node *parent = NULL;
        struct throtl_grp *__tg;
        unsigned long key = tg->disptime;
@@ -371,89 +603,135 @@ tg_service_tree_add(struct throtl_rb_root *st, struct throtl_grp *tg)
        }
 
        if (left)
-               st->left = &tg->rb_node;
+               parent_sq->first_pending = &tg->rb_node;
 
        rb_link_node(&tg->rb_node, parent, node);
-       rb_insert_color(&tg->rb_node, &st->rb);
+       rb_insert_color(&tg->rb_node, &parent_sq->pending_tree);
 }
 
-static void __throtl_enqueue_tg(struct throtl_data *td, struct throtl_grp *tg)
+static void __throtl_enqueue_tg(struct throtl_grp *tg)
 {
-       struct throtl_rb_root *st = &td->tg_service_tree;
+       tg_service_queue_add(tg);
+       tg->flags |= THROTL_TG_PENDING;
+       tg->service_queue.parent_sq->nr_pending++;
+}
 
-       tg_service_tree_add(st, tg);
-       throtl_mark_tg_on_rr(tg);
-       st->count++;
+static void throtl_enqueue_tg(struct throtl_grp *tg)
+{
+       if (!(tg->flags & THROTL_TG_PENDING))
+               __throtl_enqueue_tg(tg);
 }
 
-static void throtl_enqueue_tg(struct throtl_data *td, struct throtl_grp *tg)
+static void __throtl_dequeue_tg(struct throtl_grp *tg)
 {
-       if (!throtl_tg_on_rr(tg))
-               __throtl_enqueue_tg(td, tg);
+       throtl_rb_erase(&tg->rb_node, tg->service_queue.parent_sq);
+       tg->flags &= ~THROTL_TG_PENDING;
 }
 
-static void __throtl_dequeue_tg(struct throtl_data *td, struct throtl_grp *tg)
+static void throtl_dequeue_tg(struct throtl_grp *tg)
 {
-       throtl_rb_erase(&tg->rb_node, &td->tg_service_tree);
-       throtl_clear_tg_on_rr(tg);
+       if (tg->flags & THROTL_TG_PENDING)
+               __throtl_dequeue_tg(tg);
 }
 
-static void throtl_dequeue_tg(struct throtl_data *td, struct throtl_grp *tg)
+/* Call with queue lock held */
+static void throtl_schedule_pending_timer(struct throtl_service_queue *sq,
+                                         unsigned long expires)
 {
-       if (throtl_tg_on_rr(tg))
-               __throtl_dequeue_tg(td, tg);
+       mod_timer(&sq->pending_timer, expires);
+       throtl_log(sq, "schedule timer. delay=%lu jiffies=%lu",
+                  expires - jiffies, jiffies);
 }
 
-static void throtl_schedule_next_dispatch(struct throtl_data *td)
+/**
+ * throtl_schedule_next_dispatch - schedule the next dispatch cycle
+ * @sq: the service_queue to schedule dispatch for
+ * @force: force scheduling
+ *
+ * Arm @sq->pending_timer so that the next dispatch cycle starts on the
+ * dispatch time of the first pending child.  Returns %true if either timer
+ * is armed or there's no pending child left.  %false if the current
+ * dispatch window is still open and the caller should continue
+ * dispatching.
+ *
+ * If @force is %true, the dispatch timer is always scheduled and this
+ * function is guaranteed to return %true.  This is to be used when the
+ * caller can't dispatch itself and needs to invoke pending_timer
+ * unconditionally.  Note that forced scheduling is likely to induce short
+ * delay before dispatch starts even if @sq->first_pending_disptime is not
+ * in the future and thus shouldn't be used in hot paths.
+ */
+static bool throtl_schedule_next_dispatch(struct throtl_service_queue *sq,
+                                         bool force)
 {
-       struct throtl_rb_root *st = &td->tg_service_tree;
+       /* any pending children left? */
+       if (!sq->nr_pending)
+               return true;
 
-       /*
-        * If there are more bios pending, schedule more work.
-        */
-       if (!total_nr_queued(td))
-               return;
+       update_min_dispatch_time(sq);
 
-       BUG_ON(!st->count);
+       /* is the next dispatch time in the future? */
+       if (force || time_after(sq->first_pending_disptime, jiffies)) {
+               throtl_schedule_pending_timer(sq, sq->first_pending_disptime);
+               return true;
+       }
 
-       update_min_dispatch_time(st);
+       /* tell the caller to continue dispatching */
+       return false;
+}
 
-       if (time_before_eq(st->min_disptime, jiffies))
-               throtl_schedule_delayed_work(td, 0);
-       else
-               throtl_schedule_delayed_work(td, (st->min_disptime - jiffies));
+static inline void throtl_start_new_slice_with_credit(struct throtl_grp *tg,
+               bool rw, unsigned long start)
+{
+       tg->bytes_disp[rw] = 0;
+       tg->io_disp[rw] = 0;
+
+       /*
+        * Previous slice has expired. We must have trimmed it after last
+        * bio dispatch. That means since start of last slice, we never used
+        * that bandwidth. Do try to make use of that bandwidth while giving
+        * credit.
+        */
+       if (time_after_eq(start, tg->slice_start[rw]))
+               tg->slice_start[rw] = start;
+
+       tg->slice_end[rw] = jiffies + throtl_slice;
+       throtl_log(&tg->service_queue,
+                  "[%c] new slice with credit start=%lu end=%lu jiffies=%lu",
+                  rw == READ ? 'R' : 'W', tg->slice_start[rw],
+                  tg->slice_end[rw], jiffies);
 }
 
-static inline void
-throtl_start_new_slice(struct throtl_data *td, struct throtl_grp *tg, bool rw)
+static inline void throtl_start_new_slice(struct throtl_grp *tg, bool rw)
 {
        tg->bytes_disp[rw] = 0;
        tg->io_disp[rw] = 0;
        tg->slice_start[rw] = jiffies;
        tg->slice_end[rw] = jiffies + throtl_slice;
-       throtl_log_tg(td, tg, "[%c] new slice start=%lu end=%lu jiffies=%lu",
-                       rw == READ ? 'R' : 'W', tg->slice_start[rw],
-                       tg->slice_end[rw], jiffies);
+       throtl_log(&tg->service_queue,
+                  "[%c] new slice start=%lu end=%lu jiffies=%lu",
+                  rw == READ ? 'R' : 'W', tg->slice_start[rw],
+                  tg->slice_end[rw], jiffies);
 }
 
-static inline void throtl_set_slice_end(struct throtl_data *td,
-               struct throtl_grp *tg, bool rw, unsigned long jiffy_end)
+static inline void throtl_set_slice_end(struct throtl_grp *tg, bool rw,
+                                       unsigned long jiffy_end)
 {
        tg->slice_end[rw] = roundup(jiffy_end, throtl_slice);
 }
 
-static inline void throtl_extend_slice(struct throtl_data *td,
-               struct throtl_grp *tg, bool rw, unsigned long jiffy_end)
+static inline void throtl_extend_slice(struct throtl_grp *tg, bool rw,
+                                      unsigned long jiffy_end)
 {
        tg->slice_end[rw] = roundup(jiffy_end, throtl_slice);
-       throtl_log_tg(td, tg, "[%c] extend slice start=%lu end=%lu jiffies=%lu",
-                       rw == READ ? 'R' : 'W', tg->slice_start[rw],
-                       tg->slice_end[rw], jiffies);
+       throtl_log(&tg->service_queue,
+                  "[%c] extend slice start=%lu end=%lu jiffies=%lu",
+                  rw == READ ? 'R' : 'W', tg->slice_start[rw],
+                  tg->slice_end[rw], jiffies);
 }
 
 /* Determine if previously allocated or extended slice is complete or not */
-static bool
-throtl_slice_used(struct throtl_data *td, struct throtl_grp *tg, bool rw)
+static bool throtl_slice_used(struct throtl_grp *tg, bool rw)
 {
        if (time_in_range(jiffies, tg->slice_start[rw], tg->slice_end[rw]))
                return 0;
@@ -462,8 +740,7 @@ throtl_slice_used(struct throtl_data *td, struct throtl_grp *tg, bool rw)
 }
 
 /* Trim the used slices and adjust slice start accordingly */
-static inline void
-throtl_trim_slice(struct throtl_data *td, struct throtl_grp *tg, bool rw)
+static inline void throtl_trim_slice(struct throtl_grp *tg, bool rw)
 {
        unsigned long nr_slices, time_elapsed, io_trim;
        u64 bytes_trim, tmp;
@@ -475,7 +752,7 @@ throtl_trim_slice(struct throtl_data *td, struct throtl_grp *tg, bool rw)
         * renewed. Don't try to trim the slice if slice is used. A new
         * slice will start when appropriate.
         */
-       if (throtl_slice_used(td, tg, rw))
+       if (throtl_slice_used(tg, rw))
                return;
 
        /*
@@ -486,7 +763,7 @@ throtl_trim_slice(struct throtl_data *td, struct throtl_grp *tg, bool rw)
         * is bad because it does not allow new slice to start.
         */
 
-       throtl_set_slice_end(td, tg, rw, jiffies + throtl_slice);
+       throtl_set_slice_end(tg, rw, jiffies + throtl_slice);
 
        time_elapsed = jiffies - tg->slice_start[rw];
 
@@ -515,14 +792,14 @@ throtl_trim_slice(struct throtl_data *td, struct throtl_grp *tg, bool rw)
 
        tg->slice_start[rw] += nr_slices * throtl_slice;
 
-       throtl_log_tg(td, tg, "[%c] trim slice nr=%lu bytes=%llu io=%lu"
-                       " start=%lu end=%lu jiffies=%lu",
-                       rw == READ ? 'R' : 'W', nr_slices, bytes_trim, io_trim,
-                       tg->slice_start[rw], tg->slice_end[rw], jiffies);
+       throtl_log(&tg->service_queue,
+                  "[%c] trim slice nr=%lu bytes=%llu io=%lu start=%lu end=%lu jiffies=%lu",
+                  rw == READ ? 'R' : 'W', nr_slices, bytes_trim, io_trim,
+                  tg->slice_start[rw], tg->slice_end[rw], jiffies);
 }
 
-static bool tg_with_in_iops_limit(struct throtl_data *td, struct throtl_grp *tg,
-               struct bio *bio, unsigned long *wait)
+static bool tg_with_in_iops_limit(struct throtl_grp *tg, struct bio *bio,
+                                 unsigned long *wait)
 {
        bool rw = bio_data_dir(bio);
        unsigned int io_allowed;
@@ -571,8 +848,8 @@ static bool tg_with_in_iops_limit(struct throtl_data *td, struct throtl_grp *tg,
        return 0;
 }
 
-static bool tg_with_in_bps_limit(struct throtl_data *td, struct throtl_grp *tg,
-               struct bio *bio, unsigned long *wait)
+static bool tg_with_in_bps_limit(struct throtl_grp *tg, struct bio *bio,
+                                unsigned long *wait)
 {
        bool rw = bio_data_dir(bio);
        u64 bytes_allowed, extra_bytes, tmp;
@@ -613,18 +890,12 @@ static bool tg_with_in_bps_limit(struct throtl_data *td, struct throtl_grp *tg,
        return 0;
 }
 
-static bool tg_no_rule_group(struct throtl_grp *tg, bool rw) {
-       if (tg->bps[rw] == -1 && tg->iops[rw] == -1)
-               return 1;
-       return 0;
-}
-
 /*
  * Returns whether one can dispatch a bio or not. Also returns approx number
  * of jiffies to wait before this bio is with-in IO rate and can be dispatched
  */
-static bool tg_may_dispatch(struct throtl_data *td, struct throtl_grp *tg,
-                               struct bio *bio, unsigned long *wait)
+static bool tg_may_dispatch(struct throtl_grp *tg, struct bio *bio,
+                           unsigned long *wait)
 {
        bool rw = bio_data_dir(bio);
        unsigned long bps_wait = 0, iops_wait = 0, max_wait = 0;
@@ -635,7 +906,8 @@ static bool tg_may_dispatch(struct throtl_data *td, struct throtl_grp *tg,
         * this function with a different bio if there are other bios
         * queued.
         */
-       BUG_ON(tg->nr_queued[rw] && bio != bio_list_peek(&tg->bio_lists[rw]));
+       BUG_ON(tg->service_queue.nr_queued[rw] &&
+              bio != throtl_peek_queued(&tg->service_queue.queued[rw]));
 
        /* If tg->bps = -1, then BW is unlimited */
        if (tg->bps[rw] == -1 && tg->iops[rw] == -1) {
@@ -649,15 +921,15 @@ static bool tg_may_dispatch(struct throtl_data *td, struct throtl_grp *tg,
         * existing slice to make sure it is at least throtl_slice interval
         * long since now.
         */
-       if (throtl_slice_used(td, tg, rw))
-               throtl_start_new_slice(td, tg, rw);
+       if (throtl_slice_used(tg, rw))
+               throtl_start_new_slice(tg, rw);
        else {
                if (time_before(tg->slice_end[rw], jiffies + throtl_slice))
-                       throtl_extend_slice(td, tg, rw, jiffies + throtl_slice);
+                       throtl_extend_slice(tg, rw, jiffies + throtl_slice);
        }
 
-       if (tg_with_in_bps_limit(td, tg, bio, &bps_wait)
-           && tg_with_in_iops_limit(td, tg, bio, &iops_wait)) {
+       if (tg_with_in_bps_limit(tg, bio, &bps_wait) &&
+           tg_with_in_iops_limit(tg, bio, &iops_wait)) {
                if (wait)
                        *wait = 0;
                return 1;
@@ -669,7 +941,7 @@ static bool tg_may_dispatch(struct throtl_data *td, struct throtl_grp *tg,
                *wait = max_wait;
 
        if (time_before(tg->slice_end[rw], jiffies + max_wait))
-               throtl_extend_slice(td, tg, rw, jiffies + max_wait);
+               throtl_extend_slice(tg, rw, jiffies + max_wait);
 
        return 0;
 }
@@ -708,65 +980,136 @@ static void throtl_charge_bio(struct throtl_grp *tg, struct bio *bio)
        tg->bytes_disp[rw] += bio->bi_size;
        tg->io_disp[rw]++;
 
-       throtl_update_dispatch_stats(tg_to_blkg(tg), bio->bi_size, bio->bi_rw);
+       /*
+        * REQ_THROTTLED is used to prevent the same bio to be throttled
+        * more than once as a throttled bio will go through blk-throtl the
+        * second time when it eventually gets issued.  Set it when a bio
+        * is being charged to a tg.
+        *
+        * Dispatch stats aren't recursive and each @bio should only be
+        * accounted by the @tg it was originally associated with.  Let's
+        * update the stats when setting REQ_THROTTLED for the first time
+        * which is guaranteed to be for the @bio's original tg.
+        */
+       if (!(bio->bi_rw & REQ_THROTTLED)) {
+               bio->bi_rw |= REQ_THROTTLED;
+               throtl_update_dispatch_stats(tg_to_blkg(tg), bio->bi_size,
+                                            bio->bi_rw);
+       }
 }
 
-static void throtl_add_bio_tg(struct throtl_data *td, struct throtl_grp *tg,
-                       struct bio *bio)
+/**
+ * throtl_add_bio_tg - add a bio to the specified throtl_grp
+ * @bio: bio to add
+ * @qn: qnode to use
+ * @tg: the target throtl_grp
+ *
+ * Add @bio to @tg's service_queue using @qn.  If @qn is not specified,
+ * tg->qnode_on_self[] is used.
+ */
+static void throtl_add_bio_tg(struct bio *bio, struct throtl_qnode *qn,
+                             struct throtl_grp *tg)
 {
+       struct throtl_service_queue *sq = &tg->service_queue;
        bool rw = bio_data_dir(bio);
 
-       bio_list_add(&tg->bio_lists[rw], bio);
-       /* Take a bio reference on tg */
-       blkg_get(tg_to_blkg(tg));
-       tg->nr_queued[rw]++;
-       td->nr_queued[rw]++;
-       throtl_enqueue_tg(td, tg);
+       if (!qn)
+               qn = &tg->qnode_on_self[rw];
+
+       /*
+        * If @tg doesn't currently have any bios queued in the same
+        * direction, queueing @bio can change when @tg should be
+        * dispatched.  Mark that @tg was empty.  This is automatically
+        * cleaered on the next tg_update_disptime().
+        */
+       if (!sq->nr_queued[rw])
+               tg->flags |= THROTL_TG_WAS_EMPTY;
+
+       throtl_qnode_add_bio(bio, qn, &sq->queued[rw]);
+
+       sq->nr_queued[rw]++;
+       throtl_enqueue_tg(tg);
 }
 
-static void tg_update_disptime(struct throtl_data *td, struct throtl_grp *tg)
+static void tg_update_disptime(struct throtl_grp *tg)
 {
+       struct throtl_service_queue *sq = &tg->service_queue;
        unsigned long read_wait = -1, write_wait = -1, min_wait = -1, disptime;
        struct bio *bio;
 
-       if ((bio = bio_list_peek(&tg->bio_lists[READ])))
-               tg_may_dispatch(td, tg, bio, &read_wait);
+       if ((bio = throtl_peek_queued(&sq->queued[READ])))
+               tg_may_dispatch(tg, bio, &read_wait);
 
-       if ((bio = bio_list_peek(&tg->bio_lists[WRITE])))
-               tg_may_dispatch(td, tg, bio, &write_wait);
+       if ((bio = throtl_peek_queued(&sq->queued[WRITE])))
+               tg_may_dispatch(tg, bio, &write_wait);
 
        min_wait = min(read_wait, write_wait);
        disptime = jiffies + min_wait;
 
        /* Update dispatch time */
-       throtl_dequeue_tg(td, tg);
+       throtl_dequeue_tg(tg);
        tg->disptime = disptime;
-       throtl_enqueue_tg(td, tg);
+       throtl_enqueue_tg(tg);
+
+       /* see throtl_add_bio_tg() */
+       tg->flags &= ~THROTL_TG_WAS_EMPTY;
 }
 
-static void tg_dispatch_one_bio(struct throtl_data *td, struct throtl_grp *tg,
-                               bool rw, struct bio_list *bl)
+static void start_parent_slice_with_credit(struct throtl_grp *child_tg,
+                                       struct throtl_grp *parent_tg, bool rw)
 {
-       struct bio *bio;
+       if (throtl_slice_used(parent_tg, rw)) {
+               throtl_start_new_slice_with_credit(parent_tg, rw,
+                               child_tg->slice_start[rw]);
+       }
+
+}
 
-       bio = bio_list_pop(&tg->bio_lists[rw]);
-       tg->nr_queued[rw]--;
-       /* Drop bio reference on blkg */
-       blkg_put(tg_to_blkg(tg));
+static void tg_dispatch_one_bio(struct throtl_grp *tg, bool rw)
+{
+       struct throtl_service_queue *sq = &tg->service_queue;
+       struct throtl_service_queue *parent_sq = sq->parent_sq;
+       struct throtl_grp *parent_tg = sq_to_tg(parent_sq);
+       struct throtl_grp *tg_to_put = NULL;
+       struct bio *bio;
 
-       BUG_ON(td->nr_queued[rw] <= 0);
-       td->nr_queued[rw]--;
+       /*
+        * @bio is being transferred from @tg to @parent_sq.  Popping a bio
+        * from @tg may put its reference and @parent_sq might end up
+        * getting released prematurely.  Remember the tg to put and put it
+        * after @bio is transferred to @parent_sq.
+        */
+       bio = throtl_pop_queued(&sq->queued[rw], &tg_to_put);
+       sq->nr_queued[rw]--;
 
        throtl_charge_bio(tg, bio);
-       bio_list_add(bl, bio);
-       bio->bi_rw |= REQ_THROTTLED;
 
-       throtl_trim_slice(td, tg, rw);
+       /*
+        * If our parent is another tg, we just need to transfer @bio to
+        * the parent using throtl_add_bio_tg().  If our parent is
+        * @td->service_queue, @bio is ready to be issued.  Put it on its
+        * bio_lists[] and decrease total number queued.  The caller is
+        * responsible for issuing these bios.
+        */
+       if (parent_tg) {
+               throtl_add_bio_tg(bio, &tg->qnode_on_parent[rw], parent_tg);
+               start_parent_slice_with_credit(tg, parent_tg, rw);
+       } else {
+               throtl_qnode_add_bio(bio, &tg->qnode_on_parent[rw],
+                                    &parent_sq->queued[rw]);
+               BUG_ON(tg->td->nr_queued[rw] <= 0);
+               tg->td->nr_queued[rw]--;
+       }
+
+       throtl_trim_slice(tg, rw);
+
+       if (tg_to_put)
+               blkg_put(tg_to_blkg(tg_to_put));
 }
 
-static int throtl_dispatch_tg(struct throtl_data *td, struct throtl_grp *tg,
-                               struct bio_list *bl)
+static int throtl_dispatch_tg(struct throtl_grp *tg)
 {
+       struct throtl_service_queue *sq = &tg->service_queue;
        unsigned int nr_reads = 0, nr_writes = 0;
        unsigned int max_nr_reads = throtl_grp_quantum*3/4;
        unsigned int max_nr_writes = throtl_grp_quantum - max_nr_reads;
@@ -774,20 +1117,20 @@ static int throtl_dispatch_tg(struct throtl_data *td, struct throtl_grp *tg,
 
        /* Try to dispatch 75% READS and 25% WRITES */
 
-       while ((bio = bio_list_peek(&tg->bio_lists[READ]))
-               && tg_may_dispatch(td, tg, bio, NULL)) {
+       while ((bio = throtl_peek_queued(&sq->queued[READ])) &&
+              tg_may_dispatch(tg, bio, NULL)) {
 
-               tg_dispatch_one_bio(td, tg, bio_data_dir(bio), bl);
+               tg_dispatch_one_bio(tg, bio_data_dir(bio));
                nr_reads++;
 
                if (nr_reads >= max_nr_reads)
                        break;
        }
 
-       while ((bio = bio_list_peek(&tg->bio_lists[WRITE]))
-               && tg_may_dispatch(td, tg, bio, NULL)) {
+       while ((bio = throtl_peek_queued(&sq->queued[WRITE])) &&
+              tg_may_dispatch(tg, bio, NULL)) {
 
-               tg_dispatch_one_bio(td, tg, bio_data_dir(bio), bl);
+               tg_dispatch_one_bio(tg, bio_data_dir(bio));
                nr_writes++;
 
                if (nr_writes >= max_nr_writes)
@@ -797,14 +1140,13 @@ static int throtl_dispatch_tg(struct throtl_data *td, struct throtl_grp *tg,
        return nr_reads + nr_writes;
 }
 
-static int throtl_select_dispatch(struct throtl_data *td, struct bio_list *bl)
+static int throtl_select_dispatch(struct throtl_service_queue *parent_sq)
 {
        unsigned int nr_disp = 0;
-       struct throtl_grp *tg;
-       struct throtl_rb_root *st = &td->tg_service_tree;
 
        while (1) {
-               tg = throtl_rb_first(st);
+               struct throtl_grp *tg = throtl_rb_first(parent_sq);
+               struct throtl_service_queue *sq = &tg->service_queue;
 
                if (!tg)
                        break;
@@ -812,14 +1154,12 @@ static int throtl_select_dispatch(struct throtl_data *td, struct bio_list *bl)
                if (time_before(jiffies, tg->disptime))
                        break;
 
-               throtl_dequeue_tg(td, tg);
+               throtl_dequeue_tg(tg);
 
-               nr_disp += throtl_dispatch_tg(td, tg, bl);
+               nr_disp += throtl_dispatch_tg(tg);
 
-               if (tg->nr_queued[0] || tg->nr_queued[1]) {
-                       tg_update_disptime(td, tg);
-                       throtl_enqueue_tg(td, tg);
-               }
+               if (sq->nr_queued[0] || sq->nr_queued[1])
+                       tg_update_disptime(tg);
 
                if (nr_disp >= throtl_quantum)
                        break;
@@ -828,111 +1168,111 @@ static int throtl_select_dispatch(struct throtl_data *td, struct bio_list *bl)
        return nr_disp;
 }
 
-static void throtl_process_limit_change(struct throtl_data *td)
+/**
+ * throtl_pending_timer_fn - timer function for service_queue->pending_timer
+ * @arg: the throtl_service_queue being serviced
+ *
+ * This timer is armed when a child throtl_grp with active bio's become
+ * pending and queued on the service_queue's pending_tree and expires when
+ * the first child throtl_grp should be dispatched.  This function
+ * dispatches bio's from the children throtl_grps to the parent
+ * service_queue.
+ *
+ * If the parent's parent is another throtl_grp, dispatching is propagated
+ * by either arming its pending_timer or repeating dispatch directly.  If
+ * the top-level service_tree is reached, throtl_data->dispatch_work is
+ * kicked so that the ready bio's are issued.
+ */
+static void throtl_pending_timer_fn(unsigned long arg)
 {
+       struct throtl_service_queue *sq = (void *)arg;
+       struct throtl_grp *tg = sq_to_tg(sq);
+       struct throtl_data *td = sq_to_td(sq);
        struct request_queue *q = td->queue;
-       struct blkcg_gq *blkg, *n;
-
-       if (!td->limits_changed)
-               return;
-
-       xchg(&td->limits_changed, false);
-
-       throtl_log(td, "limits changed");
-
-       list_for_each_entry_safe(blkg, n, &q->blkg_list, q_node) {
-               struct throtl_grp *tg = blkg_to_tg(blkg);
+       struct throtl_service_queue *parent_sq;
+       bool dispatched;
+       int ret;
 
-               if (!tg->limits_changed)
-                       continue;
+       spin_lock_irq(q->queue_lock);
+again:
+       parent_sq = sq->parent_sq;
+       dispatched = false;
+
+       while (true) {
+               throtl_log(sq, "dispatch nr_queued=%u read=%u write=%u",
+                          sq->nr_queued[READ] + sq->nr_queued[WRITE],
+                          sq->nr_queued[READ], sq->nr_queued[WRITE]);
+
+               ret = throtl_select_dispatch(sq);
+               if (ret) {
+                       throtl_log(sq, "bios disp=%u", ret);
+                       dispatched = true;
+               }
 
-               if (!xchg(&tg->limits_changed, false))
-                       continue;
+               if (throtl_schedule_next_dispatch(sq, false))
+                       break;
 
-               throtl_log_tg(td, tg, "limit change rbps=%llu wbps=%llu"
-                       " riops=%u wiops=%u", tg->bps[READ], tg->bps[WRITE],
-                       tg->iops[READ], tg->iops[WRITE]);
+               /* this dispatch windows is still open, relax and repeat */
+               spin_unlock_irq(q->queue_lock);
+               cpu_relax();
+               spin_lock_irq(q->queue_lock);
+       }
 
-               /*
-                * Restart the slices for both READ and WRITES. It
-                * might happen that a group's limit are dropped
-                * suddenly and we don't want to account recently
-                * dispatched IO with new low rate
-                */
-               throtl_start_new_slice(td, tg, 0);
-               throtl_start_new_slice(td, tg, 1);
+       if (!dispatched)
+               goto out_unlock;
 
-               if (throtl_tg_on_rr(tg))
-                       tg_update_disptime(td, tg);
+       if (parent_sq) {
+               /* @parent_sq is another throl_grp, propagate dispatch */
+               if (tg->flags & THROTL_TG_WAS_EMPTY) {
+                       tg_update_disptime(tg);
+                       if (!throtl_schedule_next_dispatch(parent_sq, false)) {
+                               /* window is already open, repeat dispatching */
+                               sq = parent_sq;
+                               tg = sq_to_tg(sq);
+                               goto again;
+                       }
+               }
+       } else {
+               /* reached the top-level, queue issueing */
+               queue_work(kthrotld_workqueue, &td->dispatch_work);
        }
+out_unlock:
+       spin_unlock_irq(q->queue_lock);
 }
 
-/* Dispatch throttled bios. Should be called without queue lock held. */
-static int throtl_dispatch(struct request_queue *q)
+/**
+ * blk_throtl_dispatch_work_fn - work function for throtl_data->dispatch_work
+ * @work: work item being executed
+ *
+ * This function is queued for execution when bio's reach the bio_lists[]
+ * of throtl_data->service_queue.  Those bio's are ready and issued by this
+ * function.
+ */
+void blk_throtl_dispatch_work_fn(struct work_struct *work)
 {
-       struct throtl_data *td = q->td;
-       unsigned int nr_disp = 0;
+       struct throtl_data *td = container_of(work, struct throtl_data,
+                                             dispatch_work);
+       struct throtl_service_queue *td_sq = &td->service_queue;
+       struct request_queue *q = td->queue;
        struct bio_list bio_list_on_stack;
        struct bio *bio;
        struct blk_plug plug;
-
-       spin_lock_irq(q->queue_lock);
-
-       throtl_process_limit_change(td);
-
-       if (!total_nr_queued(td))
-               goto out;
+       int rw;
 
        bio_list_init(&bio_list_on_stack);
 
-       throtl_log(td, "dispatch nr_queued=%u read=%u write=%u",
-                       total_nr_queued(td), td->nr_queued[READ],
-                       td->nr_queued[WRITE]);
-
-       nr_disp = throtl_select_dispatch(td, &bio_list_on_stack);
-
-       if (nr_disp)
-               throtl_log(td, "bios disp=%u", nr_disp);
-
-       throtl_schedule_next_dispatch(td);
-out:
+       spin_lock_irq(q->queue_lock);
+       for (rw = READ; rw <= WRITE; rw++)
+               while ((bio = throtl_pop_queued(&td_sq->queued[rw], NULL)))
+                       bio_list_add(&bio_list_on_stack, bio);
        spin_unlock_irq(q->queue_lock);
 
-       /*
-        * If we dispatched some requests, unplug the queue to make sure
-        * immediate dispatch
-        */
-       if (nr_disp) {
+       if (!bio_list_empty(&bio_list_on_stack)) {
                blk_start_plug(&plug);
                while((bio = bio_list_pop(&bio_list_on_stack)))
                        generic_make_request(bio);
                blk_finish_plug(&plug);
        }
-       return nr_disp;
-}
-
-void blk_throtl_work(struct work_struct *work)
-{
-       struct throtl_data *td = container_of(work, struct throtl_data,
-                                       throtl_work.work);
-       struct request_queue *q = td->queue;
-
-       throtl_dispatch(q);
-}
-
-/* Call with queue lock held */
-static void
-throtl_schedule_delayed_work(struct throtl_data *td, unsigned long delay)
-{
-
-       struct delayed_work *dwork = &td->throtl_work;
-
-       /* schedule work if limits changed even if no bio is queued */
-       if (total_nr_queued(td) || td->limits_changed) {
-               mod_delayed_work(kthrotld_workqueue, dwork, delay);
-               throtl_log(td, "schedule work. delay=%lu jiffies=%lu",
-                               delay, jiffies);
-       }
 }
 
 static u64 tg_prfill_cpu_rwstat(struct seq_file *sf,
@@ -1007,7 +1347,9 @@ static int tg_set_conf(struct cgroup *cgrp, struct cftype *cft, const char *buf,
        struct blkcg *blkcg = cgroup_to_blkcg(cgrp);
        struct blkg_conf_ctx ctx;
        struct throtl_grp *tg;
-       struct throtl_data *td;
+       struct throtl_service_queue *sq;
+       struct blkcg_gq *blkg;
+       struct cgroup *pos_cgrp;
        int ret;
 
        ret = blkg_conf_prep(blkcg, &blkcg_policy_throtl, buf, &ctx);
@@ -1015,7 +1357,7 @@ static int tg_set_conf(struct cgroup *cgrp, struct cftype *cft, const char *buf,
                return ret;
 
        tg = blkg_to_tg(ctx.blkg);
-       td = ctx.blkg->q->td;
+       sq = &tg->service_queue;
 
        if (!ctx.v)
                ctx.v = -1;
@@ -1025,10 +1367,37 @@ static int tg_set_conf(struct cgroup *cgrp, struct cftype *cft, const char *buf,
        else
                *(unsigned int *)((void *)tg + cft->private) = ctx.v;
 
-       /* XXX: we don't need the following deferred processing */
-       xchg(&tg->limits_changed, true);
-       xchg(&td->limits_changed, true);
-       throtl_schedule_delayed_work(td, 0);
+       throtl_log(&tg->service_queue,
+                  "limit change rbps=%llu wbps=%llu riops=%u wiops=%u",
+                  tg->bps[READ], tg->bps[WRITE],
+                  tg->iops[READ], tg->iops[WRITE]);
+
+       /*
+        * Update has_rules[] flags for the updated tg's subtree.  A tg is
+        * considered to have rules if either the tg itself or any of its
+        * ancestors has rules.  This identifies groups without any
+        * restrictions in the whole hierarchy and allows them to bypass
+        * blk-throttle.
+        */
+       tg_update_has_rules(tg);
+       blkg_for_each_descendant_pre(blkg, pos_cgrp, ctx.blkg)
+               tg_update_has_rules(blkg_to_tg(blkg));
+
+       /*
+        * We're already holding queue_lock and know @tg is valid.  Let's
+        * apply the new config directly.
+        *
+        * Restart the slices for both READ and WRITES. It might happen
+        * that a group's limit are dropped suddenly and we don't want to
+        * account recently dispatched IO with new low rate.
+        */
+       throtl_start_new_slice(tg, 0);
+       throtl_start_new_slice(tg, 1);
+
+       if (tg->flags & THROTL_TG_PENDING) {
+               tg_update_disptime(tg);
+               throtl_schedule_next_dispatch(sq->parent_sq, true);
+       }
 
        blkg_conf_finish(&ctx);
        return 0;
@@ -1092,7 +1461,7 @@ static void throtl_shutdown_wq(struct request_queue *q)
 {
        struct throtl_data *td = q->td;
 
-       cancel_delayed_work_sync(&td->throtl_work);
+       cancel_work_sync(&td->dispatch_work);
 }
 
 static struct blkcg_policy blkcg_policy_throtl = {
@@ -1100,6 +1469,7 @@ static struct blkcg_policy blkcg_policy_throtl = {
        .cftypes                = throtl_files,
 
        .pd_init_fn             = throtl_pd_init,
+       .pd_online_fn           = throtl_pd_online,
        .pd_exit_fn             = throtl_pd_exit,
        .pd_reset_stats_fn      = throtl_pd_reset_stats,
 };
@@ -1107,15 +1477,16 @@ static struct blkcg_policy blkcg_policy_throtl = {
 bool blk_throtl_bio(struct request_queue *q, struct bio *bio)
 {
        struct throtl_data *td = q->td;
+       struct throtl_qnode *qn = NULL;
        struct throtl_grp *tg;
-       bool rw = bio_data_dir(bio), update_disptime = true;
+       struct throtl_service_queue *sq;
+       bool rw = bio_data_dir(bio);
        struct blkcg *blkcg;
        bool throttled = false;
 
-       if (bio->bi_rw & REQ_THROTTLED) {
-               bio->bi_rw &= ~REQ_THROTTLED;
+       /* see throtl_charge_bio() */
+       if (bio->bi_rw & REQ_THROTTLED)
                goto out;
-       }
 
        /*
         * A throtl_grp pointer retrieved under rcu can be used to access
@@ -1126,7 +1497,7 @@ bool blk_throtl_bio(struct request_queue *q, struct bio *bio)
        blkcg = bio_blkcg(bio);
        tg = throtl_lookup_tg(td, blkcg);
        if (tg) {
-               if (tg_no_rule_group(tg, rw)) {
+               if (!tg->has_rules[rw]) {
                        throtl_update_dispatch_stats(tg_to_blkg(tg),
                                                     bio->bi_size, bio->bi_rw);
                        goto out_unlock_rcu;
@@ -1142,18 +1513,18 @@ bool blk_throtl_bio(struct request_queue *q, struct bio *bio)
        if (unlikely(!tg))
                goto out_unlock;
 
-       if (tg->nr_queued[rw]) {
-               /*
-                * There is already another bio queued in same dir. No
-                * need to update dispatch time.
-                */
-               update_disptime = false;
-               goto queue_bio;
+       sq = &tg->service_queue;
 
-       }
+       while (true) {
+               /* throtl is FIFO - if bios are already queued, should queue */
+               if (sq->nr_queued[rw])
+                       break;
+
+               /* if above limits, break to queue */
+               if (!tg_may_dispatch(tg, bio, NULL))
+                       break;
 
-       /* Bio is with-in rate limit of group */
-       if (tg_may_dispatch(td, tg, bio, NULL)) {
+               /* within limits, let's charge and dispatch directly */
                throtl_charge_bio(tg, bio);
 
                /*
@@ -1167,25 +1538,41 @@ bool blk_throtl_bio(struct request_queue *q, struct bio *bio)
                 *
                 * So keep on trimming slice even if bio is not queued.
                 */
-               throtl_trim_slice(td, tg, rw);
-               goto out_unlock;
+               throtl_trim_slice(tg, rw);
+
+               /*
+                * @bio passed through this layer without being throttled.
+                * Climb up the ladder.  If we''re already at the top, it
+                * can be executed directly.
+                */
+               qn = &tg->qnode_on_parent[rw];
+               sq = sq->parent_sq;
+               tg = sq_to_tg(sq);
+               if (!tg)
+                       goto out_unlock;
        }
 
-queue_bio:
-       throtl_log_tg(td, tg, "[%c] bio. bdisp=%llu sz=%u bps=%llu"
-                       " iodisp=%u iops=%u queued=%d/%d",
-                       rw == READ ? 'R' : 'W',
-                       tg->bytes_disp[rw], bio->bi_size, tg->bps[rw],
-                       tg->io_disp[rw], tg->iops[rw],
-                       tg->nr_queued[READ], tg->nr_queued[WRITE]);
+       /* out-of-limit, queue to @tg */
+       throtl_log(sq, "[%c] bio. bdisp=%llu sz=%u bps=%llu iodisp=%u iops=%u queued=%d/%d",
+                  rw == READ ? 'R' : 'W',
+                  tg->bytes_disp[rw], bio->bi_size, tg->bps[rw],
+                  tg->io_disp[rw], tg->iops[rw],
+                  sq->nr_queued[READ], sq->nr_queued[WRITE]);
 
        bio_associate_current(bio);
-       throtl_add_bio_tg(q->td, tg, bio);
+       tg->td->nr_queued[rw]++;
+       throtl_add_bio_tg(bio, qn, tg);
        throttled = true;
 
-       if (update_disptime) {
-               tg_update_disptime(td, tg);
-               throtl_schedule_next_dispatch(td);
+       /*
+        * Update @tg's dispatch time and force schedule dispatch if @tg
+        * was empty before @bio.  The forced scheduling isn't likely to
+        * cause undue delay as @bio is likely to be dispatched directly if
+        * its @tg's disptime is not in the future.
+        */
+       if (tg->flags & THROTL_TG_WAS_EMPTY) {
+               tg_update_disptime(tg);
+               throtl_schedule_next_dispatch(tg->service_queue.parent_sq, true);
        }
 
 out_unlock:
@@ -1193,9 +1580,38 @@ out_unlock:
 out_unlock_rcu:
        rcu_read_unlock();
 out:
+       /*
+        * As multiple blk-throtls may stack in the same issue path, we
+        * don't want bios to leave with the flag set.  Clear the flag if
+        * being issued.
+        */
+       if (!throttled)
+               bio->bi_rw &= ~REQ_THROTTLED;
        return throttled;
 }
 
+/*
+ * Dispatch all bios from all children tg's queued on @parent_sq.  On
+ * return, @parent_sq is guaranteed to not have any active children tg's
+ * and all bios from previously active tg's are on @parent_sq->bio_lists[].
+ */
+static void tg_drain_bios(struct throtl_service_queue *parent_sq)
+{
+       struct throtl_grp *tg;
+
+       while ((tg = throtl_rb_first(parent_sq))) {
+               struct throtl_service_queue *sq = &tg->service_queue;
+               struct bio *bio;
+
+               throtl_dequeue_tg(tg);
+
+               while ((bio = throtl_peek_queued(&sq->queued[READ])))
+                       tg_dispatch_one_bio(tg, bio_data_dir(bio));
+               while ((bio = throtl_peek_queued(&sq->queued[WRITE])))
+                       tg_dispatch_one_bio(tg, bio_data_dir(bio));
+       }
+}
+
 /**
  * blk_throtl_drain - drain throttled bios
  * @q: request_queue to drain throttled bios for
@@ -1206,27 +1622,36 @@ void blk_throtl_drain(struct request_queue *q)
        __releases(q->queue_lock) __acquires(q->queue_lock)
 {
        struct throtl_data *td = q->td;
-       struct throtl_rb_root *st = &td->tg_service_tree;
-       struct throtl_grp *tg;
-       struct bio_list bl;
+       struct blkcg_gq *blkg;
+       struct cgroup *pos_cgrp;
        struct bio *bio;
+       int rw;
 
        queue_lockdep_assert_held(q);
+       rcu_read_lock();
+
+       /*
+        * Drain each tg while doing post-order walk on the blkg tree, so
+        * that all bios are propagated to td->service_queue.  It'd be
+        * better to walk service_queue tree directly but blkg walk is
+        * easier.
+        */
+       blkg_for_each_descendant_post(blkg, pos_cgrp, td->queue->root_blkg)
+               tg_drain_bios(&blkg_to_tg(blkg)->service_queue);
 
-       bio_list_init(&bl);
+       tg_drain_bios(&td_root_tg(td)->service_queue);
 
-       while ((tg = throtl_rb_first(st))) {
-               throtl_dequeue_tg(td, tg);
+       /* finally, transfer bios from top-level tg's into the td */
+       tg_drain_bios(&td->service_queue);
 
-               while ((bio = bio_list_peek(&tg->bio_lists[READ])))
-                       tg_dispatch_one_bio(td, tg, bio_data_dir(bio), &bl);
-               while ((bio = bio_list_peek(&tg->bio_lists[WRITE])))
-                       tg_dispatch_one_bio(td, tg, bio_data_dir(bio), &bl);
-       }
+       rcu_read_unlock();
        spin_unlock_irq(q->queue_lock);
 
-       while ((bio = bio_list_pop(&bl)))
-               generic_make_request(bio);
+       /* all bios now should be in td->service_queue, issue them */
+       for (rw = READ; rw <= WRITE; rw++)
+               while ((bio = throtl_pop_queued(&td->service_queue.queued[rw],
+                                               NULL)))
+                       generic_make_request(bio);
 
        spin_lock_irq(q->queue_lock);
 }
@@ -1240,9 +1665,8 @@ int blk_throtl_init(struct request_queue *q)
        if (!td)
                return -ENOMEM;
 
-       td->tg_service_tree = THROTL_RB_ROOT;
-       td->limits_changed = false;
-       INIT_DELAYED_WORK(&td->throtl_work, blk_throtl_work);
+       INIT_WORK(&td->dispatch_work, blk_throtl_dispatch_work_fn);
+       throtl_service_queue_init(&td->service_queue, NULL);
 
        q->td = td;
        td->queue = q;
index d5cd313..d5bbdcf 100644 (file)
@@ -4347,18 +4347,28 @@ static void cfq_exit_queue(struct elevator_queue *e)
        kfree(cfqd);
 }
 
-static int cfq_init_queue(struct request_queue *q)
+static int cfq_init_queue(struct request_queue *q, struct elevator_type *e)
 {
        struct cfq_data *cfqd;
        struct blkcg_gq *blkg __maybe_unused;
        int i, ret;
+       struct elevator_queue *eq;
+
+       eq = elevator_alloc(q, e);
+       if (!eq)
+               return -ENOMEM;
 
        cfqd = kmalloc_node(sizeof(*cfqd), GFP_KERNEL | __GFP_ZERO, q->node);
-       if (!cfqd)
+       if (!cfqd) {
+               kobject_put(&eq->kobj);
                return -ENOMEM;
+       }
+       eq->elevator_data = cfqd;
 
        cfqd->queue = q;
-       q->elevator->elevator_data = cfqd;
+       spin_lock_irq(q->queue_lock);
+       q->elevator = eq;
+       spin_unlock_irq(q->queue_lock);
 
        /* Init root service tree */
        cfqd->grp_service_tree = CFQ_RB_ROOT;
@@ -4433,6 +4443,7 @@ static int cfq_init_queue(struct request_queue *q)
 
 out_free:
        kfree(cfqd);
+       kobject_put(&eq->kobj);
        return ret;
 }
 
index ba19a3a..20614a3 100644 (file)
@@ -337,13 +337,21 @@ static void deadline_exit_queue(struct elevator_queue *e)
 /*
  * initialize elevator private data (deadline_data).
  */
-static int deadline_init_queue(struct request_queue *q)
+static int deadline_init_queue(struct request_queue *q, struct elevator_type *e)
 {
        struct deadline_data *dd;
+       struct elevator_queue *eq;
+
+       eq = elevator_alloc(q, e);
+       if (!eq)
+               return -ENOMEM;
 
        dd = kmalloc_node(sizeof(*dd), GFP_KERNEL | __GFP_ZERO, q->node);
-       if (!dd)
+       if (!dd) {
+               kobject_put(&eq->kobj);
                return -ENOMEM;
+       }
+       eq->elevator_data = dd;
 
        INIT_LIST_HEAD(&dd->fifo_list[READ]);
        INIT_LIST_HEAD(&dd->fifo_list[WRITE]);
@@ -355,7 +363,9 @@ static int deadline_init_queue(struct request_queue *q)
        dd->front_merges = 1;
        dd->fifo_batch = fifo_batch;
 
-       q->elevator->elevator_data = dd;
+       spin_lock_irq(q->queue_lock);
+       q->elevator = eq;
+       spin_unlock_irq(q->queue_lock);
        return 0;
 }
 
index eba5b04..668394d 100644 (file)
@@ -150,7 +150,7 @@ void __init load_default_elevator_module(void)
 
 static struct kobj_type elv_ktype;
 
-static struct elevator_queue *elevator_alloc(struct request_queue *q,
+struct elevator_queue *elevator_alloc(struct request_queue *q,
                                  struct elevator_type *e)
 {
        struct elevator_queue *eq;
@@ -170,6 +170,7 @@ err:
        elevator_put(e);
        return NULL;
 }
+EXPORT_SYMBOL(elevator_alloc);
 
 static void elevator_release(struct kobject *kobj)
 {
@@ -221,16 +222,7 @@ int elevator_init(struct request_queue *q, char *name)
                }
        }
 
-       q->elevator = elevator_alloc(q, e);
-       if (!q->elevator)
-               return -ENOMEM;
-
-       err = e->ops.elevator_init_fn(q);
-       if (err) {
-               kobject_put(&q->elevator->kobj);
-               return err;
-       }
-
+       err = e->ops.elevator_init_fn(q, e);
        return 0;
 }
 EXPORT_SYMBOL(elevator_init);
@@ -935,16 +927,9 @@ static int elevator_switch(struct request_queue *q, struct elevator_type *new_e)
        spin_unlock_irq(q->queue_lock);
 
        /* allocate, init and register new elevator */
-       err = -ENOMEM;
-       q->elevator = elevator_alloc(q, new_e);
-       if (!q->elevator)
-               goto fail_init;
-
-       err = new_e->ops.elevator_init_fn(q);
-       if (err) {
-               kobject_put(&q->elevator->kobj);
+       err = new_e->ops.elevator_init_fn(q, new_e);
+       if (err)
                goto fail_init;
-       }
 
        if (registered) {
                err = elv_register_queue(q);
index 5d1bf70..3de89d4 100644 (file)
@@ -59,16 +59,27 @@ noop_latter_request(struct request_queue *q, struct request *rq)
        return list_entry(rq->queuelist.next, struct request, queuelist);
 }
 
-static int noop_init_queue(struct request_queue *q)
+static int noop_init_queue(struct request_queue *q, struct elevator_type *e)
 {
        struct noop_data *nd;
+       struct elevator_queue *eq;
+
+       eq = elevator_alloc(q, e);
+       if (!eq)
+               return -ENOMEM;
 
        nd = kmalloc_node(sizeof(*nd), GFP_KERNEL, q->node);
-       if (!nd)
+       if (!nd) {
+               kobject_put(&eq->kobj);
                return -ENOMEM;
+       }
+       eq->elevator_data = nd;
 
        INIT_LIST_HEAD(&nd->queue);
-       q->elevator->elevator_data = nd;
+
+       spin_lock_irq(q->queue_lock);
+       q->elevator = eq;
+       spin_unlock_irq(q->queue_lock);
        return 0;
 }
 
index ae050b5..aa43b91 100644 (file)
@@ -52,8 +52,6 @@ source "drivers/i2c/Kconfig"
 
 source "drivers/spi/Kconfig"
 
-source "drivers/ssbi/Kconfig"
-
 source "drivers/hsi/Kconfig"
 
 source "drivers/pps/Kconfig"
index 336b0ad..ab93de8 100644 (file)
@@ -117,7 +117,6 @@ obj-y                               += firmware/
 obj-$(CONFIG_CRYPTO)           += crypto/
 obj-$(CONFIG_SUPERH)           += sh/
 obj-$(CONFIG_ARCH_SHMOBILE)    += sh/
-obj-$(CONFIG_SSBI)             += ssbi/
 ifndef CONFIG_ARCH_USES_GETTIMEOFFSET
 obj-y                          += clocksource/
 endif
index e9e8bb2..4ab807d 100644 (file)
@@ -324,14 +324,27 @@ int acpi_bus_update_power(acpi_handle handle, int *state_p)
        if (result)
                return result;
 
-       if (state == ACPI_STATE_UNKNOWN)
+       if (state == ACPI_STATE_UNKNOWN) {
                state = ACPI_STATE_D0;
-
-       result = acpi_device_set_power(device, state);
-       if (!result && state_p)
+               result = acpi_device_set_power(device, state);
+               if (result)
+                       return result;
+       } else {
+               if (device->power.flags.power_resources) {
+                       /*
+                        * We don't need to really switch the state, bu we need
+                        * to update the power resources' reference counters.
+                        */
+                       result = acpi_power_transition(device, state);
+                       if (result)
+                               return result;
+               }
+               device->power.state = state;
+       }
+       if (state_p)
                *state_p = state;
 
-       return result;
+       return 0;
 }
 EXPORT_SYMBOL_GPL(acpi_bus_update_power);
 
index 14de9f4..8265607 100644 (file)
@@ -1064,10 +1064,10 @@ find_dock_and_bay(acpi_handle handle, u32 lvl, void *context, void **rv)
        return AE_OK;
 }
 
-int __init acpi_dock_init(void)
+void __init acpi_dock_init(void)
 {
        if (acpi_disabled)
-               return 0;
+               return;
 
        /* look for dock stations and bays */
        acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
@@ -1075,11 +1075,10 @@ int __init acpi_dock_init(void)
 
        if (!dock_station_count) {
                pr_info(PREFIX "No dock devices found.\n");
-               return 0;
+               return;
        }
 
        register_acpi_bus_notifier(&dock_acpi_notifier);
        pr_info(PREFIX "%s: %d docks/bays found\n",
                ACPI_DOCK_DRIVER_DESCRIPTION, dock_station_count);
-       return 0;
 }
index 8d1c010..5b02a0a 100644 (file)
@@ -84,7 +84,7 @@ static int fan_get_cur_state(struct thermal_cooling_device *cdev, unsigned long
 {
        struct acpi_device *device = cdev->devdata;
        int result;
-       int acpi_state;
+       int acpi_state = ACPI_STATE_D0;
 
        if (!device)
                return -EINVAL;
index 288bb27..5c28c89 100644 (file)
@@ -279,7 +279,7 @@ static int acpi_power_on_unlocked(struct acpi_power_resource *resource)
 
        if (resource->ref_count++) {
                ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-                                 "Power resource [%s] already on",
+                                 "Power resource [%s] already on\n",
                                  resource->name));
        } else {
                result = __acpi_power_on(resource);
@@ -325,7 +325,7 @@ static int acpi_power_off_unlocked(struct acpi_power_resource *resource)
 
        if (!resource->ref_count) {
                ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-                                 "Power resource [%s] already off",
+                                 "Power resource [%s] already off\n",
                                  resource->name));
                return 0;
        }
index dfe76f1..1098557 100644 (file)
@@ -35,7 +35,6 @@ bool acpi_force_hot_remove;
 
 static const char *dummy_hid = "device";
 
-static LIST_HEAD(acpi_device_list);
 static LIST_HEAD(acpi_bus_id_list);
 static DEFINE_MUTEX(acpi_scan_lock);
 static LIST_HEAD(acpi_scan_handlers_list);
index aba6e93..80dc988 100644 (file)
@@ -160,7 +160,7 @@ config PDC_ADMA
 
 config PATA_OCTEON_CF
        tristate "OCTEON Boot Bus Compact Flash support"
-       depends on CPU_CAVIUM_OCTEON
+       depends on CAVIUM_OCTEON_SOC
        help
          This option enables a polled compact flash driver for use with
          compact flash cards attached to the OCTEON boot bus.
index 08fe897..6687ba7 100644 (file)
@@ -680,10 +680,7 @@ int dma_buf_debugfs_create_file(const char *name,
        d = debugfs_create_file(name, S_IRUGO, dma_buf_debugfs_dir,
                        write, &dma_buf_debug_fops);
 
-       if (IS_ERR(d))
-               return PTR_ERR(d);
-
-       return 0;
+       return PTR_RET(d);
 }
 #else
 static inline int dma_buf_init_debugfs(void)
index 3fd130f..1393b88 100644 (file)
@@ -407,7 +407,7 @@ static void ace_dump_regs(struct ace_device *ace)
                 ace_in32(ace, ACE_CFGLBA), ace_in(ace, ACE_FATSTAT));
 }
 
-void ace_fix_driveid(u16 *id)
+static void ace_fix_driveid(u16 *id)
 {
 #if defined(__BIG_ENDIAN)
        int i;
@@ -463,7 +463,7 @@ static inline void ace_fsm_yieldirq(struct ace_device *ace)
 }
 
 /* Get the next read/write request; ending requests that we don't handle */
-struct request *ace_get_next_request(struct request_queue * q)
+static struct request *ace_get_next_request(struct request_queue *q)
 {
        struct request *req;
 
index 2f9dbf7..40a8654 100644 (file)
@@ -167,7 +167,7 @@ config HW_RANDOM_OMAP
 
 config HW_RANDOM_OCTEON
        tristate "Octeon Random Number Generator support"
-       depends on HW_RANDOM && CPU_CAVIUM_OCTEON
+       depends on HW_RANDOM && CAVIUM_OCTEON_SOC
        default HW_RANDOM
        ---help---
          This driver provides kernel-side support for the Random Number
index 81465c2..b7b9b04 100644 (file)
@@ -27,6 +27,11 @@ config DW_APB_TIMER_OF
 config ARMADA_370_XP_TIMER
        bool
 
+config ORION_TIMER
+       select CLKSRC_OF
+       select CLKSRC_MMIO
+       bool
+
 config SUN4I_TIMER
        bool
 
@@ -69,6 +74,19 @@ config ARM_ARCH_TIMER
        bool
        select CLKSRC_OF if OF
 
+config ARM_GLOBAL_TIMER
+       bool
+       select CLKSRC_OF if OF
+       help
+         This options enables support for the ARM global timer unit
+
+config CLKSRC_ARM_GLOBAL_TIMER_SCHED_CLOCK
+       bool
+       depends on ARM_GLOBAL_TIMER
+       default y
+       help
+        Use ARM global timer clock source as sched_clock
+
 config CLKSRC_METAG_GENERIC
        def_bool y if METAG
        help
index 9ba8b4d..8b00c5c 100644 (file)
@@ -15,6 +15,7 @@ obj-$(CONFIG_DW_APB_TIMER_OF) += dw_apb_timer_of.o
 obj-$(CONFIG_CLKSRC_NOMADIK_MTU)       += nomadik-mtu.o
 obj-$(CONFIG_CLKSRC_DBX500_PRCMU)      += clksrc-dbx500-prcmu.o
 obj-$(CONFIG_ARMADA_370_XP_TIMER)      += time-armada-370-xp.o
+obj-$(CONFIG_ORION_TIMER)      += time-orion.o
 obj-$(CONFIG_ARCH_BCM2835)     += bcm2835_timer.o
 obj-$(CONFIG_ARCH_MARCO)       += timer-marco.o
 obj-$(CONFIG_ARCH_MXS)         += mxs_timer.o
@@ -30,5 +31,6 @@ obj-$(CONFIG_CLKSRC_SAMSUNG_PWM)      += samsung_pwm_timer.o
 obj-$(CONFIG_VF_PIT_TIMER)     += vf_pit_timer.o
 
 obj-$(CONFIG_ARM_ARCH_TIMER)           += arm_arch_timer.o
+obj-$(CONFIG_ARM_GLOBAL_TIMER)         += arm_global_timer.o
 obj-$(CONFIG_CLKSRC_METAG_GENERIC)     += metag_generic.o
 obj-$(CONFIG_ARCH_HAS_TICK_BROADCAST)  += dummy_timer.o
diff --git a/drivers/clocksource/arm_global_timer.c b/drivers/clocksource/arm_global_timer.c
new file mode 100644 (file)
index 0000000..db8afc7
--- /dev/null
@@ -0,0 +1,321 @@
+/*
+ * drivers/clocksource/arm_global_timer.c
+ *
+ * Copyright (C) 2013 STMicroelectronics (R&D) Limited.
+ * Author: Stuart Menefy <stuart.menefy@st.com>
+ * Author: Srinivas Kandagatla <srinivas.kandagatla@st.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/clocksource.h>
+#include <linux/clockchips.h>
+#include <linux/cpu.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
+#include <linux/sched_clock.h>
+
+#include <asm/cputype.h>
+
+#define GT_COUNTER0    0x00
+#define GT_COUNTER1    0x04
+
+#define GT_CONTROL     0x08
+#define GT_CONTROL_TIMER_ENABLE                BIT(0)  /* this bit is NOT banked */
+#define GT_CONTROL_COMP_ENABLE         BIT(1)  /* banked */
+#define GT_CONTROL_IRQ_ENABLE          BIT(2)  /* banked */
+#define GT_CONTROL_AUTO_INC            BIT(3)  /* banked */
+
+#define GT_INT_STATUS  0x0c
+#define GT_INT_STATUS_EVENT_FLAG       BIT(0)
+
+#define GT_COMP0       0x10
+#define GT_COMP1       0x14
+#define GT_AUTO_INC    0x18
+
+/*
+ * We are expecting to be clocked by the ARM peripheral clock.
+ *
+ * Note: it is assumed we are using a prescaler value of zero, so this is
+ * the units for all operations.
+ */
+static void __iomem *gt_base;
+static unsigned long gt_clk_rate;
+static int gt_ppi;
+static struct clock_event_device __percpu *gt_evt;
+
+/*
+ * To get the value from the Global Timer Counter register proceed as follows:
+ * 1. Read the upper 32-bit timer counter register
+ * 2. Read the lower 32-bit timer counter register
+ * 3. Read the upper 32-bit timer counter register again. If the value is
+ *  different to the 32-bit upper value read previously, go back to step 2.
+ *  Otherwise the 64-bit timer counter value is correct.
+ */
+static u64 gt_counter_read(void)
+{
+       u64 counter;
+       u32 lower;
+       u32 upper, old_upper;
+
+       upper = readl_relaxed(gt_base + GT_COUNTER1);
+       do {
+               old_upper = upper;
+               lower = readl_relaxed(gt_base + GT_COUNTER0);
+               upper = readl_relaxed(gt_base + GT_COUNTER1);
+       } while (upper != old_upper);
+
+       counter = upper;
+       counter <<= 32;
+       counter |= lower;
+       return counter;
+}
+
+/**
+ * To ensure that updates to comparator value register do not set the
+ * Interrupt Status Register proceed as follows:
+ * 1. Clear the Comp Enable bit in the Timer Control Register.
+ * 2. Write the lower 32-bit Comparator Value Register.
+ * 3. Write the upper 32-bit Comparator Value Register.
+ * 4. Set the Comp Enable bit and, if necessary, the IRQ enable bit.
+ */
+static void gt_compare_set(unsigned long delta, int periodic)
+{
+       u64 counter = gt_counter_read();
+       unsigned long ctrl;
+
+       counter += delta;
+       ctrl = GT_CONTROL_TIMER_ENABLE;
+       writel(ctrl, gt_base + GT_CONTROL);
+       writel(lower_32_bits(counter), gt_base + GT_COMP0);
+       writel(upper_32_bits(counter), gt_base + GT_COMP1);
+
+       if (periodic) {
+               writel(delta, gt_base + GT_AUTO_INC);
+               ctrl |= GT_CONTROL_AUTO_INC;
+       }
+
+       ctrl |= GT_CONTROL_COMP_ENABLE | GT_CONTROL_IRQ_ENABLE;
+       writel(ctrl, gt_base + GT_CONTROL);
+}
+
+static void gt_clockevent_set_mode(enum clock_event_mode mode,
+                                  struct clock_event_device *clk)
+{
+       unsigned long ctrl;
+
+       switch (mode) {
+       case CLOCK_EVT_MODE_PERIODIC:
+               gt_compare_set(DIV_ROUND_CLOSEST(gt_clk_rate, HZ), 1);
+               break;
+       case CLOCK_EVT_MODE_ONESHOT:
+       case CLOCK_EVT_MODE_UNUSED:
+       case CLOCK_EVT_MODE_SHUTDOWN:
+               ctrl = readl(gt_base + GT_CONTROL);
+               ctrl &= ~(GT_CONTROL_COMP_ENABLE |
+                               GT_CONTROL_IRQ_ENABLE | GT_CONTROL_AUTO_INC);
+               writel(ctrl, gt_base + GT_CONTROL);
+               break;
+       default:
+               break;
+       }
+}
+
+static int gt_clockevent_set_next_event(unsigned long evt,
+                                       struct clock_event_device *unused)
+{
+       gt_compare_set(evt, 0);
+       return 0;
+}
+
+static irqreturn_t gt_clockevent_interrupt(int irq, void *dev_id)
+{
+       struct clock_event_device *evt = dev_id;
+
+       if (!(readl_relaxed(gt_base + GT_INT_STATUS) &
+                               GT_INT_STATUS_EVENT_FLAG))
+               return IRQ_NONE;
+
+       /**
+        * ERRATA 740657( Global Timer can send 2 interrupts for
+        * the same event in single-shot mode)
+        * Workaround:
+        *      Either disable single-shot mode.
+        *      Or
+        *      Modify the Interrupt Handler to avoid the
+        *      offending sequence. This is achieved by clearing
+        *      the Global Timer flag _after_ having incremented
+        *      the Comparator register value to a higher value.
+        */
+       if (evt->mode == CLOCK_EVT_MODE_ONESHOT)
+               gt_compare_set(ULONG_MAX, 0);
+
+       writel_relaxed(GT_INT_STATUS_EVENT_FLAG, gt_base + GT_INT_STATUS);
+       evt->event_handler(evt);
+
+       return IRQ_HANDLED;
+}
+
+static int __cpuinit gt_clockevents_init(struct clock_event_device *clk)
+{
+       int cpu = smp_processor_id();
+
+       clk->name = "arm_global_timer";
+       clk->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
+       clk->set_mode = gt_clockevent_set_mode;
+       clk->set_next_event = gt_clockevent_set_next_event;
+       clk->cpumask = cpumask_of(cpu);
+       clk->rating = 300;
+       clk->irq = gt_ppi;
+       clockevents_config_and_register(clk, gt_clk_rate,
+                                       1, 0xffffffff);
+       enable_percpu_irq(clk->irq, IRQ_TYPE_NONE);
+       return 0;
+}
+
+static void gt_clockevents_stop(struct clock_event_device *clk)
+{
+       gt_clockevent_set_mode(CLOCK_EVT_MODE_UNUSED, clk);
+       disable_percpu_irq(clk->irq);
+}
+
+static cycle_t gt_clocksource_read(struct clocksource *cs)
+{
+       return gt_counter_read();
+}
+
+static struct clocksource gt_clocksource = {
+       .name   = "arm_global_timer",
+       .rating = 300,
+       .read   = gt_clocksource_read,
+       .mask   = CLOCKSOURCE_MASK(64),
+       .flags  = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+#ifdef CONFIG_CLKSRC_ARM_GLOBAL_TIMER_SCHED_CLOCK
+static u32 notrace gt_sched_clock_read(void)
+{
+       return gt_counter_read();
+}
+#endif
+
+static void __init gt_clocksource_init(void)
+{
+       writel(0, gt_base + GT_CONTROL);
+       writel(0, gt_base + GT_COUNTER0);
+       writel(0, gt_base + GT_COUNTER1);
+       /* enables timer on all the cores */
+       writel(GT_CONTROL_TIMER_ENABLE, gt_base + GT_CONTROL);
+
+#ifdef CONFIG_CLKSRC_ARM_GLOBAL_TIMER_SCHED_CLOCK
+       setup_sched_clock(gt_sched_clock_read, 32, gt_clk_rate);
+#endif
+       clocksource_register_hz(&gt_clocksource, gt_clk_rate);
+}
+
+static int __cpuinit gt_cpu_notify(struct notifier_block *self,
+                                          unsigned long action, void *hcpu)
+{
+       switch (action & ~CPU_TASKS_FROZEN) {
+       case CPU_STARTING:
+               gt_clockevents_init(this_cpu_ptr(gt_evt));
+               break;
+       case CPU_DYING:
+               gt_clockevents_stop(this_cpu_ptr(gt_evt));
+               break;
+       }
+
+       return NOTIFY_OK;
+}
+static struct notifier_block gt_cpu_nb __cpuinitdata = {
+       .notifier_call = gt_cpu_notify,
+};
+
+static void __init global_timer_of_register(struct device_node *np)
+{
+       struct clk *gt_clk;
+       int err = 0;
+
+       /*
+        * In r2p0 the comparators for each processor with the global timer
+        * fire when the timer value is greater than or equal to. In previous
+        * revisions the comparators fired when the timer value was equal to.
+        */
+       if ((read_cpuid_id() & 0xf0000f) < 0x200000) {
+               pr_warn("global-timer: non support for this cpu version.\n");
+               return;
+       }
+
+       gt_ppi = irq_of_parse_and_map(np, 0);
+       if (!gt_ppi) {
+               pr_warn("global-timer: unable to parse irq\n");
+               return;
+       }
+
+       gt_base = of_iomap(np, 0);
+       if (!gt_base) {
+               pr_warn("global-timer: invalid base address\n");
+               return;
+       }
+
+       gt_clk = of_clk_get(np, 0);
+       if (!IS_ERR(gt_clk)) {
+               err = clk_prepare_enable(gt_clk);
+               if (err)
+                       goto out_unmap;
+       } else {
+               pr_warn("global-timer: clk not found\n");
+               err = -EINVAL;
+               goto out_unmap;
+       }
+
+       gt_clk_rate = clk_get_rate(gt_clk);
+       gt_evt = alloc_percpu(struct clock_event_device);
+       if (!gt_evt) {
+               pr_warn("global-timer: can't allocate memory\n");
+               err = -ENOMEM;
+               goto out_clk;
+       }
+
+       err = request_percpu_irq(gt_ppi, gt_clockevent_interrupt,
+                                "gt", gt_evt);
+       if (err) {
+               pr_warn("global-timer: can't register interrupt %d (%d)\n",
+                       gt_ppi, err);
+               goto out_free;
+       }
+
+       err = register_cpu_notifier(&gt_cpu_nb);
+       if (err) {
+               pr_warn("global-timer: unable to register cpu notifier.\n");
+               goto out_irq;
+       }
+
+       /* Immediately configure the timer on the boot CPU */
+       gt_clocksource_init();
+       gt_clockevents_init(this_cpu_ptr(gt_evt));
+
+       return;
+
+out_irq:
+       free_percpu_irq(gt_ppi, gt_evt);
+out_free:
+       free_percpu(gt_evt);
+out_clk:
+       clk_disable_unprepare(gt_clk);
+out_unmap:
+       iounmap(gt_base);
+       WARN(err, "ARM Global timer register failed (%d)\n", err);
+}
+
+/* Only tested on r2p2 and r3p0  */
+CLOCKSOURCE_OF_DECLARE(arm_gt, "arm,cortex-a9-global-timer",
+                       global_timer_of_register);
diff --git a/drivers/clocksource/time-orion.c b/drivers/clocksource/time-orion.c
new file mode 100644 (file)
index 0000000..ecbeb68
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+ * Marvell Orion SoC timer handling.
+ *
+ * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ *
+ * Timer 0 is used as free-running clocksource, while timer 1 is
+ * used as clock_event_device.
+ */
+
+#include <linux/kernel.h>
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/clockchips.h>
+#include <linux/interrupt.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/spinlock.h>
+#include <asm/sched_clock.h>
+
+#define TIMER_CTRL             0x00
+#define  TIMER0_EN             BIT(0)
+#define  TIMER0_RELOAD_EN      BIT(1)
+#define  TIMER1_EN             BIT(2)
+#define  TIMER1_RELOAD_EN      BIT(3)
+#define TIMER0_RELOAD          0x10
+#define TIMER0_VAL             0x14
+#define TIMER1_RELOAD          0x18
+#define TIMER1_VAL             0x1c
+
+#define ORION_ONESHOT_MIN      1
+#define ORION_ONESHOT_MAX      0xfffffffe
+
+static void __iomem *timer_base;
+static DEFINE_SPINLOCK(timer_ctrl_lock);
+
+/*
+ * Thread-safe access to TIMER_CTRL register
+ * (shared with watchdog timer)
+ */
+void orion_timer_ctrl_clrset(u32 clr, u32 set)
+{
+       spin_lock(&timer_ctrl_lock);
+       writel((readl(timer_base + TIMER_CTRL) & ~clr) | set,
+               timer_base + TIMER_CTRL);
+       spin_unlock(&timer_ctrl_lock);
+}
+EXPORT_SYMBOL(orion_timer_ctrl_clrset);
+
+/*
+ * Free-running clocksource handling.
+ */
+static u32 notrace orion_read_sched_clock(void)
+{
+       return ~readl(timer_base + TIMER0_VAL);
+}
+
+/*
+ * Clockevent handling.
+ */
+static u32 ticks_per_jiffy;
+
+static int orion_clkevt_next_event(unsigned long delta,
+                                  struct clock_event_device *dev)
+{
+       /* setup and enable one-shot timer */
+       writel(delta, timer_base + TIMER1_VAL);
+       orion_timer_ctrl_clrset(TIMER1_RELOAD_EN, TIMER1_EN);
+
+       return 0;
+}
+
+static void orion_clkevt_mode(enum clock_event_mode mode,
+                             struct clock_event_device *dev)
+{
+       if (mode == CLOCK_EVT_MODE_PERIODIC) {
+               /* setup and enable periodic timer at 1/HZ intervals */
+               writel(ticks_per_jiffy - 1, timer_base + TIMER1_RELOAD);
+               writel(ticks_per_jiffy - 1, timer_base + TIMER1_VAL);
+               orion_timer_ctrl_clrset(0, TIMER1_RELOAD_EN | TIMER1_EN);
+       } else {
+               /* disable timer */
+               orion_timer_ctrl_clrset(TIMER1_RELOAD_EN | TIMER1_EN, 0);
+       }
+}
+
+static struct clock_event_device orion_clkevt = {
+       .name           = "orion_event",
+       .features       = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC,
+       .shift          = 32,
+       .rating         = 300,
+       .set_next_event = orion_clkevt_next_event,
+       .set_mode       = orion_clkevt_mode,
+};
+
+static irqreturn_t orion_clkevt_irq_handler(int irq, void *dev_id)
+{
+       orion_clkevt.event_handler(&orion_clkevt);
+       return IRQ_HANDLED;
+}
+
+static struct irqaction orion_clkevt_irq = {
+       .name           = "orion_event",
+       .flags          = IRQF_TIMER,
+       .handler        = orion_clkevt_irq_handler,
+};
+
+static void __init orion_timer_init(struct device_node *np)
+{
+       struct clk *clk;
+       int irq;
+
+       /* timer registers are shared with watchdog timer */
+       timer_base = of_iomap(np, 0);
+       if (!timer_base)
+               panic("%s: unable to map resource\n", np->name);
+
+       clk = of_clk_get(np, 0);
+       if (IS_ERR(clk))
+               panic("%s: unable to get clk\n", np->name);
+       clk_prepare_enable(clk);
+
+       /* we are only interested in timer1 irq */
+       irq = irq_of_parse_and_map(np, 1);
+       if (irq <= 0)
+               panic("%s: unable to parse timer1 irq\n", np->name);
+
+       /* setup timer0 as free-running clocksource */
+       writel(~0, timer_base + TIMER0_VAL);
+       writel(~0, timer_base + TIMER0_RELOAD);
+       orion_timer_ctrl_clrset(0, TIMER0_RELOAD_EN | TIMER0_EN);
+       clocksource_mmio_init(timer_base + TIMER0_VAL, "orion_clocksource",
+                             clk_get_rate(clk), 300, 32,
+                             clocksource_mmio_readl_down);
+       setup_sched_clock(orion_read_sched_clock, 32, clk_get_rate(clk));
+
+       /* setup timer1 as clockevent timer */
+       if (setup_irq(irq, &orion_clkevt_irq))
+               panic("%s: unable to setup irq\n", np->name);
+
+       ticks_per_jiffy = (clk_get_rate(clk) + HZ/2) / HZ;
+       orion_clkevt.cpumask = cpumask_of(0);
+       orion_clkevt.irq = irq;
+       clockevents_config_and_register(&orion_clkevt, clk_get_rate(clk),
+                                       ORION_ONESHOT_MIN, ORION_ONESHOT_MAX);
+}
+CLOCKSOURCE_OF_DECLARE(orion_timer, "marvell,orion-timer", orion_timer_init);
index 6a015ad..0937b8d 100644 (file)
@@ -312,11 +312,12 @@ static void __cpufreq_notify_transition(struct cpufreq_policy *policy,
        switch (state) {
 
        case CPUFREQ_PRECHANGE:
-               if (WARN(policy->transition_ongoing,
+               if (WARN(policy->transition_ongoing ==
+                                       cpumask_weight(policy->cpus),
                                "In middle of another frequency transition\n"))
                        return;
 
-               policy->transition_ongoing = true;
+               policy->transition_ongoing++;
 
                /* detect if the driver reported a value as "old frequency"
                 * which is not equal to what the cpufreq core thinks is
@@ -341,7 +342,7 @@ static void __cpufreq_notify_transition(struct cpufreq_policy *policy,
                                "No frequency transition in progress\n"))
                        return;
 
-               policy->transition_ongoing = false;
+               policy->transition_ongoing--;
 
                adjust_jiffies(CPUFREQ_POSTCHANGE, freqs);
                pr_debug("FREQ: %lu - CPU: %lu", (unsigned long)freqs->new,
index a697a64..878f090 100644 (file)
@@ -349,21 +349,21 @@ config EDAC_OCTEON_PC
 
 config EDAC_OCTEON_L2C
        tristate "Cavium Octeon Secondary Caches (L2C)"
-       depends on EDAC_MM_EDAC && CPU_CAVIUM_OCTEON
+       depends on EDAC_MM_EDAC && CAVIUM_OCTEON_SOC
        help
          Support for error detection and correction on the
          Cavium Octeon family of SOCs.
 
 config EDAC_OCTEON_LMC
        tristate "Cavium Octeon DRAM Memory Controller (LMC)"
-       depends on EDAC_MM_EDAC && CPU_CAVIUM_OCTEON
+       depends on EDAC_MM_EDAC && CAVIUM_OCTEON_SOC
        help
          Support for error detection and correction on the
          Cavium Octeon family of SOCs.
 
 config EDAC_OCTEON_PCI
        tristate "Cavium Octeon PCI Controller"
-       depends on EDAC_MM_EDAC && PCI && CPU_CAVIUM_OCTEON
+       depends on EDAC_MM_EDAC && PCI && CAVIUM_OCTEON_SOC
        help
          Support for error detection and correction on the
          Cavium Octeon family of SOCs.
index 664a6ff..de4aa40 100644 (file)
@@ -165,25 +165,44 @@ static bool match_ids(const struct ieee1394_device_id *id_table, int *id)
        return (match & id_table->match_flags) == id_table->match_flags;
 }
 
-static bool is_fw_unit(struct device *dev);
-
-static int fw_unit_match(struct device *dev, struct device_driver *drv)
+static const struct ieee1394_device_id *unit_match(struct device *dev,
+                                                  struct device_driver *drv)
 {
        const struct ieee1394_device_id *id_table =
                        container_of(drv, struct fw_driver, driver)->id_table;
        int id[] = {0, 0, 0, 0};
 
-       /* We only allow binding to fw_units. */
-       if (!is_fw_unit(dev))
-               return 0;
-
        get_modalias_ids(fw_unit(dev), id);
 
        for (; id_table->match_flags != 0; id_table++)
                if (match_ids(id_table, id))
-                       return 1;
+                       return id_table;
 
-       return 0;
+       return NULL;
+}
+
+static bool is_fw_unit(struct device *dev);
+
+static int fw_unit_match(struct device *dev, struct device_driver *drv)
+{
+       /* We only allow binding to fw_units. */
+       return is_fw_unit(dev) && unit_match(dev, drv) != NULL;
+}
+
+static int fw_unit_probe(struct device *dev)
+{
+       struct fw_driver *driver =
+                       container_of(dev->driver, struct fw_driver, driver);
+
+       return driver->probe(fw_unit(dev), unit_match(dev, dev->driver));
+}
+
+static int fw_unit_remove(struct device *dev)
+{
+       struct fw_driver *driver =
+                       container_of(dev->driver, struct fw_driver, driver);
+
+       return driver->remove(fw_unit(dev)), 0;
 }
 
 static int get_modalias(struct fw_unit *unit, char *buffer, size_t buffer_size)
@@ -213,6 +232,8 @@ static int fw_unit_uevent(struct device *dev, struct kobj_uevent_env *env)
 struct bus_type fw_bus_type = {
        .name = "firewire",
        .match = fw_unit_match,
+       .probe = fw_unit_probe,
+       .remove = fw_unit_remove,
 };
 EXPORT_SYMBOL(fw_bus_type);
 
index 815b0fc..6b89598 100644 (file)
@@ -1440,9 +1440,9 @@ static int fwnet_add_peer(struct fwnet_device *dev,
        return 0;
 }
 
-static int fwnet_probe(struct device *_dev)
+static int fwnet_probe(struct fw_unit *unit,
+                      const struct ieee1394_device_id *id)
 {
-       struct fw_unit *unit = fw_unit(_dev);
        struct fw_device *device = fw_parent_device(unit);
        struct fw_card *card = device->card;
        struct net_device *net;
@@ -1526,6 +1526,24 @@ static int fwnet_probe(struct device *_dev)
        return ret;
 }
 
+/*
+ * FIXME abort partially sent fragmented datagrams,
+ * discard partially received fragmented datagrams
+ */
+static void fwnet_update(struct fw_unit *unit)
+{
+       struct fw_device *device = fw_parent_device(unit);
+       struct fwnet_peer *peer = dev_get_drvdata(&unit->device);
+       int generation;
+
+       generation = device->generation;
+
+       spin_lock_irq(&peer->dev->lock);
+       peer->node_id    = device->node_id;
+       peer->generation = generation;
+       spin_unlock_irq(&peer->dev->lock);
+}
+
 static void fwnet_remove_peer(struct fwnet_peer *peer, struct fwnet_device *dev)
 {
        struct fwnet_partial_datagram *pd, *pd_next;
@@ -1542,9 +1560,9 @@ static void fwnet_remove_peer(struct fwnet_peer *peer, struct fwnet_device *dev)
        kfree(peer);
 }
 
-static int fwnet_remove(struct device *_dev)
+static void fwnet_remove(struct fw_unit *unit)
 {
-       struct fwnet_peer *peer = dev_get_drvdata(_dev);
+       struct fwnet_peer *peer = dev_get_drvdata(&unit->device);
        struct fwnet_device *dev = peer->dev;
        struct net_device *net;
        int i;
@@ -1569,26 +1587,6 @@ static int fwnet_remove(struct device *_dev)
        }
 
        mutex_unlock(&fwnet_device_mutex);
-
-       return 0;
-}
-
-/*
- * FIXME abort partially sent fragmented datagrams,
- * discard partially received fragmented datagrams
- */
-static void fwnet_update(struct fw_unit *unit)
-{
-       struct fw_device *device = fw_parent_device(unit);
-       struct fwnet_peer *peer = dev_get_drvdata(&unit->device);
-       int generation;
-
-       generation = device->generation;
-
-       spin_lock_irq(&peer->dev->lock);
-       peer->node_id    = device->node_id;
-       peer->generation = generation;
-       spin_unlock_irq(&peer->dev->lock);
 }
 
 static const struct ieee1394_device_id fwnet_id_table[] = {
@@ -1614,10 +1612,10 @@ static struct fw_driver fwnet_driver = {
                .owner  = THIS_MODULE,
                .name   = KBUILD_MODNAME,
                .bus    = &fw_bus_type,
-               .probe  = fwnet_probe,
-               .remove = fwnet_remove,
        },
+       .probe    = fwnet_probe,
        .update   = fwnet_update,
+       .remove   = fwnet_remove,
        .id_table = fwnet_id_table,
 };
 
index 47674b9..281029d 100644 (file)
@@ -1128,11 +1128,10 @@ static void sbp2_init_workarounds(struct sbp2_target *tgt, u32 model,
 }
 
 static struct scsi_host_template scsi_driver_template;
-static int sbp2_remove(struct device *dev);
+static void sbp2_remove(struct fw_unit *unit);
 
-static int sbp2_probe(struct device *dev)
+static int sbp2_probe(struct fw_unit *unit, const struct ieee1394_device_id *id)
 {
-       struct fw_unit *unit = fw_unit(dev);
        struct fw_device *device = fw_parent_device(unit);
        struct sbp2_target *tgt;
        struct sbp2_logical_unit *lu;
@@ -1196,7 +1195,7 @@ static int sbp2_probe(struct device *dev)
        return 0;
 
  fail_remove:
-       sbp2_remove(dev);
+       sbp2_remove(unit);
        return -ENOMEM;
 
  fail_shost_put:
@@ -1222,9 +1221,8 @@ static void sbp2_update(struct fw_unit *unit)
        }
 }
 
-static int sbp2_remove(struct device *dev)
+static void sbp2_remove(struct fw_unit *unit)
 {
-       struct fw_unit *unit = fw_unit(dev);
        struct fw_device *device = fw_parent_device(unit);
        struct sbp2_target *tgt = dev_get_drvdata(&unit->device);
        struct sbp2_logical_unit *lu, *next;
@@ -1261,10 +1259,9 @@ static int sbp2_remove(struct device *dev)
                kfree(lu);
        }
        scsi_remove_host(shost);
-       dev_notice(dev, "released target %d:0:0\n", shost->host_no);
+       dev_notice(&unit->device, "released target %d:0:0\n", shost->host_no);
 
        scsi_host_put(shost);
-       return 0;
 }
 
 #define SBP2_UNIT_SPEC_ID_ENTRY        0x0000609e
@@ -1285,10 +1282,10 @@ static struct fw_driver sbp2_driver = {
                .owner  = THIS_MODULE,
                .name   = KBUILD_MODNAME,
                .bus    = &fw_bus_type,
-               .probe  = sbp2_probe,
-               .remove = sbp2_remove,
        },
+       .probe    = sbp2_probe,
        .update   = sbp2_update,
+       .remove   = sbp2_remove,
        .id_table = sbp2_id_table,
 };
 
index a4f5ce1..271b42b 100644 (file)
@@ -133,8 +133,8 @@ static u8 generic_edid[GENERIC_EDIDS][128] = {
        },
 };
 
-static u8 *edid_load(struct drm_connector *connector, char *name,
-                       char *connector_name)
+static u8 *edid_load(struct drm_connector *connector, const char *name,
+                       const char *connector_name)
 {
        const struct firmware *fw;
        struct platform_device *pdev;
@@ -242,7 +242,7 @@ out:
 
 int drm_load_edid_firmware(struct drm_connector *connector)
 {
-       char *connector_name = drm_get_connector_name(connector);
+       const char *connector_name = drm_get_connector_name(connector);
        char *edidname = edid_firmware, *last, *colon;
        int ret;
        struct edid *edid;
index f644a2e..d0def50 100644 (file)
@@ -247,9 +247,8 @@ static struct lm63_data *lm63_update_device(struct device *dev)
 
        mutex_lock(&data->update_lock);
 
-       next_update = data->last_updated
-         + msecs_to_jiffies(data->update_interval) + 1;
-
+       next_update = data->last_updated +
+                     msecs_to_jiffies(data->update_interval);
        if (time_after(jiffies, next_update) || !data->valid) {
                if (data->config & 0x04) { /* tachometer enabled  */
                        /* order matters for fan1_input */
index 8eeb141..cdff742 100644 (file)
@@ -470,8 +470,8 @@ static struct lm90_data *lm90_update_device(struct device *dev)
 
        mutex_lock(&data->update_lock);
 
-       next_update = data->last_updated
-         + msecs_to_jiffies(data->update_interval) + 1;
+       next_update = data->last_updated +
+                     msecs_to_jiffies(data->update_interval);
        if (time_after(jiffies, next_update) || !data->valid) {
                u8 h, l;
                u8 alarms;
index fdc2ab4..dc6dea6 100644 (file)
@@ -739,7 +739,7 @@ config I2C_WMT
 
 config I2C_OCTEON
        tristate "Cavium OCTEON I2C bus support"
-       depends on CPU_CAVIUM_OCTEON
+       depends on CAVIUM_OCTEON_SOC
        help
          Say yes if you want to support the I2C serial bus on Cavium
          OCTEON SOC.
index 7e27d32..300daab 100644 (file)
@@ -173,18 +173,7 @@ static struct pci_driver delkin_cb_pci_driver = {
        .resume         = delkin_cb_resume,
 };
 
-static int __init delkin_cb_init(void)
-{
-       return pci_register_driver(&delkin_cb_pci_driver);
-}
-
-static void __exit delkin_cb_exit(void)
-{
-       pci_unregister_driver(&delkin_cb_pci_driver);
-}
-
-module_init(delkin_cb_init);
-module_exit(delkin_cb_exit);
+module_pci_driver(delkin_cb_pci_driver);
 
 MODULE_AUTHOR("Mark Lord");
 MODULE_DESCRIPTION("Basic support for Delkin/ASKA/Workbit Cardbus IDE");
index 51beb85..0a8440a 100644 (file)
@@ -183,20 +183,7 @@ static struct platform_driver amiga_gayle_ide_driver = {
        },
 };
 
-static int __init amiga_gayle_ide_init(void)
-{
-       return platform_driver_probe(&amiga_gayle_ide_driver,
-                                    amiga_gayle_ide_probe);
-}
-
-module_init(amiga_gayle_ide_init);
-
-static void __exit amiga_gayle_ide_exit(void)
-{
-       platform_driver_unregister(&amiga_gayle_ide_driver);
-}
-
-module_exit(amiga_gayle_ide_exit);
+module_platform_driver_probe(amiga_gayle_ide_driver, amiga_gayle_ide_probe);
 
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("platform:amiga-gayle-ide");
index 729428e..dabb88b 100644 (file)
@@ -239,9 +239,6 @@ void ide_pio_bytes(ide_drive_t *drive, struct ide_cmd *cmd,
                unsigned nr_bytes = min(len, cursg->length - cmd->cursg_ofs);
                int page_is_high;
 
-               if (nr_bytes > PAGE_SIZE)
-                       nr_bytes = PAGE_SIZE;
-
                page = sg_page(cursg);
                offset = cursg->offset + cmd->cursg_ofs;
 
@@ -249,6 +246,8 @@ void ide_pio_bytes(ide_drive_t *drive, struct ide_cmd *cmd,
                page = nth_page(page, (offset >> PAGE_SHIFT));
                offset %= PAGE_SIZE;
 
+               nr_bytes = min_t(unsigned, nr_bytes, (PAGE_SIZE - offset));
+
                page_is_high = PageHighMem(page);
                if (page_is_high)
                        local_irq_save(flags);
index 91d49dd..ede8575 100644 (file)
@@ -203,18 +203,7 @@ static struct platform_driver tx4938ide_driver = {
        .remove = __exit_p(tx4938ide_remove),
 };
 
-static int __init tx4938ide_init(void)
-{
-       return platform_driver_probe(&tx4938ide_driver, tx4938ide_probe);
-}
-
-static void __exit tx4938ide_exit(void)
-{
-       platform_driver_unregister(&tx4938ide_driver);
-}
-
-module_init(tx4938ide_init);
-module_exit(tx4938ide_exit);
+module_platform_driver_probe(tx4938ide_driver, tx4938ide_probe);
 
 MODULE_DESCRIPTION("TX4938 internal IDE driver");
 MODULE_LICENSE("GPL");
index c0ab800..4ecdee5 100644 (file)
@@ -624,18 +624,7 @@ static struct platform_driver tx4939ide_driver = {
        .resume = tx4939ide_resume,
 };
 
-static int __init tx4939ide_init(void)
-{
-       return platform_driver_probe(&tx4939ide_driver, tx4939ide_probe);
-}
-
-static void __exit tx4939ide_exit(void)
-{
-       platform_driver_unregister(&tx4939ide_driver);
-}
-
-module_init(tx4939ide_init);
-module_exit(tx4939ide_exit);
+module_platform_driver_probe(tx4939ide_driver, tx4939ide_probe);
 
 MODULE_DESCRIPTION("TX4939 internal IDE driver");
 MODULE_LICENSE("GPL");
index 5f9a7e7..4427e8e 100644 (file)
 #include <linux/platform_device.h>
 #include <linux/io.h>
 #include <linux/iio/iio.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/iio/machine.h>
+#include <linux/iio/driver.h>
 
 #include <linux/mfd/ti_am335x_tscadc.h>
-#include <linux/platform_data/ti_am335x_adc.h>
 
 struct tiadc_device {
        struct ti_tscadc_dev *mfd_tscadc;
        int channels;
+       u8 channel_line[8];
+       u8 channel_step[8];
 };
 
 static unsigned int tiadc_readl(struct tiadc_device *adc, unsigned int reg)
@@ -42,10 +47,20 @@ static void tiadc_writel(struct tiadc_device *adc, unsigned int reg,
        writel(val, adc->mfd_tscadc->tscadc_base + reg);
 }
 
+static u32 get_adc_step_mask(struct tiadc_device *adc_dev)
+{
+       u32 step_en;
+
+       step_en = ((1 << adc_dev->channels) - 1);
+       step_en <<= TOTAL_STEPS - adc_dev->channels + 1;
+       return step_en;
+}
+
 static void tiadc_step_config(struct tiadc_device *adc_dev)
 {
        unsigned int stepconfig;
-       int i, channels = 0, steps;
+       int i, steps;
+       u32 step_en;
 
        /*
         * There are 16 configurable steps and 8 analog input
@@ -58,43 +73,63 @@ static void tiadc_step_config(struct tiadc_device *adc_dev)
         */
 
        steps = TOTAL_STEPS - adc_dev->channels;
-       channels = TOTAL_CHANNELS - adc_dev->channels;
-
        stepconfig = STEPCONFIG_AVG_16 | STEPCONFIG_FIFO1;
 
-       for (i = (steps + 1); i <= TOTAL_STEPS; i++) {
-               tiadc_writel(adc_dev, REG_STEPCONFIG(i),
-                               stepconfig | STEPCONFIG_INP(channels));
-               tiadc_writel(adc_dev, REG_STEPDELAY(i),
+       for (i = 0; i < adc_dev->channels; i++) {
+               int chan;
+
+               chan = adc_dev->channel_line[i];
+               tiadc_writel(adc_dev, REG_STEPCONFIG(steps),
+                               stepconfig | STEPCONFIG_INP(chan));
+               tiadc_writel(adc_dev, REG_STEPDELAY(steps),
                                STEPCONFIG_OPENDLY);
-               channels++;
+               adc_dev->channel_step[i] = steps;
+               steps++;
        }
-       tiadc_writel(adc_dev, REG_SE, STPENB_STEPENB);
+       step_en = get_adc_step_mask(adc_dev);
+       am335x_tsc_se_set(adc_dev->mfd_tscadc, step_en);
 }
 
+static const char * const chan_name_ain[] = {
+       "AIN0",
+       "AIN1",
+       "AIN2",
+       "AIN3",
+       "AIN4",
+       "AIN5",
+       "AIN6",
+       "AIN7",
+};
+
 static int tiadc_channel_init(struct iio_dev *indio_dev, int channels)
 {
+       struct tiadc_device *adc_dev = iio_priv(indio_dev);
        struct iio_chan_spec *chan_array;
+       struct iio_chan_spec *chan;
        int i;
 
        indio_dev->num_channels = channels;
-       chan_array = kcalloc(indio_dev->num_channels,
+       chan_array = kcalloc(channels,
                        sizeof(struct iio_chan_spec), GFP_KERNEL);
-
        if (chan_array == NULL)
                return -ENOMEM;
 
-       for (i = 0; i < (indio_dev->num_channels); i++) {
-               struct iio_chan_spec *chan = chan_array + i;
+       chan = chan_array;
+       for (i = 0; i < channels; i++, chan++) {
+
                chan->type = IIO_VOLTAGE;
                chan->indexed = 1;
-               chan->channel = i;
+               chan->channel = adc_dev->channel_line[i];
                chan->info_mask_separate = BIT(IIO_CHAN_INFO_RAW);
+               chan->datasheet_name = chan_name_ain[chan->channel];
+               chan->scan_type.sign = 'u';
+               chan->scan_type.realbits = 12;
+               chan->scan_type.storagebits = 32;
        }
 
        indio_dev->channels = chan_array;
 
-       return indio_dev->num_channels;
+       return 0;
 }
 
 static void tiadc_channels_remove(struct iio_dev *indio_dev)
@@ -108,7 +143,9 @@ static int tiadc_read_raw(struct iio_dev *indio_dev,
 {
        struct tiadc_device *adc_dev = iio_priv(indio_dev);
        int i;
-       unsigned int fifo1count, readx1;
+       unsigned int fifo1count, read;
+       u32 step = UINT_MAX;
+       bool found = false;
 
        /*
         * When the sub-system is first enabled,
@@ -121,14 +158,26 @@ static int tiadc_read_raw(struct iio_dev *indio_dev,
         * Hence we need to flush out this data.
         */
 
+       for (i = 0; i < ARRAY_SIZE(adc_dev->channel_step); i++) {
+               if (chan->channel == adc_dev->channel_line[i]) {
+                       step = adc_dev->channel_step[i];
+                       break;
+               }
+       }
+       if (WARN_ON_ONCE(step == UINT_MAX))
+               return -EINVAL;
+
        fifo1count = tiadc_readl(adc_dev, REG_FIFO1CNT);
        for (i = 0; i < fifo1count; i++) {
-               readx1 = tiadc_readl(adc_dev, REG_FIFO1);
-               if (i == chan->channel)
-                       *val = readx1 & 0xfff;
+               read = tiadc_readl(adc_dev, REG_FIFO1);
+               if (read >> 16 == step) {
+                       *val = read & 0xfff;
+                       found = true;
+               }
        }
-       tiadc_writel(adc_dev, REG_SE, STPENB_STEPENB);
-
+       am335x_tsc_se_update(adc_dev->mfd_tscadc);
+       if (found == false)
+               return -EBUSY;
        return IIO_VAL_INT;
 }
 
@@ -140,13 +189,15 @@ static int tiadc_probe(struct platform_device *pdev)
 {
        struct iio_dev          *indio_dev;
        struct tiadc_device     *adc_dev;
-       struct ti_tscadc_dev    *tscadc_dev = pdev->dev.platform_data;
-       struct mfd_tscadc_board *pdata;
+       struct device_node      *node = pdev->dev.of_node;
+       struct property         *prop;
+       const __be32            *cur;
        int                     err;
+       u32                     val;
+       int                     channels = 0;
 
-       pdata = tscadc_dev->dev->platform_data;
-       if (!pdata || !pdata->adc_init) {
-               dev_err(&pdev->dev, "Could not find platform data\n");
+       if (!node) {
+               dev_err(&pdev->dev, "Could not find valid DT data.\n");
                return -EINVAL;
        }
 
@@ -158,8 +209,13 @@ static int tiadc_probe(struct platform_device *pdev)
        }
        adc_dev = iio_priv(indio_dev);
 
-       adc_dev->mfd_tscadc = tscadc_dev;
-       adc_dev->channels = pdata->adc_init->adc_channels;
+       adc_dev->mfd_tscadc = ti_tscadc_dev_get(pdev);
+
+       of_property_for_each_u32(node, "ti,adc-channels", prop, cur, val) {
+               adc_dev->channel_line[channels] = val;
+               channels++;
+       }
+       adc_dev->channels = channels;
 
        indio_dev->dev.parent = &pdev->dev;
        indio_dev->name = dev_name(&pdev->dev);
@@ -191,10 +247,15 @@ err_ret:
 static int tiadc_remove(struct platform_device *pdev)
 {
        struct iio_dev *indio_dev = platform_get_drvdata(pdev);
+       struct tiadc_device *adc_dev = iio_priv(indio_dev);
+       u32 step_en;
 
        iio_device_unregister(indio_dev);
        tiadc_channels_remove(indio_dev);
 
+       step_en = get_adc_step_mask(adc_dev);
+       am335x_tsc_se_clr(adc_dev->mfd_tscadc, step_en);
+
        iio_device_free(indio_dev);
 
        return 0;
@@ -205,9 +266,10 @@ static int tiadc_suspend(struct device *dev)
 {
        struct iio_dev *indio_dev = dev_get_drvdata(dev);
        struct tiadc_device *adc_dev = iio_priv(indio_dev);
-       struct ti_tscadc_dev *tscadc_dev = dev->platform_data;
+       struct ti_tscadc_dev *tscadc_dev;
        unsigned int idle;
 
+       tscadc_dev = ti_tscadc_dev_get(to_platform_device(dev));
        if (!device_may_wakeup(tscadc_dev->dev)) {
                idle = tiadc_readl(adc_dev, REG_CTRL);
                idle &= ~(CNTRLREG_TSCSSENB);
@@ -243,16 +305,22 @@ static const struct dev_pm_ops tiadc_pm_ops = {
 #define TIADC_PM_OPS NULL
 #endif
 
+static const struct of_device_id ti_adc_dt_ids[] = {
+       { .compatible = "ti,am3359-adc", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, ti_adc_dt_ids);
+
 static struct platform_driver tiadc_driver = {
        .driver = {
-               .name   = "tiadc",
+               .name   = "TI-am335x-adc",
                .owner  = THIS_MODULE,
                .pm     = TIADC_PM_OPS,
+               .of_match_table = of_match_ptr(ti_adc_dt_ids),
        },
        .probe  = tiadc_probe,
        .remove = tiadc_remove,
 };
-
 module_platform_driver(tiadc_driver);
 
 MODULE_DESCRIPTION("TI ADC controller driver");
index c85b56c..5ceda71 100644 (file)
@@ -50,6 +50,7 @@ source "drivers/infiniband/hw/amso1100/Kconfig"
 source "drivers/infiniband/hw/cxgb3/Kconfig"
 source "drivers/infiniband/hw/cxgb4/Kconfig"
 source "drivers/infiniband/hw/mlx4/Kconfig"
+source "drivers/infiniband/hw/mlx5/Kconfig"
 source "drivers/infiniband/hw/nes/Kconfig"
 source "drivers/infiniband/hw/ocrdma/Kconfig"
 
index b126fef..1fe6988 100644 (file)
@@ -7,6 +7,7 @@ obj-$(CONFIG_INFINIBAND_AMSO1100)       += hw/amso1100/
 obj-$(CONFIG_INFINIBAND_CXGB3)         += hw/cxgb3/
 obj-$(CONFIG_INFINIBAND_CXGB4)         += hw/cxgb4/
 obj-$(CONFIG_MLX4_INFINIBAND)          += hw/mlx4/
+obj-$(CONFIG_MLX5_INFINIBAND)          += hw/mlx5/
 obj-$(CONFIG_INFINIBAND_NES)           += hw/nes/
 obj-$(CONFIG_INFINIBAND_OCRDMA)                += hw/ocrdma/
 obj-$(CONFIG_INFINIBAND_IPOIB)         += ulp/ipoib/
index eaec8d7..e90f2b2 100644 (file)
@@ -45,6 +45,7 @@
 #include <net/addrconf.h>
 #include <net/ip6_route.h>
 #include <rdma/ib_addr.h>
+#include <rdma/ib.h>
 
 MODULE_AUTHOR("Sean Hefty");
 MODULE_DESCRIPTION("IB Address Translation");
@@ -70,6 +71,21 @@ static LIST_HEAD(req_list);
 static DECLARE_DELAYED_WORK(work, process_req);
 static struct workqueue_struct *addr_wq;
 
+int rdma_addr_size(struct sockaddr *addr)
+{
+       switch (addr->sa_family) {
+       case AF_INET:
+               return sizeof(struct sockaddr_in);
+       case AF_INET6:
+               return sizeof(struct sockaddr_in6);
+       case AF_IB:
+               return sizeof(struct sockaddr_ib);
+       default:
+               return 0;
+       }
+}
+EXPORT_SYMBOL(rdma_addr_size);
+
 void rdma_addr_register_client(struct rdma_addr_client *client)
 {
        atomic_set(&client->refcount, 1);
@@ -369,12 +385,12 @@ int rdma_resolve_ip(struct rdma_addr_client *client,
                        goto err;
                }
 
-               memcpy(src_in, src_addr, ip_addr_size(src_addr));
+               memcpy(src_in, src_addr, rdma_addr_size(src_addr));
        } else {
                src_in->sa_family = dst_addr->sa_family;
        }
 
-       memcpy(dst_in, dst_addr, ip_addr_size(dst_addr));
+       memcpy(dst_in, dst_addr, rdma_addr_size(dst_addr));
        req->addr = addr;
        req->callback = callback;
        req->context = context;
index 34fbc2f..f1c279f 100644 (file)
@@ -50,6 +50,7 @@
 #include <rdma/rdma_cm.h>
 #include <rdma/rdma_cm_ib.h>
 #include <rdma/rdma_netlink.h>
+#include <rdma/ib.h>
 #include <rdma/ib_cache.h>
 #include <rdma/ib_cm.h>
 #include <rdma/ib_sa.h>
@@ -79,7 +80,6 @@ static LIST_HEAD(dev_list);
 static LIST_HEAD(listen_any_list);
 static DEFINE_MUTEX(lock);
 static struct workqueue_struct *cma_wq;
-static DEFINE_IDR(sdp_ps);
 static DEFINE_IDR(tcp_ps);
 static DEFINE_IDR(udp_ps);
 static DEFINE_IDR(ipoib_ps);
@@ -195,24 +195,7 @@ struct cma_hdr {
        union cma_ip_addr dst_addr;
 };
 
-struct sdp_hh {
-       u8 bsdh[16];
-       u8 sdp_version; /* Major version: 7:4 */
-       u8 ip_version;  /* IP version: 7:4 */
-       u8 sdp_specific1[10];
-       __be16 port;
-       __be16 sdp_specific2;
-       union cma_ip_addr src_addr;
-       union cma_ip_addr dst_addr;
-};
-
-struct sdp_hah {
-       u8 bsdh[16];
-       u8 sdp_version;
-};
-
 #define CMA_VERSION 0x00
-#define SDP_MAJ_VERSION 0x2
 
 static int cma_comp(struct rdma_id_private *id_priv, enum rdma_cm_state comp)
 {
@@ -261,21 +244,6 @@ static inline void cma_set_ip_ver(struct cma_hdr *hdr, u8 ip_ver)
        hdr->ip_version = (ip_ver << 4) | (hdr->ip_version & 0xF);
 }
 
-static inline u8 sdp_get_majv(u8 sdp_version)
-{
-       return sdp_version >> 4;
-}
-
-static inline u8 sdp_get_ip_ver(struct sdp_hh *hh)
-{
-       return hh->ip_version >> 4;
-}
-
-static inline void sdp_set_ip_ver(struct sdp_hh *hh, u8 ip_ver)
-{
-       hh->ip_version = (ip_ver << 4) | (hh->ip_version & 0xF);
-}
-
 static void cma_attach_to_dev(struct rdma_id_private *id_priv,
                              struct cma_device *cma_dev)
 {
@@ -310,16 +278,40 @@ static void cma_release_dev(struct rdma_id_private *id_priv)
        mutex_unlock(&lock);
 }
 
-static int cma_set_qkey(struct rdma_id_private *id_priv)
+static inline struct sockaddr *cma_src_addr(struct rdma_id_private *id_priv)
+{
+       return (struct sockaddr *) &id_priv->id.route.addr.src_addr;
+}
+
+static inline struct sockaddr *cma_dst_addr(struct rdma_id_private *id_priv)
+{
+       return (struct sockaddr *) &id_priv->id.route.addr.dst_addr;
+}
+
+static inline unsigned short cma_family(struct rdma_id_private *id_priv)
+{
+       return id_priv->id.route.addr.src_addr.ss_family;
+}
+
+static int cma_set_qkey(struct rdma_id_private *id_priv, u32 qkey)
 {
        struct ib_sa_mcmember_rec rec;
        int ret = 0;
 
-       if (id_priv->qkey)
+       if (id_priv->qkey) {
+               if (qkey && id_priv->qkey != qkey)
+                       return -EINVAL;
+               return 0;
+       }
+
+       if (qkey) {
+               id_priv->qkey = qkey;
                return 0;
+       }
 
        switch (id_priv->id.ps) {
        case RDMA_PS_UDP:
+       case RDMA_PS_IB:
                id_priv->qkey = RDMA_UDP_QKEY;
                break;
        case RDMA_PS_IPOIB:
@@ -358,6 +350,27 @@ static int find_gid_port(struct ib_device *device, union ib_gid *gid, u8 port_nu
        return -EADDRNOTAVAIL;
 }
 
+static void cma_translate_ib(struct sockaddr_ib *sib, struct rdma_dev_addr *dev_addr)
+{
+       dev_addr->dev_type = ARPHRD_INFINIBAND;
+       rdma_addr_set_sgid(dev_addr, (union ib_gid *) &sib->sib_addr);
+       ib_addr_set_pkey(dev_addr, ntohs(sib->sib_pkey));
+}
+
+static int cma_translate_addr(struct sockaddr *addr, struct rdma_dev_addr *dev_addr)
+{
+       int ret;
+
+       if (addr->sa_family != AF_IB) {
+               ret = rdma_translate_ip(addr, dev_addr);
+       } else {
+               cma_translate_ib((struct sockaddr_ib *) addr, dev_addr);
+               ret = 0;
+       }
+
+       return ret;
+}
+
 static int cma_acquire_dev(struct rdma_id_private *id_priv)
 {
        struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr;
@@ -401,6 +414,61 @@ out:
        return ret;
 }
 
+/*
+ * Select the source IB device and address to reach the destination IB address.
+ */
+static int cma_resolve_ib_dev(struct rdma_id_private *id_priv)
+{
+       struct cma_device *cma_dev, *cur_dev;
+       struct sockaddr_ib *addr;
+       union ib_gid gid, sgid, *dgid;
+       u16 pkey, index;
+       u8 port, p;
+       int i;
+
+       cma_dev = NULL;
+       addr = (struct sockaddr_ib *) cma_dst_addr(id_priv);
+       dgid = (union ib_gid *) &addr->sib_addr;
+       pkey = ntohs(addr->sib_pkey);
+
+       list_for_each_entry(cur_dev, &dev_list, list) {
+               if (rdma_node_get_transport(cur_dev->device->node_type) != RDMA_TRANSPORT_IB)
+                       continue;
+
+               for (p = 1; p <= cur_dev->device->phys_port_cnt; ++p) {
+                       if (ib_find_cached_pkey(cur_dev->device, p, pkey, &index))
+                               continue;
+
+                       for (i = 0; !ib_get_cached_gid(cur_dev->device, p, i, &gid); i++) {
+                               if (!memcmp(&gid, dgid, sizeof(gid))) {
+                                       cma_dev = cur_dev;
+                                       sgid = gid;
+                                       port = p;
+                                       goto found;
+                               }
+
+                               if (!cma_dev && (gid.global.subnet_prefix ==
+                                                dgid->global.subnet_prefix)) {
+                                       cma_dev = cur_dev;
+                                       sgid = gid;
+                                       port = p;
+                               }
+                       }
+               }
+       }
+
+       if (!cma_dev)
+               return -ENODEV;
+
+found:
+       cma_attach_to_dev(id_priv, cma_dev);
+       id_priv->id.port_num = port;
+       addr = (struct sockaddr_ib *) cma_src_addr(id_priv);
+       memcpy(&addr->sib_addr, &sgid, sizeof sgid);
+       cma_translate_ib(addr, &id_priv->id.route.addr.dev_addr);
+       return 0;
+}
+
 static void cma_deref_id(struct rdma_id_private *id_priv)
 {
        if (atomic_dec_and_test(&id_priv->refcount))
@@ -630,7 +698,7 @@ static int cma_ib_init_qp_attr(struct rdma_id_private *id_priv,
        *qp_attr_mask = IB_QP_STATE | IB_QP_PKEY_INDEX | IB_QP_PORT;
 
        if (id_priv->id.qp_type == IB_QPT_UD) {
-               ret = cma_set_qkey(id_priv);
+               ret = cma_set_qkey(id_priv, 0);
                if (ret)
                        return ret;
 
@@ -679,26 +747,30 @@ EXPORT_SYMBOL(rdma_init_qp_attr);
 
 static inline int cma_zero_addr(struct sockaddr *addr)
 {
-       struct in6_addr *ip6;
-
-       if (addr->sa_family == AF_INET)
-               return ipv4_is_zeronet(
-                       ((struct sockaddr_in *)addr)->sin_addr.s_addr);
-       else {
-               ip6 = &((struct sockaddr_in6 *) addr)->sin6_addr;
-               return (ip6->s6_addr32[0] | ip6->s6_addr32[1] |
-                       ip6->s6_addr32[2] | ip6->s6_addr32[3]) == 0;
+       switch (addr->sa_family) {
+       case AF_INET:
+               return ipv4_is_zeronet(((struct sockaddr_in *)addr)->sin_addr.s_addr);
+       case AF_INET6:
+               return ipv6_addr_any(&((struct sockaddr_in6 *) addr)->sin6_addr);
+       case AF_IB:
+               return ib_addr_any(&((struct sockaddr_ib *) addr)->sib_addr);
+       default:
+               return 0;
        }
 }
 
 static inline int cma_loopback_addr(struct sockaddr *addr)
 {
-       if (addr->sa_family == AF_INET)
-               return ipv4_is_loopback(
-                       ((struct sockaddr_in *) addr)->sin_addr.s_addr);
-       else
-               return ipv6_addr_loopback(
-                       &((struct sockaddr_in6 *) addr)->sin6_addr);
+       switch (addr->sa_family) {
+       case AF_INET:
+               return ipv4_is_loopback(((struct sockaddr_in *) addr)->sin_addr.s_addr);
+       case AF_INET6:
+               return ipv6_addr_loopback(&((struct sockaddr_in6 *) addr)->sin6_addr);
+       case AF_IB:
+               return ib_addr_loopback(&((struct sockaddr_ib *) addr)->sib_addr);
+       default:
+               return 0;
+       }
 }
 
 static inline int cma_any_addr(struct sockaddr *addr)
@@ -715,18 +787,31 @@ static int cma_addr_cmp(struct sockaddr *src, struct sockaddr *dst)
        case AF_INET:
                return ((struct sockaddr_in *) src)->sin_addr.s_addr !=
                       ((struct sockaddr_in *) dst)->sin_addr.s_addr;
-       default:
+       case AF_INET6:
                return ipv6_addr_cmp(&((struct sockaddr_in6 *) src)->sin6_addr,
                                     &((struct sockaddr_in6 *) dst)->sin6_addr);
+       default:
+               return ib_addr_cmp(&((struct sockaddr_ib *) src)->sib_addr,
+                                  &((struct sockaddr_ib *) dst)->sib_addr);
        }
 }
 
-static inline __be16 cma_port(struct sockaddr *addr)
+static __be16 cma_port(struct sockaddr *addr)
 {
-       if (addr->sa_family == AF_INET)
+       struct sockaddr_ib *sib;
+
+       switch (addr->sa_family) {
+       case AF_INET:
                return ((struct sockaddr_in *) addr)->sin_port;
-       else
+       case AF_INET6:
                return ((struct sockaddr_in6 *) addr)->sin6_port;
+       case AF_IB:
+               sib = (struct sockaddr_ib *) addr;
+               return htons((u16) (be64_to_cpu(sib->sib_sid) &
+                                   be64_to_cpu(sib->sib_sid_mask)));
+       default:
+               return 0;
+       }
 }
 
 static inline int cma_any_port(struct sockaddr *addr)
@@ -734,83 +819,92 @@ static inline int cma_any_port(struct sockaddr *addr)
        return !cma_port(addr);
 }
 
-static int cma_get_net_info(void *hdr, enum rdma_port_space ps,
-                           u8 *ip_ver, __be16 *port,
-                           union cma_ip_addr **src, union cma_ip_addr **dst)
+static void cma_save_ib_info(struct rdma_cm_id *id, struct rdma_cm_id *listen_id,
+                            struct ib_sa_path_rec *path)
 {
-       switch (ps) {
-       case RDMA_PS_SDP:
-               if (sdp_get_majv(((struct sdp_hh *) hdr)->sdp_version) !=
-                   SDP_MAJ_VERSION)
-                       return -EINVAL;
+       struct sockaddr_ib *listen_ib, *ib;
 
-               *ip_ver = sdp_get_ip_ver(hdr);
-               *port   = ((struct sdp_hh *) hdr)->port;
-               *src    = &((struct sdp_hh *) hdr)->src_addr;
-               *dst    = &((struct sdp_hh *) hdr)->dst_addr;
-               break;
-       default:
-               if (((struct cma_hdr *) hdr)->cma_version != CMA_VERSION)
-                       return -EINVAL;
+       listen_ib = (struct sockaddr_ib *) &listen_id->route.addr.src_addr;
+       ib = (struct sockaddr_ib *) &id->route.addr.src_addr;
+       ib->sib_family = listen_ib->sib_family;
+       ib->sib_pkey = path->pkey;
+       ib->sib_flowinfo = path->flow_label;
+       memcpy(&ib->sib_addr, &path->sgid, 16);
+       ib->sib_sid = listen_ib->sib_sid;
+       ib->sib_sid_mask = cpu_to_be64(0xffffffffffffffffULL);
+       ib->sib_scope_id = listen_ib->sib_scope_id;
 
-               *ip_ver = cma_get_ip_ver(hdr);
-               *port   = ((struct cma_hdr *) hdr)->port;
-               *src    = &((struct cma_hdr *) hdr)->src_addr;
-               *dst    = &((struct cma_hdr *) hdr)->dst_addr;
-               break;
-       }
-
-       if (*ip_ver != 4 && *ip_ver != 6)
-               return -EINVAL;
-       return 0;
+       ib = (struct sockaddr_ib *) &id->route.addr.dst_addr;
+       ib->sib_family = listen_ib->sib_family;
+       ib->sib_pkey = path->pkey;
+       ib->sib_flowinfo = path->flow_label;
+       memcpy(&ib->sib_addr, &path->dgid, 16);
 }
 
-static void cma_save_net_info(struct rdma_addr *addr,
-                             struct rdma_addr *listen_addr,
-                             u8 ip_ver, __be16 port,
-                             union cma_ip_addr *src, union cma_ip_addr *dst)
+static void cma_save_ip4_info(struct rdma_cm_id *id, struct rdma_cm_id *listen_id,
+                             struct cma_hdr *hdr)
 {
        struct sockaddr_in *listen4, *ip4;
+
+       listen4 = (struct sockaddr_in *) &listen_id->route.addr.src_addr;
+       ip4 = (struct sockaddr_in *) &id->route.addr.src_addr;
+       ip4->sin_family = listen4->sin_family;
+       ip4->sin_addr.s_addr = hdr->dst_addr.ip4.addr;
+       ip4->sin_port = listen4->sin_port;
+
+       ip4 = (struct sockaddr_in *) &id->route.addr.dst_addr;
+       ip4->sin_family = listen4->sin_family;
+       ip4->sin_addr.s_addr = hdr->src_addr.ip4.addr;
+       ip4->sin_port = hdr->port;
+}
+
+static void cma_save_ip6_info(struct rdma_cm_id *id, struct rdma_cm_id *listen_id,
+                             struct cma_hdr *hdr)
+{
        struct sockaddr_in6 *listen6, *ip6;
 
-       switch (ip_ver) {
+       listen6 = (struct sockaddr_in6 *) &listen_id->route.addr.src_addr;
+       ip6 = (struct sockaddr_in6 *) &id->route.addr.src_addr;
+       ip6->sin6_family = listen6->sin6_family;
+       ip6->sin6_addr = hdr->dst_addr.ip6;
+       ip6->sin6_port = listen6->sin6_port;
+
+       ip6 = (struct sockaddr_in6 *) &id->route.addr.dst_addr;
+       ip6->sin6_family = listen6->sin6_family;
+       ip6->sin6_addr = hdr->src_addr.ip6;
+       ip6->sin6_port = hdr->port;
+}
+
+static int cma_save_net_info(struct rdma_cm_id *id, struct rdma_cm_id *listen_id,
+                            struct ib_cm_event *ib_event)
+{
+       struct cma_hdr *hdr;
+
+       if (listen_id->route.addr.src_addr.ss_family == AF_IB) {
+               cma_save_ib_info(id, listen_id, ib_event->param.req_rcvd.primary_path);
+               return 0;
+       }
+
+       hdr = ib_event->private_data;
+       if (hdr->cma_version != CMA_VERSION)
+               return -EINVAL;
+
+       switch (cma_get_ip_ver(hdr)) {
        case 4:
-               listen4 = (struct sockaddr_in *) &listen_addr->src_addr;
-               ip4 = (struct sockaddr_in *) &addr->src_addr;
-               ip4->sin_family = listen4->sin_family;
-               ip4->sin_addr.s_addr = dst->ip4.addr;
-               ip4->sin_port = listen4->sin_port;
-
-               ip4 = (struct sockaddr_in *) &addr->dst_addr;
-               ip4->sin_family = listen4->sin_family;
-               ip4->sin_addr.s_addr = src->ip4.addr;
-               ip4->sin_port = port;
+               cma_save_ip4_info(id, listen_id, hdr);
                break;
        case 6:
-               listen6 = (struct sockaddr_in6 *) &listen_addr->src_addr;
-               ip6 = (struct sockaddr_in6 *) &addr->src_addr;
-               ip6->sin6_family = listen6->sin6_family;
-               ip6->sin6_addr = dst->ip6;
-               ip6->sin6_port = listen6->sin6_port;
-
-               ip6 = (struct sockaddr_in6 *) &addr->dst_addr;
-               ip6->sin6_family = listen6->sin6_family;
-               ip6->sin6_addr = src->ip6;
-               ip6->sin6_port = port;
+               cma_save_ip6_info(id, listen_id, hdr);
                break;
        default:
-               break;
+               return -EINVAL;
        }
+       return 0;
 }
 
-static inline int cma_user_data_offset(enum rdma_port_space ps)
+static inline int cma_user_data_offset(struct rdma_id_private *id_priv)
 {
-       switch (ps) {
-       case RDMA_PS_SDP:
-               return 0;
-       default:
-               return sizeof(struct cma_hdr);
-       }
+       return cma_family(id_priv) == AF_IB ? 0 : sizeof(struct cma_hdr);
 }
 
 static void cma_cancel_route(struct rdma_id_private *id_priv)
@@ -861,8 +955,7 @@ static void cma_cancel_operation(struct rdma_id_private *id_priv,
                cma_cancel_route(id_priv);
                break;
        case RDMA_CM_LISTEN:
-               if (cma_any_addr((struct sockaddr *) &id_priv->id.route.addr.src_addr)
-                               && !id_priv->cma_dev)
+               if (cma_any_addr(cma_src_addr(id_priv)) && !id_priv->cma_dev)
                        cma_cancel_listens(id_priv);
                break;
        default:
@@ -977,16 +1070,6 @@ reject:
        return ret;
 }
 
-static int cma_verify_rep(struct rdma_id_private *id_priv, void *data)
-{
-       if (id_priv->id.ps == RDMA_PS_SDP &&
-           sdp_get_majv(((struct sdp_hah *) data)->sdp_version) !=
-           SDP_MAJ_VERSION)
-               return -EINVAL;
-
-       return 0;
-}
-
 static void cma_set_rep_event_data(struct rdma_cm_event *event,
                                   struct ib_cm_rep_event_param *rep_data,
                                   void *private_data)
@@ -1021,15 +1104,13 @@ static int cma_ib_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event)
                event.status = -ETIMEDOUT;
                break;
        case IB_CM_REP_RECEIVED:
-               event.status = cma_verify_rep(id_priv, ib_event->private_data);
-               if (event.status)
-                       event.event = RDMA_CM_EVENT_CONNECT_ERROR;
-               else if (id_priv->id.qp && id_priv->id.ps != RDMA_PS_SDP) {
+               if (id_priv->id.qp) {
                        event.status = cma_rep_recv(id_priv);
                        event.event = event.status ? RDMA_CM_EVENT_CONNECT_ERROR :
                                                     RDMA_CM_EVENT_ESTABLISHED;
-               } else
+               } else {
                        event.event = RDMA_CM_EVENT_CONNECT_RESPONSE;
+               }
                cma_set_rep_event_data(&event, &ib_event->param.rep_rcvd,
                                       ib_event->private_data);
                break;
@@ -1085,22 +1166,16 @@ static struct rdma_id_private *cma_new_conn_id(struct rdma_cm_id *listen_id,
        struct rdma_id_private *id_priv;
        struct rdma_cm_id *id;
        struct rdma_route *rt;
-       union cma_ip_addr *src, *dst;
-       __be16 port;
-       u8 ip_ver;
        int ret;
 
-       if (cma_get_net_info(ib_event->private_data, listen_id->ps,
-                            &ip_ver, &port, &src, &dst))
-               return NULL;
-
        id = rdma_create_id(listen_id->event_handler, listen_id->context,
                            listen_id->ps, ib_event->param.req_rcvd.qp_type);
        if (IS_ERR(id))
                return NULL;
 
-       cma_save_net_info(&id->route.addr, &listen_id->route.addr,
-                         ip_ver, port, src, dst);
+       id_priv = container_of(id, struct rdma_id_private, id);
+       if (cma_save_net_info(id, listen_id, ib_event))
+               goto err;
 
        rt = &id->route;
        rt->num_paths = ib_event->param.req_rcvd.alternate_path ? 2 : 1;
@@ -1113,19 +1188,17 @@ static struct rdma_id_private *cma_new_conn_id(struct rdma_cm_id *listen_id,
        if (rt->num_paths == 2)
                rt->path_rec[1] = *ib_event->param.req_rcvd.alternate_path;
 
-       if (cma_any_addr((struct sockaddr *) &rt->addr.src_addr)) {
+       if (cma_any_addr(cma_src_addr(id_priv))) {
                rt->addr.dev_addr.dev_type = ARPHRD_INFINIBAND;
                rdma_addr_set_sgid(&rt->addr.dev_addr, &rt->path_rec[0].sgid);
                ib_addr_set_pkey(&rt->addr.dev_addr, be16_to_cpu(rt->path_rec[0].pkey));
        } else {
-               ret = rdma_translate_ip((struct sockaddr *) &rt->addr.src_addr,
-                                       &rt->addr.dev_addr);
+               ret = cma_translate_addr(cma_src_addr(id_priv), &rt->addr.dev_addr);
                if (ret)
                        goto err;
        }
        rdma_addr_set_dgid(&rt->addr.dev_addr, &rt->path_rec[0].dgid);
 
-       id_priv = container_of(id, struct rdma_id_private, id);
        id_priv->state = RDMA_CM_CONNECT;
        return id_priv;
 
@@ -1139,9 +1212,6 @@ static struct rdma_id_private *cma_new_udp_id(struct rdma_cm_id *listen_id,
 {
        struct rdma_id_private *id_priv;
        struct rdma_cm_id *id;
-       union cma_ip_addr *src, *dst;
-       __be16 port;
-       u8 ip_ver;
        int ret;
 
        id = rdma_create_id(listen_id->event_handler, listen_id->context,
@@ -1149,22 +1219,16 @@ static struct rdma_id_private *cma_new_udp_id(struct rdma_cm_id *listen_id,
        if (IS_ERR(id))
                return NULL;
 
-
-       if (cma_get_net_info(ib_event->private_data, listen_id->ps,
-                            &ip_ver, &port, &src, &dst))
+       id_priv = container_of(id, struct rdma_id_private, id);
+       if (cma_save_net_info(id, listen_id, ib_event))
                goto err;
 
-       cma_save_net_info(&id->route.addr, &listen_id->route.addr,
-                         ip_ver, port, src, dst);
-
        if (!cma_any_addr((struct sockaddr *) &id->route.addr.src_addr)) {
-               ret = rdma_translate_ip((struct sockaddr *) &id->route.addr.src_addr,
-                                       &id->route.addr.dev_addr);
+               ret = cma_translate_addr(cma_src_addr(id_priv), &id->route.addr.dev_addr);
                if (ret)
                        goto err;
        }
 
-       id_priv = container_of(id, struct rdma_id_private, id);
        id_priv->state = RDMA_CM_CONNECT;
        return id_priv;
 err:
@@ -1210,7 +1274,7 @@ static int cma_req_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event)
                return -ECONNABORTED;
 
        memset(&event, 0, sizeof event);
-       offset = cma_user_data_offset(listen_id->id.ps);
+       offset = cma_user_data_offset(listen_id);
        event.event = RDMA_CM_EVENT_CONNECT_REQUEST;
        if (ib_event->event == IB_CM_SIDR_REQ_RECEIVED) {
                conn_id = cma_new_udp_id(&listen_id->id, ib_event);
@@ -1272,58 +1336,44 @@ err1:
        return ret;
 }
 
-static __be64 cma_get_service_id(enum rdma_port_space ps, struct sockaddr *addr)
+__be64 rdma_get_service_id(struct rdma_cm_id *id, struct sockaddr *addr)
 {
-       return cpu_to_be64(((u64)ps << 16) + be16_to_cpu(cma_port(addr)));
+       if (addr->sa_family == AF_IB)
+               return ((struct sockaddr_ib *) addr)->sib_sid;
+
+       return cpu_to_be64(((u64)id->ps << 16) + be16_to_cpu(cma_port(addr)));
 }
+EXPORT_SYMBOL(rdma_get_service_id);
 
 static void cma_set_compare_data(enum rdma_port_space ps, struct sockaddr *addr,
                                 struct ib_cm_compare_data *compare)
 {
        struct cma_hdr *cma_data, *cma_mask;
-       struct sdp_hh *sdp_data, *sdp_mask;
        __be32 ip4_addr;
        struct in6_addr ip6_addr;
 
        memset(compare, 0, sizeof *compare);
        cma_data = (void *) compare->data;
        cma_mask = (void *) compare->mask;
-       sdp_data = (void *) compare->data;
-       sdp_mask = (void *) compare->mask;
 
        switch (addr->sa_family) {
        case AF_INET:
                ip4_addr = ((struct sockaddr_in *) addr)->sin_addr.s_addr;
-               if (ps == RDMA_PS_SDP) {
-                       sdp_set_ip_ver(sdp_data, 4);
-                       sdp_set_ip_ver(sdp_mask, 0xF);
-                       sdp_data->dst_addr.ip4.addr = ip4_addr;
-                       sdp_mask->dst_addr.ip4.addr = htonl(~0);
-               } else {
-                       cma_set_ip_ver(cma_data, 4);
-                       cma_set_ip_ver(cma_mask, 0xF);
-                       if (!cma_any_addr(addr)) {
-                               cma_data->dst_addr.ip4.addr = ip4_addr;
-                               cma_mask->dst_addr.ip4.addr = htonl(~0);
-                       }
+               cma_set_ip_ver(cma_data, 4);
+               cma_set_ip_ver(cma_mask, 0xF);
+               if (!cma_any_addr(addr)) {
+                       cma_data->dst_addr.ip4.addr = ip4_addr;
+                       cma_mask->dst_addr.ip4.addr = htonl(~0);
                }
                break;
        case AF_INET6:
                ip6_addr = ((struct sockaddr_in6 *) addr)->sin6_addr;
-               if (ps == RDMA_PS_SDP) {
-                       sdp_set_ip_ver(sdp_data, 6);
-                       sdp_set_ip_ver(sdp_mask, 0xF);
-                       sdp_data->dst_addr.ip6 = ip6_addr;
-                       memset(&sdp_mask->dst_addr.ip6, 0xFF,
-                              sizeof sdp_mask->dst_addr.ip6);
-               } else {
-                       cma_set_ip_ver(cma_data, 6);
-                       cma_set_ip_ver(cma_mask, 0xF);
-                       if (!cma_any_addr(addr)) {
-                               cma_data->dst_addr.ip6 = ip6_addr;
-                               memset(&cma_mask->dst_addr.ip6, 0xFF,
-                                      sizeof cma_mask->dst_addr.ip6);
-                       }
+               cma_set_ip_ver(cma_data, 6);
+               cma_set_ip_ver(cma_mask, 0xF);
+               if (!cma_any_addr(addr)) {
+                       cma_data->dst_addr.ip6 = ip6_addr;
+                       memset(&cma_mask->dst_addr.ip6, 0xFF,
+                              sizeof cma_mask->dst_addr.ip6);
                }
                break;
        default:
@@ -1347,9 +1397,9 @@ static int cma_iw_handler(struct iw_cm_id *iw_id, struct iw_cm_event *iw_event)
                event.event = RDMA_CM_EVENT_DISCONNECTED;
                break;
        case IW_CM_EVENT_CONNECT_REPLY:
-               sin = (struct sockaddr_in *) &id_priv->id.route.addr.src_addr;
+               sin = (struct sockaddr_in *) cma_src_addr(id_priv);
                *sin = iw_event->local_addr;
-               sin = (struct sockaddr_in *) &id_priv->id.route.addr.dst_addr;
+               sin = (struct sockaddr_in *) cma_dst_addr(id_priv);
                *sin = iw_event->remote_addr;
                switch (iw_event->status) {
                case 0:
@@ -1447,9 +1497,9 @@ static int iw_conn_req_handler(struct iw_cm_id *cm_id,
        cm_id->context = conn_id;
        cm_id->cm_handler = cma_iw_handler;
 
-       sin = (struct sockaddr_in *) &new_cm_id->route.addr.src_addr;
+       sin = (struct sockaddr_in *) cma_src_addr(conn_id);
        *sin = iw_event->local_addr;
-       sin = (struct sockaddr_in *) &new_cm_id->route.addr.dst_addr;
+       sin = (struct sockaddr_in *) cma_dst_addr(conn_id);
        *sin = iw_event->remote_addr;
 
        ret = ib_query_device(conn_id->id.device, &attr);
@@ -1506,8 +1556,8 @@ static int cma_ib_listen(struct rdma_id_private *id_priv)
 
        id_priv->cm_id.ib = id;
 
-       addr = (struct sockaddr *) &id_priv->id.route.addr.src_addr;
-       svc_id = cma_get_service_id(id_priv->id.ps, addr);
+       addr = cma_src_addr(id_priv);
+       svc_id = rdma_get_service_id(&id_priv->id, addr);
        if (cma_any_addr(addr) && !id_priv->afonly)
                ret = ib_cm_listen(id_priv->cm_id.ib, svc_id, 0, NULL);
        else {
@@ -1537,7 +1587,7 @@ static int cma_iw_listen(struct rdma_id_private *id_priv, int backlog)
 
        id_priv->cm_id.iw = id;
 
-       sin = (struct sockaddr_in *) &id_priv->id.route.addr.src_addr;
+       sin = (struct sockaddr_in *) cma_src_addr(id_priv);
        id_priv->cm_id.iw->local_addr = *sin;
 
        ret = iw_cm_listen(id_priv->cm_id.iw, backlog);
@@ -1567,6 +1617,10 @@ static void cma_listen_on_dev(struct rdma_id_private *id_priv,
        struct rdma_cm_id *id;
        int ret;
 
+       if (cma_family(id_priv) == AF_IB &&
+           rdma_node_get_transport(cma_dev->device->node_type) != RDMA_TRANSPORT_IB)
+               return;
+
        id = rdma_create_id(cma_listen_handler, id_priv, id_priv->id.ps,
                            id_priv->id.qp_type);
        if (IS_ERR(id))
@@ -1575,8 +1629,8 @@ static void cma_listen_on_dev(struct rdma_id_private *id_priv,
        dev_id_priv = container_of(id, struct rdma_id_private, id);
 
        dev_id_priv->state = RDMA_CM_ADDR_BOUND;
-       memcpy(&id->route.addr.src_addr, &id_priv->id.route.addr.src_addr,
-              ip_addr_size((struct sockaddr *) &id_priv->id.route.addr.src_addr));
+       memcpy(cma_src_addr(dev_id_priv), cma_src_addr(id_priv),
+              rdma_addr_size(cma_src_addr(id_priv)));
 
        cma_attach_to_dev(dev_id_priv, cma_dev);
        list_add_tail(&dev_id_priv->listen_list, &id_priv->listen_list);
@@ -1634,31 +1688,39 @@ static void cma_query_handler(int status, struct ib_sa_path_rec *path_rec,
 static int cma_query_ib_route(struct rdma_id_private *id_priv, int timeout_ms,
                              struct cma_work *work)
 {
-       struct rdma_addr *addr = &id_priv->id.route.addr;
+       struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr;
        struct ib_sa_path_rec path_rec;
        ib_sa_comp_mask comp_mask;
        struct sockaddr_in6 *sin6;
+       struct sockaddr_ib *sib;
 
        memset(&path_rec, 0, sizeof path_rec);
-       rdma_addr_get_sgid(&addr->dev_addr, &path_rec.sgid);
-       rdma_addr_get_dgid(&addr->dev_addr, &path_rec.dgid);
-       path_rec.pkey = cpu_to_be16(ib_addr_get_pkey(&addr->dev_addr));
+       rdma_addr_get_sgid(dev_addr, &path_rec.sgid);
+       rdma_addr_get_dgid(dev_addr, &path_rec.dgid);
+       path_rec.pkey = cpu_to_be16(ib_addr_get_pkey(dev_addr));
        path_rec.numb_path = 1;
        path_rec.reversible = 1;
-       path_rec.service_id = cma_get_service_id(id_priv->id.ps,
-                                                       (struct sockaddr *) &addr->dst_addr);
+       path_rec.service_id = rdma_get_service_id(&id_priv->id, cma_dst_addr(id_priv));
 
        comp_mask = IB_SA_PATH_REC_DGID | IB_SA_PATH_REC_SGID |
                    IB_SA_PATH_REC_PKEY | IB_SA_PATH_REC_NUMB_PATH |
                    IB_SA_PATH_REC_REVERSIBLE | IB_SA_PATH_REC_SERVICE_ID;
 
-       if (addr->src_addr.ss_family == AF_INET) {
+       switch (cma_family(id_priv)) {
+       case AF_INET:
                path_rec.qos_class = cpu_to_be16((u16) id_priv->tos);
                comp_mask |= IB_SA_PATH_REC_QOS_CLASS;
-       } else {
-               sin6 = (struct sockaddr_in6 *) &addr->src_addr;
+               break;
+       case AF_INET6:
+               sin6 = (struct sockaddr_in6 *) cma_src_addr(id_priv);
                path_rec.traffic_class = (u8) (be32_to_cpu(sin6->sin6_flowinfo) >> 20);
                comp_mask |= IB_SA_PATH_REC_TRAFFIC_CLASS;
+               break;
+       case AF_IB:
+               sib = (struct sockaddr_ib *) cma_src_addr(id_priv);
+               path_rec.traffic_class = (u8) (be32_to_cpu(sib->sib_flowinfo) >> 20);
+               comp_mask |= IB_SA_PATH_REC_TRAFFIC_CLASS;
+               break;
        }
 
        id_priv->query_id = ib_sa_path_rec_get(&sa_client, id_priv->id.device,
@@ -1800,14 +1862,9 @@ static int cma_resolve_iboe_route(struct rdma_id_private *id_priv)
        struct rdma_addr *addr = &route->addr;
        struct cma_work *work;
        int ret;
-       struct sockaddr_in *src_addr = (struct sockaddr_in *)&route->addr.src_addr;
-       struct sockaddr_in *dst_addr = (struct sockaddr_in *)&route->addr.dst_addr;
        struct net_device *ndev = NULL;
        u16 vid;
 
-       if (src_addr->sin_family != dst_addr->sin_family)
-               return -EINVAL;
-
        work = kzalloc(sizeof *work, GFP_KERNEL);
        if (!work)
                return -ENOMEM;
@@ -1913,28 +1970,57 @@ err:
 }
 EXPORT_SYMBOL(rdma_resolve_route);
 
+static void cma_set_loopback(struct sockaddr *addr)
+{
+       switch (addr->sa_family) {
+       case AF_INET:
+               ((struct sockaddr_in *) addr)->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+               break;
+       case AF_INET6:
+               ipv6_addr_set(&((struct sockaddr_in6 *) addr)->sin6_addr,
+                             0, 0, 0, htonl(1));
+               break;
+       default:
+               ib_addr_set(&((struct sockaddr_ib *) addr)->sib_addr,
+                           0, 0, 0, htonl(1));
+               break;
+       }
+}
+
 static int cma_bind_loopback(struct rdma_id_private *id_priv)
 {
-       struct cma_device *cma_dev;
+       struct cma_device *cma_dev, *cur_dev;
        struct ib_port_attr port_attr;
        union ib_gid gid;
        u16 pkey;
        int ret;
        u8 p;
 
+       cma_dev = NULL;
        mutex_lock(&lock);
-       if (list_empty(&dev_list)) {
+       list_for_each_entry(cur_dev, &dev_list, list) {
+               if (cma_family(id_priv) == AF_IB &&
+                   rdma_node_get_transport(cur_dev->device->node_type) != RDMA_TRANSPORT_IB)
+                       continue;
+
+               if (!cma_dev)
+                       cma_dev = cur_dev;
+
+               for (p = 1; p <= cur_dev->device->phys_port_cnt; ++p) {
+                       if (!ib_query_port(cur_dev->device, p, &port_attr) &&
+                           port_attr.state == IB_PORT_ACTIVE) {
+                               cma_dev = cur_dev;
+                               goto port_found;
+                       }
+               }
+       }
+
+       if (!cma_dev) {
                ret = -ENODEV;
                goto out;
        }
-       list_for_each_entry(cma_dev, &dev_list, list)
-               for (p = 1; p <= cma_dev->device->phys_port_cnt; ++p)
-                       if (!ib_query_port(cma_dev->device, p, &port_attr) &&
-                           port_attr.state == IB_PORT_ACTIVE)
-                               goto port_found;
 
        p = 1;
-       cma_dev = list_entry(dev_list.next, struct cma_device, list);
 
 port_found:
        ret = ib_get_cached_gid(cma_dev->device, p, 0, &gid);
@@ -1953,6 +2039,7 @@ port_found:
        ib_addr_set_pkey(&id_priv->id.route.addr.dev_addr, pkey);
        id_priv->id.port_num = p;
        cma_attach_to_dev(id_priv, cma_dev);
+       cma_set_loopback(cma_src_addr(id_priv));
 out:
        mutex_unlock(&lock);
        return ret;
@@ -1980,8 +2067,7 @@ static void addr_handler(int status, struct sockaddr *src_addr,
                event.event = RDMA_CM_EVENT_ADDR_ERROR;
                event.status = status;
        } else {
-               memcpy(&id_priv->id.route.addr.src_addr, src_addr,
-                      ip_addr_size(src_addr));
+               memcpy(cma_src_addr(id_priv), src_addr, rdma_addr_size(src_addr));
                event.event = RDMA_CM_EVENT_ADDR_RESOLVED;
        }
 
@@ -2000,7 +2086,6 @@ out:
 static int cma_resolve_loopback(struct rdma_id_private *id_priv)
 {
        struct cma_work *work;
-       struct sockaddr *src, *dst;
        union ib_gid gid;
        int ret;
 
@@ -2017,18 +2102,36 @@ static int cma_resolve_loopback(struct rdma_id_private *id_priv)
        rdma_addr_get_sgid(&id_priv->id.route.addr.dev_addr, &gid);
        rdma_addr_set_dgid(&id_priv->id.route.addr.dev_addr, &gid);
 
-       src = (struct sockaddr *) &id_priv->id.route.addr.src_addr;
-       if (cma_zero_addr(src)) {
-               dst = (struct sockaddr *) &id_priv->id.route.addr.dst_addr;
-               if ((src->sa_family = dst->sa_family) == AF_INET) {
-                       ((struct sockaddr_in *)src)->sin_addr =
-                               ((struct sockaddr_in *)dst)->sin_addr;
-               } else {
-                       ((struct sockaddr_in6 *)src)->sin6_addr =
-                               ((struct sockaddr_in6 *)dst)->sin6_addr;
-               }
+       work->id = id_priv;
+       INIT_WORK(&work->work, cma_work_handler);
+       work->old_state = RDMA_CM_ADDR_QUERY;
+       work->new_state = RDMA_CM_ADDR_RESOLVED;
+       work->event.event = RDMA_CM_EVENT_ADDR_RESOLVED;
+       queue_work(cma_wq, &work->work);
+       return 0;
+err:
+       kfree(work);
+       return ret;
+}
+
+static int cma_resolve_ib_addr(struct rdma_id_private *id_priv)
+{
+       struct cma_work *work;
+       int ret;
+
+       work = kzalloc(sizeof *work, GFP_KERNEL);
+       if (!work)
+               return -ENOMEM;
+
+       if (!id_priv->cma_dev) {
+               ret = cma_resolve_ib_dev(id_priv);
+               if (ret)
+                       goto err;
        }
 
+       rdma_addr_set_dgid(&id_priv->id.route.addr.dev_addr, (union ib_gid *)
+               &(((struct sockaddr_ib *) &id_priv->id.route.addr.dst_addr)->sib_addr));
+
        work->id = id_priv;
        INIT_WORK(&work->work, cma_work_handler);
        work->old_state = RDMA_CM_ADDR_QUERY;
@@ -2046,9 +2149,13 @@ static int cma_bind_addr(struct rdma_cm_id *id, struct sockaddr *src_addr,
 {
        if (!src_addr || !src_addr->sa_family) {
                src_addr = (struct sockaddr *) &id->route.addr.src_addr;
-               if ((src_addr->sa_family = dst_addr->sa_family) == AF_INET6) {
+               src_addr->sa_family = dst_addr->sa_family;
+               if (dst_addr->sa_family == AF_INET6) {
                        ((struct sockaddr_in6 *) src_addr)->sin6_scope_id =
                                ((struct sockaddr_in6 *) dst_addr)->sin6_scope_id;
+               } else if (dst_addr->sa_family == AF_IB) {
+                       ((struct sockaddr_ib *) src_addr)->sib_pkey =
+                               ((struct sockaddr_ib *) dst_addr)->sib_pkey;
                }
        }
        return rdma_bind_addr(id, src_addr);
@@ -2067,17 +2174,25 @@ int rdma_resolve_addr(struct rdma_cm_id *id, struct sockaddr *src_addr,
                        return ret;
        }
 
+       if (cma_family(id_priv) != dst_addr->sa_family)
+               return -EINVAL;
+
        if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_BOUND, RDMA_CM_ADDR_QUERY))
                return -EINVAL;
 
        atomic_inc(&id_priv->refcount);
-       memcpy(&id->route.addr.dst_addr, dst_addr, ip_addr_size(dst_addr));
-       if (cma_any_addr(dst_addr))
+       memcpy(cma_dst_addr(id_priv), dst_addr, rdma_addr_size(dst_addr));
+       if (cma_any_addr(dst_addr)) {
                ret = cma_resolve_loopback(id_priv);
-       else
-               ret = rdma_resolve_ip(&addr_client, (struct sockaddr *) &id->route.addr.src_addr,
-                                     dst_addr, &id->route.addr.dev_addr,
-                                     timeout_ms, addr_handler, id_priv);
+       } else {
+               if (dst_addr->sa_family == AF_IB) {
+                       ret = cma_resolve_ib_addr(id_priv);
+               } else {
+                       ret = rdma_resolve_ip(&addr_client, cma_src_addr(id_priv),
+                                             dst_addr, &id->route.addr.dev_addr,
+                                             timeout_ms, addr_handler, id_priv);
+               }
+       }
        if (ret)
                goto err;
 
@@ -2097,7 +2212,7 @@ int rdma_set_reuseaddr(struct rdma_cm_id *id, int reuse)
 
        id_priv = container_of(id, struct rdma_id_private, id);
        spin_lock_irqsave(&id_priv->lock, flags);
-       if (id_priv->state == RDMA_CM_IDLE) {
+       if (reuse || id_priv->state == RDMA_CM_IDLE) {
                id_priv->reuseaddr = reuse;
                ret = 0;
        } else {
@@ -2131,10 +2246,29 @@ EXPORT_SYMBOL(rdma_set_afonly);
 static void cma_bind_port(struct rdma_bind_list *bind_list,
                          struct rdma_id_private *id_priv)
 {
-       struct sockaddr_in *sin;
+       struct sockaddr *addr;
+       struct sockaddr_ib *sib;
+       u64 sid, mask;
+       __be16 port;
 
-       sin = (struct sockaddr_in *) &id_priv->id.route.addr.src_addr;
-       sin->sin_port = htons(bind_list->port);
+       addr = cma_src_addr(id_priv);
+       port = htons(bind_list->port);
+
+       switch (addr->sa_family) {
+       case AF_INET:
+               ((struct sockaddr_in *) addr)->sin_port = port;
+               break;
+       case AF_INET6:
+               ((struct sockaddr_in6 *) addr)->sin6_port = port;
+               break;
+       case AF_IB:
+               sib = (struct sockaddr_ib *) addr;
+               sid = be64_to_cpu(sib->sib_sid);
+               mask = be64_to_cpu(sib->sib_sid_mask);
+               sib->sib_sid = cpu_to_be64((sid & mask) | (u64) ntohs(port));
+               sib->sib_sid_mask = cpu_to_be64(~0ULL);
+               break;
+       }
        id_priv->bind_list = bind_list;
        hlist_add_head(&id_priv->node, &bind_list->owners);
 }
@@ -2205,7 +2339,7 @@ static int cma_check_port(struct rdma_bind_list *bind_list,
        struct rdma_id_private *cur_id;
        struct sockaddr *addr, *cur_addr;
 
-       addr = (struct sockaddr *) &id_priv->id.route.addr.src_addr;
+       addr = cma_src_addr(id_priv);
        hlist_for_each_entry(cur_id, &bind_list->owners, node) {
                if (id_priv == cur_id)
                        continue;
@@ -2214,7 +2348,7 @@ static int cma_check_port(struct rdma_bind_list *bind_list,
                    cur_id->reuseaddr)
                        continue;
 
-               cur_addr = (struct sockaddr *) &cur_id->id.route.addr.src_addr;
+               cur_addr = cma_src_addr(cur_id);
                if (id_priv->afonly && cur_id->afonly &&
                    (addr->sa_family != cur_addr->sa_family))
                        continue;
@@ -2234,7 +2368,7 @@ static int cma_use_port(struct idr *ps, struct rdma_id_private *id_priv)
        unsigned short snum;
        int ret;
 
-       snum = ntohs(cma_port((struct sockaddr *) &id_priv->id.route.addr.src_addr));
+       snum = ntohs(cma_port(cma_src_addr(id_priv)));
        if (snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE))
                return -EACCES;
 
@@ -2261,33 +2395,67 @@ static int cma_bind_listen(struct rdma_id_private *id_priv)
        return ret;
 }
 
-static int cma_get_port(struct rdma_id_private *id_priv)
+static struct idr *cma_select_inet_ps(struct rdma_id_private *id_priv)
 {
-       struct idr *ps;
-       int ret;
-
        switch (id_priv->id.ps) {
-       case RDMA_PS_SDP:
-               ps = &sdp_ps;
-               break;
        case RDMA_PS_TCP:
-               ps = &tcp_ps;
-               break;
+               return &tcp_ps;
        case RDMA_PS_UDP:
-               ps = &udp_ps;
-               break;
+               return &udp_ps;
        case RDMA_PS_IPOIB:
-               ps = &ipoib_ps;
-               break;
+               return &ipoib_ps;
        case RDMA_PS_IB:
-               ps = &ib_ps;
-               break;
+               return &ib_ps;
        default:
-               return -EPROTONOSUPPORT;
+               return NULL;
+       }
+}
+
+static struct idr *cma_select_ib_ps(struct rdma_id_private *id_priv)
+{
+       struct idr *ps = NULL;
+       struct sockaddr_ib *sib;
+       u64 sid_ps, mask, sid;
+
+       sib = (struct sockaddr_ib *) cma_src_addr(id_priv);
+       mask = be64_to_cpu(sib->sib_sid_mask) & RDMA_IB_IP_PS_MASK;
+       sid = be64_to_cpu(sib->sib_sid) & mask;
+
+       if ((id_priv->id.ps == RDMA_PS_IB) && (sid == (RDMA_IB_IP_PS_IB & mask))) {
+               sid_ps = RDMA_IB_IP_PS_IB;
+               ps = &ib_ps;
+       } else if (((id_priv->id.ps == RDMA_PS_IB) || (id_priv->id.ps == RDMA_PS_TCP)) &&
+                  (sid == (RDMA_IB_IP_PS_TCP & mask))) {
+               sid_ps = RDMA_IB_IP_PS_TCP;
+               ps = &tcp_ps;
+       } else if (((id_priv->id.ps == RDMA_PS_IB) || (id_priv->id.ps == RDMA_PS_UDP)) &&
+                  (sid == (RDMA_IB_IP_PS_UDP & mask))) {
+               sid_ps = RDMA_IB_IP_PS_UDP;
+               ps = &udp_ps;
        }
 
+       if (ps) {
+               sib->sib_sid = cpu_to_be64(sid_ps | ntohs(cma_port((struct sockaddr *) sib)));
+               sib->sib_sid_mask = cpu_to_be64(RDMA_IB_IP_PS_MASK |
+                                               be64_to_cpu(sib->sib_sid_mask));
+       }
+       return ps;
+}
+
+static int cma_get_port(struct rdma_id_private *id_priv)
+{
+       struct idr *ps;
+       int ret;
+
+       if (cma_family(id_priv) != AF_IB)
+               ps = cma_select_inet_ps(id_priv);
+       else
+               ps = cma_select_ib_ps(id_priv);
+       if (!ps)
+               return -EPROTONOSUPPORT;
+
        mutex_lock(&lock);
-       if (cma_any_port((struct sockaddr *) &id_priv->id.route.addr.src_addr))
+       if (cma_any_port(cma_src_addr(id_priv)))
                ret = cma_alloc_any_port(ps, id_priv);
        else
                ret = cma_use_port(ps, id_priv);
@@ -2322,8 +2490,8 @@ int rdma_listen(struct rdma_cm_id *id, int backlog)
 
        id_priv = container_of(id, struct rdma_id_private, id);
        if (id_priv->state == RDMA_CM_IDLE) {
-               ((struct sockaddr *) &id->route.addr.src_addr)->sa_family = AF_INET;
-               ret = rdma_bind_addr(id, (struct sockaddr *) &id->route.addr.src_addr);
+               id->route.addr.src_addr.ss_family = AF_INET;
+               ret = rdma_bind_addr(id, cma_src_addr(id_priv));
                if (ret)
                        return ret;
        }
@@ -2370,7 +2538,8 @@ int rdma_bind_addr(struct rdma_cm_id *id, struct sockaddr *addr)
        struct rdma_id_private *id_priv;
        int ret;
 
-       if (addr->sa_family != AF_INET && addr->sa_family != AF_INET6)
+       if (addr->sa_family != AF_INET && addr->sa_family != AF_INET6 &&
+           addr->sa_family != AF_IB)
                return -EAFNOSUPPORT;
 
        id_priv = container_of(id, struct rdma_id_private, id);
@@ -2382,7 +2551,7 @@ int rdma_bind_addr(struct rdma_cm_id *id, struct sockaddr *addr)
                goto err1;
 
        if (!cma_any_addr(addr)) {
-               ret = rdma_translate_ip(addr, &id->route.addr.dev_addr);
+               ret = cma_translate_addr(addr, &id->route.addr.dev_addr);
                if (ret)
                        goto err1;
 
@@ -2391,7 +2560,7 @@ int rdma_bind_addr(struct rdma_cm_id *id, struct sockaddr *addr)
                        goto err1;
        }
 
-       memcpy(&id->route.addr.src_addr, addr, ip_addr_size(addr));
+       memcpy(cma_src_addr(id_priv), addr, rdma_addr_size(addr));
        if (!(id_priv->options & (1 << CMA_OPTION_AFONLY))) {
                if (addr->sa_family == AF_INET)
                        id_priv->afonly = 1;
@@ -2414,62 +2583,32 @@ err1:
 }
 EXPORT_SYMBOL(rdma_bind_addr);
 
-static int cma_format_hdr(void *hdr, enum rdma_port_space ps,
-                         struct rdma_route *route)
+static int cma_format_hdr(void *hdr, struct rdma_id_private *id_priv)
 {
        struct cma_hdr *cma_hdr;
-       struct sdp_hh *sdp_hdr;
 
-       if (route->addr.src_addr.ss_family == AF_INET) {
+       cma_hdr = hdr;
+       cma_hdr->cma_version = CMA_VERSION;
+       if (cma_family(id_priv) == AF_INET) {
                struct sockaddr_in *src4, *dst4;
 
-               src4 = (struct sockaddr_in *) &route->addr.src_addr;
-               dst4 = (struct sockaddr_in *) &route->addr.dst_addr;
-
-               switch (ps) {
-               case RDMA_PS_SDP:
-                       sdp_hdr = hdr;
-                       if (sdp_get_majv(sdp_hdr->sdp_version) != SDP_MAJ_VERSION)
-                               return -EINVAL;
-                       sdp_set_ip_ver(sdp_hdr, 4);
-                       sdp_hdr->src_addr.ip4.addr = src4->sin_addr.s_addr;
-                       sdp_hdr->dst_addr.ip4.addr = dst4->sin_addr.s_addr;
-                       sdp_hdr->port = src4->sin_port;
-                       break;
-               default:
-                       cma_hdr = hdr;
-                       cma_hdr->cma_version = CMA_VERSION;
-                       cma_set_ip_ver(cma_hdr, 4);
-                       cma_hdr->src_addr.ip4.addr = src4->sin_addr.s_addr;
-                       cma_hdr->dst_addr.ip4.addr = dst4->sin_addr.s_addr;
-                       cma_hdr->port = src4->sin_port;
-                       break;
-               }
-       } else {
+               src4 = (struct sockaddr_in *) cma_src_addr(id_priv);
+               dst4 = (struct sockaddr_in *) cma_dst_addr(id_priv);
+
+               cma_set_ip_ver(cma_hdr, 4);
+               cma_hdr->src_addr.ip4.addr = src4->sin_addr.s_addr;
+               cma_hdr->dst_addr.ip4.addr = dst4->sin_addr.s_addr;
+               cma_hdr->port = src4->sin_port;
+       } else if (cma_family(id_priv) == AF_INET6) {
                struct sockaddr_in6 *src6, *dst6;
 
-               src6 = (struct sockaddr_in6 *) &route->addr.src_addr;
-               dst6 = (struct sockaddr_in6 *) &route->addr.dst_addr;
-
-               switch (ps) {
-               case RDMA_PS_SDP:
-                       sdp_hdr = hdr;
-                       if (sdp_get_majv(sdp_hdr->sdp_version) != SDP_MAJ_VERSION)
-                               return -EINVAL;
-                       sdp_set_ip_ver(sdp_hdr, 6);
-                       sdp_hdr->src_addr.ip6 = src6->sin6_addr;
-                       sdp_hdr->dst_addr.ip6 = dst6->sin6_addr;
-                       sdp_hdr->port = src6->sin6_port;
-                       break;
-               default:
-                       cma_hdr = hdr;
-                       cma_hdr->cma_version = CMA_VERSION;
-                       cma_set_ip_ver(cma_hdr, 6);
-                       cma_hdr->src_addr.ip6 = src6->sin6_addr;
-                       cma_hdr->dst_addr.ip6 = dst6->sin6_addr;
-                       cma_hdr->port = src6->sin6_port;
-                       break;
-               }
+               src6 = (struct sockaddr_in6 *) cma_src_addr(id_priv);
+               dst6 = (struct sockaddr_in6 *) cma_dst_addr(id_priv);
+
+               cma_set_ip_ver(cma_hdr, 6);
+               cma_hdr->src_addr.ip6 = src6->sin6_addr;
+               cma_hdr->dst_addr.ip6 = dst6->sin6_addr;
+               cma_hdr->port = src6->sin6_port;
        }
        return 0;
 }
@@ -2499,15 +2638,10 @@ static int cma_sidr_rep_handler(struct ib_cm_id *cm_id,
                        event.status = ib_event->param.sidr_rep_rcvd.status;
                        break;
                }
-               ret = cma_set_qkey(id_priv);
+               ret = cma_set_qkey(id_priv, rep->qkey);
                if (ret) {
                        event.event = RDMA_CM_EVENT_ADDR_ERROR;
-                       event.status = -EINVAL;
-                       break;
-               }
-               if (id_priv->qkey != rep->qkey) {
-                       event.event = RDMA_CM_EVENT_UNREACHABLE;
-                       event.status = -EINVAL;
+                       event.status = ret;
                        break;
                }
                ib_init_ah_from_path(id_priv->id.device, id_priv->id.port_num,
@@ -2542,27 +2676,31 @@ static int cma_resolve_ib_udp(struct rdma_id_private *id_priv,
                              struct rdma_conn_param *conn_param)
 {
        struct ib_cm_sidr_req_param req;
-       struct rdma_route *route;
        struct ib_cm_id *id;
-       int ret;
+       int offset, ret;
 
-       req.private_data_len = sizeof(struct cma_hdr) +
-                              conn_param->private_data_len;
+       offset = cma_user_data_offset(id_priv);
+       req.private_data_len = offset + conn_param->private_data_len;
        if (req.private_data_len < conn_param->private_data_len)
                return -EINVAL;
 
-       req.private_data = kzalloc(req.private_data_len, GFP_ATOMIC);
-       if (!req.private_data)
-               return -ENOMEM;
+       if (req.private_data_len) {
+               req.private_data = kzalloc(req.private_data_len, GFP_ATOMIC);
+               if (!req.private_data)
+                       return -ENOMEM;
+       } else {
+               req.private_data = NULL;
+       }
 
        if (conn_param->private_data && conn_param->private_data_len)
-               memcpy((void *) req.private_data + sizeof(struct cma_hdr),
+               memcpy((void *) req.private_data + offset,
                       conn_param->private_data, conn_param->private_data_len);
 
-       route = &id_priv->id.route;
-       ret = cma_format_hdr((void *) req.private_data, id_priv->id.ps, route);
-       if (ret)
-               goto out;
+       if (req.private_data) {
+               ret = cma_format_hdr((void *) req.private_data, id_priv);
+               if (ret)
+                       goto out;
+       }
 
        id = ib_create_cm_id(id_priv->id.device, cma_sidr_rep_handler,
                             id_priv);
@@ -2572,9 +2710,8 @@ static int cma_resolve_ib_udp(struct rdma_id_private *id_priv,
        }
        id_priv->cm_id.ib = id;
 
-       req.path = route->path_rec;
-       req.service_id = cma_get_service_id(id_priv->id.ps,
-                                           (struct sockaddr *) &route->addr.dst_addr);
+       req.path = id_priv->id.route.path_rec;
+       req.service_id = rdma_get_service_id(&id_priv->id, cma_dst_addr(id_priv));
        req.timeout_ms = 1 << (CMA_CM_RESPONSE_TIMEOUT - 8);
        req.max_cm_retries = CMA_MAX_CM_RETRIES;
 
@@ -2598,14 +2735,18 @@ static int cma_connect_ib(struct rdma_id_private *id_priv,
        int offset, ret;
 
        memset(&req, 0, sizeof req);
-       offset = cma_user_data_offset(id_priv->id.ps);
+       offset = cma_user_data_offset(id_priv);
        req.private_data_len = offset + conn_param->private_data_len;
        if (req.private_data_len < conn_param->private_data_len)
                return -EINVAL;
 
-       private_data = kzalloc(req.private_data_len, GFP_ATOMIC);
-       if (!private_data)
-               return -ENOMEM;
+       if (req.private_data_len) {
+               private_data = kzalloc(req.private_data_len, GFP_ATOMIC);
+               if (!private_data)
+                       return -ENOMEM;
+       } else {
+               private_data = NULL;
+       }
 
        if (conn_param->private_data && conn_param->private_data_len)
                memcpy(private_data + offset, conn_param->private_data,
@@ -2619,17 +2760,18 @@ static int cma_connect_ib(struct rdma_id_private *id_priv,
        id_priv->cm_id.ib = id;
 
        route = &id_priv->id.route;
-       ret = cma_format_hdr(private_data, id_priv->id.ps, route);
-       if (ret)
-               goto out;
-       req.private_data = private_data;
+       if (private_data) {
+               ret = cma_format_hdr(private_data, id_priv);
+               if (ret)
+                       goto out;
+               req.private_data = private_data;
+       }
 
        req.primary_path = &route->path_rec[0];
        if (route->num_paths == 2)
                req.alternate_path = &route->path_rec[1];
 
-       req.service_id = cma_get_service_id(id_priv->id.ps,
-                                           (struct sockaddr *) &route->addr.dst_addr);
+       req.service_id = rdma_get_service_id(&id_priv->id, cma_dst_addr(id_priv));
        req.qp_num = id_priv->qp_num;
        req.qp_type = id_priv->id.qp_type;
        req.starting_psn = id_priv->seq_num;
@@ -2668,10 +2810,10 @@ static int cma_connect_iw(struct rdma_id_private *id_priv,
 
        id_priv->cm_id.iw = cm_id;
 
-       sin = (struct sockaddr_in*) &id_priv->id.route.addr.src_addr;
+       sin = (struct sockaddr_in *) cma_src_addr(id_priv);
        cm_id->local_addr = *sin;
 
-       sin = (struct sockaddr_in*) &id_priv->id.route.addr.dst_addr;
+       sin = (struct sockaddr_in *) cma_dst_addr(id_priv);
        cm_id->remote_addr = *sin;
 
        ret = cma_modify_qp_rtr(id_priv, conn_param);
@@ -2789,7 +2931,7 @@ static int cma_accept_iw(struct rdma_id_private *id_priv,
 }
 
 static int cma_send_sidr_rep(struct rdma_id_private *id_priv,
-                            enum ib_cm_sidr_status status,
+                            enum ib_cm_sidr_status status, u32 qkey,
                             const void *private_data, int private_data_len)
 {
        struct ib_cm_sidr_rep_param rep;
@@ -2798,7 +2940,7 @@ static int cma_send_sidr_rep(struct rdma_id_private *id_priv,
        memset(&rep, 0, sizeof rep);
        rep.status = status;
        if (status == IB_SIDR_SUCCESS) {
-               ret = cma_set_qkey(id_priv);
+               ret = cma_set_qkey(id_priv, qkey);
                if (ret)
                        return ret;
                rep.qp_num = id_priv->qp_num;
@@ -2832,11 +2974,12 @@ int rdma_accept(struct rdma_cm_id *id, struct rdma_conn_param *conn_param)
                if (id->qp_type == IB_QPT_UD) {
                        if (conn_param)
                                ret = cma_send_sidr_rep(id_priv, IB_SIDR_SUCCESS,
+                                                       conn_param->qkey,
                                                        conn_param->private_data,
                                                        conn_param->private_data_len);
                        else
                                ret = cma_send_sidr_rep(id_priv, IB_SIDR_SUCCESS,
-                                                       NULL, 0);
+                                                       0, NULL, 0);
                } else {
                        if (conn_param)
                                ret = cma_accept_ib(id_priv, conn_param);
@@ -2897,7 +3040,7 @@ int rdma_reject(struct rdma_cm_id *id, const void *private_data,
        switch (rdma_node_get_transport(id->device->node_type)) {
        case RDMA_TRANSPORT_IB:
                if (id->qp_type == IB_QPT_UD)
-                       ret = cma_send_sidr_rep(id_priv, IB_SIDR_REJECT,
+                       ret = cma_send_sidr_rep(id_priv, IB_SIDR_REJECT, 0,
                                                private_data, private_data_len);
                else
                        ret = ib_send_cm_rej(id_priv->cm_id.ib,
@@ -2958,6 +3101,8 @@ static int cma_ib_mc_handler(int status, struct ib_sa_multicast *multicast)
            cma_disable_callback(id_priv, RDMA_CM_ADDR_RESOLVED))
                return 0;
 
+       if (!status)
+               status = cma_set_qkey(id_priv, be32_to_cpu(multicast->rec.qkey));
        mutex_lock(&id_priv->qp_mutex);
        if (!status && id_priv->id.qp)
                status = ib_attach_mcast(id_priv->id.qp, &multicast->rec.mgid,
@@ -3004,6 +3149,8 @@ static void cma_set_mgid(struct rdma_id_private *id_priv,
                                                                 0xFF10A01B)) {
                /* IPv6 address is an SA assigned MGID. */
                memcpy(mgid, &sin6->sin6_addr, sizeof *mgid);
+       } else if (addr->sa_family == AF_IB) {
+               memcpy(mgid, &((struct sockaddr_ib *) addr)->sib_addr, sizeof *mgid);
        } else if ((addr->sa_family == AF_INET6)) {
                ipv6_ib_mc_map(&sin6->sin6_addr, dev_addr->broadcast, mc_map);
                if (id_priv->id.ps == RDMA_PS_UDP)
@@ -3031,9 +3178,12 @@ static int cma_join_ib_multicast(struct rdma_id_private *id_priv,
        if (ret)
                return ret;
 
+       ret = cma_set_qkey(id_priv, 0);
+       if (ret)
+               return ret;
+
        cma_set_mgid(id_priv, (struct sockaddr *) &mc->addr, &rec.mgid);
-       if (id_priv->id.ps == RDMA_PS_UDP)
-               rec.qkey = cpu_to_be32(RDMA_UDP_QKEY);
+       rec.qkey = cpu_to_be32(id_priv->qkey);
        rdma_addr_get_sgid(dev_addr, &rec.port_gid);
        rec.pkey = cpu_to_be16(ib_addr_get_pkey(dev_addr));
        rec.join_state = 1;
@@ -3170,7 +3320,7 @@ int rdma_join_multicast(struct rdma_cm_id *id, struct sockaddr *addr,
        if (!mc)
                return -ENOMEM;
 
-       memcpy(&mc->addr, addr, ip_addr_size(addr));
+       memcpy(&mc->addr, addr, rdma_addr_size(addr));
        mc->context = context;
        mc->id_priv = id_priv;
 
@@ -3215,7 +3365,7 @@ void rdma_leave_multicast(struct rdma_cm_id *id, struct sockaddr *addr)
        id_priv = container_of(id, struct rdma_id_private, id);
        spin_lock_irq(&id_priv->lock);
        list_for_each_entry(mc, &id_priv->mc_list, list) {
-               if (!memcmp(&mc->addr, addr, ip_addr_size(addr))) {
+               if (!memcmp(&mc->addr, addr, rdma_addr_size(addr))) {
                        list_del(&mc->list);
                        spin_unlock_irq(&id_priv->lock);
 
@@ -3436,33 +3586,16 @@ static int cma_get_id_stats(struct sk_buff *skb, struct netlink_callback *cb)
                        id_stats->bound_dev_if =
                                id->route.addr.dev_addr.bound_dev_if;
 
-                       if (id->route.addr.src_addr.ss_family == AF_INET) {
-                               if (ibnl_put_attr(skb, nlh,
-                                                 sizeof(struct sockaddr_in),
-                                                 &id->route.addr.src_addr,
-                                                 RDMA_NL_RDMA_CM_ATTR_SRC_ADDR)) {
-                                       goto out;
-                               }
-                               if (ibnl_put_attr(skb, nlh,
-                                                 sizeof(struct sockaddr_in),
-                                                 &id->route.addr.dst_addr,
-                                                 RDMA_NL_RDMA_CM_ATTR_DST_ADDR)) {
-                                       goto out;
-                               }
-                       } else if (id->route.addr.src_addr.ss_family == AF_INET6) {
-                               if (ibnl_put_attr(skb, nlh,
-                                                 sizeof(struct sockaddr_in6),
-                                                 &id->route.addr.src_addr,
-                                                 RDMA_NL_RDMA_CM_ATTR_SRC_ADDR)) {
-                                       goto out;
-                               }
-                               if (ibnl_put_attr(skb, nlh,
-                                                 sizeof(struct sockaddr_in6),
-                                                 &id->route.addr.dst_addr,
-                                                 RDMA_NL_RDMA_CM_ATTR_DST_ADDR)) {
-                                       goto out;
-                               }
-                       }
+                       if (ibnl_put_attr(skb, nlh,
+                                         rdma_addr_size(cma_src_addr(id_priv)),
+                                         cma_src_addr(id_priv),
+                                         RDMA_NL_RDMA_CM_ATTR_SRC_ADDR))
+                               goto out;
+                       if (ibnl_put_attr(skb, nlh,
+                                         rdma_addr_size(cma_src_addr(id_priv)),
+                                         cma_dst_addr(id_priv),
+                                         RDMA_NL_RDMA_CM_ATTR_DST_ADDR))
+                               goto out;
 
                        id_stats->pid           = id_priv->owner;
                        id_stats->port_space    = id->ps;
@@ -3527,7 +3660,6 @@ static void __exit cma_cleanup(void)
        rdma_addr_unregister_client(&addr_client);
        ib_sa_unregister_client(&sa_client);
        destroy_workqueue(cma_wq);
-       idr_destroy(&sdp_ps);
        idr_destroy(&tcp_ps);
        idr_destroy(&udp_ps);
        idr_destroy(&ipoib_ps);
index 934f45e..9838ca4 100644 (file)
@@ -652,6 +652,12 @@ void ib_sa_unpack_path(void *attribute, struct ib_sa_path_rec *rec)
 }
 EXPORT_SYMBOL(ib_sa_unpack_path);
 
+void ib_sa_pack_path(struct ib_sa_path_rec *rec, void *attribute)
+{
+       ib_pack(path_rec_table, ARRAY_SIZE(path_rec_table), rec, attribute);
+}
+EXPORT_SYMBOL(ib_sa_pack_path);
+
 static void ib_sa_path_rec_callback(struct ib_sa_query *sa_query,
                                    int status,
                                    struct ib_sa_mad *mad)
index 99904f7..cde1e7b 100644 (file)
@@ -545,8 +545,10 @@ static int add_port(struct ib_device *device, int port_num,
 
        p->gid_group.name  = "gids";
        p->gid_group.attrs = alloc_group_attrs(show_port_gid, attr.gid_tbl_len);
-       if (!p->gid_group.attrs)
+       if (!p->gid_group.attrs) {
+               ret = -ENOMEM;
                goto err_remove_pma;
+       }
 
        ret = sysfs_create_group(&p->kobj, &p->gid_group);
        if (ret)
@@ -555,8 +557,10 @@ static int add_port(struct ib_device *device, int port_num,
        p->pkey_group.name  = "pkeys";
        p->pkey_group.attrs = alloc_group_attrs(show_port_pkey,
                                                attr.pkey_tbl_len);
-       if (!p->pkey_group.attrs)
+       if (!p->pkey_group.attrs) {
+               ret = -ENOMEM;
                goto err_remove_gid;
+       }
 
        ret = sysfs_create_group(&p->kobj, &p->pkey_group);
        if (ret)
index 5ca44cd..b0f189b 100644 (file)
@@ -47,6 +47,8 @@
 #include <rdma/ib_marshall.h>
 #include <rdma/rdma_cm.h>
 #include <rdma/rdma_cm_ib.h>
+#include <rdma/ib_addr.h>
+#include <rdma/ib.h>
 
 MODULE_AUTHOR("Sean Hefty");
 MODULE_DESCRIPTION("RDMA Userspace Connection Manager Access");
@@ -510,10 +512,10 @@ static ssize_t ucma_destroy_id(struct ucma_file *file, const char __user *inbuf,
        return ret;
 }
 
-static ssize_t ucma_bind_addr(struct ucma_file *file, const char __user *inbuf,
+static ssize_t ucma_bind_ip(struct ucma_file *file, const char __user *inbuf,
                              int in_len, int out_len)
 {
-       struct rdma_ucm_bind_addr cmd;
+       struct rdma_ucm_bind_ip cmd;
        struct ucma_context *ctx;
        int ret;
 
@@ -529,24 +531,75 @@ static ssize_t ucma_bind_addr(struct ucma_file *file, const char __user *inbuf,
        return ret;
 }
 
+static ssize_t ucma_bind(struct ucma_file *file, const char __user *inbuf,
+                        int in_len, int out_len)
+{
+       struct rdma_ucm_bind cmd;
+       struct sockaddr *addr;
+       struct ucma_context *ctx;
+       int ret;
+
+       if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
+               return -EFAULT;
+
+       addr = (struct sockaddr *) &cmd.addr;
+       if (cmd.reserved || !cmd.addr_size || (cmd.addr_size != rdma_addr_size(addr)))
+               return -EINVAL;
+
+       ctx = ucma_get_ctx(file, cmd.id);
+       if (IS_ERR(ctx))
+               return PTR_ERR(ctx);
+
+       ret = rdma_bind_addr(ctx->cm_id, addr);
+       ucma_put_ctx(ctx);
+       return ret;
+}
+
+static ssize_t ucma_resolve_ip(struct ucma_file *file,
+                              const char __user *inbuf,
+                              int in_len, int out_len)
+{
+       struct rdma_ucm_resolve_ip cmd;
+       struct ucma_context *ctx;
+       int ret;
+
+       if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
+               return -EFAULT;
+
+       ctx = ucma_get_ctx(file, cmd.id);
+       if (IS_ERR(ctx))
+               return PTR_ERR(ctx);
+
+       ret = rdma_resolve_addr(ctx->cm_id, (struct sockaddr *) &cmd.src_addr,
+                               (struct sockaddr *) &cmd.dst_addr,
+                               cmd.timeout_ms);
+       ucma_put_ctx(ctx);
+       return ret;
+}
+
 static ssize_t ucma_resolve_addr(struct ucma_file *file,
                                 const char __user *inbuf,
                                 int in_len, int out_len)
 {
        struct rdma_ucm_resolve_addr cmd;
+       struct sockaddr *src, *dst;
        struct ucma_context *ctx;
        int ret;
 
        if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
                return -EFAULT;
 
+       src = (struct sockaddr *) &cmd.src_addr;
+       dst = (struct sockaddr *) &cmd.dst_addr;
+       if (cmd.reserved || (cmd.src_size && (cmd.src_size != rdma_addr_size(src))) ||
+           !cmd.dst_size || (cmd.dst_size != rdma_addr_size(dst)))
+               return -EINVAL;
+
        ctx = ucma_get_ctx(file, cmd.id);
        if (IS_ERR(ctx))
                return PTR_ERR(ctx);
 
-       ret = rdma_resolve_addr(ctx->cm_id, (struct sockaddr *) &cmd.src_addr,
-                               (struct sockaddr *) &cmd.dst_addr,
-                               cmd.timeout_ms);
+       ret = rdma_resolve_addr(ctx->cm_id, src, dst, cmd.timeout_ms);
        ucma_put_ctx(ctx);
        return ret;
 }
@@ -649,7 +702,7 @@ static ssize_t ucma_query_route(struct ucma_file *file,
                                const char __user *inbuf,
                                int in_len, int out_len)
 {
-       struct rdma_ucm_query_route cmd;
+       struct rdma_ucm_query cmd;
        struct rdma_ucm_query_route_resp resp;
        struct ucma_context *ctx;
        struct sockaddr *addr;
@@ -709,7 +762,162 @@ out:
        return ret;
 }
 
-static void ucma_copy_conn_param(struct rdma_conn_param *dst,
+static void ucma_query_device_addr(struct rdma_cm_id *cm_id,
+                                  struct rdma_ucm_query_addr_resp *resp)
+{
+       if (!cm_id->device)
+               return;
+
+       resp->node_guid = (__force __u64) cm_id->device->node_guid;
+       resp->port_num = cm_id->port_num;
+       resp->pkey = (__force __u16) cpu_to_be16(
+                    ib_addr_get_pkey(&cm_id->route.addr.dev_addr));
+}
+
+static ssize_t ucma_query_addr(struct ucma_context *ctx,
+                              void __user *response, int out_len)
+{
+       struct rdma_ucm_query_addr_resp resp;
+       struct sockaddr *addr;
+       int ret = 0;
+
+       if (out_len < sizeof(resp))
+               return -ENOSPC;
+
+       memset(&resp, 0, sizeof resp);
+
+       addr = (struct sockaddr *) &ctx->cm_id->route.addr.src_addr;
+       resp.src_size = rdma_addr_size(addr);
+       memcpy(&resp.src_addr, addr, resp.src_size);
+
+       addr = (struct sockaddr *) &ctx->cm_id->route.addr.dst_addr;
+       resp.dst_size = rdma_addr_size(addr);
+       memcpy(&resp.dst_addr, addr, resp.dst_size);
+
+       ucma_query_device_addr(ctx->cm_id, &resp);
+
+       if (copy_to_user(response, &resp, sizeof(resp)))
+               ret = -EFAULT;
+
+       return ret;
+}
+
+static ssize_t ucma_query_path(struct ucma_context *ctx,
+                              void __user *response, int out_len)
+{
+       struct rdma_ucm_query_path_resp *resp;
+       int i, ret = 0;
+
+       if (out_len < sizeof(*resp))
+               return -ENOSPC;
+
+       resp = kzalloc(out_len, GFP_KERNEL);
+       if (!resp)
+               return -ENOMEM;
+
+       resp->num_paths = ctx->cm_id->route.num_paths;
+       for (i = 0, out_len -= sizeof(*resp);
+            i < resp->num_paths && out_len > sizeof(struct ib_path_rec_data);
+            i++, out_len -= sizeof(struct ib_path_rec_data)) {
+
+               resp->path_data[i].flags = IB_PATH_GMP | IB_PATH_PRIMARY |
+                                          IB_PATH_BIDIRECTIONAL;
+               ib_sa_pack_path(&ctx->cm_id->route.path_rec[i],
+                               &resp->path_data[i].path_rec);
+       }
+
+       if (copy_to_user(response, resp,
+                        sizeof(*resp) + (i * sizeof(struct ib_path_rec_data))))
+               ret = -EFAULT;
+
+       kfree(resp);
+       return ret;
+}
+
+static ssize_t ucma_query_gid(struct ucma_context *ctx,
+                             void __user *response, int out_len)
+{
+       struct rdma_ucm_query_addr_resp resp;
+       struct sockaddr_ib *addr;
+       int ret = 0;
+
+       if (out_len < sizeof(resp))
+               return -ENOSPC;
+
+       memset(&resp, 0, sizeof resp);
+
+       ucma_query_device_addr(ctx->cm_id, &resp);
+
+       addr = (struct sockaddr_ib *) &resp.src_addr;
+       resp.src_size = sizeof(*addr);
+       if (ctx->cm_id->route.addr.src_addr.ss_family == AF_IB) {
+               memcpy(addr, &ctx->cm_id->route.addr.src_addr, resp.src_size);
+       } else {
+               addr->sib_family = AF_IB;
+               addr->sib_pkey = (__force __be16) resp.pkey;
+               rdma_addr_get_sgid(&ctx->cm_id->route.addr.dev_addr,
+                                  (union ib_gid *) &addr->sib_addr);
+               addr->sib_sid = rdma_get_service_id(ctx->cm_id, (struct sockaddr *)
+                                                   &ctx->cm_id->route.addr.src_addr);
+       }
+
+       addr = (struct sockaddr_ib *) &resp.dst_addr;
+       resp.dst_size = sizeof(*addr);
+       if (ctx->cm_id->route.addr.dst_addr.ss_family == AF_IB) {
+               memcpy(addr, &ctx->cm_id->route.addr.dst_addr, resp.dst_size);
+       } else {
+               addr->sib_family = AF_IB;
+               addr->sib_pkey = (__force __be16) resp.pkey;
+               rdma_addr_get_dgid(&ctx->cm_id->route.addr.dev_addr,
+                                  (union ib_gid *) &addr->sib_addr);
+               addr->sib_sid = rdma_get_service_id(ctx->cm_id, (struct sockaddr *)
+                                                   &ctx->cm_id->route.addr.dst_addr);
+       }
+
+       if (copy_to_user(response, &resp, sizeof(resp)))
+               ret = -EFAULT;
+
+       return ret;
+}
+
+static ssize_t ucma_query(struct ucma_file *file,
+                         const char __user *inbuf,
+                         int in_len, int out_len)
+{
+       struct rdma_ucm_query cmd;
+       struct ucma_context *ctx;
+       void __user *response;
+       int ret;
+
+       if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
+               return -EFAULT;
+
+       response = (void __user *)(unsigned long) cmd.response;
+       ctx = ucma_get_ctx(file, cmd.id);
+       if (IS_ERR(ctx))
+               return PTR_ERR(ctx);
+
+       switch (cmd.option) {
+       case RDMA_USER_CM_QUERY_ADDR:
+               ret = ucma_query_addr(ctx, response, out_len);
+               break;
+       case RDMA_USER_CM_QUERY_PATH:
+               ret = ucma_query_path(ctx, response, out_len);
+               break;
+       case RDMA_USER_CM_QUERY_GID:
+               ret = ucma_query_gid(ctx, response, out_len);
+               break;
+       default:
+               ret = -ENOSYS;
+               break;
+       }
+
+       ucma_put_ctx(ctx);
+       return ret;
+}
+
+static void ucma_copy_conn_param(struct rdma_cm_id *id,
+                                struct rdma_conn_param *dst,
                                 struct rdma_ucm_conn_param *src)
 {
        dst->private_data = src->private_data;
@@ -721,6 +929,7 @@ static void ucma_copy_conn_param(struct rdma_conn_param *dst,
        dst->rnr_retry_count = src->rnr_retry_count;
        dst->srq = src->srq;
        dst->qp_num = src->qp_num;
+       dst->qkey = (id->route.addr.src_addr.ss_family == AF_IB) ? src->qkey : 0;
 }
 
 static ssize_t ucma_connect(struct ucma_file *file, const char __user *inbuf,
@@ -741,7 +950,7 @@ static ssize_t ucma_connect(struct ucma_file *file, const char __user *inbuf,
        if (IS_ERR(ctx))
                return PTR_ERR(ctx);
 
-       ucma_copy_conn_param(&conn_param, &cmd.conn_param);
+       ucma_copy_conn_param(ctx->cm_id, &conn_param, &cmd.conn_param);
        ret = rdma_connect(ctx->cm_id, &conn_param);
        ucma_put_ctx(ctx);
        return ret;
@@ -784,7 +993,7 @@ static ssize_t ucma_accept(struct ucma_file *file, const char __user *inbuf,
                return PTR_ERR(ctx);
 
        if (cmd.conn_param.valid) {
-               ucma_copy_conn_param(&conn_param, &cmd.conn_param);
+               ucma_copy_conn_param(ctx->cm_id, &conn_param, &cmd.conn_param);
                mutex_lock(&file->mut);
                ret = rdma_accept(ctx->cm_id, &conn_param);
                if (!ret)
@@ -1020,23 +1229,23 @@ static ssize_t ucma_notify(struct ucma_file *file, const char __user *inbuf,
        return ret;
 }
 
-static ssize_t ucma_join_multicast(struct ucma_file *file,
-                                  const char __user *inbuf,
-                                  int in_len, int out_len)
+static ssize_t ucma_process_join(struct ucma_file *file,
+                                struct rdma_ucm_join_mcast *cmd,  int out_len)
 {
-       struct rdma_ucm_join_mcast cmd;
        struct rdma_ucm_create_id_resp resp;
        struct ucma_context *ctx;
        struct ucma_multicast *mc;
+       struct sockaddr *addr;
        int ret;
 
        if (out_len < sizeof(resp))
                return -ENOSPC;
 
-       if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
-               return -EFAULT;
+       addr = (struct sockaddr *) &cmd->addr;
+       if (cmd->reserved || !cmd->addr_size || (cmd->addr_size != rdma_addr_size(addr)))
+               return -EINVAL;
 
-       ctx = ucma_get_ctx(file, cmd.id);
+       ctx = ucma_get_ctx(file, cmd->id);
        if (IS_ERR(ctx))
                return PTR_ERR(ctx);
 
@@ -1047,14 +1256,14 @@ static ssize_t ucma_join_multicast(struct ucma_file *file,
                goto err1;
        }
 
-       mc->uid = cmd.uid;
-       memcpy(&mc->addr, &cmd.addr, sizeof cmd.addr);
+       mc->uid = cmd->uid;
+       memcpy(&mc->addr, addr, cmd->addr_size);
        ret = rdma_join_multicast(ctx->cm_id, (struct sockaddr *) &mc->addr, mc);
        if (ret)
                goto err2;
 
        resp.id = mc->id;
-       if (copy_to_user((void __user *)(unsigned long)cmd.response,
+       if (copy_to_user((void __user *)(unsigned long) cmd->response,
                         &resp, sizeof(resp))) {
                ret = -EFAULT;
                goto err3;
@@ -1079,6 +1288,38 @@ err1:
        return ret;
 }
 
+static ssize_t ucma_join_ip_multicast(struct ucma_file *file,
+                                     const char __user *inbuf,
+                                     int in_len, int out_len)
+{
+       struct rdma_ucm_join_ip_mcast cmd;
+       struct rdma_ucm_join_mcast join_cmd;
+
+       if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
+               return -EFAULT;
+
+       join_cmd.response = cmd.response;
+       join_cmd.uid = cmd.uid;
+       join_cmd.id = cmd.id;
+       join_cmd.addr_size = rdma_addr_size((struct sockaddr *) &cmd.addr);
+       join_cmd.reserved = 0;
+       memcpy(&join_cmd.addr, &cmd.addr, join_cmd.addr_size);
+
+       return ucma_process_join(file, &join_cmd, out_len);
+}
+
+static ssize_t ucma_join_multicast(struct ucma_file *file,
+                                  const char __user *inbuf,
+                                  int in_len, int out_len)
+{
+       struct rdma_ucm_join_mcast cmd;
+
+       if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
+               return -EFAULT;
+
+       return ucma_process_join(file, &cmd, out_len);
+}
+
 static ssize_t ucma_leave_multicast(struct ucma_file *file,
                                    const char __user *inbuf,
                                    int in_len, int out_len)
@@ -1221,25 +1462,29 @@ file_put:
 static ssize_t (*ucma_cmd_table[])(struct ucma_file *file,
                                   const char __user *inbuf,
                                   int in_len, int out_len) = {
-       [RDMA_USER_CM_CMD_CREATE_ID]    = ucma_create_id,
-       [RDMA_USER_CM_CMD_DESTROY_ID]   = ucma_destroy_id,
-       [RDMA_USER_CM_CMD_BIND_ADDR]    = ucma_bind_addr,
-       [RDMA_USER_CM_CMD_RESOLVE_ADDR] = ucma_resolve_addr,
-       [RDMA_USER_CM_CMD_RESOLVE_ROUTE]= ucma_resolve_route,
-       [RDMA_USER_CM_CMD_QUERY_ROUTE]  = ucma_query_route,
-       [RDMA_USER_CM_CMD_CONNECT]      = ucma_connect,
-       [RDMA_USER_CM_CMD_LISTEN]       = ucma_listen,
-       [RDMA_USER_CM_CMD_ACCEPT]       = ucma_accept,
-       [RDMA_USER_CM_CMD_REJECT]       = ucma_reject,
-       [RDMA_USER_CM_CMD_DISCONNECT]   = ucma_disconnect,
-       [RDMA_USER_CM_CMD_INIT_QP_ATTR] = ucma_init_qp_attr,
-       [RDMA_USER_CM_CMD_GET_EVENT]    = ucma_get_event,
-       [RDMA_USER_CM_CMD_GET_OPTION]   = NULL,
-       [RDMA_USER_CM_CMD_SET_OPTION]   = ucma_set_option,
-       [RDMA_USER_CM_CMD_NOTIFY]       = ucma_notify,
-       [RDMA_USER_CM_CMD_JOIN_MCAST]   = ucma_join_multicast,
-       [RDMA_USER_CM_CMD_LEAVE_MCAST]  = ucma_leave_multicast,
-       [RDMA_USER_CM_CMD_MIGRATE_ID]   = ucma_migrate_id
+       [RDMA_USER_CM_CMD_CREATE_ID]     = ucma_create_id,
+       [RDMA_USER_CM_CMD_DESTROY_ID]    = ucma_destroy_id,
+       [RDMA_USER_CM_CMD_BIND_IP]       = ucma_bind_ip,
+       [RDMA_USER_CM_CMD_RESOLVE_IP]    = ucma_resolve_ip,
+       [RDMA_USER_CM_CMD_RESOLVE_ROUTE] = ucma_resolve_route,
+       [RDMA_USER_CM_CMD_QUERY_ROUTE]   = ucma_query_route,
+       [RDMA_USER_CM_CMD_CONNECT]       = ucma_connect,
+       [RDMA_USER_CM_CMD_LISTEN]        = ucma_listen,
+       [RDMA_USER_CM_CMD_ACCEPT]        = ucma_accept,
+       [RDMA_USER_CM_CMD_REJECT]        = ucma_reject,
+       [RDMA_USER_CM_CMD_DISCONNECT]    = ucma_disconnect,
+       [RDMA_USER_CM_CMD_INIT_QP_ATTR]  = ucma_init_qp_attr,
+       [RDMA_USER_CM_CMD_GET_EVENT]     = ucma_get_event,
+       [RDMA_USER_CM_CMD_GET_OPTION]    = NULL,
+       [RDMA_USER_CM_CMD_SET_OPTION]    = ucma_set_option,
+       [RDMA_USER_CM_CMD_NOTIFY]        = ucma_notify,
+       [RDMA_USER_CM_CMD_JOIN_IP_MCAST] = ucma_join_ip_multicast,
+       [RDMA_USER_CM_CMD_LEAVE_MCAST]   = ucma_leave_multicast,
+       [RDMA_USER_CM_CMD_MIGRATE_ID]    = ucma_migrate_id,
+       [RDMA_USER_CM_CMD_QUERY]         = ucma_query,
+       [RDMA_USER_CM_CMD_BIND]          = ucma_bind,
+       [RDMA_USER_CM_CMD_RESOLVE_ADDR]  = ucma_resolve_addr,
+       [RDMA_USER_CM_CMD_JOIN_MCAST]    = ucma_join_multicast
 };
 
 static ssize_t ucma_write(struct file *filp, const char __user *buf,
index a7d00f6..b3c07b0 100644 (file)
@@ -334,7 +334,7 @@ ssize_t ib_uverbs_get_context(struct ib_uverbs_file *file,
 
        resp.num_comp_vectors = file->device->num_comp_vectors;
 
-       ret = get_unused_fd();
+       ret = get_unused_fd_flags(O_CLOEXEC);
        if (ret < 0)
                goto err_free;
        resp.async_fd = ret;
@@ -1184,7 +1184,7 @@ ssize_t ib_uverbs_create_comp_channel(struct ib_uverbs_file *file,
        if (copy_from_user(&cmd, buf, sizeof cmd))
                return -EFAULT;
 
-       ret = get_unused_fd();
+       ret = get_unused_fd_flags(O_CLOEXEC);
        if (ret < 0)
                return ret;
        resp.fd = ret;
index e5649e8..b57c0be 100644 (file)
@@ -883,7 +883,8 @@ u16 iwch_rqes_posted(struct iwch_qp *qhp)
 {
        union t3_wr *wqe = qhp->wq.queue;
        u16 count = 0;
-       while ((count+1) != 0 && fw_riwrh_opcode((struct fw_riwrh *)wqe) == T3_WR_RCV) {
+
+       while (count < USHRT_MAX && fw_riwrh_opcode((struct fw_riwrh *)wqe) == T3_WR_RCV) {
                count++;
                wqe++;
        }
index 982e3ef..cd8d290 100644 (file)
@@ -211,6 +211,7 @@ static int ehca_create_slab_caches(void)
        if (!ctblk_cache) {
                ehca_gen_err("Cannot create ctblk SLAB cache.");
                ehca_cleanup_small_qp_cache();
+               ret = -ENOMEM;
                goto create_slab_caches6;
        }
 #endif
diff --git a/drivers/infiniband/hw/mlx5/Kconfig b/drivers/infiniband/hw/mlx5/Kconfig
new file mode 100644 (file)
index 0000000..8e6aebf
--- /dev/null
@@ -0,0 +1,10 @@
+config MLX5_INFINIBAND
+       tristate "Mellanox Connect-IB HCA support"
+       depends on NETDEVICES && ETHERNET && PCI && X86
+       select NET_VENDOR_MELLANOX
+       select MLX5_CORE
+       ---help---
+         This driver provides low-level InfiniBand support for
+         Mellanox Connect-IB PCI Express host channel adapters (HCAs).
+         This is required to use InfiniBand protocols such as
+         IP-over-IB or SRP with these devices.
diff --git a/drivers/infiniband/hw/mlx5/Makefile b/drivers/infiniband/hw/mlx5/Makefile
new file mode 100644 (file)
index 0000000..4ea0135
--- /dev/null
@@ -0,0 +1,3 @@
+obj-$(CONFIG_MLX5_INFINIBAND)  += mlx5_ib.o
+
+mlx5_ib-y :=   main.o cq.o doorbell.o qp.o mem.o srq.o mr.o ah.o mad.o
diff --git a/drivers/infiniband/hw/mlx5/ah.c b/drivers/infiniband/hw/mlx5/ah.c
new file mode 100644 (file)
index 0000000..39ab0ca
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2013, Mellanox Technologies inc.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "mlx5_ib.h"
+
+struct ib_ah *create_ib_ah(struct ib_ah_attr *ah_attr,
+                          struct mlx5_ib_ah *ah)
+{
+       if (ah_attr->ah_flags & IB_AH_GRH) {
+               memcpy(ah->av.rgid, &ah_attr->grh.dgid, 16);
+               ah->av.grh_gid_fl = cpu_to_be32(ah_attr->grh.flow_label |
+                                               (1 << 30) |
+                                               ah_attr->grh.sgid_index << 20);
+               ah->av.hop_limit = ah_attr->grh.hop_limit;
+               ah->av.tclass = ah_attr->grh.traffic_class;
+       }
+
+       ah->av.rlid = cpu_to_be16(ah_attr->dlid);
+       ah->av.fl_mlid = ah_attr->src_path_bits & 0x7f;
+       ah->av.stat_rate_sl = (ah_attr->static_rate << 4) | (ah_attr->sl & 0xf);
+
+       return &ah->ibah;
+}
+
+struct ib_ah *mlx5_ib_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr)
+{
+       struct mlx5_ib_ah *ah;
+
+       ah = kzalloc(sizeof(*ah), GFP_ATOMIC);
+       if (!ah)
+               return ERR_PTR(-ENOMEM);
+
+       return create_ib_ah(ah_attr, ah); /* never fails */
+}
+
+int mlx5_ib_query_ah(struct ib_ah *ibah, struct ib_ah_attr *ah_attr)
+{
+       struct mlx5_ib_ah *ah = to_mah(ibah);
+       u32 tmp;
+
+       memset(ah_attr, 0, sizeof(*ah_attr));
+
+       tmp = be32_to_cpu(ah->av.grh_gid_fl);
+       if (tmp & (1 << 30)) {
+               ah_attr->ah_flags = IB_AH_GRH;
+               ah_attr->grh.sgid_index = (tmp >> 20) & 0xff;
+               ah_attr->grh.flow_label = tmp & 0xfffff;
+               memcpy(&ah_attr->grh.dgid, ah->av.rgid, 16);
+               ah_attr->grh.hop_limit = ah->av.hop_limit;
+               ah_attr->grh.traffic_class = ah->av.tclass;
+       }
+       ah_attr->dlid = be16_to_cpu(ah->av.rlid);
+       ah_attr->static_rate = ah->av.stat_rate_sl >> 4;
+       ah_attr->sl = ah->av.stat_rate_sl & 0xf;
+
+       return 0;
+}
+
+int mlx5_ib_destroy_ah(struct ib_ah *ah)
+{
+       kfree(to_mah(ah));
+       return 0;
+}
diff --git a/drivers/infiniband/hw/mlx5/cq.c b/drivers/infiniband/hw/mlx5/cq.c
new file mode 100644 (file)
index 0000000..344ab03
--- /dev/null
@@ -0,0 +1,843 @@
+/*
+ * Copyright (c) 2013, Mellanox Technologies inc.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/kref.h>
+#include <rdma/ib_umem.h>
+#include "mlx5_ib.h"
+#include "user.h"
+
+static void mlx5_ib_cq_comp(struct mlx5_core_cq *cq)
+{
+       struct ib_cq *ibcq = &to_mibcq(cq)->ibcq;
+
+       ibcq->comp_handler(ibcq, ibcq->cq_context);
+}
+
+static void mlx5_ib_cq_event(struct mlx5_core_cq *mcq, enum mlx5_event type)
+{
+       struct mlx5_ib_cq *cq = container_of(mcq, struct mlx5_ib_cq, mcq);
+       struct mlx5_ib_dev *dev = to_mdev(cq->ibcq.device);
+       struct ib_cq *ibcq = &cq->ibcq;
+       struct ib_event event;
+
+       if (type != MLX5_EVENT_TYPE_CQ_ERROR) {
+               mlx5_ib_warn(dev, "Unexpected event type %d on CQ %06x\n",
+                            type, mcq->cqn);
+               return;
+       }
+
+       if (ibcq->event_handler) {
+               event.device     = &dev->ib_dev;
+               event.event      = IB_EVENT_CQ_ERR;
+               event.element.cq = ibcq;
+               ibcq->event_handler(&event, ibcq->cq_context);
+       }
+}
+
+static void *get_cqe_from_buf(struct mlx5_ib_cq_buf *buf, int n, int size)
+{
+       return mlx5_buf_offset(&buf->buf, n * size);
+}
+
+static void *get_cqe(struct mlx5_ib_cq *cq, int n)
+{
+       return get_cqe_from_buf(&cq->buf, n, cq->mcq.cqe_sz);
+}
+
+static void *get_sw_cqe(struct mlx5_ib_cq *cq, int n)
+{
+       void *cqe = get_cqe(cq, n & cq->ibcq.cqe);
+       struct mlx5_cqe64 *cqe64;
+
+       cqe64 = (cq->mcq.cqe_sz == 64) ? cqe : cqe + 64;
+       return ((cqe64->op_own & MLX5_CQE_OWNER_MASK) ^
+               !!(n & (cq->ibcq.cqe + 1))) ? NULL : cqe;
+}
+
+static void *next_cqe_sw(struct mlx5_ib_cq *cq)
+{
+       return get_sw_cqe(cq, cq->mcq.cons_index);
+}
+
+static enum ib_wc_opcode get_umr_comp(struct mlx5_ib_wq *wq, int idx)
+{
+       switch (wq->wr_data[idx]) {
+       case MLX5_IB_WR_UMR:
+               return 0;
+
+       case IB_WR_LOCAL_INV:
+               return IB_WC_LOCAL_INV;
+
+       case IB_WR_FAST_REG_MR:
+               return IB_WC_FAST_REG_MR;
+
+       default:
+               pr_warn("unknown completion status\n");
+               return 0;
+       }
+}
+
+static void handle_good_req(struct ib_wc *wc, struct mlx5_cqe64 *cqe,
+                           struct mlx5_ib_wq *wq, int idx)
+{
+       wc->wc_flags = 0;
+       switch (be32_to_cpu(cqe->sop_drop_qpn) >> 24) {
+       case MLX5_OPCODE_RDMA_WRITE_IMM:
+               wc->wc_flags |= IB_WC_WITH_IMM;
+       case MLX5_OPCODE_RDMA_WRITE:
+               wc->opcode    = IB_WC_RDMA_WRITE;
+               break;
+       case MLX5_OPCODE_SEND_IMM:
+               wc->wc_flags |= IB_WC_WITH_IMM;
+       case MLX5_OPCODE_SEND:
+       case MLX5_OPCODE_SEND_INVAL:
+               wc->opcode    = IB_WC_SEND;
+               break;
+       case MLX5_OPCODE_RDMA_READ:
+               wc->opcode    = IB_WC_RDMA_READ;
+               wc->byte_len  = be32_to_cpu(cqe->byte_cnt);
+               break;
+       case MLX5_OPCODE_ATOMIC_CS:
+               wc->opcode    = IB_WC_COMP_SWAP;
+               wc->byte_len  = 8;
+               break;
+       case MLX5_OPCODE_ATOMIC_FA:
+               wc->opcode    = IB_WC_FETCH_ADD;
+               wc->byte_len  = 8;
+               break;
+       case MLX5_OPCODE_ATOMIC_MASKED_CS:
+               wc->opcode    = IB_WC_MASKED_COMP_SWAP;
+               wc->byte_len  = 8;
+               break;
+       case MLX5_OPCODE_ATOMIC_MASKED_FA:
+               wc->opcode    = IB_WC_MASKED_FETCH_ADD;
+               wc->byte_len  = 8;
+               break;
+       case MLX5_OPCODE_BIND_MW:
+               wc->opcode    = IB_WC_BIND_MW;
+               break;
+       case MLX5_OPCODE_UMR:
+               wc->opcode = get_umr_comp(wq, idx);
+               break;
+       }
+}
+
+enum {
+       MLX5_GRH_IN_BUFFER = 1,
+       MLX5_GRH_IN_CQE    = 2,
+};
+
+static void handle_responder(struct ib_wc *wc, struct mlx5_cqe64 *cqe,
+                            struct mlx5_ib_qp *qp)
+{
+       struct mlx5_ib_dev *dev = to_mdev(qp->ibqp.device);
+       struct mlx5_ib_srq *srq;
+       struct mlx5_ib_wq *wq;
+       u16 wqe_ctr;
+       u8 g;
+
+       if (qp->ibqp.srq || qp->ibqp.xrcd) {
+               struct mlx5_core_srq *msrq = NULL;
+
+               if (qp->ibqp.xrcd) {
+                       msrq = mlx5_core_get_srq(&dev->mdev,
+                                                be32_to_cpu(cqe->srqn));
+                       srq = to_mibsrq(msrq);
+               } else {
+                       srq = to_msrq(qp->ibqp.srq);
+               }
+               if (srq) {
+                       wqe_ctr = be16_to_cpu(cqe->wqe_counter);
+                       wc->wr_id = srq->wrid[wqe_ctr];
+                       mlx5_ib_free_srq_wqe(srq, wqe_ctr);
+                       if (msrq && atomic_dec_and_test(&msrq->refcount))
+                               complete(&msrq->free);
+               }
+       } else {
+               wq        = &qp->rq;
+               wc->wr_id = wq->wrid[wq->tail & (wq->wqe_cnt - 1)];
+               ++wq->tail;
+       }
+       wc->byte_len = be32_to_cpu(cqe->byte_cnt);
+
+       switch (cqe->op_own >> 4) {
+       case MLX5_CQE_RESP_WR_IMM:
+               wc->opcode      = IB_WC_RECV_RDMA_WITH_IMM;
+               wc->wc_flags    = IB_WC_WITH_IMM;
+               wc->ex.imm_data = cqe->imm_inval_pkey;
+               break;
+       case MLX5_CQE_RESP_SEND:
+               wc->opcode   = IB_WC_RECV;
+               wc->wc_flags = 0;
+               break;
+       case MLX5_CQE_RESP_SEND_IMM:
+               wc->opcode      = IB_WC_RECV;
+               wc->wc_flags    = IB_WC_WITH_IMM;
+               wc->ex.imm_data = cqe->imm_inval_pkey;
+               break;
+       case MLX5_CQE_RESP_SEND_INV:
+               wc->opcode      = IB_WC_RECV;
+               wc->wc_flags    = IB_WC_WITH_INVALIDATE;
+               wc->ex.invalidate_rkey = be32_to_cpu(cqe->imm_inval_pkey);
+               break;
+       }
+       wc->slid           = be16_to_cpu(cqe->slid);
+       wc->sl             = (be32_to_cpu(cqe->flags_rqpn) >> 24) & 0xf;
+       wc->src_qp         = be32_to_cpu(cqe->flags_rqpn) & 0xffffff;
+       wc->dlid_path_bits = cqe->ml_path;
+       g = (be32_to_cpu(cqe->flags_rqpn) >> 28) & 3;
+       wc->wc_flags |= g ? IB_WC_GRH : 0;
+       wc->pkey_index     = be32_to_cpu(cqe->imm_inval_pkey) & 0xffff;
+}
+
+static void dump_cqe(struct mlx5_ib_dev *dev, struct mlx5_err_cqe *cqe)
+{
+       __be32 *p = (__be32 *)cqe;
+       int i;
+
+       mlx5_ib_warn(dev, "dump error cqe\n");
+       for (i = 0; i < sizeof(*cqe) / 16; i++, p += 4)
+               pr_info("%08x %08x %08x %08x\n", be32_to_cpu(p[0]),
+                       be32_to_cpu(p[1]), be32_to_cpu(p[2]),
+                       be32_to_cpu(p[3]));
+}
+
+static void mlx5_handle_error_cqe(struct mlx5_ib_dev *dev,
+                                 struct mlx5_err_cqe *cqe,
+                                 struct ib_wc *wc)
+{
+       int dump = 1;
+
+       switch (cqe->syndrome) {
+       case MLX5_CQE_SYNDROME_LOCAL_LENGTH_ERR:
+               wc->status = IB_WC_LOC_LEN_ERR;
+               break;
+       case MLX5_CQE_SYNDROME_LOCAL_QP_OP_ERR:
+               wc->status = IB_WC_LOC_QP_OP_ERR;
+               break;
+       case MLX5_CQE_SYNDROME_LOCAL_PROT_ERR:
+               wc->status = IB_WC_LOC_PROT_ERR;
+               break;
+       case MLX5_CQE_SYNDROME_WR_FLUSH_ERR:
+               dump = 0;
+               wc->status = IB_WC_WR_FLUSH_ERR;
+               break;
+       case MLX5_CQE_SYNDROME_MW_BIND_ERR:
+               wc->status = IB_WC_MW_BIND_ERR;
+               break;
+       case MLX5_CQE_SYNDROME_BAD_RESP_ERR:
+               wc->status = IB_WC_BAD_RESP_ERR;
+               break;
+       case MLX5_CQE_SYNDROME_LOCAL_ACCESS_ERR:
+               wc->status = IB_WC_LOC_ACCESS_ERR;
+               break;
+       case MLX5_CQE_SYNDROME_REMOTE_INVAL_REQ_ERR:
+               wc->status = IB_WC_REM_INV_REQ_ERR;
+               break;
+       case MLX5_CQE_SYNDROME_REMOTE_ACCESS_ERR:
+               wc->status = IB_WC_REM_ACCESS_ERR;
+               break;
+       case MLX5_CQE_SYNDROME_REMOTE_OP_ERR:
+               wc->status = IB_WC_REM_OP_ERR;
+               break;
+       case MLX5_CQE_SYNDROME_TRANSPORT_RETRY_EXC_ERR:
+               wc->status = IB_WC_RETRY_EXC_ERR;
+               dump = 0;
+               break;
+       case MLX5_CQE_SYNDROME_RNR_RETRY_EXC_ERR:
+               wc->status = IB_WC_RNR_RETRY_EXC_ERR;
+               dump = 0;
+               break;
+       case MLX5_CQE_SYNDROME_REMOTE_ABORTED_ERR:
+               wc->status = IB_WC_REM_ABORT_ERR;
+               break;
+       default:
+               wc->status = IB_WC_GENERAL_ERR;
+               break;
+       }
+
+       wc->vendor_err = cqe->vendor_err_synd;
+       if (dump)
+               dump_cqe(dev, cqe);
+}
+
+static int is_atomic_response(struct mlx5_ib_qp *qp, uint16_t idx)
+{
+       /* TBD: waiting decision
+       */
+       return 0;
+}
+
+static void *mlx5_get_atomic_laddr(struct mlx5_ib_qp *qp, uint16_t idx)
+{
+       struct mlx5_wqe_data_seg *dpseg;
+       void *addr;
+
+       dpseg = mlx5_get_send_wqe(qp, idx) + sizeof(struct mlx5_wqe_ctrl_seg) +
+               sizeof(struct mlx5_wqe_raddr_seg) +
+               sizeof(struct mlx5_wqe_atomic_seg);
+       addr = (void *)(unsigned long)be64_to_cpu(dpseg->addr);
+       return addr;
+}
+
+static void handle_atomic(struct mlx5_ib_qp *qp, struct mlx5_cqe64 *cqe64,
+                         uint16_t idx)
+{
+       void *addr;
+       int byte_count;
+       int i;
+
+       if (!is_atomic_response(qp, idx))
+               return;
+
+       byte_count = be32_to_cpu(cqe64->byte_cnt);
+       addr = mlx5_get_atomic_laddr(qp, idx);
+
+       if (byte_count == 4) {
+               *(uint32_t *)addr = be32_to_cpu(*((__be32 *)addr));
+       } else {
+               for (i = 0; i < byte_count; i += 8) {
+                       *(uint64_t *)addr = be64_to_cpu(*((__be64 *)addr));
+                       addr += 8;
+               }
+       }
+
+       return;
+}
+
+static void handle_atomics(struct mlx5_ib_qp *qp, struct mlx5_cqe64 *cqe64,
+                          u16 tail, u16 head)
+{
+       int idx;
+
+       do {
+               idx = tail & (qp->sq.wqe_cnt - 1);
+               handle_atomic(qp, cqe64, idx);
+               if (idx == head)
+                       break;
+
+               tail = qp->sq.w_list[idx].next;
+       } while (1);
+       tail = qp->sq.w_list[idx].next;
+       qp->sq.last_poll = tail;
+}
+
+static int mlx5_poll_one(struct mlx5_ib_cq *cq,
+                        struct mlx5_ib_qp **cur_qp,
+                        struct ib_wc *wc)
+{
+       struct mlx5_ib_dev *dev = to_mdev(cq->ibcq.device);
+       struct mlx5_err_cqe *err_cqe;
+       struct mlx5_cqe64 *cqe64;
+       struct mlx5_core_qp *mqp;
+       struct mlx5_ib_wq *wq;
+       uint8_t opcode;
+       uint32_t qpn;
+       u16 wqe_ctr;
+       void *cqe;
+       int idx;
+
+       cqe = next_cqe_sw(cq);
+       if (!cqe)
+               return -EAGAIN;
+
+       cqe64 = (cq->mcq.cqe_sz == 64) ? cqe : cqe + 64;
+
+       ++cq->mcq.cons_index;
+
+       /* Make sure we read CQ entry contents after we've checked the
+        * ownership bit.
+        */
+       rmb();
+
+       /* TBD: resize CQ */
+
+       qpn = ntohl(cqe64->sop_drop_qpn) & 0xffffff;
+       if (!*cur_qp || (qpn != (*cur_qp)->ibqp.qp_num)) {
+               /* We do not have to take the QP table lock here,
+                * because CQs will be locked while QPs are removed
+                * from the table.
+                */
+               mqp = __mlx5_qp_lookup(&dev->mdev, qpn);
+               if (unlikely(!mqp)) {
+                       mlx5_ib_warn(dev, "CQE@CQ %06x for unknown QPN %6x\n",
+                                    cq->mcq.cqn, qpn);
+                       return -EINVAL;
+               }
+
+               *cur_qp = to_mibqp(mqp);
+       }
+
+       wc->qp  = &(*cur_qp)->ibqp;
+       opcode = cqe64->op_own >> 4;
+       switch (opcode) {
+       case MLX5_CQE_REQ:
+               wq = &(*cur_qp)->sq;
+               wqe_ctr = be16_to_cpu(cqe64->wqe_counter);
+               idx = wqe_ctr & (wq->wqe_cnt - 1);
+               handle_good_req(wc, cqe64, wq, idx);
+               handle_atomics(*cur_qp, cqe64, wq->last_poll, idx);
+               wc->wr_id = wq->wrid[idx];
+               wq->tail = wq->wqe_head[idx] + 1;
+               wc->status = IB_WC_SUCCESS;
+               break;
+       case MLX5_CQE_RESP_WR_IMM:
+       case MLX5_CQE_RESP_SEND:
+       case MLX5_CQE_RESP_SEND_IMM:
+       case MLX5_CQE_RESP_SEND_INV:
+               handle_responder(wc, cqe64, *cur_qp);
+               wc->status = IB_WC_SUCCESS;
+               break;
+       case MLX5_CQE_RESIZE_CQ:
+               break;
+       case MLX5_CQE_REQ_ERR:
+       case MLX5_CQE_RESP_ERR:
+               err_cqe = (struct mlx5_err_cqe *)cqe64;
+               mlx5_handle_error_cqe(dev, err_cqe, wc);
+               mlx5_ib_dbg(dev, "%s error cqe on cqn 0x%x:\n",
+                           opcode == MLX5_CQE_REQ_ERR ?
+                           "Requestor" : "Responder", cq->mcq.cqn);
+               mlx5_ib_dbg(dev, "syndrome 0x%x, vendor syndrome 0x%x\n",
+                           err_cqe->syndrome, err_cqe->vendor_err_synd);
+               if (opcode == MLX5_CQE_REQ_ERR) {
+                       wq = &(*cur_qp)->sq;
+                       wqe_ctr = be16_to_cpu(cqe64->wqe_counter);
+                       idx = wqe_ctr & (wq->wqe_cnt - 1);
+                       wc->wr_id = wq->wrid[idx];
+                       wq->tail = wq->wqe_head[idx] + 1;
+               } else {
+                       struct mlx5_ib_srq *srq;
+
+                       if ((*cur_qp)->ibqp.srq) {
+                               srq = to_msrq((*cur_qp)->ibqp.srq);
+                               wqe_ctr = be16_to_cpu(cqe64->wqe_counter);
+                               wc->wr_id = srq->wrid[wqe_ctr];
+                               mlx5_ib_free_srq_wqe(srq, wqe_ctr);
+                       } else {
+                               wq = &(*cur_qp)->rq;
+                               wc->wr_id = wq->wrid[wq->tail & (wq->wqe_cnt - 1)];
+                               ++wq->tail;
+                       }
+               }
+               break;
+       }
+
+       return 0;
+}
+
+int mlx5_ib_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc)
+{
+       struct mlx5_ib_cq *cq = to_mcq(ibcq);
+       struct mlx5_ib_qp *cur_qp = NULL;
+       unsigned long flags;
+       int npolled;
+       int err = 0;
+
+       spin_lock_irqsave(&cq->lock, flags);
+
+       for (npolled = 0; npolled < num_entries; npolled++) {
+               err = mlx5_poll_one(cq, &cur_qp, wc + npolled);
+               if (err)
+                       break;
+       }
+
+       if (npolled)
+               mlx5_cq_set_ci(&cq->mcq);
+
+       spin_unlock_irqrestore(&cq->lock, flags);
+
+       if (err == 0 || err == -EAGAIN)
+               return npolled;
+       else
+               return err;
+}
+
+int mlx5_ib_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags flags)
+{
+       mlx5_cq_arm(&to_mcq(ibcq)->mcq,
+                   (flags & IB_CQ_SOLICITED_MASK) == IB_CQ_SOLICITED ?
+                   MLX5_CQ_DB_REQ_NOT_SOL : MLX5_CQ_DB_REQ_NOT,
+                   to_mdev(ibcq->device)->mdev.priv.uuari.uars[0].map,
+                   MLX5_GET_DOORBELL_LOCK(&to_mdev(ibcq->device)->mdev.priv.cq_uar_lock));
+
+       return 0;
+}
+
+static int alloc_cq_buf(struct mlx5_ib_dev *dev, struct mlx5_ib_cq_buf *buf,
+                       int nent, int cqe_size)
+{
+       int err;
+
+       err = mlx5_buf_alloc(&dev->mdev, nent * cqe_size,
+                            PAGE_SIZE * 2, &buf->buf);
+       if (err)
+               return err;
+
+       buf->cqe_size = cqe_size;
+
+       return 0;
+}
+
+static void free_cq_buf(struct mlx5_ib_dev *dev, struct mlx5_ib_cq_buf *buf)
+{
+       mlx5_buf_free(&dev->mdev, &buf->buf);
+}
+
+static int create_cq_user(struct mlx5_ib_dev *dev, struct ib_udata *udata,
+                         struct ib_ucontext *context, struct mlx5_ib_cq *cq,
+                         int entries, struct mlx5_create_cq_mbox_in **cqb,
+                         int *cqe_size, int *index, int *inlen)
+{
+       struct mlx5_ib_create_cq ucmd;
+       int page_shift;
+       int npages;
+       int ncont;
+       int err;
+
+       if (ib_copy_from_udata(&ucmd, udata, sizeof(ucmd)))
+               return -EFAULT;
+
+       if (ucmd.cqe_size != 64 && ucmd.cqe_size != 128)
+               return -EINVAL;
+
+       *cqe_size = ucmd.cqe_size;
+
+       cq->buf.umem = ib_umem_get(context, ucmd.buf_addr,
+                                  entries * ucmd.cqe_size,
+                                  IB_ACCESS_LOCAL_WRITE, 1);
+       if (IS_ERR(cq->buf.umem)) {
+               err = PTR_ERR(cq->buf.umem);
+               return err;
+       }
+
+       err = mlx5_ib_db_map_user(to_mucontext(context), ucmd.db_addr,
+                                 &cq->db);
+       if (err)
+               goto err_umem;
+
+       mlx5_ib_cont_pages(cq->buf.umem, ucmd.buf_addr, &npages, &page_shift,
+                          &ncont, NULL);
+       mlx5_ib_dbg(dev, "addr 0x%llx, size %u, npages %d, page_shift %d, ncont %d\n",
+                   ucmd.buf_addr, entries * ucmd.cqe_size, npages, page_shift, ncont);
+
+       *inlen = sizeof(**cqb) + sizeof(*(*cqb)->pas) * ncont;
+       *cqb = mlx5_vzalloc(*inlen);
+       if (!*cqb) {
+               err = -ENOMEM;
+               goto err_db;
+       }
+       mlx5_ib_populate_pas(dev, cq->buf.umem, page_shift, (*cqb)->pas, 0);
+       (*cqb)->ctx.log_pg_sz = page_shift - PAGE_SHIFT;
+
+       *index = to_mucontext(context)->uuari.uars[0].index;
+
+       return 0;
+
+err_db:
+       mlx5_ib_db_unmap_user(to_mucontext(context), &cq->db);
+
+err_umem:
+       ib_umem_release(cq->buf.umem);
+       return err;
+}
+
+static void destroy_cq_user(struct mlx5_ib_cq *cq, struct ib_ucontext *context)
+{
+       mlx5_ib_db_unmap_user(to_mucontext(context), &cq->db);
+       ib_umem_release(cq->buf.umem);
+}
+
+static void init_cq_buf(struct mlx5_ib_cq *cq, int nent)
+{
+       int i;
+       void *cqe;
+       struct mlx5_cqe64 *cqe64;
+
+       for (i = 0; i < nent; i++) {
+               cqe = get_cqe(cq, i);
+               cqe64 = (cq->buf.cqe_size == 64) ? cqe : cqe + 64;
+               cqe64->op_own = 0xf1;
+       }
+}
+
+static int create_cq_kernel(struct mlx5_ib_dev *dev, struct mlx5_ib_cq *cq,
+                           int entries, int cqe_size,
+                           struct mlx5_create_cq_mbox_in **cqb,
+                           int *index, int *inlen)
+{
+       int err;
+
+       err = mlx5_db_alloc(&dev->mdev, &cq->db);
+       if (err)
+               return err;
+
+       cq->mcq.set_ci_db  = cq->db.db;
+       cq->mcq.arm_db     = cq->db.db + 1;
+       *cq->mcq.set_ci_db = 0;
+       *cq->mcq.arm_db    = 0;
+       cq->mcq.cqe_sz = cqe_size;
+
+       err = alloc_cq_buf(dev, &cq->buf, entries, cqe_size);
+       if (err)
+               goto err_db;
+
+       init_cq_buf(cq, entries);
+
+       *inlen = sizeof(**cqb) + sizeof(*(*cqb)->pas) * cq->buf.buf.npages;
+       *cqb = mlx5_vzalloc(*inlen);
+       if (!*cqb) {
+               err = -ENOMEM;
+               goto err_buf;
+       }
+       mlx5_fill_page_array(&cq->buf.buf, (*cqb)->pas);
+
+       (*cqb)->ctx.log_pg_sz = cq->buf.buf.page_shift - PAGE_SHIFT;
+       *index = dev->mdev.priv.uuari.uars[0].index;
+
+       return 0;
+
+err_buf:
+       free_cq_buf(dev, &cq->buf);
+
+err_db:
+       mlx5_db_free(&dev->mdev, &cq->db);
+       return err;
+}
+
+static void destroy_cq_kernel(struct mlx5_ib_dev *dev, struct mlx5_ib_cq *cq)
+{
+       free_cq_buf(dev, &cq->buf);
+       mlx5_db_free(&dev->mdev, &cq->db);
+}
+
+struct ib_cq *mlx5_ib_create_cq(struct ib_device *ibdev, int entries,
+                               int vector, struct ib_ucontext *context,
+                               struct ib_udata *udata)
+{
+       struct mlx5_create_cq_mbox_in *cqb = NULL;
+       struct mlx5_ib_dev *dev = to_mdev(ibdev);
+       struct mlx5_ib_cq *cq;
+       int uninitialized_var(index);
+       int uninitialized_var(inlen);
+       int cqe_size;
+       int irqn;
+       int eqn;
+       int err;
+
+       entries = roundup_pow_of_two(entries + 1);
+       if (entries < 1 || entries > dev->mdev.caps.max_cqes)
+               return ERR_PTR(-EINVAL);
+
+       cq = kzalloc(sizeof(*cq), GFP_KERNEL);
+       if (!cq)
+               return ERR_PTR(-ENOMEM);
+
+       cq->ibcq.cqe = entries - 1;
+       mutex_init(&cq->resize_mutex);
+       spin_lock_init(&cq->lock);
+       cq->resize_buf = NULL;
+       cq->resize_umem = NULL;
+
+       if (context) {
+               err = create_cq_user(dev, udata, context, cq, entries,
+                                    &cqb, &cqe_size, &index, &inlen);
+               if (err)
+                       goto err_create;
+       } else {
+               /* for now choose 64 bytes till we have a proper interface */
+               cqe_size = 64;
+               err = create_cq_kernel(dev, cq, entries, cqe_size, &cqb,
+                                      &index, &inlen);
+               if (err)
+                       goto err_create;
+       }
+
+       cq->cqe_size = cqe_size;
+       cqb->ctx.cqe_sz_flags = cqe_sz_to_mlx_sz(cqe_size) << 5;
+       cqb->ctx.log_sz_usr_page = cpu_to_be32((ilog2(entries) << 24) | index);
+       err = mlx5_vector2eqn(dev, vector, &eqn, &irqn);
+       if (err)
+               goto err_cqb;
+
+       cqb->ctx.c_eqn = cpu_to_be16(eqn);
+       cqb->ctx.db_record_addr = cpu_to_be64(cq->db.dma);
+
+       err = mlx5_core_create_cq(&dev->mdev, &cq->mcq, cqb, inlen);
+       if (err)
+               goto err_cqb;
+
+       mlx5_ib_dbg(dev, "cqn 0x%x\n", cq->mcq.cqn);
+       cq->mcq.irqn = irqn;
+       cq->mcq.comp  = mlx5_ib_cq_comp;
+       cq->mcq.event = mlx5_ib_cq_event;
+
+       if (context)
+               if (ib_copy_to_udata(udata, &cq->mcq.cqn, sizeof(__u32))) {
+                       err = -EFAULT;
+                       goto err_cmd;
+               }
+
+
+       mlx5_vfree(cqb);
+       return &cq->ibcq;
+
+err_cmd:
+       mlx5_core_destroy_cq(&dev->mdev, &cq->mcq);
+
+err_cqb:
+       mlx5_vfree(cqb);
+       if (context)
+               destroy_cq_user(cq, context);
+       else
+               destroy_cq_kernel(dev, cq);
+
+err_create:
+       kfree(cq);
+
+       return ERR_PTR(err);
+}
+
+
+int mlx5_ib_destroy_cq(struct ib_cq *cq)
+{
+       struct mlx5_ib_dev *dev = to_mdev(cq->device);
+       struct mlx5_ib_cq *mcq = to_mcq(cq);
+       struct ib_ucontext *context = NULL;
+
+       if (cq->uobject)
+               context = cq->uobject->context;
+
+       mlx5_core_destroy_cq(&dev->mdev, &mcq->mcq);
+       if (context)
+               destroy_cq_user(mcq, context);
+       else
+               destroy_cq_kernel(dev, mcq);
+
+       kfree(mcq);
+
+       return 0;
+}
+
+static int is_equal_rsn(struct mlx5_cqe64 *cqe64, struct mlx5_ib_srq *srq,
+                       u32 rsn)
+{
+       u32 lrsn;
+
+       if (srq)
+               lrsn = be32_to_cpu(cqe64->srqn) & 0xffffff;
+       else
+               lrsn = be32_to_cpu(cqe64->sop_drop_qpn) & 0xffffff;
+
+       return rsn == lrsn;
+}
+
+void __mlx5_ib_cq_clean(struct mlx5_ib_cq *cq, u32 rsn, struct mlx5_ib_srq *srq)
+{
+       struct mlx5_cqe64 *cqe64, *dest64;
+       void *cqe, *dest;
+       u32 prod_index;
+       int nfreed = 0;
+       u8 owner_bit;
+
+       if (!cq)
+               return;
+
+       /* First we need to find the current producer index, so we
+        * know where to start cleaning from.  It doesn't matter if HW
+        * adds new entries after this loop -- the QP we're worried
+        * about is already in RESET, so the new entries won't come
+        * from our QP and therefore don't need to be checked.
+        */
+       for (prod_index = cq->mcq.cons_index; get_sw_cqe(cq, prod_index); prod_index++)
+               if (prod_index == cq->mcq.cons_index + cq->ibcq.cqe)
+                       break;
+
+       /* Now sweep backwards through the CQ, removing CQ entries
+        * that match our QP by copying older entries on top of them.
+        */
+       while ((int) --prod_index - (int) cq->mcq.cons_index >= 0) {
+               cqe = get_cqe(cq, prod_index & cq->ibcq.cqe);
+               cqe64 = (cq->mcq.cqe_sz == 64) ? cqe : cqe + 64;
+               if (is_equal_rsn(cqe64, srq, rsn)) {
+                       if (srq)
+                               mlx5_ib_free_srq_wqe(srq, be16_to_cpu(cqe64->wqe_counter));
+                       ++nfreed;
+               } else if (nfreed) {
+                       dest = get_cqe(cq, (prod_index + nfreed) & cq->ibcq.cqe);
+                       dest64 = (cq->mcq.cqe_sz == 64) ? dest : dest + 64;
+                       owner_bit = dest64->op_own & MLX5_CQE_OWNER_MASK;
+                       memcpy(dest, cqe, cq->mcq.cqe_sz);
+                       dest64->op_own = owner_bit |
+                               (dest64->op_own & ~MLX5_CQE_OWNER_MASK);
+               }
+       }
+
+       if (nfreed) {
+               cq->mcq.cons_index += nfreed;
+               /* Make sure update of buffer contents is done before
+                * updating consumer index.
+                */
+               wmb();
+               mlx5_cq_set_ci(&cq->mcq);
+       }
+}
+
+void mlx5_ib_cq_clean(struct mlx5_ib_cq *cq, u32 qpn, struct mlx5_ib_srq *srq)
+{
+       if (!cq)
+               return;
+
+       spin_lock_irq(&cq->lock);
+       __mlx5_ib_cq_clean(cq, qpn, srq);
+       spin_unlock_irq(&cq->lock);
+}
+
+int mlx5_ib_modify_cq(struct ib_cq *cq, u16 cq_count, u16 cq_period)
+{
+       return -ENOSYS;
+}
+
+int mlx5_ib_resize_cq(struct ib_cq *ibcq, int entries, struct ib_udata *udata)
+{
+       return -ENOSYS;
+}
+
+int mlx5_ib_get_cqe_size(struct mlx5_ib_dev *dev, struct ib_cq *ibcq)
+{
+       struct mlx5_ib_cq *cq;
+
+       if (!ibcq)
+               return 128;
+
+       cq = to_mcq(ibcq);
+       return cq->cqe_size;
+}
diff --git a/drivers/infiniband/hw/mlx5/doorbell.c b/drivers/infiniband/hw/mlx5/doorbell.c
new file mode 100644 (file)
index 0000000..256a233
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2013, Mellanox Technologies inc.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/kref.h>
+#include <linux/slab.h>
+#include <rdma/ib_umem.h>
+
+#include "mlx5_ib.h"
+
+struct mlx5_ib_user_db_page {
+       struct list_head        list;
+       struct ib_umem         *umem;
+       unsigned long           user_virt;
+       int                     refcnt;
+};
+
+int mlx5_ib_db_map_user(struct mlx5_ib_ucontext *context, unsigned long virt,
+                       struct mlx5_db *db)
+{
+       struct mlx5_ib_user_db_page *page;
+       struct ib_umem_chunk *chunk;
+       int err = 0;
+
+       mutex_lock(&context->db_page_mutex);
+
+       list_for_each_entry(page, &context->db_page_list, list)
+               if (page->user_virt == (virt & PAGE_MASK))
+                       goto found;
+
+       page = kmalloc(sizeof(*page), GFP_KERNEL);
+       if (!page) {
+               err = -ENOMEM;
+               goto out;
+       }
+
+       page->user_virt = (virt & PAGE_MASK);
+       page->refcnt    = 0;
+       page->umem      = ib_umem_get(&context->ibucontext, virt & PAGE_MASK,
+                                     PAGE_SIZE, 0, 0);
+       if (IS_ERR(page->umem)) {
+               err = PTR_ERR(page->umem);
+               kfree(page);
+               goto out;
+       }
+
+       list_add(&page->list, &context->db_page_list);
+
+found:
+       chunk = list_entry(page->umem->chunk_list.next, struct ib_umem_chunk, list);
+       db->dma         = sg_dma_address(chunk->page_list) + (virt & ~PAGE_MASK);
+       db->u.user_page = page;
+       ++page->refcnt;
+
+out:
+       mutex_unlock(&context->db_page_mutex);
+
+       return err;
+}
+
+void mlx5_ib_db_unmap_user(struct mlx5_ib_ucontext *context, struct mlx5_db *db)
+{
+       mutex_lock(&context->db_page_mutex);
+
+       if (!--db->u.user_page->refcnt) {
+               list_del(&db->u.user_page->list);
+               ib_umem_release(db->u.user_page->umem);
+               kfree(db->u.user_page);
+       }
+
+       mutex_unlock(&context->db_page_mutex);
+}
diff --git a/drivers/infiniband/hw/mlx5/mad.c b/drivers/infiniband/hw/mlx5/mad.c
new file mode 100644 (file)
index 0000000..5c8938b
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2013, Mellanox Technologies inc.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/mlx5/cmd.h>
+#include <rdma/ib_mad.h>
+#include <rdma/ib_smi.h>
+#include "mlx5_ib.h"
+
+enum {
+       MLX5_IB_VENDOR_CLASS1 = 0x9,
+       MLX5_IB_VENDOR_CLASS2 = 0xa
+};
+
+int mlx5_MAD_IFC(struct mlx5_ib_dev *dev, int ignore_mkey, int ignore_bkey,
+                int port, struct ib_wc *in_wc, struct ib_grh *in_grh,
+                void *in_mad, void *response_mad)
+{
+       u8 op_modifier = 0;
+
+       /* Key check traps can't be generated unless we have in_wc to
+        * tell us where to send the trap.
+        */
+       if (ignore_mkey || !in_wc)
+               op_modifier |= 0x1;
+       if (ignore_bkey || !in_wc)
+               op_modifier |= 0x2;
+
+       return mlx5_core_mad_ifc(&dev->mdev, in_mad, response_mad, op_modifier, port);
+}
+
+int mlx5_ib_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num,
+                       struct ib_wc *in_wc, struct ib_grh *in_grh,
+                       struct ib_mad *in_mad, struct ib_mad *out_mad)
+{
+       u16 slid;
+       int err;
+
+       slid = in_wc ? in_wc->slid : be16_to_cpu(IB_LID_PERMISSIVE);
+
+       if (in_mad->mad_hdr.method == IB_MGMT_METHOD_TRAP && slid == 0)
+               return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_CONSUMED;
+
+       if (in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED ||
+           in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) {
+               if (in_mad->mad_hdr.method   != IB_MGMT_METHOD_GET &&
+                   in_mad->mad_hdr.method   != IB_MGMT_METHOD_SET &&
+                   in_mad->mad_hdr.method   != IB_MGMT_METHOD_TRAP_REPRESS)
+                       return IB_MAD_RESULT_SUCCESS;
+
+               /* Don't process SMInfo queries -- the SMA can't handle them.
+                */
+               if (in_mad->mad_hdr.attr_id == IB_SMP_ATTR_SM_INFO)
+                       return IB_MAD_RESULT_SUCCESS;
+       } else if (in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_PERF_MGMT ||
+                  in_mad->mad_hdr.mgmt_class == MLX5_IB_VENDOR_CLASS1   ||
+                  in_mad->mad_hdr.mgmt_class == MLX5_IB_VENDOR_CLASS2   ||
+                  in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_CONG_MGMT) {
+               if (in_mad->mad_hdr.method  != IB_MGMT_METHOD_GET &&
+                   in_mad->mad_hdr.method  != IB_MGMT_METHOD_SET)
+                       return IB_MAD_RESULT_SUCCESS;
+       } else {
+               return IB_MAD_RESULT_SUCCESS;
+       }
+
+       err = mlx5_MAD_IFC(to_mdev(ibdev),
+                          mad_flags & IB_MAD_IGNORE_MKEY,
+                          mad_flags & IB_MAD_IGNORE_BKEY,
+                          port_num, in_wc, in_grh, in_mad, out_mad);
+       if (err)
+               return IB_MAD_RESULT_FAILURE;
+
+       /* set return bit in status of directed route responses */
+       if (in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE)
+               out_mad->mad_hdr.status |= cpu_to_be16(1 << 15);
+
+       if (in_mad->mad_hdr.method == IB_MGMT_METHOD_TRAP_REPRESS)
+               /* no response for trap repress */
+               return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_CONSUMED;
+
+       return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_REPLY;
+}
+
+int mlx5_query_ext_port_caps(struct mlx5_ib_dev *dev, u8 port)
+{
+       struct ib_smp *in_mad  = NULL;
+       struct ib_smp *out_mad = NULL;
+       int err = -ENOMEM;
+       u16 packet_error;
+
+       in_mad  = kzalloc(sizeof(*in_mad), GFP_KERNEL);
+       out_mad = kmalloc(sizeof(*out_mad), GFP_KERNEL);
+       if (!in_mad || !out_mad)
+               goto out;
+
+       init_query_mad(in_mad);
+       in_mad->attr_id = MLX5_ATTR_EXTENDED_PORT_INFO;
+       in_mad->attr_mod = cpu_to_be32(port);
+
+       err = mlx5_MAD_IFC(dev, 1, 1, 1, NULL, NULL, in_mad, out_mad);
+
+       packet_error = be16_to_cpu(out_mad->status);
+
+       dev->mdev.caps.ext_port_cap[port - 1] = (!err && !packet_error) ?
+               MLX_EXT_PORT_CAP_FLAG_EXTENDED_PORT_INFO : 0;
+
+out:
+       kfree(in_mad);
+       kfree(out_mad);
+       return err;
+}
diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c
new file mode 100644 (file)
index 0000000..8000fff
--- /dev/null
@@ -0,0 +1,1504 @@
+/*
+ * Copyright (c) 2013, Mellanox Technologies inc.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <asm-generic/kmap_types.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <linux/io-mapping.h>
+#include <linux/sched.h>
+#include <rdma/ib_user_verbs.h>
+#include <rdma/ib_smi.h>
+#include <rdma/ib_umem.h>
+#include "user.h"
+#include "mlx5_ib.h"
+
+#define DRIVER_NAME "mlx5_ib"
+#define DRIVER_VERSION "1.0"
+#define DRIVER_RELDATE "June 2013"
+
+MODULE_AUTHOR("Eli Cohen <eli@mellanox.com>");
+MODULE_DESCRIPTION("Mellanox Connect-IB HCA IB driver");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_VERSION(DRIVER_VERSION);
+
+static int prof_sel = 2;
+module_param_named(prof_sel, prof_sel, int, 0444);
+MODULE_PARM_DESC(prof_sel, "profile selector. Valid range 0 - 2");
+
+static char mlx5_version[] =
+       DRIVER_NAME ": Mellanox Connect-IB Infiniband driver v"
+       DRIVER_VERSION " (" DRIVER_RELDATE ")\n";
+
+static struct mlx5_profile profile[] = {
+       [0] = {
+               .mask           = 0,
+       },
+       [1] = {
+               .mask           = MLX5_PROF_MASK_QP_SIZE,
+               .log_max_qp     = 12,
+       },
+       [2] = {
+               .mask           = MLX5_PROF_MASK_QP_SIZE |
+                                 MLX5_PROF_MASK_MR_CACHE,
+               .log_max_qp     = 17,
+               .mr_cache[0]    = {
+                       .size   = 500,
+                       .limit  = 250
+               },
+               .mr_cache[1]    = {
+                       .size   = 500,
+                       .limit  = 250
+               },
+               .mr_cache[2]    = {
+                       .size   = 500,
+                       .limit  = 250
+               },
+               .mr_cache[3]    = {
+                       .size   = 500,
+                       .limit  = 250
+               },
+               .mr_cache[4]    = {
+                       .size   = 500,
+                       .limit  = 250
+               },
+               .mr_cache[5]    = {
+                       .size   = 500,
+                       .limit  = 250
+               },
+               .mr_cache[6]    = {
+                       .size   = 500,
+                       .limit  = 250
+               },
+               .mr_cache[7]    = {
+                       .size   = 500,
+                       .limit  = 250
+               },
+               .mr_cache[8]    = {
+                       .size   = 500,
+                       .limit  = 250
+               },
+               .mr_cache[9]    = {
+                       .size   = 500,
+                       .limit  = 250
+               },
+               .mr_cache[10]   = {
+                       .size   = 500,
+                       .limit  = 250
+               },
+               .mr_cache[11]   = {
+                       .size   = 500,
+                       .limit  = 250
+               },
+               .mr_cache[12]   = {
+                       .size   = 64,
+                       .limit  = 32
+               },
+               .mr_cache[13]   = {
+                       .size   = 32,
+                       .limit  = 16
+               },
+               .mr_cache[14]   = {
+                       .size   = 16,
+                       .limit  = 8
+               },
+               .mr_cache[15]   = {
+                       .size   = 8,
+                       .limit  = 4
+               },
+       },
+};
+
+int mlx5_vector2eqn(struct mlx5_ib_dev *dev, int vector, int *eqn, int *irqn)
+{
+       struct mlx5_eq_table *table = &dev->mdev.priv.eq_table;
+       struct mlx5_eq *eq, *n;
+       int err = -ENOENT;
+
+       spin_lock(&table->lock);
+       list_for_each_entry_safe(eq, n, &dev->eqs_list, list) {
+               if (eq->index == vector) {
+                       *eqn = eq->eqn;
+                       *irqn = eq->irqn;
+                       err = 0;
+                       break;
+               }
+       }
+       spin_unlock(&table->lock);
+
+       return err;
+}
+
+static int alloc_comp_eqs(struct mlx5_ib_dev *dev)
+{
+       struct mlx5_eq_table *table = &dev->mdev.priv.eq_table;
+       struct mlx5_eq *eq, *n;
+       int ncomp_vec;
+       int nent;
+       int err;
+       int i;
+
+       INIT_LIST_HEAD(&dev->eqs_list);
+       ncomp_vec = table->num_comp_vectors;
+       nent = MLX5_COMP_EQ_SIZE;
+       for (i = 0; i < ncomp_vec; i++) {
+               eq = kzalloc(sizeof(*eq), GFP_KERNEL);
+               if (!eq) {
+                       err = -ENOMEM;
+                       goto clean;
+               }
+
+               snprintf(eq->name, MLX5_MAX_EQ_NAME, "mlx5_comp%d", i);
+               err = mlx5_create_map_eq(&dev->mdev, eq,
+                                        i + MLX5_EQ_VEC_COMP_BASE, nent, 0,
+                                        eq->name,
+                                        &dev->mdev.priv.uuari.uars[0]);
+               if (err) {
+                       kfree(eq);
+                       goto clean;
+               }
+               mlx5_ib_dbg(dev, "allocated completion EQN %d\n", eq->eqn);
+               eq->index = i;
+               spin_lock(&table->lock);
+               list_add_tail(&eq->list, &dev->eqs_list);
+               spin_unlock(&table->lock);
+       }
+
+       dev->num_comp_vectors = ncomp_vec;
+       return 0;
+
+clean:
+       spin_lock(&table->lock);
+       list_for_each_entry_safe(eq, n, &dev->eqs_list, list) {
+               list_del(&eq->list);
+               spin_unlock(&table->lock);
+               if (mlx5_destroy_unmap_eq(&dev->mdev, eq))
+                       mlx5_ib_warn(dev, "failed to destroy EQ 0x%x\n", eq->eqn);
+               kfree(eq);
+               spin_lock(&table->lock);
+       }
+       spin_unlock(&table->lock);
+       return err;
+}
+
+static void free_comp_eqs(struct mlx5_ib_dev *dev)
+{
+       struct mlx5_eq_table *table = &dev->mdev.priv.eq_table;
+       struct mlx5_eq *eq, *n;
+
+       spin_lock(&table->lock);
+       list_for_each_entry_safe(eq, n, &dev->eqs_list, list) {
+               list_del(&eq->list);
+               spin_unlock(&table->lock);
+               if (mlx5_destroy_unmap_eq(&dev->mdev, eq))
+                       mlx5_ib_warn(dev, "failed to destroy EQ 0x%x\n", eq->eqn);
+               kfree(eq);
+               spin_lock(&table->lock);
+       }
+       spin_unlock(&table->lock);
+}
+
+static int mlx5_ib_query_device(struct ib_device *ibdev,
+                               struct ib_device_attr *props)
+{
+       struct mlx5_ib_dev *dev = to_mdev(ibdev);
+       struct ib_smp *in_mad  = NULL;
+       struct ib_smp *out_mad = NULL;
+       int err = -ENOMEM;
+       int max_rq_sg;
+       int max_sq_sg;
+       u64 flags;
+
+       in_mad  = kzalloc(sizeof(*in_mad), GFP_KERNEL);
+       out_mad = kmalloc(sizeof(*out_mad), GFP_KERNEL);
+       if (!in_mad || !out_mad)
+               goto out;
+
+       init_query_mad(in_mad);
+       in_mad->attr_id = IB_SMP_ATTR_NODE_INFO;
+
+       err = mlx5_MAD_IFC(to_mdev(ibdev), 1, 1, 1, NULL, NULL, in_mad, out_mad);
+       if (err)
+               goto out;
+
+       memset(props, 0, sizeof(*props));
+
+       props->fw_ver = ((u64)fw_rev_maj(&dev->mdev) << 32) |
+               (fw_rev_min(&dev->mdev) << 16) |
+               fw_rev_sub(&dev->mdev);
+       props->device_cap_flags    = IB_DEVICE_CHANGE_PHY_PORT |
+               IB_DEVICE_PORT_ACTIVE_EVENT             |
+               IB_DEVICE_SYS_IMAGE_GUID                |
+               IB_DEVICE_RC_RNR_NAK_GEN                |
+               IB_DEVICE_BLOCK_MULTICAST_LOOPBACK;
+       flags = dev->mdev.caps.flags;
+       if (flags & MLX5_DEV_CAP_FLAG_BAD_PKEY_CNTR)
+               props->device_cap_flags |= IB_DEVICE_BAD_PKEY_CNTR;
+       if (flags & MLX5_DEV_CAP_FLAG_BAD_QKEY_CNTR)
+               props->device_cap_flags |= IB_DEVICE_BAD_QKEY_CNTR;
+       if (flags & MLX5_DEV_CAP_FLAG_APM)
+               props->device_cap_flags |= IB_DEVICE_AUTO_PATH_MIG;
+       props->device_cap_flags |= IB_DEVICE_LOCAL_DMA_LKEY;
+       if (flags & MLX5_DEV_CAP_FLAG_XRC)
+               props->device_cap_flags |= IB_DEVICE_XRC;
+       props->device_cap_flags |= IB_DEVICE_MEM_MGT_EXTENSIONS;
+
+       props->vendor_id           = be32_to_cpup((__be32 *)(out_mad->data + 36)) &
+               0xffffff;
+       props->vendor_part_id      = be16_to_cpup((__be16 *)(out_mad->data + 30));
+       props->hw_ver              = be32_to_cpup((__be32 *)(out_mad->data + 32));
+       memcpy(&props->sys_image_guid, out_mad->data +  4, 8);
+
+       props->max_mr_size         = ~0ull;
+       props->page_size_cap       = dev->mdev.caps.min_page_sz;
+       props->max_qp              = 1 << dev->mdev.caps.log_max_qp;
+       props->max_qp_wr           = dev->mdev.caps.max_wqes;
+       max_rq_sg = dev->mdev.caps.max_rq_desc_sz / sizeof(struct mlx5_wqe_data_seg);
+       max_sq_sg = (dev->mdev.caps.max_sq_desc_sz - sizeof(struct mlx5_wqe_ctrl_seg)) /
+               sizeof(struct mlx5_wqe_data_seg);
+       props->max_sge = min(max_rq_sg, max_sq_sg);
+       props->max_cq              = 1 << dev->mdev.caps.log_max_cq;
+       props->max_cqe             = dev->mdev.caps.max_cqes - 1;
+       props->max_mr              = 1 << dev->mdev.caps.log_max_mkey;
+       props->max_pd              = 1 << dev->mdev.caps.log_max_pd;
+       props->max_qp_rd_atom      = dev->mdev.caps.max_ra_req_qp;
+       props->max_qp_init_rd_atom = dev->mdev.caps.max_ra_res_qp;
+       props->max_res_rd_atom     = props->max_qp_rd_atom * props->max_qp;
+       props->max_srq             = 1 << dev->mdev.caps.log_max_srq;
+       props->max_srq_wr          = dev->mdev.caps.max_srq_wqes - 1;
+       props->max_srq_sge         = max_rq_sg - 1;
+       props->max_fast_reg_page_list_len = (unsigned int)-1;
+       props->local_ca_ack_delay  = dev->mdev.caps.local_ca_ack_delay;
+       props->atomic_cap          = dev->mdev.caps.flags & MLX5_DEV_CAP_FLAG_ATOMIC ?
+               IB_ATOMIC_HCA : IB_ATOMIC_NONE;
+       props->masked_atomic_cap   = IB_ATOMIC_HCA;
+       props->max_pkeys           = be16_to_cpup((__be16 *)(out_mad->data + 28));
+       props->max_mcast_grp       = 1 << dev->mdev.caps.log_max_mcg;
+       props->max_mcast_qp_attach = dev->mdev.caps.max_qp_mcg;
+       props->max_total_mcast_qp_attach = props->max_mcast_qp_attach *
+                                          props->max_mcast_grp;
+       props->max_map_per_fmr = INT_MAX; /* no limit in ConnectIB */
+
+out:
+       kfree(in_mad);
+       kfree(out_mad);
+
+       return err;
+}
+
+int mlx5_ib_query_port(struct ib_device *ibdev, u8 port,
+                      struct ib_port_attr *props)
+{
+       struct mlx5_ib_dev *dev = to_mdev(ibdev);
+       struct ib_smp *in_mad  = NULL;
+       struct ib_smp *out_mad = NULL;
+       int ext_active_speed;
+       int err = -ENOMEM;
+
+       if (port < 1 || port > dev->mdev.caps.num_ports) {
+               mlx5_ib_warn(dev, "invalid port number %d\n", port);
+               return -EINVAL;
+       }
+
+       in_mad  = kzalloc(sizeof(*in_mad), GFP_KERNEL);
+       out_mad = kmalloc(sizeof(*out_mad), GFP_KERNEL);
+       if (!in_mad || !out_mad)
+               goto out;
+
+       memset(props, 0, sizeof(*props));
+
+       init_query_mad(in_mad);
+       in_mad->attr_id  = IB_SMP_ATTR_PORT_INFO;
+       in_mad->attr_mod = cpu_to_be32(port);
+
+       err = mlx5_MAD_IFC(dev, 1, 1, port, NULL, NULL, in_mad, out_mad);
+       if (err) {
+               mlx5_ib_warn(dev, "err %d\n", err);
+               goto out;
+       }
+
+
+       props->lid              = be16_to_cpup((__be16 *)(out_mad->data + 16));
+       props->lmc              = out_mad->data[34] & 0x7;
+       props->sm_lid           = be16_to_cpup((__be16 *)(out_mad->data + 18));
+       props->sm_sl            = out_mad->data[36] & 0xf;
+       props->state            = out_mad->data[32] & 0xf;
+       props->phys_state       = out_mad->data[33] >> 4;
+       props->port_cap_flags   = be32_to_cpup((__be32 *)(out_mad->data + 20));
+       props->gid_tbl_len      = out_mad->data[50];
+       props->max_msg_sz       = 1 << to_mdev(ibdev)->mdev.caps.log_max_msg;
+       props->pkey_tbl_len     = to_mdev(ibdev)->mdev.caps.port[port - 1].pkey_table_len;
+       props->bad_pkey_cntr    = be16_to_cpup((__be16 *)(out_mad->data + 46));
+       props->qkey_viol_cntr   = be16_to_cpup((__be16 *)(out_mad->data + 48));
+       props->active_width     = out_mad->data[31] & 0xf;
+       props->active_speed     = out_mad->data[35] >> 4;
+       props->max_mtu          = out_mad->data[41] & 0xf;
+       props->active_mtu       = out_mad->data[36] >> 4;
+       props->subnet_timeout   = out_mad->data[51] & 0x1f;
+       props->max_vl_num       = out_mad->data[37] >> 4;
+       props->init_type_reply  = out_mad->data[41] >> 4;
+
+       /* Check if extended speeds (EDR/FDR/...) are supported */
+       if (props->port_cap_flags & IB_PORT_EXTENDED_SPEEDS_SUP) {
+               ext_active_speed = out_mad->data[62] >> 4;
+
+               switch (ext_active_speed) {
+               case 1:
+                       props->active_speed = 16; /* FDR */
+                       break;
+               case 2:
+                       props->active_speed = 32; /* EDR */
+                       break;
+               }
+       }
+
+       /* If reported active speed is QDR, check if is FDR-10 */
+       if (props->active_speed == 4) {
+               if (dev->mdev.caps.ext_port_cap[port - 1] &
+                   MLX_EXT_PORT_CAP_FLAG_EXTENDED_PORT_INFO) {
+                       init_query_mad(in_mad);
+                       in_mad->attr_id = MLX5_ATTR_EXTENDED_PORT_INFO;
+                       in_mad->attr_mod = cpu_to_be32(port);
+
+                       err = mlx5_MAD_IFC(dev, 1, 1, port,
+                                          NULL, NULL, in_mad, out_mad);
+                       if (err)
+                               goto out;
+
+                       /* Checking LinkSpeedActive for FDR-10 */
+                       if (out_mad->data[15] & 0x1)
+                               props->active_speed = 8;
+               }
+       }
+
+out:
+       kfree(in_mad);
+       kfree(out_mad);
+
+       return err;
+}
+
+static int mlx5_ib_query_gid(struct ib_device *ibdev, u8 port, int index,
+                            union ib_gid *gid)
+{
+       struct ib_smp *in_mad  = NULL;
+       struct ib_smp *out_mad = NULL;
+       int err = -ENOMEM;
+
+       in_mad  = kzalloc(sizeof(*in_mad), GFP_KERNEL);
+       out_mad = kmalloc(sizeof(*out_mad), GFP_KERNEL);
+       if (!in_mad || !out_mad)
+               goto out;
+
+       init_query_mad(in_mad);
+       in_mad->attr_id  = IB_SMP_ATTR_PORT_INFO;
+       in_mad->attr_mod = cpu_to_be32(port);
+
+       err = mlx5_MAD_IFC(to_mdev(ibdev), 1, 1, port, NULL, NULL, in_mad, out_mad);
+       if (err)
+               goto out;
+
+       memcpy(gid->raw, out_mad->data + 8, 8);
+
+       init_query_mad(in_mad);
+       in_mad->attr_id  = IB_SMP_ATTR_GUID_INFO;
+       in_mad->attr_mod = cpu_to_be32(index / 8);
+
+       err = mlx5_MAD_IFC(to_mdev(ibdev), 1, 1, port, NULL, NULL, in_mad, out_mad);
+       if (err)
+               goto out;
+
+       memcpy(gid->raw + 8, out_mad->data + (index % 8) * 8, 8);
+
+out:
+       kfree(in_mad);
+       kfree(out_mad);
+       return err;
+}
+
+static int mlx5_ib_query_pkey(struct ib_device *ibdev, u8 port, u16 index,
+                             u16 *pkey)
+{
+       struct ib_smp *in_mad  = NULL;
+       struct ib_smp *out_mad = NULL;
+       int err = -ENOMEM;
+
+       in_mad  = kzalloc(sizeof(*in_mad), GFP_KERNEL);
+       out_mad = kmalloc(sizeof(*out_mad), GFP_KERNEL);
+       if (!in_mad || !out_mad)
+               goto out;
+
+       init_query_mad(in_mad);
+       in_mad->attr_id  = IB_SMP_ATTR_PKEY_TABLE;
+       in_mad->attr_mod = cpu_to_be32(index / 32);
+
+       err = mlx5_MAD_IFC(to_mdev(ibdev), 1, 1, port, NULL, NULL, in_mad, out_mad);
+       if (err)
+               goto out;
+
+       *pkey = be16_to_cpu(((__be16 *)out_mad->data)[index % 32]);
+
+out:
+       kfree(in_mad);
+       kfree(out_mad);
+       return err;
+}
+
+struct mlx5_reg_node_desc {
+       u8      desc[64];
+};
+
+static int mlx5_ib_modify_device(struct ib_device *ibdev, int mask,
+                                struct ib_device_modify *props)
+{
+       struct mlx5_ib_dev *dev = to_mdev(ibdev);
+       struct mlx5_reg_node_desc in;
+       struct mlx5_reg_node_desc out;
+       int err;
+
+       if (mask & ~IB_DEVICE_MODIFY_NODE_DESC)
+               return -EOPNOTSUPP;
+
+       if (!(mask & IB_DEVICE_MODIFY_NODE_DESC))
+               return 0;
+
+       /*
+        * If possible, pass node desc to FW, so it can generate
+        * a 144 trap.  If cmd fails, just ignore.
+        */
+       memcpy(&in, props->node_desc, 64);
+       err = mlx5_core_access_reg(&dev->mdev, &in, sizeof(in), &out,
+                                  sizeof(out), MLX5_REG_NODE_DESC, 0, 1);
+       if (err)
+               return err;
+
+       memcpy(ibdev->node_desc, props->node_desc, 64);
+
+       return err;
+}
+
+static int mlx5_ib_modify_port(struct ib_device *ibdev, u8 port, int mask,
+                              struct ib_port_modify *props)
+{
+       struct mlx5_ib_dev *dev = to_mdev(ibdev);
+       struct ib_port_attr attr;
+       u32 tmp;
+       int err;
+
+       mutex_lock(&dev->cap_mask_mutex);
+
+       err = mlx5_ib_query_port(ibdev, port, &attr);
+       if (err)
+               goto out;
+
+       tmp = (attr.port_cap_flags | props->set_port_cap_mask) &
+               ~props->clr_port_cap_mask;
+
+       err = mlx5_set_port_caps(&dev->mdev, port, tmp);
+
+out:
+       mutex_unlock(&dev->cap_mask_mutex);
+       return err;
+}
+
+static struct ib_ucontext *mlx5_ib_alloc_ucontext(struct ib_device *ibdev,
+                                                 struct ib_udata *udata)
+{
+       struct mlx5_ib_dev *dev = to_mdev(ibdev);
+       struct mlx5_ib_alloc_ucontext_req req;
+       struct mlx5_ib_alloc_ucontext_resp resp;
+       struct mlx5_ib_ucontext *context;
+       struct mlx5_uuar_info *uuari;
+       struct mlx5_uar *uars;
+       int num_uars;
+       int uuarn;
+       int err;
+       int i;
+
+       if (!dev->ib_active)
+               return ERR_PTR(-EAGAIN);
+
+       err = ib_copy_from_udata(&req, udata, sizeof(req));
+       if (err)
+               return ERR_PTR(err);
+
+       if (req.total_num_uuars > MLX5_MAX_UUARS)
+               return ERR_PTR(-ENOMEM);
+
+       if (req.total_num_uuars == 0)
+               return ERR_PTR(-EINVAL);
+
+       req.total_num_uuars = ALIGN(req.total_num_uuars, MLX5_BF_REGS_PER_PAGE);
+       if (req.num_low_latency_uuars > req.total_num_uuars - 1)
+               return ERR_PTR(-EINVAL);
+
+       num_uars = req.total_num_uuars / MLX5_BF_REGS_PER_PAGE;
+       resp.qp_tab_size      = 1 << dev->mdev.caps.log_max_qp;
+       resp.bf_reg_size      = dev->mdev.caps.bf_reg_size;
+       resp.cache_line_size  = L1_CACHE_BYTES;
+       resp.max_sq_desc_sz = dev->mdev.caps.max_sq_desc_sz;
+       resp.max_rq_desc_sz = dev->mdev.caps.max_rq_desc_sz;
+       resp.max_send_wqebb = dev->mdev.caps.max_wqes;
+       resp.max_recv_wr = dev->mdev.caps.max_wqes;
+       resp.max_srq_recv_wr = dev->mdev.caps.max_srq_wqes;
+
+       context = kzalloc(sizeof(*context), GFP_KERNEL);
+       if (!context)
+               return ERR_PTR(-ENOMEM);
+
+       uuari = &context->uuari;
+       mutex_init(&uuari->lock);
+       uars = kcalloc(num_uars, sizeof(*uars), GFP_KERNEL);
+       if (!uars) {
+               err = -ENOMEM;
+               goto out_ctx;
+       }
+
+       uuari->bitmap = kcalloc(BITS_TO_LONGS(req.total_num_uuars),
+                               sizeof(*uuari->bitmap),
+                               GFP_KERNEL);
+       if (!uuari->bitmap) {
+               err = -ENOMEM;
+               goto out_uar_ctx;
+       }
+       /*
+        * clear all fast path uuars
+        */
+       for (i = 0; i < req.total_num_uuars; i++) {
+               uuarn = i & 3;
+               if (uuarn == 2 || uuarn == 3)
+                       set_bit(i, uuari->bitmap);
+       }
+
+       uuari->count = kcalloc(req.total_num_uuars, sizeof(*uuari->count), GFP_KERNEL);
+       if (!uuari->count) {
+               err = -ENOMEM;
+               goto out_bitmap;
+       }
+
+       for (i = 0; i < num_uars; i++) {
+               err = mlx5_cmd_alloc_uar(&dev->mdev, &uars[i].index);
+               if (err)
+                       goto out_count;
+       }
+
+       INIT_LIST_HEAD(&context->db_page_list);
+       mutex_init(&context->db_page_mutex);
+
+       resp.tot_uuars = req.total_num_uuars;
+       resp.num_ports = dev->mdev.caps.num_ports;
+       err = ib_copy_to_udata(udata, &resp, sizeof(resp));
+       if (err)
+               goto out_uars;
+
+       uuari->num_low_latency_uuars = req.num_low_latency_uuars;
+       uuari->uars = uars;
+       uuari->num_uars = num_uars;
+       return &context->ibucontext;
+
+out_uars:
+       for (i--; i >= 0; i--)
+               mlx5_cmd_free_uar(&dev->mdev, uars[i].index);
+out_count:
+       kfree(uuari->count);
+
+out_bitmap:
+       kfree(uuari->bitmap);
+
+out_uar_ctx:
+       kfree(uars);
+
+out_ctx:
+       kfree(context);
+       return ERR_PTR(err);
+}
+
+static int mlx5_ib_dealloc_ucontext(struct ib_ucontext *ibcontext)
+{
+       struct mlx5_ib_ucontext *context = to_mucontext(ibcontext);
+       struct mlx5_ib_dev *dev = to_mdev(ibcontext->device);
+       struct mlx5_uuar_info *uuari = &context->uuari;
+       int i;
+
+       for (i = 0; i < uuari->num_uars; i++) {
+               if (mlx5_cmd_free_uar(&dev->mdev, uuari->uars[i].index))
+                       mlx5_ib_warn(dev, "failed to free UAR 0x%x\n", uuari->uars[i].index);
+       }
+
+       kfree(uuari->count);
+       kfree(uuari->bitmap);
+       kfree(uuari->uars);
+       kfree(context);
+
+       return 0;
+}
+
+static phys_addr_t uar_index2pfn(struct mlx5_ib_dev *dev, int index)
+{
+       return (pci_resource_start(dev->mdev.pdev, 0) >> PAGE_SHIFT) + index;
+}
+
+static int get_command(unsigned long offset)
+{
+       return (offset >> MLX5_IB_MMAP_CMD_SHIFT) & MLX5_IB_MMAP_CMD_MASK;
+}
+
+static int get_arg(unsigned long offset)
+{
+       return offset & ((1 << MLX5_IB_MMAP_CMD_SHIFT) - 1);
+}
+
+static int get_index(unsigned long offset)
+{
+       return get_arg(offset);
+}
+
+static int mlx5_ib_mmap(struct ib_ucontext *ibcontext, struct vm_area_struct *vma)
+{
+       struct mlx5_ib_ucontext *context = to_mucontext(ibcontext);
+       struct mlx5_ib_dev *dev = to_mdev(ibcontext->device);
+       struct mlx5_uuar_info *uuari = &context->uuari;
+       unsigned long command;
+       unsigned long idx;
+       phys_addr_t pfn;
+
+       command = get_command(vma->vm_pgoff);
+       switch (command) {
+       case MLX5_IB_MMAP_REGULAR_PAGE:
+               if (vma->vm_end - vma->vm_start != PAGE_SIZE)
+                       return -EINVAL;
+
+               idx = get_index(vma->vm_pgoff);
+               pfn = uar_index2pfn(dev, uuari->uars[idx].index);
+               mlx5_ib_dbg(dev, "uar idx 0x%lx, pfn 0x%llx\n", idx,
+                           (unsigned long long)pfn);
+
+               if (idx >= uuari->num_uars)
+                       return -EINVAL;
+
+               vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+               if (io_remap_pfn_range(vma, vma->vm_start, pfn,
+                                      PAGE_SIZE, vma->vm_page_prot))
+                       return -EAGAIN;
+
+               mlx5_ib_dbg(dev, "mapped WC at 0x%lx, PA 0x%llx\n",
+                           vma->vm_start,
+                           (unsigned long long)pfn << PAGE_SHIFT);
+               break;
+
+       case MLX5_IB_MMAP_GET_CONTIGUOUS_PAGES:
+               return -ENOSYS;
+
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int alloc_pa_mkey(struct mlx5_ib_dev *dev, u32 *key, u32 pdn)
+{
+       struct mlx5_create_mkey_mbox_in *in;
+       struct mlx5_mkey_seg *seg;
+       struct mlx5_core_mr mr;
+       int err;
+
+       in = kzalloc(sizeof(*in), GFP_KERNEL);
+       if (!in)
+               return -ENOMEM;
+
+       seg = &in->seg;
+       seg->flags = MLX5_PERM_LOCAL_READ | MLX5_ACCESS_MODE_PA;
+       seg->flags_pd = cpu_to_be32(pdn | MLX5_MKEY_LEN64);
+       seg->qpn_mkey7_0 = cpu_to_be32(0xffffff << 8);
+       seg->start_addr = 0;
+
+       err = mlx5_core_create_mkey(&dev->mdev, &mr, in, sizeof(*in));
+       if (err) {
+               mlx5_ib_warn(dev, "failed to create mkey, %d\n", err);
+               goto err_in;
+       }
+
+       kfree(in);
+       *key = mr.key;
+
+       return 0;
+
+err_in:
+       kfree(in);
+
+       return err;
+}
+
+static void free_pa_mkey(struct mlx5_ib_dev *dev, u32 key)
+{
+       struct mlx5_core_mr mr;
+       int err;
+
+       memset(&mr, 0, sizeof(mr));
+       mr.key = key;
+       err = mlx5_core_destroy_mkey(&dev->mdev, &mr);
+       if (err)
+               mlx5_ib_warn(dev, "failed to destroy mkey 0x%x\n", key);
+}
+
+static struct ib_pd *mlx5_ib_alloc_pd(struct ib_device *ibdev,
+                                     struct ib_ucontext *context,
+                                     struct ib_udata *udata)
+{
+       struct mlx5_ib_alloc_pd_resp resp;
+       struct mlx5_ib_pd *pd;
+       int err;
+
+       pd = kmalloc(sizeof(*pd), GFP_KERNEL);
+       if (!pd)
+               return ERR_PTR(-ENOMEM);
+
+       err = mlx5_core_alloc_pd(&to_mdev(ibdev)->mdev, &pd->pdn);
+       if (err) {
+               kfree(pd);
+               return ERR_PTR(err);
+       }
+
+       if (context) {
+               resp.pdn = pd->pdn;
+               if (ib_copy_to_udata(udata, &resp, sizeof(resp))) {
+                       mlx5_core_dealloc_pd(&to_mdev(ibdev)->mdev, pd->pdn);
+                       kfree(pd);
+                       return ERR_PTR(-EFAULT);
+               }
+       } else {
+               err = alloc_pa_mkey(to_mdev(ibdev), &pd->pa_lkey, pd->pdn);
+               if (err) {
+                       mlx5_core_dealloc_pd(&to_mdev(ibdev)->mdev, pd->pdn);
+                       kfree(pd);
+                       return ERR_PTR(err);
+               }
+       }
+
+       return &pd->ibpd;
+}
+
+static int mlx5_ib_dealloc_pd(struct ib_pd *pd)
+{
+       struct mlx5_ib_dev *mdev = to_mdev(pd->device);
+       struct mlx5_ib_pd *mpd = to_mpd(pd);
+
+       if (!pd->uobject)
+               free_pa_mkey(mdev, mpd->pa_lkey);
+
+       mlx5_core_dealloc_pd(&mdev->mdev, mpd->pdn);
+       kfree(mpd);
+
+       return 0;
+}
+
+static int mlx5_ib_mcg_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
+{
+       struct mlx5_ib_dev *dev = to_mdev(ibqp->device);
+       int err;
+
+       err = mlx5_core_attach_mcg(&dev->mdev, gid, ibqp->qp_num);
+       if (err)
+               mlx5_ib_warn(dev, "failed attaching QPN 0x%x, MGID %pI6\n",
+                            ibqp->qp_num, gid->raw);
+
+       return err;
+}
+
+static int mlx5_ib_mcg_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
+{
+       struct mlx5_ib_dev *dev = to_mdev(ibqp->device);
+       int err;
+
+       err = mlx5_core_detach_mcg(&dev->mdev, gid, ibqp->qp_num);
+       if (err)
+               mlx5_ib_warn(dev, "failed detaching QPN 0x%x, MGID %pI6\n",
+                            ibqp->qp_num, gid->raw);
+
+       return err;
+}
+
+static int init_node_data(struct mlx5_ib_dev *dev)
+{
+       struct ib_smp *in_mad  = NULL;
+       struct ib_smp *out_mad = NULL;
+       int err = -ENOMEM;
+
+       in_mad  = kzalloc(sizeof(*in_mad), GFP_KERNEL);
+       out_mad = kmalloc(sizeof(*out_mad), GFP_KERNEL);
+       if (!in_mad || !out_mad)
+               goto out;
+
+       init_query_mad(in_mad);
+       in_mad->attr_id = IB_SMP_ATTR_NODE_DESC;
+
+       err = mlx5_MAD_IFC(dev, 1, 1, 1, NULL, NULL, in_mad, out_mad);
+       if (err)
+               goto out;
+
+       memcpy(dev->ib_dev.node_desc, out_mad->data, 64);
+
+       in_mad->attr_id = IB_SMP_ATTR_NODE_INFO;
+
+       err = mlx5_MAD_IFC(dev, 1, 1, 1, NULL, NULL, in_mad, out_mad);
+       if (err)
+               goto out;
+
+       dev->mdev.rev_id = be32_to_cpup((__be32 *)(out_mad->data + 32));
+       memcpy(&dev->ib_dev.node_guid, out_mad->data + 12, 8);
+
+out:
+       kfree(in_mad);
+       kfree(out_mad);
+       return err;
+}
+
+static ssize_t show_fw_pages(struct device *device, struct device_attribute *attr,
+                            char *buf)
+{
+       struct mlx5_ib_dev *dev =
+               container_of(device, struct mlx5_ib_dev, ib_dev.dev);
+
+       return sprintf(buf, "%d\n", dev->mdev.priv.fw_pages);
+}
+
+static ssize_t show_reg_pages(struct device *device,
+                             struct device_attribute *attr, char *buf)
+{
+       struct mlx5_ib_dev *dev =
+               container_of(device, struct mlx5_ib_dev, ib_dev.dev);
+
+       return sprintf(buf, "%d\n", dev->mdev.priv.reg_pages);
+}
+
+static ssize_t show_hca(struct device *device, struct device_attribute *attr,
+                       char *buf)
+{
+       struct mlx5_ib_dev *dev =
+               container_of(device, struct mlx5_ib_dev, ib_dev.dev);
+       return sprintf(buf, "MT%d\n", dev->mdev.pdev->device);
+}
+
+static ssize_t show_fw_ver(struct device *device, struct device_attribute *attr,
+                          char *buf)
+{
+       struct mlx5_ib_dev *dev =
+               container_of(device, struct mlx5_ib_dev, ib_dev.dev);
+       return sprintf(buf, "%d.%d.%d\n", fw_rev_maj(&dev->mdev),
+                      fw_rev_min(&dev->mdev), fw_rev_sub(&dev->mdev));
+}
+
+static ssize_t show_rev(struct device *device, struct device_attribute *attr,
+                       char *buf)
+{
+       struct mlx5_ib_dev *dev =
+               container_of(device, struct mlx5_ib_dev, ib_dev.dev);
+       return sprintf(buf, "%x\n", dev->mdev.rev_id);
+}
+
+static ssize_t show_board(struct device *device, struct device_attribute *attr,
+                         char *buf)
+{
+       struct mlx5_ib_dev *dev =
+               container_of(device, struct mlx5_ib_dev, ib_dev.dev);
+       return sprintf(buf, "%.*s\n", MLX5_BOARD_ID_LEN,
+                      dev->mdev.board_id);
+}
+
+static DEVICE_ATTR(hw_rev,   S_IRUGO, show_rev,    NULL);
+static DEVICE_ATTR(fw_ver,   S_IRUGO, show_fw_ver, NULL);
+static DEVICE_ATTR(hca_type, S_IRUGO, show_hca,    NULL);
+static DEVICE_ATTR(board_id, S_IRUGO, show_board,  NULL);
+static DEVICE_ATTR(fw_pages, S_IRUGO, show_fw_pages, NULL);
+static DEVICE_ATTR(reg_pages, S_IRUGO, show_reg_pages, NULL);
+
+static struct device_attribute *mlx5_class_attributes[] = {
+       &dev_attr_hw_rev,
+       &dev_attr_fw_ver,
+       &dev_attr_hca_type,
+       &dev_attr_board_id,
+       &dev_attr_fw_pages,
+       &dev_attr_reg_pages,
+};
+
+static void mlx5_ib_event(struct mlx5_core_dev *dev, enum mlx5_dev_event event,
+                         void *data)
+{
+       struct mlx5_ib_dev *ibdev = container_of(dev, struct mlx5_ib_dev, mdev);
+       struct ib_event ibev;
+       u8 port = 0;
+
+       switch (event) {
+       case MLX5_DEV_EVENT_SYS_ERROR:
+               ibdev->ib_active = false;
+               ibev.event = IB_EVENT_DEVICE_FATAL;
+               break;
+
+       case MLX5_DEV_EVENT_PORT_UP:
+               ibev.event = IB_EVENT_PORT_ACTIVE;
+               port = *(u8 *)data;
+               break;
+
+       case MLX5_DEV_EVENT_PORT_DOWN:
+               ibev.event = IB_EVENT_PORT_ERR;
+               port = *(u8 *)data;
+               break;
+
+       case MLX5_DEV_EVENT_PORT_INITIALIZED:
+               /* not used by ULPs */
+               return;
+
+       case MLX5_DEV_EVENT_LID_CHANGE:
+               ibev.event = IB_EVENT_LID_CHANGE;
+               port = *(u8 *)data;
+               break;
+
+       case MLX5_DEV_EVENT_PKEY_CHANGE:
+               ibev.event = IB_EVENT_PKEY_CHANGE;
+               port = *(u8 *)data;
+               break;
+
+       case MLX5_DEV_EVENT_GUID_CHANGE:
+               ibev.event = IB_EVENT_GID_CHANGE;
+               port = *(u8 *)data;
+               break;
+
+       case MLX5_DEV_EVENT_CLIENT_REREG:
+               ibev.event = IB_EVENT_CLIENT_REREGISTER;
+               port = *(u8 *)data;
+               break;
+       }
+
+       ibev.device           = &ibdev->ib_dev;
+       ibev.element.port_num = port;
+
+       if (ibdev->ib_active)
+               ib_dispatch_event(&ibev);
+}
+
+static void get_ext_port_caps(struct mlx5_ib_dev *dev)
+{
+       int port;
+
+       for (port = 1; port <= dev->mdev.caps.num_ports; port++)
+               mlx5_query_ext_port_caps(dev, port);
+}
+
+static int get_port_caps(struct mlx5_ib_dev *dev)
+{
+       struct ib_device_attr *dprops = NULL;
+       struct ib_port_attr *pprops = NULL;
+       int err = 0;
+       int port;
+
+       pprops = kmalloc(sizeof(*pprops), GFP_KERNEL);
+       if (!pprops)
+               goto out;
+
+       dprops = kmalloc(sizeof(*dprops), GFP_KERNEL);
+       if (!dprops)
+               goto out;
+
+       err = mlx5_ib_query_device(&dev->ib_dev, dprops);
+       if (err) {
+               mlx5_ib_warn(dev, "query_device failed %d\n", err);
+               goto out;
+       }
+
+       for (port = 1; port <= dev->mdev.caps.num_ports; port++) {
+               err = mlx5_ib_query_port(&dev->ib_dev, port, pprops);
+               if (err) {
+                       mlx5_ib_warn(dev, "query_port %d failed %d\n", port, err);
+                       break;
+               }
+               dev->mdev.caps.port[port - 1].pkey_table_len = dprops->max_pkeys;
+               dev->mdev.caps.port[port - 1].gid_table_len = pprops->gid_tbl_len;
+               mlx5_ib_dbg(dev, "pkey_table_len %d, gid_table_len %d\n",
+                           dprops->max_pkeys, pprops->gid_tbl_len);
+       }
+
+out:
+       kfree(pprops);
+       kfree(dprops);
+
+       return err;
+}
+
+static void destroy_umrc_res(struct mlx5_ib_dev *dev)
+{
+       int err;
+
+       err = mlx5_mr_cache_cleanup(dev);
+       if (err)
+               mlx5_ib_warn(dev, "mr cache cleanup failed\n");
+
+       mlx5_ib_destroy_qp(dev->umrc.qp);
+       ib_destroy_cq(dev->umrc.cq);
+       ib_dereg_mr(dev->umrc.mr);
+       ib_dealloc_pd(dev->umrc.pd);
+}
+
+enum {
+       MAX_UMR_WR = 128,
+};
+
+static int create_umr_res(struct mlx5_ib_dev *dev)
+{
+       struct ib_qp_init_attr *init_attr = NULL;
+       struct ib_qp_attr *attr = NULL;
+       struct ib_pd *pd;
+       struct ib_cq *cq;
+       struct ib_qp *qp;
+       struct ib_mr *mr;
+       int ret;
+
+       attr = kzalloc(sizeof(*attr), GFP_KERNEL);
+       init_attr = kzalloc(sizeof(*init_attr), GFP_KERNEL);
+       if (!attr || !init_attr) {
+               ret = -ENOMEM;
+               goto error_0;
+       }
+
+       pd = ib_alloc_pd(&dev->ib_dev);
+       if (IS_ERR(pd)) {
+               mlx5_ib_dbg(dev, "Couldn't create PD for sync UMR QP\n");
+               ret = PTR_ERR(pd);
+               goto error_0;
+       }
+
+       mr = ib_get_dma_mr(pd,  IB_ACCESS_LOCAL_WRITE);
+       if (IS_ERR(mr)) {
+               mlx5_ib_dbg(dev, "Couldn't create DMA MR for sync UMR QP\n");
+               ret = PTR_ERR(mr);
+               goto error_1;
+       }
+
+       cq = ib_create_cq(&dev->ib_dev, mlx5_umr_cq_handler, NULL, NULL, 128,
+                         0);
+       if (IS_ERR(cq)) {
+               mlx5_ib_dbg(dev, "Couldn't create CQ for sync UMR QP\n");
+               ret = PTR_ERR(cq);
+               goto error_2;
+       }
+       ib_req_notify_cq(cq, IB_CQ_NEXT_COMP);
+
+       init_attr->send_cq = cq;
+       init_attr->recv_cq = cq;
+       init_attr->sq_sig_type = IB_SIGNAL_ALL_WR;
+       init_attr->cap.max_send_wr = MAX_UMR_WR;
+       init_attr->cap.max_send_sge = 1;
+       init_attr->qp_type = MLX5_IB_QPT_REG_UMR;
+       init_attr->port_num = 1;
+       qp = mlx5_ib_create_qp(pd, init_attr, NULL);
+       if (IS_ERR(qp)) {
+               mlx5_ib_dbg(dev, "Couldn't create sync UMR QP\n");
+               ret = PTR_ERR(qp);
+               goto error_3;
+       }
+       qp->device     = &dev->ib_dev;
+       qp->real_qp    = qp;
+       qp->uobject    = NULL;
+       qp->qp_type    = MLX5_IB_QPT_REG_UMR;
+
+       attr->qp_state = IB_QPS_INIT;
+       attr->port_num = 1;
+       ret = mlx5_ib_modify_qp(qp, attr, IB_QP_STATE | IB_QP_PKEY_INDEX |
+                               IB_QP_PORT, NULL);
+       if (ret) {
+               mlx5_ib_dbg(dev, "Couldn't modify UMR QP\n");
+               goto error_4;
+       }
+
+       memset(attr, 0, sizeof(*attr));
+       attr->qp_state = IB_QPS_RTR;
+       attr->path_mtu = IB_MTU_256;
+
+       ret = mlx5_ib_modify_qp(qp, attr, IB_QP_STATE, NULL);
+       if (ret) {
+               mlx5_ib_dbg(dev, "Couldn't modify umr QP to rtr\n");
+               goto error_4;
+       }
+
+       memset(attr, 0, sizeof(*attr));
+       attr->qp_state = IB_QPS_RTS;
+       ret = mlx5_ib_modify_qp(qp, attr, IB_QP_STATE, NULL);
+       if (ret) {
+               mlx5_ib_dbg(dev, "Couldn't modify umr QP to rts\n");
+               goto error_4;
+       }
+
+       dev->umrc.qp = qp;
+       dev->umrc.cq = cq;
+       dev->umrc.mr = mr;
+       dev->umrc.pd = pd;
+
+       sema_init(&dev->umrc.sem, MAX_UMR_WR);
+       ret = mlx5_mr_cache_init(dev);
+       if (ret) {
+               mlx5_ib_warn(dev, "mr cache init failed %d\n", ret);
+               goto error_4;
+       }
+
+       kfree(attr);
+       kfree(init_attr);
+
+       return 0;
+
+error_4:
+       mlx5_ib_destroy_qp(qp);
+
+error_3:
+       ib_destroy_cq(cq);
+
+error_2:
+       ib_dereg_mr(mr);
+
+error_1:
+       ib_dealloc_pd(pd);
+
+error_0:
+       kfree(attr);
+       kfree(init_attr);
+       return ret;
+}
+
+static int create_dev_resources(struct mlx5_ib_resources *devr)
+{
+       struct ib_srq_init_attr attr;
+       struct mlx5_ib_dev *dev;
+       int ret = 0;
+
+       dev = container_of(devr, struct mlx5_ib_dev, devr);
+
+       devr->p0 = mlx5_ib_alloc_pd(&dev->ib_dev, NULL, NULL);
+       if (IS_ERR(devr->p0)) {
+               ret = PTR_ERR(devr->p0);
+               goto error0;
+       }
+       devr->p0->device  = &dev->ib_dev;
+       devr->p0->uobject = NULL;
+       atomic_set(&devr->p0->usecnt, 0);
+
+       devr->c0 = mlx5_ib_create_cq(&dev->ib_dev, 1, 0, NULL, NULL);
+       if (IS_ERR(devr->c0)) {
+               ret = PTR_ERR(devr->c0);
+               goto error1;
+       }
+       devr->c0->device        = &dev->ib_dev;
+       devr->c0->uobject       = NULL;
+       devr->c0->comp_handler  = NULL;
+       devr->c0->event_handler = NULL;
+       devr->c0->cq_context    = NULL;
+       atomic_set(&devr->c0->usecnt, 0);
+
+       devr->x0 = mlx5_ib_alloc_xrcd(&dev->ib_dev, NULL, NULL);
+       if (IS_ERR(devr->x0)) {
+               ret = PTR_ERR(devr->x0);
+               goto error2;
+       }
+       devr->x0->device = &dev->ib_dev;
+       devr->x0->inode = NULL;
+       atomic_set(&devr->x0->usecnt, 0);
+       mutex_init(&devr->x0->tgt_qp_mutex);
+       INIT_LIST_HEAD(&devr->x0->tgt_qp_list);
+
+       devr->x1 = mlx5_ib_alloc_xrcd(&dev->ib_dev, NULL, NULL);
+       if (IS_ERR(devr->x1)) {
+               ret = PTR_ERR(devr->x1);
+               goto error3;
+       }
+       devr->x1->device = &dev->ib_dev;
+       devr->x1->inode = NULL;
+       atomic_set(&devr->x1->usecnt, 0);
+       mutex_init(&devr->x1->tgt_qp_mutex);
+       INIT_LIST_HEAD(&devr->x1->tgt_qp_list);
+
+       memset(&attr, 0, sizeof(attr));
+       attr.attr.max_sge = 1;
+       attr.attr.max_wr = 1;
+       attr.srq_type = IB_SRQT_XRC;
+       attr.ext.xrc.cq = devr->c0;
+       attr.ext.xrc.xrcd = devr->x0;
+
+       devr->s0 = mlx5_ib_create_srq(devr->p0, &attr, NULL);
+       if (IS_ERR(devr->s0)) {
+               ret = PTR_ERR(devr->s0);
+               goto error4;
+       }
+       devr->s0->device        = &dev->ib_dev;
+       devr->s0->pd            = devr->p0;
+       devr->s0->uobject       = NULL;
+       devr->s0->event_handler = NULL;
+       devr->s0->srq_context   = NULL;
+       devr->s0->srq_type      = IB_SRQT_XRC;
+       devr->s0->ext.xrc.xrcd  = devr->x0;
+       devr->s0->ext.xrc.cq    = devr->c0;
+       atomic_inc(&devr->s0->ext.xrc.xrcd->usecnt);
+       atomic_inc(&devr->s0->ext.xrc.cq->usecnt);
+       atomic_inc(&devr->p0->usecnt);
+       atomic_set(&devr->s0->usecnt, 0);
+
+       return 0;
+
+error4:
+       mlx5_ib_dealloc_xrcd(devr->x1);
+error3:
+       mlx5_ib_dealloc_xrcd(devr->x0);
+error2:
+       mlx5_ib_destroy_cq(devr->c0);
+error1:
+       mlx5_ib_dealloc_pd(devr->p0);
+error0:
+       return ret;
+}
+
+static void destroy_dev_resources(struct mlx5_ib_resources *devr)
+{
+       mlx5_ib_destroy_srq(devr->s0);
+       mlx5_ib_dealloc_xrcd(devr->x0);
+       mlx5_ib_dealloc_xrcd(devr->x1);
+       mlx5_ib_destroy_cq(devr->c0);
+       mlx5_ib_dealloc_pd(devr->p0);
+}
+
+static int init_one(struct pci_dev *pdev,
+                   const struct pci_device_id *id)
+{
+       struct mlx5_core_dev *mdev;
+       struct mlx5_ib_dev *dev;
+       int err;
+       int i;
+
+       printk_once(KERN_INFO "%s", mlx5_version);
+
+       dev = (struct mlx5_ib_dev *)ib_alloc_device(sizeof(*dev));
+       if (!dev)
+               return -ENOMEM;
+
+       mdev = &dev->mdev;
+       mdev->event = mlx5_ib_event;
+       if (prof_sel >= ARRAY_SIZE(profile)) {
+               pr_warn("selected pofile out of range, selceting default\n");
+               prof_sel = 0;
+       }
+       mdev->profile = &profile[prof_sel];
+       err = mlx5_dev_init(mdev, pdev);
+       if (err)
+               goto err_free;
+
+       err = get_port_caps(dev);
+       if (err)
+               goto err_cleanup;
+
+       get_ext_port_caps(dev);
+
+       err = alloc_comp_eqs(dev);
+       if (err)
+               goto err_cleanup;
+
+       MLX5_INIT_DOORBELL_LOCK(&dev->uar_lock);
+
+       strlcpy(dev->ib_dev.name, "mlx5_%d", IB_DEVICE_NAME_MAX);
+       dev->ib_dev.owner               = THIS_MODULE;
+       dev->ib_dev.node_type           = RDMA_NODE_IB_CA;
+       dev->ib_dev.local_dma_lkey      = mdev->caps.reserved_lkey;
+       dev->num_ports          = mdev->caps.num_ports;
+       dev->ib_dev.phys_port_cnt     = dev->num_ports;
+       dev->ib_dev.num_comp_vectors    = dev->num_comp_vectors;
+       dev->ib_dev.dma_device  = &mdev->pdev->dev;
+
+       dev->ib_dev.uverbs_abi_ver      = MLX5_IB_UVERBS_ABI_VERSION;
+       dev->ib_dev.uverbs_cmd_mask     =
+               (1ull << IB_USER_VERBS_CMD_GET_CONTEXT)         |
+               (1ull << IB_USER_VERBS_CMD_QUERY_DEVICE)        |
+               (1ull << IB_USER_VERBS_CMD_QUERY_PORT)          |
+               (1ull << IB_USER_VERBS_CMD_ALLOC_PD)            |
+               (1ull << IB_USER_VERBS_CMD_DEALLOC_PD)          |
+               (1ull << IB_USER_VERBS_CMD_REG_MR)              |
+               (1ull << IB_USER_VERBS_CMD_DEREG_MR)            |
+               (1ull << IB_USER_VERBS_CMD_CREATE_COMP_CHANNEL) |
+               (1ull << IB_USER_VERBS_CMD_CREATE_CQ)           |
+               (1ull << IB_USER_VERBS_CMD_RESIZE_CQ)           |
+               (1ull << IB_USER_VERBS_CMD_DESTROY_CQ)          |
+               (1ull << IB_USER_VERBS_CMD_CREATE_QP)           |
+               (1ull << IB_USER_VERBS_CMD_MODIFY_QP)           |
+               (1ull << IB_USER_VERBS_CMD_QUERY_QP)            |
+               (1ull << IB_USER_VERBS_CMD_DESTROY_QP)          |
+               (1ull << IB_USER_VERBS_CMD_ATTACH_MCAST)        |
+               (1ull << IB_USER_VERBS_CMD_DETACH_MCAST)        |
+               (1ull << IB_USER_VERBS_CMD_CREATE_SRQ)          |
+               (1ull << IB_USER_VERBS_CMD_MODIFY_SRQ)          |
+               (1ull << IB_USER_VERBS_CMD_QUERY_SRQ)           |
+               (1ull << IB_USER_VERBS_CMD_DESTROY_SRQ)         |
+               (1ull << IB_USER_VERBS_CMD_CREATE_XSRQ)         |
+               (1ull << IB_USER_VERBS_CMD_OPEN_QP);
+
+       dev->ib_dev.query_device        = mlx5_ib_query_device;
+       dev->ib_dev.query_port          = mlx5_ib_query_port;
+       dev->ib_dev.query_gid           = mlx5_ib_query_gid;
+       dev->ib_dev.query_pkey          = mlx5_ib_query_pkey;
+       dev->ib_dev.modify_device       = mlx5_ib_modify_device;
+       dev->ib_dev.modify_port         = mlx5_ib_modify_port;
+       dev->ib_dev.alloc_ucontext      = mlx5_ib_alloc_ucontext;
+       dev->ib_dev.dealloc_ucontext    = mlx5_ib_dealloc_ucontext;
+       dev->ib_dev.mmap                = mlx5_ib_mmap;
+       dev->ib_dev.alloc_pd            = mlx5_ib_alloc_pd;
+       dev->ib_dev.dealloc_pd          = mlx5_ib_dealloc_pd;
+       dev->ib_dev.create_ah           = mlx5_ib_create_ah;
+       dev->ib_dev.query_ah            = mlx5_ib_query_ah;
+       dev->ib_dev.destroy_ah          = mlx5_ib_destroy_ah;
+       dev->ib_dev.create_srq          = mlx5_ib_create_srq;
+       dev->ib_dev.modify_srq          = mlx5_ib_modify_srq;
+       dev->ib_dev.query_srq           = mlx5_ib_query_srq;
+       dev->ib_dev.destroy_srq         = mlx5_ib_destroy_srq;
+       dev->ib_dev.post_srq_recv       = mlx5_ib_post_srq_recv;
+       dev->ib_dev.create_qp           = mlx5_ib_create_qp;
+       dev->ib_dev.modify_qp           = mlx5_ib_modify_qp;
+       dev->ib_dev.query_qp            = mlx5_ib_query_qp;
+       dev->ib_dev.destroy_qp          = mlx5_ib_destroy_qp;
+       dev->ib_dev.post_send           = mlx5_ib_post_send;
+       dev->ib_dev.post_recv           = mlx5_ib_post_recv;
+       dev->ib_dev.create_cq           = mlx5_ib_create_cq;
+       dev->ib_dev.modify_cq           = mlx5_ib_modify_cq;
+       dev->ib_dev.resize_cq           = mlx5_ib_resize_cq;
+       dev->ib_dev.destroy_cq          = mlx5_ib_destroy_cq;
+       dev->ib_dev.poll_cq             = mlx5_ib_poll_cq;
+       dev->ib_dev.req_notify_cq       = mlx5_ib_arm_cq;
+       dev->ib_dev.get_dma_mr          = mlx5_ib_get_dma_mr;
+       dev->ib_dev.reg_user_mr         = mlx5_ib_reg_user_mr;
+       dev->ib_dev.dereg_mr            = mlx5_ib_dereg_mr;
+       dev->ib_dev.attach_mcast        = mlx5_ib_mcg_attach;
+       dev->ib_dev.detach_mcast        = mlx5_ib_mcg_detach;
+       dev->ib_dev.process_mad         = mlx5_ib_process_mad;
+       dev->ib_dev.alloc_fast_reg_mr   = mlx5_ib_alloc_fast_reg_mr;
+       dev->ib_dev.alloc_fast_reg_page_list = mlx5_ib_alloc_fast_reg_page_list;
+       dev->ib_dev.free_fast_reg_page_list  = mlx5_ib_free_fast_reg_page_list;
+
+       if (mdev->caps.flags & MLX5_DEV_CAP_FLAG_XRC) {
+               dev->ib_dev.alloc_xrcd = mlx5_ib_alloc_xrcd;
+               dev->ib_dev.dealloc_xrcd = mlx5_ib_dealloc_xrcd;
+               dev->ib_dev.uverbs_cmd_mask |=
+                       (1ull << IB_USER_VERBS_CMD_OPEN_XRCD) |
+                       (1ull << IB_USER_VERBS_CMD_CLOSE_XRCD);
+       }
+
+       err = init_node_data(dev);
+       if (err)
+               goto err_eqs;
+
+       mutex_init(&dev->cap_mask_mutex);
+       spin_lock_init(&dev->mr_lock);
+
+       err = create_dev_resources(&dev->devr);
+       if (err)
+               goto err_eqs;
+
+       if (ib_register_device(&dev->ib_dev, NULL))
+               goto err_rsrc;
+
+       err = create_umr_res(dev);
+       if (err)
+               goto err_dev;
+
+       for (i = 0; i < ARRAY_SIZE(mlx5_class_attributes); i++) {
+               if (device_create_file(&dev->ib_dev.dev,
+                                      mlx5_class_attributes[i]))
+                       goto err_umrc;
+       }
+
+       dev->ib_active = true;
+
+       return 0;
+
+err_umrc:
+       destroy_umrc_res(dev);
+
+err_dev:
+       ib_unregister_device(&dev->ib_dev);
+
+err_rsrc:
+       destroy_dev_resources(&dev->devr);
+
+err_eqs:
+       free_comp_eqs(dev);
+
+err_cleanup:
+       mlx5_dev_cleanup(mdev);
+
+err_free:
+       ib_dealloc_device((struct ib_device *)dev);
+
+       return err;
+}
+
+static void remove_one(struct pci_dev *pdev)
+{
+       struct mlx5_ib_dev *dev = mlx5_pci2ibdev(pdev);
+
+       destroy_umrc_res(dev);
+       ib_unregister_device(&dev->ib_dev);
+       destroy_dev_resources(&dev->devr);
+       free_comp_eqs(dev);
+       mlx5_dev_cleanup(&dev->mdev);
+       ib_dealloc_device(&dev->ib_dev);
+}
+
+static DEFINE_PCI_DEVICE_TABLE(mlx5_ib_pci_table) = {
+       { PCI_VDEVICE(MELLANOX, 4113) }, /* MT4113 Connect-IB */
+       { 0, }
+};
+
+MODULE_DEVICE_TABLE(pci, mlx5_ib_pci_table);
+
+static struct pci_driver mlx5_ib_driver = {
+       .name           = DRIVER_NAME,
+       .id_table       = mlx5_ib_pci_table,
+       .probe          = init_one,
+       .remove         = remove_one
+};
+
+static int __init mlx5_ib_init(void)
+{
+       return pci_register_driver(&mlx5_ib_driver);
+}
+
+static void __exit mlx5_ib_cleanup(void)
+{
+       pci_unregister_driver(&mlx5_ib_driver);
+}
+
+module_init(mlx5_ib_init);
+module_exit(mlx5_ib_cleanup);
diff --git a/drivers/infiniband/hw/mlx5/mem.c b/drivers/infiniband/hw/mlx5/mem.c
new file mode 100644 (file)
index 0000000..3a53228
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2013, Mellanox Technologies inc.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/module.h>
+#include <rdma/ib_umem.h>
+#include "mlx5_ib.h"
+
+/* @umem: umem object to scan
+ * @addr: ib virtual address requested by the user
+ * @count: number of PAGE_SIZE pages covered by umem
+ * @shift: page shift for the compound pages found in the region
+ * @ncont: number of compund pages
+ * @order: log2 of the number of compound pages
+ */
+void mlx5_ib_cont_pages(struct ib_umem *umem, u64 addr, int *count, int *shift,
+                       int *ncont, int *order)
+{
+       struct ib_umem_chunk *chunk;
+       unsigned long tmp;
+       unsigned long m;
+       int i, j, k;
+       u64 base = 0;
+       int p = 0;
+       int skip;
+       int mask;
+       u64 len;
+       u64 pfn;
+
+       addr = addr >> PAGE_SHIFT;
+       tmp = (unsigned long)addr;
+       m = find_first_bit(&tmp, sizeof(tmp));
+       skip = 1 << m;
+       mask = skip - 1;
+       i = 0;
+       list_for_each_entry(chunk, &umem->chunk_list, list)
+               for (j = 0; j < chunk->nmap; j++) {
+                       len = sg_dma_len(&chunk->page_list[j]) >> PAGE_SHIFT;
+                       pfn = sg_dma_address(&chunk->page_list[j]) >> PAGE_SHIFT;
+                       for (k = 0; k < len; k++) {
+                               if (!(i & mask)) {
+                                       tmp = (unsigned long)pfn;
+                                       m = min(m, find_first_bit(&tmp, sizeof(tmp)));
+                                       skip = 1 << m;
+                                       mask = skip - 1;
+                                       base = pfn;
+                                       p = 0;
+                               } else {
+                                       if (base + p != pfn) {
+                                               tmp = (unsigned long)p;
+                                               m = find_first_bit(&tmp, sizeof(tmp));
+                                               skip = 1 << m;
+                                               mask = skip - 1;
+                                               base = pfn;
+                                               p = 0;
+                                       }
+                               }
+                               p++;
+                               i++;
+                       }
+               }
+
+       if (i) {
+               m = min_t(unsigned long, ilog2(roundup_pow_of_two(i)), m);
+
+               if (order)
+                       *order = ilog2(roundup_pow_of_two(i) >> m);
+
+               *ncont = DIV_ROUND_UP(i, (1 << m));
+       } else {
+               m  = 0;
+
+               if (order)
+                       *order = 0;
+
+               *ncont = 0;
+       }
+       *shift = PAGE_SHIFT + m;
+       *count = i;
+}
+
+void mlx5_ib_populate_pas(struct mlx5_ib_dev *dev, struct ib_umem *umem,
+                         int page_shift, __be64 *pas, int umr)
+{
+       int shift = page_shift - PAGE_SHIFT;
+       int mask = (1 << shift) - 1;
+       struct ib_umem_chunk *chunk;
+       int i, j, k;
+       u64 cur = 0;
+       u64 base;
+       int len;
+
+       i = 0;
+       list_for_each_entry(chunk, &umem->chunk_list, list)
+               for (j = 0; j < chunk->nmap; j++) {
+                       len = sg_dma_len(&chunk->page_list[j]) >> PAGE_SHIFT;
+                       base = sg_dma_address(&chunk->page_list[j]);
+                       for (k = 0; k < len; k++) {
+                               if (!(i & mask)) {
+                                       cur = base + (k << PAGE_SHIFT);
+                                       if (umr)
+                                               cur |= 3;
+
+                                       pas[i >> shift] = cpu_to_be64(cur);
+                                       mlx5_ib_dbg(dev, "pas[%d] 0x%llx\n",
+                                                   i >> shift, be64_to_cpu(pas[i >> shift]));
+                               }  else
+                                       mlx5_ib_dbg(dev, "=====> 0x%llx\n",
+                                                   base + (k << PAGE_SHIFT));
+                               i++;
+                       }
+               }
+}
+
+int mlx5_ib_get_buf_offset(u64 addr, int page_shift, u32 *offset)
+{
+       u64 page_size;
+       u64 page_mask;
+       u64 off_size;
+       u64 off_mask;
+       u64 buf_off;
+
+       page_size = 1 << page_shift;
+       page_mask = page_size - 1;
+       buf_off = addr & page_mask;
+       off_size = page_size >> 6;
+       off_mask = off_size - 1;
+
+       if (buf_off & off_mask)
+               return -EINVAL;
+
+       *offset = buf_off >> ilog2(off_size);
+       return 0;
+}
diff --git a/drivers/infiniband/hw/mlx5/mlx5_ib.h b/drivers/infiniband/hw/mlx5/mlx5_ib.h
new file mode 100644 (file)
index 0000000..836be91
--- /dev/null
@@ -0,0 +1,545 @@
+/*
+ * Copyright (c) 2013, Mellanox Technologies inc.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef MLX5_IB_H
+#define MLX5_IB_H
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <rdma/ib_verbs.h>
+#include <rdma/ib_smi.h>
+#include <linux/mlx5/driver.h>
+#include <linux/mlx5/cq.h>
+#include <linux/mlx5/qp.h>
+#include <linux/mlx5/srq.h>
+#include <linux/types.h>
+
+#define mlx5_ib_dbg(dev, format, arg...)                               \
+pr_debug("%s:%s:%d:(pid %d): " format, (dev)->ib_dev.name, __func__,   \
+        __LINE__, current->pid, ##arg)
+
+#define mlx5_ib_err(dev, format, arg...)                               \
+pr_err("%s:%s:%d:(pid %d): " format, (dev)->ib_dev.name, __func__,     \
+       __LINE__, current->pid, ##arg)
+
+#define mlx5_ib_warn(dev, format, arg...)                              \
+pr_warn("%s:%s:%d:(pid %d): " format, (dev)->ib_dev.name, __func__,    \
+       __LINE__, current->pid, ##arg)
+
+enum {
+       MLX5_IB_MMAP_CMD_SHIFT  = 8,
+       MLX5_IB_MMAP_CMD_MASK   = 0xff,
+};
+
+enum mlx5_ib_mmap_cmd {
+       MLX5_IB_MMAP_REGULAR_PAGE               = 0,
+       MLX5_IB_MMAP_GET_CONTIGUOUS_PAGES       = 1, /* always last */
+};
+
+enum {
+       MLX5_RES_SCAT_DATA32_CQE        = 0x1,
+       MLX5_RES_SCAT_DATA64_CQE        = 0x2,
+       MLX5_REQ_SCAT_DATA32_CQE        = 0x11,
+       MLX5_REQ_SCAT_DATA64_CQE        = 0x22,
+};
+
+enum mlx5_ib_latency_class {
+       MLX5_IB_LATENCY_CLASS_LOW,
+       MLX5_IB_LATENCY_CLASS_MEDIUM,
+       MLX5_IB_LATENCY_CLASS_HIGH,
+       MLX5_IB_LATENCY_CLASS_FAST_PATH
+};
+
+enum mlx5_ib_mad_ifc_flags {
+       MLX5_MAD_IFC_IGNORE_MKEY        = 1,
+       MLX5_MAD_IFC_IGNORE_BKEY        = 2,
+       MLX5_MAD_IFC_NET_VIEW           = 4,
+};
+
+struct mlx5_ib_ucontext {
+       struct ib_ucontext      ibucontext;
+       struct list_head        db_page_list;
+
+       /* protect doorbell record alloc/free
+        */
+       struct mutex            db_page_mutex;
+       struct mlx5_uuar_info   uuari;
+};
+
+static inline struct mlx5_ib_ucontext *to_mucontext(struct ib_ucontext *ibucontext)
+{
+       return container_of(ibucontext, struct mlx5_ib_ucontext, ibucontext);
+}
+
+struct mlx5_ib_pd {
+       struct ib_pd            ibpd;
+       u32                     pdn;
+       u32                     pa_lkey;
+};
+
+/* Use macros here so that don't have to duplicate
+ * enum ib_send_flags and enum ib_qp_type for low-level driver
+ */
+
+#define MLX5_IB_SEND_UMR_UNREG IB_SEND_RESERVED_START
+#define MLX5_IB_QPT_REG_UMR    IB_QPT_RESERVED1
+#define MLX5_IB_WR_UMR         IB_WR_RESERVED1
+
+struct wr_list {
+       u16     opcode;
+       u16     next;
+};
+
+struct mlx5_ib_wq {
+       u64                    *wrid;
+       u32                    *wr_data;
+       struct wr_list         *w_list;
+       unsigned               *wqe_head;
+       u16                     unsig_count;
+
+       /* serialize post to the work queue
+        */
+       spinlock_t              lock;
+       int                     wqe_cnt;
+       int                     max_post;
+       int                     max_gs;
+       int                     offset;
+       int                     wqe_shift;
+       unsigned                head;
+       unsigned                tail;
+       u16                     cur_post;
+       u16                     last_poll;
+       void                   *qend;
+};
+
+enum {
+       MLX5_QP_USER,
+       MLX5_QP_KERNEL,
+       MLX5_QP_EMPTY
+};
+
+struct mlx5_ib_qp {
+       struct ib_qp            ibqp;
+       struct mlx5_core_qp     mqp;
+       struct mlx5_buf         buf;
+
+       struct mlx5_db          db;
+       struct mlx5_ib_wq       rq;
+
+       u32                     doorbell_qpn;
+       u8                      sq_signal_bits;
+       u8                      fm_cache;
+       int                     sq_max_wqes_per_wr;
+       int                     sq_spare_wqes;
+       struct mlx5_ib_wq       sq;
+
+       struct ib_umem         *umem;
+       int                     buf_size;
+
+       /* serialize qp state modifications
+        */
+       struct mutex            mutex;
+       u16                     xrcdn;
+       u32                     flags;
+       u8                      port;
+       u8                      alt_port;
+       u8                      atomic_rd_en;
+       u8                      resp_depth;
+       u8                      state;
+       int                     mlx_type;
+       int                     wq_sig;
+       int                     scat_cqe;
+       int                     max_inline_data;
+       struct mlx5_bf         *bf;
+       int                     has_rq;
+
+       /* only for user space QPs. For kernel
+        * we have it from the bf object
+        */
+       int                     uuarn;
+
+       int                     create_type;
+       u32                     pa_lkey;
+};
+
+struct mlx5_ib_cq_buf {
+       struct mlx5_buf         buf;
+       struct ib_umem          *umem;
+       int                     cqe_size;
+};
+
+enum mlx5_ib_qp_flags {
+       MLX5_IB_QP_BLOCK_MULTICAST_LOOPBACK     = 1 << 0,
+       MLX5_IB_QP_SIGNATURE_HANDLING           = 1 << 1,
+};
+
+struct mlx5_shared_mr_info {
+       int mr_id;
+       struct ib_umem          *umem;
+};
+
+struct mlx5_ib_cq {
+       struct ib_cq            ibcq;
+       struct mlx5_core_cq     mcq;
+       struct mlx5_ib_cq_buf   buf;
+       struct mlx5_db          db;
+
+       /* serialize access to the CQ
+        */
+       spinlock_t              lock;
+
+       /* protect resize cq
+        */
+       struct mutex            resize_mutex;
+       struct mlx5_ib_cq_resize *resize_buf;
+       struct ib_umem         *resize_umem;
+       int                     cqe_size;
+};
+
+struct mlx5_ib_srq {
+       struct ib_srq           ibsrq;
+       struct mlx5_core_srq    msrq;
+       struct mlx5_buf         buf;
+       struct mlx5_db          db;
+       u64                    *wrid;
+       /* protect SRQ hanlding
+        */
+       spinlock_t              lock;
+       int                     head;
+       int                     tail;
+       u16                     wqe_ctr;
+       struct ib_umem         *umem;
+       /* serialize arming a SRQ
+        */
+       struct mutex            mutex;
+       int                     wq_sig;
+};
+
+struct mlx5_ib_xrcd {
+       struct ib_xrcd          ibxrcd;
+       u32                     xrcdn;
+};
+
+struct mlx5_ib_mr {
+       struct ib_mr            ibmr;
+       struct mlx5_core_mr     mmr;
+       struct ib_umem         *umem;
+       struct mlx5_shared_mr_info      *smr_info;
+       struct list_head        list;
+       int                     order;
+       int                     umred;
+       __be64                  *pas;
+       dma_addr_t              dma;
+       int                     npages;
+       struct completion       done;
+       enum ib_wc_status       status;
+};
+
+struct mlx5_ib_fast_reg_page_list {
+       struct ib_fast_reg_page_list    ibfrpl;
+       __be64                         *mapped_page_list;
+       dma_addr_t                      map;
+};
+
+struct umr_common {
+       struct ib_pd    *pd;
+       struct ib_cq    *cq;
+       struct ib_qp    *qp;
+       struct ib_mr    *mr;
+       /* control access to UMR QP
+        */
+       struct semaphore        sem;
+};
+
+enum {
+       MLX5_FMR_INVALID,
+       MLX5_FMR_VALID,
+       MLX5_FMR_BUSY,
+};
+
+struct mlx5_ib_fmr {
+       struct ib_fmr                   ibfmr;
+       struct mlx5_core_mr             mr;
+       int                             access_flags;
+       int                             state;
+       /* protect fmr state
+        */
+       spinlock_t                      lock;
+       u64                             wrid;
+       struct ib_send_wr               wr[2];
+       u8                              page_shift;
+       struct ib_fast_reg_page_list    page_list;
+};
+
+struct mlx5_cache_ent {
+       struct list_head        head;
+       /* sync access to the cahce entry
+        */
+       spinlock_t              lock;
+
+
+       struct dentry          *dir;
+       char                    name[4];
+       u32                     order;
+       u32                     size;
+       u32                     cur;
+       u32                     miss;
+       u32                     limit;
+
+       struct dentry          *fsize;
+       struct dentry          *fcur;
+       struct dentry          *fmiss;
+       struct dentry          *flimit;
+
+       struct mlx5_ib_dev     *dev;
+       struct work_struct      work;
+       struct delayed_work     dwork;
+};
+
+struct mlx5_mr_cache {
+       struct workqueue_struct *wq;
+       struct mlx5_cache_ent   ent[MAX_MR_CACHE_ENTRIES];
+       int                     stopped;
+       struct dentry           *root;
+       unsigned long           last_add;
+};
+
+struct mlx5_ib_resources {
+       struct ib_cq    *c0;
+       struct ib_xrcd  *x0;
+       struct ib_xrcd  *x1;
+       struct ib_pd    *p0;
+       struct ib_srq   *s0;
+};
+
+struct mlx5_ib_dev {
+       struct ib_device                ib_dev;
+       struct mlx5_core_dev            mdev;
+       MLX5_DECLARE_DOORBELL_LOCK(uar_lock);
+       struct list_head                eqs_list;
+       int                             num_ports;
+       int                             num_comp_vectors;
+       /* serialize update of capability mask
+        */
+       struct mutex                    cap_mask_mutex;
+       bool                            ib_active;
+       struct umr_common               umrc;
+       /* sync used page count stats
+        */
+       spinlock_t                      mr_lock;
+       struct mlx5_ib_resources        devr;
+       struct mlx5_mr_cache            cache;
+};
+
+static inline struct mlx5_ib_cq *to_mibcq(struct mlx5_core_cq *mcq)
+{
+       return container_of(mcq, struct mlx5_ib_cq, mcq);
+}
+
+static inline struct mlx5_ib_xrcd *to_mxrcd(struct ib_xrcd *ibxrcd)
+{
+       return container_of(ibxrcd, struct mlx5_ib_xrcd, ibxrcd);
+}
+
+static inline struct mlx5_ib_dev *to_mdev(struct ib_device *ibdev)
+{
+       return container_of(ibdev, struct mlx5_ib_dev, ib_dev);
+}
+
+static inline struct mlx5_ib_fmr *to_mfmr(struct ib_fmr *ibfmr)
+{
+       return container_of(ibfmr, struct mlx5_ib_fmr, ibfmr);
+}
+
+static inline struct mlx5_ib_cq *to_mcq(struct ib_cq *ibcq)
+{
+       return container_of(ibcq, struct mlx5_ib_cq, ibcq);
+}
+
+static inline struct mlx5_ib_qp *to_mibqp(struct mlx5_core_qp *mqp)
+{
+       return container_of(mqp, struct mlx5_ib_qp, mqp);
+}
+
+static inline struct mlx5_ib_pd *to_mpd(struct ib_pd *ibpd)
+{
+       return container_of(ibpd, struct mlx5_ib_pd, ibpd);
+}
+
+static inline struct mlx5_ib_srq *to_msrq(struct ib_srq *ibsrq)
+{
+       return container_of(ibsrq, struct mlx5_ib_srq, ibsrq);
+}
+
+static inline struct mlx5_ib_qp *to_mqp(struct ib_qp *ibqp)
+{
+       return container_of(ibqp, struct mlx5_ib_qp, ibqp);
+}
+
+static inline struct mlx5_ib_srq *to_mibsrq(struct mlx5_core_srq *msrq)
+{
+       return container_of(msrq, struct mlx5_ib_srq, msrq);
+}
+
+static inline struct mlx5_ib_mr *to_mmr(struct ib_mr *ibmr)
+{
+       return container_of(ibmr, struct mlx5_ib_mr, ibmr);
+}
+
+static inline struct mlx5_ib_fast_reg_page_list *to_mfrpl(struct ib_fast_reg_page_list *ibfrpl)
+{
+       return container_of(ibfrpl, struct mlx5_ib_fast_reg_page_list, ibfrpl);
+}
+
+struct mlx5_ib_ah {
+       struct ib_ah            ibah;
+       struct mlx5_av          av;
+};
+
+static inline struct mlx5_ib_ah *to_mah(struct ib_ah *ibah)
+{
+       return container_of(ibah, struct mlx5_ib_ah, ibah);
+}
+
+static inline struct mlx5_ib_dev *mlx5_core2ibdev(struct mlx5_core_dev *dev)
+{
+       return container_of(dev, struct mlx5_ib_dev, mdev);
+}
+
+static inline struct mlx5_ib_dev *mlx5_pci2ibdev(struct pci_dev *pdev)
+{
+       return mlx5_core2ibdev(pci2mlx5_core_dev(pdev));
+}
+
+int mlx5_ib_db_map_user(struct mlx5_ib_ucontext *context, unsigned long virt,
+                       struct mlx5_db *db);
+void mlx5_ib_db_unmap_user(struct mlx5_ib_ucontext *context, struct mlx5_db *db);
+void __mlx5_ib_cq_clean(struct mlx5_ib_cq *cq, u32 qpn, struct mlx5_ib_srq *srq);
+void mlx5_ib_cq_clean(struct mlx5_ib_cq *cq, u32 qpn, struct mlx5_ib_srq *srq);
+void mlx5_ib_free_srq_wqe(struct mlx5_ib_srq *srq, int wqe_index);
+int mlx5_MAD_IFC(struct mlx5_ib_dev *dev, int ignore_mkey, int ignore_bkey,
+                int port, struct ib_wc *in_wc, struct ib_grh *in_grh,
+                void *in_mad, void *response_mad);
+struct ib_ah *create_ib_ah(struct ib_ah_attr *ah_attr,
+                          struct mlx5_ib_ah *ah);
+struct ib_ah *mlx5_ib_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr);
+int mlx5_ib_query_ah(struct ib_ah *ibah, struct ib_ah_attr *ah_attr);
+int mlx5_ib_destroy_ah(struct ib_ah *ah);
+struct ib_srq *mlx5_ib_create_srq(struct ib_pd *pd,
+                                 struct ib_srq_init_attr *init_attr,
+                                 struct ib_udata *udata);
+int mlx5_ib_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr,
+                      enum ib_srq_attr_mask attr_mask, struct ib_udata *udata);
+int mlx5_ib_query_srq(struct ib_srq *ibsrq, struct ib_srq_attr *srq_attr);
+int mlx5_ib_destroy_srq(struct ib_srq *srq);
+int mlx5_ib_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr,
+                         struct ib_recv_wr **bad_wr);
+struct ib_qp *mlx5_ib_create_qp(struct ib_pd *pd,
+                               struct ib_qp_init_attr *init_attr,
+                               struct ib_udata *udata);
+int mlx5_ib_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
+                     int attr_mask, struct ib_udata *udata);
+int mlx5_ib_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr, int qp_attr_mask,
+                    struct ib_qp_init_attr *qp_init_attr);
+int mlx5_ib_destroy_qp(struct ib_qp *qp);
+int mlx5_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
+                     struct ib_send_wr **bad_wr);
+int mlx5_ib_post_recv(struct ib_qp *ibqp, struct ib_recv_wr *wr,
+                     struct ib_recv_wr **bad_wr);
+void *mlx5_get_send_wqe(struct mlx5_ib_qp *qp, int n);
+struct ib_cq *mlx5_ib_create_cq(struct ib_device *ibdev, int entries,
+                               int vector, struct ib_ucontext *context,
+                               struct ib_udata *udata);
+int mlx5_ib_destroy_cq(struct ib_cq *cq);
+int mlx5_ib_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc);
+int mlx5_ib_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags flags);
+int mlx5_ib_modify_cq(struct ib_cq *cq, u16 cq_count, u16 cq_period);
+int mlx5_ib_resize_cq(struct ib_cq *ibcq, int entries, struct ib_udata *udata);
+struct ib_mr *mlx5_ib_get_dma_mr(struct ib_pd *pd, int acc);
+struct ib_mr *mlx5_ib_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
+                                 u64 virt_addr, int access_flags,
+                                 struct ib_udata *udata);
+int mlx5_ib_dereg_mr(struct ib_mr *ibmr);
+struct ib_mr *mlx5_ib_alloc_fast_reg_mr(struct ib_pd *pd,
+                                       int max_page_list_len);
+struct ib_fast_reg_page_list *mlx5_ib_alloc_fast_reg_page_list(struct ib_device *ibdev,
+                                                              int page_list_len);
+void mlx5_ib_free_fast_reg_page_list(struct ib_fast_reg_page_list *page_list);
+struct ib_fmr *mlx5_ib_fmr_alloc(struct ib_pd *pd, int acc,
+                                struct ib_fmr_attr *fmr_attr);
+int mlx5_ib_map_phys_fmr(struct ib_fmr *ibfmr, u64 *page_list,
+                     int npages, u64 iova);
+int mlx5_ib_unmap_fmr(struct list_head *fmr_list);
+int mlx5_ib_fmr_dealloc(struct ib_fmr *ibfmr);
+int mlx5_ib_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num,
+                       struct ib_wc *in_wc, struct ib_grh *in_grh,
+                       struct ib_mad *in_mad, struct ib_mad *out_mad);
+struct ib_xrcd *mlx5_ib_alloc_xrcd(struct ib_device *ibdev,
+                                         struct ib_ucontext *context,
+                                         struct ib_udata *udata);
+int mlx5_ib_dealloc_xrcd(struct ib_xrcd *xrcd);
+int mlx5_vector2eqn(struct mlx5_ib_dev *dev, int vector, int *eqn, int *irqn);
+int mlx5_ib_get_buf_offset(u64 addr, int page_shift, u32 *offset);
+int mlx5_query_ext_port_caps(struct mlx5_ib_dev *dev, u8 port);
+int mlx5_ib_query_port(struct ib_device *ibdev, u8 port,
+                      struct ib_port_attr *props);
+int mlx5_ib_init_fmr(struct mlx5_ib_dev *dev);
+void mlx5_ib_cleanup_fmr(struct mlx5_ib_dev *dev);
+void mlx5_ib_cont_pages(struct ib_umem *umem, u64 addr, int *count, int *shift,
+                       int *ncont, int *order);
+void mlx5_ib_populate_pas(struct mlx5_ib_dev *dev, struct ib_umem *umem,
+                         int page_shift, __be64 *pas, int umr);
+void mlx5_ib_copy_pas(u64 *old, u64 *new, int step, int num);
+int mlx5_ib_get_cqe_size(struct mlx5_ib_dev *dev, struct ib_cq *ibcq);
+int mlx5_mr_cache_init(struct mlx5_ib_dev *dev);
+int mlx5_mr_cache_cleanup(struct mlx5_ib_dev *dev);
+int mlx5_mr_ib_cont_pages(struct ib_umem *umem, u64 addr, int *count, int *shift);
+void mlx5_umr_cq_handler(struct ib_cq *cq, void *cq_context);
+
+static inline void init_query_mad(struct ib_smp *mad)
+{
+       mad->base_version  = 1;
+       mad->mgmt_class    = IB_MGMT_CLASS_SUBN_LID_ROUTED;
+       mad->class_version = 1;
+       mad->method        = IB_MGMT_METHOD_GET;
+}
+
+static inline u8 convert_access(int acc)
+{
+       return (acc & IB_ACCESS_REMOTE_ATOMIC ? MLX5_PERM_ATOMIC       : 0) |
+              (acc & IB_ACCESS_REMOTE_WRITE  ? MLX5_PERM_REMOTE_WRITE : 0) |
+              (acc & IB_ACCESS_REMOTE_READ   ? MLX5_PERM_REMOTE_READ  : 0) |
+              (acc & IB_ACCESS_LOCAL_WRITE   ? MLX5_PERM_LOCAL_WRITE  : 0) |
+              MLX5_PERM_LOCAL_READ;
+}
+
+#endif /* MLX5_IB_H */
diff --git a/drivers/infiniband/hw/mlx5/mr.c b/drivers/infiniband/hw/mlx5/mr.c
new file mode 100644 (file)
index 0000000..bd41df9
--- /dev/null
@@ -0,0 +1,1007 @@
+/*
+ * Copyright (c) 2013, Mellanox Technologies inc.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+
+#include <linux/kref.h>
+#include <linux/random.h>
+#include <linux/debugfs.h>
+#include <linux/export.h>
+#include <rdma/ib_umem.h>
+#include "mlx5_ib.h"
+
+enum {
+       DEF_CACHE_SIZE  = 10,
+};
+
+static __be64 *mr_align(__be64 *ptr, int align)
+{
+       unsigned long mask = align - 1;
+
+       return (__be64 *)(((unsigned long)ptr + mask) & ~mask);
+}
+
+static int order2idx(struct mlx5_ib_dev *dev, int order)
+{
+       struct mlx5_mr_cache *cache = &dev->cache;
+
+       if (order < cache->ent[0].order)
+               return 0;
+       else
+               return order - cache->ent[0].order;
+}
+
+static int add_keys(struct mlx5_ib_dev *dev, int c, int num)
+{
+       struct device *ddev = dev->ib_dev.dma_device;
+       struct mlx5_mr_cache *cache = &dev->cache;
+       struct mlx5_cache_ent *ent = &cache->ent[c];
+       struct mlx5_create_mkey_mbox_in *in;
+       struct mlx5_ib_mr *mr;
+       int npages = 1 << ent->order;
+       int size = sizeof(u64) * npages;
+       int err = 0;
+       int i;
+
+       in = kzalloc(sizeof(*in), GFP_KERNEL);
+       if (!in)
+               return -ENOMEM;
+
+       for (i = 0; i < num; i++) {
+               mr = kzalloc(sizeof(*mr), GFP_KERNEL);
+               if (!mr) {
+                       err = -ENOMEM;
+                       goto out;
+               }
+               mr->order = ent->order;
+               mr->umred = 1;
+               mr->pas = kmalloc(size + 0x3f, GFP_KERNEL);
+               if (!mr->pas) {
+                       kfree(mr);
+                       err = -ENOMEM;
+                       goto out;
+               }
+               mr->dma = dma_map_single(ddev, mr_align(mr->pas, 0x40), size,
+                                        DMA_TO_DEVICE);
+               if (dma_mapping_error(ddev, mr->dma)) {
+                       kfree(mr->pas);
+                       kfree(mr);
+                       err = -ENOMEM;
+                       goto out;
+               }
+
+               in->seg.status = 1 << 6;
+               in->seg.xlt_oct_size = cpu_to_be32((npages + 1) / 2);
+               in->seg.qpn_mkey7_0 = cpu_to_be32(0xffffff << 8);
+               in->seg.flags = MLX5_ACCESS_MODE_MTT | MLX5_PERM_UMR_EN;
+               in->seg.log2_page_size = 12;
+
+               err = mlx5_core_create_mkey(&dev->mdev, &mr->mmr, in,
+                                           sizeof(*in));
+               if (err) {
+                       mlx5_ib_warn(dev, "create mkey failed %d\n", err);
+                       dma_unmap_single(ddev, mr->dma, size, DMA_TO_DEVICE);
+                       kfree(mr->pas);
+                       kfree(mr);
+                       goto out;
+               }
+               cache->last_add = jiffies;
+
+               spin_lock(&ent->lock);
+               list_add_tail(&mr->list, &ent->head);
+               ent->cur++;
+               ent->size++;
+               spin_unlock(&ent->lock);
+       }
+
+out:
+       kfree(in);
+       return err;
+}
+
+static void remove_keys(struct mlx5_ib_dev *dev, int c, int num)
+{
+       struct device *ddev = dev->ib_dev.dma_device;
+       struct mlx5_mr_cache *cache = &dev->cache;
+       struct mlx5_cache_ent *ent = &cache->ent[c];
+       struct mlx5_ib_mr *mr;
+       int size;
+       int err;
+       int i;
+
+       for (i = 0; i < num; i++) {
+               spin_lock(&ent->lock);
+               if (list_empty(&ent->head)) {
+                       spin_unlock(&ent->lock);
+                       return;
+               }
+               mr = list_first_entry(&ent->head, struct mlx5_ib_mr, list);
+               list_del(&mr->list);
+               ent->cur--;
+               ent->size--;
+               spin_unlock(&ent->lock);
+               err = mlx5_core_destroy_mkey(&dev->mdev, &mr->mmr);
+               if (err) {
+                       mlx5_ib_warn(dev, "failed destroy mkey\n");
+               } else {
+                       size = ALIGN(sizeof(u64) * (1 << mr->order), 0x40);
+                       dma_unmap_single(ddev, mr->dma, size, DMA_TO_DEVICE);
+                       kfree(mr->pas);
+                       kfree(mr);
+               }
+       }
+}
+
+static ssize_t size_write(struct file *filp, const char __user *buf,
+                         size_t count, loff_t *pos)
+{
+       struct mlx5_cache_ent *ent = filp->private_data;
+       struct mlx5_ib_dev *dev = ent->dev;
+       char lbuf[20];
+       u32 var;
+       int err;
+       int c;
+
+       if (copy_from_user(lbuf, buf, sizeof(lbuf)))
+               return -EFAULT;
+
+       c = order2idx(dev, ent->order);
+       lbuf[sizeof(lbuf) - 1] = 0;
+
+       if (sscanf(lbuf, "%u", &var) != 1)
+               return -EINVAL;
+
+       if (var < ent->limit)
+               return -EINVAL;
+
+       if (var > ent->size) {
+               err = add_keys(dev, c, var - ent->size);
+               if (err)
+                       return err;
+       } else if (var < ent->size) {
+               remove_keys(dev, c, ent->size - var);
+       }
+
+       return count;
+}
+
+static ssize_t size_read(struct file *filp, char __user *buf, size_t count,
+                        loff_t *pos)
+{
+       struct mlx5_cache_ent *ent = filp->private_data;
+       char lbuf[20];
+       int err;
+
+       if (*pos)
+               return 0;
+
+       err = snprintf(lbuf, sizeof(lbuf), "%d\n", ent->size);
+       if (err < 0)
+               return err;
+
+       if (copy_to_user(buf, lbuf, err))
+               return -EFAULT;
+
+       *pos += err;
+
+       return err;
+}
+
+static const struct file_operations size_fops = {
+       .owner  = THIS_MODULE,
+       .open   = simple_open,
+       .write  = size_write,
+       .read   = size_read,
+};
+
+static ssize_t limit_write(struct file *filp, const char __user *buf,
+                          size_t count, loff_t *pos)
+{
+       struct mlx5_cache_ent *ent = filp->private_data;
+       struct mlx5_ib_dev *dev = ent->dev;
+       char lbuf[20];
+       u32 var;
+       int err;
+       int c;
+
+       if (copy_from_user(lbuf, buf, sizeof(lbuf)))
+               return -EFAULT;
+
+       c = order2idx(dev, ent->order);
+       lbuf[sizeof(lbuf) - 1] = 0;
+
+       if (sscanf(lbuf, "%u", &var) != 1)
+               return -EINVAL;
+
+       if (var > ent->size)
+               return -EINVAL;
+
+       ent->limit = var;
+
+       if (ent->cur < ent->limit) {
+               err = add_keys(dev, c, 2 * ent->limit - ent->cur);
+               if (err)
+                       return err;
+       }
+
+       return count;
+}
+
+static ssize_t limit_read(struct file *filp, char __user *buf, size_t count,
+                         loff_t *pos)
+{
+       struct mlx5_cache_ent *ent = filp->private_data;
+       char lbuf[20];
+       int err;
+
+       if (*pos)
+               return 0;
+
+       err = snprintf(lbuf, sizeof(lbuf), "%d\n", ent->limit);
+       if (err < 0)
+               return err;
+
+       if (copy_to_user(buf, lbuf, err))
+               return -EFAULT;
+
+       *pos += err;
+
+       return err;
+}
+
+static const struct file_operations limit_fops = {
+       .owner  = THIS_MODULE,
+       .open   = simple_open,
+       .write  = limit_write,
+       .read   = limit_read,
+};
+
+static int someone_adding(struct mlx5_mr_cache *cache)
+{
+       int i;
+
+       for (i = 0; i < MAX_MR_CACHE_ENTRIES; i++) {
+               if (cache->ent[i].cur < cache->ent[i].limit)
+                       return 1;
+       }
+
+       return 0;
+}
+
+static void __cache_work_func(struct mlx5_cache_ent *ent)
+{
+       struct mlx5_ib_dev *dev = ent->dev;
+       struct mlx5_mr_cache *cache = &dev->cache;
+       int i = order2idx(dev, ent->order);
+
+       if (cache->stopped)
+               return;
+
+       ent = &dev->cache.ent[i];
+       if (ent->cur < 2 * ent->limit) {
+               add_keys(dev, i, 1);
+               if (ent->cur < 2 * ent->limit)
+                       queue_work(cache->wq, &ent->work);
+       } else if (ent->cur > 2 * ent->limit) {
+               if (!someone_adding(cache) &&
+                   time_after(jiffies, cache->last_add + 60 * HZ)) {
+                       remove_keys(dev, i, 1);
+                       if (ent->cur > ent->limit)
+                               queue_work(cache->wq, &ent->work);
+               } else {
+                       queue_delayed_work(cache->wq, &ent->dwork, 60 * HZ);
+               }
+       }
+}
+
+static void delayed_cache_work_func(struct work_struct *work)
+{
+       struct mlx5_cache_ent *ent;
+
+       ent = container_of(work, struct mlx5_cache_ent, dwork.work);
+       __cache_work_func(ent);
+}
+
+static void cache_work_func(struct work_struct *work)
+{
+       struct mlx5_cache_ent *ent;
+
+       ent = container_of(work, struct mlx5_cache_ent, work);
+       __cache_work_func(ent);
+}
+
+static struct mlx5_ib_mr *alloc_cached_mr(struct mlx5_ib_dev *dev, int order)
+{
+       struct mlx5_mr_cache *cache = &dev->cache;
+       struct mlx5_ib_mr *mr = NULL;
+       struct mlx5_cache_ent *ent;
+       int c;
+       int i;
+
+       c = order2idx(dev, order);
+       if (c < 0 || c >= MAX_MR_CACHE_ENTRIES) {
+               mlx5_ib_warn(dev, "order %d, cache index %d\n", order, c);
+               return NULL;
+       }
+
+       for (i = c; i < MAX_MR_CACHE_ENTRIES; i++) {
+               ent = &cache->ent[i];
+
+               mlx5_ib_dbg(dev, "order %d, cache index %d\n", ent->order, i);
+
+               spin_lock(&ent->lock);
+               if (!list_empty(&ent->head)) {
+                       mr = list_first_entry(&ent->head, struct mlx5_ib_mr,
+                                             list);
+                       list_del(&mr->list);
+                       ent->cur--;
+                       spin_unlock(&ent->lock);
+                       if (ent->cur < ent->limit)
+                               queue_work(cache->wq, &ent->work);
+                       break;
+               }
+               spin_unlock(&ent->lock);
+
+               queue_work(cache->wq, &ent->work);
+
+               if (mr)
+                       break;
+       }
+
+       if (!mr)
+               cache->ent[c].miss++;
+
+       return mr;
+}
+
+static void free_cached_mr(struct mlx5_ib_dev *dev, struct mlx5_ib_mr *mr)
+{
+       struct mlx5_mr_cache *cache = &dev->cache;
+       struct mlx5_cache_ent *ent;
+       int shrink = 0;
+       int c;
+
+       c = order2idx(dev, mr->order);
+       if (c < 0 || c >= MAX_MR_CACHE_ENTRIES) {
+               mlx5_ib_warn(dev, "order %d, cache index %d\n", mr->order, c);
+               return;
+       }
+       ent = &cache->ent[c];
+       spin_lock(&ent->lock);
+       list_add_tail(&mr->list, &ent->head);
+       ent->cur++;
+       if (ent->cur > 2 * ent->limit)
+               shrink = 1;
+       spin_unlock(&ent->lock);
+
+       if (shrink)
+               queue_work(cache->wq, &ent->work);
+}
+
+static void clean_keys(struct mlx5_ib_dev *dev, int c)
+{
+       struct device *ddev = dev->ib_dev.dma_device;
+       struct mlx5_mr_cache *cache = &dev->cache;
+       struct mlx5_cache_ent *ent = &cache->ent[c];
+       struct mlx5_ib_mr *mr;
+       int size;
+       int err;
+
+       while (1) {
+               spin_lock(&ent->lock);
+               if (list_empty(&ent->head)) {
+                       spin_unlock(&ent->lock);
+                       return;
+               }
+               mr = list_first_entry(&ent->head, struct mlx5_ib_mr, list);
+               list_del(&mr->list);
+               ent->cur--;
+               ent->size--;
+               spin_unlock(&ent->lock);
+               err = mlx5_core_destroy_mkey(&dev->mdev, &mr->mmr);
+               if (err) {
+                       mlx5_ib_warn(dev, "failed destroy mkey\n");
+               } else {
+                       size = ALIGN(sizeof(u64) * (1 << mr->order), 0x40);
+                       dma_unmap_single(ddev, mr->dma, size, DMA_TO_DEVICE);
+                       kfree(mr->pas);
+                       kfree(mr);
+               }
+       }
+}
+
+static int mlx5_mr_cache_debugfs_init(struct mlx5_ib_dev *dev)
+{
+       struct mlx5_mr_cache *cache = &dev->cache;
+       struct mlx5_cache_ent *ent;
+       int i;
+
+       if (!mlx5_debugfs_root)
+               return 0;
+
+       cache->root = debugfs_create_dir("mr_cache", dev->mdev.priv.dbg_root);
+       if (!cache->root)
+               return -ENOMEM;
+
+       for (i = 0; i < MAX_MR_CACHE_ENTRIES; i++) {
+               ent = &cache->ent[i];
+               sprintf(ent->name, "%d", ent->order);
+               ent->dir = debugfs_create_dir(ent->name,  cache->root);
+               if (!ent->dir)
+                       return -ENOMEM;
+
+               ent->fsize = debugfs_create_file("size", 0600, ent->dir, ent,
+                                                &size_fops);
+               if (!ent->fsize)
+                       return -ENOMEM;
+
+               ent->flimit = debugfs_create_file("limit", 0600, ent->dir, ent,
+                                                 &limit_fops);
+               if (!ent->flimit)
+                       return -ENOMEM;
+
+               ent->fcur = debugfs_create_u32("cur", 0400, ent->dir,
+                                              &ent->cur);
+               if (!ent->fcur)
+                       return -ENOMEM;
+
+               ent->fmiss = debugfs_create_u32("miss", 0600, ent->dir,
+                                               &ent->miss);
+               if (!ent->fmiss)
+                       return -ENOMEM;
+       }
+
+       return 0;
+}
+
+static void mlx5_mr_cache_debugfs_cleanup(struct mlx5_ib_dev *dev)
+{
+       if (!mlx5_debugfs_root)
+               return;
+
+       debugfs_remove_recursive(dev->cache.root);
+}
+
+int mlx5_mr_cache_init(struct mlx5_ib_dev *dev)
+{
+       struct mlx5_mr_cache *cache = &dev->cache;
+       struct mlx5_cache_ent *ent;
+       int limit;
+       int size;
+       int err;
+       int i;
+
+       cache->wq = create_singlethread_workqueue("mkey_cache");
+       if (!cache->wq) {
+               mlx5_ib_warn(dev, "failed to create work queue\n");
+               return -ENOMEM;
+       }
+
+       for (i = 0; i < MAX_MR_CACHE_ENTRIES; i++) {
+               INIT_LIST_HEAD(&cache->ent[i].head);
+               spin_lock_init(&cache->ent[i].lock);
+
+               ent = &cache->ent[i];
+               INIT_LIST_HEAD(&ent->head);
+               spin_lock_init(&ent->lock);
+               ent->order = i + 2;
+               ent->dev = dev;
+
+               if (dev->mdev.profile->mask & MLX5_PROF_MASK_MR_CACHE) {
+                       size = dev->mdev.profile->mr_cache[i].size;
+                       limit = dev->mdev.profile->mr_cache[i].limit;
+               } else {
+                       size = DEF_CACHE_SIZE;
+                       limit = 0;
+               }
+               INIT_WORK(&ent->work, cache_work_func);
+               INIT_DELAYED_WORK(&ent->dwork, delayed_cache_work_func);
+               ent->limit = limit;
+               queue_work(cache->wq, &ent->work);
+       }
+
+       err = mlx5_mr_cache_debugfs_init(dev);
+       if (err)
+               mlx5_ib_warn(dev, "cache debugfs failure\n");
+
+       return 0;
+}
+
+int mlx5_mr_cache_cleanup(struct mlx5_ib_dev *dev)
+{
+       int i;
+
+       dev->cache.stopped = 1;
+       destroy_workqueue(dev->cache.wq);
+
+       mlx5_mr_cache_debugfs_cleanup(dev);
+
+       for (i = 0; i < MAX_MR_CACHE_ENTRIES; i++)
+               clean_keys(dev, i);
+
+       return 0;
+}
+
+struct ib_mr *mlx5_ib_get_dma_mr(struct ib_pd *pd, int acc)
+{
+       struct mlx5_ib_dev *dev = to_mdev(pd->device);
+       struct mlx5_core_dev *mdev = &dev->mdev;
+       struct mlx5_create_mkey_mbox_in *in;
+       struct mlx5_mkey_seg *seg;
+       struct mlx5_ib_mr *mr;
+       int err;
+
+       mr = kzalloc(sizeof(*mr), GFP_KERNEL);
+       if (!mr)
+               return ERR_PTR(-ENOMEM);
+
+       in = kzalloc(sizeof(*in), GFP_KERNEL);
+       if (!in) {
+               err = -ENOMEM;
+               goto err_free;
+       }
+
+       seg = &in->seg;
+       seg->flags = convert_access(acc) | MLX5_ACCESS_MODE_PA;
+       seg->flags_pd = cpu_to_be32(to_mpd(pd)->pdn | MLX5_MKEY_LEN64);
+       seg->qpn_mkey7_0 = cpu_to_be32(0xffffff << 8);
+       seg->start_addr = 0;
+
+       err = mlx5_core_create_mkey(mdev, &mr->mmr, in, sizeof(*in));
+       if (err)
+               goto err_in;
+
+       kfree(in);
+       mr->ibmr.lkey = mr->mmr.key;
+       mr->ibmr.rkey = mr->mmr.key;
+       mr->umem = NULL;
+
+       return &mr->ibmr;
+
+err_in:
+       kfree(in);
+
+err_free:
+       kfree(mr);
+
+       return ERR_PTR(err);
+}
+
+static int get_octo_len(u64 addr, u64 len, int page_size)
+{
+       u64 offset;
+       int npages;
+
+       offset = addr & (page_size - 1);
+       npages = ALIGN(len + offset, page_size) >> ilog2(page_size);
+       return (npages + 1) / 2;
+}
+
+static int use_umr(int order)
+{
+       return order <= 17;
+}
+
+static void prep_umr_reg_wqe(struct ib_pd *pd, struct ib_send_wr *wr,
+                            struct ib_sge *sg, u64 dma, int n, u32 key,
+                            int page_shift, u64 virt_addr, u64 len,
+                            int access_flags)
+{
+       struct mlx5_ib_dev *dev = to_mdev(pd->device);
+       struct ib_mr *mr = dev->umrc.mr;
+
+       sg->addr = dma;
+       sg->length = ALIGN(sizeof(u64) * n, 64);
+       sg->lkey = mr->lkey;
+
+       wr->next = NULL;
+       wr->send_flags = 0;
+       wr->sg_list = sg;
+       if (n)
+               wr->num_sge = 1;
+       else
+               wr->num_sge = 0;
+
+       wr->opcode = MLX5_IB_WR_UMR;
+       wr->wr.fast_reg.page_list_len = n;
+       wr->wr.fast_reg.page_shift = page_shift;
+       wr->wr.fast_reg.rkey = key;
+       wr->wr.fast_reg.iova_start = virt_addr;
+       wr->wr.fast_reg.length = len;
+       wr->wr.fast_reg.access_flags = access_flags;
+       wr->wr.fast_reg.page_list = (struct ib_fast_reg_page_list *)pd;
+}
+
+static void prep_umr_unreg_wqe(struct mlx5_ib_dev *dev,
+                              struct ib_send_wr *wr, u32 key)
+{
+       wr->send_flags = MLX5_IB_SEND_UMR_UNREG;
+       wr->opcode = MLX5_IB_WR_UMR;
+       wr->wr.fast_reg.rkey = key;
+}
+
+void mlx5_umr_cq_handler(struct ib_cq *cq, void *cq_context)
+{
+       struct mlx5_ib_mr *mr;
+       struct ib_wc wc;
+       int err;
+
+       while (1) {
+               err = ib_poll_cq(cq, 1, &wc);
+               if (err < 0) {
+                       pr_warn("poll cq error %d\n", err);
+                       return;
+               }
+               if (err == 0)
+                       break;
+
+               mr = (struct mlx5_ib_mr *)(unsigned long)wc.wr_id;
+               mr->status = wc.status;
+               complete(&mr->done);
+       }
+       ib_req_notify_cq(cq, IB_CQ_NEXT_COMP);
+}
+
+static struct mlx5_ib_mr *reg_umr(struct ib_pd *pd, struct ib_umem *umem,
+                                 u64 virt_addr, u64 len, int npages,
+                                 int page_shift, int order, int access_flags)
+{
+       struct mlx5_ib_dev *dev = to_mdev(pd->device);
+       struct umr_common *umrc = &dev->umrc;
+       struct ib_send_wr wr, *bad;
+       struct mlx5_ib_mr *mr;
+       struct ib_sge sg;
+       int err;
+       int i;
+
+       for (i = 0; i < 10; i++) {
+               mr = alloc_cached_mr(dev, order);
+               if (mr)
+                       break;
+
+               err = add_keys(dev, order2idx(dev, order), 1);
+               if (err) {
+                       mlx5_ib_warn(dev, "add_keys failed\n");
+                       break;
+               }
+       }
+
+       if (!mr)
+               return ERR_PTR(-EAGAIN);
+
+       mlx5_ib_populate_pas(dev, umem, page_shift, mr_align(mr->pas, 0x40), 1);
+
+       memset(&wr, 0, sizeof(wr));
+       wr.wr_id = (u64)(unsigned long)mr;
+       prep_umr_reg_wqe(pd, &wr, &sg, mr->dma, npages, mr->mmr.key, page_shift, virt_addr, len, access_flags);
+
+       /* We serialize polls so one process does not kidnap another's
+        * completion. This is not a problem since wr is completed in
+        * around 1 usec
+        */
+       down(&umrc->sem);
+       init_completion(&mr->done);
+       err = ib_post_send(umrc->qp, &wr, &bad);
+       if (err) {
+               mlx5_ib_warn(dev, "post send failed, err %d\n", err);
+               up(&umrc->sem);
+               goto error;
+       }
+       wait_for_completion(&mr->done);
+       up(&umrc->sem);
+
+       if (mr->status != IB_WC_SUCCESS) {
+               mlx5_ib_warn(dev, "reg umr failed\n");
+               err = -EFAULT;
+               goto error;
+       }
+
+       return mr;
+
+error:
+       free_cached_mr(dev, mr);
+       return ERR_PTR(err);
+}
+
+static struct mlx5_ib_mr *reg_create(struct ib_pd *pd, u64 virt_addr,
+                                    u64 length, struct ib_umem *umem,
+                                    int npages, int page_shift,
+                                    int access_flags)
+{
+       struct mlx5_ib_dev *dev = to_mdev(pd->device);
+       struct mlx5_create_mkey_mbox_in *in;
+       struct mlx5_ib_mr *mr;
+       int inlen;
+       int err;
+
+       mr = kzalloc(sizeof(*mr), GFP_KERNEL);
+       if (!mr)
+               return ERR_PTR(-ENOMEM);
+
+       inlen = sizeof(*in) + sizeof(*in->pas) * ((npages + 1) / 2) * 2;
+       in = mlx5_vzalloc(inlen);
+       if (!in) {
+               err = -ENOMEM;
+               goto err_1;
+       }
+       mlx5_ib_populate_pas(dev, umem, page_shift, in->pas, 0);
+
+       in->seg.flags = convert_access(access_flags) |
+               MLX5_ACCESS_MODE_MTT;
+       in->seg.flags_pd = cpu_to_be32(to_mpd(pd)->pdn);
+       in->seg.start_addr = cpu_to_be64(virt_addr);
+       in->seg.len = cpu_to_be64(length);
+       in->seg.bsfs_octo_size = 0;
+       in->seg.xlt_oct_size = cpu_to_be32(get_octo_len(virt_addr, length, 1 << page_shift));
+       in->seg.log2_page_size = page_shift;
+       in->seg.qpn_mkey7_0 = cpu_to_be32(0xffffff << 8);
+       in->xlat_oct_act_size = cpu_to_be32(get_octo_len(virt_addr, length, 1 << page_shift));
+       err = mlx5_core_create_mkey(&dev->mdev, &mr->mmr, in, inlen);
+       if (err) {
+               mlx5_ib_warn(dev, "create mkey failed\n");
+               goto err_2;
+       }
+       mr->umem = umem;
+       mlx5_vfree(in);
+
+       mlx5_ib_dbg(dev, "mkey = 0x%x\n", mr->mmr.key);
+
+       return mr;
+
+err_2:
+       mlx5_vfree(in);
+
+err_1:
+       kfree(mr);
+
+       return ERR_PTR(err);
+}
+
+struct ib_mr *mlx5_ib_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
+                                 u64 virt_addr, int access_flags,
+                                 struct ib_udata *udata)
+{
+       struct mlx5_ib_dev *dev = to_mdev(pd->device);
+       struct mlx5_ib_mr *mr = NULL;
+       struct ib_umem *umem;
+       int page_shift;
+       int npages;
+       int ncont;
+       int order;
+       int err;
+
+       mlx5_ib_dbg(dev, "start 0x%llx, virt_addr 0x%llx, length 0x%llx\n",
+                   start, virt_addr, length);
+       umem = ib_umem_get(pd->uobject->context, start, length, access_flags,
+                          0);
+       if (IS_ERR(umem)) {
+               mlx5_ib_dbg(dev, "umem get failed\n");
+               return (void *)umem;
+       }
+
+       mlx5_ib_cont_pages(umem, start, &npages, &page_shift, &ncont, &order);
+       if (!npages) {
+               mlx5_ib_warn(dev, "avoid zero region\n");
+               err = -EINVAL;
+               goto error;
+       }
+
+       mlx5_ib_dbg(dev, "npages %d, ncont %d, order %d, page_shift %d\n",
+                   npages, ncont, order, page_shift);
+
+       if (use_umr(order)) {
+               mr = reg_umr(pd, umem, virt_addr, length, ncont, page_shift,
+                            order, access_flags);
+               if (PTR_ERR(mr) == -EAGAIN) {
+                       mlx5_ib_dbg(dev, "cache empty for order %d", order);
+                       mr = NULL;
+               }
+       }
+
+       if (!mr)
+               mr = reg_create(pd, virt_addr, length, umem, ncont, page_shift,
+                               access_flags);
+
+       if (IS_ERR(mr)) {
+               err = PTR_ERR(mr);
+               goto error;
+       }
+
+       mlx5_ib_dbg(dev, "mkey 0x%x\n", mr->mmr.key);
+
+       mr->umem = umem;
+       mr->npages = npages;
+       spin_lock(&dev->mr_lock);
+       dev->mdev.priv.reg_pages += npages;
+       spin_unlock(&dev->mr_lock);
+       mr->ibmr.lkey = mr->mmr.key;
+       mr->ibmr.rkey = mr->mmr.key;
+
+       return &mr->ibmr;
+
+error:
+       ib_umem_release(umem);
+       return ERR_PTR(err);
+}
+
+static int unreg_umr(struct mlx5_ib_dev *dev, struct mlx5_ib_mr *mr)
+{
+       struct umr_common *umrc = &dev->umrc;
+       struct ib_send_wr wr, *bad;
+       int err;
+
+       memset(&wr, 0, sizeof(wr));
+       wr.wr_id = (u64)(unsigned long)mr;
+       prep_umr_unreg_wqe(dev, &wr, mr->mmr.key);
+
+       down(&umrc->sem);
+       init_completion(&mr->done);
+       err = ib_post_send(umrc->qp, &wr, &bad);
+       if (err) {
+               up(&umrc->sem);
+               mlx5_ib_dbg(dev, "err %d\n", err);
+               goto error;
+       }
+       wait_for_completion(&mr->done);
+       up(&umrc->sem);
+       if (mr->status != IB_WC_SUCCESS) {
+               mlx5_ib_warn(dev, "unreg umr failed\n");
+               err = -EFAULT;
+               goto error;
+       }
+       return 0;
+
+error:
+       return err;
+}
+
+int mlx5_ib_dereg_mr(struct ib_mr *ibmr)
+{
+       struct mlx5_ib_dev *dev = to_mdev(ibmr->device);
+       struct mlx5_ib_mr *mr = to_mmr(ibmr);
+       struct ib_umem *umem = mr->umem;
+       int npages = mr->npages;
+       int umred = mr->umred;
+       int err;
+
+       if (!umred) {
+               err = mlx5_core_destroy_mkey(&dev->mdev, &mr->mmr);
+               if (err) {
+                       mlx5_ib_warn(dev, "failed to destroy mkey 0x%x (%d)\n",
+                                    mr->mmr.key, err);
+                       return err;
+               }
+       } else {
+               err = unreg_umr(dev, mr);
+               if (err) {
+                       mlx5_ib_warn(dev, "failed unregister\n");
+                       return err;
+               }
+               free_cached_mr(dev, mr);
+       }
+
+       if (umem) {
+               ib_umem_release(umem);
+               spin_lock(&dev->mr_lock);
+               dev->mdev.priv.reg_pages -= npages;
+               spin_unlock(&dev->mr_lock);
+       }
+
+       if (!umred)
+               kfree(mr);
+
+       return 0;
+}
+
+struct ib_mr *mlx5_ib_alloc_fast_reg_mr(struct ib_pd *pd,
+                                       int max_page_list_len)
+{
+       struct mlx5_ib_dev *dev = to_mdev(pd->device);
+       struct mlx5_create_mkey_mbox_in *in;
+       struct mlx5_ib_mr *mr;
+       int err;
+
+       mr = kzalloc(sizeof(*mr), GFP_KERNEL);
+       if (!mr)
+               return ERR_PTR(-ENOMEM);
+
+       in = kzalloc(sizeof(*in), GFP_KERNEL);
+       if (!in) {
+               err = -ENOMEM;
+               goto err_free;
+       }
+
+       in->seg.status = 1 << 6; /* free */
+       in->seg.xlt_oct_size = cpu_to_be32((max_page_list_len + 1) / 2);
+       in->seg.qpn_mkey7_0 = cpu_to_be32(0xffffff << 8);
+       in->seg.flags = MLX5_PERM_UMR_EN | MLX5_ACCESS_MODE_MTT;
+       in->seg.flags_pd = cpu_to_be32(to_mpd(pd)->pdn);
+       /*
+        * TBD not needed - issue 197292 */
+       in->seg.log2_page_size = PAGE_SHIFT;
+
+       err = mlx5_core_create_mkey(&dev->mdev, &mr->mmr, in, sizeof(*in));
+       kfree(in);
+       if (err)
+               goto err_free;
+
+       mr->ibmr.lkey = mr->mmr.key;
+       mr->ibmr.rkey = mr->mmr.key;
+       mr->umem = NULL;
+
+       return &mr->ibmr;
+
+err_free:
+       kfree(mr);
+       return ERR_PTR(err);
+}
+
+struct ib_fast_reg_page_list *mlx5_ib_alloc_fast_reg_page_list(struct ib_device *ibdev,
+                                                              int page_list_len)
+{
+       struct mlx5_ib_fast_reg_page_list *mfrpl;
+       int size = page_list_len * sizeof(u64);
+
+       mfrpl = kmalloc(sizeof(*mfrpl), GFP_KERNEL);
+       if (!mfrpl)
+               return ERR_PTR(-ENOMEM);
+
+       mfrpl->ibfrpl.page_list = kmalloc(size, GFP_KERNEL);
+       if (!mfrpl->ibfrpl.page_list)
+               goto err_free;
+
+       mfrpl->mapped_page_list = dma_alloc_coherent(ibdev->dma_device,
+                                                    size, &mfrpl->map,
+                                                    GFP_KERNEL);
+       if (!mfrpl->mapped_page_list)
+               goto err_free;
+
+       WARN_ON(mfrpl->map & 0x3f);
+
+       return &mfrpl->ibfrpl;
+
+err_free:
+       kfree(mfrpl->ibfrpl.page_list);
+       kfree(mfrpl);
+       return ERR_PTR(-ENOMEM);
+}
+
+void mlx5_ib_free_fast_reg_page_list(struct ib_fast_reg_page_list *page_list)
+{
+       struct mlx5_ib_fast_reg_page_list *mfrpl = to_mfrpl(page_list);
+       struct mlx5_ib_dev *dev = to_mdev(page_list->device);
+       int size = page_list->max_page_list_len * sizeof(u64);
+
+       dma_free_coherent(&dev->mdev.pdev->dev, size, mfrpl->mapped_page_list,
+                         mfrpl->map);
+       kfree(mfrpl->ibfrpl.page_list);
+       kfree(mfrpl);
+}
diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c
new file mode 100644 (file)
index 0000000..16ac54c
--- /dev/null
@@ -0,0 +1,2524 @@
+/*
+ * Copyright (c) 2013, Mellanox Technologies inc.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/module.h>
+#include <rdma/ib_umem.h>
+#include "mlx5_ib.h"
+#include "user.h"
+
+/* not supported currently */
+static int wq_signature;
+
+enum {
+       MLX5_IB_ACK_REQ_FREQ    = 8,
+};
+
+enum {
+       MLX5_IB_DEFAULT_SCHED_QUEUE     = 0x83,
+       MLX5_IB_DEFAULT_QP0_SCHED_QUEUE = 0x3f,
+       MLX5_IB_LINK_TYPE_IB            = 0,
+       MLX5_IB_LINK_TYPE_ETH           = 1
+};
+
+enum {
+       MLX5_IB_SQ_STRIDE       = 6,
+       MLX5_IB_CACHE_LINE_SIZE = 64,
+};
+
+static const u32 mlx5_ib_opcode[] = {
+       [IB_WR_SEND]                            = MLX5_OPCODE_SEND,
+       [IB_WR_SEND_WITH_IMM]                   = MLX5_OPCODE_SEND_IMM,
+       [IB_WR_RDMA_WRITE]                      = MLX5_OPCODE_RDMA_WRITE,
+       [IB_WR_RDMA_WRITE_WITH_IMM]             = MLX5_OPCODE_RDMA_WRITE_IMM,
+       [IB_WR_RDMA_READ]                       = MLX5_OPCODE_RDMA_READ,
+       [IB_WR_ATOMIC_CMP_AND_SWP]              = MLX5_OPCODE_ATOMIC_CS,
+       [IB_WR_ATOMIC_FETCH_AND_ADD]            = MLX5_OPCODE_ATOMIC_FA,
+       [IB_WR_SEND_WITH_INV]                   = MLX5_OPCODE_SEND_INVAL,
+       [IB_WR_LOCAL_INV]                       = MLX5_OPCODE_UMR,
+       [IB_WR_FAST_REG_MR]                     = MLX5_OPCODE_UMR,
+       [IB_WR_MASKED_ATOMIC_CMP_AND_SWP]       = MLX5_OPCODE_ATOMIC_MASKED_CS,
+       [IB_WR_MASKED_ATOMIC_FETCH_AND_ADD]     = MLX5_OPCODE_ATOMIC_MASKED_FA,
+       [MLX5_IB_WR_UMR]                        = MLX5_OPCODE_UMR,
+};
+
+struct umr_wr {
+       u64                             virt_addr;
+       struct ib_pd                   *pd;
+       unsigned int                    page_shift;
+       unsigned int                    npages;
+       u32                             length;
+       int                             access_flags;
+       u32                             mkey;
+};
+
+static int is_qp0(enum ib_qp_type qp_type)
+{
+       return qp_type == IB_QPT_SMI;
+}
+
+static int is_qp1(enum ib_qp_type qp_type)
+{
+       return qp_type == IB_QPT_GSI;
+}
+
+static int is_sqp(enum ib_qp_type qp_type)
+{
+       return is_qp0(qp_type) || is_qp1(qp_type);
+}
+
+static void *get_wqe(struct mlx5_ib_qp *qp, int offset)
+{
+       return mlx5_buf_offset(&qp->buf, offset);
+}
+
+static void *get_recv_wqe(struct mlx5_ib_qp *qp, int n)
+{
+       return get_wqe(qp, qp->rq.offset + (n << qp->rq.wqe_shift));
+}
+
+void *mlx5_get_send_wqe(struct mlx5_ib_qp *qp, int n)
+{
+       return get_wqe(qp, qp->sq.offset + (n << MLX5_IB_SQ_STRIDE));
+}
+
+static void mlx5_ib_qp_event(struct mlx5_core_qp *qp, int type)
+{
+       struct ib_qp *ibqp = &to_mibqp(qp)->ibqp;
+       struct ib_event event;
+
+       if (type == MLX5_EVENT_TYPE_PATH_MIG)
+               to_mibqp(qp)->port = to_mibqp(qp)->alt_port;
+
+       if (ibqp->event_handler) {
+               event.device     = ibqp->device;
+               event.element.qp = ibqp;
+               switch (type) {
+               case MLX5_EVENT_TYPE_PATH_MIG:
+                       event.event = IB_EVENT_PATH_MIG;
+                       break;
+               case MLX5_EVENT_TYPE_COMM_EST:
+                       event.event = IB_EVENT_COMM_EST;
+                       break;
+               case MLX5_EVENT_TYPE_SQ_DRAINED:
+                       event.event = IB_EVENT_SQ_DRAINED;
+                       break;
+               case MLX5_EVENT_TYPE_SRQ_LAST_WQE:
+                       event.event = IB_EVENT_QP_LAST_WQE_REACHED;
+                       break;
+               case MLX5_EVENT_TYPE_WQ_CATAS_ERROR:
+                       event.event = IB_EVENT_QP_FATAL;
+                       break;
+               case MLX5_EVENT_TYPE_PATH_MIG_FAILED:
+                       event.event = IB_EVENT_PATH_MIG_ERR;
+                       break;
+               case MLX5_EVENT_TYPE_WQ_INVAL_REQ_ERROR:
+                       event.event = IB_EVENT_QP_REQ_ERR;
+                       break;
+               case MLX5_EVENT_TYPE_WQ_ACCESS_ERROR:
+                       event.event = IB_EVENT_QP_ACCESS_ERR;
+                       break;
+               default:
+                       pr_warn("mlx5_ib: Unexpected event type %d on QP %06x\n", type, qp->qpn);
+                       return;
+               }
+
+               ibqp->event_handler(&event, ibqp->qp_context);
+       }
+}
+
+static int set_rq_size(struct mlx5_ib_dev *dev, struct ib_qp_cap *cap,
+                      int has_rq, struct mlx5_ib_qp *qp, struct mlx5_ib_create_qp *ucmd)
+{
+       int wqe_size;
+       int wq_size;
+
+       /* Sanity check RQ size before proceeding */
+       if (cap->max_recv_wr  > dev->mdev.caps.max_wqes)
+               return -EINVAL;
+
+       if (!has_rq) {
+               qp->rq.max_gs = 0;
+               qp->rq.wqe_cnt = 0;
+               qp->rq.wqe_shift = 0;
+       } else {
+               if (ucmd) {
+                       qp->rq.wqe_cnt = ucmd->rq_wqe_count;
+                       qp->rq.wqe_shift = ucmd->rq_wqe_shift;
+                       qp->rq.max_gs = (1 << qp->rq.wqe_shift) / sizeof(struct mlx5_wqe_data_seg) - qp->wq_sig;
+                       qp->rq.max_post = qp->rq.wqe_cnt;
+               } else {
+                       wqe_size = qp->wq_sig ? sizeof(struct mlx5_wqe_signature_seg) : 0;
+                       wqe_size += cap->max_recv_sge * sizeof(struct mlx5_wqe_data_seg);
+                       wqe_size = roundup_pow_of_two(wqe_size);
+                       wq_size = roundup_pow_of_two(cap->max_recv_wr) * wqe_size;
+                       wq_size = max_t(int, wq_size, MLX5_SEND_WQE_BB);
+                       qp->rq.wqe_cnt = wq_size / wqe_size;
+                       if (wqe_size > dev->mdev.caps.max_rq_desc_sz) {
+                               mlx5_ib_dbg(dev, "wqe_size %d, max %d\n",
+                                           wqe_size,
+                                           dev->mdev.caps.max_rq_desc_sz);
+                               return -EINVAL;
+                       }
+                       qp->rq.wqe_shift = ilog2(wqe_size);
+                       qp->rq.max_gs = (1 << qp->rq.wqe_shift) / sizeof(struct mlx5_wqe_data_seg) - qp->wq_sig;
+                       qp->rq.max_post = qp->rq.wqe_cnt;
+               }
+       }
+
+       return 0;
+}
+
+static int sq_overhead(enum ib_qp_type qp_type)
+{
+       int size;
+
+       switch (qp_type) {
+       case IB_QPT_XRC_INI:
+               size = sizeof(struct mlx5_wqe_xrc_seg);
+               /* fall through */
+       case IB_QPT_RC:
+               size += sizeof(struct mlx5_wqe_ctrl_seg) +
+                       sizeof(struct mlx5_wqe_atomic_seg) +
+                       sizeof(struct mlx5_wqe_raddr_seg);
+               break;
+
+       case IB_QPT_UC:
+               size = sizeof(struct mlx5_wqe_ctrl_seg) +
+                       sizeof(struct mlx5_wqe_raddr_seg);
+               break;
+
+       case IB_QPT_UD:
+       case IB_QPT_SMI:
+       case IB_QPT_GSI:
+               size = sizeof(struct mlx5_wqe_ctrl_seg) +
+                       sizeof(struct mlx5_wqe_datagram_seg);
+               break;
+
+       case MLX5_IB_QPT_REG_UMR:
+               size = sizeof(struct mlx5_wqe_ctrl_seg) +
+                       sizeof(struct mlx5_wqe_umr_ctrl_seg) +
+                       sizeof(struct mlx5_mkey_seg);
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       return size;
+}
+
+static int calc_send_wqe(struct ib_qp_init_attr *attr)
+{
+       int inl_size = 0;
+       int size;
+
+       size = sq_overhead(attr->qp_type);
+       if (size < 0)
+               return size;
+
+       if (attr->cap.max_inline_data) {
+               inl_size = size + sizeof(struct mlx5_wqe_inline_seg) +
+                       attr->cap.max_inline_data;
+       }
+
+       size += attr->cap.max_send_sge * sizeof(struct mlx5_wqe_data_seg);
+
+       return ALIGN(max_t(int, inl_size, size), MLX5_SEND_WQE_BB);
+}
+
+static int calc_sq_size(struct mlx5_ib_dev *dev, struct ib_qp_init_attr *attr,
+                       struct mlx5_ib_qp *qp)
+{
+       int wqe_size;
+       int wq_size;
+
+       if (!attr->cap.max_send_wr)
+               return 0;
+
+       wqe_size = calc_send_wqe(attr);
+       mlx5_ib_dbg(dev, "wqe_size %d\n", wqe_size);
+       if (wqe_size < 0)
+               return wqe_size;
+
+       if (wqe_size > dev->mdev.caps.max_sq_desc_sz) {
+               mlx5_ib_dbg(dev, "\n");
+               return -EINVAL;
+       }
+
+       qp->max_inline_data = wqe_size - sq_overhead(attr->qp_type) -
+               sizeof(struct mlx5_wqe_inline_seg);
+       attr->cap.max_inline_data = qp->max_inline_data;
+
+       wq_size = roundup_pow_of_two(attr->cap.max_send_wr * wqe_size);
+       qp->sq.wqe_cnt = wq_size / MLX5_SEND_WQE_BB;
+       qp->sq.wqe_shift = ilog2(MLX5_SEND_WQE_BB);
+       qp->sq.max_gs = attr->cap.max_send_sge;
+       qp->sq.max_post = 1 << ilog2(wq_size / wqe_size);
+
+       return wq_size;
+}
+
+static int set_user_buf_size(struct mlx5_ib_dev *dev,
+                           struct mlx5_ib_qp *qp,
+                           struct mlx5_ib_create_qp *ucmd)
+{
+       int desc_sz = 1 << qp->sq.wqe_shift;
+
+       if (desc_sz > dev->mdev.caps.max_sq_desc_sz) {
+               mlx5_ib_warn(dev, "desc_sz %d, max_sq_desc_sz %d\n",
+                            desc_sz, dev->mdev.caps.max_sq_desc_sz);
+               return -EINVAL;
+       }
+
+       if (ucmd->sq_wqe_count && ((1 << ilog2(ucmd->sq_wqe_count)) != ucmd->sq_wqe_count)) {
+               mlx5_ib_warn(dev, "sq_wqe_count %d, sq_wqe_count %d\n",
+                            ucmd->sq_wqe_count, ucmd->sq_wqe_count);
+               return -EINVAL;
+       }
+
+       qp->sq.wqe_cnt = ucmd->sq_wqe_count;
+
+       if (qp->sq.wqe_cnt > dev->mdev.caps.max_wqes) {
+               mlx5_ib_warn(dev, "wqe_cnt %d, max_wqes %d\n",
+                            qp->sq.wqe_cnt, dev->mdev.caps.max_wqes);
+               return -EINVAL;
+       }
+
+       qp->buf_size = (qp->rq.wqe_cnt << qp->rq.wqe_shift) +
+               (qp->sq.wqe_cnt << 6);
+
+       return 0;
+}
+
+static int qp_has_rq(struct ib_qp_init_attr *attr)
+{
+       if (attr->qp_type == IB_QPT_XRC_INI ||
+           attr->qp_type == IB_QPT_XRC_TGT || attr->srq ||
+           attr->qp_type == MLX5_IB_QPT_REG_UMR ||
+           !attr->cap.max_recv_wr)
+               return 0;
+
+       return 1;
+}
+
+static int alloc_high_class_uuar(struct mlx5_uuar_info *uuari)
+{
+       int nuuars = uuari->num_uars * MLX5_BF_REGS_PER_PAGE;
+       int start_uuar;
+       int i;
+
+       start_uuar = nuuars - uuari->num_low_latency_uuars;
+       for (i = start_uuar; i < nuuars; i++) {
+               if (!test_bit(i, uuari->bitmap)) {
+                       set_bit(i, uuari->bitmap);
+                       uuari->count[i]++;
+                       return i;
+               }
+       }
+
+       return -ENOMEM;
+}
+
+static int alloc_med_class_uuar(struct mlx5_uuar_info *uuari)
+{
+       int nuuars = uuari->num_uars * MLX5_BF_REGS_PER_PAGE;
+       int minidx = 1;
+       int uuarn;
+       int end;
+       int i;
+
+       end = nuuars - uuari->num_low_latency_uuars;
+
+       for (i = 1; i < end; i++) {
+               uuarn = i & 3;
+               if (uuarn == 2 || uuarn == 3)
+                       continue;
+
+               if (uuari->count[i] < uuari->count[minidx])
+                       minidx = i;
+       }
+
+       uuari->count[minidx]++;
+       return minidx;
+}
+
+static int alloc_uuar(struct mlx5_uuar_info *uuari,
+                     enum mlx5_ib_latency_class lat)
+{
+       int uuarn = -EINVAL;
+
+       mutex_lock(&uuari->lock);
+       switch (lat) {
+       case MLX5_IB_LATENCY_CLASS_LOW:
+               uuarn = 0;
+               uuari->count[uuarn]++;
+               break;
+
+       case MLX5_IB_LATENCY_CLASS_MEDIUM:
+               uuarn = alloc_med_class_uuar(uuari);
+               break;
+
+       case MLX5_IB_LATENCY_CLASS_HIGH:
+               uuarn = alloc_high_class_uuar(uuari);
+               break;
+
+       case MLX5_IB_LATENCY_CLASS_FAST_PATH:
+               uuarn = 2;
+               break;
+       }
+       mutex_unlock(&uuari->lock);
+
+       return uuarn;
+}
+
+static void free_med_class_uuar(struct mlx5_uuar_info *uuari, int uuarn)
+{
+       clear_bit(uuarn, uuari->bitmap);
+       --uuari->count[uuarn];
+}
+
+static void free_high_class_uuar(struct mlx5_uuar_info *uuari, int uuarn)
+{
+       clear_bit(uuarn, uuari->bitmap);
+       --uuari->count[uuarn];
+}
+
+static void free_uuar(struct mlx5_uuar_info *uuari, int uuarn)
+{
+       int nuuars = uuari->num_uars * MLX5_BF_REGS_PER_PAGE;
+       int high_uuar = nuuars - uuari->num_low_latency_uuars;
+
+       mutex_lock(&uuari->lock);
+       if (uuarn == 0) {
+               --uuari->count[uuarn];
+               goto out;
+       }
+
+       if (uuarn < high_uuar) {
+               free_med_class_uuar(uuari, uuarn);
+               goto out;
+       }
+
+       free_high_class_uuar(uuari, uuarn);
+
+out:
+       mutex_unlock(&uuari->lock);
+}
+
+static enum mlx5_qp_state to_mlx5_state(enum ib_qp_state state)
+{
+       switch (state) {
+       case IB_QPS_RESET:      return MLX5_QP_STATE_RST;
+       case IB_QPS_INIT:       return MLX5_QP_STATE_INIT;
+       case IB_QPS_RTR:        return MLX5_QP_STATE_RTR;
+       case IB_QPS_RTS:        return MLX5_QP_STATE_RTS;
+       case IB_QPS_SQD:        return MLX5_QP_STATE_SQD;
+       case IB_QPS_SQE:        return MLX5_QP_STATE_SQER;
+       case IB_QPS_ERR:        return MLX5_QP_STATE_ERR;
+       default:                return -1;
+       }
+}
+
+static int to_mlx5_st(enum ib_qp_type type)
+{
+       switch (type) {
+       case IB_QPT_RC:                 return MLX5_QP_ST_RC;
+       case IB_QPT_UC:                 return MLX5_QP_ST_UC;
+       case IB_QPT_UD:                 return MLX5_QP_ST_UD;
+       case MLX5_IB_QPT_REG_UMR:       return MLX5_QP_ST_REG_UMR;
+       case IB_QPT_XRC_INI:
+       case IB_QPT_XRC_TGT:            return MLX5_QP_ST_XRC;
+       case IB_QPT_SMI:                return MLX5_QP_ST_QP0;
+       case IB_QPT_GSI:                return MLX5_QP_ST_QP1;
+       case IB_QPT_RAW_IPV6:           return MLX5_QP_ST_RAW_IPV6;
+       case IB_QPT_RAW_ETHERTYPE:      return MLX5_QP_ST_RAW_ETHERTYPE;
+       case IB_QPT_RAW_PACKET:
+       case IB_QPT_MAX:
+       default:                return -EINVAL;
+       }
+}
+
+static int uuarn_to_uar_index(struct mlx5_uuar_info *uuari, int uuarn)
+{
+       return uuari->uars[uuarn / MLX5_BF_REGS_PER_PAGE].index;
+}
+
+static int create_user_qp(struct mlx5_ib_dev *dev, struct ib_pd *pd,
+                         struct mlx5_ib_qp *qp, struct ib_udata *udata,
+                         struct mlx5_create_qp_mbox_in **in,
+                         struct mlx5_ib_create_qp_resp *resp, int *inlen)
+{
+       struct mlx5_ib_ucontext *context;
+       struct mlx5_ib_create_qp ucmd;
+       int page_shift;
+       int uar_index;
+       int npages;
+       u32 offset;
+       int uuarn;
+       int ncont;
+       int err;
+
+       err = ib_copy_from_udata(&ucmd, udata, sizeof(ucmd));
+       if (err) {
+               mlx5_ib_dbg(dev, "copy failed\n");
+               return err;
+       }
+
+       context = to_mucontext(pd->uobject->context);
+       /*
+        * TBD: should come from the verbs when we have the API
+        */
+       uuarn = alloc_uuar(&context->uuari, MLX5_IB_LATENCY_CLASS_HIGH);
+       if (uuarn < 0) {
+               mlx5_ib_dbg(dev, "failed to allocate low latency UUAR\n");
+               mlx5_ib_dbg(dev, "reverting to high latency\n");
+               uuarn = alloc_uuar(&context->uuari, MLX5_IB_LATENCY_CLASS_LOW);
+               if (uuarn < 0) {
+                       mlx5_ib_dbg(dev, "uuar allocation failed\n");
+                       return uuarn;
+               }
+       }
+
+       uar_index = uuarn_to_uar_index(&context->uuari, uuarn);
+       mlx5_ib_dbg(dev, "uuarn 0x%x, uar_index 0x%x\n", uuarn, uar_index);
+
+       err = set_user_buf_size(dev, qp, &ucmd);
+       if (err)
+               goto err_uuar;
+
+       qp->umem = ib_umem_get(pd->uobject->context, ucmd.buf_addr,
+                              qp->buf_size, 0, 0);
+       if (IS_ERR(qp->umem)) {
+               mlx5_ib_dbg(dev, "umem_get failed\n");
+               err = PTR_ERR(qp->umem);
+               goto err_uuar;
+       }
+
+       mlx5_ib_cont_pages(qp->umem, ucmd.buf_addr, &npages, &page_shift,
+                          &ncont, NULL);
+       err = mlx5_ib_get_buf_offset(ucmd.buf_addr, page_shift, &offset);
+       if (err) {
+               mlx5_ib_warn(dev, "bad offset\n");
+               goto err_umem;
+       }
+       mlx5_ib_dbg(dev, "addr 0x%llx, size %d, npages %d, page_shift %d, ncont %d, offset %d\n",
+                   ucmd.buf_addr, qp->buf_size, npages, page_shift, ncont, offset);
+
+       *inlen = sizeof(**in) + sizeof(*(*in)->pas) * ncont;
+       *in = mlx5_vzalloc(*inlen);
+       if (!*in) {
+               err = -ENOMEM;
+               goto err_umem;
+       }
+       mlx5_ib_populate_pas(dev, qp->umem, page_shift, (*in)->pas, 0);
+       (*in)->ctx.log_pg_sz_remote_qpn =
+               cpu_to_be32((page_shift - PAGE_SHIFT) << 24);
+       (*in)->ctx.params2 = cpu_to_be32(offset << 6);
+
+       (*in)->ctx.qp_counter_set_usr_page = cpu_to_be32(uar_index);
+       resp->uuar_index = uuarn;
+       qp->uuarn = uuarn;
+
+       err = mlx5_ib_db_map_user(context, ucmd.db_addr, &qp->db);
+       if (err) {
+               mlx5_ib_dbg(dev, "map failed\n");
+               goto err_free;
+       }
+
+       err = ib_copy_to_udata(udata, resp, sizeof(*resp));
+       if (err) {
+               mlx5_ib_dbg(dev, "copy failed\n");
+               goto err_unmap;
+       }
+       qp->create_type = MLX5_QP_USER;
+
+       return 0;
+
+err_unmap:
+       mlx5_ib_db_unmap_user(context, &qp->db);
+
+err_free:
+       mlx5_vfree(*in);
+
+err_umem:
+       ib_umem_release(qp->umem);
+
+err_uuar:
+       free_uuar(&context->uuari, uuarn);
+       return err;
+}
+
+static void destroy_qp_user(struct ib_pd *pd, struct mlx5_ib_qp *qp)
+{
+       struct mlx5_ib_ucontext *context;
+
+       context = to_mucontext(pd->uobject->context);
+       mlx5_ib_db_unmap_user(context, &qp->db);
+       ib_umem_release(qp->umem);
+       free_uuar(&context->uuari, qp->uuarn);
+}
+
+static int create_kernel_qp(struct mlx5_ib_dev *dev,
+                           struct ib_qp_init_attr *init_attr,
+                           struct mlx5_ib_qp *qp,
+                           struct mlx5_create_qp_mbox_in **in, int *inlen)
+{
+       enum mlx5_ib_latency_class lc = MLX5_IB_LATENCY_CLASS_LOW;
+       struct mlx5_uuar_info *uuari;
+       int uar_index;
+       int uuarn;
+       int err;
+
+       uuari = &dev->mdev.priv.uuari;
+       if (init_attr->create_flags & IB_QP_CREATE_BLOCK_MULTICAST_LOOPBACK)
+               qp->flags |= MLX5_IB_QP_BLOCK_MULTICAST_LOOPBACK;
+
+       if (init_attr->qp_type == MLX5_IB_QPT_REG_UMR)
+               lc = MLX5_IB_LATENCY_CLASS_FAST_PATH;
+
+       uuarn = alloc_uuar(uuari, lc);
+       if (uuarn < 0) {
+               mlx5_ib_dbg(dev, "\n");
+               return -ENOMEM;
+       }
+
+       qp->bf = &uuari->bfs[uuarn];
+       uar_index = qp->bf->uar->index;
+
+       err = calc_sq_size(dev, init_attr, qp);
+       if (err < 0) {
+               mlx5_ib_dbg(dev, "err %d\n", err);
+               goto err_uuar;
+       }
+
+       qp->rq.offset = 0;
+       qp->sq.offset = qp->rq.wqe_cnt << qp->rq.wqe_shift;
+       qp->buf_size = err + (qp->rq.wqe_cnt << qp->rq.wqe_shift);
+
+       err = mlx5_buf_alloc(&dev->mdev, qp->buf_size, PAGE_SIZE * 2, &qp->buf);
+       if (err) {
+               mlx5_ib_dbg(dev, "err %d\n", err);
+               goto err_uuar;
+       }
+
+       qp->sq.qend = mlx5_get_send_wqe(qp, qp->sq.wqe_cnt);
+       *inlen = sizeof(**in) + sizeof(*(*in)->pas) * qp->buf.npages;
+       *in = mlx5_vzalloc(*inlen);
+       if (!*in) {
+               err = -ENOMEM;
+               goto err_buf;
+       }
+       (*in)->ctx.qp_counter_set_usr_page = cpu_to_be32(uar_index);
+       (*in)->ctx.log_pg_sz_remote_qpn = cpu_to_be32((qp->buf.page_shift - PAGE_SHIFT) << 24);
+       /* Set "fast registration enabled" for all kernel QPs */
+       (*in)->ctx.params1 |= cpu_to_be32(1 << 11);
+       (*in)->ctx.sq_crq_size |= cpu_to_be16(1 << 4);
+
+       mlx5_fill_page_array(&qp->buf, (*in)->pas);
+
+       err = mlx5_db_alloc(&dev->mdev, &qp->db);
+       if (err) {
+               mlx5_ib_dbg(dev, "err %d\n", err);
+               goto err_free;
+       }
+
+       qp->db.db[0] = 0;
+       qp->db.db[1] = 0;
+
+       qp->sq.wrid = kmalloc(qp->sq.wqe_cnt * sizeof(*qp->sq.wrid), GFP_KERNEL);
+       qp->sq.wr_data = kmalloc(qp->sq.wqe_cnt * sizeof(*qp->sq.wr_data), GFP_KERNEL);
+       qp->rq.wrid = kmalloc(qp->rq.wqe_cnt * sizeof(*qp->rq.wrid), GFP_KERNEL);
+       qp->sq.w_list = kmalloc(qp->sq.wqe_cnt * sizeof(*qp->sq.w_list), GFP_KERNEL);
+       qp->sq.wqe_head = kmalloc(qp->sq.wqe_cnt * sizeof(*qp->sq.wqe_head), GFP_KERNEL);
+
+       if (!qp->sq.wrid || !qp->sq.wr_data || !qp->rq.wrid ||
+           !qp->sq.w_list || !qp->sq.wqe_head) {
+               err = -ENOMEM;
+               goto err_wrid;
+       }
+       qp->create_type = MLX5_QP_KERNEL;
+
+       return 0;
+
+err_wrid:
+       mlx5_db_free(&dev->mdev, &qp->db);
+       kfree(qp->sq.wqe_head);
+       kfree(qp->sq.w_list);
+       kfree(qp->sq.wrid);
+       kfree(qp->sq.wr_data);
+       kfree(qp->rq.wrid);
+
+err_free:
+       mlx5_vfree(*in);
+
+err_buf:
+       mlx5_buf_free(&dev->mdev, &qp->buf);
+
+err_uuar:
+       free_uuar(&dev->mdev.priv.uuari, uuarn);
+       return err;
+}
+
+static void destroy_qp_kernel(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp)
+{
+       mlx5_db_free(&dev->mdev, &qp->db);
+       kfree(qp->sq.wqe_head);
+       kfree(qp->sq.w_list);
+       kfree(qp->sq.wrid);
+       kfree(qp->sq.wr_data);
+       kfree(qp->rq.wrid);
+       mlx5_buf_free(&dev->mdev, &qp->buf);
+       free_uuar(&dev->mdev.priv.uuari, qp->bf->uuarn);
+}
+
+static __be32 get_rx_type(struct mlx5_ib_qp *qp, struct ib_qp_init_attr *attr)
+{
+       if (attr->srq || (attr->qp_type == IB_QPT_XRC_TGT) ||
+           (attr->qp_type == IB_QPT_XRC_INI))
+               return cpu_to_be32(MLX5_SRQ_RQ);
+       else if (!qp->has_rq)
+               return cpu_to_be32(MLX5_ZERO_LEN_RQ);
+       else
+               return cpu_to_be32(MLX5_NON_ZERO_RQ);
+}
+
+static int is_connected(enum ib_qp_type qp_type)
+{
+       if (qp_type == IB_QPT_RC || qp_type == IB_QPT_UC)
+               return 1;
+
+       return 0;
+}
+
+static int create_qp_common(struct mlx5_ib_dev *dev, struct ib_pd *pd,
+                           struct ib_qp_init_attr *init_attr,
+                           struct ib_udata *udata, struct mlx5_ib_qp *qp)
+{
+       struct mlx5_ib_resources *devr = &dev->devr;
+       struct mlx5_ib_create_qp_resp resp;
+       struct mlx5_create_qp_mbox_in *in;
+       struct mlx5_ib_create_qp ucmd;
+       int inlen = sizeof(*in);
+       int err;
+
+       mutex_init(&qp->mutex);
+       spin_lock_init(&qp->sq.lock);
+       spin_lock_init(&qp->rq.lock);
+
+       if (init_attr->sq_sig_type == IB_SIGNAL_ALL_WR)
+               qp->sq_signal_bits = MLX5_WQE_CTRL_CQ_UPDATE;
+
+       if (pd && pd->uobject) {
+               if (ib_copy_from_udata(&ucmd, udata, sizeof(ucmd))) {
+                       mlx5_ib_dbg(dev, "copy failed\n");
+                       return -EFAULT;
+               }
+
+               qp->wq_sig = !!(ucmd.flags & MLX5_QP_FLAG_SIGNATURE);
+               qp->scat_cqe = !!(ucmd.flags & MLX5_QP_FLAG_SCATTER_CQE);
+       } else {
+               qp->wq_sig = !!wq_signature;
+       }
+
+       qp->has_rq = qp_has_rq(init_attr);
+       err = set_rq_size(dev, &init_attr->cap, qp->has_rq,
+                         qp, (pd && pd->uobject) ? &ucmd : NULL);
+       if (err) {
+               mlx5_ib_dbg(dev, "err %d\n", err);
+               return err;
+       }
+
+       if (pd) {
+               if (pd->uobject) {
+                       mlx5_ib_dbg(dev, "requested sq_wqe_count (%d)\n", ucmd.sq_wqe_count);
+                       if (ucmd.rq_wqe_shift != qp->rq.wqe_shift ||
+                           ucmd.rq_wqe_count != qp->rq.wqe_cnt) {
+                               mlx5_ib_dbg(dev, "invalid rq params\n");
+                               return -EINVAL;
+                       }
+                       if (ucmd.sq_wqe_count > dev->mdev.caps.max_wqes) {
+                               mlx5_ib_dbg(dev, "requested sq_wqe_count (%d) > max allowed (%d)\n",
+                                           ucmd.sq_wqe_count, dev->mdev.caps.max_wqes);
+                               return -EINVAL;
+                       }
+                       err = create_user_qp(dev, pd, qp, udata, &in, &resp, &inlen);
+                       if (err)
+                               mlx5_ib_dbg(dev, "err %d\n", err);
+               } else {
+                       err = create_kernel_qp(dev, init_attr, qp, &in, &inlen);
+                       if (err)
+                               mlx5_ib_dbg(dev, "err %d\n", err);
+                       else
+                               qp->pa_lkey = to_mpd(pd)->pa_lkey;
+               }
+
+               if (err)
+                       return err;
+       } else {
+               in = mlx5_vzalloc(sizeof(*in));
+               if (!in)
+                       return -ENOMEM;
+
+               qp->create_type = MLX5_QP_EMPTY;
+       }
+
+       if (is_sqp(init_attr->qp_type))
+               qp->port = init_attr->port_num;
+
+       in->ctx.flags = cpu_to_be32(to_mlx5_st(init_attr->qp_type) << 16 |
+                                   MLX5_QP_PM_MIGRATED << 11);
+
+       if (init_attr->qp_type != MLX5_IB_QPT_REG_UMR)
+               in->ctx.flags_pd = cpu_to_be32(to_mpd(pd ? pd : devr->p0)->pdn);
+       else
+               in->ctx.flags_pd = cpu_to_be32(MLX5_QP_LAT_SENSITIVE);
+
+       if (qp->wq_sig)
+               in->ctx.flags_pd |= cpu_to_be32(MLX5_QP_ENABLE_SIG);
+
+       if (qp->scat_cqe && is_connected(init_attr->qp_type)) {
+               int rcqe_sz;
+               int scqe_sz;
+
+               rcqe_sz = mlx5_ib_get_cqe_size(dev, init_attr->recv_cq);
+               scqe_sz = mlx5_ib_get_cqe_size(dev, init_attr->send_cq);
+
+               if (rcqe_sz == 128)
+                       in->ctx.cs_res = MLX5_RES_SCAT_DATA64_CQE;
+               else
+                       in->ctx.cs_res = MLX5_RES_SCAT_DATA32_CQE;
+
+               if (init_attr->sq_sig_type == IB_SIGNAL_ALL_WR) {
+                       if (scqe_sz == 128)
+                               in->ctx.cs_req = MLX5_REQ_SCAT_DATA64_CQE;
+                       else
+                               in->ctx.cs_req = MLX5_REQ_SCAT_DATA32_CQE;
+               }
+       }
+
+       if (qp->rq.wqe_cnt) {
+               in->ctx.rq_size_stride = (qp->rq.wqe_shift - 4);
+               in->ctx.rq_size_stride |= ilog2(qp->rq.wqe_cnt) << 3;
+       }
+
+       in->ctx.rq_type_srqn = get_rx_type(qp, init_attr);
+
+       if (qp->sq.wqe_cnt)
+               in->ctx.sq_crq_size |= cpu_to_be16(ilog2(qp->sq.wqe_cnt) << 11);
+       else
+               in->ctx.sq_crq_size |= cpu_to_be16(0x8000);
+
+       /* Set default resources */
+       switch (init_attr->qp_type) {
+       case IB_QPT_XRC_TGT:
+               in->ctx.cqn_recv = cpu_to_be32(to_mcq(devr->c0)->mcq.cqn);
+               in->ctx.cqn_send = cpu_to_be32(to_mcq(devr->c0)->mcq.cqn);
+               in->ctx.rq_type_srqn |= cpu_to_be32(to_msrq(devr->s0)->msrq.srqn);
+               in->ctx.xrcd = cpu_to_be32(to_mxrcd(init_attr->xrcd)->xrcdn);
+               break;
+       case IB_QPT_XRC_INI:
+               in->ctx.cqn_recv = cpu_to_be32(to_mcq(devr->c0)->mcq.cqn);
+               in->ctx.xrcd = cpu_to_be32(to_mxrcd(devr->x1)->xrcdn);
+               in->ctx.rq_type_srqn |= cpu_to_be32(to_msrq(devr->s0)->msrq.srqn);
+               break;
+       default:
+               if (init_attr->srq) {
+                       in->ctx.xrcd = cpu_to_be32(to_mxrcd(devr->x0)->xrcdn);
+                       in->ctx.rq_type_srqn |= cpu_to_be32(to_msrq(init_attr->srq)->msrq.srqn);
+               } else {
+                       in->ctx.xrcd = cpu_to_be32(to_mxrcd(devr->x1)->xrcdn);
+                       in->ctx.rq_type_srqn |= cpu_to_be32(to_msrq(devr->s0)->msrq.srqn);
+               }
+       }
+
+       if (init_attr->send_cq)
+               in->ctx.cqn_send = cpu_to_be32(to_mcq(init_attr->send_cq)->mcq.cqn);
+
+       if (init_attr->recv_cq)
+               in->ctx.cqn_recv = cpu_to_be32(to_mcq(init_attr->recv_cq)->mcq.cqn);
+
+       in->ctx.db_rec_addr = cpu_to_be64(qp->db.dma);
+
+       err = mlx5_core_create_qp(&dev->mdev, &qp->mqp, in, inlen);
+       if (err) {
+               mlx5_ib_dbg(dev, "create qp failed\n");
+               goto err_create;
+       }
+
+       mlx5_vfree(in);
+       /* Hardware wants QPN written in big-endian order (after
+        * shifting) for send doorbell.  Precompute this value to save
+        * a little bit when posting sends.
+        */
+       qp->doorbell_qpn = swab32(qp->mqp.qpn << 8);
+
+       qp->mqp.event = mlx5_ib_qp_event;
+
+       return 0;
+
+err_create:
+       if (qp->create_type == MLX5_QP_USER)
+               destroy_qp_user(pd, qp);
+       else if (qp->create_type == MLX5_QP_KERNEL)
+               destroy_qp_kernel(dev, qp);
+
+       mlx5_vfree(in);
+       return err;
+}
+
+static void mlx5_ib_lock_cqs(struct mlx5_ib_cq *send_cq, struct mlx5_ib_cq *recv_cq)
+       __acquires(&send_cq->lock) __acquires(&recv_cq->lock)
+{
+       if (send_cq) {
+               if (recv_cq) {
+                       if (send_cq->mcq.cqn < recv_cq->mcq.cqn)  {
+                               spin_lock_irq(&send_cq->lock);
+                               spin_lock_nested(&recv_cq->lock,
+                                                SINGLE_DEPTH_NESTING);
+                       } else if (send_cq->mcq.cqn == recv_cq->mcq.cqn) {
+                               spin_lock_irq(&send_cq->lock);
+                               __acquire(&recv_cq->lock);
+                       } else {
+                               spin_lock_irq(&recv_cq->lock);
+                               spin_lock_nested(&send_cq->lock,
+                                                SINGLE_DEPTH_NESTING);
+                       }
+               } else {
+                       spin_lock_irq(&send_cq->lock);
+               }
+       } else if (recv_cq) {
+               spin_lock_irq(&recv_cq->lock);
+       }
+}
+
+static void mlx5_ib_unlock_cqs(struct mlx5_ib_cq *send_cq, struct mlx5_ib_cq *recv_cq)
+       __releases(&send_cq->lock) __releases(&recv_cq->lock)
+{
+       if (send_cq) {
+               if (recv_cq) {
+                       if (send_cq->mcq.cqn < recv_cq->mcq.cqn)  {
+                               spin_unlock(&recv_cq->lock);
+                               spin_unlock_irq(&send_cq->lock);
+                       } else if (send_cq->mcq.cqn == recv_cq->mcq.cqn) {
+                               __release(&recv_cq->lock);
+                               spin_unlock_irq(&send_cq->lock);
+                       } else {
+                               spin_unlock(&send_cq->lock);
+                               spin_unlock_irq(&recv_cq->lock);
+                       }
+               } else {
+                       spin_unlock_irq(&send_cq->lock);
+               }
+       } else if (recv_cq) {
+               spin_unlock_irq(&recv_cq->lock);
+       }
+}
+
+static struct mlx5_ib_pd *get_pd(struct mlx5_ib_qp *qp)
+{
+       return to_mpd(qp->ibqp.pd);
+}
+
+static void get_cqs(struct mlx5_ib_qp *qp,
+                   struct mlx5_ib_cq **send_cq, struct mlx5_ib_cq **recv_cq)
+{
+       switch (qp->ibqp.qp_type) {
+       case IB_QPT_XRC_TGT:
+               *send_cq = NULL;
+               *recv_cq = NULL;
+               break;
+       case MLX5_IB_QPT_REG_UMR:
+       case IB_QPT_XRC_INI:
+               *send_cq = to_mcq(qp->ibqp.send_cq);
+               *recv_cq = NULL;
+               break;
+
+       case IB_QPT_SMI:
+       case IB_QPT_GSI:
+       case IB_QPT_RC:
+       case IB_QPT_UC:
+       case IB_QPT_UD:
+       case IB_QPT_RAW_IPV6:
+       case IB_QPT_RAW_ETHERTYPE:
+               *send_cq = to_mcq(qp->ibqp.send_cq);
+               *recv_cq = to_mcq(qp->ibqp.recv_cq);
+               break;
+
+       case IB_QPT_RAW_PACKET:
+       case IB_QPT_MAX:
+       default:
+               *send_cq = NULL;
+               *recv_cq = NULL;
+               break;
+       }
+}
+
+static void destroy_qp_common(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp)
+{
+       struct mlx5_ib_cq *send_cq, *recv_cq;
+       struct mlx5_modify_qp_mbox_in *in;
+       int err;
+
+       in = kzalloc(sizeof(*in), GFP_KERNEL);
+       if (!in)
+               return;
+       if (qp->state != IB_QPS_RESET)
+               if (mlx5_core_qp_modify(&dev->mdev, to_mlx5_state(qp->state),
+                                       MLX5_QP_STATE_RST, in, sizeof(*in), &qp->mqp))
+                       mlx5_ib_warn(dev, "mlx5_ib: modify QP %06x to RESET failed\n",
+                                    qp->mqp.qpn);
+
+       get_cqs(qp, &send_cq, &recv_cq);
+
+       if (qp->create_type == MLX5_QP_KERNEL) {
+               mlx5_ib_lock_cqs(send_cq, recv_cq);
+               __mlx5_ib_cq_clean(recv_cq, qp->mqp.qpn,
+                                  qp->ibqp.srq ? to_msrq(qp->ibqp.srq) : NULL);
+               if (send_cq != recv_cq)
+                       __mlx5_ib_cq_clean(send_cq, qp->mqp.qpn, NULL);
+               mlx5_ib_unlock_cqs(send_cq, recv_cq);
+       }
+
+       err = mlx5_core_destroy_qp(&dev->mdev, &qp->mqp);
+       if (err)
+               mlx5_ib_warn(dev, "failed to destroy QP 0x%x\n", qp->mqp.qpn);
+       kfree(in);
+
+
+       if (qp->create_type == MLX5_QP_KERNEL)
+               destroy_qp_kernel(dev, qp);
+       else if (qp->create_type == MLX5_QP_USER)
+               destroy_qp_user(&get_pd(qp)->ibpd, qp);
+}
+
+static const char *ib_qp_type_str(enum ib_qp_type type)
+{
+       switch (type) {
+       case IB_QPT_SMI:
+               return "IB_QPT_SMI";
+       case IB_QPT_GSI:
+               return "IB_QPT_GSI";
+       case IB_QPT_RC:
+               return "IB_QPT_RC";
+       case IB_QPT_UC:
+               return "IB_QPT_UC";
+       case IB_QPT_UD:
+               return "IB_QPT_UD";
+       case IB_QPT_RAW_IPV6:
+               return "IB_QPT_RAW_IPV6";
+       case IB_QPT_RAW_ETHERTYPE:
+               return "IB_QPT_RAW_ETHERTYPE";
+       case IB_QPT_XRC_INI:
+               return "IB_QPT_XRC_INI";
+       case IB_QPT_XRC_TGT:
+               return "IB_QPT_XRC_TGT";
+       case IB_QPT_RAW_PACKET:
+               return "IB_QPT_RAW_PACKET";
+       case MLX5_IB_QPT_REG_UMR:
+               return "MLX5_IB_QPT_REG_UMR";
+       case IB_QPT_MAX:
+       default:
+               return "Invalid QP type";
+       }
+}
+
+struct ib_qp *mlx5_ib_create_qp(struct ib_pd *pd,
+                               struct ib_qp_init_attr *init_attr,
+                               struct ib_udata *udata)
+{
+       struct mlx5_ib_dev *dev;
+       struct mlx5_ib_qp *qp;
+       u16 xrcdn = 0;
+       int err;
+
+       if (pd) {
+               dev = to_mdev(pd->device);
+       } else {
+               /* being cautious here */
+               if (init_attr->qp_type != IB_QPT_XRC_TGT &&
+                   init_attr->qp_type != MLX5_IB_QPT_REG_UMR) {
+                       pr_warn("%s: no PD for transport %s\n", __func__,
+                               ib_qp_type_str(init_attr->qp_type));
+                       return ERR_PTR(-EINVAL);
+               }
+               dev = to_mdev(to_mxrcd(init_attr->xrcd)->ibxrcd.device);
+       }
+
+       switch (init_attr->qp_type) {
+       case IB_QPT_XRC_TGT:
+       case IB_QPT_XRC_INI:
+               if (!(dev->mdev.caps.flags & MLX5_DEV_CAP_FLAG_XRC)) {
+                       mlx5_ib_dbg(dev, "XRC not supported\n");
+                       return ERR_PTR(-ENOSYS);
+               }
+               init_attr->recv_cq = NULL;
+               if (init_attr->qp_type == IB_QPT_XRC_TGT) {
+                       xrcdn = to_mxrcd(init_attr->xrcd)->xrcdn;
+                       init_attr->send_cq = NULL;
+               }
+
+               /* fall through */
+       case IB_QPT_RC:
+       case IB_QPT_UC:
+       case IB_QPT_UD:
+       case IB_QPT_SMI:
+       case IB_QPT_GSI:
+       case MLX5_IB_QPT_REG_UMR:
+               qp = kzalloc(sizeof(*qp), GFP_KERNEL);
+               if (!qp)
+                       return ERR_PTR(-ENOMEM);
+
+               err = create_qp_common(dev, pd, init_attr, udata, qp);
+               if (err) {
+                       mlx5_ib_dbg(dev, "create_qp_common failed\n");
+                       kfree(qp);
+                       return ERR_PTR(err);
+               }
+
+               if (is_qp0(init_attr->qp_type))
+                       qp->ibqp.qp_num = 0;
+               else if (is_qp1(init_attr->qp_type))
+                       qp->ibqp.qp_num = 1;
+               else
+                       qp->ibqp.qp_num = qp->mqp.qpn;
+
+               mlx5_ib_dbg(dev, "ib qpnum 0x%x, mlx qpn 0x%x, rcqn 0x%x, scqn 0x%x\n",
+                           qp->ibqp.qp_num, qp->mqp.qpn, to_mcq(init_attr->recv_cq)->mcq.cqn,
+                           to_mcq(init_attr->send_cq)->mcq.cqn);
+
+               qp->xrcdn = xrcdn;
+
+               break;
+
+       case IB_QPT_RAW_IPV6:
+       case IB_QPT_RAW_ETHERTYPE:
+       case IB_QPT_RAW_PACKET:
+       case IB_QPT_MAX:
+       default:
+               mlx5_ib_dbg(dev, "unsupported qp type %d\n",
+                           init_attr->qp_type);
+               /* Don't support raw QPs */
+               return ERR_PTR(-EINVAL);
+       }
+
+       return &qp->ibqp;
+}
+
+int mlx5_ib_destroy_qp(struct ib_qp *qp)
+{
+       struct mlx5_ib_dev *dev = to_mdev(qp->device);
+       struct mlx5_ib_qp *mqp = to_mqp(qp);
+
+       destroy_qp_common(dev, mqp);
+
+       kfree(mqp);
+
+       return 0;
+}
+
+static __be32 to_mlx5_access_flags(struct mlx5_ib_qp *qp, const struct ib_qp_attr *attr,
+                                  int attr_mask)
+{
+       u32 hw_access_flags = 0;
+       u8 dest_rd_atomic;
+       u32 access_flags;
+
+       if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC)
+               dest_rd_atomic = attr->max_dest_rd_atomic;
+       else
+               dest_rd_atomic = qp->resp_depth;
+
+       if (attr_mask & IB_QP_ACCESS_FLAGS)
+               access_flags = attr->qp_access_flags;
+       else
+               access_flags = qp->atomic_rd_en;
+
+       if (!dest_rd_atomic)
+               access_flags &= IB_ACCESS_REMOTE_WRITE;
+
+       if (access_flags & IB_ACCESS_REMOTE_READ)
+               hw_access_flags |= MLX5_QP_BIT_RRE;
+       if (access_flags & IB_ACCESS_REMOTE_ATOMIC)
+               hw_access_flags |= (MLX5_QP_BIT_RAE | MLX5_ATOMIC_MODE_CX);
+       if (access_flags & IB_ACCESS_REMOTE_WRITE)
+               hw_access_flags |= MLX5_QP_BIT_RWE;
+
+       return cpu_to_be32(hw_access_flags);
+}
+
+enum {
+       MLX5_PATH_FLAG_FL       = 1 << 0,
+       MLX5_PATH_FLAG_FREE_AR  = 1 << 1,
+       MLX5_PATH_FLAG_COUNTER  = 1 << 2,
+};
+
+static int ib_rate_to_mlx5(struct mlx5_ib_dev *dev, u8 rate)
+{
+       if (rate == IB_RATE_PORT_CURRENT) {
+               return 0;
+       } else if (rate < IB_RATE_2_5_GBPS || rate > IB_RATE_300_GBPS) {
+               return -EINVAL;
+       } else {
+               while (rate != IB_RATE_2_5_GBPS &&
+                      !(1 << (rate + MLX5_STAT_RATE_OFFSET) &
+                        dev->mdev.caps.stat_rate_support))
+                       --rate;
+       }
+
+       return rate + MLX5_STAT_RATE_OFFSET;
+}
+
+static int mlx5_set_path(struct mlx5_ib_dev *dev, const struct ib_ah_attr *ah,
+                        struct mlx5_qp_path *path, u8 port, int attr_mask,
+                        u32 path_flags, const struct ib_qp_attr *attr)
+{
+       int err;
+
+       path->fl = (path_flags & MLX5_PATH_FLAG_FL) ? 0x80 : 0;
+       path->free_ar = (path_flags & MLX5_PATH_FLAG_FREE_AR) ? 0x80 : 0;
+
+       if (attr_mask & IB_QP_PKEY_INDEX)
+               path->pkey_index = attr->pkey_index;
+
+       path->grh_mlid  = ah->src_path_bits & 0x7f;
+       path->rlid      = cpu_to_be16(ah->dlid);
+
+       if (ah->ah_flags & IB_AH_GRH) {
+               path->grh_mlid |= 1 << 7;
+               path->mgid_index = ah->grh.sgid_index;
+               path->hop_limit  = ah->grh.hop_limit;
+               path->tclass_flowlabel =
+                       cpu_to_be32((ah->grh.traffic_class << 20) |
+                                   (ah->grh.flow_label));
+               memcpy(path->rgid, ah->grh.dgid.raw, 16);
+       }
+
+       err = ib_rate_to_mlx5(dev, ah->static_rate);
+       if (err < 0)
+               return err;
+       path->static_rate = err;
+       path->port = port;
+
+       if (ah->ah_flags & IB_AH_GRH) {
+               if (ah->grh.sgid_index >= dev->mdev.caps.port[port - 1].gid_table_len) {
+                       pr_err(KERN_ERR "sgid_index (%u) too large. max is %d\n",
+                              ah->grh.sgid_index, dev->mdev.caps.port[port - 1].gid_table_len);
+                       return -EINVAL;
+               }
+
+               path->grh_mlid |= 1 << 7;
+               path->mgid_index = ah->grh.sgid_index;
+               path->hop_limit  = ah->grh.hop_limit;
+               path->tclass_flowlabel =
+                       cpu_to_be32((ah->grh.traffic_class << 20) |
+                                   (ah->grh.flow_label));
+               memcpy(path->rgid, ah->grh.dgid.raw, 16);
+       }
+
+       if (attr_mask & IB_QP_TIMEOUT)
+               path->ackto_lt = attr->timeout << 3;
+
+       path->sl = ah->sl & 0xf;
+
+       return 0;
+}
+
+static enum mlx5_qp_optpar opt_mask[MLX5_QP_NUM_STATE][MLX5_QP_NUM_STATE][MLX5_QP_ST_MAX] = {
+       [MLX5_QP_STATE_INIT] = {
+               [MLX5_QP_STATE_INIT] = {
+                       [MLX5_QP_ST_RC] = MLX5_QP_OPTPAR_RRE            |
+                                         MLX5_QP_OPTPAR_RAE            |
+                                         MLX5_QP_OPTPAR_RWE            |
+                                         MLX5_QP_OPTPAR_PKEY_INDEX     |
+                                         MLX5_QP_OPTPAR_PRI_PORT,
+                       [MLX5_QP_ST_UC] = MLX5_QP_OPTPAR_RWE            |
+                                         MLX5_QP_OPTPAR_PKEY_INDEX     |
+                                         MLX5_QP_OPTPAR_PRI_PORT,
+                       [MLX5_QP_ST_UD] = MLX5_QP_OPTPAR_PKEY_INDEX     |
+                                         MLX5_QP_OPTPAR_Q_KEY          |
+                                         MLX5_QP_OPTPAR_PRI_PORT,
+               },
+               [MLX5_QP_STATE_RTR] = {
+                       [MLX5_QP_ST_RC] = MLX5_QP_OPTPAR_ALT_ADDR_PATH  |
+                                         MLX5_QP_OPTPAR_RRE            |
+                                         MLX5_QP_OPTPAR_RAE            |
+                                         MLX5_QP_OPTPAR_RWE            |
+                                         MLX5_QP_OPTPAR_PKEY_INDEX,
+                       [MLX5_QP_ST_UC] = MLX5_QP_OPTPAR_ALT_ADDR_PATH  |
+                                         MLX5_QP_OPTPAR_RWE            |
+                                         MLX5_QP_OPTPAR_PKEY_INDEX,
+                       [MLX5_QP_ST_UD] = MLX5_QP_OPTPAR_PKEY_INDEX     |
+                                         MLX5_QP_OPTPAR_Q_KEY,
+                       [MLX5_QP_ST_MLX] = MLX5_QP_OPTPAR_PKEY_INDEX    |
+                                          MLX5_QP_OPTPAR_Q_KEY,
+               },
+       },
+       [MLX5_QP_STATE_RTR] = {
+               [MLX5_QP_STATE_RTS] = {
+                       [MLX5_QP_ST_RC] = MLX5_QP_OPTPAR_ALT_ADDR_PATH  |
+                                         MLX5_QP_OPTPAR_RRE            |
+                                         MLX5_QP_OPTPAR_RAE            |
+                                         MLX5_QP_OPTPAR_RWE            |
+                                         MLX5_QP_OPTPAR_PM_STATE       |
+                                         MLX5_QP_OPTPAR_RNR_TIMEOUT,
+                       [MLX5_QP_ST_UC] = MLX5_QP_OPTPAR_ALT_ADDR_PATH  |
+                                         MLX5_QP_OPTPAR_RWE            |
+                                         MLX5_QP_OPTPAR_PM_STATE,
+                       [MLX5_QP_ST_UD] = MLX5_QP_OPTPAR_Q_KEY,
+               },
+       },
+       [MLX5_QP_STATE_RTS] = {
+               [MLX5_QP_STATE_RTS] = {
+                       [MLX5_QP_ST_RC] = MLX5_QP_OPTPAR_RRE            |
+                                         MLX5_QP_OPTPAR_RAE            |
+                                         MLX5_QP_OPTPAR_RWE            |
+                                         MLX5_QP_OPTPAR_RNR_TIMEOUT    |
+                                         MLX5_QP_OPTPAR_PM_STATE,
+                       [MLX5_QP_ST_UC] = MLX5_QP_OPTPAR_RWE            |
+                                         MLX5_QP_OPTPAR_PM_STATE,
+                       [MLX5_QP_ST_UD] = MLX5_QP_OPTPAR_Q_KEY          |
+                                         MLX5_QP_OPTPAR_SRQN           |
+                                         MLX5_QP_OPTPAR_CQN_RCV,
+               },
+       },
+       [MLX5_QP_STATE_SQER] = {
+               [MLX5_QP_STATE_RTS] = {
+                       [MLX5_QP_ST_UD]  = MLX5_QP_OPTPAR_Q_KEY,
+                       [MLX5_QP_ST_MLX] = MLX5_QP_OPTPAR_Q_KEY,
+               },
+       },
+};
+
+static int ib_nr_to_mlx5_nr(int ib_mask)
+{
+       switch (ib_mask) {
+       case IB_QP_STATE:
+               return 0;
+       case IB_QP_CUR_STATE:
+               return 0;
+       case IB_QP_EN_SQD_ASYNC_NOTIFY:
+               return 0;
+       case IB_QP_ACCESS_FLAGS:
+               return MLX5_QP_OPTPAR_RWE | MLX5_QP_OPTPAR_RRE |
+                       MLX5_QP_OPTPAR_RAE;
+       case IB_QP_PKEY_INDEX:
+               return MLX5_QP_OPTPAR_PKEY_INDEX;
+       case IB_QP_PORT:
+               return MLX5_QP_OPTPAR_PRI_PORT;
+       case IB_QP_QKEY:
+               return MLX5_QP_OPTPAR_Q_KEY;
+       case IB_QP_AV:
+               return MLX5_QP_OPTPAR_PRIMARY_ADDR_PATH |
+                       MLX5_QP_OPTPAR_PRI_PORT;
+       case IB_QP_PATH_MTU:
+               return 0;
+       case IB_QP_TIMEOUT:
+               return MLX5_QP_OPTPAR_ACK_TIMEOUT;
+       case IB_QP_RETRY_CNT:
+               return MLX5_QP_OPTPAR_RETRY_COUNT;
+       case IB_QP_RNR_RETRY:
+               return MLX5_QP_OPTPAR_RNR_RETRY;
+       case IB_QP_RQ_PSN:
+               return 0;
+       case IB_QP_MAX_QP_RD_ATOMIC:
+               return MLX5_QP_OPTPAR_SRA_MAX;
+       case IB_QP_ALT_PATH:
+               return MLX5_QP_OPTPAR_ALT_ADDR_PATH;
+       case IB_QP_MIN_RNR_TIMER:
+               return MLX5_QP_OPTPAR_RNR_TIMEOUT;
+       case IB_QP_SQ_PSN:
+               return 0;
+       case IB_QP_MAX_DEST_RD_ATOMIC:
+               return MLX5_QP_OPTPAR_RRA_MAX | MLX5_QP_OPTPAR_RWE |
+                       MLX5_QP_OPTPAR_RRE | MLX5_QP_OPTPAR_RAE;
+       case IB_QP_PATH_MIG_STATE:
+               return MLX5_QP_OPTPAR_PM_STATE;
+       case IB_QP_CAP:
+               return 0;
+       case IB_QP_DEST_QPN:
+               return 0;
+       }
+       return 0;
+}
+
+static int ib_mask_to_mlx5_opt(int ib_mask)
+{
+       int result = 0;
+       int i;
+
+       for (i = 0; i < 8 * sizeof(int); i++) {
+               if ((1 << i) & ib_mask)
+                       result |= ib_nr_to_mlx5_nr(1 << i);
+       }
+
+       return result;
+}
+
+static int __mlx5_ib_modify_qp(struct ib_qp *ibqp,
+                              const struct ib_qp_attr *attr, int attr_mask,
+                              enum ib_qp_state cur_state, enum ib_qp_state new_state)
+{
+       struct mlx5_ib_dev *dev = to_mdev(ibqp->device);
+       struct mlx5_ib_qp *qp = to_mqp(ibqp);
+       struct mlx5_ib_cq *send_cq, *recv_cq;
+       struct mlx5_qp_context *context;
+       struct mlx5_modify_qp_mbox_in *in;
+       struct mlx5_ib_pd *pd;
+       enum mlx5_qp_state mlx5_cur, mlx5_new;
+       enum mlx5_qp_optpar optpar;
+       int sqd_event;
+       int mlx5_st;
+       int err;
+
+       in = kzalloc(sizeof(*in), GFP_KERNEL);
+       if (!in)
+               return -ENOMEM;
+
+       context = &in->ctx;
+       err = to_mlx5_st(ibqp->qp_type);
+       if (err < 0)
+               goto out;
+
+       context->flags = cpu_to_be32(err << 16);
+
+       if (!(attr_mask & IB_QP_PATH_MIG_STATE)) {
+               context->flags |= cpu_to_be32(MLX5_QP_PM_MIGRATED << 11);
+       } else {
+               switch (attr->path_mig_state) {
+               case IB_MIG_MIGRATED:
+                       context->flags |= cpu_to_be32(MLX5_QP_PM_MIGRATED << 11);
+                       break;
+               case IB_MIG_REARM:
+                       context->flags |= cpu_to_be32(MLX5_QP_PM_REARM << 11);
+                       break;
+               case IB_MIG_ARMED:
+                       context->flags |= cpu_to_be32(MLX5_QP_PM_ARMED << 11);
+                       break;
+               }
+       }
+
+       if (ibqp->qp_type == IB_QPT_GSI || ibqp->qp_type == IB_QPT_SMI) {
+               context->mtu_msgmax = (IB_MTU_256 << 5) | 8;
+       } else if (ibqp->qp_type == IB_QPT_UD ||
+                  ibqp->qp_type == MLX5_IB_QPT_REG_UMR) {
+               context->mtu_msgmax = (IB_MTU_4096 << 5) | 12;
+       } else if (attr_mask & IB_QP_PATH_MTU) {
+               if (attr->path_mtu < IB_MTU_256 ||
+                   attr->path_mtu > IB_MTU_4096) {
+                       mlx5_ib_warn(dev, "invalid mtu %d\n", attr->path_mtu);
+                       err = -EINVAL;
+                       goto out;
+               }
+               context->mtu_msgmax = (attr->path_mtu << 5) | dev->mdev.caps.log_max_msg;
+       }
+
+       if (attr_mask & IB_QP_DEST_QPN)
+               context->log_pg_sz_remote_qpn = cpu_to_be32(attr->dest_qp_num);
+
+       if (attr_mask & IB_QP_PKEY_INDEX)
+               context->pri_path.pkey_index = attr->pkey_index;
+
+       /* todo implement counter_index functionality */
+
+       if (is_sqp(ibqp->qp_type))
+               context->pri_path.port = qp->port;
+
+       if (attr_mask & IB_QP_PORT)
+               context->pri_path.port = attr->port_num;
+
+       if (attr_mask & IB_QP_AV) {
+               err = mlx5_set_path(dev, &attr->ah_attr, &context->pri_path,
+                                   attr_mask & IB_QP_PORT ? attr->port_num : qp->port,
+                                   attr_mask, 0, attr);
+               if (err)
+                       goto out;
+       }
+
+       if (attr_mask & IB_QP_TIMEOUT)
+               context->pri_path.ackto_lt |= attr->timeout << 3;
+
+       if (attr_mask & IB_QP_ALT_PATH) {
+               err = mlx5_set_path(dev, &attr->alt_ah_attr, &context->alt_path,
+                                   attr->alt_port_num, attr_mask, 0, attr);
+               if (err)
+                       goto out;
+       }
+
+       pd = get_pd(qp);
+       get_cqs(qp, &send_cq, &recv_cq);
+
+       context->flags_pd = cpu_to_be32(pd ? pd->pdn : to_mpd(dev->devr.p0)->pdn);
+       context->cqn_send = send_cq ? cpu_to_be32(send_cq->mcq.cqn) : 0;
+       context->cqn_recv = recv_cq ? cpu_to_be32(recv_cq->mcq.cqn) : 0;
+       context->params1  = cpu_to_be32(MLX5_IB_ACK_REQ_FREQ << 28);
+
+       if (attr_mask & IB_QP_RNR_RETRY)
+               context->params1 |= cpu_to_be32(attr->rnr_retry << 13);
+
+       if (attr_mask & IB_QP_RETRY_CNT)
+               context->params1 |= cpu_to_be32(attr->retry_cnt << 16);
+
+       if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC) {
+               if (attr->max_rd_atomic)
+                       context->params1 |=
+                               cpu_to_be32(fls(attr->max_rd_atomic - 1) << 21);
+       }
+
+       if (attr_mask & IB_QP_SQ_PSN)
+               context->next_send_psn = cpu_to_be32(attr->sq_psn);
+
+       if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC) {
+               if (attr->max_dest_rd_atomic)
+                       context->params2 |=
+                               cpu_to_be32(fls(attr->max_dest_rd_atomic - 1) << 21);
+       }
+
+       if (attr_mask & (IB_QP_ACCESS_FLAGS | IB_QP_MAX_DEST_RD_ATOMIC))
+               context->params2 |= to_mlx5_access_flags(qp, attr, attr_mask);
+
+       if (attr_mask & IB_QP_MIN_RNR_TIMER)
+               context->rnr_nextrecvpsn |= cpu_to_be32(attr->min_rnr_timer << 24);
+
+       if (attr_mask & IB_QP_RQ_PSN)
+               context->rnr_nextrecvpsn |= cpu_to_be32(attr->rq_psn);
+
+       if (attr_mask & IB_QP_QKEY)
+               context->qkey = cpu_to_be32(attr->qkey);
+
+       if (qp->rq.wqe_cnt && cur_state == IB_QPS_RESET && new_state == IB_QPS_INIT)
+               context->db_rec_addr = cpu_to_be64(qp->db.dma);
+
+       if (cur_state == IB_QPS_RTS && new_state == IB_QPS_SQD  &&
+           attr_mask & IB_QP_EN_SQD_ASYNC_NOTIFY && attr->en_sqd_async_notify)
+               sqd_event = 1;
+       else
+               sqd_event = 0;
+
+       if (!ibqp->uobject && cur_state == IB_QPS_RESET && new_state == IB_QPS_INIT)
+               context->sq_crq_size |= cpu_to_be16(1 << 4);
+
+
+       mlx5_cur = to_mlx5_state(cur_state);
+       mlx5_new = to_mlx5_state(new_state);
+       mlx5_st = to_mlx5_st(ibqp->qp_type);
+       if (mlx5_cur < 0 || mlx5_new < 0 || mlx5_st < 0)
+               goto out;
+
+       optpar = ib_mask_to_mlx5_opt(attr_mask);
+       optpar &= opt_mask[mlx5_cur][mlx5_new][mlx5_st];
+       in->optparam = cpu_to_be32(optpar);
+       err = mlx5_core_qp_modify(&dev->mdev, to_mlx5_state(cur_state),
+                                 to_mlx5_state(new_state), in, sqd_event,
+                                 &qp->mqp);
+       if (err)
+               goto out;
+
+       qp->state = new_state;
+
+       if (attr_mask & IB_QP_ACCESS_FLAGS)
+               qp->atomic_rd_en = attr->qp_access_flags;
+       if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC)
+               qp->resp_depth = attr->max_dest_rd_atomic;
+       if (attr_mask & IB_QP_PORT)
+               qp->port = attr->port_num;
+       if (attr_mask & IB_QP_ALT_PATH)
+               qp->alt_port = attr->alt_port_num;
+
+       /*
+        * If we moved a kernel QP to RESET, clean up all old CQ
+        * entries and reinitialize the QP.
+        */
+       if (new_state == IB_QPS_RESET && !ibqp->uobject) {
+               mlx5_ib_cq_clean(recv_cq, qp->mqp.qpn,
+                                ibqp->srq ? to_msrq(ibqp->srq) : NULL);
+               if (send_cq != recv_cq)
+                       mlx5_ib_cq_clean(send_cq, qp->mqp.qpn, NULL);
+
+               qp->rq.head = 0;
+               qp->rq.tail = 0;
+               qp->sq.head = 0;
+               qp->sq.tail = 0;
+               qp->sq.cur_post = 0;
+               qp->sq.last_poll = 0;
+               qp->db.db[MLX5_RCV_DBR] = 0;
+               qp->db.db[MLX5_SND_DBR] = 0;
+       }
+
+out:
+       kfree(in);
+       return err;
+}
+
+int mlx5_ib_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
+                     int attr_mask, struct ib_udata *udata)
+{
+       struct mlx5_ib_dev *dev = to_mdev(ibqp->device);
+       struct mlx5_ib_qp *qp = to_mqp(ibqp);
+       enum ib_qp_state cur_state, new_state;
+       int err = -EINVAL;
+       int port;
+
+       mutex_lock(&qp->mutex);
+
+       cur_state = attr_mask & IB_QP_CUR_STATE ? attr->cur_qp_state : qp->state;
+       new_state = attr_mask & IB_QP_STATE ? attr->qp_state : cur_state;
+
+       if (ibqp->qp_type != MLX5_IB_QPT_REG_UMR &&
+           !ib_modify_qp_is_ok(cur_state, new_state, ibqp->qp_type, attr_mask))
+               goto out;
+
+       if ((attr_mask & IB_QP_PORT) &&
+           (attr->port_num == 0 || attr->port_num > dev->mdev.caps.num_ports))
+               goto out;
+
+       if (attr_mask & IB_QP_PKEY_INDEX) {
+               port = attr_mask & IB_QP_PORT ? attr->port_num : qp->port;
+               if (attr->pkey_index >= dev->mdev.caps.port[port - 1].pkey_table_len)
+                       goto out;
+       }
+
+       if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC &&
+           attr->max_rd_atomic > dev->mdev.caps.max_ra_res_qp)
+               goto out;
+
+       if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC &&
+           attr->max_dest_rd_atomic > dev->mdev.caps.max_ra_req_qp)
+               goto out;
+
+       if (cur_state == new_state && cur_state == IB_QPS_RESET) {
+               err = 0;
+               goto out;
+       }
+
+       err = __mlx5_ib_modify_qp(ibqp, attr, attr_mask, cur_state, new_state);
+
+out:
+       mutex_unlock(&qp->mutex);
+       return err;
+}
+
+static int mlx5_wq_overflow(struct mlx5_ib_wq *wq, int nreq, struct ib_cq *ib_cq)
+{
+       struct mlx5_ib_cq *cq;
+       unsigned cur;
+
+       cur = wq->head - wq->tail;
+       if (likely(cur + nreq < wq->max_post))
+               return 0;
+
+       cq = to_mcq(ib_cq);
+       spin_lock(&cq->lock);
+       cur = wq->head - wq->tail;
+       spin_unlock(&cq->lock);
+
+       return cur + nreq >= wq->max_post;
+}
+
+static __always_inline void set_raddr_seg(struct mlx5_wqe_raddr_seg *rseg,
+                                         u64 remote_addr, u32 rkey)
+{
+       rseg->raddr    = cpu_to_be64(remote_addr);
+       rseg->rkey     = cpu_to_be32(rkey);
+       rseg->reserved = 0;
+}
+
+static void set_atomic_seg(struct mlx5_wqe_atomic_seg *aseg, struct ib_send_wr *wr)
+{
+       if (wr->opcode == IB_WR_ATOMIC_CMP_AND_SWP) {
+               aseg->swap_add = cpu_to_be64(wr->wr.atomic.swap);
+               aseg->compare  = cpu_to_be64(wr->wr.atomic.compare_add);
+       } else if (wr->opcode == IB_WR_MASKED_ATOMIC_FETCH_AND_ADD) {
+               aseg->swap_add = cpu_to_be64(wr->wr.atomic.compare_add);
+               aseg->compare  = cpu_to_be64(wr->wr.atomic.compare_add_mask);
+       } else {
+               aseg->swap_add = cpu_to_be64(wr->wr.atomic.compare_add);
+               aseg->compare  = 0;
+       }
+}
+
+static void set_masked_atomic_seg(struct mlx5_wqe_masked_atomic_seg *aseg,
+                                 struct ib_send_wr *wr)
+{
+       aseg->swap_add          = cpu_to_be64(wr->wr.atomic.swap);
+       aseg->swap_add_mask     = cpu_to_be64(wr->wr.atomic.swap_mask);
+       aseg->compare           = cpu_to_be64(wr->wr.atomic.compare_add);
+       aseg->compare_mask      = cpu_to_be64(wr->wr.atomic.compare_add_mask);
+}
+
+static void set_datagram_seg(struct mlx5_wqe_datagram_seg *dseg,
+                            struct ib_send_wr *wr)
+{
+       memcpy(&dseg->av, &to_mah(wr->wr.ud.ah)->av, sizeof(struct mlx5_av));
+       dseg->av.dqp_dct = cpu_to_be32(wr->wr.ud.remote_qpn | MLX5_EXTENDED_UD_AV);
+       dseg->av.key.qkey.qkey = cpu_to_be32(wr->wr.ud.remote_qkey);
+}
+
+static void set_data_ptr_seg(struct mlx5_wqe_data_seg *dseg, struct ib_sge *sg)
+{
+       dseg->byte_count = cpu_to_be32(sg->length);
+       dseg->lkey       = cpu_to_be32(sg->lkey);
+       dseg->addr       = cpu_to_be64(sg->addr);
+}
+
+static __be16 get_klm_octo(int npages)
+{
+       return cpu_to_be16(ALIGN(npages, 8) / 2);
+}
+
+static __be64 frwr_mkey_mask(void)
+{
+       u64 result;
+
+       result = MLX5_MKEY_MASK_LEN             |
+               MLX5_MKEY_MASK_PAGE_SIZE        |
+               MLX5_MKEY_MASK_START_ADDR       |
+               MLX5_MKEY_MASK_EN_RINVAL        |
+               MLX5_MKEY_MASK_KEY              |
+               MLX5_MKEY_MASK_LR               |
+               MLX5_MKEY_MASK_LW               |
+               MLX5_MKEY_MASK_RR               |
+               MLX5_MKEY_MASK_RW               |
+               MLX5_MKEY_MASK_A                |
+               MLX5_MKEY_MASK_SMALL_FENCE      |
+               MLX5_MKEY_MASK_FREE;
+
+       return cpu_to_be64(result);
+}
+
+static void set_frwr_umr_segment(struct mlx5_wqe_umr_ctrl_seg *umr,
+                                struct ib_send_wr *wr, int li)
+{
+       memset(umr, 0, sizeof(*umr));
+
+       if (li) {
+               umr->mkey_mask = cpu_to_be64(MLX5_MKEY_MASK_FREE);
+               umr->flags = 1 << 7;
+               return;
+       }
+
+       umr->flags = (1 << 5); /* fail if not free */
+       umr->klm_octowords = get_klm_octo(wr->wr.fast_reg.page_list_len);
+       umr->mkey_mask = frwr_mkey_mask();
+}
+
+static void set_reg_umr_segment(struct mlx5_wqe_umr_ctrl_seg *umr,
+                               struct ib_send_wr *wr)
+{
+       struct umr_wr *umrwr = (struct umr_wr *)&wr->wr.fast_reg;
+       u64 mask;
+
+       memset(umr, 0, sizeof(*umr));
+
+       if (!(wr->send_flags & MLX5_IB_SEND_UMR_UNREG)) {
+               umr->flags = 1 << 5; /* fail if not free */
+               umr->klm_octowords = get_klm_octo(umrwr->npages);
+               mask =  MLX5_MKEY_MASK_LEN              |
+                       MLX5_MKEY_MASK_PAGE_SIZE        |
+                       MLX5_MKEY_MASK_START_ADDR       |
+                       MLX5_MKEY_MASK_PD               |
+                       MLX5_MKEY_MASK_LR               |
+                       MLX5_MKEY_MASK_LW               |
+                       MLX5_MKEY_MASK_RR               |
+                       MLX5_MKEY_MASK_RW               |
+                       MLX5_MKEY_MASK_A                |
+                       MLX5_MKEY_MASK_FREE;
+               umr->mkey_mask = cpu_to_be64(mask);
+       } else {
+               umr->flags = 2 << 5; /* fail if free */
+               mask = MLX5_MKEY_MASK_FREE;
+               umr->mkey_mask = cpu_to_be64(mask);
+       }
+
+       if (!wr->num_sge)
+               umr->flags |= (1 << 7); /* inline */
+}
+
+static u8 get_umr_flags(int acc)
+{
+       return (acc & IB_ACCESS_REMOTE_ATOMIC ? MLX5_PERM_ATOMIC       : 0) |
+              (acc & IB_ACCESS_REMOTE_WRITE  ? MLX5_PERM_REMOTE_WRITE : 0) |
+              (acc & IB_ACCESS_REMOTE_READ   ? MLX5_PERM_REMOTE_READ  : 0) |
+              (acc & IB_ACCESS_LOCAL_WRITE   ? MLX5_PERM_LOCAL_WRITE  : 0) |
+               MLX5_PERM_LOCAL_READ | MLX5_PERM_UMR_EN | MLX5_ACCESS_MODE_MTT;
+}
+
+static void set_mkey_segment(struct mlx5_mkey_seg *seg, struct ib_send_wr *wr,
+                            int li, int *writ)
+{
+       memset(seg, 0, sizeof(*seg));
+       if (li) {
+               seg->status = 1 << 6;
+               return;
+       }
+
+       seg->flags = get_umr_flags(wr->wr.fast_reg.access_flags);
+       *writ = seg->flags & (MLX5_PERM_LOCAL_WRITE | IB_ACCESS_REMOTE_WRITE);
+       seg->qpn_mkey7_0 = cpu_to_be32((wr->wr.fast_reg.rkey & 0xff) | 0xffffff00);
+       seg->flags_pd = cpu_to_be32(MLX5_MKEY_REMOTE_INVAL);
+       seg->start_addr = cpu_to_be64(wr->wr.fast_reg.iova_start);
+       seg->len = cpu_to_be64(wr->wr.fast_reg.length);
+       seg->xlt_oct_size = cpu_to_be32((wr->wr.fast_reg.page_list_len + 1) / 2);
+       seg->log2_page_size = wr->wr.fast_reg.page_shift;
+}
+
+static void set_reg_mkey_segment(struct mlx5_mkey_seg *seg, struct ib_send_wr *wr)
+{
+       memset(seg, 0, sizeof(*seg));
+       if (wr->send_flags & MLX5_IB_SEND_UMR_UNREG) {
+               seg->status = 1 << 6;
+               return;
+       }
+
+       seg->flags = convert_access(wr->wr.fast_reg.access_flags);
+       seg->flags_pd = cpu_to_be32(to_mpd((struct ib_pd *)wr->wr.fast_reg.page_list)->pdn);
+       seg->start_addr = cpu_to_be64(wr->wr.fast_reg.iova_start);
+       seg->len = cpu_to_be64(wr->wr.fast_reg.length);
+       seg->log2_page_size = wr->wr.fast_reg.page_shift;
+       seg->qpn_mkey7_0 = cpu_to_be32(0xffffff << 8);
+}
+
+static void set_frwr_pages(struct mlx5_wqe_data_seg *dseg,
+                          struct ib_send_wr *wr,
+                          struct mlx5_core_dev *mdev,
+                          struct mlx5_ib_pd *pd,
+                          int writ)
+{
+       struct mlx5_ib_fast_reg_page_list *mfrpl = to_mfrpl(wr->wr.fast_reg.page_list);
+       u64 *page_list = wr->wr.fast_reg.page_list->page_list;
+       u64 perm = MLX5_EN_RD | (writ ? MLX5_EN_WR : 0);
+       int i;
+
+       for (i = 0; i < wr->wr.fast_reg.page_list_len; i++)
+               mfrpl->mapped_page_list[i] = cpu_to_be64(page_list[i] | perm);
+       dseg->addr = cpu_to_be64(mfrpl->map);
+       dseg->byte_count = cpu_to_be32(ALIGN(sizeof(u64) * wr->wr.fast_reg.page_list_len, 64));
+       dseg->lkey = cpu_to_be32(pd->pa_lkey);
+}
+
+static __be32 send_ieth(struct ib_send_wr *wr)
+{
+       switch (wr->opcode) {
+       case IB_WR_SEND_WITH_IMM:
+       case IB_WR_RDMA_WRITE_WITH_IMM:
+               return wr->ex.imm_data;
+
+       case IB_WR_SEND_WITH_INV:
+               return cpu_to_be32(wr->ex.invalidate_rkey);
+
+       default:
+               return 0;
+       }
+}
+
+static u8 calc_sig(void *wqe, int size)
+{
+       u8 *p = wqe;
+       u8 res = 0;
+       int i;
+
+       for (i = 0; i < size; i++)
+               res ^= p[i];
+
+       return ~res;
+}
+
+static u8 wq_sig(void *wqe)
+{
+       return calc_sig(wqe, (*((u8 *)wqe + 8) & 0x3f) << 4);
+}
+
+static int set_data_inl_seg(struct mlx5_ib_qp *qp, struct ib_send_wr *wr,
+                           void *wqe, int *sz)
+{
+       struct mlx5_wqe_inline_seg *seg;
+       void *qend = qp->sq.qend;
+       void *addr;
+       int inl = 0;
+       int copy;
+       int len;
+       int i;
+
+       seg = wqe;
+       wqe += sizeof(*seg);
+       for (i = 0; i < wr->num_sge; i++) {
+               addr = (void *)(unsigned long)(wr->sg_list[i].addr);
+               len  = wr->sg_list[i].length;
+               inl += len;
+
+               if (unlikely(inl > qp->max_inline_data))
+                       return -ENOMEM;
+
+               if (unlikely(wqe + len > qend)) {
+                       copy = qend - wqe;
+                       memcpy(wqe, addr, copy);
+                       addr += copy;
+                       len -= copy;
+                       wqe = mlx5_get_send_wqe(qp, 0);
+               }
+               memcpy(wqe, addr, len);
+               wqe += len;
+       }
+
+       seg->byte_count = cpu_to_be32(inl | MLX5_INLINE_SEG);
+
+       *sz = ALIGN(inl + sizeof(seg->byte_count), 16) / 16;
+
+       return 0;
+}
+
+static int set_frwr_li_wr(void **seg, struct ib_send_wr *wr, int *size,
+                         struct mlx5_core_dev *mdev, struct mlx5_ib_pd *pd, struct mlx5_ib_qp *qp)
+{
+       int writ = 0;
+       int li;
+
+       li = wr->opcode == IB_WR_LOCAL_INV ? 1 : 0;
+       if (unlikely(wr->send_flags & IB_SEND_INLINE))
+               return -EINVAL;
+
+       set_frwr_umr_segment(*seg, wr, li);
+       *seg += sizeof(struct mlx5_wqe_umr_ctrl_seg);
+       *size += sizeof(struct mlx5_wqe_umr_ctrl_seg) / 16;
+       if (unlikely((*seg == qp->sq.qend)))
+               *seg = mlx5_get_send_wqe(qp, 0);
+       set_mkey_segment(*seg, wr, li, &writ);
+       *seg += sizeof(struct mlx5_mkey_seg);
+       *size += sizeof(struct mlx5_mkey_seg) / 16;
+       if (unlikely((*seg == qp->sq.qend)))
+               *seg = mlx5_get_send_wqe(qp, 0);
+       if (!li) {
+               set_frwr_pages(*seg, wr, mdev, pd, writ);
+               *seg += sizeof(struct mlx5_wqe_data_seg);
+               *size += (sizeof(struct mlx5_wqe_data_seg) / 16);
+       }
+       return 0;
+}
+
+static void dump_wqe(struct mlx5_ib_qp *qp, int idx, int size_16)
+{
+       __be32 *p = NULL;
+       int tidx = idx;
+       int i, j;
+
+       pr_debug("dump wqe at %p\n", mlx5_get_send_wqe(qp, tidx));
+       for (i = 0, j = 0; i < size_16 * 4; i += 4, j += 4) {
+               if ((i & 0xf) == 0) {
+                       void *buf = mlx5_get_send_wqe(qp, tidx);
+                       tidx = (tidx + 1) & (qp->sq.wqe_cnt - 1);
+                       p = buf;
+                       j = 0;
+               }
+               pr_debug("%08x %08x %08x %08x\n", be32_to_cpu(p[j]),
+                        be32_to_cpu(p[j + 1]), be32_to_cpu(p[j + 2]),
+                        be32_to_cpu(p[j + 3]));
+       }
+}
+
+static void mlx5_bf_copy(u64 __iomem *dst, u64 *src,
+                        unsigned bytecnt, struct mlx5_ib_qp *qp)
+{
+       while (bytecnt > 0) {
+               __iowrite64_copy(dst++, src++, 8);
+               __iowrite64_copy(dst++, src++, 8);
+               __iowrite64_copy(dst++, src++, 8);
+               __iowrite64_copy(dst++, src++, 8);
+               __iowrite64_copy(dst++, src++, 8);
+               __iowrite64_copy(dst++, src++, 8);
+               __iowrite64_copy(dst++, src++, 8);
+               __iowrite64_copy(dst++, src++, 8);
+               bytecnt -= 64;
+               if (unlikely(src == qp->sq.qend))
+                       src = mlx5_get_send_wqe(qp, 0);
+       }
+}
+
+static u8 get_fence(u8 fence, struct ib_send_wr *wr)
+{
+       if (unlikely(wr->opcode == IB_WR_LOCAL_INV &&
+                    wr->send_flags & IB_SEND_FENCE))
+               return MLX5_FENCE_MODE_STRONG_ORDERING;
+
+       if (unlikely(fence)) {
+               if (wr->send_flags & IB_SEND_FENCE)
+                       return MLX5_FENCE_MODE_SMALL_AND_FENCE;
+               else
+                       return fence;
+
+       } else {
+               return 0;
+       }
+}
+
+int mlx5_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
+                     struct ib_send_wr **bad_wr)
+{
+       struct mlx5_wqe_ctrl_seg *ctrl = NULL;  /* compiler warning */
+       struct mlx5_ib_dev *dev = to_mdev(ibqp->device);
+       struct mlx5_core_dev *mdev = &dev->mdev;
+       struct mlx5_ib_qp *qp = to_mqp(ibqp);
+       struct mlx5_wqe_data_seg *dpseg;
+       struct mlx5_wqe_xrc_seg *xrc;
+       struct mlx5_bf *bf = qp->bf;
+       int uninitialized_var(size);
+       void *qend = qp->sq.qend;
+       unsigned long flags;
+       u32 mlx5_opcode;
+       unsigned idx;
+       int err = 0;
+       int inl = 0;
+       int num_sge;
+       void *seg;
+       int nreq;
+       int i;
+       u8 next_fence = 0;
+       u8 opmod = 0;
+       u8 fence;
+
+       spin_lock_irqsave(&qp->sq.lock, flags);
+
+       for (nreq = 0; wr; nreq++, wr = wr->next) {
+               if (unlikely(wr->opcode >= sizeof(mlx5_ib_opcode) / sizeof(mlx5_ib_opcode[0]))) {
+                       mlx5_ib_warn(dev, "\n");
+                       err = -EINVAL;
+                       *bad_wr = wr;
+                       goto out;
+               }
+
+               if (unlikely(mlx5_wq_overflow(&qp->sq, nreq, qp->ibqp.send_cq))) {
+                       mlx5_ib_warn(dev, "\n");
+                       err = -ENOMEM;
+                       *bad_wr = wr;
+                       goto out;
+               }
+
+               fence = qp->fm_cache;
+               num_sge = wr->num_sge;
+               if (unlikely(num_sge > qp->sq.max_gs)) {
+                       mlx5_ib_warn(dev, "\n");
+                       err = -ENOMEM;
+                       *bad_wr = wr;
+                       goto out;
+               }
+
+               idx = qp->sq.cur_post & (qp->sq.wqe_cnt - 1);
+               seg = mlx5_get_send_wqe(qp, idx);
+               ctrl = seg;
+               *(uint32_t *)(seg + 8) = 0;
+               ctrl->imm = send_ieth(wr);
+               ctrl->fm_ce_se = qp->sq_signal_bits |
+                       (wr->send_flags & IB_SEND_SIGNALED ?
+                        MLX5_WQE_CTRL_CQ_UPDATE : 0) |
+                       (wr->send_flags & IB_SEND_SOLICITED ?
+                        MLX5_WQE_CTRL_SOLICITED : 0);
+
+               seg += sizeof(*ctrl);
+               size = sizeof(*ctrl) / 16;
+
+               switch (ibqp->qp_type) {
+               case IB_QPT_XRC_INI:
+                       xrc = seg;
+                       xrc->xrc_srqn = htonl(wr->xrc_remote_srq_num);
+                       seg += sizeof(*xrc);
+                       size += sizeof(*xrc) / 16;
+                       /* fall through */
+               case IB_QPT_RC:
+                       switch (wr->opcode) {
+                       case IB_WR_RDMA_READ:
+                       case IB_WR_RDMA_WRITE:
+                       case IB_WR_RDMA_WRITE_WITH_IMM:
+                               set_raddr_seg(seg, wr->wr.rdma.remote_addr,
+                                             wr->wr.rdma.rkey);
+                               seg  += sizeof(struct mlx5_wqe_raddr_seg);
+                               size += sizeof(struct mlx5_wqe_raddr_seg) / 16;
+                               break;
+
+                       case IB_WR_ATOMIC_CMP_AND_SWP:
+                       case IB_WR_ATOMIC_FETCH_AND_ADD:
+                               set_raddr_seg(seg, wr->wr.atomic.remote_addr,
+                                             wr->wr.atomic.rkey);
+                               seg  += sizeof(struct mlx5_wqe_raddr_seg);
+
+                               set_atomic_seg(seg, wr);
+                               seg  += sizeof(struct mlx5_wqe_atomic_seg);
+
+                               size += (sizeof(struct mlx5_wqe_raddr_seg) +
+                                        sizeof(struct mlx5_wqe_atomic_seg)) / 16;
+                               break;
+
+                       case IB_WR_MASKED_ATOMIC_CMP_AND_SWP:
+                               set_raddr_seg(seg, wr->wr.atomic.remote_addr,
+                                             wr->wr.atomic.rkey);
+                               seg  += sizeof(struct mlx5_wqe_raddr_seg);
+
+                               set_masked_atomic_seg(seg, wr);
+                               seg  += sizeof(struct mlx5_wqe_masked_atomic_seg);
+
+                               size += (sizeof(struct mlx5_wqe_raddr_seg) +
+                                        sizeof(struct mlx5_wqe_masked_atomic_seg)) / 16;
+                               break;
+
+                       case IB_WR_LOCAL_INV:
+                               next_fence = MLX5_FENCE_MODE_INITIATOR_SMALL;
+                               qp->sq.wr_data[idx] = IB_WR_LOCAL_INV;
+                               ctrl->imm = cpu_to_be32(wr->ex.invalidate_rkey);
+                               err = set_frwr_li_wr(&seg, wr, &size, mdev, to_mpd(ibqp->pd), qp);
+                               if (err) {
+                                       mlx5_ib_warn(dev, "\n");
+                                       *bad_wr = wr;
+                                       goto out;
+                               }
+                               num_sge = 0;
+                               break;
+
+                       case IB_WR_FAST_REG_MR:
+                               next_fence = MLX5_FENCE_MODE_INITIATOR_SMALL;
+                               qp->sq.wr_data[idx] = IB_WR_FAST_REG_MR;
+                               ctrl->imm = cpu_to_be32(wr->wr.fast_reg.rkey);
+                               err = set_frwr_li_wr(&seg, wr, &size, mdev, to_mpd(ibqp->pd), qp);
+                               if (err) {
+                                       mlx5_ib_warn(dev, "\n");
+                                       *bad_wr = wr;
+                                       goto out;
+                               }
+                               num_sge = 0;
+                               break;
+
+                       default:
+                               break;
+                       }
+                       break;
+
+               case IB_QPT_UC:
+                       switch (wr->opcode) {
+                       case IB_WR_RDMA_WRITE:
+                       case IB_WR_RDMA_WRITE_WITH_IMM:
+                               set_raddr_seg(seg, wr->wr.rdma.remote_addr,
+                                             wr->wr.rdma.rkey);
+                               seg  += sizeof(struct mlx5_wqe_raddr_seg);
+                               size += sizeof(struct mlx5_wqe_raddr_seg) / 16;
+                               break;
+
+                       default:
+                               break;
+                       }
+                       break;
+
+               case IB_QPT_UD:
+               case IB_QPT_SMI:
+               case IB_QPT_GSI:
+                       set_datagram_seg(seg, wr);
+                       seg  += sizeof(struct mlx5_wqe_datagram_seg);
+                       size += sizeof(struct mlx5_wqe_datagram_seg) / 16;
+                       if (unlikely((seg == qend)))
+                               seg = mlx5_get_send_wqe(qp, 0);
+                       break;
+
+               case MLX5_IB_QPT_REG_UMR:
+                       if (wr->opcode != MLX5_IB_WR_UMR) {
+                               err = -EINVAL;
+                               mlx5_ib_warn(dev, "bad opcode\n");
+                               goto out;
+                       }
+                       qp->sq.wr_data[idx] = MLX5_IB_WR_UMR;
+                       ctrl->imm = cpu_to_be32(wr->wr.fast_reg.rkey);
+                       set_reg_umr_segment(seg, wr);
+                       seg += sizeof(struct mlx5_wqe_umr_ctrl_seg);
+                       size += sizeof(struct mlx5_wqe_umr_ctrl_seg) / 16;
+                       if (unlikely((seg == qend)))
+                               seg = mlx5_get_send_wqe(qp, 0);
+                       set_reg_mkey_segment(seg, wr);
+                       seg += sizeof(struct mlx5_mkey_seg);
+                       size += sizeof(struct mlx5_mkey_seg) / 16;
+                       if (unlikely((seg == qend)))
+                               seg = mlx5_get_send_wqe(qp, 0);
+                       break;
+
+               default:
+                       break;
+               }
+
+               if (wr->send_flags & IB_SEND_INLINE && num_sge) {
+                       int uninitialized_var(sz);
+
+                       err = set_data_inl_seg(qp, wr, seg, &sz);
+                       if (unlikely(err)) {
+                               mlx5_ib_warn(dev, "\n");
+                               *bad_wr = wr;
+                               goto out;
+                       }
+                       inl = 1;
+                       size += sz;
+               } else {
+                       dpseg = seg;
+                       for (i = 0; i < num_sge; i++) {
+                               if (unlikely(dpseg == qend)) {
+                                       seg = mlx5_get_send_wqe(qp, 0);
+                                       dpseg = seg;
+                               }
+                               if (likely(wr->sg_list[i].length)) {
+                                       set_data_ptr_seg(dpseg, wr->sg_list + i);
+                                       size += sizeof(struct mlx5_wqe_data_seg) / 16;
+                                       dpseg++;
+                               }
+                       }
+               }
+
+               mlx5_opcode = mlx5_ib_opcode[wr->opcode];
+               ctrl->opmod_idx_opcode = cpu_to_be32(((u32)(qp->sq.cur_post) << 8)      |
+                                                    mlx5_opcode                        |
+                                                    ((u32)opmod << 24));
+               ctrl->qpn_ds = cpu_to_be32(size | (qp->mqp.qpn << 8));
+               ctrl->fm_ce_se |= get_fence(fence, wr);
+               qp->fm_cache = next_fence;
+               if (unlikely(qp->wq_sig))
+                       ctrl->signature = wq_sig(ctrl);
+
+               qp->sq.wrid[idx] = wr->wr_id;
+               qp->sq.w_list[idx].opcode = mlx5_opcode;
+               qp->sq.wqe_head[idx] = qp->sq.head + nreq;
+               qp->sq.cur_post += DIV_ROUND_UP(size * 16, MLX5_SEND_WQE_BB);
+               qp->sq.w_list[idx].next = qp->sq.cur_post;
+
+               if (0)
+                       dump_wqe(qp, idx, size);
+       }
+
+out:
+       if (likely(nreq)) {
+               qp->sq.head += nreq;
+
+               /* Make sure that descriptors are written before
+                * updating doorbell record and ringing the doorbell
+                */
+               wmb();
+
+               qp->db.db[MLX5_SND_DBR] = cpu_to_be32(qp->sq.cur_post);
+
+               if (bf->need_lock)
+                       spin_lock(&bf->lock);
+
+               /* TBD enable WC */
+               if (0 && nreq == 1 && bf->uuarn && inl && size > 1 && size <= bf->buf_size / 16) {
+                       mlx5_bf_copy(bf->reg + bf->offset, (u64 *)ctrl, ALIGN(size * 16, 64), qp);
+                       /* wc_wmb(); */
+               } else {
+                       mlx5_write64((__be32 *)ctrl, bf->regreg + bf->offset,
+                                    MLX5_GET_DOORBELL_LOCK(&bf->lock32));
+                       /* Make sure doorbells don't leak out of SQ spinlock
+                        * and reach the HCA out of order.
+                        */
+                       mmiowb();
+               }
+               bf->offset ^= bf->buf_size;
+               if (bf->need_lock)
+                       spin_unlock(&bf->lock);
+       }
+
+       spin_unlock_irqrestore(&qp->sq.lock, flags);
+
+       return err;
+}
+
+static void set_sig_seg(struct mlx5_rwqe_sig *sig, int size)
+{
+       sig->signature = calc_sig(sig, size);
+}
+
+int mlx5_ib_post_recv(struct ib_qp *ibqp, struct ib_recv_wr *wr,
+                     struct ib_recv_wr **bad_wr)
+{
+       struct mlx5_ib_qp *qp = to_mqp(ibqp);
+       struct mlx5_wqe_data_seg *scat;
+       struct mlx5_rwqe_sig *sig;
+       unsigned long flags;
+       int err = 0;
+       int nreq;
+       int ind;
+       int i;
+
+       spin_lock_irqsave(&qp->rq.lock, flags);
+
+       ind = qp->rq.head & (qp->rq.wqe_cnt - 1);
+
+       for (nreq = 0; wr; nreq++, wr = wr->next) {
+               if (mlx5_wq_overflow(&qp->rq, nreq, qp->ibqp.recv_cq)) {
+                       err = -ENOMEM;
+                       *bad_wr = wr;
+                       goto out;
+               }
+
+               if (unlikely(wr->num_sge > qp->rq.max_gs)) {
+                       err = -EINVAL;
+                       *bad_wr = wr;
+                       goto out;
+               }
+
+               scat = get_recv_wqe(qp, ind);
+               if (qp->wq_sig)
+                       scat++;
+
+               for (i = 0; i < wr->num_sge; i++)
+                       set_data_ptr_seg(scat + i, wr->sg_list + i);
+
+               if (i < qp->rq.max_gs) {
+                       scat[i].byte_count = 0;
+                       scat[i].lkey       = cpu_to_be32(MLX5_INVALID_LKEY);
+                       scat[i].addr       = 0;
+               }
+
+               if (qp->wq_sig) {
+                       sig = (struct mlx5_rwqe_sig *)scat;
+                       set_sig_seg(sig, (qp->rq.max_gs + 1) << 2);
+               }
+
+               qp->rq.wrid[ind] = wr->wr_id;
+
+               ind = (ind + 1) & (qp->rq.wqe_cnt - 1);
+       }
+
+out:
+       if (likely(nreq)) {
+               qp->rq.head += nreq;
+
+               /* Make sure that descriptors are written before
+                * doorbell record.
+                */
+               wmb();
+
+               *qp->db.db = cpu_to_be32(qp->rq.head & 0xffff);
+       }
+
+       spin_unlock_irqrestore(&qp->rq.lock, flags);
+
+       return err;
+}
+
+static inline enum ib_qp_state to_ib_qp_state(enum mlx5_qp_state mlx5_state)
+{
+       switch (mlx5_state) {
+       case MLX5_QP_STATE_RST:      return IB_QPS_RESET;
+       case MLX5_QP_STATE_INIT:     return IB_QPS_INIT;
+       case MLX5_QP_STATE_RTR:      return IB_QPS_RTR;
+       case MLX5_QP_STATE_RTS:      return IB_QPS_RTS;
+       case MLX5_QP_STATE_SQ_DRAINING:
+       case MLX5_QP_STATE_SQD:      return IB_QPS_SQD;
+       case MLX5_QP_STATE_SQER:     return IB_QPS_SQE;
+       case MLX5_QP_STATE_ERR:      return IB_QPS_ERR;
+       default:                     return -1;
+       }
+}
+
+static inline enum ib_mig_state to_ib_mig_state(int mlx5_mig_state)
+{
+       switch (mlx5_mig_state) {
+       case MLX5_QP_PM_ARMED:          return IB_MIG_ARMED;
+       case MLX5_QP_PM_REARM:          return IB_MIG_REARM;
+       case MLX5_QP_PM_MIGRATED:       return IB_MIG_MIGRATED;
+       default: return -1;
+       }
+}
+
+static int to_ib_qp_access_flags(int mlx5_flags)
+{
+       int ib_flags = 0;
+
+       if (mlx5_flags & MLX5_QP_BIT_RRE)
+               ib_flags |= IB_ACCESS_REMOTE_READ;
+       if (mlx5_flags & MLX5_QP_BIT_RWE)
+               ib_flags |= IB_ACCESS_REMOTE_WRITE;
+       if (mlx5_flags & MLX5_QP_BIT_RAE)
+               ib_flags |= IB_ACCESS_REMOTE_ATOMIC;
+
+       return ib_flags;
+}
+
+static void to_ib_ah_attr(struct mlx5_ib_dev *ibdev, struct ib_ah_attr *ib_ah_attr,
+                               struct mlx5_qp_path *path)
+{
+       struct mlx5_core_dev *dev = &ibdev->mdev;
+
+       memset(ib_ah_attr, 0, sizeof(*ib_ah_attr));
+       ib_ah_attr->port_num      = path->port;
+
+       if (ib_ah_attr->port_num == 0 || ib_ah_attr->port_num > dev->caps.num_ports)
+               return;
+
+       ib_ah_attr->sl = path->sl & 0xf;
+
+       ib_ah_attr->dlid          = be16_to_cpu(path->rlid);
+       ib_ah_attr->src_path_bits = path->grh_mlid & 0x7f;
+       ib_ah_attr->static_rate   = path->static_rate ? path->static_rate - 5 : 0;
+       ib_ah_attr->ah_flags      = (path->grh_mlid & (1 << 7)) ? IB_AH_GRH : 0;
+       if (ib_ah_attr->ah_flags) {
+               ib_ah_attr->grh.sgid_index = path->mgid_index;
+               ib_ah_attr->grh.hop_limit  = path->hop_limit;
+               ib_ah_attr->grh.traffic_class =
+                       (be32_to_cpu(path->tclass_flowlabel) >> 20) & 0xff;
+               ib_ah_attr->grh.flow_label =
+                       be32_to_cpu(path->tclass_flowlabel) & 0xfffff;
+               memcpy(ib_ah_attr->grh.dgid.raw,
+                      path->rgid, sizeof(ib_ah_attr->grh.dgid.raw));
+       }
+}
+
+int mlx5_ib_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr, int qp_attr_mask,
+                    struct ib_qp_init_attr *qp_init_attr)
+{
+       struct mlx5_ib_dev *dev = to_mdev(ibqp->device);
+       struct mlx5_ib_qp *qp = to_mqp(ibqp);
+       struct mlx5_query_qp_mbox_out *outb;
+       struct mlx5_qp_context *context;
+       int mlx5_state;
+       int err = 0;
+
+       mutex_lock(&qp->mutex);
+       outb = kzalloc(sizeof(*outb), GFP_KERNEL);
+       if (!outb) {
+               err = -ENOMEM;
+               goto out;
+       }
+       context = &outb->ctx;
+       err = mlx5_core_qp_query(&dev->mdev, &qp->mqp, outb, sizeof(*outb));
+       if (err)
+               goto out_free;
+
+       mlx5_state = be32_to_cpu(context->flags) >> 28;
+
+       qp->state                    = to_ib_qp_state(mlx5_state);
+       qp_attr->qp_state            = qp->state;
+       qp_attr->path_mtu            = context->mtu_msgmax >> 5;
+       qp_attr->path_mig_state      =
+               to_ib_mig_state((be32_to_cpu(context->flags) >> 11) & 0x3);
+       qp_attr->qkey                = be32_to_cpu(context->qkey);
+       qp_attr->rq_psn              = be32_to_cpu(context->rnr_nextrecvpsn) & 0xffffff;
+       qp_attr->sq_psn              = be32_to_cpu(context->next_send_psn) & 0xffffff;
+       qp_attr->dest_qp_num         = be32_to_cpu(context->log_pg_sz_remote_qpn) & 0xffffff;
+       qp_attr->qp_access_flags     =
+               to_ib_qp_access_flags(be32_to_cpu(context->params2));
+
+       if (qp->ibqp.qp_type == IB_QPT_RC || qp->ibqp.qp_type == IB_QPT_UC) {
+               to_ib_ah_attr(dev, &qp_attr->ah_attr, &context->pri_path);
+               to_ib_ah_attr(dev, &qp_attr->alt_ah_attr, &context->alt_path);
+               qp_attr->alt_pkey_index = context->alt_path.pkey_index & 0x7f;
+               qp_attr->alt_port_num   = qp_attr->alt_ah_attr.port_num;
+       }
+
+       qp_attr->pkey_index = context->pri_path.pkey_index & 0x7f;
+       qp_attr->port_num = context->pri_path.port;
+
+       /* qp_attr->en_sqd_async_notify is only applicable in modify qp */
+       qp_attr->sq_draining = mlx5_state == MLX5_QP_STATE_SQ_DRAINING;
+
+       qp_attr->max_rd_atomic = 1 << ((be32_to_cpu(context->params1) >> 21) & 0x7);
+
+       qp_attr->max_dest_rd_atomic =
+               1 << ((be32_to_cpu(context->params2) >> 21) & 0x7);
+       qp_attr->min_rnr_timer      =
+               (be32_to_cpu(context->rnr_nextrecvpsn) >> 24) & 0x1f;
+       qp_attr->timeout            = context->pri_path.ackto_lt >> 3;
+       qp_attr->retry_cnt          = (be32_to_cpu(context->params1) >> 16) & 0x7;
+       qp_attr->rnr_retry          = (be32_to_cpu(context->params1) >> 13) & 0x7;
+       qp_attr->alt_timeout        = context->alt_path.ackto_lt >> 3;
+       qp_attr->cur_qp_state        = qp_attr->qp_state;
+       qp_attr->cap.max_recv_wr     = qp->rq.wqe_cnt;
+       qp_attr->cap.max_recv_sge    = qp->rq.max_gs;
+
+       if (!ibqp->uobject) {
+               qp_attr->cap.max_send_wr  = qp->sq.wqe_cnt;
+               qp_attr->cap.max_send_sge = qp->sq.max_gs;
+       } else {
+               qp_attr->cap.max_send_wr  = 0;
+               qp_attr->cap.max_send_sge = 0;
+       }
+
+       /* We don't support inline sends for kernel QPs (yet), and we
+        * don't know what userspace's value should be.
+        */
+       qp_attr->cap.max_inline_data = 0;
+
+       qp_init_attr->cap            = qp_attr->cap;
+
+       qp_init_attr->create_flags = 0;
+       if (qp->flags & MLX5_IB_QP_BLOCK_MULTICAST_LOOPBACK)
+               qp_init_attr->create_flags |= IB_QP_CREATE_BLOCK_MULTICAST_LOOPBACK;
+
+       qp_init_attr->sq_sig_type = qp->sq_signal_bits & MLX5_WQE_CTRL_CQ_UPDATE ?
+               IB_SIGNAL_ALL_WR : IB_SIGNAL_REQ_WR;
+
+out_free:
+       kfree(outb);
+
+out:
+       mutex_unlock(&qp->mutex);
+       return err;
+}
+
+struct ib_xrcd *mlx5_ib_alloc_xrcd(struct ib_device *ibdev,
+                                         struct ib_ucontext *context,
+                                         struct ib_udata *udata)
+{
+       struct mlx5_ib_dev *dev = to_mdev(ibdev);
+       struct mlx5_ib_xrcd *xrcd;
+       int err;
+
+       if (!(dev->mdev.caps.flags & MLX5_DEV_CAP_FLAG_XRC))
+               return ERR_PTR(-ENOSYS);
+
+       xrcd = kmalloc(sizeof(*xrcd), GFP_KERNEL);
+       if (!xrcd)
+               return ERR_PTR(-ENOMEM);
+
+       err = mlx5_core_xrcd_alloc(&dev->mdev, &xrcd->xrcdn);
+       if (err) {
+               kfree(xrcd);
+               return ERR_PTR(-ENOMEM);
+       }
+
+       return &xrcd->ibxrcd;
+}
+
+int mlx5_ib_dealloc_xrcd(struct ib_xrcd *xrcd)
+{
+       struct mlx5_ib_dev *dev = to_mdev(xrcd->device);
+       u32 xrcdn = to_mxrcd(xrcd)->xrcdn;
+       int err;
+
+       err = mlx5_core_xrcd_dealloc(&dev->mdev, xrcdn);
+       if (err) {
+               mlx5_ib_warn(dev, "failed to dealloc xrcdn 0x%x\n", xrcdn);
+               return err;
+       }
+
+       kfree(xrcd);
+
+       return 0;
+}
diff --git a/drivers/infiniband/hw/mlx5/srq.c b/drivers/infiniband/hw/mlx5/srq.c
new file mode 100644 (file)
index 0000000..84d297a
--- /dev/null
@@ -0,0 +1,473 @@
+/*
+ * Copyright (c) 2013, Mellanox Technologies inc.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/module.h>
+#include <linux/mlx5/qp.h>
+#include <linux/mlx5/srq.h>
+#include <linux/slab.h>
+#include <rdma/ib_umem.h>
+
+#include "mlx5_ib.h"
+#include "user.h"
+
+/* not supported currently */
+static int srq_signature;
+
+static void *get_wqe(struct mlx5_ib_srq *srq, int n)
+{
+       return mlx5_buf_offset(&srq->buf, n << srq->msrq.wqe_shift);
+}
+
+static void mlx5_ib_srq_event(struct mlx5_core_srq *srq, enum mlx5_event type)
+{
+       struct ib_event event;
+       struct ib_srq *ibsrq = &to_mibsrq(srq)->ibsrq;
+
+       if (ibsrq->event_handler) {
+               event.device      = ibsrq->device;
+               event.element.srq = ibsrq;
+               switch (type) {
+               case MLX5_EVENT_TYPE_SRQ_RQ_LIMIT:
+                       event.event = IB_EVENT_SRQ_LIMIT_REACHED;
+                       break;
+               case MLX5_EVENT_TYPE_SRQ_CATAS_ERROR:
+                       event.event = IB_EVENT_SRQ_ERR;
+                       break;
+               default:
+                       pr_warn("mlx5_ib: Unexpected event type %d on SRQ %06x\n",
+                               type, srq->srqn);
+                       return;
+               }
+
+               ibsrq->event_handler(&event, ibsrq->srq_context);
+       }
+}
+
+static int create_srq_user(struct ib_pd *pd, struct mlx5_ib_srq *srq,
+                          struct mlx5_create_srq_mbox_in **in,
+                          struct ib_udata *udata, int buf_size, int *inlen)
+{
+       struct mlx5_ib_dev *dev = to_mdev(pd->device);
+       struct mlx5_ib_create_srq ucmd;
+       int err;
+       int npages;
+       int page_shift;
+       int ncont;
+       u32 offset;
+
+       if (ib_copy_from_udata(&ucmd, udata, sizeof(ucmd))) {
+               mlx5_ib_dbg(dev, "failed copy udata\n");
+               return -EFAULT;
+       }
+       srq->wq_sig = !!(ucmd.flags & MLX5_SRQ_FLAG_SIGNATURE);
+
+       srq->umem = ib_umem_get(pd->uobject->context, ucmd.buf_addr, buf_size,
+                               0, 0);
+       if (IS_ERR(srq->umem)) {
+               mlx5_ib_dbg(dev, "failed umem get, size %d\n", buf_size);
+               err = PTR_ERR(srq->umem);
+               return err;
+       }
+
+       mlx5_ib_cont_pages(srq->umem, ucmd.buf_addr, &npages,
+                          &page_shift, &ncont, NULL);
+       err = mlx5_ib_get_buf_offset(ucmd.buf_addr, page_shift,
+                                    &offset);
+       if (err) {
+               mlx5_ib_warn(dev, "bad offset\n");
+               goto err_umem;
+       }
+
+       *inlen = sizeof(**in) + sizeof(*(*in)->pas) * ncont;
+       *in = mlx5_vzalloc(*inlen);
+       if (!(*in)) {
+               err = -ENOMEM;
+               goto err_umem;
+       }
+
+       mlx5_ib_populate_pas(dev, srq->umem, page_shift, (*in)->pas, 0);
+
+       err = mlx5_ib_db_map_user(to_mucontext(pd->uobject->context),
+                                 ucmd.db_addr, &srq->db);
+       if (err) {
+               mlx5_ib_dbg(dev, "map doorbell failed\n");
+               goto err_in;
+       }
+
+       (*in)->ctx.log_pg_sz = page_shift - PAGE_SHIFT;
+       (*in)->ctx.pgoff_cqn = cpu_to_be32(offset << 26);
+
+       return 0;
+
+err_in:
+       mlx5_vfree(*in);
+
+err_umem:
+       ib_umem_release(srq->umem);
+
+       return err;
+}
+
+static int create_srq_kernel(struct mlx5_ib_dev *dev, struct mlx5_ib_srq *srq,
+                            struct mlx5_create_srq_mbox_in **in, int buf_size,
+                            int *inlen)
+{
+       int err;
+       int i;
+       struct mlx5_wqe_srq_next_seg *next;
+       int page_shift;
+       int npages;
+
+       err = mlx5_db_alloc(&dev->mdev, &srq->db);
+       if (err) {
+               mlx5_ib_warn(dev, "alloc dbell rec failed\n");
+               return err;
+       }
+
+       *srq->db.db = 0;
+
+       if (mlx5_buf_alloc(&dev->mdev, buf_size, PAGE_SIZE * 2, &srq->buf)) {
+               mlx5_ib_dbg(dev, "buf alloc failed\n");
+               err = -ENOMEM;
+               goto err_db;
+       }
+       page_shift = srq->buf.page_shift;
+
+       srq->head    = 0;
+       srq->tail    = srq->msrq.max - 1;
+       srq->wqe_ctr = 0;
+
+       for (i = 0; i < srq->msrq.max; i++) {
+               next = get_wqe(srq, i);
+               next->next_wqe_index =
+                       cpu_to_be16((i + 1) & (srq->msrq.max - 1));
+       }
+
+       npages = DIV_ROUND_UP(srq->buf.npages, 1 << (page_shift - PAGE_SHIFT));
+       mlx5_ib_dbg(dev, "buf_size %d, page_shift %d, npages %d, calc npages %d\n",
+                   buf_size, page_shift, srq->buf.npages, npages);
+       *inlen = sizeof(**in) + sizeof(*(*in)->pas) * npages;
+       *in = mlx5_vzalloc(*inlen);
+       if (!*in) {
+               err = -ENOMEM;
+               goto err_buf;
+       }
+       mlx5_fill_page_array(&srq->buf, (*in)->pas);
+
+       srq->wrid = kmalloc(srq->msrq.max * sizeof(u64), GFP_KERNEL);
+       if (!srq->wrid) {
+               mlx5_ib_dbg(dev, "kmalloc failed %lu\n",
+                           (unsigned long)(srq->msrq.max * sizeof(u64)));
+               err = -ENOMEM;
+               goto err_in;
+       }
+       srq->wq_sig = !!srq_signature;
+
+       (*in)->ctx.log_pg_sz = page_shift - PAGE_SHIFT;
+
+       return 0;
+
+err_in:
+       mlx5_vfree(*in);
+
+err_buf:
+       mlx5_buf_free(&dev->mdev, &srq->buf);
+
+err_db:
+       mlx5_db_free(&dev->mdev, &srq->db);
+       return err;
+}
+
+static void destroy_srq_user(struct ib_pd *pd, struct mlx5_ib_srq *srq)
+{
+       mlx5_ib_db_unmap_user(to_mucontext(pd->uobject->context), &srq->db);
+       ib_umem_release(srq->umem);
+}
+
+
+static void destroy_srq_kernel(struct mlx5_ib_dev *dev, struct mlx5_ib_srq *srq)
+{
+       kfree(srq->wrid);
+       mlx5_buf_free(&dev->mdev, &srq->buf);
+       mlx5_db_free(&dev->mdev, &srq->db);
+}
+
+struct ib_srq *mlx5_ib_create_srq(struct ib_pd *pd,
+                                 struct ib_srq_init_attr *init_attr,
+                                 struct ib_udata *udata)
+{
+       struct mlx5_ib_dev *dev = to_mdev(pd->device);
+       struct mlx5_ib_srq *srq;
+       int desc_size;
+       int buf_size;
+       int err;
+       struct mlx5_create_srq_mbox_in *uninitialized_var(in);
+       int uninitialized_var(inlen);
+       int is_xrc;
+       u32 flgs, xrcdn;
+
+       /* Sanity check SRQ size before proceeding */
+       if (init_attr->attr.max_wr >= dev->mdev.caps.max_srq_wqes) {
+               mlx5_ib_dbg(dev, "max_wr %d, cap %d\n",
+                           init_attr->attr.max_wr,
+                           dev->mdev.caps.max_srq_wqes);
+               return ERR_PTR(-EINVAL);
+       }
+
+       srq = kmalloc(sizeof(*srq), GFP_KERNEL);
+       if (!srq)
+               return ERR_PTR(-ENOMEM);
+
+       mutex_init(&srq->mutex);
+       spin_lock_init(&srq->lock);
+       srq->msrq.max    = roundup_pow_of_two(init_attr->attr.max_wr + 1);
+       srq->msrq.max_gs = init_attr->attr.max_sge;
+
+       desc_size = sizeof(struct mlx5_wqe_srq_next_seg) +
+                   srq->msrq.max_gs * sizeof(struct mlx5_wqe_data_seg);
+       desc_size = roundup_pow_of_two(desc_size);
+       desc_size = max_t(int, 32, desc_size);
+       srq->msrq.max_avail_gather = (desc_size - sizeof(struct mlx5_wqe_srq_next_seg)) /
+               sizeof(struct mlx5_wqe_data_seg);
+       srq->msrq.wqe_shift = ilog2(desc_size);
+       buf_size = srq->msrq.max * desc_size;
+       mlx5_ib_dbg(dev, "desc_size 0x%x, req wr 0x%x, srq size 0x%x, max_gs 0x%x, max_avail_gather 0x%x\n",
+                   desc_size, init_attr->attr.max_wr, srq->msrq.max, srq->msrq.max_gs,
+                   srq->msrq.max_avail_gather);
+
+       if (pd->uobject)
+               err = create_srq_user(pd, srq, &in, udata, buf_size, &inlen);
+       else
+               err = create_srq_kernel(dev, srq, &in, buf_size, &inlen);
+
+       if (err) {
+               mlx5_ib_warn(dev, "create srq %s failed, err %d\n",
+                            pd->uobject ? "user" : "kernel", err);
+               goto err_srq;
+       }
+
+       is_xrc = (init_attr->srq_type == IB_SRQT_XRC);
+       in->ctx.state_log_sz = ilog2(srq->msrq.max);
+       flgs = ((srq->msrq.wqe_shift - 4) | (is_xrc << 5) | (srq->wq_sig << 7)) << 24;
+       xrcdn = 0;
+       if (is_xrc) {
+               xrcdn = to_mxrcd(init_attr->ext.xrc.xrcd)->xrcdn;
+               in->ctx.pgoff_cqn |= cpu_to_be32(to_mcq(init_attr->ext.xrc.cq)->mcq.cqn);
+       } else if (init_attr->srq_type == IB_SRQT_BASIC) {
+               xrcdn = to_mxrcd(dev->devr.x0)->xrcdn;
+               in->ctx.pgoff_cqn |= cpu_to_be32(to_mcq(dev->devr.c0)->mcq.cqn);
+       }
+
+       in->ctx.flags_xrcd = cpu_to_be32((flgs & 0xFF000000) | (xrcdn & 0xFFFFFF));
+
+       in->ctx.pd = cpu_to_be32(to_mpd(pd)->pdn);
+       in->ctx.db_record = cpu_to_be64(srq->db.dma);
+       err = mlx5_core_create_srq(&dev->mdev, &srq->msrq, in, inlen);
+       mlx5_vfree(in);
+       if (err) {
+               mlx5_ib_dbg(dev, "create SRQ failed, err %d\n", err);
+               goto err_srq;
+       }
+
+       mlx5_ib_dbg(dev, "create SRQ with srqn 0x%x\n", srq->msrq.srqn);
+
+       srq->msrq.event = mlx5_ib_srq_event;
+       srq->ibsrq.ext.xrc.srq_num = srq->msrq.srqn;
+
+       if (pd->uobject)
+               if (ib_copy_to_udata(udata, &srq->msrq.srqn, sizeof(__u32))) {
+                       mlx5_ib_dbg(dev, "copy to user failed\n");
+                       err = -EFAULT;
+                       goto err_core;
+               }
+
+       init_attr->attr.max_wr = srq->msrq.max - 1;
+
+       return &srq->ibsrq;
+
+err_core:
+       mlx5_core_destroy_srq(&dev->mdev, &srq->msrq);
+       if (pd->uobject)
+               destroy_srq_user(pd, srq);
+       else
+               destroy_srq_kernel(dev, srq);
+
+err_srq:
+       kfree(srq);
+
+       return ERR_PTR(err);
+}
+
+int mlx5_ib_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr,
+                      enum ib_srq_attr_mask attr_mask, struct ib_udata *udata)
+{
+       struct mlx5_ib_dev *dev = to_mdev(ibsrq->device);
+       struct mlx5_ib_srq *srq = to_msrq(ibsrq);
+       int ret;
+
+       /* We don't support resizing SRQs yet */
+       if (attr_mask & IB_SRQ_MAX_WR)
+               return -EINVAL;
+
+       if (attr_mask & IB_SRQ_LIMIT) {
+               if (attr->srq_limit >= srq->msrq.max)
+                       return -EINVAL;
+
+               mutex_lock(&srq->mutex);
+               ret = mlx5_core_arm_srq(&dev->mdev, &srq->msrq, attr->srq_limit, 1);
+               mutex_unlock(&srq->mutex);
+
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+int mlx5_ib_query_srq(struct ib_srq *ibsrq, struct ib_srq_attr *srq_attr)
+{
+       struct mlx5_ib_dev *dev = to_mdev(ibsrq->device);
+       struct mlx5_ib_srq *srq = to_msrq(ibsrq);
+       int ret;
+       struct mlx5_query_srq_mbox_out *out;
+
+       out = kzalloc(sizeof(*out), GFP_KERNEL);
+       if (!out)
+               return -ENOMEM;
+
+       ret = mlx5_core_query_srq(&dev->mdev, &srq->msrq, out);
+       if (ret)
+               goto out_box;
+
+       srq_attr->srq_limit = be16_to_cpu(out->ctx.lwm);
+       srq_attr->max_wr    = srq->msrq.max - 1;
+       srq_attr->max_sge   = srq->msrq.max_gs;
+
+out_box:
+       kfree(out);
+       return ret;
+}
+
+int mlx5_ib_destroy_srq(struct ib_srq *srq)
+{
+       struct mlx5_ib_dev *dev = to_mdev(srq->device);
+       struct mlx5_ib_srq *msrq = to_msrq(srq);
+
+       mlx5_core_destroy_srq(&dev->mdev, &msrq->msrq);
+
+       if (srq->uobject) {
+               mlx5_ib_db_unmap_user(to_mucontext(srq->uobject->context), &msrq->db);
+               ib_umem_release(msrq->umem);
+       } else {
+               kfree(msrq->wrid);
+               mlx5_buf_free(&dev->mdev, &msrq->buf);
+               mlx5_db_free(&dev->mdev, &msrq->db);
+       }
+
+       kfree(srq);
+       return 0;
+}
+
+void mlx5_ib_free_srq_wqe(struct mlx5_ib_srq *srq, int wqe_index)
+{
+       struct mlx5_wqe_srq_next_seg *next;
+
+       /* always called with interrupts disabled. */
+       spin_lock(&srq->lock);
+
+       next = get_wqe(srq, srq->tail);
+       next->next_wqe_index = cpu_to_be16(wqe_index);
+       srq->tail = wqe_index;
+
+       spin_unlock(&srq->lock);
+}
+
+int mlx5_ib_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr,
+                         struct ib_recv_wr **bad_wr)
+{
+       struct mlx5_ib_srq *srq = to_msrq(ibsrq);
+       struct mlx5_wqe_srq_next_seg *next;
+       struct mlx5_wqe_data_seg *scat;
+       unsigned long flags;
+       int err = 0;
+       int nreq;
+       int i;
+
+       spin_lock_irqsave(&srq->lock, flags);
+
+       for (nreq = 0; wr; nreq++, wr = wr->next) {
+               if (unlikely(wr->num_sge > srq->msrq.max_gs)) {
+                       err = -EINVAL;
+                       *bad_wr = wr;
+                       break;
+               }
+
+               if (unlikely(srq->head == srq->tail)) {
+                       err = -ENOMEM;
+                       *bad_wr = wr;
+                       break;
+               }
+
+               srq->wrid[srq->head] = wr->wr_id;
+
+               next      = get_wqe(srq, srq->head);
+               srq->head = be16_to_cpu(next->next_wqe_index);
+               scat      = (struct mlx5_wqe_data_seg *)(next + 1);
+
+               for (i = 0; i < wr->num_sge; i++) {
+                       scat[i].byte_count = cpu_to_be32(wr->sg_list[i].length);
+                       scat[i].lkey       = cpu_to_be32(wr->sg_list[i].lkey);
+                       scat[i].addr       = cpu_to_be64(wr->sg_list[i].addr);
+               }
+
+               if (i < srq->msrq.max_avail_gather) {
+                       scat[i].byte_count = 0;
+                       scat[i].lkey       = cpu_to_be32(MLX5_INVALID_LKEY);
+                       scat[i].addr       = 0;
+               }
+       }
+
+       if (likely(nreq)) {
+               srq->wqe_ctr += nreq;
+
+               /* Make sure that descriptors are written before
+                * doorbell record.
+                */
+               wmb();
+
+               *srq->db.db = cpu_to_be32(srq->wqe_ctr);
+       }
+
+       spin_unlock_irqrestore(&srq->lock, flags);
+
+       return err;
+}
diff --git a/drivers/infiniband/hw/mlx5/user.h b/drivers/infiniband/hw/mlx5/user.h
new file mode 100644 (file)
index 0000000..a886de3
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2013, Mellanox Technologies inc.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef MLX5_IB_USER_H
+#define MLX5_IB_USER_H
+
+#include <linux/types.h>
+
+enum {
+       MLX5_QP_FLAG_SIGNATURE          = 1 << 0,
+       MLX5_QP_FLAG_SCATTER_CQE        = 1 << 1,
+};
+
+enum {
+       MLX5_SRQ_FLAG_SIGNATURE         = 1 << 0,
+};
+
+
+/* Increment this value if any changes that break userspace ABI
+ * compatibility are made.
+ */
+#define MLX5_IB_UVERBS_ABI_VERSION     1
+
+/* Make sure that all structs defined in this file remain laid out so
+ * that they pack the same way on 32-bit and 64-bit architectures (to
+ * avoid incompatibility between 32-bit userspace and 64-bit kernels).
+ * In particular do not use pointer types -- pass pointers in __u64
+ * instead.
+ */
+
+struct mlx5_ib_alloc_ucontext_req {
+       __u32   total_num_uuars;
+       __u32   num_low_latency_uuars;
+};
+
+struct mlx5_ib_alloc_ucontext_resp {
+       __u32   qp_tab_size;
+       __u32   bf_reg_size;
+       __u32   tot_uuars;
+       __u32   cache_line_size;
+       __u16   max_sq_desc_sz;
+       __u16   max_rq_desc_sz;
+       __u32   max_send_wqebb;
+       __u32   max_recv_wr;
+       __u32   max_srq_recv_wr;
+       __u16   num_ports;
+       __u16   reserved;
+};
+
+struct mlx5_ib_alloc_pd_resp {
+       __u32   pdn;
+};
+
+struct mlx5_ib_create_cq {
+       __u64   buf_addr;
+       __u64   db_addr;
+       __u32   cqe_size;
+};
+
+struct mlx5_ib_create_cq_resp {
+       __u32   cqn;
+       __u32   reserved;
+};
+
+struct mlx5_ib_resize_cq {
+       __u64   buf_addr;
+};
+
+struct mlx5_ib_create_srq {
+       __u64   buf_addr;
+       __u64   db_addr;
+       __u32   flags;
+};
+
+struct mlx5_ib_create_srq_resp {
+       __u32   srqn;
+       __u32   reserved;
+};
+
+struct mlx5_ib_create_qp {
+       __u64   buf_addr;
+       __u64   db_addr;
+       __u32   sq_wqe_count;
+       __u32   rq_wqe_count;
+       __u32   rq_wqe_shift;
+       __u32   flags;
+};
+
+struct mlx5_ib_create_qp_resp {
+       __u32   uuar_index;
+};
+#endif /* MLX5_IB_USER_H */
index 48970af..d540180 100644 (file)
@@ -42,8 +42,6 @@
 #define OCRDMA_ROCE_DEV_VERSION "1.0.0"
 #define OCRDMA_NODE_DESC "Emulex OneConnect RoCE HCA"
 
-#define ocrdma_err(format, arg...) printk(KERN_ERR format, ##arg)
-
 #define OCRDMA_MAX_AH 512
 
 #define OCRDMA_UVERBS(CMD_NAME) (1ull << IB_USER_VERBS_CMD_##CMD_NAME)
@@ -97,7 +95,6 @@ struct ocrdma_queue_info {
        u16 id;                 /* qid, where to ring the doorbell. */
        u16 head, tail;
        bool created;
-       atomic_t used;          /* Number of valid elements in the queue */
 };
 
 struct ocrdma_eq {
@@ -198,7 +195,6 @@ struct ocrdma_cq {
        struct ocrdma_ucontext *ucontext;
        dma_addr_t pa;
        u32 len;
-       atomic_t use_cnt;
 
        /* head of all qp's sq and rq for which cqes need to be flushed
         * by the software.
@@ -210,7 +206,6 @@ struct ocrdma_pd {
        struct ib_pd ibpd;
        struct ocrdma_dev *dev;
        struct ocrdma_ucontext *uctx;
-       atomic_t use_cnt;
        u32 id;
        int num_dpp_qp;
        u32 dpp_page;
@@ -241,16 +236,16 @@ struct ocrdma_srq {
        struct ib_srq ibsrq;
        struct ocrdma_dev *dev;
        u8 __iomem *db;
+       struct ocrdma_qp_hwq_info rq;
+       u64 *rqe_wr_id_tbl;
+       u32 *idx_bit_fields;
+       u32 bit_fields_len;
+
        /* provide synchronization to multiple context(s) posting rqe */
        spinlock_t q_lock ____cacheline_aligned;
 
-       struct ocrdma_qp_hwq_info rq;
        struct ocrdma_pd *pd;
-       atomic_t use_cnt;
        u32 id;
-       u64 *rqe_wr_id_tbl;
-       u32 *idx_bit_fields;
-       u32 bit_fields_len;
 };
 
 struct ocrdma_qp {
@@ -258,8 +253,6 @@ struct ocrdma_qp {
        struct ocrdma_dev *dev;
 
        u8 __iomem *sq_db;
-       /* provide synchronization to multiple context(s) posting wqe, rqe */
-       spinlock_t q_lock ____cacheline_aligned;
        struct ocrdma_qp_hwq_info sq;
        struct {
                uint64_t wrid;
@@ -269,6 +262,9 @@ struct ocrdma_qp {
                uint8_t  rsvd[3];
        } *wqe_wr_id_tbl;
        u32 max_inline_data;
+
+       /* provide synchronization to multiple context(s) posting wqe, rqe */
+       spinlock_t q_lock ____cacheline_aligned;
        struct ocrdma_cq *sq_cq;
        /* list maintained per CQ to flush SQ errors */
        struct list_head sq_entry;
@@ -296,10 +292,6 @@ struct ocrdma_qp {
        u8 *ird_q_va;
 };
 
-#define OCRDMA_GET_NUM_POSTED_SHIFT_VAL(qp) \
-       (((qp->dev->nic_info.dev_family == OCRDMA_GEN2_FAMILY) && \
-               (qp->id < 64)) ? 24 : 16)
-
 struct ocrdma_hw_mr {
        struct ocrdma_dev *dev;
        u32 lkey;
@@ -390,4 +382,43 @@ static inline struct ocrdma_srq *get_ocrdma_srq(struct ib_srq *ibsrq)
        return container_of(ibsrq, struct ocrdma_srq, ibsrq);
 }
 
+
+static inline int ocrdma_get_num_posted_shift(struct ocrdma_qp *qp)
+{
+       return ((qp->dev->nic_info.dev_family == OCRDMA_GEN2_FAMILY &&
+                qp->id < 64) ? 24 : 16);
+}
+
+static inline int is_cqe_valid(struct ocrdma_cq *cq, struct ocrdma_cqe *cqe)
+{
+       int cqe_valid;
+       cqe_valid = le32_to_cpu(cqe->flags_status_srcqpn) & OCRDMA_CQE_VALID;
+       return ((cqe_valid == cq->phase) ? 1 : 0);
+}
+
+static inline int is_cqe_for_sq(struct ocrdma_cqe *cqe)
+{
+       return (le32_to_cpu(cqe->flags_status_srcqpn) &
+               OCRDMA_CQE_QTYPE) ? 0 : 1;
+}
+
+static inline int is_cqe_invalidated(struct ocrdma_cqe *cqe)
+{
+       return (le32_to_cpu(cqe->flags_status_srcqpn) &
+               OCRDMA_CQE_INVALIDATE) ? 1 : 0;
+}
+
+static inline int is_cqe_imm(struct ocrdma_cqe *cqe)
+{
+       return (le32_to_cpu(cqe->flags_status_srcqpn) &
+               OCRDMA_CQE_IMM) ? 1 : 0;
+}
+
+static inline int is_cqe_wr_imm(struct ocrdma_cqe *cqe)
+{
+       return (le32_to_cpu(cqe->flags_status_srcqpn) &
+               OCRDMA_CQE_WRITE_IMM) ? 1 : 0;
+}
+
+
 #endif
index 71942af..0965278 100644 (file)
@@ -128,7 +128,6 @@ static inline struct ocrdma_mqe *ocrdma_get_mqe(struct ocrdma_dev *dev)
 static inline void ocrdma_mq_inc_head(struct ocrdma_dev *dev)
 {
        dev->mq.sq.head = (dev->mq.sq.head + 1) & (OCRDMA_MQ_LEN - 1);
-       atomic_inc(&dev->mq.sq.used);
 }
 
 static inline void *ocrdma_get_mqe_rsp(struct ocrdma_dev *dev)
@@ -564,32 +563,19 @@ static int ocrdma_mbx_create_mq(struct ocrdma_dev *dev,
        memset(cmd, 0, sizeof(*cmd));
        num_pages = PAGES_4K_SPANNED(mq->va, mq->size);
 
-       if (dev->nic_info.dev_family == OCRDMA_GEN2_FAMILY) {
-               ocrdma_init_mch(&cmd->req, OCRDMA_CMD_CREATE_MQ,
-                               OCRDMA_SUBSYS_COMMON, sizeof(*cmd));
-               cmd->v0.pages = num_pages;
-               cmd->v0.async_cqid_valid = OCRDMA_CREATE_MQ_ASYNC_CQ_VALID;
-               cmd->v0.async_cqid_valid = (cq->id << 1);
-               cmd->v0.cqid_ringsize |= (ocrdma_encoded_q_len(mq->len) <<
-                                            OCRDMA_CREATE_MQ_RING_SIZE_SHIFT);
-               cmd->v0.cqid_ringsize |=
-                       (cq->id << OCRDMA_CREATE_MQ_V0_CQ_ID_SHIFT);
-               cmd->v0.valid = OCRDMA_CREATE_MQ_VALID;
-               pa = &cmd->v0.pa[0];
-       } else {
-               ocrdma_init_mch(&cmd->req, OCRDMA_CMD_CREATE_MQ_EXT,
-                               OCRDMA_SUBSYS_COMMON, sizeof(*cmd));
-               cmd->req.rsvd_version = 1;
-               cmd->v1.cqid_pages = num_pages;
-               cmd->v1.cqid_pages |= (cq->id << OCRDMA_CREATE_MQ_CQ_ID_SHIFT);
-               cmd->v1.async_cqid_valid = OCRDMA_CREATE_MQ_ASYNC_CQ_VALID;
-               cmd->v1.async_event_bitmap = Bit(20);
-               cmd->v1.async_cqid_ringsize = cq->id;
-               cmd->v1.async_cqid_ringsize |= (ocrdma_encoded_q_len(mq->len) <<
-                                            OCRDMA_CREATE_MQ_RING_SIZE_SHIFT);
-               cmd->v1.valid = OCRDMA_CREATE_MQ_VALID;
-               pa = &cmd->v1.pa[0];
-       }
+       ocrdma_init_mch(&cmd->req, OCRDMA_CMD_CREATE_MQ_EXT,
+                       OCRDMA_SUBSYS_COMMON, sizeof(*cmd));
+       cmd->req.rsvd_version = 1;
+       cmd->cqid_pages = num_pages;
+       cmd->cqid_pages |= (cq->id << OCRDMA_CREATE_MQ_CQ_ID_SHIFT);
+       cmd->async_cqid_valid = OCRDMA_CREATE_MQ_ASYNC_CQ_VALID;
+       cmd->async_event_bitmap = Bit(20);
+       cmd->async_cqid_ringsize = cq->id;
+       cmd->async_cqid_ringsize |= (ocrdma_encoded_q_len(mq->len) <<
+                               OCRDMA_CREATE_MQ_RING_SIZE_SHIFT);
+       cmd->valid = OCRDMA_CREATE_MQ_VALID;
+       pa = &cmd->pa[0];
+
        ocrdma_build_q_pages(pa, num_pages, mq->dma, PAGE_SIZE_4K);
        status = be_roce_mcc_cmd(dev->nic_info.netdev,
                                 cmd, sizeof(*cmd), NULL, NULL);
@@ -745,7 +731,7 @@ static void ocrdma_dispatch_ibevent(struct ocrdma_dev *dev,
                qp_event = 0;
                srq_event = 0;
                dev_event = 0;
-               ocrdma_err("%s() unknown type=0x%x\n", __func__, type);
+               pr_err("%s() unknown type=0x%x\n", __func__, type);
                break;
        }
 
@@ -775,8 +761,8 @@ static void ocrdma_process_acqe(struct ocrdma_dev *dev, void *ae_cqe)
        if (evt_code == OCRDMA_ASYNC_EVE_CODE)
                ocrdma_dispatch_ibevent(dev, cqe);
        else
-               ocrdma_err("%s(%d) invalid evt code=0x%x\n",
-                          __func__, dev->id, evt_code);
+               pr_err("%s(%d) invalid evt code=0x%x\n", __func__,
+                      dev->id, evt_code);
 }
 
 static void ocrdma_process_mcqe(struct ocrdma_dev *dev, struct ocrdma_mcqe *cqe)
@@ -790,8 +776,8 @@ static void ocrdma_process_mcqe(struct ocrdma_dev *dev, struct ocrdma_mcqe *cqe)
                dev->mqe_ctx.cmd_done = true;
                wake_up(&dev->mqe_ctx.cmd_wait);
        } else
-               ocrdma_err("%s() cqe for invalid tag0x%x.expected=0x%x\n",
-                          __func__, cqe->tag_lo, dev->mqe_ctx.tag);
+               pr_err("%s() cqe for invalid tag0x%x.expected=0x%x\n",
+                      __func__, cqe->tag_lo, dev->mqe_ctx.tag);
 }
 
 static int ocrdma_mq_cq_handler(struct ocrdma_dev *dev, u16 cq_id)
@@ -810,7 +796,7 @@ static int ocrdma_mq_cq_handler(struct ocrdma_dev *dev, u16 cq_id)
                else if (cqe->valid_ae_cmpl_cons & OCRDMA_MCQE_CMPL_MASK)
                        ocrdma_process_mcqe(dev, cqe);
                else
-                       ocrdma_err("%s() cqe->compl is not set.\n", __func__);
+                       pr_err("%s() cqe->compl is not set.\n", __func__);
                memset(cqe, 0, sizeof(struct ocrdma_mcqe));
                ocrdma_mcq_inc_tail(dev);
        }
@@ -869,7 +855,7 @@ static void ocrdma_qp_cq_handler(struct ocrdma_dev *dev, u16 cq_idx)
 
        cq = dev->cq_tbl[cq_idx];
        if (cq == NULL) {
-               ocrdma_err("%s%d invalid id=0x%x\n", __func__, dev->id, cq_idx);
+               pr_err("%s%d invalid id=0x%x\n", __func__, dev->id, cq_idx);
                return;
        }
        spin_lock_irqsave(&cq->cq_lock, flags);
@@ -971,7 +957,7 @@ static int ocrdma_mbx_cmd(struct ocrdma_dev *dev, struct ocrdma_mqe *mqe)
        rsp = ocrdma_get_mqe_rsp(dev);
        ocrdma_copy_le32_to_cpu(mqe, rsp, (sizeof(*mqe)));
        if (cqe_status || ext_status) {
-               ocrdma_err
+               pr_err
                    ("%s() opcode=0x%x, cqe_status=0x%x, ext_status=0x%x\n",
                     __func__,
                     (rsp->u.rsp.subsys_op & OCRDMA_MBX_RSP_OPCODE_MASK) >>
@@ -1353,8 +1339,8 @@ int ocrdma_mbx_create_cq(struct ocrdma_dev *dev, struct ocrdma_cq *cq,
        if (dpp_cq)
                return -EINVAL;
        if (entries > dev->attr.max_cqe) {
-               ocrdma_err("%s(%d) max_cqe=0x%x, requester_cqe=0x%x\n",
-                          __func__, dev->id, dev->attr.max_cqe, entries);
+               pr_err("%s(%d) max_cqe=0x%x, requester_cqe=0x%x\n",
+                      __func__, dev->id, dev->attr.max_cqe, entries);
                return -EINVAL;
        }
        if (dpp_cq && (dev->nic_info.dev_family != OCRDMA_GEN2_FAMILY))
@@ -1621,7 +1607,7 @@ int ocrdma_reg_mr(struct ocrdma_dev *dev,
        status = ocrdma_mbx_reg_mr(dev, hwmr, pdid,
                                   cur_pbl_cnt, hwmr->pbe_size, last);
        if (status) {
-               ocrdma_err("%s() status=%d\n", __func__, status);
+               pr_err("%s() status=%d\n", __func__, status);
                return status;
        }
        /* if there is no more pbls to register then exit. */
@@ -1644,7 +1630,7 @@ int ocrdma_reg_mr(struct ocrdma_dev *dev,
                        break;
        }
        if (status)
-               ocrdma_err("%s() err. status=%d\n", __func__, status);
+               pr_err("%s() err. status=%d\n", __func__, status);
 
        return status;
 }
@@ -1841,8 +1827,8 @@ static int ocrdma_set_create_qp_sq_cmd(struct ocrdma_create_qp_req *cmd,
        status = ocrdma_build_q_conf(&max_wqe_allocated,
                dev->attr.wqe_size, &hw_pages, &hw_page_size);
        if (status) {
-               ocrdma_err("%s() req. max_send_wr=0x%x\n", __func__,
-                          max_wqe_allocated);
+               pr_err("%s() req. max_send_wr=0x%x\n", __func__,
+                      max_wqe_allocated);
                return -EINVAL;
        }
        qp->sq.max_cnt = max_wqe_allocated;
@@ -1891,8 +1877,8 @@ static int ocrdma_set_create_qp_rq_cmd(struct ocrdma_create_qp_req *cmd,
        status = ocrdma_build_q_conf(&max_rqe_allocated, dev->attr.rqe_size,
                                     &hw_pages, &hw_page_size);
        if (status) {
-               ocrdma_err("%s() req. max_recv_wr=0x%x\n", __func__,
-                          attrs->cap.max_recv_wr + 1);
+               pr_err("%s() req. max_recv_wr=0x%x\n", __func__,
+                      attrs->cap.max_recv_wr + 1);
                return status;
        }
        qp->rq.max_cnt = max_rqe_allocated;
@@ -1900,7 +1886,7 @@ static int ocrdma_set_create_qp_rq_cmd(struct ocrdma_create_qp_req *cmd,
 
        qp->rq.va = dma_alloc_coherent(&pdev->dev, len, &pa, GFP_KERNEL);
        if (!qp->rq.va)
-               return status;
+               return -ENOMEM;
        memset(qp->rq.va, 0, len);
        qp->rq.pa = pa;
        qp->rq.len = len;
@@ -2087,10 +2073,10 @@ mbx_err:
        if (qp->rq.va)
                dma_free_coherent(&pdev->dev, qp->rq.len, qp->rq.va, qp->rq.pa);
 rq_err:
-       ocrdma_err("%s(%d) rq_err\n", __func__, dev->id);
+       pr_err("%s(%d) rq_err\n", __func__, dev->id);
        dma_free_coherent(&pdev->dev, qp->sq.len, qp->sq.va, qp->sq.pa);
 sq_err:
-       ocrdma_err("%s(%d) sq_err\n", __func__, dev->id);
+       pr_err("%s(%d) sq_err\n", __func__, dev->id);
        kfree(cmd);
        return status;
 }
@@ -2127,7 +2113,7 @@ int ocrdma_resolve_dgid(struct ocrdma_dev *dev, union ib_gid *dgid,
        else if (rdma_link_local_addr(&in6))
                rdma_get_ll_mac(&in6, mac_addr);
        else {
-               ocrdma_err("%s() fail to resolve mac_addr.\n", __func__);
+               pr_err("%s() fail to resolve mac_addr.\n", __func__);
                return -EINVAL;
        }
        return 0;
@@ -2362,8 +2348,8 @@ int ocrdma_mbx_create_srq(struct ocrdma_srq *srq,
                                dev->attr.rqe_size,
                                &hw_pages, &hw_page_size);
        if (status) {
-               ocrdma_err("%s() req. max_wr=0x%x\n", __func__,
-                          srq_attr->attr.max_wr);
+               pr_err("%s() req. max_wr=0x%x\n", __func__,
+                      srq_attr->attr.max_wr);
                status = -EINVAL;
                goto ret;
        }
@@ -2614,7 +2600,7 @@ mq_err:
        ocrdma_destroy_qp_eqs(dev);
 qpeq_err:
        ocrdma_destroy_eq(dev, &dev->meq);
-       ocrdma_err("%s() status=%d\n", __func__, status);
+       pr_err("%s() status=%d\n", __func__, status);
        return status;
 }
 
index 48928c8..ded416f 100644 (file)
@@ -378,7 +378,7 @@ static int ocrdma_alloc_resources(struct ocrdma_dev *dev)
        spin_lock_init(&dev->flush_q_lock);
        return 0;
 alloc_err:
-       ocrdma_err("%s(%d) error.\n", __func__, dev->id);
+       pr_err("%s(%d) error.\n", __func__, dev->id);
        return -ENOMEM;
 }
 
@@ -396,7 +396,7 @@ static struct ocrdma_dev *ocrdma_add(struct be_dev_info *dev_info)
 
        dev = (struct ocrdma_dev *)ib_alloc_device(sizeof(struct ocrdma_dev));
        if (!dev) {
-               ocrdma_err("Unable to allocate ib device\n");
+               pr_err("Unable to allocate ib device\n");
                return NULL;
        }
        dev->mbx_cmd = kzalloc(sizeof(struct ocrdma_mqe_emb_cmd), GFP_KERNEL);
@@ -437,7 +437,7 @@ init_err:
 idr_err:
        kfree(dev->mbx_cmd);
        ib_dealloc_device(&dev->ibdev);
-       ocrdma_err("%s() leaving. ret=%d\n", __func__, status);
+       pr_err("%s() leaving. ret=%d\n", __func__, status);
        return NULL;
 }
 
index c75cbdf..36b062d 100644 (file)
@@ -608,16 +608,8 @@ enum {
        OCRDMA_CREATE_MQ_ASYNC_CQ_VALID         = Bit(0)
 };
 
-struct ocrdma_create_mq_v0 {
-       u32 pages;
-       u32 cqid_ringsize;
-       u32 valid;
-       u32 async_cqid_valid;
-       u32 rsvd;
-       struct ocrdma_pa pa[8];
-} __packed;
-
-struct ocrdma_create_mq_v1 {
+struct ocrdma_create_mq_req {
+       struct ocrdma_mbx_hdr req;
        u32 cqid_pages;
        u32 async_event_bitmap;
        u32 async_cqid_ringsize;
@@ -627,14 +619,6 @@ struct ocrdma_create_mq_v1 {
        struct ocrdma_pa pa[8];
 } __packed;
 
-struct ocrdma_create_mq_req {
-       struct ocrdma_mbx_hdr req;
-       union {
-               struct ocrdma_create_mq_v0 v0;
-               struct ocrdma_create_mq_v1 v1;
-       };
-} __packed;
-
 struct ocrdma_create_mq_rsp {
        struct ocrdma_mbx_rsp rsp;
        u32 id;
@@ -1550,21 +1534,6 @@ struct ocrdma_cqe {
        u32 flags_status_srcqpn;        /* w3 */
 } __packed;
 
-#define is_cqe_valid(cq, cqe) \
-       (((le32_to_cpu(cqe->flags_status_srcqpn) & OCRDMA_CQE_VALID)\
-       == cq->phase) ? 1 : 0)
-#define is_cqe_for_sq(cqe) \
-       ((le32_to_cpu(cqe->flags_status_srcqpn) & OCRDMA_CQE_QTYPE) ? 0 : 1)
-#define is_cqe_for_rq(cqe) \
-       ((le32_to_cpu(cqe->flags_status_srcqpn) & OCRDMA_CQE_QTYPE) ? 1 : 0)
-#define is_cqe_invalidated(cqe) \
-       ((le32_to_cpu(cqe->flags_status_srcqpn) & OCRDMA_CQE_INVALIDATE) ? \
-       1 : 0)
-#define is_cqe_imm(cqe) \
-       ((le32_to_cpu(cqe->flags_status_srcqpn) & OCRDMA_CQE_IMM) ? 1 : 0)
-#define is_cqe_wr_imm(cqe) \
-       ((le32_to_cpu(cqe->flags_status_srcqpn) & OCRDMA_CQE_WRITE_IMM) ? 1 : 0)
-
 struct ocrdma_sge {
        u32 addr_hi;
        u32 addr_lo;
index b29a424..dcfbab1 100644 (file)
@@ -114,8 +114,8 @@ int ocrdma_query_port(struct ib_device *ibdev,
 
        dev = get_ocrdma_dev(ibdev);
        if (port > 1) {
-               ocrdma_err("%s(%d) invalid_port=0x%x\n", __func__,
-                          dev->id, port);
+               pr_err("%s(%d) invalid_port=0x%x\n", __func__,
+                      dev->id, port);
                return -EINVAL;
        }
        netdev = dev->nic_info.netdev;
@@ -155,8 +155,7 @@ int ocrdma_modify_port(struct ib_device *ibdev, u8 port, int mask,
 
        dev = get_ocrdma_dev(ibdev);
        if (port > 1) {
-               ocrdma_err("%s(%d) invalid_port=0x%x\n", __func__,
-                          dev->id, port);
+               pr_err("%s(%d) invalid_port=0x%x\n", __func__, dev->id, port);
                return -EINVAL;
        }
        return 0;
@@ -398,7 +397,6 @@ struct ib_pd *ocrdma_alloc_pd(struct ib_device *ibdev,
                kfree(pd);
                return ERR_PTR(status);
        }
-       atomic_set(&pd->use_cnt, 0);
 
        if (udata && context) {
                status = ocrdma_copy_pd_uresp(pd, context, udata);
@@ -419,12 +417,6 @@ int ocrdma_dealloc_pd(struct ib_pd *ibpd)
        int status;
        u64 usr_db;
 
-       if (atomic_read(&pd->use_cnt)) {
-               ocrdma_err("%s(%d) pd=0x%x is in use.\n",
-                          __func__, dev->id, pd->id);
-               status = -EFAULT;
-               goto dealloc_err;
-       }
        status = ocrdma_mbx_dealloc_pd(dev, pd);
        if (pd->uctx) {
                u64 dpp_db = dev->nic_info.dpp_unmapped_addr +
@@ -436,7 +428,6 @@ int ocrdma_dealloc_pd(struct ib_pd *ibpd)
                ocrdma_del_mmap(pd->uctx, usr_db, dev->nic_info.db_page_size);
        }
        kfree(pd);
-dealloc_err:
        return status;
 }
 
@@ -450,8 +441,8 @@ static struct ocrdma_mr *ocrdma_alloc_lkey(struct ib_pd *ibpd,
        struct ocrdma_dev *dev = pd->dev;
 
        if (acc & IB_ACCESS_REMOTE_WRITE && !(acc & IB_ACCESS_LOCAL_WRITE)) {
-               ocrdma_err("%s(%d) leaving err, invalid access rights\n",
-                          __func__, dev->id);
+               pr_err("%s(%d) leaving err, invalid access rights\n",
+                      __func__, dev->id);
                return ERR_PTR(-EINVAL);
        }
 
@@ -474,7 +465,6 @@ static struct ocrdma_mr *ocrdma_alloc_lkey(struct ib_pd *ibpd,
                return ERR_PTR(-ENOMEM);
        }
        mr->pd = pd;
-       atomic_inc(&pd->use_cnt);
        mr->ibmr.lkey = mr->hwmr.lkey;
        if (mr->hwmr.remote_wr || mr->hwmr.remote_rd)
                mr->ibmr.rkey = mr->hwmr.lkey;
@@ -664,7 +654,6 @@ struct ib_mr *ocrdma_reg_user_mr(struct ib_pd *ibpd, u64 start, u64 len,
        if (status)
                goto mbx_err;
        mr->pd = pd;
-       atomic_inc(&pd->use_cnt);
        mr->ibmr.lkey = mr->hwmr.lkey;
        if (mr->hwmr.remote_wr || mr->hwmr.remote_rd)
                mr->ibmr.rkey = mr->hwmr.lkey;
@@ -689,7 +678,6 @@ int ocrdma_dereg_mr(struct ib_mr *ib_mr)
        if (mr->hwmr.fr_mr == 0)
                ocrdma_free_mr_pbl_tbl(dev, &mr->hwmr);
 
-       atomic_dec(&mr->pd->use_cnt);
        /* it could be user registered memory. */
        if (mr->umem)
                ib_umem_release(mr->umem);
@@ -714,8 +702,8 @@ static int ocrdma_copy_cq_uresp(struct ocrdma_cq *cq, struct ib_udata *udata,
        uresp.phase_change = cq->phase_change ? 1 : 0;
        status = ib_copy_to_udata(udata, &uresp, sizeof(uresp));
        if (status) {
-               ocrdma_err("%s(%d) copy error cqid=0x%x.\n",
-                          __func__, cq->dev->id, cq->id);
+               pr_err("%s(%d) copy error cqid=0x%x.\n",
+                      __func__, cq->dev->id, cq->id);
                goto err;
        }
        uctx = get_ocrdma_ucontext(ib_ctx);
@@ -752,7 +740,6 @@ struct ib_cq *ocrdma_create_cq(struct ib_device *ibdev, int entries, int vector,
 
        spin_lock_init(&cq->cq_lock);
        spin_lock_init(&cq->comp_handler_lock);
-       atomic_set(&cq->use_cnt, 0);
        INIT_LIST_HEAD(&cq->sq_head);
        INIT_LIST_HEAD(&cq->rq_head);
        cq->dev = dev;
@@ -799,9 +786,6 @@ int ocrdma_destroy_cq(struct ib_cq *ibcq)
        struct ocrdma_cq *cq = get_ocrdma_cq(ibcq);
        struct ocrdma_dev *dev = cq->dev;
 
-       if (atomic_read(&cq->use_cnt))
-               return -EINVAL;
-
        status = ocrdma_mbx_destroy_cq(dev, cq);
 
        if (cq->ucontext) {
@@ -837,57 +821,56 @@ static int ocrdma_check_qp_params(struct ib_pd *ibpd, struct ocrdma_dev *dev,
        if (attrs->qp_type != IB_QPT_GSI &&
            attrs->qp_type != IB_QPT_RC &&
            attrs->qp_type != IB_QPT_UD) {
-               ocrdma_err("%s(%d) unsupported qp type=0x%x requested\n",
-                          __func__, dev->id, attrs->qp_type);
+               pr_err("%s(%d) unsupported qp type=0x%x requested\n",
+                      __func__, dev->id, attrs->qp_type);
                return -EINVAL;
        }
        if (attrs->cap.max_send_wr > dev->attr.max_wqe) {
-               ocrdma_err("%s(%d) unsupported send_wr=0x%x requested\n",
-                          __func__, dev->id, attrs->cap.max_send_wr);
-               ocrdma_err("%s(%d) supported send_wr=0x%x\n",
-                          __func__, dev->id, dev->attr.max_wqe);
+               pr_err("%s(%d) unsupported send_wr=0x%x requested\n",
+                      __func__, dev->id, attrs->cap.max_send_wr);
+               pr_err("%s(%d) supported send_wr=0x%x\n",
+                      __func__, dev->id, dev->attr.max_wqe);
                return -EINVAL;
        }
        if (!attrs->srq && (attrs->cap.max_recv_wr > dev->attr.max_rqe)) {
-               ocrdma_err("%s(%d) unsupported recv_wr=0x%x requested\n",
-                          __func__, dev->id, attrs->cap.max_recv_wr);
-               ocrdma_err("%s(%d) supported recv_wr=0x%x\n",
-                          __func__, dev->id, dev->attr.max_rqe);
+               pr_err("%s(%d) unsupported recv_wr=0x%x requested\n",
+                      __func__, dev->id, attrs->cap.max_recv_wr);
+               pr_err("%s(%d) supported recv_wr=0x%x\n",
+                      __func__, dev->id, dev->attr.max_rqe);
                return -EINVAL;
        }
        if (attrs->cap.max_inline_data > dev->attr.max_inline_data) {
-               ocrdma_err("%s(%d) unsupported inline data size=0x%x"
-                          " requested\n", __func__, dev->id,
-                          attrs->cap.max_inline_data);
-               ocrdma_err("%s(%d) supported inline data size=0x%x\n",
-                          __func__, dev->id, dev->attr.max_inline_data);
+               pr_err("%s(%d) unsupported inline data size=0x%x requested\n",
+                      __func__, dev->id, attrs->cap.max_inline_data);
+               pr_err("%s(%d) supported inline data size=0x%x\n",
+                      __func__, dev->id, dev->attr.max_inline_data);
                return -EINVAL;
        }
        if (attrs->cap.max_send_sge > dev->attr.max_send_sge) {
-               ocrdma_err("%s(%d) unsupported send_sge=0x%x requested\n",
-                          __func__, dev->id, attrs->cap.max_send_sge);
-               ocrdma_err("%s(%d) supported send_sge=0x%x\n",
-                          __func__, dev->id, dev->attr.max_send_sge);
+               pr_err("%s(%d) unsupported send_sge=0x%x requested\n",
+                      __func__, dev->id, attrs->cap.max_send_sge);
+               pr_err("%s(%d) supported send_sge=0x%x\n",
+                      __func__, dev->id, dev->attr.max_send_sge);
                return -EINVAL;
        }
        if (attrs->cap.max_recv_sge > dev->attr.max_recv_sge) {
-               ocrdma_err("%s(%d) unsupported recv_sge=0x%x requested\n",
-                          __func__, dev->id, attrs->cap.max_recv_sge);
-               ocrdma_err("%s(%d) supported recv_sge=0x%x\n",
-                          __func__, dev->id, dev->attr.max_recv_sge);
+               pr_err("%s(%d) unsupported recv_sge=0x%x requested\n",
+                      __func__, dev->id, attrs->cap.max_recv_sge);
+               pr_err("%s(%d) supported recv_sge=0x%x\n",
+                      __func__, dev->id, dev->attr.max_recv_sge);
                return -EINVAL;
        }
        /* unprivileged user space cannot create special QP */
        if (ibpd->uobject && attrs->qp_type == IB_QPT_GSI) {
-               ocrdma_err
+               pr_err
                    ("%s(%d) Userspace can't create special QPs of type=0x%x\n",
                     __func__, dev->id, attrs->qp_type);
                return -EINVAL;
        }
        /* allow creating only one GSI type of QP */
        if (attrs->qp_type == IB_QPT_GSI && dev->gsi_qp_created) {
-               ocrdma_err("%s(%d) GSI special QPs already created.\n",
-                          __func__, dev->id);
+               pr_err("%s(%d) GSI special QPs already created.\n",
+                      __func__, dev->id);
                return -EINVAL;
        }
        /* verify consumer QPs are not trying to use GSI QP's CQ */
@@ -896,8 +879,8 @@ static int ocrdma_check_qp_params(struct ib_pd *ibpd, struct ocrdma_dev *dev,
                    (dev->gsi_sqcq == get_ocrdma_cq(attrs->recv_cq)) ||
                    (dev->gsi_rqcq == get_ocrdma_cq(attrs->send_cq)) ||
                    (dev->gsi_rqcq == get_ocrdma_cq(attrs->recv_cq))) {
-                       ocrdma_err("%s(%d) Consumer QP cannot use GSI CQs.\n",
-                                  __func__, dev->id);
+                       pr_err("%s(%d) Consumer QP cannot use GSI CQs.\n",
+                              __func__, dev->id);
                        return -EINVAL;
                }
        }
@@ -949,7 +932,7 @@ static int ocrdma_copy_qp_uresp(struct ocrdma_qp *qp,
        }
        status = ib_copy_to_udata(udata, &uresp, sizeof(uresp));
        if (status) {
-               ocrdma_err("%s(%d) user copy error.\n", __func__, dev->id);
+               pr_err("%s(%d) user copy error.\n", __func__, dev->id);
                goto err;
        }
        status = ocrdma_add_mmap(pd->uctx, uresp.sq_page_addr[0],
@@ -1023,15 +1006,6 @@ static void ocrdma_set_qp_init_params(struct ocrdma_qp *qp,
        qp->state = OCRDMA_QPS_RST;
 }
 
-static void ocrdma_set_qp_use_cnt(struct ocrdma_qp *qp, struct ocrdma_pd *pd)
-{
-       atomic_inc(&pd->use_cnt);
-       atomic_inc(&qp->sq_cq->use_cnt);
-       atomic_inc(&qp->rq_cq->use_cnt);
-       if (qp->srq)
-               atomic_inc(&qp->srq->use_cnt);
-       qp->ibqp.qp_num = qp->id;
-}
 
 static void ocrdma_store_gsi_qp_cq(struct ocrdma_dev *dev,
                                   struct ib_qp_init_attr *attrs)
@@ -1099,7 +1073,7 @@ struct ib_qp *ocrdma_create_qp(struct ib_pd *ibpd,
                        goto cpy_err;
        }
        ocrdma_store_gsi_qp_cq(dev, attrs);
-       ocrdma_set_qp_use_cnt(qp, pd);
+       qp->ibqp.qp_num = qp->id;
        mutex_unlock(&dev->dev_lock);
        return &qp->ibqp;
 
@@ -1112,7 +1086,7 @@ mbx_err:
        kfree(qp->wqe_wr_id_tbl);
        kfree(qp->rqe_wr_id_tbl);
        kfree(qp);
-       ocrdma_err("%s(%d) error=%d\n", __func__, dev->id, status);
+       pr_err("%s(%d) error=%d\n", __func__, dev->id, status);
 gen_err:
        return ERR_PTR(status);
 }
@@ -1162,10 +1136,10 @@ int ocrdma_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
        spin_unlock_irqrestore(&qp->q_lock, flags);
 
        if (!ib_modify_qp_is_ok(old_qps, new_qps, ibqp->qp_type, attr_mask)) {
-               ocrdma_err("%s(%d) invalid attribute mask=0x%x specified for "
-                          "qpn=0x%x of type=0x%x old_qps=0x%x, new_qps=0x%x\n",
-                          __func__, dev->id, attr_mask, qp->id, ibqp->qp_type,
-                          old_qps, new_qps);
+               pr_err("%s(%d) invalid attribute mask=0x%x specified for\n"
+                      "qpn=0x%x of type=0x%x old_qps=0x%x, new_qps=0x%x\n",
+                      __func__, dev->id, attr_mask, qp->id, ibqp->qp_type,
+                      old_qps, new_qps);
                goto param_err;
        }
 
@@ -1475,11 +1449,6 @@ int ocrdma_destroy_qp(struct ib_qp *ibqp)
 
        ocrdma_del_flush_qp(qp);
 
-       atomic_dec(&qp->pd->use_cnt);
-       atomic_dec(&qp->sq_cq->use_cnt);
-       atomic_dec(&qp->rq_cq->use_cnt);
-       if (qp->srq)
-               atomic_dec(&qp->srq->use_cnt);
        kfree(qp->wqe_wr_id_tbl);
        kfree(qp->rqe_wr_id_tbl);
        kfree(qp);
@@ -1565,14 +1534,12 @@ struct ib_srq *ocrdma_create_srq(struct ib_pd *ibpd,
                        goto arm_err;
        }
 
-       atomic_set(&srq->use_cnt, 0);
        if (udata) {
                status = ocrdma_copy_srq_uresp(srq, udata);
                if (status)
                        goto arm_err;
        }
 
-       atomic_inc(&pd->use_cnt);
        return &srq->ibsrq;
 
 arm_err:
@@ -1618,18 +1585,12 @@ int ocrdma_destroy_srq(struct ib_srq *ibsrq)
 
        srq = get_ocrdma_srq(ibsrq);
        dev = srq->dev;
-       if (atomic_read(&srq->use_cnt)) {
-               ocrdma_err("%s(%d) err, srq=0x%x in use\n",
-                          __func__, dev->id, srq->id);
-               return -EAGAIN;
-       }
 
        status = ocrdma_mbx_destroy_srq(dev, srq);
 
        if (srq->pd->uctx)
                ocrdma_del_mmap(srq->pd->uctx, (u64) srq->rq.pa, srq->rq.len);
 
-       atomic_dec(&srq->pd->use_cnt);
        kfree(srq->idx_bit_fields);
        kfree(srq->rqe_wr_id_tbl);
        kfree(srq);
@@ -1677,9 +1638,9 @@ static int ocrdma_build_inline_sges(struct ocrdma_qp *qp,
 {
        if (wr->send_flags & IB_SEND_INLINE) {
                if (wr->sg_list[0].length > qp->max_inline_data) {
-                       ocrdma_err("%s() supported_len=0x%x,"
-                               " unspported len req=0x%x\n", __func__,
-                               qp->max_inline_data, wr->sg_list[0].length);
+                       pr_err("%s() supported_len=0x%x,\n"
+                              " unspported len req=0x%x\n", __func__,
+                              qp->max_inline_data, wr->sg_list[0].length);
                        return -EINVAL;
                }
                memcpy(sge,
@@ -1773,12 +1734,14 @@ int ocrdma_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
        spin_lock_irqsave(&qp->q_lock, flags);
        if (qp->state != OCRDMA_QPS_RTS && qp->state != OCRDMA_QPS_SQD) {
                spin_unlock_irqrestore(&qp->q_lock, flags);
+               *bad_wr = wr;
                return -EINVAL;
        }
 
        while (wr) {
                if (ocrdma_hwq_free_cnt(&qp->sq) == 0 ||
                    wr->num_sge > qp->sq.max_sges) {
+                       *bad_wr = wr;
                        status = -ENOMEM;
                        break;
                }
@@ -1856,7 +1819,7 @@ int ocrdma_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
 
 static void ocrdma_ring_rq_db(struct ocrdma_qp *qp)
 {
-       u32 val = qp->rq.dbid | (1 << OCRDMA_GET_NUM_POSTED_SHIFT_VAL(qp));
+       u32 val = qp->rq.dbid | (1 << ocrdma_get_num_posted_shift(qp));
 
        iowrite32(val, qp->rq_db);
 }
@@ -2094,8 +2057,8 @@ static void ocrdma_update_wc(struct ocrdma_qp *qp, struct ib_wc *ibwc,
                break;
        default:
                ibwc->status = IB_WC_GENERAL_ERR;
-               ocrdma_err("%s() invalid opcode received = 0x%x\n",
-                          __func__, hdr->cw & OCRDMA_WQE_OPCODE_MASK);
+               pr_err("%s() invalid opcode received = 0x%x\n",
+                      __func__, hdr->cw & OCRDMA_WQE_OPCODE_MASK);
                break;
        };
 }
index 1e603a3..d03ca4c 100644 (file)
@@ -5,3 +5,11 @@ config INFINIBAND_QIB
        This is a low-level driver for Intel PCIe QLE InfiniBand host
        channel adapters.  This driver does not support the Intel
        HyperTransport card (model QHT7140).
+
+config INFINIBAND_QIB_DCA
+       bool "QIB DCA support"
+       depends on INFINIBAND_QIB && DCA && SMP && GENERIC_HARDIRQS && !(INFINIBAND_QIB=y && DCA=m)
+       default y
+       ---help---
+       Setting this enables DCA support on some Intel chip sets
+       with the iba7322 HCA.
index f12d7bb..57f8103 100644 (file)
@@ -13,3 +13,4 @@ ib_qib-$(CONFIG_PCI_MSI) += qib_iba6120.o
 
 ib_qib-$(CONFIG_X86_64) += qib_wc_x86_64.o
 ib_qib-$(CONFIG_PPC64) += qib_wc_ppc64.o
+ib_qib-$(CONFIG_DEBUG_FS) += qib_debugfs.o
index 4d11575..4a9af79 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef _QIB_KERNEL_H
 #define _QIB_KERNEL_H
 /*
- * Copyright (c) 2012 Intel Corporation.  All rights reserved.
+ * Copyright (c) 2012, 2013 Intel Corporation.  All rights reserved.
  * Copyright (c) 2006 - 2012 QLogic Corporation. All rights reserved.
  * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
  *
@@ -51,6 +51,7 @@
 #include <linux/completion.h>
 #include <linux/kref.h>
 #include <linux/sched.h>
+#include <linux/kthread.h>
 
 #include "qib_common.h"
 #include "qib_verbs.h"
@@ -114,6 +115,11 @@ struct qib_eep_log_mask {
 /*
  * Below contains all data related to a single context (formerly called port).
  */
+
+#ifdef CONFIG_DEBUG_FS
+struct qib_opcode_stats_perctx;
+#endif
+
 struct qib_ctxtdata {
        void **rcvegrbuf;
        dma_addr_t *rcvegrbuf_phys;
@@ -154,6 +160,8 @@ struct qib_ctxtdata {
         */
        /* instead of calculating it */
        unsigned ctxt;
+       /* local node of context */
+       int node_id;
        /* non-zero if ctxt is being shared. */
        u16 subctxt_cnt;
        /* non-zero if ctxt is being shared. */
@@ -222,12 +230,15 @@ struct qib_ctxtdata {
        u8 redirect_seq_cnt;
        /* ctxt rcvhdrq head offset */
        u32 head;
-       u32 pkt_count;
        /* lookaside fields */
        struct qib_qp *lookaside_qp;
        u32 lookaside_qpn;
        /* QPs waiting for context processing */
        struct list_head qp_wait_list;
+#ifdef CONFIG_DEBUG_FS
+       /* verbs stats per CTX */
+       struct qib_opcode_stats_perctx *opstats;
+#endif
 };
 
 struct qib_sge_state;
@@ -428,9 +439,19 @@ struct qib_verbs_txreq {
 #define ACTIVITY_TIMER 5
 
 #define MAX_NAME_SIZE 64
+
+#ifdef CONFIG_INFINIBAND_QIB_DCA
+struct qib_irq_notify;
+#endif
+
 struct qib_msix_entry {
        struct msix_entry msix;
        void *arg;
+#ifdef CONFIG_INFINIBAND_QIB_DCA
+       int dca;
+       int rcv;
+       struct qib_irq_notify *notifier;
+#endif
        char name[MAX_NAME_SIZE];
        cpumask_var_t mask;
 };
@@ -828,6 +849,9 @@ struct qib_devdata {
                struct qib_ctxtdata *);
        void (*f_writescratch)(struct qib_devdata *, u32);
        int (*f_tempsense_rd)(struct qib_devdata *, int regnum);
+#ifdef CONFIG_INFINIBAND_QIB_DCA
+       int (*f_notify_dca)(struct qib_devdata *, unsigned long event);
+#endif
 
        char *boardname; /* human readable board info */
 
@@ -1075,6 +1099,10 @@ struct qib_devdata {
        u16 psxmitwait_check_rate;
        /* high volume overflow errors defered to tasklet */
        struct tasklet_struct error_tasklet;
+       /* per device cq worker */
+       struct kthread_worker *worker;
+
+       int assigned_node_id; /* NUMA node closest to HCA */
 };
 
 /* hol_state values */
@@ -1154,7 +1182,7 @@ int qib_create_rcvhdrq(struct qib_devdata *, struct qib_ctxtdata *);
 int qib_setup_eagerbufs(struct qib_ctxtdata *);
 void qib_set_ctxtcnt(struct qib_devdata *);
 int qib_create_ctxts(struct qib_devdata *dd);
-struct qib_ctxtdata *qib_create_ctxtdata(struct qib_pportdata *, u32);
+struct qib_ctxtdata *qib_create_ctxtdata(struct qib_pportdata *, u32, int);
 void qib_init_pportdata(struct qib_pportdata *, struct qib_devdata *, u8, u8);
 void qib_free_ctxtdata(struct qib_devdata *, struct qib_ctxtdata *);
 
@@ -1320,7 +1348,7 @@ static inline int __qib_sdma_running(struct qib_pportdata *ppd)
        return ppd->sdma_state.current_state == qib_sdma_state_s99_running;
 }
 int qib_sdma_running(struct qib_pportdata *);
-
+void dump_sdma_state(struct qib_pportdata *ppd);
 void __qib_sdma_process_event(struct qib_pportdata *, enum qib_sdma_events);
 void qib_sdma_process_event(struct qib_pportdata *, enum qib_sdma_events);
 
@@ -1445,6 +1473,7 @@ extern unsigned qib_n_krcv_queues;
 extern unsigned qib_sdma_fetch_arb;
 extern unsigned qib_compat_ddr_negotiate;
 extern int qib_special_trigger;
+extern unsigned qib_numa_aware;
 
 extern struct mutex qib_mutex;
 
@@ -1474,27 +1503,23 @@ extern struct mutex qib_mutex;
  * first to avoid possible serial port delays from printk.
  */
 #define qib_early_err(dev, fmt, ...) \
-       do { \
-               dev_err(dev, fmt, ##__VA_ARGS__); \
-       } while (0)
+       dev_err(dev, fmt, ##__VA_ARGS__)
 
 #define qib_dev_err(dd, fmt, ...) \
-       do { \
-               dev_err(&(dd)->pcidev->dev, "%s: " fmt, \
-                       qib_get_unit_name((dd)->unit), ##__VA_ARGS__); \
-       } while (0)
+       dev_err(&(dd)->pcidev->dev, "%s: " fmt, \
+               qib_get_unit_name((dd)->unit), ##__VA_ARGS__)
+
+#define qib_dev_warn(dd, fmt, ...) \
+       dev_warn(&(dd)->pcidev->dev, "%s: " fmt, \
+               qib_get_unit_name((dd)->unit), ##__VA_ARGS__)
 
 #define qib_dev_porterr(dd, port, fmt, ...) \
-       do { \
-               dev_err(&(dd)->pcidev->dev, "%s: IB%u:%u " fmt, \
-                       qib_get_unit_name((dd)->unit), (dd)->unit, (port), \
-                       ##__VA_ARGS__); \
-       } while (0)
+       dev_err(&(dd)->pcidev->dev, "%s: IB%u:%u " fmt, \
+               qib_get_unit_name((dd)->unit), (dd)->unit, (port), \
+               ##__VA_ARGS__)
 
 #define qib_devinfo(pcidev, fmt, ...) \
-       do { \
-               dev_info(&(pcidev)->dev, fmt, ##__VA_ARGS__); \
-       } while (0)
+       dev_info(&(pcidev)->dev, fmt, ##__VA_ARGS__)
 
 /*
  * this is used for formatting hw error messages...
index d39e018..4f255b7 100644 (file)
@@ -279,7 +279,7 @@ struct qib_base_info {
  * may not be implemented; the user code must deal with this if it
  * cares, or it must abort after initialization reports the difference.
  */
-#define QIB_USER_SWMINOR 11
+#define QIB_USER_SWMINOR 12
 
 #define QIB_USER_SWVERSION ((QIB_USER_SWMAJOR << 16) | QIB_USER_SWMINOR)
 
index 5246aa4..ab4e11c 100644 (file)
@@ -1,4 +1,5 @@
 /*
+ * Copyright (c) 2013 Intel Corporation.  All rights reserved.
  * Copyright (c) 2006, 2007, 2008, 2010 QLogic Corporation. All rights reserved.
  * Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved.
  *
 #include <linux/err.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
+#include <linux/kthread.h>
 
 #include "qib_verbs.h"
+#include "qib.h"
 
 /**
  * qib_cq_enter - add a new entry to the completion queue
@@ -102,13 +105,18 @@ void qib_cq_enter(struct qib_cq *cq, struct ib_wc *entry, int solicited)
        if (cq->notify == IB_CQ_NEXT_COMP ||
            (cq->notify == IB_CQ_SOLICITED &&
             (solicited || entry->status != IB_WC_SUCCESS))) {
-               cq->notify = IB_CQ_NONE;
-               cq->triggered++;
+               struct kthread_worker *worker;
                /*
                 * This will cause send_complete() to be called in
                 * another thread.
                 */
-               queue_work(qib_cq_wq, &cq->comptask);
+               smp_rmb();
+               worker = cq->dd->worker;
+               if (likely(worker)) {
+                       cq->notify = IB_CQ_NONE;
+                       cq->triggered++;
+                       queue_kthread_work(worker, &cq->comptask);
+               }
        }
 
        spin_unlock_irqrestore(&cq->lock, flags);
@@ -163,7 +171,7 @@ bail:
        return npolled;
 }
 
-static void send_complete(struct work_struct *work)
+static void send_complete(struct kthread_work *work)
 {
        struct qib_cq *cq = container_of(work, struct qib_cq, comptask);
 
@@ -287,11 +295,12 @@ struct ib_cq *qib_create_cq(struct ib_device *ibdev, int entries,
         * The number of entries should be >= the number requested or return
         * an error.
         */
+       cq->dd = dd_from_dev(dev);
        cq->ibcq.cqe = entries;
        cq->notify = IB_CQ_NONE;
        cq->triggered = 0;
        spin_lock_init(&cq->lock);
-       INIT_WORK(&cq->comptask, send_complete);
+       init_kthread_work(&cq->comptask, send_complete);
        wc->head = 0;
        wc->tail = 0;
        cq->queue = wc;
@@ -323,7 +332,7 @@ int qib_destroy_cq(struct ib_cq *ibcq)
        struct qib_ibdev *dev = to_idev(ibcq->device);
        struct qib_cq *cq = to_icq(ibcq);
 
-       flush_work(&cq->comptask);
+       flush_kthread_work(&cq->comptask);
        spin_lock(&dev->n_cqs_lock);
        dev->n_cqs_allocated--;
        spin_unlock(&dev->n_cqs_lock);
@@ -483,3 +492,49 @@ bail_free:
 bail:
        return ret;
 }
+
+int qib_cq_init(struct qib_devdata *dd)
+{
+       int ret = 0;
+       int cpu;
+       struct task_struct *task;
+
+       if (dd->worker)
+               return 0;
+       dd->worker = kzalloc(sizeof(*dd->worker), GFP_KERNEL);
+       if (!dd->worker)
+               return -ENOMEM;
+       init_kthread_worker(dd->worker);
+       task = kthread_create_on_node(
+               kthread_worker_fn,
+               dd->worker,
+               dd->assigned_node_id,
+               "qib_cq%d", dd->unit);
+       if (IS_ERR(task))
+               goto task_fail;
+       cpu = cpumask_first(cpumask_of_node(dd->assigned_node_id));
+       kthread_bind(task, cpu);
+       wake_up_process(task);
+out:
+       return ret;
+task_fail:
+       ret = PTR_ERR(task);
+       kfree(dd->worker);
+       dd->worker = NULL;
+       goto out;
+}
+
+void qib_cq_exit(struct qib_devdata *dd)
+{
+       struct kthread_worker *worker;
+
+       worker = dd->worker;
+       if (!worker)
+               return;
+       /* blocks future queuing from send_complete() */
+       dd->worker = NULL;
+       smp_wmb();
+       flush_kthread_worker(worker);
+       kthread_stop(worker->task);
+       kfree(worker);
+}
diff --git a/drivers/infiniband/hw/qib/qib_debugfs.c b/drivers/infiniband/hw/qib/qib_debugfs.c
new file mode 100644 (file)
index 0000000..799a0c3
--- /dev/null
@@ -0,0 +1,283 @@
+#ifdef CONFIG_DEBUG_FS
+/*
+ * Copyright (c) 2013 Intel Corporation.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/kernel.h>
+#include <linux/export.h>
+
+#include "qib.h"
+#include "qib_verbs.h"
+#include "qib_debugfs.h"
+
+static struct dentry *qib_dbg_root;
+
+#define DEBUGFS_FILE(name) \
+static const struct seq_operations _##name##_seq_ops = { \
+       .start = _##name##_seq_start, \
+       .next  = _##name##_seq_next, \
+       .stop  = _##name##_seq_stop, \
+       .show  = _##name##_seq_show \
+}; \
+static int _##name##_open(struct inode *inode, struct file *s) \
+{ \
+       struct seq_file *seq; \
+       int ret; \
+       ret =  seq_open(s, &_##name##_seq_ops); \
+       if (ret) \
+               return ret; \
+       seq = s->private_data; \
+       seq->private = inode->i_private; \
+       return 0; \
+} \
+static const struct file_operations _##name##_file_ops = { \
+       .owner   = THIS_MODULE, \
+       .open    = _##name##_open, \
+       .read    = seq_read, \
+       .llseek  = seq_lseek, \
+       .release = seq_release \
+};
+
+#define DEBUGFS_FILE_CREATE(name) \
+do { \
+       struct dentry *ent; \
+       ent = debugfs_create_file(#name , 0400, ibd->qib_ibdev_dbg, \
+               ibd, &_##name##_file_ops); \
+       if (!ent) \
+               pr_warn("create of " #name " failed\n"); \
+} while (0)
+
+static void *_opcode_stats_seq_start(struct seq_file *s, loff_t *pos)
+{
+       struct qib_opcode_stats_perctx *opstats;
+
+       if (*pos >= ARRAY_SIZE(opstats->stats))
+               return NULL;
+       return pos;
+}
+
+static void *_opcode_stats_seq_next(struct seq_file *s, void *v, loff_t *pos)
+{
+       struct qib_opcode_stats_perctx *opstats;
+
+       ++*pos;
+       if (*pos >= ARRAY_SIZE(opstats->stats))
+               return NULL;
+       return pos;
+}
+
+
+static void _opcode_stats_seq_stop(struct seq_file *s, void *v)
+{
+       /* nothing allocated */
+}
+
+static int _opcode_stats_seq_show(struct seq_file *s, void *v)
+{
+       loff_t *spos = v;
+       loff_t i = *spos, j;
+       u64 n_packets = 0, n_bytes = 0;
+       struct qib_ibdev *ibd = (struct qib_ibdev *)s->private;
+       struct qib_devdata *dd = dd_from_dev(ibd);
+
+       for (j = 0; j < dd->first_user_ctxt; j++) {
+               if (!dd->rcd[j])
+                       continue;
+               n_packets += dd->rcd[j]->opstats->stats[i].n_packets;
+               n_bytes += dd->rcd[j]->opstats->stats[i].n_bytes;
+       }
+       if (!n_packets && !n_bytes)
+               return SEQ_SKIP;
+       seq_printf(s, "%02llx %llu/%llu\n", i,
+               (unsigned long long) n_packets,
+               (unsigned long long) n_bytes);
+
+       return 0;
+}
+
+DEBUGFS_FILE(opcode_stats)
+
+static void *_ctx_stats_seq_start(struct seq_file *s, loff_t *pos)
+{
+       struct qib_ibdev *ibd = (struct qib_ibdev *)s->private;
+       struct qib_devdata *dd = dd_from_dev(ibd);
+
+       if (!*pos)
+               return SEQ_START_TOKEN;
+       if (*pos >= dd->first_user_ctxt)
+               return NULL;
+       return pos;
+}
+
+static void *_ctx_stats_seq_next(struct seq_file *s, void *v, loff_t *pos)
+{
+       struct qib_ibdev *ibd = (struct qib_ibdev *)s->private;
+       struct qib_devdata *dd = dd_from_dev(ibd);
+
+       if (v == SEQ_START_TOKEN)
+               return pos;
+
+       ++*pos;
+       if (*pos >= dd->first_user_ctxt)
+               return NULL;
+       return pos;
+}
+
+static void _ctx_stats_seq_stop(struct seq_file *s, void *v)
+{
+       /* nothing allocated */
+}
+
+static int _ctx_stats_seq_show(struct seq_file *s, void *v)
+{
+       loff_t *spos;
+       loff_t i, j;
+       u64 n_packets = 0;
+       struct qib_ibdev *ibd = (struct qib_ibdev *)s->private;
+       struct qib_devdata *dd = dd_from_dev(ibd);
+
+       if (v == SEQ_START_TOKEN) {
+               seq_puts(s, "Ctx:npkts\n");
+               return 0;
+       }
+
+       spos = v;
+       i = *spos;
+
+       if (!dd->rcd[i])
+               return SEQ_SKIP;
+
+       for (j = 0; j < ARRAY_SIZE(dd->rcd[i]->opstats->stats); j++)
+               n_packets += dd->rcd[i]->opstats->stats[j].n_packets;
+
+       if (!n_packets)
+               return SEQ_SKIP;
+
+       seq_printf(s, "  %llu:%llu\n", i, n_packets);
+       return 0;
+}
+
+DEBUGFS_FILE(ctx_stats)
+
+static void *_qp_stats_seq_start(struct seq_file *s, loff_t *pos)
+{
+       struct qib_qp_iter *iter;
+       loff_t n = *pos;
+
+       iter = qib_qp_iter_init(s->private);
+       if (!iter)
+               return NULL;
+
+       while (n--) {
+               if (qib_qp_iter_next(iter)) {
+                       kfree(iter);
+                       return NULL;
+               }
+       }
+
+       return iter;
+}
+
+static void *_qp_stats_seq_next(struct seq_file *s, void *iter_ptr,
+                                  loff_t *pos)
+{
+       struct qib_qp_iter *iter = iter_ptr;
+
+       (*pos)++;
+
+       if (qib_qp_iter_next(iter)) {
+               kfree(iter);
+               return NULL;
+       }
+
+       return iter;
+}
+
+static void _qp_stats_seq_stop(struct seq_file *s, void *iter_ptr)
+{
+       /* nothing for now */
+}
+
+static int _qp_stats_seq_show(struct seq_file *s, void *iter_ptr)
+{
+       struct qib_qp_iter *iter = iter_ptr;
+
+       if (!iter)
+               return 0;
+
+       qib_qp_iter_print(s, iter);
+
+       return 0;
+}
+
+DEBUGFS_FILE(qp_stats)
+
+void qib_dbg_ibdev_init(struct qib_ibdev *ibd)
+{
+       char name[10];
+
+       snprintf(name, sizeof(name), "qib%d", dd_from_dev(ibd)->unit);
+       ibd->qib_ibdev_dbg = debugfs_create_dir(name, qib_dbg_root);
+       if (!ibd->qib_ibdev_dbg) {
+               pr_warn("create of %s failed\n", name);
+               return;
+       }
+       DEBUGFS_FILE_CREATE(opcode_stats);
+       DEBUGFS_FILE_CREATE(ctx_stats);
+       DEBUGFS_FILE_CREATE(qp_stats);
+       return;
+}
+
+void qib_dbg_ibdev_exit(struct qib_ibdev *ibd)
+{
+       if (!qib_dbg_root)
+               goto out;
+       debugfs_remove_recursive(ibd->qib_ibdev_dbg);
+out:
+       ibd->qib_ibdev_dbg = NULL;
+}
+
+void qib_dbg_init(void)
+{
+       qib_dbg_root = debugfs_create_dir(QIB_DRV_NAME, NULL);
+       if (!qib_dbg_root)
+               pr_warn("init of debugfs failed\n");
+}
+
+void qib_dbg_exit(void)
+{
+       debugfs_remove_recursive(qib_dbg_root);
+       qib_dbg_root = NULL;
+}
+
+#endif
+
diff --git a/drivers/infiniband/hw/qib/qib_debugfs.h b/drivers/infiniband/hw/qib/qib_debugfs.h
new file mode 100644 (file)
index 0000000..7ae983a
--- /dev/null
@@ -0,0 +1,45 @@
+#ifndef _QIB_DEBUGFS_H
+#define _QIB_DEBUGFS_H
+
+#ifdef CONFIG_DEBUG_FS
+/*
+ * Copyright (c) 2013 Intel Corporation.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+struct qib_ibdev;
+void qib_dbg_ibdev_init(struct qib_ibdev *ibd);
+void qib_dbg_ibdev_exit(struct qib_ibdev *ibd);
+void qib_dbg_init(void);
+void qib_dbg_exit(void);
+
+#endif
+
+#endif                          /* _QIB_DEBUGFS_H */
index 2160924..5bee08f 100644 (file)
@@ -558,7 +558,6 @@ move_along:
        }
 
        rcd->head = l;
-       rcd->pkt_count += i;
 
        /*
         * Iterate over all QPs waiting to respond.
index 9dd0bc8..b51a514 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012 Intel Corporation. All rights reserved.
+ * Copyright (c) 2012, 2013 Intel Corporation. All rights reserved.
  * Copyright (c) 2006 - 2012 QLogic Corporation. All rights reserved.
  * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
  *
@@ -1155,6 +1155,49 @@ static unsigned int qib_poll(struct file *fp, struct poll_table_struct *pt)
        return pollflag;
 }
 
+static void assign_ctxt_affinity(struct file *fp, struct qib_devdata *dd)
+{
+       struct qib_filedata *fd = fp->private_data;
+       const unsigned int weight = cpumask_weight(&current->cpus_allowed);
+       const struct cpumask *local_mask = cpumask_of_pcibus(dd->pcidev->bus);
+       int local_cpu;
+
+       /*
+        * If process has NOT already set it's affinity, select and
+        * reserve a processor for it on the local NUMA node.
+        */
+       if ((weight >= qib_cpulist_count) &&
+               (cpumask_weight(local_mask) <= qib_cpulist_count)) {
+               for_each_cpu(local_cpu, local_mask)
+                       if (!test_and_set_bit(local_cpu, qib_cpulist)) {
+                               fd->rec_cpu_num = local_cpu;
+                               return;
+                       }
+       }
+
+       /*
+        * If process has NOT already set it's affinity, select and
+        * reserve a processor for it, as a rendevous for all
+        * users of the driver.  If they don't actually later
+        * set affinity to this cpu, or set it to some other cpu,
+        * it just means that sooner or later we don't recommend
+        * a cpu, and let the scheduler do it's best.
+        */
+       if (weight >= qib_cpulist_count) {
+               int cpu;
+               cpu = find_first_zero_bit(qib_cpulist,
+                                         qib_cpulist_count);
+               if (cpu == qib_cpulist_count)
+                       qib_dev_err(dd,
+                       "no cpus avail for affinity PID %u\n",
+                       current->pid);
+               else {
+                       __set_bit(cpu, qib_cpulist);
+                       fd->rec_cpu_num = cpu;
+               }
+       }
+}
+
 /*
  * Check that userland and driver are compatible for subcontexts.
  */
@@ -1259,12 +1302,20 @@ bail:
 static int setup_ctxt(struct qib_pportdata *ppd, int ctxt,
                      struct file *fp, const struct qib_user_info *uinfo)
 {
+       struct qib_filedata *fd = fp->private_data;
        struct qib_devdata *dd = ppd->dd;
        struct qib_ctxtdata *rcd;
        void *ptmp = NULL;
        int ret;
+       int numa_id;
+
+       assign_ctxt_affinity(fp, dd);
 
-       rcd = qib_create_ctxtdata(ppd, ctxt);
+       numa_id = qib_numa_aware ? ((fd->rec_cpu_num != -1) ?
+               cpu_to_node(fd->rec_cpu_num) :
+               numa_node_id()) : dd->assigned_node_id;
+
+       rcd = qib_create_ctxtdata(ppd, ctxt, numa_id);
 
        /*
         * Allocate memory for use in qib_tid_update() at open to
@@ -1296,6 +1347,9 @@ static int setup_ctxt(struct qib_pportdata *ppd, int ctxt,
        goto bail;
 
 bailerr:
+       if (fd->rec_cpu_num != -1)
+               __clear_bit(fd->rec_cpu_num, qib_cpulist);
+
        dd->rcd[ctxt] = NULL;
        kfree(rcd);
        kfree(ptmp);
@@ -1485,6 +1539,57 @@ static int qib_open(struct inode *in, struct file *fp)
        return fp->private_data ? 0 : -ENOMEM;
 }
 
+static int find_hca(unsigned int cpu, int *unit)
+{
+       int ret = 0, devmax, npresent, nup, ndev;
+
+       *unit = -1;
+
+       devmax = qib_count_units(&npresent, &nup);
+       if (!npresent) {
+               ret = -ENXIO;
+               goto done;
+       }
+       if (!nup) {
+               ret = -ENETDOWN;
+               goto done;
+       }
+       for (ndev = 0; ndev < devmax; ndev++) {
+               struct qib_devdata *dd = qib_lookup(ndev);
+               if (dd) {
+                       if (pcibus_to_node(dd->pcidev->bus) < 0) {
+                               ret = -EINVAL;
+                               goto done;
+                       }
+                       if (cpu_to_node(cpu) ==
+                               pcibus_to_node(dd->pcidev->bus)) {
+                               *unit = ndev;
+                               goto done;
+                       }
+               }
+       }
+done:
+       return ret;
+}
+
+static int do_qib_user_sdma_queue_create(struct file *fp)
+{
+       struct qib_filedata *fd = fp->private_data;
+       struct qib_ctxtdata *rcd = fd->rcd;
+       struct qib_devdata *dd = rcd->dd;
+
+       if (dd->flags & QIB_HAS_SEND_DMA)
+
+               fd->pq = qib_user_sdma_queue_create(&dd->pcidev->dev,
+                                                   dd->unit,
+                                                   rcd->ctxt,
+                                                   fd->subctxt);
+               if (!fd->pq)
+                       return -ENOMEM;
+
+       return 0;
+}
+
 /*
  * Get ctxt early, so can set affinity prior to memory allocation.
  */
@@ -1517,61 +1622,36 @@ static int qib_assign_ctxt(struct file *fp, const struct qib_user_info *uinfo)
        if (qib_compatible_subctxts(swmajor, swminor) &&
            uinfo->spu_subctxt_cnt) {
                ret = find_shared_ctxt(fp, uinfo);
-               if (ret) {
-                       if (ret > 0)
-                               ret = 0;
-                       goto done_chk_sdma;
+               if (ret > 0) {
+                       ret = do_qib_user_sdma_queue_create(fp);
+                       if (!ret)
+                               assign_ctxt_affinity(fp, (ctxt_fp(fp))->dd);
+                       goto done_ok;
                }
        }
 
        i_minor = iminor(file_inode(fp)) - QIB_USER_MINOR_BASE;
        if (i_minor)
                ret = find_free_ctxt(i_minor - 1, fp, uinfo);
-       else
+       else {
+               int unit;
+               const unsigned int cpu = cpumask_first(&current->cpus_allowed);
+               const unsigned int weight =
+                       cpumask_weight(&current->cpus_allowed);
+
+               if (weight == 1 && !test_bit(cpu, qib_cpulist))
+                       if (!find_hca(cpu, &unit) && unit >= 0)
+                               if (!find_free_ctxt(unit, fp, uinfo)) {
+                                       ret = 0;
+                                       goto done_chk_sdma;
+                               }
                ret = get_a_ctxt(fp, uinfo, alg);
-
-done_chk_sdma:
-       if (!ret) {
-               struct qib_filedata *fd = fp->private_data;
-               const struct qib_ctxtdata *rcd = fd->rcd;
-               const struct qib_devdata *dd = rcd->dd;
-               unsigned int weight;
-
-               if (dd->flags & QIB_HAS_SEND_DMA) {
-                       fd->pq = qib_user_sdma_queue_create(&dd->pcidev->dev,
-                                                           dd->unit,
-                                                           rcd->ctxt,
-                                                           fd->subctxt);
-                       if (!fd->pq)
-                               ret = -ENOMEM;
-               }
-
-               /*
-                * If process has NOT already set it's affinity, select and
-                * reserve a processor for it, as a rendezvous for all
-                * users of the driver.  If they don't actually later
-                * set affinity to this cpu, or set it to some other cpu,
-                * it just means that sooner or later we don't recommend
-                * a cpu, and let the scheduler do it's best.
-                */
-               weight = cpumask_weight(tsk_cpus_allowed(current));
-               if (!ret && weight >= qib_cpulist_count) {
-                       int cpu;
-                       cpu = find_first_zero_bit(qib_cpulist,
-                                                 qib_cpulist_count);
-                       if (cpu != qib_cpulist_count) {
-                               __set_bit(cpu, qib_cpulist);
-                               fd->rec_cpu_num = cpu;
-                       }
-               } else if (weight == 1 &&
-                       test_bit(cpumask_first(tsk_cpus_allowed(current)),
-                                qib_cpulist))
-                       qib_devinfo(dd->pcidev,
-                               "%s PID %u affinity set to cpu %d; already allocated\n",
-                               current->comm, current->pid,
-                               cpumask_first(tsk_cpus_allowed(current)));
        }
 
+done_chk_sdma:
+       if (!ret)
+               ret = do_qib_user_sdma_queue_create(fp);
+done_ok:
        mutex_unlock(&qib_mutex);
 
 done:
index 0232ae5..84e593d 100644 (file)
@@ -3464,6 +3464,13 @@ static int qib_6120_tempsense_rd(struct qib_devdata *dd, int regnum)
        return -ENXIO;
 }
 
+#ifdef CONFIG_INFINIBAND_QIB_DCA
+static int qib_6120_notify_dca(struct qib_devdata *dd, unsigned long event)
+{
+       return 0;
+}
+#endif
+
 /* Dummy function, as 6120 boards never disable EEPROM Write */
 static int qib_6120_eeprom_wen(struct qib_devdata *dd, int wen)
 {
@@ -3539,6 +3546,9 @@ struct qib_devdata *qib_init_iba6120_funcs(struct pci_dev *pdev,
        dd->f_xgxs_reset        = qib_6120_xgxs_reset;
        dd->f_writescratch      = writescratch;
        dd->f_tempsense_rd      = qib_6120_tempsense_rd;
+#ifdef CONFIG_INFINIBAND_QIB_DCA
+       dd->f_notify_dca = qib_6120_notify_dca;
+#endif
        /*
         * Do remaining pcie setup and save pcie values in dd.
         * Any error printing is already done by the init code.
index 64d0ecb..454c2e7 100644 (file)
@@ -4513,6 +4513,13 @@ bail:
        return ret;
 }
 
+#ifdef CONFIG_INFINIBAND_QIB_DCA
+static int qib_7220_notify_dca(struct qib_devdata *dd, unsigned long event)
+{
+       return 0;
+}
+#endif
+
 /* Dummy function, as 7220 boards never disable EEPROM Write */
 static int qib_7220_eeprom_wen(struct qib_devdata *dd, int wen)
 {
@@ -4587,6 +4594,9 @@ struct qib_devdata *qib_init_iba7220_funcs(struct pci_dev *pdev,
        dd->f_xgxs_reset        = qib_7220_xgxs_reset;
        dd->f_writescratch      = writescratch;
        dd->f_tempsense_rd      = qib_7220_tempsense_rd;
+#ifdef CONFIG_INFINIBAND_QIB_DCA
+       dd->f_notify_dca = qib_7220_notify_dca;
+#endif
        /*
         * Do remaining pcie setup and save pcie values in dd.
         * Any error printing is already done by the init code.
index 3f6b21e..21e8b09 100644 (file)
@@ -44,6 +44,9 @@
 #include <linux/module.h>
 #include <rdma/ib_verbs.h>
 #include <rdma/ib_smi.h>
+#ifdef CONFIG_INFINIBAND_QIB_DCA
+#include <linux/dca.h>
+#endif
 
 #include "qib.h"
 #include "qib_7322_regs.h"
@@ -80,6 +83,7 @@ static void ibsd_wr_allchans(struct qib_pportdata *, int, unsigned, unsigned);
 static void serdes_7322_los_enable(struct qib_pportdata *, int);
 static int serdes_7322_init_old(struct qib_pportdata *);
 static int serdes_7322_init_new(struct qib_pportdata *);
+static void dump_sdma_7322_state(struct qib_pportdata *);
 
 #define BMASK(msb, lsb) (((1 << ((msb) + 1 - (lsb))) - 1) << (lsb))
 
@@ -519,6 +523,14 @@ static const u8 qib_7322_physportstate[0x20] = {
        [0x17] = IB_PHYSPORTSTATE_CFG_TRAIN
 };
 
+#ifdef CONFIG_INFINIBAND_QIB_DCA
+struct qib_irq_notify {
+       int rcv;
+       void *arg;
+       struct irq_affinity_notify notify;
+};
+#endif
+
 struct qib_chip_specific {
        u64 __iomem *cregbase;
        u64 *cntrs;
@@ -546,6 +558,12 @@ struct qib_chip_specific {
        u32 lastbuf_for_pio;
        u32 stay_in_freeze;
        u32 recovery_ports_initted;
+#ifdef CONFIG_INFINIBAND_QIB_DCA
+       u32 dca_ctrl;
+       int rhdr_cpu[18];
+       int sdma_cpu[2];
+       u64 dca_rcvhdr_ctrl[5]; /* B, C, D, E, F */
+#endif
        struct qib_msix_entry *msix_entries;
        unsigned long *sendchkenable;
        unsigned long *sendgrhchk;
@@ -573,7 +591,7 @@ struct vendor_txdds_ent {
 static void write_tx_serdes_param(struct qib_pportdata *, struct txdds_ent *);
 
 #define TXDDS_TABLE_SZ 16 /* number of entries per speed in onchip table */
-#define TXDDS_EXTRA_SZ 13 /* number of extra tx settings entries */
+#define TXDDS_EXTRA_SZ 18 /* number of extra tx settings entries */
 #define TXDDS_MFG_SZ 2    /* number of mfg tx settings entries */
 #define SERDES_CHANS 4 /* yes, it's obvious, but one less magic number */
 
@@ -635,6 +653,7 @@ struct qib_chippport_specific {
        u8 ibmalfusesnap;
        struct qib_qsfp_data qsfp_data;
        char epmsgbuf[192]; /* for port error interrupt msg buffer */
+       char sdmamsgbuf[192]; /* for per-port sdma error messages */
 };
 
 static struct {
@@ -642,28 +661,76 @@ static struct {
        irq_handler_t handler;
        int lsb;
        int port; /* 0 if not port-specific, else port # */
+       int dca;
 } irq_table[] = {
-       { "", qib_7322intr, -1, 0 },
+       { "", qib_7322intr, -1, 0, 0 },
        { " (buf avail)", qib_7322bufavail,
-               SYM_LSB(IntStatus, SendBufAvail), 0 },
+               SYM_LSB(IntStatus, SendBufAvail), 0, 0},
        { " (sdma 0)", sdma_intr,
-               SYM_LSB(IntStatus, SDmaInt_0), 1 },
+               SYM_LSB(IntStatus, SDmaInt_0), 1, 1 },
        { " (sdma 1)", sdma_intr,
-               SYM_LSB(IntStatus, SDmaInt_1), 2 },
+               SYM_LSB(IntStatus, SDmaInt_1), 2, 1 },
        { " (sdmaI 0)", sdma_idle_intr,
-               SYM_LSB(IntStatus, SDmaIdleInt_0), 1 },
+               SYM_LSB(IntStatus, SDmaIdleInt_0), 1, 1},
        { " (sdmaI 1)", sdma_idle_intr,
-               SYM_LSB(IntStatus, SDmaIdleInt_1), 2 },
+               SYM_LSB(IntStatus, SDmaIdleInt_1), 2, 1},
        { " (sdmaP 0)", sdma_progress_intr,
-               SYM_LSB(IntStatus, SDmaProgressInt_0), 1 },
+               SYM_LSB(IntStatus, SDmaProgressInt_0), 1, 1 },
        { " (sdmaP 1)", sdma_progress_intr,
-               SYM_LSB(IntStatus, SDmaProgressInt_1), 2 },
+               SYM_LSB(IntStatus, SDmaProgressInt_1), 2, 1 },
        { " (sdmaC 0)", sdma_cleanup_intr,
-               SYM_LSB(IntStatus, SDmaCleanupDone_0), 1 },
+               SYM_LSB(IntStatus, SDmaCleanupDone_0), 1, 0 },
        { " (sdmaC 1)", sdma_cleanup_intr,
-               SYM_LSB(IntStatus, SDmaCleanupDone_1), 2 },
+               SYM_LSB(IntStatus, SDmaCleanupDone_1), 2 , 0},
 };
 
+#ifdef CONFIG_INFINIBAND_QIB_DCA
+
+static const struct dca_reg_map {
+       int     shadow_inx;
+       int     lsb;
+       u64     mask;
+       u16     regno;
+} dca_rcvhdr_reg_map[] = {
+       { 0, SYM_LSB(DCACtrlB, RcvHdrq0DCAOPH),
+          ~SYM_MASK(DCACtrlB, RcvHdrq0DCAOPH) , KREG_IDX(DCACtrlB) },
+       { 0, SYM_LSB(DCACtrlB, RcvHdrq1DCAOPH),
+          ~SYM_MASK(DCACtrlB, RcvHdrq1DCAOPH) , KREG_IDX(DCACtrlB) },
+       { 0, SYM_LSB(DCACtrlB, RcvHdrq2DCAOPH),
+          ~SYM_MASK(DCACtrlB, RcvHdrq2DCAOPH) , KREG_IDX(DCACtrlB) },
+       { 0, SYM_LSB(DCACtrlB, RcvHdrq3DCAOPH),
+          ~SYM_MASK(DCACtrlB, RcvHdrq3DCAOPH) , KREG_IDX(DCACtrlB) },
+       { 1, SYM_LSB(DCACtrlC, RcvHdrq4DCAOPH),
+          ~SYM_MASK(DCACtrlC, RcvHdrq4DCAOPH) , KREG_IDX(DCACtrlC) },
+       { 1, SYM_LSB(DCACtrlC, RcvHdrq5DCAOPH),
+          ~SYM_MASK(DCACtrlC, RcvHdrq5DCAOPH) , KREG_IDX(DCACtrlC) },
+       { 1, SYM_LSB(DCACtrlC, RcvHdrq6DCAOPH),
+          ~SYM_MASK(DCACtrlC, RcvHdrq6DCAOPH) , KREG_IDX(DCACtrlC) },
+       { 1, SYM_LSB(DCACtrlC, RcvHdrq7DCAOPH),
+          ~SYM_MASK(DCACtrlC, RcvHdrq7DCAOPH) , KREG_IDX(DCACtrlC) },
+       { 2, SYM_LSB(DCACtrlD, RcvHdrq8DCAOPH),
+          ~SYM_MASK(DCACtrlD, RcvHdrq8DCAOPH) , KREG_IDX(DCACtrlD) },
+       { 2, SYM_LSB(DCACtrlD, RcvHdrq9DCAOPH),
+          ~SYM_MASK(DCACtrlD, RcvHdrq9DCAOPH) , KREG_IDX(DCACtrlD) },
+       { 2, SYM_LSB(DCACtrlD, RcvHdrq10DCAOPH),
+          ~SYM_MASK(DCACtrlD, RcvHdrq10DCAOPH) , KREG_IDX(DCACtrlD) },
+       { 2, SYM_LSB(DCACtrlD, RcvHdrq11DCAOPH),
+          ~SYM_MASK(DCACtrlD, RcvHdrq11DCAOPH) , KREG_IDX(DCACtrlD) },
+       { 3, SYM_LSB(DCACtrlE, RcvHdrq12DCAOPH),
+          ~SYM_MASK(DCACtrlE, RcvHdrq12DCAOPH) , KREG_IDX(DCACtrlE) },
+       { 3, SYM_LSB(DCACtrlE, RcvHdrq13DCAOPH),
+          ~SYM_MASK(DCACtrlE, RcvHdrq13DCAOPH) , KREG_IDX(DCACtrlE) },
+       { 3, SYM_LSB(DCACtrlE, RcvHdrq14DCAOPH),
+          ~SYM_MASK(DCACtrlE, RcvHdrq14DCAOPH) , KREG_IDX(DCACtrlE) },
+       { 3, SYM_LSB(DCACtrlE, RcvHdrq15DCAOPH),
+          ~SYM_MASK(DCACtrlE, RcvHdrq15DCAOPH) , KREG_IDX(DCACtrlE) },
+       { 4, SYM_LSB(DCACtrlF, RcvHdrq16DCAOPH),
+          ~SYM_MASK(DCACtrlF, RcvHdrq16DCAOPH) , KREG_IDX(DCACtrlF) },
+       { 4, SYM_LSB(DCACtrlF, RcvHdrq17DCAOPH),
+          ~SYM_MASK(DCACtrlF, RcvHdrq17DCAOPH) , KREG_IDX(DCACtrlF) },
+};
+#endif
+
 /* ibcctrl bits */
 #define QLOGIC_IB_IBCC_LINKINITCMD_DISABLE 1
 /* cycle through TS1/TS2 till OK */
@@ -686,6 +753,13 @@ static void write_7322_init_portregs(struct qib_pportdata *);
 static void setup_7322_link_recovery(struct qib_pportdata *, u32);
 static void check_7322_rxe_status(struct qib_pportdata *);
 static u32 __iomem *qib_7322_getsendbuf(struct qib_pportdata *, u64, u32 *);
+#ifdef CONFIG_INFINIBAND_QIB_DCA
+static void qib_setup_dca(struct qib_devdata *dd);
+static void setup_dca_notifier(struct qib_devdata *dd,
+                              struct qib_msix_entry *m);
+static void reset_dca_notifier(struct qib_devdata *dd,
+                              struct qib_msix_entry *m);
+#endif
 
 /**
  * qib_read_ureg32 - read 32-bit virtualized per-context register
@@ -1529,6 +1603,15 @@ static void sdma_7322_p_errors(struct qib_pportdata *ppd, u64 errs)
 
        spin_lock_irqsave(&ppd->sdma_lock, flags);
 
+       if (errs != QIB_E_P_SDMAHALT) {
+               /* SDMA errors have QIB_E_P_SDMAHALT and another bit set */
+               qib_dev_porterr(dd, ppd->port,
+                       "SDMA %s 0x%016llx %s\n",
+                       qib_sdma_state_names[ppd->sdma_state.current_state],
+                       errs, ppd->cpspec->sdmamsgbuf);
+               dump_sdma_7322_state(ppd);
+       }
+
        switch (ppd->sdma_state.current_state) {
        case qib_sdma_state_s00_hw_down:
                break;
@@ -2084,6 +2167,29 @@ static void qib_7322_handle_hwerrors(struct qib_devdata *dd, char *msg,
 
        qib_dev_err(dd, "%s hardware error\n", msg);
 
+       if (hwerrs &
+                  (SYM_MASK(HwErrMask, SDmaMemReadErrMask_0) |
+                   SYM_MASK(HwErrMask, SDmaMemReadErrMask_1))) {
+               int pidx = 0;
+               int err;
+               unsigned long flags;
+               struct qib_pportdata *ppd = dd->pport;
+               for (; pidx < dd->num_pports; ++pidx, ppd++) {
+                       err = 0;
+                       if (pidx == 0 && (hwerrs &
+                               SYM_MASK(HwErrMask, SDmaMemReadErrMask_0)))
+                               err++;
+                       if (pidx == 1 && (hwerrs &
+                               SYM_MASK(HwErrMask, SDmaMemReadErrMask_1)))
+                               err++;
+                       if (err) {
+                               spin_lock_irqsave(&ppd->sdma_lock, flags);
+                               dump_sdma_7322_state(ppd);
+                               spin_unlock_irqrestore(&ppd->sdma_lock, flags);
+                       }
+               }
+       }
+
        if (isfatal && !dd->diag_client) {
                qib_dev_err(dd,
                        "Fatal Hardware Error, no longer usable, SN %.16s\n",
@@ -2558,6 +2664,162 @@ static void qib_setup_7322_setextled(struct qib_pportdata *ppd, u32 on)
                qib_write_kreg_port(ppd, krp_rcvpktledcnt, ledblink);
 }
 
+#ifdef CONFIG_INFINIBAND_QIB_DCA
+
+static int qib_7322_notify_dca(struct qib_devdata *dd, unsigned long event)
+{
+       switch (event) {
+       case DCA_PROVIDER_ADD:
+               if (dd->flags & QIB_DCA_ENABLED)
+                       break;
+               if (!dca_add_requester(&dd->pcidev->dev)) {
+                       qib_devinfo(dd->pcidev, "DCA enabled\n");
+                       dd->flags |= QIB_DCA_ENABLED;
+                       qib_setup_dca(dd);
+               }
+               break;
+       case DCA_PROVIDER_REMOVE:
+               if (dd->flags & QIB_DCA_ENABLED) {
+                       dca_remove_requester(&dd->pcidev->dev);
+                       dd->flags &= ~QIB_DCA_ENABLED;
+                       dd->cspec->dca_ctrl = 0;
+                       qib_write_kreg(dd, KREG_IDX(DCACtrlA),
+                               dd->cspec->dca_ctrl);
+               }
+               break;
+       }
+       return 0;
+}
+
+static void qib_update_rhdrq_dca(struct qib_ctxtdata *rcd, int cpu)
+{
+       struct qib_devdata *dd = rcd->dd;
+       struct qib_chip_specific *cspec = dd->cspec;
+
+       if (!(dd->flags & QIB_DCA_ENABLED))
+               return;
+       if (cspec->rhdr_cpu[rcd->ctxt] != cpu) {
+               const struct dca_reg_map *rmp;
+
+               cspec->rhdr_cpu[rcd->ctxt] = cpu;
+               rmp = &dca_rcvhdr_reg_map[rcd->ctxt];
+               cspec->dca_rcvhdr_ctrl[rmp->shadow_inx] &= rmp->mask;
+               cspec->dca_rcvhdr_ctrl[rmp->shadow_inx] |=
+                       (u64) dca3_get_tag(&dd->pcidev->dev, cpu) << rmp->lsb;
+               qib_devinfo(dd->pcidev,
+                       "Ctxt %d cpu %d dca %llx\n", rcd->ctxt, cpu,
+                       (long long) cspec->dca_rcvhdr_ctrl[rmp->shadow_inx]);
+               qib_write_kreg(dd, rmp->regno,
+                              cspec->dca_rcvhdr_ctrl[rmp->shadow_inx]);
+               cspec->dca_ctrl |= SYM_MASK(DCACtrlA, RcvHdrqDCAEnable);
+               qib_write_kreg(dd, KREG_IDX(DCACtrlA), cspec->dca_ctrl);
+       }
+}
+
+static void qib_update_sdma_dca(struct qib_pportdata *ppd, int cpu)
+{
+       struct qib_devdata *dd = ppd->dd;
+       struct qib_chip_specific *cspec = dd->cspec;
+       unsigned pidx = ppd->port - 1;
+
+       if (!(dd->flags & QIB_DCA_ENABLED))
+               return;
+       if (cspec->sdma_cpu[pidx] != cpu) {
+               cspec->sdma_cpu[pidx] = cpu;
+               cspec->dca_rcvhdr_ctrl[4] &= ~(ppd->hw_pidx ?
+                       SYM_MASK(DCACtrlF, SendDma1DCAOPH) :
+                       SYM_MASK(DCACtrlF, SendDma0DCAOPH));
+               cspec->dca_rcvhdr_ctrl[4] |=
+                       (u64) dca3_get_tag(&dd->pcidev->dev, cpu) <<
+                               (ppd->hw_pidx ?
+                                       SYM_LSB(DCACtrlF, SendDma1DCAOPH) :
+                                       SYM_LSB(DCACtrlF, SendDma0DCAOPH));
+               qib_devinfo(dd->pcidev,
+                       "sdma %d cpu %d dca %llx\n", ppd->hw_pidx, cpu,
+                       (long long) cspec->dca_rcvhdr_ctrl[4]);
+               qib_write_kreg(dd, KREG_IDX(DCACtrlF),
+                              cspec->dca_rcvhdr_ctrl[4]);
+               cspec->dca_ctrl |= ppd->hw_pidx ?
+                       SYM_MASK(DCACtrlA, SendDMAHead1DCAEnable) :
+                       SYM_MASK(DCACtrlA, SendDMAHead0DCAEnable);
+               qib_write_kreg(dd, KREG_IDX(DCACtrlA), cspec->dca_ctrl);
+       }
+}
+
+static void qib_setup_dca(struct qib_devdata *dd)
+{
+       struct qib_chip_specific *cspec = dd->cspec;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(cspec->rhdr_cpu); i++)
+               cspec->rhdr_cpu[i] = -1;
+       for (i = 0; i < ARRAY_SIZE(cspec->sdma_cpu); i++)
+               cspec->sdma_cpu[i] = -1;
+       cspec->dca_rcvhdr_ctrl[0] =
+               (1ULL << SYM_LSB(DCACtrlB, RcvHdrq0DCAXfrCnt)) |
+               (1ULL << SYM_LSB(DCACtrlB, RcvHdrq1DCAXfrCnt)) |
+               (1ULL << SYM_LSB(DCACtrlB, RcvHdrq2DCAXfrCnt)) |
+               (1ULL << SYM_LSB(DCACtrlB, RcvHdrq3DCAXfrCnt));
+       cspec->dca_rcvhdr_ctrl[1] =
+               (1ULL << SYM_LSB(DCACtrlC, RcvHdrq4DCAXfrCnt)) |
+               (1ULL << SYM_LSB(DCACtrlC, RcvHdrq5DCAXfrCnt)) |
+               (1ULL << SYM_LSB(DCACtrlC, RcvHdrq6DCAXfrCnt)) |
+               (1ULL << SYM_LSB(DCACtrlC, RcvHdrq7DCAXfrCnt));
+       cspec->dca_rcvhdr_ctrl[2] =
+               (1ULL << SYM_LSB(DCACtrlD, RcvHdrq8DCAXfrCnt)) |
+               (1ULL << SYM_LSB(DCACtrlD, RcvHdrq9DCAXfrCnt)) |
+               (1ULL << SYM_LSB(DCACtrlD, RcvHdrq10DCAXfrCnt)) |
+               (1ULL << SYM_LSB(DCACtrlD, RcvHdrq11DCAXfrCnt));
+       cspec->dca_rcvhdr_ctrl[3] =
+               (1ULL << SYM_LSB(DCACtrlE, RcvHdrq12DCAXfrCnt)) |
+               (1ULL << SYM_LSB(DCACtrlE, RcvHdrq13DCAXfrCnt)) |
+               (1ULL << SYM_LSB(DCACtrlE, RcvHdrq14DCAXfrCnt)) |
+               (1ULL << SYM_LSB(DCACtrlE, RcvHdrq15DCAXfrCnt));
+       cspec->dca_rcvhdr_ctrl[4] =
+               (1ULL << SYM_LSB(DCACtrlF, RcvHdrq16DCAXfrCnt)) |
+               (1ULL << SYM_LSB(DCACtrlF, RcvHdrq17DCAXfrCnt));
+       for (i = 0; i < ARRAY_SIZE(cspec->sdma_cpu); i++)
+               qib_write_kreg(dd, KREG_IDX(DCACtrlB) + i,
+                              cspec->dca_rcvhdr_ctrl[i]);
+       for (i = 0; i < cspec->num_msix_entries; i++)
+               setup_dca_notifier(dd, &cspec->msix_entries[i]);
+}
+
+static void qib_irq_notifier_notify(struct irq_affinity_notify *notify,
+                            const cpumask_t *mask)
+{
+       struct qib_irq_notify *n =
+               container_of(notify, struct qib_irq_notify, notify);
+       int cpu = cpumask_first(mask);
+
+       if (n->rcv) {
+               struct qib_ctxtdata *rcd = (struct qib_ctxtdata *)n->arg;
+               qib_update_rhdrq_dca(rcd, cpu);
+       } else {
+               struct qib_pportdata *ppd = (struct qib_pportdata *)n->arg;
+               qib_update_sdma_dca(ppd, cpu);
+       }
+}
+
+static void qib_irq_notifier_release(struct kref *ref)
+{
+       struct qib_irq_notify *n =
+               container_of(ref, struct qib_irq_notify, notify.kref);
+       struct qib_devdata *dd;
+
+       if (n->rcv) {
+               struct qib_ctxtdata *rcd = (struct qib_ctxtdata *)n->arg;
+               dd = rcd->dd;
+       } else {
+               struct qib_pportdata *ppd = (struct qib_pportdata *)n->arg;
+               dd = ppd->dd;
+       }
+       qib_devinfo(dd->pcidev,
+               "release on HCA notify 0x%p n 0x%p\n", ref, n);
+       kfree(n);
+}
+#endif
+
 /*
  * Disable MSIx interrupt if enabled, call generic MSIx code
  * to cleanup, and clear pending MSIx interrupts.
@@ -2575,6 +2837,9 @@ static void qib_7322_nomsix(struct qib_devdata *dd)
 
                dd->cspec->num_msix_entries = 0;
                for (i = 0; i < n; i++) {
+#ifdef CONFIG_INFINIBAND_QIB_DCA
+                       reset_dca_notifier(dd, &dd->cspec->msix_entries[i]);
+#endif
                        irq_set_affinity_hint(
                          dd->cspec->msix_entries[i].msix.vector, NULL);
                        free_cpumask_var(dd->cspec->msix_entries[i].mask);
@@ -2602,6 +2867,15 @@ static void qib_setup_7322_cleanup(struct qib_devdata *dd)
 {
        int i;
 
+#ifdef CONFIG_INFINIBAND_QIB_DCA
+       if (dd->flags & QIB_DCA_ENABLED) {
+               dca_remove_requester(&dd->pcidev->dev);
+               dd->flags &= ~QIB_DCA_ENABLED;
+               dd->cspec->dca_ctrl = 0;
+               qib_write_kreg(dd, KREG_IDX(DCACtrlA), dd->cspec->dca_ctrl);
+       }
+#endif
+
        qib_7322_free_irq(dd);
        kfree(dd->cspec->cntrs);
        kfree(dd->cspec->sendchkenable);
@@ -3068,6 +3342,53 @@ static irqreturn_t sdma_cleanup_intr(int irq, void *data)
        return IRQ_HANDLED;
 }
 
+#ifdef CONFIG_INFINIBAND_QIB_DCA
+
+static void reset_dca_notifier(struct qib_devdata *dd, struct qib_msix_entry *m)
+{
+       if (!m->dca)
+               return;
+       qib_devinfo(dd->pcidev,
+               "Disabling notifier on HCA %d irq %d\n",
+               dd->unit,
+               m->msix.vector);
+       irq_set_affinity_notifier(
+               m->msix.vector,
+               NULL);
+       m->notifier = NULL;
+}
+
+static void setup_dca_notifier(struct qib_devdata *dd, struct qib_msix_entry *m)
+{
+       struct qib_irq_notify *n;
+
+       if (!m->dca)
+               return;
+       n = kzalloc(sizeof(*n), GFP_KERNEL);
+       if (n) {
+               int ret;
+
+               m->notifier = n;
+               n->notify.irq = m->msix.vector;
+               n->notify.notify = qib_irq_notifier_notify;
+               n->notify.release = qib_irq_notifier_release;
+               n->arg = m->arg;
+               n->rcv = m->rcv;
+               qib_devinfo(dd->pcidev,
+                       "set notifier irq %d rcv %d notify %p\n",
+                       n->notify.irq, n->rcv, &n->notify);
+               ret = irq_set_affinity_notifier(
+                               n->notify.irq,
+                               &n->notify);
+               if (ret) {
+                       m->notifier = NULL;
+                       kfree(n);
+               }
+       }
+}
+
+#endif
+
 /*
  * Set up our chip-specific interrupt handler.
  * The interrupt type has already been setup, so
@@ -3149,6 +3470,9 @@ try_intx:
                void *arg;
                u64 val;
                int lsb, reg, sh;
+#ifdef CONFIG_INFINIBAND_QIB_DCA
+               int dca = 0;
+#endif
 
                dd->cspec->msix_entries[msixnum].
                        name[sizeof(dd->cspec->msix_entries[msixnum].name) - 1]
@@ -3161,6 +3485,9 @@ try_intx:
                                arg = dd->pport + irq_table[i].port - 1;
                        } else
                                arg = dd;
+#ifdef CONFIG_INFINIBAND_QIB_DCA
+                       dca = irq_table[i].dca;
+#endif
                        lsb = irq_table[i].lsb;
                        handler = irq_table[i].handler;
                        snprintf(dd->cspec->msix_entries[msixnum].name,
@@ -3178,6 +3505,9 @@ try_intx:
                                continue;
                        if (qib_krcvq01_no_msi && ctxt < 2)
                                continue;
+#ifdef CONFIG_INFINIBAND_QIB_DCA
+                       dca = 1;
+#endif
                        lsb = QIB_I_RCVAVAIL_LSB + ctxt;
                        handler = qib_7322pintr;
                        snprintf(dd->cspec->msix_entries[msixnum].name,
@@ -3203,6 +3533,11 @@ try_intx:
                        goto try_intx;
                }
                dd->cspec->msix_entries[msixnum].arg = arg;
+#ifdef CONFIG_INFINIBAND_QIB_DCA
+               dd->cspec->msix_entries[msixnum].dca = dca;
+               dd->cspec->msix_entries[msixnum].rcv =
+                       handler == qib_7322pintr;
+#endif
                if (lsb >= 0) {
                        reg = lsb / IBA7322_REDIRECT_VEC_PER_REG;
                        sh = (lsb % IBA7322_REDIRECT_VEC_PER_REG) *
@@ -6452,6 +6787,86 @@ static void qib_sdma_set_7322_desc_cnt(struct qib_pportdata *ppd, unsigned cnt)
        qib_write_kreg_port(ppd, krp_senddmadesccnt, cnt);
 }
 
+/*
+ * sdma_lock should be acquired before calling this routine
+ */
+static void dump_sdma_7322_state(struct qib_pportdata *ppd)
+{
+       u64 reg, reg1, reg2;
+
+       reg = qib_read_kreg_port(ppd, krp_senddmastatus);
+       qib_dev_porterr(ppd->dd, ppd->port,
+               "SDMA senddmastatus: 0x%016llx\n", reg);
+
+       reg = qib_read_kreg_port(ppd, krp_sendctrl);
+       qib_dev_porterr(ppd->dd, ppd->port,
+               "SDMA sendctrl: 0x%016llx\n", reg);
+
+       reg = qib_read_kreg_port(ppd, krp_senddmabase);
+       qib_dev_porterr(ppd->dd, ppd->port,
+               "SDMA senddmabase: 0x%016llx\n", reg);
+
+       reg = qib_read_kreg_port(ppd, krp_senddmabufmask0);
+       reg1 = qib_read_kreg_port(ppd, krp_senddmabufmask1);
+       reg2 = qib_read_kreg_port(ppd, krp_senddmabufmask2);
+       qib_dev_porterr(ppd->dd, ppd->port,
+               "SDMA senddmabufmask 0:%llx  1:%llx  2:%llx\n",
+                reg, reg1, reg2);
+
+       /* get bufuse bits, clear them, and print them again if non-zero */
+       reg = qib_read_kreg_port(ppd, krp_senddmabuf_use0);
+       qib_write_kreg_port(ppd, krp_senddmabuf_use0, reg);
+       reg1 = qib_read_kreg_port(ppd, krp_senddmabuf_use1);
+       qib_write_kreg_port(ppd, krp_senddmabuf_use0, reg1);
+       reg2 = qib_read_kreg_port(ppd, krp_senddmabuf_use2);
+       qib_write_kreg_port(ppd, krp_senddmabuf_use0, reg2);
+       /* 0 and 1 should always be zero, so print as short form */
+       qib_dev_porterr(ppd->dd, ppd->port,
+                "SDMA current senddmabuf_use 0:%llx  1:%llx  2:%llx\n",
+                reg, reg1, reg2);
+       reg = qib_read_kreg_port(ppd, krp_senddmabuf_use0);
+       reg1 = qib_read_kreg_port(ppd, krp_senddmabuf_use1);
+       reg2 = qib_read_kreg_port(ppd, krp_senddmabuf_use2);
+       /* 0 and 1 should always be zero, so print as short form */
+       qib_dev_porterr(ppd->dd, ppd->port,
+                "SDMA cleared senddmabuf_use 0:%llx  1:%llx  2:%llx\n",
+                reg, reg1, reg2);
+
+       reg = qib_read_kreg_port(ppd, krp_senddmatail);
+       qib_dev_porterr(ppd->dd, ppd->port,
+               "SDMA senddmatail: 0x%016llx\n", reg);
+
+       reg = qib_read_kreg_port(ppd, krp_senddmahead);
+       qib_dev_porterr(ppd->dd, ppd->port,
+               "SDMA senddmahead: 0x%016llx\n", reg);
+
+       reg = qib_read_kreg_port(ppd, krp_senddmaheadaddr);
+       qib_dev_porterr(ppd->dd, ppd->port,
+               "SDMA senddmaheadaddr: 0x%016llx\n", reg);
+
+       reg = qib_read_kreg_port(ppd, krp_senddmalengen);
+       qib_dev_porterr(ppd->dd, ppd->port,
+               "SDMA senddmalengen: 0x%016llx\n", reg);
+
+       reg = qib_read_kreg_port(ppd, krp_senddmadesccnt);
+       qib_dev_porterr(ppd->dd, ppd->port,
+               "SDMA senddmadesccnt: 0x%016llx\n", reg);
+
+       reg = qib_read_kreg_port(ppd, krp_senddmaidlecnt);
+       qib_dev_porterr(ppd->dd, ppd->port,
+               "SDMA senddmaidlecnt: 0x%016llx\n", reg);
+
+       reg = qib_read_kreg_port(ppd, krp_senddmaprioritythld);
+       qib_dev_porterr(ppd->dd, ppd->port,
+               "SDMA senddmapriorityhld: 0x%016llx\n", reg);
+
+       reg = qib_read_kreg_port(ppd, krp_senddmareloadcnt);
+       qib_dev_porterr(ppd->dd, ppd->port,
+               "SDMA senddmareloadcnt: 0x%016llx\n", reg);
+
+       dump_sdma_state(ppd);
+}
+
 static struct sdma_set_state_action sdma_7322_action_table[] = {
        [qib_sdma_state_s00_hw_down] = {
                .go_s99_running_tofalse = 1,
@@ -6885,6 +7300,9 @@ struct qib_devdata *qib_init_iba7322_funcs(struct pci_dev *pdev,
        dd->f_sdma_init_early   = qib_7322_sdma_init_early;
        dd->f_writescratch      = writescratch;
        dd->f_tempsense_rd      = qib_7322_tempsense_rd;
+#ifdef CONFIG_INFINIBAND_QIB_DCA
+       dd->f_notify_dca        = qib_7322_notify_dca;
+#endif
        /*
         * Do remaining PCIe setup and save PCIe values in dd.
         * Any error printing is already done by the init code.
@@ -6921,7 +7339,7 @@ struct qib_devdata *qib_init_iba7322_funcs(struct pci_dev *pdev,
                actual_cnt -= dd->num_pports;
 
        tabsize = actual_cnt;
-       dd->cspec->msix_entries = kmalloc(tabsize *
+       dd->cspec->msix_entries = kzalloc(tabsize *
                        sizeof(struct qib_msix_entry), GFP_KERNEL);
        if (!dd->cspec->msix_entries) {
                qib_dev_err(dd, "No memory for MSIx table\n");
@@ -6941,7 +7359,13 @@ struct qib_devdata *qib_init_iba7322_funcs(struct pci_dev *pdev,
 
        /* clear diagctrl register, in case diags were running and crashed */
        qib_write_kreg(dd, kr_hwdiagctrl, 0);
-
+#ifdef CONFIG_INFINIBAND_QIB_DCA
+       if (!dca_add_requester(&pdev->dev)) {
+               qib_devinfo(dd->pcidev, "DCA enabled\n");
+               dd->flags |= QIB_DCA_ENABLED;
+               qib_setup_dca(dd);
+       }
+#endif
        goto bail;
 
 bail_cleanup:
@@ -7156,15 +7580,20 @@ static const struct txdds_ent txdds_extra_sdr[TXDDS_EXTRA_SZ] = {
        {  0, 0, 0,  1 },       /* QMH7342 backplane settings */
        {  0, 0, 0,  2 },       /* QMH7342 backplane settings */
        {  0, 0, 0,  2 },       /* QMH7342 backplane settings */
-       {  0, 0, 0, 11 },       /* QME7342 backplane settings */
-       {  0, 0, 0, 11 },       /* QME7342 backplane settings */
-       {  0, 0, 0, 11 },       /* QME7342 backplane settings */
-       {  0, 0, 0, 11 },       /* QME7342 backplane settings */
-       {  0, 0, 0, 11 },       /* QME7342 backplane settings */
-       {  0, 0, 0, 11 },       /* QME7342 backplane settings */
-       {  0, 0, 0, 11 },       /* QME7342 backplane settings */
        {  0, 0, 0,  3 },       /* QMH7342 backplane settings */
        {  0, 0, 0,  4 },       /* QMH7342 backplane settings */
+       {  0, 1, 4, 15 },       /* QME7342 backplane settings 1.0 */
+       {  0, 1, 3, 15 },       /* QME7342 backplane settings 1.0 */
+       {  0, 1, 0, 12 },       /* QME7342 backplane settings 1.0 */
+       {  0, 1, 0, 11 },       /* QME7342 backplane settings 1.0 */
+       {  0, 1, 0,  9 },       /* QME7342 backplane settings 1.0 */
+       {  0, 1, 0, 14 },       /* QME7342 backplane settings 1.0 */
+       {  0, 1, 2, 15 },       /* QME7342 backplane settings 1.0 */
+       {  0, 1, 0, 11 },       /* QME7342 backplane settings 1.1 */
+       {  0, 1, 0,  7 },       /* QME7342 backplane settings 1.1 */
+       {  0, 1, 0,  9 },       /* QME7342 backplane settings 1.1 */
+       {  0, 1, 0,  6 },       /* QME7342 backplane settings 1.1 */
+       {  0, 1, 0,  8 },       /* QME7342 backplane settings 1.1 */
 };
 
 static const struct txdds_ent txdds_extra_ddr[TXDDS_EXTRA_SZ] = {
@@ -7173,15 +7602,20 @@ static const struct txdds_ent txdds_extra_ddr[TXDDS_EXTRA_SZ] = {
        {  0, 0, 0,  7 },       /* QMH7342 backplane settings */
        {  0, 0, 0,  8 },       /* QMH7342 backplane settings */
        {  0, 0, 0,  8 },       /* QMH7342 backplane settings */
-       {  0, 0, 0, 13 },       /* QME7342 backplane settings */
-       {  0, 0, 0, 13 },       /* QME7342 backplane settings */
-       {  0, 0, 0, 13 },       /* QME7342 backplane settings */
-       {  0, 0, 0, 13 },       /* QME7342 backplane settings */
-       {  0, 0, 0, 13 },       /* QME7342 backplane settings */
-       {  0, 0, 0, 13 },       /* QME7342 backplane settings */
-       {  0, 0, 0, 13 },       /* QME7342 backplane settings */
        {  0, 0, 0,  9 },       /* QMH7342 backplane settings */
        {  0, 0, 0, 10 },       /* QMH7342 backplane settings */
+       {  0, 1, 4, 15 },       /* QME7342 backplane settings 1.0 */
+       {  0, 1, 3, 15 },       /* QME7342 backplane settings 1.0 */
+       {  0, 1, 0, 12 },       /* QME7342 backplane settings 1.0 */
+       {  0, 1, 0, 11 },       /* QME7342 backplane settings 1.0 */
+       {  0, 1, 0,  9 },       /* QME7342 backplane settings 1.0 */
+       {  0, 1, 0, 14 },       /* QME7342 backplane settings 1.0 */
+       {  0, 1, 2, 15 },       /* QME7342 backplane settings 1.0 */
+       {  0, 1, 0, 11 },       /* QME7342 backplane settings 1.1 */
+       {  0, 1, 0,  7 },       /* QME7342 backplane settings 1.1 */
+       {  0, 1, 0,  9 },       /* QME7342 backplane settings 1.1 */
+       {  0, 1, 0,  6 },       /* QME7342 backplane settings 1.1 */
+       {  0, 1, 0,  8 },       /* QME7342 backplane settings 1.1 */
 };
 
 static const struct txdds_ent txdds_extra_qdr[TXDDS_EXTRA_SZ] = {
@@ -7190,15 +7624,20 @@ static const struct txdds_ent txdds_extra_qdr[TXDDS_EXTRA_SZ] = {
        {  0, 1,  0,  5 },      /* QMH7342 backplane settings */
        {  0, 1,  0,  6 },      /* QMH7342 backplane settings */
        {  0, 1,  0,  8 },      /* QMH7342 backplane settings */
-       {  0, 1, 12, 10 },      /* QME7342 backplane setting */
-       {  0, 1, 12, 11 },      /* QME7342 backplane setting */
-       {  0, 1, 12, 12 },      /* QME7342 backplane setting */
-       {  0, 1, 12, 14 },      /* QME7342 backplane setting */
-       {  0, 1, 12,  6 },      /* QME7342 backplane setting */
-       {  0, 1, 12,  7 },      /* QME7342 backplane setting */
-       {  0, 1, 12,  8 },      /* QME7342 backplane setting */
        {  0, 1,  0, 10 },      /* QMH7342 backplane settings */
        {  0, 1,  0, 12 },      /* QMH7342 backplane settings */
+       {  0, 1,  4, 15 },      /* QME7342 backplane settings 1.0 */
+       {  0, 1,  3, 15 },      /* QME7342 backplane settings 1.0 */
+       {  0, 1,  0, 12 },      /* QME7342 backplane settings 1.0 */
+       {  0, 1,  0, 11 },      /* QME7342 backplane settings 1.0 */
+       {  0, 1,  0,  9 },      /* QME7342 backplane settings 1.0 */
+       {  0, 1,  0, 14 },      /* QME7342 backplane settings 1.0 */
+       {  0, 1,  2, 15 },      /* QME7342 backplane settings 1.0 */
+       {  0, 1,  0, 11 },      /* QME7342 backplane settings 1.1 */
+       {  0, 1,  0,  7 },      /* QME7342 backplane settings 1.1 */
+       {  0, 1,  0,  9 },      /* QME7342 backplane settings 1.1 */
+       {  0, 1,  0,  6 },      /* QME7342 backplane settings 1.1 */
+       {  0, 1,  0,  8 },      /* QME7342 backplane settings 1.1 */
 };
 
 static const struct txdds_ent txdds_extra_mfg[TXDDS_MFG_SZ] = {
index 173f805..36e048e 100644 (file)
 #include <linux/idr.h>
 #include <linux/module.h>
 #include <linux/printk.h>
+#ifdef CONFIG_INFINIBAND_QIB_DCA
+#include <linux/dca.h>
+#endif
 
 #include "qib.h"
 #include "qib_common.h"
 #include "qib_mad.h"
+#ifdef CONFIG_DEBUG_FS
+#include "qib_debugfs.h"
+#include "qib_verbs.h"
+#endif
 
 #undef pr_fmt
 #define pr_fmt(fmt) QIB_DRV_NAME ": " fmt
@@ -64,6 +71,11 @@ ushort qib_cfgctxts;
 module_param_named(cfgctxts, qib_cfgctxts, ushort, S_IRUGO);
 MODULE_PARM_DESC(cfgctxts, "Set max number of contexts to use");
 
+unsigned qib_numa_aware;
+module_param_named(numa_aware, qib_numa_aware, uint, S_IRUGO);
+MODULE_PARM_DESC(numa_aware,
+       "0 -> PSM allocation close to HCA, 1 -> PSM allocation local to process");
+
 /*
  * If set, do not write to any regs if avoidable, hack to allow
  * check for deranged default register values.
@@ -89,8 +101,6 @@ unsigned qib_wc_pat = 1; /* default (1) is to use PAT, not MTRR */
 module_param_named(wc_pat, qib_wc_pat, uint, S_IRUGO);
 MODULE_PARM_DESC(wc_pat, "enable write-combining via PAT mechanism");
 
-struct workqueue_struct *qib_cq_wq;
-
 static void verify_interrupt(unsigned long);
 
 static struct idr qib_unit_table;
@@ -121,6 +131,11 @@ int qib_create_ctxts(struct qib_devdata *dd)
 {
        unsigned i;
        int ret;
+       int local_node_id = pcibus_to_node(dd->pcidev->bus);
+
+       if (local_node_id < 0)
+               local_node_id = numa_node_id();
+       dd->assigned_node_id = local_node_id;
 
        /*
         * Allocate full ctxtcnt array, rather than just cfgctxts, because
@@ -143,7 +158,8 @@ int qib_create_ctxts(struct qib_devdata *dd)
                        continue;
 
                ppd = dd->pport + (i % dd->num_pports);
-               rcd = qib_create_ctxtdata(ppd, i);
+
+               rcd = qib_create_ctxtdata(ppd, i, dd->assigned_node_id);
                if (!rcd) {
                        qib_dev_err(dd,
                                "Unable to allocate ctxtdata for Kernel ctxt, failing\n");
@@ -161,20 +177,33 @@ done:
 /*
  * Common code for user and kernel context setup.
  */
-struct qib_ctxtdata *qib_create_ctxtdata(struct qib_pportdata *ppd, u32 ctxt)
+struct qib_ctxtdata *qib_create_ctxtdata(struct qib_pportdata *ppd, u32 ctxt,
+       int node_id)
 {
        struct qib_devdata *dd = ppd->dd;
        struct qib_ctxtdata *rcd;
 
-       rcd = kzalloc(sizeof(*rcd), GFP_KERNEL);
+       rcd = kzalloc_node(sizeof(*rcd), GFP_KERNEL, node_id);
        if (rcd) {
                INIT_LIST_HEAD(&rcd->qp_wait_list);
+               rcd->node_id = node_id;
                rcd->ppd = ppd;
                rcd->dd = dd;
                rcd->cnt = 1;
                rcd->ctxt = ctxt;
                dd->rcd[ctxt] = rcd;
-
+#ifdef CONFIG_DEBUG_FS
+               if (ctxt < dd->first_user_ctxt) { /* N/A for PSM contexts */
+                       rcd->opstats = kzalloc_node(sizeof(*rcd->opstats),
+                               GFP_KERNEL, node_id);
+                       if (!rcd->opstats) {
+                               kfree(rcd);
+                               qib_dev_err(dd,
+                                       "Unable to allocate per ctxt stats buffer\n");
+                               return NULL;
+                       }
+               }
+#endif
                dd->f_init_ctxt(rcd);
 
                /*
@@ -429,6 +458,7 @@ static int loadtime_init(struct qib_devdata *dd)
        dd->intrchk_timer.function = verify_interrupt;
        dd->intrchk_timer.data = (unsigned long) dd;
 
+       ret = qib_cq_init(dd);
 done:
        return ret;
 }
@@ -944,6 +974,10 @@ void qib_free_ctxtdata(struct qib_devdata *dd, struct qib_ctxtdata *rcd)
        vfree(rcd->subctxt_uregbase);
        vfree(rcd->subctxt_rcvegrbuf);
        vfree(rcd->subctxt_rcvhdr_base);
+#ifdef CONFIG_DEBUG_FS
+       kfree(rcd->opstats);
+       rcd->opstats = NULL;
+#endif
        kfree(rcd);
 }
 
@@ -1033,7 +1067,6 @@ done:
        dd->f_set_armlaunch(dd, 1);
 }
 
-
 void qib_free_devdata(struct qib_devdata *dd)
 {
        unsigned long flags;
@@ -1043,6 +1076,9 @@ void qib_free_devdata(struct qib_devdata *dd)
        list_del(&dd->list);
        spin_unlock_irqrestore(&qib_devs_lock, flags);
 
+#ifdef CONFIG_DEBUG_FS
+       qib_dbg_ibdev_exit(&dd->verbs_dev);
+#endif
        ib_dealloc_device(&dd->verbs_dev.ibdev);
 }
 
@@ -1066,6 +1102,10 @@ struct qib_devdata *qib_alloc_devdata(struct pci_dev *pdev, size_t extra)
                goto bail;
        }
 
+#ifdef CONFIG_DEBUG_FS
+       qib_dbg_ibdev_init(&dd->verbs_dev);
+#endif
+
        idr_preload(GFP_KERNEL);
        spin_lock_irqsave(&qib_devs_lock, flags);
 
@@ -1081,6 +1121,9 @@ struct qib_devdata *qib_alloc_devdata(struct pci_dev *pdev, size_t extra)
        if (ret < 0) {
                qib_early_err(&pdev->dev,
                              "Could not allocate unit ID: error %d\n", -ret);
+#ifdef CONFIG_DEBUG_FS
+               qib_dbg_ibdev_exit(&dd->verbs_dev);
+#endif
                ib_dealloc_device(&dd->verbs_dev.ibdev);
                dd = ERR_PTR(ret);
                goto bail;
@@ -1158,6 +1201,35 @@ struct pci_driver qib_driver = {
        .err_handler = &qib_pci_err_handler,
 };
 
+#ifdef CONFIG_INFINIBAND_QIB_DCA
+
+static int qib_notify_dca(struct notifier_block *, unsigned long, void *);
+static struct notifier_block dca_notifier = {
+       .notifier_call  = qib_notify_dca,
+       .next           = NULL,
+       .priority       = 0
+};
+
+static int qib_notify_dca_device(struct device *device, void *data)
+{
+       struct qib_devdata *dd = dev_get_drvdata(device);
+       unsigned long event = *(unsigned long *)data;
+
+       return dd->f_notify_dca(dd, event);
+}
+
+static int qib_notify_dca(struct notifier_block *nb, unsigned long event,
+                                         void *p)
+{
+       int rval;
+
+       rval = driver_for_each_device(&qib_driver.driver, NULL,
+                                     &event, qib_notify_dca_device);
+       return rval ? NOTIFY_BAD : NOTIFY_DONE;
+}
+
+#endif
+
 /*
  * Do all the generic driver unit- and chip-independent memory
  * allocation and initialization.
@@ -1170,22 +1242,22 @@ static int __init qlogic_ib_init(void)
        if (ret)
                goto bail;
 
-       qib_cq_wq = create_singlethread_workqueue("qib_cq");
-       if (!qib_cq_wq) {
-               ret = -ENOMEM;
-               goto bail_dev;
-       }
-
        /*
         * These must be called before the driver is registered with
         * the PCI subsystem.
         */
        idr_init(&qib_unit_table);
 
+#ifdef CONFIG_INFINIBAND_QIB_DCA
+       dca_register_notify(&dca_notifier);
+#endif
+#ifdef CONFIG_DEBUG_FS
+       qib_dbg_init();
+#endif
        ret = pci_register_driver(&qib_driver);
        if (ret < 0) {
                pr_err("Unable to register driver: error %d\n", -ret);
-               goto bail_unit;
+               goto bail_dev;
        }
 
        /* not fatal if it doesn't work */
@@ -1193,10 +1265,14 @@ static int __init qlogic_ib_init(void)
                pr_err("Unable to register ipathfs\n");
        goto bail; /* all OK */
 
-bail_unit:
-       idr_destroy(&qib_unit_table);
-       destroy_workqueue(qib_cq_wq);
 bail_dev:
+#ifdef CONFIG_INFINIBAND_QIB_DCA
+       dca_unregister_notify(&dca_notifier);
+#endif
+#ifdef CONFIG_DEBUG_FS
+       qib_dbg_exit();
+#endif
+       idr_destroy(&qib_unit_table);
        qib_dev_cleanup();
 bail:
        return ret;
@@ -1217,9 +1293,13 @@ static void __exit qlogic_ib_cleanup(void)
                        "Unable to cleanup counter filesystem: error %d\n",
                        -ret);
 
+#ifdef CONFIG_INFINIBAND_QIB_DCA
+       dca_unregister_notify(&dca_notifier);
+#endif
        pci_unregister_driver(&qib_driver);
-
-       destroy_workqueue(qib_cq_wq);
+#ifdef CONFIG_DEBUG_FS
+       qib_dbg_exit();
+#endif
 
        qib_cpulist_count = 0;
        kfree(qib_cpulist);
@@ -1270,7 +1350,7 @@ static void cleanup_device_data(struct qib_devdata *dd)
        if (dd->pageshadow) {
                struct page **tmpp = dd->pageshadow;
                dma_addr_t *tmpd = dd->physshadow;
-               int i, cnt = 0;
+               int i;
 
                for (ctxt = 0; ctxt < dd->cfgctxts; ctxt++) {
                        int ctxt_tidbase = ctxt * dd->rcvtidcnt;
@@ -1283,13 +1363,13 @@ static void cleanup_device_data(struct qib_devdata *dd)
                                               PAGE_SIZE, PCI_DMA_FROMDEVICE);
                                qib_release_user_pages(&tmpp[i], 1);
                                tmpp[i] = NULL;
-                               cnt++;
                        }
                }
 
-               tmpp = dd->pageshadow;
                dd->pageshadow = NULL;
                vfree(tmpp);
+               dd->physshadow = NULL;
+               vfree(tmpd);
        }
 
        /*
@@ -1311,6 +1391,7 @@ static void cleanup_device_data(struct qib_devdata *dd)
        }
        kfree(tmp);
        kfree(dd->boardname);
+       qib_cq_exit(dd);
 }
 
 /*
@@ -1483,6 +1564,7 @@ static void qib_remove_one(struct pci_dev *pdev)
 int qib_create_rcvhdrq(struct qib_devdata *dd, struct qib_ctxtdata *rcd)
 {
        unsigned amt;
+       int old_node_id;
 
        if (!rcd->rcvhdrq) {
                dma_addr_t phys_hdrqtail;
@@ -1492,9 +1574,13 @@ int qib_create_rcvhdrq(struct qib_devdata *dd, struct qib_ctxtdata *rcd)
                            sizeof(u32), PAGE_SIZE);
                gfp_flags = (rcd->ctxt >= dd->first_user_ctxt) ?
                        GFP_USER : GFP_KERNEL;
+
+               old_node_id = dev_to_node(&dd->pcidev->dev);
+               set_dev_node(&dd->pcidev->dev, rcd->node_id);
                rcd->rcvhdrq = dma_alloc_coherent(
                        &dd->pcidev->dev, amt, &rcd->rcvhdrq_phys,
                        gfp_flags | __GFP_COMP);
+               set_dev_node(&dd->pcidev->dev, old_node_id);
 
                if (!rcd->rcvhdrq) {
                        qib_dev_err(dd,
@@ -1510,9 +1596,11 @@ int qib_create_rcvhdrq(struct qib_devdata *dd, struct qib_ctxtdata *rcd)
                }
 
                if (!(dd->flags & QIB_NODMA_RTAIL)) {
+                       set_dev_node(&dd->pcidev->dev, rcd->node_id);
                        rcd->rcvhdrtail_kvaddr = dma_alloc_coherent(
                                &dd->pcidev->dev, PAGE_SIZE, &phys_hdrqtail,
                                gfp_flags);
+                       set_dev_node(&dd->pcidev->dev, old_node_id);
                        if (!rcd->rcvhdrtail_kvaddr)
                                goto bail_free;
                        rcd->rcvhdrqtailaddr_phys = phys_hdrqtail;
@@ -1556,6 +1644,7 @@ int qib_setup_eagerbufs(struct qib_ctxtdata *rcd)
        unsigned e, egrcnt, egrperchunk, chunk, egrsize, egroff;
        size_t size;
        gfp_t gfp_flags;
+       int old_node_id;
 
        /*
         * GFP_USER, but without GFP_FS, so buffer cache can be
@@ -1574,25 +1663,29 @@ int qib_setup_eagerbufs(struct qib_ctxtdata *rcd)
        size = rcd->rcvegrbuf_size;
        if (!rcd->rcvegrbuf) {
                rcd->rcvegrbuf =
-                       kzalloc(chunk * sizeof(rcd->rcvegrbuf[0]),
-                               GFP_KERNEL);
+                       kzalloc_node(chunk * sizeof(rcd->rcvegrbuf[0]),
+                               GFP_KERNEL, rcd->node_id);
                if (!rcd->rcvegrbuf)
                        goto bail;
        }
        if (!rcd->rcvegrbuf_phys) {
                rcd->rcvegrbuf_phys =
-                       kmalloc(chunk * sizeof(rcd->rcvegrbuf_phys[0]),
-                               GFP_KERNEL);
+                       kmalloc_node(chunk * sizeof(rcd->rcvegrbuf_phys[0]),
+                               GFP_KERNEL, rcd->node_id);
                if (!rcd->rcvegrbuf_phys)
                        goto bail_rcvegrbuf;
        }
        for (e = 0; e < rcd->rcvegrbuf_chunks; e++) {
                if (rcd->rcvegrbuf[e])
                        continue;
+
+               old_node_id = dev_to_node(&dd->pcidev->dev);
+               set_dev_node(&dd->pcidev->dev, rcd->node_id);
                rcd->rcvegrbuf[e] =
                        dma_alloc_coherent(&dd->pcidev->dev, size,
                                           &rcd->rcvegrbuf_phys[e],
                                           gfp_flags);
+               set_dev_node(&dd->pcidev->dev, old_node_id);
                if (!rcd->rcvegrbuf[e])
                        goto bail_rcvegrbuf_phys;
        }
index a6a2cc2..3cca55b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012 Intel Corporation.  All rights reserved.
+ * Copyright (c) 2012, 2013 Intel Corporation.  All rights reserved.
  * Copyright (c) 2006 - 2012 QLogic Corporation.  * All rights reserved.
  * Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved.
  *
@@ -35,6 +35,9 @@
 #include <linux/err.h>
 #include <linux/vmalloc.h>
 #include <linux/jhash.h>
+#ifdef CONFIG_DEBUG_FS
+#include <linux/seq_file.h>
+#endif
 
 #include "qib.h"
 
@@ -222,8 +225,8 @@ static void insert_qp(struct qib_ibdev *dev, struct qib_qp *qp)
        unsigned long flags;
        unsigned n = qpn_hash(dev, qp->ibqp.qp_num);
 
-       spin_lock_irqsave(&dev->qpt_lock, flags);
        atomic_inc(&qp->refcount);
+       spin_lock_irqsave(&dev->qpt_lock, flags);
 
        if (qp->ibqp.qp_num == 0)
                rcu_assign_pointer(ibp->qp0, qp);
@@ -235,7 +238,6 @@ static void insert_qp(struct qib_ibdev *dev, struct qib_qp *qp)
        }
 
        spin_unlock_irqrestore(&dev->qpt_lock, flags);
-       synchronize_rcu();
 }
 
 /*
@@ -247,36 +249,39 @@ static void remove_qp(struct qib_ibdev *dev, struct qib_qp *qp)
        struct qib_ibport *ibp = to_iport(qp->ibqp.device, qp->port_num);
        unsigned n = qpn_hash(dev, qp->ibqp.qp_num);
        unsigned long flags;
+       int removed = 1;
 
        spin_lock_irqsave(&dev->qpt_lock, flags);
 
        if (rcu_dereference_protected(ibp->qp0,
                        lockdep_is_held(&dev->qpt_lock)) == qp) {
-               atomic_dec(&qp->refcount);
                rcu_assign_pointer(ibp->qp0, NULL);
        } else if (rcu_dereference_protected(ibp->qp1,
                        lockdep_is_held(&dev->qpt_lock)) == qp) {
-               atomic_dec(&qp->refcount);
                rcu_assign_pointer(ibp->qp1, NULL);
        } else {
                struct qib_qp *q;
                struct qib_qp __rcu **qpp;
 
+               removed = 0;
                qpp = &dev->qp_table[n];
                for (; (q = rcu_dereference_protected(*qpp,
                                lockdep_is_held(&dev->qpt_lock))) != NULL;
                                qpp = &q->next)
                        if (q == qp) {
-                               atomic_dec(&qp->refcount);
                                rcu_assign_pointer(*qpp,
                                        rcu_dereference_protected(qp->next,
                                         lockdep_is_held(&dev->qpt_lock)));
+                               removed = 1;
                                break;
                        }
        }
 
        spin_unlock_irqrestore(&dev->qpt_lock, flags);
-       synchronize_rcu();
+       if (removed) {
+               synchronize_rcu();
+               atomic_dec(&qp->refcount);
+       }
 }
 
 /**
@@ -334,26 +339,25 @@ struct qib_qp *qib_lookup_qpn(struct qib_ibport *ibp, u32 qpn)
 {
        struct qib_qp *qp = NULL;
 
+       rcu_read_lock();
        if (unlikely(qpn <= 1)) {
-               rcu_read_lock();
                if (qpn == 0)
                        qp = rcu_dereference(ibp->qp0);
                else
                        qp = rcu_dereference(ibp->qp1);
+               if (qp)
+                       atomic_inc(&qp->refcount);
        } else {
                struct qib_ibdev *dev = &ppd_from_ibp(ibp)->dd->verbs_dev;
                unsigned n = qpn_hash(dev, qpn);
 
-               rcu_read_lock();
                for (qp = rcu_dereference(dev->qp_table[n]); qp;
                        qp = rcu_dereference(qp->next))
-                       if (qp->ibqp.qp_num == qpn)
+                       if (qp->ibqp.qp_num == qpn) {
+                               atomic_inc(&qp->refcount);
                                break;
+                       }
        }
-       if (qp)
-               if (unlikely(!atomic_inc_not_zero(&qp->refcount)))
-                       qp = NULL;
-
        rcu_read_unlock();
        return qp;
 }
@@ -1286,3 +1290,94 @@ void qib_get_credit(struct qib_qp *qp, u32 aeth)
                }
        }
 }
+
+#ifdef CONFIG_DEBUG_FS
+
+struct qib_qp_iter {
+       struct qib_ibdev *dev;
+       struct qib_qp *qp;
+       int n;
+};
+
+struct qib_qp_iter *qib_qp_iter_init(struct qib_ibdev *dev)
+{
+       struct qib_qp_iter *iter;
+
+       iter = kzalloc(sizeof(*iter), GFP_KERNEL);
+       if (!iter)
+               return NULL;
+
+       iter->dev = dev;
+       if (qib_qp_iter_next(iter)) {
+               kfree(iter);
+               return NULL;
+       }
+
+       return iter;
+}
+
+int qib_qp_iter_next(struct qib_qp_iter *iter)
+{
+       struct qib_ibdev *dev = iter->dev;
+       int n = iter->n;
+       int ret = 1;
+       struct qib_qp *pqp = iter->qp;
+       struct qib_qp *qp;
+
+       rcu_read_lock();
+       for (; n < dev->qp_table_size; n++) {
+               if (pqp)
+                       qp = rcu_dereference(pqp->next);
+               else
+                       qp = rcu_dereference(dev->qp_table[n]);
+               pqp = qp;
+               if (qp) {
+                       if (iter->qp)
+                               atomic_dec(&iter->qp->refcount);
+                       atomic_inc(&qp->refcount);
+                       rcu_read_unlock();
+                       iter->qp = qp;
+                       iter->n = n;
+                       return 0;
+               }
+       }
+       rcu_read_unlock();
+       if (iter->qp)
+               atomic_dec(&iter->qp->refcount);
+       return ret;
+}
+
+static const char * const qp_type_str[] = {
+       "SMI", "GSI", "RC", "UC", "UD",
+};
+
+void qib_qp_iter_print(struct seq_file *s, struct qib_qp_iter *iter)
+{
+       struct qib_swqe *wqe;
+       struct qib_qp *qp = iter->qp;
+
+       wqe = get_swqe_ptr(qp, qp->s_last);
+       seq_printf(s,
+                  "N %d QP%u %s %u %u %u f=%x %u %u %u %u %u PSN %x %x %x %x %x (%u %u %u %u %u %u) QP%u LID %x\n",
+                  iter->n,
+                  qp->ibqp.qp_num,
+                  qp_type_str[qp->ibqp.qp_type],
+                  qp->state,
+                  wqe->wr.opcode,
+                  qp->s_hdrwords,
+                  qp->s_flags,
+                  atomic_read(&qp->s_dma_busy),
+                  !list_empty(&qp->iowait),
+                  qp->timeout,
+                  wqe->ssn,
+                  qp->s_lsn,
+                  qp->s_last_psn,
+                  qp->s_psn, qp->s_next_psn,
+                  qp->s_sending_psn, qp->s_sending_hpsn,
+                  qp->s_last, qp->s_acked, qp->s_cur,
+                  qp->s_tail, qp->s_head, qp->s_size,
+                  qp->remote_qpn,
+                  qp->remote_ah_attr.dlid);
+}
+
+#endif
index 3fc5144..32162d3 100644 (file)
@@ -708,6 +708,62 @@ unlock:
        return ret;
 }
 
+/*
+ * sdma_lock should be acquired before calling this routine
+ */
+void dump_sdma_state(struct qib_pportdata *ppd)
+{
+       struct qib_sdma_desc *descq;
+       struct qib_sdma_txreq *txp, *txpnext;
+       __le64 *descqp;
+       u64 desc[2];
+       dma_addr_t addr;
+       u16 gen, dwlen, dwoffset;
+       u16 head, tail, cnt;
+
+       head = ppd->sdma_descq_head;
+       tail = ppd->sdma_descq_tail;
+       cnt = qib_sdma_descq_freecnt(ppd);
+       descq = ppd->sdma_descq;
+
+       qib_dev_porterr(ppd->dd, ppd->port,
+               "SDMA ppd->sdma_descq_head: %u\n", head);
+       qib_dev_porterr(ppd->dd, ppd->port,
+               "SDMA ppd->sdma_descq_tail: %u\n", tail);
+       qib_dev_porterr(ppd->dd, ppd->port,
+               "SDMA sdma_descq_freecnt: %u\n", cnt);
+
+       /* print info for each entry in the descriptor queue */
+       while (head != tail) {
+               char flags[6] = { 'x', 'x', 'x', 'x', 'x', 0 };
+
+               descqp = &descq[head].qw[0];
+               desc[0] = le64_to_cpu(descqp[0]);
+               desc[1] = le64_to_cpu(descqp[1]);
+               flags[0] = (desc[0] & 1<<15) ? 'I' : '-';
+               flags[1] = (desc[0] & 1<<14) ? 'L' : 'S';
+               flags[2] = (desc[0] & 1<<13) ? 'H' : '-';
+               flags[3] = (desc[0] & 1<<12) ? 'F' : '-';
+               flags[4] = (desc[0] & 1<<11) ? 'L' : '-';
+               addr = (desc[1] << 32) | ((desc[0] >> 32) & 0xfffffffcULL);
+               gen = (desc[0] >> 30) & 3ULL;
+               dwlen = (desc[0] >> 14) & (0x7ffULL << 2);
+               dwoffset = (desc[0] & 0x7ffULL) << 2;
+               qib_dev_porterr(ppd->dd, ppd->port,
+                       "SDMA sdmadesc[%u]: flags:%s addr:0x%016llx gen:%u len:%u bytes offset:%u bytes\n",
+                        head, flags, addr, gen, dwlen, dwoffset);
+               if (++head == ppd->sdma_descq_cnt)
+                       head = 0;
+       }
+
+       /* print dma descriptor indices from the TX requests */
+       list_for_each_entry_safe(txp, txpnext, &ppd->sdma_activelist,
+                                list)
+               qib_dev_porterr(ppd->dd, ppd->port,
+                       "SDMA txp->start_idx: %u txp->next_descq_idx: %u\n",
+                       txp->start_idx, txp->next_descq_idx);
+}
+
 void qib_sdma_process_event(struct qib_pportdata *ppd,
        enum qib_sdma_events event)
 {
index 904c384..092b0bb 100644 (file)
@@ -645,9 +645,11 @@ void qib_ib_rcv(struct qib_ctxtdata *rcd, void *rhdr, void *data, u32 tlen)
        } else
                goto drop;
 
-       opcode = be32_to_cpu(ohdr->bth[0]) >> 24;
-       ibp->opstats[opcode & 0x7f].n_bytes += tlen;
-       ibp->opstats[opcode & 0x7f].n_packets++;
+       opcode = (be32_to_cpu(ohdr->bth[0]) >> 24) & 0x7f;
+#ifdef CONFIG_DEBUG_FS
+       rcd->opstats->stats[opcode].n_bytes += tlen;
+       rcd->opstats->stats[opcode].n_packets++;
+#endif
 
        /* Get the destination QP number. */
        qp_num = be32_to_cpu(ohdr->bth[1]) & QIB_QPN_MASK;
index aff8b2c..012e2c7 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012 Intel Corporation.  All rights reserved.
+ * Copyright (c) 2012, 2013 Intel Corporation.  All rights reserved.
  * Copyright (c) 2006 - 2012 QLogic Corporation. All rights reserved.
  * Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved.
  *
@@ -41,6 +41,7 @@
 #include <linux/interrupt.h>
 #include <linux/kref.h>
 #include <linux/workqueue.h>
+#include <linux/kthread.h>
 #include <linux/completion.h>
 #include <rdma/ib_pack.h>
 #include <rdma/ib_user_verbs.h>
@@ -267,7 +268,8 @@ struct qib_cq_wc {
  */
 struct qib_cq {
        struct ib_cq ibcq;
-       struct work_struct comptask;
+       struct kthread_work comptask;
+       struct qib_devdata *dd;
        spinlock_t lock; /* protect changes in this struct */
        u8 notify;
        u8 triggered;
@@ -658,6 +660,10 @@ struct qib_opcode_stats {
        u64 n_bytes;            /* total number of bytes */
 };
 
+struct qib_opcode_stats_perctx {
+       struct qib_opcode_stats stats[128];
+};
+
 struct qib_ibport {
        struct qib_qp __rcu *qp0;
        struct qib_qp __rcu *qp1;
@@ -724,7 +730,6 @@ struct qib_ibport {
        u8 vl_high_limit;
        u8 sl_to_vl[16];
 
-       struct qib_opcode_stats opstats[128];
 };
 
 
@@ -768,6 +773,10 @@ struct qib_ibdev {
        spinlock_t n_srqs_lock;
        u32 n_mcast_grps_allocated; /* number of mcast groups allocated */
        spinlock_t n_mcast_grps_lock;
+#ifdef CONFIG_DEBUG_FS
+       /* per HCA debugfs */
+       struct dentry *qib_ibdev_dbg;
+#endif
 };
 
 struct qib_verbs_counters {
@@ -832,8 +841,6 @@ static inline int qib_send_ok(struct qib_qp *qp)
                 !(qp->s_flags & QIB_S_ANY_WAIT_SEND));
 }
 
-extern struct workqueue_struct *qib_cq_wq;
-
 /*
  * This must be called with s_lock held.
  */
@@ -910,6 +917,18 @@ void qib_init_qpn_table(struct qib_devdata *dd, struct qib_qpn_table *qpt);
 
 void qib_free_qpn_table(struct qib_qpn_table *qpt);
 
+#ifdef CONFIG_DEBUG_FS
+
+struct qib_qp_iter;
+
+struct qib_qp_iter *qib_qp_iter_init(struct qib_ibdev *dev);
+
+int qib_qp_iter_next(struct qib_qp_iter *iter);
+
+void qib_qp_iter_print(struct seq_file *s, struct qib_qp_iter *iter);
+
+#endif
+
 void qib_get_credit(struct qib_qp *qp, u32 aeth);
 
 unsigned qib_pkt_delay(u32 plen, u8 snd_mult, u8 rcv_mult);
@@ -972,6 +991,10 @@ int qib_query_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr);
 
 int qib_destroy_srq(struct ib_srq *ibsrq);
 
+int qib_cq_init(struct qib_devdata *dd);
+
+void qib_cq_exit(struct qib_devdata *dd);
+
 void qib_cq_enter(struct qib_cq *cq, struct ib_wc *entry, int sig);
 
 int qib_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry);
index 2693129..3f62041 100644 (file)
@@ -388,6 +388,7 @@ isert_connect_request(struct rdma_cm_id *cma_id, struct rdma_cm_event *event)
        init_waitqueue_head(&isert_conn->conn_wait_comp_err);
        kref_init(&isert_conn->conn_kref);
        kref_get(&isert_conn->conn_kref);
+       mutex_init(&isert_conn->conn_mutex);
 
        cma_id->context = isert_conn;
        isert_conn->conn_cm_id = cma_id;
@@ -540,15 +541,32 @@ isert_disconnect_work(struct work_struct *work)
                                struct isert_conn, conn_logout_work);
 
        pr_debug("isert_disconnect_work(): >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
-
+       mutex_lock(&isert_conn->conn_mutex);
        isert_conn->state = ISER_CONN_DOWN;
 
        if (isert_conn->post_recv_buf_count == 0 &&
            atomic_read(&isert_conn->post_send_buf_count) == 0) {
                pr_debug("Calling wake_up(&isert_conn->conn_wait);\n");
-               wake_up(&isert_conn->conn_wait);
+               mutex_unlock(&isert_conn->conn_mutex);
+               goto wake_up;
+       }
+       if (!isert_conn->conn_cm_id) {
+               mutex_unlock(&isert_conn->conn_mutex);
+               isert_put_conn(isert_conn);
+               return;
        }
+       if (!isert_conn->logout_posted) {
+               pr_debug("Calling rdma_disconnect for !logout_posted from"
+                        " isert_disconnect_work\n");
+               rdma_disconnect(isert_conn->conn_cm_id);
+               mutex_unlock(&isert_conn->conn_mutex);
+               iscsit_cause_connection_reinstatement(isert_conn->conn, 0);
+               goto wake_up;
+       }
+       mutex_unlock(&isert_conn->conn_mutex);
 
+wake_up:
+       wake_up(&isert_conn->conn_wait);
        isert_put_conn(isert_conn);
 }
 
@@ -934,16 +952,11 @@ isert_handle_scsi_cmd(struct isert_conn *isert_conn,
        }
 
 sequence_cmd:
-       rc = iscsit_sequence_cmd(conn, cmd, hdr->cmdsn);
+       rc = iscsit_sequence_cmd(conn, cmd, buf, hdr->cmdsn);
 
        if (!rc && dump_payload == false && unsol_data)
                iscsit_set_unsoliticed_dataout(cmd);
 
-       if (rc == CMDSN_ERROR_CANNOT_RECOVER)
-               return iscsit_add_reject_from_cmd(
-                          ISCSI_REASON_PROTOCOL_ERROR,
-                          1, 0, (unsigned char *)hdr, cmd);
-
        return 0;
 }
 
@@ -1001,17 +1014,71 @@ isert_handle_iscsi_dataout(struct isert_conn *isert_conn,
 }
 
 static int
+isert_handle_nop_out(struct isert_conn *isert_conn, struct isert_cmd *isert_cmd,
+                    struct iser_rx_desc *rx_desc, unsigned char *buf)
+{
+       struct iscsi_cmd *cmd = &isert_cmd->iscsi_cmd;
+       struct iscsi_conn *conn = isert_conn->conn;
+       struct iscsi_nopout *hdr = (struct iscsi_nopout *)buf;
+       int rc;
+
+       rc = iscsit_setup_nop_out(conn, cmd, hdr);
+       if (rc < 0)
+               return rc;
+       /*
+        * FIXME: Add support for NOPOUT payload using unsolicited RDMA payload
+        */
+
+       return iscsit_process_nop_out(conn, cmd, hdr);
+}
+
+static int
+isert_handle_text_cmd(struct isert_conn *isert_conn, struct isert_cmd *isert_cmd,
+                     struct iser_rx_desc *rx_desc, struct iscsi_text *hdr)
+{
+       struct iscsi_cmd *cmd = &isert_cmd->iscsi_cmd;
+       struct iscsi_conn *conn = isert_conn->conn;
+       u32 payload_length = ntoh24(hdr->dlength);
+       int rc;
+       unsigned char *text_in;
+
+       rc = iscsit_setup_text_cmd(conn, cmd, hdr);
+       if (rc < 0)
+               return rc;
+
+       text_in = kzalloc(payload_length, GFP_KERNEL);
+       if (!text_in) {
+               pr_err("Unable to allocate text_in of payload_length: %u\n",
+                      payload_length);
+               return -ENOMEM;
+       }
+       cmd->text_in_ptr = text_in;
+
+       memcpy(cmd->text_in_ptr, &rx_desc->data[0], payload_length);
+
+       return iscsit_process_text_cmd(conn, cmd, hdr);
+}
+
+static int
 isert_rx_opcode(struct isert_conn *isert_conn, struct iser_rx_desc *rx_desc,
                uint32_t read_stag, uint64_t read_va,
                uint32_t write_stag, uint64_t write_va)
 {
        struct iscsi_hdr *hdr = &rx_desc->iscsi_header;
        struct iscsi_conn *conn = isert_conn->conn;
+       struct iscsi_session *sess = conn->sess;
        struct iscsi_cmd *cmd;
        struct isert_cmd *isert_cmd;
        int ret = -EINVAL;
        u8 opcode = (hdr->opcode & ISCSI_OPCODE_MASK);
 
+       if (sess->sess_ops->SessionType &&
+          (!(opcode & ISCSI_OP_TEXT) || !(opcode & ISCSI_OP_LOGOUT))) {
+               pr_err("Got illegal opcode: 0x%02x in SessionType=Discovery,"
+                      " ignoring\n", opcode);
+               return 0;
+       }
+
        switch (opcode) {
        case ISCSI_OP_SCSI_CMD:
                cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);
@@ -1032,7 +1099,9 @@ isert_rx_opcode(struct isert_conn *isert_conn, struct iser_rx_desc *rx_desc,
                if (!cmd)
                        break;
 
-               ret = iscsit_handle_nop_out(conn, cmd, (unsigned char *)hdr);
+               isert_cmd = container_of(cmd, struct isert_cmd, iscsi_cmd);
+               ret = isert_handle_nop_out(isert_conn, isert_cmd,
+                                          rx_desc, (unsigned char *)hdr);
                break;
        case ISCSI_OP_SCSI_DATA_OUT:
                ret = isert_handle_iscsi_dataout(isert_conn, rx_desc,
@@ -1057,6 +1126,15 @@ isert_rx_opcode(struct isert_conn *isert_conn, struct iser_rx_desc *rx_desc,
                                                    SECONDS_FOR_LOGOUT_COMP *
                                                    HZ);
                break;
+       case ISCSI_OP_TEXT:
+               cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);
+               if (!cmd)
+                       break;
+
+               isert_cmd = container_of(cmd, struct isert_cmd, iscsi_cmd);
+               ret = isert_handle_text_cmd(isert_conn, isert_cmd,
+                                           rx_desc, (struct iscsi_text *)hdr);
+               break;
        default:
                pr_err("Got unknown iSCSI OpCode: 0x%02x\n", opcode);
                dump_stack();
@@ -1184,14 +1262,12 @@ isert_put_cmd(struct isert_cmd *isert_cmd)
 {
        struct iscsi_cmd *cmd = &isert_cmd->iscsi_cmd;
        struct isert_conn *isert_conn = isert_cmd->conn;
-       struct iscsi_conn *conn;
+       struct iscsi_conn *conn = isert_conn->conn;
 
        pr_debug("Entering isert_put_cmd: %p\n", isert_cmd);
 
        switch (cmd->iscsi_opcode) {
        case ISCSI_OP_SCSI_CMD:
-               conn = isert_conn->conn;
-
                spin_lock_bh(&conn->cmd_lock);
                if (!list_empty(&cmd->i_conn_node))
                        list_del(&cmd->i_conn_node);
@@ -1201,16 +1277,19 @@ isert_put_cmd(struct isert_cmd *isert_cmd)
                        iscsit_stop_dataout_timer(cmd);
 
                isert_unmap_cmd(isert_cmd, isert_conn);
-               /*
-                * Fall-through
-                */
+               transport_generic_free_cmd(&cmd->se_cmd, 0);
+               break;
        case ISCSI_OP_SCSI_TMFUNC:
+               spin_lock_bh(&conn->cmd_lock);
+               if (!list_empty(&cmd->i_conn_node))
+                       list_del(&cmd->i_conn_node);
+               spin_unlock_bh(&conn->cmd_lock);
+
                transport_generic_free_cmd(&cmd->se_cmd, 0);
                break;
        case ISCSI_OP_REJECT:
        case ISCSI_OP_NOOP_OUT:
-               conn = isert_conn->conn;
-
+       case ISCSI_OP_TEXT:
                spin_lock_bh(&conn->cmd_lock);
                if (!list_empty(&cmd->i_conn_node))
                        list_del(&cmd->i_conn_node);
@@ -1222,6 +1301,9 @@ isert_put_cmd(struct isert_cmd *isert_cmd)
                 * associated cmd->se_cmd needs to be released.
                 */
                if (cmd->se_cmd.se_tfo != NULL) {
+                       pr_debug("Calling transport_generic_free_cmd from"
+                                " isert_put_cmd for 0x%02x\n",
+                                cmd->iscsi_opcode);
                        transport_generic_free_cmd(&cmd->se_cmd, 0);
                        break;
                }
@@ -1249,11 +1331,11 @@ static void
 isert_completion_put(struct iser_tx_desc *tx_desc, struct isert_cmd *isert_cmd,
                     struct ib_device *ib_dev)
 {
-       if (isert_cmd->sense_buf_dma != 0) {
-               pr_debug("Calling ib_dma_unmap_single for isert_cmd->sense_buf_dma\n");
-               ib_dma_unmap_single(ib_dev, isert_cmd->sense_buf_dma,
-                                   isert_cmd->sense_buf_len, DMA_TO_DEVICE);
-               isert_cmd->sense_buf_dma = 0;
+       if (isert_cmd->pdu_buf_dma != 0) {
+               pr_debug("Calling ib_dma_unmap_single for isert_cmd->pdu_buf_dma\n");
+               ib_dma_unmap_single(ib_dev, isert_cmd->pdu_buf_dma,
+                                   isert_cmd->pdu_buf_len, DMA_TO_DEVICE);
+               isert_cmd->pdu_buf_dma = 0;
        }
 
        isert_unmap_tx_desc(tx_desc, ib_dev);
@@ -1318,8 +1400,8 @@ isert_do_control_comp(struct work_struct *work)
                atomic_dec(&isert_conn->post_send_buf_count);
 
                cmd->i_state = ISTATE_SENT_STATUS;
-               complete(&cmd->reject_comp);
                isert_completion_put(&isert_cmd->tx_desc, isert_cmd, ib_dev);
+               break;
        case ISTATE_SEND_LOGOUTRSP:
                pr_debug("Calling iscsit_logout_post_handler >>>>>>>>>>>>>>\n");
                /*
@@ -1329,6 +1411,11 @@ isert_do_control_comp(struct work_struct *work)
                isert_conn->logout_posted = true;
                iscsit_logout_post_handler(cmd, cmd->conn);
                break;
+       case ISTATE_SEND_TEXTRSP:
+               atomic_dec(&isert_conn->post_send_buf_count);
+               cmd->i_state = ISTATE_SENT_STATUS;
+               isert_completion_put(&isert_cmd->tx_desc, isert_cmd, ib_dev);
+               break;
        default:
                pr_err("Unknown do_control_comp i_state %d\n", cmd->i_state);
                dump_stack();
@@ -1345,7 +1432,9 @@ isert_response_completion(struct iser_tx_desc *tx_desc,
        struct iscsi_cmd *cmd = &isert_cmd->iscsi_cmd;
 
        if (cmd->i_state == ISTATE_SEND_TASKMGTRSP ||
-           cmd->i_state == ISTATE_SEND_LOGOUTRSP) {
+           cmd->i_state == ISTATE_SEND_LOGOUTRSP ||
+           cmd->i_state == ISTATE_SEND_REJECT ||
+           cmd->i_state == ISTATE_SEND_TEXTRSP) {
                isert_unmap_tx_desc(tx_desc, ib_dev);
 
                INIT_WORK(&isert_cmd->comp_work, isert_do_control_comp);
@@ -1419,7 +1508,11 @@ isert_cq_comp_err(struct iser_tx_desc *tx_desc, struct isert_conn *isert_conn)
                pr_debug("isert_cq_comp_err >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
                pr_debug("Calling wake_up from isert_cq_comp_err\n");
 
-               isert_conn->state = ISER_CONN_TERMINATING;
+               mutex_lock(&isert_conn->conn_mutex);
+               if (isert_conn->state != ISER_CONN_DOWN)
+                       isert_conn->state = ISER_CONN_TERMINATING;
+               mutex_unlock(&isert_conn->conn_mutex);
+
                wake_up(&isert_conn->conn_wait_comp_err);
        }
 }
@@ -1445,6 +1538,7 @@ isert_cq_tx_work(struct work_struct *work)
                } else {
                        pr_debug("TX wc.status != IB_WC_SUCCESS >>>>>>>>>>>>>>\n");
                        pr_debug("TX wc.status: 0x%08x\n", wc.status);
+                       pr_debug("TX wc.vendor_err: 0x%08x\n", wc.vendor_err);
                        atomic_dec(&isert_conn->post_send_buf_count);
                        isert_cq_comp_err(tx_desc, isert_conn);
                }
@@ -1484,9 +1578,11 @@ isert_cq_rx_work(struct work_struct *work)
                        isert_rx_completion(rx_desc, isert_conn, xfer_len);
                } else {
                        pr_debug("RX wc.status != IB_WC_SUCCESS >>>>>>>>>>>>>>\n");
-                       if (wc.status != IB_WC_WR_FLUSH_ERR)
+                       if (wc.status != IB_WC_WR_FLUSH_ERR) {
                                pr_debug("RX wc.status: 0x%08x\n", wc.status);
-
+                               pr_debug("RX wc.vendor_err: 0x%08x\n",
+                                        wc.vendor_err);
+                       }
                        isert_conn->post_recv_buf_count--;
                        isert_cq_comp_err(NULL, isert_conn);
                }
@@ -1543,7 +1639,7 @@ isert_put_response(struct iscsi_conn *conn, struct iscsi_cmd *cmd)
            (cmd->se_cmd.se_cmd_flags & SCF_EMULATED_TASK_SENSE))) {
                struct ib_device *ib_dev = isert_conn->conn_cm_id->device;
                struct ib_sge *tx_dsg = &isert_cmd->tx_desc.tx_sg[1];
-               u32 padding, sense_len;
+               u32 padding, pdu_len;
 
                put_unaligned_be16(cmd->se_cmd.scsi_sense_length,
                                   cmd->sense_buffer);
@@ -1551,15 +1647,15 @@ isert_put_response(struct iscsi_conn *conn, struct iscsi_cmd *cmd)
 
                padding = -(cmd->se_cmd.scsi_sense_length) & 3;
                hton24(hdr->dlength, (u32)cmd->se_cmd.scsi_sense_length);
-               sense_len = cmd->se_cmd.scsi_sense_length + padding;
+               pdu_len = cmd->se_cmd.scsi_sense_length + padding;
 
-               isert_cmd->sense_buf_dma = ib_dma_map_single(ib_dev,
-                               (void *)cmd->sense_buffer, sense_len,
+               isert_cmd->pdu_buf_dma = ib_dma_map_single(ib_dev,
+                               (void *)cmd->sense_buffer, pdu_len,
                                DMA_TO_DEVICE);
 
-               isert_cmd->sense_buf_len = sense_len;
-               tx_dsg->addr    = isert_cmd->sense_buf_dma;
-               tx_dsg->length  = sense_len;
+               isert_cmd->pdu_buf_len = pdu_len;
+               tx_dsg->addr    = isert_cmd->pdu_buf_dma;
+               tx_dsg->length  = pdu_len;
                tx_dsg->lkey    = isert_conn->conn_mr->lkey;
                isert_cmd->tx_desc.num_sge = 2;
        }
@@ -1637,11 +1733,25 @@ isert_put_reject(struct iscsi_cmd *cmd, struct iscsi_conn *conn)
                                struct isert_cmd, iscsi_cmd);
        struct isert_conn *isert_conn = (struct isert_conn *)conn->context;
        struct ib_send_wr *send_wr = &isert_cmd->tx_desc.send_wr;
+       struct ib_device *ib_dev = isert_conn->conn_cm_id->device;
+       struct ib_sge *tx_dsg = &isert_cmd->tx_desc.tx_sg[1];
+       struct iscsi_reject *hdr =
+               (struct iscsi_reject *)&isert_cmd->tx_desc.iscsi_header;
 
        isert_create_send_desc(isert_conn, isert_cmd, &isert_cmd->tx_desc);
-       iscsit_build_reject(cmd, conn, (struct iscsi_reject *)
-                               &isert_cmd->tx_desc.iscsi_header);
+       iscsit_build_reject(cmd, conn, hdr);
        isert_init_tx_hdrs(isert_conn, &isert_cmd->tx_desc);
+
+       hton24(hdr->dlength, ISCSI_HDR_LEN);
+       isert_cmd->pdu_buf_dma = ib_dma_map_single(ib_dev,
+                       (void *)cmd->buf_ptr, ISCSI_HDR_LEN,
+                       DMA_TO_DEVICE);
+       isert_cmd->pdu_buf_len = ISCSI_HDR_LEN;
+       tx_dsg->addr    = isert_cmd->pdu_buf_dma;
+       tx_dsg->length  = ISCSI_HDR_LEN;
+       tx_dsg->lkey    = isert_conn->conn_mr->lkey;
+       isert_cmd->tx_desc.num_sge = 2;
+
        isert_init_send_wr(isert_cmd, send_wr);
 
        pr_debug("Posting Reject IB_WR_SEND >>>>>>>>>>>>>>>>>>>>>>\n");
@@ -1650,6 +1760,47 @@ isert_put_reject(struct iscsi_cmd *cmd, struct iscsi_conn *conn)
 }
 
 static int
+isert_put_text_rsp(struct iscsi_cmd *cmd, struct iscsi_conn *conn)
+{
+       struct isert_cmd *isert_cmd = container_of(cmd,
+                               struct isert_cmd, iscsi_cmd);
+       struct isert_conn *isert_conn = (struct isert_conn *)conn->context;
+       struct ib_send_wr *send_wr = &isert_cmd->tx_desc.send_wr;
+       struct iscsi_text_rsp *hdr =
+               (struct iscsi_text_rsp *)&isert_cmd->tx_desc.iscsi_header;
+       u32 txt_rsp_len;
+       int rc;
+
+       isert_create_send_desc(isert_conn, isert_cmd, &isert_cmd->tx_desc);
+       rc = iscsit_build_text_rsp(cmd, conn, hdr);
+       if (rc < 0)
+               return rc;
+
+       txt_rsp_len = rc;
+       isert_init_tx_hdrs(isert_conn, &isert_cmd->tx_desc);
+
+       if (txt_rsp_len) {
+               struct ib_device *ib_dev = isert_conn->conn_cm_id->device;
+               struct ib_sge *tx_dsg = &isert_cmd->tx_desc.tx_sg[1];
+               void *txt_rsp_buf = cmd->buf_ptr;
+
+               isert_cmd->pdu_buf_dma = ib_dma_map_single(ib_dev,
+                               txt_rsp_buf, txt_rsp_len, DMA_TO_DEVICE);
+
+               isert_cmd->pdu_buf_len = txt_rsp_len;
+               tx_dsg->addr    = isert_cmd->pdu_buf_dma;
+               tx_dsg->length  = txt_rsp_len;
+               tx_dsg->lkey    = isert_conn->conn_mr->lkey;
+               isert_cmd->tx_desc.num_sge = 2;
+       }
+       isert_init_send_wr(isert_cmd, send_wr);
+
+       pr_debug("Posting Text Response IB_WR_SEND >>>>>>>>>>>>>>>>>>>>>>\n");
+
+       return isert_post_response(isert_conn, isert_cmd);
+}
+
+static int
 isert_build_rdma_wr(struct isert_conn *isert_conn, struct isert_cmd *isert_cmd,
                    struct ib_sge *ib_sge, struct ib_send_wr *send_wr,
                    u32 data_left, u32 offset)
@@ -1947,6 +2098,9 @@ isert_response_queue(struct iscsi_conn *conn, struct iscsi_cmd *cmd, int state)
        case ISTATE_SEND_REJECT:
                ret = isert_put_reject(cmd, conn);
                break;
+       case ISTATE_SEND_TEXTRSP:
+               ret = isert_put_text_rsp(cmd, conn);
+               break;
        case ISTATE_SEND_STATUS:
                /*
                 * Special case for sending non GOOD SCSI status from TX thread
@@ -2175,6 +2329,17 @@ isert_free_np(struct iscsi_np *np)
        kfree(isert_np);
 }
 
+static int isert_check_state(struct isert_conn *isert_conn, int state)
+{
+       int ret;
+
+       mutex_lock(&isert_conn->conn_mutex);
+       ret = (isert_conn->state == state);
+       mutex_unlock(&isert_conn->conn_mutex);
+
+       return ret;
+}
+
 static void isert_free_conn(struct iscsi_conn *conn)
 {
        struct isert_conn *isert_conn = conn->context;
@@ -2184,26 +2349,43 @@ static void isert_free_conn(struct iscsi_conn *conn)
         * Decrement post_send_buf_count for special case when called
         * from isert_do_control_comp() -> iscsit_logout_post_handler()
         */
+       mutex_lock(&isert_conn->conn_mutex);
        if (isert_conn->logout_posted)
                atomic_dec(&isert_conn->post_send_buf_count);
 
-       if (isert_conn->conn_cm_id)
+       if (isert_conn->conn_cm_id && isert_conn->state != ISER_CONN_DOWN) {
+               pr_debug("Calling rdma_disconnect from isert_free_conn\n");
                rdma_disconnect(isert_conn->conn_cm_id);
+       }
        /*
         * Only wait for conn_wait_comp_err if the isert_conn made it
         * into full feature phase..
         */
-       if (isert_conn->state > ISER_CONN_INIT) {
+       if (isert_conn->state == ISER_CONN_UP) {
                pr_debug("isert_free_conn: Before wait_event comp_err %d\n",
                         isert_conn->state);
+               mutex_unlock(&isert_conn->conn_mutex);
+
                wait_event(isert_conn->conn_wait_comp_err,
-                          isert_conn->state == ISER_CONN_TERMINATING);
-               pr_debug("isert_free_conn: After wait_event #1 >>>>>>>>>>>>\n");
+                         (isert_check_state(isert_conn, ISER_CONN_TERMINATING)));
+
+               wait_event(isert_conn->conn_wait,
+                         (isert_check_state(isert_conn, ISER_CONN_DOWN)));
+
+               isert_put_conn(isert_conn);
+               return;
+       }
+       if (isert_conn->state == ISER_CONN_INIT) {
+               mutex_unlock(&isert_conn->conn_mutex);
+               isert_put_conn(isert_conn);
+               return;
        }
+       pr_debug("isert_free_conn: wait_event conn_wait %d\n",
+                isert_conn->state);
+       mutex_unlock(&isert_conn->conn_mutex);
 
-       pr_debug("isert_free_conn: wait_event conn_wait %d\n", isert_conn->state);
-       wait_event(isert_conn->conn_wait, isert_conn->state == ISER_CONN_DOWN);
-       pr_debug("isert_free_conn: After wait_event #2 >>>>>>>>>>>>>>>>>>>>\n");
+       wait_event(isert_conn->conn_wait,
+                 (isert_check_state(isert_conn, ISER_CONN_DOWN)));
 
        isert_put_conn(isert_conn);
 }
index b104f4c..191117b 100644 (file)
@@ -61,8 +61,8 @@ struct isert_cmd {
        uint32_t                write_stag;
        uint64_t                read_va;
        uint64_t                write_va;
-       u64                     sense_buf_dma;
-       u32                     sense_buf_len;
+       u64                     pdu_buf_dma;
+       u32                     pdu_buf_len;
        u32                     read_va_off;
        u32                     write_va_off;
        u32                     rdma_wr_num;
@@ -102,6 +102,7 @@ struct isert_conn {
        struct ib_qp            *conn_qp;
        struct isert_device     *conn_device;
        struct work_struct      conn_logout_work;
+       struct mutex            conn_mutex;
        wait_queue_head_t       conn_wait;
        wait_queue_head_t       conn_wait_comp_err;
        struct kref             conn_kref;
index 7ccf328..f93baf8 100644 (file)
@@ -53,8 +53,8 @@
 
 #define DRV_NAME       "ib_srp"
 #define PFX            DRV_NAME ": "
-#define DRV_VERSION    "0.2"
-#define DRV_RELDATE    "November 1, 2005"
+#define DRV_VERSION    "1.0"
+#define DRV_RELDATE    "July 1, 2013"
 
 MODULE_AUTHOR("Roland Dreier");
 MODULE_DESCRIPTION("InfiniBand SCSI RDMA Protocol initiator "
@@ -231,14 +231,16 @@ static int srp_create_target_ib(struct srp_target_port *target)
                return -ENOMEM;
 
        recv_cq = ib_create_cq(target->srp_host->srp_dev->dev,
-                              srp_recv_completion, NULL, target, SRP_RQ_SIZE, 0);
+                              srp_recv_completion, NULL, target, SRP_RQ_SIZE,
+                              target->comp_vector);
        if (IS_ERR(recv_cq)) {
                ret = PTR_ERR(recv_cq);
                goto err;
        }
 
        send_cq = ib_create_cq(target->srp_host->srp_dev->dev,
-                              srp_send_completion, NULL, target, SRP_SQ_SIZE, 0);
+                              srp_send_completion, NULL, target, SRP_SQ_SIZE,
+                              target->comp_vector);
        if (IS_ERR(send_cq)) {
                ret = PTR_ERR(send_cq);
                goto err_recv_cq;
@@ -542,11 +544,11 @@ static void srp_remove_work(struct work_struct *work)
 
        WARN_ON_ONCE(target->state != SRP_TARGET_REMOVED);
 
+       srp_remove_target(target);
+
        spin_lock(&target->srp_host->target_lock);
        list_del(&target->list);
        spin_unlock(&target->srp_host->target_lock);
-
-       srp_remove_target(target);
 }
 
 static void srp_rport_delete(struct srp_rport *rport)
@@ -1744,18 +1746,24 @@ static int srp_abort(struct scsi_cmnd *scmnd)
 {
        struct srp_target_port *target = host_to_target(scmnd->device->host);
        struct srp_request *req = (struct srp_request *) scmnd->host_scribble;
+       int ret;
 
        shost_printk(KERN_ERR, target->scsi_host, "SRP abort called\n");
 
        if (!req || !srp_claim_req(target, req, scmnd))
                return FAILED;
-       srp_send_tsk_mgmt(target, req->index, scmnd->device->lun,
-                         SRP_TSK_ABORT_TASK);
+       if (srp_send_tsk_mgmt(target, req->index, scmnd->device->lun,
+                             SRP_TSK_ABORT_TASK) == 0)
+               ret = SUCCESS;
+       else if (target->transport_offline)
+               ret = FAST_IO_FAIL;
+       else
+               ret = FAILED;
        srp_free_req(target, req, scmnd, 0);
        scmnd->result = DID_ABORT << 16;
        scmnd->scsi_done(scmnd);
 
-       return SUCCESS;
+       return ret;
 }
 
 static int srp_reset_device(struct scsi_cmnd *scmnd)
@@ -1891,6 +1899,14 @@ static ssize_t show_local_ib_device(struct device *dev,
        return sprintf(buf, "%s\n", target->srp_host->srp_dev->dev->name);
 }
 
+static ssize_t show_comp_vector(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       struct srp_target_port *target = host_to_target(class_to_shost(dev));
+
+       return sprintf(buf, "%d\n", target->comp_vector);
+}
+
 static ssize_t show_cmd_sg_entries(struct device *dev,
                                   struct device_attribute *attr, char *buf)
 {
@@ -1917,6 +1933,7 @@ static DEVICE_ATTR(req_lim,         S_IRUGO, show_req_lim,         NULL);
 static DEVICE_ATTR(zero_req_lim,    S_IRUGO, show_zero_req_lim,           NULL);
 static DEVICE_ATTR(local_ib_port,   S_IRUGO, show_local_ib_port,   NULL);
 static DEVICE_ATTR(local_ib_device, S_IRUGO, show_local_ib_device, NULL);
+static DEVICE_ATTR(comp_vector,     S_IRUGO, show_comp_vector,     NULL);
 static DEVICE_ATTR(cmd_sg_entries,  S_IRUGO, show_cmd_sg_entries,  NULL);
 static DEVICE_ATTR(allow_ext_sg,    S_IRUGO, show_allow_ext_sg,    NULL);
 
@@ -1931,6 +1948,7 @@ static struct device_attribute *srp_host_attrs[] = {
        &dev_attr_zero_req_lim,
        &dev_attr_local_ib_port,
        &dev_attr_local_ib_device,
+       &dev_attr_comp_vector,
        &dev_attr_cmd_sg_entries,
        &dev_attr_allow_ext_sg,
        NULL
@@ -1946,6 +1964,7 @@ static struct scsi_host_template srp_template = {
        .eh_abort_handler               = srp_abort,
        .eh_device_reset_handler        = srp_reset_device,
        .eh_host_reset_handler          = srp_reset_host,
+       .skip_settle_delay              = true,
        .sg_tablesize                   = SRP_DEF_SG_TABLESIZE,
        .can_queue                      = SRP_CMD_SQ_SIZE,
        .this_id                        = -1,
@@ -2001,6 +2020,36 @@ static struct class srp_class = {
        .dev_release = srp_release_dev
 };
 
+/**
+ * srp_conn_unique() - check whether the connection to a target is unique
+ */
+static bool srp_conn_unique(struct srp_host *host,
+                           struct srp_target_port *target)
+{
+       struct srp_target_port *t;
+       bool ret = false;
+
+       if (target->state == SRP_TARGET_REMOVED)
+               goto out;
+
+       ret = true;
+
+       spin_lock(&host->target_lock);
+       list_for_each_entry(t, &host->target_list, list) {
+               if (t != target &&
+                   target->id_ext == t->id_ext &&
+                   target->ioc_guid == t->ioc_guid &&
+                   target->initiator_ext == t->initiator_ext) {
+                       ret = false;
+                       break;
+               }
+       }
+       spin_unlock(&host->target_lock);
+
+out:
+       return ret;
+}
+
 /*
  * Target ports are added by writing
  *
@@ -2023,6 +2072,7 @@ enum {
        SRP_OPT_CMD_SG_ENTRIES  = 1 << 9,
        SRP_OPT_ALLOW_EXT_SG    = 1 << 10,
        SRP_OPT_SG_TABLESIZE    = 1 << 11,
+       SRP_OPT_COMP_VECTOR     = 1 << 12,
        SRP_OPT_ALL             = (SRP_OPT_ID_EXT       |
                                   SRP_OPT_IOC_GUID     |
                                   SRP_OPT_DGID         |
@@ -2043,6 +2093,7 @@ static const match_table_t srp_opt_tokens = {
        { SRP_OPT_CMD_SG_ENTRIES,       "cmd_sg_entries=%u"     },
        { SRP_OPT_ALLOW_EXT_SG,         "allow_ext_sg=%u"       },
        { SRP_OPT_SG_TABLESIZE,         "sg_tablesize=%u"       },
+       { SRP_OPT_COMP_VECTOR,          "comp_vector=%u"        },
        { SRP_OPT_ERR,                  NULL                    }
 };
 
@@ -2198,6 +2249,14 @@ static int srp_parse_options(const char *buf, struct srp_target_port *target)
                        target->sg_tablesize = token;
                        break;
 
+               case SRP_OPT_COMP_VECTOR:
+                       if (match_int(args, &token) || token < 0) {
+                               pr_warn("bad comp_vector parameter '%s'\n", p);
+                               goto out;
+                       }
+                       target->comp_vector = token;
+                       break;
+
                default:
                        pr_warn("unknown parameter or missing value '%s' in target creation request\n",
                                p);
@@ -2257,6 +2316,16 @@ static ssize_t srp_create_target(struct device *dev,
        if (ret)
                goto err;
 
+       if (!srp_conn_unique(target->srp_host, target)) {
+               shost_printk(KERN_INFO, target->scsi_host,
+                            PFX "Already connected to target port with id_ext=%016llx;ioc_guid=%016llx;initiator_ext=%016llx\n",
+                            be64_to_cpu(target->id_ext),
+                            be64_to_cpu(target->ioc_guid),
+                            be64_to_cpu(target->initiator_ext));
+               ret = -EEXIST;
+               goto err;
+       }
+
        if (!host->srp_dev->fmr_pool && !target->allow_ext_sg &&
                                target->cmd_sg_cnt < target->sg_tablesize) {
                pr_warn("No FMR pool and no external indirect descriptors, limiting sg_tablesize to cmd_sg_cnt\n");
@@ -2507,6 +2576,8 @@ static void srp_remove_one(struct ib_device *device)
        struct srp_target_port *target;
 
        srp_dev = ib_get_client_data(device, &srp_client);
+       if (!srp_dev)
+               return;
 
        list_for_each_entry_safe(host, tmp_host, &srp_dev->dev_list, list) {
                device_unregister(&host->dev);
index 66fbedd..e641088 100644 (file)
@@ -156,6 +156,7 @@ struct srp_target_port {
        char                    target_name[32];
        unsigned int            scsi_id;
        unsigned int            sg_tablesize;
+       int                     comp_vector;
 
        struct ib_sa_path_rec   path;
        __be16                  orig_dgid[8];
index 3f3f041..653ac6b 100644 (file)
@@ -3011,7 +3011,7 @@ static u8 tcm_to_srp_tsk_mgmt_status(const int tcm_mgmt_status)
  * Callback function called by the TCM core. Must not block since it can be
  * invoked on the context of the IB completion handler.
  */
-static int srpt_queue_response(struct se_cmd *cmd)
+static void srpt_queue_response(struct se_cmd *cmd)
 {
        struct srpt_rdma_ch *ch;
        struct srpt_send_ioctx *ioctx;
@@ -3022,8 +3022,6 @@ static int srpt_queue_response(struct se_cmd *cmd)
        int resp_len;
        u8 srp_tm_status;
 
-       ret = 0;
-
        ioctx = container_of(cmd, struct srpt_send_ioctx, cmd);
        ch = ioctx->ch;
        BUG_ON(!ch);
@@ -3049,7 +3047,7 @@ static int srpt_queue_response(struct se_cmd *cmd)
                     || WARN_ON_ONCE(state == SRPT_STATE_CMD_RSP_SENT))) {
                atomic_inc(&ch->req_lim_delta);
                srpt_abort_cmd(ioctx);
-               goto out;
+               return;
        }
 
        dir = ioctx->cmd.data_direction;
@@ -3061,7 +3059,7 @@ static int srpt_queue_response(struct se_cmd *cmd)
                if (ret) {
                        printk(KERN_ERR "xfer_data failed for tag %llu\n",
                               ioctx->tag);
-                       goto out;
+                       return;
                }
        }
 
@@ -3082,9 +3080,17 @@ static int srpt_queue_response(struct se_cmd *cmd)
                srpt_set_cmd_state(ioctx, SRPT_STATE_DONE);
                target_put_sess_cmd(ioctx->ch->sess, &ioctx->cmd);
        }
+}
 
-out:
-       return ret;
+static int srpt_queue_data_in(struct se_cmd *cmd)
+{
+       srpt_queue_response(cmd);
+       return 0;
+}
+
+static void srpt_queue_tm_rsp(struct se_cmd *cmd)
+{
+       srpt_queue_response(cmd);
 }
 
 static int srpt_queue_status(struct se_cmd *cmd)
@@ -3097,7 +3103,8 @@ static int srpt_queue_status(struct se_cmd *cmd)
            (SCF_TRANSPORT_TASK_SENSE | SCF_EMULATED_TASK_SENSE))
                WARN_ON(cmd->scsi_status != SAM_STAT_CHECK_CONDITION);
        ioctx->queue_status_only = true;
-       return srpt_queue_response(cmd);
+       srpt_queue_response(cmd);
+       return 0;
 }
 
 static void srpt_refresh_port_work(struct work_struct *work)
@@ -3930,9 +3937,9 @@ static struct target_core_fabric_ops srpt_template = {
        .set_default_node_attributes    = srpt_set_default_node_attrs,
        .get_task_tag                   = srpt_get_task_tag,
        .get_cmd_state                  = srpt_get_tcm_cmd_state,
-       .queue_data_in                  = srpt_queue_response,
+       .queue_data_in                  = srpt_queue_data_in,
        .queue_status                   = srpt_queue_status,
-       .queue_tm_rsp                   = srpt_queue_response,
+       .queue_tm_rsp                   = srpt_queue_tm_rsp,
        /*
         * Setup function pointers for generic logic in
         * target_core_fabric_configfs.c
index e0a1339..20d872d 100644 (file)
@@ -122,7 +122,7 @@ static int nspire_keypad_chip_init(struct nspire_keypad *keypad)
 
        /* Enable interrupts */
        keypad->int_mask = 1 << 1;
-       writel(keypad->int_mask, keypad->reg_base + 0xc);
+       writel(keypad->int_mask, keypad->reg_base + KEYPAD_INTMSK);
 
        /* Disable GPIO interrupts to prevent hanging on touchpad */
        /* Possibly used to detect touchpad events */
index 1e8e42f..57b2637 100644 (file)
@@ -694,18 +694,18 @@ static int elantech_packet_check_v3(struct psmouse *psmouse)
 static int elantech_packet_check_v4(struct psmouse *psmouse)
 {
        unsigned char *packet = psmouse->packet;
+       unsigned char packet_type = packet[3] & 0x03;
 
-       if ((packet[0] & 0x0c) == 0x04 &&
-           (packet[3] & 0x1f) == 0x11)
+       switch (packet_type) {
+       case 0:
+               return PACKET_V4_STATUS;
+
+       case 1:
                return PACKET_V4_HEAD;
 
-       if ((packet[0] & 0x0c) == 0x04 &&
-           (packet[3] & 0x1f) == 0x12)
+       case 2:
                return PACKET_V4_MOTION;
-
-       if ((packet[0] & 0x0c) == 0x04 &&
-           (packet[3] & 0x1f) == 0x10)
-               return PACKET_V4_STATUS;
+       }
 
        return PACKET_UNKNOWN;
 }
@@ -1282,6 +1282,7 @@ static int elantech_set_properties(struct elantech_data *etd)
                        etd->hw_version = 3;
                        break;
                case 6:
+               case 7:
                        etd->hw_version = 4;
                        break;
                default:
index 84ccf14..ea19536 100644 (file)
@@ -27,6 +27,9 @@
 #include <linux/interrupt.h>
 #include <linux/slab.h>
 #include <linux/pm.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/of_device.h>
 #include <linux/gpio.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/ads7846.h>
@@ -961,9 +964,9 @@ static int ads7846_resume(struct device *dev)
 static SIMPLE_DEV_PM_OPS(ads7846_pm, ads7846_suspend, ads7846_resume);
 
 static int ads7846_setup_pendown(struct spi_device *spi,
-                                          struct ads7846 *ts)
+                                struct ads7846 *ts,
+                                const struct ads7846_platform_data *pdata)
 {
-       struct ads7846_platform_data *pdata = spi->dev.platform_data;
        int err;
 
        /*
@@ -1003,7 +1006,7 @@ static int ads7846_setup_pendown(struct spi_device *spi,
  * use formula #2 for pressure, not #3.
  */
 static void ads7846_setup_spi_msg(struct ads7846 *ts,
-                               const struct ads7846_platform_data *pdata)
+                                 const struct ads7846_platform_data *pdata)
 {
        struct spi_message *m = &ts->msg[0];
        struct spi_transfer *x = ts->xfer;
@@ -1201,33 +1204,107 @@ static void ads7846_setup_spi_msg(struct ads7846 *ts,
        spi_message_add_tail(x, m);
 }
 
+#ifdef CONFIG_OF
+static const struct of_device_id ads7846_dt_ids[] = {
+       { .compatible = "ti,tsc2046",   .data = (void *) 7846 },
+       { .compatible = "ti,ads7843",   .data = (void *) 7843 },
+       { .compatible = "ti,ads7845",   .data = (void *) 7845 },
+       { .compatible = "ti,ads7846",   .data = (void *) 7846 },
+       { .compatible = "ti,ads7873",   .data = (void *) 7873 },
+       { }
+};
+MODULE_DEVICE_TABLE(of, ads7846_dt_ids);
+
+static const struct ads7846_platform_data *ads7846_probe_dt(struct device *dev)
+{
+       struct ads7846_platform_data *pdata;
+       struct device_node *node = dev->of_node;
+       const struct of_device_id *match;
+
+       if (!node) {
+               dev_err(dev, "Device does not have associated DT data\n");
+               return ERR_PTR(-EINVAL);
+       }
+
+       match = of_match_device(ads7846_dt_ids, dev);
+       if (!match) {
+               dev_err(dev, "Unknown device model\n");
+               return ERR_PTR(-EINVAL);
+       }
+
+       pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+       if (!pdata)
+               return ERR_PTR(-ENOMEM);
+
+       pdata->model = (unsigned long)match->data;
+
+       of_property_read_u16(node, "ti,vref-delay-usecs",
+                            &pdata->vref_delay_usecs);
+       of_property_read_u16(node, "ti,vref-mv", &pdata->vref_mv);
+       pdata->keep_vref_on = of_property_read_bool(node, "ti,keep-vref-on");
+
+       pdata->swap_xy = of_property_read_bool(node, "ti,swap-xy");
+
+       of_property_read_u16(node, "ti,settle-delay-usec",
+                            &pdata->settle_delay_usecs);
+       of_property_read_u16(node, "ti,penirq-recheck-delay-usecs",
+                            &pdata->penirq_recheck_delay_usecs);
+
+       of_property_read_u16(node, "ti,x-plate-ohms", &pdata->x_plate_ohms);
+       of_property_read_u16(node, "ti,y-plate-ohms", &pdata->y_plate_ohms);
+
+       of_property_read_u16(node, "ti,x-min", &pdata->x_min);
+       of_property_read_u16(node, "ti,y-min", &pdata->y_min);
+       of_property_read_u16(node, "ti,x-max", &pdata->x_max);
+       of_property_read_u16(node, "ti,y-max", &pdata->y_max);
+
+       of_property_read_u16(node, "ti,pressure-min", &pdata->pressure_min);
+       of_property_read_u16(node, "ti,pressure-max", &pdata->pressure_max);
+
+       of_property_read_u16(node, "ti,debounce-max", &pdata->debounce_max);
+       of_property_read_u16(node, "ti,debounce-tol", &pdata->debounce_tol);
+       of_property_read_u16(node, "ti,debounce-rep", &pdata->debounce_rep);
+
+       of_property_read_u32(node, "ti,pendown-gpio-debounce",
+                            &pdata->gpio_pendown_debounce);
+
+       pdata->wakeup = of_property_read_bool(node, "linux,wakeup");
+
+       pdata->gpio_pendown = of_get_named_gpio(dev->of_node, "pendown-gpio", 0);
+
+       return pdata;
+}
+#else
+static const struct ads7846_platform_data *ads7846_probe_dt(struct device *dev)
+{
+       dev_err(dev, "no platform data defined\n");
+       return ERR_PTR(-EINVAL);
+}
+#endif
+
 static int ads7846_probe(struct spi_device *spi)
 {
+       const struct ads7846_platform_data *pdata;
        struct ads7846 *ts;
        struct ads7846_packet *packet;
        struct input_dev *input_dev;
-       struct ads7846_platform_data *pdata = spi->dev.platform_data;
        unsigned long irq_flags;
        int err;
 
        if (!spi->irq) {
                dev_dbg(&spi->dev, "no IRQ?\n");
-               return -ENODEV;
-       }
-
-       if (!pdata) {
-               dev_dbg(&spi->dev, "no platform data?\n");
-               return -ENODEV;
+               return -EINVAL;
        }
 
        /* don't exceed max specified sample rate */
        if (spi->max_speed_hz > (125000 * SAMPLE_BITS)) {
-               dev_dbg(&spi->dev, "f(sample) %d KHz?\n",
+               dev_err(&spi->dev, "f(sample) %d KHz?\n",
                                (spi->max_speed_hz/SAMPLE_BITS)/1000);
                return -EINVAL;
        }
 
-       /* We'd set TX word size 8 bits and RX word size to 13 bits ... except
+       /*
+        * We'd set TX word size 8 bits and RX word size to 13 bits ... except
         * that even if the hardware can do that, the SPI controller driver
         * may not.  So we stick to very-portable 8 bit words, both RX and TX.
         */
@@ -1250,17 +1327,25 @@ static int ads7846_probe(struct spi_device *spi)
        ts->packet = packet;
        ts->spi = spi;
        ts->input = input_dev;
-       ts->vref_mv = pdata->vref_mv;
-       ts->swap_xy = pdata->swap_xy;
 
        mutex_init(&ts->lock);
        init_waitqueue_head(&ts->wait);
 
+       pdata = dev_get_platdata(&spi->dev);
+       if (!pdata) {
+               pdata = ads7846_probe_dt(&spi->dev);
+               if (IS_ERR(pdata))
+                       return PTR_ERR(pdata);
+       }
+
        ts->model = pdata->model ? : 7846;
        ts->vref_delay_usecs = pdata->vref_delay_usecs ? : 100;
        ts->x_plate_ohms = pdata->x_plate_ohms ? : 400;
        ts->pressure_max = pdata->pressure_max ? : ~0;
 
+       ts->vref_mv = pdata->vref_mv;
+       ts->swap_xy = pdata->swap_xy;
+
        if (pdata->filter != NULL) {
                if (pdata->filter_init != NULL) {
                        err = pdata->filter_init(pdata, &ts->filter_data);
@@ -1281,7 +1366,7 @@ static int ads7846_probe(struct spi_device *spi)
                ts->filter = ads7846_no_filter;
        }
 
-       err = ads7846_setup_pendown(spi, ts);
+       err = ads7846_setup_pendown(spi, ts, pdata);
        if (err)
                goto err_cleanup_filter;
 
@@ -1370,6 +1455,13 @@ static int ads7846_probe(struct spi_device *spi)
 
        device_init_wakeup(&spi->dev, pdata->wakeup);
 
+       /*
+        * If device does not carry platform data we must have allocated it
+        * when parsing DT data.
+        */
+       if (!dev_get_platdata(&spi->dev))
+               devm_kfree(&spi->dev, (void *)pdata);
+
        return 0;
 
  err_remove_attr_group:
@@ -1437,6 +1529,7 @@ static struct spi_driver ads7846_driver = {
                .name   = "ads7846",
                .owner  = THIS_MODULE,
                .pm     = &ads7846_pm,
+               .of_match_table = of_match_ptr(ads7846_dt_ids),
        },
        .probe          = ads7846_probe,
        .remove         = ads7846_remove,
index 86a2543..8e0d4d4 100644 (file)
@@ -369,9 +369,9 @@ struct cyttsp4 {
 
 struct cyttsp4_bus_ops {
        u16 bustype;
-       int (*write)(struct device *dev, u8 *xfer_buf, u8 addr, u8 length,
+       int (*write)(struct device *dev, u8 *xfer_buf, u16 addr, u8 length,
                        const void *values);
-       int (*read)(struct device *dev, u8 *xfer_buf, u8 addr, u8 length,
+       int (*read)(struct device *dev, u8 *xfer_buf, u16 addr, u8 length,
                        void *values);
 };
 
@@ -448,13 +448,13 @@ enum cyttsp4_event_id {
 /* y-axis, 0:origin is on top side of panel, 1: bottom */
 #define CY_PCFG_ORIGIN_Y_MASK          0x80
 
-static inline int cyttsp4_adap_read(struct cyttsp4 *ts, u8 addr, int size,
+static inline int cyttsp4_adap_read(struct cyttsp4 *ts, u16 addr, int size,
                void *buf)
 {
        return ts->bus_ops->read(ts->dev, ts->xfer_buf, addr, size, buf);
 }
 
-static inline int cyttsp4_adap_write(struct cyttsp4 *ts, u8 addr, int size,
+static inline int cyttsp4_adap_write(struct cyttsp4 *ts, u16 addr, int size,
                const void *buf)
 {
        return ts->bus_ops->write(ts->dev, ts->xfer_buf, addr, size, buf);
@@ -463,9 +463,9 @@ static inline int cyttsp4_adap_write(struct cyttsp4 *ts, u8 addr, int size,
 extern struct cyttsp4 *cyttsp4_probe(const struct cyttsp4_bus_ops *ops,
                struct device *dev, u16 irq, size_t xfer_buf_size);
 extern int cyttsp4_remove(struct cyttsp4 *ts);
-int cyttsp_i2c_write_block_data(struct device *dev, u8 *xfer_buf, u8 addr,
+int cyttsp_i2c_write_block_data(struct device *dev, u8 *xfer_buf, u16 addr,
                u8 length, const void *values);
-int cyttsp_i2c_read_block_data(struct device *dev, u8 *xfer_buf, u8 addr,
+int cyttsp_i2c_read_block_data(struct device *dev, u8 *xfer_buf, u16 addr,
                u8 length, void *values);
 extern const struct dev_pm_ops cyttsp4_pm_ops;
 
index f8f891b..a71e114 100644 (file)
@@ -44,7 +44,7 @@
 #define CY_SPI_DATA_BUF_SIZE   (CY_SPI_CMD_BYTES + CY_SPI_DATA_SIZE)
 
 static int cyttsp_spi_xfer(struct device *dev, u8 *xfer_buf,
-                          u8 op, u8 reg, u8 *buf, int length)
+                          u8 op, u16 reg, u8 *buf, int length)
 {
        struct spi_device *spi = to_spi_device(dev);
        struct spi_message msg;
@@ -63,14 +63,12 @@ static int cyttsp_spi_xfer(struct device *dev, u8 *xfer_buf,
        memset(wr_buf, 0, CY_SPI_DATA_BUF_SIZE);
        memset(rd_buf, 0, CY_SPI_CMD_BYTES);
 
-       if (reg > 255)
-               wr_buf[0] = op + CY_SPI_A8_BIT;
-       else
-               wr_buf[0] = op;
-       if (op == CY_SPI_WR_OP)
-               wr_buf[1] = reg % 256;
-       if (op == CY_SPI_WR_OP && length > 0)
-               memcpy(wr_buf + CY_SPI_CMD_BYTES, buf, length);
+       wr_buf[0] = op + (((reg >> 8) & 0x1) ? CY_SPI_A8_BIT : 0);
+       if (op == CY_SPI_WR_OP) {
+               wr_buf[1] = reg & 0xFF;
+               if (length > 0)
+                       memcpy(wr_buf + CY_SPI_CMD_BYTES, buf, length);
+       }
 
        memset(xfer, 0, sizeof(xfer));
        spi_message_init(&msg);
@@ -130,7 +128,7 @@ static int cyttsp_spi_xfer(struct device *dev, u8 *xfer_buf,
 }
 
 static int cyttsp_spi_read_block_data(struct device *dev, u8 *xfer_buf,
-                                     u8 addr, u8 length, void *data)
+                                     u16 addr, u8 length, void *data)
 {
        int rc;
 
@@ -143,7 +141,7 @@ static int cyttsp_spi_read_block_data(struct device *dev, u8 *xfer_buf,
 }
 
 static int cyttsp_spi_write_block_data(struct device *dev, u8 *xfer_buf,
-                                      u8 addr, u8 length, const void *data)
+                                      u16 addr, u8 length, const void *data)
 {
        return cyttsp_spi_xfer(dev, xfer_buf, CY_SPI_WR_OP, addr, (void *)data,
                        length);
index 0cf564a..0707411 100644 (file)
@@ -112,9 +112,9 @@ struct cyttsp;
 
 struct cyttsp_bus_ops {
        u16 bustype;
-       int (*write)(struct device *dev, u8 *xfer_buf, u8 addr, u8 length,
+       int (*write)(struct device *dev, u8 *xfer_buf, u16 addr, u8 length,
                        const void *values);
-       int (*read)(struct device *dev, u8 *xfer_buf, u8 addr, u8 length,
+       int (*read)(struct device *dev, u8 *xfer_buf, u16 addr, u8 length,
                        void *values);
 };
 
@@ -145,9 +145,9 @@ struct cyttsp *cyttsp_probe(const struct cyttsp_bus_ops *bus_ops,
                            struct device *dev, int irq, size_t xfer_buf_size);
 void cyttsp_remove(struct cyttsp *ts);
 
-int cyttsp_i2c_write_block_data(struct device *dev, u8 *xfer_buf, u8 addr,
+int cyttsp_i2c_write_block_data(struct device *dev, u8 *xfer_buf, u16 addr,
                u8 length, const void *values);
-int cyttsp_i2c_read_block_data(struct device *dev, u8 *xfer_buf, u8 addr,
+int cyttsp_i2c_read_block_data(struct device *dev, u8 *xfer_buf, u16 addr,
                u8 length, void *values);
 extern const struct dev_pm_ops cyttsp_pm_ops;
 
index 07c553f..1d7b6f1 100644 (file)
 #include <linux/types.h>
 
 int cyttsp_i2c_read_block_data(struct device *dev, u8 *xfer_buf,
-                                     u8 addr, u8 length, void *values)
+                                     u16 addr, u8 length, void *values)
 {
        struct i2c_client *client = to_i2c_client(dev);
+       u8 client_addr = client->addr | ((addr >> 8) & 0x1);
+       u8 addr_lo = addr & 0xFF;
        struct i2c_msg msgs[] = {
                {
-                       .addr = client->addr,
+                       .addr = client_addr,
                        .flags = 0,
                        .len = 1,
-                       .buf = &addr,
+                       .buf = &addr_lo,
                },
                {
-                       .addr = client->addr,
+                       .addr = client_addr,
                        .flags = I2C_M_RD,
                        .len = length,
                        .buf = values,
@@ -60,17 +62,29 @@ int cyttsp_i2c_read_block_data(struct device *dev, u8 *xfer_buf,
 EXPORT_SYMBOL_GPL(cyttsp_i2c_read_block_data);
 
 int cyttsp_i2c_write_block_data(struct device *dev, u8 *xfer_buf,
-                                      u8 addr, u8 length, const void *values)
+                                      u16 addr, u8 length, const void *values)
 {
        struct i2c_client *client = to_i2c_client(dev);
+       u8 client_addr = client->addr | ((addr >> 8) & 0x1);
+       u8 addr_lo = addr & 0xFF;
+       struct i2c_msg msgs[] = {
+               {
+                       .addr = client_addr,
+                       .flags = 0,
+                       .len = length + 1,
+                       .buf = xfer_buf,
+               },
+       };
        int retval;
 
-       xfer_buf[0] = addr;
+       xfer_buf[0] = addr_lo;
        memcpy(&xfer_buf[1], values, length);
 
-       retval = i2c_master_send(client, xfer_buf, length + 1);
+       retval = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
+       if (retval < 0)
+               return retval;
 
-       return retval < 0 ? retval : 0;
+       return retval != ARRAY_SIZE(msgs) ? -EIO : 0;
 }
 EXPORT_SYMBOL_GPL(cyttsp_i2c_write_block_data);
 
index 1df6253..4728bcb 100644 (file)
@@ -41,7 +41,7 @@
 #define CY_SPI_BITS_PER_WORD   8
 
 static int cyttsp_spi_xfer(struct device *dev, u8 *xfer_buf,
-                          u8 op, u8 reg, u8 *buf, int length)
+                          u8 op, u16 reg, u8 *buf, int length)
 {
        struct spi_device *spi = to_spi_device(dev);
        struct spi_message msg;
@@ -126,14 +126,14 @@ static int cyttsp_spi_xfer(struct device *dev, u8 *xfer_buf,
 }
 
 static int cyttsp_spi_read_block_data(struct device *dev, u8 *xfer_buf,
-                                     u8 addr, u8 length, void *data)
+                                     u16 addr, u8 length, void *data)
 {
        return cyttsp_spi_xfer(dev, xfer_buf, CY_SPI_RD_OP, addr, data,
                        length);
 }
 
 static int cyttsp_spi_write_block_data(struct device *dev, u8 *xfer_buf,
-                                      u8 addr, u8 length, const void *data)
+                                      u16 addr, u8 length, const void *data)
 {
        return cyttsp_spi_xfer(dev, xfer_buf, CY_SPI_WR_OP, addr, (void *)data,
                        length);
index 50fb129..e1c5300 100644 (file)
@@ -24,8 +24,9 @@
 #include <linux/clk.h>
 #include <linux/platform_device.h>
 #include <linux/io.h>
-#include <linux/input/ti_am335x_tsc.h>
 #include <linux/delay.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 #include <linux/mfd/ti_am335x_tscadc.h>
 
 #define SEQ_SETTLE             275
 #define MAX_12BIT              ((1 << 12) - 1)
 
+static const int config_pins[] = {
+       STEPCONFIG_XPP,
+       STEPCONFIG_XNN,
+       STEPCONFIG_YPP,
+       STEPCONFIG_YNN,
+};
+
 struct titsc {
        struct input_dev        *input;
        struct ti_tscadc_dev    *mfd_tscadc;
@@ -40,7 +48,10 @@ struct titsc {
        unsigned int            wires;
        unsigned int            x_plate_resistance;
        bool                    pen_down;
-       int                     steps_to_configure;
+       int                     coordinate_readouts;
+       u32                     config_inp[4];
+       u32                     bit_xp, bit_xn, bit_yp, bit_yn;
+       u32                     inp_xp, inp_xn, inp_yp, inp_yn;
 };
 
 static unsigned int titsc_readl(struct titsc *ts, unsigned int reg)
@@ -54,92 +65,153 @@ static void titsc_writel(struct titsc *tsc, unsigned int reg,
        writel(val, tsc->mfd_tscadc->tscadc_base + reg);
 }
 
+static int titsc_config_wires(struct titsc *ts_dev)
+{
+       u32 analog_line[4];
+       u32 wire_order[4];
+       int i, bit_cfg;
+
+       for (i = 0; i < 4; i++) {
+               /*
+                * Get the order in which TSC wires are attached
+                * w.r.t. each of the analog input lines on the EVM.
+                */
+               analog_line[i] = (ts_dev->config_inp[i] & 0xF0) >> 4;
+               wire_order[i] = ts_dev->config_inp[i] & 0x0F;
+               if (WARN_ON(analog_line[i] > 7))
+                       return -EINVAL;
+               if (WARN_ON(wire_order[i] > ARRAY_SIZE(config_pins)))
+                       return -EINVAL;
+       }
+
+       for (i = 0; i < 4; i++) {
+               int an_line;
+               int wi_order;
+
+               an_line = analog_line[i];
+               wi_order = wire_order[i];
+               bit_cfg = config_pins[wi_order];
+               if (bit_cfg == 0)
+                       return -EINVAL;
+               switch (wi_order) {
+               case 0:
+                       ts_dev->bit_xp = bit_cfg;
+                       ts_dev->inp_xp = an_line;
+                       break;
+
+               case 1:
+                       ts_dev->bit_xn = bit_cfg;
+                       ts_dev->inp_xn = an_line;
+                       break;
+
+               case 2:
+                       ts_dev->bit_yp = bit_cfg;
+                       ts_dev->inp_yp = an_line;
+                       break;
+               case 3:
+                       ts_dev->bit_yn = bit_cfg;
+                       ts_dev->inp_yn = an_line;
+                       break;
+               }
+       }
+       return 0;
+}
+
 static void titsc_step_config(struct titsc *ts_dev)
 {
        unsigned int    config;
-       int i, total_steps;
-
-       /* Configure the Step registers */
-       total_steps = 2 * ts_dev->steps_to_configure;
+       int i;
+       int end_step;
+       u32 stepenable;
 
        config = STEPCONFIG_MODE_HWSYNC |
-                       STEPCONFIG_AVG_16 | STEPCONFIG_XPP;
+                       STEPCONFIG_AVG_16 | ts_dev->bit_xp;
        switch (ts_dev->wires) {
        case 4:
-               config |= STEPCONFIG_INP_AN2 | STEPCONFIG_XNN;
+               config |= STEPCONFIG_INP(ts_dev->inp_yp) | ts_dev->bit_xn;
                break;
        case 5:
-               config |= STEPCONFIG_YNN |
-                               STEPCONFIG_INP_AN4 | STEPCONFIG_XNN |
-                               STEPCONFIG_YPP;
+               config |= ts_dev->bit_yn |
+                               STEPCONFIG_INP_AN4 | ts_dev->bit_xn |
+                               ts_dev->bit_yp;
                break;
        case 8:
-               config |= STEPCONFIG_INP_AN2 | STEPCONFIG_XNN;
+               config |= STEPCONFIG_INP(ts_dev->inp_yp) | ts_dev->bit_xn;
                break;
        }
 
-       for (i = 1; i <= ts_dev->steps_to_configure; i++) {
+       /* 1 … coordinate_readouts is for X */
+       end_step = ts_dev->coordinate_readouts;
+       for (i = 0; i < end_step; i++) {
                titsc_writel(ts_dev, REG_STEPCONFIG(i), config);
                titsc_writel(ts_dev, REG_STEPDELAY(i), STEPCONFIG_OPENDLY);
        }
 
        config = 0;
        config = STEPCONFIG_MODE_HWSYNC |
-                       STEPCONFIG_AVG_16 | STEPCONFIG_YNN |
-                       STEPCONFIG_INM_ADCREFM | STEPCONFIG_FIFO1;
+                       STEPCONFIG_AVG_16 | ts_dev->bit_yn |
+                       STEPCONFIG_INM_ADCREFM;
        switch (ts_dev->wires) {
        case 4:
-               config |= STEPCONFIG_YPP;
+               config |= ts_dev->bit_yp | STEPCONFIG_INP(ts_dev->inp_xp);
                break;
        case 5:
-               config |= STEPCONFIG_XPP | STEPCONFIG_INP_AN4 |
-                               STEPCONFIG_XNP | STEPCONFIG_YPN;
+               config |= ts_dev->bit_xp | STEPCONFIG_INP_AN4 |
+                               ts_dev->bit_xn | ts_dev->bit_yp;
                break;
        case 8:
-               config |= STEPCONFIG_YPP;
+               config |= ts_dev->bit_yp | STEPCONFIG_INP(ts_dev->inp_xp);
                break;
        }
 
-       for (i = (ts_dev->steps_to_configure + 1); i <= total_steps; i++) {
+       /* coordinate_readouts … coordinate_readouts * 2 is for Y */
+       end_step = ts_dev->coordinate_readouts * 2;
+       for (i = ts_dev->coordinate_readouts; i < end_step; i++) {
                titsc_writel(ts_dev, REG_STEPCONFIG(i), config);
                titsc_writel(ts_dev, REG_STEPDELAY(i), STEPCONFIG_OPENDLY);
        }
 
-       config = 0;
        /* Charge step configuration */
-       config = STEPCONFIG_XPP | STEPCONFIG_YNN |
+       config = ts_dev->bit_xp | ts_dev->bit_yn |
                        STEPCHARGE_RFP_XPUL | STEPCHARGE_RFM_XNUR |
-                       STEPCHARGE_INM_AN1 | STEPCHARGE_INP_AN1;
+                       STEPCHARGE_INM_AN1 | STEPCHARGE_INP(ts_dev->inp_yp);
 
        titsc_writel(ts_dev, REG_CHARGECONFIG, config);
        titsc_writel(ts_dev, REG_CHARGEDELAY, CHARGEDLY_OPENDLY);
 
-       config = 0;
-       /* Configure to calculate pressure */
+       /* coordinate_readouts * 2 … coordinate_readouts * 2 + 2 is for Z */
        config = STEPCONFIG_MODE_HWSYNC |
-                       STEPCONFIG_AVG_16 | STEPCONFIG_YPP |
-                       STEPCONFIG_XNN | STEPCONFIG_INM_ADCREFM;
-       titsc_writel(ts_dev, REG_STEPCONFIG(total_steps + 1), config);
-       titsc_writel(ts_dev, REG_STEPDELAY(total_steps + 1),
+                       STEPCONFIG_AVG_16 | ts_dev->bit_yp |
+                       ts_dev->bit_xn | STEPCONFIG_INM_ADCREFM |
+                       STEPCONFIG_INP(ts_dev->inp_xp);
+       titsc_writel(ts_dev, REG_STEPCONFIG(end_step), config);
+       titsc_writel(ts_dev, REG_STEPDELAY(end_step),
                        STEPCONFIG_OPENDLY);
 
-       config |= STEPCONFIG_INP_AN3 | STEPCONFIG_FIFO1;
-       titsc_writel(ts_dev, REG_STEPCONFIG(total_steps + 2), config);
-       titsc_writel(ts_dev, REG_STEPDELAY(total_steps + 2),
+       end_step++;
+       config |= STEPCONFIG_INP(ts_dev->inp_yn);
+       titsc_writel(ts_dev, REG_STEPCONFIG(end_step), config);
+       titsc_writel(ts_dev, REG_STEPDELAY(end_step),
                        STEPCONFIG_OPENDLY);
 
-       titsc_writel(ts_dev, REG_SE, STPENB_STEPENB_TC);
+       /* The steps1 … end and bit 0 for TS_Charge */
+       stepenable = (1 << (end_step + 2)) - 1;
+       am335x_tsc_se_set(ts_dev->mfd_tscadc, stepenable);
 }
 
 static void titsc_read_coordinates(struct titsc *ts_dev,
-                                   unsigned int *x, unsigned int *y)
+               u32 *x, u32 *y, u32 *z1, u32 *z2)
 {
        unsigned int fifocount = titsc_readl(ts_dev, REG_FIFO0CNT);
        unsigned int prev_val_x = ~0, prev_val_y = ~0;
        unsigned int prev_diff_x = ~0, prev_diff_y = ~0;
        unsigned int read, diff;
        unsigned int i, channel;
+       unsigned int creads = ts_dev->coordinate_readouts;
 
+       *z1 = *z2 = 0;
+       if (fifocount % (creads * 2 + 2))
+               fifocount -= fifocount % (creads * 2 + 2);
        /*
         * Delta filter is used to remove large variations in sampled
         * values from ADC. The filter tries to predict where the next
@@ -148,32 +220,32 @@ static void titsc_read_coordinates(struct titsc *ts_dev,
         * algorithm compares the difference with that of a present value,
         * if true the value is reported to the sub system.
         */
-       for (i = 0; i < fifocount - 1; i++) {
+       for (i = 0; i < fifocount; i++) {
                read = titsc_readl(ts_dev, REG_FIFO0);
-               channel = read & 0xf0000;
-               channel = channel >> 0x10;
-               if ((channel >= 0) && (channel < ts_dev->steps_to_configure)) {
-                       read &= 0xfff;
+
+               channel = (read & 0xf0000) >> 16;
+               read &= 0xfff;
+               if (channel < creads) {
                        diff = abs(read - prev_val_x);
                        if (diff < prev_diff_x) {
                                prev_diff_x = diff;
                                *x = read;
                        }
                        prev_val_x = read;
-               }
 
-               read = titsc_readl(ts_dev, REG_FIFO1);
-               channel = read & 0xf0000;
-               channel = channel >> 0x10;
-               if ((channel >= ts_dev->steps_to_configure) &&
-                       (channel < (2 * ts_dev->steps_to_configure - 1))) {
-                       read &= 0xfff;
+               } else if (channel < creads * 2) {
                        diff = abs(read - prev_val_y);
                        if (diff < prev_diff_y) {
                                prev_diff_y = diff;
                                *y = read;
                        }
                        prev_val_y = read;
+
+               } else if (channel < creads * 2 + 1) {
+                       *z1 = read;
+
+               } else if (channel < creads * 2 + 2) {
+                       *z2 = read;
                }
        }
 }
@@ -186,23 +258,11 @@ static irqreturn_t titsc_irq(int irq, void *dev)
        unsigned int x = 0, y = 0;
        unsigned int z1, z2, z;
        unsigned int fsm;
-       unsigned int fifo1count, fifo0count;
-       int i;
 
        status = titsc_readl(ts_dev, REG_IRQSTATUS);
        if (status & IRQENB_FIFO0THRES) {
-               titsc_read_coordinates(ts_dev, &x, &y);
 
-               z1 = titsc_readl(ts_dev, REG_FIFO0) & 0xfff;
-               z2 = titsc_readl(ts_dev, REG_FIFO1) & 0xfff;
-
-               fifo1count = titsc_readl(ts_dev, REG_FIFO1CNT);
-               for (i = 0; i < fifo1count; i++)
-                       titsc_readl(ts_dev, REG_FIFO1);
-
-               fifo0count = titsc_readl(ts_dev, REG_FIFO0CNT);
-               for (i = 0; i < fifo0count; i++)
-                       titsc_readl(ts_dev, REG_FIFO0);
+               titsc_read_coordinates(ts_dev, &x, &y, &z1, &z2);
 
                if (ts_dev->pen_down && z1 != 0 && z2 != 0) {
                        /*
@@ -210,10 +270,10 @@ static irqreturn_t titsc_irq(int irq, void *dev)
                         * Resistance(touch) = x plate resistance *
                         * x postion/4096 * ((z2 / z1) - 1)
                         */
-                       z = z2 - z1;
+                       z = z1 - z2;
                        z *= x;
                        z *= ts_dev->x_plate_resistance;
-                       z /= z1;
+                       z /= z2;
                        z = (z + 2047) >> 12;
 
                        if (z <= MAX_12BIT) {
@@ -248,10 +308,53 @@ static irqreturn_t titsc_irq(int irq, void *dev)
                irqclr |= IRQENB_PENUP;
        }
 
-       titsc_writel(ts_dev, REG_IRQSTATUS, irqclr);
+       if (status & IRQENB_HW_PEN) {
+
+               titsc_writel(ts_dev, REG_IRQWAKEUP, 0x00);
+               titsc_writel(ts_dev, REG_IRQCLR, IRQENB_HW_PEN);
+       }
 
-       titsc_writel(ts_dev, REG_SE, STPENB_STEPENB_TC);
-       return IRQ_HANDLED;
+       if (irqclr) {
+               titsc_writel(ts_dev, REG_IRQSTATUS, irqclr);
+               am335x_tsc_se_update(ts_dev->mfd_tscadc);
+               return IRQ_HANDLED;
+       }
+       return IRQ_NONE;
+}
+
+static int titsc_parse_dt(struct platform_device *pdev,
+                                       struct titsc *ts_dev)
+{
+       struct device_node *node = pdev->dev.of_node;
+       int err;
+
+       if (!node)
+               return -EINVAL;
+
+       err = of_property_read_u32(node, "ti,wires", &ts_dev->wires);
+       if (err < 0)
+               return err;
+       switch (ts_dev->wires) {
+       case 4:
+       case 5:
+       case 8:
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       err = of_property_read_u32(node, "ti,x-plate-resistance",
+                       &ts_dev->x_plate_resistance);
+       if (err < 0)
+               return err;
+
+       err = of_property_read_u32(node, "ti,coordiante-readouts",
+                       &ts_dev->coordinate_readouts);
+       if (err < 0)
+               return err;
+
+       return of_property_read_u32_array(node, "ti,wire-config",
+                       ts_dev->config_inp, ARRAY_SIZE(ts_dev->config_inp));
 }
 
 /*
@@ -262,17 +365,9 @@ static int titsc_probe(struct platform_device *pdev)
 {
        struct titsc *ts_dev;
        struct input_dev *input_dev;
-       struct ti_tscadc_dev *tscadc_dev = pdev->dev.platform_data;
-       struct mfd_tscadc_board *pdata;
+       struct ti_tscadc_dev *tscadc_dev = ti_tscadc_dev_get(pdev);
        int err;
 
-       pdata = tscadc_dev->dev->platform_data;
-
-       if (!pdata) {
-               dev_err(&pdev->dev, "Could not find platform data\n");
-               return -EINVAL;
-       }
-
        /* Allocate memory for device */
        ts_dev = kzalloc(sizeof(struct titsc), GFP_KERNEL);
        input_dev = input_allocate_device();
@@ -286,9 +381,12 @@ static int titsc_probe(struct platform_device *pdev)
        ts_dev->mfd_tscadc = tscadc_dev;
        ts_dev->input = input_dev;
        ts_dev->irq = tscadc_dev->irq;
-       ts_dev->wires = pdata->tsc_init->wires;
-       ts_dev->x_plate_resistance = pdata->tsc_init->x_plate_resistance;
-       ts_dev->steps_to_configure = pdata->tsc_init->steps_to_configure;
+
+       err = titsc_parse_dt(pdev, ts_dev);
+       if (err) {
+               dev_err(&pdev->dev, "Could not find valid DT data.\n");
+               goto err_free_mem;
+       }
 
        err = request_irq(ts_dev->irq, titsc_irq,
                          0, pdev->dev.driver->name, ts_dev);
@@ -298,8 +396,14 @@ static int titsc_probe(struct platform_device *pdev)
        }
 
        titsc_writel(ts_dev, REG_IRQENABLE, IRQENB_FIFO0THRES);
+       err = titsc_config_wires(ts_dev);
+       if (err) {
+               dev_err(&pdev->dev, "wrong i/p wire configuration\n");
+               goto err_free_irq;
+       }
        titsc_step_config(ts_dev);
-       titsc_writel(ts_dev, REG_FIFO0THR, ts_dev->steps_to_configure);
+       titsc_writel(ts_dev, REG_FIFO0THR,
+                       ts_dev->coordinate_readouts * 2 + 2 - 1);
 
        input_dev->name = "ti-tsc";
        input_dev->dev.parent = &pdev->dev;
@@ -329,11 +433,16 @@ err_free_mem:
 
 static int titsc_remove(struct platform_device *pdev)
 {
-       struct ti_tscadc_dev *tscadc_dev = pdev->dev.platform_data;
-       struct titsc *ts_dev = tscadc_dev->tsc;
+       struct titsc *ts_dev = platform_get_drvdata(pdev);
+       u32 steps;
 
        free_irq(ts_dev->irq, ts_dev);
 
+       /* total steps followed by the enable mask */
+       steps = 2 * ts_dev->coordinate_readouts + 2;
+       steps = (1 << steps) - 1;
+       am335x_tsc_se_clr(ts_dev->mfd_tscadc, steps);
+
        input_unregister_device(ts_dev->input);
 
        kfree(ts_dev);
@@ -343,10 +452,11 @@ static int titsc_remove(struct platform_device *pdev)
 #ifdef CONFIG_PM
 static int titsc_suspend(struct device *dev)
 {
-       struct ti_tscadc_dev *tscadc_dev = dev->platform_data;
-       struct titsc *ts_dev = tscadc_dev->tsc;
+       struct titsc *ts_dev = dev_get_drvdata(dev);
+       struct ti_tscadc_dev *tscadc_dev;
        unsigned int idle;
 
+       tscadc_dev = ti_tscadc_dev_get(to_platform_device(dev));
        if (device_may_wakeup(tscadc_dev->dev)) {
                idle = titsc_readl(ts_dev, REG_IRQENABLE);
                titsc_writel(ts_dev, REG_IRQENABLE,
@@ -358,9 +468,10 @@ static int titsc_suspend(struct device *dev)
 
 static int titsc_resume(struct device *dev)
 {
-       struct ti_tscadc_dev *tscadc_dev = dev->platform_data;
-       struct titsc *ts_dev = tscadc_dev->tsc;
+       struct titsc *ts_dev = dev_get_drvdata(dev);
+       struct ti_tscadc_dev *tscadc_dev;
 
+       tscadc_dev = ti_tscadc_dev_get(to_platform_device(dev));
        if (device_may_wakeup(tscadc_dev->dev)) {
                titsc_writel(ts_dev, REG_IRQWAKEUP,
                                0x00);
@@ -368,7 +479,7 @@ static int titsc_resume(struct device *dev)
        }
        titsc_step_config(ts_dev);
        titsc_writel(ts_dev, REG_FIFO0THR,
-                       ts_dev->steps_to_configure);
+                       ts_dev->coordinate_readouts * 2 + 2 - 1);
        return 0;
 }
 
@@ -381,13 +492,20 @@ static const struct dev_pm_ops titsc_pm_ops = {
 #define TITSC_PM_OPS NULL
 #endif
 
+static const struct of_device_id ti_tsc_dt_ids[] = {
+       { .compatible = "ti,am3359-tsc", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, ti_tsc_dt_ids);
+
 static struct platform_driver ti_tsc_driver = {
        .probe  = titsc_probe,
        .remove = titsc_remove,
        .driver = {
-               .name   = "tsc",
+               .name   = "TI-am335x-tsc",
                .owner  = THIS_MODULE,
                .pm     = TITSC_PM_OPS,
+               .of_match_table = of_match_ptr(ti_tsc_dt_ids),
        },
 };
 module_platform_driver(ti_tsc_driver);
index 01730b2..820d85c 100644 (file)
@@ -269,4 +269,17 @@ config SPAPR_TCE_IOMMU
          Enables bits of IOMMU API required by VFIO. The iommu_ops
          is not implemented as it is not necessary for VFIO.
 
+config ARM_SMMU
+       bool "ARM Ltd. System MMU (SMMU) Support"
+       depends on ARM64 || (ARM_LPAE && OF)
+       select IOMMU_API
+       select ARM_DMA_USE_IOMMU if ARM
+       help
+         Support for implementations of the ARM System MMU architecture
+         versions 1 and 2. The driver supports both v7l and v8l table
+         formats with 4k and 64k page sizes.
+
+         Say Y here if your SoC includes an IOMMU device implementing
+         the ARM SMMU architecture.
+
 endif # IOMMU_SUPPORT
index ef0e520..bbe7041 100644 (file)
@@ -3,6 +3,7 @@ obj-$(CONFIG_OF_IOMMU)  += of_iommu.o
 obj-$(CONFIG_MSM_IOMMU) += msm_iommu.o msm_iommu_dev.o
 obj-$(CONFIG_AMD_IOMMU) += amd_iommu.o amd_iommu_init.o
 obj-$(CONFIG_AMD_IOMMU_V2) += amd_iommu_v2.o
+obj-$(CONFIG_ARM_SMMU) += arm-smmu.o
 obj-$(CONFIG_DMAR_TABLE) += dmar.o
 obj-$(CONFIG_INTEL_IOMMU) += iova.o intel-iommu.o
 obj-$(CONFIG_IRQ_REMAP) += intel_irq_remapping.o irq_remapping.o
index 21d02b0..6dc6594 100644 (file)
@@ -287,14 +287,27 @@ static struct pci_dev *get_isolation_root(struct pci_dev *pdev)
 
        /*
         * If it's a multifunction device that does not support our
-        * required ACS flags, add to the same group as function 0.
+        * required ACS flags, add to the same group as lowest numbered
+        * function that also does not suport the required ACS flags.
         */
        if (dma_pdev->multifunction &&
-           !pci_acs_enabled(dma_pdev, REQ_ACS_FLAGS))
-               swap_pci_ref(&dma_pdev,
-                            pci_get_slot(dma_pdev->bus,
-                                         PCI_DEVFN(PCI_SLOT(dma_pdev->devfn),
-                                         0)));
+           !pci_acs_enabled(dma_pdev, REQ_ACS_FLAGS)) {
+               u8 i, slot = PCI_SLOT(dma_pdev->devfn);
+
+               for (i = 0; i < 8; i++) {
+                       struct pci_dev *tmp;
+
+                       tmp = pci_get_slot(dma_pdev->bus, PCI_DEVFN(slot, i));
+                       if (!tmp)
+                               continue;
+
+                       if (!pci_acs_enabled(tmp, REQ_ACS_FLAGS)) {
+                               swap_pci_ref(&dma_pdev, tmp);
+                               break;
+                       }
+                       pci_dev_put(tmp);
+               }
+       }
 
        /*
         * Devices on the root bus go through the iommu.  If that's not us,
@@ -1484,6 +1497,10 @@ static unsigned long iommu_unmap_page(struct protection_domain *dom,
 
                        /* Large PTE found which maps this address */
                        unmap_size = PTE_PAGE_SIZE(*pte);
+
+                       /* Only unmap from the first pte in the page */
+                       if ((unmap_size - 1) & bus_addr)
+                               break;
                        count      = PAGE_SIZE_PTE_COUNT(unmap_size);
                        for (i = 0; i < count; i++)
                                pte[i] = 0ULL;
@@ -1493,7 +1510,7 @@ static unsigned long iommu_unmap_page(struct protection_domain *dom,
                unmapped += unmap_size;
        }
 
-       BUG_ON(!is_power_of_2(unmapped));
+       BUG_ON(unmapped && !is_power_of_2(unmapped));
 
        return unmapped;
 }
@@ -1893,34 +1910,59 @@ static void domain_id_free(int id)
        write_unlock_irqrestore(&amd_iommu_devtable_lock, flags);
 }
 
+#define DEFINE_FREE_PT_FN(LVL, FN)                             \
+static void free_pt_##LVL (unsigned long __pt)                 \
+{                                                              \
+       unsigned long p;                                        \
+       u64 *pt;                                                \
+       int i;                                                  \
+                                                               \
+       pt = (u64 *)__pt;                                       \
+                                                               \
+       for (i = 0; i < 512; ++i) {                             \
+               if (!IOMMU_PTE_PRESENT(pt[i]))                  \
+                       continue;                               \
+                                                               \
+               p = (unsigned long)IOMMU_PTE_PAGE(pt[i]);       \
+               FN(p);                                          \
+       }                                                       \
+       free_page((unsigned long)pt);                           \
+}
+
+DEFINE_FREE_PT_FN(l2, free_page)
+DEFINE_FREE_PT_FN(l3, free_pt_l2)
+DEFINE_FREE_PT_FN(l4, free_pt_l3)
+DEFINE_FREE_PT_FN(l5, free_pt_l4)
+DEFINE_FREE_PT_FN(l6, free_pt_l5)
+
 static void free_pagetable(struct protection_domain *domain)
 {
-       int i, j;
-       u64 *p1, *p2, *p3;
-
-       p1 = domain->pt_root;
-
-       if (!p1)
-               return;
-
-       for (i = 0; i < 512; ++i) {
-               if (!IOMMU_PTE_PRESENT(p1[i]))
-                       continue;
-
-               p2 = IOMMU_PTE_PAGE(p1[i]);
-               for (j = 0; j < 512; ++j) {
-                       if (!IOMMU_PTE_PRESENT(p2[j]))
-                               continue;
-                       p3 = IOMMU_PTE_PAGE(p2[j]);
-                       free_page((unsigned long)p3);
-               }
+       unsigned long root = (unsigned long)domain->pt_root;
 
-               free_page((unsigned long)p2);
+       switch (domain->mode) {
+       case PAGE_MODE_NONE:
+               break;
+       case PAGE_MODE_1_LEVEL:
+               free_page(root);
+               break;
+       case PAGE_MODE_2_LEVEL:
+               free_pt_l2(root);
+               break;
+       case PAGE_MODE_3_LEVEL:
+               free_pt_l3(root);
+               break;
+       case PAGE_MODE_4_LEVEL:
+               free_pt_l4(root);
+               break;
+       case PAGE_MODE_5_LEVEL:
+               free_pt_l5(root);
+               break;
+       case PAGE_MODE_6_LEVEL:
+               free_pt_l6(root);
+               break;
+       default:
+               BUG();
        }
-
-       free_page((unsigned long)p1);
-
-       domain->pt_root = NULL;
 }
 
 static void free_gcr3_tbl_level1(u64 *tbl)
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
new file mode 100644 (file)
index 0000000..ebd0a4c
--- /dev/null
@@ -0,0 +1,1969 @@
+/*
+ * IOMMU API for ARM architected SMMU implementations.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright (C) 2013 ARM Limited
+ *
+ * Author: Will Deacon <will.deacon@arm.com>
+ *
+ * This driver currently supports:
+ *     - SMMUv1 and v2 implementations
+ *     - Stream-matching and stream-indexing
+ *     - v7/v8 long-descriptor format
+ *     - Non-secure access to the SMMU
+ *     - 4k and 64k pages, with contiguous pte hints.
+ *     - Up to 39-bit addressing
+ *     - Context fault reporting
+ */
+
+#define pr_fmt(fmt) "arm-smmu: " fmt
+
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/iommu.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+#include <linux/amba/bus.h>
+
+#include <asm/pgalloc.h>
+
+/* Maximum number of stream IDs assigned to a single device */
+#define MAX_MASTER_STREAMIDS           8
+
+/* Maximum number of context banks per SMMU */
+#define ARM_SMMU_MAX_CBS               128
+
+/* Maximum number of mapping groups per SMMU */
+#define ARM_SMMU_MAX_SMRS              128
+
+/* Number of VMIDs per SMMU */
+#define ARM_SMMU_NUM_VMIDS             256
+
+/* SMMU global address space */
+#define ARM_SMMU_GR0(smmu)             ((smmu)->base)
+#define ARM_SMMU_GR1(smmu)             ((smmu)->base + (smmu)->pagesize)
+
+/* Page table bits */
+#define ARM_SMMU_PTE_PAGE              (((pteval_t)3) << 0)
+#define ARM_SMMU_PTE_CONT              (((pteval_t)1) << 52)
+#define ARM_SMMU_PTE_AF                        (((pteval_t)1) << 10)
+#define ARM_SMMU_PTE_SH_NS             (((pteval_t)0) << 8)
+#define ARM_SMMU_PTE_SH_OS             (((pteval_t)2) << 8)
+#define ARM_SMMU_PTE_SH_IS             (((pteval_t)3) << 8)
+
+#if PAGE_SIZE == SZ_4K
+#define ARM_SMMU_PTE_CONT_ENTRIES      16
+#elif PAGE_SIZE == SZ_64K
+#define ARM_SMMU_PTE_CONT_ENTRIES      32
+#else
+#define ARM_SMMU_PTE_CONT_ENTRIES      1
+#endif
+
+#define ARM_SMMU_PTE_CONT_SIZE         (PAGE_SIZE * ARM_SMMU_PTE_CONT_ENTRIES)
+#define ARM_SMMU_PTE_CONT_MASK         (~(ARM_SMMU_PTE_CONT_SIZE - 1))
+#define ARM_SMMU_PTE_HWTABLE_SIZE      (PTRS_PER_PTE * sizeof(pte_t))
+
+/* Stage-1 PTE */
+#define ARM_SMMU_PTE_AP_UNPRIV         (((pteval_t)1) << 6)
+#define ARM_SMMU_PTE_AP_RDONLY         (((pteval_t)2) << 6)
+#define ARM_SMMU_PTE_ATTRINDX_SHIFT    2
+
+/* Stage-2 PTE */
+#define ARM_SMMU_PTE_HAP_FAULT         (((pteval_t)0) << 6)
+#define ARM_SMMU_PTE_HAP_READ          (((pteval_t)1) << 6)
+#define ARM_SMMU_PTE_HAP_WRITE         (((pteval_t)2) << 6)
+#define ARM_SMMU_PTE_MEMATTR_OIWB      (((pteval_t)0xf) << 2)
+#define ARM_SMMU_PTE_MEMATTR_NC                (((pteval_t)0x5) << 2)
+#define ARM_SMMU_PTE_MEMATTR_DEV       (((pteval_t)0x1) << 2)
+
+/* Configuration registers */
+#define ARM_SMMU_GR0_sCR0              0x0
+#define sCR0_CLIENTPD                  (1 << 0)
+#define sCR0_GFRE                      (1 << 1)
+#define sCR0_GFIE                      (1 << 2)
+#define sCR0_GCFGFRE                   (1 << 4)
+#define sCR0_GCFGFIE                   (1 << 5)
+#define sCR0_USFCFG                    (1 << 10)
+#define sCR0_VMIDPNE                   (1 << 11)
+#define sCR0_PTM                       (1 << 12)
+#define sCR0_FB                                (1 << 13)
+#define sCR0_BSU_SHIFT                 14
+#define sCR0_BSU_MASK                  0x3
+
+/* Identification registers */
+#define ARM_SMMU_GR0_ID0               0x20
+#define ARM_SMMU_GR0_ID1               0x24
+#define ARM_SMMU_GR0_ID2               0x28
+#define ARM_SMMU_GR0_ID3               0x2c
+#define ARM_SMMU_GR0_ID4               0x30
+#define ARM_SMMU_GR0_ID5               0x34
+#define ARM_SMMU_GR0_ID6               0x38
+#define ARM_SMMU_GR0_ID7               0x3c
+#define ARM_SMMU_GR0_sGFSR             0x48
+#define ARM_SMMU_GR0_sGFSYNR0          0x50
+#define ARM_SMMU_GR0_sGFSYNR1          0x54
+#define ARM_SMMU_GR0_sGFSYNR2          0x58
+#define ARM_SMMU_GR0_PIDR0             0xfe0
+#define ARM_SMMU_GR0_PIDR1             0xfe4
+#define ARM_SMMU_GR0_PIDR2             0xfe8
+
+#define ID0_S1TS                       (1 << 30)
+#define ID0_S2TS                       (1 << 29)
+#define ID0_NTS                                (1 << 28)
+#define ID0_SMS                                (1 << 27)
+#define ID0_PTFS_SHIFT                 24
+#define ID0_PTFS_MASK                  0x2
+#define ID0_PTFS_V8_ONLY               0x2
+#define ID0_CTTW                       (1 << 14)
+#define ID0_NUMIRPT_SHIFT              16
+#define ID0_NUMIRPT_MASK               0xff
+#define ID0_NUMSMRG_SHIFT              0
+#define ID0_NUMSMRG_MASK               0xff
+
+#define ID1_PAGESIZE                   (1 << 31)
+#define ID1_NUMPAGENDXB_SHIFT          28
+#define ID1_NUMPAGENDXB_MASK           7
+#define ID1_NUMS2CB_SHIFT              16
+#define ID1_NUMS2CB_MASK               0xff
+#define ID1_NUMCB_SHIFT                        0
+#define ID1_NUMCB_MASK                 0xff
+
+#define ID2_OAS_SHIFT                  4
+#define ID2_OAS_MASK                   0xf
+#define ID2_IAS_SHIFT                  0
+#define ID2_IAS_MASK                   0xf
+#define ID2_UBS_SHIFT                  8
+#define ID2_UBS_MASK                   0xf
+#define ID2_PTFS_4K                    (1 << 12)
+#define ID2_PTFS_16K                   (1 << 13)
+#define ID2_PTFS_64K                   (1 << 14)
+
+#define PIDR2_ARCH_SHIFT               4
+#define PIDR2_ARCH_MASK                        0xf
+
+/* Global TLB invalidation */
+#define ARM_SMMU_GR0_STLBIALL          0x60
+#define ARM_SMMU_GR0_TLBIVMID          0x64
+#define ARM_SMMU_GR0_TLBIALLNSNH       0x68
+#define ARM_SMMU_GR0_TLBIALLH          0x6c
+#define ARM_SMMU_GR0_sTLBGSYNC         0x70
+#define ARM_SMMU_GR0_sTLBGSTATUS       0x74
+#define sTLBGSTATUS_GSACTIVE           (1 << 0)
+#define TLB_LOOP_TIMEOUT               1000000 /* 1s! */
+
+/* Stream mapping registers */
+#define ARM_SMMU_GR0_SMR(n)            (0x800 + ((n) << 2))
+#define SMR_VALID                      (1 << 31)
+#define SMR_MASK_SHIFT                 16
+#define SMR_MASK_MASK                  0x7fff
+#define SMR_ID_SHIFT                   0
+#define SMR_ID_MASK                    0x7fff
+
+#define ARM_SMMU_GR0_S2CR(n)           (0xc00 + ((n) << 2))
+#define S2CR_CBNDX_SHIFT               0
+#define S2CR_CBNDX_MASK                        0xff
+#define S2CR_TYPE_SHIFT                        16
+#define S2CR_TYPE_MASK                 0x3
+#define S2CR_TYPE_TRANS                        (0 << S2CR_TYPE_SHIFT)
+#define S2CR_TYPE_BYPASS               (1 << S2CR_TYPE_SHIFT)
+#define S2CR_TYPE_FAULT                        (2 << S2CR_TYPE_SHIFT)
+
+/* Context bank attribute registers */
+#define ARM_SMMU_GR1_CBAR(n)           (0x0 + ((n) << 2))
+#define CBAR_VMID_SHIFT                        0
+#define CBAR_VMID_MASK                 0xff
+#define CBAR_S1_MEMATTR_SHIFT          12
+#define CBAR_S1_MEMATTR_MASK           0xf
+#define CBAR_S1_MEMATTR_WB             0xf
+#define CBAR_TYPE_SHIFT                        16
+#define CBAR_TYPE_MASK                 0x3
+#define CBAR_TYPE_S2_TRANS             (0 << CBAR_TYPE_SHIFT)
+#define CBAR_TYPE_S1_TRANS_S2_BYPASS   (1 << CBAR_TYPE_SHIFT)
+#define CBAR_TYPE_S1_TRANS_S2_FAULT    (2 << CBAR_TYPE_SHIFT)
+#define CBAR_TYPE_S1_TRANS_S2_TRANS    (3 << CBAR_TYPE_SHIFT)
+#define CBAR_IRPTNDX_SHIFT             24
+#define CBAR_IRPTNDX_MASK              0xff
+
+#define ARM_SMMU_GR1_CBA2R(n)          (0x800 + ((n) << 2))
+#define CBA2R_RW64_32BIT               (0 << 0)
+#define CBA2R_RW64_64BIT               (1 << 0)
+
+/* Translation context bank */
+#define ARM_SMMU_CB_BASE(smmu)         ((smmu)->base + ((smmu)->size >> 1))
+#define ARM_SMMU_CB(smmu, n)           ((n) * (smmu)->pagesize)
+
+#define ARM_SMMU_CB_SCTLR              0x0
+#define ARM_SMMU_CB_RESUME             0x8
+#define ARM_SMMU_CB_TTBCR2             0x10
+#define ARM_SMMU_CB_TTBR0_LO           0x20
+#define ARM_SMMU_CB_TTBR0_HI           0x24
+#define ARM_SMMU_CB_TTBCR              0x30
+#define ARM_SMMU_CB_S1_MAIR0           0x38
+#define ARM_SMMU_CB_FSR                        0x58
+#define ARM_SMMU_CB_FAR_LO             0x60
+#define ARM_SMMU_CB_FAR_HI             0x64
+#define ARM_SMMU_CB_FSYNR0             0x68
+
+#define SCTLR_S1_ASIDPNE               (1 << 12)
+#define SCTLR_CFCFG                    (1 << 7)
+#define SCTLR_CFIE                     (1 << 6)
+#define SCTLR_CFRE                     (1 << 5)
+#define SCTLR_E                                (1 << 4)
+#define SCTLR_AFE                      (1 << 2)
+#define SCTLR_TRE                      (1 << 1)
+#define SCTLR_M                                (1 << 0)
+#define SCTLR_EAE_SBOP                 (SCTLR_AFE | SCTLR_TRE)
+
+#define RESUME_RETRY                   (0 << 0)
+#define RESUME_TERMINATE               (1 << 0)
+
+#define TTBCR_EAE                      (1 << 31)
+
+#define TTBCR_PASIZE_SHIFT             16
+#define TTBCR_PASIZE_MASK              0x7
+
+#define TTBCR_TG0_4K                   (0 << 14)
+#define TTBCR_TG0_64K                  (1 << 14)
+
+#define TTBCR_SH0_SHIFT                        12
+#define TTBCR_SH0_MASK                 0x3
+#define TTBCR_SH_NS                    0
+#define TTBCR_SH_OS                    2
+#define TTBCR_SH_IS                    3
+
+#define TTBCR_ORGN0_SHIFT              10
+#define TTBCR_IRGN0_SHIFT              8
+#define TTBCR_RGN_MASK                 0x3
+#define TTBCR_RGN_NC                   0
+#define TTBCR_RGN_WBWA                 1
+#define TTBCR_RGN_WT                   2
+#define TTBCR_RGN_WB                   3
+
+#define TTBCR_SL0_SHIFT                        6
+#define TTBCR_SL0_MASK                 0x3
+#define TTBCR_SL0_LVL_2                        0
+#define TTBCR_SL0_LVL_1                        1
+
+#define TTBCR_T1SZ_SHIFT               16
+#define TTBCR_T0SZ_SHIFT               0
+#define TTBCR_SZ_MASK                  0xf
+
+#define TTBCR2_SEP_SHIFT               15
+#define TTBCR2_SEP_MASK                        0x7
+
+#define TTBCR2_PASIZE_SHIFT            0
+#define TTBCR2_PASIZE_MASK             0x7
+
+/* Common definitions for PASize and SEP fields */
+#define TTBCR2_ADDR_32                 0
+#define TTBCR2_ADDR_36                 1
+#define TTBCR2_ADDR_40                 2
+#define TTBCR2_ADDR_42                 3
+#define TTBCR2_ADDR_44                 4
+#define TTBCR2_ADDR_48                 5
+
+#define MAIR_ATTR_SHIFT(n)             ((n) << 3)
+#define MAIR_ATTR_MASK                 0xff
+#define MAIR_ATTR_DEVICE               0x04
+#define MAIR_ATTR_NC                   0x44
+#define MAIR_ATTR_WBRWA                        0xff
+#define MAIR_ATTR_IDX_NC               0
+#define MAIR_ATTR_IDX_CACHE            1
+#define MAIR_ATTR_IDX_DEV              2
+
+#define FSR_MULTI                      (1 << 31)
+#define FSR_SS                         (1 << 30)
+#define FSR_UUT                                (1 << 8)
+#define FSR_ASF                                (1 << 7)
+#define FSR_TLBLKF                     (1 << 6)
+#define FSR_TLBMCF                     (1 << 5)
+#define FSR_EF                         (1 << 4)
+#define FSR_PF                         (1 << 3)
+#define FSR_AFF                                (1 << 2)
+#define FSR_TF                         (1 << 1)
+
+#define FSR_IGN                                (FSR_AFF | FSR_ASF | FSR_TLBMCF |       \
+                                        FSR_TLBLKF)
+#define FSR_FAULT                      (FSR_MULTI | FSR_SS | FSR_UUT |         \
+                                        FSR_EF | FSR_PF | FSR_TF)
+
+#define FSYNR0_WNR                     (1 << 4)
+
+struct arm_smmu_smr {
+       u8                              idx;
+       u16                             mask;
+       u16                             id;
+};
+
+struct arm_smmu_master {
+       struct device_node              *of_node;
+
+       /*
+        * The following is specific to the master's position in the
+        * SMMU chain.
+        */
+       struct rb_node                  node;
+       int                             num_streamids;
+       u16                             streamids[MAX_MASTER_STREAMIDS];
+
+       /*
+        * We only need to allocate these on the root SMMU, as we
+        * configure unmatched streams to bypass translation.
+        */
+       struct arm_smmu_smr             *smrs;
+};
+
+struct arm_smmu_device {
+       struct device                   *dev;
+       struct device_node              *parent_of_node;
+
+       void __iomem                    *base;
+       unsigned long                   size;
+       unsigned long                   pagesize;
+
+#define ARM_SMMU_FEAT_COHERENT_WALK    (1 << 0)
+#define ARM_SMMU_FEAT_STREAM_MATCH     (1 << 1)
+#define ARM_SMMU_FEAT_TRANS_S1         (1 << 2)
+#define ARM_SMMU_FEAT_TRANS_S2         (1 << 3)
+#define ARM_SMMU_FEAT_TRANS_NESTED     (1 << 4)
+       u32                             features;
+       int                             version;
+
+       u32                             num_context_banks;
+       u32                             num_s2_context_banks;
+       DECLARE_BITMAP(context_map, ARM_SMMU_MAX_CBS);
+       atomic_t                        irptndx;
+
+       u32                             num_mapping_groups;
+       DECLARE_BITMAP(smr_map, ARM_SMMU_MAX_SMRS);
+
+       unsigned long                   input_size;
+       unsigned long                   s1_output_size;
+       unsigned long                   s2_output_size;
+
+       u32                             num_global_irqs;
+       u32                             num_context_irqs;
+       unsigned int                    *irqs;
+
+       DECLARE_BITMAP(vmid_map, ARM_SMMU_NUM_VMIDS);
+
+       struct list_head                list;
+       struct rb_root                  masters;
+};
+
+struct arm_smmu_cfg {
+       struct arm_smmu_device          *smmu;
+       u8                              vmid;
+       u8                              cbndx;
+       u8                              irptndx;
+       u32                             cbar;
+       pgd_t                           *pgd;
+};
+
+struct arm_smmu_domain {
+       /*
+        * A domain can span across multiple, chained SMMUs and requires
+        * all devices within the domain to follow the same translation
+        * path.
+        */
+       struct arm_smmu_device          *leaf_smmu;
+       struct arm_smmu_cfg             root_cfg;
+       phys_addr_t                     output_mask;
+
+       spinlock_t                      lock;
+};
+
+static DEFINE_SPINLOCK(arm_smmu_devices_lock);
+static LIST_HEAD(arm_smmu_devices);
+
+static struct arm_smmu_master *find_smmu_master(struct arm_smmu_device *smmu,
+                                               struct device_node *dev_node)
+{
+       struct rb_node *node = smmu->masters.rb_node;
+
+       while (node) {
+               struct arm_smmu_master *master;
+               master = container_of(node, struct arm_smmu_master, node);
+
+               if (dev_node < master->of_node)
+                       node = node->rb_left;
+               else if (dev_node > master->of_node)
+                       node = node->rb_right;
+               else
+                       return master;
+       }
+
+       return NULL;
+}
+
+static int insert_smmu_master(struct arm_smmu_device *smmu,
+                             struct arm_smmu_master *master)
+{
+       struct rb_node **new, *parent;
+
+       new = &smmu->masters.rb_node;
+       parent = NULL;
+       while (*new) {
+               struct arm_smmu_master *this;
+               this = container_of(*new, struct arm_smmu_master, node);
+
+               parent = *new;
+               if (master->of_node < this->of_node)
+                       new = &((*new)->rb_left);
+               else if (master->of_node > this->of_node)
+                       new = &((*new)->rb_right);
+               else
+                       return -EEXIST;
+       }
+
+       rb_link_node(&master->node, parent, new);
+       rb_insert_color(&master->node, &smmu->masters);
+       return 0;
+}
+
+static int register_smmu_master(struct arm_smmu_device *smmu,
+                               struct device *dev,
+                               struct of_phandle_args *masterspec)
+{
+       int i;
+       struct arm_smmu_master *master;
+
+       master = find_smmu_master(smmu, masterspec->np);
+       if (master) {
+               dev_err(dev,
+                       "rejecting multiple registrations for master device %s\n",
+                       masterspec->np->name);
+               return -EBUSY;
+       }
+
+       if (masterspec->args_count > MAX_MASTER_STREAMIDS) {
+               dev_err(dev,
+                       "reached maximum number (%d) of stream IDs for master device %s\n",
+                       MAX_MASTER_STREAMIDS, masterspec->np->name);
+               return -ENOSPC;
+       }
+
+       master = devm_kzalloc(dev, sizeof(*master), GFP_KERNEL);
+       if (!master)
+               return -ENOMEM;
+
+       master->of_node         = masterspec->np;
+       master->num_streamids   = masterspec->args_count;
+
+       for (i = 0; i < master->num_streamids; ++i)
+               master->streamids[i] = masterspec->args[i];
+
+       return insert_smmu_master(smmu, master);
+}
+
+static struct arm_smmu_device *find_parent_smmu(struct arm_smmu_device *smmu)
+{
+       struct arm_smmu_device *parent;
+
+       if (!smmu->parent_of_node)
+               return NULL;
+
+       spin_lock(&arm_smmu_devices_lock);
+       list_for_each_entry(parent, &arm_smmu_devices, list)
+               if (parent->dev->of_node == smmu->parent_of_node)
+                       goto out_unlock;
+
+       parent = NULL;
+       dev_warn(smmu->dev,
+                "Failed to find SMMU parent despite parent in DT\n");
+out_unlock:
+       spin_unlock(&arm_smmu_devices_lock);
+       return parent;
+}
+
+static int __arm_smmu_alloc_bitmap(unsigned long *map, int start, int end)
+{
+       int idx;
+
+       do {
+               idx = find_next_zero_bit(map, end, start);
+               if (idx == end)
+                       return -ENOSPC;
+       } while (test_and_set_bit(idx, map));
+
+       return idx;
+}
+
+static void __arm_smmu_free_bitmap(unsigned long *map, int idx)
+{
+       clear_bit(idx, map);
+}
+
+/* Wait for any pending TLB invalidations to complete */
+static void arm_smmu_tlb_sync(struct arm_smmu_device *smmu)
+{
+       int count = 0;
+       void __iomem *gr0_base = ARM_SMMU_GR0(smmu);
+
+       writel_relaxed(0, gr0_base + ARM_SMMU_GR0_sTLBGSYNC);
+       while (readl_relaxed(gr0_base + ARM_SMMU_GR0_sTLBGSTATUS)
+              & sTLBGSTATUS_GSACTIVE) {
+               cpu_relax();
+               if (++count == TLB_LOOP_TIMEOUT) {
+                       dev_err_ratelimited(smmu->dev,
+                       "TLB sync timed out -- SMMU may be deadlocked\n");
+                       return;
+               }
+               udelay(1);
+       }
+}
+
+static irqreturn_t arm_smmu_context_fault(int irq, void *dev)
+{
+       int flags, ret;
+       u32 fsr, far, fsynr, resume;
+       unsigned long iova;
+       struct iommu_domain *domain = dev;
+       struct arm_smmu_domain *smmu_domain = domain->priv;
+       struct arm_smmu_cfg *root_cfg = &smmu_domain->root_cfg;
+       struct arm_smmu_device *smmu = root_cfg->smmu;
+       void __iomem *cb_base;
+
+       cb_base = ARM_SMMU_CB_BASE(smmu) + ARM_SMMU_CB(smmu, root_cfg->cbndx);
+       fsr = readl_relaxed(cb_base + ARM_SMMU_CB_FSR);
+
+       if (!(fsr & FSR_FAULT))
+               return IRQ_NONE;
+
+       if (fsr & FSR_IGN)
+               dev_err_ratelimited(smmu->dev,
+                                   "Unexpected context fault (fsr 0x%u)\n",
+                                   fsr);
+
+       fsynr = readl_relaxed(cb_base + ARM_SMMU_CB_FSYNR0);
+       flags = fsynr & FSYNR0_WNR ? IOMMU_FAULT_WRITE : IOMMU_FAULT_READ;
+
+       far = readl_relaxed(cb_base + ARM_SMMU_CB_FAR_LO);
+       iova = far;
+#ifdef CONFIG_64BIT
+       far = readl_relaxed(cb_base + ARM_SMMU_CB_FAR_HI);
+       iova |= ((unsigned long)far << 32);
+#endif
+
+       if (!report_iommu_fault(domain, smmu->dev, iova, flags)) {
+               ret = IRQ_HANDLED;
+               resume = RESUME_RETRY;
+       } else {
+               ret = IRQ_NONE;
+               resume = RESUME_TERMINATE;
+       }
+
+       /* Clear the faulting FSR */
+       writel(fsr, cb_base + ARM_SMMU_CB_FSR);
+
+       /* Retry or terminate any stalled transactions */
+       if (fsr & FSR_SS)
+               writel_relaxed(resume, cb_base + ARM_SMMU_CB_RESUME);
+
+       return ret;
+}
+
+static irqreturn_t arm_smmu_global_fault(int irq, void *dev)
+{
+       u32 gfsr, gfsynr0, gfsynr1, gfsynr2;
+       struct arm_smmu_device *smmu = dev;
+       void __iomem *gr0_base = ARM_SMMU_GR0(smmu);
+
+       gfsr = readl_relaxed(gr0_base + ARM_SMMU_GR0_sGFSR);
+       gfsynr0 = readl_relaxed(gr0_base + ARM_SMMU_GR0_sGFSYNR0);
+       gfsynr1 = readl_relaxed(gr0_base + ARM_SMMU_GR0_sGFSYNR1);
+       gfsynr2 = readl_relaxed(gr0_base + ARM_SMMU_GR0_sGFSYNR2);
+
+       dev_err_ratelimited(smmu->dev,
+               "Unexpected global fault, this could be serious\n");
+       dev_err_ratelimited(smmu->dev,
+               "\tGFSR 0x%08x, GFSYNR0 0x%08x, GFSYNR1 0x%08x, GFSYNR2 0x%08x\n",
+               gfsr, gfsynr0, gfsynr1, gfsynr2);
+
+       writel(gfsr, gr0_base + ARM_SMMU_GR0_sGFSR);
+       return IRQ_NONE;
+}
+
+static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain)
+{
+       u32 reg;
+       bool stage1;
+       struct arm_smmu_cfg *root_cfg = &smmu_domain->root_cfg;
+       struct arm_smmu_device *smmu = root_cfg->smmu;
+       void __iomem *cb_base, *gr0_base, *gr1_base;
+
+       gr0_base = ARM_SMMU_GR0(smmu);
+       gr1_base = ARM_SMMU_GR1(smmu);
+       stage1 = root_cfg->cbar != CBAR_TYPE_S2_TRANS;
+       cb_base = ARM_SMMU_CB_BASE(smmu) + ARM_SMMU_CB(smmu, root_cfg->cbndx);
+
+       /* CBAR */
+       reg = root_cfg->cbar |
+             (root_cfg->vmid << CBAR_VMID_SHIFT);
+       if (smmu->version == 1)
+             reg |= root_cfg->irptndx << CBAR_IRPTNDX_SHIFT;
+
+       /* Use the weakest memory type, so it is overridden by the pte */
+       if (stage1)
+               reg |= (CBAR_S1_MEMATTR_WB << CBAR_S1_MEMATTR_SHIFT);
+       writel_relaxed(reg, gr1_base + ARM_SMMU_GR1_CBAR(root_cfg->cbndx));
+
+       if (smmu->version > 1) {
+               /* CBA2R */
+#ifdef CONFIG_64BIT
+               reg = CBA2R_RW64_64BIT;
+#else
+               reg = CBA2R_RW64_32BIT;
+#endif
+               writel_relaxed(reg,
+                              gr1_base + ARM_SMMU_GR1_CBA2R(root_cfg->cbndx));
+
+               /* TTBCR2 */
+               switch (smmu->input_size) {
+               case 32:
+                       reg = (TTBCR2_ADDR_32 << TTBCR2_SEP_SHIFT);
+                       break;
+               case 36:
+                       reg = (TTBCR2_ADDR_36 << TTBCR2_SEP_SHIFT);
+                       break;
+               case 39:
+                       reg = (TTBCR2_ADDR_40 << TTBCR2_SEP_SHIFT);
+                       break;
+               case 42:
+                       reg = (TTBCR2_ADDR_42 << TTBCR2_SEP_SHIFT);
+                       break;
+               case 44:
+                       reg = (TTBCR2_ADDR_44 << TTBCR2_SEP_SHIFT);
+                       break;
+               case 48:
+                       reg = (TTBCR2_ADDR_48 << TTBCR2_SEP_SHIFT);
+                       break;
+               }
+
+               switch (smmu->s1_output_size) {
+               case 32:
+                       reg |= (TTBCR2_ADDR_32 << TTBCR2_PASIZE_SHIFT);
+                       break;
+               case 36:
+                       reg |= (TTBCR2_ADDR_36 << TTBCR2_PASIZE_SHIFT);
+                       break;
+               case 39:
+                       reg |= (TTBCR2_ADDR_40 << TTBCR2_PASIZE_SHIFT);
+                       break;
+               case 42:
+                       reg |= (TTBCR2_ADDR_42 << TTBCR2_PASIZE_SHIFT);
+                       break;
+               case 44:
+                       reg |= (TTBCR2_ADDR_44 << TTBCR2_PASIZE_SHIFT);
+                       break;
+               case 48:
+                       reg |= (TTBCR2_ADDR_48 << TTBCR2_PASIZE_SHIFT);
+                       break;
+               }
+
+               if (stage1)
+                       writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBCR2);
+       }
+
+       /* TTBR0 */
+       reg = __pa(root_cfg->pgd);
+#ifndef __BIG_ENDIAN
+       writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBR0_LO);
+       reg = (phys_addr_t)__pa(root_cfg->pgd) >> 32;
+       writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBR0_HI);
+#else
+       writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBR0_HI);
+       reg = (phys_addr_t)__pa(root_cfg->pgd) >> 32;
+       writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBR0_LO);
+#endif
+
+       /*
+        * TTBCR
+        * We use long descriptor, with inner-shareable WBWA tables in TTBR0.
+        */
+       if (smmu->version > 1) {
+               if (PAGE_SIZE == SZ_4K)
+                       reg = TTBCR_TG0_4K;
+               else
+                       reg = TTBCR_TG0_64K;
+
+               if (!stage1) {
+                       switch (smmu->s2_output_size) {
+                       case 32:
+                               reg |= (TTBCR2_ADDR_32 << TTBCR_PASIZE_SHIFT);
+                               break;
+                       case 36:
+                               reg |= (TTBCR2_ADDR_36 << TTBCR_PASIZE_SHIFT);
+                               break;
+                       case 40:
+                               reg |= (TTBCR2_ADDR_40 << TTBCR_PASIZE_SHIFT);
+                               break;
+                       case 42:
+                               reg |= (TTBCR2_ADDR_42 << TTBCR_PASIZE_SHIFT);
+                               break;
+                       case 44:
+                               reg |= (TTBCR2_ADDR_44 << TTBCR_PASIZE_SHIFT);
+                               break;
+                       case 48:
+                               reg |= (TTBCR2_ADDR_48 << TTBCR_PASIZE_SHIFT);
+                               break;
+                       }
+               } else {
+                       reg |= (64 - smmu->s1_output_size) << TTBCR_T0SZ_SHIFT;
+               }
+       } else {
+               reg = 0;
+       }
+
+       reg |= TTBCR_EAE |
+             (TTBCR_SH_IS << TTBCR_SH0_SHIFT) |
+             (TTBCR_RGN_WBWA << TTBCR_ORGN0_SHIFT) |
+             (TTBCR_RGN_WBWA << TTBCR_IRGN0_SHIFT) |
+             (TTBCR_SL0_LVL_1 << TTBCR_SL0_SHIFT);
+       writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBCR);
+
+       /* MAIR0 (stage-1 only) */
+       if (stage1) {
+               reg = (MAIR_ATTR_NC << MAIR_ATTR_SHIFT(MAIR_ATTR_IDX_NC)) |
+                     (MAIR_ATTR_WBRWA << MAIR_ATTR_SHIFT(MAIR_ATTR_IDX_CACHE)) |
+                     (MAIR_ATTR_DEVICE << MAIR_ATTR_SHIFT(MAIR_ATTR_IDX_DEV));
+               writel_relaxed(reg, cb_base + ARM_SMMU_CB_S1_MAIR0);
+       }
+
+       /* Nuke the TLB */
+       writel_relaxed(root_cfg->vmid, gr0_base + ARM_SMMU_GR0_TLBIVMID);
+       arm_smmu_tlb_sync(smmu);
+
+       /* SCTLR */
+       reg = SCTLR_CFCFG | SCTLR_CFIE | SCTLR_CFRE | SCTLR_M | SCTLR_EAE_SBOP;
+       if (stage1)
+               reg |= SCTLR_S1_ASIDPNE;
+#ifdef __BIG_ENDIAN
+       reg |= SCTLR_E;
+#endif
+       writel(reg, cb_base + ARM_SMMU_CB_SCTLR);
+}
+
+static int arm_smmu_init_domain_context(struct iommu_domain *domain,
+                                       struct device *dev)
+{
+       int irq, ret, start;
+       struct arm_smmu_domain *smmu_domain = domain->priv;
+       struct arm_smmu_cfg *root_cfg = &smmu_domain->root_cfg;
+       struct arm_smmu_device *smmu, *parent;
+
+       /*
+        * Walk the SMMU chain to find the root device for this chain.
+        * We assume that no masters have translations which terminate
+        * early, and therefore check that the root SMMU does indeed have
+        * a StreamID for the master in question.
+        */
+       parent = dev->archdata.iommu;
+       smmu_domain->output_mask = -1;
+       do {
+               smmu = parent;
+               smmu_domain->output_mask &= (1ULL << smmu->s2_output_size) - 1;
+       } while ((parent = find_parent_smmu(smmu)));
+
+       if (!find_smmu_master(smmu, dev->of_node)) {
+               dev_err(dev, "unable to find root SMMU for device\n");
+               return -ENODEV;
+       }
+
+       ret = __arm_smmu_alloc_bitmap(smmu->vmid_map, 0, ARM_SMMU_NUM_VMIDS);
+       if (IS_ERR_VALUE(ret))
+               return ret;
+
+       root_cfg->vmid = ret;
+       if (smmu->features & ARM_SMMU_FEAT_TRANS_NESTED) {
+               /*
+                * We will likely want to change this if/when KVM gets
+                * involved.
+                */
+               root_cfg->cbar = CBAR_TYPE_S1_TRANS_S2_BYPASS;
+               start = smmu->num_s2_context_banks;
+       } else if (smmu->features & ARM_SMMU_FEAT_TRANS_S2) {
+               root_cfg->cbar = CBAR_TYPE_S2_TRANS;
+               start = 0;
+       } else {
+               root_cfg->cbar = CBAR_TYPE_S1_TRANS_S2_BYPASS;
+               start = smmu->num_s2_context_banks;
+       }
+
+       ret = __arm_smmu_alloc_bitmap(smmu->context_map, start,
+                                     smmu->num_context_banks);
+       if (IS_ERR_VALUE(ret))
+               goto out_free_vmid;
+
+       root_cfg->cbndx = ret;
+
+       if (smmu->version == 1) {
+               root_cfg->irptndx = atomic_inc_return(&smmu->irptndx);
+               root_cfg->irptndx %= smmu->num_context_irqs;
+       } else {
+               root_cfg->irptndx = root_cfg->cbndx;
+       }
+
+       irq = smmu->irqs[smmu->num_global_irqs + root_cfg->irptndx];
+       ret = request_irq(irq, arm_smmu_context_fault, IRQF_SHARED,
+                         "arm-smmu-context-fault", domain);
+       if (IS_ERR_VALUE(ret)) {
+               dev_err(smmu->dev, "failed to request context IRQ %d (%u)\n",
+                       root_cfg->irptndx, irq);
+               root_cfg->irptndx = -1;
+               goto out_free_context;
+       }
+
+       root_cfg->smmu = smmu;
+       arm_smmu_init_context_bank(smmu_domain);
+       return ret;
+
+out_free_context:
+       __arm_smmu_free_bitmap(smmu->context_map, root_cfg->cbndx);
+out_free_vmid:
+       __arm_smmu_free_bitmap(smmu->vmid_map, root_cfg->vmid);
+       return ret;
+}
+
+static void arm_smmu_destroy_domain_context(struct iommu_domain *domain)
+{
+       struct arm_smmu_domain *smmu_domain = domain->priv;
+       struct arm_smmu_cfg *root_cfg = &smmu_domain->root_cfg;
+       struct arm_smmu_device *smmu = root_cfg->smmu;
+       int irq;
+
+       if (!smmu)
+               return;
+
+       if (root_cfg->irptndx != -1) {
+               irq = smmu->irqs[smmu->num_global_irqs + root_cfg->irptndx];
+               free_irq(irq, domain);
+       }
+
+       __arm_smmu_free_bitmap(smmu->vmid_map, root_cfg->vmid);
+       __arm_smmu_free_bitmap(smmu->context_map, root_cfg->cbndx);
+}
+
+static int arm_smmu_domain_init(struct iommu_domain *domain)
+{
+       struct arm_smmu_domain *smmu_domain;
+       pgd_t *pgd;
+
+       /*
+        * Allocate the domain and initialise some of its data structures.
+        * We can't really do anything meaningful until we've added a
+        * master.
+        */
+       smmu_domain = kzalloc(sizeof(*smmu_domain), GFP_KERNEL);
+       if (!smmu_domain)
+               return -ENOMEM;
+
+       pgd = kzalloc(PTRS_PER_PGD * sizeof(pgd_t), GFP_KERNEL);
+       if (!pgd)
+               goto out_free_domain;
+       smmu_domain->root_cfg.pgd = pgd;
+
+       spin_lock_init(&smmu_domain->lock);
+       domain->priv = smmu_domain;
+       return 0;
+
+out_free_domain:
+       kfree(smmu_domain);
+       return -ENOMEM;
+}
+
+static void arm_smmu_free_ptes(pmd_t *pmd)
+{
+       pgtable_t table = pmd_pgtable(*pmd);
+       pgtable_page_dtor(table);
+       __free_page(table);
+}
+
+static void arm_smmu_free_pmds(pud_t *pud)
+{
+       int i;
+       pmd_t *pmd, *pmd_base = pmd_offset(pud, 0);
+
+       pmd = pmd_base;
+       for (i = 0; i < PTRS_PER_PMD; ++i) {
+               if (pmd_none(*pmd))
+                       continue;
+
+               arm_smmu_free_ptes(pmd);
+               pmd++;
+       }
+
+       pmd_free(NULL, pmd_base);
+}
+
+static void arm_smmu_free_puds(pgd_t *pgd)
+{
+       int i;
+       pud_t *pud, *pud_base = pud_offset(pgd, 0);
+
+       pud = pud_base;
+       for (i = 0; i < PTRS_PER_PUD; ++i) {
+               if (pud_none(*pud))
+                       continue;
+
+               arm_smmu_free_pmds(pud);
+               pud++;
+       }
+
+       pud_free(NULL, pud_base);
+}
+
+static void arm_smmu_free_pgtables(struct arm_smmu_domain *smmu_domain)
+{
+       int i;
+       struct arm_smmu_cfg *root_cfg = &smmu_domain->root_cfg;
+       pgd_t *pgd, *pgd_base = root_cfg->pgd;
+
+       /*
+        * Recursively free the page tables for this domain. We don't
+        * care about speculative TLB filling, because the TLB will be
+        * nuked next time this context bank is re-allocated and no devices
+        * currently map to these tables.
+        */
+       pgd = pgd_base;
+       for (i = 0; i < PTRS_PER_PGD; ++i) {
+               if (pgd_none(*pgd))
+                       continue;
+               arm_smmu_free_puds(pgd);
+               pgd++;
+       }
+
+       kfree(pgd_base);
+}
+
+static void arm_smmu_domain_destroy(struct iommu_domain *domain)
+{
+       struct arm_smmu_domain *smmu_domain = domain->priv;
+       arm_smmu_destroy_domain_context(domain);
+       arm_smmu_free_pgtables(smmu_domain);
+       kfree(smmu_domain);
+}
+
+static int arm_smmu_master_configure_smrs(struct arm_smmu_device *smmu,
+                                         struct arm_smmu_master *master)
+{
+       int i;
+       struct arm_smmu_smr *smrs;
+       void __iomem *gr0_base = ARM_SMMU_GR0(smmu);
+
+       if (!(smmu->features & ARM_SMMU_FEAT_STREAM_MATCH))
+               return 0;
+
+       if (master->smrs)
+               return -EEXIST;
+
+       smrs = kmalloc(sizeof(*smrs) * master->num_streamids, GFP_KERNEL);
+       if (!smrs) {
+               dev_err(smmu->dev, "failed to allocate %d SMRs for master %s\n",
+                       master->num_streamids, master->of_node->name);
+               return -ENOMEM;
+       }
+
+       /* Allocate the SMRs on the root SMMU */
+       for (i = 0; i < master->num_streamids; ++i) {
+               int idx = __arm_smmu_alloc_bitmap(smmu->smr_map, 0,
+                                                 smmu->num_mapping_groups);
+               if (IS_ERR_VALUE(idx)) {
+                       dev_err(smmu->dev, "failed to allocate free SMR\n");
+                       goto err_free_smrs;
+               }
+
+               smrs[i] = (struct arm_smmu_smr) {
+                       .idx    = idx,
+                       .mask   = 0, /* We don't currently share SMRs */
+                       .id     = master->streamids[i],
+               };
+       }
+
+       /* It worked! Now, poke the actual hardware */
+       for (i = 0; i < master->num_streamids; ++i) {
+               u32 reg = SMR_VALID | smrs[i].id << SMR_ID_SHIFT |
+                         smrs[i].mask << SMR_MASK_SHIFT;
+               writel_relaxed(reg, gr0_base + ARM_SMMU_GR0_SMR(smrs[i].idx));
+       }
+
+       master->smrs = smrs;
+       return 0;
+
+err_free_smrs:
+       while (--i >= 0)
+               __arm_smmu_free_bitmap(smmu->smr_map, smrs[i].idx);
+       kfree(smrs);
+       return -ENOSPC;
+}
+
+static void arm_smmu_master_free_smrs(struct arm_smmu_device *smmu,
+                                     struct arm_smmu_master *master)
+{
+       int i;
+       void __iomem *gr0_base = ARM_SMMU_GR0(smmu);
+       struct arm_smmu_smr *smrs = master->smrs;
+
+       /* Invalidate the SMRs before freeing back to the allocator */
+       for (i = 0; i < master->num_streamids; ++i) {
+               u8 idx = smrs[i].idx;
+               writel_relaxed(~SMR_VALID, gr0_base + ARM_SMMU_GR0_SMR(idx));
+               __arm_smmu_free_bitmap(smmu->smr_map, idx);
+       }
+
+       master->smrs = NULL;
+       kfree(smrs);
+}
+
+static void arm_smmu_bypass_stream_mapping(struct arm_smmu_device *smmu,
+                                          struct arm_smmu_master *master)
+{
+       int i;
+       void __iomem *gr0_base = ARM_SMMU_GR0(smmu);
+
+       for (i = 0; i < master->num_streamids; ++i) {
+               u16 sid = master->streamids[i];
+               writel_relaxed(S2CR_TYPE_BYPASS,
+                              gr0_base + ARM_SMMU_GR0_S2CR(sid));
+       }
+}
+
+static int arm_smmu_domain_add_master(struct arm_smmu_domain *smmu_domain,
+                                     struct arm_smmu_master *master)
+{
+       int i, ret;
+       struct arm_smmu_device *parent, *smmu = smmu_domain->root_cfg.smmu;
+       void __iomem *gr0_base = ARM_SMMU_GR0(smmu);
+
+       ret = arm_smmu_master_configure_smrs(smmu, master);
+       if (ret)
+               return ret;
+
+       /* Bypass the leaves */
+       smmu = smmu_domain->leaf_smmu;
+       while ((parent = find_parent_smmu(smmu))) {
+               /*
+                * We won't have a StreamID match for anything but the root
+                * smmu, so we only need to worry about StreamID indexing,
+                * where we must install bypass entries in the S2CRs.
+                */
+               if (smmu->features & ARM_SMMU_FEAT_STREAM_MATCH)
+                       continue;
+
+               arm_smmu_bypass_stream_mapping(smmu, master);
+               smmu = parent;
+       }
+
+       /* Now we're at the root, time to point at our context bank */
+       for (i = 0; i < master->num_streamids; ++i) {
+               u32 idx, s2cr;
+               idx = master->smrs ? master->smrs[i].idx : master->streamids[i];
+               s2cr = (S2CR_TYPE_TRANS << S2CR_TYPE_SHIFT) |
+                      (smmu_domain->root_cfg.cbndx << S2CR_CBNDX_SHIFT);
+               writel_relaxed(s2cr, gr0_base + ARM_SMMU_GR0_S2CR(idx));
+       }
+
+       return 0;
+}
+
+static void arm_smmu_domain_remove_master(struct arm_smmu_domain *smmu_domain,
+                                         struct arm_smmu_master *master)
+{
+       struct arm_smmu_device *smmu = smmu_domain->root_cfg.smmu;
+
+       /*
+        * We *must* clear the S2CR first, because freeing the SMR means
+        * that it can be re-allocated immediately.
+        */
+       arm_smmu_bypass_stream_mapping(smmu, master);
+       arm_smmu_master_free_smrs(smmu, master);
+}
+
+static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
+{
+       int ret = -EINVAL;
+       struct arm_smmu_domain *smmu_domain = domain->priv;
+       struct arm_smmu_device *device_smmu = dev->archdata.iommu;
+       struct arm_smmu_master *master;
+
+       if (!device_smmu) {
+               dev_err(dev, "cannot attach to SMMU, is it on the same bus?\n");
+               return -ENXIO;
+       }
+
+       /*
+        * Sanity check the domain. We don't currently support domains
+        * that cross between different SMMU chains.
+        */
+       spin_lock(&smmu_domain->lock);
+       if (!smmu_domain->leaf_smmu) {
+               /* Now that we have a master, we can finalise the domain */
+               ret = arm_smmu_init_domain_context(domain, dev);
+               if (IS_ERR_VALUE(ret))
+                       goto err_unlock;
+
+               smmu_domain->leaf_smmu = device_smmu;
+       } else if (smmu_domain->leaf_smmu != device_smmu) {
+               dev_err(dev,
+                       "cannot attach to SMMU %s whilst already attached to domain on SMMU %s\n",
+                       dev_name(smmu_domain->leaf_smmu->dev),
+                       dev_name(device_smmu->dev));
+               goto err_unlock;
+       }
+       spin_unlock(&smmu_domain->lock);
+
+       /* Looks ok, so add the device to the domain */
+       master = find_smmu_master(smmu_domain->leaf_smmu, dev->of_node);
+       if (!master)
+               return -ENODEV;
+
+       return arm_smmu_domain_add_master(smmu_domain, master);
+
+err_unlock:
+       spin_unlock(&smmu_domain->lock);
+       return ret;
+}
+
+static void arm_smmu_detach_dev(struct iommu_domain *domain, struct device *dev)
+{
+       struct arm_smmu_domain *smmu_domain = domain->priv;
+       struct arm_smmu_master *master;
+
+       master = find_smmu_master(smmu_domain->leaf_smmu, dev->of_node);
+       if (master)
+               arm_smmu_domain_remove_master(smmu_domain, master);
+}
+
+static void arm_smmu_flush_pgtable(struct arm_smmu_device *smmu, void *addr,
+                                  size_t size)
+{
+       unsigned long offset = (unsigned long)addr & ~PAGE_MASK;
+
+       /*
+        * If the SMMU can't walk tables in the CPU caches, treat them
+        * like non-coherent DMA since we need to flush the new entries
+        * all the way out to memory. There's no possibility of recursion
+        * here as the SMMU table walker will not be wired through another
+        * SMMU.
+        */
+       if (!(smmu->features & ARM_SMMU_FEAT_COHERENT_WALK))
+               dma_map_page(smmu->dev, virt_to_page(addr), offset, size,
+                            DMA_TO_DEVICE);
+}
+
+static bool arm_smmu_pte_is_contiguous_range(unsigned long addr,
+                                            unsigned long end)
+{
+       return !(addr & ~ARM_SMMU_PTE_CONT_MASK) &&
+               (addr + ARM_SMMU_PTE_CONT_SIZE <= end);
+}
+
+static int arm_smmu_alloc_init_pte(struct arm_smmu_device *smmu, pmd_t *pmd,
+                                  unsigned long addr, unsigned long end,
+                                  unsigned long pfn, int flags, int stage)
+{
+       pte_t *pte, *start;
+       pteval_t pteval = ARM_SMMU_PTE_PAGE | ARM_SMMU_PTE_AF;
+
+       if (pmd_none(*pmd)) {
+               /* Allocate a new set of tables */
+               pgtable_t table = alloc_page(PGALLOC_GFP);
+               if (!table)
+                       return -ENOMEM;
+
+               arm_smmu_flush_pgtable(smmu, page_address(table),
+                                      ARM_SMMU_PTE_HWTABLE_SIZE);
+               pgtable_page_ctor(table);
+               pmd_populate(NULL, pmd, table);
+               arm_smmu_flush_pgtable(smmu, pmd, sizeof(*pmd));
+       }
+
+       if (stage == 1) {
+               pteval |= ARM_SMMU_PTE_AP_UNPRIV;
+               if (!(flags & IOMMU_WRITE) && (flags & IOMMU_READ))
+                       pteval |= ARM_SMMU_PTE_AP_RDONLY;
+
+               if (flags & IOMMU_CACHE)
+                       pteval |= (MAIR_ATTR_IDX_CACHE <<
+                                  ARM_SMMU_PTE_ATTRINDX_SHIFT);
+       } else {
+               pteval |= ARM_SMMU_PTE_HAP_FAULT;
+               if (flags & IOMMU_READ)
+                       pteval |= ARM_SMMU_PTE_HAP_READ;
+               if (flags & IOMMU_WRITE)
+                       pteval |= ARM_SMMU_PTE_HAP_WRITE;
+               if (flags & IOMMU_CACHE)
+                       pteval |= ARM_SMMU_PTE_MEMATTR_OIWB;
+               else
+                       pteval |= ARM_SMMU_PTE_MEMATTR_NC;
+       }
+
+       /* If no access, create a faulting entry to avoid TLB fills */
+       if (!(flags & (IOMMU_READ | IOMMU_WRITE)))
+               pteval &= ~ARM_SMMU_PTE_PAGE;
+
+       pteval |= ARM_SMMU_PTE_SH_IS;
+       start = pmd_page_vaddr(*pmd) + pte_index(addr);
+       pte = start;
+
+       /*
+        * Install the page table entries. This is fairly complicated
+        * since we attempt to make use of the contiguous hint in the
+        * ptes where possible. The contiguous hint indicates a series
+        * of ARM_SMMU_PTE_CONT_ENTRIES ptes mapping a physically
+        * contiguous region with the following constraints:
+        *
+        *   - The region start is aligned to ARM_SMMU_PTE_CONT_SIZE
+        *   - Each pte in the region has the contiguous hint bit set
+        *
+        * This complicates unmapping (also handled by this code, when
+        * neither IOMMU_READ or IOMMU_WRITE are set) because it is
+        * possible, yet highly unlikely, that a client may unmap only
+        * part of a contiguous range. This requires clearing of the
+        * contiguous hint bits in the range before installing the new
+        * faulting entries.
+        *
+        * Note that re-mapping an address range without first unmapping
+        * it is not supported, so TLB invalidation is not required here
+        * and is instead performed at unmap and domain-init time.
+        */
+       do {
+               int i = 1;
+               pteval &= ~ARM_SMMU_PTE_CONT;
+
+               if (arm_smmu_pte_is_contiguous_range(addr, end)) {
+                       i = ARM_SMMU_PTE_CONT_ENTRIES;
+                       pteval |= ARM_SMMU_PTE_CONT;
+               } else if (pte_val(*pte) &
+                          (ARM_SMMU_PTE_CONT | ARM_SMMU_PTE_PAGE)) {
+                       int j;
+                       pte_t *cont_start;
+                       unsigned long idx = pte_index(addr);
+
+                       idx &= ~(ARM_SMMU_PTE_CONT_ENTRIES - 1);
+                       cont_start = pmd_page_vaddr(*pmd) + idx;
+                       for (j = 0; j < ARM_SMMU_PTE_CONT_ENTRIES; ++j)
+                               pte_val(*(cont_start + j)) &= ~ARM_SMMU_PTE_CONT;
+
+                       arm_smmu_flush_pgtable(smmu, cont_start,
+                                              sizeof(*pte) *
+                                              ARM_SMMU_PTE_CONT_ENTRIES);
+               }
+
+               do {
+                       *pte = pfn_pte(pfn, __pgprot(pteval));
+               } while (pte++, pfn++, addr += PAGE_SIZE, --i);
+       } while (addr != end);
+
+       arm_smmu_flush_pgtable(smmu, start, sizeof(*pte) * (pte - start));
+       return 0;
+}
+
+static int arm_smmu_alloc_init_pmd(struct arm_smmu_device *smmu, pud_t *pud,
+                                  unsigned long addr, unsigned long end,
+                                  phys_addr_t phys, int flags, int stage)
+{
+       int ret;
+       pmd_t *pmd;
+       unsigned long next, pfn = __phys_to_pfn(phys);
+
+#ifndef __PAGETABLE_PMD_FOLDED
+       if (pud_none(*pud)) {
+               pmd = pmd_alloc_one(NULL, addr);
+               if (!pmd)
+                       return -ENOMEM;
+       } else
+#endif
+               pmd = pmd_offset(pud, addr);
+
+       do {
+               next = pmd_addr_end(addr, end);
+               ret = arm_smmu_alloc_init_pte(smmu, pmd, addr, end, pfn,
+                                             flags, stage);
+               pud_populate(NULL, pud, pmd);
+               arm_smmu_flush_pgtable(smmu, pud, sizeof(*pud));
+               phys += next - addr;
+       } while (pmd++, addr = next, addr < end);
+
+       return ret;
+}
+
+static int arm_smmu_alloc_init_pud(struct arm_smmu_device *smmu, pgd_t *pgd,
+                                  unsigned long addr, unsigned long end,
+                                  phys_addr_t phys, int flags, int stage)
+{
+       int ret = 0;
+       pud_t *pud;
+       unsigned long next;
+
+#ifndef __PAGETABLE_PUD_FOLDED
+       if (pgd_none(*pgd)) {
+               pud = pud_alloc_one(NULL, addr);
+               if (!pud)
+                       return -ENOMEM;
+       } else
+#endif
+               pud = pud_offset(pgd, addr);
+
+       do {
+               next = pud_addr_end(addr, end);
+               ret = arm_smmu_alloc_init_pmd(smmu, pud, addr, next, phys,
+                                             flags, stage);
+               pgd_populate(NULL, pud, pgd);
+               arm_smmu_flush_pgtable(smmu, pgd, sizeof(*pgd));
+               phys += next - addr;
+       } while (pud++, addr = next, addr < end);
+
+       return ret;
+}
+
+static int arm_smmu_handle_mapping(struct arm_smmu_domain *smmu_domain,
+                                  unsigned long iova, phys_addr_t paddr,
+                                  size_t size, int flags)
+{
+       int ret, stage;
+       unsigned long end;
+       phys_addr_t input_mask, output_mask;
+       struct arm_smmu_cfg *root_cfg = &smmu_domain->root_cfg;
+       pgd_t *pgd = root_cfg->pgd;
+       struct arm_smmu_device *smmu = root_cfg->smmu;
+
+       if (root_cfg->cbar == CBAR_TYPE_S2_TRANS) {
+               stage = 2;
+               output_mask = (1ULL << smmu->s2_output_size) - 1;
+       } else {
+               stage = 1;
+               output_mask = (1ULL << smmu->s1_output_size) - 1;
+       }
+
+       if (!pgd)
+               return -EINVAL;
+
+       if (size & ~PAGE_MASK)
+               return -EINVAL;
+
+       input_mask = (1ULL << smmu->input_size) - 1;
+       if ((phys_addr_t)iova & ~input_mask)
+               return -ERANGE;
+
+       if (paddr & ~output_mask)
+               return -ERANGE;
+
+       spin_lock(&smmu_domain->lock);
+       pgd += pgd_index(iova);
+       end = iova + size;
+       do {
+               unsigned long next = pgd_addr_end(iova, end);
+
+               ret = arm_smmu_alloc_init_pud(smmu, pgd, iova, next, paddr,
+                                             flags, stage);
+               if (ret)
+                       goto out_unlock;
+
+               paddr += next - iova;
+               iova = next;
+       } while (pgd++, iova != end);
+
+out_unlock:
+       spin_unlock(&smmu_domain->lock);
+
+       /* Ensure new page tables are visible to the hardware walker */
+       if (smmu->features & ARM_SMMU_FEAT_COHERENT_WALK)
+               dsb();
+
+       return ret;
+}
+
+static int arm_smmu_map(struct iommu_domain *domain, unsigned long iova,
+                       phys_addr_t paddr, size_t size, int flags)
+{
+       struct arm_smmu_domain *smmu_domain = domain->priv;
+       struct arm_smmu_device *smmu = smmu_domain->leaf_smmu;
+
+       if (!smmu_domain || !smmu)
+               return -ENODEV;
+
+       /* Check for silent address truncation up the SMMU chain. */
+       if ((phys_addr_t)iova & ~smmu_domain->output_mask)
+               return -ERANGE;
+
+       return arm_smmu_handle_mapping(smmu_domain, iova, paddr, size, flags);
+}
+
+static size_t arm_smmu_unmap(struct iommu_domain *domain, unsigned long iova,
+                            size_t size)
+{
+       int ret;
+       struct arm_smmu_domain *smmu_domain = domain->priv;
+       struct arm_smmu_cfg *root_cfg = &smmu_domain->root_cfg;
+       struct arm_smmu_device *smmu = root_cfg->smmu;
+       void __iomem *gr0_base = ARM_SMMU_GR0(smmu);
+
+       ret = arm_smmu_handle_mapping(smmu_domain, iova, 0, size, 0);
+       writel_relaxed(root_cfg->vmid, gr0_base + ARM_SMMU_GR0_TLBIVMID);
+       arm_smmu_tlb_sync(smmu);
+       return ret ? ret : size;
+}
+
+static phys_addr_t arm_smmu_iova_to_phys(struct iommu_domain *domain,
+                                        dma_addr_t iova)
+{
+       pgd_t *pgd;
+       pud_t *pud;
+       pmd_t *pmd;
+       pte_t *pte;
+       struct arm_smmu_domain *smmu_domain = domain->priv;
+       struct arm_smmu_cfg *root_cfg = &smmu_domain->root_cfg;
+       struct arm_smmu_device *smmu = root_cfg->smmu;
+
+       spin_lock(&smmu_domain->lock);
+       pgd = root_cfg->pgd;
+       if (!pgd)
+               goto err_unlock;
+
+       pgd += pgd_index(iova);
+       if (pgd_none_or_clear_bad(pgd))
+               goto err_unlock;
+
+       pud = pud_offset(pgd, iova);
+       if (pud_none_or_clear_bad(pud))
+               goto err_unlock;
+
+       pmd = pmd_offset(pud, iova);
+       if (pmd_none_or_clear_bad(pmd))
+               goto err_unlock;
+
+       pte = pmd_page_vaddr(*pmd) + pte_index(iova);
+       if (pte_none(pte))
+               goto err_unlock;
+
+       spin_unlock(&smmu_domain->lock);
+       return __pfn_to_phys(pte_pfn(*pte)) | (iova & ~PAGE_MASK);
+
+err_unlock:
+       spin_unlock(&smmu_domain->lock);
+       dev_warn(smmu->dev,
+                "invalid (corrupt?) page tables detected for iova 0x%llx\n",
+                (unsigned long long)iova);
+       return -EINVAL;
+}
+
+static int arm_smmu_domain_has_cap(struct iommu_domain *domain,
+                                  unsigned long cap)
+{
+       unsigned long caps = 0;
+       struct arm_smmu_domain *smmu_domain = domain->priv;
+
+       if (smmu_domain->root_cfg.smmu->features & ARM_SMMU_FEAT_COHERENT_WALK)
+               caps |= IOMMU_CAP_CACHE_COHERENCY;
+
+       return !!(cap & caps);
+}
+
+static int arm_smmu_add_device(struct device *dev)
+{
+       struct arm_smmu_device *child, *parent, *smmu;
+       struct arm_smmu_master *master = NULL;
+
+       spin_lock(&arm_smmu_devices_lock);
+       list_for_each_entry(parent, &arm_smmu_devices, list) {
+               smmu = parent;
+
+               /* Try to find a child of the current SMMU. */
+               list_for_each_entry(child, &arm_smmu_devices, list) {
+                       if (child->parent_of_node == parent->dev->of_node) {
+                               /* Does the child sit above our master? */
+                               master = find_smmu_master(child, dev->of_node);
+                               if (master) {
+                                       smmu = NULL;
+                                       break;
+                               }
+                       }
+               }
+
+               /* We found some children, so keep searching. */
+               if (!smmu) {
+                       master = NULL;
+                       continue;
+               }
+
+               master = find_smmu_master(smmu, dev->of_node);
+               if (master)
+                       break;
+       }
+       spin_unlock(&arm_smmu_devices_lock);
+
+       if (!master)
+               return -ENODEV;
+
+       dev->archdata.iommu = smmu;
+       return 0;
+}
+
+static void arm_smmu_remove_device(struct device *dev)
+{
+       dev->archdata.iommu = NULL;
+}
+
+static struct iommu_ops arm_smmu_ops = {
+       .domain_init    = arm_smmu_domain_init,
+       .domain_destroy = arm_smmu_domain_destroy,
+       .attach_dev     = arm_smmu_attach_dev,
+       .detach_dev     = arm_smmu_detach_dev,
+       .map            = arm_smmu_map,
+       .unmap          = arm_smmu_unmap,
+       .iova_to_phys   = arm_smmu_iova_to_phys,
+       .domain_has_cap = arm_smmu_domain_has_cap,
+       .add_device     = arm_smmu_add_device,
+       .remove_device  = arm_smmu_remove_device,
+       .pgsize_bitmap  = (SECTION_SIZE |
+                          ARM_SMMU_PTE_CONT_SIZE |
+                          PAGE_SIZE),
+};
+
+static void arm_smmu_device_reset(struct arm_smmu_device *smmu)
+{
+       void __iomem *gr0_base = ARM_SMMU_GR0(smmu);
+       int i = 0;
+       u32 scr0 = readl_relaxed(gr0_base + ARM_SMMU_GR0_sCR0);
+
+       /* Mark all SMRn as invalid and all S2CRn as bypass */
+       for (i = 0; i < smmu->num_mapping_groups; ++i) {
+               writel_relaxed(~SMR_VALID, gr0_base + ARM_SMMU_GR0_SMR(i));
+               writel_relaxed(S2CR_TYPE_BYPASS, gr0_base + ARM_SMMU_GR0_S2CR(i));
+       }
+
+       /* Invalidate the TLB, just in case */
+       writel_relaxed(0, gr0_base + ARM_SMMU_GR0_STLBIALL);
+       writel_relaxed(0, gr0_base + ARM_SMMU_GR0_TLBIALLH);
+       writel_relaxed(0, gr0_base + ARM_SMMU_GR0_TLBIALLNSNH);
+
+       /* Enable fault reporting */
+       scr0 |= (sCR0_GFRE | sCR0_GFIE | sCR0_GCFGFRE | sCR0_GCFGFIE);
+
+       /* Disable TLB broadcasting. */
+       scr0 |= (sCR0_VMIDPNE | sCR0_PTM);
+
+       /* Enable client access, but bypass when no mapping is found */
+       scr0 &= ~(sCR0_CLIENTPD | sCR0_USFCFG);
+
+       /* Disable forced broadcasting */
+       scr0 &= ~sCR0_FB;
+
+       /* Don't upgrade barriers */
+       scr0 &= ~(sCR0_BSU_MASK << sCR0_BSU_SHIFT);
+
+       /* Push the button */
+       arm_smmu_tlb_sync(smmu);
+       writel(scr0, gr0_base + ARM_SMMU_GR0_sCR0);
+}
+
+static int arm_smmu_id_size_to_bits(int size)
+{
+       switch (size) {
+       case 0:
+               return 32;
+       case 1:
+               return 36;
+       case 2:
+               return 40;
+       case 3:
+               return 42;
+       case 4:
+               return 44;
+       case 5:
+       default:
+               return 48;
+       }
+}
+
+static int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu)
+{
+       unsigned long size;
+       void __iomem *gr0_base = ARM_SMMU_GR0(smmu);
+       u32 id;
+
+       dev_notice(smmu->dev, "probing hardware configuration...\n");
+
+       /* Primecell ID */
+       id = readl_relaxed(gr0_base + ARM_SMMU_GR0_PIDR2);
+       smmu->version = ((id >> PIDR2_ARCH_SHIFT) & PIDR2_ARCH_MASK) + 1;
+       dev_notice(smmu->dev, "SMMUv%d with:\n", smmu->version);
+
+       /* ID0 */
+       id = readl_relaxed(gr0_base + ARM_SMMU_GR0_ID0);
+#ifndef CONFIG_64BIT
+       if (((id >> ID0_PTFS_SHIFT) & ID0_PTFS_MASK) == ID0_PTFS_V8_ONLY) {
+               dev_err(smmu->dev, "\tno v7 descriptor support!\n");
+               return -ENODEV;
+       }
+#endif
+       if (id & ID0_S1TS) {
+               smmu->features |= ARM_SMMU_FEAT_TRANS_S1;
+               dev_notice(smmu->dev, "\tstage 1 translation\n");
+       }
+
+       if (id & ID0_S2TS) {
+               smmu->features |= ARM_SMMU_FEAT_TRANS_S2;
+               dev_notice(smmu->dev, "\tstage 2 translation\n");
+       }
+
+       if (id & ID0_NTS) {
+               smmu->features |= ARM_SMMU_FEAT_TRANS_NESTED;
+               dev_notice(smmu->dev, "\tnested translation\n");
+       }
+
+       if (!(smmu->features &
+               (ARM_SMMU_FEAT_TRANS_S1 | ARM_SMMU_FEAT_TRANS_S2 |
+                ARM_SMMU_FEAT_TRANS_NESTED))) {
+               dev_err(smmu->dev, "\tno translation support!\n");
+               return -ENODEV;
+       }
+
+       if (id & ID0_CTTW) {
+               smmu->features |= ARM_SMMU_FEAT_COHERENT_WALK;
+               dev_notice(smmu->dev, "\tcoherent table walk\n");
+       }
+
+       if (id & ID0_SMS) {
+               u32 smr, sid, mask;
+
+               smmu->features |= ARM_SMMU_FEAT_STREAM_MATCH;
+               smmu->num_mapping_groups = (id >> ID0_NUMSMRG_SHIFT) &
+                                          ID0_NUMSMRG_MASK;
+               if (smmu->num_mapping_groups == 0) {
+                       dev_err(smmu->dev,
+                               "stream-matching supported, but no SMRs present!\n");
+                       return -ENODEV;
+               }
+
+               smr = SMR_MASK_MASK << SMR_MASK_SHIFT;
+               smr |= (SMR_ID_MASK << SMR_ID_SHIFT);
+               writel_relaxed(smr, gr0_base + ARM_SMMU_GR0_SMR(0));
+               smr = readl_relaxed(gr0_base + ARM_SMMU_GR0_SMR(0));
+
+               mask = (smr >> SMR_MASK_SHIFT) & SMR_MASK_MASK;
+               sid = (smr >> SMR_ID_SHIFT) & SMR_ID_MASK;
+               if ((mask & sid) != sid) {
+                       dev_err(smmu->dev,
+                               "SMR mask bits (0x%x) insufficient for ID field (0x%x)\n",
+                               mask, sid);
+                       return -ENODEV;
+               }
+
+               dev_notice(smmu->dev,
+                          "\tstream matching with %u register groups, mask 0x%x",
+                          smmu->num_mapping_groups, mask);
+       }
+
+       /* ID1 */
+       id = readl_relaxed(gr0_base + ARM_SMMU_GR0_ID1);
+       smmu->pagesize = (id & ID1_PAGESIZE) ? SZ_64K : SZ_4K;
+
+       /* Check that we ioremapped enough */
+       size = 1 << (((id >> ID1_NUMPAGENDXB_SHIFT) & ID1_NUMPAGENDXB_MASK) + 1);
+       size *= (smmu->pagesize << 1);
+       if (smmu->size < size)
+               dev_warn(smmu->dev,
+                        "device is 0x%lx bytes but only mapped 0x%lx!\n",
+                        size, smmu->size);
+
+       smmu->num_s2_context_banks = (id >> ID1_NUMS2CB_SHIFT) &
+                                     ID1_NUMS2CB_MASK;
+       smmu->num_context_banks = (id >> ID1_NUMCB_SHIFT) & ID1_NUMCB_MASK;
+       if (smmu->num_s2_context_banks > smmu->num_context_banks) {
+               dev_err(smmu->dev, "impossible number of S2 context banks!\n");
+               return -ENODEV;
+       }
+       dev_notice(smmu->dev, "\t%u context banks (%u stage-2 only)\n",
+                  smmu->num_context_banks, smmu->num_s2_context_banks);
+
+       /* ID2 */
+       id = readl_relaxed(gr0_base + ARM_SMMU_GR0_ID2);
+       size = arm_smmu_id_size_to_bits((id >> ID2_IAS_SHIFT) & ID2_IAS_MASK);
+
+       /*
+        * Stage-1 output limited by stage-2 input size due to pgd
+        * allocation (PTRS_PER_PGD).
+        */
+#ifdef CONFIG_64BIT
+       /* Current maximum output size of 39 bits */
+       smmu->s1_output_size = min(39UL, size);
+#else
+       smmu->s1_output_size = min(32UL, size);
+#endif
+
+       /* The stage-2 output mask is also applied for bypass */
+       size = arm_smmu_id_size_to_bits((id >> ID2_OAS_SHIFT) & ID2_OAS_MASK);
+       smmu->s2_output_size = min((unsigned long)PHYS_MASK_SHIFT, size);
+
+       if (smmu->version == 1) {
+               smmu->input_size = 32;
+       } else {
+#ifdef CONFIG_64BIT
+               size = (id >> ID2_UBS_SHIFT) & ID2_UBS_MASK;
+               size = min(39, arm_smmu_id_size_to_bits(size));
+#else
+               size = 32;
+#endif
+               smmu->input_size = size;
+
+               if ((PAGE_SIZE == SZ_4K && !(id & ID2_PTFS_4K)) ||
+                   (PAGE_SIZE == SZ_64K && !(id & ID2_PTFS_64K)) ||
+                   (PAGE_SIZE != SZ_4K && PAGE_SIZE != SZ_64K)) {
+                       dev_err(smmu->dev, "CPU page size 0x%lx unsupported\n",
+                               PAGE_SIZE);
+                       return -ENODEV;
+               }
+       }
+
+       dev_notice(smmu->dev,
+                  "\t%lu-bit VA, %lu-bit IPA, %lu-bit PA\n",
+                  smmu->input_size, smmu->s1_output_size, smmu->s2_output_size);
+       return 0;
+}
+
+static int arm_smmu_device_dt_probe(struct platform_device *pdev)
+{
+       struct resource *res;
+       struct arm_smmu_device *smmu;
+       struct device_node *dev_node;
+       struct device *dev = &pdev->dev;
+       struct rb_node *node;
+       struct of_phandle_args masterspec;
+       int num_irqs, i, err;
+
+       smmu = devm_kzalloc(dev, sizeof(*smmu), GFP_KERNEL);
+       if (!smmu) {
+               dev_err(dev, "failed to allocate arm_smmu_device\n");
+               return -ENOMEM;
+       }
+       smmu->dev = dev;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(dev, "missing base address/size\n");
+               return -ENODEV;
+       }
+
+       smmu->size = resource_size(res);
+       smmu->base = devm_request_and_ioremap(dev, res);
+       if (!smmu->base)
+               return -EADDRNOTAVAIL;
+
+       if (of_property_read_u32(dev->of_node, "#global-interrupts",
+                                &smmu->num_global_irqs)) {
+               dev_err(dev, "missing #global-interrupts property\n");
+               return -ENODEV;
+       }
+
+       num_irqs = 0;
+       while ((res = platform_get_resource(pdev, IORESOURCE_IRQ, num_irqs))) {
+               num_irqs++;
+               if (num_irqs > smmu->num_global_irqs)
+                       smmu->num_context_irqs++;
+       }
+
+       if (num_irqs < smmu->num_global_irqs) {
+               dev_warn(dev, "found %d interrupts but expected at least %d\n",
+                        num_irqs, smmu->num_global_irqs);
+               smmu->num_global_irqs = num_irqs;
+       }
+       smmu->num_context_irqs = num_irqs - smmu->num_global_irqs;
+
+       smmu->irqs = devm_kzalloc(dev, sizeof(*smmu->irqs) * num_irqs,
+                                 GFP_KERNEL);
+       if (!smmu->irqs) {
+               dev_err(dev, "failed to allocate %d irqs\n", num_irqs);
+               return -ENOMEM;
+       }
+
+       for (i = 0; i < num_irqs; ++i) {
+               int irq = platform_get_irq(pdev, i);
+               if (irq < 0) {
+                       dev_err(dev, "failed to get irq index %d\n", i);
+                       return -ENODEV;
+               }
+               smmu->irqs[i] = irq;
+       }
+
+       i = 0;
+       smmu->masters = RB_ROOT;
+       while (!of_parse_phandle_with_args(dev->of_node, "mmu-masters",
+                                          "#stream-id-cells", i,
+                                          &masterspec)) {
+               err = register_smmu_master(smmu, dev, &masterspec);
+               if (err) {
+                       dev_err(dev, "failed to add master %s\n",
+                               masterspec.np->name);
+                       goto out_put_masters;
+               }
+
+               i++;
+       }
+       dev_notice(dev, "registered %d master devices\n", i);
+
+       if ((dev_node = of_parse_phandle(dev->of_node, "smmu-parent", 0)))
+               smmu->parent_of_node = dev_node;
+
+       err = arm_smmu_device_cfg_probe(smmu);
+       if (err)
+               goto out_put_parent;
+
+       if (smmu->version > 1 &&
+           smmu->num_context_banks != smmu->num_context_irqs) {
+               dev_err(dev,
+                       "found only %d context interrupt(s) but %d required\n",
+                       smmu->num_context_irqs, smmu->num_context_banks);
+               goto out_put_parent;
+       }
+
+       arm_smmu_device_reset(smmu);
+
+       for (i = 0; i < smmu->num_global_irqs; ++i) {
+               err = request_irq(smmu->irqs[i],
+                                 arm_smmu_global_fault,
+                                 IRQF_SHARED,
+                                 "arm-smmu global fault",
+                                 smmu);
+               if (err) {
+                       dev_err(dev, "failed to request global IRQ %d (%u)\n",
+                               i, smmu->irqs[i]);
+                       goto out_free_irqs;
+               }
+       }
+
+       INIT_LIST_HEAD(&smmu->list);
+       spin_lock(&arm_smmu_devices_lock);
+       list_add(&smmu->list, &arm_smmu_devices);
+       spin_unlock(&arm_smmu_devices_lock);
+       return 0;
+
+out_free_irqs:
+       while (i--)
+               free_irq(smmu->irqs[i], smmu);
+
+out_put_parent:
+       if (smmu->parent_of_node)
+               of_node_put(smmu->parent_of_node);
+
+out_put_masters:
+       for (node = rb_first(&smmu->masters); node; node = rb_next(node)) {
+               struct arm_smmu_master *master;
+               master = container_of(node, struct arm_smmu_master, node);
+               of_node_put(master->of_node);
+       }
+
+       return err;
+}
+
+static int arm_smmu_device_remove(struct platform_device *pdev)
+{
+       int i;
+       struct device *dev = &pdev->dev;
+       struct arm_smmu_device *curr, *smmu = NULL;
+       struct rb_node *node;
+
+       spin_lock(&arm_smmu_devices_lock);
+       list_for_each_entry(curr, &arm_smmu_devices, list) {
+               if (curr->dev == dev) {
+                       smmu = curr;
+                       list_del(&smmu->list);
+                       break;
+               }
+       }
+       spin_unlock(&arm_smmu_devices_lock);
+
+       if (!smmu)
+               return -ENODEV;
+
+       if (smmu->parent_of_node)
+               of_node_put(smmu->parent_of_node);
+
+       for (node = rb_first(&smmu->masters); node; node = rb_next(node)) {
+               struct arm_smmu_master *master;
+               master = container_of(node, struct arm_smmu_master, node);
+               of_node_put(master->of_node);
+       }
+
+       if (!bitmap_empty(smmu->vmid_map, ARM_SMMU_NUM_VMIDS))
+               dev_err(dev, "removing device with active domains!\n");
+
+       for (i = 0; i < smmu->num_global_irqs; ++i)
+               free_irq(smmu->irqs[i], smmu);
+
+       /* Turn the thing off */
+       writel(sCR0_CLIENTPD, ARM_SMMU_GR0(smmu) + ARM_SMMU_GR0_sCR0);
+       return 0;
+}
+
+#ifdef CONFIG_OF
+static struct of_device_id arm_smmu_of_match[] = {
+       { .compatible = "arm,smmu-v1", },
+       { .compatible = "arm,smmu-v2", },
+       { .compatible = "arm,mmu-400", },
+       { .compatible = "arm,mmu-500", },
+       { },
+};
+MODULE_DEVICE_TABLE(of, arm_smmu_of_match);
+#endif
+
+static struct platform_driver arm_smmu_driver = {
+       .driver = {
+               .owner          = THIS_MODULE,
+               .name           = "arm-smmu",
+               .of_match_table = of_match_ptr(arm_smmu_of_match),
+       },
+       .probe  = arm_smmu_device_dt_probe,
+       .remove = arm_smmu_device_remove,
+};
+
+static int __init arm_smmu_init(void)
+{
+       int ret;
+
+       ret = platform_driver_register(&arm_smmu_driver);
+       if (ret)
+               return ret;
+
+       /* Oh, for a proper bus abstraction */
+       if (!iommu_present(&platform_bus_type));
+               bus_set_iommu(&platform_bus_type, &arm_smmu_ops);
+
+       if (!iommu_present(&amba_bustype));
+               bus_set_iommu(&amba_bustype, &arm_smmu_ops);
+
+       return 0;
+}
+
+static void __exit arm_smmu_exit(void)
+{
+       return platform_driver_unregister(&arm_smmu_driver);
+}
+
+module_init(arm_smmu_init);
+module_exit(arm_smmu_exit);
+
+MODULE_DESCRIPTION("IOMMU API for ARM architected SMMU implementations");
+MODULE_AUTHOR("Will Deacon <will.deacon@arm.com>");
+MODULE_LICENSE("GPL v2");
index a7967ce..785675a 100644 (file)
@@ -309,6 +309,7 @@ parse_dmar_table(void)
        struct acpi_table_dmar *dmar;
        struct acpi_dmar_header *entry_header;
        int ret = 0;
+       int drhd_count = 0;
 
        /*
         * Do it again, earlier dmar_tbl mapping could be mapped with
@@ -347,6 +348,7 @@ parse_dmar_table(void)
 
                switch (entry_header->type) {
                case ACPI_DMAR_TYPE_HARDWARE_UNIT:
+                       drhd_count++;
                        ret = dmar_parse_one_drhd(entry_header);
                        break;
                case ACPI_DMAR_TYPE_RESERVED_MEMORY:
@@ -371,6 +373,8 @@ parse_dmar_table(void)
 
                entry_header = ((void *)entry_header + entry_header->length);
        }
+       if (drhd_count == 0)
+               pr_warn(FW_BUG "No DRHD structure found in DMAR table\n");
        return ret;
 }
 
index b4f0e28..eec0d3e 100644 (file)
@@ -4182,14 +4182,27 @@ static int intel_iommu_add_device(struct device *dev)
 
        /*
         * If it's a multifunction device that does not support our
-        * required ACS flags, add to the same group as function 0.
+        * required ACS flags, add to the same group as lowest numbered
+        * function that also does not suport the required ACS flags.
         */
        if (dma_pdev->multifunction &&
-           !pci_acs_enabled(dma_pdev, REQ_ACS_FLAGS))
-               swap_pci_ref(&dma_pdev,
-                            pci_get_slot(dma_pdev->bus,
-                                         PCI_DEVFN(PCI_SLOT(dma_pdev->devfn),
-                                         0)));
+           !pci_acs_enabled(dma_pdev, REQ_ACS_FLAGS)) {
+               u8 i, slot = PCI_SLOT(dma_pdev->devfn);
+
+               for (i = 0; i < 8; i++) {
+                       struct pci_dev *tmp;
+
+                       tmp = pci_get_slot(dma_pdev->bus, PCI_DEVFN(slot, i));
+                       if (!tmp)
+                               continue;
+
+                       if (!pci_acs_enabled(tmp, REQ_ACS_FLAGS)) {
+                               swap_pci_ref(&dma_pdev, tmp);
+                               break;
+                       }
+                       pci_dev_put(tmp);
+               }
+       }
 
        /*
         * Devices on the root bus go through the iommu.  If that's not us,
index 5b19b2d..f71673d 100644 (file)
@@ -664,8 +664,7 @@ error:
         */
 
        if (x2apic_present)
-               WARN(1, KERN_WARNING
-                       "Failed to enable irq remapping.  You are vulnerable to irq-injection attacks.\n");
+               pr_warn("Failed to enable irq remapping.  You are vulnerable to irq-injection attacks.\n");
 
        return -1;
 }
index d8f98b1..fbe9ca7 100644 (file)
@@ -754,6 +754,38 @@ int iommu_domain_has_cap(struct iommu_domain *domain,
 }
 EXPORT_SYMBOL_GPL(iommu_domain_has_cap);
 
+static size_t iommu_pgsize(struct iommu_domain *domain,
+                          unsigned long addr_merge, size_t size)
+{
+       unsigned int pgsize_idx;
+       size_t pgsize;
+
+       /* Max page size that still fits into 'size' */
+       pgsize_idx = __fls(size);
+
+       /* need to consider alignment requirements ? */
+       if (likely(addr_merge)) {
+               /* Max page size allowed by address */
+               unsigned int align_pgsize_idx = __ffs(addr_merge);
+               pgsize_idx = min(pgsize_idx, align_pgsize_idx);
+       }
+
+       /* build a mask of acceptable page sizes */
+       pgsize = (1UL << (pgsize_idx + 1)) - 1;
+
+       /* throw away page sizes not supported by the hardware */
+       pgsize &= domain->ops->pgsize_bitmap;
+
+       /* make sure we're still sane */
+       BUG_ON(!pgsize);
+
+       /* pick the biggest page */
+       pgsize_idx = __fls(pgsize);
+       pgsize = 1UL << pgsize_idx;
+
+       return pgsize;
+}
+
 int iommu_map(struct iommu_domain *domain, unsigned long iova,
              phys_addr_t paddr, size_t size, int prot)
 {
@@ -775,45 +807,18 @@ int iommu_map(struct iommu_domain *domain, unsigned long iova,
         * size of the smallest page supported by the hardware
         */
        if (!IS_ALIGNED(iova | paddr | size, min_pagesz)) {
-               pr_err("unaligned: iova 0x%lx pa 0x%lx size 0x%lx min_pagesz "
-                       "0x%x\n", iova, (unsigned long)paddr,
-                       (unsigned long)size, min_pagesz);
+               pr_err("unaligned: iova 0x%lx pa 0x%pa size 0x%zx min_pagesz 0x%x\n",
+                      iova, &paddr, size, min_pagesz);
                return -EINVAL;
        }
 
-       pr_debug("map: iova 0x%lx pa 0x%lx size 0x%lx\n", iova,
-                               (unsigned long)paddr, (unsigned long)size);
+       pr_debug("map: iova 0x%lx pa 0x%pa size 0x%zx\n", iova, &paddr, size);
 
        while (size) {
-               unsigned long pgsize, addr_merge = iova | paddr;
-               unsigned int pgsize_idx;
-
-               /* Max page size that still fits into 'size' */
-               pgsize_idx = __fls(size);
-
-               /* need to consider alignment requirements ? */
-               if (likely(addr_merge)) {
-                       /* Max page size allowed by both iova and paddr */
-                       unsigned int align_pgsize_idx = __ffs(addr_merge);
-
-                       pgsize_idx = min(pgsize_idx, align_pgsize_idx);
-               }
-
-               /* build a mask of acceptable page sizes */
-               pgsize = (1UL << (pgsize_idx + 1)) - 1;
-
-               /* throw away page sizes not supported by the hardware */
-               pgsize &= domain->ops->pgsize_bitmap;
-
-               /* make sure we're still sane */
-               BUG_ON(!pgsize);
-
-               /* pick the biggest page */
-               pgsize_idx = __fls(pgsize);
-               pgsize = 1UL << pgsize_idx;
+               size_t pgsize = iommu_pgsize(domain, iova | paddr, size);
 
-               pr_debug("mapping: iova 0x%lx pa 0x%lx pgsize %lu\n", iova,
-                                       (unsigned long)paddr, pgsize);
+               pr_debug("mapping: iova 0x%lx pa 0x%pa pgsize 0x%zx\n",
+                        iova, &paddr, pgsize);
 
                ret = domain->ops->map(domain, iova, paddr, pgsize, prot);
                if (ret)
@@ -850,27 +855,26 @@ size_t iommu_unmap(struct iommu_domain *domain, unsigned long iova, size_t size)
         * by the hardware
         */
        if (!IS_ALIGNED(iova | size, min_pagesz)) {
-               pr_err("unaligned: iova 0x%lx size 0x%lx min_pagesz 0x%x\n",
-                                       iova, (unsigned long)size, min_pagesz);
+               pr_err("unaligned: iova 0x%lx size 0x%zx min_pagesz 0x%x\n",
+                      iova, size, min_pagesz);
                return -EINVAL;
        }
 
-       pr_debug("unmap this: iova 0x%lx size 0x%lx\n", iova,
-                                                       (unsigned long)size);
+       pr_debug("unmap this: iova 0x%lx size 0x%zx\n", iova, size);
 
        /*
         * Keep iterating until we either unmap 'size' bytes (or more)
         * or we hit an area that isn't mapped.
         */
        while (unmapped < size) {
-               size_t left = size - unmapped;
+               size_t pgsize = iommu_pgsize(domain, iova, size - unmapped);
 
-               unmapped_page = domain->ops->unmap(domain, iova, left);
+               unmapped_page = domain->ops->unmap(domain, iova, pgsize);
                if (!unmapped_page)
                        break;
 
-               pr_debug("unmapped: iova 0x%lx size %lx\n", iova,
-                                       (unsigned long)unmapped_page);
+               pr_debug("unmapped: iova 0x%lx size 0x%zx\n",
+                        iova, unmapped_page);
 
                iova += unmapped_page;
                unmapped += unmapped_page;
index e02e5d7..0ba3766 100644 (file)
@@ -833,16 +833,15 @@ static irqreturn_t iommu_fault_handler(int irq, void *data)
        iopgd = iopgd_offset(obj, da);
 
        if (!iopgd_is_table(*iopgd)) {
-               dev_err(obj->dev, "%s: errs:0x%08x da:0x%08x pgd:0x%p "
-                       "*pgd:px%08x\n", obj->name, errs, da, iopgd, *iopgd);
+               dev_err(obj->dev, "%s: errs:0x%08x da:0x%08x pgd:0x%p *pgd:px%08x\n",
+                               obj->name, errs, da, iopgd, *iopgd);
                return IRQ_NONE;
        }
 
        iopte = iopte_offset(iopgd, da);
 
-       dev_err(obj->dev, "%s: errs:0x%08x da:0x%08x pgd:0x%p *pgd:0x%08x "
-               "pte:0x%p *pte:0x%08x\n", obj->name, errs, da, iopgd, *iopgd,
-               iopte, *iopte);
+       dev_err(obj->dev, "%s: errs:0x%08x da:0x%08x pgd:0x%p *pgd:0x%08x pte:0x%p *pte:0x%08x\n",
+                       obj->name, errs, da, iopgd, *iopgd, iopte, *iopte);
 
        return IRQ_NONE;
 }
@@ -1235,14 +1234,16 @@ static phys_addr_t omap_iommu_iova_to_phys(struct iommu_domain *domain,
                else if (iopte_is_large(*pte))
                        ret = omap_iommu_translate(*pte, da, IOLARGE_MASK);
                else
-                       dev_err(dev, "bogus pte 0x%x, da 0x%lx", *pte, da);
+                       dev_err(dev, "bogus pte 0x%x, da 0x%llx", *pte,
+                                                       (unsigned long long)da);
        } else {
                if (iopgd_is_section(*pgd))
                        ret = omap_iommu_translate(*pgd, da, IOSECTION_MASK);
                else if (iopgd_is_super(*pgd))
                        ret = omap_iommu_translate(*pgd, da, IOSUPER_MASK);
                else
-                       dev_err(dev, "bogus pgd 0x%x, da 0x%lx", *pgd, da);
+                       dev_err(dev, "bogus pgd 0x%x, da 0x%llx", *pgd,
+                                                       (unsigned long long)da);
        }
 
        return ret;
index cd4ae9e..f4003d5 100644 (file)
@@ -95,4 +95,4 @@ static inline phys_addr_t omap_iommu_translate(u32 d, u32 va, u32 mask)
 #define iopte_offset(iopgd, da)        (iopgd_page_vaddr(iopgd) + iopte_index(da))
 
 #define to_iommu(dev)                                                  \
-       (struct omap_iommu *)platform_get_drvdata(to_platform_device(dev))
+       ((struct omap_iommu *)platform_get_drvdata(to_platform_device(dev)))
index 46d8756..d147259 100644 (file)
@@ -102,8 +102,8 @@ static size_t sgtable_len(const struct sg_table *sgt)
                }
 
                if (i && sg->offset) {
-                       pr_err("%s: sg[%d] offset not allowed in internal "
-                                       "entries\n", __func__, i);
+                       pr_err("%s: sg[%d] offset not allowed in internal entries\n",
+                               __func__, i);
                        return 0;
                }
 
index 2065ef6..e65c41a 100644 (file)
@@ -7,6 +7,7 @@ obj-$(CONFIG_ARCH_MXS)                  += irq-mxs.o
 obj-$(CONFIG_ARCH_S3C24XX)             += irq-s3c24xx.o
 obj-$(CONFIG_METAG)                    += irq-metag-ext.o
 obj-$(CONFIG_METAG_PERFCOUNTER_IRQS)   += irq-metag.o
+obj-$(CONFIG_ARCH_MOXART)              += irq-moxart.o
 obj-$(CONFIG_ORION_IRQCHIP)            += irq-orion.o
 obj-$(CONFIG_ARCH_SUNXI)               += irq-sun4i.o
 obj-$(CONFIG_ARCH_SPEAR3XX)            += spear-shirq.o
diff --git a/drivers/irqchip/irq-moxart.c b/drivers/irqchip/irq-moxart.c
new file mode 100644 (file)
index 0000000..5552fc2
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * MOXA ART SoCs IRQ chip driver.
+ *
+ * Copyright (C) 2013 Jonas Jensen
+ *
+ * Jonas Jensen <jonas.jensen@gmail.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/irqdomain.h>
+
+#include <asm/exception.h>
+
+#include "irqchip.h"
+
+#define IRQ_SOURCE_REG         0
+#define IRQ_MASK_REG           0x04
+#define IRQ_CLEAR_REG          0x08
+#define IRQ_MODE_REG           0x0c
+#define IRQ_LEVEL_REG          0x10
+#define IRQ_STATUS_REG         0x14
+
+#define FIQ_SOURCE_REG         0x20
+#define FIQ_MASK_REG           0x24
+#define FIQ_CLEAR_REG          0x28
+#define FIQ_MODE_REG           0x2c
+#define FIQ_LEVEL_REG          0x30
+#define FIQ_STATUS_REG         0x34
+
+
+struct moxart_irq_data {
+       void __iomem *base;
+       struct irq_domain *domain;
+       unsigned int interrupt_mask;
+};
+
+static struct moxart_irq_data intc;
+
+static asmlinkage void __exception_irq_entry handle_irq(struct pt_regs *regs)
+{
+       u32 irqstat;
+       int hwirq;
+
+       irqstat = readl(intc.base + IRQ_STATUS_REG);
+
+       while (irqstat) {
+               hwirq = ffs(irqstat) - 1;
+               handle_IRQ(irq_linear_revmap(intc.domain, hwirq), regs);
+               irqstat &= ~(1 << hwirq);
+       }
+}
+
+static int __init moxart_of_intc_init(struct device_node *node,
+                                     struct device_node *parent)
+{
+       unsigned int clr = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN;
+       int ret;
+       struct irq_chip_generic *gc;
+
+       intc.base = of_iomap(node, 0);
+       if (!intc.base) {
+               pr_err("%s: unable to map IC registers\n",
+                      node->full_name);
+               return -EINVAL;
+       }
+
+       intc.domain = irq_domain_add_linear(node, 32, &irq_generic_chip_ops,
+                                           intc.base);
+       if (!intc.domain) {
+               pr_err("%s: unable to create IRQ domain\n", node->full_name);
+               return -EINVAL;
+       }
+
+       ret = irq_alloc_domain_generic_chips(intc.domain, 32, 1,
+                                            "MOXARTINTC", handle_edge_irq,
+                                            clr, 0, IRQ_GC_INIT_MASK_CACHE);
+       if (ret) {
+               pr_err("%s: could not allocate generic chip\n",
+                      node->full_name);
+               irq_domain_remove(intc.domain);
+               return -EINVAL;
+       }
+
+       ret = of_property_read_u32(node, "interrupt-mask",
+                                  &intc.interrupt_mask);
+       if (ret)
+               pr_err("%s: could not read interrupt-mask DT property\n",
+                      node->full_name);
+
+       gc = irq_get_domain_generic_chip(intc.domain, 0);
+
+       gc->reg_base = intc.base;
+       gc->chip_types[0].regs.mask = IRQ_MASK_REG;
+       gc->chip_types[0].regs.ack = IRQ_CLEAR_REG;
+       gc->chip_types[0].chip.irq_ack = irq_gc_ack_set_bit;
+       gc->chip_types[0].chip.irq_mask = irq_gc_mask_clr_bit;
+       gc->chip_types[0].chip.irq_unmask = irq_gc_mask_set_bit;
+
+       writel(0, intc.base + IRQ_MASK_REG);
+       writel(0xffffffff, intc.base + IRQ_CLEAR_REG);
+
+       writel(intc.interrupt_mask, intc.base + IRQ_MODE_REG);
+       writel(intc.interrupt_mask, intc.base + IRQ_LEVEL_REG);
+
+       set_handle_irq(handle_irq);
+
+       return 0;
+}
+IRQCHIP_DECLARE(moxa_moxart_ic, "moxa,moxart-ic", moxart_of_intc_init);
index 8d0c8b3..70bdf6e 100644 (file)
@@ -84,7 +84,7 @@ static int __init nvic_of_init(struct device_node *node,
                return -ENOMEM;
        }
 
-       ret = irq_alloc_domain_generic_chips(nvic_irq_domain, 32, numbanks,
+       ret = irq_alloc_domain_generic_chips(nvic_irq_domain, 32, 1,
                                             "nvic_irq", handle_fasteoi_irq,
                                             clr, 0, IRQ_GC_INIT_MASK_CACHE);
        if (ret) {
index b66d4ae..a5438d8 100644 (file)
@@ -38,7 +38,7 @@ static struct irq_domain *sun4i_irq_domain;
 
 static asmlinkage void __exception_irq_entry sun4i_handle_irq(struct pt_regs *regs);
 
-void sun4i_irq_ack(struct irq_data *irqd)
+static void sun4i_irq_ack(struct irq_data *irqd)
 {
        unsigned int irq = irqd_to_hwirq(irqd);
        unsigned int irq_off = irq % 32;
index d970595..1846e7d 100644 (file)
@@ -178,7 +178,8 @@ static struct irq_domain_ops vt8500_irq_domain_ops = {
        .xlate = irq_domain_xlate_onecell,
 };
 
-asmlinkage void __exception_irq_entry vt8500_handle_irq(struct pt_regs *regs)
+static asmlinkage
+void __exception_irq_entry vt8500_handle_irq(struct pt_regs *regs)
 {
        u32 stat, i;
        int irqnr, virq;
@@ -203,7 +204,8 @@ asmlinkage void __exception_irq_entry vt8500_handle_irq(struct pt_regs *regs)
        }
 }
 
-int __init vt8500_irq_init(struct device_node *node, struct device_node *parent)
+static int __init vt8500_irq_init(struct device_node *node,
+                                 struct device_node *parent)
 {
        int irq, i;
        struct device_node *np = node;
index 3bfc8f1..30b426e 100644 (file)
@@ -412,4 +412,18 @@ config DM_VERITY
 
          If unsure, say N.
 
+config DM_SWITCH
+       tristate "Switch target support (EXPERIMENTAL)"
+       depends on BLK_DEV_DM
+       ---help---
+         This device-mapper target creates a device that supports an arbitrary
+         mapping of fixed-size regions of I/O across a fixed set of paths.
+         The path used for any specific region can be switched dynamically
+         by sending the target a message.
+
+         To compile this code as a module, choose M here: the module will
+         be called dm-switch.
+
+         If unsure, say N.
+
 endif # MD
index 1439fd4..5ef78ef 100644 (file)
@@ -40,6 +40,7 @@ obj-$(CONFIG_DM_FLAKEY)               += dm-flakey.o
 obj-$(CONFIG_DM_MULTIPATH)     += dm-multipath.o dm-round-robin.o
 obj-$(CONFIG_DM_MULTIPATH_QL)  += dm-queue-length.o
 obj-$(CONFIG_DM_MULTIPATH_ST)  += dm-service-time.o
+obj-$(CONFIG_DM_SWITCH)                += dm-switch.o
 obj-$(CONFIG_DM_SNAPSHOT)      += dm-snapshot.o
 obj-$(CONFIG_DM_PERSISTENT_DATA)       += persistent-data/
 obj-$(CONFIG_DM_MIRROR)                += dm-mirror.o dm-log.o dm-region-hash.o
index 0387e05..5227e07 100644 (file)
@@ -145,6 +145,7 @@ struct dm_buffer {
        unsigned long state;
        unsigned long last_accessed;
        struct dm_bufio_client *c;
+       struct list_head write_list;
        struct bio bio;
        struct bio_vec bio_vec[DM_BUFIO_INLINE_VECS];
 };
@@ -349,7 +350,7 @@ static void *alloc_buffer_data(struct dm_bufio_client *c, gfp_t gfp_mask,
        if (gfp_mask & __GFP_NORETRY)
                noio_flag = memalloc_noio_save();
 
-       ptr = __vmalloc(c->block_size, gfp_mask, PAGE_KERNEL);
+       ptr = __vmalloc(c->block_size, gfp_mask | __GFP_HIGHMEM, PAGE_KERNEL);
 
        if (gfp_mask & __GFP_NORETRY)
                memalloc_noio_restore(noio_flag);
@@ -630,7 +631,8 @@ static int do_io_schedule(void *word)
  * - Submit our write and don't wait on it. We set B_WRITING indicating
  *   that there is a write in progress.
  */
-static void __write_dirty_buffer(struct dm_buffer *b)
+static void __write_dirty_buffer(struct dm_buffer *b,
+                                struct list_head *write_list)
 {
        if (!test_bit(B_DIRTY, &b->state))
                return;
@@ -639,7 +641,24 @@ static void __write_dirty_buffer(struct dm_buffer *b)
        wait_on_bit_lock(&b->state, B_WRITING,
                         do_io_schedule, TASK_UNINTERRUPTIBLE);
 
-       submit_io(b, WRITE, b->block, write_endio);
+       if (!write_list)
+               submit_io(b, WRITE, b->block, write_endio);
+       else
+               list_add_tail(&b->write_list, write_list);
+}
+
+static void __flush_write_list(struct list_head *write_list)
+{
+       struct blk_plug plug;
+       blk_start_plug(&plug);
+       while (!list_empty(write_list)) {
+               struct dm_buffer *b =
+                       list_entry(write_list->next, struct dm_buffer, write_list);
+               list_del(&b->write_list);
+               submit_io(b, WRITE, b->block, write_endio);
+               dm_bufio_cond_resched();
+       }
+       blk_finish_plug(&plug);
 }
 
 /*
@@ -655,7 +674,7 @@ static void __make_buffer_clean(struct dm_buffer *b)
                return;
 
        wait_on_bit(&b->state, B_READING, do_io_schedule, TASK_UNINTERRUPTIBLE);
-       __write_dirty_buffer(b);
+       __write_dirty_buffer(b, NULL);
        wait_on_bit(&b->state, B_WRITING, do_io_schedule, TASK_UNINTERRUPTIBLE);
 }
 
@@ -802,7 +821,8 @@ static void __free_buffer_wake(struct dm_buffer *b)
        wake_up(&c->free_buffer_wait);
 }
 
-static void __write_dirty_buffers_async(struct dm_bufio_client *c, int no_wait)
+static void __write_dirty_buffers_async(struct dm_bufio_client *c, int no_wait,
+                                       struct list_head *write_list)
 {
        struct dm_buffer *b, *tmp;
 
@@ -818,7 +838,7 @@ static void __write_dirty_buffers_async(struct dm_bufio_client *c, int no_wait)
                if (no_wait && test_bit(B_WRITING, &b->state))
                        return;
 
-               __write_dirty_buffer(b);
+               __write_dirty_buffer(b, write_list);
                dm_bufio_cond_resched();
        }
 }
@@ -853,7 +873,8 @@ static void __get_memory_limit(struct dm_bufio_client *c,
  * If we are over threshold_buffers, start freeing buffers.
  * If we're over "limit_buffers", block until we get under the limit.
  */
-static void __check_watermark(struct dm_bufio_client *c)
+static void __check_watermark(struct dm_bufio_client *c,
+                             struct list_head *write_list)
 {
        unsigned long threshold_buffers, limit_buffers;
 
@@ -872,7 +893,7 @@ static void __check_watermark(struct dm_bufio_client *c)
        }
 
        if (c->n_buffers[LIST_DIRTY] > threshold_buffers)
-               __write_dirty_buffers_async(c, 1);
+               __write_dirty_buffers_async(c, 1, write_list);
 }
 
 /*
@@ -897,7 +918,8 @@ static struct dm_buffer *__find(struct dm_bufio_client *c, sector_t block)
  *--------------------------------------------------------------*/
 
 static struct dm_buffer *__bufio_new(struct dm_bufio_client *c, sector_t block,
-                                    enum new_flag nf, int *need_submit)
+                                    enum new_flag nf, int *need_submit,
+                                    struct list_head *write_list)
 {
        struct dm_buffer *b, *new_b = NULL;
 
@@ -924,7 +946,7 @@ static struct dm_buffer *__bufio_new(struct dm_bufio_client *c, sector_t block,
                goto found_buffer;
        }
 
-       __check_watermark(c);
+       __check_watermark(c, write_list);
 
        b = new_b;
        b->hold_count = 1;
@@ -992,10 +1014,14 @@ static void *new_read(struct dm_bufio_client *c, sector_t block,
        int need_submit;
        struct dm_buffer *b;
 
+       LIST_HEAD(write_list);
+
        dm_bufio_lock(c);
-       b = __bufio_new(c, block, nf, &need_submit);
+       b = __bufio_new(c, block, nf, &need_submit, &write_list);
        dm_bufio_unlock(c);
 
+       __flush_write_list(&write_list);
+
        if (!b)
                return b;
 
@@ -1047,6 +1073,8 @@ void dm_bufio_prefetch(struct dm_bufio_client *c,
 {
        struct blk_plug plug;
 
+       LIST_HEAD(write_list);
+
        BUG_ON(dm_bufio_in_request());
 
        blk_start_plug(&plug);
@@ -1055,7 +1083,15 @@ void dm_bufio_prefetch(struct dm_bufio_client *c,
        for (; n_blocks--; block++) {
                int need_submit;
                struct dm_buffer *b;
-               b = __bufio_new(c, block, NF_PREFETCH, &need_submit);
+               b = __bufio_new(c, block, NF_PREFETCH, &need_submit,
+                               &write_list);
+               if (unlikely(!list_empty(&write_list))) {
+                       dm_bufio_unlock(c);
+                       blk_finish_plug(&plug);
+                       __flush_write_list(&write_list);
+                       blk_start_plug(&plug);
+                       dm_bufio_lock(c);
+               }
                if (unlikely(b != NULL)) {
                        dm_bufio_unlock(c);
 
@@ -1069,7 +1105,6 @@ void dm_bufio_prefetch(struct dm_bufio_client *c,
                                goto flush_plug;
                        dm_bufio_lock(c);
                }
-
        }
 
        dm_bufio_unlock(c);
@@ -1126,11 +1161,14 @@ EXPORT_SYMBOL_GPL(dm_bufio_mark_buffer_dirty);
 
 void dm_bufio_write_dirty_buffers_async(struct dm_bufio_client *c)
 {
+       LIST_HEAD(write_list);
+
        BUG_ON(dm_bufio_in_request());
 
        dm_bufio_lock(c);
-       __write_dirty_buffers_async(c, 0);
+       __write_dirty_buffers_async(c, 0, &write_list);
        dm_bufio_unlock(c);
+       __flush_write_list(&write_list);
 }
 EXPORT_SYMBOL_GPL(dm_bufio_write_dirty_buffers_async);
 
@@ -1147,8 +1185,13 @@ int dm_bufio_write_dirty_buffers(struct dm_bufio_client *c)
        unsigned long buffers_processed = 0;
        struct dm_buffer *b, *tmp;
 
+       LIST_HEAD(write_list);
+
+       dm_bufio_lock(c);
+       __write_dirty_buffers_async(c, 0, &write_list);
+       dm_bufio_unlock(c);
+       __flush_write_list(&write_list);
        dm_bufio_lock(c);
-       __write_dirty_buffers_async(c, 0);
 
 again:
        list_for_each_entry_safe_reverse(b, tmp, &c->lru[LIST_DIRTY], lru_list) {
@@ -1274,7 +1317,7 @@ retry:
        BUG_ON(!b->hold_count);
        BUG_ON(test_bit(B_READING, &b->state));
 
-       __write_dirty_buffer(b);
+       __write_dirty_buffer(b, NULL);
        if (b->hold_count == 1) {
                wait_on_bit(&b->state, B_WRITING,
                            do_io_schedule, TASK_UNINTERRUPTIBLE);
index df44b60..0df3ec0 100644 (file)
@@ -425,6 +425,10 @@ static bool block_size_is_power_of_two(struct cache *cache)
        return cache->sectors_per_block_shift >= 0;
 }
 
+/* gcc on ARM generates spurious references to __udivdi3 and __umoddi3 */
+#if defined(CONFIG_ARM) && __GNUC__ == 4 && __GNUC_MINOR__ <= 6
+__always_inline
+#endif
 static dm_block_t block_div(dm_block_t b, uint32_t n)
 {
        do_div(b, n);
index 7fcf21c..c80a0ec 100644 (file)
@@ -176,7 +176,7 @@ static int flakey_ctr(struct dm_target *ti, unsigned int argc, char **argv)
 
        fc = kzalloc(sizeof(*fc), GFP_KERNEL);
        if (!fc) {
-               ti->error = "Cannot allocate linear context";
+               ti->error = "Cannot allocate context";
                return -ENOMEM;
        }
        fc->start_time = jiffies;
index aa04f02..f1b7586 100644 (file)
@@ -36,6 +36,14 @@ struct hash_cell {
        struct dm_table *new_map;
 };
 
+/*
+ * A dummy definition to make RCU happy.
+ * struct dm_table should never be dereferenced in this file.
+ */
+struct dm_table {
+       int undefined__;
+};
+
 struct vers_iter {
     size_t param_size;
     struct dm_target_versions *vers, *old_vers;
@@ -242,9 +250,10 @@ static int dm_hash_insert(const char *name, const char *uuid, struct mapped_devi
        return -EBUSY;
 }
 
-static void __hash_remove(struct hash_cell *hc)
+static struct dm_table *__hash_remove(struct hash_cell *hc)
 {
        struct dm_table *table;
+       int srcu_idx;
 
        /* remove from the dev hash */
        list_del(&hc->uuid_list);
@@ -253,16 +262,18 @@ static void __hash_remove(struct hash_cell *hc)
        dm_set_mdptr(hc->md, NULL);
        mutex_unlock(&dm_hash_cells_mutex);
 
-       table = dm_get_live_table(hc->md);
-       if (table) {
+       table = dm_get_live_table(hc->md, &srcu_idx);
+       if (table)
                dm_table_event(table);
-               dm_table_put(table);
-       }
+       dm_put_live_table(hc->md, srcu_idx);
 
+       table = NULL;
        if (hc->new_map)
-               dm_table_destroy(hc->new_map);
+               table = hc->new_map;
        dm_put(hc->md);
        free_cell(hc);
+
+       return table;
 }
 
 static void dm_hash_remove_all(int keep_open_devices)
@@ -270,6 +281,7 @@ static void dm_hash_remove_all(int keep_open_devices)
        int i, dev_skipped;
        struct hash_cell *hc;
        struct mapped_device *md;
+       struct dm_table *t;
 
 retry:
        dev_skipped = 0;
@@ -287,10 +299,14 @@ retry:
                                continue;
                        }
 
-                       __hash_remove(hc);
+                       t = __hash_remove(hc);
 
                        up_write(&_hash_lock);
 
+                       if (t) {
+                               dm_sync_table(md);
+                               dm_table_destroy(t);
+                       }
                        dm_put(md);
                        if (likely(keep_open_devices))
                                dm_destroy(md);
@@ -356,6 +372,7 @@ static struct mapped_device *dm_hash_rename(struct dm_ioctl *param,
        struct dm_table *table;
        struct mapped_device *md;
        unsigned change_uuid = (param->flags & DM_UUID_FLAG) ? 1 : 0;
+       int srcu_idx;
 
        /*
         * duplicate new.
@@ -418,11 +435,10 @@ static struct mapped_device *dm_hash_rename(struct dm_ioctl *param,
        /*
         * Wake up any dm event waiters.
         */
-       table = dm_get_live_table(hc->md);
-       if (table) {
+       table = dm_get_live_table(hc->md, &srcu_idx);
+       if (table)
                dm_table_event(table);
-               dm_table_put(table);
-       }
+       dm_put_live_table(hc->md, srcu_idx);
 
        if (!dm_kobject_uevent(hc->md, KOBJ_CHANGE, param->event_nr))
                param->flags |= DM_UEVENT_GENERATED_FLAG;
@@ -620,11 +636,14 @@ static int check_name(const char *name)
  * _hash_lock without first calling dm_table_put, because dm_table_destroy
  * waits for this dm_table_put and could be called under this lock.
  */
-static struct dm_table *dm_get_inactive_table(struct mapped_device *md)
+static struct dm_table *dm_get_inactive_table(struct mapped_device *md, int *srcu_idx)
 {
        struct hash_cell *hc;
        struct dm_table *table = NULL;
 
+       /* increment rcu count, we don't care about the table pointer */
+       dm_get_live_table(md, srcu_idx);
+
        down_read(&_hash_lock);
        hc = dm_get_mdptr(md);
        if (!hc || hc->md != md) {
@@ -633,8 +652,6 @@ static struct dm_table *dm_get_inactive_table(struct mapped_device *md)
        }
 
        table = hc->new_map;
-       if (table)
-               dm_table_get(table);
 
 out:
        up_read(&_hash_lock);
@@ -643,10 +660,11 @@ out:
 }
 
 static struct dm_table *dm_get_live_or_inactive_table(struct mapped_device *md,
-                                                     struct dm_ioctl *param)
+                                                     struct dm_ioctl *param,
+                                                     int *srcu_idx)
 {
        return (param->flags & DM_QUERY_INACTIVE_TABLE_FLAG) ?
-               dm_get_inactive_table(md) : dm_get_live_table(md);
+               dm_get_inactive_table(md, srcu_idx) : dm_get_live_table(md, srcu_idx);
 }
 
 /*
@@ -657,6 +675,7 @@ static void __dev_status(struct mapped_device *md, struct dm_ioctl *param)
 {
        struct gendisk *disk = dm_disk(md);
        struct dm_table *table;
+       int srcu_idx;
 
        param->flags &= ~(DM_SUSPEND_FLAG | DM_READONLY_FLAG |
                          DM_ACTIVE_PRESENT_FLAG);
@@ -676,26 +695,27 @@ static void __dev_status(struct mapped_device *md, struct dm_ioctl *param)
        param->event_nr = dm_get_event_nr(md);
        param->target_count = 0;
 
-       table = dm_get_live_table(md);
+       table = dm_get_live_table(md, &srcu_idx);
        if (table) {
                if (!(param->flags & DM_QUERY_INACTIVE_TABLE_FLAG)) {
                        if (get_disk_ro(disk))
                                param->flags |= DM_READONLY_FLAG;
                        param->target_count = dm_table_get_num_targets(table);
                }
-               dm_table_put(table);
 
                param->flags |= DM_ACTIVE_PRESENT_FLAG;
        }
+       dm_put_live_table(md, srcu_idx);
 
        if (param->flags & DM_QUERY_INACTIVE_TABLE_FLAG) {
-               table = dm_get_inactive_table(md);
+               int srcu_idx;
+               table = dm_get_inactive_table(md, &srcu_idx);
                if (table) {
                        if (!(dm_table_get_mode(table) & FMODE_WRITE))
                                param->flags |= DM_READONLY_FLAG;
                        param->target_count = dm_table_get_num_targets(table);
-                       dm_table_put(table);
                }
+               dm_put_live_table(md, srcu_idx);
        }
 }
 
@@ -796,6 +816,7 @@ static int dev_remove(struct dm_ioctl *param, size_t param_size)
        struct hash_cell *hc;
        struct mapped_device *md;
        int r;
+       struct dm_table *t;
 
        down_write(&_hash_lock);
        hc = __find_device_hash_cell(param);
@@ -819,9 +840,14 @@ static int dev_remove(struct dm_ioctl *param, size_t param_size)
                return r;
        }
 
-       __hash_remove(hc);
+       t = __hash_remove(hc);
        up_write(&_hash_lock);
 
+       if (t) {
+               dm_sync_table(md);
+               dm_table_destroy(t);
+       }
+
        if (!dm_kobject_uevent(md, KOBJ_REMOVE, param->event_nr))
                param->flags |= DM_UEVENT_GENERATED_FLAG;
 
@@ -986,6 +1012,7 @@ static int do_resume(struct dm_ioctl *param)
 
                old_map = dm_swap_table(md, new_map);
                if (IS_ERR(old_map)) {
+                       dm_sync_table(md);
                        dm_table_destroy(new_map);
                        dm_put(md);
                        return PTR_ERR(old_map);
@@ -1003,6 +1030,10 @@ static int do_resume(struct dm_ioctl *param)
                        param->flags |= DM_UEVENT_GENERATED_FLAG;
        }
 
+       /*
+        * Since dm_swap_table synchronizes RCU, nobody should be in
+        * read-side critical section already.
+        */
        if (old_map)
                dm_table_destroy(old_map);
 
@@ -1125,6 +1156,7 @@ static int dev_wait(struct dm_ioctl *param, size_t param_size)
        int r = 0;
        struct mapped_device *md;
        struct dm_table *table;
+       int srcu_idx;
 
        md = find_device(param);
        if (!md)
@@ -1145,11 +1177,10 @@ static int dev_wait(struct dm_ioctl *param, size_t param_size)
         */
        __dev_status(md, param);
 
-       table = dm_get_live_or_inactive_table(md, param);
-       if (table) {
+       table = dm_get_live_or_inactive_table(md, param, &srcu_idx);
+       if (table)
                retrieve_status(table, param, param_size);
-               dm_table_put(table);
-       }
+       dm_put_live_table(md, srcu_idx);
 
 out:
        dm_put(md);
@@ -1221,7 +1252,7 @@ static int table_load(struct dm_ioctl *param, size_t param_size)
 {
        int r;
        struct hash_cell *hc;
-       struct dm_table *t;
+       struct dm_table *t, *old_map = NULL;
        struct mapped_device *md;
        struct target_type *immutable_target_type;
 
@@ -1277,14 +1308,14 @@ static int table_load(struct dm_ioctl *param, size_t param_size)
        hc = dm_get_mdptr(md);
        if (!hc || hc->md != md) {
                DMWARN("device has been removed from the dev hash table.");
-               dm_table_destroy(t);
                up_write(&_hash_lock);
+               dm_table_destroy(t);
                r = -ENXIO;
                goto out;
        }
 
        if (hc->new_map)
-               dm_table_destroy(hc->new_map);
+               old_map = hc->new_map;
        hc->new_map = t;
        up_write(&_hash_lock);
 
@@ -1292,6 +1323,11 @@ static int table_load(struct dm_ioctl *param, size_t param_size)
        __dev_status(md, param);
 
 out:
+       if (old_map) {
+               dm_sync_table(md);
+               dm_table_destroy(old_map);
+       }
+
        dm_put(md);
 
        return r;
@@ -1301,6 +1337,7 @@ static int table_clear(struct dm_ioctl *param, size_t param_size)
 {
        struct hash_cell *hc;
        struct mapped_device *md;
+       struct dm_table *old_map = NULL;
 
        down_write(&_hash_lock);
 
@@ -1312,7 +1349,7 @@ static int table_clear(struct dm_ioctl *param, size_t param_size)
        }
 
        if (hc->new_map) {
-               dm_table_destroy(hc->new_map);
+               old_map = hc->new_map;
                hc->new_map = NULL;
        }
 
@@ -1321,6 +1358,10 @@ static int table_clear(struct dm_ioctl *param, size_t param_size)
        __dev_status(hc->md, param);
        md = hc->md;
        up_write(&_hash_lock);
+       if (old_map) {
+               dm_sync_table(md);
+               dm_table_destroy(old_map);
+       }
        dm_put(md);
 
        return 0;
@@ -1370,6 +1411,7 @@ static int table_deps(struct dm_ioctl *param, size_t param_size)
 {
        struct mapped_device *md;
        struct dm_table *table;
+       int srcu_idx;
 
        md = find_device(param);
        if (!md)
@@ -1377,11 +1419,10 @@ static int table_deps(struct dm_ioctl *param, size_t param_size)
 
        __dev_status(md, param);
 
-       table = dm_get_live_or_inactive_table(md, param);
-       if (table) {
+       table = dm_get_live_or_inactive_table(md, param, &srcu_idx);
+       if (table)
                retrieve_deps(table, param, param_size);
-               dm_table_put(table);
-       }
+       dm_put_live_table(md, srcu_idx);
 
        dm_put(md);
 
@@ -1396,6 +1437,7 @@ static int table_status(struct dm_ioctl *param, size_t param_size)
 {
        struct mapped_device *md;
        struct dm_table *table;
+       int srcu_idx;
 
        md = find_device(param);
        if (!md)
@@ -1403,11 +1445,10 @@ static int table_status(struct dm_ioctl *param, size_t param_size)
 
        __dev_status(md, param);
 
-       table = dm_get_live_or_inactive_table(md, param);
-       if (table) {
+       table = dm_get_live_or_inactive_table(md, param, &srcu_idx);
+       if (table)
                retrieve_status(table, param, param_size);
-               dm_table_put(table);
-       }
+       dm_put_live_table(md, srcu_idx);
 
        dm_put(md);
 
@@ -1443,6 +1484,7 @@ static int target_message(struct dm_ioctl *param, size_t param_size)
        struct dm_target_msg *tmsg = (void *) param + param->data_start;
        size_t maxlen;
        char *result = get_result_buffer(param, param_size, &maxlen);
+       int srcu_idx;
 
        md = find_device(param);
        if (!md)
@@ -1470,9 +1512,9 @@ static int target_message(struct dm_ioctl *param, size_t param_size)
        if (r <= 1)
                goto out_argv;
 
-       table = dm_get_live_table(md);
+       table = dm_get_live_table(md, &srcu_idx);
        if (!table)
-               goto out_argv;
+               goto out_table;
 
        if (dm_deleting_md(md)) {
                r = -ENXIO;
@@ -1491,7 +1533,7 @@ static int target_message(struct dm_ioctl *param, size_t param_size)
        }
 
  out_table:
-       dm_table_put(table);
+       dm_put_live_table(md, srcu_idx);
  out_argv:
        kfree(argv);
  out:
@@ -1644,7 +1686,10 @@ static int copy_params(struct dm_ioctl __user *user, struct dm_ioctl *param_kern
        }
 
        if (!dmi) {
-               dmi = __vmalloc(param_kernel->data_size, GFP_NOIO | __GFP_REPEAT | __GFP_HIGH, PAGE_KERNEL);
+               unsigned noio_flag;
+               noio_flag = memalloc_noio_save();
+               dmi = __vmalloc(param_kernel->data_size, GFP_NOIO | __GFP_REPEAT | __GFP_HIGH | __GFP_HIGHMEM, PAGE_KERNEL);
+               memalloc_noio_restore(noio_flag);
                if (dmi)
                        *param_flags |= DM_PARAMS_VMALLOC;
        }
index bdf26f5..5adede1 100644 (file)
@@ -1561,7 +1561,6 @@ static int multipath_ioctl(struct dm_target *ti, unsigned int cmd,
        unsigned long flags;
        int r;
 
-again:
        bdev = NULL;
        mode = 0;
        r = 0;
@@ -1579,7 +1578,7 @@ again:
        }
 
        if ((pgpath && m->queue_io) || (!pgpath && m->queue_if_no_path))
-               r = -EAGAIN;
+               r = -ENOTCONN;
        else if (!bdev)
                r = -EIO;
 
@@ -1591,11 +1590,8 @@ again:
        if (!r && ti->len != i_size_read(bdev->bd_inode) >> SECTOR_SHIFT)
                r = scsi_verify_blk_ioctl(NULL, cmd);
 
-       if (r == -EAGAIN && !fatal_signal_pending(current)) {
+       if (r == -ENOTCONN && !fatal_signal_pending(current))
                queue_work(kmultipathd, &m->process_queued_ios);
-               msleep(10);
-               goto again;
-       }
 
        return r ? : __blkdev_driver_ioctl(bdev, mode, cmd, arg);
 }
diff --git a/drivers/md/dm-switch.c b/drivers/md/dm-switch.c
new file mode 100644 (file)
index 0000000..ff9ac4b
--- /dev/null
@@ -0,0 +1,538 @@
+/*
+ * Copyright (C) 2010-2012 by Dell Inc.  All rights reserved.
+ * Copyright (C) 2011-2013 Red Hat, Inc.
+ *
+ * This file is released under the GPL.
+ *
+ * dm-switch is a device-mapper target that maps IO to underlying block
+ * devices efficiently when there are a large number of fixed-sized
+ * address regions but there is no simple pattern to allow for a compact
+ * mapping representation such as dm-stripe.
+ */
+
+#include <linux/device-mapper.h>
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/vmalloc.h>
+
+#define DM_MSG_PREFIX "switch"
+
+/*
+ * One region_table_slot_t holds <region_entries_per_slot> region table
+ * entries each of which is <region_table_entry_bits> in size.
+ */
+typedef unsigned long region_table_slot_t;
+
+/*
+ * A device with the offset to its start sector.
+ */
+struct switch_path {
+       struct dm_dev *dmdev;
+       sector_t start;
+};
+
+/*
+ * Context block for a dm switch device.
+ */
+struct switch_ctx {
+       struct dm_target *ti;
+
+       unsigned nr_paths;              /* Number of paths in path_list. */
+
+       unsigned region_size;           /* Region size in 512-byte sectors */
+       unsigned long nr_regions;       /* Number of regions making up the device */
+       signed char region_size_bits;   /* log2 of region_size or -1 */
+
+       unsigned char region_table_entry_bits;  /* Number of bits in one region table entry */
+       unsigned char region_entries_per_slot;  /* Number of entries in one region table slot */
+       signed char region_entries_per_slot_bits;       /* log2 of region_entries_per_slot or -1 */
+
+       region_table_slot_t *region_table;      /* Region table */
+
+       /*
+        * Array of dm devices to switch between.
+        */
+       struct switch_path path_list[0];
+};
+
+static struct switch_ctx *alloc_switch_ctx(struct dm_target *ti, unsigned nr_paths,
+                                          unsigned region_size)
+{
+       struct switch_ctx *sctx;
+
+       sctx = kzalloc(sizeof(struct switch_ctx) + nr_paths * sizeof(struct switch_path),
+                      GFP_KERNEL);
+       if (!sctx)
+               return NULL;
+
+       sctx->ti = ti;
+       sctx->region_size = region_size;
+
+       ti->private = sctx;
+
+       return sctx;
+}
+
+static int alloc_region_table(struct dm_target *ti, unsigned nr_paths)
+{
+       struct switch_ctx *sctx = ti->private;
+       sector_t nr_regions = ti->len;
+       sector_t nr_slots;
+
+       if (!(sctx->region_size & (sctx->region_size - 1)))
+               sctx->region_size_bits = __ffs(sctx->region_size);
+       else
+               sctx->region_size_bits = -1;
+
+       sctx->region_table_entry_bits = 1;
+       while (sctx->region_table_entry_bits < sizeof(region_table_slot_t) * 8 &&
+              (region_table_slot_t)1 << sctx->region_table_entry_bits < nr_paths)
+               sctx->region_table_entry_bits++;
+
+       sctx->region_entries_per_slot = (sizeof(region_table_slot_t) * 8) / sctx->region_table_entry_bits;
+       if (!(sctx->region_entries_per_slot & (sctx->region_entries_per_slot - 1)))
+               sctx->region_entries_per_slot_bits = __ffs(sctx->region_entries_per_slot);
+       else
+               sctx->region_entries_per_slot_bits = -1;
+
+       if (sector_div(nr_regions, sctx->region_size))
+               nr_regions++;
+
+       sctx->nr_regions = nr_regions;
+       if (sctx->nr_regions != nr_regions || sctx->nr_regions >= ULONG_MAX) {
+               ti->error = "Region table too large";
+               return -EINVAL;
+       }
+
+       nr_slots = nr_regions;
+       if (sector_div(nr_slots, sctx->region_entries_per_slot))
+               nr_slots++;
+
+       if (nr_slots > ULONG_MAX / sizeof(region_table_slot_t)) {
+               ti->error = "Region table too large";
+               return -EINVAL;
+       }
+
+       sctx->region_table = vmalloc(nr_slots * sizeof(region_table_slot_t));
+       if (!sctx->region_table) {
+               ti->error = "Cannot allocate region table";
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
+static void switch_get_position(struct switch_ctx *sctx, unsigned long region_nr,
+                               unsigned long *region_index, unsigned *bit)
+{
+       if (sctx->region_entries_per_slot_bits >= 0) {
+               *region_index = region_nr >> sctx->region_entries_per_slot_bits;
+               *bit = region_nr & (sctx->region_entries_per_slot - 1);
+       } else {
+               *region_index = region_nr / sctx->region_entries_per_slot;
+               *bit = region_nr % sctx->region_entries_per_slot;
+       }
+
+       *bit *= sctx->region_table_entry_bits;
+}
+
+/*
+ * Find which path to use at given offset.
+ */
+static unsigned switch_get_path_nr(struct switch_ctx *sctx, sector_t offset)
+{
+       unsigned long region_index;
+       unsigned bit, path_nr;
+       sector_t p;
+
+       p = offset;
+       if (sctx->region_size_bits >= 0)
+               p >>= sctx->region_size_bits;
+       else
+               sector_div(p, sctx->region_size);
+
+       switch_get_position(sctx, p, &region_index, &bit);
+       path_nr = (ACCESS_ONCE(sctx->region_table[region_index]) >> bit) &
+              ((1 << sctx->region_table_entry_bits) - 1);
+
+       /* This can only happen if the processor uses non-atomic stores. */
+       if (unlikely(path_nr >= sctx->nr_paths))
+               path_nr = 0;
+
+       return path_nr;
+}
+
+static void switch_region_table_write(struct switch_ctx *sctx, unsigned long region_nr,
+                                     unsigned value)
+{
+       unsigned long region_index;
+       unsigned bit;
+       region_table_slot_t pte;
+
+       switch_get_position(sctx, region_nr, &region_index, &bit);
+
+       pte = sctx->region_table[region_index];
+       pte &= ~((((region_table_slot_t)1 << sctx->region_table_entry_bits) - 1) << bit);
+       pte |= (region_table_slot_t)value << bit;
+       sctx->region_table[region_index] = pte;
+}
+
+/*
+ * Fill the region table with an initial round robin pattern.
+ */
+static void initialise_region_table(struct switch_ctx *sctx)
+{
+       unsigned path_nr = 0;
+       unsigned long region_nr;
+
+       for (region_nr = 0; region_nr < sctx->nr_regions; region_nr++) {
+               switch_region_table_write(sctx, region_nr, path_nr);
+               if (++path_nr >= sctx->nr_paths)
+                       path_nr = 0;
+       }
+}
+
+static int parse_path(struct dm_arg_set *as, struct dm_target *ti)
+{
+       struct switch_ctx *sctx = ti->private;
+       unsigned long long start;
+       int r;
+
+       r = dm_get_device(ti, dm_shift_arg(as), dm_table_get_mode(ti->table),
+                         &sctx->path_list[sctx->nr_paths].dmdev);
+       if (r) {
+               ti->error = "Device lookup failed";
+               return r;
+       }
+
+       if (kstrtoull(dm_shift_arg(as), 10, &start) || start != (sector_t)start) {
+               ti->error = "Invalid device starting offset";
+               dm_put_device(ti, sctx->path_list[sctx->nr_paths].dmdev);
+               return -EINVAL;
+       }
+
+       sctx->path_list[sctx->nr_paths].start = start;
+
+       sctx->nr_paths++;
+
+       return 0;
+}
+
+/*
+ * Destructor: Don't free the dm_target, just the ti->private data (if any).
+ */
+static void switch_dtr(struct dm_target *ti)
+{
+       struct switch_ctx *sctx = ti->private;
+
+       while (sctx->nr_paths--)
+               dm_put_device(ti, sctx->path_list[sctx->nr_paths].dmdev);
+
+       vfree(sctx->region_table);
+       kfree(sctx);
+}
+
+/*
+ * Constructor arguments:
+ *   <num_paths> <region_size> <num_optional_args> [<optional_args>...]
+ *   [<dev_path> <offset>]+
+ *
+ * Optional args are to allow for future extension: currently this
+ * parameter must be 0.
+ */
+static int switch_ctr(struct dm_target *ti, unsigned argc, char **argv)
+{
+       static struct dm_arg _args[] = {
+               {1, (KMALLOC_MAX_SIZE - sizeof(struct switch_ctx)) / sizeof(struct switch_path), "Invalid number of paths"},
+               {1, UINT_MAX, "Invalid region size"},
+               {0, 0, "Invalid number of optional args"},
+       };
+
+       struct switch_ctx *sctx;
+       struct dm_arg_set as;
+       unsigned nr_paths, region_size, nr_optional_args;
+       int r;
+
+       as.argc = argc;
+       as.argv = argv;
+
+       r = dm_read_arg(_args, &as, &nr_paths, &ti->error);
+       if (r)
+               return -EINVAL;
+
+       r = dm_read_arg(_args + 1, &as, &region_size, &ti->error);
+       if (r)
+               return r;
+
+       r = dm_read_arg_group(_args + 2, &as, &nr_optional_args, &ti->error);
+       if (r)
+               return r;
+       /* parse optional arguments here, if we add any */
+
+       if (as.argc != nr_paths * 2) {
+               ti->error = "Incorrect number of path arguments";
+               return -EINVAL;
+       }
+
+       sctx = alloc_switch_ctx(ti, nr_paths, region_size);
+       if (!sctx) {
+               ti->error = "Cannot allocate redirection context";
+               return -ENOMEM;
+       }
+
+       r = dm_set_target_max_io_len(ti, region_size);
+       if (r)
+               goto error;
+
+       while (as.argc) {
+               r = parse_path(&as, ti);
+               if (r)
+                       goto error;
+       }
+
+       r = alloc_region_table(ti, nr_paths);
+       if (r)
+               goto error;
+
+       initialise_region_table(sctx);
+
+       /* For UNMAP, sending the request down any path is sufficient */
+       ti->num_discard_bios = 1;
+
+       return 0;
+
+error:
+       switch_dtr(ti);
+
+       return r;
+}
+
+static int switch_map(struct dm_target *ti, struct bio *bio)
+{
+       struct switch_ctx *sctx = ti->private;
+       sector_t offset = dm_target_offset(ti, bio->bi_sector);
+       unsigned path_nr = switch_get_path_nr(sctx, offset);
+
+       bio->bi_bdev = sctx->path_list[path_nr].dmdev->bdev;
+       bio->bi_sector = sctx->path_list[path_nr].start + offset;
+
+       return DM_MAPIO_REMAPPED;
+}
+
+/*
+ * We need to parse hex numbers in the message as quickly as possible.
+ *
+ * This table-based hex parser improves performance.
+ * It improves a time to load 1000000 entries compared to the condition-based
+ * parser.
+ *             table-based parser      condition-based parser
+ * PA-RISC     0.29s                   0.31s
+ * Opteron     0.0495s                 0.0498s
+ */
+static const unsigned char hex_table[256] = {
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 255, 255, 255, 255, 255, 255,
+255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255
+};
+
+static __always_inline unsigned long parse_hex(const char **string)
+{
+       unsigned char d;
+       unsigned long r = 0;
+
+       while ((d = hex_table[(unsigned char)**string]) < 16) {
+               r = (r << 4) | d;
+               (*string)++;
+       }
+
+       return r;
+}
+
+static int process_set_region_mappings(struct switch_ctx *sctx,
+                            unsigned argc, char **argv)
+{
+       unsigned i;
+       unsigned long region_index = 0;
+
+       for (i = 1; i < argc; i++) {
+               unsigned long path_nr;
+               const char *string = argv[i];
+
+               if (*string == ':')
+                       region_index++;
+               else {
+                       region_index = parse_hex(&string);
+                       if (unlikely(*string != ':')) {
+                               DMWARN("invalid set_region_mappings argument: '%s'", argv[i]);
+                               return -EINVAL;
+                       }
+               }
+
+               string++;
+               if (unlikely(!*string)) {
+                       DMWARN("invalid set_region_mappings argument: '%s'", argv[i]);
+                       return -EINVAL;
+               }
+
+               path_nr = parse_hex(&string);
+               if (unlikely(*string)) {
+                       DMWARN("invalid set_region_mappings argument: '%s'", argv[i]);
+                       return -EINVAL;
+               }
+               if (unlikely(region_index >= sctx->nr_regions)) {
+                       DMWARN("invalid set_region_mappings region number: %lu >= %lu", region_index, sctx->nr_regions);
+                       return -EINVAL;
+               }
+               if (unlikely(path_nr >= sctx->nr_paths)) {
+                       DMWARN("invalid set_region_mappings device: %lu >= %u", path_nr, sctx->nr_paths);
+                       return -EINVAL;
+               }
+
+               switch_region_table_write(sctx, region_index, path_nr);
+       }
+
+       return 0;
+}
+
+/*
+ * Messages are processed one-at-a-time.
+ *
+ * Only set_region_mappings is supported.
+ */
+static int switch_message(struct dm_target *ti, unsigned argc, char **argv)
+{
+       static DEFINE_MUTEX(message_mutex);
+
+       struct switch_ctx *sctx = ti->private;
+       int r = -EINVAL;
+
+       mutex_lock(&message_mutex);
+
+       if (!strcasecmp(argv[0], "set_region_mappings"))
+               r = process_set_region_mappings(sctx, argc, argv);
+       else
+               DMWARN("Unrecognised message received.");
+
+       mutex_unlock(&message_mutex);
+
+       return r;
+}
+
+static void switch_status(struct dm_target *ti, status_type_t type,
+                         unsigned status_flags, char *result, unsigned maxlen)
+{
+       struct switch_ctx *sctx = ti->private;
+       unsigned sz = 0;
+       int path_nr;
+
+       switch (type) {
+       case STATUSTYPE_INFO:
+               result[0] = '\0';
+               break;
+
+       case STATUSTYPE_TABLE:
+               DMEMIT("%u %u 0", sctx->nr_paths, sctx->region_size);
+               for (path_nr = 0; path_nr < sctx->nr_paths; path_nr++)
+                       DMEMIT(" %s %llu", sctx->path_list[path_nr].dmdev->name,
+                              (unsigned long long)sctx->path_list[path_nr].start);
+               break;
+       }
+}
+
+/*
+ * Switch ioctl:
+ *
+ * Passthrough all ioctls to the path for sector 0
+ */
+static int switch_ioctl(struct dm_target *ti, unsigned cmd,
+                       unsigned long arg)
+{
+       struct switch_ctx *sctx = ti->private;
+       struct block_device *bdev;
+       fmode_t mode;
+       unsigned path_nr;
+       int r = 0;
+
+       path_nr = switch_get_path_nr(sctx, 0);
+
+       bdev = sctx->path_list[path_nr].dmdev->bdev;
+       mode = sctx->path_list[path_nr].dmdev->mode;
+
+       /*
+        * Only pass ioctls through if the device sizes match exactly.
+        */
+       if (ti->len + sctx->path_list[path_nr].start != i_size_read(bdev->bd_inode) >> SECTOR_SHIFT)
+               r = scsi_verify_blk_ioctl(NULL, cmd);
+
+       return r ? : __blkdev_driver_ioctl(bdev, mode, cmd, arg);
+}
+
+static int switch_iterate_devices(struct dm_target *ti,
+                                 iterate_devices_callout_fn fn, void *data)
+{
+       struct switch_ctx *sctx = ti->private;
+       int path_nr;
+       int r;
+
+       for (path_nr = 0; path_nr < sctx->nr_paths; path_nr++) {
+               r = fn(ti, sctx->path_list[path_nr].dmdev,
+                        sctx->path_list[path_nr].start, ti->len, data);
+               if (r)
+                       return r;
+       }
+
+       return 0;
+}
+
+static struct target_type switch_target = {
+       .name = "switch",
+       .version = {1, 0, 0},
+       .module = THIS_MODULE,
+       .ctr = switch_ctr,
+       .dtr = switch_dtr,
+       .map = switch_map,
+       .message = switch_message,
+       .status = switch_status,
+       .ioctl = switch_ioctl,
+       .iterate_devices = switch_iterate_devices,
+};
+
+static int __init dm_switch_init(void)
+{
+       int r;
+
+       r = dm_register_target(&switch_target);
+       if (r < 0)
+               DMERR("dm_register_target() failed %d", r);
+
+       return r;
+}
+
+static void __exit dm_switch_exit(void)
+{
+       dm_unregister_target(&switch_target);
+}
+
+module_init(dm_switch_init);
+module_exit(dm_switch_exit);
+
+MODULE_DESCRIPTION(DM_NAME " dynamic path switching target");
+MODULE_AUTHOR("Kevin D. O'Kelley <Kevin_OKelley@dell.com>");
+MODULE_AUTHOR("Narendran Ganapathy <Narendran_Ganapathy@dell.com>");
+MODULE_AUTHOR("Jim Ramsay <Jim_Ramsay@dell.com>");
+MODULE_AUTHOR("Mikulas Patocka <mpatocka@redhat.com>");
+MODULE_LICENSE("GPL");
index 1ff252a..f221812 100644 (file)
 #define KEYS_PER_NODE (NODE_SIZE / sizeof(sector_t))
 #define CHILDREN_PER_NODE (KEYS_PER_NODE + 1)
 
-/*
- * The table has always exactly one reference from either mapped_device->map
- * or hash_cell->new_map. This reference is not counted in table->holders.
- * A pair of dm_create_table/dm_destroy_table functions is used for table
- * creation/destruction.
- *
- * Temporary references from the other code increase table->holders. A pair
- * of dm_table_get/dm_table_put functions is used to manipulate it.
- *
- * When the table is about to be destroyed, we wait for table->holders to
- * drop to zero.
- */
-
 struct dm_table {
        struct mapped_device *md;
-       atomic_t holders;
        unsigned type;
 
        /* btree table */
@@ -208,7 +194,6 @@ int dm_table_create(struct dm_table **result, fmode_t mode,
 
        INIT_LIST_HEAD(&t->devices);
        INIT_LIST_HEAD(&t->target_callbacks);
-       atomic_set(&t->holders, 0);
 
        if (!num_targets)
                num_targets = KEYS_PER_NODE;
@@ -246,10 +231,6 @@ void dm_table_destroy(struct dm_table *t)
        if (!t)
                return;
 
-       while (atomic_read(&t->holders))
-               msleep(1);
-       smp_mb();
-
        /* free the indexes */
        if (t->depth >= 2)
                vfree(t->index[t->depth - 2]);
@@ -274,22 +255,6 @@ void dm_table_destroy(struct dm_table *t)
        kfree(t);
 }
 
-void dm_table_get(struct dm_table *t)
-{
-       atomic_inc(&t->holders);
-}
-EXPORT_SYMBOL(dm_table_get);
-
-void dm_table_put(struct dm_table *t)
-{
-       if (!t)
-               return;
-
-       smp_mb__before_atomic_dec();
-       atomic_dec(&t->holders);
-}
-EXPORT_SYMBOL(dm_table_put);
-
 /*
  * Checks to see if we need to extend highs or targets.
  */
index b948fd8..4b7941d 100644 (file)
@@ -451,7 +451,7 @@ static void verity_prefetch_io(struct work_struct *work)
                                goto no_prefetch_cluster;
 
                        if (unlikely(cluster & (cluster - 1)))
-                               cluster = 1 << (fls(cluster) - 1);
+                               cluster = 1 << __fls(cluster);
 
                        hash_block_start &= ~(sector_t)(cluster - 1);
                        hash_block_end |= cluster - 1;
@@ -695,8 +695,8 @@ static int verity_ctr(struct dm_target *ti, unsigned argc, char **argv)
                goto bad;
        }
 
-       if (sscanf(argv[0], "%d%c", &num, &dummy) != 1 ||
-           num < 0 || num > 1) {
+       if (sscanf(argv[0], "%u%c", &num, &dummy) != 1 ||
+           num > 1) {
                ti->error = "Invalid version";
                r = -EINVAL;
                goto bad;
@@ -723,7 +723,7 @@ static int verity_ctr(struct dm_target *ti, unsigned argc, char **argv)
                r = -EINVAL;
                goto bad;
        }
-       v->data_dev_block_bits = ffs(num) - 1;
+       v->data_dev_block_bits = __ffs(num);
 
        if (sscanf(argv[4], "%u%c", &num, &dummy) != 1 ||
            !num || (num & (num - 1)) ||
@@ -733,7 +733,7 @@ static int verity_ctr(struct dm_target *ti, unsigned argc, char **argv)
                r = -EINVAL;
                goto bad;
        }
-       v->hash_dev_block_bits = ffs(num) - 1;
+       v->hash_dev_block_bits = __ffs(num);
 
        if (sscanf(argv[5], "%llu%c", &num_ll, &dummy) != 1 ||
            (sector_t)(num_ll << (v->data_dev_block_bits - SECTOR_SHIFT))
@@ -812,7 +812,7 @@ static int verity_ctr(struct dm_target *ti, unsigned argc, char **argv)
        }
 
        v->hash_per_block_bits =
-               fls((1 << v->hash_dev_block_bits) / v->digest_size) - 1;
+               __fls((1 << v->hash_dev_block_bits) / v->digest_size);
 
        v->levels = 0;
        if (v->data_blocks)
@@ -831,9 +831,8 @@ static int verity_ctr(struct dm_target *ti, unsigned argc, char **argv)
        for (i = v->levels - 1; i >= 0; i--) {
                sector_t s;
                v->hash_level_block[i] = hash_position;
-               s = verity_position_at_level(v, v->data_blocks, i);
-               s = (s >> v->hash_per_block_bits) +
-                   !!(s & ((1 << v->hash_per_block_bits) - 1));
+               s = (v->data_blocks + ((sector_t)1 << ((i + 1) * v->hash_per_block_bits)) - 1)
+                                       >> ((i + 1) * v->hash_per_block_bits);
                if (hash_position + s < hash_position) {
                        ti->error = "Hash device offset overflow";
                        r = -E2BIG;
index d5370a9..9e39d2b 100644 (file)
@@ -117,15 +117,29 @@ EXPORT_SYMBOL_GPL(dm_get_rq_mapinfo);
 #define DMF_MERGE_IS_OPTIONAL 6
 
 /*
+ * A dummy definition to make RCU happy.
+ * struct dm_table should never be dereferenced in this file.
+ */
+struct dm_table {
+       int undefined__;
+};
+
+/*
  * Work processed by per-device workqueue.
  */
 struct mapped_device {
-       struct rw_semaphore io_lock;
+       struct srcu_struct io_barrier;
        struct mutex suspend_lock;
-       rwlock_t map_lock;
        atomic_t holders;
        atomic_t open_count;
 
+       /*
+        * The current mapping.
+        * Use dm_get_live_table{_fast} or take suspend_lock for
+        * dereference.
+        */
+       struct dm_table *map;
+
        unsigned long flags;
 
        struct request_queue *queue;
@@ -155,11 +169,6 @@ struct mapped_device {
        struct workqueue_struct *wq;
 
        /*
-        * The current mapping.
-        */
-       struct dm_table *map;
-
-       /*
         * io objects are allocated from here.
         */
        mempool_t *io_pool;
@@ -386,10 +395,14 @@ static int dm_blk_ioctl(struct block_device *bdev, fmode_t mode,
                        unsigned int cmd, unsigned long arg)
 {
        struct mapped_device *md = bdev->bd_disk->private_data;
-       struct dm_table *map = dm_get_live_table(md);
+       int srcu_idx;
+       struct dm_table *map;
        struct dm_target *tgt;
        int r = -ENOTTY;
 
+retry:
+       map = dm_get_live_table(md, &srcu_idx);
+
        if (!map || !dm_table_get_size(map))
                goto out;
 
@@ -408,7 +421,12 @@ static int dm_blk_ioctl(struct block_device *bdev, fmode_t mode,
                r = tgt->type->ioctl(tgt, cmd, arg);
 
 out:
-       dm_table_put(map);
+       dm_put_live_table(md, srcu_idx);
+
+       if (r == -ENOTCONN) {
+               msleep(10);
+               goto retry;
+       }
 
        return r;
 }
@@ -502,20 +520,39 @@ static void queue_io(struct mapped_device *md, struct bio *bio)
 /*
  * Everyone (including functions in this file), should use this
  * function to access the md->map field, and make sure they call
- * dm_table_put() when finished.
+ * dm_put_live_table() when finished.
  */
-struct dm_table *dm_get_live_table(struct mapped_device *md)
+struct dm_table *dm_get_live_table(struct mapped_device *md, int *srcu_idx) __acquires(md->io_barrier)
 {
-       struct dm_table *t;
-       unsigned long flags;
+       *srcu_idx = srcu_read_lock(&md->io_barrier);
+
+       return srcu_dereference(md->map, &md->io_barrier);
+}
 
-       read_lock_irqsave(&md->map_lock, flags);
-       t = md->map;
-       if (t)
-               dm_table_get(t);
-       read_unlock_irqrestore(&md->map_lock, flags);
+void dm_put_live_table(struct mapped_device *md, int srcu_idx) __releases(md->io_barrier)
+{
+       srcu_read_unlock(&md->io_barrier, srcu_idx);
+}
 
-       return t;
+void dm_sync_table(struct mapped_device *md)
+{
+       synchronize_srcu(&md->io_barrier);
+       synchronize_rcu_expedited();
+}
+
+/*
+ * A fast alternative to dm_get_live_table/dm_put_live_table.
+ * The caller must not block between these two functions.
+ */
+static struct dm_table *dm_get_live_table_fast(struct mapped_device *md) __acquires(RCU)
+{
+       rcu_read_lock();
+       return rcu_dereference(md->map);
+}
+
+static void dm_put_live_table_fast(struct mapped_device *md) __releases(RCU)
+{
+       rcu_read_unlock();
 }
 
 /*
@@ -1349,17 +1386,18 @@ static int __split_and_process_non_flush(struct clone_info *ci)
 /*
  * Entry point to split a bio into clones and submit them to the targets.
  */
-static void __split_and_process_bio(struct mapped_device *md, struct bio *bio)
+static void __split_and_process_bio(struct mapped_device *md,
+                                   struct dm_table *map, struct bio *bio)
 {
        struct clone_info ci;
        int error = 0;
 
-       ci.map = dm_get_live_table(md);
-       if (unlikely(!ci.map)) {
+       if (unlikely(!map)) {
                bio_io_error(bio);
                return;
        }
 
+       ci.map = map;
        ci.md = md;
        ci.io = alloc_io(md);
        ci.io->error = 0;
@@ -1386,7 +1424,6 @@ static void __split_and_process_bio(struct mapped_device *md, struct bio *bio)
 
        /* drop the extra reference count */
        dec_pending(ci.io, error);
-       dm_table_put(ci.map);
 }
 /*-----------------------------------------------------------------
  * CRUD END
@@ -1397,7 +1434,7 @@ static int dm_merge_bvec(struct request_queue *q,
                         struct bio_vec *biovec)
 {
        struct mapped_device *md = q->queuedata;
-       struct dm_table *map = dm_get_live_table(md);
+       struct dm_table *map = dm_get_live_table_fast(md);
        struct dm_target *ti;
        sector_t max_sectors;
        int max_size = 0;
@@ -1407,7 +1444,7 @@ static int dm_merge_bvec(struct request_queue *q,
 
        ti = dm_table_find_target(map, bvm->bi_sector);
        if (!dm_target_is_valid(ti))
-               goto out_table;
+               goto out;
 
        /*
         * Find maximum amount of I/O that won't need splitting
@@ -1436,10 +1473,8 @@ static int dm_merge_bvec(struct request_queue *q,
 
                max_size = 0;
 
-out_table:
-       dm_table_put(map);
-
 out:
+       dm_put_live_table_fast(md);
        /*
         * Always allow an entire first page
         */
@@ -1458,8 +1493,10 @@ static void _dm_request(struct request_queue *q, struct bio *bio)
        int rw = bio_data_dir(bio);
        struct mapped_device *md = q->queuedata;
        int cpu;
+       int srcu_idx;
+       struct dm_table *map;
 
-       down_read(&md->io_lock);
+       map = dm_get_live_table(md, &srcu_idx);
 
        cpu = part_stat_lock();
        part_stat_inc(cpu, &dm_disk(md)->part0, ios[rw]);
@@ -1468,7 +1505,7 @@ static void _dm_request(struct request_queue *q, struct bio *bio)
 
        /* if we're suspended, we have to queue this io for later */
        if (unlikely(test_bit(DMF_BLOCK_IO_FOR_SUSPEND, &md->flags))) {
-               up_read(&md->io_lock);
+               dm_put_live_table(md, srcu_idx);
 
                if (bio_rw(bio) != READA)
                        queue_io(md, bio);
@@ -1477,8 +1514,8 @@ static void _dm_request(struct request_queue *q, struct bio *bio)
                return;
        }
 
-       __split_and_process_bio(md, bio);
-       up_read(&md->io_lock);
+       __split_and_process_bio(md, map, bio);
+       dm_put_live_table(md, srcu_idx);
        return;
 }
 
@@ -1664,7 +1701,8 @@ static struct request *dm_start_request(struct mapped_device *md, struct request
 static void dm_request_fn(struct request_queue *q)
 {
        struct mapped_device *md = q->queuedata;
-       struct dm_table *map = dm_get_live_table(md);
+       int srcu_idx;
+       struct dm_table *map = dm_get_live_table(md, &srcu_idx);
        struct dm_target *ti;
        struct request *rq, *clone;
        sector_t pos;
@@ -1719,7 +1757,7 @@ requeued:
 delay_and_out:
        blk_delay_queue(q, HZ / 10);
 out:
-       dm_table_put(map);
+       dm_put_live_table(md, srcu_idx);
 }
 
 int dm_underlying_device_busy(struct request_queue *q)
@@ -1732,14 +1770,14 @@ static int dm_lld_busy(struct request_queue *q)
 {
        int r;
        struct mapped_device *md = q->queuedata;
-       struct dm_table *map = dm_get_live_table(md);
+       struct dm_table *map = dm_get_live_table_fast(md);
 
        if (!map || test_bit(DMF_BLOCK_IO_FOR_SUSPEND, &md->flags))
                r = 1;
        else
                r = dm_table_any_busy_target(map);
 
-       dm_table_put(map);
+       dm_put_live_table_fast(md);
 
        return r;
 }
@@ -1751,7 +1789,7 @@ static int dm_any_congested(void *congested_data, int bdi_bits)
        struct dm_table *map;
 
        if (!test_bit(DMF_BLOCK_IO_FOR_SUSPEND, &md->flags)) {
-               map = dm_get_live_table(md);
+               map = dm_get_live_table_fast(md);
                if (map) {
                        /*
                         * Request-based dm cares about only own queue for
@@ -1762,9 +1800,8 @@ static int dm_any_congested(void *congested_data, int bdi_bits)
                                    bdi_bits;
                        else
                                r = dm_table_any_congested(map, bdi_bits);
-
-                       dm_table_put(map);
                }
+               dm_put_live_table_fast(md);
        }
 
        return r;
@@ -1869,12 +1906,14 @@ static struct mapped_device *alloc_dev(int minor)
        if (r < 0)
                goto bad_minor;
 
+       r = init_srcu_struct(&md->io_barrier);
+       if (r < 0)
+               goto bad_io_barrier;
+
        md->type = DM_TYPE_NONE;
-       init_rwsem(&md->io_lock);
        mutex_init(&md->suspend_lock);
        mutex_init(&md->type_lock);
        spin_lock_init(&md->deferred_lock);
-       rwlock_init(&md->map_lock);
        atomic_set(&md->holders, 1);
        atomic_set(&md->open_count, 0);
        atomic_set(&md->event_nr, 0);
@@ -1937,6 +1976,8 @@ bad_thread:
 bad_disk:
        blk_cleanup_queue(md->queue);
 bad_queue:
+       cleanup_srcu_struct(&md->io_barrier);
+bad_io_barrier:
        free_minor(minor);
 bad_minor:
        module_put(THIS_MODULE);
@@ -1960,6 +2001,7 @@ static void free_dev(struct mapped_device *md)
                bioset_free(md->bs);
        blk_integrity_unregister(md->disk);
        del_gendisk(md->disk);
+       cleanup_srcu_struct(&md->io_barrier);
        free_minor(minor);
 
        spin_lock(&_minor_lock);
@@ -2102,7 +2144,6 @@ static struct dm_table *__bind(struct mapped_device *md, struct dm_table *t,
        struct dm_table *old_map;
        struct request_queue *q = md->queue;
        sector_t size;
-       unsigned long flags;
        int merge_is_optional;
 
        size = dm_table_get_size(t);
@@ -2131,9 +2172,8 @@ static struct dm_table *__bind(struct mapped_device *md, struct dm_table *t,
 
        merge_is_optional = dm_table_merge_is_optional(t);
 
-       write_lock_irqsave(&md->map_lock, flags);
        old_map = md->map;
-       md->map = t;
+       rcu_assign_pointer(md->map, t);
        md->immutable_target_type = dm_table_get_immutable_target_type(t);
 
        dm_table_set_restrictions(t, q, limits);
@@ -2141,7 +2181,7 @@ static struct dm_table *__bind(struct mapped_device *md, struct dm_table *t,
                set_bit(DMF_MERGE_IS_OPTIONAL, &md->flags);
        else
                clear_bit(DMF_MERGE_IS_OPTIONAL, &md->flags);
-       write_unlock_irqrestore(&md->map_lock, flags);
+       dm_sync_table(md);
 
        return old_map;
 }
@@ -2152,15 +2192,13 @@ static struct dm_table *__bind(struct mapped_device *md, struct dm_table *t,
 static struct dm_table *__unbind(struct mapped_device *md)
 {
        struct dm_table *map = md->map;
-       unsigned long flags;
 
        if (!map)
                return NULL;
 
        dm_table_event_callback(map, NULL, NULL);
-       write_lock_irqsave(&md->map_lock, flags);
-       md->map = NULL;
-       write_unlock_irqrestore(&md->map_lock, flags);
+       rcu_assign_pointer(md->map, NULL);
+       dm_sync_table(md);
 
        return map;
 }
@@ -2312,11 +2350,12 @@ EXPORT_SYMBOL_GPL(dm_device_name);
 static void __dm_destroy(struct mapped_device *md, bool wait)
 {
        struct dm_table *map;
+       int srcu_idx;
 
        might_sleep();
 
        spin_lock(&_minor_lock);
-       map = dm_get_live_table(md);
+       map = dm_get_live_table(md, &srcu_idx);
        idr_replace(&_minor_idr, MINOR_ALLOCED, MINOR(disk_devt(dm_disk(md))));
        set_bit(DMF_FREEING, &md->flags);
        spin_unlock(&_minor_lock);
@@ -2326,6 +2365,9 @@ static void __dm_destroy(struct mapped_device *md, bool wait)
                dm_table_postsuspend_targets(map);
        }
 
+       /* dm_put_live_table must be before msleep, otherwise deadlock is possible */
+       dm_put_live_table(md, srcu_idx);
+
        /*
         * Rare, but there may be I/O requests still going to complete,
         * for example.  Wait for all references to disappear.
@@ -2340,7 +2382,6 @@ static void __dm_destroy(struct mapped_device *md, bool wait)
                       dm_device_name(md), atomic_read(&md->holders));
 
        dm_sysfs_exit(md);
-       dm_table_put(map);
        dm_table_destroy(__unbind(md));
        free_dev(md);
 }
@@ -2397,8 +2438,10 @@ static void dm_wq_work(struct work_struct *work)
        struct mapped_device *md = container_of(work, struct mapped_device,
                                                work);
        struct bio *c;
+       int srcu_idx;
+       struct dm_table *map;
 
-       down_read(&md->io_lock);
+       map = dm_get_live_table(md, &srcu_idx);
 
        while (!test_bit(DMF_BLOCK_IO_FOR_SUSPEND, &md->flags)) {
                spin_lock_irq(&md->deferred_lock);
@@ -2408,17 +2451,13 @@ static void dm_wq_work(struct work_struct *work)
                if (!c)
                        break;
 
-               up_read(&md->io_lock);
-
                if (dm_request_based(md))
                        generic_make_request(c);
                else
-                       __split_and_process_bio(md, c);
-
-               down_read(&md->io_lock);
+                       __split_and_process_bio(md, map, c);
        }
 
-       up_read(&md->io_lock);
+       dm_put_live_table(md, srcu_idx);
 }
 
 static void dm_queue_flush(struct mapped_device *md)
@@ -2450,10 +2489,10 @@ struct dm_table *dm_swap_table(struct mapped_device *md, struct dm_table *table)
         * reappear.
         */
        if (dm_table_has_no_data_devices(table)) {
-               live_map = dm_get_live_table(md);
+               live_map = dm_get_live_table_fast(md);
                if (live_map)
                        limits = md->queue->limits;
-               dm_table_put(live_map);
+               dm_put_live_table_fast(md);
        }
 
        if (!live_map) {
@@ -2533,7 +2572,7 @@ int dm_suspend(struct mapped_device *md, unsigned suspend_flags)
                goto out_unlock;
        }
 
-       map = dm_get_live_table(md);
+       map = md->map;
 
        /*
         * DMF_NOFLUSH_SUSPENDING must be set before presuspend.
@@ -2554,7 +2593,7 @@ int dm_suspend(struct mapped_device *md, unsigned suspend_flags)
        if (!noflush && do_lockfs) {
                r = lock_fs(md);
                if (r)
-                       goto out;
+                       goto out_unlock;
        }
 
        /*
@@ -2569,9 +2608,8 @@ int dm_suspend(struct mapped_device *md, unsigned suspend_flags)
         * (dm_wq_work), we set BMF_BLOCK_IO_FOR_SUSPEND and call
         * flush_workqueue(md->wq).
         */
-       down_write(&md->io_lock);
        set_bit(DMF_BLOCK_IO_FOR_SUSPEND, &md->flags);
-       up_write(&md->io_lock);
+       synchronize_srcu(&md->io_barrier);
 
        /*
         * Stop md->queue before flushing md->wq in case request-based
@@ -2589,10 +2627,9 @@ int dm_suspend(struct mapped_device *md, unsigned suspend_flags)
         */
        r = dm_wait_for_completion(md, TASK_INTERRUPTIBLE);
 
-       down_write(&md->io_lock);
        if (noflush)
                clear_bit(DMF_NOFLUSH_SUSPENDING, &md->flags);
-       up_write(&md->io_lock);
+       synchronize_srcu(&md->io_barrier);
 
        /* were we interrupted ? */
        if (r < 0) {
@@ -2602,7 +2639,7 @@ int dm_suspend(struct mapped_device *md, unsigned suspend_flags)
                        start_queue(md->queue);
 
                unlock_fs(md);
-               goto out; /* pushback list is already flushed, so skip flush */
+               goto out_unlock; /* pushback list is already flushed, so skip flush */
        }
 
        /*
@@ -2615,9 +2652,6 @@ int dm_suspend(struct mapped_device *md, unsigned suspend_flags)
 
        dm_table_postsuspend_targets(map);
 
-out:
-       dm_table_put(map);
-
 out_unlock:
        mutex_unlock(&md->suspend_lock);
        return r;
@@ -2632,7 +2666,7 @@ int dm_resume(struct mapped_device *md)
        if (!dm_suspended_md(md))
                goto out;
 
-       map = dm_get_live_table(md);
+       map = md->map;
        if (!map || !dm_table_get_size(map))
                goto out;
 
@@ -2656,7 +2690,6 @@ int dm_resume(struct mapped_device *md)
 
        r = 0;
 out:
-       dm_table_put(map);
        mutex_unlock(&md->suspend_lock);
 
        return r;
index fe907f2..3077949 100644 (file)
@@ -1,7 +1,6 @@
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
 #include <media/saa7146_vv.h>
-#include <media/v4l2-chip-ident.h>
 #include <media/v4l2-event.h>
 #include <media/v4l2-ctrls.h>
 #include <linux/module.h>
@@ -988,26 +987,6 @@ static int vidioc_streamoff(struct file *file, void *__fh, enum v4l2_buf_type ty
        return err;
 }
 
-static int vidioc_g_chip_ident(struct file *file, void *__fh,
-               struct v4l2_dbg_chip_ident *chip)
-{
-       struct saa7146_fh *fh = __fh;
-       struct saa7146_dev *dev = fh->dev;
-
-       chip->ident = V4L2_IDENT_NONE;
-       chip->revision = 0;
-       if (chip->match.type == V4L2_CHIP_MATCH_HOST) {
-               if (v4l2_chip_match_host(&chip->match))
-                       chip->ident = V4L2_IDENT_SAA7146;
-               return 0;
-       }
-       if (chip->match.type != V4L2_CHIP_MATCH_I2C_DRIVER &&
-           chip->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
-               return -EINVAL;
-       return v4l2_device_call_until_err(&dev->v4l2_dev, 0,
-                       core, g_chip_ident, chip);
-}
-
 const struct v4l2_ioctl_ops saa7146_video_ioctl_ops = {
        .vidioc_querycap             = vidioc_querycap,
        .vidioc_enum_fmt_vid_cap     = vidioc_enum_fmt_vid_cap,
@@ -1018,7 +997,6 @@ const struct v4l2_ioctl_ops saa7146_video_ioctl_ops = {
        .vidioc_g_fmt_vid_overlay    = vidioc_g_fmt_vid_overlay,
        .vidioc_try_fmt_vid_overlay  = vidioc_try_fmt_vid_overlay,
        .vidioc_s_fmt_vid_overlay    = vidioc_s_fmt_vid_overlay,
-       .vidioc_g_chip_ident         = vidioc_g_chip_ident,
 
        .vidioc_overlay              = vidioc_overlay,
        .vidioc_g_fbuf               = vidioc_g_fbuf,
@@ -1039,7 +1017,6 @@ const struct v4l2_ioctl_ops saa7146_video_ioctl_ops = {
 const struct v4l2_ioctl_ops saa7146_vbi_ioctl_ops = {
        .vidioc_querycap             = vidioc_querycap,
        .vidioc_g_fmt_vbi_cap        = vidioc_g_fmt_vbi_cap,
-       .vidioc_g_chip_ident         = vidioc_g_chip_ident,
 
        .vidioc_reqbufs              = vidioc_reqbufs,
        .vidioc_querybuf             = vidioc_querybuf,
index 45ac9ee..a142f79 100644 (file)
@@ -1154,7 +1154,7 @@ static int smscore_load_firmware_from_file(struct smscore_device_t *coredev,
 
        char *fw_filename = smscore_get_fw_filename(coredev, mode);
        if (!fw_filename) {
-               sms_info("mode %d not supported on this device", mode);
+               sms_err("mode %d not supported on this device", mode);
                return -ENOENT;
        }
        sms_debug("Firmware name: %s", fw_filename);
@@ -1165,23 +1165,24 @@ static int smscore_load_firmware_from_file(struct smscore_device_t *coredev,
 
        rc = request_firmware(&fw, fw_filename, coredev->device);
        if (rc < 0) {
-               sms_info("failed to open \"%s\"", fw_filename);
+               sms_err("failed to open firmware file \"%s\"", fw_filename);
                return rc;
        }
        sms_info("read fw %s, buffer size=0x%zx", fw_filename, fw->size);
        fw_buf = kmalloc(ALIGN(fw->size, SMS_ALLOC_ALIGNMENT),
                         GFP_KERNEL | GFP_DMA);
        if (!fw_buf) {
-               sms_info("failed to allocate firmware buffer");
-               return -ENOMEM;
-       }
-       memcpy(fw_buf, fw->data, fw->size);
-       fw_buf_size = fw->size;
+               sms_err("failed to allocate firmware buffer");
+               rc = -ENOMEM;
+       } else {
+               memcpy(fw_buf, fw->data, fw->size);
+               fw_buf_size = fw->size;
 
-       rc = (coredev->device_flags & SMS_DEVICE_FAMILY2) ?
-               smscore_load_firmware_family2(coredev, fw_buf, fw_buf_size)
-               : loadfirmware_handler(coredev->context, fw_buf,
-               fw_buf_size);
+               rc = (coredev->device_flags & SMS_DEVICE_FAMILY2) ?
+                       smscore_load_firmware_family2(coredev, fw_buf, fw_buf_size)
+                       : loadfirmware_handler(coredev->context, fw_buf,
+                       fw_buf_size);
+       }
 
        kfree(fw_buf);
        release_firmware(fw);
index 297f1b2..0862622 100644 (file)
@@ -140,6 +140,7 @@ static void smsdvb_stats_not_ready(struct dvb_frontend *fe)
        case DEVICE_MODE_ISDBT:
        case DEVICE_MODE_ISDBT_BDA:
                n_layers = 4;
+               break;
        default:
                n_layers = 1;
        }
index cc1e172..c7dace6 100644 (file)
@@ -40,7 +40,6 @@
 #include <media/tuner.h>
 #include <media/tveeprom.h>
 #include <media/v4l2-common.h>
-#include <media/v4l2-chip-ident.h>
 
 MODULE_DESCRIPTION("i2c Hauppauge eeprom decoder driver");
 MODULE_AUTHOR("John Klar");
@@ -67,13 +66,10 @@ MODULE_PARM_DESC(debug, "Debug level (0-1)");
  * The Hauppauge eeprom uses an 8bit field to determine which
  * tuner formats the tuner supports.
  */
-static struct HAUPPAUGE_TUNER_FMT
-{
+static const struct {
        int     id;
-       char *name;
-}
-hauppauge_tuner_fmt[] =
-{
+       const char * const name;
+} hauppauge_tuner_fmt[] = {
        { V4L2_STD_UNKNOWN,                   " UNKNOWN" },
        { V4L2_STD_UNKNOWN,                   " FM" },
        { V4L2_STD_B|V4L2_STD_GH,             " PAL(B/G)" },
@@ -88,13 +84,10 @@ hauppauge_tuner_fmt[] =
    supplying this information. Note that many tuners where only used for
    testing and never made it to the outside world. So you will only see
    a subset in actual produced cards. */
-static struct HAUPPAUGE_TUNER
-{
+static const struct {
        int  id;
-       char *name;
-}
-hauppauge_tuner[] =
-{
+       const char * const name;
+} hauppauge_tuner[] = {
        /* 0-9 */
        { TUNER_ABSENT,                 "None" },
        { TUNER_ABSENT,                 "External" },
@@ -298,69 +291,66 @@ hauppauge_tuner[] =
        { TUNER_ABSENT,                 "NXP 18272S"},
 };
 
-/* Use V4L2_IDENT_AMBIGUOUS for those audio 'chips' that are
+/* Use TVEEPROM_AUDPROC_INTERNAL for those audio 'chips' that are
  * internal to a video chip, i.e. not a separate audio chip. */
-static struct HAUPPAUGE_AUDIOIC
-{
+static const struct {
        u32   id;
-       char *name;
-}
-audioIC[] =
-{
+       const char * const name;
+} audio_ic[] = {
        /* 0-4 */
-       { V4L2_IDENT_NONE,      "None"      },
-       { V4L2_IDENT_UNKNOWN,   "TEA6300"   },
-       { V4L2_IDENT_UNKNOWN,   "TEA6320"   },
-       { V4L2_IDENT_UNKNOWN,   "TDA9850"   },
-       { V4L2_IDENT_MSPX4XX,   "MSP3400C"  },
+       { TVEEPROM_AUDPROC_NONE,  "None"      },
+       { TVEEPROM_AUDPROC_OTHER, "TEA6300"   },
+       { TVEEPROM_AUDPROC_OTHER, "TEA6320"   },
+       { TVEEPROM_AUDPROC_OTHER, "TDA9850"   },
+       { TVEEPROM_AUDPROC_MSP,   "MSP3400C"  },
        /* 5-9 */
-       { V4L2_IDENT_MSPX4XX,   "MSP3410D"  },
-       { V4L2_IDENT_MSPX4XX,   "MSP3415"   },
-       { V4L2_IDENT_MSPX4XX,   "MSP3430"   },
-       { V4L2_IDENT_MSPX4XX,   "MSP3438"   },
-       { V4L2_IDENT_UNKNOWN,   "CS5331"    },
+       { TVEEPROM_AUDPROC_MSP,   "MSP3410D"  },
+       { TVEEPROM_AUDPROC_MSP,   "MSP3415"   },
+       { TVEEPROM_AUDPROC_MSP,   "MSP3430"   },
+       { TVEEPROM_AUDPROC_MSP,   "MSP3438"   },
+       { TVEEPROM_AUDPROC_OTHER, "CS5331"    },
        /* 10-14 */
-       { V4L2_IDENT_MSPX4XX,   "MSP3435"   },
-       { V4L2_IDENT_MSPX4XX,   "MSP3440"   },
-       { V4L2_IDENT_MSPX4XX,   "MSP3445"   },
-       { V4L2_IDENT_MSPX4XX,   "MSP3411"   },
-       { V4L2_IDENT_MSPX4XX,   "MSP3416"   },
+       { TVEEPROM_AUDPROC_MSP,   "MSP3435"   },
+       { TVEEPROM_AUDPROC_MSP,   "MSP3440"   },
+       { TVEEPROM_AUDPROC_MSP,   "MSP3445"   },
+       { TVEEPROM_AUDPROC_MSP,   "MSP3411"   },
+       { TVEEPROM_AUDPROC_MSP,   "MSP3416"   },
        /* 15-19 */
-       { V4L2_IDENT_MSPX4XX,   "MSP3425"   },
-       { V4L2_IDENT_MSPX4XX,   "MSP3451"   },
-       { V4L2_IDENT_MSPX4XX,   "MSP3418"   },
-       { V4L2_IDENT_UNKNOWN,   "Type 0x12" },
-       { V4L2_IDENT_UNKNOWN,   "OKI7716"   },
+       { TVEEPROM_AUDPROC_MSP,   "MSP3425"   },
+       { TVEEPROM_AUDPROC_MSP,   "MSP3451"   },
+       { TVEEPROM_AUDPROC_MSP,   "MSP3418"   },
+       { TVEEPROM_AUDPROC_OTHER, "Type 0x12" },
+       { TVEEPROM_AUDPROC_OTHER, "OKI7716"   },
        /* 20-24 */
-       { V4L2_IDENT_MSPX4XX,   "MSP4410"   },
-       { V4L2_IDENT_MSPX4XX,   "MSP4420"   },
-       { V4L2_IDENT_MSPX4XX,   "MSP4440"   },
-       { V4L2_IDENT_MSPX4XX,   "MSP4450"   },
-       { V4L2_IDENT_MSPX4XX,   "MSP4408"   },
+       { TVEEPROM_AUDPROC_MSP,   "MSP4410"   },
+       { TVEEPROM_AUDPROC_MSP,   "MSP4420"   },
+       { TVEEPROM_AUDPROC_MSP,   "MSP4440"   },
+       { TVEEPROM_AUDPROC_MSP,   "MSP4450"   },
+       { TVEEPROM_AUDPROC_MSP,   "MSP4408"   },
        /* 25-29 */
-       { V4L2_IDENT_MSPX4XX,   "MSP4418"   },
-       { V4L2_IDENT_MSPX4XX,   "MSP4428"   },
-       { V4L2_IDENT_MSPX4XX,   "MSP4448"   },
-       { V4L2_IDENT_MSPX4XX,   "MSP4458"   },
-       { V4L2_IDENT_MSPX4XX,   "Type 0x1d" },
+       { TVEEPROM_AUDPROC_MSP,   "MSP4418"   },
+       { TVEEPROM_AUDPROC_MSP,   "MSP4428"   },
+       { TVEEPROM_AUDPROC_MSP,   "MSP4448"   },
+       { TVEEPROM_AUDPROC_MSP,   "MSP4458"   },
+       { TVEEPROM_AUDPROC_MSP,   "Type 0x1d" },
        /* 30-34 */
-       { V4L2_IDENT_AMBIGUOUS, "CX880"     },
-       { V4L2_IDENT_AMBIGUOUS, "CX881"     },
-       { V4L2_IDENT_AMBIGUOUS, "CX883"     },
-       { V4L2_IDENT_AMBIGUOUS, "CX882"     },
-       { V4L2_IDENT_AMBIGUOUS, "CX25840"   },
+       { TVEEPROM_AUDPROC_INTERNAL, "CX880"     },
+       { TVEEPROM_AUDPROC_INTERNAL, "CX881"     },
+       { TVEEPROM_AUDPROC_INTERNAL, "CX883"     },
+       { TVEEPROM_AUDPROC_INTERNAL, "CX882"     },
+       { TVEEPROM_AUDPROC_INTERNAL, "CX25840"   },
        /* 35-39 */
-       { V4L2_IDENT_AMBIGUOUS, "CX25841"   },
-       { V4L2_IDENT_AMBIGUOUS, "CX25842"   },
-       { V4L2_IDENT_AMBIGUOUS, "CX25843"   },
-       { V4L2_IDENT_AMBIGUOUS, "CX23418"   },
-       { V4L2_IDENT_AMBIGUOUS, "CX23885"   },
+       { TVEEPROM_AUDPROC_INTERNAL, "CX25841"   },
+       { TVEEPROM_AUDPROC_INTERNAL, "CX25842"   },
+       { TVEEPROM_AUDPROC_INTERNAL, "CX25843"   },
+       { TVEEPROM_AUDPROC_INTERNAL, "CX23418"   },
+       { TVEEPROM_AUDPROC_INTERNAL, "CX23885"   },
        /* 40-44 */
-       { V4L2_IDENT_AMBIGUOUS, "CX23888"   },
-       { V4L2_IDENT_AMBIGUOUS, "SAA7131"   },
-       { V4L2_IDENT_AMBIGUOUS, "CX23887"   },
-       { V4L2_IDENT_AMBIGUOUS, "SAA7164"   },
-       { V4L2_IDENT_AMBIGUOUS, "AU8522"    },
+       { TVEEPROM_AUDPROC_INTERNAL, "CX23888"   },
+       { TVEEPROM_AUDPROC_INTERNAL, "SAA7131"   },
+       { TVEEPROM_AUDPROC_INTERNAL, "CX23887"   },
+       { TVEEPROM_AUDPROC_INTERNAL, "SAA7164"   },
+       { TVEEPROM_AUDPROC_INTERNAL, "AU8522"    },
 };
 
 /* This list is supplied by Hauppauge. Thanks! */
@@ -453,11 +443,11 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
        int i, j, len, done, beenhere, tag, start;
 
        int tuner1 = 0, t_format1 = 0, audioic = -1;
-       char *t_name1 = NULL;
+       const char *t_name1 = NULL;
        const char *t_fmt_name1[8] = { " none", "", "", "", "", "", "", "" };
 
        int tuner2 = 0, t_format2 = 0;
-       char *t_name2 = NULL;
+       const char *t_name2 = NULL;
        const char *t_fmt_name2[8] = { " none", "", "", "", "", "", "", "" };
 
        memset(tvee, 0, sizeof(*tvee));
@@ -545,10 +535,10 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
                        to indicate 4052 mux was removed in favor of using MSP
                        inputs directly. */
                        audioic = eeprom_data[i+2] & 0x7f;
-                       if (audioic < ARRAY_SIZE(audioIC))
-                               tvee->audio_processor = audioIC[audioic].id;
+                       if (audioic < ARRAY_SIZE(audio_ic))
+                               tvee->audio_processor = audio_ic[audioic].id;
                        else
-                               tvee->audio_processor = V4L2_IDENT_UNKNOWN;
+                               tvee->audio_processor = TVEEPROM_AUDPROC_OTHER;
                        break;
 
                /* case 0x03: tag 'EEInfo' */
@@ -578,10 +568,10 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
                        to indicate 4052 mux was removed in favor of using MSP
                        inputs directly. */
                        audioic = eeprom_data[i+1] & 0x7f;
-                       if (audioic < ARRAY_SIZE(audioIC))
-                               tvee->audio_processor = audioIC[audioic].id;
+                       if (audioic < ARRAY_SIZE(audio_ic))
+                               tvee->audio_processor = audio_ic[audioic].id;
                        else
-                               tvee->audio_processor = V4L2_IDENT_UNKNOWN;
+                               tvee->audio_processor = TVEEPROM_AUDPROC_OTHER;
 
                        break;
 
@@ -726,11 +716,11 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
                        t_fmt_name2[6], t_fmt_name2[7], t_format2);
        if (audioic < 0) {
                tveeprom_info("audio processor is unknown (no idx)\n");
-               tvee->audio_processor = V4L2_IDENT_UNKNOWN;
+               tvee->audio_processor = TVEEPROM_AUDPROC_OTHER;
        } else {
-               if (audioic < ARRAY_SIZE(audioIC))
+               if (audioic < ARRAY_SIZE(audio_ic))
                        tveeprom_info("audio processor is %s (idx %d)\n",
-                                       audioIC[audioic].name, audioic);
+                                       audio_ic[audioic].name, audioic);
                else
                        tveeprom_info("audio processor is unknown (idx %d)\n",
                                                                audioic);
index a1a3a51..0b4616b 100644 (file)
@@ -377,10 +377,8 @@ static int dvb_dmxdev_section_callback(const u8 *buffer1, size_t buffer1_len,
                ret = dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, buffer2,
                                              buffer2_len);
        }
-       if (ret < 0) {
-               dvb_ringbuffer_flush(&dmxdevfilter->buffer);
+       if (ret < 0)
                dmxdevfilter->buffer.error = ret;
-       }
        if (dmxdevfilter->params.sec.flags & DMX_ONESHOT)
                dmxdevfilter->state = DMXDEV_STATE_DONE;
        spin_unlock(&dmxdevfilter->dev->lock);
@@ -416,10 +414,8 @@ static int dvb_dmxdev_ts_callback(const u8 *buffer1, size_t buffer1_len,
        ret = dvb_dmxdev_buffer_write(buffer, buffer1, buffer1_len);
        if (ret == buffer1_len)
                ret = dvb_dmxdev_buffer_write(buffer, buffer2, buffer2_len);
-       if (ret < 0) {
-               dvb_ringbuffer_flush(buffer);
+       if (ret < 0)
                buffer->error = ret;
-       }
        spin_unlock(&dmxdevfilter->dev->lock);
        wake_up(&buffer->queue);
        return 0;
index 335a8f4..886da16 100644 (file)
 #define USB_PID_TECHNISAT_USB2_HDCI_V2                 0x0002
 #define USB_PID_TECHNISAT_AIRSTAR_TELESTICK_2          0x0004
 #define USB_PID_TECHNISAT_USB2_DVB_S2                  0x0500
+#define USB_PID_CPYTO_REDI_PC50A                       0xa803
+#define USB_PID_CTVDIGDUAL_V2                          0xe410
 #endif
index 2099f21..23a0d05 100644 (file)
@@ -35,7 +35,6 @@
 #include <linux/i2c.h>
 #include <linux/delay.h>
 #include <media/v4l2-common.h>
-#include <media/v4l2-chip-ident.h>
 #include <media/v4l2-device.h>
 #include "au8522.h"
 #include "au8522_priv.h"
@@ -524,13 +523,8 @@ static int au8522_s_ctrl(struct v4l2_ctrl *ctrl)
 static int au8522_g_register(struct v4l2_subdev *sd,
                             struct v4l2_dbg_register *reg)
 {
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct au8522_state *state = to_state(sd);
 
-       if (!v4l2_chip_match_i2c_client(client, &reg->match))
-               return -EINVAL;
-       if (!capable(CAP_SYS_ADMIN))
-               return -EPERM;
        reg->val = au8522_readreg(state, reg->reg & 0xffff);
        return 0;
 }
@@ -538,13 +532,8 @@ static int au8522_g_register(struct v4l2_subdev *sd,
 static int au8522_s_register(struct v4l2_subdev *sd,
                             const struct v4l2_dbg_register *reg)
 {
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct au8522_state *state = to_state(sd);
 
-       if (!v4l2_chip_match_i2c_client(client, &reg->match))
-               return -EINVAL;
-       if (!capable(CAP_SYS_ADMIN))
-               return -EPERM;
        au8522_writereg(state, reg->reg, reg->val & 0xff);
        return 0;
 }
@@ -636,20 +625,10 @@ static int au8522_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
        return 0;
 }
 
-static int au8522_g_chip_ident(struct v4l2_subdev *sd,
-                              struct v4l2_dbg_chip_ident *chip)
-{
-       struct au8522_state *state = to_state(sd);
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       return v4l2_chip_ident_i2c_client(client, chip, state->id, state->rev);
-}
-
 /* ----------------------------------------------------------------------- */
 
 static const struct v4l2_subdev_core_ops au8522_core_ops = {
        .log_status = v4l2_ctrl_subdev_log_status,
-       .g_chip_ident = au8522_g_chip_ident,
        .reset = au8522_reset,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
        .g_register = au8522_g_register,
index a54182d..9053614 100644 (file)
@@ -3406,7 +3406,7 @@ static int dib8000_set_frontend(struct dvb_frontend *fe)
 {
        struct dib8000_state *state = fe->demodulator_priv;
        struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
-       int l, i, active, time, ret, time_slave = FE_CALLBACK_TIME_NEVER;
+       int l, i, active, time, time_slave = FE_CALLBACK_TIME_NEVER;
        u8 exit_condition, index_frontend;
        u32 delay, callback_time;
 
@@ -3553,7 +3553,7 @@ static int dib8000_set_frontend(struct dvb_frontend *fe)
                }
        }
 
-       return ret;
+       return 0;
 }
 
 static int dib8000_read_status(struct dvb_frontend *fe, fe_status_t * stat)
index e666718..f22eb9f 100644 (file)
@@ -8,7 +8,7 @@
 /**
  * struct drxk_config - Configure the initial parameters for DRX-K
  *
- * @adr:               I2C Address of the DRX-K
+ * @adr:               I2C address of the DRX-K
  * @parallel_ts:       True means that the device uses parallel TS,
  *                     Serial otherwise.
  * @dynamic_clk:       True means that the clock will be dynamically
index ec24d71..082014d 100644 (file)
@@ -21,6 +21,8 @@
  * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include "dvb_frontend.h"
 #include "drxk.h"
 #include "drxk_hard.h"
-
-static int PowerDownDVBT(struct drxk_state *state, bool setPowerMode);
-static int PowerDownQAM(struct drxk_state *state);
-static int SetDVBTStandard(struct drxk_state *state,
-                          enum OperationMode oMode);
-static int SetQAMStandard(struct drxk_state *state,
-                         enum OperationMode oMode);
-static int SetQAM(struct drxk_state *state, u16 IntermediateFreqkHz,
-                 s32 tunerFreqOffset);
-static int SetDVBTStandard(struct drxk_state *state,
-                          enum OperationMode oMode);
-static int DVBTStart(struct drxk_state *state);
-static int SetDVBT(struct drxk_state *state, u16 IntermediateFreqkHz,
-                  s32 tunerFreqOffset);
-static int GetQAMLockStatus(struct drxk_state *state, u32 *pLockStatus);
-static int GetDVBTLockStatus(struct drxk_state *state, u32 *pLockStatus);
-static int SwitchAntennaToQAM(struct drxk_state *state);
-static int SwitchAntennaToDVBT(struct drxk_state *state);
-
-static bool IsDVBT(struct drxk_state *state)
+#include "dvb_math.h"
+
+static int power_down_dvbt(struct drxk_state *state, bool set_power_mode);
+static int power_down_qam(struct drxk_state *state);
+static int set_dvbt_standard(struct drxk_state *state,
+                          enum operation_mode o_mode);
+static int set_qam_standard(struct drxk_state *state,
+                         enum operation_mode o_mode);
+static int set_qam(struct drxk_state *state, u16 intermediate_freqk_hz,
+                 s32 tuner_freq_offset);
+static int set_dvbt_standard(struct drxk_state *state,
+                          enum operation_mode o_mode);
+static int dvbt_start(struct drxk_state *state);
+static int set_dvbt(struct drxk_state *state, u16 intermediate_freqk_hz,
+                  s32 tuner_freq_offset);
+static int get_qam_lock_status(struct drxk_state *state, u32 *p_lock_status);
+static int get_dvbt_lock_status(struct drxk_state *state, u32 *p_lock_status);
+static int switch_antenna_to_qam(struct drxk_state *state);
+static int switch_antenna_to_dvbt(struct drxk_state *state);
+
+static bool is_dvbt(struct drxk_state *state)
 {
-       return state->m_OperationMode == OM_DVBT;
+       return state->m_operation_mode == OM_DVBT;
 }
 
-static bool IsQAM(struct drxk_state *state)
+static bool is_qam(struct drxk_state *state)
 {
-       return state->m_OperationMode == OM_QAM_ITU_A ||
-           state->m_OperationMode == OM_QAM_ITU_B ||
-           state->m_OperationMode == OM_QAM_ITU_C;
+       return state->m_operation_mode == OM_QAM_ITU_A ||
+           state->m_operation_mode == OM_QAM_ITU_B ||
+           state->m_operation_mode == OM_QAM_ITU_C;
 }
 
 #define NOA1ROM 0
@@ -165,7 +168,7 @@ MODULE_PARM_DESC(debug, "enable debug messages");
 
 #define dprintk(level, fmt, arg...) do {                       \
 if (debug >= level)                                            \
-       printk(KERN_DEBUG "drxk: %s" fmt, __func__, ## arg);    \
+       pr_debug(fmt, ##arg);                                   \
 } while (0)
 
 
@@ -186,8 +189,10 @@ static inline u32 Frac28a(u32 a, u32 c)
        u32 R0 = 0;
 
        R0 = (a % c) << 4;      /* 32-28 == 4 shifts possible at max */
-       Q1 = a / c;             /* integer part, only the 4 least significant bits
-                                  will be visible in the result */
+       Q1 = a / c;             /*
+                                * integer part, only the 4 least significant
+                                * bits will be visible in the result
+                                */
 
        /* division using radix 16, 7 nibbles in the result */
        for (i = 0; i < 7; i++) {
@@ -201,98 +206,9 @@ static inline u32 Frac28a(u32 a, u32 c)
        return Q1;
 }
 
-static u32 Log10Times100(u32 x)
+static inline u32 log10times100(u32 value)
 {
-       static const u8 scale = 15;
-       static const u8 indexWidth = 5;
-       u8 i = 0;
-       u32 y = 0;
-       u32 d = 0;
-       u32 k = 0;
-       u32 r = 0;
-       /*
-          log2lut[n] = (1<<scale) * 200 * log2(1.0 + ((1.0/(1<<INDEXWIDTH)) * n))
-          0 <= n < ((1<<INDEXWIDTH)+1)
-        */
-
-       static const u32 log2lut[] = {
-               0,              /* 0.000000 */
-               290941,         /* 290941.300628 */
-               573196,         /* 573196.476418 */
-               847269,         /* 847269.179851 */
-               1113620,        /* 1113620.489452 */
-               1372674,        /* 1372673.576986 */
-               1624818,        /* 1624817.752104 */
-               1870412,        /* 1870411.981536 */
-               2109788,        /* 2109787.962654 */
-               2343253,        /* 2343252.817465 */
-               2571091,        /* 2571091.461923 */
-               2793569,        /* 2793568.696416 */
-               3010931,        /* 3010931.055901 */
-               3223408,        /* 3223408.452106 */
-               3431216,        /* 3431215.635215 */
-               3634553,        /* 3634553.498355 */
-               3833610,        /* 3833610.244726 */
-               4028562,        /* 4028562.434393 */
-               4219576,        /* 4219575.925308 */
-               4406807,        /* 4406806.721144 */
-               4590402,        /* 4590401.736809 */
-               4770499,        /* 4770499.491025 */
-               4947231,        /* 4947230.734179 */
-               5120719,        /* 5120719.018555 */
-               5291081,        /* 5291081.217197 */
-               5458428,        /* 5458427.996830 */
-               5622864,        /* 5622864.249668 */
-               5784489,        /* 5784489.488298 */
-               5943398,        /* 5943398.207380 */
-               6099680,        /* 6099680.215452 */
-               6253421,        /* 6253420.939751 */
-               6404702,        /* 6404701.706649 */
-               6553600,        /* 6553600.000000 */
-       };
-
-
-       if (x == 0)
-               return 0;
-
-       /* Scale x (normalize) */
-       /* computing y in log(x/y) = log(x) - log(y) */
-       if ((x & ((0xffffffff) << (scale + 1))) == 0) {
-               for (k = scale; k > 0; k--) {
-                       if (x & (((u32) 1) << scale))
-                               break;
-                       x <<= 1;
-               }
-       } else {
-               for (k = scale; k < 31; k++) {
-                       if ((x & (((u32) (-1)) << (scale + 1))) == 0)
-                               break;
-                       x >>= 1;
-               }
-       }
-       /*
-          Now x has binary point between bit[scale] and bit[scale-1]
-          and 1.0 <= x < 2.0 */
-
-       /* correction for divison: log(x) = log(x/y)+log(y) */
-       y = k * ((((u32) 1) << scale) * 200);
-
-       /* remove integer part */
-       x &= ((((u32) 1) << scale) - 1);
-       /* get index */
-       i = (u8) (x >> (scale - indexWidth));
-       /* compute delta (x - a) */
-       d = x & ((((u32) 1) << (scale - indexWidth)) - 1);
-       /* compute log, multiplication (d* (..)) must be within range ! */
-       y += log2lut[i] +
-           ((d * (log2lut[i + 1] - log2lut[i])) >> (scale - indexWidth));
-       /* Conver to log10() */
-       y /= 108853;            /* (log2(10) << scale) */
-       r = (y >> 1);
-       /* rounding */
-       if (y & ((u32) 1))
-               r++;
-       return r;
+       return (100L * intlog10(value)) >> 24;
 }
 
 /****************************************************************************/
@@ -344,15 +260,15 @@ static int i2c_write(struct drxk_state *state, u8 adr, u8 *data, int len)
        if (debug > 2) {
                int i;
                for (i = 0; i < len; i++)
-                       printk(KERN_CONT " %02x", data[i]);
-               printk(KERN_CONT "\n");
+                       pr_cont(" %02x", data[i]);
+               pr_cont("\n");
        }
        status = drxk_i2c_transfer(state, &msg, 1);
        if (status >= 0 && status != 1)
                status = -EIO;
 
        if (status < 0)
-               printk(KERN_ERR "drxk: i2c write error at addr 0x%02x\n", adr);
+               pr_err("i2c write error at addr 0x%02x\n", adr);
 
        return status;
 }
@@ -371,22 +287,22 @@ static int i2c_read(struct drxk_state *state,
        status = drxk_i2c_transfer(state, msgs, 2);
        if (status != 2) {
                if (debug > 2)
-                       printk(KERN_CONT ": ERROR!\n");
+                       pr_cont(": ERROR!\n");
                if (status >= 0)
                        status = -EIO;
 
-               printk(KERN_ERR "drxk: i2c read error at addr 0x%02x\n", adr);
+               pr_err("i2c read error at addr 0x%02x\n", adr);
                return status;
        }
        if (debug > 2) {
                int i;
                dprintk(2, ": read from");
                for (i = 0; i < len; i++)
-                       printk(KERN_CONT " %02x", msg[i]);
-               printk(KERN_CONT ", value = ");
+                       pr_cont(" %02x", msg[i]);
+               pr_cont(", value = ");
                for (i = 0; i < alen; i++)
-                       printk(KERN_CONT " %02x", answ[i]);
-               printk(KERN_CONT "\n");
+                       pr_cont(" %02x", answ[i]);
+               pr_cont("\n");
        }
        return 0;
 }
@@ -520,55 +436,55 @@ static int write32(struct drxk_state *state, u32 reg, u32 data)
        return write32_flags(state, reg, data, 0);
 }
 
-static int write_block(struct drxk_state *state, u32 Address,
-                     const int BlockSize, const u8 pBlock[])
+static int write_block(struct drxk_state *state, u32 address,
+                     const int block_size, const u8 p_block[])
 {
-       int status = 0, BlkSize = BlockSize;
-       u8 Flags = 0;
+       int status = 0, blk_size = block_size;
+       u8 flags = 0;
 
        if (state->single_master)
-               Flags |= 0xC0;
-
-       while (BlkSize > 0) {
-               int Chunk = BlkSize > state->m_ChunkSize ?
-                   state->m_ChunkSize : BlkSize;
-               u8 *AdrBuf = &state->Chunk[0];
-               u32 AdrLength = 0;
-
-               if (DRXDAP_FASI_LONG_FORMAT(Address) || (Flags != 0)) {
-                       AdrBuf[0] = (((Address << 1) & 0xFF) | 0x01);
-                       AdrBuf[1] = ((Address >> 16) & 0xFF);
-                       AdrBuf[2] = ((Address >> 24) & 0xFF);
-                       AdrBuf[3] = ((Address >> 7) & 0xFF);
-                       AdrBuf[2] |= Flags;
-                       AdrLength = 4;
-                       if (Chunk == state->m_ChunkSize)
-                               Chunk -= 2;
+               flags |= 0xC0;
+
+       while (blk_size > 0) {
+               int chunk = blk_size > state->m_chunk_size ?
+                   state->m_chunk_size : blk_size;
+               u8 *adr_buf = &state->chunk[0];
+               u32 adr_length = 0;
+
+               if (DRXDAP_FASI_LONG_FORMAT(address) || (flags != 0)) {
+                       adr_buf[0] = (((address << 1) & 0xFF) | 0x01);
+                       adr_buf[1] = ((address >> 16) & 0xFF);
+                       adr_buf[2] = ((address >> 24) & 0xFF);
+                       adr_buf[3] = ((address >> 7) & 0xFF);
+                       adr_buf[2] |= flags;
+                       adr_length = 4;
+                       if (chunk == state->m_chunk_size)
+                               chunk -= 2;
                } else {
-                       AdrBuf[0] = ((Address << 1) & 0xFF);
-                       AdrBuf[1] = (((Address >> 16) & 0x0F) |
-                                    ((Address >> 18) & 0xF0));
-                       AdrLength = 2;
+                       adr_buf[0] = ((address << 1) & 0xFF);
+                       adr_buf[1] = (((address >> 16) & 0x0F) |
+                                    ((address >> 18) & 0xF0));
+                       adr_length = 2;
                }
-               memcpy(&state->Chunk[AdrLength], pBlock, Chunk);
-               dprintk(2, "(0x%08x, 0x%02x)\n", Address, Flags);
+               memcpy(&state->chunk[adr_length], p_block, chunk);
+               dprintk(2, "(0x%08x, 0x%02x)\n", address, flags);
                if (debug > 1) {
                        int i;
-                       if (pBlock)
-                               for (i = 0; i < Chunk; i++)
-                                       printk(KERN_CONT " %02x", pBlock[i]);
-                       printk(KERN_CONT "\n");
+                       if (p_block)
+                               for (i = 0; i < chunk; i++)
+                                       pr_cont(" %02x", p_block[i]);
+                       pr_cont("\n");
                }
                status = i2c_write(state, state->demod_address,
-                                  &state->Chunk[0], Chunk + AdrLength);
+                                  &state->chunk[0], chunk + adr_length);
                if (status < 0) {
-                       printk(KERN_ERR "drxk: %s: i2c write error at addr 0x%02x\n",
-                              __func__, Address);
+                       pr_err("%s: i2c write error at addr 0x%02x\n",
+                              __func__, address);
                        break;
                }
-               pBlock += Chunk;
-               Address += (Chunk >> 1);
-               BlkSize -= Chunk;
+               p_block += chunk;
+               address += (chunk >> 1);
+               blk_size -= chunk;
        }
        return status;
 }
@@ -577,11 +493,11 @@ static int write_block(struct drxk_state *state, u32 Address,
 #define DRXK_MAX_RETRIES_POWERUP 20
 #endif
 
-static int PowerUpDevice(struct drxk_state *state)
+static int power_up_device(struct drxk_state *state)
 {
        int status;
        u8 data = 0;
-       u16 retryCount = 0;
+       u16 retry_count = 0;
 
        dprintk(1, "\n");
 
@@ -591,15 +507,15 @@ static int PowerUpDevice(struct drxk_state *state)
                        data = 0;
                        status = i2c_write(state, state->demod_address,
                                           &data, 1);
-                       msleep(10);
-                       retryCount++;
+                       usleep_range(10000, 11000);
+                       retry_count++;
                        if (status < 0)
                                continue;
                        status = i2c_read1(state, state->demod_address,
                                           &data);
                } while (status < 0 &&
-                        (retryCount < DRXK_MAX_RETRIES_POWERUP));
-               if (status < 0 && retryCount >= DRXK_MAX_RETRIES_POWERUP)
+                        (retry_count < DRXK_MAX_RETRIES_POWERUP));
+               if (status < 0 && retry_count >= DRXK_MAX_RETRIES_POWERUP)
                        goto error;
        }
 
@@ -615,11 +531,11 @@ static int PowerUpDevice(struct drxk_state *state)
        if (status < 0)
                goto error;
 
-       state->m_currentPowerMode = DRX_POWER_UP;
+       state->m_current_power_mode = DRX_POWER_UP;
 
 error:
        if (status < 0)
-               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+               pr_err("Error %d on %s\n", status, __func__);
 
        return status;
 }
@@ -631,106 +547,106 @@ static int init_state(struct drxk_state *state)
         * FIXME: most (all?) of the values bellow should be moved into
         * struct drxk_config, as they are probably board-specific
         */
-       u32 ulVSBIfAgcMode = DRXK_AGC_CTRL_AUTO;
-       u32 ulVSBIfAgcOutputLevel = 0;
-       u32 ulVSBIfAgcMinLevel = 0;
-       u32 ulVSBIfAgcMaxLevel = 0x7FFF;
-       u32 ulVSBIfAgcSpeed = 3;
-
-       u32 ulVSBRfAgcMode = DRXK_AGC_CTRL_AUTO;
-       u32 ulVSBRfAgcOutputLevel = 0;
-       u32 ulVSBRfAgcMinLevel = 0;
-       u32 ulVSBRfAgcMaxLevel = 0x7FFF;
-       u32 ulVSBRfAgcSpeed = 3;
-       u32 ulVSBRfAgcTop = 9500;
-       u32 ulVSBRfAgcCutOffCurrent = 4000;
-
-       u32 ulATVIfAgcMode = DRXK_AGC_CTRL_AUTO;
-       u32 ulATVIfAgcOutputLevel = 0;
-       u32 ulATVIfAgcMinLevel = 0;
-       u32 ulATVIfAgcMaxLevel = 0;
-       u32 ulATVIfAgcSpeed = 3;
-
-       u32 ulATVRfAgcMode = DRXK_AGC_CTRL_OFF;
-       u32 ulATVRfAgcOutputLevel = 0;
-       u32 ulATVRfAgcMinLevel = 0;
-       u32 ulATVRfAgcMaxLevel = 0;
-       u32 ulATVRfAgcTop = 9500;
-       u32 ulATVRfAgcCutOffCurrent = 4000;
-       u32 ulATVRfAgcSpeed = 3;
+       u32 ul_vsb_if_agc_mode = DRXK_AGC_CTRL_AUTO;
+       u32 ul_vsb_if_agc_output_level = 0;
+       u32 ul_vsb_if_agc_min_level = 0;
+       u32 ul_vsb_if_agc_max_level = 0x7FFF;
+       u32 ul_vsb_if_agc_speed = 3;
+
+       u32 ul_vsb_rf_agc_mode = DRXK_AGC_CTRL_AUTO;
+       u32 ul_vsb_rf_agc_output_level = 0;
+       u32 ul_vsb_rf_agc_min_level = 0;
+       u32 ul_vsb_rf_agc_max_level = 0x7FFF;
+       u32 ul_vsb_rf_agc_speed = 3;
+       u32 ul_vsb_rf_agc_top = 9500;
+       u32 ul_vsb_rf_agc_cut_off_current = 4000;
+
+       u32 ul_atv_if_agc_mode = DRXK_AGC_CTRL_AUTO;
+       u32 ul_atv_if_agc_output_level = 0;
+       u32 ul_atv_if_agc_min_level = 0;
+       u32 ul_atv_if_agc_max_level = 0;
+       u32 ul_atv_if_agc_speed = 3;
+
+       u32 ul_atv_rf_agc_mode = DRXK_AGC_CTRL_OFF;
+       u32 ul_atv_rf_agc_output_level = 0;
+       u32 ul_atv_rf_agc_min_level = 0;
+       u32 ul_atv_rf_agc_max_level = 0;
+       u32 ul_atv_rf_agc_top = 9500;
+       u32 ul_atv_rf_agc_cut_off_current = 4000;
+       u32 ul_atv_rf_agc_speed = 3;
 
        u32 ulQual83 = DEFAULT_MER_83;
        u32 ulQual93 = DEFAULT_MER_93;
 
-       u32 ulMpegLockTimeOut = DEFAULT_DRXK_MPEG_LOCK_TIMEOUT;
-       u32 ulDemodLockTimeOut = DEFAULT_DRXK_DEMOD_LOCK_TIMEOUT;
+       u32 ul_mpeg_lock_time_out = DEFAULT_DRXK_MPEG_LOCK_TIMEOUT;
+       u32 ul_demod_lock_time_out = DEFAULT_DRXK_DEMOD_LOCK_TIMEOUT;
 
        /* io_pad_cfg register (8 bit reg.) MSB bit is 1 (default value) */
        /* io_pad_cfg_mode output mode is drive always */
        /* io_pad_cfg_drive is set to power 2 (23 mA) */
-       u32 ulGPIOCfg = 0x0113;
-       u32 ulInvertTSClock = 0;
-       u32 ulTSDataStrength = DRXK_MPEG_SERIAL_OUTPUT_PIN_DRIVE_STRENGTH;
-       u32 ulDVBTBitrate = 50000000;
-       u32 ulDVBCBitrate = DRXK_QAM_SYMBOLRATE_MAX * 8;
+       u32 ul_gpio_cfg = 0x0113;
+       u32 ul_invert_ts_clock = 0;
+       u32 ul_ts_data_strength = DRXK_MPEG_SERIAL_OUTPUT_PIN_DRIVE_STRENGTH;
+       u32 ul_dvbt_bitrate = 50000000;
+       u32 ul_dvbc_bitrate = DRXK_QAM_SYMBOLRATE_MAX * 8;
 
-       u32 ulInsertRSByte = 0;
+       u32 ul_insert_rs_byte = 0;
 
-       u32 ulRfMirror = 1;
-       u32 ulPowerDown = 0;
+       u32 ul_rf_mirror = 1;
+       u32 ul_power_down = 0;
 
        dprintk(1, "\n");
 
-       state->m_hasLNA = false;
-       state->m_hasDVBT = false;
-       state->m_hasDVBC = false;
-       state->m_hasATV = false;
-       state->m_hasOOB = false;
-       state->m_hasAudio = false;
+       state->m_has_lna = false;
+       state->m_has_dvbt = false;
+       state->m_has_dvbc = false;
+       state->m_has_atv = false;
+       state->m_has_oob = false;
+       state->m_has_audio = false;
 
-       if (!state->m_ChunkSize)
-               state->m_ChunkSize = 124;
+       if (!state->m_chunk_size)
+               state->m_chunk_size = 124;
 
-       state->m_oscClockFreq = 0;
-       state->m_smartAntInverted = false;
-       state->m_bPDownOpenBridge = false;
+       state->m_osc_clock_freq = 0;
+       state->m_smart_ant_inverted = false;
+       state->m_b_p_down_open_bridge = false;
 
        /* real system clock frequency in kHz */
-       state->m_sysClockFreq = 151875;
+       state->m_sys_clock_freq = 151875;
        /* Timing div, 250ns/Psys */
        /* Timing div, = (delay (nano seconds) * sysclk (kHz))/ 1000 */
-       state->m_HICfgTimingDiv = ((state->m_sysClockFreq / 1000) *
+       state->m_hi_cfg_timing_div = ((state->m_sys_clock_freq / 1000) *
                                   HI_I2C_DELAY) / 1000;
        /* Clipping */
-       if (state->m_HICfgTimingDiv > SIO_HI_RA_RAM_PAR_2_CFG_DIV__M)
-               state->m_HICfgTimingDiv = SIO_HI_RA_RAM_PAR_2_CFG_DIV__M;
-       state->m_HICfgWakeUpKey = (state->demod_address << 1);
+       if (state->m_hi_cfg_timing_div > SIO_HI_RA_RAM_PAR_2_CFG_DIV__M)
+               state->m_hi_cfg_timing_div = SIO_HI_RA_RAM_PAR_2_CFG_DIV__M;
+       state->m_hi_cfg_wake_up_key = (state->demod_address << 1);
        /* port/bridge/power down ctrl */
-       state->m_HICfgCtrl = SIO_HI_RA_RAM_PAR_5_CFG_SLV0_SLAVE;
+       state->m_hi_cfg_ctrl = SIO_HI_RA_RAM_PAR_5_CFG_SLV0_SLAVE;
 
-       state->m_bPowerDown = (ulPowerDown != 0);
+       state->m_b_power_down = (ul_power_down != 0);
 
-       state->m_DRXK_A3_PATCH_CODE = false;
+       state->m_drxk_a3_patch_code = false;
 
        /* Init AGC and PGA parameters */
        /* VSB IF */
-       state->m_vsbIfAgcCfg.ctrlMode = (ulVSBIfAgcMode);
-       state->m_vsbIfAgcCfg.outputLevel = (ulVSBIfAgcOutputLevel);
-       state->m_vsbIfAgcCfg.minOutputLevel = (ulVSBIfAgcMinLevel);
-       state->m_vsbIfAgcCfg.maxOutputLevel = (ulVSBIfAgcMaxLevel);
-       state->m_vsbIfAgcCfg.speed = (ulVSBIfAgcSpeed);
-       state->m_vsbPgaCfg = 140;
+       state->m_vsb_if_agc_cfg.ctrl_mode = ul_vsb_if_agc_mode;
+       state->m_vsb_if_agc_cfg.output_level = ul_vsb_if_agc_output_level;
+       state->m_vsb_if_agc_cfg.min_output_level = ul_vsb_if_agc_min_level;
+       state->m_vsb_if_agc_cfg.max_output_level = ul_vsb_if_agc_max_level;
+       state->m_vsb_if_agc_cfg.speed = ul_vsb_if_agc_speed;
+       state->m_vsb_pga_cfg = 140;
 
        /* VSB RF */
-       state->m_vsbRfAgcCfg.ctrlMode = (ulVSBRfAgcMode);
-       state->m_vsbRfAgcCfg.outputLevel = (ulVSBRfAgcOutputLevel);
-       state->m_vsbRfAgcCfg.minOutputLevel = (ulVSBRfAgcMinLevel);
-       state->m_vsbRfAgcCfg.maxOutputLevel = (ulVSBRfAgcMaxLevel);
-       state->m_vsbRfAgcCfg.speed = (ulVSBRfAgcSpeed);
-       state->m_vsbRfAgcCfg.top = (ulVSBRfAgcTop);
-       state->m_vsbRfAgcCfg.cutOffCurrent = (ulVSBRfAgcCutOffCurrent);
-       state->m_vsbPreSawCfg.reference = 0x07;
-       state->m_vsbPreSawCfg.usePreSaw = true;
+       state->m_vsb_rf_agc_cfg.ctrl_mode = ul_vsb_rf_agc_mode;
+       state->m_vsb_rf_agc_cfg.output_level = ul_vsb_rf_agc_output_level;
+       state->m_vsb_rf_agc_cfg.min_output_level = ul_vsb_rf_agc_min_level;
+       state->m_vsb_rf_agc_cfg.max_output_level = ul_vsb_rf_agc_max_level;
+       state->m_vsb_rf_agc_cfg.speed = ul_vsb_rf_agc_speed;
+       state->m_vsb_rf_agc_cfg.top = ul_vsb_rf_agc_top;
+       state->m_vsb_rf_agc_cfg.cut_off_current = ul_vsb_rf_agc_cut_off_current;
+       state->m_vsb_pre_saw_cfg.reference = 0x07;
+       state->m_vsb_pre_saw_cfg.use_pre_saw = true;
 
        state->m_Quality83percent = DEFAULT_MER_83;
        state->m_Quality93percent = DEFAULT_MER_93;
@@ -740,127 +656,127 @@ static int init_state(struct drxk_state *state)
        }
 
        /* ATV IF */
-       state->m_atvIfAgcCfg.ctrlMode = (ulATVIfAgcMode);
-       state->m_atvIfAgcCfg.outputLevel = (ulATVIfAgcOutputLevel);
-       state->m_atvIfAgcCfg.minOutputLevel = (ulATVIfAgcMinLevel);
-       state->m_atvIfAgcCfg.maxOutputLevel = (ulATVIfAgcMaxLevel);
-       state->m_atvIfAgcCfg.speed = (ulATVIfAgcSpeed);
+       state->m_atv_if_agc_cfg.ctrl_mode = ul_atv_if_agc_mode;
+       state->m_atv_if_agc_cfg.output_level = ul_atv_if_agc_output_level;
+       state->m_atv_if_agc_cfg.min_output_level = ul_atv_if_agc_min_level;
+       state->m_atv_if_agc_cfg.max_output_level = ul_atv_if_agc_max_level;
+       state->m_atv_if_agc_cfg.speed = ul_atv_if_agc_speed;
 
        /* ATV RF */
-       state->m_atvRfAgcCfg.ctrlMode = (ulATVRfAgcMode);
-       state->m_atvRfAgcCfg.outputLevel = (ulATVRfAgcOutputLevel);
-       state->m_atvRfAgcCfg.minOutputLevel = (ulATVRfAgcMinLevel);
-       state->m_atvRfAgcCfg.maxOutputLevel = (ulATVRfAgcMaxLevel);
-       state->m_atvRfAgcCfg.speed = (ulATVRfAgcSpeed);
-       state->m_atvRfAgcCfg.top = (ulATVRfAgcTop);
-       state->m_atvRfAgcCfg.cutOffCurrent = (ulATVRfAgcCutOffCurrent);
-       state->m_atvPreSawCfg.reference = 0x04;
-       state->m_atvPreSawCfg.usePreSaw = true;
+       state->m_atv_rf_agc_cfg.ctrl_mode = ul_atv_rf_agc_mode;
+       state->m_atv_rf_agc_cfg.output_level = ul_atv_rf_agc_output_level;
+       state->m_atv_rf_agc_cfg.min_output_level = ul_atv_rf_agc_min_level;
+       state->m_atv_rf_agc_cfg.max_output_level = ul_atv_rf_agc_max_level;
+       state->m_atv_rf_agc_cfg.speed = ul_atv_rf_agc_speed;
+       state->m_atv_rf_agc_cfg.top = ul_atv_rf_agc_top;
+       state->m_atv_rf_agc_cfg.cut_off_current = ul_atv_rf_agc_cut_off_current;
+       state->m_atv_pre_saw_cfg.reference = 0x04;
+       state->m_atv_pre_saw_cfg.use_pre_saw = true;
 
 
        /* DVBT RF */
-       state->m_dvbtRfAgcCfg.ctrlMode = DRXK_AGC_CTRL_OFF;
-       state->m_dvbtRfAgcCfg.outputLevel = 0;
-       state->m_dvbtRfAgcCfg.minOutputLevel = 0;
-       state->m_dvbtRfAgcCfg.maxOutputLevel = 0xFFFF;
-       state->m_dvbtRfAgcCfg.top = 0x2100;
-       state->m_dvbtRfAgcCfg.cutOffCurrent = 4000;
-       state->m_dvbtRfAgcCfg.speed = 1;
+       state->m_dvbt_rf_agc_cfg.ctrl_mode = DRXK_AGC_CTRL_OFF;
+       state->m_dvbt_rf_agc_cfg.output_level = 0;
+       state->m_dvbt_rf_agc_cfg.min_output_level = 0;
+       state->m_dvbt_rf_agc_cfg.max_output_level = 0xFFFF;
+       state->m_dvbt_rf_agc_cfg.top = 0x2100;
+       state->m_dvbt_rf_agc_cfg.cut_off_current = 4000;
+       state->m_dvbt_rf_agc_cfg.speed = 1;
 
 
        /* DVBT IF */
-       state->m_dvbtIfAgcCfg.ctrlMode = DRXK_AGC_CTRL_AUTO;
-       state->m_dvbtIfAgcCfg.outputLevel = 0;
-       state->m_dvbtIfAgcCfg.minOutputLevel = 0;
-       state->m_dvbtIfAgcCfg.maxOutputLevel = 9000;
-       state->m_dvbtIfAgcCfg.top = 13424;
-       state->m_dvbtIfAgcCfg.cutOffCurrent = 0;
-       state->m_dvbtIfAgcCfg.speed = 3;
-       state->m_dvbtIfAgcCfg.FastClipCtrlDelay = 30;
-       state->m_dvbtIfAgcCfg.IngainTgtMax = 30000;
+       state->m_dvbt_if_agc_cfg.ctrl_mode = DRXK_AGC_CTRL_AUTO;
+       state->m_dvbt_if_agc_cfg.output_level = 0;
+       state->m_dvbt_if_agc_cfg.min_output_level = 0;
+       state->m_dvbt_if_agc_cfg.max_output_level = 9000;
+       state->m_dvbt_if_agc_cfg.top = 13424;
+       state->m_dvbt_if_agc_cfg.cut_off_current = 0;
+       state->m_dvbt_if_agc_cfg.speed = 3;
+       state->m_dvbt_if_agc_cfg.fast_clip_ctrl_delay = 30;
+       state->m_dvbt_if_agc_cfg.ingain_tgt_max = 30000;
        /* state->m_dvbtPgaCfg = 140; */
 
-       state->m_dvbtPreSawCfg.reference = 4;
-       state->m_dvbtPreSawCfg.usePreSaw = false;
+       state->m_dvbt_pre_saw_cfg.reference = 4;
+       state->m_dvbt_pre_saw_cfg.use_pre_saw = false;
 
        /* QAM RF */
-       state->m_qamRfAgcCfg.ctrlMode = DRXK_AGC_CTRL_OFF;
-       state->m_qamRfAgcCfg.outputLevel = 0;
-       state->m_qamRfAgcCfg.minOutputLevel = 6023;
-       state->m_qamRfAgcCfg.maxOutputLevel = 27000;
-       state->m_qamRfAgcCfg.top = 0x2380;
-       state->m_qamRfAgcCfg.cutOffCurrent = 4000;
-       state->m_qamRfAgcCfg.speed = 3;
+       state->m_qam_rf_agc_cfg.ctrl_mode = DRXK_AGC_CTRL_OFF;
+       state->m_qam_rf_agc_cfg.output_level = 0;
+       state->m_qam_rf_agc_cfg.min_output_level = 6023;
+       state->m_qam_rf_agc_cfg.max_output_level = 27000;
+       state->m_qam_rf_agc_cfg.top = 0x2380;
+       state->m_qam_rf_agc_cfg.cut_off_current = 4000;
+       state->m_qam_rf_agc_cfg.speed = 3;
 
        /* QAM IF */
-       state->m_qamIfAgcCfg.ctrlMode = DRXK_AGC_CTRL_AUTO;
-       state->m_qamIfAgcCfg.outputLevel = 0;
-       state->m_qamIfAgcCfg.minOutputLevel = 0;
-       state->m_qamIfAgcCfg.maxOutputLevel = 9000;
-       state->m_qamIfAgcCfg.top = 0x0511;
-       state->m_qamIfAgcCfg.cutOffCurrent = 0;
-       state->m_qamIfAgcCfg.speed = 3;
-       state->m_qamIfAgcCfg.IngainTgtMax = 5119;
-       state->m_qamIfAgcCfg.FastClipCtrlDelay = 50;
-
-       state->m_qamPgaCfg = 140;
-       state->m_qamPreSawCfg.reference = 4;
-       state->m_qamPreSawCfg.usePreSaw = false;
-
-       state->m_OperationMode = OM_NONE;
-       state->m_DrxkState = DRXK_UNINITIALIZED;
+       state->m_qam_if_agc_cfg.ctrl_mode = DRXK_AGC_CTRL_AUTO;
+       state->m_qam_if_agc_cfg.output_level = 0;
+       state->m_qam_if_agc_cfg.min_output_level = 0;
+       state->m_qam_if_agc_cfg.max_output_level = 9000;
+       state->m_qam_if_agc_cfg.top = 0x0511;
+       state->m_qam_if_agc_cfg.cut_off_current = 0;
+       state->m_qam_if_agc_cfg.speed = 3;
+       state->m_qam_if_agc_cfg.ingain_tgt_max = 5119;
+       state->m_qam_if_agc_cfg.fast_clip_ctrl_delay = 50;
+
+       state->m_qam_pga_cfg = 140;
+       state->m_qam_pre_saw_cfg.reference = 4;
+       state->m_qam_pre_saw_cfg.use_pre_saw = false;
+
+       state->m_operation_mode = OM_NONE;
+       state->m_drxk_state = DRXK_UNINITIALIZED;
 
        /* MPEG output configuration */
-       state->m_enableMPEGOutput = true;       /* If TRUE; enable MPEG ouput */
-       state->m_insertRSByte = false;  /* If TRUE; insert RS byte */
-       state->m_invertDATA = false;    /* If TRUE; invert DATA signals */
-       state->m_invertERR = false;     /* If TRUE; invert ERR signal */
-       state->m_invertSTR = false;     /* If TRUE; invert STR signals */
-       state->m_invertVAL = false;     /* If TRUE; invert VAL signals */
-       state->m_invertCLK = (ulInvertTSClock != 0);    /* If TRUE; invert CLK signals */
+       state->m_enable_mpeg_output = true;     /* If TRUE; enable MPEG ouput */
+       state->m_insert_rs_byte = false;        /* If TRUE; insert RS byte */
+       state->m_invert_data = false;   /* If TRUE; invert DATA signals */
+       state->m_invert_err = false;    /* If TRUE; invert ERR signal */
+       state->m_invert_str = false;    /* If TRUE; invert STR signals */
+       state->m_invert_val = false;    /* If TRUE; invert VAL signals */
+       state->m_invert_clk = (ul_invert_ts_clock != 0);        /* If TRUE; invert CLK signals */
 
        /* If TRUE; static MPEG clockrate will be used;
           otherwise clockrate will adapt to the bitrate of the TS */
 
-       state->m_DVBTBitrate = ulDVBTBitrate;
-       state->m_DVBCBitrate = ulDVBCBitrate;
+       state->m_dvbt_bitrate = ul_dvbt_bitrate;
+       state->m_dvbc_bitrate = ul_dvbc_bitrate;
 
-       state->m_TSDataStrength = (ulTSDataStrength & 0x07);
+       state->m_ts_data_strength = (ul_ts_data_strength & 0x07);
 
        /* Maximum bitrate in b/s in case static clockrate is selected */
-       state->m_mpegTsStaticBitrate = 19392658;
-       state->m_disableTEIhandling = false;
+       state->m_mpeg_ts_static_bitrate = 19392658;
+       state->m_disable_te_ihandling = false;
 
-       if (ulInsertRSByte)
-               state->m_insertRSByte = true;
+       if (ul_insert_rs_byte)
+               state->m_insert_rs_byte = true;
 
-       state->m_MpegLockTimeOut = DEFAULT_DRXK_MPEG_LOCK_TIMEOUT;
-       if (ulMpegLockTimeOut < 10000)
-               state->m_MpegLockTimeOut = ulMpegLockTimeOut;
-       state->m_DemodLockTimeOut = DEFAULT_DRXK_DEMOD_LOCK_TIMEOUT;
-       if (ulDemodLockTimeOut < 10000)
-               state->m_DemodLockTimeOut = ulDemodLockTimeOut;
+       state->m_mpeg_lock_time_out = DEFAULT_DRXK_MPEG_LOCK_TIMEOUT;
+       if (ul_mpeg_lock_time_out < 10000)
+               state->m_mpeg_lock_time_out = ul_mpeg_lock_time_out;
+       state->m_demod_lock_time_out = DEFAULT_DRXK_DEMOD_LOCK_TIMEOUT;
+       if (ul_demod_lock_time_out < 10000)
+               state->m_demod_lock_time_out = ul_demod_lock_time_out;
 
        /* QAM defaults */
-       state->m_Constellation = DRX_CONSTELLATION_AUTO;
-       state->m_qamInterleaveMode = DRXK_QAM_I12_J17;
-       state->m_fecRsPlen = 204 * 8;   /* fecRsPlen  annex A */
-       state->m_fecRsPrescale = 1;
+       state->m_constellation = DRX_CONSTELLATION_AUTO;
+       state->m_qam_interleave_mode = DRXK_QAM_I12_J17;
+       state->m_fec_rs_plen = 204 * 8; /* fecRsPlen  annex A */
+       state->m_fec_rs_prescale = 1;
 
-       state->m_sqiSpeed = DRXK_DVBT_SQI_SPEED_MEDIUM;
-       state->m_agcFastClipCtrlDelay = 0;
+       state->m_sqi_speed = DRXK_DVBT_SQI_SPEED_MEDIUM;
+       state->m_agcfast_clip_ctrl_delay = 0;
 
-       state->m_GPIOCfg = (ulGPIOCfg);
+       state->m_gpio_cfg = ul_gpio_cfg;
 
-       state->m_bPowerDown = false;
-       state->m_currentPowerMode = DRX_POWER_DOWN;
+       state->m_b_power_down = false;
+       state->m_current_power_mode = DRX_POWER_DOWN;
 
-       state->m_rfmirror = (ulRfMirror == 0);
-       state->m_IfAgcPol = false;
+       state->m_rfmirror = (ul_rf_mirror == 0);
+       state->m_if_agc_pol = false;
        return 0;
 }
 
-static int DRXX_Open(struct drxk_state *state)
+static int drxx_open(struct drxk_state *state)
 {
        int status = 0;
        u32 jtag = 0;
@@ -869,7 +785,8 @@ static int DRXX_Open(struct drxk_state *state)
 
        dprintk(1, "\n");
        /* stop lock indicator process */
-       status = write16(state, SCU_RAM_GPIO__A, SCU_RAM_GPIO_HW_LOCK_IND_DISABLE);
+       status = write16(state, SCU_RAM_GPIO__A,
+                        SCU_RAM_GPIO_HW_LOCK_IND_DISABLE);
        if (status < 0)
                goto error;
        /* Check device id */
@@ -888,14 +805,14 @@ static int DRXX_Open(struct drxk_state *state)
        status = write16(state, SIO_TOP_COMM_KEY__A, key);
 error:
        if (status < 0)
-               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+               pr_err("Error %d on %s\n", status, __func__);
        return status;
 }
 
-static int GetDeviceCapabilities(struct drxk_state *state)
+static int get_device_capabilities(struct drxk_state *state)
 {
-       u16 sioPdrOhwCfg = 0;
-       u32 sioTopJtagidLo = 0;
+       u16 sio_pdr_ohw_cfg = 0;
+       u32 sio_top_jtagid_lo = 0;
        int status;
        const char *spin = "";
 
@@ -903,197 +820,196 @@ static int GetDeviceCapabilities(struct drxk_state *state)
 
        /* driver 0.9.0 */
        /* stop lock indicator process */
-       status = write16(state, SCU_RAM_GPIO__A, SCU_RAM_GPIO_HW_LOCK_IND_DISABLE);
+       status = write16(state, SCU_RAM_GPIO__A,
+                        SCU_RAM_GPIO_HW_LOCK_IND_DISABLE);
        if (status < 0)
                goto error;
        status = write16(state, SIO_TOP_COMM_KEY__A, SIO_TOP_COMM_KEY_KEY);
        if (status < 0)
                goto error;
-       status = read16(state, SIO_PDR_OHW_CFG__A, &sioPdrOhwCfg);
+       status = read16(state, SIO_PDR_OHW_CFG__A, &sio_pdr_ohw_cfg);
        if (status < 0)
                goto error;
        status = write16(state, SIO_TOP_COMM_KEY__A, 0x0000);
        if (status < 0)
                goto error;
 
-       switch ((sioPdrOhwCfg & SIO_PDR_OHW_CFG_FREF_SEL__M)) {
+       switch ((sio_pdr_ohw_cfg & SIO_PDR_OHW_CFG_FREF_SEL__M)) {
        case 0:
                /* ignore (bypass ?) */
                break;
        case 1:
                /* 27 MHz */
-               state->m_oscClockFreq = 27000;
+               state->m_osc_clock_freq = 27000;
                break;
        case 2:
                /* 20.25 MHz */
-               state->m_oscClockFreq = 20250;
+               state->m_osc_clock_freq = 20250;
                break;
        case 3:
                /* 4 MHz */
-               state->m_oscClockFreq = 20250;
+               state->m_osc_clock_freq = 20250;
                break;
        default:
-               printk(KERN_ERR "drxk: Clock Frequency is unknown\n");
+               pr_err("Clock Frequency is unknown\n");
                return -EINVAL;
        }
        /*
                Determine device capabilities
                Based on pinning v14
                */
-       status = read32(state, SIO_TOP_JTAGID_LO__A, &sioTopJtagidLo);
+       status = read32(state, SIO_TOP_JTAGID_LO__A, &sio_top_jtagid_lo);
        if (status < 0)
                goto error;
 
-       printk(KERN_INFO "drxk: status = 0x%08x\n", sioTopJtagidLo);
+       pr_info("status = 0x%08x\n", sio_top_jtagid_lo);
 
        /* driver 0.9.0 */
-       switch ((sioTopJtagidLo >> 29) & 0xF) {
+       switch ((sio_top_jtagid_lo >> 29) & 0xF) {
        case 0:
-               state->m_deviceSpin = DRXK_SPIN_A1;
+               state->m_device_spin = DRXK_SPIN_A1;
                spin = "A1";
                break;
        case 2:
-               state->m_deviceSpin = DRXK_SPIN_A2;
+               state->m_device_spin = DRXK_SPIN_A2;
                spin = "A2";
                break;
        case 3:
-               state->m_deviceSpin = DRXK_SPIN_A3;
+               state->m_device_spin = DRXK_SPIN_A3;
                spin = "A3";
                break;
        default:
-               state->m_deviceSpin = DRXK_SPIN_UNKNOWN;
+               state->m_device_spin = DRXK_SPIN_UNKNOWN;
                status = -EINVAL;
-               printk(KERN_ERR "drxk: Spin %d unknown\n",
-                      (sioTopJtagidLo >> 29) & 0xF);
+               pr_err("Spin %d unknown\n", (sio_top_jtagid_lo >> 29) & 0xF);
                goto error2;
        }
-       switch ((sioTopJtagidLo >> 12) & 0xFF) {
+       switch ((sio_top_jtagid_lo >> 12) & 0xFF) {
        case 0x13:
                /* typeId = DRX3913K_TYPE_ID */
-               state->m_hasLNA = false;
-               state->m_hasOOB = false;
-               state->m_hasATV = false;
-               state->m_hasAudio = false;
-               state->m_hasDVBT = true;
-               state->m_hasDVBC = true;
-               state->m_hasSAWSW = true;
-               state->m_hasGPIO2 = false;
-               state->m_hasGPIO1 = false;
-               state->m_hasIRQN = false;
+               state->m_has_lna = false;
+               state->m_has_oob = false;
+               state->m_has_atv = false;
+               state->m_has_audio = false;
+               state->m_has_dvbt = true;
+               state->m_has_dvbc = true;
+               state->m_has_sawsw = true;
+               state->m_has_gpio2 = false;
+               state->m_has_gpio1 = false;
+               state->m_has_irqn = false;
                break;
        case 0x15:
                /* typeId = DRX3915K_TYPE_ID */
-               state->m_hasLNA = false;
-               state->m_hasOOB = false;
-               state->m_hasATV = true;
-               state->m_hasAudio = false;
-               state->m_hasDVBT = true;
-               state->m_hasDVBC = false;
-               state->m_hasSAWSW = true;
-               state->m_hasGPIO2 = true;
-               state->m_hasGPIO1 = true;
-               state->m_hasIRQN = false;
+               state->m_has_lna = false;
+               state->m_has_oob = false;
+               state->m_has_atv = true;
+               state->m_has_audio = false;
+               state->m_has_dvbt = true;
+               state->m_has_dvbc = false;
+               state->m_has_sawsw = true;
+               state->m_has_gpio2 = true;
+               state->m_has_gpio1 = true;
+               state->m_has_irqn = false;
                break;
        case 0x16:
                /* typeId = DRX3916K_TYPE_ID */
-               state->m_hasLNA = false;
-               state->m_hasOOB = false;
-               state->m_hasATV = true;
-               state->m_hasAudio = false;
-               state->m_hasDVBT = true;
-               state->m_hasDVBC = false;
-               state->m_hasSAWSW = true;
-               state->m_hasGPIO2 = true;
-               state->m_hasGPIO1 = true;
-               state->m_hasIRQN = false;
+               state->m_has_lna = false;
+               state->m_has_oob = false;
+               state->m_has_atv = true;
+               state->m_has_audio = false;
+               state->m_has_dvbt = true;
+               state->m_has_dvbc = false;
+               state->m_has_sawsw = true;
+               state->m_has_gpio2 = true;
+               state->m_has_gpio1 = true;
+               state->m_has_irqn = false;
                break;
        case 0x18:
                /* typeId = DRX3918K_TYPE_ID */
-               state->m_hasLNA = false;
-               state->m_hasOOB = false;
-               state->m_hasATV = true;
-               state->m_hasAudio = true;
-               state->m_hasDVBT = true;
-               state->m_hasDVBC = false;
-               state->m_hasSAWSW = true;
-               state->m_hasGPIO2 = true;
-               state->m_hasGPIO1 = true;
-               state->m_hasIRQN = false;
+               state->m_has_lna = false;
+               state->m_has_oob = false;
+               state->m_has_atv = true;
+               state->m_has_audio = true;
+               state->m_has_dvbt = true;
+               state->m_has_dvbc = false;
+               state->m_has_sawsw = true;
+               state->m_has_gpio2 = true;
+               state->m_has_gpio1 = true;
+               state->m_has_irqn = false;
                break;
        case 0x21:
                /* typeId = DRX3921K_TYPE_ID */
-               state->m_hasLNA = false;
-               state->m_hasOOB = false;
-               state->m_hasATV = true;
-               state->m_hasAudio = true;
-               state->m_hasDVBT = true;
-               state->m_hasDVBC = true;
-               state->m_hasSAWSW = true;
-               state->m_hasGPIO2 = true;
-               state->m_hasGPIO1 = true;
-               state->m_hasIRQN = false;
+               state->m_has_lna = false;
+               state->m_has_oob = false;
+               state->m_has_atv = true;
+               state->m_has_audio = true;
+               state->m_has_dvbt = true;
+               state->m_has_dvbc = true;
+               state->m_has_sawsw = true;
+               state->m_has_gpio2 = true;
+               state->m_has_gpio1 = true;
+               state->m_has_irqn = false;
                break;
        case 0x23:
                /* typeId = DRX3923K_TYPE_ID */
-               state->m_hasLNA = false;
-               state->m_hasOOB = false;
-               state->m_hasATV = true;
-               state->m_hasAudio = true;
-               state->m_hasDVBT = true;
-               state->m_hasDVBC = true;
-               state->m_hasSAWSW = true;
-               state->m_hasGPIO2 = true;
-               state->m_hasGPIO1 = true;
-               state->m_hasIRQN = false;
+               state->m_has_lna = false;
+               state->m_has_oob = false;
+               state->m_has_atv = true;
+               state->m_has_audio = true;
+               state->m_has_dvbt = true;
+               state->m_has_dvbc = true;
+               state->m_has_sawsw = true;
+               state->m_has_gpio2 = true;
+               state->m_has_gpio1 = true;
+               state->m_has_irqn = false;
                break;
        case 0x25:
                /* typeId = DRX3925K_TYPE_ID */
-               state->m_hasLNA = false;
-               state->m_hasOOB = false;
-               state->m_hasATV = true;
-               state->m_hasAudio = true;
-               state->m_hasDVBT = true;
-               state->m_hasDVBC = true;
-               state->m_hasSAWSW = true;
-               state->m_hasGPIO2 = true;
-               state->m_hasGPIO1 = true;
-               state->m_hasIRQN = false;
+               state->m_has_lna = false;
+               state->m_has_oob = false;
+               state->m_has_atv = true;
+               state->m_has_audio = true;
+               state->m_has_dvbt = true;
+               state->m_has_dvbc = true;
+               state->m_has_sawsw = true;
+               state->m_has_gpio2 = true;
+               state->m_has_gpio1 = true;
+               state->m_has_irqn = false;
                break;
        case 0x26:
                /* typeId = DRX3926K_TYPE_ID */
-               state->m_hasLNA = false;
-               state->m_hasOOB = false;
-               state->m_hasATV = true;
-               state->m_hasAudio = false;
-               state->m_hasDVBT = true;
-               state->m_hasDVBC = true;
-               state->m_hasSAWSW = true;
-               state->m_hasGPIO2 = true;
-               state->m_hasGPIO1 = true;
-               state->m_hasIRQN = false;
+               state->m_has_lna = false;
+               state->m_has_oob = false;
+               state->m_has_atv = true;
+               state->m_has_audio = false;
+               state->m_has_dvbt = true;
+               state->m_has_dvbc = true;
+               state->m_has_sawsw = true;
+               state->m_has_gpio2 = true;
+               state->m_has_gpio1 = true;
+               state->m_has_irqn = false;
                break;
        default:
-               printk(KERN_ERR "drxk: DeviceID 0x%02x not supported\n",
-                       ((sioTopJtagidLo >> 12) & 0xFF));
+               pr_err("DeviceID 0x%02x not supported\n",
+                       ((sio_top_jtagid_lo >> 12) & 0xFF));
                status = -EINVAL;
                goto error2;
        }
 
-       printk(KERN_INFO
-              "drxk: detected a drx-39%02xk, spin %s, xtal %d.%03d MHz\n",
-              ((sioTopJtagidLo >> 12) & 0xFF), spin,
-              state->m_oscClockFreq / 1000,
-              state->m_oscClockFreq % 1000);
+       pr_info("detected a drx-39%02xk, spin %s, xtal %d.%03d MHz\n",
+              ((sio_top_jtagid_lo >> 12) & 0xFF), spin,
+              state->m_osc_clock_freq / 1000,
+              state->m_osc_clock_freq % 1000);
 
 error:
        if (status < 0)
-               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+               pr_err("Error %d on %s\n", status, __func__);
 
 error2:
        return status;
 }
 
-static int HI_Command(struct drxk_state *state, u16 cmd, u16 *pResult)
+static int hi_command(struct drxk_state *state, u16 cmd, u16 *p_result)
 {
        int status;
        bool powerdown_cmd;
@@ -1105,37 +1021,37 @@ static int HI_Command(struct drxk_state *state, u16 cmd, u16 *pResult)
        if (status < 0)
                goto error;
        if (cmd == SIO_HI_RA_RAM_CMD_RESET)
-               msleep(1);
+               usleep_range(1000, 2000);
 
        powerdown_cmd =
            (bool) ((cmd == SIO_HI_RA_RAM_CMD_CONFIG) &&
-                   ((state->m_HICfgCtrl) &
+                   ((state->m_hi_cfg_ctrl) &
                     SIO_HI_RA_RAM_PAR_5_CFG_SLEEP__M) ==
                    SIO_HI_RA_RAM_PAR_5_CFG_SLEEP_ZZZ);
        if (powerdown_cmd == false) {
                /* Wait until command rdy */
-               u32 retryCount = 0;
-               u16 waitCmd;
+               u32 retry_count = 0;
+               u16 wait_cmd;
 
                do {
-                       msleep(1);
-                       retryCount += 1;
+                       usleep_range(1000, 2000);
+                       retry_count += 1;
                        status = read16(state, SIO_HI_RA_RAM_CMD__A,
-                                         &waitCmd);
-               } while ((status < 0) && (retryCount < DRXK_MAX_RETRIES)
-                        && (waitCmd != 0));
+                                         &wait_cmd);
+               } while ((status < 0) && (retry_count < DRXK_MAX_RETRIES)
+                        && (wait_cmd != 0));
                if (status < 0)
                        goto error;
-               status = read16(state, SIO_HI_RA_RAM_RES__A, pResult);
+               status = read16(state, SIO_HI_RA_RAM_RES__A, p_result);
        }
 error:
        if (status < 0)
-               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+               pr_err("Error %d on %s\n", status, __func__);
 
        return status;
 }
 
-static int HI_CfgCommand(struct drxk_state *state)
+static int hi_cfg_command(struct drxk_state *state)
 {
        int status;
 
@@ -1143,61 +1059,68 @@ static int HI_CfgCommand(struct drxk_state *state)
 
        mutex_lock(&state->mutex);
 
-       status = write16(state, SIO_HI_RA_RAM_PAR_6__A, state->m_HICfgTimeout);
+       status = write16(state, SIO_HI_RA_RAM_PAR_6__A,
+                        state->m_hi_cfg_timeout);
        if (status < 0)
                goto error;
-       status = write16(state, SIO_HI_RA_RAM_PAR_5__A, state->m_HICfgCtrl);
+       status = write16(state, SIO_HI_RA_RAM_PAR_5__A,
+                        state->m_hi_cfg_ctrl);
        if (status < 0)
                goto error;
-       status = write16(state, SIO_HI_RA_RAM_PAR_4__A, state->m_HICfgWakeUpKey);
+       status = write16(state, SIO_HI_RA_RAM_PAR_4__A,
+                        state->m_hi_cfg_wake_up_key);
        if (status < 0)
                goto error;
-       status = write16(state, SIO_HI_RA_RAM_PAR_3__A, state->m_HICfgBridgeDelay);
+       status = write16(state, SIO_HI_RA_RAM_PAR_3__A,
+                        state->m_hi_cfg_bridge_delay);
        if (status < 0)
                goto error;
-       status = write16(state, SIO_HI_RA_RAM_PAR_2__A, state->m_HICfgTimingDiv);
+       status = write16(state, SIO_HI_RA_RAM_PAR_2__A,
+                        state->m_hi_cfg_timing_div);
        if (status < 0)
                goto error;
-       status = write16(state, SIO_HI_RA_RAM_PAR_1__A, SIO_HI_RA_RAM_PAR_1_PAR1_SEC_KEY);
+       status = write16(state, SIO_HI_RA_RAM_PAR_1__A,
+                        SIO_HI_RA_RAM_PAR_1_PAR1_SEC_KEY);
        if (status < 0)
                goto error;
-       status = HI_Command(state, SIO_HI_RA_RAM_CMD_CONFIG, 0);
+       status = hi_command(state, SIO_HI_RA_RAM_CMD_CONFIG, 0);
        if (status < 0)
                goto error;
 
-       state->m_HICfgCtrl &= ~SIO_HI_RA_RAM_PAR_5_CFG_SLEEP_ZZZ;
+       state->m_hi_cfg_ctrl &= ~SIO_HI_RA_RAM_PAR_5_CFG_SLEEP_ZZZ;
 error:
        mutex_unlock(&state->mutex);
        if (status < 0)
-               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+               pr_err("Error %d on %s\n", status, __func__);
        return status;
 }
 
-static int InitHI(struct drxk_state *state)
+static int init_hi(struct drxk_state *state)
 {
        dprintk(1, "\n");
 
-       state->m_HICfgWakeUpKey = (state->demod_address << 1);
-       state->m_HICfgTimeout = 0x96FF;
+       state->m_hi_cfg_wake_up_key = (state->demod_address << 1);
+       state->m_hi_cfg_timeout = 0x96FF;
        /* port/bridge/power down ctrl */
-       state->m_HICfgCtrl = SIO_HI_RA_RAM_PAR_5_CFG_SLV0_SLAVE;
+       state->m_hi_cfg_ctrl = SIO_HI_RA_RAM_PAR_5_CFG_SLV0_SLAVE;
 
-       return HI_CfgCommand(state);
+       return hi_cfg_command(state);
 }
 
-static int MPEGTSConfigurePins(struct drxk_state *state, bool mpegEnable)
+static int mpegts_configure_pins(struct drxk_state *state, bool mpeg_enable)
 {
        int status = -1;
-       u16 sioPdrMclkCfg = 0;
-       u16 sioPdrMdxCfg = 0;
+       u16 sio_pdr_mclk_cfg = 0;
+       u16 sio_pdr_mdx_cfg = 0;
        u16 err_cfg = 0;
 
        dprintk(1, ": mpeg %s, %s mode\n",
-               mpegEnable ? "enable" : "disable",
-               state->m_enableParallel ? "parallel" : "serial");
+               mpeg_enable ? "enable" : "disable",
+               state->m_enable_parallel ? "parallel" : "serial");
 
        /* stop lock indicator process */
-       status = write16(state, SCU_RAM_GPIO__A, SCU_RAM_GPIO_HW_LOCK_IND_DISABLE);
+       status = write16(state, SCU_RAM_GPIO__A,
+                        SCU_RAM_GPIO_HW_LOCK_IND_DISABLE);
        if (status < 0)
                goto error;
 
@@ -1206,7 +1129,7 @@ static int MPEGTSConfigurePins(struct drxk_state *state, bool mpegEnable)
        if (status < 0)
                goto error;
 
-       if (mpegEnable == false) {
+       if (mpeg_enable == false) {
                /*  Set MPEG TS pads to inputmode */
                status = write16(state, SIO_PDR_MSTRT_CFG__A, 0x0000);
                if (status < 0)
@@ -1246,19 +1169,19 @@ static int MPEGTSConfigurePins(struct drxk_state *state, bool mpegEnable)
                        goto error;
        } else {
                /* Enable MPEG output */
-               sioPdrMdxCfg =
-                       ((state->m_TSDataStrength <<
+               sio_pdr_mdx_cfg =
+                       ((state->m_ts_data_strength <<
                        SIO_PDR_MD0_CFG_DRIVE__B) | 0x0003);
-               sioPdrMclkCfg = ((state->m_TSClockkStrength <<
+               sio_pdr_mclk_cfg = ((state->m_ts_clockk_strength <<
                                        SIO_PDR_MCLK_CFG_DRIVE__B) |
                                        0x0003);
 
-               status = write16(state, SIO_PDR_MSTRT_CFG__A, sioPdrMdxCfg);
+               status = write16(state, SIO_PDR_MSTRT_CFG__A, sio_pdr_mdx_cfg);
                if (status < 0)
                        goto error;
 
                if (state->enable_merr_cfg)
-                       err_cfg = sioPdrMdxCfg;
+                       err_cfg = sio_pdr_mdx_cfg;
 
                status = write16(state, SIO_PDR_MERR_CFG__A, err_cfg);
                if (status < 0)
@@ -1267,31 +1190,38 @@ static int MPEGTSConfigurePins(struct drxk_state *state, bool mpegEnable)
                if (status < 0)
                        goto error;
 
-               if (state->m_enableParallel == true) {
+               if (state->m_enable_parallel == true) {
                        /* paralel -> enable MD1 to MD7 */
-                       status = write16(state, SIO_PDR_MD1_CFG__A, sioPdrMdxCfg);
+                       status = write16(state, SIO_PDR_MD1_CFG__A,
+                                        sio_pdr_mdx_cfg);
                        if (status < 0)
                                goto error;
-                       status = write16(state, SIO_PDR_MD2_CFG__A, sioPdrMdxCfg);
+                       status = write16(state, SIO_PDR_MD2_CFG__A,
+                                        sio_pdr_mdx_cfg);
                        if (status < 0)
                                goto error;
-                       status = write16(state, SIO_PDR_MD3_CFG__A, sioPdrMdxCfg);
+                       status = write16(state, SIO_PDR_MD3_CFG__A,
+                                        sio_pdr_mdx_cfg);
                        if (status < 0)
                                goto error;
-                       status = write16(state, SIO_PDR_MD4_CFG__A, sioPdrMdxCfg);
+                       status = write16(state, SIO_PDR_MD4_CFG__A,
+                                        sio_pdr_mdx_cfg);
                        if (status < 0)
                                goto error;
-                       status = write16(state, SIO_PDR_MD5_CFG__A, sioPdrMdxCfg);
+                       status = write16(state, SIO_PDR_MD5_CFG__A,
+                                        sio_pdr_mdx_cfg);
                        if (status < 0)
                                goto error;
-                       status = write16(state, SIO_PDR_MD6_CFG__A, sioPdrMdxCfg);
+                       status = write16(state, SIO_PDR_MD6_CFG__A,
+                                        sio_pdr_mdx_cfg);
                        if (status < 0)
                                goto error;
-                       status = write16(state, SIO_PDR_MD7_CFG__A, sioPdrMdxCfg);
+                       status = write16(state, SIO_PDR_MD7_CFG__A,
+                                        sio_pdr_mdx_cfg);
                        if (status < 0)
                                goto error;
                } else {
-                       sioPdrMdxCfg = ((state->m_TSDataStrength <<
+                       sio_pdr_mdx_cfg = ((state->m_ts_data_strength <<
                                                SIO_PDR_MD0_CFG_DRIVE__B)
                                        | 0x0003);
                        /* serial -> disable MD1 to MD7 */
@@ -1317,10 +1247,10 @@ static int MPEGTSConfigurePins(struct drxk_state *state, bool mpegEnable)
                        if (status < 0)
                                goto error;
                }
-               status = write16(state, SIO_PDR_MCLK_CFG__A, sioPdrMclkCfg);
+               status = write16(state, SIO_PDR_MCLK_CFG__A, sio_pdr_mclk_cfg);
                if (status < 0)
                        goto error;
-               status = write16(state, SIO_PDR_MD0_CFG__A, sioPdrMdxCfg);
+               status = write16(state, SIO_PDR_MD0_CFG__A, sio_pdr_mdx_cfg);
                if (status < 0)
                        goto error;
        }
@@ -1332,21 +1262,21 @@ static int MPEGTSConfigurePins(struct drxk_state *state, bool mpegEnable)
        status = write16(state, SIO_TOP_COMM_KEY__A, 0x0000);
 error:
        if (status < 0)
-               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+               pr_err("Error %d on %s\n", status, __func__);
        return status;
 }
 
-static int MPEGTSDisable(struct drxk_state *state)
+static int mpegts_disable(struct drxk_state *state)
 {
        dprintk(1, "\n");
 
-       return MPEGTSConfigurePins(state, false);
+       return mpegts_configure_pins(state, false);
 }
 
-static int BLChainCmd(struct drxk_state *state,
-                     u16 romOffset, u16 nrOfElements, u32 timeOut)
+static int bl_chain_cmd(struct drxk_state *state,
+                     u16 rom_offset, u16 nr_of_elements, u32 time_out)
 {
-       u16 blStatus = 0;
+       u16 bl_status = 0;
        int status;
        unsigned long end;
 
@@ -1355,46 +1285,46 @@ static int BLChainCmd(struct drxk_state *state,
        status = write16(state, SIO_BL_MODE__A, SIO_BL_MODE_CHAIN);
        if (status < 0)
                goto error;
-       status = write16(state, SIO_BL_CHAIN_ADDR__A, romOffset);
+       status = write16(state, SIO_BL_CHAIN_ADDR__A, rom_offset);
        if (status < 0)
                goto error;
-       status = write16(state, SIO_BL_CHAIN_LEN__A, nrOfElements);
+       status = write16(state, SIO_BL_CHAIN_LEN__A, nr_of_elements);
        if (status < 0)
                goto error;
        status = write16(state, SIO_BL_ENABLE__A, SIO_BL_ENABLE_ON);
        if (status < 0)
                goto error;
 
-       end = jiffies + msecs_to_jiffies(timeOut);
+       end = jiffies + msecs_to_jiffies(time_out);
        do {
-               msleep(1);
-               status = read16(state, SIO_BL_STATUS__A, &blStatus);
+               usleep_range(1000, 2000);
+               status = read16(state, SIO_BL_STATUS__A, &bl_status);
                if (status < 0)
                        goto error;
-       } while ((blStatus == 0x1) &&
+       } while ((bl_status == 0x1) &&
                        ((time_is_after_jiffies(end))));
 
-       if (blStatus == 0x1) {
-               printk(KERN_ERR "drxk: SIO not ready\n");
+       if (bl_status == 0x1) {
+               pr_err("SIO not ready\n");
                status = -EINVAL;
                goto error2;
        }
 error:
        if (status < 0)
-               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+               pr_err("Error %d on %s\n", status, __func__);
 error2:
        mutex_unlock(&state->mutex);
        return status;
 }
 
 
-static int DownloadMicrocode(struct drxk_state *state,
-                            const u8 pMCImage[], u32 Length)
+static int download_microcode(struct drxk_state *state,
+                            const u8 p_mc_image[], u32 length)
 {
-       const u8 *pSrc = pMCImage;
-       u32 Address;
-       u16 nBlocks;
-       u16 BlockSize;
+       const u8 *p_src = p_mc_image;
+       u32 address;
+       u16 n_blocks;
+       u16 block_size;
        u32 offset = 0;
        u32 i;
        int status = 0;
@@ -1404,130 +1334,131 @@ static int DownloadMicrocode(struct drxk_state *state,
        /* down the drain (we don't care about MAGIC_WORD) */
 #if 0
        /* For future reference */
-       Drain = (pSrc[0] << 8) | pSrc[1];
+       drain = (p_src[0] << 8) | p_src[1];
 #endif
-       pSrc += sizeof(u16);
+       p_src += sizeof(u16);
        offset += sizeof(u16);
-       nBlocks = (pSrc[0] << 8) | pSrc[1];
-       pSrc += sizeof(u16);
+       n_blocks = (p_src[0] << 8) | p_src[1];
+       p_src += sizeof(u16);
        offset += sizeof(u16);
 
-       for (i = 0; i < nBlocks; i += 1) {
-               Address = (pSrc[0] << 24) | (pSrc[1] << 16) |
-                   (pSrc[2] << 8) | pSrc[3];
-               pSrc += sizeof(u32);
+       for (i = 0; i < n_blocks; i += 1) {
+               address = (p_src[0] << 24) | (p_src[1] << 16) |
+                   (p_src[2] << 8) | p_src[3];
+               p_src += sizeof(u32);
                offset += sizeof(u32);
 
-               BlockSize = ((pSrc[0] << 8) | pSrc[1]) * sizeof(u16);
-               pSrc += sizeof(u16);
+               block_size = ((p_src[0] << 8) | p_src[1]) * sizeof(u16);
+               p_src += sizeof(u16);
                offset += sizeof(u16);
 
 #if 0
                /* For future reference */
-               Flags = (pSrc[0] << 8) | pSrc[1];
+               flags = (p_src[0] << 8) | p_src[1];
 #endif
-               pSrc += sizeof(u16);
+               p_src += sizeof(u16);
                offset += sizeof(u16);
 
 #if 0
                /* For future reference */
-               BlockCRC = (pSrc[0] << 8) | pSrc[1];
+               block_crc = (p_src[0] << 8) | p_src[1];
 #endif
-               pSrc += sizeof(u16);
+               p_src += sizeof(u16);
                offset += sizeof(u16);
 
-               if (offset + BlockSize > Length) {
-                       printk(KERN_ERR "drxk: Firmware is corrupted.\n");
+               if (offset + block_size > length) {
+                       pr_err("Firmware is corrupted.\n");
                        return -EINVAL;
                }
 
-               status = write_block(state, Address, BlockSize, pSrc);
+               status = write_block(state, address, block_size, p_src);
                if (status < 0) {
-                       printk(KERN_ERR "drxk: Error %d while loading firmware\n", status);
+                       pr_err("Error %d while loading firmware\n", status);
                        break;
                }
-               pSrc += BlockSize;
-               offset += BlockSize;
+               p_src += block_size;
+               offset += block_size;
        }
        return status;
 }
 
-static int DVBTEnableOFDMTokenRing(struct drxk_state *state, bool enable)
+static int dvbt_enable_ofdm_token_ring(struct drxk_state *state, bool enable)
 {
        int status;
        u16 data = 0;
-       u16 desiredCtrl = SIO_OFDM_SH_OFDM_RING_ENABLE_ON;
-       u16 desiredStatus = SIO_OFDM_SH_OFDM_RING_STATUS_ENABLED;
+       u16 desired_ctrl = SIO_OFDM_SH_OFDM_RING_ENABLE_ON;
+       u16 desired_status = SIO_OFDM_SH_OFDM_RING_STATUS_ENABLED;
        unsigned long end;
 
        dprintk(1, "\n");
 
        if (enable == false) {
-               desiredCtrl = SIO_OFDM_SH_OFDM_RING_ENABLE_OFF;
-               desiredStatus = SIO_OFDM_SH_OFDM_RING_STATUS_DOWN;
+               desired_ctrl = SIO_OFDM_SH_OFDM_RING_ENABLE_OFF;
+               desired_status = SIO_OFDM_SH_OFDM_RING_STATUS_DOWN;
        }
 
        status = read16(state, SIO_OFDM_SH_OFDM_RING_STATUS__A, &data);
-       if (status >= 0 && data == desiredStatus) {
+       if (status >= 0 && data == desired_status) {
                /* tokenring already has correct status */
                return status;
        }
        /* Disable/enable dvbt tokenring bridge   */
-       status = write16(state, SIO_OFDM_SH_OFDM_RING_ENABLE__A, desiredCtrl);
+       status = write16(state, SIO_OFDM_SH_OFDM_RING_ENABLE__A, desired_ctrl);
 
        end = jiffies + msecs_to_jiffies(DRXK_OFDM_TR_SHUTDOWN_TIMEOUT);
        do {
                status = read16(state, SIO_OFDM_SH_OFDM_RING_STATUS__A, &data);
-               if ((status >= 0 && data == desiredStatus) || time_is_after_jiffies(end))
+               if ((status >= 0 && data == desired_status)
+                   || time_is_after_jiffies(end))
                        break;
-               msleep(1);
+               usleep_range(1000, 2000);
        } while (1);
-       if (data != desiredStatus) {
-               printk(KERN_ERR "drxk: SIO not ready\n");
+       if (data != desired_status) {
+               pr_err("SIO not ready\n");
                return -EINVAL;
        }
        return status;
 }
 
-static int MPEGTSStop(struct drxk_state *state)
+static int mpegts_stop(struct drxk_state *state)
 {
        int status = 0;
-       u16 fecOcSncMode = 0;
-       u16 fecOcIprMode = 0;
+       u16 fec_oc_snc_mode = 0;
+       u16 fec_oc_ipr_mode = 0;
 
        dprintk(1, "\n");
 
        /* Gracefull shutdown (byte boundaries) */
-       status = read16(state, FEC_OC_SNC_MODE__A, &fecOcSncMode);
+       status = read16(state, FEC_OC_SNC_MODE__A, &fec_oc_snc_mode);
        if (status < 0)
                goto error;
-       fecOcSncMode |= FEC_OC_SNC_MODE_SHUTDOWN__M;
-       status = write16(state, FEC_OC_SNC_MODE__A, fecOcSncMode);
+       fec_oc_snc_mode |= FEC_OC_SNC_MODE_SHUTDOWN__M;
+       status = write16(state, FEC_OC_SNC_MODE__A, fec_oc_snc_mode);
        if (status < 0)
                goto error;
 
        /* Suppress MCLK during absence of data */
-       status = read16(state, FEC_OC_IPR_MODE__A, &fecOcIprMode);
+       status = read16(state, FEC_OC_IPR_MODE__A, &fec_oc_ipr_mode);
        if (status < 0)
                goto error;
-       fecOcIprMode |= FEC_OC_IPR_MODE_MCLK_DIS_DAT_ABS__M;
-       status = write16(state, FEC_OC_IPR_MODE__A, fecOcIprMode);
+       fec_oc_ipr_mode |= FEC_OC_IPR_MODE_MCLK_DIS_DAT_ABS__M;
+       status = write16(state, FEC_OC_IPR_MODE__A, fec_oc_ipr_mode);
 
 error:
        if (status < 0)
-               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+               pr_err("Error %d on %s\n", status, __func__);
 
        return status;
 }
 
 static int scu_command(struct drxk_state *state,
-                      u16 cmd, u8 parameterLen,
-                      u16 *parameter, u8 resultLen, u16 *result)
+                      u16 cmd, u8 parameter_len,
+                      u16 *parameter, u8 result_len, u16 *result)
 {
 #if (SCU_RAM_PARAM_0__A - SCU_RAM_PARAM_15__A) != 15
 #error DRXK register mapping no longer compatible with this routine!
 #endif
-       u16 curCmd = 0;
+       u16 cur_cmd = 0;
        int status = -EINVAL;
        unsigned long end;
        u8 buffer[34];
@@ -1537,9 +1468,9 @@ static int scu_command(struct drxk_state *state,
 
        dprintk(1, "\n");
 
-       if ((cmd == 0) || ((parameterLen > 0) && (parameter == NULL)) ||
-           ((resultLen > 0) && (result == NULL))) {
-               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+       if ((cmd == 0) || ((parameter_len > 0) && (parameter == NULL)) ||
+           ((result_len > 0) && (result == NULL))) {
+               pr_err("Error %d on %s\n", status, __func__);
                return status;
        }
 
@@ -1547,7 +1478,7 @@ static int scu_command(struct drxk_state *state,
 
        /* assume that the command register is ready
                since it is checked afterwards */
-       for (ii = parameterLen - 1; ii >= 0; ii -= 1) {
+       for (ii = parameter_len - 1; ii >= 0; ii -= 1) {
                buffer[cnt++] = (parameter[ii] & 0xFF);
                buffer[cnt++] = ((parameter[ii] >> 8) & 0xFF);
        }
@@ -1555,27 +1486,28 @@ static int scu_command(struct drxk_state *state,
        buffer[cnt++] = ((cmd >> 8) & 0xFF);
 
        write_block(state, SCU_RAM_PARAM_0__A -
-                       (parameterLen - 1), cnt, buffer);
+                       (parameter_len - 1), cnt, buffer);
        /* Wait until SCU has processed command */
        end = jiffies + msecs_to_jiffies(DRXK_MAX_WAITTIME);
        do {
-               msleep(1);
-               status = read16(state, SCU_RAM_COMMAND__A, &curCmd);
+               usleep_range(1000, 2000);
+               status = read16(state, SCU_RAM_COMMAND__A, &cur_cmd);
                if (status < 0)
                        goto error;
-       } while (!(curCmd == DRX_SCU_READY) && (time_is_after_jiffies(end)));
-       if (curCmd != DRX_SCU_READY) {
-               printk(KERN_ERR "drxk: SCU not ready\n");
+       } while (!(cur_cmd == DRX_SCU_READY) && (time_is_after_jiffies(end)));
+       if (cur_cmd != DRX_SCU_READY) {
+               pr_err("SCU not ready\n");
                status = -EIO;
                goto error2;
        }
        /* read results */
-       if ((resultLen > 0) && (result != NULL)) {
+       if ((result_len > 0) && (result != NULL)) {
                s16 err;
                int ii;
 
-               for (ii = resultLen - 1; ii >= 0; ii -= 1) {
-                       status = read16(state, SCU_RAM_PARAM_0__A - ii, &result[ii]);
+               for (ii = result_len - 1; ii >= 0; ii -= 1) {
+                       status = read16(state, SCU_RAM_PARAM_0__A - ii,
+                                       &result[ii]);
                        if (status < 0)
                                goto error;
                }
@@ -1603,7 +1535,7 @@ static int scu_command(struct drxk_state *state,
                        sprintf(errname, "ERROR: %d\n", err);
                        p = errname;
                }
-               printk(KERN_ERR "drxk: %s while sending cmd 0x%04x with params:", p, cmd);
+               pr_err("%s while sending cmd 0x%04x with params:", p, cmd);
                print_hex_dump_bytes("drxk: ", DUMP_PREFIX_NONE, buffer, cnt);
                status = -EINVAL;
                goto error2;
@@ -1611,13 +1543,13 @@ static int scu_command(struct drxk_state *state,
 
 error:
        if (status < 0)
-               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+               pr_err("Error %d on %s\n", status, __func__);
 error2:
        mutex_unlock(&state->mutex);
        return status;
 }
 
-static int SetIqmAf(struct drxk_state *state, bool active)
+static int set_iqm_af(struct drxk_state *state, bool active)
 {
        u16 data = 0;
        int status;
@@ -1647,14 +1579,14 @@ static int SetIqmAf(struct drxk_state *state, bool active)
 
 error:
        if (status < 0)
-               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+               pr_err("Error %d on %s\n", status, __func__);
        return status;
 }
 
-static int CtrlPowerMode(struct drxk_state *state, enum DRXPowerMode *mode)
+static int ctrl_power_mode(struct drxk_state *state, enum drx_power_mode *mode)
 {
        int status = 0;
-       u16 sioCcPwdMode = 0;
+       u16 sio_cc_pwd_mode = 0;
 
        dprintk(1, "\n");
 
@@ -1664,19 +1596,19 @@ static int CtrlPowerMode(struct drxk_state *state, enum DRXPowerMode *mode)
 
        switch (*mode) {
        case DRX_POWER_UP:
-               sioCcPwdMode = SIO_CC_PWD_MODE_LEVEL_NONE;
+               sio_cc_pwd_mode = SIO_CC_PWD_MODE_LEVEL_NONE;
                break;
        case DRXK_POWER_DOWN_OFDM:
-               sioCcPwdMode = SIO_CC_PWD_MODE_LEVEL_OFDM;
+               sio_cc_pwd_mode = SIO_CC_PWD_MODE_LEVEL_OFDM;
                break;
        case DRXK_POWER_DOWN_CORE:
-               sioCcPwdMode = SIO_CC_PWD_MODE_LEVEL_CLOCK;
+               sio_cc_pwd_mode = SIO_CC_PWD_MODE_LEVEL_CLOCK;
                break;
        case DRXK_POWER_DOWN_PLL:
-               sioCcPwdMode = SIO_CC_PWD_MODE_LEVEL_PLL;
+               sio_cc_pwd_mode = SIO_CC_PWD_MODE_LEVEL_PLL;
                break;
        case DRX_POWER_DOWN:
-               sioCcPwdMode = SIO_CC_PWD_MODE_LEVEL_OSC;
+               sio_cc_pwd_mode = SIO_CC_PWD_MODE_LEVEL_OSC;
                break;
        default:
                /* Unknow sleep mode */
@@ -1684,15 +1616,15 @@ static int CtrlPowerMode(struct drxk_state *state, enum DRXPowerMode *mode)
        }
 
        /* If already in requested power mode, do nothing */
-       if (state->m_currentPowerMode == *mode)
+       if (state->m_current_power_mode == *mode)
                return 0;
 
        /* For next steps make sure to start from DRX_POWER_UP mode */
-       if (state->m_currentPowerMode != DRX_POWER_UP) {
-               status = PowerUpDevice(state);
+       if (state->m_current_power_mode != DRX_POWER_UP) {
+               status = power_up_device(state);
                if (status < 0)
                        goto error;
-               status = DVBTEnableOFDMTokenRing(state, true);
+               status = dvbt_enable_ofdm_token_ring(state, true);
                if (status < 0)
                        goto error;
        }
@@ -1709,31 +1641,31 @@ static int CtrlPowerMode(struct drxk_state *state, enum DRXPowerMode *mode)
                /* Power down device */
                /* stop all comm_exec */
                /* Stop and power down previous standard */
-               switch (state->m_OperationMode) {
+               switch (state->m_operation_mode) {
                case OM_DVBT:
-                       status = MPEGTSStop(state);
+                       status = mpegts_stop(state);
                        if (status < 0)
                                goto error;
-                       status = PowerDownDVBT(state, false);
+                       status = power_down_dvbt(state, false);
                        if (status < 0)
                                goto error;
                        break;
                case OM_QAM_ITU_A:
                case OM_QAM_ITU_C:
-                       status = MPEGTSStop(state);
+                       status = mpegts_stop(state);
                        if (status < 0)
                                goto error;
-                       status = PowerDownQAM(state);
+                       status = power_down_qam(state);
                        if (status < 0)
                                goto error;
                        break;
                default:
                        break;
                }
-               status = DVBTEnableOFDMTokenRing(state, false);
+               status = dvbt_enable_ofdm_token_ring(state, false);
                if (status < 0)
                        goto error;
-               status = write16(state, SIO_CC_PWD_MODE__A, sioCcPwdMode);
+               status = write16(state, SIO_CC_PWD_MODE__A, sio_cc_pwd_mode);
                if (status < 0)
                        goto error;
                status = write16(state, SIO_CC_UPDATE__A, SIO_CC_UPDATE_KEY);
@@ -1741,26 +1673,26 @@ static int CtrlPowerMode(struct drxk_state *state, enum DRXPowerMode *mode)
                        goto error;
 
                if (*mode != DRXK_POWER_DOWN_OFDM) {
-                       state->m_HICfgCtrl |=
+                       state->m_hi_cfg_ctrl |=
                                SIO_HI_RA_RAM_PAR_5_CFG_SLEEP_ZZZ;
-                       status = HI_CfgCommand(state);
+                       status = hi_cfg_command(state);
                        if (status < 0)
                                goto error;
                }
        }
-       state->m_currentPowerMode = *mode;
+       state->m_current_power_mode = *mode;
 
 error:
        if (status < 0)
-               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+               pr_err("Error %d on %s\n", status, __func__);
 
        return status;
 }
 
-static int PowerDownDVBT(struct drxk_state *state, bool setPowerMode)
+static int power_down_dvbt(struct drxk_state *state, bool set_power_mode)
 {
-       enum DRXPowerMode powerMode = DRXK_POWER_DOWN_OFDM;
-       u16 cmdResult = 0;
+       enum drx_power_mode power_mode = DRXK_POWER_DOWN_OFDM;
+       u16 cmd_result = 0;
        u16 data = 0;
        int status;
 
@@ -1771,11 +1703,17 @@ static int PowerDownDVBT(struct drxk_state *state, bool setPowerMode)
                goto error;
        if (data == SCU_COMM_EXEC_ACTIVE) {
                /* Send OFDM stop command */
-               status = scu_command(state, SCU_RAM_COMMAND_STANDARD_OFDM | SCU_RAM_COMMAND_CMD_DEMOD_STOP, 0, NULL, 1, &cmdResult);
+               status = scu_command(state,
+                                    SCU_RAM_COMMAND_STANDARD_OFDM
+                                    | SCU_RAM_COMMAND_CMD_DEMOD_STOP,
+                                    0, NULL, 1, &cmd_result);
                if (status < 0)
                        goto error;
                /* Send OFDM reset command */
-               status = scu_command(state, SCU_RAM_COMMAND_STANDARD_OFDM | SCU_RAM_COMMAND_CMD_DEMOD_RESET, 0, NULL, 1, &cmdResult);
+               status = scu_command(state,
+                                    SCU_RAM_COMMAND_STANDARD_OFDM
+                                    | SCU_RAM_COMMAND_CMD_DEMOD_RESET,
+                                    0, NULL, 1, &cmd_result);
                if (status < 0)
                        goto error;
        }
@@ -1792,24 +1730,24 @@ static int PowerDownDVBT(struct drxk_state *state, bool setPowerMode)
                goto error;
 
        /* powerdown AFE                   */
-       status = SetIqmAf(state, false);
+       status = set_iqm_af(state, false);
        if (status < 0)
                goto error;
 
        /* powerdown to OFDM mode          */
-       if (setPowerMode) {
-               status = CtrlPowerMode(state, &powerMode);
+       if (set_power_mode) {
+               status = ctrl_power_mode(state, &power_mode);
                if (status < 0)
                        goto error;
        }
 error:
        if (status < 0)
-               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+               pr_err("Error %d on %s\n", status, __func__);
        return status;
 }
 
-static int SetOperationMode(struct drxk_state *state,
-                           enum OperationMode oMode)
+static int setoperation_mode(struct drxk_state *state,
+                           enum operation_mode o_mode)
 {
        int status = 0;
 
@@ -1821,36 +1759,37 @@ static int SetOperationMode(struct drxk_state *state,
         */
 
        /* disable HW lock indicator */
-       status = write16(state, SCU_RAM_GPIO__A, SCU_RAM_GPIO_HW_LOCK_IND_DISABLE);
+       status = write16(state, SCU_RAM_GPIO__A,
+                        SCU_RAM_GPIO_HW_LOCK_IND_DISABLE);
        if (status < 0)
                goto error;
 
        /* Device is already at the required mode */
-       if (state->m_OperationMode == oMode)
+       if (state->m_operation_mode == o_mode)
                return 0;
 
-       switch (state->m_OperationMode) {
+       switch (state->m_operation_mode) {
                /* OM_NONE was added for start up */
        case OM_NONE:
                break;
        case OM_DVBT:
-               status = MPEGTSStop(state);
+               status = mpegts_stop(state);
                if (status < 0)
                        goto error;
-               status = PowerDownDVBT(state, true);
+               status = power_down_dvbt(state, true);
                if (status < 0)
                        goto error;
-               state->m_OperationMode = OM_NONE;
+               state->m_operation_mode = OM_NONE;
                break;
        case OM_QAM_ITU_A:      /* fallthrough */
        case OM_QAM_ITU_C:
-               status = MPEGTSStop(state);
+               status = mpegts_stop(state);
                if (status < 0)
                        goto error;
-               status = PowerDownQAM(state);
+               status = power_down_qam(state);
                if (status < 0)
                        goto error;
-               state->m_OperationMode = OM_NONE;
+               state->m_operation_mode = OM_NONE;
                break;
        case OM_QAM_ITU_B:
        default:
@@ -1861,20 +1800,20 @@ static int SetOperationMode(struct drxk_state *state,
        /*
                Power up new standard
                */
-       switch (oMode) {
+       switch (o_mode) {
        case OM_DVBT:
                dprintk(1, ": DVB-T\n");
-               state->m_OperationMode = oMode;
-               status = SetDVBTStandard(state, oMode);
+               state->m_operation_mode = o_mode;
+               status = set_dvbt_standard(state, o_mode);
                if (status < 0)
                        goto error;
                break;
        case OM_QAM_ITU_A:      /* fallthrough */
        case OM_QAM_ITU_C:
                dprintk(1, ": DVB-C Annex %c\n",
-                       (state->m_OperationMode == OM_QAM_ITU_A) ? 'A' : 'C');
-               state->m_OperationMode = oMode;
-               status = SetQAMStandard(state, oMode);
+                       (state->m_operation_mode == OM_QAM_ITU_A) ? 'A' : 'C');
+               state->m_operation_mode = o_mode;
+               status = set_qam_standard(state, o_mode);
                if (status < 0)
                        goto error;
                break;
@@ -1884,121 +1823,121 @@ static int SetOperationMode(struct drxk_state *state,
        }
 error:
        if (status < 0)
-               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+               pr_err("Error %d on %s\n", status, __func__);
        return status;
 }
 
-static int Start(struct drxk_state *state, s32 offsetFreq,
-                s32 IntermediateFrequency)
+static int start(struct drxk_state *state, s32 offset_freq,
+                s32 intermediate_frequency)
 {
        int status = -EINVAL;
 
-       u16 IFreqkHz;
-       s32 OffsetkHz = offsetFreq / 1000;
+       u16 i_freqk_hz;
+       s32 offsetk_hz = offset_freq / 1000;
 
        dprintk(1, "\n");
-       if (state->m_DrxkState != DRXK_STOPPED &&
-               state->m_DrxkState != DRXK_DTV_STARTED)
+       if (state->m_drxk_state != DRXK_STOPPED &&
+               state->m_drxk_state != DRXK_DTV_STARTED)
                goto error;
 
-       state->m_bMirrorFreqSpect = (state->props.inversion == INVERSION_ON);
+       state->m_b_mirror_freq_spect = (state->props.inversion == INVERSION_ON);
 
-       if (IntermediateFrequency < 0) {
-               state->m_bMirrorFreqSpect = !state->m_bMirrorFreqSpect;
-               IntermediateFrequency = -IntermediateFrequency;
+       if (intermediate_frequency < 0) {
+               state->m_b_mirror_freq_spect = !state->m_b_mirror_freq_spect;
+               intermediate_frequency = -intermediate_frequency;
        }
 
-       switch (state->m_OperationMode) {
+       switch (state->m_operation_mode) {
        case OM_QAM_ITU_A:
        case OM_QAM_ITU_C:
-               IFreqkHz = (IntermediateFrequency / 1000);
-               status = SetQAM(state, IFreqkHz, OffsetkHz);
+               i_freqk_hz = (intermediate_frequency / 1000);
+               status = set_qam(state, i_freqk_hz, offsetk_hz);
                if (status < 0)
                        goto error;
-               state->m_DrxkState = DRXK_DTV_STARTED;
+               state->m_drxk_state = DRXK_DTV_STARTED;
                break;
        case OM_DVBT:
-               IFreqkHz = (IntermediateFrequency / 1000);
-               status = MPEGTSStop(state);
+               i_freqk_hz = (intermediate_frequency / 1000);
+               status = mpegts_stop(state);
                if (status < 0)
                        goto error;
-               status = SetDVBT(state, IFreqkHz, OffsetkHz);
+               status = set_dvbt(state, i_freqk_hz, offsetk_hz);
                if (status < 0)
                        goto error;
-               status = DVBTStart(state);
+               status = dvbt_start(state);
                if (status < 0)
                        goto error;
-               state->m_DrxkState = DRXK_DTV_STARTED;
+               state->m_drxk_state = DRXK_DTV_STARTED;
                break;
        default:
                break;
        }
 error:
        if (status < 0)
-               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+               pr_err("Error %d on %s\n", status, __func__);
        return status;
 }
 
-static int ShutDown(struct drxk_state *state)
+static int shut_down(struct drxk_state *state)
 {
        dprintk(1, "\n");
 
-       MPEGTSStop(state);
+       mpegts_stop(state);
        return 0;
 }
 
-static int GetLockStatus(struct drxk_state *state, u32 *pLockStatus)
+static int get_lock_status(struct drxk_state *state, u32 *p_lock_status)
 {
        int status = -EINVAL;
 
        dprintk(1, "\n");
 
-       if (pLockStatus == NULL)
+       if (p_lock_status == NULL)
                goto error;
 
-       *pLockStatus = NOT_LOCKED;
+       *p_lock_status = NOT_LOCKED;
 
        /* define the SCU command code */
-       switch (state->m_OperationMode) {
+       switch (state->m_operation_mode) {
        case OM_QAM_ITU_A:
        case OM_QAM_ITU_B:
        case OM_QAM_ITU_C:
-               status = GetQAMLockStatus(state, pLockStatus);
+               status = get_qam_lock_status(state, p_lock_status);
                break;
        case OM_DVBT:
-               status = GetDVBTLockStatus(state, pLockStatus);
+               status = get_dvbt_lock_status(state, p_lock_status);
                break;
        default:
                break;
        }
 error:
        if (status < 0)
-               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+               pr_err("Error %d on %s\n", status, __func__);
        return status;
 }
 
-static int MPEGTSStart(struct drxk_state *state)
+static int mpegts_start(struct drxk_state *state)
 {
        int status;
 
-       u16 fecOcSncMode = 0;
+       u16 fec_oc_snc_mode = 0;
 
        /* Allow OC to sync again */
-       status = read16(state, FEC_OC_SNC_MODE__A, &fecOcSncMode);
+       status = read16(state, FEC_OC_SNC_MODE__A, &fec_oc_snc_mode);
        if (status < 0)
                goto error;
-       fecOcSncMode &= ~FEC_OC_SNC_MODE_SHUTDOWN__M;
-       status = write16(state, FEC_OC_SNC_MODE__A, fecOcSncMode);
+       fec_oc_snc_mode &= ~FEC_OC_SNC_MODE_SHUTDOWN__M;
+       status = write16(state, FEC_OC_SNC_MODE__A, fec_oc_snc_mode);
        if (status < 0)
                goto error;
        status = write16(state, FEC_OC_SNC_UNLOCK__A, 1);
 error:
        if (status < 0)
-               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+               pr_err("Error %d on %s\n", status, __func__);
        return status;
 }
 
-static int MPEGTSDtoInit(struct drxk_state *state)
+static int mpegts_dto_init(struct drxk_state *state)
 {
        int status;
 
@@ -2040,68 +1979,68 @@ static int MPEGTSDtoInit(struct drxk_state *state)
        status = write16(state, FEC_OC_SNC_HWM__A, 12);
 error:
        if (status < 0)
-               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+               pr_err("Error %d on %s\n", status, __func__);
 
        return status;
 }
 
-static int MPEGTSDtoSetup(struct drxk_state *state,
-                         enum OperationMode oMode)
+static int mpegts_dto_setup(struct drxk_state *state,
+                         enum operation_mode o_mode)
 {
        int status;
 
-       u16 fecOcRegMode = 0;   /* FEC_OC_MODE       register value */
-       u16 fecOcRegIprMode = 0;        /* FEC_OC_IPR_MODE   register value */
-       u16 fecOcDtoMode = 0;   /* FEC_OC_IPR_INVERT register value */
-       u16 fecOcFctMode = 0;   /* FEC_OC_IPR_INVERT register value */
-       u16 fecOcDtoPeriod = 2; /* FEC_OC_IPR_INVERT register value */
-       u16 fecOcDtoBurstLen = 188;     /* FEC_OC_IPR_INVERT register value */
-       u32 fecOcRcnCtlRate = 0;        /* FEC_OC_IPR_INVERT register value */
-       u16 fecOcTmdMode = 0;
-       u16 fecOcTmdIntUpdRate = 0;
-       u32 maxBitRate = 0;
-       bool staticCLK = false;
+       u16 fec_oc_reg_mode = 0;        /* FEC_OC_MODE       register value */
+       u16 fec_oc_reg_ipr_mode = 0;    /* FEC_OC_IPR_MODE   register value */
+       u16 fec_oc_dto_mode = 0;        /* FEC_OC_IPR_INVERT register value */
+       u16 fec_oc_fct_mode = 0;        /* FEC_OC_IPR_INVERT register value */
+       u16 fec_oc_dto_period = 2;      /* FEC_OC_IPR_INVERT register value */
+       u16 fec_oc_dto_burst_len = 188; /* FEC_OC_IPR_INVERT register value */
+       u32 fec_oc_rcn_ctl_rate = 0;    /* FEC_OC_IPR_INVERT register value */
+       u16 fec_oc_tmd_mode = 0;
+       u16 fec_oc_tmd_int_upd_rate = 0;
+       u32 max_bit_rate = 0;
+       bool static_clk = false;
 
        dprintk(1, "\n");
 
        /* Check insertion of the Reed-Solomon parity bytes */
-       status = read16(state, FEC_OC_MODE__A, &fecOcRegMode);
+       status = read16(state, FEC_OC_MODE__A, &fec_oc_reg_mode);
        if (status < 0)
                goto error;
-       status = read16(state, FEC_OC_IPR_MODE__A, &fecOcRegIprMode);
+       status = read16(state, FEC_OC_IPR_MODE__A, &fec_oc_reg_ipr_mode);
        if (status < 0)
                goto error;
-       fecOcRegMode &= (~FEC_OC_MODE_PARITY__M);
-       fecOcRegIprMode &= (~FEC_OC_IPR_MODE_MVAL_DIS_PAR__M);
-       if (state->m_insertRSByte == true) {
+       fec_oc_reg_mode &= (~FEC_OC_MODE_PARITY__M);
+       fec_oc_reg_ipr_mode &= (~FEC_OC_IPR_MODE_MVAL_DIS_PAR__M);
+       if (state->m_insert_rs_byte == true) {
                /* enable parity symbol forward */
-               fecOcRegMode |= FEC_OC_MODE_PARITY__M;
+               fec_oc_reg_mode |= FEC_OC_MODE_PARITY__M;
                /* MVAL disable during parity bytes */
-               fecOcRegIprMode |= FEC_OC_IPR_MODE_MVAL_DIS_PAR__M;
+               fec_oc_reg_ipr_mode |= FEC_OC_IPR_MODE_MVAL_DIS_PAR__M;
                /* TS burst length to 204 */
-               fecOcDtoBurstLen = 204;
+               fec_oc_dto_burst_len = 204;
        }
 
        /* Check serial or parrallel output */
-       fecOcRegIprMode &= (~(FEC_OC_IPR_MODE_SERIAL__M));
-       if (state->m_enableParallel == false) {
+       fec_oc_reg_ipr_mode &= (~(FEC_OC_IPR_MODE_SERIAL__M));
+       if (state->m_enable_parallel == false) {
                /* MPEG data output is serial -> set ipr_mode[0] */
-               fecOcRegIprMode |= FEC_OC_IPR_MODE_SERIAL__M;
+               fec_oc_reg_ipr_mode |= FEC_OC_IPR_MODE_SERIAL__M;
        }
 
-       switch (oMode) {
+       switch (o_mode) {
        case OM_DVBT:
-               maxBitRate = state->m_DVBTBitrate;
-               fecOcTmdMode = 3;
-               fecOcRcnCtlRate = 0xC00000;
-               staticCLK = state->m_DVBTStaticCLK;
+               max_bit_rate = state->m_dvbt_bitrate;
+               fec_oc_tmd_mode = 3;
+               fec_oc_rcn_ctl_rate = 0xC00000;
+               static_clk = state->m_dvbt_static_clk;
                break;
        case OM_QAM_ITU_A:      /* fallthrough */
        case OM_QAM_ITU_C:
-               fecOcTmdMode = 0x0004;
-               fecOcRcnCtlRate = 0xD2B4EE;     /* good for >63 Mb/s */
-               maxBitRate = state->m_DVBCBitrate;
-               staticCLK = state->m_DVBCStaticCLK;
+               fec_oc_tmd_mode = 0x0004;
+               fec_oc_rcn_ctl_rate = 0xD2B4EE; /* good for >63 Mb/s */
+               max_bit_rate = state->m_dvbc_bitrate;
+               static_clk = state->m_dvbc_static_clk;
                break;
        default:
                status = -EINVAL;
@@ -2110,83 +2049,84 @@ static int MPEGTSDtoSetup(struct drxk_state *state,
                goto error;
 
        /* Configure DTO's */
-       if (staticCLK) {
-               u32 bitRate = 0;
+       if (static_clk) {
+               u32 bit_rate = 0;
 
                /* Rational DTO for MCLK source (static MCLK rate),
                        Dynamic DTO for optimal grouping
                        (avoid intra-packet gaps),
                        DTO offset enable to sync TS burst with MSTRT */
-               fecOcDtoMode = (FEC_OC_DTO_MODE_DYNAMIC__M |
+               fec_oc_dto_mode = (FEC_OC_DTO_MODE_DYNAMIC__M |
                                FEC_OC_DTO_MODE_OFFSET_ENABLE__M);
-               fecOcFctMode = (FEC_OC_FCT_MODE_RAT_ENA__M |
+               fec_oc_fct_mode = (FEC_OC_FCT_MODE_RAT_ENA__M |
                                FEC_OC_FCT_MODE_VIRT_ENA__M);
 
                /* Check user defined bitrate */
-               bitRate = maxBitRate;
-               if (bitRate > 75900000UL) {     /* max is 75.9 Mb/s */
-                       bitRate = 75900000UL;
+               bit_rate = max_bit_rate;
+               if (bit_rate > 75900000UL) {    /* max is 75.9 Mb/s */
+                       bit_rate = 75900000UL;
                }
                /* Rational DTO period:
                        dto_period = (Fsys / bitrate) - 2
 
-                       Result should be floored,
+                       result should be floored,
                        to make sure >= requested bitrate
                        */
-               fecOcDtoPeriod = (u16) (((state->m_sysClockFreq)
-                                               * 1000) / bitRate);
-               if (fecOcDtoPeriod <= 2)
-                       fecOcDtoPeriod = 0;
+               fec_oc_dto_period = (u16) (((state->m_sys_clock_freq)
+                                               * 1000) / bit_rate);
+               if (fec_oc_dto_period <= 2)
+                       fec_oc_dto_period = 0;
                else
-                       fecOcDtoPeriod -= 2;
-               fecOcTmdIntUpdRate = 8;
+                       fec_oc_dto_period -= 2;
+               fec_oc_tmd_int_upd_rate = 8;
        } else {
-               /* (commonAttr->staticCLK == false) => dynamic mode */
-               fecOcDtoMode = FEC_OC_DTO_MODE_DYNAMIC__M;
-               fecOcFctMode = FEC_OC_FCT_MODE__PRE;
-               fecOcTmdIntUpdRate = 5;
+               /* (commonAttr->static_clk == false) => dynamic mode */
+               fec_oc_dto_mode = FEC_OC_DTO_MODE_DYNAMIC__M;
+               fec_oc_fct_mode = FEC_OC_FCT_MODE__PRE;
+               fec_oc_tmd_int_upd_rate = 5;
        }
 
        /* Write appropriate registers with requested configuration */
-       status = write16(state, FEC_OC_DTO_BURST_LEN__A, fecOcDtoBurstLen);
+       status = write16(state, FEC_OC_DTO_BURST_LEN__A, fec_oc_dto_burst_len);
        if (status < 0)
                goto error;
-       status = write16(state, FEC_OC_DTO_PERIOD__A, fecOcDtoPeriod);
+       status = write16(state, FEC_OC_DTO_PERIOD__A, fec_oc_dto_period);
        if (status < 0)
                goto error;
-       status = write16(state, FEC_OC_DTO_MODE__A, fecOcDtoMode);
+       status = write16(state, FEC_OC_DTO_MODE__A, fec_oc_dto_mode);
        if (status < 0)
                goto error;
-       status = write16(state, FEC_OC_FCT_MODE__A, fecOcFctMode);
+       status = write16(state, FEC_OC_FCT_MODE__A, fec_oc_fct_mode);
        if (status < 0)
                goto error;
-       status = write16(state, FEC_OC_MODE__A, fecOcRegMode);
+       status = write16(state, FEC_OC_MODE__A, fec_oc_reg_mode);
        if (status < 0)
                goto error;
-       status = write16(state, FEC_OC_IPR_MODE__A, fecOcRegIprMode);
+       status = write16(state, FEC_OC_IPR_MODE__A, fec_oc_reg_ipr_mode);
        if (status < 0)
                goto error;
 
        /* Rate integration settings */
-       status = write32(state, FEC_OC_RCN_CTL_RATE_LO__A, fecOcRcnCtlRate);
+       status = write32(state, FEC_OC_RCN_CTL_RATE_LO__A, fec_oc_rcn_ctl_rate);
        if (status < 0)
                goto error;
-       status = write16(state, FEC_OC_TMD_INT_UPD_RATE__A, fecOcTmdIntUpdRate);
+       status = write16(state, FEC_OC_TMD_INT_UPD_RATE__A,
+                        fec_oc_tmd_int_upd_rate);
        if (status < 0)
                goto error;
-       status = write16(state, FEC_OC_TMD_MODE__A, fecOcTmdMode);
+       status = write16(state, FEC_OC_TMD_MODE__A, fec_oc_tmd_mode);
 error:
        if (status < 0)
-               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+               pr_err("Error %d on %s\n", status, __func__);
        return status;
 }
 
-static int MPEGTSConfigurePolarity(struct drxk_state *state)
+static int mpegts_configure_polarity(struct drxk_state *state)
 {
-       u16 fecOcRegIprInvert = 0;
+       u16 fec_oc_reg_ipr_invert = 0;
 
        /* Data mask for the output data byte */
-       u16 InvertDataMask =
+       u16 invert_data_mask =
            FEC_OC_IPR_INVERT_MD7__M | FEC_OC_IPR_INVERT_MD6__M |
            FEC_OC_IPR_INVERT_MD5__M | FEC_OC_IPR_INVERT_MD4__M |
            FEC_OC_IPR_INVERT_MD3__M | FEC_OC_IPR_INVERT_MD2__M |
@@ -2195,40 +2135,40 @@ static int MPEGTSConfigurePolarity(struct drxk_state *state)
        dprintk(1, "\n");
 
        /* Control selective inversion of output bits */
-       fecOcRegIprInvert &= (~(InvertDataMask));
-       if (state->m_invertDATA == true)
-               fecOcRegIprInvert |= InvertDataMask;
-       fecOcRegIprInvert &= (~(FEC_OC_IPR_INVERT_MERR__M));
-       if (state->m_invertERR == true)
-               fecOcRegIprInvert |= FEC_OC_IPR_INVERT_MERR__M;
-       fecOcRegIprInvert &= (~(FEC_OC_IPR_INVERT_MSTRT__M));
-       if (state->m_invertSTR == true)
-               fecOcRegIprInvert |= FEC_OC_IPR_INVERT_MSTRT__M;
-       fecOcRegIprInvert &= (~(FEC_OC_IPR_INVERT_MVAL__M));
-       if (state->m_invertVAL == true)
-               fecOcRegIprInvert |= FEC_OC_IPR_INVERT_MVAL__M;
-       fecOcRegIprInvert &= (~(FEC_OC_IPR_INVERT_MCLK__M));
-       if (state->m_invertCLK == true)
-               fecOcRegIprInvert |= FEC_OC_IPR_INVERT_MCLK__M;
-
-       return write16(state, FEC_OC_IPR_INVERT__A, fecOcRegIprInvert);
+       fec_oc_reg_ipr_invert &= (~(invert_data_mask));
+       if (state->m_invert_data == true)
+               fec_oc_reg_ipr_invert |= invert_data_mask;
+       fec_oc_reg_ipr_invert &= (~(FEC_OC_IPR_INVERT_MERR__M));
+       if (state->m_invert_err == true)
+               fec_oc_reg_ipr_invert |= FEC_OC_IPR_INVERT_MERR__M;
+       fec_oc_reg_ipr_invert &= (~(FEC_OC_IPR_INVERT_MSTRT__M));
+       if (state->m_invert_str == true)
+               fec_oc_reg_ipr_invert |= FEC_OC_IPR_INVERT_MSTRT__M;
+       fec_oc_reg_ipr_invert &= (~(FEC_OC_IPR_INVERT_MVAL__M));
+       if (state->m_invert_val == true)
+               fec_oc_reg_ipr_invert |= FEC_OC_IPR_INVERT_MVAL__M;
+       fec_oc_reg_ipr_invert &= (~(FEC_OC_IPR_INVERT_MCLK__M));
+       if (state->m_invert_clk == true)
+               fec_oc_reg_ipr_invert |= FEC_OC_IPR_INVERT_MCLK__M;
+
+       return write16(state, FEC_OC_IPR_INVERT__A, fec_oc_reg_ipr_invert);
 }
 
 #define   SCU_RAM_AGC_KI_INV_RF_POL__M 0x4000
 
-static int SetAgcRf(struct drxk_state *state,
-                   struct SCfgAgc *pAgcCfg, bool isDTV)
+static int set_agc_rf(struct drxk_state *state,
+                   struct s_cfg_agc *p_agc_cfg, bool is_dtv)
 {
        int status = -EINVAL;
        u16 data = 0;
-       struct SCfgAgc *pIfAgcSettings;
+       struct s_cfg_agc *p_if_agc_settings;
 
        dprintk(1, "\n");
 
-       if (pAgcCfg == NULL)
+       if (p_agc_cfg == NULL)
                goto error;
 
-       switch (pAgcCfg->ctrlMode) {
+       switch (p_agc_cfg->ctrl_mode) {
        case DRXK_AGC_CTRL_AUTO:
                /* Enable RF AGC DAC */
                status = read16(state, IQM_AF_STDBY__A, &data);
@@ -2246,7 +2186,7 @@ static int SetAgcRf(struct drxk_state *state,
                data &= ~SCU_RAM_AGC_CONFIG_DISABLE_RF_AGC__M;
 
                /* Polarity */
-               if (state->m_RfAgcPol)
+               if (state->m_rf_agc_pol)
                        data |= SCU_RAM_AGC_CONFIG_INV_RF_POL__M;
                else
                        data &= ~SCU_RAM_AGC_CONFIG_INV_RF_POL__M;
@@ -2260,7 +2200,7 @@ static int SetAgcRf(struct drxk_state *state,
                        goto error;
 
                data &= ~SCU_RAM_AGC_KI_RED_RAGC_RED__M;
-               data |= (~(pAgcCfg->speed <<
+               data |= (~(p_agc_cfg->speed <<
                                SCU_RAM_AGC_KI_RED_RAGC_RED__B)
                                & SCU_RAM_AGC_KI_RED_RAGC_RED__M);
 
@@ -2268,30 +2208,34 @@ static int SetAgcRf(struct drxk_state *state,
                if (status < 0)
                        goto error;
 
-               if (IsDVBT(state))
-                       pIfAgcSettings = &state->m_dvbtIfAgcCfg;
-               else if (IsQAM(state))
-                       pIfAgcSettings = &state->m_qamIfAgcCfg;
+               if (is_dvbt(state))
+                       p_if_agc_settings = &state->m_dvbt_if_agc_cfg;
+               else if (is_qam(state))
+                       p_if_agc_settings = &state->m_qam_if_agc_cfg;
                else
-                       pIfAgcSettings = &state->m_atvIfAgcCfg;
-               if (pIfAgcSettings == NULL) {
+                       p_if_agc_settings = &state->m_atv_if_agc_cfg;
+               if (p_if_agc_settings == NULL) {
                        status = -EINVAL;
                        goto error;
                }
 
                /* Set TOP, only if IF-AGC is in AUTO mode */
-               if (pIfAgcSettings->ctrlMode == DRXK_AGC_CTRL_AUTO)
-                       status = write16(state, SCU_RAM_AGC_IF_IACCU_HI_TGT_MAX__A, pAgcCfg->top);
+               if (p_if_agc_settings->ctrl_mode == DRXK_AGC_CTRL_AUTO)
+                       status = write16(state,
+                                        SCU_RAM_AGC_IF_IACCU_HI_TGT_MAX__A,
+                                        p_agc_cfg->top);
                        if (status < 0)
                                goto error;
 
                /* Cut-Off current */
-               status = write16(state, SCU_RAM_AGC_RF_IACCU_HI_CO__A, pAgcCfg->cutOffCurrent);
+               status = write16(state, SCU_RAM_AGC_RF_IACCU_HI_CO__A,
+                                p_agc_cfg->cut_off_current);
                if (status < 0)
                        goto error;
 
                /* Max. output level */
-               status = write16(state, SCU_RAM_AGC_RF_MAX__A, pAgcCfg->maxOutputLevel);
+               status = write16(state, SCU_RAM_AGC_RF_MAX__A,
+                                p_agc_cfg->max_output_level);
                if (status < 0)
                        goto error;
 
@@ -2312,7 +2256,7 @@ static int SetAgcRf(struct drxk_state *state,
                if (status < 0)
                        goto error;
                data |= SCU_RAM_AGC_CONFIG_DISABLE_RF_AGC__M;
-               if (state->m_RfAgcPol)
+               if (state->m_rf_agc_pol)
                        data |= SCU_RAM_AGC_CONFIG_INV_RF_POL__M;
                else
                        data &= ~SCU_RAM_AGC_CONFIG_INV_RF_POL__M;
@@ -2326,7 +2270,8 @@ static int SetAgcRf(struct drxk_state *state,
                        goto error;
 
                /* Write value to output pin */
-               status = write16(state, SCU_RAM_AGC_RF_IACCU_HI__A, pAgcCfg->outputLevel);
+               status = write16(state, SCU_RAM_AGC_RF_IACCU_HI__A,
+                                p_agc_cfg->output_level);
                if (status < 0)
                        goto error;
                break;
@@ -2357,22 +2302,22 @@ static int SetAgcRf(struct drxk_state *state,
        }
 error:
        if (status < 0)
-               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+               pr_err("Error %d on %s\n", status, __func__);
        return status;
 }
 
 #define SCU_RAM_AGC_KI_INV_IF_POL__M 0x2000
 
-static int SetAgcIf(struct drxk_state *state,
-                   struct SCfgAgc *pAgcCfg, bool isDTV)
+static int set_agc_if(struct drxk_state *state,
+                   struct s_cfg_agc *p_agc_cfg, bool is_dtv)
 {
        u16 data = 0;
        int status = 0;
-       struct SCfgAgc *pRfAgcSettings;
+       struct s_cfg_agc *p_rf_agc_settings;
 
        dprintk(1, "\n");
 
-       switch (pAgcCfg->ctrlMode) {
+       switch (p_agc_cfg->ctrl_mode) {
        case DRXK_AGC_CTRL_AUTO:
 
                /* Enable IF AGC DAC */
@@ -2392,7 +2337,7 @@ static int SetAgcIf(struct drxk_state *state,
                data &= ~SCU_RAM_AGC_CONFIG_DISABLE_IF_AGC__M;
 
                /* Polarity */
-               if (state->m_IfAgcPol)
+               if (state->m_if_agc_pol)
                        data |= SCU_RAM_AGC_CONFIG_INV_IF_POL__M;
                else
                        data &= ~SCU_RAM_AGC_CONFIG_INV_IF_POL__M;
@@ -2405,7 +2350,7 @@ static int SetAgcIf(struct drxk_state *state,
                if (status < 0)
                        goto error;
                data &= ~SCU_RAM_AGC_KI_RED_IAGC_RED__M;
-               data |= (~(pAgcCfg->speed <<
+               data |= (~(p_agc_cfg->speed <<
                                SCU_RAM_AGC_KI_RED_IAGC_RED__B)
                                & SCU_RAM_AGC_KI_RED_IAGC_RED__M);
 
@@ -2413,14 +2358,15 @@ static int SetAgcIf(struct drxk_state *state,
                if (status < 0)
                        goto error;
 
-               if (IsQAM(state))
-                       pRfAgcSettings = &state->m_qamRfAgcCfg;
+               if (is_qam(state))
+                       p_rf_agc_settings = &state->m_qam_rf_agc_cfg;
                else
-                       pRfAgcSettings = &state->m_atvRfAgcCfg;
-               if (pRfAgcSettings == NULL)
+                       p_rf_agc_settings = &state->m_atv_rf_agc_cfg;
+               if (p_rf_agc_settings == NULL)
                        return -1;
                /* Restore TOP */
-               status = write16(state, SCU_RAM_AGC_IF_IACCU_HI_TGT_MAX__A, pRfAgcSettings->top);
+               status = write16(state, SCU_RAM_AGC_IF_IACCU_HI_TGT_MAX__A,
+                                p_rf_agc_settings->top);
                if (status < 0)
                        goto error;
                break;
@@ -2444,7 +2390,7 @@ static int SetAgcIf(struct drxk_state *state,
                data |= SCU_RAM_AGC_CONFIG_DISABLE_IF_AGC__M;
 
                /* Polarity */
-               if (state->m_IfAgcPol)
+               if (state->m_if_agc_pol)
                        data |= SCU_RAM_AGC_CONFIG_INV_IF_POL__M;
                else
                        data &= ~SCU_RAM_AGC_CONFIG_INV_IF_POL__M;
@@ -2453,7 +2399,8 @@ static int SetAgcIf(struct drxk_state *state,
                        goto error;
 
                /* Write value to output pin */
-               status = write16(state, SCU_RAM_AGC_IF_IACCU_HI_TGT_MAX__A, pAgcCfg->outputLevel);
+               status = write16(state, SCU_RAM_AGC_IF_IACCU_HI_TGT_MAX__A,
+                                p_agc_cfg->output_level);
                if (status < 0)
                        goto error;
                break;
@@ -2478,176 +2425,181 @@ static int SetAgcIf(struct drxk_state *state,
                if (status < 0)
                        goto error;
                break;
-       }               /* switch (agcSettingsIf->ctrlMode) */
+       }               /* switch (agcSettingsIf->ctrl_mode) */
 
        /* always set the top to support
                configurations without if-loop */
-       status = write16(state, SCU_RAM_AGC_INGAIN_TGT_MIN__A, pAgcCfg->top);
+       status = write16(state, SCU_RAM_AGC_INGAIN_TGT_MIN__A, p_agc_cfg->top);
 error:
        if (status < 0)
-               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+               pr_err("Error %d on %s\n", status, __func__);
        return status;
 }
 
-static int GetQAMSignalToNoise(struct drxk_state *state,
-                              s32 *pSignalToNoise)
+static int get_qam_signal_to_noise(struct drxk_state *state,
+                              s32 *p_signal_to_noise)
 {
        int status = 0;
-       u16 qamSlErrPower = 0;  /* accum. error between
+       u16 qam_sl_err_power = 0;       /* accum. error between
                                        raw and sliced symbols */
-       u32 qamSlSigPower = 0;  /* used for MER, depends of
+       u32 qam_sl_sig_power = 0;       /* used for MER, depends of
                                        QAM modulation */
-       u32 qamSlMer = 0;       /* QAM MER */
+       u32 qam_sl_mer = 0;     /* QAM MER */
 
        dprintk(1, "\n");
 
        /* MER calculation */
 
        /* get the register value needed for MER */
-       status = read16(state, QAM_SL_ERR_POWER__A, &qamSlErrPower);
+       status = read16(state, QAM_SL_ERR_POWER__A, &qam_sl_err_power);
        if (status < 0) {
-               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+               pr_err("Error %d on %s\n", status, __func__);
                return -EINVAL;
        }
 
        switch (state->props.modulation) {
        case QAM_16:
-               qamSlSigPower = DRXK_QAM_SL_SIG_POWER_QAM16 << 2;
+               qam_sl_sig_power = DRXK_QAM_SL_SIG_POWER_QAM16 << 2;
                break;
        case QAM_32:
-               qamSlSigPower = DRXK_QAM_SL_SIG_POWER_QAM32 << 2;
+               qam_sl_sig_power = DRXK_QAM_SL_SIG_POWER_QAM32 << 2;
                break;
        case QAM_64:
-               qamSlSigPower = DRXK_QAM_SL_SIG_POWER_QAM64 << 2;
+               qam_sl_sig_power = DRXK_QAM_SL_SIG_POWER_QAM64 << 2;
                break;
        case QAM_128:
-               qamSlSigPower = DRXK_QAM_SL_SIG_POWER_QAM128 << 2;
+               qam_sl_sig_power = DRXK_QAM_SL_SIG_POWER_QAM128 << 2;
                break;
        default:
        case QAM_256:
-               qamSlSigPower = DRXK_QAM_SL_SIG_POWER_QAM256 << 2;
+               qam_sl_sig_power = DRXK_QAM_SL_SIG_POWER_QAM256 << 2;
                break;
        }
 
-       if (qamSlErrPower > 0) {
-               qamSlMer = Log10Times100(qamSlSigPower) -
-                       Log10Times100((u32) qamSlErrPower);
+       if (qam_sl_err_power > 0) {
+               qam_sl_mer = log10times100(qam_sl_sig_power) -
+                       log10times100((u32) qam_sl_err_power);
        }
-       *pSignalToNoise = qamSlMer;
+       *p_signal_to_noise = qam_sl_mer;
 
        return status;
 }
 
-static int GetDVBTSignalToNoise(struct drxk_state *state,
-                               s32 *pSignalToNoise)
+static int get_dvbt_signal_to_noise(struct drxk_state *state,
+                               s32 *p_signal_to_noise)
 {
        int status;
-       u16 regData = 0;
-       u32 EqRegTdSqrErrI = 0;
-       u32 EqRegTdSqrErrQ = 0;
-       u16 EqRegTdSqrErrExp = 0;
-       u16 EqRegTdTpsPwrOfs = 0;
-       u16 EqRegTdReqSmbCnt = 0;
-       u32 tpsCnt = 0;
-       u32 SqrErrIQ = 0;
+       u16 reg_data = 0;
+       u32 eq_reg_td_sqr_err_i = 0;
+       u32 eq_reg_td_sqr_err_q = 0;
+       u16 eq_reg_td_sqr_err_exp = 0;
+       u16 eq_reg_td_tps_pwr_ofs = 0;
+       u16 eq_reg_td_req_smb_cnt = 0;
+       u32 tps_cnt = 0;
+       u32 sqr_err_iq = 0;
        u32 a = 0;
        u32 b = 0;
        u32 c = 0;
-       u32 iMER = 0;
-       u16 transmissionParams = 0;
+       u32 i_mer = 0;
+       u16 transmission_params = 0;
 
        dprintk(1, "\n");
 
-       status = read16(state, OFDM_EQ_TOP_TD_TPS_PWR_OFS__A, &EqRegTdTpsPwrOfs);
+       status = read16(state, OFDM_EQ_TOP_TD_TPS_PWR_OFS__A,
+                       &eq_reg_td_tps_pwr_ofs);
        if (status < 0)
                goto error;
-       status = read16(state, OFDM_EQ_TOP_TD_REQ_SMB_CNT__A, &EqRegTdReqSmbCnt);
+       status = read16(state, OFDM_EQ_TOP_TD_REQ_SMB_CNT__A,
+                       &eq_reg_td_req_smb_cnt);
        if (status < 0)
                goto error;
-       status = read16(state, OFDM_EQ_TOP_TD_SQR_ERR_EXP__A, &EqRegTdSqrErrExp);
+       status = read16(state, OFDM_EQ_TOP_TD_SQR_ERR_EXP__A,
+                       &eq_reg_td_sqr_err_exp);
        if (status < 0)
                goto error;
-       status = read16(state, OFDM_EQ_TOP_TD_SQR_ERR_I__A, &regData);
+       status = read16(state, OFDM_EQ_TOP_TD_SQR_ERR_I__A,
+                       &reg_data);
        if (status < 0)
                goto error;
        /* Extend SQR_ERR_I operational range */
-       EqRegTdSqrErrI = (u32) regData;
-       if ((EqRegTdSqrErrExp > 11) &&
-               (EqRegTdSqrErrI < 0x00000FFFUL)) {
-               EqRegTdSqrErrI += 0x00010000UL;
+       eq_reg_td_sqr_err_i = (u32) reg_data;
+       if ((eq_reg_td_sqr_err_exp > 11) &&
+               (eq_reg_td_sqr_err_i < 0x00000FFFUL)) {
+               eq_reg_td_sqr_err_i += 0x00010000UL;
        }
-       status = read16(state, OFDM_EQ_TOP_TD_SQR_ERR_Q__A, &regData);
+       status = read16(state, OFDM_EQ_TOP_TD_SQR_ERR_Q__A, &reg_data);
        if (status < 0)
                goto error;
        /* Extend SQR_ERR_Q operational range */
-       EqRegTdSqrErrQ = (u32) regData;
-       if ((EqRegTdSqrErrExp > 11) &&
-               (EqRegTdSqrErrQ < 0x00000FFFUL))
-               EqRegTdSqrErrQ += 0x00010000UL;
+       eq_reg_td_sqr_err_q = (u32) reg_data;
+       if ((eq_reg_td_sqr_err_exp > 11) &&
+               (eq_reg_td_sqr_err_q < 0x00000FFFUL))
+               eq_reg_td_sqr_err_q += 0x00010000UL;
 
-       status = read16(state, OFDM_SC_RA_RAM_OP_PARAM__A, &transmissionParams);
+       status = read16(state, OFDM_SC_RA_RAM_OP_PARAM__A,
+                       &transmission_params);
        if (status < 0)
                goto error;
 
        /* Check input data for MER */
 
        /* MER calculation (in 0.1 dB) without math.h */
-       if ((EqRegTdTpsPwrOfs == 0) || (EqRegTdReqSmbCnt == 0))
-               iMER = 0;
-       else if ((EqRegTdSqrErrI + EqRegTdSqrErrQ) == 0) {
+       if ((eq_reg_td_tps_pwr_ofs == 0) || (eq_reg_td_req_smb_cnt == 0))
+               i_mer = 0;
+       else if ((eq_reg_td_sqr_err_i + eq_reg_td_sqr_err_q) == 0) {
                /* No error at all, this must be the HW reset value
                        * Apparently no first measurement yet
                        * Set MER to 0.0 */
-               iMER = 0;
+               i_mer = 0;
        } else {
-               SqrErrIQ = (EqRegTdSqrErrI + EqRegTdSqrErrQ) <<
-                       EqRegTdSqrErrExp;
-               if ((transmissionParams &
+               sqr_err_iq = (eq_reg_td_sqr_err_i + eq_reg_td_sqr_err_q) <<
+                       eq_reg_td_sqr_err_exp;
+               if ((transmission_params &
                        OFDM_SC_RA_RAM_OP_PARAM_MODE__M)
                        == OFDM_SC_RA_RAM_OP_PARAM_MODE_2K)
-                       tpsCnt = 17;
+                       tps_cnt = 17;
                else
-                       tpsCnt = 68;
+                       tps_cnt = 68;
 
                /* IMER = 100 * log10 (x)
-                       where x = (EqRegTdTpsPwrOfs^2 *
-                       EqRegTdReqSmbCnt * tpsCnt)/SqrErrIQ
+                       where x = (eq_reg_td_tps_pwr_ofs^2 *
+                       eq_reg_td_req_smb_cnt * tps_cnt)/sqr_err_iq
 
                        => IMER = a + b -c
-                       where a = 100 * log10 (EqRegTdTpsPwrOfs^2)
-                       b = 100 * log10 (EqRegTdReqSmbCnt * tpsCnt)
-                       c = 100 * log10 (SqrErrIQ)
+                       where a = 100 * log10 (eq_reg_td_tps_pwr_ofs^2)
+                       b = 100 * log10 (eq_reg_td_req_smb_cnt * tps_cnt)
+                       c = 100 * log10 (sqr_err_iq)
                        */
 
                /* log(x) x = 9bits * 9bits->18 bits  */
-               a = Log10Times100(EqRegTdTpsPwrOfs *
-                                       EqRegTdTpsPwrOfs);
+               a = log10times100(eq_reg_td_tps_pwr_ofs *
+                                       eq_reg_td_tps_pwr_ofs);
                /* log(x) x = 16bits * 7bits->23 bits  */
-               b = Log10Times100(EqRegTdReqSmbCnt * tpsCnt);
+               b = log10times100(eq_reg_td_req_smb_cnt * tps_cnt);
                /* log(x) x = (16bits + 16bits) << 15 ->32 bits  */
-               c = Log10Times100(SqrErrIQ);
+               c = log10times100(sqr_err_iq);
 
-               iMER = a + b - c;
+               i_mer = a + b - c;
        }
-       *pSignalToNoise = iMER;
+       *p_signal_to_noise = i_mer;
 
 error:
        if (status < 0)
-               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+               pr_err("Error %d on %s\n", status, __func__);
        return status;
 }
 
-static int GetSignalToNoise(struct drxk_state *state, s32 *pSignalToNoise)
+static int get_signal_to_noise(struct drxk_state *state, s32 *p_signal_to_noise)
 {
        dprintk(1, "\n");
 
-       *pSignalToNoise = 0;
-       switch (state->m_OperationMode) {
+       *p_signal_to_noise = 0;
+       switch (state->m_operation_mode) {
        case OM_DVBT:
-               return GetDVBTSignalToNoise(state, pSignalToNoise);
+               return get_dvbt_signal_to_noise(state, p_signal_to_noise);
        case OM_QAM_ITU_A:
        case OM_QAM_ITU_C:
-               return GetQAMSignalToNoise(state, pSignalToNoise);
+               return get_qam_signal_to_noise(state, p_signal_to_noise);
        default:
                break;
        }
@@ -2655,7 +2607,7 @@ static int GetSignalToNoise(struct drxk_state *state, s32 *pSignalToNoise)
 }
 
 #if 0
-static int GetDVBTQuality(struct drxk_state *state, s32 *pQuality)
+static int get_dvbt_quality(struct drxk_state *state, s32 *p_quality)
 {
        /* SNR Values for quasi errorfree reception rom Nordig 2.2 */
        int status = 0;
@@ -2680,102 +2632,104 @@ static int GetDVBTQuality(struct drxk_state *state, s32 *pQuality)
                225,            /* 64-QAM 7/8 */
        };
 
-       *pQuality = 0;
+       *p_quality = 0;
 
        do {
-               s32 SignalToNoise = 0;
-               u16 Constellation = 0;
-               u16 CodeRate = 0;
-               u32 SignalToNoiseRel;
-               u32 BERQuality;
+               s32 signal_to_noise = 0;
+               u16 constellation = 0;
+               u16 code_rate = 0;
+               u32 signal_to_noise_rel;
+               u32 ber_quality;
 
-               status = GetDVBTSignalToNoise(state, &SignalToNoise);
+               status = get_dvbt_signal_to_noise(state, &signal_to_noise);
                if (status < 0)
                        break;
-               status = read16(state, OFDM_EQ_TOP_TD_TPS_CONST__A, &Constellation);
+               status = read16(state, OFDM_EQ_TOP_TD_TPS_CONST__A,
+                               &constellation);
                if (status < 0)
                        break;
-               Constellation &= OFDM_EQ_TOP_TD_TPS_CONST__M;
+               constellation &= OFDM_EQ_TOP_TD_TPS_CONST__M;
 
-               status = read16(state, OFDM_EQ_TOP_TD_TPS_CODE_HP__A, &CodeRate);
+               status = read16(state, OFDM_EQ_TOP_TD_TPS_CODE_HP__A,
+                               &code_rate);
                if (status < 0)
                        break;
-               CodeRate &= OFDM_EQ_TOP_TD_TPS_CODE_HP__M;
+               code_rate &= OFDM_EQ_TOP_TD_TPS_CODE_HP__M;
 
-               if (Constellation > OFDM_EQ_TOP_TD_TPS_CONST_64QAM ||
-                   CodeRate > OFDM_EQ_TOP_TD_TPS_CODE_LP_7_8)
+               if (constellation > OFDM_EQ_TOP_TD_TPS_CONST_64QAM ||
+                   code_rate > OFDM_EQ_TOP_TD_TPS_CODE_LP_7_8)
                        break;
-               SignalToNoiseRel = SignalToNoise -
-                   QE_SN[Constellation * 5 + CodeRate];
-               BERQuality = 100;
-
-               if (SignalToNoiseRel < -70)
-                       *pQuality = 0;
-               else if (SignalToNoiseRel < 30)
-                       *pQuality = ((SignalToNoiseRel + 70) *
-                                    BERQuality) / 100;
+               signal_to_noise_rel = signal_to_noise -
+                   QE_SN[constellation * 5 + code_rate];
+               ber_quality = 100;
+
+               if (signal_to_noise_rel < -70)
+                       *p_quality = 0;
+               else if (signal_to_noise_rel < 30)
+                       *p_quality = ((signal_to_noise_rel + 70) *
+                                    ber_quality) / 100;
                else
-                       *pQuality = BERQuality;
+                       *p_quality = ber_quality;
        } while (0);
        return 0;
 };
 
-static int GetDVBCQuality(struct drxk_state *state, s32 *pQuality)
+static int get_dvbc_quality(struct drxk_state *state, s32 *p_quality)
 {
        int status = 0;
-       *pQuality = 0;
+       *p_quality = 0;
 
        dprintk(1, "\n");
 
        do {
-               u32 SignalToNoise = 0;
-               u32 BERQuality = 100;
-               u32 SignalToNoiseRel = 0;
+               u32 signal_to_noise = 0;
+               u32 ber_quality = 100;
+               u32 signal_to_noise_rel = 0;
 
-               status = GetQAMSignalToNoise(state, &SignalToNoise);
+               status = get_qam_signal_to_noise(state, &signal_to_noise);
                if (status < 0)
                        break;
 
                switch (state->props.modulation) {
                case QAM_16:
-                       SignalToNoiseRel = SignalToNoise - 200;
+                       signal_to_noise_rel = signal_to_noise - 200;
                        break;
                case QAM_32:
-                       SignalToNoiseRel = SignalToNoise - 230;
+                       signal_to_noise_rel = signal_to_noise - 230;
                        break;  /* Not in NorDig */
                case QAM_64:
-                       SignalToNoiseRel = SignalToNoise - 260;
+                       signal_to_noise_rel = signal_to_noise - 260;
                        break;
                case QAM_128:
-                       SignalToNoiseRel = SignalToNoise - 290;
+                       signal_to_noise_rel = signal_to_noise - 290;
                        break;
                default:
                case QAM_256:
-                       SignalToNoiseRel = SignalToNoise - 320;
+                       signal_to_noise_rel = signal_to_noise - 320;
                        break;
                }
 
-               if (SignalToNoiseRel < -70)
-                       *pQuality = 0;
-               else if (SignalToNoiseRel < 30)
-                       *pQuality = ((SignalToNoiseRel + 70) *
-                                    BERQuality) / 100;
+               if (signal_to_noise_rel < -70)
+                       *p_quality = 0;
+               else if (signal_to_noise_rel < 30)
+                       *p_quality = ((signal_to_noise_rel + 70) *
+                                    ber_quality) / 100;
                else
-                       *pQuality = BERQuality;
+                       *p_quality = ber_quality;
        } while (0);
 
        return status;
 }
 
-static int GetQuality(struct drxk_state *state, s32 *pQuality)
+static int get_quality(struct drxk_state *state, s32 *p_quality)
 {
        dprintk(1, "\n");
 
-       switch (state->m_OperationMode) {
+       switch (state->m_operation_mode) {
        case OM_DVBT:
-               return GetDVBTQuality(state, pQuality);
+               return get_dvbt_quality(state, p_quality);
        case OM_QAM_ITU_A:
-               return GetDVBCQuality(state, pQuality);
+               return get_dvbc_quality(state, p_quality);
        default:
                break;
        }
@@ -2797,65 +2751,68 @@ static int GetQuality(struct drxk_state *state, s32 *pQuality)
 #define DRXDAP_FASI_ADDR2BANK(addr)   (((addr) >> 16) & 0x3F)
 #define DRXDAP_FASI_ADDR2OFFSET(addr) ((addr) & 0x7FFF)
 
-static int ConfigureI2CBridge(struct drxk_state *state, bool bEnableBridge)
+static int ConfigureI2CBridge(struct drxk_state *state, bool b_enable_bridge)
 {
        int status = -EINVAL;
 
        dprintk(1, "\n");
 
-       if (state->m_DrxkState == DRXK_UNINITIALIZED)
+       if (state->m_drxk_state == DRXK_UNINITIALIZED)
                return 0;
-       if (state->m_DrxkState == DRXK_POWERED_DOWN)
+       if (state->m_drxk_state == DRXK_POWERED_DOWN)
                goto error;
 
        if (state->no_i2c_bridge)
                return 0;
 
-       status = write16(state, SIO_HI_RA_RAM_PAR_1__A, SIO_HI_RA_RAM_PAR_1_PAR1_SEC_KEY);
+       status = write16(state, SIO_HI_RA_RAM_PAR_1__A,
+                        SIO_HI_RA_RAM_PAR_1_PAR1_SEC_KEY);
        if (status < 0)
                goto error;
-       if (bEnableBridge) {
-               status = write16(state, SIO_HI_RA_RAM_PAR_2__A, SIO_HI_RA_RAM_PAR_2_BRD_CFG_CLOSED);
+       if (b_enable_bridge) {
+               status = write16(state, SIO_HI_RA_RAM_PAR_2__A,
+                                SIO_HI_RA_RAM_PAR_2_BRD_CFG_CLOSED);
                if (status < 0)
                        goto error;
        } else {
-               status = write16(state, SIO_HI_RA_RAM_PAR_2__A, SIO_HI_RA_RAM_PAR_2_BRD_CFG_OPEN);
+               status = write16(state, SIO_HI_RA_RAM_PAR_2__A,
+                                SIO_HI_RA_RAM_PAR_2_BRD_CFG_OPEN);
                if (status < 0)
                        goto error;
        }
 
-       status = HI_Command(state, SIO_HI_RA_RAM_CMD_BRDCTRL, 0);
+       status = hi_command(state, SIO_HI_RA_RAM_CMD_BRDCTRL, 0);
 
 error:
        if (status < 0)
-               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+               pr_err("Error %d on %s\n", status, __func__);
        return status;
 }
 
-static int SetPreSaw(struct drxk_state *state,
-                    struct SCfgPreSaw *pPreSawCfg)
+static int set_pre_saw(struct drxk_state *state,
+                    struct s_cfg_pre_saw *p_pre_saw_cfg)
 {
        int status = -EINVAL;
 
        dprintk(1, "\n");
 
-       if ((pPreSawCfg == NULL)
-           || (pPreSawCfg->reference > IQM_AF_PDREF__M))
+       if ((p_pre_saw_cfg == NULL)
+           || (p_pre_saw_cfg->reference > IQM_AF_PDREF__M))
                goto error;
 
-       status = write16(state, IQM_AF_PDREF__A, pPreSawCfg->reference);
+       status = write16(state, IQM_AF_PDREF__A, p_pre_saw_cfg->reference);
 error:
        if (status < 0)
-               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+               pr_err("Error %d on %s\n", status, __func__);
        return status;
 }
 
-static int BLDirectCmd(struct drxk_state *state, u32 targetAddr,
-                      u16 romOffset, u16 nrOfElements, u32 timeOut)
+static int bl_direct_cmd(struct drxk_state *state, u32 target_addr,
+                      u16 rom_offset, u16 nr_of_elements, u32 time_out)
 {
-       u16 blStatus = 0;
-       u16 offset = (u16) ((targetAddr >> 0) & 0x00FFFF);
-       u16 blockbank = (u16) ((targetAddr >> 16) & 0x000FFF);
+       u16 bl_status = 0;
+       u16 offset = (u16) ((target_addr >> 0) & 0x00FFFF);
+       u16 blockbank = (u16) ((target_addr >> 16) & 0x000FFF);
        int status;
        unsigned long end;
 
@@ -2871,44 +2828,44 @@ static int BLDirectCmd(struct drxk_state *state, u32 targetAddr,
        status = write16(state, SIO_BL_TGT_ADDR__A, offset);
        if (status < 0)
                goto error;
-       status = write16(state, SIO_BL_SRC_ADDR__A, romOffset);
+       status = write16(state, SIO_BL_SRC_ADDR__A, rom_offset);
        if (status < 0)
                goto error;
-       status = write16(state, SIO_BL_SRC_LEN__A, nrOfElements);
+       status = write16(state, SIO_BL_SRC_LEN__A, nr_of_elements);
        if (status < 0)
                goto error;
        status = write16(state, SIO_BL_ENABLE__A, SIO_BL_ENABLE_ON);
        if (status < 0)
                goto error;
 
-       end = jiffies + msecs_to_jiffies(timeOut);
+       end = jiffies + msecs_to_jiffies(time_out);
        do {
-               status = read16(state, SIO_BL_STATUS__A, &blStatus);
+               status = read16(state, SIO_BL_STATUS__A, &bl_status);
                if (status < 0)
                        goto error;
-       } while ((blStatus == 0x1) && time_is_after_jiffies(end));
-       if (blStatus == 0x1) {
-               printk(KERN_ERR "drxk: SIO not ready\n");
+       } while ((bl_status == 0x1) && time_is_after_jiffies(end));
+       if (bl_status == 0x1) {
+               pr_err("SIO not ready\n");
                status = -EINVAL;
                goto error2;
        }
 error:
        if (status < 0)
-               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+               pr_err("Error %d on %s\n", status, __func__);
 error2:
        mutex_unlock(&state->mutex);
        return status;
 
 }
 
-static int ADCSyncMeasurement(struct drxk_state *state, u16 *count)
+static int adc_sync_measurement(struct drxk_state *state, u16 *count)
 {
        u16 data = 0;
        int status;
 
        dprintk(1, "\n");
 
-       /* Start measurement */
+       /* start measurement */
        status = write16(state, IQM_AF_COMM_EXEC__A, IQM_AF_COMM_EXEC_ACTIVE);
        if (status < 0)
                goto error;
@@ -2935,42 +2892,42 @@ static int ADCSyncMeasurement(struct drxk_state *state, u16 *count)
 
 error:
        if (status < 0)
-               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+               pr_err("Error %d on %s\n", status, __func__);
        return status;
 }
 
-static int ADCSynchronization(struct drxk_state *state)
+static int adc_synchronization(struct drxk_state *state)
 {
        u16 count = 0;
        int status;
 
        dprintk(1, "\n");
 
-       status = ADCSyncMeasurement(state, &count);
+       status = adc_sync_measurement(state, &count);
        if (status < 0)
                goto error;
 
        if (count == 1) {
                /* Try sampling on a diffrent edge */
-               u16 clkNeg = 0;
+               u16 clk_neg = 0;
 
-               status = read16(state, IQM_AF_CLKNEG__A, &clkNeg);
+               status = read16(state, IQM_AF_CLKNEG__A, &clk_neg);
                if (status < 0)
                        goto error;
-               if ((clkNeg & IQM_AF_CLKNEG_CLKNEGDATA__M) ==
+               if ((clk_neg & IQM_AF_CLKNEG_CLKNEGDATA__M) ==
                        IQM_AF_CLKNEG_CLKNEGDATA_CLK_ADC_DATA_POS) {
-                       clkNeg &= (~(IQM_AF_CLKNEG_CLKNEGDATA__M));
-                       clkNeg |=
+                       clk_neg &= (~(IQM_AF_CLKNEG_CLKNEGDATA__M));
+                       clk_neg |=
                                IQM_AF_CLKNEG_CLKNEGDATA_CLK_ADC_DATA_NEG;
                } else {
-                       clkNeg &= (~(IQM_AF_CLKNEG_CLKNEGDATA__M));
-                       clkNeg |=
+                       clk_neg &= (~(IQM_AF_CLKNEG_CLKNEGDATA__M));
+                       clk_neg |=
                                IQM_AF_CLKNEG_CLKNEGDATA_CLK_ADC_DATA_POS;
                }
-               status = write16(state, IQM_AF_CLKNEG__A, clkNeg);
+               status = write16(state, IQM_AF_CLKNEG__A, clk_neg);
                if (status < 0)
                        goto error;
-               status = ADCSyncMeasurement(state, &count);
+               status = adc_sync_measurement(state, &count);
                if (status < 0)
                        goto error;
        }
@@ -2979,25 +2936,25 @@ static int ADCSynchronization(struct drxk_state *state)
                status = -EINVAL;
 error:
        if (status < 0)
-               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+               pr_err("Error %d on %s\n", status, __func__);
        return status;
 }
 
-static int SetFrequencyShifter(struct drxk_state *state,
-                              u16 intermediateFreqkHz,
-                              s32 tunerFreqOffset, bool isDTV)
+static int set_frequency_shifter(struct drxk_state *state,
+                              u16 intermediate_freqk_hz,
+                              s32 tuner_freq_offset, bool is_dtv)
 {
-       bool selectPosImage = false;
-       u32 rfFreqResidual = tunerFreqOffset;
-       u32 fmFrequencyShift = 0;
-       bool tunerMirror = !state->m_bMirrorFreqSpect;
-       u32 adcFreq;
-       bool adcFlip;
+       bool select_pos_image = false;
+       u32 rf_freq_residual = tuner_freq_offset;
+       u32 fm_frequency_shift = 0;
+       bool tuner_mirror = !state->m_b_mirror_freq_spect;
+       u32 adc_freq;
+       bool adc_flip;
        int status;
-       u32 ifFreqActual;
-       u32 samplingFrequency = (u32) (state->m_sysClockFreq / 3);
-       u32 frequencyShift;
-       bool imageToSelect;
+       u32 if_freq_actual;
+       u32 sampling_frequency = (u32) (state->m_sys_clock_freq / 3);
+       u32 frequency_shift;
+       bool image_to_select;
 
        dprintk(1, "\n");
 
@@ -3005,121 +2962,125 @@ static int SetFrequencyShifter(struct drxk_state *state,
           Program frequency shifter
           No need to account for mirroring on RF
         */
-       if (isDTV) {
-               if ((state->m_OperationMode == OM_QAM_ITU_A) ||
-                   (state->m_OperationMode == OM_QAM_ITU_C) ||
-                   (state->m_OperationMode == OM_DVBT))
-                       selectPosImage = true;
+       if (is_dtv) {
+               if ((state->m_operation_mode == OM_QAM_ITU_A) ||
+                   (state->m_operation_mode == OM_QAM_ITU_C) ||
+                   (state->m_operation_mode == OM_DVBT))
+                       select_pos_image = true;
                else
-                       selectPosImage = false;
+                       select_pos_image = false;
        }
-       if (tunerMirror)
+       if (tuner_mirror)
                /* tuner doesn't mirror */
-               ifFreqActual = intermediateFreqkHz +
-                   rfFreqResidual + fmFrequencyShift;
+               if_freq_actual = intermediate_freqk_hz +
+                   rf_freq_residual + fm_frequency_shift;
        else
                /* tuner mirrors */
-               ifFreqActual = intermediateFreqkHz -
-                   rfFreqResidual - fmFrequencyShift;
-       if (ifFreqActual > samplingFrequency / 2) {
+               if_freq_actual = intermediate_freqk_hz -
+                   rf_freq_residual - fm_frequency_shift;
+       if (if_freq_actual > sampling_frequency / 2) {
                /* adc mirrors */
-               adcFreq = samplingFrequency - ifFreqActual;
-               adcFlip = true;
+               adc_freq = sampling_frequency - if_freq_actual;
+               adc_flip = true;
        } else {
                /* adc doesn't mirror */
-               adcFreq = ifFreqActual;
-               adcFlip = false;
+               adc_freq = if_freq_actual;
+               adc_flip = false;
        }
 
-       frequencyShift = adcFreq;
-       imageToSelect = state->m_rfmirror ^ tunerMirror ^
-           adcFlip ^ selectPosImage;
-       state->m_IqmFsRateOfs =
-           Frac28a((frequencyShift), samplingFrequency);
+       frequency_shift = adc_freq;
+       image_to_select = state->m_rfmirror ^ tuner_mirror ^
+           adc_flip ^ select_pos_image;
+       state->m_iqm_fs_rate_ofs =
+           Frac28a((frequency_shift), sampling_frequency);
 
-       if (imageToSelect)
-               state->m_IqmFsRateOfs = ~state->m_IqmFsRateOfs + 1;
+       if (image_to_select)
+               state->m_iqm_fs_rate_ofs = ~state->m_iqm_fs_rate_ofs + 1;
 
        /* Program frequency shifter with tuner offset compensation */
-       /* frequencyShift += tunerFreqOffset; TODO */
+       /* frequency_shift += tuner_freq_offset; TODO */
        status = write32(state, IQM_FS_RATE_OFS_LO__A,
-                        state->m_IqmFsRateOfs);
+                        state->m_iqm_fs_rate_ofs);
        if (status < 0)
-               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+               pr_err("Error %d on %s\n", status, __func__);
        return status;
 }
 
-static int InitAGC(struct drxk_state *state, bool isDTV)
+static int init_agc(struct drxk_state *state, bool is_dtv)
 {
-       u16 ingainTgt = 0;
-       u16 ingainTgtMin = 0;
-       u16 ingainTgtMax = 0;
-       u16 clpCyclen = 0;
-       u16 clpSumMin = 0;
-       u16 clpDirTo = 0;
-       u16 snsSumMin = 0;
-       u16 snsSumMax = 0;
-       u16 clpSumMax = 0;
-       u16 snsDirTo = 0;
-       u16 kiInnergainMin = 0;
-       u16 ifIaccuHiTgt = 0;
-       u16 ifIaccuHiTgtMin = 0;
-       u16 ifIaccuHiTgtMax = 0;
+       u16 ingain_tgt = 0;
+       u16 ingain_tgt_min = 0;
+       u16 ingain_tgt_max = 0;
+       u16 clp_cyclen = 0;
+       u16 clp_sum_min = 0;
+       u16 clp_dir_to = 0;
+       u16 sns_sum_min = 0;
+       u16 sns_sum_max = 0;
+       u16 clp_sum_max = 0;
+       u16 sns_dir_to = 0;
+       u16 ki_innergain_min = 0;
+       u16 if_iaccu_hi_tgt = 0;
+       u16 if_iaccu_hi_tgt_min = 0;
+       u16 if_iaccu_hi_tgt_max = 0;
        u16 data = 0;
-       u16 fastClpCtrlDelay = 0;
-       u16 clpCtrlMode = 0;
+       u16 fast_clp_ctrl_delay = 0;
+       u16 clp_ctrl_mode = 0;
        int status = 0;
 
        dprintk(1, "\n");
 
        /* Common settings */
-       snsSumMax = 1023;
-       ifIaccuHiTgtMin = 2047;
-       clpCyclen = 500;
-       clpSumMax = 1023;
+       sns_sum_max = 1023;
+       if_iaccu_hi_tgt_min = 2047;
+       clp_cyclen = 500;
+       clp_sum_max = 1023;
 
        /* AGCInit() not available for DVBT; init done in microcode */
-       if (!IsQAM(state)) {
-               printk(KERN_ERR "drxk: %s: mode %d is not DVB-C\n", __func__, state->m_OperationMode);
+       if (!is_qam(state)) {
+               pr_err("%s: mode %d is not DVB-C\n",
+                      __func__, state->m_operation_mode);
                return -EINVAL;
        }
 
        /* FIXME: Analog TV AGC require different settings */
 
        /* Standard specific settings */
-       clpSumMin = 8;
-       clpDirTo = (u16) -9;
-       clpCtrlMode = 0;
-       snsSumMin = 8;
-       snsDirTo = (u16) -9;
-       kiInnergainMin = (u16) -1030;
-       ifIaccuHiTgtMax = 0x2380;
-       ifIaccuHiTgt = 0x2380;
-       ingainTgtMin = 0x0511;
-       ingainTgt = 0x0511;
-       ingainTgtMax = 5119;
-       fastClpCtrlDelay = state->m_qamIfAgcCfg.FastClipCtrlDelay;
+       clp_sum_min = 8;
+       clp_dir_to = (u16) -9;
+       clp_ctrl_mode = 0;
+       sns_sum_min = 8;
+       sns_dir_to = (u16) -9;
+       ki_innergain_min = (u16) -1030;
+       if_iaccu_hi_tgt_max = 0x2380;
+       if_iaccu_hi_tgt = 0x2380;
+       ingain_tgt_min = 0x0511;
+       ingain_tgt = 0x0511;
+       ingain_tgt_max = 5119;
+       fast_clp_ctrl_delay = state->m_qam_if_agc_cfg.fast_clip_ctrl_delay;
 
-       status = write16(state, SCU_RAM_AGC_FAST_CLP_CTRL_DELAY__A, fastClpCtrlDelay);
+       status = write16(state, SCU_RAM_AGC_FAST_CLP_CTRL_DELAY__A,
+                        fast_clp_ctrl_delay);
        if (status < 0)
                goto error;
 
-       status = write16(state, SCU_RAM_AGC_CLP_CTRL_MODE__A, clpCtrlMode);
+       status = write16(state, SCU_RAM_AGC_CLP_CTRL_MODE__A, clp_ctrl_mode);
        if (status < 0)
                goto error;
-       status = write16(state, SCU_RAM_AGC_INGAIN_TGT__A, ingainTgt);
+       status = write16(state, SCU_RAM_AGC_INGAIN_TGT__A, ingain_tgt);
        if (status < 0)
                goto error;
-       status = write16(state, SCU_RAM_AGC_INGAIN_TGT_MIN__A, ingainTgtMin);
+       status = write16(state, SCU_RAM_AGC_INGAIN_TGT_MIN__A, ingain_tgt_min);
        if (status < 0)
                goto error;
-       status = write16(state, SCU_RAM_AGC_INGAIN_TGT_MAX__A, ingainTgtMax);
+       status = write16(state, SCU_RAM_AGC_INGAIN_TGT_MAX__A, ingain_tgt_max);
        if (status < 0)
                goto error;
-       status = write16(state, SCU_RAM_AGC_IF_IACCU_HI_TGT_MIN__A, ifIaccuHiTgtMin);
+       status = write16(state, SCU_RAM_AGC_IF_IACCU_HI_TGT_MIN__A,
+                        if_iaccu_hi_tgt_min);
        if (status < 0)
                goto error;
-       status = write16(state, SCU_RAM_AGC_IF_IACCU_HI_TGT_MAX__A, ifIaccuHiTgtMax);
+       status = write16(state, SCU_RAM_AGC_IF_IACCU_HI_TGT_MAX__A,
+                        if_iaccu_hi_tgt_max);
        if (status < 0)
                goto error;
        status = write16(state, SCU_RAM_AGC_IF_IACCU_HI__A, 0);
@@ -3134,20 +3095,22 @@ static int InitAGC(struct drxk_state *state, bool isDTV)
        status = write16(state, SCU_RAM_AGC_RF_IACCU_LO__A, 0);
        if (status < 0)
                goto error;
-       status = write16(state, SCU_RAM_AGC_CLP_SUM_MAX__A, clpSumMax);
+       status = write16(state, SCU_RAM_AGC_CLP_SUM_MAX__A, clp_sum_max);
        if (status < 0)
                goto error;
-       status = write16(state, SCU_RAM_AGC_SNS_SUM_MAX__A, snsSumMax);
+       status = write16(state, SCU_RAM_AGC_SNS_SUM_MAX__A, sns_sum_max);
        if (status < 0)
                goto error;
 
-       status = write16(state, SCU_RAM_AGC_KI_INNERGAIN_MIN__A, kiInnergainMin);
+       status = write16(state, SCU_RAM_AGC_KI_INNERGAIN_MIN__A,
+                        ki_innergain_min);
        if (status < 0)
                goto error;
-       status = write16(state, SCU_RAM_AGC_IF_IACCU_HI_TGT__A, ifIaccuHiTgt);
+       status = write16(state, SCU_RAM_AGC_IF_IACCU_HI_TGT__A,
+                        if_iaccu_hi_tgt);
        if (status < 0)
                goto error;
-       status = write16(state, SCU_RAM_AGC_CLP_CYCLEN__A, clpCyclen);
+       status = write16(state, SCU_RAM_AGC_CLP_CYCLEN__A, clp_cyclen);
        if (status < 0)
                goto error;
 
@@ -3164,16 +3127,16 @@ static int InitAGC(struct drxk_state *state, bool isDTV)
        status = write16(state, SCU_RAM_AGC_KI_MAXMINGAIN_TH__A, 20);
        if (status < 0)
                goto error;
-       status = write16(state, SCU_RAM_AGC_CLP_SUM_MIN__A, clpSumMin);
+       status = write16(state, SCU_RAM_AGC_CLP_SUM_MIN__A, clp_sum_min);
        if (status < 0)
                goto error;
-       status = write16(state, SCU_RAM_AGC_SNS_SUM_MIN__A, snsSumMin);
+       status = write16(state, SCU_RAM_AGC_SNS_SUM_MIN__A, sns_sum_min);
        if (status < 0)
                goto error;
-       status = write16(state, SCU_RAM_AGC_CLP_DIR_TO__A, clpDirTo);
+       status = write16(state, SCU_RAM_AGC_CLP_DIR_TO__A, clp_dir_to);
        if (status < 0)
                goto error;
-       status = write16(state, SCU_RAM_AGC_SNS_DIR_TO__A, snsDirTo);
+       status = write16(state, SCU_RAM_AGC_SNS_DIR_TO__A, sns_dir_to);
        if (status < 0)
                goto error;
        status = write16(state, SCU_RAM_AGC_KI_MINGAIN__A, 0x7fff);
@@ -3233,38 +3196,39 @@ static int InitAGC(struct drxk_state *state, bool isDTV)
        status = write16(state, SCU_RAM_AGC_KI__A, data);
 error:
        if (status < 0)
-               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+               pr_err("Error %d on %s\n", status, __func__);
        return status;
 }
 
-static int DVBTQAMGetAccPktErr(struct drxk_state *state, u16 *packetErr)
+static int dvbtqam_get_acc_pkt_err(struct drxk_state *state, u16 *packet_err)
 {
        int status;
 
        dprintk(1, "\n");
-       if (packetErr == NULL)
+       if (packet_err == NULL)
                status = write16(state, SCU_RAM_FEC_ACCUM_PKT_FAILURES__A, 0);
        else
-               status = read16(state, SCU_RAM_FEC_ACCUM_PKT_FAILURES__A, packetErr);
+               status = read16(state, SCU_RAM_FEC_ACCUM_PKT_FAILURES__A,
+                               packet_err);
        if (status < 0)
-               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+               pr_err("Error %d on %s\n", status, __func__);
        return status;
 }
 
-static int DVBTScCommand(struct drxk_state *state,
+static int dvbt_sc_command(struct drxk_state *state,
                         u16 cmd, u16 subcmd,
                         u16 param0, u16 param1, u16 param2,
                         u16 param3, u16 param4)
 {
-       u16 curCmd = 0;
-       u16 errCode = 0;
-       u16 retryCnt = 0;
-       u16 scExec = 0;
+       u16 cur_cmd = 0;
+       u16 err_code = 0;
+       u16 retry_cnt = 0;
+       u16 sc_exec = 0;
        int status;
 
        dprintk(1, "\n");
-       status = read16(state, OFDM_SC_COMM_EXEC__A, &scExec);
-       if (scExec != 1) {
+       status = read16(state, OFDM_SC_COMM_EXEC__A, &sc_exec);
+       if (sc_exec != 1) {
                /* SC is not running */
                status = -EINVAL;
        }
@@ -3272,13 +3236,13 @@ static int DVBTScCommand(struct drxk_state *state,
                goto error;
 
        /* Wait until sc is ready to receive command */
-       retryCnt = 0;
+       retry_cnt = 0;
        do {
-               msleep(1);
-               status = read16(state, OFDM_SC_RA_RAM_CMD__A, &curCmd);
-               retryCnt++;
-       } while ((curCmd != 0) && (retryCnt < DRXK_MAX_RETRIES));
-       if (retryCnt >= DRXK_MAX_RETRIES && (status < 0))
+               usleep_range(1000, 2000);
+               status = read16(state, OFDM_SC_RA_RAM_CMD__A, &cur_cmd);
+               retry_cnt++;
+       } while ((cur_cmd != 0) && (retry_cnt < DRXK_MAX_RETRIES));
+       if (retry_cnt >= DRXK_MAX_RETRIES && (status < 0))
                goto error;
 
        /* Write sub-command */
@@ -3324,18 +3288,18 @@ static int DVBTScCommand(struct drxk_state *state,
                goto error;
 
        /* Wait until sc is ready processing command */
-       retryCnt = 0;
+       retry_cnt = 0;
        do {
-               msleep(1);
-               status = read16(state, OFDM_SC_RA_RAM_CMD__A, &curCmd);
-               retryCnt++;
-       } while ((curCmd != 0) && (retryCnt < DRXK_MAX_RETRIES));
-       if (retryCnt >= DRXK_MAX_RETRIES && (status < 0))
+               usleep_range(1000, 2000);
+               status = read16(state, OFDM_SC_RA_RAM_CMD__A, &cur_cmd);
+               retry_cnt++;
+       } while ((cur_cmd != 0) && (retry_cnt < DRXK_MAX_RETRIES));
+       if (retry_cnt >= DRXK_MAX_RETRIES && (status < 0))
                goto error;
 
        /* Check for illegal cmd */
-       status = read16(state, OFDM_SC_RA_RAM_CMD_ADDR__A, &errCode);
-       if (errCode == 0xFFFF) {
+       status = read16(state, OFDM_SC_RA_RAM_CMD_ADDR__A, &err_code);
+       if (err_code == 0xFFFF) {
                /* illegal command */
                status = -EINVAL;
        }
@@ -3367,23 +3331,23 @@ static int DVBTScCommand(struct drxk_state *state,
        }                       /* switch (cmd->cmd) */
 error:
        if (status < 0)
-               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+               pr_err("Error %d on %s\n", status, __func__);
        return status;
 }
 
-static int PowerUpDVBT(struct drxk_state *state)
+static int power_up_dvbt(struct drxk_state *state)
 {
-       enum DRXPowerMode powerMode = DRX_POWER_UP;
+       enum drx_power_mode power_mode = DRX_POWER_UP;
        int status;
 
        dprintk(1, "\n");
-       status = CtrlPowerMode(state, &powerMode);
+       status = ctrl_power_mode(state, &power_mode);
        if (status < 0)
-               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+               pr_err("Error %d on %s\n", status, __func__);
        return status;
 }
 
-static int DVBTCtrlSetIncEnable(struct drxk_state *state, bool *enabled)
+static int dvbt_ctrl_set_inc_enable(struct drxk_state *state, bool *enabled)
 {
        int status;
 
@@ -3393,12 +3357,12 @@ static int DVBTCtrlSetIncEnable(struct drxk_state *state, bool *enabled)
        else
                status = write16(state, IQM_CF_BYPASSDET__A, 1);
        if (status < 0)
-               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+               pr_err("Error %d on %s\n", status, __func__);
        return status;
 }
 
 #define DEFAULT_FR_THRES_8K     4000
-static int DVBTCtrlSetFrEnable(struct drxk_state *state, bool *enabled)
+static int dvbt_ctrl_set_fr_enable(struct drxk_state *state, bool *enabled)
 {
 
        int status;
@@ -3413,13 +3377,13 @@ static int DVBTCtrlSetFrEnable(struct drxk_state *state, bool *enabled)
                status = write16(state, OFDM_SC_RA_RAM_FR_THRES_8K__A, 0);
        }
        if (status < 0)
-               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+               pr_err("Error %d on %s\n", status, __func__);
 
        return status;
 }
 
-static int DVBTCtrlSetEchoThreshold(struct drxk_state *state,
-                                   struct DRXKCfgDvbtEchoThres_t *echoThres)
+static int dvbt_ctrl_set_echo_threshold(struct drxk_state *state,
+                               struct drxk_cfg_dvbt_echo_thres_t *echo_thres)
 {
        u16 data = 0;
        int status;
@@ -3429,16 +3393,16 @@ static int DVBTCtrlSetEchoThreshold(struct drxk_state *state,
        if (status < 0)
                goto error;
 
-       switch (echoThres->fftMode) {
+       switch (echo_thres->fft_mode) {
        case DRX_FFTMODE_2K:
                data &= ~OFDM_SC_RA_RAM_ECHO_THRES_2K__M;
-               data |= ((echoThres->threshold <<
+               data |= ((echo_thres->threshold <<
                        OFDM_SC_RA_RAM_ECHO_THRES_2K__B)
                        & (OFDM_SC_RA_RAM_ECHO_THRES_2K__M));
                break;
        case DRX_FFTMODE_8K:
                data &= ~OFDM_SC_RA_RAM_ECHO_THRES_8K__M;
-               data |= ((echoThres->threshold <<
+               data |= ((echo_thres->threshold <<
                        OFDM_SC_RA_RAM_ECHO_THRES_8K__B)
                        & (OFDM_SC_RA_RAM_ECHO_THRES_8K__M));
                break;
@@ -3449,12 +3413,12 @@ static int DVBTCtrlSetEchoThreshold(struct drxk_state *state,
        status = write16(state, OFDM_SC_RA_RAM_ECHO_THRES__A, data);
 error:
        if (status < 0)
-               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+               pr_err("Error %d on %s\n", status, __func__);
        return status;
 }
 
-static int DVBTCtrlSetSqiSpeed(struct drxk_state *state,
-                              enum DRXKCfgDvbtSqiSpeed *speed)
+static int dvbt_ctrl_set_sqi_speed(struct drxk_state *state,
+                              enum drxk_cfg_dvbt_sqi_speed *speed)
 {
        int status = -EINVAL;
 
@@ -3472,7 +3436,7 @@ static int DVBTCtrlSetSqiSpeed(struct drxk_state *state,
                           (u16) *speed);
 error:
        if (status < 0)
-               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+               pr_err("Error %d on %s\n", status, __func__);
        return status;
 }
 
@@ -3486,32 +3450,33 @@ error:
 * Called in DVBTSetStandard
 *
 */
-static int DVBTActivatePresets(struct drxk_state *state)
+static int dvbt_activate_presets(struct drxk_state *state)
 {
        int status;
        bool setincenable = false;
        bool setfrenable = true;
 
-       struct DRXKCfgDvbtEchoThres_t echoThres2k = { 0, DRX_FFTMODE_2K };
-       struct DRXKCfgDvbtEchoThres_t echoThres8k = { 0, DRX_FFTMODE_8K };
+       struct drxk_cfg_dvbt_echo_thres_t echo_thres2k = { 0, DRX_FFTMODE_2K };
+       struct drxk_cfg_dvbt_echo_thres_t echo_thres8k = { 0, DRX_FFTMODE_8K };
 
        dprintk(1, "\n");
-       status = DVBTCtrlSetIncEnable(state, &setincenable);
+       status = dvbt_ctrl_set_inc_enable(state, &setincenable);
        if (status < 0)
                goto error;
-       status = DVBTCtrlSetFrEnable(state, &setfrenable);
+       status = dvbt_ctrl_set_fr_enable(state, &setfrenable);
        if (status < 0)
                goto error;
-       status = DVBTCtrlSetEchoThreshold(state, &echoThres2k);
+       status = dvbt_ctrl_set_echo_threshold(state, &echo_thres2k);
        if (status < 0)
                goto error;
-       status = DVBTCtrlSetEchoThreshold(state, &echoThres8k);
+       status = dvbt_ctrl_set_echo_threshold(state, &echo_thres8k);
        if (status < 0)
                goto error;
-       status = write16(state, SCU_RAM_AGC_INGAIN_TGT_MAX__A, state->m_dvbtIfAgcCfg.IngainTgtMax);
+       status = write16(state, SCU_RAM_AGC_INGAIN_TGT_MAX__A,
+                        state->m_dvbt_if_agc_cfg.ingain_tgt_max);
 error:
        if (status < 0)
-               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+               pr_err("Error %d on %s\n", status, __func__);
        return status;
 }
 
@@ -3525,25 +3490,30 @@ error:
 * For ROM code channel filter taps are loaded from the bootloader. For microcode
 * the DVB-T taps from the drxk_filters.h are used.
 */
-static int SetDVBTStandard(struct drxk_state *state,
-                          enum OperationMode oMode)
+static int set_dvbt_standard(struct drxk_state *state,
+                          enum operation_mode o_mode)
 {
-       u16 cmdResult = 0;
+       u16 cmd_result = 0;
        u16 data = 0;
        int status;
 
        dprintk(1, "\n");
 
-       PowerUpDVBT(state);
+       power_up_dvbt(state);
        /* added antenna switch */
-       SwitchAntennaToDVBT(state);
+       switch_antenna_to_dvbt(state);
        /* send OFDM reset command */
-       status = scu_command(state, SCU_RAM_COMMAND_STANDARD_OFDM | SCU_RAM_COMMAND_CMD_DEMOD_RESET, 0, NULL, 1, &cmdResult);
+       status = scu_command(state,
+                            SCU_RAM_COMMAND_STANDARD_OFDM
+                            | SCU_RAM_COMMAND_CMD_DEMOD_RESET,
+                            0, NULL, 1, &cmd_result);
        if (status < 0)
                goto error;
 
        /* send OFDM setenv command */
-       status = scu_command(state, SCU_RAM_COMMAND_STANDARD_OFDM | SCU_RAM_COMMAND_CMD_DEMOD_SET_ENV, 0, NULL, 1, &cmdResult);
+       status = scu_command(state, SCU_RAM_COMMAND_STANDARD_OFDM
+                            | SCU_RAM_COMMAND_CMD_DEMOD_SET_ENV,
+                            0, NULL, 1, &cmd_result);
        if (status < 0)
                goto error;
 
@@ -3575,7 +3545,7 @@ static int SetDVBTStandard(struct drxk_state *state,
        status = write16(state, IQM_AF_AMUX__A, IQM_AF_AMUX_SIGNAL2ADC);
        if (status < 0)
                goto error;
-       status = SetIqmAf(state, true);
+       status = set_iqm_af(state, true);
        if (status < 0)
                goto error;
 
@@ -3597,7 +3567,7 @@ static int SetDVBTStandard(struct drxk_state *state,
        status = write16(state, IQM_RC_STRETCH__A, 16);
        if (status < 0)
                goto error;
-       status = write16(state, IQM_CF_OUT_ENA__A, 0x4);        /* enable output 2 */
+       status = write16(state, IQM_CF_OUT_ENA__A, 0x4); /* enable output 2 */
        if (status < 0)
                goto error;
        status = write16(state, IQM_CF_DS_ENA__A, 0x4); /* decimate output 2 */
@@ -3618,7 +3588,8 @@ static int SetDVBTStandard(struct drxk_state *state,
        if (status < 0)
                goto error;
 
-       status = BLChainCmd(state, DRXK_BL_ROM_OFFSET_TAPS_DVBT, DRXK_BLCC_NR_ELEMENTS_TAPS, DRXK_BLC_TIMEOUT);
+       status = bl_chain_cmd(state, DRXK_BL_ROM_OFFSET_TAPS_DVBT,
+                             DRXK_BLCC_NR_ELEMENTS_TAPS, DRXK_BLC_TIMEOUT);
        if (status < 0)
                goto error;
 
@@ -3637,10 +3608,10 @@ static int SetDVBTStandard(struct drxk_state *state,
                goto error;
 
        /* IQM will not be reset from here, sync ADC and update/init AGC */
-       status = ADCSynchronization(state);
+       status = adc_synchronization(state);
        if (status < 0)
                goto error;
-       status = SetPreSaw(state, &state->m_dvbtPreSawCfg);
+       status = set_pre_saw(state, &state->m_dvbt_pre_saw_cfg);
        if (status < 0)
                goto error;
 
@@ -3649,10 +3620,10 @@ static int SetDVBTStandard(struct drxk_state *state,
        if (status < 0)
                goto error;
 
-       status = SetAgcRf(state, &state->m_dvbtRfAgcCfg, true);
+       status = set_agc_rf(state, &state->m_dvbt_rf_agc_cfg, true);
        if (status < 0)
                goto error;
-       status = SetAgcIf(state, &state->m_dvbtIfAgcCfg, true);
+       status = set_agc_if(state, &state->m_dvbt_if_agc_cfg, true);
        if (status < 0)
                goto error;
 
@@ -3670,9 +3641,10 @@ static int SetDVBTStandard(struct drxk_state *state,
        if (status < 0)
                goto error;
 
-       if (!state->m_DRXK_A3_ROM_CODE) {
-               /* AGCInit() is not done for DVBT, so set agcFastClipCtrlDelay  */
-               status = write16(state, SCU_RAM_AGC_FAST_CLP_CTRL_DELAY__A, state->m_dvbtIfAgcCfg.FastClipCtrlDelay);
+       if (!state->m_drxk_a3_rom_code) {
+               /* AGCInit() is not done for DVBT, so set agcfast_clip_ctrl_delay  */
+               status = write16(state, SCU_RAM_AGC_FAST_CLP_CTRL_DELAY__A,
+                                state->m_dvbt_if_agc_cfg.fast_clip_ctrl_delay);
                if (status < 0)
                        goto error;
        }
@@ -3707,41 +3679,43 @@ static int SetDVBTStandard(struct drxk_state *state,
                goto error;
 
        /* Setup MPEG bus */
-       status = MPEGTSDtoSetup(state, OM_DVBT);
+       status = mpegts_dto_setup(state, OM_DVBT);
        if (status < 0)
                goto error;
        /* Set DVBT Presets */
-       status = DVBTActivatePresets(state);
+       status = dvbt_activate_presets(state);
        if (status < 0)
                goto error;
 
 error:
        if (status < 0)
-               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+               pr_err("Error %d on %s\n", status, __func__);
        return status;
 }
 
 /*============================================================================*/
 /**
-* \brief Start dvbt demodulating for channel.
+* \brief start dvbt demodulating for channel.
 * \param demod instance of demodulator.
 * \return DRXStatus_t.
 */
-static int DVBTStart(struct drxk_state *state)
+static int dvbt_start(struct drxk_state *state)
 {
        u16 param1;
        int status;
-       /* DRXKOfdmScCmd_t scCmd; */
+       /* drxk_ofdm_sc_cmd_t scCmd; */
 
        dprintk(1, "\n");
-       /* Start correct processes to get in lock */
+       /* start correct processes to get in lock */
        /* DRXK: OFDM_SC_RA_RAM_PROC_LOCKTRACK is no longer in mapfile! */
        param1 = OFDM_SC_RA_RAM_LOCKTRACK_MIN;
-       status = DVBTScCommand(state, OFDM_SC_RA_RAM_CMD_PROC_START, 0, OFDM_SC_RA_RAM_SW_EVENT_RUN_NMASK__M, param1, 0, 0, 0);
+       status = dvbt_sc_command(state, OFDM_SC_RA_RAM_CMD_PROC_START, 0,
+                                OFDM_SC_RA_RAM_SW_EVENT_RUN_NMASK__M, param1,
+                                0, 0, 0);
        if (status < 0)
                goto error;
-       /* Start FEC OC */
-       status = MPEGTSStart(state);
+       /* start FEC OC */
+       status = mpegts_start(state);
        if (status < 0)
                goto error;
        status = write16(state, FEC_COMM_EXEC__A, FEC_COMM_EXEC_ACTIVE);
@@ -3749,7 +3723,7 @@ static int DVBTStart(struct drxk_state *state)
                goto error;
 error:
        if (status < 0)
-               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+               pr_err("Error %d on %s\n", status, __func__);
        return status;
 }
 
@@ -3762,20 +3736,23 @@ error:
 * \return DRXStatus_t.
 * // original DVBTSetChannel()
 */
-static int SetDVBT(struct drxk_state *state, u16 IntermediateFreqkHz,
-                  s32 tunerFreqOffset)
+static int set_dvbt(struct drxk_state *state, u16 intermediate_freqk_hz,
+                  s32 tuner_freq_offset)
 {
-       u16 cmdResult = 0;
-       u16 transmissionParams = 0;
-       u16 operationMode = 0;
-       u32 iqmRcRateOfs = 0;
+       u16 cmd_result = 0;
+       u16 transmission_params = 0;
+       u16 operation_mode = 0;
+       u32 iqm_rc_rate_ofs = 0;
        u32 bandwidth = 0;
        u16 param1;
        int status;
 
-       dprintk(1, "IF =%d, TFO = %d\n", IntermediateFreqkHz, tunerFreqOffset);
+       dprintk(1, "IF =%d, TFO = %d\n",
+               intermediate_freqk_hz, tuner_freq_offset);
 
-       status = scu_command(state, SCU_RAM_COMMAND_STANDARD_OFDM | SCU_RAM_COMMAND_CMD_DEMOD_STOP, 0, NULL, 1, &cmdResult);
+       status = scu_command(state, SCU_RAM_COMMAND_STANDARD_OFDM
+                           | SCU_RAM_COMMAND_CMD_DEMOD_STOP,
+                           0, NULL, 1, &cmd_result);
        if (status < 0)
                goto error;
 
@@ -3798,19 +3775,19 @@ static int SetDVBT(struct drxk_state *state, u16 IntermediateFreqkHz,
        if (status < 0)
                goto error;
 
-       /*== Write channel settings to device =====================================*/
+       /*== Write channel settings to device ================================*/
 
        /* mode */
        switch (state->props.transmission_mode) {
        case TRANSMISSION_MODE_AUTO:
        default:
-               operationMode |= OFDM_SC_RA_RAM_OP_AUTO_MODE__M;
+               operation_mode |= OFDM_SC_RA_RAM_OP_AUTO_MODE__M;
                /* fall through , try first guess DRX_FFTMODE_8K */
        case TRANSMISSION_MODE_8K:
-               transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_MODE_8K;
+               transmission_params |= OFDM_SC_RA_RAM_OP_PARAM_MODE_8K;
                break;
        case TRANSMISSION_MODE_2K:
-               transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_MODE_2K;
+               transmission_params |= OFDM_SC_RA_RAM_OP_PARAM_MODE_2K;
                break;
        }
 
@@ -3818,19 +3795,19 @@ static int SetDVBT(struct drxk_state *state, u16 IntermediateFreqkHz,
        switch (state->props.guard_interval) {
        default:
        case GUARD_INTERVAL_AUTO:
-               operationMode |= OFDM_SC_RA_RAM_OP_AUTO_GUARD__M;
+               operation_mode |= OFDM_SC_RA_RAM_OP_AUTO_GUARD__M;
                /* fall through , try first guess DRX_GUARD_1DIV4 */
        case GUARD_INTERVAL_1_4:
-               transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_GUARD_4;
+               transmission_params |= OFDM_SC_RA_RAM_OP_PARAM_GUARD_4;
                break;
        case GUARD_INTERVAL_1_32:
-               transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_GUARD_32;
+               transmission_params |= OFDM_SC_RA_RAM_OP_PARAM_GUARD_32;
                break;
        case GUARD_INTERVAL_1_16:
-               transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_GUARD_16;
+               transmission_params |= OFDM_SC_RA_RAM_OP_PARAM_GUARD_16;
                break;
        case GUARD_INTERVAL_1_8:
-               transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_GUARD_8;
+               transmission_params |= OFDM_SC_RA_RAM_OP_PARAM_GUARD_8;
                break;
        }
 
@@ -3839,18 +3816,18 @@ static int SetDVBT(struct drxk_state *state, u16 IntermediateFreqkHz,
        case HIERARCHY_AUTO:
        case HIERARCHY_NONE:
        default:
-               operationMode |= OFDM_SC_RA_RAM_OP_AUTO_HIER__M;
+               operation_mode |= OFDM_SC_RA_RAM_OP_AUTO_HIER__M;
                /* fall through , try first guess SC_RA_RAM_OP_PARAM_HIER_NO */
-               /* transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_HIER_NO; */
+               /* transmission_params |= OFDM_SC_RA_RAM_OP_PARAM_HIER_NO; */
                /* break; */
        case HIERARCHY_1:
-               transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_HIER_A1;
+               transmission_params |= OFDM_SC_RA_RAM_OP_PARAM_HIER_A1;
                break;
        case HIERARCHY_2:
-               transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_HIER_A2;
+               transmission_params |= OFDM_SC_RA_RAM_OP_PARAM_HIER_A2;
                break;
        case HIERARCHY_4:
-               transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_HIER_A4;
+               transmission_params |= OFDM_SC_RA_RAM_OP_PARAM_HIER_A4;
                break;
        }
 
@@ -3859,16 +3836,16 @@ static int SetDVBT(struct drxk_state *state, u16 IntermediateFreqkHz,
        switch (state->props.modulation) {
        case QAM_AUTO:
        default:
-               operationMode |= OFDM_SC_RA_RAM_OP_AUTO_CONST__M;
+               operation_mode |= OFDM_SC_RA_RAM_OP_AUTO_CONST__M;
                /* fall through , try first guess DRX_CONSTELLATION_QAM64 */
        case QAM_64:
-               transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_CONST_QAM64;
+               transmission_params |= OFDM_SC_RA_RAM_OP_PARAM_CONST_QAM64;
                break;
        case QPSK:
-               transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_CONST_QPSK;
+               transmission_params |= OFDM_SC_RA_RAM_OP_PARAM_CONST_QPSK;
                break;
        case QAM_16:
-               transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_CONST_QAM16;
+               transmission_params |= OFDM_SC_RA_RAM_OP_PARAM_CONST_QAM16;
                break;
        }
 #if 0
@@ -3876,13 +3853,13 @@ static int SetDVBT(struct drxk_state *state, u16 IntermediateFreqkHz,
        /* Priority (only for hierarchical channels) */
        switch (channel->priority) {
        case DRX_PRIORITY_LOW:
-               transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_PRIO_LO;
-               WR16(devAddr, OFDM_EC_SB_PRIOR__A,
+               transmission_params |= OFDM_SC_RA_RAM_OP_PARAM_PRIO_LO;
+               WR16(dev_addr, OFDM_EC_SB_PRIOR__A,
                        OFDM_EC_SB_PRIOR_LO);
                break;
        case DRX_PRIORITY_HIGH:
-               transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_PRIO_HI;
-               WR16(devAddr, OFDM_EC_SB_PRIOR__A,
+               transmission_params |= OFDM_SC_RA_RAM_OP_PARAM_PRIO_HI;
+               WR16(dev_addr, OFDM_EC_SB_PRIOR__A,
                        OFDM_EC_SB_PRIOR_HI));
                break;
        case DRX_PRIORITY_UNKNOWN:      /* fall through */
@@ -3892,7 +3869,7 @@ static int SetDVBT(struct drxk_state *state, u16 IntermediateFreqkHz,
        }
 #else
        /* Set Priorty high */
-       transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_PRIO_HI;
+       transmission_params |= OFDM_SC_RA_RAM_OP_PARAM_PRIO_HI;
        status = write16(state, OFDM_EC_SB_PRIOR__A, OFDM_EC_SB_PRIOR_HI);
        if (status < 0)
                goto error;
@@ -3902,90 +3879,111 @@ static int SetDVBT(struct drxk_state *state, u16 IntermediateFreqkHz,
        switch (state->props.code_rate_HP) {
        case FEC_AUTO:
        default:
-               operationMode |= OFDM_SC_RA_RAM_OP_AUTO_RATE__M;
+               operation_mode |= OFDM_SC_RA_RAM_OP_AUTO_RATE__M;
                /* fall through , try first guess DRX_CODERATE_2DIV3 */
        case FEC_2_3:
-               transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_RATE_2_3;
+               transmission_params |= OFDM_SC_RA_RAM_OP_PARAM_RATE_2_3;
                break;
        case FEC_1_2:
-               transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_RATE_1_2;
+               transmission_params |= OFDM_SC_RA_RAM_OP_PARAM_RATE_1_2;
                break;
        case FEC_3_4:
-               transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_RATE_3_4;
+               transmission_params |= OFDM_SC_RA_RAM_OP_PARAM_RATE_3_4;
                break;
        case FEC_5_6:
-               transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_RATE_5_6;
+               transmission_params |= OFDM_SC_RA_RAM_OP_PARAM_RATE_5_6;
                break;
        case FEC_7_8:
-               transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_RATE_7_8;
+               transmission_params |= OFDM_SC_RA_RAM_OP_PARAM_RATE_7_8;
                break;
        }
 
-       /* SAW filter selection: normaly not necesarry, but if wanted
-               the application can select a SAW filter via the driver by using UIOs */
+       /*
+        * SAW filter selection: normaly not necesarry, but if wanted
+        * the application can select a SAW filter via the driver by
+        * using UIOs
+        */
+
        /* First determine real bandwidth (Hz) */
        /* Also set delay for impulse noise cruncher */
-       /* Also set parameters for EC_OC fix, note EC_OC_REG_TMD_HIL_MAR is changed
-               by SC for fix for some 8K,1/8 guard but is restored by InitEC and ResetEC
-               functions */
+       /*
+        * Also set parameters for EC_OC fix, note EC_OC_REG_TMD_HIL_MAR is
+        * changed by SC for fix for some 8K,1/8 guard but is restored by
+        * InitEC and ResetEC functions
+        */
        switch (state->props.bandwidth_hz) {
        case 0:
                state->props.bandwidth_hz = 8000000;
                /* fall though */
        case 8000000:
                bandwidth = DRXK_BANDWIDTH_8MHZ_IN_HZ;
-               status = write16(state, OFDM_SC_RA_RAM_SRMM_FIX_FACT_8K__A, 3052);
+               status = write16(state, OFDM_SC_RA_RAM_SRMM_FIX_FACT_8K__A,
+                                3052);
                if (status < 0)
                        goto error;
                /* cochannel protection for PAL 8 MHz */
-               status = write16(state, OFDM_SC_RA_RAM_NI_INIT_8K_PER_LEFT__A, 7);
+               status = write16(state, OFDM_SC_RA_RAM_NI_INIT_8K_PER_LEFT__A,
+                                7);
                if (status < 0)
                        goto error;
-               status = write16(state, OFDM_SC_RA_RAM_NI_INIT_8K_PER_RIGHT__A, 7);
+               status = write16(state, OFDM_SC_RA_RAM_NI_INIT_8K_PER_RIGHT__A,
+                                7);
                if (status < 0)
                        goto error;
-               status = write16(state, OFDM_SC_RA_RAM_NI_INIT_2K_PER_LEFT__A, 7);
+               status = write16(state, OFDM_SC_RA_RAM_NI_INIT_2K_PER_LEFT__A,
+                                7);
                if (status < 0)
                        goto error;
-               status = write16(state, OFDM_SC_RA_RAM_NI_INIT_2K_PER_RIGHT__A, 1);
+               status = write16(state, OFDM_SC_RA_RAM_NI_INIT_2K_PER_RIGHT__A,
+                                1);
                if (status < 0)
                        goto error;
                break;
        case 7000000:
                bandwidth = DRXK_BANDWIDTH_7MHZ_IN_HZ;
-               status = write16(state, OFDM_SC_RA_RAM_SRMM_FIX_FACT_8K__A, 3491);
+               status = write16(state, OFDM_SC_RA_RAM_SRMM_FIX_FACT_8K__A,
+                                3491);
                if (status < 0)
                        goto error;
                /* cochannel protection for PAL 7 MHz */
-               status = write16(state, OFDM_SC_RA_RAM_NI_INIT_8K_PER_LEFT__A, 8);
+               status = write16(state, OFDM_SC_RA_RAM_NI_INIT_8K_PER_LEFT__A,
+                                8);
                if (status < 0)
                        goto error;
-               status = write16(state, OFDM_SC_RA_RAM_NI_INIT_8K_PER_RIGHT__A, 8);
+               status = write16(state, OFDM_SC_RA_RAM_NI_INIT_8K_PER_RIGHT__A,
+                                8);
                if (status < 0)
                        goto error;
-               status = write16(state, OFDM_SC_RA_RAM_NI_INIT_2K_PER_LEFT__A, 4);
+               status = write16(state, OFDM_SC_RA_RAM_NI_INIT_2K_PER_LEFT__A,
+                                4);
                if (status < 0)
                        goto error;
-               status = write16(state, OFDM_SC_RA_RAM_NI_INIT_2K_PER_RIGHT__A, 1);
+               status = write16(state, OFDM_SC_RA_RAM_NI_INIT_2K_PER_RIGHT__A,
+                                1);
                if (status < 0)
                        goto error;
                break;
        case 6000000:
                bandwidth = DRXK_BANDWIDTH_6MHZ_IN_HZ;
-               status = write16(state, OFDM_SC_RA_RAM_SRMM_FIX_FACT_8K__A, 4073);
+               status = write16(state, OFDM_SC_RA_RAM_SRMM_FIX_FACT_8K__A,
+                                4073);
                if (status < 0)
                        goto error;
                /* cochannel protection for NTSC 6 MHz */
-               status = write16(state, OFDM_SC_RA_RAM_NI_INIT_8K_PER_LEFT__A, 19);
+               status = write16(state, OFDM_SC_RA_RAM_NI_INIT_8K_PER_LEFT__A,
+                                19);
                if (status < 0)
                        goto error;
-               status = write16(state, OFDM_SC_RA_RAM_NI_INIT_8K_PER_RIGHT__A, 19);
+               status = write16(state, OFDM_SC_RA_RAM_NI_INIT_8K_PER_RIGHT__A,
+                                19);
                if (status < 0)
                        goto error;
-               status = write16(state, OFDM_SC_RA_RAM_NI_INIT_2K_PER_LEFT__A, 14);
+               status = write16(state, OFDM_SC_RA_RAM_NI_INIT_2K_PER_LEFT__A,
+                                14);
                if (status < 0)
                        goto error;
-               status = write16(state, OFDM_SC_RA_RAM_NI_INIT_2K_PER_RIGHT__A, 1);
+               status = write16(state, OFDM_SC_RA_RAM_NI_INIT_2K_PER_RIGHT__A,
+                                1);
                if (status < 0)
                        goto error;
                break;
@@ -3994,46 +3992,50 @@ static int SetDVBT(struct drxk_state *state, u16 IntermediateFreqkHz,
                goto error;
        }
 
-       if (iqmRcRateOfs == 0) {
+       if (iqm_rc_rate_ofs == 0) {
                /* Now compute IQM_RC_RATE_OFS
                        (((SysFreq/BandWidth)/2)/2) -1) * 2^23)
                        =>
                        ((SysFreq / BandWidth) * (2^21)) - (2^23)
                        */
                /* (SysFreq / BandWidth) * (2^28)  */
-               /* assert (MAX(sysClk)/MIN(bandwidth) < 16)
-                       => assert(MAX(sysClk) < 16*MIN(bandwidth))
-                       => assert(109714272 > 48000000) = true so Frac 28 can be used  */
-               iqmRcRateOfs = Frac28a((u32)
-                                       ((state->m_sysClockFreq *
+               /*
+                * assert (MAX(sysClk)/MIN(bandwidth) < 16)
+                *      => assert(MAX(sysClk) < 16*MIN(bandwidth))
+                *      => assert(109714272 > 48000000) = true
+                * so Frac 28 can be used
+                */
+               iqm_rc_rate_ofs = Frac28a((u32)
+                                       ((state->m_sys_clock_freq *
                                                1000) / 3), bandwidth);
-               /* (SysFreq / BandWidth) * (2^21), rounding before truncating  */
-               if ((iqmRcRateOfs & 0x7fL) >= 0x40)
-                       iqmRcRateOfs += 0x80L;
-               iqmRcRateOfs = iqmRcRateOfs >> 7;
+               /* (SysFreq / BandWidth) * (2^21), rounding before truncating */
+               if ((iqm_rc_rate_ofs & 0x7fL) >= 0x40)
+                       iqm_rc_rate_ofs += 0x80L;
+               iqm_rc_rate_ofs = iqm_rc_rate_ofs >> 7;
                /* ((SysFreq / BandWidth) * (2^21)) - (2^23)  */
-               iqmRcRateOfs = iqmRcRateOfs - (1 << 23);
+               iqm_rc_rate_ofs = iqm_rc_rate_ofs - (1 << 23);
        }
 
-       iqmRcRateOfs &=
+       iqm_rc_rate_ofs &=
                ((((u32) IQM_RC_RATE_OFS_HI__M) <<
                IQM_RC_RATE_OFS_LO__W) | IQM_RC_RATE_OFS_LO__M);
-       status = write32(state, IQM_RC_RATE_OFS_LO__A, iqmRcRateOfs);
+       status = write32(state, IQM_RC_RATE_OFS_LO__A, iqm_rc_rate_ofs);
        if (status < 0)
                goto error;
 
        /* Bandwidth setting done */
 
 #if 0
-       status = DVBTSetFrequencyShift(demod, channel, tunerOffset);
+       status = dvbt_set_frequency_shift(demod, channel, tuner_offset);
        if (status < 0)
                goto error;
 #endif
-       status = SetFrequencyShifter(state, IntermediateFreqkHz, tunerFreqOffset, true);
+       status = set_frequency_shifter(state, intermediate_freqk_hz,
+                                      tuner_freq_offset, true);
        if (status < 0)
                goto error;
 
-       /*== Start SC, write channel settings to SC ===============================*/
+       /*== start SC, write channel settings to SC ==========================*/
 
        /* Activate SCU to enable SCU commands */
        status = write16(state, SCU_COMM_EXEC__A, SCU_COMM_EXEC_ACTIVE);
@@ -4049,7 +4051,9 @@ static int SetDVBT(struct drxk_state *state, u16 IntermediateFreqkHz,
                goto error;
 
 
-       status = scu_command(state, SCU_RAM_COMMAND_STANDARD_OFDM | SCU_RAM_COMMAND_CMD_DEMOD_START, 0, NULL, 1, &cmdResult);
+       status = scu_command(state, SCU_RAM_COMMAND_STANDARD_OFDM
+                            | SCU_RAM_COMMAND_CMD_DEMOD_START,
+                            0, NULL, 1, &cmd_result);
        if (status < 0)
                goto error;
 
@@ -4059,16 +4063,16 @@ static int SetDVBT(struct drxk_state *state, u16 IntermediateFreqkHz,
                        OFDM_SC_RA_RAM_OP_AUTO_CONST__M |
                        OFDM_SC_RA_RAM_OP_AUTO_HIER__M |
                        OFDM_SC_RA_RAM_OP_AUTO_RATE__M);
-       status = DVBTScCommand(state, OFDM_SC_RA_RAM_CMD_SET_PREF_PARAM,
-                               0, transmissionParams, param1, 0, 0, 0);
+       status = dvbt_sc_command(state, OFDM_SC_RA_RAM_CMD_SET_PREF_PARAM,
+                               0, transmission_params, param1, 0, 0, 0);
        if (status < 0)
                goto error;
 
-       if (!state->m_DRXK_A3_ROM_CODE)
-               status = DVBTCtrlSetSqiSpeed(state, &state->m_sqiSpeed);
+       if (!state->m_drxk_a3_rom_code)
+               status = dvbt_ctrl_set_sqi_speed(state, &state->m_sqi_speed);
 error:
        if (status < 0)
-               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+               pr_err("Error %d on %s\n", status, __func__);
 
        return status;
 }
@@ -4083,7 +4087,7 @@ error:
 * \return DRXStatus_t.
 *
 */
-static int GetDVBTLockStatus(struct drxk_state *state, u32 *pLockStatus)
+static int get_dvbt_lock_status(struct drxk_state *state, u32 *p_lock_status)
 {
        int status;
        const u16 mpeg_lock_mask = (OFDM_SC_RA_RAM_LOCK_MPEG__M |
@@ -4091,58 +4095,58 @@ static int GetDVBTLockStatus(struct drxk_state *state, u32 *pLockStatus)
        const u16 fec_lock_mask = (OFDM_SC_RA_RAM_LOCK_FEC__M);
        const u16 demod_lock_mask = OFDM_SC_RA_RAM_LOCK_DEMOD__M;
 
-       u16 ScRaRamLock = 0;
-       u16 ScCommExec = 0;
+       u16 sc_ra_ram_lock = 0;
+       u16 sc_comm_exec = 0;
 
        dprintk(1, "\n");
 
-       *pLockStatus = NOT_LOCKED;
+       *p_lock_status = NOT_LOCKED;
        /* driver 0.9.0 */
        /* Check if SC is running */
-       status = read16(state, OFDM_SC_COMM_EXEC__A, &ScCommExec);
+       status = read16(state, OFDM_SC_COMM_EXEC__A, &sc_comm_exec);
        if (status < 0)
                goto end;
-       if (ScCommExec == OFDM_SC_COMM_EXEC_STOP)
+       if (sc_comm_exec == OFDM_SC_COMM_EXEC_STOP)
                goto end;
 
-       status = read16(state, OFDM_SC_RA_RAM_LOCK__A, &ScRaRamLock);
+       status = read16(state, OFDM_SC_RA_RAM_LOCK__A, &sc_ra_ram_lock);
        if (status < 0)
                goto end;
 
-       if ((ScRaRamLock & mpeg_lock_mask) == mpeg_lock_mask)
-               *pLockStatus = MPEG_LOCK;
-       else if ((ScRaRamLock & fec_lock_mask) == fec_lock_mask)
-               *pLockStatus = FEC_LOCK;
-       else if ((ScRaRamLock & demod_lock_mask) == demod_lock_mask)
-               *pLockStatus = DEMOD_LOCK;
-       else if (ScRaRamLock & OFDM_SC_RA_RAM_LOCK_NODVBT__M)
-               *pLockStatus = NEVER_LOCK;
+       if ((sc_ra_ram_lock & mpeg_lock_mask) == mpeg_lock_mask)
+               *p_lock_status = MPEG_LOCK;
+       else if ((sc_ra_ram_lock & fec_lock_mask) == fec_lock_mask)
+               *p_lock_status = FEC_LOCK;
+       else if ((sc_ra_ram_lock & demod_lock_mask) == demod_lock_mask)
+               *p_lock_status = DEMOD_LOCK;
+       else if (sc_ra_ram_lock & OFDM_SC_RA_RAM_LOCK_NODVBT__M)
+               *p_lock_status = NEVER_LOCK;
 end:
        if (status < 0)
-               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+               pr_err("Error %d on %s\n", status, __func__);
 
        return status;
 }
 
-static int PowerUpQAM(struct drxk_state *state)
+static int power_up_qam(struct drxk_state *state)
 {
-       enum DRXPowerMode powerMode = DRXK_POWER_DOWN_OFDM;
+       enum drx_power_mode power_mode = DRXK_POWER_DOWN_OFDM;
        int status;
 
        dprintk(1, "\n");
-       status = CtrlPowerMode(state, &powerMode);
+       status = ctrl_power_mode(state, &power_mode);
        if (status < 0)
-               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+               pr_err("Error %d on %s\n", status, __func__);
 
        return status;
 }
 
 
 /** Power Down QAM */
-static int PowerDownQAM(struct drxk_state *state)
+static int power_down_qam(struct drxk_state *state)
 {
        u16 data = 0;
-       u16 cmdResult;
+       u16 cmd_result;
        int status = 0;
 
        dprintk(1, "\n");
@@ -4158,16 +4162,18 @@ static int PowerDownQAM(struct drxk_state *state)
                status = write16(state, QAM_COMM_EXEC__A, QAM_COMM_EXEC_STOP);
                if (status < 0)
                        goto error;
-               status = scu_command(state, SCU_RAM_COMMAND_STANDARD_QAM | SCU_RAM_COMMAND_CMD_DEMOD_STOP, 0, NULL, 1, &cmdResult);
+               status = scu_command(state, SCU_RAM_COMMAND_STANDARD_QAM
+                                    | SCU_RAM_COMMAND_CMD_DEMOD_STOP,
+                                    0, NULL, 1, &cmd_result);
                if (status < 0)
                        goto error;
        }
        /* powerdown AFE                   */
-       status = SetIqmAf(state, false);
+       status = set_iqm_af(state, false);
 
 error:
        if (status < 0)
-               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+               pr_err("Error %d on %s\n", status, __func__);
 
        return status;
 }
@@ -4185,20 +4191,20 @@ error:
 *  The implementation does not check this.
 *
 */
-static int SetQAMMeasurement(struct drxk_state *state,
-                            enum EDrxkConstellation modulation,
-                            u32 symbolRate)
+static int set_qam_measurement(struct drxk_state *state,
+                            enum e_drxk_constellation modulation,
+                            u32 symbol_rate)
 {
-       u32 fecBitsDesired = 0; /* BER accounting period */
-       u32 fecRsPeriodTotal = 0;       /* Total period */
-       u16 fecRsPrescale = 0;  /* ReedSolomon Measurement Prescale */
-       u16 fecRsPeriod = 0;    /* Value for corresponding I2C register */
+       u32 fec_bits_desired = 0;       /* BER accounting period */
+       u32 fec_rs_period_total = 0;    /* Total period */
+       u16 fec_rs_prescale = 0;        /* ReedSolomon Measurement Prescale */
+       u16 fec_rs_period = 0;  /* Value for corresponding I2C register */
        int status = 0;
 
        dprintk(1, "\n");
 
-       fecRsPrescale = 1;
-       /* fecBitsDesired = symbolRate [kHz] *
+       fec_rs_prescale = 1;
+       /* fec_bits_desired = symbol_rate [kHz] *
                FrameLenght [ms] *
                (modulation + 1) *
                SyncLoss (== 1) *
@@ -4206,19 +4212,19 @@ static int SetQAMMeasurement(struct drxk_state *state,
                */
        switch (modulation) {
        case DRX_CONSTELLATION_QAM16:
-               fecBitsDesired = 4 * symbolRate;
+               fec_bits_desired = 4 * symbol_rate;
                break;
        case DRX_CONSTELLATION_QAM32:
-               fecBitsDesired = 5 * symbolRate;
+               fec_bits_desired = 5 * symbol_rate;
                break;
        case DRX_CONSTELLATION_QAM64:
-               fecBitsDesired = 6 * symbolRate;
+               fec_bits_desired = 6 * symbol_rate;
                break;
        case DRX_CONSTELLATION_QAM128:
-               fecBitsDesired = 7 * symbolRate;
+               fec_bits_desired = 7 * symbol_rate;
                break;
        case DRX_CONSTELLATION_QAM256:
-               fecBitsDesired = 8 * symbolRate;
+               fec_bits_desired = 8 * symbol_rate;
                break;
        default:
                status = -EINVAL;
@@ -4226,40 +4232,41 @@ static int SetQAMMeasurement(struct drxk_state *state,
        if (status < 0)
                goto error;
 
-       fecBitsDesired /= 1000; /* symbolRate [Hz] -> symbolRate [kHz]  */
-       fecBitsDesired *= 500;  /* meas. period [ms] */
+       fec_bits_desired /= 1000;       /* symbol_rate [Hz] -> symbol_rate [kHz] */
+       fec_bits_desired *= 500;        /* meas. period [ms] */
 
        /* Annex A/C: bits/RsPeriod = 204 * 8 = 1632 */
-       /* fecRsPeriodTotal = fecBitsDesired / 1632 */
-       fecRsPeriodTotal = (fecBitsDesired / 1632UL) + 1;       /* roughly ceil */
+       /* fec_rs_period_total = fec_bits_desired / 1632 */
+       fec_rs_period_total = (fec_bits_desired / 1632UL) + 1;  /* roughly ceil */
 
-       /* fecRsPeriodTotal =  fecRsPrescale * fecRsPeriod  */
-       fecRsPrescale = 1 + (u16) (fecRsPeriodTotal >> 16);
-       if (fecRsPrescale == 0) {
+       /* fec_rs_period_total =  fec_rs_prescale * fec_rs_period  */
+       fec_rs_prescale = 1 + (u16) (fec_rs_period_total >> 16);
+       if (fec_rs_prescale == 0) {
                /* Divide by zero (though impossible) */
                status = -EINVAL;
                if (status < 0)
                        goto error;
        }
-       fecRsPeriod =
-               ((u16) fecRsPeriodTotal +
-               (fecRsPrescale >> 1)) / fecRsPrescale;
+       fec_rs_period =
+               ((u16) fec_rs_period_total +
+               (fec_rs_prescale >> 1)) / fec_rs_prescale;
 
        /* write corresponding registers */
-       status = write16(state, FEC_RS_MEASUREMENT_PERIOD__A, fecRsPeriod);
+       status = write16(state, FEC_RS_MEASUREMENT_PERIOD__A, fec_rs_period);
        if (status < 0)
                goto error;
-       status = write16(state, FEC_RS_MEASUREMENT_PRESCALE__A, fecRsPrescale);
+       status = write16(state, FEC_RS_MEASUREMENT_PRESCALE__A,
+                        fec_rs_prescale);
        if (status < 0)
                goto error;
-       status = write16(state, FEC_OC_SNC_FAIL_PERIOD__A, fecRsPeriod);
+       status = write16(state, FEC_OC_SNC_FAIL_PERIOD__A, fec_rs_period);
 error:
        if (status < 0)
-               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+               pr_err("Error %d on %s\n", status, __func__);
        return status;
 }
 
-static int SetQAM16(struct drxk_state *state)
+static int set_qam16(struct drxk_state *state)
 {
        int status = 0;
 
@@ -4315,7 +4322,8 @@ static int SetQAM16(struct drxk_state *state)
                goto error;
 
        /* QAM Slicer Settings */
-       status = write16(state, SCU_RAM_QAM_SL_SIG_POWER__A, DRXK_QAM_SL_SIG_POWER_QAM16);
+       status = write16(state, SCU_RAM_QAM_SL_SIG_POWER__A,
+                        DRXK_QAM_SL_SIG_POWER_QAM16);
        if (status < 0)
                goto error;
 
@@ -4441,7 +4449,7 @@ static int SetQAM16(struct drxk_state *state)
 
 error:
        if (status < 0)
-               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+               pr_err("Error %d on %s\n", status, __func__);
        return status;
 }
 
@@ -4452,7 +4460,7 @@ error:
 * \param demod instance of demod.
 * \return DRXStatus_t.
 */
-static int SetQAM32(struct drxk_state *state)
+static int set_qam32(struct drxk_state *state)
 {
        int status = 0;
 
@@ -4511,7 +4519,8 @@ static int SetQAM32(struct drxk_state *state)
 
        /* QAM Slicer Settings */
 
-       status = write16(state, SCU_RAM_QAM_SL_SIG_POWER__A, DRXK_QAM_SL_SIG_POWER_QAM32);
+       status = write16(state, SCU_RAM_QAM_SL_SIG_POWER__A,
+                        DRXK_QAM_SL_SIG_POWER_QAM32);
        if (status < 0)
                goto error;
 
@@ -4636,7 +4645,7 @@ static int SetQAM32(struct drxk_state *state)
        status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET5__A, (u16) -86);
 error:
        if (status < 0)
-               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+               pr_err("Error %d on %s\n", status, __func__);
        return status;
 }
 
@@ -4647,7 +4656,7 @@ error:
 * \param demod instance of demod.
 * \return DRXStatus_t.
 */
-static int SetQAM64(struct drxk_state *state)
+static int set_qam64(struct drxk_state *state)
 {
        int status = 0;
 
@@ -4704,7 +4713,8 @@ static int SetQAM64(struct drxk_state *state)
                goto error;
 
        /* QAM Slicer Settings */
-       status = write16(state, SCU_RAM_QAM_SL_SIG_POWER__A, DRXK_QAM_SL_SIG_POWER_QAM64);
+       status = write16(state, SCU_RAM_QAM_SL_SIG_POWER__A,
+                        DRXK_QAM_SL_SIG_POWER_QAM64);
        if (status < 0)
                goto error;
 
@@ -4829,7 +4839,7 @@ static int SetQAM64(struct drxk_state *state)
        status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET5__A, (u16) -80);
 error:
        if (status < 0)
-               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+               pr_err("Error %d on %s\n", status, __func__);
 
        return status;
 }
@@ -4841,7 +4851,7 @@ error:
 * \param demod: instance of demod.
 * \return DRXStatus_t.
 */
-static int SetQAM128(struct drxk_state *state)
+static int set_qam128(struct drxk_state *state)
 {
        int status = 0;
 
@@ -4900,7 +4910,8 @@ static int SetQAM128(struct drxk_state *state)
 
        /* QAM Slicer Settings */
 
-       status = write16(state, SCU_RAM_QAM_SL_SIG_POWER__A, DRXK_QAM_SL_SIG_POWER_QAM128);
+       status = write16(state, SCU_RAM_QAM_SL_SIG_POWER__A,
+                        DRXK_QAM_SL_SIG_POWER_QAM128);
        if (status < 0)
                goto error;
 
@@ -5025,7 +5036,7 @@ static int SetQAM128(struct drxk_state *state)
        status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET5__A, (u16) -23);
 error:
        if (status < 0)
-               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+               pr_err("Error %d on %s\n", status, __func__);
 
        return status;
 }
@@ -5037,7 +5048,7 @@ error:
 * \param demod: instance of demod.
 * \return DRXStatus_t.
 */
-static int SetQAM256(struct drxk_state *state)
+static int set_qam256(struct drxk_state *state)
 {
        int status = 0;
 
@@ -5095,7 +5106,8 @@ static int SetQAM256(struct drxk_state *state)
 
        /* QAM Slicer Settings */
 
-       status = write16(state, SCU_RAM_QAM_SL_SIG_POWER__A, DRXK_QAM_SL_SIG_POWER_QAM256);
+       status = write16(state, SCU_RAM_QAM_SL_SIG_POWER__A,
+                        DRXK_QAM_SL_SIG_POWER_QAM256);
        if (status < 0)
                goto error;
 
@@ -5220,7 +5232,7 @@ static int SetQAM256(struct drxk_state *state)
        status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET5__A, (u16) -8);
 error:
        if (status < 0)
-               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+               pr_err("Error %d on %s\n", status, __func__);
        return status;
 }
 
@@ -5232,10 +5244,10 @@ error:
 * \param channel: pointer to channel data.
 * \return DRXStatus_t.
 */
-static int QAMResetQAM(struct drxk_state *state)
+static int qam_reset_qam(struct drxk_state *state)
 {
        int status;
-       u16 cmdResult;
+       u16 cmd_result;
 
        dprintk(1, "\n");
        /* Stop QAM comstate->m_exec */
@@ -5243,10 +5255,12 @@ static int QAMResetQAM(struct drxk_state *state)
        if (status < 0)
                goto error;
 
-       status = scu_command(state, SCU_RAM_COMMAND_STANDARD_QAM | SCU_RAM_COMMAND_CMD_DEMOD_RESET, 0, NULL, 1, &cmdResult);
+       status = scu_command(state, SCU_RAM_COMMAND_STANDARD_QAM
+                            | SCU_RAM_COMMAND_CMD_DEMOD_RESET,
+                            0, NULL, 1, &cmd_result);
 error:
        if (status < 0)
-               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+               pr_err("Error %d on %s\n", status, __func__);
        return status;
 }
 
@@ -5258,18 +5272,18 @@ error:
 * \param channel: pointer to channel data.
 * \return DRXStatus_t.
 */
-static int QAMSetSymbolrate(struct drxk_state *state)
+static int qam_set_symbolrate(struct drxk_state *state)
 {
-       u32 adcFrequency = 0;
-       u32 symbFreq = 0;
-       u32 iqmRcRate = 0;
+       u32 adc_frequency = 0;
+       u32 symb_freq = 0;
+       u32 iqm_rc_rate = 0;
        u16 ratesel = 0;
-       u32 lcSymbRate = 0;
+       u32 lc_symb_rate = 0;
        int status;
 
        dprintk(1, "\n");
        /* Select & calculate correct IQM rate */
-       adcFrequency = (state->m_sysClockFreq * 1000) / 3;
+       adc_frequency = (state->m_sys_clock_freq * 1000) / 3;
        ratesel = 0;
        /* printk(KERN_DEBUG "drxk: SR %d\n", state->props.symbol_rate); */
        if (state->props.symbol_rate <= 1188750)
@@ -5285,38 +5299,38 @@ static int QAMSetSymbolrate(struct drxk_state *state)
        /*
                IqmRcRate = ((Fadc / (symbolrate * (4<<ratesel))) - 1) * (1<<23)
                */
-       symbFreq = state->props.symbol_rate * (1 << ratesel);
-       if (symbFreq == 0) {
+       symb_freq = state->props.symbol_rate * (1 << ratesel);
+       if (symb_freq == 0) {
                /* Divide by zero */
                status = -EINVAL;
                goto error;
        }
-       iqmRcRate = (adcFrequency / symbFreq) * (1 << 21) +
-               (Frac28a((adcFrequency % symbFreq), symbFreq) >> 7) -
+       iqm_rc_rate = (adc_frequency / symb_freq) * (1 << 21) +
+               (Frac28a((adc_frequency % symb_freq), symb_freq) >> 7) -
                (1 << 23);
-       status = write32(state, IQM_RC_RATE_OFS_LO__A, iqmRcRate);
+       status = write32(state, IQM_RC_RATE_OFS_LO__A, iqm_rc_rate);
        if (status < 0)
                goto error;
-       state->m_iqmRcRate = iqmRcRate;
+       state->m_iqm_rc_rate = iqm_rc_rate;
        /*
-               LcSymbFreq = round (.125 *  symbolrate / adcFreq * (1<<15))
+               LcSymbFreq = round (.125 *  symbolrate / adc_freq * (1<<15))
                */
-       symbFreq = state->props.symbol_rate;
-       if (adcFrequency == 0) {
+       symb_freq = state->props.symbol_rate;
+       if (adc_frequency == 0) {
                /* Divide by zero */
                status = -EINVAL;
                goto error;
        }
-       lcSymbRate = (symbFreq / adcFrequency) * (1 << 12) +
-               (Frac28a((symbFreq % adcFrequency), adcFrequency) >>
+       lc_symb_rate = (symb_freq / adc_frequency) * (1 << 12) +
+               (Frac28a((symb_freq % adc_frequency), adc_frequency) >>
                16);
-       if (lcSymbRate > 511)
-               lcSymbRate = 511;
-       status = write16(state, QAM_LC_SYMBOL_FREQ__A, (u16) lcSymbRate);
+       if (lc_symb_rate > 511)
+               lc_symb_rate = 511;
+       status = write16(state, QAM_LC_SYMBOL_FREQ__A, (u16) lc_symb_rate);
 
 error:
        if (status < 0)
-               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+               pr_err("Error %d on %s\n", status, __func__);
        return status;
 }
 
@@ -5329,34 +5343,36 @@ error:
 * \return DRXStatus_t.
 */
 
-static int GetQAMLockStatus(struct drxk_state *state, u32 *pLockStatus)
+static int get_qam_lock_status(struct drxk_state *state, u32 *p_lock_status)
 {
        int status;
-       u16 Result[2] = { 0, 0 };
+       u16 result[2] = { 0, 0 };
 
        dprintk(1, "\n");
-       *pLockStatus = NOT_LOCKED;
+       *p_lock_status = NOT_LOCKED;
        status = scu_command(state,
                        SCU_RAM_COMMAND_STANDARD_QAM |
                        SCU_RAM_COMMAND_CMD_DEMOD_GET_LOCK, 0, NULL, 2,
-                       Result);
+                       result);
        if (status < 0)
-               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+               pr_err("Error %d on %s\n", status, __func__);
 
-       if (Result[1] < SCU_RAM_QAM_LOCKED_LOCKED_DEMOD_LOCKED) {
+       if (result[1] < SCU_RAM_QAM_LOCKED_LOCKED_DEMOD_LOCKED) {
                /* 0x0000 NOT LOCKED */
-       } else if (Result[1] < SCU_RAM_QAM_LOCKED_LOCKED_LOCKED) {
+       } else if (result[1] < SCU_RAM_QAM_LOCKED_LOCKED_LOCKED) {
                /* 0x4000 DEMOD LOCKED */
-               *pLockStatus = DEMOD_LOCK;
-       } else if (Result[1] < SCU_RAM_QAM_LOCKED_LOCKED_NEVER_LOCK) {
+               *p_lock_status = DEMOD_LOCK;
+       } else if (result[1] < SCU_RAM_QAM_LOCKED_LOCKED_NEVER_LOCK) {
                /* 0x8000 DEMOD + FEC LOCKED (system lock) */
-               *pLockStatus = MPEG_LOCK;
+               *p_lock_status = MPEG_LOCK;
        } else {
                /* 0xC000 NEVER LOCKED */
                /* (system will never be able to lock to the signal) */
-               /* TODO: check this, intermediate & standard specific lock states are not
-                  taken into account here */
-               *pLockStatus = NEVER_LOCK;
+               /*
+                * TODO: check this, intermediate & standard specific lock
+                * states are not taken into account here
+                */
+               *p_lock_status = NEVER_LOCK;
        }
        return status;
 }
@@ -5368,68 +5384,70 @@ static int GetQAMLockStatus(struct drxk_state *state, u32 *pLockStatus)
 #define QAM_LOCKRANGE__M      0x10
 #define QAM_LOCKRANGE_NORMAL  0x10
 
-static int QAMDemodulatorCommand(struct drxk_state *state,
-                                int numberOfParameters)
+static int qam_demodulator_command(struct drxk_state *state,
+                                int number_of_parameters)
 {
        int status;
-       u16 cmdResult;
-       u16 setParamParameters[4] = { 0, 0, 0, 0 };
+       u16 cmd_result;
+       u16 set_param_parameters[4] = { 0, 0, 0, 0 };
 
-       setParamParameters[0] = state->m_Constellation; /* modulation     */
-       setParamParameters[1] = DRXK_QAM_I12_J17;       /* interleave mode   */
+       set_param_parameters[0] = state->m_constellation;       /* modulation     */
+       set_param_parameters[1] = DRXK_QAM_I12_J17;     /* interleave mode   */
 
-       if (numberOfParameters == 2) {
-               u16 setEnvParameters[1] = { 0 };
+       if (number_of_parameters == 2) {
+               u16 set_env_parameters[1] = { 0 };
 
-               if (state->m_OperationMode == OM_QAM_ITU_C)
-                       setEnvParameters[0] = QAM_TOP_ANNEX_C;
+               if (state->m_operation_mode == OM_QAM_ITU_C)
+                       set_env_parameters[0] = QAM_TOP_ANNEX_C;
                else
-                       setEnvParameters[0] = QAM_TOP_ANNEX_A;
+                       set_env_parameters[0] = QAM_TOP_ANNEX_A;
 
                status = scu_command(state,
-                                    SCU_RAM_COMMAND_STANDARD_QAM | SCU_RAM_COMMAND_CMD_DEMOD_SET_ENV,
-                                    1, setEnvParameters, 1, &cmdResult);
+                                    SCU_RAM_COMMAND_STANDARD_QAM
+                                    | SCU_RAM_COMMAND_CMD_DEMOD_SET_ENV,
+                                    1, set_env_parameters, 1, &cmd_result);
                if (status < 0)
                        goto error;
 
                status = scu_command(state,
-                                    SCU_RAM_COMMAND_STANDARD_QAM | SCU_RAM_COMMAND_CMD_DEMOD_SET_PARAM,
-                                    numberOfParameters, setParamParameters,
-                                    1, &cmdResult);
-       } else if (numberOfParameters == 4) {
-               if (state->m_OperationMode == OM_QAM_ITU_C)
-                       setParamParameters[2] = QAM_TOP_ANNEX_C;
+                                    SCU_RAM_COMMAND_STANDARD_QAM
+                                    | SCU_RAM_COMMAND_CMD_DEMOD_SET_PARAM,
+                                    number_of_parameters, set_param_parameters,
+                                    1, &cmd_result);
+       } else if (number_of_parameters == 4) {
+               if (state->m_operation_mode == OM_QAM_ITU_C)
+                       set_param_parameters[2] = QAM_TOP_ANNEX_C;
                else
-                       setParamParameters[2] = QAM_TOP_ANNEX_A;
+                       set_param_parameters[2] = QAM_TOP_ANNEX_A;
 
-               setParamParameters[3] |= (QAM_MIRROR_AUTO_ON);
+               set_param_parameters[3] |= (QAM_MIRROR_AUTO_ON);
                /* Env parameters */
                /* check for LOCKRANGE Extented */
-               /* setParamParameters[3] |= QAM_LOCKRANGE_NORMAL; */
+               /* set_param_parameters[3] |= QAM_LOCKRANGE_NORMAL; */
 
                status = scu_command(state,
-                                    SCU_RAM_COMMAND_STANDARD_QAM | SCU_RAM_COMMAND_CMD_DEMOD_SET_PARAM,
-                                    numberOfParameters, setParamParameters,
-                                    1, &cmdResult);
+                                    SCU_RAM_COMMAND_STANDARD_QAM
+                                    | SCU_RAM_COMMAND_CMD_DEMOD_SET_PARAM,
+                                    number_of_parameters, set_param_parameters,
+                                    1, &cmd_result);
        } else {
-               printk(KERN_WARNING "drxk: Unknown QAM demodulator parameter "
-                       "count %d\n", numberOfParameters);
+               pr_warn("Unknown QAM demodulator parameter count %d\n",
+                       number_of_parameters);
                status = -EINVAL;
        }
 
 error:
        if (status < 0)
-               printk(KERN_WARNING "drxk: Warning %d on %s\n",
-                      status, __func__);
+               pr_warn("Warning %d on %s\n", status, __func__);
        return status;
 }
 
-static int SetQAM(struct drxk_state *state, u16 IntermediateFreqkHz,
-                 s32 tunerFreqOffset)
+static int set_qam(struct drxk_state *state, u16 intermediate_freqk_hz,
+                 s32 tuner_freq_offset)
 {
        int status;
-       u16 cmdResult;
-       int qamDemodParamCount = state->qam_demod_parameter_count;
+       u16 cmd_result;
+       int qam_demod_param_count = state->qam_demod_parameter_count;
 
        dprintk(1, "\n");
        /*
@@ -5444,7 +5462,7 @@ static int SetQAM(struct drxk_state *state, u16 IntermediateFreqkHz,
        status = write16(state, FEC_RS_COMM_EXEC__A, FEC_RS_COMM_EXEC_STOP);
        if (status < 0)
                goto error;
-       status = QAMResetQAM(state);
+       status = qam_reset_qam(state);
        if (status < 0)
                goto error;
 
@@ -5453,27 +5471,27 @@ static int SetQAM(struct drxk_state *state, u16 IntermediateFreqkHz,
         *      -set params; resets IQM,QAM,FEC HW; initializes some
         *       SCU variables
         */
-       status = QAMSetSymbolrate(state);
+       status = qam_set_symbolrate(state);
        if (status < 0)
                goto error;
 
        /* Set params */
        switch (state->props.modulation) {
        case QAM_256:
-               state->m_Constellation = DRX_CONSTELLATION_QAM256;
+               state->m_constellation = DRX_CONSTELLATION_QAM256;
                break;
        case QAM_AUTO:
        case QAM_64:
-               state->m_Constellation = DRX_CONSTELLATION_QAM64;
+               state->m_constellation = DRX_CONSTELLATION_QAM64;
                break;
        case QAM_16:
-               state->m_Constellation = DRX_CONSTELLATION_QAM16;
+               state->m_constellation = DRX_CONSTELLATION_QAM16;
                break;
        case QAM_32:
-               state->m_Constellation = DRX_CONSTELLATION_QAM32;
+               state->m_constellation = DRX_CONSTELLATION_QAM32;
                break;
        case QAM_128:
-               state->m_Constellation = DRX_CONSTELLATION_QAM128;
+               state->m_constellation = DRX_CONSTELLATION_QAM128;
                break;
        default:
                status = -EINVAL;
@@ -5486,8 +5504,8 @@ static int SetQAM(struct drxk_state *state, u16 IntermediateFreqkHz,
         * the correct command. */
        if (state->qam_demod_parameter_count == 4
                || !state->qam_demod_parameter_count) {
-               qamDemodParamCount = 4;
-               status = QAMDemodulatorCommand(state, qamDemodParamCount);
+               qam_demod_param_count = 4;
+               status = qam_demodulator_command(state, qam_demod_param_count);
        }
 
        /* Use the 2-parameter command if it was requested or if we're
@@ -5495,27 +5513,27 @@ static int SetQAM(struct drxk_state *state, u16 IntermediateFreqkHz,
         * failed. */
        if (state->qam_demod_parameter_count == 2
                || (!state->qam_demod_parameter_count && status < 0)) {
-               qamDemodParamCount = 2;
-               status = QAMDemodulatorCommand(state, qamDemodParamCount);
+               qam_demod_param_count = 2;
+               status = qam_demodulator_command(state, qam_demod_param_count);
        }
 
        if (status < 0) {
-               dprintk(1, "Could not set demodulator parameters. Make "
-                       "sure qam_demod_parameter_count (%d) is correct for "
-                       "your firmware (%s).\n",
+               dprintk(1, "Could not set demodulator parameters.\n");
+               dprintk(1,
+                       "Make sure qam_demod_parameter_count (%d) is correct for your firmware (%s).\n",
                        state->qam_demod_parameter_count,
                        state->microcode_name);
                goto error;
        } else if (!state->qam_demod_parameter_count) {
-               dprintk(1, "Auto-probing the correct QAM demodulator command "
-                       "parameters was successful - using %d parameters.\n",
-                       qamDemodParamCount);
+               dprintk(1,
+                       "Auto-probing the QAM command parameters was successful - using %d parameters.\n",
+                       qam_demod_param_count);
 
                /*
                 * One of our commands was successful. We don't need to
                 * auto-probe anymore, now that we got the correct command.
                 */
-               state->qam_demod_parameter_count = qamDemodParamCount;
+               state->qam_demod_parameter_count = qam_demod_param_count;
        }
 
        /*
@@ -5523,16 +5541,18 @@ static int SetQAM(struct drxk_state *state, u16 IntermediateFreqkHz,
         * signal setup modulation independent registers
         */
 #if 0
-       status = SetFrequency(channel, tunerFreqOffset));
+       status = set_frequency(channel, tuner_freq_offset));
        if (status < 0)
                goto error;
 #endif
-       status = SetFrequencyShifter(state, IntermediateFreqkHz, tunerFreqOffset, true);
+       status = set_frequency_shifter(state, intermediate_freqk_hz,
+                                      tuner_freq_offset, true);
        if (status < 0)
                goto error;
 
        /* Setup BER measurement */
-       status = SetQAMMeasurement(state, state->m_Constellation, state->props.symbol_rate);
+       status = set_qam_measurement(state, state->m_constellation,
+                                    state->props.symbol_rate);
        if (status < 0)
                goto error;
 
@@ -5605,7 +5625,8 @@ static int SetQAM(struct drxk_state *state, u16 IntermediateFreqkHz,
                goto error;
 
        /* Mirroring, QAM-block starting point not inverted */
-       status = write16(state, QAM_SY_SP_INV__A, QAM_SY_SP_INV_SPECTRUM_INV_DIS);
+       status = write16(state, QAM_SY_SP_INV__A,
+                        QAM_SY_SP_INV_SPECTRUM_INV_DIS);
        if (status < 0)
                goto error;
 
@@ -5617,20 +5638,20 @@ static int SetQAM(struct drxk_state *state, u16 IntermediateFreqkHz,
        /* STEP 4: modulation specific setup */
        switch (state->props.modulation) {
        case QAM_16:
-               status = SetQAM16(state);
+               status = set_qam16(state);
                break;
        case QAM_32:
-               status = SetQAM32(state);
+               status = set_qam32(state);
                break;
        case QAM_AUTO:
        case QAM_64:
-               status = SetQAM64(state);
+               status = set_qam64(state);
                break;
        case QAM_128:
-               status = SetQAM128(state);
+               status = set_qam128(state);
                break;
        case QAM_256:
-               status = SetQAM256(state);
+               status = set_qam256(state);
                break;
        default:
                status = -EINVAL;
@@ -5647,12 +5668,12 @@ static int SetQAM(struct drxk_state *state, u16 IntermediateFreqkHz,
        /* Re-configure MPEG output, requires knowledge of channel bitrate */
        /* extAttr->currentChannel.modulation = channel->modulation; */
        /* extAttr->currentChannel.symbolrate    = channel->symbolrate; */
-       status = MPEGTSDtoSetup(state, state->m_OperationMode);
+       status = mpegts_dto_setup(state, state->m_operation_mode);
        if (status < 0)
                goto error;
 
-       /* Start processes */
-       status = MPEGTSStart(state);
+       /* start processes */
+       status = mpegts_start(state);
        if (status < 0)
                goto error;
        status = write16(state, FEC_COMM_EXEC__A, FEC_COMM_EXEC_ACTIVE);
@@ -5666,7 +5687,9 @@ static int SetQAM(struct drxk_state *state, u16 IntermediateFreqkHz,
                goto error;
 
        /* STEP 5: start QAM demodulator (starts FEC, QAM and IQM HW) */
-       status = scu_command(state, SCU_RAM_COMMAND_STANDARD_QAM | SCU_RAM_COMMAND_CMD_DEMOD_START, 0, NULL, 1, &cmdResult);
+       status = scu_command(state, SCU_RAM_COMMAND_STANDARD_QAM
+                            | SCU_RAM_COMMAND_CMD_DEMOD_START,
+                            0, NULL, 1, &cmd_result);
        if (status < 0)
                goto error;
 
@@ -5675,12 +5698,12 @@ static int SetQAM(struct drxk_state *state, u16 IntermediateFreqkHz,
 
 error:
        if (status < 0)
-               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+               pr_err("Error %d on %s\n", status, __func__);
        return status;
 }
 
-static int SetQAMStandard(struct drxk_state *state,
-                         enum OperationMode oMode)
+static int set_qam_standard(struct drxk_state *state,
+                         enum operation_mode o_mode)
 {
        int status;
 #ifdef DRXK_QAM_TAPS
@@ -5692,14 +5715,14 @@ static int SetQAMStandard(struct drxk_state *state,
        dprintk(1, "\n");
 
        /* added antenna switch */
-       SwitchAntennaToQAM(state);
+       switch_antenna_to_qam(state);
 
        /* Ensure correct power-up mode */
-       status = PowerUpQAM(state);
+       status = power_up_qam(state);
        if (status < 0)
                goto error;
        /* Reset QAM block */
-       status = QAMResetQAM(state);
+       status = qam_reset_qam(state);
        if (status < 0)
                goto error;
 
@@ -5714,15 +5737,24 @@ static int SetQAMStandard(struct drxk_state *state,
 
        /* Upload IQM Channel Filter settings by
                boot loader from ROM table */
-       switch (oMode) {
+       switch (o_mode) {
        case OM_QAM_ITU_A:
-               status = BLChainCmd(state, DRXK_BL_ROM_OFFSET_TAPS_ITU_A, DRXK_BLCC_NR_ELEMENTS_TAPS, DRXK_BLC_TIMEOUT);
+               status = bl_chain_cmd(state, DRXK_BL_ROM_OFFSET_TAPS_ITU_A,
+                                     DRXK_BLCC_NR_ELEMENTS_TAPS,
+                       DRXK_BLC_TIMEOUT);
                break;
        case OM_QAM_ITU_C:
-               status = BLDirectCmd(state, IQM_CF_TAP_RE0__A, DRXK_BL_ROM_OFFSET_TAPS_ITU_C, DRXK_BLDC_NR_ELEMENTS_TAPS, DRXK_BLC_TIMEOUT);
+               status = bl_direct_cmd(state, IQM_CF_TAP_RE0__A,
+                                      DRXK_BL_ROM_OFFSET_TAPS_ITU_C,
+                                      DRXK_BLDC_NR_ELEMENTS_TAPS,
+                                      DRXK_BLC_TIMEOUT);
                if (status < 0)
                        goto error;
-               status = BLDirectCmd(state, IQM_CF_TAP_IM0__A, DRXK_BL_ROM_OFFSET_TAPS_ITU_C, DRXK_BLDC_NR_ELEMENTS_TAPS, DRXK_BLC_TIMEOUT);
+               status = bl_direct_cmd(state,
+                                      IQM_CF_TAP_IM0__A,
+                                      DRXK_BL_ROM_OFFSET_TAPS_ITU_C,
+                                      DRXK_BLDC_NR_ELEMENTS_TAPS,
+                                      DRXK_BLC_TIMEOUT);
                break;
        default:
                status = -EINVAL;
@@ -5730,13 +5762,14 @@ static int SetQAMStandard(struct drxk_state *state,
        if (status < 0)
                goto error;
 
-       status = write16(state, IQM_CF_OUT_ENA__A, (1 << IQM_CF_OUT_ENA_QAM__B));
+       status = write16(state, IQM_CF_OUT_ENA__A, 1 << IQM_CF_OUT_ENA_QAM__B);
        if (status < 0)
                goto error;
        status = write16(state, IQM_CF_SYMMETRIC__A, 0);
        if (status < 0)
                goto error;
-       status = write16(state, IQM_CF_MIDTAP__A, ((1 << IQM_CF_MIDTAP_RE__B) | (1 << IQM_CF_MIDTAP_IM__B)));
+       status = write16(state, IQM_CF_MIDTAP__A,
+                    ((1 << IQM_CF_MIDTAP_RE__B) | (1 << IQM_CF_MIDTAP_IM__B)));
        if (status < 0)
                goto error;
 
@@ -5793,7 +5826,7 @@ static int SetQAMStandard(struct drxk_state *state,
                goto error;
 
        /* turn on IQMAF. Must be done before setAgc**() */
-       status = SetIqmAf(state, true);
+       status = set_iqm_af(state, true);
        if (status < 0)
                goto error;
        status = write16(state, IQM_AF_START_LOCK__A, 0x01);
@@ -5801,7 +5834,7 @@ static int SetQAMStandard(struct drxk_state *state,
                goto error;
 
        /* IQM will not be reset from here, sync ADC and update/init AGC */
-       status = ADCSynchronization(state);
+       status = adc_synchronization(state);
        if (status < 0)
                goto error;
 
@@ -5818,18 +5851,18 @@ static int SetQAMStandard(struct drxk_state *state,
        /* No more resets of the IQM, current standard correctly set =>
                now AGCs can be configured. */
 
-       status = InitAGC(state, true);
+       status = init_agc(state, true);
        if (status < 0)
                goto error;
-       status = SetPreSaw(state, &(state->m_qamPreSawCfg));
+       status = set_pre_saw(state, &(state->m_qam_pre_saw_cfg));
        if (status < 0)
                goto error;
 
        /* Configure AGC's */
-       status = SetAgcRf(state, &(state->m_qamRfAgcCfg), true);
+       status = set_agc_rf(state, &(state->m_qam_rf_agc_cfg), true);
        if (status < 0)
                goto error;
-       status = SetAgcIf(state, &(state->m_qamIfAgcCfg), true);
+       status = set_agc_if(state, &(state->m_qam_if_agc_cfg), true);
        if (status < 0)
                goto error;
 
@@ -5837,18 +5870,19 @@ static int SetQAMStandard(struct drxk_state *state,
        status = write16(state, SCU_COMM_EXEC__A, SCU_COMM_EXEC_ACTIVE);
 error:
        if (status < 0)
-               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+               pr_err("Error %d on %s\n", status, __func__);
        return status;
 }
 
-static int WriteGPIO(struct drxk_state *state)
+static int write_gpio(struct drxk_state *state)
 {
        int status;
        u16 value = 0;
 
        dprintk(1, "\n");
        /* stop lock indicator process */
-       status = write16(state, SCU_RAM_GPIO__A, SCU_RAM_GPIO_HW_LOCK_IND_DISABLE);
+       status = write16(state, SCU_RAM_GPIO__A,
+                        SCU_RAM_GPIO_HW_LOCK_IND_DISABLE);
        if (status < 0)
                goto error;
 
@@ -5857,10 +5891,11 @@ static int WriteGPIO(struct drxk_state *state)
        if (status < 0)
                goto error;
 
-       if (state->m_hasSAWSW) {
-               if (state->UIO_mask & 0x0001) { /* UIO-1 */
+       if (state->m_has_sawsw) {
+               if (state->uio_mask & 0x0001) { /* UIO-1 */
                        /* write to io pad configuration register - output mode */
-                       status = write16(state, SIO_PDR_SMA_TX_CFG__A, state->m_GPIOCfg);
+                       status = write16(state, SIO_PDR_SMA_TX_CFG__A,
+                                        state->m_gpio_cfg);
                        if (status < 0)
                                goto error;
 
@@ -5868,7 +5903,7 @@ static int WriteGPIO(struct drxk_state *state)
                        status = read16(state, SIO_PDR_UIO_OUT_LO__A, &value);
                        if (status < 0)
                                goto error;
-                       if ((state->m_GPIO & 0x0001) == 0)
+                       if ((state->m_gpio & 0x0001) == 0)
                                value &= 0x7FFF;        /* write zero to 15th bit - 1st UIO */
                        else
                                value |= 0x8000;        /* write one to 15th bit - 1st UIO */
@@ -5877,9 +5912,10 @@ static int WriteGPIO(struct drxk_state *state)
                        if (status < 0)
                                goto error;
                }
-               if (state->UIO_mask & 0x0002) { /* UIO-2 */
+               if (state->uio_mask & 0x0002) { /* UIO-2 */
                        /* write to io pad configuration register - output mode */
-                       status = write16(state, SIO_PDR_SMA_RX_CFG__A, state->m_GPIOCfg);
+                       status = write16(state, SIO_PDR_SMA_RX_CFG__A,
+                                        state->m_gpio_cfg);
                        if (status < 0)
                                goto error;
 
@@ -5887,7 +5923,7 @@ static int WriteGPIO(struct drxk_state *state)
                        status = read16(state, SIO_PDR_UIO_OUT_LO__A, &value);
                        if (status < 0)
                                goto error;
-                       if ((state->m_GPIO & 0x0002) == 0)
+                       if ((state->m_gpio & 0x0002) == 0)
                                value &= 0xBFFF;        /* write zero to 14th bit - 2st UIO */
                        else
                                value |= 0x4000;        /* write one to 14th bit - 2st UIO */
@@ -5896,9 +5932,10 @@ static int WriteGPIO(struct drxk_state *state)
                        if (status < 0)
                                goto error;
                }
-               if (state->UIO_mask & 0x0004) { /* UIO-3 */
+               if (state->uio_mask & 0x0004) { /* UIO-3 */
                        /* write to io pad configuration register - output mode */
-                       status = write16(state, SIO_PDR_GPIO_CFG__A, state->m_GPIOCfg);
+                       status = write16(state, SIO_PDR_GPIO_CFG__A,
+                                        state->m_gpio_cfg);
                        if (status < 0)
                                goto error;
 
@@ -5906,7 +5943,7 @@ static int WriteGPIO(struct drxk_state *state)
                        status = read16(state, SIO_PDR_UIO_OUT_LO__A, &value);
                        if (status < 0)
                                goto error;
-                       if ((state->m_GPIO & 0x0004) == 0)
+                       if ((state->m_gpio & 0x0004) == 0)
                                value &= 0xFFFB;            /* write zero to 2nd bit - 3rd UIO */
                        else
                                value |= 0x0004;            /* write one to 2nd bit - 3rd UIO */
@@ -5920,11 +5957,11 @@ static int WriteGPIO(struct drxk_state *state)
        status = write16(state, SIO_TOP_COMM_KEY__A, 0x0000);
 error:
        if (status < 0)
-               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+               pr_err("Error %d on %s\n", status, __func__);
        return status;
 }
 
-static int SwitchAntennaToQAM(struct drxk_state *state)
+static int switch_antenna_to_qam(struct drxk_state *state)
 {
        int status = 0;
        bool gpio_state;
@@ -5934,22 +5971,22 @@ static int SwitchAntennaToQAM(struct drxk_state *state)
        if (!state->antenna_gpio)
                return 0;
 
-       gpio_state = state->m_GPIO & state->antenna_gpio;
+       gpio_state = state->m_gpio & state->antenna_gpio;
 
        if (state->antenna_dvbt ^ gpio_state) {
                /* Antenna is on DVB-T mode. Switch */
                if (state->antenna_dvbt)
-                       state->m_GPIO &= ~state->antenna_gpio;
+                       state->m_gpio &= ~state->antenna_gpio;
                else
-                       state->m_GPIO |= state->antenna_gpio;
-               status = WriteGPIO(state);
+                       state->m_gpio |= state->antenna_gpio;
+               status = write_gpio(state);
        }
        if (status < 0)
-               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+               pr_err("Error %d on %s\n", status, __func__);
        return status;
 }
 
-static int SwitchAntennaToDVBT(struct drxk_state *state)
+static int switch_antenna_to_dvbt(struct drxk_state *state)
 {
        int status = 0;
        bool gpio_state;
@@ -5959,23 +5996,23 @@ static int SwitchAntennaToDVBT(struct drxk_state *state)
        if (!state->antenna_gpio)
                return 0;
 
-       gpio_state = state->m_GPIO & state->antenna_gpio;
+       gpio_state = state->m_gpio & state->antenna_gpio;
 
        if (!(state->antenna_dvbt ^ gpio_state)) {
                /* Antenna is on DVB-C mode. Switch */
                if (state->antenna_dvbt)
-                       state->m_GPIO |= state->antenna_gpio;
+                       state->m_gpio |= state->antenna_gpio;
                else
-                       state->m_GPIO &= ~state->antenna_gpio;
-               status = WriteGPIO(state);
+                       state->m_gpio &= ~state->antenna_gpio;
+               status = write_gpio(state);
        }
        if (status < 0)
-               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+               pr_err("Error %d on %s\n", status, __func__);
        return status;
 }
 
 
-static int PowerDownDevice(struct drxk_state *state)
+static int power_down_device(struct drxk_state *state)
 {
        /* Power down to requested mode */
        /* Backup some register settings */
@@ -5986,28 +6023,29 @@ static int PowerDownDevice(struct drxk_state *state)
        int status;
 
        dprintk(1, "\n");
-       if (state->m_bPDownOpenBridge) {
+       if (state->m_b_p_down_open_bridge) {
                /* Open I2C bridge before power down of DRXK */
                status = ConfigureI2CBridge(state, true);
                if (status < 0)
                        goto error;
        }
        /* driver 0.9.0 */
-       status = DVBTEnableOFDMTokenRing(state, false);
+       status = dvbt_enable_ofdm_token_ring(state, false);
        if (status < 0)
                goto error;
 
-       status = write16(state, SIO_CC_PWD_MODE__A, SIO_CC_PWD_MODE_LEVEL_CLOCK);
+       status = write16(state, SIO_CC_PWD_MODE__A,
+                        SIO_CC_PWD_MODE_LEVEL_CLOCK);
        if (status < 0)
                goto error;
        status = write16(state, SIO_CC_UPDATE__A, SIO_CC_UPDATE_KEY);
        if (status < 0)
                goto error;
-       state->m_HICfgCtrl |= SIO_HI_RA_RAM_PAR_5_CFG_SLEEP_ZZZ;
-       status = HI_CfgCommand(state);
+       state->m_hi_cfg_ctrl |= SIO_HI_RA_RAM_PAR_5_CFG_SLEEP_ZZZ;
+       status = hi_cfg_command(state);
 error:
        if (status < 0)
-               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+               pr_err("Error %d on %s\n", status, __func__);
 
        return status;
 }
@@ -6015,50 +6053,56 @@ error:
 static int init_drxk(struct drxk_state *state)
 {
        int status = 0, n = 0;
-       enum DRXPowerMode powerMode = DRXK_POWER_DOWN_OFDM;
-       u16 driverVersion;
+       enum drx_power_mode power_mode = DRXK_POWER_DOWN_OFDM;
+       u16 driver_version;
 
        dprintk(1, "\n");
-       if ((state->m_DrxkState == DRXK_UNINITIALIZED)) {
+       if ((state->m_drxk_state == DRXK_UNINITIALIZED)) {
                drxk_i2c_lock(state);
-               status = PowerUpDevice(state);
+               status = power_up_device(state);
                if (status < 0)
                        goto error;
-               status = DRXX_Open(state);
+               status = drxx_open(state);
                if (status < 0)
                        goto error;
                /* Soft reset of OFDM-, sys- and osc-clockdomain */
-               status = write16(state, SIO_CC_SOFT_RST__A, SIO_CC_SOFT_RST_OFDM__M | SIO_CC_SOFT_RST_SYS__M | SIO_CC_SOFT_RST_OSC__M);
+               status = write16(state, SIO_CC_SOFT_RST__A,
+                                SIO_CC_SOFT_RST_OFDM__M
+                                | SIO_CC_SOFT_RST_SYS__M
+                                | SIO_CC_SOFT_RST_OSC__M);
                if (status < 0)
                        goto error;
                status = write16(state, SIO_CC_UPDATE__A, SIO_CC_UPDATE_KEY);
                if (status < 0)
                        goto error;
-               /* TODO is this needed, if yes how much delay in worst case scenario */
-               msleep(1);
-               state->m_DRXK_A3_PATCH_CODE = true;
-               status = GetDeviceCapabilities(state);
+               /*
+                * TODO is this needed? If yes, how much delay in
+                * worst case scenario
+                */
+               usleep_range(1000, 2000);
+               state->m_drxk_a3_patch_code = true;
+               status = get_device_capabilities(state);
                if (status < 0)
                        goto error;
 
                /* Bridge delay, uses oscilator clock */
                /* Delay = (delay (nano seconds) * oscclk (kHz))/ 1000 */
                /* SDA brdige delay */
-               state->m_HICfgBridgeDelay =
-                       (u16) ((state->m_oscClockFreq / 1000) *
+               state->m_hi_cfg_bridge_delay =
+                       (u16) ((state->m_osc_clock_freq / 1000) *
                                HI_I2C_BRIDGE_DELAY) / 1000;
                /* Clipping */
-               if (state->m_HICfgBridgeDelay >
+               if (state->m_hi_cfg_bridge_delay >
                        SIO_HI_RA_RAM_PAR_3_CFG_DBL_SDA__M) {
-                       state->m_HICfgBridgeDelay =
+                       state->m_hi_cfg_bridge_delay =
                                SIO_HI_RA_RAM_PAR_3_CFG_DBL_SDA__M;
                }
                /* SCL bridge delay, same as SDA for now */
-               state->m_HICfgBridgeDelay +=
-                       state->m_HICfgBridgeDelay <<
+               state->m_hi_cfg_bridge_delay +=
+                       state->m_hi_cfg_bridge_delay <<
                        SIO_HI_RA_RAM_PAR_3_CFG_DBL_SCL__B;
 
-               status = InitHI(state);
+               status = init_hi(state);
                if (status < 0)
                        goto error;
                /* disable various processes */
@@ -6067,13 +6111,14 @@ static int init_drxk(struct drxk_state *state)
                        && !(state->m_DRXK_A2_ROM_CODE))
 #endif
                {
-                       status = write16(state, SCU_RAM_GPIO__A, SCU_RAM_GPIO_HW_LOCK_IND_DISABLE);
+                       status = write16(state, SCU_RAM_GPIO__A,
+                                        SCU_RAM_GPIO_HW_LOCK_IND_DISABLE);
                        if (status < 0)
                                goto error;
                }
 
                /* disable MPEG port */
-               status = MPEGTSDisable(state);
+               status = mpegts_disable(state);
                if (status < 0)
                        goto error;
 
@@ -6086,27 +6131,30 @@ static int init_drxk(struct drxk_state *state)
                        goto error;
 
                /* enable token-ring bus through OFDM block for possible ucode upload */
-               status = write16(state, SIO_OFDM_SH_OFDM_RING_ENABLE__A, SIO_OFDM_SH_OFDM_RING_ENABLE_ON);
+               status = write16(state, SIO_OFDM_SH_OFDM_RING_ENABLE__A,
+                                SIO_OFDM_SH_OFDM_RING_ENABLE_ON);
                if (status < 0)
                        goto error;
 
                /* include boot loader section */
-               status = write16(state, SIO_BL_COMM_EXEC__A, SIO_BL_COMM_EXEC_ACTIVE);
+               status = write16(state, SIO_BL_COMM_EXEC__A,
+                                SIO_BL_COMM_EXEC_ACTIVE);
                if (status < 0)
                        goto error;
-               status = BLChainCmd(state, 0, 6, 100);
+               status = bl_chain_cmd(state, 0, 6, 100);
                if (status < 0)
                        goto error;
 
                if (state->fw) {
-                       status = DownloadMicrocode(state, state->fw->data,
+                       status = download_microcode(state, state->fw->data,
                                                   state->fw->size);
                        if (status < 0)
                                goto error;
                }
 
                /* disable token-ring bus through OFDM block for possible ucode upload */
-               status = write16(state, SIO_OFDM_SH_OFDM_RING_ENABLE__A, SIO_OFDM_SH_OFDM_RING_ENABLE_OFF);
+               status = write16(state, SIO_OFDM_SH_OFDM_RING_ENABLE__A,
+                                SIO_OFDM_SH_OFDM_RING_ENABLE_OFF);
                if (status < 0)
                        goto error;
 
@@ -6114,14 +6162,14 @@ static int init_drxk(struct drxk_state *state)
                status = write16(state, SCU_COMM_EXEC__A, SCU_COMM_EXEC_ACTIVE);
                if (status < 0)
                        goto error;
-               status = DRXX_Open(state);
+               status = drxx_open(state);
                if (status < 0)
                        goto error;
                /* added for test */
                msleep(30);
 
-               powerMode = DRXK_POWER_DOWN_OFDM;
-               status = CtrlPowerMode(state, &powerMode);
+               power_mode = DRXK_POWER_DOWN_OFDM;
+               status = ctrl_power_mode(state, &power_mode);
                if (status < 0)
                        goto error;
 
@@ -6131,33 +6179,38 @@ static int init_drxk(struct drxk_state *state)
                        Not using SCU command interface for SCU register access since no
                        microcode may be present.
                        */
-               driverVersion =
+               driver_version =
                        (((DRXK_VERSION_MAJOR / 100) % 10) << 12) +
                        (((DRXK_VERSION_MAJOR / 10) % 10) << 8) +
                        ((DRXK_VERSION_MAJOR % 10) << 4) +
                        (DRXK_VERSION_MINOR % 10);
-               status = write16(state, SCU_RAM_DRIVER_VER_HI__A, driverVersion);
+               status = write16(state, SCU_RAM_DRIVER_VER_HI__A,
+                                driver_version);
                if (status < 0)
                        goto error;
-               driverVersion =
+               driver_version =
                        (((DRXK_VERSION_PATCH / 1000) % 10) << 12) +
                        (((DRXK_VERSION_PATCH / 100) % 10) << 8) +
                        (((DRXK_VERSION_PATCH / 10) % 10) << 4) +
                        (DRXK_VERSION_PATCH % 10);
-               status = write16(state, SCU_RAM_DRIVER_VER_LO__A, driverVersion);
+               status = write16(state, SCU_RAM_DRIVER_VER_LO__A,
+                                driver_version);
                if (status < 0)
                        goto error;
 
-               printk(KERN_INFO "DRXK driver version %d.%d.%d\n",
+               pr_info("DRXK driver version %d.%d.%d\n",
                        DRXK_VERSION_MAJOR, DRXK_VERSION_MINOR,
                        DRXK_VERSION_PATCH);
 
-               /* Dirty fix of default values for ROM/PATCH microcode
-                       Dirty because this fix makes it impossible to setup suitable values
-                       before calling DRX_Open. This solution requires changes to RF AGC speed
-                       to be done via the CTRL function after calling DRX_Open */
+               /*
+                * Dirty fix of default values for ROM/PATCH microcode
+                * Dirty because this fix makes it impossible to setup
+                * suitable values before calling DRX_Open. This solution
+                * requires changes to RF AGC speed to be done via the CTRL
+                * function after calling DRX_Open
+                */
 
-               /* m_dvbtRfAgcCfg.speed = 3; */
+               /* m_dvbt_rf_agc_cfg.speed = 3; */
 
                /* Reset driver debug flags to 0 */
                status = write16(state, SCU_RAM_DRIVER_DEBUG__A, 0);
@@ -6170,42 +6223,42 @@ static int init_drxk(struct drxk_state *state)
                if (status < 0)
                        goto error;
                /* MPEGTS functions are still the same */
-               status = MPEGTSDtoInit(state);
+               status = mpegts_dto_init(state);
                if (status < 0)
                        goto error;
-               status = MPEGTSStop(state);
+               status = mpegts_stop(state);
                if (status < 0)
                        goto error;
-               status = MPEGTSConfigurePolarity(state);
+               status = mpegts_configure_polarity(state);
                if (status < 0)
                        goto error;
-               status = MPEGTSConfigurePins(state, state->m_enableMPEGOutput);
+               status = mpegts_configure_pins(state, state->m_enable_mpeg_output);
                if (status < 0)
                        goto error;
                /* added: configure GPIO */
-               status = WriteGPIO(state);
+               status = write_gpio(state);
                if (status < 0)
                        goto error;
 
-               state->m_DrxkState = DRXK_STOPPED;
+               state->m_drxk_state = DRXK_STOPPED;
 
-               if (state->m_bPowerDown) {
-                       status = PowerDownDevice(state);
+               if (state->m_b_power_down) {
+                       status = power_down_device(state);
                        if (status < 0)
                                goto error;
-                       state->m_DrxkState = DRXK_POWERED_DOWN;
+                       state->m_drxk_state = DRXK_POWERED_DOWN;
                } else
-                       state->m_DrxkState = DRXK_STOPPED;
+                       state->m_drxk_state = DRXK_STOPPED;
 
                /* Initialize the supported delivery systems */
                n = 0;
-               if (state->m_hasDVBC) {
+               if (state->m_has_dvbc) {
                        state->frontend.ops.delsys[n++] = SYS_DVBC_ANNEX_A;
                        state->frontend.ops.delsys[n++] = SYS_DVBC_ANNEX_C;
                        strlcat(state->frontend.ops.info.name, " DVB-C",
                                sizeof(state->frontend.ops.info.name));
                }
-               if (state->m_hasDVBT) {
+               if (state->m_has_dvbt) {
                        state->frontend.ops.delsys[n++] = SYS_DVBT;
                        strlcat(state->frontend.ops.info.name, " DVB-T",
                                sizeof(state->frontend.ops.info.name));
@@ -6214,9 +6267,9 @@ static int init_drxk(struct drxk_state *state)
        }
 error:
        if (status < 0) {
-               state->m_DrxkState = DRXK_NO_DEV;
+               state->m_drxk_state = DRXK_NO_DEV;
                drxk_i2c_unlock(state);
-               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+               pr_err("Error %d on %s\n", status, __func__);
        }
 
        return status;
@@ -6229,11 +6282,9 @@ static void load_firmware_cb(const struct firmware *fw,
 
        dprintk(1, ": %s\n", fw ? "firmware loaded" : "firmware not loaded");
        if (!fw) {
-               printk(KERN_ERR
-                      "drxk: Could not load firmware file %s.\n",
+               pr_err("Could not load firmware file %s.\n",
                        state->microcode_name);
-               printk(KERN_INFO
-                      "drxk: Copy %s to your hotplug directory!\n",
+               pr_info("Copy %s to your hotplug directory!\n",
                        state->microcode_name);
                state->microcode_name = NULL;
 
@@ -6270,12 +6321,12 @@ static int drxk_sleep(struct dvb_frontend *fe)
 
        dprintk(1, "\n");
 
-       if (state->m_DrxkState == DRXK_NO_DEV)
+       if (state->m_drxk_state == DRXK_NO_DEV)
                return -ENODEV;
-       if (state->m_DrxkState == DRXK_UNINITIALIZED)
+       if (state->m_drxk_state == DRXK_UNINITIALIZED)
                return 0;
 
-       ShutDown(state);
+       shut_down(state);
        return 0;
 }
 
@@ -6285,7 +6336,7 @@ static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable)
 
        dprintk(1, ": %s\n", enable ? "enable" : "disable");
 
-       if (state->m_DrxkState == DRXK_NO_DEV)
+       if (state->m_drxk_state == DRXK_NO_DEV)
                return -ENODEV;
 
        return ConfigureI2CBridge(state, enable ? true : false);
@@ -6300,15 +6351,14 @@ static int drxk_set_parameters(struct dvb_frontend *fe)
 
        dprintk(1, "\n");
 
-       if (state->m_DrxkState == DRXK_NO_DEV)
+       if (state->m_drxk_state == DRXK_NO_DEV)
                return -ENODEV;
 
-       if (state->m_DrxkState == DRXK_UNINITIALIZED)
+       if (state->m_drxk_state == DRXK_UNINITIALIZED)
                return -EAGAIN;
 
        if (!fe->ops.tuner_ops.get_if_frequency) {
-               printk(KERN_ERR
-                      "drxk: Error: get_if_frequency() not defined at tuner. Can't work without it!\n");
+               pr_err("Error: get_if_frequency() not defined at tuner. Can't work without it!\n");
                return -EINVAL;
        }
 
@@ -6323,22 +6373,23 @@ static int drxk_set_parameters(struct dvb_frontend *fe)
        state->props = *p;
 
        if (old_delsys != delsys) {
-               ShutDown(state);
+               shut_down(state);
                switch (delsys) {
                case SYS_DVBC_ANNEX_A:
                case SYS_DVBC_ANNEX_C:
-                       if (!state->m_hasDVBC)
+                       if (!state->m_has_dvbc)
                                return -EINVAL;
-                       state->m_itut_annex_c = (delsys == SYS_DVBC_ANNEX_C) ? true : false;
+                       state->m_itut_annex_c = (delsys == SYS_DVBC_ANNEX_C) ?
+                                               true : false;
                        if (state->m_itut_annex_c)
-                               SetOperationMode(state, OM_QAM_ITU_C);
+                               setoperation_mode(state, OM_QAM_ITU_C);
                        else
-                               SetOperationMode(state, OM_QAM_ITU_A);
+                               setoperation_mode(state, OM_QAM_ITU_A);
                        break;
                case SYS_DVBT:
-                       if (!state->m_hasDVBT)
+                       if (!state->m_has_dvbt)
                                return -EINVAL;
-                       SetOperationMode(state, OM_DVBT);
+                       setoperation_mode(state, OM_DVBT);
                        break;
                default:
                        return -EINVAL;
@@ -6346,7 +6397,7 @@ static int drxk_set_parameters(struct dvb_frontend *fe)
        }
 
        fe->ops.tuner_ops.get_if_frequency(fe, &IF);
-       Start(state, 0, IF);
+       start(state, 0, IF);
 
        /* After set_frontend, stats aren't avaliable */
        p->strength.stat[0].scale = FE_SCALE_RELATIVE;
@@ -6366,31 +6417,31 @@ static int drxk_set_parameters(struct dvb_frontend *fe)
 static int get_strength(struct drxk_state *state, u64 *strength)
 {
        int status;
-       struct SCfgAgc   rfAgc, ifAgc;
-       u32          totalGain  = 0;
+       struct s_cfg_agc   rf_agc, if_agc;
+       u32          total_gain  = 0;
        u32          atten      = 0;
-       u32          agcRange   = 0;
+       u32          agc_range   = 0;
        u16            scu_lvl  = 0;
        u16            scu_coc  = 0;
        /* FIXME: those are part of the tuner presets */
-       u16 tunerRfGain         = 50; /* Default value on az6007 driver */
-       u16 tunerIfGain         = 40; /* Default value on az6007 driver */
+       u16 tuner_rf_gain         = 50; /* Default value on az6007 driver */
+       u16 tuner_if_gain         = 40; /* Default value on az6007 driver */
 
        *strength = 0;
 
-       if (IsDVBT(state)) {
-               rfAgc = state->m_dvbtRfAgcCfg;
-               ifAgc = state->m_dvbtIfAgcCfg;
-       } else if (IsQAM(state)) {
-               rfAgc = state->m_qamRfAgcCfg;
-               ifAgc = state->m_qamIfAgcCfg;
+       if (is_dvbt(state)) {
+               rf_agc = state->m_dvbt_rf_agc_cfg;
+               if_agc = state->m_dvbt_if_agc_cfg;
+       } else if (is_qam(state)) {
+               rf_agc = state->m_qam_rf_agc_cfg;
+               if_agc = state->m_qam_if_agc_cfg;
        } else {
-               rfAgc = state->m_atvRfAgcCfg;
-               ifAgc = state->m_atvIfAgcCfg;
+               rf_agc = state->m_atv_rf_agc_cfg;
+               if_agc = state->m_atv_if_agc_cfg;
        }
 
-       if (rfAgc.ctrlMode == DRXK_AGC_CTRL_AUTO) {
-               /* SCU outputLevel */
+       if (rf_agc.ctrl_mode == DRXK_AGC_CTRL_AUTO) {
+               /* SCU output_level */
                status = read16(state, SCU_RAM_AGC_RF_IACCU_HI__A, &scu_lvl);
                if (status < 0)
                        return status;
@@ -6401,54 +6452,54 @@ static int get_strength(struct drxk_state *state, u64 *strength)
                        return status;
 
                if (((u32) scu_lvl + (u32) scu_coc) < 0xffff)
-                       rfAgc.outputLevel = scu_lvl + scu_coc;
+                       rf_agc.output_level = scu_lvl + scu_coc;
                else
-                       rfAgc.outputLevel = 0xffff;
+                       rf_agc.output_level = 0xffff;
 
                /* Take RF gain into account */
-               totalGain += tunerRfGain;
+               total_gain += tuner_rf_gain;
 
                /* clip output value */
-               if (rfAgc.outputLevel < rfAgc.minOutputLevel)
-                       rfAgc.outputLevel = rfAgc.minOutputLevel;
-               if (rfAgc.outputLevel > rfAgc.maxOutputLevel)
-                       rfAgc.outputLevel = rfAgc.maxOutputLevel;
+               if (rf_agc.output_level < rf_agc.min_output_level)
+                       rf_agc.output_level = rf_agc.min_output_level;
+               if (rf_agc.output_level > rf_agc.max_output_level)
+                       rf_agc.output_level = rf_agc.max_output_level;
 
-               agcRange = (u32) (rfAgc.maxOutputLevel - rfAgc.minOutputLevel);
-               if (agcRange > 0) {
+               agc_range = (u32) (rf_agc.max_output_level - rf_agc.min_output_level);
+               if (agc_range > 0) {
                        atten += 100UL *
-                               ((u32)(tunerRfGain)) *
-                               ((u32)(rfAgc.outputLevel - rfAgc.minOutputLevel))
-                               / agcRange;
+                               ((u32)(tuner_rf_gain)) *
+                               ((u32)(rf_agc.output_level - rf_agc.min_output_level))
+                               / agc_range;
                }
        }
 
-       if (ifAgc.ctrlMode == DRXK_AGC_CTRL_AUTO) {
+       if (if_agc.ctrl_mode == DRXK_AGC_CTRL_AUTO) {
                status = read16(state, SCU_RAM_AGC_IF_IACCU_HI__A,
-                               &ifAgc.outputLevel);
+                               &if_agc.output_level);
                if (status < 0)
                        return status;
 
                status = read16(state, SCU_RAM_AGC_INGAIN_TGT_MIN__A,
-                               &ifAgc.top);
+                               &if_agc.top);
                if (status < 0)
                        return status;
 
                /* Take IF gain into account */
-               totalGain += (u32) tunerIfGain;
+               total_gain += (u32) tuner_if_gain;
 
                /* clip output value */
-               if (ifAgc.outputLevel < ifAgc.minOutputLevel)
-                       ifAgc.outputLevel = ifAgc.minOutputLevel;
-               if (ifAgc.outputLevel > ifAgc.maxOutputLevel)
-                       ifAgc.outputLevel = ifAgc.maxOutputLevel;
+               if (if_agc.output_level < if_agc.min_output_level)
+                       if_agc.output_level = if_agc.min_output_level;
+               if (if_agc.output_level > if_agc.max_output_level)
+                       if_agc.output_level = if_agc.max_output_level;
 
-               agcRange  = (u32) (ifAgc.maxOutputLevel - ifAgc.minOutputLevel);
-               if (agcRange > 0) {
+               agc_range  = (u32)(if_agc.max_output_level - if_agc.min_output_level);
+               if (agc_range > 0) {
                        atten += 100UL *
-                               ((u32)(tunerIfGain)) *
-                               ((u32)(ifAgc.outputLevel - ifAgc.minOutputLevel))
-                               / agcRange;
+                               ((u32)(tuner_if_gain)) *
+                               ((u32)(if_agc.output_level - if_agc.min_output_level))
+                               / agc_range;
                }
        }
 
@@ -6456,8 +6507,8 @@ static int get_strength(struct drxk_state *state, u64 *strength)
         * Convert to 0..65535 scale.
         * If it can't be measured (AGC is disabled), just show 100%.
         */
-       if (totalGain > 0)
-               *strength = (65535UL * atten / totalGain / 100);
+       if (total_gain > 0)
+               *strength = (65535UL * atten / total_gain / 100);
        else
                *strength = 65535;
 
@@ -6480,14 +6531,14 @@ static int drxk_get_stats(struct dvb_frontend *fe)
        u32 pkt_error_count;
        s32 cnr;
 
-       if (state->m_DrxkState == DRXK_NO_DEV)
+       if (state->m_drxk_state == DRXK_NO_DEV)
                return -ENODEV;
-       if (state->m_DrxkState == DRXK_UNINITIALIZED)
+       if (state->m_drxk_state == DRXK_UNINITIALIZED)
                return -EAGAIN;
 
        /* get status */
        state->fe_status = 0;
-       GetLockStatus(state, &stat);
+       get_lock_status(state, &stat);
        if (stat == MPEG_LOCK)
                state->fe_status |= 0x1f;
        if (stat == FEC_LOCK)
@@ -6503,7 +6554,7 @@ static int drxk_get_stats(struct dvb_frontend *fe)
 
 
        if (stat >= DEMOD_LOCK) {
-               GetSignalToNoise(state, &cnr);
+               get_signal_to_noise(state, &cnr);
                c->cnr.stat[0].svalue = cnr * 100;
                c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
        } else {
@@ -6524,9 +6575,11 @@ static int drxk_get_stats(struct dvb_frontend *fe)
 
        /* BER measurement is valid if at least FEC lock is achieved */
 
-       /* OFDM_EC_VD_REQ_SMB_CNT__A and/or OFDM_EC_VD_REQ_BIT_CNT can be written
-               to set nr of symbols or bits over which
-               to measure EC_VD_REG_ERR_BIT_CNT__A . See CtrlSetCfg(). */
+       /*
+        * OFDM_EC_VD_REQ_SMB_CNT__A and/or OFDM_EC_VD_REQ_BIT_CNT can be
+        * written to set nr of symbols or bits over which to measure
+        * EC_VD_REG_ERR_BIT_CNT__A . See CtrlSetCfg().
+        */
 
        /* Read registers for post/preViterbi BER calculation */
        status = read16(state, OFDM_EC_VD_ERR_BIT_CNT__A, &reg16);
@@ -6610,9 +6663,9 @@ static int drxk_read_signal_strength(struct dvb_frontend *fe,
 
        dprintk(1, "\n");
 
-       if (state->m_DrxkState == DRXK_NO_DEV)
+       if (state->m_drxk_state == DRXK_NO_DEV)
                return -ENODEV;
-       if (state->m_DrxkState == DRXK_UNINITIALIZED)
+       if (state->m_drxk_state == DRXK_UNINITIALIZED)
                return -EAGAIN;
 
        *strength = c->strength.stat[0].uvalue;
@@ -6626,12 +6679,12 @@ static int drxk_read_snr(struct dvb_frontend *fe, u16 *snr)
 
        dprintk(1, "\n");
 
-       if (state->m_DrxkState == DRXK_NO_DEV)
+       if (state->m_drxk_state == DRXK_NO_DEV)
                return -ENODEV;
-       if (state->m_DrxkState == DRXK_UNINITIALIZED)
+       if (state->m_drxk_state == DRXK_UNINITIALIZED)
                return -EAGAIN;
 
-       GetSignalToNoise(state, &snr2);
+       get_signal_to_noise(state, &snr2);
 
        /* No negative SNR, clip to zero */
        if (snr2 < 0)
@@ -6647,27 +6700,27 @@ static int drxk_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
 
        dprintk(1, "\n");
 
-       if (state->m_DrxkState == DRXK_NO_DEV)
+       if (state->m_drxk_state == DRXK_NO_DEV)
                return -ENODEV;
-       if (state->m_DrxkState == DRXK_UNINITIALIZED)
+       if (state->m_drxk_state == DRXK_UNINITIALIZED)
                return -EAGAIN;
 
-       DVBTQAMGetAccPktErr(state, &err);
+       dvbtqam_get_acc_pkt_err(state, &err);
        *ucblocks = (u32) err;
        return 0;
 }
 
-static int drxk_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings
-                                   *sets)
+static int drxk_get_tune_settings(struct dvb_frontend *fe,
+                                 struct dvb_frontend_tune_settings *sets)
 {
        struct drxk_state *state = fe->demodulator_priv;
        struct dtv_frontend_properties *p = &fe->dtv_property_cache;
 
        dprintk(1, "\n");
 
-       if (state->m_DrxkState == DRXK_NO_DEV)
+       if (state->m_drxk_state == DRXK_NO_DEV)
                return -ENODEV;
-       if (state->m_DrxkState == DRXK_UNINITIALIZED)
+       if (state->m_drxk_state == DRXK_UNINITIALIZED)
                return -EAGAIN;
 
        switch (p->delivery_system) {
@@ -6737,36 +6790,36 @@ struct dvb_frontend *drxk_attach(const struct drxk_config *config,
        state->no_i2c_bridge = config->no_i2c_bridge;
        state->antenna_gpio = config->antenna_gpio;
        state->antenna_dvbt = config->antenna_dvbt;
-       state->m_ChunkSize = config->chunk_size;
+       state->m_chunk_size = config->chunk_size;
        state->enable_merr_cfg = config->enable_merr_cfg;
 
        if (config->dynamic_clk) {
-               state->m_DVBTStaticCLK = 0;
-               state->m_DVBCStaticCLK = 0;
+               state->m_dvbt_static_clk = 0;
+               state->m_dvbc_static_clk = 0;
        } else {
-               state->m_DVBTStaticCLK = 1;
-               state->m_DVBCStaticCLK = 1;
+               state->m_dvbt_static_clk = 1;
+               state->m_dvbc_static_clk = 1;
        }
 
 
        if (config->mpeg_out_clk_strength)
-               state->m_TSClockkStrength = config->mpeg_out_clk_strength & 0x07;
+               state->m_ts_clockk_strength = config->mpeg_out_clk_strength & 0x07;
        else
-               state->m_TSClockkStrength = 0x06;
+               state->m_ts_clockk_strength = 0x06;
 
        if (config->parallel_ts)
-               state->m_enableParallel = true;
+               state->m_enable_parallel = true;
        else
-               state->m_enableParallel = false;
+               state->m_enable_parallel = false;
 
        /* NOTE: as more UIO bits will be used, add them to the mask */
-       state->UIO_mask = config->antenna_gpio;
+       state->uio_mask = config->antenna_gpio;
 
        /* Default gpio to DVB-C */
        if (!state->antenna_dvbt && state->antenna_gpio)
-               state->m_GPIO |= state->antenna_gpio;
+               state->m_gpio |= state->antenna_gpio;
        else
-               state->m_GPIO &= ~state->antenna_gpio;
+               state->m_gpio &= ~state->antenna_gpio;
 
        mutex_init(&state->mutex);
 
@@ -6792,8 +6845,7 @@ struct dvb_frontend *drxk_attach(const struct drxk_config *config,
                                              GFP_KERNEL,
                                              state, load_firmware_cb);
                        if (status < 0) {
-                               printk(KERN_ERR
-                                      "drxk: failed to request a firmware\n");
+                               pr_err("failed to request a firmware\n");
                                return NULL;
                        }
                }
@@ -6821,11 +6873,11 @@ struct dvb_frontend *drxk_attach(const struct drxk_config *config,
        p->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
        p->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
 
-       printk(KERN_INFO "drxk: frontend initialized.\n");
+       pr_info("frontend initialized.\n");
        return &state->frontend;
 
 error:
-       printk(KERN_ERR "drxk: not found\n");
+       pr_err("not found\n");
        kfree(state);
        return NULL;
 }
index b8424f1..bae9c71 100644 (file)
@@ -46,7 +46,7 @@
 #define     IQM_RC_ADJ_SEL_B_QAM                                            0x1
 #define     IQM_RC_ADJ_SEL_B_VSB                                            0x2
 
-enum OperationMode {
+enum operation_mode {
        OM_NONE,
        OM_QAM_ITU_A,
        OM_QAM_ITU_B,
@@ -54,7 +54,7 @@ enum OperationMode {
        OM_DVBT
 };
 
-enum DRXPowerMode {
+enum drx_power_mode {
        DRX_POWER_UP = 0,
        DRX_POWER_MODE_1,
        DRX_POWER_MODE_2,
@@ -77,24 +77,29 @@ enum DRXPowerMode {
 };
 
 
-/** /brief Intermediate power mode for DRXK, power down OFDM clock domain */
+/* Intermediate power mode for DRXK, power down OFDM clock domain */
 #ifndef DRXK_POWER_DOWN_OFDM
 #define DRXK_POWER_DOWN_OFDM        DRX_POWER_MODE_1
 #endif
 
-/** /brief Intermediate power mode for DRXK, power down core (sysclk) */
+/* Intermediate power mode for DRXK, power down core (sysclk) */
 #ifndef DRXK_POWER_DOWN_CORE
 #define DRXK_POWER_DOWN_CORE        DRX_POWER_MODE_9
 #endif
 
-/** /brief Intermediate power mode for DRXK, power down pll (only osc runs) */
+/* Intermediate power mode for DRXK, power down pll (only osc runs) */
 #ifndef DRXK_POWER_DOWN_PLL
 #define DRXK_POWER_DOWN_PLL         DRX_POWER_MODE_10
 #endif
 
 
-enum AGC_CTRL_MODE { DRXK_AGC_CTRL_AUTO = 0, DRXK_AGC_CTRL_USER, DRXK_AGC_CTRL_OFF };
-enum EDrxkState {
+enum agc_ctrl_mode {
+       DRXK_AGC_CTRL_AUTO = 0,
+       DRXK_AGC_CTRL_USER,
+       DRXK_AGC_CTRL_OFF
+};
+
+enum e_drxk_state {
        DRXK_UNINITIALIZED = 0,
        DRXK_STOPPED,
        DRXK_DTV_STARTED,
@@ -103,7 +108,7 @@ enum EDrxkState {
        DRXK_NO_DEV                     /* If drxk init failed */
 };
 
-enum EDrxkCoefArrayIndex {
+enum e_drxk_coef_array_index {
        DRXK_COEF_IDX_MN = 0,
        DRXK_COEF_IDX_FM    ,
        DRXK_COEF_IDX_L     ,
@@ -113,13 +118,13 @@ enum EDrxkCoefArrayIndex {
        DRXK_COEF_IDX_I     ,
        DRXK_COEF_IDX_MAX
 };
-enum EDrxkSifAttenuation {
+enum e_drxk_sif_attenuation {
        DRXK_SIF_ATTENUATION_0DB,
        DRXK_SIF_ATTENUATION_3DB,
        DRXK_SIF_ATTENUATION_6DB,
        DRXK_SIF_ATTENUATION_9DB
 };
-enum EDrxkConstellation {
+enum e_drxk_constellation {
        DRX_CONSTELLATION_BPSK = 0,
        DRX_CONSTELLATION_QPSK,
        DRX_CONSTELLATION_PSK8,
@@ -133,7 +138,7 @@ enum EDrxkConstellation {
        DRX_CONSTELLATION_UNKNOWN = DRX_UNKNOWN,
        DRX_CONSTELLATION_AUTO    = DRX_AUTO
 };
-enum EDrxkInterleaveMode {
+enum e_drxk_interleave_mode {
        DRXK_QAM_I12_J17    = 16,
        DRXK_QAM_I_UNKNOWN  = DRX_UNKNOWN
 };
@@ -144,14 +149,14 @@ enum {
        DRXK_SPIN_UNKNOWN
 };
 
-enum DRXKCfgDvbtSqiSpeed {
+enum drxk_cfg_dvbt_sqi_speed {
        DRXK_DVBT_SQI_SPEED_FAST = 0,
        DRXK_DVBT_SQI_SPEED_MEDIUM,
        DRXK_DVBT_SQI_SPEED_SLOW,
        DRXK_DVBT_SQI_SPEED_UNKNOWN = DRX_UNKNOWN
 } ;
 
-enum DRXFftmode_t {
+enum drx_fftmode_t {
        DRX_FFTMODE_2K = 0,
        DRX_FFTMODE_4K,
        DRX_FFTMODE_8K,
@@ -159,47 +164,47 @@ enum DRXFftmode_t {
        DRX_FFTMODE_AUTO    = DRX_AUTO
 };
 
-enum DRXMPEGStrWidth_t {
+enum drxmpeg_str_width_t {
        DRX_MPEG_STR_WIDTH_1,
        DRX_MPEG_STR_WIDTH_8
 };
 
-enum DRXQamLockRange_t {
+enum drx_qam_lock_range_t {
        DRX_QAM_LOCKRANGE_NORMAL,
        DRX_QAM_LOCKRANGE_EXTENDED
 };
 
-struct DRXKCfgDvbtEchoThres_t {
+struct drxk_cfg_dvbt_echo_thres_t {
        u16             threshold;
-       enum DRXFftmode_t      fftMode;
+       enum drx_fftmode_t      fft_mode;
 } ;
 
-struct SCfgAgc {
-       enum AGC_CTRL_MODE     ctrlMode;        /* off, user, auto */
-       u16            outputLevel;     /* range dependent on AGC */
-       u16            minOutputLevel;  /* range dependent on AGC */
-       u16            maxOutputLevel;  /* range dependent on AGC */
+struct s_cfg_agc {
+       enum agc_ctrl_mode     ctrl_mode;        /* off, user, auto */
+       u16            output_level;     /* range dependent on AGC */
+       u16            min_output_level;  /* range dependent on AGC */
+       u16            max_output_level;  /* range dependent on AGC */
        u16            speed;           /* range dependent on AGC */
        u16            top;             /* rf-agc take over point */
-       u16            cutOffCurrent;   /* rf-agc is accelerated if output current
+       u16            cut_off_current;   /* rf-agc is accelerated if output current
                                           is below cut-off current */
-       u16            IngainTgtMax;
-       u16            FastClipCtrlDelay;
+       u16            ingain_tgt_max;
+       u16            fast_clip_ctrl_delay;
 };
 
-struct SCfgPreSaw {
+struct s_cfg_pre_saw {
        u16        reference; /* pre SAW reference value, range 0 .. 31 */
-       bool          usePreSaw; /* TRUE algorithms must use pre SAW sense */
+       bool          use_pre_saw; /* TRUE algorithms must use pre SAW sense */
 };
 
-struct DRXKOfdmScCmd_t {
-       u16 cmd;        /**< Command number */
-       u16 subcmd;     /**< Sub-command parameter*/
-       u16 param0;     /**< General purpous param */
-       u16 param1;     /**< General purpous param */
-       u16 param2;     /**< General purpous param */
-       u16 param3;     /**< General purpous param */
-       u16 param4;     /**< General purpous param */
+struct drxk_ofdm_sc_cmd_t {
+       u16 cmd;        /* Command number */
+       u16 subcmd;     /* Sub-command parameter*/
+       u16 param0;     /* General purpous param */
+       u16 param1;     /* General purpous param */
+       u16 param2;     /* General purpous param */
+       u16 param3;     /* General purpous param */
+       u16 param4;     /* General purpous param */
 };
 
 struct drxk_state {
@@ -213,121 +218,121 @@ struct drxk_state {
 
        struct mutex mutex;
 
-       u32    m_Instance;           /**< Channel 1,2,3 or 4 */
-
-       int    m_ChunkSize;
-       u8 Chunk[256];
-
-       bool   m_hasLNA;
-       bool   m_hasDVBT;
-       bool   m_hasDVBC;
-       bool   m_hasAudio;
-       bool   m_hasATV;
-       bool   m_hasOOB;
-       bool   m_hasSAWSW;         /**< TRUE if mat_tx is available */
-       bool   m_hasGPIO1;         /**< TRUE if mat_rx is available */
-       bool   m_hasGPIO2;         /**< TRUE if GPIO is available */
-       bool   m_hasIRQN;          /**< TRUE if IRQN is available */
-       u16    m_oscClockFreq;
-       u16    m_HICfgTimingDiv;
-       u16    m_HICfgBridgeDelay;
-       u16    m_HICfgWakeUpKey;
-       u16    m_HICfgTimeout;
-       u16    m_HICfgCtrl;
-       s32    m_sysClockFreq;      /**< system clock frequency in kHz */
-
-       enum EDrxkState    m_DrxkState;      /**< State of Drxk (init,stopped,started) */
-       enum OperationMode m_OperationMode;  /**< digital standards */
-       struct SCfgAgc     m_vsbRfAgcCfg;    /**< settings for VSB RF-AGC */
-       struct SCfgAgc     m_vsbIfAgcCfg;    /**< settings for VSB IF-AGC */
-       u16                m_vsbPgaCfg;      /**< settings for VSB PGA */
-       struct SCfgPreSaw  m_vsbPreSawCfg;   /**< settings for pre SAW sense */
-       s32    m_Quality83percent;  /**< MER level (*0.1 dB) for 83% quality indication */
-       s32    m_Quality93percent;  /**< MER level (*0.1 dB) for 93% quality indication */
-       bool   m_smartAntInverted;
-       bool   m_bDebugEnableBridge;
-       bool   m_bPDownOpenBridge;  /**< only open DRXK bridge before power-down once it has been accessed */
-       bool   m_bPowerDown;        /**< Power down when not used */
-
-       u32    m_IqmFsRateOfs;      /**< frequency shift as written to DRXK register (28bit fixpoint) */
-
-       bool   m_enableMPEGOutput;  /**< If TRUE, enable MPEG output */
-       bool   m_insertRSByte;      /**< If TRUE, insert RS byte */
-       bool   m_enableParallel;    /**< If TRUE, parallel out otherwise serial */
-       bool   m_invertDATA;        /**< If TRUE, invert DATA signals */
-       bool   m_invertERR;         /**< If TRUE, invert ERR signal */
-       bool   m_invertSTR;         /**< If TRUE, invert STR signals */
-       bool   m_invertVAL;         /**< If TRUE, invert VAL signals */
-       bool   m_invertCLK;         /**< If TRUE, invert CLK signals */
-       bool   m_DVBCStaticCLK;
-       bool   m_DVBTStaticCLK;     /**< If TRUE, static MPEG clockrate will
+       u32    m_instance;           /* Channel 1,2,3 or 4 */
+
+       int    m_chunk_size;
+       u8 chunk[256];
+
+       bool   m_has_lna;
+       bool   m_has_dvbt;
+       bool   m_has_dvbc;
+       bool   m_has_audio;
+       bool   m_has_atv;
+       bool   m_has_oob;
+       bool   m_has_sawsw;         /* TRUE if mat_tx is available */
+       bool   m_has_gpio1;         /* TRUE if mat_rx is available */
+       bool   m_has_gpio2;         /* TRUE if GPIO is available */
+       bool   m_has_irqn;          /* TRUE if IRQN is available */
+       u16    m_osc_clock_freq;
+       u16    m_hi_cfg_timing_div;
+       u16    m_hi_cfg_bridge_delay;
+       u16    m_hi_cfg_wake_up_key;
+       u16    m_hi_cfg_timeout;
+       u16    m_hi_cfg_ctrl;
+       s32    m_sys_clock_freq;      /* system clock frequency in kHz */
+
+       enum e_drxk_state    m_drxk_state;      /* State of Drxk (init,stopped,started) */
+       enum operation_mode m_operation_mode;  /* digital standards */
+       struct s_cfg_agc     m_vsb_rf_agc_cfg;    /* settings for VSB RF-AGC */
+       struct s_cfg_agc     m_vsb_if_agc_cfg;    /* settings for VSB IF-AGC */
+       u16                m_vsb_pga_cfg;      /* settings for VSB PGA */
+       struct s_cfg_pre_saw  m_vsb_pre_saw_cfg;   /* settings for pre SAW sense */
+       s32    m_Quality83percent;  /* MER level (*0.1 dB) for 83% quality indication */
+       s32    m_Quality93percent;  /* MER level (*0.1 dB) for 93% quality indication */
+       bool   m_smart_ant_inverted;
+       bool   m_b_debug_enable_bridge;
+       bool   m_b_p_down_open_bridge;  /* only open DRXK bridge before power-down once it has been accessed */
+       bool   m_b_power_down;        /* Power down when not used */
+
+       u32    m_iqm_fs_rate_ofs;      /* frequency shift as written to DRXK register (28bit fixpoint) */
+
+       bool   m_enable_mpeg_output;  /* If TRUE, enable MPEG output */
+       bool   m_insert_rs_byte;      /* If TRUE, insert RS byte */
+       bool   m_enable_parallel;    /* If TRUE, parallel out otherwise serial */
+       bool   m_invert_data;        /* If TRUE, invert DATA signals */
+       bool   m_invert_err;         /* If TRUE, invert ERR signal */
+       bool   m_invert_str;         /* If TRUE, invert STR signals */
+       bool   m_invert_val;         /* If TRUE, invert VAL signals */
+       bool   m_invert_clk;         /* If TRUE, invert CLK signals */
+       bool   m_dvbc_static_clk;
+       bool   m_dvbt_static_clk;     /* If TRUE, static MPEG clockrate will
                                         be used, otherwise clockrate will
                                         adapt to the bitrate of the TS */
-       u32    m_DVBTBitrate;
-       u32    m_DVBCBitrate;
+       u32    m_dvbt_bitrate;
+       u32    m_dvbc_bitrate;
 
-       u8     m_TSDataStrength;
-       u8     m_TSClockkStrength;
+       u8     m_ts_data_strength;
+       u8     m_ts_clockk_strength;
 
        bool   m_itut_annex_c;      /* If true, uses ITU-T DVB-C Annex C, instead of Annex A */
 
-       enum DRXMPEGStrWidth_t  m_widthSTR;    /**< MPEG start width */
-       u32    m_mpegTsStaticBitrate;          /**< Maximum bitrate in b/s in case
+       enum drxmpeg_str_width_t  m_width_str;    /* MPEG start width */
+       u32    m_mpeg_ts_static_bitrate;          /* Maximum bitrate in b/s in case
                                                    static clockrate is selected */
 
-       /* LARGE_INTEGER   m_StartTime; */     /**< Contains the time of the last demod start */
-       s32    m_MpegLockTimeOut;      /**< WaitForLockStatus Timeout (counts from start time) */
-       s32    m_DemodLockTimeOut;     /**< WaitForLockStatus Timeout (counts from start time) */
-
-       bool   m_disableTEIhandling;
-
-       bool   m_RfAgcPol;
-       bool   m_IfAgcPol;
-
-       struct SCfgAgc    m_atvRfAgcCfg;  /**< settings for ATV RF-AGC */
-       struct SCfgAgc    m_atvIfAgcCfg;  /**< settings for ATV IF-AGC */
-       struct SCfgPreSaw m_atvPreSawCfg; /**< settings for ATV pre SAW sense */
-       bool              m_phaseCorrectionBypass;
-       s16               m_atvTopVidPeak;
-       u16               m_atvTopNoiseTh;
-       enum EDrxkSifAttenuation m_sifAttenuation;
-       bool              m_enableCVBSOutput;
-       bool              m_enableSIFOutput;
-       bool              m_bMirrorFreqSpect;
-       enum EDrxkConstellation  m_Constellation; /**< Constellation type of the channel */
-       u32               m_CurrSymbolRate;       /**< Current QAM symbol rate */
-       struct SCfgAgc    m_qamRfAgcCfg;          /**< settings for QAM RF-AGC */
-       struct SCfgAgc    m_qamIfAgcCfg;          /**< settings for QAM IF-AGC */
-       u16               m_qamPgaCfg;            /**< settings for QAM PGA */
-       struct SCfgPreSaw m_qamPreSawCfg;         /**< settings for QAM pre SAW sense */
-       enum EDrxkInterleaveMode m_qamInterleaveMode; /**< QAM Interleave mode */
-       u16               m_fecRsPlen;
-       u16               m_fecRsPrescale;
-
-       enum DRXKCfgDvbtSqiSpeed m_sqiSpeed;
-
-       u16               m_GPIO;
-       u16               m_GPIOCfg;
-
-       struct SCfgAgc    m_dvbtRfAgcCfg;     /**< settings for QAM RF-AGC */
-       struct SCfgAgc    m_dvbtIfAgcCfg;     /**< settings for QAM IF-AGC */
-       struct SCfgPreSaw m_dvbtPreSawCfg;    /**< settings for QAM pre SAW sense */
-
-       u16               m_agcFastClipCtrlDelay;
-       bool              m_adcCompPassed;
+       /* LARGE_INTEGER   m_startTime; */     /* Contains the time of the last demod start */
+       s32    m_mpeg_lock_time_out;      /* WaitForLockStatus Timeout (counts from start time) */
+       s32    m_demod_lock_time_out;     /* WaitForLockStatus Timeout (counts from start time) */
+
+       bool   m_disable_te_ihandling;
+
+       bool   m_rf_agc_pol;
+       bool   m_if_agc_pol;
+
+       struct s_cfg_agc    m_atv_rf_agc_cfg;  /* settings for ATV RF-AGC */
+       struct s_cfg_agc    m_atv_if_agc_cfg;  /* settings for ATV IF-AGC */
+       struct s_cfg_pre_saw m_atv_pre_saw_cfg; /* settings for ATV pre SAW sense */
+       bool              m_phase_correction_bypass;
+       s16               m_atv_top_vid_peak;
+       u16               m_atv_top_noise_th;
+       enum e_drxk_sif_attenuation m_sif_attenuation;
+       bool              m_enable_cvbs_output;
+       bool              m_enable_sif_output;
+       bool              m_b_mirror_freq_spect;
+       enum e_drxk_constellation  m_constellation; /* constellation type of the channel */
+       u32               m_curr_symbol_rate;       /* Current QAM symbol rate */
+       struct s_cfg_agc    m_qam_rf_agc_cfg;          /* settings for QAM RF-AGC */
+       struct s_cfg_agc    m_qam_if_agc_cfg;          /* settings for QAM IF-AGC */
+       u16               m_qam_pga_cfg;            /* settings for QAM PGA */
+       struct s_cfg_pre_saw m_qam_pre_saw_cfg;         /* settings for QAM pre SAW sense */
+       enum e_drxk_interleave_mode m_qam_interleave_mode; /* QAM Interleave mode */
+       u16               m_fec_rs_plen;
+       u16               m_fec_rs_prescale;
+
+       enum drxk_cfg_dvbt_sqi_speed m_sqi_speed;
+
+       u16               m_gpio;
+       u16               m_gpio_cfg;
+
+       struct s_cfg_agc    m_dvbt_rf_agc_cfg;     /* settings for QAM RF-AGC */
+       struct s_cfg_agc    m_dvbt_if_agc_cfg;     /* settings for QAM IF-AGC */
+       struct s_cfg_pre_saw m_dvbt_pre_saw_cfg;    /* settings for QAM pre SAW sense */
+
+       u16               m_agcfast_clip_ctrl_delay;
+       bool              m_adc_comp_passed;
        u16               m_adcCompCoef[64];
-       u16               m_adcState;
+       u16               m_adc_state;
 
        u8               *m_microcode;
        int               m_microcode_length;
-       bool              m_DRXK_A3_ROM_CODE;
-       bool              m_DRXK_A3_PATCH_CODE;
+       bool              m_drxk_a3_rom_code;
+       bool              m_drxk_a3_patch_code;
 
        bool              m_rfmirror;
-       u8                m_deviceSpin;
-       u32               m_iqmRcRate;
+       u8                m_device_spin;
+       u32               m_iqm_rc_rate;
 
-       enum DRXPowerMode m_currentPowerMode;
+       enum drx_power_mode m_current_power_mode;
 
        /* when true, avoids other devices to use the I2C bus */
        bool              drxk_i2c_exclusive_lock;
@@ -337,7 +342,7 @@ struct drxk_state {
         * at struct drxk_config.
         */
 
-       u16     UIO_mask;       /* Bits used by UIO */
+       u16     uio_mask;       /* Bits used by UIO */
 
        bool    enable_merr_cfg;
        bool    single_master;
index 117a569..93596e0 100644 (file)
@@ -226,8 +226,8 @@ static enum stb0899_status stb0899_search_tmg(struct stb0899_state *state)
                        next_loop--;
 
                if (next_loop) {
-                       STB0899_SETFIELD_VAL(CFRM, cfr[0], MSB(state->config->inversion * derot_freq));
-                       STB0899_SETFIELD_VAL(CFRL, cfr[1], LSB(state->config->inversion * derot_freq));
+                       STB0899_SETFIELD_VAL(CFRM, cfr[0], MSB(internal->inversion * derot_freq));
+                       STB0899_SETFIELD_VAL(CFRL, cfr[1], LSB(internal->inversion * derot_freq));
                        stb0899_write_regs(state, STB0899_CFRM, cfr, 2); /* derotator frequency         */
                }
                internal->direction = -internal->direction;     /* Change zigzag direction              */
@@ -235,7 +235,7 @@ static enum stb0899_status stb0899_search_tmg(struct stb0899_state *state)
 
        if (internal->status == TIMINGOK) {
                stb0899_read_regs(state, STB0899_CFRM, cfr, 2); /* get derotator frequency              */
-               internal->derot_freq = state->config->inversion * MAKEWORD16(cfr[0], cfr[1]);
+               internal->derot_freq = internal->inversion * MAKEWORD16(cfr[0], cfr[1]);
                dprintk(state->verbose, FE_DEBUG, 1, "------->TIMING OK ! Derot Freq = %d", internal->derot_freq);
        }
 
@@ -306,8 +306,8 @@ static enum stb0899_status stb0899_search_carrier(struct stb0899_state *state)
                                STB0899_SETFIELD_VAL(CFD_ON, reg, 1);
                                stb0899_write_reg(state, STB0899_CFD, reg);
 
-                               STB0899_SETFIELD_VAL(CFRM, cfr[0], MSB(state->config->inversion * derot_freq));
-                               STB0899_SETFIELD_VAL(CFRL, cfr[1], LSB(state->config->inversion * derot_freq));
+                               STB0899_SETFIELD_VAL(CFRM, cfr[0], MSB(internal->inversion * derot_freq));
+                               STB0899_SETFIELD_VAL(CFRL, cfr[1], LSB(internal->inversion * derot_freq));
                                stb0899_write_regs(state, STB0899_CFRM, cfr, 2); /* derotator frequency */
                        }
                }
@@ -317,7 +317,7 @@ static enum stb0899_status stb0899_search_carrier(struct stb0899_state *state)
 
        if (internal->status == CARRIEROK) {
                stb0899_read_regs(state, STB0899_CFRM, cfr, 2); /* get derotator frequency */
-               internal->derot_freq = state->config->inversion * MAKEWORD16(cfr[0], cfr[1]);
+               internal->derot_freq = internal->inversion * MAKEWORD16(cfr[0], cfr[1]);
                dprintk(state->verbose, FE_DEBUG, 1, "----> CARRIER OK !, Derot Freq=%d", internal->derot_freq);
        } else {
                internal->derot_freq = last_derot_freq;
@@ -412,8 +412,8 @@ static enum stb0899_status stb0899_search_data(struct stb0899_state *state)
                                STB0899_SETFIELD_VAL(CFD_ON, reg, 1);
                                stb0899_write_reg(state, STB0899_CFD, reg);
 
-                               STB0899_SETFIELD_VAL(CFRM, cfr[0], MSB(state->config->inversion * derot_freq));
-                               STB0899_SETFIELD_VAL(CFRL, cfr[1], LSB(state->config->inversion * derot_freq));
+                               STB0899_SETFIELD_VAL(CFRM, cfr[0], MSB(internal->inversion * derot_freq));
+                               STB0899_SETFIELD_VAL(CFRL, cfr[1], LSB(internal->inversion * derot_freq));
                                stb0899_write_regs(state, STB0899_CFRM, cfr, 2); /* derotator frequency */
 
                                stb0899_check_carrier(state);
@@ -425,7 +425,15 @@ static enum stb0899_status stb0899_search_data(struct stb0899_state *state)
 
        if (internal->status == DATAOK) {
                stb0899_read_regs(state, STB0899_CFRM, cfr, 2); /* get derotator frequency */
-               internal->derot_freq = state->config->inversion * MAKEWORD16(cfr[0], cfr[1]);
+
+               /* store autodetected IQ swapping as default for DVB-S2 tuning */
+               reg = stb0899_read_reg(state, STB0899_IQSWAP);
+               if (STB0899_GETFIELD(SYM, reg))
+                       internal->inversion = IQ_SWAP_ON;
+               else
+                       internal->inversion = IQ_SWAP_OFF;
+
+               internal->derot_freq = internal->inversion * MAKEWORD16(cfr[0], cfr[1]);
                dprintk(state->verbose, FE_DEBUG, 1, "------> DATAOK ! Derot Freq=%d", internal->derot_freq);
        }
 
@@ -444,7 +452,7 @@ static enum stb0899_status stb0899_check_range(struct stb0899_state *state)
        int range_offst, tp_freq;
 
        range_offst = internal->srch_range / 2000;
-       tp_freq = internal->freq + (internal->derot_freq * internal->mclk) / 1000;
+       tp_freq = internal->freq - (internal->derot_freq * internal->mclk) / 1000;
 
        if ((tp_freq >= params->freq - range_offst) && (tp_freq <= params->freq + range_offst)) {
                internal->status = RANGEOK;
@@ -638,7 +646,7 @@ enum stb0899_status stb0899_dvbs_algo(struct stb0899_state *state)
                                                        "RANGE OK ! derot freq=%d, mclk=%d",
                                                        internal->derot_freq, internal->mclk);
 
-                                               internal->freq = params->freq + ((internal->derot_freq * internal->mclk) / 1000);
+                                               internal->freq = params->freq - ((internal->derot_freq * internal->mclk) / 1000);
                                                reg = stb0899_read_reg(state, STB0899_PLPARM);
                                                internal->fecrate = STB0899_GETFIELD(VITCURPUN, reg);
                                                dprintk(state->verbose, FE_DEBUG, 1,
@@ -1373,9 +1381,6 @@ enum stb0899_status stb0899_dvbs2_algo(struct stb0899_state *state)
        case IQ_SWAP_ON:
                STB0899_SETFIELD_VAL(SPECTRUM_INVERT, reg, 1);
                break;
-       case IQ_SWAP_AUTO:      /* use last successful search first     */
-               STB0899_SETFIELD_VAL(SPECTRUM_INVERT, reg, 1);
-               break;
        }
        stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_DMD_CNTRL2, STB0899_OFF0_DMD_CNTRL2, reg);
        stb0899_dvbs2_reacquire(state);
@@ -1405,41 +1410,39 @@ enum stb0899_status stb0899_dvbs2_algo(struct stb0899_state *state)
        }
 
        if (internal->status != DVBS2_FEC_LOCK) {
-               if (internal->inversion == IQ_SWAP_AUTO) {
-                       reg = STB0899_READ_S2REG(STB0899_S2DEMOD, DMD_CNTRL2);
-                       iqSpectrum = STB0899_GETFIELD(SPECTRUM_INVERT, reg);
-                       /* IQ Spectrum Inversion        */
-                       STB0899_SETFIELD_VAL(SPECTRUM_INVERT, reg, !iqSpectrum);
-                       stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_DMD_CNTRL2, STB0899_OFF0_DMD_CNTRL2, reg);
-                       /* start acquistion process     */
-                       stb0899_dvbs2_reacquire(state);
+               reg = STB0899_READ_S2REG(STB0899_S2DEMOD, DMD_CNTRL2);
+               iqSpectrum = STB0899_GETFIELD(SPECTRUM_INVERT, reg);
+               /* IQ Spectrum Inversion        */
+               STB0899_SETFIELD_VAL(SPECTRUM_INVERT, reg, !iqSpectrum);
+               stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_DMD_CNTRL2, STB0899_OFF0_DMD_CNTRL2, reg);
+               /* start acquistion process     */
+               stb0899_dvbs2_reacquire(state);
+
+               /* Wait for demod lock (UWP and CSM)    */
+               internal->status = stb0899_dvbs2_get_dmd_status(state, searchTime);
+               if (internal->status == DVBS2_DEMOD_LOCK) {
+                       i = 0;
+                       /* Demod Locked, check FEC      */
+                       internal->status = stb0899_dvbs2_get_fec_status(state, FecLockTime);
+                       /*try thrice for false locks, (UWP and CSM Locked but no FEC)   */
+                       while ((internal->status != DVBS2_FEC_LOCK) && (i < 3)) {
+                               /*      Read the frequency offset*/
+                               offsetfreq = STB0899_READ_S2REG(STB0899_S2DEMOD, CRL_FREQ);
 
-                       /* Wait for demod lock (UWP and CSM)    */
-                       internal->status = stb0899_dvbs2_get_dmd_status(state, searchTime);
-                       if (internal->status == DVBS2_DEMOD_LOCK) {
-                               i = 0;
-                               /* Demod Locked, check FEC      */
-                               internal->status = stb0899_dvbs2_get_fec_status(state, FecLockTime);
-                               /*try thrice for false locks, (UWP and CSM Locked but no FEC)   */
-                               while ((internal->status != DVBS2_FEC_LOCK) && (i < 3)) {
-                                       /*      Read the frequency offset*/
-                                       offsetfreq = STB0899_READ_S2REG(STB0899_S2DEMOD, CRL_FREQ);
-
-                                       /* Set the Nominal frequency to the found frequency offset for the next reacquire*/
-                                       reg = STB0899_READ_S2REG(STB0899_S2DEMOD, CRL_NOM_FREQ);
-                                       STB0899_SETFIELD_VAL(CRL_NOM_FREQ, reg, offsetfreq);
-                                       stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CRL_NOM_FREQ, STB0899_OFF0_CRL_NOM_FREQ, reg);
-
-                                       stb0899_dvbs2_reacquire(state);
-                                       internal->status = stb0899_dvbs2_get_fec_status(state, searchTime);
-                                       i++;
-                               }
+                               /* Set the Nominal frequency to the found frequency offset for the next reacquire*/
+                               reg = STB0899_READ_S2REG(STB0899_S2DEMOD, CRL_NOM_FREQ);
+                               STB0899_SETFIELD_VAL(CRL_NOM_FREQ, reg, offsetfreq);
+                               stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CRL_NOM_FREQ, STB0899_OFF0_CRL_NOM_FREQ, reg);
+
+                               stb0899_dvbs2_reacquire(state);
+                               internal->status = stb0899_dvbs2_get_fec_status(state, searchTime);
+                               i++;
                        }
+               }
 /*
-                       if (pParams->DVBS2State == FE_DVBS2_FEC_LOCKED)
-                               pParams->IQLocked = !iqSpectrum;
+               if (pParams->DVBS2State == FE_DVBS2_FEC_LOCKED)
+                       pParams->IQLocked = !iqSpectrum;
 */
-               }
        }
        if (internal->status == DVBS2_FEC_LOCK) {
                dprintk(state->verbose, FE_DEBUG, 1, "----------------> DVB-S2 FEC Lock !");
@@ -1487,13 +1490,21 @@ enum stb0899_status stb0899_dvbs2_algo(struct stb0899_state *state)
                /* Store signal parameters      */
                offsetfreq = STB0899_READ_S2REG(STB0899_S2DEMOD, CRL_FREQ);
 
+               /* sign extend 30 bit value before using it in calculations */
+               if (offsetfreq & (1 << 29))
+                       offsetfreq |= -1 << 30;
+
                offsetfreq = offsetfreq / ((1 << 30) / 1000);
                offsetfreq *= (internal->master_clk / 1000000);
+
+               /* store current inversion for next run */
                reg = STB0899_READ_S2REG(STB0899_S2DEMOD, DMD_CNTRL2);
                if (STB0899_GETFIELD(SPECTRUM_INVERT, reg))
-                       offsetfreq *= -1;
+                       internal->inversion = IQ_SWAP_ON;
+               else
+                       internal->inversion = IQ_SWAP_OFF;
 
-               internal->freq = internal->freq - offsetfreq;
+               internal->freq = internal->freq + offsetfreq;
                internal->srate = stb0899_dvbs2_get_srate(state);
 
                reg = STB0899_READ_S2REG(STB0899_S2DEMOD, UWP_STAT2);
index cc278b3..3dd5714 100644 (file)
@@ -1618,19 +1618,18 @@ static struct dvb_frontend_ops stb0899_ops = {
 struct dvb_frontend *stb0899_attach(struct stb0899_config *config, struct i2c_adapter *i2c)
 {
        struct stb0899_state *state = NULL;
-       enum stb0899_inversion inversion;
 
        state = kzalloc(sizeof (struct stb0899_state), GFP_KERNEL);
        if (state == NULL)
                goto error;
 
-       inversion                               = config->inversion;
        state->verbose                          = &verbose;
        state->config                           = config;
        state->i2c                              = i2c;
        state->frontend.ops                     = stb0899_ops;
        state->frontend.demodulator_priv        = state;
-       state->internal.inversion               = inversion;
+       /* use configured inversion as default -- we'll later autodetect inversion */
+       state->internal.inversion               = config->inversion;
 
        stb0899_wakeup(&state->frontend);
        if (stb0899_get_dev_id(state) == -ENODEV) {
index 8d26ff6..139264d 100644 (file)
@@ -45,9 +45,8 @@ struct stb0899_s2_reg {
 };
 
 enum stb0899_inversion {
-       IQ_SWAP_OFF     = 0,
-       IQ_SWAP_ON,
-       IQ_SWAP_AUTO
+       IQ_SWAP_OFF     = +1, /* inversion affects the sign of e. g. */
+       IQ_SWAP_ON      = -1, /* the derotator frequency register    */
 };
 
 #define STB0899_GPIO00                         0xf140
index e24ec53..247f0e7 100644 (file)
@@ -248,7 +248,7 @@ static const char * const model_names[] = {
 /* Adjust the template string if models with longer names appear. */
 #define MAX_MODEL_NAME_LEN sizeof("FireDTV ????")
 
-static int node_probe(struct device *dev)
+static int node_probe(struct fw_unit *unit, const struct ieee1394_device_id *id)
 {
        struct firedtv *fdtv;
        char name[MAX_MODEL_NAME_LEN];
@@ -258,8 +258,8 @@ static int node_probe(struct device *dev)
        if (!fdtv)
                return -ENOMEM;
 
-       dev_set_drvdata(dev, fdtv);
-       fdtv->device            = dev;
+       dev_set_drvdata(&unit->device, fdtv);
+       fdtv->device            = &unit->device;
        fdtv->isochannel        = -1;
        fdtv->voltage           = 0xff;
        fdtv->tone              = 0xff;
@@ -269,7 +269,7 @@ static int node_probe(struct device *dev)
        mutex_init(&fdtv->demux_mutex);
        INIT_WORK(&fdtv->remote_ctrl_work, avc_remote_ctrl_work);
 
-       name_len = fw_csr_string(fw_unit(dev)->directory, CSR_MODEL,
+       name_len = fw_csr_string(unit->directory, CSR_MODEL,
                                 name, sizeof(name));
        for (i = ARRAY_SIZE(model_names); --i; )
                if (strlen(model_names[i]) <= name_len &&
@@ -277,7 +277,7 @@ static int node_probe(struct device *dev)
                        break;
        fdtv->type = i;
 
-       err = fdtv_register_rc(fdtv, dev);
+       err = fdtv_register_rc(fdtv, &unit->device);
        if (err)
                goto fail_free;
 
@@ -307,9 +307,9 @@ fail_free:
        return err;
 }
 
-static int node_remove(struct device *dev)
+static void node_remove(struct fw_unit *unit)
 {
-       struct firedtv *fdtv = dev_get_drvdata(dev);
+       struct firedtv *fdtv = dev_get_drvdata(&unit->device);
 
        fdtv_dvb_unregister(fdtv);
 
@@ -320,7 +320,6 @@ static int node_remove(struct device *dev)
        fdtv_unregister_rc(fdtv);
 
        kfree(fdtv);
-       return 0;
 }
 
 static void node_update(struct fw_unit *unit)
@@ -391,10 +390,10 @@ static struct fw_driver fdtv_driver = {
                .owner  = THIS_MODULE,
                .name   = "firedtv",
                .bus    = &fw_bus_type,
-               .probe  = node_probe,
-               .remove = node_remove,
        },
+       .probe    = node_probe,
        .update   = node_update,
+       .remove   = node_remove,
        .id_table = fdtv_id_table,
 };
 
index f981d50..b2cd8ca 100644 (file)
@@ -245,6 +245,15 @@ config VIDEO_KS0127
          To compile this driver as a module, choose M here: the
          module will be called ks0127.
 
+config VIDEO_ML86V7667
+       tristate "OKI ML86V7667 video decoder"
+       depends on VIDEO_V4L2 && I2C
+       ---help---
+         Support for the OKI Semiconductor ML86V7667 video decoder.
+
+         To compile this driver as a module, choose M here: the
+         module will be called ml86v7667.
+
 config VIDEO_SAA7110
        tristate "Philips SAA7110 video decoder"
        depends on VIDEO_V4L2 && I2C
@@ -425,6 +434,15 @@ config VIDEO_AK881X
        help
          Video output driver for AKM AK8813 and AK8814 TV encoders
 
+config VIDEO_THS8200
+       tristate "Texas Instruments THS8200 video encoder"
+       depends on VIDEO_V4L2 && I2C
+       ---help---
+         Support for the Texas Instruments THS8200 video encoder.
+
+         To compile this driver as a module, choose M here: the
+         module will be called ths8200.
+
 comment "Camera sensor devices"
 
 config VIDEO_APTINA_PLL
index 720f42d..dc20653 100644 (file)
@@ -34,6 +34,7 @@ obj-$(CONFIG_VIDEO_BT856) += bt856.o
 obj-$(CONFIG_VIDEO_BT866) += bt866.o
 obj-$(CONFIG_VIDEO_KS0127) += ks0127.o
 obj-$(CONFIG_VIDEO_THS7303) += ths7303.o
+obj-$(CONFIG_VIDEO_THS8200) += ths8200.o
 obj-$(CONFIG_VIDEO_TVP5150) += tvp5150.o
 obj-$(CONFIG_VIDEO_TVP514X) += tvp514x.o
 obj-$(CONFIG_VIDEO_TVP7002) += tvp7002.o
@@ -70,3 +71,4 @@ obj-$(CONFIG_VIDEO_AS3645A)   += as3645a.o
 obj-$(CONFIG_VIDEO_SMIAPP_PLL) += smiapp-pll.o
 obj-$(CONFIG_VIDEO_AK881X)             += ak881x.o
 obj-$(CONFIG_VIDEO_IR_I2C)  += ir-kbd-i2c.o
+obj-$(CONFIG_VIDEO_ML86V7667)  += ml86v7667.o
index 58344b6..ba4364d 100644 (file)
@@ -32,7 +32,6 @@
 #include <linux/workqueue.h>
 #include <linux/v4l2-dv-timings.h>
 #include <media/v4l2-device.h>
-#include <media/v4l2-chip-ident.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-ctrls.h>
 #include <media/ad9389b.h>
@@ -343,12 +342,6 @@ static const struct v4l2_ctrl_ops ad9389b_ctrl_ops = {
 #ifdef CONFIG_VIDEO_ADV_DEBUG
 static int ad9389b_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
 {
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       if (!v4l2_chip_match_i2c_client(client, &reg->match))
-               return -EINVAL;
-       if (!capable(CAP_SYS_ADMIN))
-               return -EPERM;
        reg->val = ad9389b_rd(sd, reg->reg & 0xff);
        reg->size = 1;
        return 0;
@@ -356,24 +349,11 @@ static int ad9389b_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *
 
 static int ad9389b_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg)
 {
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       if (!v4l2_chip_match_i2c_client(client, &reg->match))
-               return -EINVAL;
-       if (!capable(CAP_SYS_ADMIN))
-               return -EPERM;
        ad9389b_wr(sd, reg->reg & 0xff, reg->val & 0xff);
        return 0;
 }
 #endif
 
-static int ad9389b_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_AD9389B, 0);
-}
-
 static int ad9389b_log_status(struct v4l2_subdev *sd)
 {
        struct ad9389b_state *state = get_ad9389b_state(sd);
@@ -600,7 +580,6 @@ static int ad9389b_isr(struct v4l2_subdev *sd, u32 status, bool *handled)
 
 static const struct v4l2_subdev_core_ops ad9389b_core_ops = {
        .log_status = ad9389b_log_status,
-       .g_chip_ident = ad9389b_g_chip_ident,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
        .g_register = ad9389b_g_register,
        .s_register = ad9389b_s_register,
@@ -1188,15 +1167,14 @@ static int ad9389b_probe(struct i2c_client *client, const struct i2c_device_id *
        v4l_dbg(1, debug, client, "detecting ad9389b client on address 0x%x\n",
                        client->addr << 1);
 
-       state = kzalloc(sizeof(struct ad9389b_state), GFP_KERNEL);
+       state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL);
        if (!state)
                return -ENOMEM;
 
        /* Platform data */
        if (pdata == NULL) {
                v4l_err(client, "No platform data!\n");
-               err = -ENODEV;
-               goto err_free;
+               return -ENODEV;
        }
        memcpy(&state->pdata, pdata, sizeof(state->pdata));
 
@@ -1251,12 +1229,14 @@ static int ad9389b_probe(struct i2c_client *client, const struct i2c_device_id *
        state->edid_i2c_client = i2c_new_dummy(client->adapter, (0x7e>>1));
        if (state->edid_i2c_client == NULL) {
                v4l2_err(sd, "failed to register edid i2c client\n");
+               err = -ENOMEM;
                goto err_entity;
        }
 
        state->work_queue = create_singlethread_workqueue(sd->name);
        if (state->work_queue == NULL) {
                v4l2_err(sd, "could not create workqueue\n");
+               err = -ENOMEM;
                goto err_unreg;
        }
 
@@ -1276,8 +1256,6 @@ err_entity:
        media_entity_cleanup(&sd->entity);
 err_hdl:
        v4l2_ctrl_handler_free(&state->hdl);
-err_free:
-       kfree(state);
        return err;
 }
 
@@ -1302,15 +1280,14 @@ static int ad9389b_remove(struct i2c_client *client)
        v4l2_device_unregister_subdev(sd);
        media_entity_cleanup(&sd->entity);
        v4l2_ctrl_handler_free(sd->ctrl_handler);
-       kfree(get_ad9389b_state(sd));
        return 0;
 }
 
 /* ----------------------------------------------------------------------- */
 
 static struct i2c_device_id ad9389b_id[] = {
-       { "ad9389b", V4L2_IDENT_AD9389B },
-       { "ad9889b", V4L2_IDENT_AD9389B },
+       { "ad9389b", 0 },
+       { "ad9889b", 0 },
        { }
 };
 MODULE_DEVICE_TABLE(i2c, ad9389b_id);
index ef75abe..873fe19 100644 (file)
@@ -417,7 +417,7 @@ static int adp1653_probe(struct i2c_client *client,
        if (client->dev.platform_data == NULL)
                return -ENODEV;
 
-       flash = kzalloc(sizeof(*flash), GFP_KERNEL);
+       flash = devm_kzalloc(&client->dev, sizeof(*flash), GFP_KERNEL);
        if (flash == NULL)
                return -ENOMEM;
 
@@ -443,7 +443,6 @@ static int adp1653_probe(struct i2c_client *client,
 
 free_and_quit:
        v4l2_ctrl_handler_free(&flash->ctrls);
-       kfree(flash);
        return ret;
 }
 
@@ -455,7 +454,7 @@ static int adp1653_remove(struct i2c_client *client)
        v4l2_device_unregister_subdev(&flash->subdev);
        v4l2_ctrl_handler_free(&flash->ctrls);
        media_entity_cleanup(&flash->subdev.entity);
-       kfree(flash);
+
        return 0;
 }
 
index 6bc01fb..04bb297 100644 (file)
@@ -36,7 +36,6 @@
 #include <linux/i2c.h>
 #include <linux/videodev2.h>
 #include <media/v4l2-device.h>
-#include <media/v4l2-chip-ident.h>
 
 MODULE_DESCRIPTION("Analog Devices ADV7170 video encoder driver");
 MODULE_AUTHOR("Maxim Yevtyushkin");
@@ -317,19 +316,8 @@ static int adv7170_s_fmt(struct v4l2_subdev *sd,
        return ret;
 }
 
-static int adv7170_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_ADV7170, 0);
-}
-
 /* ----------------------------------------------------------------------- */
 
-static const struct v4l2_subdev_core_ops adv7170_core_ops = {
-       .g_chip_ident = adv7170_g_chip_ident,
-};
-
 static const struct v4l2_subdev_video_ops adv7170_video_ops = {
        .s_std_output = adv7170_s_std_output,
        .s_routing = adv7170_s_routing,
@@ -339,7 +327,6 @@ static const struct v4l2_subdev_video_ops adv7170_video_ops = {
 };
 
 static const struct v4l2_subdev_ops adv7170_ops = {
-       .core = &adv7170_core_ops,
        .video = &adv7170_video_ops,
 };
 
@@ -359,7 +346,7 @@ static int adv7170_probe(struct i2c_client *client,
        v4l_info(client, "chip found @ 0x%x (%s)\n",
                        client->addr << 1, client->adapter->name);
 
-       encoder = kzalloc(sizeof(struct adv7170), GFP_KERNEL);
+       encoder = devm_kzalloc(&client->dev, sizeof(*encoder), GFP_KERNEL);
        if (encoder == NULL)
                return -ENOMEM;
        sd = &encoder->sd;
@@ -384,7 +371,6 @@ static int adv7170_remove(struct i2c_client *client)
        struct v4l2_subdev *sd = i2c_get_clientdata(client);
 
        v4l2_device_unregister_subdev(sd);
-       kfree(to_adv7170(sd));
        return 0;
 }
 
index c7640fa..b88f3b3 100644 (file)
@@ -32,7 +32,6 @@
 #include <linux/i2c.h>
 #include <linux/videodev2.h>
 #include <media/v4l2-device.h>
-#include <media/v4l2-chip-ident.h>
 
 MODULE_DESCRIPTION("Analog Devices ADV7175 video encoder driver");
 MODULE_AUTHOR("Dave Perks");
@@ -355,13 +354,6 @@ static int adv7175_s_fmt(struct v4l2_subdev *sd,
        return ret;
 }
 
-static int adv7175_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_ADV7175, 0);
-}
-
 static int adv7175_s_power(struct v4l2_subdev *sd, int on)
 {
        if (on)
@@ -375,7 +367,6 @@ static int adv7175_s_power(struct v4l2_subdev *sd, int on)
 /* ----------------------------------------------------------------------- */
 
 static const struct v4l2_subdev_core_ops adv7175_core_ops = {
-       .g_chip_ident = adv7175_g_chip_ident,
        .init = adv7175_init,
        .s_power = adv7175_s_power,
 };
@@ -409,7 +400,7 @@ static int adv7175_probe(struct i2c_client *client,
        v4l_info(client, "chip found @ 0x%x (%s)\n",
                        client->addr << 1, client->adapter->name);
 
-       encoder = kzalloc(sizeof(struct adv7175), GFP_KERNEL);
+       encoder = devm_kzalloc(&client->dev, sizeof(*encoder), GFP_KERNEL);
        if (encoder == NULL)
                return -ENOMEM;
        sd = &encoder->sd;
@@ -434,7 +425,6 @@ static int adv7175_remove(struct i2c_client *client)
        struct v4l2_subdev *sd = i2c_get_clientdata(client);
 
        v4l2_device_unregister_subdev(sd);
-       kfree(to_adv7175(sd));
        return 0;
 }
 
index afd561a..d7d99f1 100644 (file)
@@ -1,6 +1,8 @@
 /*
  * adv7180.c Analog Devices ADV7180 video decoder driver
  * Copyright (c) 2009 Intel Corporation
+ * Copyright (C) 2013 Cogent Embedded, Inc.
+ * Copyright (C) 2013 Renesas Solutions Corp.
  *
  * 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
@@ -27,7 +29,6 @@
 #include <linux/videodev2.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-ctrls.h>
-#include <media/v4l2-chip-ident.h>
 #include <linux/mutex.h>
 
 #define ADV7180_INPUT_CONTROL_REG                      0x00
@@ -272,14 +273,6 @@ static int adv7180_g_input_status(struct v4l2_subdev *sd, u32 *status)
        return ret;
 }
 
-static int adv7180_g_chip_ident(struct v4l2_subdev *sd,
-                               struct v4l2_dbg_chip_ident *chip)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_ADV7180, 0);
-}
-
 static int adv7180_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
 {
        struct adv7180_state *state = to_state(sd);
@@ -397,14 +390,57 @@ static void adv7180_exit_controls(struct adv7180_state *state)
        v4l2_ctrl_handler_free(&state->ctrl_hdl);
 }
 
+static int adv7180_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned int index,
+                                enum v4l2_mbus_pixelcode *code)
+{
+       if (index > 0)
+               return -EINVAL;
+
+       *code = V4L2_MBUS_FMT_YUYV8_2X8;
+
+       return 0;
+}
+
+static int adv7180_mbus_fmt(struct v4l2_subdev *sd,
+                           struct v4l2_mbus_framefmt *fmt)
+{
+       struct adv7180_state *state = to_state(sd);
+
+       fmt->code = V4L2_MBUS_FMT_YUYV8_2X8;
+       fmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
+       fmt->field = V4L2_FIELD_INTERLACED;
+       fmt->width = 720;
+       fmt->height = state->curr_norm & V4L2_STD_525_60 ? 480 : 576;
+
+       return 0;
+}
+
+static int adv7180_g_mbus_config(struct v4l2_subdev *sd,
+                                struct v4l2_mbus_config *cfg)
+{
+       /*
+        * The ADV7180 sensor supports BT.601/656 output modes.
+        * The BT.656 is default and not yet configurable by s/w.
+        */
+       cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_PCLK_SAMPLE_RISING |
+                    V4L2_MBUS_DATA_ACTIVE_HIGH;
+       cfg->type = V4L2_MBUS_BT656;
+
+       return 0;
+}
+
 static const struct v4l2_subdev_video_ops adv7180_video_ops = {
        .querystd = adv7180_querystd,
        .g_input_status = adv7180_g_input_status,
        .s_routing = adv7180_s_routing,
+       .enum_mbus_fmt = adv7180_enum_mbus_fmt,
+       .try_mbus_fmt = adv7180_mbus_fmt,
+       .g_mbus_fmt = adv7180_mbus_fmt,
+       .s_mbus_fmt = adv7180_mbus_fmt,
+       .g_mbus_config = adv7180_g_mbus_config,
 };
 
 static const struct v4l2_subdev_core_ops adv7180_core_ops = {
-       .g_chip_ident = adv7180_g_chip_ident,
        .s_std = adv7180_s_std,
 };
 
@@ -555,7 +591,7 @@ static int adv7180_probe(struct i2c_client *client,
        v4l_info(client, "chip found @ 0x%02x (%s)\n",
                 client->addr, client->adapter->name);
 
-       state = kzalloc(sizeof(struct adv7180_state), GFP_KERNEL);
+       state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL);
        if (state == NULL) {
                ret = -ENOMEM;
                goto err;
@@ -582,7 +618,6 @@ err_free_ctrl:
 err_unreg_subdev:
        mutex_destroy(&state->mutex);
        v4l2_device_unregister_subdev(sd);
-       kfree(state);
 err:
        printk(KERN_ERR KBUILD_MODNAME ": Failed to probe: %d\n", ret);
        return ret;
@@ -607,7 +642,6 @@ static int adv7180_remove(struct i2c_client *client)
 
        mutex_destroy(&state->mutex);
        v4l2_device_unregister_subdev(sd);
-       kfree(to_state(sd));
        return 0;
 }
 
@@ -616,9 +650,10 @@ static const struct i2c_device_id adv7180_id[] = {
        {},
 };
 
-#ifdef CONFIG_PM
-static int adv7180_suspend(struct i2c_client *client, pm_message_t state)
+#ifdef CONFIG_PM_SLEEP
+static int adv7180_suspend(struct device *dev)
 {
+       struct i2c_client *client = to_i2c_client(dev);
        int ret;
 
        ret = i2c_smbus_write_byte_data(client, ADV7180_PWR_MAN_REG,
@@ -628,8 +663,9 @@ static int adv7180_suspend(struct i2c_client *client, pm_message_t state)
        return 0;
 }
 
-static int adv7180_resume(struct i2c_client *client)
+static int adv7180_resume(struct device *dev)
 {
+       struct i2c_client *client = to_i2c_client(dev);
        struct v4l2_subdev *sd = i2c_get_clientdata(client);
        struct adv7180_state *state = to_state(sd);
        int ret;
@@ -643,6 +679,12 @@ static int adv7180_resume(struct i2c_client *client)
                return ret;
        return 0;
 }
+
+static SIMPLE_DEV_PM_OPS(adv7180_pm_ops, adv7180_suspend, adv7180_resume);
+#define ADV7180_PM_OPS (&adv7180_pm_ops)
+
+#else
+#define ADV7180_PM_OPS NULL
 #endif
 
 MODULE_DEVICE_TABLE(i2c, adv7180_id);
@@ -651,13 +693,10 @@ static struct i2c_driver adv7180_driver = {
        .driver = {
                   .owner = THIS_MODULE,
                   .name = KBUILD_MODNAME,
+                  .pm = ADV7180_PM_OPS,
                   },
        .probe = adv7180_probe,
        .remove = adv7180_remove,
-#ifdef CONFIG_PM
-       .suspend = adv7180_suspend,
-       .resume = adv7180_resume,
-#endif
        .id_table = adv7180_id,
 };
 
index 56a1fa4..6f738d8 100644 (file)
@@ -28,7 +28,6 @@
 #include <linux/videodev2.h>
 
 #include <media/adv7183.h>
-#include <media/v4l2-chip-ident.h>
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-device.h>
 
@@ -375,28 +374,28 @@ static int adv7183_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
        reg = adv7183_read(sd, ADV7183_STATUS_1);
        switch ((reg >> 0x4) & 0x7) {
        case 0:
-               *std = V4L2_STD_NTSC;
+               *std &= V4L2_STD_NTSC;
                break;
        case 1:
-               *std = V4L2_STD_NTSC_443;
+               *std &= V4L2_STD_NTSC_443;
                break;
        case 2:
-               *std = V4L2_STD_PAL_M;
+               *std &= V4L2_STD_PAL_M;
                break;
        case 3:
-               *std = V4L2_STD_PAL_60;
+               *std &= V4L2_STD_PAL_60;
                break;
        case 4:
-               *std = V4L2_STD_PAL;
+               *std &= V4L2_STD_PAL;
                break;
        case 5:
-               *std = V4L2_STD_SECAM;
+               *std &= V4L2_STD_SECAM;
                break;
        case 6:
-               *std = V4L2_STD_PAL_Nc;
+               *std &= V4L2_STD_PAL_Nc;
                break;
        case 7:
-               *std = V4L2_STD_SECAM;
+               *std &= V4L2_STD_SECAM;
                break;
        default:
                *std = V4L2_STD_UNKNOWN;
@@ -474,34 +473,16 @@ static int adv7183_s_stream(struct v4l2_subdev *sd, int enable)
        struct adv7183 *decoder = to_adv7183(sd);
 
        if (enable)
-               gpio_direction_output(decoder->oe_pin, 0);
+               gpio_set_value(decoder->oe_pin, 0);
        else
-               gpio_direction_output(decoder->oe_pin, 1);
+               gpio_set_value(decoder->oe_pin, 1);
        udelay(1);
        return 0;
 }
 
-static int adv7183_g_chip_ident(struct v4l2_subdev *sd,
-               struct v4l2_dbg_chip_ident *chip)
-{
-       int rev;
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       /* 0x11 for adv7183, 0x13 for adv7183b */
-       rev = adv7183_read(sd, ADV7183_IDENT);
-
-       return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_ADV7183, rev);
-}
-
 #ifdef CONFIG_VIDEO_ADV_DEBUG
 static int adv7183_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
 {
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       if (!v4l2_chip_match_i2c_client(client, &reg->match))
-               return -EINVAL;
-       if (!capable(CAP_SYS_ADMIN))
-               return -EPERM;
        reg->val = adv7183_read(sd, reg->reg & 0xff);
        reg->size = 1;
        return 0;
@@ -509,12 +490,6 @@ static int adv7183_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *
 
 static int adv7183_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg)
 {
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       if (!v4l2_chip_match_i2c_client(client, &reg->match))
-               return -EINVAL;
-       if (!capable(CAP_SYS_ADMIN))
-               return -EPERM;
        adv7183_write(sd, reg->reg & 0xff, reg->val & 0xff);
        return 0;
 }
@@ -529,7 +504,6 @@ static const struct v4l2_subdev_core_ops adv7183_core_ops = {
        .g_std = adv7183_g_std,
        .s_std = adv7183_s_std,
        .reset = adv7183_reset,
-       .g_chip_ident = adv7183_g_chip_ident,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
        .g_register = adv7183_g_register,
        .s_register = adv7183_s_register,
@@ -573,23 +547,24 @@ static int adv7183_probe(struct i2c_client *client,
        if (pin_array == NULL)
                return -EINVAL;
 
-       decoder = kzalloc(sizeof(struct adv7183), GFP_KERNEL);
+       decoder = devm_kzalloc(&client->dev, sizeof(*decoder), GFP_KERNEL);
        if (decoder == NULL)
                return -ENOMEM;
 
        decoder->reset_pin = pin_array[0];
        decoder->oe_pin = pin_array[1];
 
-       if (gpio_request(decoder->reset_pin, "ADV7183 Reset")) {
+       if (devm_gpio_request_one(&client->dev, decoder->reset_pin,
+                                 GPIOF_OUT_INIT_LOW, "ADV7183 Reset")) {
                v4l_err(client, "failed to request GPIO %d\n", decoder->reset_pin);
-               ret = -EBUSY;
-               goto err_free_decoder;
+               return -EBUSY;
        }
 
-       if (gpio_request(decoder->oe_pin, "ADV7183 Output Enable")) {
+       if (devm_gpio_request_one(&client->dev, decoder->oe_pin,
+                                 GPIOF_OUT_INIT_HIGH,
+                                 "ADV7183 Output Enable")) {
                v4l_err(client, "failed to request GPIO %d\n", decoder->oe_pin);
-               ret = -EBUSY;
-               goto err_free_reset;
+               return -EBUSY;
        }
 
        sd = &decoder->sd;
@@ -611,7 +586,7 @@ static int adv7183_probe(struct i2c_client *client,
                ret = hdl->error;
 
                v4l2_ctrl_handler_free(hdl);
-               goto err_free_oe;
+               return ret;
        }
 
        /* v4l2 doesn't support an autodetect standard, pick PAL as default */
@@ -619,12 +594,10 @@ static int adv7183_probe(struct i2c_client *client,
        decoder->input = ADV7183_COMPOSITE4;
        decoder->output = ADV7183_8BIT_OUT;
 
-       gpio_direction_output(decoder->oe_pin, 1);
        /* reset chip */
-       gpio_direction_output(decoder->reset_pin, 0);
        /* reset pulse width at least 5ms */
        mdelay(10);
-       gpio_direction_output(decoder->reset_pin, 1);
+       gpio_set_value(decoder->reset_pin, 1);
        /* wait 5ms before any further i2c writes are performed */
        mdelay(5);
 
@@ -638,29 +611,18 @@ static int adv7183_probe(struct i2c_client *client,
        ret = v4l2_ctrl_handler_setup(hdl);
        if (ret) {
                v4l2_ctrl_handler_free(hdl);
-               goto err_free_oe;
+               return ret;
        }
 
        return 0;
-err_free_oe:
-       gpio_free(decoder->oe_pin);
-err_free_reset:
-       gpio_free(decoder->reset_pin);
-err_free_decoder:
-       kfree(decoder);
-       return ret;
 }
 
 static int adv7183_remove(struct i2c_client *client)
 {
        struct v4l2_subdev *sd = i2c_get_clientdata(client);
-       struct adv7183 *decoder = to_adv7183(sd);
 
        v4l2_device_unregister_subdev(sd);
        v4l2_ctrl_handler_free(sd->ctrl_handler);
-       gpio_free(decoder->oe_pin);
-       gpio_free(decoder->reset_pin);
-       kfree(decoder);
        return 0;
 }
 
index 9fc2b98..7606218 100644 (file)
@@ -28,7 +28,6 @@
 
 #include <media/adv7343.h>
 #include <media/v4l2-device.h>
-#include <media/v4l2-chip-ident.h>
 #include <media/v4l2-ctrls.h>
 
 #include "adv7343_regs.h"
@@ -311,21 +310,12 @@ static int adv7343_s_ctrl(struct v4l2_ctrl *ctrl)
        return -EINVAL;
 }
 
-static int adv7343_g_chip_ident(struct v4l2_subdev *sd,
-                               struct v4l2_dbg_chip_ident *chip)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_ADV7343, 0);
-}
-
 static const struct v4l2_ctrl_ops adv7343_ctrl_ops = {
        .s_ctrl = adv7343_s_ctrl,
 };
 
 static const struct v4l2_subdev_core_ops adv7343_core_ops = {
        .log_status = adv7343_log_status,
-       .g_chip_ident = adv7343_g_chip_ident,
        .g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
        .try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
        .s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
index 3dc6098..558f191 100644 (file)
@@ -33,7 +33,6 @@
 
 #include <media/adv7393.h>
 #include <media/v4l2-device.h>
-#include <media/v4l2-chip-ident.h>
 #include <media/v4l2-ctrls.h>
 
 #include "adv7393_regs.h"
@@ -301,21 +300,12 @@ static int adv7393_s_ctrl(struct v4l2_ctrl *ctrl)
        return -EINVAL;
 }
 
-static int adv7393_g_chip_ident(struct v4l2_subdev *sd,
-                               struct v4l2_dbg_chip_ident *chip)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_ADV7393, 0);
-}
-
 static const struct v4l2_ctrl_ops adv7393_ctrl_ops = {
        .s_ctrl = adv7393_s_ctrl,
 };
 
 static const struct v4l2_subdev_core_ops adv7393_core_ops = {
        .log_status = adv7393_log_status,
-       .g_chip_ident = adv7393_g_chip_ident,
        .g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
        .try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
        .s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
@@ -410,7 +400,7 @@ static int adv7393_probe(struct i2c_client *client,
        v4l_info(client, "chip found @ 0x%x (%s)\n",
                        client->addr << 1, client->adapter->name);
 
-       state = kzalloc(sizeof(struct adv7393_state), GFP_KERNEL);
+       state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL);
        if (state == NULL)
                return -ENOMEM;
 
@@ -444,16 +434,13 @@ static int adv7393_probe(struct i2c_client *client,
                int err = state->hdl.error;
 
                v4l2_ctrl_handler_free(&state->hdl);
-               kfree(state);
                return err;
        }
        v4l2_ctrl_handler_setup(&state->hdl);
 
        err = adv7393_initialize(&state->sd);
-       if (err) {
+       if (err)
                v4l2_ctrl_handler_free(&state->hdl);
-               kfree(state);
-       }
        return err;
 }
 
@@ -464,7 +451,6 @@ static int adv7393_remove(struct i2c_client *client)
 
        v4l2_device_unregister_subdev(sd);
        v4l2_ctrl_handler_free(&state->hdl);
-       kfree(state);
 
        return 0;
 }
index 31a63c9..1d675b5 100644 (file)
@@ -38,7 +38,6 @@
 #include <linux/v4l2-dv-timings.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-ctrls.h>
-#include <media/v4l2-chip-ident.h>
 #include <media/adv7604.h>
 
 static int debug;
@@ -643,12 +642,6 @@ static void adv7604_inv_register(struct v4l2_subdev *sd)
 static int adv7604_g_register(struct v4l2_subdev *sd,
                                        struct v4l2_dbg_register *reg)
 {
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       if (!v4l2_chip_match_i2c_client(client, &reg->match))
-               return -EINVAL;
-       if (!capable(CAP_SYS_ADMIN))
-               return -EPERM;
        reg->size = 1;
        switch (reg->reg >> 8) {
        case 0:
@@ -701,12 +694,6 @@ static int adv7604_g_register(struct v4l2_subdev *sd,
 static int adv7604_s_register(struct v4l2_subdev *sd,
                                        const struct v4l2_dbg_register *reg)
 {
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       if (!v4l2_chip_match_i2c_client(client, &reg->match))
-               return -EINVAL;
-       if (!capable(CAP_SYS_ADMIN))
-               return -EPERM;
        switch (reg->reg >> 8) {
        case 0:
                io_write(sd, reg->reg & 0xff, reg->val & 0xff);
@@ -984,14 +971,6 @@ static int adv7604_s_ctrl(struct v4l2_ctrl *ctrl)
        return -EINVAL;
 }
 
-static int adv7604_g_chip_ident(struct v4l2_subdev *sd,
-                                       struct v4l2_dbg_chip_ident *chip)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_ADV7604, 0);
-}
-
 /* ----------------------------------------------------------------------- */
 
 static inline bool no_power(struct v4l2_subdev *sd)
@@ -1787,7 +1766,6 @@ static const struct v4l2_subdev_core_ops adv7604_core_ops = {
        .s_ctrl = v4l2_subdev_s_ctrl,
        .queryctrl = v4l2_subdev_queryctrl,
        .querymenu = v4l2_subdev_querymenu,
-       .g_chip_ident = adv7604_g_chip_ident,
        .interrupt_service_routine = adv7604_isr,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
        .g_register = adv7604_g_register,
@@ -1968,7 +1946,7 @@ static int adv7604_probe(struct i2c_client *client,
        v4l_dbg(1, debug, client, "detecting adv7604 client on address 0x%x\n",
                        client->addr << 1);
 
-       state = kzalloc(sizeof(struct adv7604_state), GFP_KERNEL);
+       state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL);
        if (!state) {
                v4l_err(client, "Could not allocate adv7604_state memory!\n");
                return -ENOMEM;
@@ -1977,8 +1955,7 @@ static int adv7604_probe(struct i2c_client *client,
        /* platform data */
        if (!pdata) {
                v4l_err(client, "No platform data!\n");
-               err = -ENODEV;
-               goto err_state;
+               return -ENODEV;
        }
        memcpy(&state->pdata, pdata, sizeof(state->pdata));
 
@@ -1991,8 +1968,7 @@ static int adv7604_probe(struct i2c_client *client,
        if (adv_smbus_read_byte_data_check(client, 0xfb, false) != 0x68) {
                v4l2_info(sd, "not an adv7604 on address 0x%x\n",
                                client->addr << 1);
-               err = -ENODEV;
-               goto err_state;
+               return -ENODEV;
        }
 
        /* control handlers */
@@ -2093,8 +2069,6 @@ err_i2c:
        adv7604_unregister_clients(state);
 err_hdl:
        v4l2_ctrl_handler_free(hdl);
-err_state:
-       kfree(state);
        return err;
 }
 
@@ -2111,7 +2085,6 @@ static int adv7604_remove(struct i2c_client *client)
        media_entity_cleanup(&sd->entity);
        adv7604_unregister_clients(to_state(sd));
        v4l2_ctrl_handler_free(sd->ctrl_handler);
-       kfree(to_state(sd));
        return 0;
 }
 
index fd47465..c14e667 100644 (file)
@@ -16,7 +16,6 @@
 #include <linux/module.h>
 
 #include <media/ak881x.h>
-#include <media/v4l2-chip-ident.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-device.h>
 
@@ -33,7 +32,6 @@ struct ak881x {
        struct v4l2_subdev subdev;
        struct ak881x_pdata *pdata;
        unsigned int lines;
-       int id; /* DEVICE_ID code V4L2_IDENT_AK881X code from v4l2-chip-ident.h */
        char revision;  /* DEVICE_REVISION content */
 };
 
@@ -62,36 +60,16 @@ static struct ak881x *to_ak881x(const struct i2c_client *client)
        return container_of(i2c_get_clientdata(client), struct ak881x, subdev);
 }
 
-static int ak881x_g_chip_ident(struct v4l2_subdev *sd,
-                              struct v4l2_dbg_chip_ident *id)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct ak881x *ak881x = to_ak881x(client);
-
-       if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
-               return -EINVAL;
-
-       if (id->match.addr != client->addr)
-               return -ENODEV;
-
-       id->ident       = ak881x->id;
-       id->revision    = ak881x->revision;
-
-       return 0;
-}
-
 #ifdef CONFIG_VIDEO_ADV_DEBUG
 static int ak881x_g_register(struct v4l2_subdev *sd,
                             struct v4l2_dbg_register *reg)
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
 
-       if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0x26)
+       if (reg->reg > 0x26)
                return -EINVAL;
 
-       if (reg->match.addr != client->addr)
-               return -ENODEV;
-
+       reg->size = 1;
        reg->val = reg_read(client, reg->reg);
 
        if (reg->val > 0xffff)
@@ -105,12 +83,9 @@ static int ak881x_s_register(struct v4l2_subdev *sd,
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
 
-       if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0x26)
+       if (reg->reg > 0x26)
                return -EINVAL;
 
-       if (reg->match.addr != client->addr)
-               return -ENODEV;
-
        if (reg_write(client, reg->reg, reg->val) < 0)
                return -EIO;
 
@@ -229,7 +204,6 @@ static int ak881x_s_stream(struct v4l2_subdev *sd, int enable)
 }
 
 static struct v4l2_subdev_core_ops ak881x_subdev_core_ops = {
-       .g_chip_ident   = ak881x_g_chip_ident,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
        .g_register     = ak881x_g_register,
        .s_register     = ak881x_s_register,
@@ -264,7 +238,7 @@ static int ak881x_probe(struct i2c_client *client,
                return -EIO;
        }
 
-       ak881x = kzalloc(sizeof(struct ak881x), GFP_KERNEL);
+       ak881x = devm_kzalloc(&client->dev, sizeof(*ak881x), GFP_KERNEL);
        if (!ak881x)
                return -ENOMEM;
 
@@ -274,15 +248,11 @@ static int ak881x_probe(struct i2c_client *client,
 
        switch (data) {
        case 0x13:
-               ak881x->id = V4L2_IDENT_AK8813;
-               break;
        case 0x14:
-               ak881x->id = V4L2_IDENT_AK8814;
                break;
        default:
                dev_err(&client->dev,
                        "No ak881x chip detected, register read %x\n", data);
-               kfree(ak881x);
                return -ENODEV;
        }
 
@@ -331,7 +301,6 @@ static int ak881x_remove(struct i2c_client *client)
        struct ak881x *ak881x = to_ak881x(client);
 
        v4l2_device_unregister_subdev(&ak881x->subdev);
-       kfree(ak881x);
 
        return 0;
 }
index 58d523f..301084b 100644 (file)
@@ -813,7 +813,7 @@ static int as3645a_probe(struct i2c_client *client,
        if (client->dev.platform_data == NULL)
                return -ENODEV;
 
-       flash = kzalloc(sizeof(*flash), GFP_KERNEL);
+       flash = devm_kzalloc(&client->dev, sizeof(*flash), GFP_KERNEL);
        if (flash == NULL)
                return -ENOMEM;
 
@@ -838,10 +838,8 @@ static int as3645a_probe(struct i2c_client *client,
        flash->led_mode = V4L2_FLASH_LED_MODE_NONE;
 
 done:
-       if (ret < 0) {
+       if (ret < 0)
                v4l2_ctrl_handler_free(&flash->ctrls);
-               kfree(flash);
-       }
 
        return ret;
 }
@@ -855,7 +853,6 @@ static int as3645a_remove(struct i2c_client *client)
        v4l2_ctrl_handler_free(&flash->ctrls);
        media_entity_cleanup(&flash->subdev.entity);
        mutex_destroy(&flash->power_lock);
-       kfree(flash);
 
        return 0;
 }
index 377bf05..369cf6f 100644 (file)
@@ -36,7 +36,6 @@
 #include <linux/videodev2.h>
 #include <linux/slab.h>
 #include <media/v4l2-device.h>
-#include <media/v4l2-chip-ident.h>
 #include <media/v4l2-ctrls.h>
 #include <media/bt819.h>
 
@@ -57,7 +56,6 @@ struct bt819 {
        unsigned char reg[32];
 
        v4l2_std_id norm;
-       int ident;
        int input;
        int enable;
 };
@@ -217,15 +215,17 @@ static int bt819_status(struct v4l2_subdev *sd, u32 *pstatus, v4l2_std_id *pstd)
        struct bt819 *decoder = to_bt819(sd);
        int status = bt819_read(decoder, 0x00);
        int res = V4L2_IN_ST_NO_SIGNAL;
-       v4l2_std_id std;
+       v4l2_std_id std = pstd ? *pstd : V4L2_STD_ALL;
 
        if ((status & 0x80))
                res = 0;
+       else
+               std = V4L2_STD_UNKNOWN;
 
        if ((status & 0x10))
-               std = V4L2_STD_PAL;
+               std &= V4L2_STD_PAL;
        else
-               std = V4L2_STD_NTSC;
+               std &= V4L2_STD_NTSC;
        if (pstd)
                *pstd = std;
        if (pstatus)
@@ -373,14 +373,6 @@ static int bt819_s_ctrl(struct v4l2_ctrl *ctrl)
        return 0;
 }
 
-static int bt819_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
-{
-       struct bt819 *decoder = to_bt819(sd);
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       return v4l2_chip_ident_i2c_client(client, chip, decoder->ident, 0);
-}
-
 /* ----------------------------------------------------------------------- */
 
 static const struct v4l2_ctrl_ops bt819_ctrl_ops = {
@@ -388,7 +380,6 @@ static const struct v4l2_ctrl_ops bt819_ctrl_ops = {
 };
 
 static const struct v4l2_subdev_core_ops bt819_core_ops = {
-       .g_chip_ident = bt819_g_chip_ident,
        .g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
        .try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
        .s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
@@ -425,7 +416,7 @@ static int bt819_probe(struct i2c_client *client,
        if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
                return -ENODEV;
 
-       decoder = kzalloc(sizeof(struct bt819), GFP_KERNEL);
+       decoder = devm_kzalloc(&client->dev, sizeof(*decoder), GFP_KERNEL);
        if (decoder == NULL)
                return -ENOMEM;
        sd = &decoder->sd;
@@ -435,15 +426,12 @@ static int bt819_probe(struct i2c_client *client,
        switch (ver & 0xf0) {
        case 0x70:
                name = "bt819a";
-               decoder->ident = V4L2_IDENT_BT819A;
                break;
        case 0x60:
                name = "bt817a";
-               decoder->ident = V4L2_IDENT_BT817A;
                break;
        case 0x20:
                name = "bt815a";
-               decoder->ident = V4L2_IDENT_BT815A;
                break;
        default:
                v4l2_dbg(1, debug, sd,
@@ -476,7 +464,6 @@ static int bt819_probe(struct i2c_client *client,
                int err = decoder->hdl.error;
 
                v4l2_ctrl_handler_free(&decoder->hdl);
-               kfree(decoder);
                return err;
        }
        v4l2_ctrl_handler_setup(&decoder->hdl);
@@ -490,7 +477,6 @@ static int bt819_remove(struct i2c_client *client)
 
        v4l2_device_unregister_subdev(sd);
        v4l2_ctrl_handler_free(&decoder->hdl);
-       kfree(decoder);
        return 0;
 }
 
index 7e5bd36..7fc163d 100644 (file)
@@ -36,7 +36,6 @@
 #include <linux/i2c.h>
 #include <linux/videodev2.h>
 #include <media/v4l2-device.h>
-#include <media/v4l2-chip-ident.h>
 
 MODULE_DESCRIPTION("Brooktree-856A video encoder driver");
 MODULE_AUTHOR("Mike Bernson & Dave Perks");
@@ -177,17 +176,9 @@ static int bt856_s_routing(struct v4l2_subdev *sd,
        return 0;
 }
 
-static int bt856_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_BT856, 0);
-}
-
 /* ----------------------------------------------------------------------- */
 
 static const struct v4l2_subdev_core_ops bt856_core_ops = {
-       .g_chip_ident = bt856_g_chip_ident,
        .init = bt856_init,
 };
 
@@ -216,7 +207,7 @@ static int bt856_probe(struct i2c_client *client,
        v4l_info(client, "chip found @ 0x%x (%s)\n",
                        client->addr << 1, client->adapter->name);
 
-       encoder = kzalloc(sizeof(struct bt856), GFP_KERNEL);
+       encoder = devm_kzalloc(&client->dev, sizeof(*encoder), GFP_KERNEL);
        if (encoder == NULL)
                return -ENOMEM;
        sd = &encoder->sd;
@@ -250,7 +241,6 @@ static int bt856_remove(struct i2c_client *client)
        struct v4l2_subdev *sd = i2c_get_clientdata(client);
 
        v4l2_device_unregister_subdev(sd);
-       kfree(to_bt856(sd));
        return 0;
 }
 
index 905320b..a8bf10f 100644 (file)
@@ -36,7 +36,6 @@
 #include <linux/i2c.h>
 #include <linux/videodev2.h>
 #include <media/v4l2-device.h>
-#include <media/v4l2-chip-ident.h>
 
 MODULE_DESCRIPTION("Brooktree-866 video encoder driver");
 MODULE_AUTHOR("Mike Bernson & Dave Perks");
@@ -175,26 +174,14 @@ static int bt866_s_routing(struct v4l2_subdev *sd,
        bt866_write(client, 0xdc, val);
 #endif
 
-static int bt866_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_BT866, 0);
-}
-
 /* ----------------------------------------------------------------------- */
 
-static const struct v4l2_subdev_core_ops bt866_core_ops = {
-       .g_chip_ident = bt866_g_chip_ident,
-};
-
 static const struct v4l2_subdev_video_ops bt866_video_ops = {
        .s_std_output = bt866_s_std_output,
        .s_routing = bt866_s_routing,
 };
 
 static const struct v4l2_subdev_ops bt866_ops = {
-       .core = &bt866_core_ops,
        .video = &bt866_video_ops,
 };
 
@@ -207,7 +194,7 @@ static int bt866_probe(struct i2c_client *client,
        v4l_info(client, "chip found @ 0x%x (%s)\n",
                        client->addr << 1, client->adapter->name);
 
-       encoder = kzalloc(sizeof(*encoder), GFP_KERNEL);
+       encoder = devm_kzalloc(&client->dev, sizeof(*encoder), GFP_KERNEL);
        if (encoder == NULL)
                return -ENOMEM;
        sd = &encoder->sd;
@@ -220,7 +207,6 @@ static int bt866_remove(struct i2c_client *client)
        struct v4l2_subdev *sd = i2c_get_clientdata(client);
 
        v4l2_device_unregister_subdev(sd);
-       kfree(to_bt866(sd));
        return 0;
 }
 
index 1d2f7c8..34b76a9 100644 (file)
@@ -24,7 +24,6 @@
 #include <linux/videodev2.h>
 #include <linux/slab.h>
 #include <media/v4l2-device.h>
-#include <media/v4l2-chip-ident.h>
 #include <media/v4l2-ctrls.h>
 
 MODULE_DESCRIPTION("i2c device driver for cs5345 Audio ADC");
@@ -99,12 +98,6 @@ static int cs5345_s_ctrl(struct v4l2_ctrl *ctrl)
 #ifdef CONFIG_VIDEO_ADV_DEBUG
 static int cs5345_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
 {
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       if (!v4l2_chip_match_i2c_client(client, &reg->match))
-               return -EINVAL;
-       if (!capable(CAP_SYS_ADMIN))
-               return -EPERM;
        reg->size = 1;
        reg->val = cs5345_read(sd, reg->reg & 0x1f);
        return 0;
@@ -112,24 +105,11 @@ static int cs5345_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *r
 
 static int cs5345_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg)
 {
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       if (!v4l2_chip_match_i2c_client(client, &reg->match))
-               return -EINVAL;
-       if (!capable(CAP_SYS_ADMIN))
-               return -EPERM;
        cs5345_write(sd, reg->reg & 0x1f, reg->val & 0xff);
        return 0;
 }
 #endif
 
-static int cs5345_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_CS5345, 0);
-}
-
 static int cs5345_log_status(struct v4l2_subdev *sd)
 {
        u8 v = cs5345_read(sd, 0x09) & 7;
@@ -152,7 +132,6 @@ static const struct v4l2_ctrl_ops cs5345_ctrl_ops = {
 
 static const struct v4l2_subdev_core_ops cs5345_core_ops = {
        .log_status = cs5345_log_status,
-       .g_chip_ident = cs5345_g_chip_ident,
        .g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
        .try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
        .s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
@@ -190,7 +169,7 @@ static int cs5345_probe(struct i2c_client *client,
        v4l_info(client, "chip found @ 0x%x (%s)\n",
                        client->addr << 1, client->adapter->name);
 
-       state = kzalloc(sizeof(struct cs5345_state), GFP_KERNEL);
+       state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL);
        if (state == NULL)
                return -ENOMEM;
        sd = &state->sd;
@@ -206,7 +185,6 @@ static int cs5345_probe(struct i2c_client *client,
                int err = state->hdl.error;
 
                v4l2_ctrl_handler_free(&state->hdl);
-               kfree(state);
                return err;
        }
        /* set volume/mute */
@@ -227,7 +205,6 @@ static int cs5345_remove(struct i2c_client *client)
 
        v4l2_device_unregister_subdev(sd);
        v4l2_ctrl_handler_free(&state->hdl);
-       kfree(state);
        return 0;
 }
 
index b293912..27400c1 100644 (file)
@@ -28,7 +28,6 @@
 #include <linux/i2c.h>
 #include <linux/videodev2.h>
 #include <media/v4l2-device.h>
-#include <media/v4l2-chip-ident.h>
 #include <media/v4l2-ctrls.h>
 
 MODULE_DESCRIPTION("i2c device driver for cs53l32a Audio ADC");
@@ -104,14 +103,6 @@ static int cs53l32a_s_ctrl(struct v4l2_ctrl *ctrl)
        return -EINVAL;
 }
 
-static int cs53l32a_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       return v4l2_chip_ident_i2c_client(client,
-                       chip, V4L2_IDENT_CS53l32A, 0);
-}
-
 static int cs53l32a_log_status(struct v4l2_subdev *sd)
 {
        struct cs53l32a_state *state = to_state(sd);
@@ -130,7 +121,6 @@ static const struct v4l2_ctrl_ops cs53l32a_ctrl_ops = {
 
 static const struct v4l2_subdev_core_ops cs53l32a_core_ops = {
        .log_status = cs53l32a_log_status,
-       .g_chip_ident = cs53l32a_g_chip_ident,
        .g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
        .try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
        .s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
@@ -175,7 +165,7 @@ static int cs53l32a_probe(struct i2c_client *client,
        v4l_info(client, "chip found @ 0x%x (%s)\n",
                        client->addr << 1, client->adapter->name);
 
-       state = kzalloc(sizeof(struct cs53l32a_state), GFP_KERNEL);
+       state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL);
        if (state == NULL)
                return -ENOMEM;
        sd = &state->sd;
@@ -197,7 +187,6 @@ static int cs53l32a_probe(struct i2c_client *client,
                int err = state->hdl.error;
 
                v4l2_ctrl_handler_free(&state->hdl);
-               kfree(state);
                return err;
        }
 
@@ -228,7 +217,6 @@ static int cs53l32a_remove(struct i2c_client *client)
 
        v4l2_device_unregister_subdev(sd);
        v4l2_ctrl_handler_free(&state->hdl);
-       kfree(state);
        return 0;
 }
 
index 12fb9b2..2e3771d 100644 (file)
@@ -45,7 +45,6 @@
 #include <linux/delay.h>
 #include <linux/math64.h>
 #include <media/v4l2-common.h>
-#include <media/v4l2-chip-ident.h>
 #include <media/cx25840.h>
 
 #include "cx25840-core.h"
@@ -498,7 +497,7 @@ static void cx23885_initialize(struct i2c_client *client)
 
        /* Sys PLL */
        switch (state->id) {
-       case V4L2_IDENT_CX23888_AV:
+       case CX23888_AV:
                /*
                 * 50.0 MHz * (0xb + 0xe8ba26/0x2000000)/4 = 5 * 28.636363 MHz
                 * 572.73 MHz before post divide
@@ -511,7 +510,7 @@ static void cx23885_initialize(struct i2c_client *client)
                cx25840_write4(client, 0x42c, 0x42600000);
                cx25840_write4(client, 0x44c, 0x161f1000);
                break;
-       case V4L2_IDENT_CX23887_AV:
+       case CX23887_AV:
                /*
                 * 25.0 MHz * (0x16 + 0x1d1744c/0x2000000)/4 = 5 * 28.636363 MHz
                 * 572.73 MHz before post divide
@@ -519,7 +518,7 @@ static void cx23885_initialize(struct i2c_client *client)
                cx25840_write4(client, 0x11c, 0x01d1744c);
                cx25840_write4(client, 0x118, 0x00000416);
                break;
-       case V4L2_IDENT_CX23885_AV:
+       case CX23885_AV:
        default:
                /*
                 * 28.636363 MHz * (0x14 + 0x0/0x2000000)/4 = 5 * 28.636363 MHz
@@ -546,7 +545,7 @@ static void cx23885_initialize(struct i2c_client *client)
 
        /* HVR1850 */
        switch (state->id) {
-       case V4L2_IDENT_CX23888_AV:
+       case CX23888_AV:
                /* 888/HVR1250 specific */
                cx25840_write4(client, 0x10c, 0x13333333);
                cx25840_write4(client, 0x108, 0x00000515);
@@ -570,7 +569,7 @@ static void cx23885_initialize(struct i2c_client *client)
         * 48 ksps, 16 bits/sample, x16 multiplier = 12.288 MHz
         */
        switch (state->id) {
-       case V4L2_IDENT_CX23888_AV:
+       case CX23888_AV:
                /*
                 * 50.0 MHz * (0x7 + 0x0bedfa4/0x2000000)/3 = 122.88 MHz
                 * 368.64 MHz before post divide
@@ -580,7 +579,7 @@ static void cx23885_initialize(struct i2c_client *client)
                cx25840_write4(client, 0x114, 0x017dbf48);
                cx25840_write4(client, 0x110, 0x000a030e);
                break;
-       case V4L2_IDENT_CX23887_AV:
+       case CX23887_AV:
                /*
                 * 25.0 MHz * (0xe + 0x17dbf48/0x2000000)/3 = 122.88 MHz
                 * 368.64 MHz before post divide
@@ -589,7 +588,7 @@ static void cx23885_initialize(struct i2c_client *client)
                cx25840_write4(client, 0x114, 0x017dbf48);
                cx25840_write4(client, 0x110, 0x000a030e);
                break;
-       case V4L2_IDENT_CX23885_AV:
+       case CX23885_AV:
        default:
                /*
                 * 28.636363 MHz * (0xc + 0x1bf0c9e/0x2000000)/3 = 122.88 MHz
@@ -1662,10 +1661,6 @@ static int cx25840_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
 
-       if (!v4l2_chip_match_i2c_client(client, &reg->match))
-               return -EINVAL;
-       if (!capable(CAP_SYS_ADMIN))
-               return -EPERM;
        reg->size = 1;
        reg->val = cx25840_read(client, reg->reg & 0x0fff);
        return 0;
@@ -1675,10 +1670,6 @@ static int cx25840_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_regi
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
 
-       if (!v4l2_chip_match_i2c_client(client, &reg->match))
-               return -EINVAL;
-       if (!capable(CAP_SYS_ADMIN))
-               return -EPERM;
        cx25840_write(client, reg->reg & 0x0fff, reg->val & 0xff);
        return 0;
 }
@@ -1938,14 +1929,6 @@ static int cx25840_reset(struct v4l2_subdev *sd, u32 val)
        return 0;
 }
 
-static int cx25840_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
-{
-       struct cx25840_state *state = to_state(sd);
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       return v4l2_chip_ident_i2c_client(client, chip, state->id, state->rev);
-}
-
 static int cx25840_log_status(struct v4l2_subdev *sd)
 {
        struct cx25840_state *state = to_state(sd);
@@ -5051,7 +5034,6 @@ static const struct v4l2_ctrl_ops cx25840_ctrl_ops = {
 
 static const struct v4l2_subdev_core_ops cx25840_core_ops = {
        .log_status = cx25840_log_status,
-       .g_chip_ident = cx25840_g_chip_ident,
        .g_ctrl = v4l2_subdev_g_ctrl,
        .s_ctrl = v4l2_subdev_s_ctrl,
        .s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
@@ -5128,18 +5110,18 @@ static u32 get_cx2388x_ident(struct i2c_client *client)
                ret = cx25840_read4(client, 0x300);
                if (((ret & 0xffff0000) >> 16) == (ret & 0xffff)) {
                        /* No DIF */
-                       ret = V4L2_IDENT_CX23885_AV;
+                       ret = CX23885_AV;
                } else {
                        /* CX23887 has a broken DIF, but the registers
                         * appear valid (but unused), good enough to detect. */
-                       ret = V4L2_IDENT_CX23887_AV;
+                       ret = CX23887_AV;
                }
        } else if (cx25840_read4(client, 0x300) & 0x0fffffff) {
                /* DIF PLL Freq Word reg exists; chip must be a CX23888 */
-               ret = V4L2_IDENT_CX23888_AV;
+               ret = CX23888_AV;
        } else {
                v4l_err(client, "Unable to detect h/w, assuming cx23887\n");
-               ret = V4L2_IDENT_CX23887_AV;
+               ret = CX23887_AV;
        }
 
        /* Back into digital power down */
@@ -5153,7 +5135,7 @@ static int cx25840_probe(struct i2c_client *client,
        struct cx25840_state *state;
        struct v4l2_subdev *sd;
        int default_volume;
-       u32 id = V4L2_IDENT_NONE;
+       u32 id;
        u16 device_id;
 
        /* Check if the adapter supports the needed features */
@@ -5169,14 +5151,14 @@ static int cx25840_probe(struct i2c_client *client,
        /* The high byte of the device ID should be
         * 0x83 for the cx2583x and 0x84 for the cx2584x */
        if ((device_id & 0xff00) == 0x8300) {
-               id = V4L2_IDENT_CX25836 + ((device_id >> 4) & 0xf) - 6;
+               id = CX25836 + ((device_id >> 4) & 0xf) - 6;
        } else if ((device_id & 0xff00) == 0x8400) {
-               id = V4L2_IDENT_CX25840 + ((device_id >> 4) & 0xf);
+               id = CX25840 + ((device_id >> 4) & 0xf);
        } else if (device_id == 0x0000) {
                id = get_cx2388x_ident(client);
        } else if ((device_id & 0xfff0) == 0x5A30) {
                /* The CX23100 (0x5A3C = 23100) doesn't have an A/V decoder */
-               id = V4L2_IDENT_CX2310X_AV;
+               id = CX2310X_AV;
        } else if ((device_id & 0xff) == (device_id >> 8)) {
                v4l_err(client,
                        "likely a confused/unresponsive cx2388[578] A/V decoder"
@@ -5190,7 +5172,7 @@ static int cx25840_probe(struct i2c_client *client,
                return -ENODEV;
        }
 
-       state = kzalloc(sizeof(struct cx25840_state), GFP_KERNEL);
+       state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL);
        if (state == NULL)
                return -ENOMEM;
 
@@ -5198,26 +5180,26 @@ static int cx25840_probe(struct i2c_client *client,
        v4l2_i2c_subdev_init(sd, client, &cx25840_ops);
 
        switch (id) {
-       case V4L2_IDENT_CX23885_AV:
+       case CX23885_AV:
                v4l_info(client, "cx23885 A/V decoder found @ 0x%x (%s)\n",
                         client->addr << 1, client->adapter->name);
                break;
-       case V4L2_IDENT_CX23887_AV:
+       case CX23887_AV:
                v4l_info(client, "cx23887 A/V decoder found @ 0x%x (%s)\n",
                         client->addr << 1, client->adapter->name);
                break;
-       case V4L2_IDENT_CX23888_AV:
+       case CX23888_AV:
                v4l_info(client, "cx23888 A/V decoder found @ 0x%x (%s)\n",
                         client->addr << 1, client->adapter->name);
                break;
-       case V4L2_IDENT_CX2310X_AV:
+       case CX2310X_AV:
                v4l_info(client, "cx%d A/V decoder found @ 0x%x (%s)\n",
                         device_id, client->addr << 1, client->adapter->name);
                break;
-       case V4L2_IDENT_CX25840:
-       case V4L2_IDENT_CX25841:
-       case V4L2_IDENT_CX25842:
-       case V4L2_IDENT_CX25843:
+       case CX25840:
+       case CX25841:
+       case CX25842:
+       case CX25843:
                /* Note: revision '(device_id & 0x0f) == 2' was never built. The
                   marking skips from 0x1 == 22 to 0x3 == 23. */
                v4l_info(client, "cx25%3x-2%x found @ 0x%x (%s)\n",
@@ -5226,8 +5208,8 @@ static int cx25840_probe(struct i2c_client *client,
                                                : (device_id & 0x0f),
                         client->addr << 1, client->adapter->name);
                break;
-       case V4L2_IDENT_CX25836:
-       case V4L2_IDENT_CX25837:
+       case CX25836:
+       case CX25837:
        default:
                v4l_info(client, "cx25%3x-%x found @ 0x%x (%s)\n",
                         (device_id & 0xfff0) >> 4, device_id & 0x0f,
@@ -5292,7 +5274,6 @@ static int cx25840_probe(struct i2c_client *client,
                int err = state->hdl.error;
 
                v4l2_ctrl_handler_free(&state->hdl);
-               kfree(state);
                return err;
        }
        if (!is_cx2583x(state))
@@ -5317,7 +5298,6 @@ static int cx25840_remove(struct i2c_client *client)
        cx25840_ir_remove(sd);
        v4l2_device_unregister_subdev(sd);
        v4l2_ctrl_handler_free(&state->hdl);
-       kfree(state);
        return 0;
 }
 
index bd4ada2..37bc042 100644 (file)
 
 #include <linux/videodev2.h>
 #include <media/v4l2-device.h>
-#include <media/v4l2-chip-ident.h>
 #include <media/v4l2-ctrls.h>
 #include <linux/i2c.h>
 
 struct cx25840_ir_state;
 
+enum cx25840_model {
+       CX23885_AV,
+       CX23887_AV,
+       CX23888_AV,
+       CX2310X_AV,
+       CX25840,
+       CX25841,
+       CX25842,
+       CX25843,
+       CX25836,
+       CX25837,
+};
+
 struct cx25840_state {
        struct i2c_client *c;
        struct v4l2_subdev sd;
@@ -46,7 +58,7 @@ struct cx25840_state {
        u32 audclk_freq;
        int audmode;
        int vbi_line_offset;
-       u32 id;
+       enum cx25840_model id;
        u32 rev;
        int is_initialized;
        wait_queue_head_t fw_wait;    /* wake up when the fw load is finished */
@@ -66,35 +78,35 @@ static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
 
 static inline bool is_cx2583x(struct cx25840_state *state)
 {
-       return state->id == V4L2_IDENT_CX25836 ||
-              state->id == V4L2_IDENT_CX25837;
+       return state->id == CX25836 ||
+              state->id == CX25837;
 }
 
 static inline bool is_cx231xx(struct cx25840_state *state)
 {
-       return state->id == V4L2_IDENT_CX2310X_AV;
+       return state->id == CX2310X_AV;
 }
 
 static inline bool is_cx2388x(struct cx25840_state *state)
 {
-       return state->id == V4L2_IDENT_CX23885_AV ||
-              state->id == V4L2_IDENT_CX23887_AV ||
-              state->id == V4L2_IDENT_CX23888_AV;
+       return state->id == CX23885_AV ||
+              state->id == CX23887_AV ||
+              state->id == CX23888_AV;
 }
 
 static inline bool is_cx23885(struct cx25840_state *state)
 {
-       return state->id == V4L2_IDENT_CX23885_AV;
+       return state->id == CX23885_AV;
 }
 
 static inline bool is_cx23887(struct cx25840_state *state)
 {
-       return state->id == V4L2_IDENT_CX23887_AV;
+       return state->id == CX23887_AV;
 }
 
 static inline bool is_cx23888(struct cx25840_state *state)
 {
-       return state->id == V4L2_IDENT_CX23888_AV;
+       return state->id == CX23888_AV;
 }
 
 /* ----------------------------------------------------------------------- */
index 9ae977b..e6588ee 100644 (file)
@@ -1230,16 +1230,14 @@ int cx25840_ir_probe(struct v4l2_subdev *sd)
        if (!(is_cx23885(state) || is_cx23887(state)))
                return 0;
 
-       ir_state = kzalloc(sizeof(struct cx25840_ir_state), GFP_KERNEL);
+       ir_state = devm_kzalloc(&state->c->dev, sizeof(*ir_state), GFP_KERNEL);
        if (ir_state == NULL)
                return -ENOMEM;
 
        spin_lock_init(&ir_state->rx_kfifo_lock);
        if (kfifo_alloc(&ir_state->rx_kfifo,
-                       CX25840_IR_RX_KFIFO_SIZE, GFP_KERNEL)) {
-               kfree(ir_state);
+                       CX25840_IR_RX_KFIFO_SIZE, GFP_KERNEL))
                return -ENOMEM;
-       }
 
        ir_state->c = state->c;
        state->ir_state = ir_state;
@@ -1273,7 +1271,6 @@ int cx25840_ir_remove(struct v4l2_subdev *sd)
        cx25840_ir_tx_shutdown(sd);
 
        kfifo_free(&ir_state->rx_kfifo);
-       kfree(ir_state);
        state->ir_state = NULL;
        return 0;
 }
index 8e2f79c..82bf567 100644 (file)
@@ -295,7 +295,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
        unsigned short addr = client->addr;
        int err;
 
-       ir = kzalloc(sizeof(struct IR_i2c), GFP_KERNEL);
+       ir = devm_kzalloc(&client->dev, sizeof(*ir), GFP_KERNEL);
        if (!ir)
                return -ENOMEM;
 
@@ -398,10 +398,8 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
                 * internally
                 */
                rc = rc_allocate_device();
-               if (!rc) {
-                       err = -ENOMEM;
-                       goto err_out_free;
-               }
+               if (!rc)
+                       return -ENOMEM;
        }
        ir->rc = rc;
 
@@ -454,7 +452,6 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
  err_out_free:
        /* Only frees rc if it were allocated internally */
        rc_free_device(rc);
-       kfree(ir);
        return err;
 }
 
@@ -470,7 +467,6 @@ static int ir_remove(struct i2c_client *client)
                rc_unregister_device(ir->rc);
 
        /* free memory */
-       kfree(ir);
        return 0;
 }
 
index 04a6efa..c3e94ae 100644 (file)
@@ -42,7 +42,6 @@
 #include <linux/videodev2.h>
 #include <linux/slab.h>
 #include <media/v4l2-device.h>
-#include <media/v4l2-chip-ident.h>
 #include "ks0127.h"
 
 MODULE_DESCRIPTION("KS0127 video decoder driver");
@@ -200,7 +199,6 @@ struct adjust {
 struct ks0127 {
        struct v4l2_subdev sd;
        v4l2_std_id     norm;
-       int             ident;
        u8              regs[256];
 };
 
@@ -371,12 +369,9 @@ static void ks0127_and_or(struct v4l2_subdev *sd, u8 reg, u8 and_v, u8 or_v)
 ****************************************************************************/
 static void ks0127_init(struct v4l2_subdev *sd)
 {
-       struct ks0127 *ks = to_ks0127(sd);
        u8 *table = reg_defaults;
        int i;
 
-       ks->ident = V4L2_IDENT_KS0127;
-
        v4l2_dbg(1, debug, sd, "reset\n");
        msleep(1);
 
@@ -397,7 +392,6 @@ static void ks0127_init(struct v4l2_subdev *sd)
 
 
        if ((ks0127_read(sd, KS_STAT) & 0x80) == 0) {
-               ks->ident = V4L2_IDENT_KS0122S;
                v4l2_dbg(1, debug, sd, "ks0122s found\n");
                return;
        }
@@ -408,7 +402,6 @@ static void ks0127_init(struct v4l2_subdev *sd)
                break;
 
        case 9:
-               ks->ident = V4L2_IDENT_KS0127B;
                v4l2_dbg(1, debug, sd, "ks0127B Revision A found\n");
                break;
 
@@ -616,17 +609,24 @@ static int ks0127_status(struct v4l2_subdev *sd, u32 *pstatus, v4l2_std_id *pstd
 {
        int stat = V4L2_IN_ST_NO_SIGNAL;
        u8 status;
-       v4l2_std_id std = V4L2_STD_ALL;
+       v4l2_std_id std = pstd ? *pstd : V4L2_STD_ALL;
 
        status = ks0127_read(sd, KS_STAT);
        if (!(status & 0x20))            /* NOVID not set */
                stat = 0;
-       if (!(status & 0x01))                 /* CLOCK set */
+       if (!(status & 0x01)) {               /* CLOCK set */
                stat |= V4L2_IN_ST_NO_COLOR;
-       if ((status & 0x08))               /* PALDET set */
-               std = V4L2_STD_PAL;
+               std = V4L2_STD_UNKNOWN;
+       } else {
+               if ((status & 0x08))               /* PALDET set */
+                       std &= V4L2_STD_PAL;
+               else
+                       std &= V4L2_STD_NTSC;
+       }
+       if ((status & 0x10))               /* PALDET set */
+               std &= V4L2_STD_525_60;
        else
-               std = V4L2_STD_NTSC;
+               std &= V4L2_STD_625_50;
        if (pstd)
                *pstd = std;
        if (pstatus)
@@ -646,18 +646,9 @@ static int ks0127_g_input_status(struct v4l2_subdev *sd, u32 *status)
        return ks0127_status(sd, status, NULL);
 }
 
-static int ks0127_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct ks0127 *ks = to_ks0127(sd);
-
-       return v4l2_chip_ident_i2c_client(client, chip, ks->ident, 0);
-}
-
 /* ----------------------------------------------------------------------- */
 
 static const struct v4l2_subdev_core_ops ks0127_core_ops = {
-       .g_chip_ident = ks0127_g_chip_ident,
        .s_std = ks0127_s_std,
 };
 
@@ -685,7 +676,7 @@ static int ks0127_probe(struct i2c_client *client, const struct i2c_device_id *i
                client->addr == (I2C_KS0127_ADDON >> 1) ? "addon" : "on-board",
                client->addr << 1, client->adapter->name);
 
-       ks = kzalloc(sizeof(*ks), GFP_KERNEL);
+       ks = devm_kzalloc(&client->dev, sizeof(*ks), GFP_KERNEL);
        if (ks == NULL)
                return -ENOMEM;
        sd = &ks->sd;
@@ -708,7 +699,6 @@ static int ks0127_remove(struct i2c_client *client)
        v4l2_device_unregister_subdev(sd);
        ks0127_write(sd, KS_OFMTA, 0x20); /* tristate */
        ks0127_write(sd, KS_CMDA, 0x2c | 0x80); /* power down */
-       kfree(to_ks0127(sd));
        return 0;
 }
 
index 39f50fd..bf47635 100644 (file)
@@ -29,7 +29,6 @@
 #include <linux/videodev2.h>
 #include <media/m52790.h>
 #include <media/v4l2-device.h>
-#include <media/v4l2-chip-ident.h>
 
 MODULE_DESCRIPTION("i2c device driver for m52790 A/V switch");
 MODULE_AUTHOR("Hans Verkuil");
@@ -83,12 +82,7 @@ static int m52790_s_routing(struct v4l2_subdev *sd,
 static int m52790_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
 {
        struct m52790_state *state = to_state(sd);
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
 
-       if (!v4l2_chip_match_i2c_client(client, &reg->match))
-               return -EINVAL;
-       if (!capable(CAP_SYS_ADMIN))
-               return -EPERM;
        if (reg->reg != 0)
                return -EINVAL;
        reg->size = 1;
@@ -99,12 +93,7 @@ static int m52790_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *r
 static int m52790_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg)
 {
        struct m52790_state *state = to_state(sd);
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
 
-       if (!v4l2_chip_match_i2c_client(client, &reg->match))
-               return -EINVAL;
-       if (!capable(CAP_SYS_ADMIN))
-               return -EPERM;
        if (reg->reg != 0)
                return -EINVAL;
        state->input = reg->val & 0x0303;
@@ -114,13 +103,6 @@ static int m52790_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_regis
 }
 #endif
 
-static int m52790_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_M52790, 0);
-}
-
 static int m52790_log_status(struct v4l2_subdev *sd)
 {
        struct m52790_state *state = to_state(sd);
@@ -136,7 +118,6 @@ static int m52790_log_status(struct v4l2_subdev *sd)
 
 static const struct v4l2_subdev_core_ops m52790_core_ops = {
        .log_status = m52790_log_status,
-       .g_chip_ident = m52790_g_chip_ident,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
        .g_register = m52790_g_register,
        .s_register = m52790_s_register,
@@ -174,7 +155,7 @@ static int m52790_probe(struct i2c_client *client,
        v4l_info(client, "chip found @ 0x%x (%s)\n",
                        client->addr << 1, client->adapter->name);
 
-       state = kzalloc(sizeof(struct m52790_state), GFP_KERNEL);
+       state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL);
        if (state == NULL)
                return -ENOMEM;
 
@@ -191,7 +172,6 @@ static int m52790_remove(struct i2c_client *client)
        struct v4l2_subdev *sd = i2c_get_clientdata(client);
 
        v4l2_device_unregister_subdev(sd);
-       kfree(to_state(sd));
        return 0;
 }
 
index 0b899cb..8d870b7 100644 (file)
@@ -930,6 +930,7 @@ static int m5mols_probe(struct i2c_client *client,
                        const struct i2c_device_id *id)
 {
        const struct m5mols_platform_data *pdata = client->dev.platform_data;
+       unsigned long gpio_flags;
        struct m5mols_info *info;
        struct v4l2_subdev *sd;
        int ret;
@@ -949,24 +950,27 @@ static int m5mols_probe(struct i2c_client *client,
                return -EINVAL;
        }
 
-       info = kzalloc(sizeof(struct m5mols_info), GFP_KERNEL);
+       info = devm_kzalloc(&client->dev, sizeof(*info), GFP_KERNEL);
        if (!info)
                return -ENOMEM;
 
        info->pdata = pdata;
        info->set_power = pdata->set_power;
 
-       ret = gpio_request(pdata->gpio_reset, "M5MOLS_NRST");
+       gpio_flags = pdata->reset_polarity
+                  ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW;
+       ret = devm_gpio_request_one(&client->dev, pdata->gpio_reset, gpio_flags,
+                                   "M5MOLS_NRST");
        if (ret) {
                dev_err(&client->dev, "Failed to request gpio: %d\n", ret);
-               goto out_free;
+               return ret;
        }
-       gpio_direction_output(pdata->gpio_reset, pdata->reset_polarity);
 
-       ret = regulator_bulk_get(&client->dev, ARRAY_SIZE(supplies), supplies);
+       ret = devm_regulator_bulk_get(&client->dev, ARRAY_SIZE(supplies),
+                                     supplies);
        if (ret) {
                dev_err(&client->dev, "Failed to get regulators: %d\n", ret);
-               goto out_gpio;
+               return ret;
        }
 
        sd = &info->sd;
@@ -978,17 +982,17 @@ static int m5mols_probe(struct i2c_client *client,
        info->pad.flags = MEDIA_PAD_FL_SOURCE;
        ret = media_entity_init(&sd->entity, 1, &info->pad, 0);
        if (ret < 0)
-               goto out_reg;
+               return ret;
        sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR;
 
        init_waitqueue_head(&info->irq_waitq);
        mutex_init(&info->lock);
 
-       ret = request_irq(client->irq, m5mols_irq_handler,
-                         IRQF_TRIGGER_RISING, MODULE_NAME, sd);
+       ret = devm_request_irq(&client->dev, client->irq, m5mols_irq_handler,
+                              IRQF_TRIGGER_RISING, MODULE_NAME, sd);
        if (ret) {
                dev_err(&client->dev, "Interrupt request failed: %d\n", ret);
-               goto out_me;
+               goto error;
        }
        info->res_type = M5MOLS_RESTYPE_MONITOR;
        info->ffmt[0] = m5mols_default_ffmt[0];
@@ -996,7 +1000,7 @@ static int m5mols_probe(struct i2c_client *client,
 
        ret = m5mols_sensor_power(info, true);
        if (ret)
-               goto out_irq;
+               goto error;
 
        ret = m5mols_fw_start(sd);
        if (!ret)
@@ -1005,32 +1009,19 @@ static int m5mols_probe(struct i2c_client *client,
        ret = m5mols_sensor_power(info, false);
        if (!ret)
                return 0;
-out_irq:
-       free_irq(client->irq, sd);
-out_me:
+error:
        media_entity_cleanup(&sd->entity);
-out_reg:
-       regulator_bulk_free(ARRAY_SIZE(supplies), supplies);
-out_gpio:
-       gpio_free(pdata->gpio_reset);
-out_free:
-       kfree(info);
        return ret;
 }
 
 static int m5mols_remove(struct i2c_client *client)
 {
        struct v4l2_subdev *sd = i2c_get_clientdata(client);
-       struct m5mols_info *info = to_m5mols(sd);
 
        v4l2_device_unregister_subdev(sd);
        v4l2_ctrl_handler_free(sd->ctrl_handler);
-       free_irq(client->irq, sd);
-
-       regulator_bulk_free(ARRAY_SIZE(supplies), supplies);
-       gpio_free(info->pdata->gpio_reset);
        media_entity_cleanup(&sd->entity);
-       kfree(info);
+
        return 0;
 }
 
diff --git a/drivers/media/i2c/ml86v7667.c b/drivers/media/i2c/ml86v7667.c
new file mode 100644 (file)
index 0000000..efdc873
--- /dev/null
@@ -0,0 +1,431 @@
+/*
+ * OKI Semiconductor ML86V7667 video decoder driver
+ *
+ * Author: Vladimir Barinov <source@cogentembedded.com>
+ * Copyright (C) 2013 Cogent Embedded, Inc.
+ * Copyright (C) 2013 Renesas Solutions Corp.
+ *
+ * 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/init.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-subdev.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-ctrls.h>
+
+#define DRV_NAME "ml86v7667"
+
+/* Subaddresses */
+#define MRA_REG                        0x00 /* Mode Register A */
+#define MRC_REG                        0x02 /* Mode Register C */
+#define LUMC_REG               0x0C /* Luminance Control */
+#define CLC_REG                        0x10 /* Contrast level control */
+#define SSEPL_REG              0x11 /* Sync separation level */
+#define CHRCA_REG              0x12 /* Chrominance Control A */
+#define ACCC_REG               0x14 /* ACC Loop filter & Chrominance control */
+#define ACCRC_REG              0x15 /* ACC Reference level control */
+#define HUE_REG                        0x16 /* Hue control */
+#define ADC2_REG               0x1F /* ADC Register 2 */
+#define PLLR1_REG              0x20 /* PLL Register 1 */
+#define STATUS_REG             0x2C /* STATUS Register */
+
+/* Mode Register A register bits */
+#define MRA_OUTPUT_MODE_MASK   (3 << 6)
+#define MRA_ITUR_BT601         (1 << 6)
+#define MRA_ITUR_BT656         (0 << 6)
+#define MRA_INPUT_MODE_MASK    (7 << 3)
+#define MRA_PAL_BT601          (4 << 3)
+#define MRA_NTSC_BT601         (0 << 3)
+#define MRA_REGISTER_MODE      (1 << 0)
+
+/* Mode Register C register bits */
+#define MRC_AUTOSELECT         (1 << 7)
+
+/* Luminance Control register bits */
+#define LUMC_ONOFF_SHIFT       7
+#define LUMC_ONOFF_MASK                (1 << 7)
+
+/* Contrast level control register bits */
+#define CLC_CONTRAST_ONOFF     (1 << 7)
+#define CLC_CONTRAST_MASK      0x0F
+
+/* Sync separation level register bits */
+#define SSEPL_LUMINANCE_ONOFF  (1 << 7)
+#define SSEPL_LUMINANCE_MASK   0x7F
+
+/* Chrominance Control A register bits */
+#define CHRCA_MODE_SHIFT       6
+#define CHRCA_MODE_MASK                (1 << 6)
+
+/* ACC Loop filter & Chrominance control register bits */
+#define ACCC_CHROMA_CR_SHIFT   3
+#define ACCC_CHROMA_CR_MASK    (7 << 3)
+#define ACCC_CHROMA_CB_SHIFT   0
+#define ACCC_CHROMA_CB_MASK    (7 << 0)
+
+/* ACC Reference level control register bits */
+#define ACCRC_CHROMA_MASK      0xfc
+#define ACCRC_CHROMA_SHIFT     2
+
+/* ADC Register 2 register bits */
+#define ADC2_CLAMP_VOLTAGE_MASK        (7 << 1)
+#define ADC2_CLAMP_VOLTAGE(n)  ((n & 7) << 1)
+
+/* PLL Register 1 register bits */
+#define PLLR1_FIXED_CLOCK      (1 << 7)
+
+/* STATUS Register register bits */
+#define STATUS_HLOCK_DETECT    (1 << 3)
+#define STATUS_NTSCPAL         (1 << 2)
+
+struct ml86v7667_priv {
+       struct v4l2_subdev              sd;
+       struct v4l2_ctrl_handler        hdl;
+       v4l2_std_id                     std;
+};
+
+static inline struct ml86v7667_priv *to_ml86v7667(struct v4l2_subdev *subdev)
+{
+       return container_of(subdev, struct ml86v7667_priv, sd);
+}
+
+static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
+{
+       return &container_of(ctrl->handler, struct ml86v7667_priv, hdl)->sd;
+}
+
+static int ml86v7667_mask_set(struct i2c_client *client, const u8 reg,
+                             const u8 mask, const u8 data)
+{
+       int val = i2c_smbus_read_byte_data(client, reg);
+       if (val < 0)
+               return val;
+
+       val = (val & ~mask) | (data & mask);
+       return i2c_smbus_write_byte_data(client, reg, val);
+}
+
+static int ml86v7667_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct v4l2_subdev *sd = to_sd(ctrl);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       int ret;
+
+       switch (ctrl->id) {
+       case V4L2_CID_BRIGHTNESS:
+               ret = ml86v7667_mask_set(client, SSEPL_REG,
+                                        SSEPL_LUMINANCE_MASK, ctrl->val);
+               break;
+       case V4L2_CID_CONTRAST:
+               ret = ml86v7667_mask_set(client, CLC_REG,
+                                        CLC_CONTRAST_MASK, ctrl->val);
+               break;
+       case V4L2_CID_CHROMA_GAIN:
+               ret = ml86v7667_mask_set(client, ACCRC_REG, ACCRC_CHROMA_MASK,
+                                        ctrl->val << ACCRC_CHROMA_SHIFT);
+               break;
+       case V4L2_CID_HUE:
+               ret = ml86v7667_mask_set(client, HUE_REG, ~0, ctrl->val);
+               break;
+       case V4L2_CID_RED_BALANCE:
+               ret = ml86v7667_mask_set(client, ACCC_REG,
+                                        ACCC_CHROMA_CR_MASK,
+                                        ctrl->val << ACCC_CHROMA_CR_SHIFT);
+               break;
+       case V4L2_CID_BLUE_BALANCE:
+               ret = ml86v7667_mask_set(client, ACCC_REG,
+                                        ACCC_CHROMA_CB_MASK,
+                                        ctrl->val << ACCC_CHROMA_CB_SHIFT);
+               break;
+       case V4L2_CID_SHARPNESS:
+               ret = ml86v7667_mask_set(client, LUMC_REG,
+                                        LUMC_ONOFF_MASK,
+                                        ctrl->val << LUMC_ONOFF_SHIFT);
+               break;
+       case V4L2_CID_COLOR_KILLER:
+               ret = ml86v7667_mask_set(client, CHRCA_REG,
+                                        CHRCA_MODE_MASK,
+                                        ctrl->val << CHRCA_MODE_SHIFT);
+               break;
+       }
+
+       return 0;
+}
+
+static int ml86v7667_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       int status;
+
+       status = i2c_smbus_read_byte_data(client, STATUS_REG);
+       if (status < 0)
+               return status;
+
+       if (status & STATUS_HLOCK_DETECT)
+               *std &= status & STATUS_NTSCPAL ? V4L2_STD_625_50 : V4L2_STD_525_60;
+       else
+               *std = V4L2_STD_UNKNOWN;
+
+       return 0;
+}
+
+static int ml86v7667_g_input_status(struct v4l2_subdev *sd, u32 *status)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       int status_reg;
+
+       status_reg = i2c_smbus_read_byte_data(client, STATUS_REG);
+       if (status_reg < 0)
+               return status_reg;
+
+       *status = status_reg & STATUS_HLOCK_DETECT ? 0 : V4L2_IN_ST_NO_SIGNAL;
+
+       return 0;
+}
+
+static int ml86v7667_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned int index,
+                                  enum v4l2_mbus_pixelcode *code)
+{
+       if (index > 0)
+               return -EINVAL;
+
+       *code = V4L2_MBUS_FMT_YUYV8_2X8;
+
+       return 0;
+}
+
+static int ml86v7667_mbus_fmt(struct v4l2_subdev *sd,
+                             struct v4l2_mbus_framefmt *fmt)
+{
+       struct ml86v7667_priv *priv = to_ml86v7667(sd);
+
+       fmt->code = V4L2_MBUS_FMT_YUYV8_2X8;
+       fmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
+       fmt->field = V4L2_FIELD_INTERLACED;
+       fmt->width = 720;
+       fmt->height = priv->std & V4L2_STD_525_60 ? 480 : 576;
+
+       return 0;
+}
+
+static int ml86v7667_g_mbus_config(struct v4l2_subdev *sd,
+                                  struct v4l2_mbus_config *cfg)
+{
+       cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_PCLK_SAMPLE_RISING |
+                    V4L2_MBUS_DATA_ACTIVE_HIGH;
+       cfg->type = V4L2_MBUS_BT656;
+
+       return 0;
+}
+
+static int ml86v7667_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
+{
+       struct ml86v7667_priv *priv = to_ml86v7667(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(&priv->sd);
+       int ret;
+       u8 mode;
+
+       /* PAL/NTSC ITU-R BT.601 input mode */
+       mode = std & V4L2_STD_525_60 ? MRA_NTSC_BT601 : MRA_PAL_BT601;
+       ret = ml86v7667_mask_set(client, MRA_REG, MRA_INPUT_MODE_MASK, mode);
+       if (ret < 0)
+               return ret;
+
+       priv->std = std;
+
+       return 0;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int ml86v7667_g_register(struct v4l2_subdev *sd,
+                               struct v4l2_dbg_register *reg)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       int ret;
+
+       ret = i2c_smbus_read_byte_data(client, (u8)reg->reg);
+       if (ret < 0)
+               return ret;
+
+       reg->val = ret;
+       reg->size = sizeof(u8);
+
+       return 0;
+}
+
+static int ml86v7667_s_register(struct v4l2_subdev *sd,
+                               const struct v4l2_dbg_register *reg)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       return i2c_smbus_write_byte_data(client, (u8)reg->reg, (u8)reg->val);
+}
+#endif
+
+static const struct v4l2_ctrl_ops ml86v7667_ctrl_ops = {
+       .s_ctrl = ml86v7667_s_ctrl,
+};
+
+static struct v4l2_subdev_video_ops ml86v7667_subdev_video_ops = {
+       .querystd = ml86v7667_querystd,
+       .g_input_status = ml86v7667_g_input_status,
+       .enum_mbus_fmt = ml86v7667_enum_mbus_fmt,
+       .try_mbus_fmt = ml86v7667_mbus_fmt,
+       .g_mbus_fmt = ml86v7667_mbus_fmt,
+       .s_mbus_fmt = ml86v7667_mbus_fmt,
+       .g_mbus_config = ml86v7667_g_mbus_config,
+};
+
+static struct v4l2_subdev_core_ops ml86v7667_subdev_core_ops = {
+       .s_std = ml86v7667_s_std,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+       .g_register = ml86v7667_g_register,
+       .s_register = ml86v7667_s_register,
+#endif
+};
+
+static struct v4l2_subdev_ops ml86v7667_subdev_ops = {
+       .core = &ml86v7667_subdev_core_ops,
+       .video = &ml86v7667_subdev_video_ops,
+};
+
+static int ml86v7667_init(struct ml86v7667_priv *priv)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(&priv->sd);
+       int val;
+       int ret;
+
+       /* BT.656-4 output mode, register mode */
+       ret = ml86v7667_mask_set(client, MRA_REG,
+                                MRA_OUTPUT_MODE_MASK | MRA_REGISTER_MODE,
+                                MRA_ITUR_BT656 | MRA_REGISTER_MODE);
+
+       /* PLL circuit fixed clock, 32MHz */
+       ret |= ml86v7667_mask_set(client, PLLR1_REG, PLLR1_FIXED_CLOCK,
+                                 PLLR1_FIXED_CLOCK);
+
+       /* ADC2 clamping voltage maximum  */
+       ret |= ml86v7667_mask_set(client, ADC2_REG, ADC2_CLAMP_VOLTAGE_MASK,
+                                 ADC2_CLAMP_VOLTAGE(7));
+
+       /* enable luminance function */
+       ret |= ml86v7667_mask_set(client, SSEPL_REG, SSEPL_LUMINANCE_ONOFF,
+                                 SSEPL_LUMINANCE_ONOFF);
+
+       /* enable contrast function */
+       ret |= ml86v7667_mask_set(client, CLC_REG, CLC_CONTRAST_ONOFF, 0);
+
+       /*
+        * PAL/NTSC autodetection is enabled after reset,
+        * set the autodetected std in manual std mode and
+        * disable autodetection
+        */
+       val = i2c_smbus_read_byte_data(client, STATUS_REG);
+       if (val < 0)
+               return val;
+
+       priv->std = val & STATUS_NTSCPAL ? V4L2_STD_625_50 : V4L2_STD_525_60;
+       ret |= ml86v7667_mask_set(client, MRC_REG, MRC_AUTOSELECT, 0);
+
+       val = priv->std & V4L2_STD_525_60 ? MRA_NTSC_BT601 : MRA_PAL_BT601;
+       ret |= ml86v7667_mask_set(client, MRA_REG, MRA_INPUT_MODE_MASK, val);
+
+       return ret;
+}
+
+static int ml86v7667_probe(struct i2c_client *client,
+                          const struct i2c_device_id *did)
+{
+       struct ml86v7667_priv *priv;
+       int ret;
+
+       if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+               return -EIO;
+
+       priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       v4l2_i2c_subdev_init(&priv->sd, client, &ml86v7667_subdev_ops);
+
+       v4l2_ctrl_handler_init(&priv->hdl, 8);
+       v4l2_ctrl_new_std(&priv->hdl, &ml86v7667_ctrl_ops,
+                         V4L2_CID_BRIGHTNESS, -64, 63, 1, 0);
+       v4l2_ctrl_new_std(&priv->hdl, &ml86v7667_ctrl_ops,
+                         V4L2_CID_CONTRAST, -8, 7, 1, 0);
+       v4l2_ctrl_new_std(&priv->hdl, &ml86v7667_ctrl_ops,
+                         V4L2_CID_CHROMA_GAIN, -32, 31, 1, 0);
+       v4l2_ctrl_new_std(&priv->hdl, &ml86v7667_ctrl_ops,
+                         V4L2_CID_HUE, -128, 127, 1, 0);
+       v4l2_ctrl_new_std(&priv->hdl, &ml86v7667_ctrl_ops,
+                         V4L2_CID_RED_BALANCE, -4, 3, 1, 0);
+       v4l2_ctrl_new_std(&priv->hdl, &ml86v7667_ctrl_ops,
+                         V4L2_CID_BLUE_BALANCE, -4, 3, 1, 0);
+       v4l2_ctrl_new_std(&priv->hdl, &ml86v7667_ctrl_ops,
+                         V4L2_CID_SHARPNESS, 0, 1, 1, 0);
+       v4l2_ctrl_new_std(&priv->hdl, &ml86v7667_ctrl_ops,
+                         V4L2_CID_COLOR_KILLER, 0, 1, 1, 0);
+       priv->sd.ctrl_handler = &priv->hdl;
+
+       ret = priv->hdl.error;
+       if (ret)
+               goto cleanup;
+
+       v4l2_ctrl_handler_setup(&priv->hdl);
+
+       ret = ml86v7667_init(priv);
+       if (ret)
+               goto cleanup;
+
+       v4l_info(client, "chip found @ 0x%02x (%s)\n",
+                client->addr, client->adapter->name);
+       return 0;
+
+cleanup:
+       v4l2_ctrl_handler_free(&priv->hdl);
+       v4l2_device_unregister_subdev(&priv->sd);
+       v4l_err(client, "failed to probe @ 0x%02x (%s)\n",
+               client->addr, client->adapter->name);
+       return ret;
+}
+
+static int ml86v7667_remove(struct i2c_client *client)
+{
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+       struct ml86v7667_priv *priv = to_ml86v7667(sd);
+
+       v4l2_ctrl_handler_free(&priv->hdl);
+       v4l2_device_unregister_subdev(&priv->sd);
+
+       return 0;
+}
+
+static const struct i2c_device_id ml86v7667_id[] = {
+       {DRV_NAME, 0},
+       {},
+};
+MODULE_DEVICE_TABLE(i2c, ml86v7667_id);
+
+static struct i2c_driver ml86v7667_i2c_driver = {
+       .driver = {
+               .name   = DRV_NAME,
+               .owner  = THIS_MODULE,
+       },
+       .probe          = ml86v7667_probe,
+       .remove         = ml86v7667_remove,
+       .id_table       = ml86v7667_id,
+};
+
+module_i2c_driver(ml86v7667_i2c_driver);
+
+MODULE_DESCRIPTION("OKI Semiconductor ML86V7667 video decoder driver");
+MODULE_AUTHOR("Vladimir Barinov");
+MODULE_LICENSE("GPL");
index 54a9dd3..8190fec 100644 (file)
@@ -570,15 +570,6 @@ static int msp_s_i2s_clock_freq(struct v4l2_subdev *sd, u32 freq)
        return 0;
 }
 
-static int msp_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
-{
-       struct msp_state *state = to_state(sd);
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       return v4l2_chip_ident_i2c_client(client, chip, state->ident,
-                       (state->rev1 << 16) | state->rev2);
-}
-
 static int msp_log_status(struct v4l2_subdev *sd)
 {
        struct msp_state *state = to_state(sd);
@@ -651,7 +642,6 @@ static const struct v4l2_ctrl_ops msp_ctrl_ops = {
 
 static const struct v4l2_subdev_core_ops msp_core_ops = {
        .log_status = msp_log_status,
-       .g_chip_ident = msp_g_chip_ident,
        .g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
        .try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
        .s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
@@ -707,7 +697,7 @@ static int msp_probe(struct i2c_client *client, const struct i2c_device_id *id)
                return -ENODEV;
        }
 
-       state = kzalloc(sizeof(*state), GFP_KERNEL);
+       state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL);
        if (!state)
                return -ENOMEM;
 
@@ -732,7 +722,6 @@ static int msp_probe(struct i2c_client *client, const struct i2c_device_id *id)
        if (state->rev1 == -1 || (state->rev1 == 0 && state->rev2 == 0)) {
                v4l_dbg(1, msp_debug, client,
                                "not an msp3400 (cannot read chip version)\n");
-               kfree(state);
                return -ENODEV;
        }
 
@@ -827,7 +816,6 @@ static int msp_probe(struct i2c_client *client, const struct i2c_device_id *id)
                int err = hdl->error;
 
                v4l2_ctrl_handler_free(hdl);
-               kfree(state);
                return err;
        }
 
@@ -889,7 +877,6 @@ static int msp_remove(struct i2c_client *client)
        msp_reset(client);
 
        v4l2_ctrl_handler_free(&state->hdl);
-       kfree(state);
        return 0;
 }
 
index 8edb3d8..846b15f 100644 (file)
@@ -554,10 +554,8 @@ static int mt9m032_g_register(struct v4l2_subdev *sd,
        struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev);
        int val;
 
-       if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
+       if (reg->reg > 0xff)
                return -EINVAL;
-       if (reg->match.addr != client->addr)
-               return -ENODEV;
 
        val = mt9m032_read(client, reg->reg);
        if (val < 0)
@@ -575,12 +573,9 @@ static int mt9m032_s_register(struct v4l2_subdev *sd,
        struct mt9m032 *sensor = to_mt9m032(sd);
        struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev);
 
-       if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
+       if (reg->reg > 0xff)
                return -EINVAL;
 
-       if (reg->match.addr != client->addr)
-               return -ENODEV;
-
        return mt9m032_write(client, reg->reg, reg->val);
 }
 #endif
@@ -730,7 +725,7 @@ static int mt9m032_probe(struct i2c_client *client,
        if (!client->dev.platform_data)
                return -ENODEV;
 
-       sensor = kzalloc(sizeof(*sensor), GFP_KERNEL);
+       sensor = devm_kzalloc(&client->dev, sizeof(*sensor), GFP_KERNEL);
        if (sensor == NULL)
                return -ENOMEM;
 
@@ -860,7 +855,6 @@ error_ctrl:
        v4l2_ctrl_handler_free(&sensor->ctrls);
 error_sensor:
        mutex_destroy(&sensor->lock);
-       kfree(sensor);
        return ret;
 }
 
@@ -873,7 +867,6 @@ static int mt9m032_remove(struct i2c_client *client)
        v4l2_ctrl_handler_free(&sensor->ctrls);
        media_entity_cleanup(&subdev->entity);
        mutex_destroy(&sensor->lock);
-       kfree(sensor);
        return 0;
 }
 
index 28cf95b..4734836 100644 (file)
 #include <linux/delay.h>
 #include <linux/device.h>
 #include <linux/gpio.h>
-#include <linux/module.h>
 #include <linux/i2c.h>
 #include <linux/log2.h>
+#include <linux/module.h>
+#include <linux/of_gpio.h>
 #include <linux/pm.h>
 #include <linux/regulator/consumer.h>
 #include <linux/slab.h>
 #include <linux/videodev2.h>
 
 #include <media/mt9p031.h>
-#include <media/v4l2-chip-ident.h>
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-device.h>
+#include <media/v4l2-of.h>
 #include <media/v4l2-subdev.h>
 
 #include "aptina-pll.h"
@@ -124,9 +125,7 @@ struct mt9p031 {
        int power_count;
 
        struct clk *clk;
-       struct regulator *vaa;
-       struct regulator *vdd;
-       struct regulator *vdd_io;
+       struct regulator_bulk_data regulators[3];
 
        enum mt9p031_model model;
        struct aptina_pll pll;
@@ -271,23 +270,26 @@ static inline int mt9p031_pll_disable(struct mt9p031 *mt9p031)
 
 static int mt9p031_power_on(struct mt9p031 *mt9p031)
 {
+       int ret;
+
        /* Ensure RESET_BAR is low */
-       if (mt9p031->reset != -1) {
+       if (gpio_is_valid(mt9p031->reset)) {
                gpio_set_value(mt9p031->reset, 0);
                usleep_range(1000, 2000);
        }
 
        /* Bring up the supplies */
-       regulator_enable(mt9p031->vdd);
-       regulator_enable(mt9p031->vdd_io);
-       regulator_enable(mt9p031->vaa);
+       ret = regulator_bulk_enable(ARRAY_SIZE(mt9p031->regulators),
+                                  mt9p031->regulators);
+       if (ret < 0)
+               return ret;
 
        /* Emable clock */
        if (mt9p031->clk)
                clk_prepare_enable(mt9p031->clk);
 
        /* Now RESET_BAR must be high */
-       if (mt9p031->reset != -1) {
+       if (gpio_is_valid(mt9p031->reset)) {
                gpio_set_value(mt9p031->reset, 1);
                usleep_range(1000, 2000);
        }
@@ -297,14 +299,13 @@ static int mt9p031_power_on(struct mt9p031 *mt9p031)
 
 static void mt9p031_power_off(struct mt9p031 *mt9p031)
 {
-       if (mt9p031->reset != -1) {
+       if (gpio_is_valid(mt9p031->reset)) {
                gpio_set_value(mt9p031->reset, 0);
                usleep_range(1000, 2000);
        }
 
-       regulator_disable(mt9p031->vaa);
-       regulator_disable(mt9p031->vdd_io);
-       regulator_disable(mt9p031->vdd);
+       regulator_bulk_disable(ARRAY_SIZE(mt9p031->regulators),
+                              mt9p031->regulators);
 
        if (mt9p031->clk)
                clk_disable_unprepare(mt9p031->clk);
@@ -849,18 +850,18 @@ static int mt9p031_registered(struct v4l2_subdev *subdev)
 
        /* Read out the chip version register */
        data = mt9p031_read(client, MT9P031_CHIP_VERSION);
+       mt9p031_power_off(mt9p031);
+
        if (data != MT9P031_CHIP_VERSION_VALUE) {
                dev_err(&client->dev, "MT9P031 not detected, wrong version "
                        "0x%04x\n", data);
                return -ENODEV;
        }
 
-       mt9p031_power_off(mt9p031);
-
        dev_info(&client->dev, "MT9P031 detected at address 0x%02x\n",
                 client->addr);
 
-       return ret;
+       return 0;
 }
 
 static int mt9p031_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
@@ -928,10 +929,36 @@ static const struct v4l2_subdev_internal_ops mt9p031_subdev_internal_ops = {
  * Driver initialization and probing
  */
 
+static struct mt9p031_platform_data *
+mt9p031_get_pdata(struct i2c_client *client)
+{
+       struct mt9p031_platform_data *pdata;
+       struct device_node *np;
+
+       if (!IS_ENABLED(CONFIG_OF) || !client->dev.of_node)
+               return client->dev.platform_data;
+
+       np = v4l2_of_get_next_endpoint(client->dev.of_node, NULL);
+       if (!np)
+               return NULL;
+
+       pdata = devm_kzalloc(&client->dev, sizeof(*pdata), GFP_KERNEL);
+       if (!pdata)
+               goto done;
+
+       pdata->reset = of_get_named_gpio(client->dev.of_node, "reset-gpios", 0);
+       of_property_read_u32(np, "input-clock-frequency", &pdata->ext_freq);
+       of_property_read_u32(np, "pixel-clock-frequency", &pdata->target_freq);
+
+done:
+       of_node_put(np);
+       return pdata;
+}
+
 static int mt9p031_probe(struct i2c_client *client,
                         const struct i2c_device_id *did)
 {
-       struct mt9p031_platform_data *pdata = client->dev.platform_data;
+       struct mt9p031_platform_data *pdata = mt9p031_get_pdata(client);
        struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
        struct mt9p031 *mt9p031;
        unsigned int i;
@@ -958,14 +985,14 @@ static int mt9p031_probe(struct i2c_client *client,
        mt9p031->model = did->driver_data;
        mt9p031->reset = -1;
 
-       mt9p031->vaa = devm_regulator_get(&client->dev, "vaa");
-       mt9p031->vdd = devm_regulator_get(&client->dev, "vdd");
-       mt9p031->vdd_io = devm_regulator_get(&client->dev, "vdd_io");
+       mt9p031->regulators[0].supply = "vdd";
+       mt9p031->regulators[1].supply = "vdd_io";
+       mt9p031->regulators[2].supply = "vaa";
 
-       if (IS_ERR(mt9p031->vaa) || IS_ERR(mt9p031->vdd) ||
-           IS_ERR(mt9p031->vdd_io)) {
+       ret = devm_regulator_bulk_get(&client->dev, 3, mt9p031->regulators);
+       if (ret < 0) {
                dev_err(&client->dev, "Unable to get regulators\n");
-               return -ENODEV;
+               return ret;
        }
 
        v4l2_ctrl_handler_init(&mt9p031->ctrls, ARRAY_SIZE(mt9p031_ctrls) + 6);
@@ -1031,7 +1058,7 @@ static int mt9p031_probe(struct i2c_client *client,
        mt9p031->format.field = V4L2_FIELD_NONE;
        mt9p031->format.colorspace = V4L2_COLORSPACE_SRGB;
 
-       if (pdata->reset != -1) {
+       if (gpio_is_valid(pdata->reset)) {
                ret = devm_gpio_request_one(&client->dev, pdata->reset,
                                            GPIOF_OUT_INIT_LOW, "mt9p031_rst");
                if (ret < 0)
@@ -1070,8 +1097,18 @@ static const struct i2c_device_id mt9p031_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, mt9p031_id);
 
+#if IS_ENABLED(CONFIG_OF)
+static const struct of_device_id mt9p031_of_match[] = {
+       { .compatible = "aptina,mt9p031", },
+       { .compatible = "aptina,mt9p031m", },
+       { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, mt9p031_of_match);
+#endif
+
 static struct i2c_driver mt9p031_i2c_driver = {
        .driver = {
+               .of_match_table = of_match_ptr(mt9p031_of_match),
                .name = "mt9p031",
        },
        .probe          = mt9p031_probe,
index 2e189d8..7964634 100644 (file)
@@ -740,7 +740,7 @@ static int mt9t001_probe(struct i2c_client *client,
        if (ret < 0)
                return ret;
 
-       mt9t001 = kzalloc(sizeof(*mt9t001), GFP_KERNEL);
+       mt9t001 = devm_kzalloc(&client->dev, sizeof(*mt9t001), GFP_KERNEL);
        if (!mt9t001)
                return -ENOMEM;
 
@@ -801,7 +801,6 @@ done:
        if (ret < 0) {
                v4l2_ctrl_handler_free(&mt9t001->ctrls);
                media_entity_cleanup(&mt9t001->subdev.entity);
-               kfree(mt9t001);
        }
 
        return ret;
@@ -815,7 +814,6 @@ static int mt9t001_remove(struct i2c_client *client)
        v4l2_ctrl_handler_free(&mt9t001->ctrls);
        v4l2_device_unregister_subdev(subdev);
        media_entity_cleanup(&subdev->entity);
-       kfree(mt9t001);
        return 0;
 }
 
index 3f415fd..f74698c 100644 (file)
@@ -12,7 +12,6 @@
 #include <linux/module.h>
 #include <asm/div64.h>
 #include <media/v4l2-device.h>
-#include <media/v4l2-chip-ident.h>
 #include <media/v4l2-ctrls.h>
 #include <media/mt9v011.h>
 
@@ -407,13 +406,6 @@ static int mt9v011_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt
 static int mt9v011_g_register(struct v4l2_subdev *sd,
                              struct v4l2_dbg_register *reg)
 {
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       if (!v4l2_chip_match_i2c_client(client, &reg->match))
-               return -EINVAL;
-       if (!capable(CAP_SYS_ADMIN))
-               return -EPERM;
-
        reg->val = mt9v011_read(sd, reg->reg & 0xff);
        reg->size = 2;
 
@@ -423,31 +415,12 @@ static int mt9v011_g_register(struct v4l2_subdev *sd,
 static int mt9v011_s_register(struct v4l2_subdev *sd,
                              const struct v4l2_dbg_register *reg)
 {
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       if (!v4l2_chip_match_i2c_client(client, &reg->match))
-               return -EINVAL;
-       if (!capable(CAP_SYS_ADMIN))
-               return -EPERM;
-
        mt9v011_write(sd, reg->reg & 0xff, reg->val & 0xffff);
 
        return 0;
 }
 #endif
 
-static int mt9v011_g_chip_ident(struct v4l2_subdev *sd,
-                               struct v4l2_dbg_chip_ident *chip)
-{
-       u16 version;
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       version = mt9v011_read(sd, R00_MT9V011_CHIP_VERSION);
-
-       return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_MT9V011,
-                                         version);
-}
-
 static int mt9v011_s_ctrl(struct v4l2_ctrl *ctrl)
 {
        struct mt9v011 *core =
@@ -489,7 +462,6 @@ static struct v4l2_ctrl_ops mt9v011_ctrl_ops = {
 
 static const struct v4l2_subdev_core_ops mt9v011_core_ops = {
        .reset = mt9v011_reset,
-       .g_chip_ident = mt9v011_g_chip_ident,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
        .g_register = mt9v011_g_register,
        .s_register = mt9v011_s_register,
@@ -526,7 +498,7 @@ static int mt9v011_probe(struct i2c_client *c,
             I2C_FUNC_SMBUS_READ_BYTE | I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
                return -EIO;
 
-       core = kzalloc(sizeof(struct mt9v011), GFP_KERNEL);
+       core = devm_kzalloc(&c->dev, sizeof(struct mt9v011), GFP_KERNEL);
        if (!core)
                return -ENOMEM;
 
@@ -539,7 +511,6 @@ static int mt9v011_probe(struct i2c_client *c,
            (version != MT9V011_REV_B_VERSION)) {
                v4l2_info(sd, "*** unknown micron chip detected (0x%04x).\n",
                          version);
-               kfree(core);
                return -EINVAL;
        }
 
@@ -562,7 +533,6 @@ static int mt9v011_probe(struct i2c_client *c,
 
                v4l2_err(sd, "control initialization error %d\n", ret);
                v4l2_ctrl_handler_free(&core->ctrls);
-               kfree(core);
                return ret;
        }
        core->sd.ctrl_handler = &core->ctrls;
@@ -598,7 +568,7 @@ static int mt9v011_remove(struct i2c_client *c)
 
        v4l2_device_unregister_subdev(sd);
        v4l2_ctrl_handler_free(&core->ctrls);
-       kfree(to_mt9v011(sd));
+
        return 0;
 }
 
index 3f356cb..60c6f67 100644 (file)
@@ -744,7 +744,7 @@ static int mt9v032_probe(struct i2c_client *client,
                return -EIO;
        }
 
-       mt9v032 = kzalloc(sizeof(*mt9v032), GFP_KERNEL);
+       mt9v032 = devm_kzalloc(&client->dev, sizeof(*mt9v032), GFP_KERNEL);
        if (!mt9v032)
                return -ENOMEM;
 
@@ -830,8 +830,9 @@ static int mt9v032_probe(struct i2c_client *client,
 
        mt9v032->pad.flags = MEDIA_PAD_FL_SOURCE;
        ret = media_entity_init(&mt9v032->subdev.entity, 1, &mt9v032->pad, 0);
+
        if (ret < 0)
-               kfree(mt9v032);
+               v4l2_ctrl_handler_free(&mt9v032->ctrls);
 
        return ret;
 }
@@ -841,9 +842,10 @@ static int mt9v032_remove(struct i2c_client *client)
        struct v4l2_subdev *subdev = i2c_get_clientdata(client);
        struct mt9v032 *mt9v032 = to_mt9v032(subdev);
 
+       v4l2_ctrl_handler_free(&mt9v032->ctrls);
        v4l2_device_unregister_subdev(subdev);
        media_entity_cleanup(&subdev->entity);
-       kfree(mt9v032);
+
        return 0;
 }
 
index 8554b47..271d0b7 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/slab.h>
 #include <linux/regulator/consumer.h>
 #include <media/noon010pc30.h>
-#include <media/v4l2-chip-ident.h>
 #include <linux/videodev2.h>
 #include <linux/module.h>
 #include <media/v4l2-ctrls.h>
@@ -712,7 +711,7 @@ static int noon010_probe(struct i2c_client *client,
                return -EIO;
        }
 
-       info = kzalloc(sizeof(*info), GFP_KERNEL);
+       info = devm_kzalloc(&client->dev, sizeof(*info), GFP_KERNEL);
        if (!info)
                return -ENOMEM;
 
@@ -746,57 +745,50 @@ static int noon010_probe(struct i2c_client *client,
        info->curr_win          = &noon010_sizes[0];
 
        if (gpio_is_valid(pdata->gpio_nreset)) {
-               ret = gpio_request(pdata->gpio_nreset, "NOON010PC30 NRST");
+               ret = devm_gpio_request_one(&client->dev, pdata->gpio_nreset,
+                                           GPIOF_OUT_INIT_LOW,
+                                           "NOON010PC30 NRST");
                if (ret) {
                        dev_err(&client->dev, "GPIO request error: %d\n", ret);
                        goto np_err;
                }
                info->gpio_nreset = pdata->gpio_nreset;
-               gpio_direction_output(info->gpio_nreset, 0);
                gpio_export(info->gpio_nreset, 0);
        }
 
        if (gpio_is_valid(pdata->gpio_nstby)) {
-               ret = gpio_request(pdata->gpio_nstby, "NOON010PC30 NSTBY");
+               ret = devm_gpio_request_one(&client->dev, pdata->gpio_nstby,
+                                           GPIOF_OUT_INIT_LOW,
+                                           "NOON010PC30 NSTBY");
                if (ret) {
                        dev_err(&client->dev, "GPIO request error: %d\n", ret);
-                       goto np_gpio_err;
+                       goto np_err;
                }
                info->gpio_nstby = pdata->gpio_nstby;
-               gpio_direction_output(info->gpio_nstby, 0);
                gpio_export(info->gpio_nstby, 0);
        }
 
        for (i = 0; i < NOON010_NUM_SUPPLIES; i++)
                info->supply[i].supply = noon010_supply_name[i];
 
-       ret = regulator_bulk_get(&client->dev, NOON010_NUM_SUPPLIES,
+       ret = devm_regulator_bulk_get(&client->dev, NOON010_NUM_SUPPLIES,
                                 info->supply);
        if (ret)
-               goto np_reg_err;
+               goto np_err;
 
        info->pad.flags = MEDIA_PAD_FL_SOURCE;
        sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR;
        ret = media_entity_init(&sd->entity, 1, &info->pad, 0);
        if (ret < 0)
-               goto np_me_err;
+               goto np_err;
 
        ret = noon010_detect(client, info);
        if (!ret)
                return 0;
 
-np_me_err:
-       regulator_bulk_free(NOON010_NUM_SUPPLIES, info->supply);
-np_reg_err:
-       if (gpio_is_valid(info->gpio_nstby))
-               gpio_free(info->gpio_nstby);
-np_gpio_err:
-       if (gpio_is_valid(info->gpio_nreset))
-               gpio_free(info->gpio_nreset);
 np_err:
        v4l2_ctrl_handler_free(&info->hdl);
        v4l2_device_unregister_subdev(sd);
-       kfree(info);
        return ret;
 }
 
@@ -807,17 +799,8 @@ static int noon010_remove(struct i2c_client *client)
 
        v4l2_device_unregister_subdev(sd);
        v4l2_ctrl_handler_free(&info->hdl);
-
-       regulator_bulk_free(NOON010_NUM_SUPPLIES, info->supply);
-
-       if (gpio_is_valid(info->gpio_nreset))
-               gpio_free(info->gpio_nreset);
-
-       if (gpio_is_valid(info->gpio_nstby))
-               gpio_free(info->gpio_nstby);
-
        media_entity_cleanup(&sd->entity);
-       kfree(info);
+
        return 0;
 }
 
index b0cc927..faa64ba 100644 (file)
@@ -20,7 +20,6 @@
 #include <linux/i2c.h>
 #include <linux/videodev2.h>
 #include <media/v4l2-device.h>
-#include <media/v4l2-chip-ident.h>
 #include <linux/slab.h>
 
 MODULE_DESCRIPTION("OmniVision ov7640 sensor driver");
@@ -59,7 +58,7 @@ static int ov7640_probe(struct i2c_client *client,
        if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
                return -ENODEV;
 
-       sd = kzalloc(sizeof(struct v4l2_subdev), GFP_KERNEL);
+       sd = devm_kzalloc(&client->dev, sizeof(*sd), GFP_KERNEL);
        if (sd == NULL)
                return -ENOMEM;
        v4l2_i2c_subdev_init(sd, client, &ov7640_ops);
@@ -71,7 +70,6 @@ static int ov7640_probe(struct i2c_client *client,
 
        if (write_regs(client, initial_registers) < 0) {
                v4l_err(client, "error initializing OV7640\n");
-               kfree(sd);
                return -ENODEV;
        }
 
@@ -84,7 +82,7 @@ static int ov7640_remove(struct i2c_client *client)
        struct v4l2_subdev *sd = i2c_get_clientdata(client);
 
        v4l2_device_unregister_subdev(sd);
-       kfree(sd);
+
        return 0;
 }
 
index 617ad3f..e8a1ce2 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/delay.h>
 #include <linux/videodev2.h>
 #include <media/v4l2-device.h>
-#include <media/v4l2-chip-ident.h>
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-mediabus.h>
 #include <media/ov7670.h>
@@ -1462,25 +1461,12 @@ static const struct v4l2_ctrl_ops ov7670_ctrl_ops = {
        .g_volatile_ctrl = ov7670_g_volatile_ctrl,
 };
 
-static int ov7670_g_chip_ident(struct v4l2_subdev *sd,
-               struct v4l2_dbg_chip_ident *chip)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_OV7670, 0);
-}
-
 #ifdef CONFIG_VIDEO_ADV_DEBUG
 static int ov7670_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
 {
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
        unsigned char val = 0;
        int ret;
 
-       if (!v4l2_chip_match_i2c_client(client, &reg->match))
-               return -EINVAL;
-       if (!capable(CAP_SYS_ADMIN))
-               return -EPERM;
        ret = ov7670_read(sd, reg->reg & 0xff, &val);
        reg->val = val;
        reg->size = 1;
@@ -1489,12 +1475,6 @@ static int ov7670_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *r
 
 static int ov7670_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg)
 {
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       if (!v4l2_chip_match_i2c_client(client, &reg->match))
-               return -EINVAL;
-       if (!capable(CAP_SYS_ADMIN))
-               return -EPERM;
        ov7670_write(sd, reg->reg & 0xff, reg->val & 0xff);
        return 0;
 }
@@ -1503,7 +1483,6 @@ static int ov7670_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_regis
 /* ----------------------------------------------------------------------- */
 
 static const struct v4l2_subdev_core_ops ov7670_core_ops = {
-       .g_chip_ident = ov7670_g_chip_ident,
        .reset = ov7670_reset,
        .init = ov7670_init,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
@@ -1552,7 +1531,7 @@ static int ov7670_probe(struct i2c_client *client,
        struct ov7670_info *info;
        int ret;
 
-       info = kzalloc(sizeof(struct ov7670_info), GFP_KERNEL);
+       info = devm_kzalloc(&client->dev, sizeof(*info), GFP_KERNEL);
        if (info == NULL)
                return -ENOMEM;
        sd = &info->sd;
@@ -1590,7 +1569,6 @@ static int ov7670_probe(struct i2c_client *client,
                v4l_dbg(1, debug, client,
                        "chip found @ 0x%x (%s) is not an ov7670 chip.\n",
                        client->addr << 1, client->adapter->name);
-               kfree(info);
                return ret;
        }
        v4l_info(client, "chip found @ 0x%02x (%s)\n",
@@ -1635,7 +1613,6 @@ static int ov7670_probe(struct i2c_client *client,
                int err = info->hdl.error;
 
                v4l2_ctrl_handler_free(&info->hdl);
-               kfree(info);
                return err;
        }
        /*
@@ -1659,7 +1636,6 @@ static int ov7670_remove(struct i2c_client *client)
 
        v4l2_device_unregister_subdev(sd);
        v4l2_ctrl_handler_free(&info->hdl);
-       kfree(info);
        return 0;
 }
 
index 9eac531..825ea86 100644 (file)
@@ -1385,9 +1385,12 @@ static int __s5c73m3_power_off(struct s5c73m3 *state)
        }
        return 0;
 err:
-       for (++i; i < S5C73M3_MAX_SUPPLIES; i++)
-               regulator_enable(state->supplies[i].consumer);
-
+       for (++i; i < S5C73M3_MAX_SUPPLIES; i++) {
+               int r = regulator_enable(state->supplies[i].consumer);
+               if (r < 0)
+                       v4l2_err(&state->oif_sd, "Failed to reenable %s: %d\n",
+                                state->supplies[i].supply, r);
+       }
        return ret;
 }
 
@@ -1511,59 +1514,40 @@ static const struct v4l2_subdev_ops oif_subdev_ops = {
        .video  = &s5c73m3_oif_video_ops,
 };
 
-static int s5c73m3_configure_gpio(int nr, int val, const char *name)
-{
-       unsigned long flags = val ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW;
-       int ret;
-
-       if (!gpio_is_valid(nr))
-               return 0;
-       ret = gpio_request_one(nr, flags, name);
-       if (!ret)
-               gpio_export(nr, 0);
-       return ret;
-}
-
-static int s5c73m3_free_gpios(struct s5c73m3 *state)
-{
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(state->gpio); i++) {
-               if (!gpio_is_valid(state->gpio[i].gpio))
-                       continue;
-               gpio_free(state->gpio[i].gpio);
-               state->gpio[i].gpio = -EINVAL;
-       }
-       return 0;
-}
-
 static int s5c73m3_configure_gpios(struct s5c73m3 *state,
                                   const struct s5c73m3_platform_data *pdata)
 {
-       const struct s5c73m3_gpio *gpio = &pdata->gpio_stby;
+       struct device *dev = &state->i2c_client->dev;
+       const struct s5c73m3_gpio *gpio;
+       unsigned long flags;
        int ret;
 
        state->gpio[STBY].gpio = -EINVAL;
        state->gpio[RST].gpio  = -EINVAL;
 
-       ret = s5c73m3_configure_gpio(gpio->gpio, gpio->level, "S5C73M3_STBY");
-       if (ret) {
-               s5c73m3_free_gpios(state);
-               return ret;
+       gpio = &pdata->gpio_stby;
+       if (gpio_is_valid(gpio->gpio)) {
+               flags = (gpio->level ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW)
+                     | GPIOF_EXPORT;
+               ret = devm_gpio_request_one(dev, gpio->gpio, flags,
+                                           "S5C73M3_STBY");
+               if (ret < 0)
+                       return ret;
+
+               state->gpio[STBY] = *gpio;
        }
-       state->gpio[STBY] = *gpio;
-       if (gpio_is_valid(gpio->gpio))
-               gpio_set_value(gpio->gpio, 0);
 
        gpio = &pdata->gpio_reset;
-       ret = s5c73m3_configure_gpio(gpio->gpio, gpio->level, "S5C73M3_RST");
-       if (ret) {
-               s5c73m3_free_gpios(state);
-               return ret;
+       if (gpio_is_valid(gpio->gpio)) {
+               flags = (gpio->level ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW)
+                     | GPIOF_EXPORT;
+               ret = devm_gpio_request_one(dev, gpio->gpio, flags,
+                                           "S5C73M3_RST");
+               if (ret < 0)
+                       return ret;
+
+               state->gpio[RST] = *gpio;
        }
-       state->gpio[RST] = *gpio;
-       if (gpio_is_valid(gpio->gpio))
-               gpio_set_value(gpio->gpio, 0);
 
        return 0;
 }
@@ -1626,10 +1610,11 @@ static int s5c73m3_probe(struct i2c_client *client,
 
        state->mclk_frequency = pdata->mclk_frequency;
        state->bus_type = pdata->bus_type;
+       state->i2c_client = client;
 
        ret = s5c73m3_configure_gpios(state, pdata);
        if (ret)
-               goto out_err1;
+               goto out_err;
 
        for (i = 0; i < S5C73M3_MAX_SUPPLIES; i++)
                state->supplies[i].supply = s5c73m3_supply_names[i];
@@ -1638,12 +1623,12 @@ static int s5c73m3_probe(struct i2c_client *client,
                               state->supplies);
        if (ret) {
                dev_err(dev, "failed to get regulators\n");
-               goto out_err2;
+               goto out_err;
        }
 
        ret = s5c73m3_init_controls(state);
        if (ret)
-               goto out_err2;
+               goto out_err;
 
        state->sensor_pix_size[RES_ISP] = &s5c73m3_isp_resolutions[1];
        state->sensor_pix_size[RES_JPEG] = &s5c73m3_jpeg_resolutions[1];
@@ -1659,16 +1644,12 @@ static int s5c73m3_probe(struct i2c_client *client,
 
        ret = s5c73m3_register_spi_driver(state);
        if (ret < 0)
-               goto out_err2;
-
-       state->i2c_client = client;
+               goto out_err;
 
        v4l2_info(sd, "%s: completed succesfully\n", __func__);
        return 0;
 
-out_err2:
-       s5c73m3_free_gpios(state);
-out_err1:
+out_err:
        media_entity_cleanup(&sd->entity);
        return ret;
 }
@@ -1688,7 +1669,6 @@ static int s5c73m3_remove(struct i2c_client *client)
        media_entity_cleanup(&sensor_sd->entity);
 
        s5c73m3_unregister_spi_driver(state);
-       s5c73m3_free_gpios(state);
 
        return 0;
 }
index 6f3a9c0..8079e26 100644 (file)
@@ -73,7 +73,7 @@ int s5c73m3_spi_write(struct s5c73m3 *state, const void *addr,
 
        memset(padding, 0, sizeof(padding));
 
-       for (i = 0; i < count ; i++) {
+       for (i = 0; i < count; i++) {
                r = spi_xmit(spi_dev, (void *)addr + j, tx_size, SPI_DIR_TX);
                if (r < 0)
                        return r;
@@ -98,7 +98,7 @@ int s5c73m3_spi_read(struct s5c73m3 *state, void *addr,
        unsigned int i, j = 0;
        int r = 0;
 
-       for (i = 0; i < count ; i++) {
+       for (i = 0; i < count; i++) {
                r = spi_xmit(spi_dev, addr + j, tx_size, SPI_DIR_RX);
                if (r < 0)
                        return r;
index bdf5e3d..789c02a 100644 (file)
@@ -1491,58 +1491,41 @@ static const struct v4l2_subdev_ops s5k6aa_subdev_ops = {
 /*
  * GPIO setup
  */
-static int s5k6aa_configure_gpio(int nr, int val, const char *name)
-{
-       unsigned long flags = val ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW;
-       int ret;
-
-       if (!gpio_is_valid(nr))
-               return 0;
-       ret = gpio_request_one(nr, flags, name);
-       if (!ret)
-               gpio_export(nr, 0);
-       return ret;
-}
-
-static void s5k6aa_free_gpios(struct s5k6aa *s5k6aa)
-{
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(s5k6aa->gpio); i++) {
-               if (!gpio_is_valid(s5k6aa->gpio[i].gpio))
-                       continue;
-               gpio_free(s5k6aa->gpio[i].gpio);
-               s5k6aa->gpio[i].gpio = -EINVAL;
-       }
-}
 
 static int s5k6aa_configure_gpios(struct s5k6aa *s5k6aa,
                                  const struct s5k6aa_platform_data *pdata)
 {
-       const struct s5k6aa_gpio *gpio = &pdata->gpio_stby;
+       struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd);
+       const struct s5k6aa_gpio *gpio;
+       unsigned long flags;
        int ret;
 
        s5k6aa->gpio[STBY].gpio = -EINVAL;
        s5k6aa->gpio[RST].gpio  = -EINVAL;
 
-       ret = s5k6aa_configure_gpio(gpio->gpio, gpio->level, "S5K6AA_STBY");
-       if (ret) {
-               s5k6aa_free_gpios(s5k6aa);
-               return ret;
+       gpio = &pdata->gpio_stby;
+       if (gpio_is_valid(gpio->gpio)) {
+               flags = (gpio->level ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW)
+                     | GPIOF_EXPORT;
+               ret = devm_gpio_request_one(&client->dev, gpio->gpio, flags,
+                                           "S5K6AA_STBY");
+               if (ret < 0)
+                       return ret;
+
+               s5k6aa->gpio[STBY] = *gpio;
        }
-       s5k6aa->gpio[STBY] = *gpio;
-       if (gpio_is_valid(gpio->gpio))
-               gpio_set_value(gpio->gpio, 0);
 
        gpio = &pdata->gpio_reset;
-       ret = s5k6aa_configure_gpio(gpio->gpio, gpio->level, "S5K6AA_RST");
-       if (ret) {
-               s5k6aa_free_gpios(s5k6aa);
-               return ret;
+       if (gpio_is_valid(gpio->gpio)) {
+               flags = (gpio->level ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW)
+                     | GPIOF_EXPORT;
+               ret = devm_gpio_request_one(&client->dev, gpio->gpio, flags,
+                                           "S5K6AA_RST");
+               if (ret < 0)
+                       return ret;
+
+               s5k6aa->gpio[RST] = *gpio;
        }
-       s5k6aa->gpio[RST] = *gpio;
-       if (gpio_is_valid(gpio->gpio))
-               gpio_set_value(gpio->gpio, 0);
 
        return 0;
 }
@@ -1593,7 +1576,7 @@ static int s5k6aa_probe(struct i2c_client *client,
 
        ret = s5k6aa_configure_gpios(s5k6aa, pdata);
        if (ret)
-               goto out_err2;
+               goto out_err;
 
        for (i = 0; i < S5K6AA_NUM_SUPPLIES; i++)
                s5k6aa->supplies[i].supply = s5k6aa_supply_names[i];
@@ -1602,12 +1585,12 @@ static int s5k6aa_probe(struct i2c_client *client,
                                 s5k6aa->supplies);
        if (ret) {
                dev_err(&client->dev, "Failed to get regulators\n");
-               goto out_err3;
+               goto out_err;
        }
 
        ret = s5k6aa_initialize_ctrls(s5k6aa);
        if (ret)
-               goto out_err3;
+               goto out_err;
 
        s5k6aa_presets_data_init(s5k6aa);
 
@@ -1618,9 +1601,7 @@ static int s5k6aa_probe(struct i2c_client *client,
 
        return 0;
 
-out_err3:
-       s5k6aa_free_gpios(s5k6aa);
-out_err2:
+out_err:
        media_entity_cleanup(&s5k6aa->sd.entity);
        return ret;
 }
@@ -1628,12 +1609,10 @@ out_err2:
 static int s5k6aa_remove(struct i2c_client *client)
 {
        struct v4l2_subdev *sd = i2c_get_clientdata(client);
-       struct s5k6aa *s5k6aa = to_s5k6aa(sd);
 
        v4l2_device_unregister_subdev(sd);
        v4l2_ctrl_handler_free(sd->ctrl_handler);
        media_entity_cleanup(&sd->entity);
-       s5k6aa_free_gpios(s5k6aa);
 
        return 0;
 }
index b4e1ccb..70bc72e 100644 (file)
@@ -33,7 +33,6 @@
 
 #include <media/saa6588.h>
 #include <media/v4l2-device.h>
-#include <media/v4l2-chip-ident.h>
 
 
 /* insmod options */
@@ -443,17 +442,9 @@ static int saa6588_s_tuner(struct v4l2_subdev *sd, const struct v4l2_tuner *vt)
        return 0;
 }
 
-static int saa6588_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_SAA6588, 0);
-}
-
 /* ----------------------------------------------------------------------- */
 
 static const struct v4l2_subdev_core_ops saa6588_core_ops = {
-       .g_chip_ident = saa6588_g_chip_ident,
        .ioctl = saa6588_ioctl,
 };
 
@@ -478,17 +469,15 @@ static int saa6588_probe(struct i2c_client *client,
        v4l_info(client, "saa6588 found @ 0x%x (%s)\n",
                        client->addr << 1, client->adapter->name);
 
-       s = kzalloc(sizeof(*s), GFP_KERNEL);
+       s = devm_kzalloc(&client->dev, sizeof(*s), GFP_KERNEL);
        if (s == NULL)
                return -ENOMEM;
 
        s->buf_size = bufblocks * 3;
 
-       s->buffer = kmalloc(s->buf_size, GFP_KERNEL);
-       if (s->buffer == NULL) {
-               kfree(s);
+       s->buffer = devm_kzalloc(&client->dev, s->buf_size, GFP_KERNEL);
+       if (s->buffer == NULL)
                return -ENOMEM;
-       }
        sd = &s->sd;
        v4l2_i2c_subdev_init(sd, client, &saa6588_ops);
        spin_lock_init(&s->lock);
@@ -516,8 +505,6 @@ static int saa6588_remove(struct i2c_client *client)
 
        cancel_delayed_work_sync(&s->work);
 
-       kfree(s->buffer);
-       kfree(s);
        return 0;
 }
 
index 51cd4c8..ac43e92 100644 (file)
@@ -35,7 +35,6 @@
 #include <linux/i2c.h>
 #include <linux/videodev2.h>
 #include <media/v4l2-device.h>
-#include <media/v4l2-chip-ident.h>
 #include <media/v4l2-ctrls.h>
 
 MODULE_DESCRIPTION("Philips SAA7110 video decoder driver");
@@ -203,7 +202,7 @@ static v4l2_std_id determine_norm(struct v4l2_subdev *sd)
        status = saa7110_read(sd);
        if (status & 0x40) {
                v4l2_dbg(1, debug, sd, "status=0x%02x (no signal)\n", status);
-               return decoder->norm;   /* no change*/
+               return V4L2_STD_UNKNOWN;
        }
        if ((status & 3) == 0) {
                saa7110_write(sd, 0x06, 0x83);
@@ -265,7 +264,7 @@ static int saa7110_g_input_status(struct v4l2_subdev *sd, u32 *pstatus)
 
 static int saa7110_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
 {
-       *(v4l2_std_id *)std = determine_norm(sd);
+       *std &= determine_norm(sd);
        return 0;
 }
 
@@ -352,13 +351,6 @@ static int saa7110_s_ctrl(struct v4l2_ctrl *ctrl)
        return 0;
 }
 
-static int saa7110_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_SAA7110, 0);
-}
-
 /* ----------------------------------------------------------------------- */
 
 static const struct v4l2_ctrl_ops saa7110_ctrl_ops = {
@@ -366,7 +358,6 @@ static const struct v4l2_ctrl_ops saa7110_ctrl_ops = {
 };
 
 static const struct v4l2_subdev_core_ops saa7110_core_ops = {
-       .g_chip_ident = saa7110_g_chip_ident,
        .g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
        .try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
        .s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
@@ -406,7 +397,7 @@ static int saa7110_probe(struct i2c_client *client,
        v4l_info(client, "chip found @ 0x%x (%s)\n",
                        client->addr << 1, client->adapter->name);
 
-       decoder = kzalloc(sizeof(struct saa7110), GFP_KERNEL);
+       decoder = devm_kzalloc(&client->dev, sizeof(*decoder), GFP_KERNEL);
        if (!decoder)
                return -ENOMEM;
        sd = &decoder->sd;
@@ -428,7 +419,6 @@ static int saa7110_probe(struct i2c_client *client,
                int err = decoder->hdl.error;
 
                v4l2_ctrl_handler_free(&decoder->hdl);
-               kfree(decoder);
                return err;
        }
        v4l2_ctrl_handler_setup(&decoder->hdl);
@@ -469,7 +459,6 @@ static int saa7110_remove(struct i2c_client *client)
 
        v4l2_device_unregister_subdev(sd);
        v4l2_ctrl_handler_free(&decoder->hdl);
-       kfree(decoder);
        return 0;
 }
 
index 52c717d..7fd766e 100644 (file)
@@ -46,7 +46,6 @@
 #include <linux/videodev2.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-ctrls.h>
-#include <media/v4l2-chip-ident.h>
 #include <media/saa7115.h>
 #include <asm/div64.h>
 
@@ -63,6 +62,16 @@ module_param(debug, bool, 0644);
 MODULE_PARM_DESC(debug, "Debug level (0-1)");
 
 
+enum saa711x_model {
+       SAA7111A,
+       SAA7111,
+       SAA7113,
+       GM7113C,
+       SAA7114,
+       SAA7115,
+       SAA7118,
+};
+
 struct saa711x_state {
        struct v4l2_subdev sd;
        struct v4l2_ctrl_handler hdl;
@@ -80,7 +89,7 @@ struct saa711x_state {
        int radio;
        int width;
        int height;
-       u32 ident;
+       enum saa711x_model ident;
        u32 audclk_freq;
        u32 crystal_freq;
        bool ucgc;
@@ -111,10 +120,10 @@ static inline int saa711x_write(struct v4l2_subdev *sd, u8 reg, u8 value)
 /* Sanity routine to check if a register is present */
 static int saa711x_has_reg(const int id, const u8 reg)
 {
-       if (id == V4L2_IDENT_SAA7111)
+       if (id == SAA7111)
                return reg < 0x20 && reg != 0x01 && reg != 0x0f &&
                       (reg < 0x13 || reg > 0x19) && reg != 0x1d && reg != 0x1e;
-       if (id == V4L2_IDENT_SAA7111A)
+       if (id == SAA7111A)
                return reg < 0x20 && reg != 0x01 && reg != 0x0f &&
                       reg != 0x14 && reg != 0x18 && reg != 0x19 &&
                       reg != 0x1d && reg != 0x1e;
@@ -127,16 +136,18 @@ static int saa711x_has_reg(const int id, const u8 reg)
                return 0;
 
        switch (id) {
-       case V4L2_IDENT_SAA7113:
+       case GM7113C:
+               return reg != 0x14 && (reg < 0x18 || reg > 0x1e) && reg < 0x20;
+       case SAA7113:
                return reg != 0x14 && (reg < 0x18 || reg > 0x1e) && (reg < 0x20 || reg > 0x3f) &&
                       reg != 0x5d && reg < 0x63;
-       case V4L2_IDENT_SAA7114:
+       case SAA7114:
                return (reg < 0x1a || reg > 0x1e) && (reg < 0x20 || reg > 0x2f) &&
                       (reg < 0x63 || reg > 0x7f) && reg != 0x33 && reg != 0x37 &&
                       reg != 0x81 && reg < 0xf0;
-       case V4L2_IDENT_SAA7115:
+       case SAA7115:
                return (reg < 0x20 || reg > 0x2f) && reg != 0x65 && (reg < 0xfc || reg > 0xfe);
-       case V4L2_IDENT_SAA7118:
+       case SAA7118:
                return (reg < 0x1a || reg > 0x1d) && (reg < 0x20 || reg > 0x22) &&
                       (reg < 0x26 || reg > 0x28) && reg != 0x33 && reg != 0x37 &&
                       (reg < 0x63 || reg > 0x7f) && reg != 0x81 && reg < 0xf0;
@@ -214,7 +225,10 @@ static const unsigned char saa7111_init[] = {
        0x00, 0x00
 };
 
-/* SAA7113 init codes */
+/* SAA7113/GM7113C init codes
+ * It's important that R_14... R_17 == 0x00
+ * for the gm7113c chip to deliver stable video
+ */
 static const unsigned char saa7113_init[] = {
        R_01_INC_DELAY, 0x08,
        R_02_INPUT_CNTL_1, 0xc2,
@@ -448,6 +462,24 @@ static const unsigned char saa7115_cfg_50hz_video[] = {
 
 /* ============== SAA7715 VIDEO templates (end) =======  */
 
+/* ============== GM7113C VIDEO templates =============  */
+static const unsigned char gm7113c_cfg_60hz_video[] = {
+       R_08_SYNC_CNTL, 0x68,                   /* 0xBO: auto detection, 0x68 = NTSC */
+       R_0E_CHROMA_CNTL_1, 0x07,               /* video autodetection is on */
+
+       0x00, 0x00
+};
+
+static const unsigned char gm7113c_cfg_50hz_video[] = {
+       R_08_SYNC_CNTL, 0x28,                   /* 0x28 = PAL */
+       R_0E_CHROMA_CNTL_1, 0x07,
+
+       0x00, 0x00
+};
+
+/* ============== GM7113C VIDEO templates (end) =======  */
+
+
 static const unsigned char saa7115_cfg_vbi_on[] = {
        R_80_GLOBAL_CNTL_1, 0x00,                       /* reset tasks */
        R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0,            /* reset scaler */
@@ -932,11 +964,17 @@ static void saa711x_set_v4lstd(struct v4l2_subdev *sd, v4l2_std_id std)
        // This works for NTSC-M, SECAM-L and the 50Hz PAL variants.
        if (std & V4L2_STD_525_60) {
                v4l2_dbg(1, debug, sd, "decoder set standard 60 Hz\n");
-               saa711x_writeregs(sd, saa7115_cfg_60hz_video);
+               if (state->ident == GM7113C)
+                       saa711x_writeregs(sd, gm7113c_cfg_60hz_video);
+               else
+                       saa711x_writeregs(sd, saa7115_cfg_60hz_video);
                saa711x_set_size(sd, 720, 480);
        } else {
                v4l2_dbg(1, debug, sd, "decoder set standard 50 Hz\n");
-               saa711x_writeregs(sd, saa7115_cfg_50hz_video);
+               if (state->ident == GM7113C)
+                       saa711x_writeregs(sd, gm7113c_cfg_50hz_video);
+               else
+                       saa711x_writeregs(sd, saa7115_cfg_50hz_video);
                saa711x_set_size(sd, 720, 576);
        }
 
@@ -949,7 +987,8 @@ static void saa711x_set_v4lstd(struct v4l2_subdev *sd, v4l2_std_id std)
        011 NTSC N (3.58MHz)            PAL M (3.58MHz)
        100 reserved                    NTSC-Japan (3.58MHz)
        */
-       if (state->ident <= V4L2_IDENT_SAA7113) {
+       if (state->ident <= SAA7113 ||
+           state->ident == GM7113C) {
                u8 reg = saa711x_read(sd, R_0E_CHROMA_CNTL_1) & 0x8f;
 
                if (std == V4L2_STD_PAL_M) {
@@ -968,9 +1007,8 @@ static void saa711x_set_v4lstd(struct v4l2_subdev *sd, v4l2_std_id std)
                /* restart task B if needed */
                int taskb = saa711x_read(sd, R_80_GLOBAL_CNTL_1) & 0x10;
 
-               if (taskb && state->ident == V4L2_IDENT_SAA7114) {
+               if (taskb && state->ident == SAA7114)
                        saa711x_writeregs(sd, saa7115_cfg_vbi_on);
-               }
 
                /* switch audio mode too! */
                saa711x_s_clock_freq(sd, state->audclk_freq);
@@ -992,7 +1030,7 @@ static void saa711x_set_lcr(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_forma
 
 #else
        /* SAA7113 and SAA7118 also should support VBI - Need testing */
-       if (state->ident != V4L2_IDENT_SAA7115)
+       if (state->ident != SAA7115)
                return;
 #endif
 
@@ -1214,13 +1252,14 @@ static int saa711x_s_routing(struct v4l2_subdev *sd,
                             u32 input, u32 output, u32 config)
 {
        struct saa711x_state *state = to_state(sd);
-       u8 mask = (state->ident <= V4L2_IDENT_SAA7111A) ? 0xf8 : 0xf0;
+       u8 mask = (state->ident <= SAA7111A) ? 0xf8 : 0xf0;
 
        v4l2_dbg(1, debug, sd, "decoder set input %d output %d\n",
                input, output);
 
        /* saa7111/3 does not have these inputs */
-       if (state->ident <= V4L2_IDENT_SAA7113 &&
+       if ((state->ident <= SAA7113 ||
+            state->ident == GM7113C) &&
            (input == SAA7115_COMPOSITE4 ||
             input == SAA7115_COMPOSITE5)) {
                return -EINVAL;
@@ -1235,7 +1274,7 @@ static int saa711x_s_routing(struct v4l2_subdev *sd,
        state->input = input;
 
        /* saa7111 has slightly different input numbering */
-       if (state->ident <= V4L2_IDENT_SAA7111A) {
+       if (state->ident <= SAA7111A) {
                if (input >= SAA7115_COMPOSITE4)
                        input -= 2;
                /* saa7111 specific */
@@ -1258,13 +1297,13 @@ static int saa711x_s_routing(struct v4l2_subdev *sd,
                        (state->input >= SAA7115_SVIDEO0 ? 0x80 : 0x0));
 
        state->output = output;
-       if (state->ident == V4L2_IDENT_SAA7114 ||
-                       state->ident == V4L2_IDENT_SAA7115) {
+       if (state->ident == SAA7114 ||
+                       state->ident == SAA7115) {
                saa711x_write(sd, R_83_X_PORT_I_O_ENA_AND_OUT_CLK,
                                (saa711x_read(sd, R_83_X_PORT_I_O_ENA_AND_OUT_CLK) & 0xfe) |
                                (state->output & 0x01));
        }
-       if (state->ident > V4L2_IDENT_SAA7111A) {
+       if (state->ident > SAA7111A) {
                if (config & SAA7115_IDQ_IS_DEFAULT)
                        saa711x_write(sd, R_85_I_PORT_SIGNAL_POLAR, 0x20);
                else
@@ -1277,7 +1316,7 @@ static int saa711x_s_gpio(struct v4l2_subdev *sd, u32 val)
 {
        struct saa711x_state *state = to_state(sd);
 
-       if (state->ident > V4L2_IDENT_SAA7111A)
+       if (state->ident > SAA7111A)
                return -EINVAL;
        saa711x_write(sd, 0x11, (saa711x_read(sd, 0x11) & 0x7f) |
                (val ? 0x80 : 0));
@@ -1367,7 +1406,7 @@ static int saa711x_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
 
        reg1f = saa711x_read(sd, R_1F_STATUS_BYTE_2_VD_DEC);
 
-       if (state->ident == V4L2_IDENT_SAA7115) {
+       if (state->ident == SAA7115) {
                reg1e = saa711x_read(sd, R_1E_STATUS_BYTE_1_VD_DEC);
 
                v4l2_dbg(1, debug, sd, "Status byte 1 (0x1e)=0x%02x\n", reg1e);
@@ -1389,6 +1428,7 @@ static int saa711x_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
                        *std &= V4L2_STD_SECAM;
                        break;
                default:
+                       *std = V4L2_STD_UNKNOWN;
                        /* Can't detect anything */
                        break;
                }
@@ -1397,8 +1437,10 @@ static int saa711x_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
        v4l2_dbg(1, debug, sd, "Status byte 2 (0x1f)=0x%02x\n", reg1f);
 
        /* horizontal/vertical not locked */
-       if (reg1f & 0x40)
+       if (reg1f & 0x40) {
+               *std = V4L2_STD_UNKNOWN;
                goto ret;
+       }
 
        if (reg1f & 0x20)
                *std &= V4L2_STD_525_60;
@@ -1418,7 +1460,7 @@ static int saa711x_g_input_status(struct v4l2_subdev *sd, u32 *status)
        int reg1f;
 
        *status = V4L2_IN_ST_NO_SIGNAL;
-       if (state->ident == V4L2_IDENT_SAA7115)
+       if (state->ident == SAA7115)
                reg1e = saa711x_read(sd, R_1E_STATUS_BYTE_1_VD_DEC);
        reg1f = saa711x_read(sd, R_1F_STATUS_BYTE_2_VD_DEC);
        if ((reg1f & 0xc1) == 0x81 && (reg1e & 0xc0) == 0x80)
@@ -1429,12 +1471,6 @@ static int saa711x_g_input_status(struct v4l2_subdev *sd, u32 *status)
 #ifdef CONFIG_VIDEO_ADV_DEBUG
 static int saa711x_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
 {
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       if (!v4l2_chip_match_i2c_client(client, &reg->match))
-               return -EINVAL;
-       if (!capable(CAP_SYS_ADMIN))
-               return -EPERM;
        reg->val = saa711x_read(sd, reg->reg & 0xff);
        reg->size = 1;
        return 0;
@@ -1442,25 +1478,11 @@ static int saa711x_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *
 
 static int saa711x_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg)
 {
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       if (!v4l2_chip_match_i2c_client(client, &reg->match))
-               return -EINVAL;
-       if (!capable(CAP_SYS_ADMIN))
-               return -EPERM;
        saa711x_write(sd, reg->reg & 0xff, reg->val & 0xff);
        return 0;
 }
 #endif
 
-static int saa711x_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
-{
-       struct saa711x_state *state = to_state(sd);
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       return v4l2_chip_ident_i2c_client(client, chip, state->ident, 0);
-}
-
 static int saa711x_log_status(struct v4l2_subdev *sd)
 {
        struct saa711x_state *state = to_state(sd);
@@ -1469,7 +1491,7 @@ static int saa711x_log_status(struct v4l2_subdev *sd)
        int vcr;
 
        v4l2_info(sd, "Audio frequency: %d Hz\n", state->audclk_freq);
-       if (state->ident != V4L2_IDENT_SAA7115) {
+       if (state->ident != SAA7115) {
                /* status for the saa7114 */
                reg1f = saa711x_read(sd, R_1F_STATUS_BYTE_2_VD_DEC);
                signalOk = (reg1f & 0xc1) == 0x81;
@@ -1520,7 +1542,6 @@ static const struct v4l2_ctrl_ops saa711x_ctrl_ops = {
 
 static const struct v4l2_subdev_core_ops saa711x_core_ops = {
        .log_status = saa711x_log_status,
-       .g_chip_ident = saa711x_g_chip_ident,
        .g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
        .try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
        .s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
@@ -1571,55 +1592,145 @@ static const struct v4l2_subdev_ops saa711x_ops = {
        .vbi = &saa711x_vbi_ops,
 };
 
+#define CHIP_VER_SIZE  16
+
 /* ----------------------------------------------------------------------- */
 
-static int saa711x_probe(struct i2c_client *client,
-                        const struct i2c_device_id *id)
+/**
+ * saa711x_detect_chip - Detects the saa711x (or clone) variant
+ * @client:            I2C client structure.
+ * @id:                        I2C device ID structure.
+ * @name:              Name of the device to be filled.
+ *
+ * Detects the Philips/NXP saa711x chip, or some clone of it.
+ * if 'id' is NULL or id->driver_data is equal to 1, it auto-probes
+ * the analog demod.
+ * If the tuner is not found, it returns -ENODEV.
+ * If auto-detection is disabled and the tuner doesn't match what it was
+ *     requred, it returns -EINVAL and fills 'name'.
+ * If the chip is found, it returns the chip ID and fills 'name'.
+ */
+static int saa711x_detect_chip(struct i2c_client *client,
+                              const struct i2c_device_id *id,
+                              char *name)
 {
-       struct saa711x_state *state;
-       struct v4l2_subdev *sd;
-       struct v4l2_ctrl_handler *hdl;
-       int i;
-       char name[17];
+       char chip_ver[CHIP_VER_SIZE];
        char chip_id;
-       int autodetect = !id || id->driver_data == 1;
+       int i;
+       int autodetect;
 
-       /* Check if the adapter supports the needed features */
-       if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
-               return -EIO;
+       autodetect = !id || id->driver_data == 1;
 
-       for (i = 0; i < 0x0f; i++) {
+       /* Read the chip version register */
+       for (i = 0; i < CHIP_VER_SIZE; i++) {
                i2c_smbus_write_byte_data(client, 0, i);
-               name[i] = (i2c_smbus_read_byte_data(client, 0) & 0x0f) + '0';
+               chip_ver[i] = i2c_smbus_read_byte_data(client, 0);
+               name[i] = (chip_ver[i] & 0x0f) + '0';
                if (name[i] > '9')
                        name[i] += 'a' - '9' - 1;
        }
        name[i] = '\0';
 
-       chip_id = name[5];
+       /* Check if it is a Philips/NXP chip */
+       if (!memcmp(name + 1, "f711", 4)) {
+               chip_id = name[5];
+               snprintf(name, CHIP_VER_SIZE, "saa711%c", chip_id);
 
-       /* Check whether this chip is part of the saa711x series */
-       if (memcmp(name + 1, "f711", 4)) {
-               v4l_dbg(1, debug, client, "chip found @ 0x%x (ID %s) does not match a known saa711x chip.\n",
-                       client->addr << 1, name);
-               return -ENODEV;
+               if (!autodetect && strcmp(name, id->name))
+                       return -EINVAL;
+
+               switch (chip_id) {
+               case '1':
+                       if (chip_ver[0] & 0xf0) {
+                               snprintf(name, CHIP_VER_SIZE, "saa711%ca", chip_id);
+                               v4l_info(client, "saa7111a variant found\n");
+                               return SAA7111A;
+                       }
+                       return SAA7111;
+               case '3':
+                       return SAA7113;
+               case '4':
+                       return SAA7114;
+               case '5':
+                       return SAA7115;
+               case '8':
+                       return SAA7118;
+               default:
+                       v4l2_info(client,
+                                 "WARNING: Philips/NXP chip unknown - Falling back to saa7111\n");
+                       return SAA7111;
+               }
        }
 
-       /* Safety check */
-       if (!autodetect && id->name[6] != chip_id) {
-               v4l_warn(client, "found saa711%c while %s was expected\n",
-                        chip_id, id->name);
+       /* Check if it is a gm7113c */
+       if (!memcmp(name, "0000", 4)) {
+               chip_id = 0;
+               for (i = 0; i < 4; i++) {
+                       chip_id = chip_id << 1;
+                       chip_id |= (chip_ver[i] & 0x80) ? 1 : 0;
+               }
+
+               /*
+                * Note: From the datasheet, only versions 1 and 2
+                * exists. However, tests on a device labeled as:
+                * "GM7113C 1145" returned "10" on all 16 chip
+                * version (reg 0x00) reads. So, we need to also
+                * accept at least verion 0. For now, let's just
+                * assume that a device that returns "0000" for
+                * the lower nibble is a gm7113c.
+                */
+
+               strlcpy(name, "gm7113c", CHIP_VER_SIZE);
+
+               if (!autodetect && strcmp(name, id->name))
+                       return -EINVAL;
+
+               v4l_dbg(1, debug, client,
+                       "It seems to be a %s chip (%*ph) @ 0x%x.\n",
+                       name, 16, chip_ver, client->addr << 1);
+
+               return GM7113C;
        }
-       snprintf(client->name, sizeof(client->name), "saa711%c", chip_id);
-       v4l_info(client, "saa711%c found (%s) @ 0x%x (%s)\n", chip_id, name,
-                client->addr << 1, client->adapter->name);
 
-       state = kzalloc(sizeof(struct saa711x_state), GFP_KERNEL);
+       /* Chip was not discovered. Return its ID and don't bind */
+       v4l_dbg(1, debug, client, "chip %*ph @ 0x%x is unknown.\n",
+               16, chip_ver, client->addr << 1);
+       return -ENODEV;
+}
+
+static int saa711x_probe(struct i2c_client *client,
+                        const struct i2c_device_id *id)
+{
+       struct saa711x_state *state;
+       struct v4l2_subdev *sd;
+       struct v4l2_ctrl_handler *hdl;
+       int ident;
+       char name[CHIP_VER_SIZE + 1];
+
+       /* Check if the adapter supports the needed features */
+       if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+               return -EIO;
+
+       ident = saa711x_detect_chip(client, id, name);
+       if (ident == -EINVAL) {
+               /* Chip exists, but doesn't match */
+               v4l_warn(client, "found %s while %s was expected\n",
+                        name, id->name);
+               return -ENODEV;
+       }
+       if (ident < 0)
+               return ident;
+
+       strlcpy(client->name, name, sizeof(client->name));
+
+       state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL);
        if (state == NULL)
                return -ENOMEM;
        sd = &state->sd;
        v4l2_i2c_subdev_init(sd, client, &saa711x_ops);
 
+       v4l_info(client, "%s found @ 0x%x (%s)\n", name,
+                client->addr << 1, client->adapter->name);
        hdl = &state->hdl;
        v4l2_ctrl_handler_init(hdl, 6);
        /* add in ascending ID order */
@@ -1640,7 +1751,6 @@ static int saa711x_probe(struct i2c_client *client,
                int err = hdl->error;
 
                v4l2_ctrl_handler_free(hdl);
-               kfree(state);
                return err;
        }
        v4l2_ctrl_auto_cluster(2, &state->agc, 0, true);
@@ -1649,31 +1759,7 @@ static int saa711x_probe(struct i2c_client *client,
        state->output = SAA7115_IPORT_ON;
        state->enable = 1;
        state->radio = 0;
-       switch (chip_id) {
-       case '1':
-               state->ident = V4L2_IDENT_SAA7111;
-               if (saa711x_read(sd, R_00_CHIP_VERSION) & 0xf0) {
-                       v4l_info(client, "saa7111a variant found\n");
-                       state->ident = V4L2_IDENT_SAA7111A;
-               }
-               break;
-       case '3':
-               state->ident = V4L2_IDENT_SAA7113;
-               break;
-       case '4':
-               state->ident = V4L2_IDENT_SAA7114;
-               break;
-       case '5':
-               state->ident = V4L2_IDENT_SAA7115;
-               break;
-       case '8':
-               state->ident = V4L2_IDENT_SAA7118;
-               break;
-       default:
-               state->ident = V4L2_IDENT_SAA7111;
-               v4l2_info(sd, "WARNING: Chip is not known - Falling back to saa7111\n");
-               break;
-       }
+       state->ident = ident;
 
        state->audclk_freq = 48000;
 
@@ -1682,18 +1768,19 @@ static int saa711x_probe(struct i2c_client *client,
        /* init to 60hz/48khz */
        state->crystal_freq = SAA7115_FREQ_24_576_MHZ;
        switch (state->ident) {
-       case V4L2_IDENT_SAA7111:
-       case V4L2_IDENT_SAA7111A:
+       case SAA7111:
+       case SAA7111A:
                saa711x_writeregs(sd, saa7111_init);
                break;
-       case V4L2_IDENT_SAA7113:
+       case GM7113C:
+       case SAA7113:
                saa711x_writeregs(sd, saa7113_init);
                break;
        default:
                state->crystal_freq = SAA7115_FREQ_32_11_MHZ;
                saa711x_writeregs(sd, saa7115_init_auto_input);
        }
-       if (state->ident > V4L2_IDENT_SAA7111A)
+       if (state->ident > SAA7111A)
                saa711x_writeregs(sd, saa7115_init_misc);
        saa711x_set_v4lstd(sd, V4L2_STD_NTSC);
        v4l2_ctrl_handler_setup(hdl);
@@ -1712,7 +1799,6 @@ static int saa711x_remove(struct i2c_client *client)
 
        v4l2_device_unregister_subdev(sd);
        v4l2_ctrl_handler_free(sd->ctrl_handler);
-       kfree(to_state(sd));
        return 0;
 }
 
@@ -1723,6 +1809,7 @@ static const struct i2c_device_id saa711x_id[] = {
        { "saa7114", 0 },
        { "saa7115", 0 },
        { "saa7118", 0 },
+       { "gm7113c", 0 },
        { }
 };
 MODULE_DEVICE_TABLE(i2c, saa711x_id);
index 8a47ac1..264b755 100644 (file)
@@ -54,7 +54,6 @@
 #include <linux/i2c.h>
 #include <linux/videodev2.h>
 #include <media/v4l2-device.h>
-#include <media/v4l2-chip-ident.h>
 #include <media/saa7127.h>
 
 static int debug;
@@ -251,10 +250,15 @@ static struct i2c_reg_value saa7127_init_config_50hz_secam[] = {
  **********************************************************************
  */
 
+enum saa712x_model {
+       SAA7127,
+       SAA7129,
+};
+
 struct saa7127_state {
        struct v4l2_subdev sd;
        v4l2_std_id std;
-       u32 ident;
+       enum saa712x_model ident;
        enum saa7127_input_type input_type;
        enum saa7127_output_type output_type;
        int video_enable;
@@ -482,7 +486,7 @@ static int saa7127_set_std(struct v4l2_subdev *sd, v4l2_std_id std)
                inittab = saa7127_init_config_60hz;
                state->reg_61 = SAA7127_60HZ_DAC_CONTROL;
 
-       } else if (state->ident == V4L2_IDENT_SAA7129 &&
+       } else if (state->ident == SAA7129 &&
                   (std & V4L2_STD_SECAM) &&
                   !(std & (V4L2_STD_625_50 & ~V4L2_STD_SECAM))) {
 
@@ -517,7 +521,7 @@ static int saa7127_set_output_type(struct v4l2_subdev *sd, int output)
                break;
 
        case SAA7127_OUTPUT_TYPE_COMPOSITE:
-               if (state->ident == V4L2_IDENT_SAA7129)
+               if (state->ident == SAA7129)
                        state->reg_2d = 0x20;   /* CVBS only */
                else
                        state->reg_2d = 0x08;   /* 00001000 CVBS only, RGB DAC's off (high impedance mode) */
@@ -525,7 +529,7 @@ static int saa7127_set_output_type(struct v4l2_subdev *sd, int output)
                break;
 
        case SAA7127_OUTPUT_TYPE_SVIDEO:
-               if (state->ident == V4L2_IDENT_SAA7129)
+               if (state->ident == SAA7129)
                        state->reg_2d = 0x18;   /* Y + C */
                else
                        state->reg_2d = 0xff;   /*11111111  croma -> R, luma -> CVBS + G + B */
@@ -543,7 +547,7 @@ static int saa7127_set_output_type(struct v4l2_subdev *sd, int output)
                break;
 
        case SAA7127_OUTPUT_TYPE_BOTH:
-               if (state->ident == V4L2_IDENT_SAA7129)
+               if (state->ident == SAA7129)
                        state->reg_2d = 0x38;
                else
                        state->reg_2d = 0xbf;
@@ -661,12 +665,6 @@ static int saa7127_s_vbi_data(struct v4l2_subdev *sd, const struct v4l2_sliced_v
 #ifdef CONFIG_VIDEO_ADV_DEBUG
 static int saa7127_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
 {
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       if (!v4l2_chip_match_i2c_client(client, &reg->match))
-               return -EINVAL;
-       if (!capable(CAP_SYS_ADMIN))
-               return -EPERM;
        reg->val = saa7127_read(sd, reg->reg & 0xff);
        reg->size = 1;
        return 0;
@@ -674,25 +672,11 @@ static int saa7127_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *
 
 static int saa7127_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg)
 {
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       if (!v4l2_chip_match_i2c_client(client, &reg->match))
-               return -EINVAL;
-       if (!capable(CAP_SYS_ADMIN))
-               return -EPERM;
        saa7127_write(sd, reg->reg & 0xff, reg->val & 0xff);
        return 0;
 }
 #endif
 
-static int saa7127_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
-{
-       struct saa7127_state *state = to_state(sd);
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       return v4l2_chip_ident_i2c_client(client, chip, state->ident, 0);
-}
-
 static int saa7127_log_status(struct v4l2_subdev *sd)
 {
        struct saa7127_state *state = to_state(sd);
@@ -712,7 +696,6 @@ static int saa7127_log_status(struct v4l2_subdev *sd)
 
 static const struct v4l2_subdev_core_ops saa7127_core_ops = {
        .log_status = saa7127_log_status,
-       .g_chip_ident = saa7127_g_chip_ident,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
        .g_register = saa7127_g_register,
        .s_register = saa7127_s_register,
@@ -752,7 +735,7 @@ static int saa7127_probe(struct i2c_client *client,
        v4l_dbg(1, debug, client, "detecting saa7127 client on address 0x%x\n",
                        client->addr << 1);
 
-       state = kzalloc(sizeof(struct saa7127_state), GFP_KERNEL);
+       state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL);
        if (state == NULL)
                return -ENOMEM;
 
@@ -767,7 +750,6 @@ static int saa7127_probe(struct i2c_client *client,
        if ((saa7127_read(sd, 0) & 0xe4) != 0 ||
                        (saa7127_read(sd, 0x29) & 0x3f) != 0x1d) {
                v4l2_dbg(1, debug, sd, "saa7127 not found\n");
-               kfree(state);
                return -ENODEV;
        }
 
@@ -782,10 +764,10 @@ static int saa7127_probe(struct i2c_client *client,
                if (saa7127_read(sd, SAA7129_REG_FADE_KEY_COL2) == 0xaa) {
                        saa7127_write(sd, SAA7129_REG_FADE_KEY_COL2,
                                        read_result);
-                       state->ident = V4L2_IDENT_SAA7129;
+                       state->ident = SAA7129;
                        strlcpy(client->name, "saa7129", I2C_NAME_SIZE);
                } else {
-                       state->ident = V4L2_IDENT_SAA7127;
+                       state->ident = SAA7127;
                        strlcpy(client->name, "saa7127", I2C_NAME_SIZE);
                }
        }
@@ -809,7 +791,7 @@ static int saa7127_probe(struct i2c_client *client,
                saa7127_set_input_type(sd, SAA7127_INPUT_TYPE_NORMAL);
        saa7127_set_video_enable(sd, 1);
 
-       if (state->ident == V4L2_IDENT_SAA7129)
+       if (state->ident == SAA7129)
                saa7127_write_inittab(sd, saa7129_init_config_extra);
        return 0;
 }
@@ -823,7 +805,6 @@ static int saa7127_remove(struct i2c_client *client)
        v4l2_device_unregister_subdev(sd);
        /* Turn off TV output */
        saa7127_set_video_enable(sd, 0);
-       kfree(to_state(sd));
        return 0;
 }
 
@@ -831,10 +812,10 @@ static int saa7127_remove(struct i2c_client *client)
 
 static struct i2c_device_id saa7127_id[] = {
        { "saa7127_auto", 0 },  /* auto-detection */
-       { "saa7126", V4L2_IDENT_SAA7127 },
-       { "saa7127", V4L2_IDENT_SAA7127 },
-       { "saa7128", V4L2_IDENT_SAA7129 },
-       { "saa7129", V4L2_IDENT_SAA7129 },
+       { "saa7126", SAA7127 },
+       { "saa7127", SAA7127 },
+       { "saa7128", SAA7129 },
+       { "saa7129", SAA7129 },
        { }
 };
 MODULE_DEVICE_TABLE(i2c, saa7127_id);
index cf3a0aa..401ca11 100644 (file)
@@ -977,12 +977,6 @@ static int saa717x_s_video_routing(struct v4l2_subdev *sd,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
 static int saa717x_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
 {
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       if (!v4l2_chip_match_i2c_client(client, &reg->match))
-               return -EINVAL;
-       if (!capable(CAP_SYS_ADMIN))
-               return -EPERM;
        reg->val = saa717x_read(sd, reg->reg);
        reg->size = 1;
        return 0;
@@ -990,14 +984,9 @@ static int saa717x_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *
 
 static int saa717x_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg)
 {
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
        u16 addr = reg->reg & 0xffff;
        u8 val = reg->val & 0xff;
 
-       if (!v4l2_chip_match_i2c_client(client, &reg->match))
-               return -EINVAL;
-       if (!capable(CAP_SYS_ADMIN))
-               return -EPERM;
        saa717x_write(sd, addr, val);
        return 0;
 }
@@ -1262,7 +1251,7 @@ static int saa717x_probe(struct i2c_client *client,
        if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
                return -EIO;
 
-       decoder = kzalloc(sizeof(struct saa717x_state), GFP_KERNEL);
+       decoder = devm_kzalloc(&client->dev, sizeof(*decoder), GFP_KERNEL);
        if (decoder == NULL)
                return -ENOMEM;
 
@@ -1276,7 +1265,6 @@ static int saa717x_probe(struct i2c_client *client,
                id = saa717x_read(sd, 0x5a0);
        if (id != 0xc2 && id != 0x32 && id != 0xf2 && id != 0x6c) {
                v4l2_dbg(1, debug, sd, "saa717x not found (id=%02x)\n", id);
-               kfree(decoder);
                return -ENODEV;
        }
        if (id == 0xc2)
@@ -1316,7 +1304,6 @@ static int saa717x_probe(struct i2c_client *client,
                int err = hdl->error;
 
                v4l2_ctrl_handler_free(hdl);
-               kfree(decoder);
                return err;
        }
 
@@ -1353,7 +1340,6 @@ static int saa717x_remove(struct i2c_client *client)
 
        v4l2_device_unregister_subdev(sd);
        v4l2_ctrl_handler_free(sd->ctrl_handler);
-       kfree(to_state(sd));
        return 0;
 }
 
index 2c6b65c..f56c1c8 100644 (file)
@@ -32,7 +32,6 @@
 #include <linux/i2c.h>
 #include <linux/videodev2.h>
 #include <media/v4l2-device.h>
-#include <media/v4l2-chip-ident.h>
 
 MODULE_DESCRIPTION("Philips SAA7185 video encoder driver");
 MODULE_AUTHOR("Dave Perks");
@@ -285,17 +284,9 @@ static int saa7185_s_routing(struct v4l2_subdev *sd,
        return 0;
 }
 
-static int saa7185_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_SAA7185, 0);
-}
-
 /* ----------------------------------------------------------------------- */
 
 static const struct v4l2_subdev_core_ops saa7185_core_ops = {
-       .g_chip_ident = saa7185_g_chip_ident,
        .init = saa7185_init,
 };
 
@@ -326,7 +317,7 @@ static int saa7185_probe(struct i2c_client *client,
        v4l_info(client, "chip found @ 0x%x (%s)\n",
                        client->addr << 1, client->adapter->name);
 
-       encoder = kzalloc(sizeof(struct saa7185), GFP_KERNEL);
+       encoder = devm_kzalloc(&client->dev, sizeof(*encoder), GFP_KERNEL);
        if (encoder == NULL)
                return -ENOMEM;
        encoder->norm = V4L2_STD_NTSC;
@@ -352,7 +343,6 @@ static int saa7185_remove(struct i2c_client *client)
        v4l2_device_unregister_subdev(sd);
        /* SW: output off is active */
        saa7185_write(sd, 0x61, (encoder->reg[0x61]) | 0x40);
-       kfree(encoder);
        return 0;
 }
 
index d7d1670..606a4ba 100644 (file)
@@ -22,7 +22,6 @@
 #include <linux/videodev2.h>
 #include <linux/i2c.h>
 #include <media/v4l2-device.h>
-#include <media/v4l2-chip-ident.h>
 
 #include "saa7191.h"
 
@@ -272,7 +271,7 @@ static int saa7191_querystd(struct v4l2_subdev *sd, v4l2_std_id *norm)
 
        dprintk("SAA7191 extended signal auto-detection...\n");
 
-       *norm = V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM;
+       *norm &= V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM;
        stdc &= ~SAA7191_STDC_SECS;
        ctl3 &= ~(SAA7191_CTL3_FSEL);
 
@@ -303,7 +302,7 @@ static int saa7191_querystd(struct v4l2_subdev *sd, v4l2_std_id *norm)
        if (status & SAA7191_STATUS_FIDT) {
                /* 60Hz signal -> NTSC */
                dprintk("60Hz signal: NTSC\n");
-               *norm = V4L2_STD_NTSC;
+               *norm &= V4L2_STD_NTSC;
                return 0;
        }
 
@@ -325,12 +324,13 @@ static int saa7191_querystd(struct v4l2_subdev *sd, v4l2_std_id *norm)
        if (status & SAA7191_STATUS_FIDT) {
                dprintk("No 50Hz signal\n");
                saa7191_s_std(sd, old_norm);
-               return -EAGAIN;
+               *norm = V4L2_STD_UNKNOWN;
+               return 0;
        }
 
        if (status & SAA7191_STATUS_CODE) {
                dprintk("PAL\n");
-               *norm = V4L2_STD_PAL;
+               *norm &= V4L2_STD_PAL;
                return saa7191_s_std(sd, old_norm);
        }
 
@@ -350,18 +350,19 @@ static int saa7191_querystd(struct v4l2_subdev *sd, v4l2_std_id *norm)
        /* not 50Hz ? */
        if (status & SAA7191_STATUS_FIDT) {
                dprintk("No 50Hz signal\n");
-               err = -EAGAIN;
+               *norm = V4L2_STD_UNKNOWN;
                goto out;
        }
 
        if (status & SAA7191_STATUS_CODE) {
                /* Color detected -> SECAM */
                dprintk("SECAM\n");
-               *norm = V4L2_STD_SECAM;
+               *norm &= V4L2_STD_SECAM;
                return saa7191_s_std(sd, old_norm);
        }
 
        dprintk("No color detected with SECAM - Going back to PAL.\n");
+       *norm = V4L2_STD_UNKNOWN;
 
 out:
        return saa7191_s_std(sd, old_norm);
@@ -567,18 +568,9 @@ static int saa7191_g_input_status(struct v4l2_subdev *sd, u32 *status)
 }
 
 
-static int saa7191_g_chip_ident(struct v4l2_subdev *sd,
-               struct v4l2_dbg_chip_ident *chip)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_SAA7191, 0);
-}
-
 /* ----------------------------------------------------------------------- */
 
 static const struct v4l2_subdev_core_ops saa7191_core_ops = {
-       .g_chip_ident = saa7191_g_chip_ident,
        .g_ctrl = saa7191_g_ctrl,
        .s_ctrl = saa7191_s_ctrl,
        .s_std = saa7191_s_std,
@@ -605,7 +597,7 @@ static int saa7191_probe(struct i2c_client *client,
        v4l_info(client, "chip found @ 0x%x (%s)\n",
                        client->addr << 1, client->adapter->name);
 
-       decoder = kzalloc(sizeof(*decoder), GFP_KERNEL);
+       decoder = devm_kzalloc(&client->dev, sizeof(*decoder), GFP_KERNEL);
        if (!decoder)
                return -ENOMEM;
 
@@ -615,7 +607,6 @@ static int saa7191_probe(struct i2c_client *client,
        err = saa7191_write_block(sd, sizeof(initseq), initseq);
        if (err) {
                printk(KERN_ERR "SAA7191 initialization failed\n");
-               kfree(decoder);
                return err;
        }
 
@@ -636,7 +627,6 @@ static int saa7191_remove(struct i2c_client *client)
        struct v4l2_subdev *sd = i2c_get_clientdata(client);
 
        v4l2_device_unregister_subdev(sd);
-       kfree(to_saa7191(sd));
        return 0;
 }
 
index cae4f46..7ac7580 100644 (file)
@@ -2383,8 +2383,9 @@ static int smiapp_registered(struct v4l2_subdev *subdev)
        }
 
        if (sensor->platform_data->xshutdown != SMIAPP_NO_XSHUTDOWN) {
-               if (gpio_request_one(sensor->platform_data->xshutdown, 0,
-                                    "SMIA++ xshutdown") != 0) {
+               if (devm_gpio_request_one(&client->dev,
+                                         sensor->platform_data->xshutdown, 0,
+                                         "SMIA++ xshutdown") != 0) {
                        dev_err(&client->dev,
                                "unable to acquire reset gpio %d\n",
                                sensor->platform_data->xshutdown);
@@ -2393,10 +2394,8 @@ static int smiapp_registered(struct v4l2_subdev *subdev)
        }
 
        rval = smiapp_power_on(sensor);
-       if (rval) {
-               rval = -ENODEV;
-               goto out_smiapp_power_on;
-       }
+       if (rval)
+               return -ENODEV;
 
        rval = smiapp_identify_module(subdev);
        if (rval) {
@@ -2656,11 +2655,6 @@ out_ident_release:
 
 out_power_off:
        smiapp_power_off(sensor);
-
-out_smiapp_power_on:
-       if (sensor->platform_data->xshutdown != SMIAPP_NO_XSHUTDOWN)
-               gpio_free(sensor->platform_data->xshutdown);
-
        return rval;
 }
 
@@ -2854,12 +2848,10 @@ static int smiapp_remove(struct i2c_client *client)
                device_remove_file(&client->dev, &dev_attr_nvm);
 
        for (i = 0; i < sensor->ssds_used; i++) {
-               media_entity_cleanup(&sensor->ssds[i].sd.entity);
                v4l2_device_unregister_subdev(&sensor->ssds[i].sd);
+               media_entity_cleanup(&sensor->ssds[i].sd.entity);
        }
        smiapp_free_controls(sensor);
-       if (sensor->platform_data->xshutdown != SMIAPP_NO_XSHUTDOWN)
-               gpio_free(sensor->platform_data->xshutdown);
 
        return 0;
 }
index a2a5cbb..1d384a3 100644 (file)
@@ -18,8 +18,9 @@
 #include <linux/module.h>
 
 #include <media/soc_camera.h>
+#include <media/v4l2-async.h>
+#include <media/v4l2-clk.h>
 #include <media/v4l2-subdev.h>
-#include <media/v4l2-chip-ident.h>
 
 /* IMX074 registers */
 
@@ -77,6 +78,7 @@ struct imx074_datafmt {
 struct imx074 {
        struct v4l2_subdev              subdev;
        const struct imx074_datafmt     *fmt;
+       struct v4l2_clk                 *clk;
 };
 
 static const struct imx074_datafmt imx074_colour_fmts[] = {
@@ -251,29 +253,13 @@ static int imx074_s_stream(struct v4l2_subdev *sd, int enable)
        return reg_write(client, MODE_SELECT, !!enable);
 }
 
-static int imx074_g_chip_ident(struct v4l2_subdev *sd,
-                              struct v4l2_dbg_chip_ident *id)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
-               return -EINVAL;
-
-       if (id->match.addr != client->addr)
-               return -ENODEV;
-
-       id->ident       = V4L2_IDENT_IMX074;
-       id->revision    = 0;
-
-       return 0;
-}
-
 static int imx074_s_power(struct v4l2_subdev *sd, int on)
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
+       struct imx074 *priv = to_imx074(client);
 
-       return soc_camera_set_power(&client->dev, ssdd, on);
+       return soc_camera_set_power(&client->dev, ssdd, priv->clk, on);
 }
 
 static int imx074_g_mbus_config(struct v4l2_subdev *sd,
@@ -299,7 +285,6 @@ static struct v4l2_subdev_video_ops imx074_subdev_video_ops = {
 };
 
 static struct v4l2_subdev_core_ops imx074_subdev_core_ops = {
-       .g_chip_ident   = imx074_g_chip_ident,
        .s_power        = imx074_s_power,
 };
 
@@ -431,6 +416,7 @@ static int imx074_probe(struct i2c_client *client,
        struct imx074 *priv;
        struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
        struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
+       int ret;
 
        if (!ssdd) {
                dev_err(&client->dev, "IMX074: missing platform data!\n");
@@ -451,12 +437,35 @@ static int imx074_probe(struct i2c_client *client,
 
        priv->fmt       = &imx074_colour_fmts[0];
 
-       return imx074_video_probe(client);
+       priv->clk = v4l2_clk_get(&client->dev, "mclk");
+       if (IS_ERR(priv->clk)) {
+               dev_info(&client->dev, "Error %ld getting clock\n", PTR_ERR(priv->clk));
+               return -EPROBE_DEFER;
+       }
+
+       ret = soc_camera_power_init(&client->dev, ssdd);
+       if (ret < 0)
+               goto epwrinit;
+
+       ret = imx074_video_probe(client);
+       if (ret < 0)
+               goto eprobe;
+
+       return v4l2_async_register_subdev(&priv->subdev);
+
+epwrinit:
+eprobe:
+       v4l2_clk_put(priv->clk);
+       return ret;
 }
 
 static int imx074_remove(struct i2c_client *client)
 {
        struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
+       struct imx074 *priv = to_imx074(client);
+
+       v4l2_async_unregister_subdev(&priv->subdev);
+       v4l2_clk_put(priv->clk);
 
        if (ssdd->free_bus)
                ssdd->free_bus(ssdd);
index dd90898..df97033 100644 (file)
@@ -16,8 +16,8 @@
 
 #include <media/soc_camera.h>
 #include <media/soc_mediabus.h>
+#include <media/v4l2-clk.h>
 #include <media/v4l2-subdev.h>
-#include <media/v4l2-chip-ident.h>
 #include <media/v4l2-ctrls.h>
 
 /*
@@ -94,10 +94,10 @@ struct mt9m001 {
                struct v4l2_ctrl *exposure;
        };
        struct v4l2_rect rect;  /* Sensor window */
+       struct v4l2_clk *clk;
        const struct mt9m001_datafmt *fmt;
        const struct mt9m001_datafmt *fmts;
        int num_fmts;
-       int model;      /* V4L2_IDENT_MT9M001* codes from v4l2-chip-ident.h */
        unsigned int total_h;
        unsigned short y_skip_top;      /* Lines to skip at the top */
 };
@@ -320,36 +320,15 @@ static int mt9m001_try_fmt(struct v4l2_subdev *sd,
        return 0;
 }
 
-static int mt9m001_g_chip_ident(struct v4l2_subdev *sd,
-                               struct v4l2_dbg_chip_ident *id)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct mt9m001 *mt9m001 = to_mt9m001(client);
-
-       if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
-               return -EINVAL;
-
-       if (id->match.addr != client->addr)
-               return -ENODEV;
-
-       id->ident       = mt9m001->model;
-       id->revision    = 0;
-
-       return 0;
-}
-
 #ifdef CONFIG_VIDEO_ADV_DEBUG
 static int mt9m001_g_register(struct v4l2_subdev *sd,
                              struct v4l2_dbg_register *reg)
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
 
-       if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
+       if (reg->reg > 0xff)
                return -EINVAL;
 
-       if (reg->match.addr != client->addr)
-               return -ENODEV;
-
        reg->size = 2;
        reg->val = reg_read(client, reg->reg);
 
@@ -364,12 +343,9 @@ static int mt9m001_s_register(struct v4l2_subdev *sd,
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
 
-       if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
+       if (reg->reg > 0xff)
                return -EINVAL;
 
-       if (reg->match.addr != client->addr)
-               return -ENODEV;
-
        if (reg_write(client, reg->reg, reg->val) < 0)
                return -EIO;
 
@@ -381,8 +357,9 @@ static int mt9m001_s_power(struct v4l2_subdev *sd, int on)
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
+       struct mt9m001 *mt9m001 = to_mt9m001(client);
 
-       return soc_camera_set_power(&client->dev, ssdd, on);
+       return soc_camera_set_power(&client->dev, ssdd, mt9m001->clk, on);
 }
 
 static int mt9m001_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
@@ -505,11 +482,9 @@ static int mt9m001_video_probe(struct soc_camera_subdev_desc *ssdd,
        switch (data) {
        case 0x8411:
        case 0x8421:
-               mt9m001->model = V4L2_IDENT_MT9M001C12ST;
                mt9m001->fmts = mt9m001_colour_fmts;
                break;
        case 0x8431:
-               mt9m001->model = V4L2_IDENT_MT9M001C12STM;
                mt9m001->fmts = mt9m001_monochrome_fmts;
                break;
        default:
@@ -580,7 +555,6 @@ static const struct v4l2_ctrl_ops mt9m001_ctrl_ops = {
 };
 
 static struct v4l2_subdev_core_ops mt9m001_subdev_core_ops = {
-       .g_chip_ident   = mt9m001_g_chip_ident,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
        .g_register     = mt9m001_g_register,
        .s_register     = mt9m001_s_register,
@@ -710,9 +684,18 @@ static int mt9m001_probe(struct i2c_client *client,
        mt9m001->rect.width     = MT9M001_MAX_WIDTH;
        mt9m001->rect.height    = MT9M001_MAX_HEIGHT;
 
+       mt9m001->clk = v4l2_clk_get(&client->dev, "mclk");
+       if (IS_ERR(mt9m001->clk)) {
+               ret = PTR_ERR(mt9m001->clk);
+               goto eclkget;
+       }
+
        ret = mt9m001_video_probe(ssdd, client);
-       if (ret)
+       if (ret) {
+               v4l2_clk_put(mt9m001->clk);
+eclkget:
                v4l2_ctrl_handler_free(&mt9m001->hdl);
+       }
 
        return ret;
 }
@@ -722,6 +705,7 @@ static int mt9m001_remove(struct i2c_client *client)
        struct mt9m001 *mt9m001 = to_mt9m001(client);
        struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
 
+       v4l2_clk_put(mt9m001->clk);
        v4l2_device_unregister_subdev(&mt9m001->subdev);
        v4l2_ctrl_handler_free(&mt9m001->hdl);
        mt9m001_video_remove(ssdd);
index 8bd4e0d..de3605d 100644 (file)
@@ -17,9 +17,9 @@
 #include <linux/module.h>
 
 #include <media/soc_camera.h>
+#include <media/v4l2-clk.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-ctrls.h>
-#include <media/v4l2-chip-ident.h>
 
 /*
  * MT9M111, MT9M112 and MT9M131:
@@ -205,10 +205,9 @@ struct mt9m111 {
        struct v4l2_subdev subdev;
        struct v4l2_ctrl_handler hdl;
        struct v4l2_ctrl *gain;
-       int model;      /* V4L2_IDENT_MT9M111 or V4L2_IDENT_MT9M112 code
-                        * from v4l2-chip-ident.h */
        struct mt9m111_context *ctx;
        struct v4l2_rect rect;  /* cropping rectangle */
+       struct v4l2_clk *clk;
        int width;              /* output */
        int height;             /* sizes */
        struct mutex power_lock; /* lock to protect power_count */
@@ -600,24 +599,6 @@ static int mt9m111_s_fmt(struct v4l2_subdev *sd,
        return ret;
 }
 
-static int mt9m111_g_chip_ident(struct v4l2_subdev *sd,
-                               struct v4l2_dbg_chip_ident *id)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev);
-
-       if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
-               return -EINVAL;
-
-       if (id->match.addr != client->addr)
-               return -ENODEV;
-
-       id->ident       = mt9m111->model;
-       id->revision    = 0;
-
-       return 0;
-}
-
 #ifdef CONFIG_VIDEO_ADV_DEBUG
 static int mt9m111_g_register(struct v4l2_subdev *sd,
                              struct v4l2_dbg_register *reg)
@@ -625,10 +606,8 @@ static int mt9m111_g_register(struct v4l2_subdev *sd,
        struct i2c_client *client = v4l2_get_subdevdata(sd);
        int val;
 
-       if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0x2ff)
+       if (reg->reg > 0x2ff)
                return -EINVAL;
-       if (reg->match.addr != client->addr)
-               return -ENODEV;
 
        val = mt9m111_reg_read(client, reg->reg);
        reg->size = 2;
@@ -645,12 +624,9 @@ static int mt9m111_s_register(struct v4l2_subdev *sd,
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
 
-       if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0x2ff)
+       if (reg->reg > 0x2ff)
                return -EINVAL;
 
-       if (reg->match.addr != client->addr)
-               return -ENODEV;
-
        if (mt9m111_reg_write(client, reg->reg, reg->val) < 0)
                return -EIO;
 
@@ -801,14 +777,14 @@ static int mt9m111_power_on(struct mt9m111 *mt9m111)
        struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
        int ret;
 
-       ret = soc_camera_power_on(&client->dev, ssdd);
+       ret = soc_camera_power_on(&client->dev, ssdd, mt9m111->clk);
        if (ret < 0)
                return ret;
 
        ret = mt9m111_resume(mt9m111);
        if (ret < 0) {
                dev_err(&client->dev, "Failed to resume the sensor: %d\n", ret);
-               soc_camera_power_off(&client->dev, ssdd);
+               soc_camera_power_off(&client->dev, ssdd, mt9m111->clk);
        }
 
        return ret;
@@ -820,7 +796,7 @@ static void mt9m111_power_off(struct mt9m111 *mt9m111)
        struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
 
        mt9m111_suspend(mt9m111);
-       soc_camera_power_off(&client->dev, ssdd);
+       soc_camera_power_off(&client->dev, ssdd, mt9m111->clk);
 }
 
 static int mt9m111_s_power(struct v4l2_subdev *sd, int on)
@@ -856,7 +832,6 @@ static const struct v4l2_ctrl_ops mt9m111_ctrl_ops = {
 };
 
 static struct v4l2_subdev_core_ops mt9m111_subdev_core_ops = {
-       .g_chip_ident   = mt9m111_g_chip_ident,
        .s_power        = mt9m111_s_power,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
        .g_register     = mt9m111_g_register,
@@ -923,12 +898,10 @@ static int mt9m111_video_probe(struct i2c_client *client)
 
        switch (data) {
        case 0x143a: /* MT9M111 or MT9M131 */
-               mt9m111->model = V4L2_IDENT_MT9M111;
                dev_info(&client->dev,
                        "Detected a MT9M111/MT9M131 chip ID %x\n", data);
                break;
        case 0x148c: /* MT9M112 */
-               mt9m111->model = V4L2_IDENT_MT9M112;
                dev_info(&client->dev, "Detected a MT9M112 chip ID %x\n", data);
                break;
        default:
@@ -1002,9 +975,18 @@ static int mt9m111_probe(struct i2c_client *client,
        mt9m111->lastpage       = -1;
        mutex_init(&mt9m111->power_lock);
 
+       mt9m111->clk = v4l2_clk_get(&client->dev, "mclk");
+       if (IS_ERR(mt9m111->clk)) {
+               ret = PTR_ERR(mt9m111->clk);
+               goto eclkget;
+       }
+
        ret = mt9m111_video_probe(client);
-       if (ret)
+       if (ret) {
+               v4l2_clk_put(mt9m111->clk);
+eclkget:
                v4l2_ctrl_handler_free(&mt9m111->hdl);
+       }
 
        return ret;
 }
@@ -1013,6 +995,7 @@ static int mt9m111_remove(struct i2c_client *client)
 {
        struct mt9m111 *mt9m111 = to_mt9m111(client);
 
+       v4l2_clk_put(mt9m111->clk);
        v4l2_device_unregister_subdev(&mt9m111->subdev);
        v4l2_ctrl_handler_free(&mt9m111->hdl);
 
index 26a15b8..47d18d0 100644 (file)
@@ -18,7 +18,7 @@
 #include <linux/module.h>
 
 #include <media/soc_camera.h>
-#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-clk.h>
 #include <media/v4l2-subdev.h>
 #include <media/v4l2-ctrls.h>
 
@@ -76,7 +76,7 @@ struct mt9t031 {
                struct v4l2_ctrl *exposure;
        };
        struct v4l2_rect rect;  /* Sensor window */
-       int model;      /* V4L2_IDENT_MT9T031* codes from v4l2-chip-ident.h */
+       struct v4l2_clk *clk;
        u16 xskip;
        u16 yskip;
        unsigned int total_h;
@@ -391,36 +391,16 @@ static int mt9t031_try_fmt(struct v4l2_subdev *sd,
        return 0;
 }
 
-static int mt9t031_g_chip_ident(struct v4l2_subdev *sd,
-                               struct v4l2_dbg_chip_ident *id)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct mt9t031 *mt9t031 = to_mt9t031(client);
-
-       if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
-               return -EINVAL;
-
-       if (id->match.addr != client->addr)
-               return -ENODEV;
-
-       id->ident       = mt9t031->model;
-       id->revision    = 0;
-
-       return 0;
-}
-
 #ifdef CONFIG_VIDEO_ADV_DEBUG
 static int mt9t031_g_register(struct v4l2_subdev *sd,
                              struct v4l2_dbg_register *reg)
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
 
-       if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
+       if (reg->reg > 0xff)
                return -EINVAL;
 
-       if (reg->match.addr != client->addr)
-               return -ENODEV;
-
+       reg->size = 1;
        reg->val = reg_read(client, reg->reg);
 
        if (reg->val > 0xffff)
@@ -434,12 +414,9 @@ static int mt9t031_s_register(struct v4l2_subdev *sd,
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
 
-       if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
+       if (reg->reg > 0xff)
                return -EINVAL;
 
-       if (reg->match.addr != client->addr)
-               return -ENODEV;
-
        if (reg_write(client, reg->reg, reg->val) < 0)
                return -EIO;
 
@@ -595,7 +572,7 @@ static int mt9t031_runtime_resume(struct device *dev)
        return 0;
 }
 
-static struct dev_pm_ops mt9t031_dev_pm_ops = {
+static const struct dev_pm_ops mt9t031_dev_pm_ops = {
        .runtime_suspend        = mt9t031_runtime_suspend,
        .runtime_resume         = mt9t031_runtime_resume,
 };
@@ -610,16 +587,17 @@ static int mt9t031_s_power(struct v4l2_subdev *sd, int on)
        struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
        struct video_device *vdev = soc_camera_i2c_to_vdev(client);
+       struct mt9t031 *mt9t031 = to_mt9t031(client);
        int ret;
 
        if (on) {
-               ret = soc_camera_power_on(&client->dev, ssdd);
+               ret = soc_camera_power_on(&client->dev, ssdd, mt9t031->clk);
                if (ret < 0)
                        return ret;
                vdev->dev.type = &mt9t031_dev_type;
        } else {
                vdev->dev.type = NULL;
-               soc_camera_power_off(&client->dev, ssdd);
+               soc_camera_power_off(&client->dev, ssdd, mt9t031->clk);
        }
 
        return 0;
@@ -650,7 +628,6 @@ static int mt9t031_video_probe(struct i2c_client *client)
 
        switch (data) {
        case 0x1621:
-               mt9t031->model = V4L2_IDENT_MT9T031;
                break;
        default:
                dev_err(&client->dev,
@@ -685,7 +662,6 @@ static const struct v4l2_ctrl_ops mt9t031_ctrl_ops = {
 };
 
 static struct v4l2_subdev_core_ops mt9t031_subdev_core_ops = {
-       .g_chip_ident   = mt9t031_g_chip_ident,
        .s_power        = mt9t031_s_power,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
        .g_register     = mt9t031_g_register,
@@ -812,9 +788,18 @@ static int mt9t031_probe(struct i2c_client *client,
        mt9t031->xskip = 1;
        mt9t031->yskip = 1;
 
+       mt9t031->clk = v4l2_clk_get(&client->dev, "mclk");
+       if (IS_ERR(mt9t031->clk)) {
+               ret = PTR_ERR(mt9t031->clk);
+               goto eclkget;
+       }
+
        ret = mt9t031_video_probe(client);
-       if (ret)
+       if (ret) {
+               v4l2_clk_put(mt9t031->clk);
+eclkget:
                v4l2_ctrl_handler_free(&mt9t031->hdl);
+       }
 
        return ret;
 }
@@ -823,6 +808,7 @@ static int mt9t031_remove(struct i2c_client *client)
 {
        struct mt9t031 *mt9t031 = to_mt9t031(client);
 
+       v4l2_clk_put(mt9t031->clk);
        v4l2_device_unregister_subdev(&mt9t031->subdev);
        v4l2_ctrl_handler_free(&mt9t031->hdl);
 
index a7256b7..46f431a 100644 (file)
@@ -27,7 +27,7 @@
 
 #include <media/mt9t112.h>
 #include <media/soc_camera.h>
-#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-clk.h>
 #include <media/v4l2-common.h>
 
 /* you can check PLL/clock info */
@@ -90,8 +90,8 @@ struct mt9t112_priv {
        struct mt9t112_camera_info      *info;
        struct i2c_client               *client;
        struct v4l2_rect                 frame;
+       struct v4l2_clk                 *clk;
        const struct mt9t112_format     *format;
-       int                              model;
        int                              num_formats;
        u32                              flags;
 /* for flags */
@@ -738,17 +738,6 @@ static int mt9t112_init_camera(const struct i2c_client *client)
 /************************************************************************
                        v4l2_subdev_core_ops
 ************************************************************************/
-static int mt9t112_g_chip_ident(struct v4l2_subdev *sd,
-                               struct v4l2_dbg_chip_ident *id)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct mt9t112_priv *priv = to_mt9t112(client);
-
-       id->ident    = priv->model;
-       id->revision = 0;
-
-       return 0;
-}
 
 #ifdef CONFIG_VIDEO_ADV_DEBUG
 static int mt9t112_g_register(struct v4l2_subdev *sd,
@@ -781,12 +770,12 @@ static int mt9t112_s_power(struct v4l2_subdev *sd, int on)
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
+       struct mt9t112_priv *priv = to_mt9t112(client);
 
-       return soc_camera_set_power(&client->dev, ssdd, on);
+       return soc_camera_set_power(&client->dev, ssdd, priv->clk, on);
 }
 
 static struct v4l2_subdev_core_ops mt9t112_subdev_core_ops = {
-       .g_chip_ident   = mt9t112_g_chip_ident,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
        .g_register     = mt9t112_g_register,
        .s_register     = mt9t112_s_register,
@@ -1061,12 +1050,10 @@ static int mt9t112_camera_probe(struct i2c_client *client)
        switch (chipid) {
        case 0x2680:
                devname = "mt9t111";
-               priv->model = V4L2_IDENT_MT9T111;
                priv->num_formats = 1;
                break;
        case 0x2682:
                devname = "mt9t112";
-               priv->model = V4L2_IDENT_MT9T112;
                priv->num_formats = ARRAY_SIZE(mt9t112_cfmts);
                break;
        default:
@@ -1108,18 +1095,26 @@ static int mt9t112_probe(struct i2c_client *client,
 
        v4l2_i2c_subdev_init(&priv->subdev, client, &mt9t112_subdev_ops);
 
+       priv->clk = v4l2_clk_get(&client->dev, "mclk");
+       if (IS_ERR(priv->clk))
+               return PTR_ERR(priv->clk);
+
        ret = mt9t112_camera_probe(client);
-       if (ret)
-               return ret;
 
        /* Cannot fail: using the default supported pixel code */
-       mt9t112_set_params(priv, &rect, V4L2_MBUS_FMT_UYVY8_2X8);
+       if (!ret)
+               mt9t112_set_params(priv, &rect, V4L2_MBUS_FMT_UYVY8_2X8);
+       else
+               v4l2_clk_put(priv->clk);
 
        return ret;
 }
 
 static int mt9t112_remove(struct i2c_client *client)
 {
+       struct mt9t112_priv *priv = to_mt9t112(client);
+
+       v4l2_clk_put(priv->clk);
        return 0;
 }
 
index a295e59..f9f95f8 100644 (file)
@@ -19,7 +19,7 @@
 #include <media/soc_camera.h>
 #include <media/soc_mediabus.h>
 #include <media/v4l2-subdev.h>
-#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-clk.h>
 #include <media/v4l2-ctrls.h>
 
 /*
@@ -133,6 +133,11 @@ static const struct mt9v02x_register mt9v024_register = {
        .pixclk_fv_lv                   = MT9V024_PIXCLK_FV_LV,
 };
 
+enum mt9v022_model {
+       MT9V022IX7ATM,
+       MT9V022IX7ATC,
+};
+
 struct mt9v022 {
        struct v4l2_subdev subdev;
        struct v4l2_ctrl_handler hdl;
@@ -149,11 +154,12 @@ struct mt9v022 {
        struct v4l2_ctrl *hblank;
        struct v4l2_ctrl *vblank;
        struct v4l2_rect rect;  /* Sensor window */
+       struct v4l2_clk *clk;
        const struct mt9v022_datafmt *fmt;
        const struct mt9v022_datafmt *fmts;
        const struct mt9v02x_register *reg;
        int num_fmts;
-       int model;      /* V4L2_IDENT_MT9V022* codes from v4l2-chip-ident.h */
+       enum mt9v022_model model;
        u16 chip_control;
        u16 chip_version;
        unsigned short y_skip_top;      /* Lines to skip at the top */
@@ -406,12 +412,12 @@ static int mt9v022_s_fmt(struct v4l2_subdev *sd,
        switch (mf->code) {
        case V4L2_MBUS_FMT_Y8_1X8:
        case V4L2_MBUS_FMT_Y10_1X10:
-               if (mt9v022->model != V4L2_IDENT_MT9V022IX7ATM)
+               if (mt9v022->model != MT9V022IX7ATM)
                        return -EINVAL;
                break;
        case V4L2_MBUS_FMT_SBGGR8_1X8:
        case V4L2_MBUS_FMT_SBGGR10_1X10:
-               if (mt9v022->model != V4L2_IDENT_MT9V022IX7ATC)
+               if (mt9v022->model != MT9V022IX7ATC)
                        return -EINVAL;
                break;
        default:
@@ -457,36 +463,15 @@ static int mt9v022_try_fmt(struct v4l2_subdev *sd,
        return 0;
 }
 
-static int mt9v022_g_chip_ident(struct v4l2_subdev *sd,
-                               struct v4l2_dbg_chip_ident *id)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct mt9v022 *mt9v022 = to_mt9v022(client);
-
-       if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
-               return -EINVAL;
-
-       if (id->match.addr != client->addr)
-               return -ENODEV;
-
-       id->ident       = mt9v022->model;
-       id->revision    = 0;
-
-       return 0;
-}
-
 #ifdef CONFIG_VIDEO_ADV_DEBUG
 static int mt9v022_g_register(struct v4l2_subdev *sd,
                              struct v4l2_dbg_register *reg)
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
 
-       if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
+       if (reg->reg > 0xff)
                return -EINVAL;
 
-       if (reg->match.addr != client->addr)
-               return -ENODEV;
-
        reg->size = 2;
        reg->val = reg_read(client, reg->reg);
 
@@ -501,12 +486,9 @@ static int mt9v022_s_register(struct v4l2_subdev *sd,
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
 
-       if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
+       if (reg->reg > 0xff)
                return -EINVAL;
 
-       if (reg->match.addr != client->addr)
-               return -ENODEV;
-
        if (reg_write(client, reg->reg, reg->val) < 0)
                return -EIO;
 
@@ -518,8 +500,9 @@ static int mt9v022_s_power(struct v4l2_subdev *sd, int on)
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
+       struct mt9v022 *mt9v022 = to_mt9v022(client);
 
-       return soc_camera_set_power(&client->dev, ssdd, on);
+       return soc_camera_set_power(&client->dev, ssdd, mt9v022->clk, on);
 }
 
 static int mt9v022_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
@@ -706,11 +689,11 @@ static int mt9v022_video_probe(struct i2c_client *client)
        if (sensor_type && (!strcmp("colour", sensor_type) ||
                            !strcmp("color", sensor_type))) {
                ret = reg_write(client, MT9V022_PIXEL_OPERATION_MODE, 4 | 0x11);
-               mt9v022->model = V4L2_IDENT_MT9V022IX7ATC;
+               mt9v022->model = MT9V022IX7ATC;
                mt9v022->fmts = mt9v022_colour_fmts;
        } else {
                ret = reg_write(client, MT9V022_PIXEL_OPERATION_MODE, 0x11);
-               mt9v022->model = V4L2_IDENT_MT9V022IX7ATM;
+               mt9v022->model = MT9V022IX7ATM;
                mt9v022->fmts = mt9v022_monochrome_fmts;
        }
 
@@ -740,7 +723,7 @@ static int mt9v022_video_probe(struct i2c_client *client)
        mt9v022->fmt = &mt9v022->fmts[0];
 
        dev_info(&client->dev, "Detected a MT9V022 chip ID %x, %s sensor\n",
-                data, mt9v022->model == V4L2_IDENT_MT9V022IX7ATM ?
+                data, mt9v022->model == MT9V022IX7ATM ?
                 "monochrome" : "colour");
 
        ret = mt9v022_init(client);
@@ -768,7 +751,6 @@ static const struct v4l2_ctrl_ops mt9v022_ctrl_ops = {
 };
 
 static struct v4l2_subdev_core_ops mt9v022_subdev_core_ops = {
-       .g_chip_ident   = mt9v022_g_chip_ident,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
        .g_register     = mt9v022_g_register,
        .s_register     = mt9v022_s_register,
@@ -957,9 +939,18 @@ static int mt9v022_probe(struct i2c_client *client,
        mt9v022->rect.width     = MT9V022_MAX_WIDTH;
        mt9v022->rect.height    = MT9V022_MAX_HEIGHT;
 
+       mt9v022->clk = v4l2_clk_get(&client->dev, "mclk");
+       if (IS_ERR(mt9v022->clk)) {
+               ret = PTR_ERR(mt9v022->clk);
+               goto eclkget;
+       }
+
        ret = mt9v022_video_probe(client);
-       if (ret)
+       if (ret) {
+               v4l2_clk_put(mt9v022->clk);
+eclkget:
                v4l2_ctrl_handler_free(&mt9v022->hdl);
+       }
 
        return ret;
 }
@@ -969,6 +960,7 @@ static int mt9v022_remove(struct i2c_client *client)
        struct mt9v022 *mt9v022 = to_mt9v022(client);
        struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
 
+       v4l2_clk_put(mt9v022->clk);
        v4l2_device_unregister_subdev(&mt9v022->subdev);
        if (ssdd->free_bus)
                ssdd->free_bus(ssdd);
index e316842..6c6b1c3 100644 (file)
@@ -22,7 +22,7 @@
 #include <linux/videodev2.h>
 
 #include <media/soc_camera.h>
-#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-clk.h>
 #include <media/v4l2-subdev.h>
 #include <media/v4l2-ctrls.h>
 
@@ -303,8 +303,8 @@ struct ov2640_priv {
        struct v4l2_subdev              subdev;
        struct v4l2_ctrl_handler        hdl;
        enum v4l2_mbus_pixelcode        cfmt_code;
+       struct v4l2_clk                 *clk;
        const struct ov2640_win_size    *win;
-       int                             model;
 };
 
 /*
@@ -723,18 +723,6 @@ static int ov2640_s_ctrl(struct v4l2_ctrl *ctrl)
        return -EINVAL;
 }
 
-static int ov2640_g_chip_ident(struct v4l2_subdev *sd,
-                              struct v4l2_dbg_chip_ident *id)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct ov2640_priv *priv = to_ov2640(client);
-
-       id->ident    = priv->model;
-       id->revision = 0;
-
-       return 0;
-}
-
 #ifdef CONFIG_VIDEO_ADV_DEBUG
 static int ov2640_g_register(struct v4l2_subdev *sd,
                             struct v4l2_dbg_register *reg)
@@ -772,8 +760,9 @@ static int ov2640_s_power(struct v4l2_subdev *sd, int on)
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
+       struct ov2640_priv *priv = to_ov2640(client);
 
-       return soc_camera_set_power(&client->dev, ssdd, on);
+       return soc_camera_set_power(&client->dev, ssdd, priv->clk, on);
 }
 
 /* Select the nearest higher resolution for capture */
@@ -1009,7 +998,6 @@ static int ov2640_video_probe(struct i2c_client *client)
        switch (VERSION(pid, ver)) {
        case PID_OV2640:
                devname     = "ov2640";
-               priv->model = V4L2_IDENT_OV2640;
                break;
        default:
                dev_err(&client->dev,
@@ -1034,7 +1022,6 @@ static const struct v4l2_ctrl_ops ov2640_ctrl_ops = {
 };
 
 static struct v4l2_subdev_core_ops ov2640_subdev_core_ops = {
-       .g_chip_ident   = ov2640_g_chip_ident,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
        .g_register     = ov2640_g_register,
        .s_register     = ov2640_s_register,
@@ -1113,11 +1100,20 @@ static int ov2640_probe(struct i2c_client *client,
        if (priv->hdl.error)
                return priv->hdl.error;
 
+       priv->clk = v4l2_clk_get(&client->dev, "mclk");
+       if (IS_ERR(priv->clk)) {
+               ret = PTR_ERR(priv->clk);
+               goto eclkget;
+       }
+
        ret = ov2640_video_probe(client);
-       if (ret)
+       if (ret) {
+               v4l2_clk_put(priv->clk);
+eclkget:
                v4l2_ctrl_handler_free(&priv->hdl);
-       else
+       } else {
                dev_info(&adapter->dev, "OV2640 Probed\n");
+       }
 
        return ret;
 }
@@ -1126,6 +1122,7 @@ static int ov2640_remove(struct i2c_client *client)
 {
        struct ov2640_priv       *priv = to_ov2640(client);
 
+       v4l2_clk_put(priv->clk);
        v4l2_device_unregister_subdev(&priv->subdev);
        v4l2_ctrl_handler_free(&priv->hdl);
        return 0;
index 9aa56de..0a5c5d4 100644 (file)
@@ -24,7 +24,7 @@
 #include <linux/v4l2-mediabus.h>
 
 #include <media/soc_camera.h>
-#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-clk.h>
 #include <media/v4l2-subdev.h>
 
 /* OV5642 registers */
@@ -610,6 +610,7 @@ struct ov5642 {
        struct v4l2_subdev              subdev;
        const struct ov5642_datafmt     *fmt;
        struct v4l2_rect                crop_rect;
+       struct v4l2_clk                 *clk;
 
        /* blanking information */
        int total_width;
@@ -848,23 +849,6 @@ static int ov5642_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
        return 0;
 }
 
-static int ov5642_g_chip_ident(struct v4l2_subdev *sd,
-                              struct v4l2_dbg_chip_ident *id)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
-               return -EINVAL;
-
-       if (id->match.addr != client->addr)
-               return -ENODEV;
-
-       id->ident       = V4L2_IDENT_OV5642;
-       id->revision    = 0;
-
-       return 0;
-}
-
 static int ov5642_s_crop(struct v4l2_subdev *sd, const struct v4l2_crop *a)
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
@@ -935,12 +919,13 @@ static int ov5642_s_power(struct v4l2_subdev *sd, int on)
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
+       struct ov5642 *priv = to_ov5642(client);
        int ret;
 
        if (!on)
-               return soc_camera_power_off(&client->dev, ssdd);
+               return soc_camera_power_off(&client->dev, ssdd, priv->clk);
 
-       ret = soc_camera_power_on(&client->dev, ssdd);
+       ret = soc_camera_power_on(&client->dev, ssdd, priv->clk);
        if (ret < 0)
                return ret;
 
@@ -966,7 +951,6 @@ static struct v4l2_subdev_video_ops ov5642_subdev_video_ops = {
 
 static struct v4l2_subdev_core_ops ov5642_subdev_core_ops = {
        .s_power        = ov5642_s_power,
-       .g_chip_ident   = ov5642_g_chip_ident,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
        .g_register     = ov5642_get_register,
        .s_register     = ov5642_set_register,
@@ -1021,6 +1005,7 @@ static int ov5642_probe(struct i2c_client *client,
 {
        struct ov5642 *priv;
        struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
+       int ret;
 
        if (!ssdd) {
                dev_err(&client->dev, "OV5642: missing platform data!\n");
@@ -1042,13 +1027,23 @@ static int ov5642_probe(struct i2c_client *client,
        priv->total_width = OV5642_DEFAULT_WIDTH + BLANKING_EXTRA_WIDTH;
        priv->total_height = BLANKING_MIN_HEIGHT;
 
-       return ov5642_video_probe(client);
+       priv->clk = v4l2_clk_get(&client->dev, "mclk");
+       if (IS_ERR(priv->clk))
+               return PTR_ERR(priv->clk);
+
+       ret = ov5642_video_probe(client);
+       if (ret < 0)
+               v4l2_clk_put(priv->clk);
+
+       return ret;
 }
 
 static int ov5642_remove(struct i2c_client *client)
 {
        struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
+       struct ov5642 *priv = to_ov5642(client);
 
+       v4l2_clk_put(priv->clk);
        if (ssdd->free_bus)
                ssdd->free_bus(ssdd);
 
index 991202d..ab01598 100644 (file)
@@ -32,7 +32,7 @@
 #include <linux/module.h>
 
 #include <media/soc_camera.h>
-#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-clk.h>
 #include <media/v4l2-ctrls.h>
 
 /* Register definitions */
@@ -196,6 +196,7 @@ struct ov6650 {
                struct v4l2_ctrl *blue;
                struct v4l2_ctrl *red;
        };
+       struct v4l2_clk         *clk;
        bool                    half_scale;     /* scale down output by 2 */
        struct v4l2_rect        rect;           /* sensor cropping window */
        unsigned long           pclk_limit;     /* from host */
@@ -390,16 +391,6 @@ static int ov6550_s_ctrl(struct v4l2_ctrl *ctrl)
        return -EINVAL;
 }
 
-/* Get chip identification */
-static int ov6650_g_chip_ident(struct v4l2_subdev *sd,
-                               struct v4l2_dbg_chip_ident *id)
-{
-       id->ident       = V4L2_IDENT_OV6650;
-       id->revision    = 0;
-
-       return 0;
-}
-
 #ifdef CONFIG_VIDEO_ADV_DEBUG
 static int ov6650_get_register(struct v4l2_subdev *sd,
                                struct v4l2_dbg_register *reg)
@@ -436,8 +427,9 @@ static int ov6650_s_power(struct v4l2_subdev *sd, int on)
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
+       struct ov6650 *priv = to_ov6650(client);
 
-       return soc_camera_set_power(&client->dev, ssdd, on);
+       return soc_camera_set_power(&client->dev, ssdd, priv->clk, on);
 }
 
 static int ov6650_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
@@ -879,7 +871,6 @@ static const struct v4l2_ctrl_ops ov6550_ctrl_ops = {
 };
 
 static struct v4l2_subdev_core_ops ov6650_core_ops = {
-       .g_chip_ident           = ov6650_g_chip_ident,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
        .g_register             = ov6650_get_register,
        .s_register             = ov6650_set_register,
@@ -1025,9 +1016,18 @@ static int ov6650_probe(struct i2c_client *client,
        priv->code        = V4L2_MBUS_FMT_YUYV8_2X8;
        priv->colorspace  = V4L2_COLORSPACE_JPEG;
 
+       priv->clk = v4l2_clk_get(&client->dev, "mclk");
+       if (IS_ERR(priv->clk)) {
+               ret = PTR_ERR(priv->clk);
+               goto eclkget;
+       }
+
        ret = ov6650_video_probe(client);
-       if (ret)
+       if (ret) {
+               v4l2_clk_put(priv->clk);
+eclkget:
                v4l2_ctrl_handler_free(&priv->hdl);
+       }
 
        return ret;
 }
@@ -1036,6 +1036,7 @@ static int ov6650_remove(struct i2c_client *client)
 {
        struct ov6650 *priv = to_ov6650(client);
 
+       v4l2_clk_put(priv->clk);
        v4l2_device_unregister_subdev(&priv->subdev);
        v4l2_ctrl_handler_free(&priv->hdl);
        return 0;
index 713d62e..7f2b3c8 100644 (file)
@@ -26,8 +26,8 @@
 
 #include <media/ov772x.h>
 #include <media/soc_camera.h>
+#include <media/v4l2-clk.h>
 #include <media/v4l2-ctrls.h>
-#include <media/v4l2-chip-ident.h>
 #include <media/v4l2-subdev.h>
 
 /*
@@ -396,10 +396,10 @@ struct ov772x_win_size {
 struct ov772x_priv {
        struct v4l2_subdev                subdev;
        struct v4l2_ctrl_handler          hdl;
+       struct v4l2_clk                  *clk;
        struct ov772x_camera_info        *info;
        const struct ov772x_color_format *cfmt;
        const struct ov772x_win_size     *win;
-       int                               model;
        unsigned short                    flag_vflip:1;
        unsigned short                    flag_hflip:1;
        /* band_filter = COM8[5] ? 256 - BDBASE : 0 */
@@ -620,17 +620,6 @@ static int ov772x_s_ctrl(struct v4l2_ctrl *ctrl)
        return -EINVAL;
 }
 
-static int ov772x_g_chip_ident(struct v4l2_subdev *sd,
-                              struct v4l2_dbg_chip_ident *id)
-{
-       struct ov772x_priv *priv = to_ov772x(sd);
-
-       id->ident    = priv->model;
-       id->revision = 0;
-
-       return 0;
-}
-
 #ifdef CONFIG_VIDEO_ADV_DEBUG
 static int ov772x_g_register(struct v4l2_subdev *sd,
                             struct v4l2_dbg_register *reg)
@@ -668,8 +657,9 @@ static int ov772x_s_power(struct v4l2_subdev *sd, int on)
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
+       struct ov772x_priv *priv = to_ov772x(sd);
 
-       return soc_camera_set_power(&client->dev, ssdd, on);
+       return soc_camera_set_power(&client->dev, ssdd, priv->clk, on);
 }
 
 static const struct ov772x_win_size *ov772x_select_win(u32 width, u32 height)
@@ -965,11 +955,9 @@ static int ov772x_video_probe(struct ov772x_priv *priv)
        switch (VERSION(pid, ver)) {
        case OV7720:
                devname     = "ov7720";
-               priv->model = V4L2_IDENT_OV7720;
                break;
        case OV7725:
                devname     = "ov7725";
-               priv->model = V4L2_IDENT_OV7725;
                break;
        default:
                dev_err(&client->dev,
@@ -997,7 +985,6 @@ static const struct v4l2_ctrl_ops ov772x_ctrl_ops = {
 };
 
 static struct v4l2_subdev_core_ops ov772x_subdev_core_ops = {
-       .g_chip_ident   = ov772x_g_chip_ident,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
        .g_register     = ov772x_g_register,
        .s_register     = ov772x_s_register,
@@ -1088,13 +1075,22 @@ static int ov772x_probe(struct i2c_client *client,
        if (priv->hdl.error)
                return priv->hdl.error;
 
+       priv->clk = v4l2_clk_get(&client->dev, "mclk");
+       if (IS_ERR(priv->clk)) {
+               ret = PTR_ERR(priv->clk);
+               goto eclkget;
+       }
+
        ret = ov772x_video_probe(priv);
        if (ret < 0) {
+               v4l2_clk_put(priv->clk);
+eclkget:
                v4l2_ctrl_handler_free(&priv->hdl);
        } else {
                priv->cfmt = &ov772x_cfmts[0];
                priv->win = &ov772x_win_sizes[0];
        }
+
        return ret;
 }
 
@@ -1102,6 +1098,7 @@ static int ov772x_remove(struct i2c_client *client)
 {
        struct ov772x_priv *priv = to_ov772x(i2c_get_clientdata(client));
 
+       v4l2_clk_put(priv->clk);
        v4l2_device_unregister_subdev(&priv->subdev);
        v4l2_ctrl_handler_free(&priv->hdl);
        return 0;
index 20ca62d..e968c3f 100644 (file)
@@ -28,7 +28,7 @@
 #include <linux/videodev2.h>
 
 #include <media/soc_camera.h>
-#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-clk.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-ctrls.h>
 
@@ -61,7 +61,7 @@ static const struct ov9640_reg ov9640_regs_dflt[] = {
 
 /* Configurations
  * NOTE: for YUV, alter the following registers:
- *             COM12 |= OV9640_COM12_YUV_AVG
+ *             COM12 |= OV9640_COM12_YUV_AVG
  *
  *      for RGB, alter the following registers:
  *             COM7  |= OV9640_COM7_RGB
@@ -287,18 +287,6 @@ static int ov9640_s_ctrl(struct v4l2_ctrl *ctrl)
        return -EINVAL;
 }
 
-/* Get chip identification */
-static int ov9640_g_chip_ident(struct v4l2_subdev *sd,
-                               struct v4l2_dbg_chip_ident *id)
-{
-       struct ov9640_priv *priv = to_ov9640_sensor(sd);
-
-       id->ident       = priv->model;
-       id->revision    = priv->revision;
-
-       return 0;
-}
-
 #ifdef CONFIG_VIDEO_ADV_DEBUG
 static int ov9640_get_register(struct v4l2_subdev *sd,
                                struct v4l2_dbg_register *reg)
@@ -337,8 +325,9 @@ static int ov9640_s_power(struct v4l2_subdev *sd, int on)
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
+       struct ov9640_priv *priv = to_ov9640_sensor(sd);
 
-       return soc_camera_set_power(&client->dev, ssdd, on);
+       return soc_camera_set_power(&client->dev, ssdd, priv->clk, on);
 }
 
 /* select nearest higher resolution for capture */
@@ -615,12 +604,10 @@ static int ov9640_video_probe(struct i2c_client *client)
        switch (VERSION(pid, ver)) {
        case OV9640_V2:
                devname         = "ov9640";
-               priv->model     = V4L2_IDENT_OV9640;
                priv->revision  = 2;
                break;
        case OV9640_V3:
                devname         = "ov9640";
-               priv->model     = V4L2_IDENT_OV9640;
                priv->revision  = 3;
                break;
        default:
@@ -644,7 +631,6 @@ static const struct v4l2_ctrl_ops ov9640_ctrl_ops = {
 };
 
 static struct v4l2_subdev_core_ops ov9640_core_ops = {
-       .g_chip_ident           = ov9640_g_chip_ident,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
        .g_register             = ov9640_get_register,
        .s_register             = ov9640_set_register,
@@ -716,10 +702,18 @@ static int ov9640_probe(struct i2c_client *client,
        if (priv->hdl.error)
                return priv->hdl.error;
 
-       ret = ov9640_video_probe(client);
+       priv->clk = v4l2_clk_get(&client->dev, "mclk");
+       if (IS_ERR(priv->clk)) {
+               ret = PTR_ERR(priv->clk);
+               goto eclkget;
+       }
 
-       if (ret)
+       ret = ov9640_video_probe(client);
+       if (ret) {
+               v4l2_clk_put(priv->clk);
+eclkget:
                v4l2_ctrl_handler_free(&priv->hdl);
+       }
 
        return ret;
 }
@@ -729,6 +723,7 @@ static int ov9640_remove(struct i2c_client *client)
        struct v4l2_subdev *sd = i2c_get_clientdata(client);
        struct ov9640_priv *priv = to_ov9640_sensor(sd);
 
+       v4l2_clk_put(priv->clk);
        v4l2_device_unregister_subdev(&priv->subdev);
        v4l2_ctrl_handler_free(&priv->hdl);
        return 0;
index 6b33a97..65d13ff 100644 (file)
@@ -199,6 +199,7 @@ struct ov9640_reg {
 struct ov9640_priv {
        struct v4l2_subdev              subdev;
        struct v4l2_ctrl_handler        hdl;
+       struct v4l2_clk                 *clk;
 
        int                             model;
        int                             revision;
index 012bd62..ea76863 100644 (file)
@@ -17,7 +17,7 @@
 #include <linux/v4l2-mediabus.h>
 
 #include <media/soc_camera.h>
-#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-clk.h>
 #include <media/v4l2-ctrls.h>
 
 #define to_ov9740(sd)          container_of(sd, struct ov9740_priv, subdev)
@@ -196,8 +196,8 @@ struct ov9740_reg {
 struct ov9740_priv {
        struct v4l2_subdev              subdev;
        struct v4l2_ctrl_handler        hdl;
+       struct v4l2_clk                 *clk;
 
-       int                             ident;
        u16                             model;
        u8                              revision;
        u8                              manid;
@@ -772,18 +772,6 @@ static int ov9740_s_ctrl(struct v4l2_ctrl *ctrl)
        return 0;
 }
 
-/* Get chip identification */
-static int ov9740_g_chip_ident(struct v4l2_subdev *sd,
-                              struct v4l2_dbg_chip_ident *id)
-{
-       struct ov9740_priv *priv = to_ov9740(sd);
-
-       id->ident = priv->ident;
-       id->revision = priv->revision;
-
-       return 0;
-}
-
 static int ov9740_s_power(struct v4l2_subdev *sd, int on)
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
@@ -792,7 +780,7 @@ static int ov9740_s_power(struct v4l2_subdev *sd, int on)
        int ret;
 
        if (on) {
-               ret = soc_camera_power_on(&client->dev, ssdd);
+               ret = soc_camera_power_on(&client->dev, ssdd, priv->clk);
                if (ret < 0)
                        return ret;
 
@@ -806,7 +794,7 @@ static int ov9740_s_power(struct v4l2_subdev *sd, int on)
                        priv->current_enable = true;
                }
 
-               soc_camera_power_off(&client->dev, ssdd);
+               soc_camera_power_off(&client->dev, ssdd, priv->clk);
        }
 
        return 0;
@@ -887,8 +875,6 @@ static int ov9740_video_probe(struct i2c_client *client)
                goto done;
        }
 
-       priv->ident = V4L2_IDENT_OV9740;
-
        dev_info(&client->dev, "ov9740 Model ID 0x%04x, Revision 0x%02x, "
                 "Manufacturer 0x%02x, SMIA Version 0x%02x\n",
                 priv->model, priv->revision, priv->manid, priv->smiaver);
@@ -927,7 +913,6 @@ static struct v4l2_subdev_video_ops ov9740_video_ops = {
 };
 
 static struct v4l2_subdev_core_ops ov9740_core_ops = {
-       .g_chip_ident           = ov9740_g_chip_ident,
        .s_power                = ov9740_s_power,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
        .g_register             = ov9740_get_register,
@@ -975,9 +960,18 @@ static int ov9740_probe(struct i2c_client *client,
        if (priv->hdl.error)
                return priv->hdl.error;
 
+       priv->clk = v4l2_clk_get(&client->dev, "mclk");
+       if (IS_ERR(priv->clk)) {
+               ret = PTR_ERR(priv->clk);
+               goto eclkget;
+       }
+
        ret = ov9740_video_probe(client);
-       if (ret < 0)
+       if (ret < 0) {
+               v4l2_clk_put(priv->clk);
+eclkget:
                v4l2_ctrl_handler_free(&priv->hdl);
+       }
 
        return ret;
 }
@@ -986,6 +980,7 @@ static int ov9740_remove(struct i2c_client *client)
 {
        struct ov9740_priv *priv = i2c_get_clientdata(client);
 
+       v4l2_clk_put(priv->clk);
        v4l2_device_unregister_subdev(&priv->subdev);
        v4l2_ctrl_handler_free(&priv->hdl);
        return 0;
index 1f9ec3b..7e6d978 100644 (file)
@@ -17,8 +17,8 @@
 
 #include <media/rj54n1cb0c.h>
 #include <media/soc_camera.h>
+#include <media/v4l2-clk.h>
 #include <media/v4l2-subdev.h>
-#include <media/v4l2-chip-ident.h>
 #include <media/v4l2-ctrls.h>
 
 #define RJ54N1_DEV_CODE                        0x0400
@@ -151,6 +151,7 @@ struct rj54n1_clock_div {
 struct rj54n1 {
        struct v4l2_subdev subdev;
        struct v4l2_ctrl_handler hdl;
+       struct v4l2_clk *clk;
        struct rj54n1_clock_div clk_div;
        const struct rj54n1_datafmt *fmt;
        struct v4l2_rect rect;  /* Sensor window */
@@ -1120,37 +1121,16 @@ static int rj54n1_s_fmt(struct v4l2_subdev *sd,
        return 0;
 }
 
-static int rj54n1_g_chip_ident(struct v4l2_subdev *sd,
-                              struct v4l2_dbg_chip_ident *id)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
-               return -EINVAL;
-
-       if (id->match.addr != client->addr)
-               return -ENODEV;
-
-       id->ident       = V4L2_IDENT_RJ54N1CB0C;
-       id->revision    = 0;
-
-       return 0;
-}
-
 #ifdef CONFIG_VIDEO_ADV_DEBUG
 static int rj54n1_g_register(struct v4l2_subdev *sd,
                             struct v4l2_dbg_register *reg)
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
 
-       if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR ||
-           reg->reg < 0x400 || reg->reg > 0x1fff)
+       if (reg->reg < 0x400 || reg->reg > 0x1fff)
                /* Registers > 0x0800 are only available from Sharp support */
                return -EINVAL;
 
-       if (reg->match.addr != client->addr)
-               return -ENODEV;
-
        reg->size = 1;
        reg->val = reg_read(client, reg->reg);
 
@@ -1165,14 +1145,10 @@ static int rj54n1_s_register(struct v4l2_subdev *sd,
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
 
-       if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR ||
-           reg->reg < 0x400 || reg->reg > 0x1fff)
+       if (reg->reg < 0x400 || reg->reg > 0x1fff)
                /* Registers >= 0x0800 are only available from Sharp support */
                return -EINVAL;
 
-       if (reg->match.addr != client->addr)
-               return -ENODEV;
-
        if (reg_write(client, reg->reg, reg->val) < 0)
                return -EIO;
 
@@ -1184,8 +1160,9 @@ static int rj54n1_s_power(struct v4l2_subdev *sd, int on)
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
+       struct rj54n1 *rj54n1 = to_rj54n1(client);
 
-       return soc_camera_set_power(&client->dev, ssdd, on);
+       return soc_camera_set_power(&client->dev, ssdd, rj54n1->clk, on);
 }
 
 static int rj54n1_s_ctrl(struct v4l2_ctrl *ctrl)
@@ -1233,7 +1210,6 @@ static const struct v4l2_ctrl_ops rj54n1_ctrl_ops = {
 };
 
 static struct v4l2_subdev_core_ops rj54n1_subdev_core_ops = {
-       .g_chip_ident   = rj54n1_g_chip_ident,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
        .g_register     = rj54n1_g_register,
        .s_register     = rj54n1_s_register,
@@ -1382,9 +1358,18 @@ static int rj54n1_probe(struct i2c_client *client,
        rj54n1->tgclk_mhz       = (rj54n1_priv->mclk_freq / PLL_L * PLL_N) /
                (clk_div.ratio_tg + 1) / (clk_div.ratio_t + 1);
 
+       rj54n1->clk = v4l2_clk_get(&client->dev, "mclk");
+       if (IS_ERR(rj54n1->clk)) {
+               ret = PTR_ERR(rj54n1->clk);
+               goto eclkget;
+       }
+
        ret = rj54n1_video_probe(client, rj54n1_priv);
-       if (ret < 0)
+       if (ret < 0) {
+               v4l2_clk_put(rj54n1->clk);
+eclkget:
                v4l2_ctrl_handler_free(&rj54n1->hdl);
+       }
 
        return ret;
 }
@@ -1394,6 +1379,7 @@ static int rj54n1_remove(struct i2c_client *client)
        struct rj54n1 *rj54n1 = to_rj54n1(client);
        struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
 
+       v4l2_clk_put(rj54n1->clk);
        v4l2_device_unregister_subdev(&rj54n1->subdev);
        if (ssdd->free_bus)
                ssdd->free_bus(ssdd);
index bad90b1..ab54628 100644 (file)
@@ -27,7 +27,7 @@
 
 #include <media/soc_camera.h>
 #include <media/tw9910.h>
-#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-clk.h>
 #include <media/v4l2-subdev.h>
 
 #define GET_ID(val)  ((val & 0xF8) >> 3)
@@ -228,6 +228,7 @@ struct tw9910_scale_ctrl {
 
 struct tw9910_priv {
        struct v4l2_subdev              subdev;
+       struct v4l2_clk                 *clk;
        struct tw9910_video_info        *info;
        const struct tw9910_scale_ctrl  *scale;
        v4l2_std_id                     norm;
@@ -518,18 +519,6 @@ static int tw9910_s_std(struct v4l2_subdev *sd, v4l2_std_id norm)
        return 0;
 }
 
-static int tw9910_g_chip_ident(struct v4l2_subdev *sd,
-                              struct v4l2_dbg_chip_ident *id)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct tw9910_priv *priv = to_tw9910(client);
-
-       id->ident = V4L2_IDENT_TW9910;
-       id->revision = priv->revision;
-
-       return 0;
-}
-
 #ifdef CONFIG_VIDEO_ADV_DEBUG
 static int tw9910_g_register(struct v4l2_subdev *sd,
                             struct v4l2_dbg_register *reg)
@@ -540,6 +529,7 @@ static int tw9910_g_register(struct v4l2_subdev *sd,
        if (reg->reg > 0xff)
                return -EINVAL;
 
+       reg->size = 1;
        ret = i2c_smbus_read_byte_data(client, reg->reg);
        if (ret < 0)
                return ret;
@@ -570,8 +560,9 @@ static int tw9910_s_power(struct v4l2_subdev *sd, int on)
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
+       struct tw9910_priv *priv = to_tw9910(client);
 
-       return soc_camera_set_power(&client->dev, ssdd, on);
+       return soc_camera_set_power(&client->dev, ssdd, priv->clk, on);
 }
 
 static int tw9910_set_frame(struct v4l2_subdev *sd, u32 *width, u32 *height)
@@ -823,7 +814,6 @@ done:
 }
 
 static struct v4l2_subdev_core_ops tw9910_subdev_core_ops = {
-       .g_chip_ident   = tw9910_g_chip_ident,
        .s_std          = tw9910_s_std,
        .g_std          = tw9910_g_std,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
@@ -912,6 +902,7 @@ static int tw9910_probe(struct i2c_client *client,
        struct i2c_adapter              *adapter =
                to_i2c_adapter(client->dev.parent);
        struct soc_camera_subdev_desc   *ssdd = soc_camera_i2c_to_desc(client);
+       int ret;
 
        if (!ssdd || !ssdd->drv_priv) {
                dev_err(&client->dev, "TW9910: missing platform data!\n");
@@ -935,11 +926,21 @@ static int tw9910_probe(struct i2c_client *client,
 
        v4l2_i2c_subdev_init(&priv->subdev, client, &tw9910_subdev_ops);
 
-       return tw9910_video_probe(client);
+       priv->clk = v4l2_clk_get(&client->dev, "mclk");
+       if (IS_ERR(priv->clk))
+               return PTR_ERR(priv->clk);
+
+       ret = tw9910_video_probe(client);
+       if (ret < 0)
+               v4l2_clk_put(priv->clk);
+
+       return ret;
 }
 
 static int tw9910_remove(struct i2c_client *client)
 {
+       struct tw9910_priv *priv = to_tw9910(client);
+       v4l2_clk_put(priv->clk);
        return 0;
 }
 
index 38cbea9..32d8232 100644 (file)
@@ -30,7 +30,7 @@ MODULE_LICENSE("GPL v2");
 
 static int debug;
 module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "debug level 0=off(default) 1=on\n");
+MODULE_PARM_DESC(debug, "debug level 0=off(default) 1=on");
 
 /* #define MPX_DEBUG */
 
@@ -355,7 +355,7 @@ static int sony_btf_mpx_probe(struct i2c_client *client,
        v4l_info(client, "chip found @ 0x%x (%s)\n",
                        client->addr << 1, client->adapter->name);
 
-       t = kzalloc(sizeof(struct sony_btf_mpx), GFP_KERNEL);
+       t = devm_kzalloc(&client->dev, sizeof(*t), GFP_KERNEL);
        if (t == NULL)
                return -ENOMEM;
 
@@ -374,7 +374,6 @@ static int sony_btf_mpx_remove(struct i2c_client *client)
        struct v4l2_subdev *sd = i2c_get_clientdata(client);
 
        v4l2_device_unregister_subdev(sd);
-       kfree(to_state(sd));
 
        return 0;
 }
index e9d95bd..ae94326 100644 (file)
@@ -23,6 +23,7 @@
 #include <media/v4l2-device.h>
 #include <media/v4l2-subdev.h>
 #include <media/v4l2-mediabus.h>
+#include <media/v4l2-ctrls.h>
 #include <media/sr030pc30.h>
 
 static int debug;
@@ -142,17 +143,24 @@ module_param(debug, int, 0644);
 
 struct sr030pc30_info {
        struct v4l2_subdev sd;
+       struct v4l2_ctrl_handler hdl;
        const struct sr030pc30_platform_data *pdata;
        const struct sr030pc30_format *curr_fmt;
        const struct sr030pc30_frmsize *curr_win;
-       unsigned int auto_wb:1;
-       unsigned int auto_exp:1;
        unsigned int hflip:1;
        unsigned int vflip:1;
        unsigned int sleep:1;
-       unsigned int exposure;
-       u8 blue_balance;
-       u8 red_balance;
+       struct {
+               /* auto whitebalance control cluster */
+               struct v4l2_ctrl *awb;
+               struct v4l2_ctrl *red;
+               struct v4l2_ctrl *blue;
+       };
+       struct {
+               /* auto exposure control cluster */
+               struct v4l2_ctrl *autoexp;
+               struct v4l2_ctrl *exp;
+       };
        u8 i2c_reg_page;
 };
 
@@ -173,52 +181,6 @@ struct i2c_regval {
        u16 val;
 };
 
-static const struct v4l2_queryctrl sr030pc30_ctrl[] = {
-       {
-               .id             = V4L2_CID_AUTO_WHITE_BALANCE,
-               .type           = V4L2_CTRL_TYPE_BOOLEAN,
-               .name           = "Auto White Balance",
-               .minimum        = 0,
-               .maximum        = 1,
-               .step           = 1,
-               .default_value  = 1,
-       }, {
-               .id             = V4L2_CID_RED_BALANCE,
-               .type           = V4L2_CTRL_TYPE_INTEGER,
-               .name           = "Red Balance",
-               .minimum        = 0,
-               .maximum        = 127,
-               .step           = 1,
-               .default_value  = 64,
-               .flags          = 0,
-       }, {
-               .id             = V4L2_CID_BLUE_BALANCE,
-               .type           = V4L2_CTRL_TYPE_INTEGER,
-               .name           = "Blue Balance",
-               .minimum        = 0,
-               .maximum        = 127,
-               .step           = 1,
-               .default_value  = 64,
-       }, {
-               .id             = V4L2_CID_EXPOSURE_AUTO,
-               .type           = V4L2_CTRL_TYPE_INTEGER,
-               .name           = "Auto Exposure",
-               .minimum        = 0,
-               .maximum        = 1,
-               .step           = 1,
-               .default_value  = 1,
-       }, {
-               .id             = V4L2_CID_EXPOSURE,
-               .type           = V4L2_CTRL_TYPE_INTEGER,
-               .name           = "Exposure",
-               .minimum        = EXPOS_MIN_MS,
-               .maximum        = EXPOS_MAX_MS,
-               .step           = 1,
-               .default_value  = 1,
-       }, {
-       }
-};
-
 /* supported resolutions */
 static const struct sr030pc30_frmsize sr030pc30_sizes[] = {
        {
@@ -394,48 +356,6 @@ static int sr030pc30_pwr_ctrl(struct v4l2_subdev *sd,
        return ret;
 }
 
-static inline int sr030pc30_enable_autoexposure(struct v4l2_subdev *sd, int on)
-{
-       struct sr030pc30_info *info = to_sr030pc30(sd);
-       /* auto anti-flicker is also enabled here */
-       int ret = cam_i2c_write(sd, AE_CTL1_REG, on ? 0xDC : 0x0C);
-       if (!ret)
-               info->auto_exp = on;
-       return ret;
-}
-
-static int sr030pc30_set_exposure(struct v4l2_subdev *sd, int value)
-{
-       struct sr030pc30_info *info = to_sr030pc30(sd);
-
-       unsigned long expos = value * info->pdata->clk_rate / (8 * 1000);
-
-       int ret = cam_i2c_write(sd, EXP_TIMEH_REG, expos >> 16 & 0xFF);
-       if (!ret)
-               ret = cam_i2c_write(sd, EXP_TIMEM_REG, expos >> 8 & 0xFF);
-       if (!ret)
-               ret = cam_i2c_write(sd, EXP_TIMEL_REG, expos & 0xFF);
-       if (!ret) { /* Turn off AE */
-               info->exposure = value;
-               ret = sr030pc30_enable_autoexposure(sd, 0);
-       }
-       return ret;
-}
-
-/* Automatic white balance control */
-static int sr030pc30_enable_autowhitebalance(struct v4l2_subdev *sd, int on)
-{
-       struct sr030pc30_info *info = to_sr030pc30(sd);
-
-       int ret = cam_i2c_write(sd, AWB_CTL2_REG, on ? 0x2E : 0x2F);
-       if (!ret)
-               ret = cam_i2c_write(sd, AWB_CTL1_REG, on ? 0xFB : 0x7B);
-       if (!ret)
-               info->auto_wb = on;
-
-       return ret;
-}
-
 static int sr030pc30_set_flip(struct v4l2_subdev *sd)
 {
        struct sr030pc30_info *info = to_sr030pc30(sd);
@@ -498,107 +418,56 @@ static int sr030pc30_try_frame_size(struct v4l2_mbus_framefmt *mf)
        return -EINVAL;
 }
 
-static int sr030pc30_queryctrl(struct v4l2_subdev *sd,
-                              struct v4l2_queryctrl *qc)
-{
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(sr030pc30_ctrl); i++)
-               if (qc->id == sr030pc30_ctrl[i].id) {
-                       *qc = sr030pc30_ctrl[i];
-                       v4l2_dbg(1, debug, sd, "%s id: %d\n",
-                                __func__, qc->id);
-                       return 0;
-               }
-
-       return -EINVAL;
-}
-
-static inline int sr030pc30_set_bluebalance(struct v4l2_subdev *sd, int value)
+static int sr030pc30_s_ctrl(struct v4l2_ctrl *ctrl)
 {
-       int ret = cam_i2c_write(sd, MWB_BGAIN_REG, value);
-       if (!ret)
-               to_sr030pc30(sd)->blue_balance = value;
-       return ret;
-}
-
-static inline int sr030pc30_set_redbalance(struct v4l2_subdev *sd, int value)
-{
-       int ret = cam_i2c_write(sd, MWB_RGAIN_REG, value);
-       if (!ret)
-               to_sr030pc30(sd)->red_balance = value;
-       return ret;
-}
-
-static int sr030pc30_s_ctrl(struct v4l2_subdev *sd,
-                           struct v4l2_control *ctrl)
-{
-       int i, ret = 0;
-
-       for (i = 0; i < ARRAY_SIZE(sr030pc30_ctrl); i++)
-               if (ctrl->id == sr030pc30_ctrl[i].id)
-                       break;
-
-       if (i == ARRAY_SIZE(sr030pc30_ctrl))
-               return -EINVAL;
-
-       if (ctrl->value < sr030pc30_ctrl[i].minimum ||
-               ctrl->value > sr030pc30_ctrl[i].maximum)
-                       return -ERANGE;
+       struct sr030pc30_info *info =
+               container_of(ctrl->handler, struct sr030pc30_info, hdl);
+       struct v4l2_subdev *sd = &info->sd;
+       int ret = 0;
 
        v4l2_dbg(1, debug, sd, "%s: ctrl_id: %d, value: %d\n",
-                        __func__, ctrl->id, ctrl->value);
+                        __func__, ctrl->id, ctrl->val);
 
        switch (ctrl->id) {
        case V4L2_CID_AUTO_WHITE_BALANCE:
-               sr030pc30_enable_autowhitebalance(sd, ctrl->value);
-               break;
-       case V4L2_CID_BLUE_BALANCE:
-               ret = sr030pc30_set_bluebalance(sd, ctrl->value);
-               break;
-       case V4L2_CID_RED_BALANCE:
-               ret = sr030pc30_set_redbalance(sd, ctrl->value);
-               break;
-       case V4L2_CID_EXPOSURE_AUTO:
-               sr030pc30_enable_autoexposure(sd,
-                       ctrl->value == V4L2_EXPOSURE_AUTO);
-               break;
-       case V4L2_CID_EXPOSURE:
-               ret = sr030pc30_set_exposure(sd, ctrl->value);
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       return ret;
-}
-
-static int sr030pc30_g_ctrl(struct v4l2_subdev *sd,
-                           struct v4l2_control *ctrl)
-{
-       struct sr030pc30_info *info = to_sr030pc30(sd);
-
-       v4l2_dbg(1, debug, sd, "%s: id: %d\n", __func__, ctrl->id);
+               if (ctrl->is_new) {
+                       ret = cam_i2c_write(sd, AWB_CTL2_REG,
+                                       ctrl->val ? 0x2E : 0x2F);
+                       if (!ret)
+                               ret = cam_i2c_write(sd, AWB_CTL1_REG,
+                                               ctrl->val ? 0xFB : 0x7B);
+               }
+               if (!ret && info->blue->is_new)
+                       ret = cam_i2c_write(sd, MWB_BGAIN_REG, info->blue->val);
+               if (!ret && info->red->is_new)
+                       ret = cam_i2c_write(sd, MWB_RGAIN_REG, info->red->val);
+               return ret;
 
-       switch (ctrl->id) {
-       case V4L2_CID_AUTO_WHITE_BALANCE:
-               ctrl->value = info->auto_wb;
-               break;
-       case V4L2_CID_BLUE_BALANCE:
-               ctrl->value = info->blue_balance;
-               break;
-       case V4L2_CID_RED_BALANCE:
-               ctrl->value = info->red_balance;
-               break;
        case V4L2_CID_EXPOSURE_AUTO:
-               ctrl->value = info->auto_exp;
-               break;
-       case V4L2_CID_EXPOSURE:
-               ctrl->value = info->exposure;
-               break;
+               /* auto anti-flicker is also enabled here */
+               if (ctrl->is_new)
+                       ret = cam_i2c_write(sd, AE_CTL1_REG,
+                               ctrl->val == V4L2_EXPOSURE_AUTO ? 0xDC : 0x0C);
+               if (info->exp->is_new) {
+                       unsigned long expos = info->exp->val;
+
+                       expos = expos * info->pdata->clk_rate / (8 * 1000);
+
+                       if (!ret)
+                               ret = cam_i2c_write(sd, EXP_TIMEH_REG,
+                                               expos >> 16 & 0xFF);
+                       if (!ret)
+                               ret = cam_i2c_write(sd, EXP_TIMEM_REG,
+                                               expos >> 8 & 0xFF);
+                       if (!ret)
+                               ret = cam_i2c_write(sd, EXP_TIMEL_REG,
+                                               expos & 0xFF);
+               }
+               return ret;
        default:
                return -EINVAL;
        }
+
        return 0;
 }
 
@@ -752,11 +621,19 @@ static int sr030pc30_s_power(struct v4l2_subdev *sd, int on)
        return ret;
 }
 
+static const struct v4l2_ctrl_ops sr030pc30_ctrl_ops = {
+       .s_ctrl = sr030pc30_s_ctrl,
+};
+
 static const struct v4l2_subdev_core_ops sr030pc30_core_ops = {
        .s_power        = sr030pc30_s_power,
-       .queryctrl      = sr030pc30_queryctrl,
-       .s_ctrl         = sr030pc30_s_ctrl,
-       .g_ctrl         = sr030pc30_g_ctrl,
+       .g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
+       .try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
+       .s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
+       .g_ctrl = v4l2_subdev_g_ctrl,
+       .s_ctrl = v4l2_subdev_s_ctrl,
+       .queryctrl = v4l2_subdev_queryctrl,
+       .querymenu = v4l2_subdev_querymenu,
 };
 
 static const struct v4l2_subdev_video_ops sr030pc30_video_ops = {
@@ -807,6 +684,7 @@ static int sr030pc30_probe(struct i2c_client *client,
 {
        struct sr030pc30_info *info;
        struct v4l2_subdev *sd;
+       struct v4l2_ctrl_handler *hdl;
        const struct sr030pc30_platform_data *pdata
                = client->dev.platform_data;
        int ret;
@@ -820,7 +698,7 @@ static int sr030pc30_probe(struct i2c_client *client,
        if (ret)
                return ret;
 
-       info = kzalloc(sizeof(*info), GFP_KERNEL);
+       info = devm_kzalloc(&client->dev, sizeof(*info), GFP_KERNEL);
        if (!info)
                return -ENOMEM;
 
@@ -830,10 +708,31 @@ static int sr030pc30_probe(struct i2c_client *client,
 
        v4l2_i2c_subdev_init(sd, client, &sr030pc30_ops);
 
+       hdl = &info->hdl;
+       v4l2_ctrl_handler_init(hdl, 6);
+       info->awb = v4l2_ctrl_new_std(hdl, &sr030pc30_ctrl_ops,
+                       V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, 1);
+       info->red = v4l2_ctrl_new_std(hdl, &sr030pc30_ctrl_ops,
+                       V4L2_CID_RED_BALANCE, 0, 127, 1, 64);
+       info->blue = v4l2_ctrl_new_std(hdl, &sr030pc30_ctrl_ops,
+                       V4L2_CID_BLUE_BALANCE, 0, 127, 1, 64);
+       info->autoexp = v4l2_ctrl_new_std(hdl, &sr030pc30_ctrl_ops,
+                       V4L2_CID_EXPOSURE_AUTO, 0, 1, 1, 1);
+       info->exp = v4l2_ctrl_new_std(hdl, &sr030pc30_ctrl_ops,
+                       V4L2_CID_EXPOSURE, EXPOS_MIN_MS, EXPOS_MAX_MS, 1, 30);
+       sd->ctrl_handler = hdl;
+       if (hdl->error) {
+               int err = hdl->error;
+
+               v4l2_ctrl_handler_free(hdl);
+               return err;
+       }
+       v4l2_ctrl_auto_cluster(3, &info->awb, 0, false);
+       v4l2_ctrl_auto_cluster(2, &info->autoexp, V4L2_EXPOSURE_MANUAL, false);
+       v4l2_ctrl_handler_setup(hdl);
+
        info->i2c_reg_page      = -1;
        info->hflip             = 1;
-       info->auto_exp          = 1;
-       info->exposure          = 30;
 
        return 0;
 }
@@ -841,10 +740,9 @@ static int sr030pc30_probe(struct i2c_client *client,
 static int sr030pc30_remove(struct i2c_client *client)
 {
        struct v4l2_subdev *sd = i2c_get_clientdata(client);
-       struct sr030pc30_info *info = to_sr030pc30(sd);
 
        v4l2_device_unregister_subdev(sd);
-       kfree(info);
+       v4l2_ctrl_handler_free(sd->ctrl_handler);
        return 0;
 }
 
index 28b5121..72af644 100644 (file)
@@ -359,7 +359,7 @@ static int tda7432_probe(struct i2c_client *client,
        v4l_info(client, "chip found @ 0x%02x (%s)\n",
                        client->addr << 1, client->adapter->name);
 
-       t = kzalloc(sizeof(*t), GFP_KERNEL);
+       t = devm_kzalloc(&client->dev, sizeof(*t), GFP_KERNEL);
        if (!t)
                return -ENOMEM;
        sd = &t->sd;
@@ -380,7 +380,6 @@ static int tda7432_probe(struct i2c_client *client,
                int err = t->hdl.error;
 
                v4l2_ctrl_handler_free(&t->hdl);
-               kfree(t);
                return err;
        }
        v4l2_ctrl_cluster(2, &t->bass);
@@ -406,7 +405,6 @@ static int tda7432_remove(struct i2c_client *client)
        tda7432_set(sd);
        v4l2_device_unregister_subdev(sd);
        v4l2_ctrl_handler_free(&t->hdl);
-       kfree(t);
        return 0;
 }
 
index 01441e3..fbdff8b 100644 (file)
@@ -31,7 +31,6 @@
 #include <linux/slab.h>
 #include <linux/i2c.h>
 #include <media/v4l2-device.h>
-#include <media/v4l2-chip-ident.h>
 
 MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
 MODULE_DESCRIPTION("tda9840 driver");
@@ -145,26 +144,14 @@ static int tda9840_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *t)
        return 0;
 }
 
-static int tda9840_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_TDA9840, 0);
-}
-
 /* ----------------------------------------------------------------------- */
 
-static const struct v4l2_subdev_core_ops tda9840_core_ops = {
-       .g_chip_ident = tda9840_g_chip_ident,
-};
-
 static const struct v4l2_subdev_tuner_ops tda9840_tuner_ops = {
        .s_tuner = tda9840_s_tuner,
        .g_tuner = tda9840_g_tuner,
 };
 
 static const struct v4l2_subdev_ops tda9840_ops = {
-       .core = &tda9840_core_ops,
        .tuner = &tda9840_tuner_ops,
 };
 
@@ -184,7 +171,7 @@ static int tda9840_probe(struct i2c_client *client,
        v4l_info(client, "chip found @ 0x%x (%s)\n",
                        client->addr << 1, client->adapter->name);
 
-       sd = kzalloc(sizeof(struct v4l2_subdev), GFP_KERNEL);
+       sd = devm_kzalloc(&client->dev, sizeof(*sd), GFP_KERNEL);
        if (sd == NULL)
                return -ENOMEM;
        v4l2_i2c_subdev_init(sd, client, &tda9840_ops);
@@ -201,7 +188,6 @@ static int tda9840_remove(struct i2c_client *client)
        struct v4l2_subdev *sd = i2c_get_clientdata(client);
 
        v4l2_device_unregister_subdev(sd);
-       kfree(sd);
        return 0;
 }
 
index 3d5b06a..bbe1a99 100644 (file)
@@ -33,7 +33,6 @@
 #include <linux/slab.h>
 #include <linux/i2c.h>
 #include <media/v4l2-device.h>
-#include <media/v4l2-chip-ident.h>
 #include "tea6415c.h"
 
 MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
@@ -119,25 +118,13 @@ static int tea6415c_s_routing(struct v4l2_subdev *sd,
        return ret;
 }
 
-static int tea6415c_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_TEA6415C, 0);
-}
-
 /* ----------------------------------------------------------------------- */
 
-static const struct v4l2_subdev_core_ops tea6415c_core_ops = {
-       .g_chip_ident = tea6415c_g_chip_ident,
-};
-
 static const struct v4l2_subdev_video_ops tea6415c_video_ops = {
        .s_routing = tea6415c_s_routing,
 };
 
 static const struct v4l2_subdev_ops tea6415c_ops = {
-       .core = &tea6415c_core_ops,
        .video = &tea6415c_video_ops,
 };
 
@@ -152,7 +139,7 @@ static int tea6415c_probe(struct i2c_client *client,
 
        v4l_info(client, "chip found @ 0x%x (%s)\n",
                        client->addr << 1, client->adapter->name);
-       sd = kzalloc(sizeof(struct v4l2_subdev), GFP_KERNEL);
+       sd = devm_kzalloc(&client->dev, sizeof(*sd), GFP_KERNEL);
        if (sd == NULL)
                return -ENOMEM;
        v4l2_i2c_subdev_init(sd, client, &tea6415c_ops);
@@ -164,7 +151,6 @@ static int tea6415c_remove(struct i2c_client *client)
        struct v4l2_subdev *sd = i2c_get_clientdata(client);
 
        v4l2_device_unregister_subdev(sd);
-       kfree(sd);
        return 0;
 }
 
index 3875721..30a8d75 100644 (file)
@@ -33,7 +33,6 @@
 #include <linux/slab.h>
 #include <linux/i2c.h>
 #include <media/v4l2-device.h>
-#include <media/v4l2-chip-ident.h>
 #include "tea6420.h"
 
 MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
@@ -90,25 +89,13 @@ static int tea6420_s_routing(struct v4l2_subdev *sd,
        return 0;
 }
 
-static int tea6420_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_TEA6420, 0);
-}
-
 /* ----------------------------------------------------------------------- */
 
-static const struct v4l2_subdev_core_ops tea6420_core_ops = {
-       .g_chip_ident = tea6420_g_chip_ident,
-};
-
 static const struct v4l2_subdev_audio_ops tea6420_audio_ops = {
        .s_routing = tea6420_s_routing,
 };
 
 static const struct v4l2_subdev_ops tea6420_ops = {
-       .core = &tea6420_core_ops,
        .audio = &tea6420_audio_ops,
 };
 
@@ -125,7 +112,7 @@ static int tea6420_probe(struct i2c_client *client,
        v4l_info(client, "chip found @ 0x%x (%s)\n",
                        client->addr << 1, client->adapter->name);
 
-       sd = kzalloc(sizeof(struct v4l2_subdev), GFP_KERNEL);
+       sd = devm_kzalloc(&client->dev, sizeof(*sd), GFP_KERNEL);
        if (sd == NULL)
                return -ENOMEM;
        v4l2_i2c_subdev_init(sd, client, &tea6420_ops);
@@ -146,7 +133,6 @@ static int tea6420_remove(struct i2c_client *client)
        struct v4l2_subdev *sd = i2c_get_clientdata(client);
 
        v4l2_device_unregister_subdev(sd);
-       kfree(sd);
        return 0;
 }
 
index c433955..0a2dacb 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/slab.h>
 
 #include <media/ths7303.h>
-#include <media/v4l2-chip-ident.h>
 #include <media/v4l2-device.h>
 
 #define THS7303_CHANNEL_1      1
 
 struct ths7303_state {
        struct v4l2_subdev              sd;
-       struct ths7303_platform_data    pdata;
+       const struct ths7303_platform_data *pdata;
        struct v4l2_bt_timings          bt;
        int std_id;
        int stream_on;
-       int driver_data;
 };
 
 enum ths7303_filter_mode {
@@ -89,7 +87,7 @@ int ths7303_setval(struct v4l2_subdev *sd, enum ths7303_filter_mode mode)
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct ths7303_state *state = to_state(sd);
-       struct ths7303_platform_data *pdata = &state->pdata;
+       const struct ths7303_platform_data *pdata = state->pdata;
        u8 val, sel = 0;
        int err, disable = 0;
 
@@ -212,15 +210,6 @@ static int ths7303_s_dv_timings(struct v4l2_subdev *sd,
        return ths7303_config(sd);
 }
 
-static int ths7303_g_chip_ident(struct v4l2_subdev *sd,
-                               struct v4l2_dbg_chip_ident *chip)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct ths7303_state *state = to_state(sd);
-
-       return v4l2_chip_ident_i2c_client(client, chip, state->driver_data, 0);
-}
-
 static const struct v4l2_subdev_video_ops ths7303_video_ops = {
        .s_stream       = ths7303_s_stream,
        .s_std_output   = ths7303_s_std_output,
@@ -232,13 +221,6 @@ static const struct v4l2_subdev_video_ops ths7303_video_ops = {
 static int ths7303_g_register(struct v4l2_subdev *sd,
                              struct v4l2_dbg_register *reg)
 {
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       if (!v4l2_chip_match_i2c_client(client, &reg->match))
-               return -EINVAL;
-       if (!capable(CAP_SYS_ADMIN))
-               return -EPERM;
-
        reg->size = 1;
        reg->val = ths7303_read(sd, reg->reg);
        return 0;
@@ -247,13 +229,6 @@ static int ths7303_g_register(struct v4l2_subdev *sd,
 static int ths7303_s_register(struct v4l2_subdev *sd,
                              const struct v4l2_dbg_register *reg)
 {
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       if (!v4l2_chip_match_i2c_client(client, &reg->match))
-               return -EINVAL;
-       if (!capable(CAP_SYS_ADMIN))
-               return -EPERM;
-
        ths7303_write(sd, reg->reg, reg->val);
        return 0;
 }
@@ -340,7 +315,6 @@ static int ths7303_log_status(struct v4l2_subdev *sd)
 }
 
 static const struct v4l2_subdev_core_ops ths7303_core_ops = {
-       .g_chip_ident = ths7303_g_chip_ident,
        .log_status = ths7303_log_status,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
        .g_register = ths7303_g_register,
@@ -353,32 +327,6 @@ static const struct v4l2_subdev_ops ths7303_ops = {
        .video  = &ths7303_video_ops,
 };
 
-static int ths7303_setup(struct v4l2_subdev *sd)
-{
-       struct ths7303_state *state = to_state(sd);
-       struct ths7303_platform_data *pdata = &state->pdata;
-       int ret;
-       u8 mask;
-
-       state->stream_on = pdata->init_enable;
-
-       mask = state->stream_on ? 0xff : 0xf8;
-
-       ret = ths7303_write(sd, THS7303_CHANNEL_1, pdata->ch_1 & mask);
-       if (ret)
-               return ret;
-
-       ret = ths7303_write(sd, THS7303_CHANNEL_2, pdata->ch_2 & mask);
-       if (ret)
-               return ret;
-
-       ret = ths7303_write(sd, THS7303_CHANNEL_3, pdata->ch_3 & mask);
-       if (ret)
-               return ret;
-
-       return 0;
-}
-
 static int ths7303_probe(struct i2c_client *client,
                        const struct i2c_device_id *id)
 {
@@ -386,6 +334,11 @@ static int ths7303_probe(struct i2c_client *client,
        struct ths7303_state *state;
        struct v4l2_subdev *sd;
 
+       if (pdata == NULL) {
+               dev_err(&client->dev, "No platform data\n");
+               return -EINVAL;
+       }
+
        if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
                return -ENODEV;
 
@@ -397,20 +350,14 @@ static int ths7303_probe(struct i2c_client *client,
        if (!state)
                return -ENOMEM;
 
-       if (!pdata)
-               v4l_warn(client, "No platform data, using default data!\n");
-       else
-               state->pdata = *pdata;
-
+       state->pdata = pdata;
        sd = &state->sd;
        v4l2_i2c_subdev_init(sd, client, &ths7303_ops);
 
-       /* store the driver data to differntiate the chip */
-       state->driver_data = (int)id->driver_data;
-
-       if (ths7303_setup(sd) < 0) {
-               v4l_err(client, "init failed\n");
-               return -EIO;
+       /* set to default 480I_576I filter mode */
+       if (ths7303_setval(sd, THS7303_FILTER_MODE_480I_576I) < 0) {
+               v4l_err(client, "Setting to 480I_576I filter mode failed!\n");
+               return -EINVAL;
        }
 
        return 0;
@@ -426,8 +373,8 @@ static int ths7303_remove(struct i2c_client *client)
 }
 
 static const struct i2c_device_id ths7303_id[] = {
-       {"ths7303", V4L2_IDENT_THS7303},
-       {"ths7353", V4L2_IDENT_THS7353},
+       {"ths7303", 0},
+       {"ths7353", 0},
        {},
 };
 
diff --git a/drivers/media/i2c/ths8200.c b/drivers/media/i2c/ths8200.c
new file mode 100644 (file)
index 0000000..a24f90c
--- /dev/null
@@ -0,0 +1,556 @@
+/*
+ * ths8200 - Texas Instruments THS8200 video encoder driver
+ *
+ * Copyright 2013 Cisco Systems, Inc. and/or its affiliates.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is 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/i2c.h>
+#include <linux/module.h>
+#include <linux/v4l2-dv-timings.h>
+
+#include <media/v4l2-device.h>
+
+#include "ths8200_regs.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "debug level (0-2)");
+
+MODULE_DESCRIPTION("Texas Instruments THS8200 video encoder driver");
+MODULE_AUTHOR("Mats Randgaard <mats.randgaard@cisco.com>");
+MODULE_AUTHOR("Martin Bugge <martin.bugge@cisco.com>");
+MODULE_LICENSE("GPL v2");
+
+struct ths8200_state {
+       struct v4l2_subdev sd;
+       uint8_t chip_version;
+       /* Is the ths8200 powered on? */
+       bool power_on;
+       struct v4l2_dv_timings dv_timings;
+};
+
+static const struct v4l2_dv_timings ths8200_timings[] = {
+       V4L2_DV_BT_CEA_720X480P59_94,
+       V4L2_DV_BT_CEA_1280X720P24,
+       V4L2_DV_BT_CEA_1280X720P25,
+       V4L2_DV_BT_CEA_1280X720P30,
+       V4L2_DV_BT_CEA_1280X720P50,
+       V4L2_DV_BT_CEA_1280X720P60,
+       V4L2_DV_BT_CEA_1920X1080P24,
+       V4L2_DV_BT_CEA_1920X1080P25,
+       V4L2_DV_BT_CEA_1920X1080P30,
+       V4L2_DV_BT_CEA_1920X1080P50,
+       V4L2_DV_BT_CEA_1920X1080P60,
+};
+
+static inline struct ths8200_state *to_state(struct v4l2_subdev *sd)
+{
+       return container_of(sd, struct ths8200_state, sd);
+}
+
+static inline unsigned hblanking(const struct v4l2_bt_timings *t)
+{
+       return t->hfrontporch + t->hsync + t->hbackporch;
+}
+
+static inline unsigned htotal(const struct v4l2_bt_timings *t)
+{
+       return t->width + t->hfrontporch + t->hsync + t->hbackporch;
+}
+
+static inline unsigned vblanking(const struct v4l2_bt_timings *t)
+{
+       return t->vfrontporch + t->vsync + t->vbackporch;
+}
+
+static inline unsigned vtotal(const struct v4l2_bt_timings *t)
+{
+       return t->height + t->vfrontporch + t->vsync + t->vbackporch;
+}
+
+static int ths8200_read(struct v4l2_subdev *sd, u8 reg)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       return i2c_smbus_read_byte_data(client, reg);
+}
+
+static int ths8200_write(struct v4l2_subdev *sd, u8 reg, u8 val)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       int ret;
+       int i;
+
+       for (i = 0; i < 3; i++) {
+               ret = i2c_smbus_write_byte_data(client, reg, val);
+               if (ret == 0)
+                       return 0;
+       }
+       v4l2_err(sd, "I2C Write Problem\n");
+       return ret;
+}
+
+/* To set specific bits in the register, a clear-mask is given (to be AND-ed),
+ * and then the value-mask (to be OR-ed).
+ */
+static inline void
+ths8200_write_and_or(struct v4l2_subdev *sd, u8 reg,
+                    uint8_t clr_mask, uint8_t val_mask)
+{
+       ths8200_write(sd, reg, (ths8200_read(sd, reg) & clr_mask) | val_mask);
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+
+static int ths8200_g_register(struct v4l2_subdev *sd,
+                             struct v4l2_dbg_register *reg)
+{
+       reg->val = ths8200_read(sd, reg->reg & 0xff);
+       reg->size = 1;
+
+       return 0;
+}
+
+static int ths8200_s_register(struct v4l2_subdev *sd,
+                             const struct v4l2_dbg_register *reg)
+{
+       ths8200_write(sd, reg->reg & 0xff, reg->val & 0xff);
+
+       return 0;
+}
+#endif
+
+static void ths8200_print_timings(struct v4l2_subdev *sd,
+                                 struct v4l2_dv_timings *timings,
+                                 const char *txt, bool detailed)
+{
+       struct v4l2_bt_timings *bt = &timings->bt;
+       u32 htot, vtot;
+
+       if (timings->type != V4L2_DV_BT_656_1120)
+               return;
+
+       htot = htotal(bt);
+       vtot = vtotal(bt);
+
+       v4l2_info(sd, "%s %dx%d%s%d (%dx%d)",
+                 txt, bt->width, bt->height, bt->interlaced ? "i" : "p",
+                 (htot * vtot) > 0 ? ((u32)bt->pixelclock / (htot * vtot)) : 0,
+                 htot, vtot);
+
+       if (detailed) {
+               v4l2_info(sd, "    horizontal: fp = %d, %ssync = %d, bp = %d\n",
+                         bt->hfrontporch,
+                         (bt->polarities & V4L2_DV_HSYNC_POS_POL) ? "+" : "-",
+                         bt->hsync, bt->hbackporch);
+               v4l2_info(sd, "    vertical: fp = %d, %ssync = %d, bp = %d\n",
+                         bt->vfrontporch,
+                         (bt->polarities & V4L2_DV_VSYNC_POS_POL) ? "+" : "-",
+                         bt->vsync, bt->vbackporch);
+               v4l2_info(sd,
+                         "    pixelclock: %lld, flags: 0x%x, standards: 0x%x\n",
+                         bt->pixelclock, bt->flags, bt->standards);
+       }
+}
+
+static int ths8200_log_status(struct v4l2_subdev *sd)
+{
+       struct ths8200_state *state = to_state(sd);
+       uint8_t reg_03 = ths8200_read(sd, THS8200_CHIP_CTL);
+
+       v4l2_info(sd, "----- Chip status -----\n");
+       v4l2_info(sd, "version: %u\n", state->chip_version);
+       v4l2_info(sd, "power: %s\n", (reg_03 & 0x0c) ? "off" : "on");
+       v4l2_info(sd, "reset: %s\n", (reg_03 & 0x01) ? "off" : "on");
+       v4l2_info(sd, "test pattern: %s\n",
+                 (reg_03 & 0x20) ? "enabled" : "disabled");
+       v4l2_info(sd, "format: %ux%u\n",
+                 ths8200_read(sd, THS8200_DTG2_PIXEL_CNT_MSB) * 256 +
+                 ths8200_read(sd, THS8200_DTG2_PIXEL_CNT_LSB),
+                 (ths8200_read(sd, THS8200_DTG2_LINE_CNT_MSB) & 0x07) * 256 +
+                 ths8200_read(sd, THS8200_DTG2_LINE_CNT_LSB));
+       ths8200_print_timings(sd, &state->dv_timings,
+                             "Configured format:", true);
+
+       return 0;
+}
+
+/* Power up/down ths8200 */
+static int ths8200_s_power(struct v4l2_subdev *sd, int on)
+{
+       struct ths8200_state *state = to_state(sd);
+
+       v4l2_dbg(1, debug, sd, "%s: power %s\n", __func__, on ? "on" : "off");
+
+       state->power_on = on;
+
+       /* Power up/down - leave in reset state until input video is present */
+       ths8200_write_and_or(sd, THS8200_CHIP_CTL, 0xf2, (on ? 0x00 : 0x0c));
+
+       return 0;
+}
+
+static const struct v4l2_subdev_core_ops ths8200_core_ops = {
+       .log_status = ths8200_log_status,
+       .s_power = ths8200_s_power,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+       .g_register = ths8200_g_register,
+       .s_register = ths8200_s_register,
+#endif
+};
+
+/* -----------------------------------------------------------------------------
+ * V4L2 subdev video operations
+ */
+
+static int ths8200_s_stream(struct v4l2_subdev *sd, int enable)
+{
+       struct ths8200_state *state = to_state(sd);
+
+       if (enable && !state->power_on)
+               ths8200_s_power(sd, true);
+
+       ths8200_write_and_or(sd, THS8200_CHIP_CTL, 0xfe,
+                            (enable ? 0x01 : 0x00));
+
+       v4l2_dbg(1, debug, sd, "%s: %sable\n",
+                __func__, (enable ? "en" : "dis"));
+
+       return 0;
+}
+
+static void ths8200_core_init(struct v4l2_subdev *sd)
+{
+       /* setup clocks */
+       ths8200_write_and_or(sd, THS8200_CHIP_CTL, 0x3f, 0xc0);
+
+       /**** Data path control (DATA) ****/
+       /* Set FSADJ 700 mV,
+        * bypass 422-444 interpolation,
+        * input format 30 bit RGB444
+        */
+       ths8200_write(sd, THS8200_DATA_CNTL, 0x70);
+
+       /* DTG Mode (Video blocked during blanking
+        * VESA slave
+        */
+       ths8200_write(sd, THS8200_DTG1_MODE, 0x87);
+
+       /**** Display Timing Generator Control, Part 1 (DTG1). ****/
+
+       /* Disable embedded syncs on the output by setting
+        * the amplitude to zero for all channels.
+        */
+       ths8200_write(sd, THS8200_DTG1_Y_SYNC_MSB, 0x2a);
+       ths8200_write(sd, THS8200_DTG1_CBCR_SYNC_MSB, 0x2a);
+}
+
+static void ths8200_setup(struct v4l2_subdev *sd, struct v4l2_bt_timings *bt)
+{
+       uint8_t polarity = 0;
+       uint16_t line_start_active_video = (bt->vsync + bt->vbackporch);
+       uint16_t line_start_front_porch  = (vtotal(bt) - bt->vfrontporch);
+
+       /*** System ****/
+       /* Set chip in reset while it is configured */
+       ths8200_s_stream(sd, false);
+
+       /* configure video output timings */
+       ths8200_write(sd, THS8200_DTG1_SPEC_A, bt->hsync);
+       ths8200_write(sd, THS8200_DTG1_SPEC_B, bt->hfrontporch);
+
+       /* Zero for progressive scan formats.*/
+       if (!bt->interlaced)
+               ths8200_write(sd, THS8200_DTG1_SPEC_C, 0x00);
+
+       /* Distance from leading edge of h sync to start of active video.
+        * MSB in 0x2b
+        */
+       ths8200_write(sd, THS8200_DTG1_SPEC_D_LSB,
+                     (bt->hbackporch + bt->hsync) & 0xff);
+       /* Zero for SDTV-mode. MSB in 0x2b */
+       ths8200_write(sd, THS8200_DTG1_SPEC_E_LSB, 0x00);
+       /*
+        * MSB for dtg1_spec(d/e/h). See comment for
+        * corresponding LSB registers.
+        */
+       ths8200_write(sd, THS8200_DTG1_SPEC_DEH_MSB,
+                     ((bt->hbackporch + bt->hsync) & 0x100) >> 1);
+
+       /* h front porch */
+       ths8200_write(sd, THS8200_DTG1_SPEC_K_LSB, (bt->hfrontporch) & 0xff);
+       ths8200_write(sd, THS8200_DTG1_SPEC_K_MSB,
+                     ((bt->hfrontporch) & 0x700) >> 8);
+
+       /* Half the line length. Used to calculate SDTV line types. */
+       ths8200_write(sd, THS8200_DTG1_SPEC_G_LSB, (htotal(bt)/2) & 0xff);
+       ths8200_write(sd, THS8200_DTG1_SPEC_G_MSB,
+                     ((htotal(bt)/2) >> 8) & 0x0f);
+
+       /* Total pixels per line (ex. 720p: 1650) */
+       ths8200_write(sd, THS8200_DTG1_TOT_PIXELS_MSB, htotal(bt) >> 8);
+       ths8200_write(sd, THS8200_DTG1_TOT_PIXELS_LSB, htotal(bt) & 0xff);
+
+       /* Frame height and field height */
+       /* Field height should be programmed higher than frame_size for
+        * progressive scan formats
+        */
+       ths8200_write(sd, THS8200_DTG1_FRAME_FIELD_SZ_MSB,
+                     ((vtotal(bt) >> 4) & 0xf0) + 0x7);
+       ths8200_write(sd, THS8200_DTG1_FRAME_SZ_LSB, vtotal(bt) & 0xff);
+
+       /* Should be programmed higher than frame_size
+        * for progressive formats
+        */
+       if (!bt->interlaced)
+               ths8200_write(sd, THS8200_DTG1_FIELD_SZ_LSB, 0xff);
+
+       /**** Display Timing Generator Control, Part 2 (DTG2). ****/
+       /* Set breakpoint line numbers and types
+        * THS8200 generates line types with different properties. A line type
+        * that sets all the RGB-outputs to zero is used in the blanking areas,
+        * while a line type that enable the RGB-outputs is used in active video
+        * area. The line numbers for start of active video, start of front
+        * porch and after the last line in the frame must be set with the
+        * corresponding line types.
+        *
+        * Line types:
+        * 0x9 - Full normal sync pulse: Blocks data when dtg1_pass is off.
+        *       Used in blanking area.
+        * 0x0 - Active video: Video data is always passed. Used in active
+        *       video area.
+        */
+       ths8200_write_and_or(sd, THS8200_DTG2_BP1_2_MSB, 0x88,
+                            ((line_start_active_video >> 4) & 0x70) +
+                            ((line_start_front_porch >> 8) & 0x07));
+       ths8200_write(sd, THS8200_DTG2_BP3_4_MSB, ((vtotal(bt)) >> 4) & 0x70);
+       ths8200_write(sd, THS8200_DTG2_BP1_LSB, line_start_active_video & 0xff);
+       ths8200_write(sd, THS8200_DTG2_BP2_LSB, line_start_front_porch & 0xff);
+       ths8200_write(sd, THS8200_DTG2_BP3_LSB, (vtotal(bt)) & 0xff);
+
+       /* line types */
+       ths8200_write(sd, THS8200_DTG2_LINETYPE1, 0x90);
+       ths8200_write(sd, THS8200_DTG2_LINETYPE2, 0x90);
+
+       /* h sync width transmitted */
+       ths8200_write(sd, THS8200_DTG2_HLENGTH_LSB, bt->hsync & 0xff);
+       ths8200_write_and_or(sd, THS8200_DTG2_HLENGTH_LSB_HDLY_MSB, 0x3f,
+                            (bt->hsync >> 2) & 0xc0);
+
+       /* The pixel value h sync is asserted on */
+       ths8200_write_and_or(sd, THS8200_DTG2_HLENGTH_LSB_HDLY_MSB, 0xe0,
+                            (htotal(bt) >> 8) & 0x1f);
+       ths8200_write(sd, THS8200_DTG2_HLENGTH_HDLY_LSB, htotal(bt));
+
+       /* v sync width transmitted */
+       ths8200_write(sd, THS8200_DTG2_VLENGTH1_LSB, (bt->vsync) & 0xff);
+       ths8200_write_and_or(sd, THS8200_DTG2_VLENGTH1_MSB_VDLY1_MSB, 0x3f,
+                            ((bt->vsync) >> 2) & 0xc0);
+
+       /* The pixel value v sync is asserted on */
+       ths8200_write_and_or(sd, THS8200_DTG2_VLENGTH1_MSB_VDLY1_MSB, 0xf8,
+                            (vtotal(bt)>>8) & 0x7);
+       ths8200_write(sd, THS8200_DTG2_VDLY1_LSB, vtotal(bt));
+
+       /* For progressive video vlength2 must be set to all 0 and vdly2 must
+        * be set to all 1.
+        */
+       ths8200_write(sd, THS8200_DTG2_VLENGTH2_LSB, 0x00);
+       ths8200_write(sd, THS8200_DTG2_VLENGTH2_MSB_VDLY2_MSB, 0x07);
+       ths8200_write(sd, THS8200_DTG2_VDLY2_LSB, 0xff);
+
+       /* Internal delay factors to synchronize the sync pulses and the data */
+       /* Experimental values delays (hor 4, ver 1) */
+       ths8200_write(sd, THS8200_DTG2_HS_IN_DLY_MSB, (htotal(bt)>>8) & 0x1f);
+       ths8200_write(sd, THS8200_DTG2_HS_IN_DLY_LSB, (htotal(bt) - 4) & 0xff);
+       ths8200_write(sd, THS8200_DTG2_VS_IN_DLY_MSB, 0);
+       ths8200_write(sd, THS8200_DTG2_VS_IN_DLY_LSB, 1);
+
+       /* Polarity of received and transmitted sync signals */
+       if (bt->polarities & V4L2_DV_HSYNC_POS_POL) {
+               polarity |= 0x01; /* HS_IN */
+               polarity |= 0x08; /* HS_OUT */
+       }
+       if (bt->polarities & V4L2_DV_VSYNC_POS_POL) {
+               polarity |= 0x02; /* VS_IN */
+               polarity |= 0x10; /* VS_OUT */
+       }
+
+       /* RGB mode, no embedded timings */
+       /* Timing of video input bus is derived from HS, VS, and FID dedicated
+        * inputs
+        */
+       ths8200_write(sd, THS8200_DTG2_CNTL, 0x47 | polarity);
+
+       /* leave reset */
+       ths8200_s_stream(sd, true);
+
+       v4l2_dbg(1, debug, sd, "%s: frame %dx%d, polarity %d\n"
+                "horizontal: front porch %d, back porch %d, sync %d\n"
+                "vertical: sync %d\n", __func__, htotal(bt), vtotal(bt),
+                polarity, bt->hfrontporch, bt->hbackporch,
+                bt->hsync, bt->vsync);
+}
+
+static int ths8200_s_dv_timings(struct v4l2_subdev *sd,
+                               struct v4l2_dv_timings *timings)
+{
+       struct ths8200_state *state = to_state(sd);
+       int i;
+
+       v4l2_dbg(1, debug, sd, "%s:\n", __func__);
+
+       if (timings->type != V4L2_DV_BT_656_1120)
+               return -EINVAL;
+
+       /* TODO Support interlaced formats */
+       if (timings->bt.interlaced) {
+               v4l2_dbg(1, debug, sd, "TODO Support interlaced formats\n");
+               return -EINVAL;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(ths8200_timings); i++) {
+               if (v4l_match_dv_timings(&ths8200_timings[i], timings, 10))
+                       break;
+       }
+
+       if (i == ARRAY_SIZE(ths8200_timings)) {
+               v4l2_dbg(1, debug, sd, "Unsupported format\n");
+               return -EINVAL;
+       }
+
+       timings->bt.flags &= ~V4L2_DV_FL_REDUCED_FPS;
+
+       /* save timings */
+       state->dv_timings = *timings;
+
+       ths8200_setup(sd, &timings->bt);
+
+       return 0;
+}
+
+static int ths8200_g_dv_timings(struct v4l2_subdev *sd,
+                               struct v4l2_dv_timings *timings)
+{
+       struct ths8200_state *state = to_state(sd);
+
+       v4l2_dbg(1, debug, sd, "%s:\n", __func__);
+
+       *timings = state->dv_timings;
+
+       return 0;
+}
+
+static int ths8200_enum_dv_timings(struct v4l2_subdev *sd,
+                                  struct v4l2_enum_dv_timings *timings)
+{
+       /* Check requested format index is within range */
+       if (timings->index >= ARRAY_SIZE(ths8200_timings))
+               return -EINVAL;
+
+       timings->timings = ths8200_timings[timings->index];
+
+       return 0;
+}
+
+static int ths8200_dv_timings_cap(struct v4l2_subdev *sd,
+                                 struct v4l2_dv_timings_cap *cap)
+{
+       cap->type = V4L2_DV_BT_656_1120;
+       cap->bt.max_width = 1920;
+       cap->bt.max_height = 1080;
+       cap->bt.min_pixelclock = 27000000;
+       cap->bt.max_pixelclock = 148500000;
+       cap->bt.standards = V4L2_DV_BT_STD_CEA861;
+       cap->bt.capabilities = V4L2_DV_BT_CAP_PROGRESSIVE;
+
+       return 0;
+}
+
+/* Specific video subsystem operation handlers */
+static const struct v4l2_subdev_video_ops ths8200_video_ops = {
+       .s_stream = ths8200_s_stream,
+       .s_dv_timings = ths8200_s_dv_timings,
+       .g_dv_timings = ths8200_g_dv_timings,
+       .enum_dv_timings = ths8200_enum_dv_timings,
+       .dv_timings_cap = ths8200_dv_timings_cap,
+};
+
+/* V4L2 top level operation handlers */
+static const struct v4l2_subdev_ops ths8200_ops = {
+       .core  = &ths8200_core_ops,
+       .video = &ths8200_video_ops,
+};
+
+static int ths8200_probe(struct i2c_client *client,
+                        const struct i2c_device_id *id)
+{
+       struct ths8200_state *state;
+       struct v4l2_subdev *sd;
+
+       /* Check if the adapter supports the needed features */
+       if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+               return -EIO;
+
+       state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL);
+       if (!state)
+               return -ENOMEM;
+
+       sd = &state->sd;
+       v4l2_i2c_subdev_init(sd, client, &ths8200_ops);
+
+       state->chip_version = ths8200_read(sd, THS8200_VERSION);
+       v4l2_dbg(1, debug, sd, "chip version 0x%x\n", state->chip_version);
+
+       ths8200_core_init(sd);
+
+       v4l2_info(sd, "%s found @ 0x%x (%s)\n", client->name,
+                 client->addr << 1, client->adapter->name);
+
+       return 0;
+}
+
+static int ths8200_remove(struct i2c_client *client)
+{
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+       v4l2_dbg(1, debug, sd, "%s removed @ 0x%x (%s)\n", client->name,
+                client->addr << 1, client->adapter->name);
+
+       ths8200_s_power(sd, false);
+
+       v4l2_device_unregister_subdev(sd);
+
+       return 0;
+}
+
+static struct i2c_device_id ths8200_id[] = {
+       { "ths8200", 0 },
+       {},
+};
+MODULE_DEVICE_TABLE(i2c, ths8200_id);
+
+static struct i2c_driver ths8200_driver = {
+       .driver = {
+               .owner = THIS_MODULE,
+               .name = "ths8200",
+       },
+       .probe = ths8200_probe,
+       .remove = ths8200_remove,
+       .id_table = ths8200_id,
+};
+
+module_i2c_driver(ths8200_driver);
diff --git a/drivers/media/i2c/ths8200_regs.h b/drivers/media/i2c/ths8200_regs.h
new file mode 100644 (file)
index 0000000..6bc9fd1
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+ * ths8200 - Texas Instruments THS8200 video encoder driver
+ *
+ * Copyright 2013 Cisco Systems, Inc. and/or its affiliates.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is 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 THS8200_REGS_H
+#define THS8200_REGS_H
+
+/* Register offset macros */
+#define THS8200_VERSION                                0x02
+#define THS8200_CHIP_CTL                       0x03
+#define THS8200_CSC_R11                                0x04
+#define THS8200_CSC_R12                                0x05
+#define THS8200_CSC_R21                                0x06
+#define THS8200_CSC_R22                                0x07
+#define THS8200_CSC_R31                                0x08
+#define THS8200_CSC_R32                                0x09
+#define THS8200_CSC_G11                                0x0a
+#define THS8200_CSC_G12                                0x0b
+#define THS8200_CSC_G21                                0x0c
+#define THS8200_CSC_G22                                0x0d
+#define THS8200_CSC_G31                                0x0e
+#define THS8200_CSC_G32                                0x0f
+#define THS8200_CSC_B11                                0x10
+#define THS8200_CSC_B12                                0x11
+#define THS8200_CSC_B21                                0x12
+#define THS8200_CSC_B22                                0x13
+#define THS8200_CSC_B31                                0x14
+#define THS8200_CSC_B32                                0x15
+#define THS8200_CSC_OFFS1                      0x16
+#define THS8200_CSC_OFFS12                     0x17
+#define THS8200_CSC_OFFS23                     0x18
+#define THS8200_CSC_OFFS3                      0x19
+#define THS8200_TST_CNTL1                      0x1a
+#define THS8200_TST_CNTL2                      0x1b
+#define THS8200_DATA_CNTL                      0x1c
+#define THS8200_DTG1_Y_SYNC1_LSB               0x1d
+#define THS8200_DTG1_Y_SYNC2_LSB               0x1e
+#define THS8200_DTG1_Y_SYNC3_LSB               0x1f
+#define THS8200_DTG1_CBCR_SYNC1_LSB            0x20
+#define THS8200_DTG1_CBCR_SYNC2_LSB            0x21
+#define THS8200_DTG1_CBCR_SYNC3_LSB            0x22
+#define THS8200_DTG1_Y_SYNC_MSB                        0x23
+#define THS8200_DTG1_CBCR_SYNC_MSB             0x24
+#define THS8200_DTG1_SPEC_A                    0x25
+#define THS8200_DTG1_SPEC_B                    0x26
+#define THS8200_DTG1_SPEC_C                    0x27
+#define THS8200_DTG1_SPEC_D_LSB                        0x28
+#define THS8200_DTG1_SPEC_D1                   0x29
+#define THS8200_DTG1_SPEC_E_LSB                        0x2a
+#define THS8200_DTG1_SPEC_DEH_MSB              0x2b
+#define THS8200_DTG1_SPEC_H_LSB                        0x2c
+#define THS8200_DTG1_SPEC_I_MSB                        0x2d
+#define THS8200_DTG1_SPEC_I_LSB                        0x2e
+#define THS8200_DTG1_SPEC_K_LSB                        0x2f
+#define THS8200_DTG1_SPEC_K_MSB                        0x30
+#define THS8200_DTG1_SPEC_K1                   0x31
+#define THS8200_DTG1_SPEC_G_LSB                        0x32
+#define THS8200_DTG1_SPEC_G_MSB                        0x33
+#define THS8200_DTG1_TOT_PIXELS_MSB            0x34
+#define THS8200_DTG1_TOT_PIXELS_LSB            0x35
+#define THS8200_DTG1_FLD_FLIP_LINECNT_MSB      0x36
+#define THS8200_DTG1_LINECNT_LSB               0x37
+#define THS8200_DTG1_MODE                      0x38
+#define THS8200_DTG1_FRAME_FIELD_SZ_MSB                0x39
+#define THS8200_DTG1_FRAME_SZ_LSB              0x3a
+#define THS8200_DTG1_FIELD_SZ_LSB              0x3b
+#define THS8200_DTG1_VESA_CBAR_SIZE            0x3c
+#define THS8200_DAC_CNTL_MSB                   0x3d
+#define THS8200_DAC1_CNTL_LSB                  0x3e
+#define THS8200_DAC2_CNTL_LSB                  0x3f
+#define THS8200_DAC3_CNTL_LSB                  0x40
+#define THS8200_CSM_CLIP_GY_LOW                        0x41
+#define THS8200_CSM_CLIP_BCB_LOW               0x42
+#define THS8200_CSM_CLIP_RCR_LOW               0x43
+#define THS8200_CSM_CLIP_GY_HIGH               0x44
+#define THS8200_CSM_CLIP_BCB_HIGH              0x45
+#define THS8200_CSM_CLIP_RCR_HIGH              0x46
+#define THS8200_CSM_SHIFT_GY                   0x47
+#define THS8200_CSM_SHIFT_BCB                  0x48
+#define THS8200_CSM_SHIFT_RCR                  0x49
+#define THS8200_CSM_GY_CNTL_MULT_MSB           0x4a
+#define THS8200_CSM_MULT_BCB_RCR_MSB           0x4b
+#define THS8200_CSM_MULT_GY_LSB                        0x4c
+#define THS8200_CSM_MULT_BCB_LSB               0x4d
+#define THS8200_CSM_MULT_RCR_LSB               0x4e
+#define THS8200_CSM_MULT_RCR_BCB_CNTL          0x4f
+#define THS8200_CSM_MULT_RCR_LSB               0x4e
+#define THS8200_DTG2_BP1_2_MSB                 0x50
+#define THS8200_DTG2_BP3_4_MSB                 0x51
+#define THS8200_DTG2_BP5_6_MSB                 0x52
+#define THS8200_DTG2_BP7_8_MSB                 0x53
+#define THS8200_DTG2_BP9_10_MSB                        0x54
+#define THS8200_DTG2_BP11_12_MSB               0x55
+#define THS8200_DTG2_BP13_14_MSB               0x56
+#define THS8200_DTG2_BP15_16_MSB               0x57
+#define THS8200_DTG2_BP1_LSB                   0x58
+#define THS8200_DTG2_BP2_LSB                   0x59
+#define THS8200_DTG2_BP3_LSB                   0x5a
+#define THS8200_DTG2_BP4_LSB                   0x5b
+#define THS8200_DTG2_BP5_LSB                   0x5c
+#define THS8200_DTG2_BP6_LSB                   0x5d
+#define THS8200_DTG2_BP7_LSB                   0x5e
+#define THS8200_DTG2_BP8_LSB                   0x5f
+#define THS8200_DTG2_BP9_LSB                   0x60
+#define THS8200_DTG2_BP10_LSB                  0x61
+#define THS8200_DTG2_BP11_LSB                  0x62
+#define THS8200_DTG2_BP12_LSB                  0x63
+#define THS8200_DTG2_BP13_LSB                  0x64
+#define THS8200_DTG2_BP14_LSB                  0x65
+#define THS8200_DTG2_BP15_LSB                  0x66
+#define THS8200_DTG2_BP16_LSB                  0x67
+#define THS8200_DTG2_LINETYPE1                 0x68
+#define THS8200_DTG2_LINETYPE2                 0x69
+#define THS8200_DTG2_LINETYPE3                 0x6a
+#define THS8200_DTG2_LINETYPE4                 0x6b
+#define THS8200_DTG2_LINETYPE5                 0x6c
+#define THS8200_DTG2_LINETYPE6                 0x6d
+#define THS8200_DTG2_LINETYPE7                 0x6e
+#define THS8200_DTG2_LINETYPE8                 0x6f
+#define THS8200_DTG2_HLENGTH_LSB               0x70
+#define THS8200_DTG2_HLENGTH_LSB_HDLY_MSB      0x71
+#define THS8200_DTG2_HLENGTH_HDLY_LSB          0x72
+#define THS8200_DTG2_VLENGTH1_LSB              0x73
+#define THS8200_DTG2_VLENGTH1_MSB_VDLY1_MSB    0x74
+#define THS8200_DTG2_VDLY1_LSB                 0x75
+#define THS8200_DTG2_VLENGTH2_LSB              0x76
+#define THS8200_DTG2_VLENGTH2_MSB_VDLY2_MSB    0x77
+#define THS8200_DTG2_VDLY2_LSB                 0x78
+#define THS8200_DTG2_HS_IN_DLY_MSB             0x79
+#define THS8200_DTG2_HS_IN_DLY_LSB             0x7a
+#define THS8200_DTG2_VS_IN_DLY_MSB             0x7b
+#define THS8200_DTG2_VS_IN_DLY_LSB             0x7c
+#define THS8200_DTG2_PIXEL_CNT_MSB             0x7d
+#define THS8200_DTG2_PIXEL_CNT_LSB             0x7e
+#define THS8200_DTG2_LINE_CNT_MSB              0x7f
+#define THS8200_DTG2_LINE_CNT_LSB              0x80
+#define THS8200_DTG2_CNTL                      0x82
+#define THS8200_CGMS_CNTL_HEADER               0x83
+#define THS8200_CGMS_PAYLOAD_MSB               0x84
+#define THS8200_CGMS_PAYLOAD_LSB               0x85
+#define THS8200_MISC_PPL_LSB                   0x86
+#define THS8200_MISC_PPL_MSB                   0x87
+#define THS8200_MISC_LPF_MSB                   0x88
+#define THS8200_MISC_LPF_LSB                   0x89
+
+#endif /* THS8200_REGS_H */
index 809a75a..ef87f7b 100644 (file)
@@ -162,7 +162,7 @@ static int tlv320aic23b_probe(struct i2c_client *client,
        v4l_info(client, "chip found @ 0x%x (%s)\n",
                        client->addr << 1, client->adapter->name);
 
-       state = kzalloc(sizeof(struct tlv320aic23b_state), GFP_KERNEL);
+       state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL);
        if (state == NULL)
                return -ENOMEM;
        sd = &state->sd;
@@ -191,7 +191,6 @@ static int tlv320aic23b_probe(struct i2c_client *client,
                int err = state->hdl.error;
 
                v4l2_ctrl_handler_free(&state->hdl);
-               kfree(state);
                return err;
        }
        v4l2_ctrl_handler_setup(&state->hdl);
@@ -205,7 +204,6 @@ static int tlv320aic23b_remove(struct i2c_client *client)
 
        v4l2_device_unregister_subdev(sd);
        v4l2_ctrl_handler_free(&state->hdl);
-       kfree(state);
        return 0;
 }
 
index e0634c8..d76c53a 100644 (file)
@@ -38,7 +38,6 @@
 
 #include <media/tvaudio.h>
 #include <media/v4l2-device.h>
-#include <media/v4l2-chip-ident.h>
 #include <media/v4l2-ctrls.h>
 
 #include <media/i2c-addr.h>
@@ -1838,13 +1837,6 @@ static int tvaudio_s_frequency(struct v4l2_subdev *sd, const struct v4l2_frequen
        return 0;
 }
 
-static int tvaudio_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_TVAUDIO, 0);
-}
-
 static int tvaudio_log_status(struct v4l2_subdev *sd)
 {
        struct CHIPSTATE *chip = to_state(sd);
@@ -1863,7 +1855,6 @@ static const struct v4l2_ctrl_ops tvaudio_ctrl_ops = {
 
 static const struct v4l2_subdev_core_ops tvaudio_core_ops = {
        .log_status = tvaudio_log_status,
-       .g_chip_ident = tvaudio_g_chip_ident,
        .g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
        .try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
        .s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
@@ -1910,7 +1901,7 @@ static int tvaudio_probe(struct i2c_client *client, const struct i2c_device_id *
                printk("\n");
        }
 
-       chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+       chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
        if (!chip)
                return -ENOMEM;
        sd = &chip->sd;
@@ -1930,7 +1921,6 @@ static int tvaudio_probe(struct i2c_client *client, const struct i2c_device_id *
        }
        if (desc->name == NULL) {
                v4l2_dbg(1, debug, sd, "no matching chip description found\n");
-               kfree(chip);
                return -EIO;
        }
        v4l2_info(sd, "%s found @ 0x%x (%s)\n", desc->name, client->addr<<1, client->adapter->name);
@@ -2001,7 +1991,6 @@ static int tvaudio_probe(struct i2c_client *client, const struct i2c_device_id *
                int err = chip->hdl.error;
 
                v4l2_ctrl_handler_free(&chip->hdl);
-               kfree(chip);
                return err;
        }
        /* set controls to the default values */
@@ -2044,7 +2033,6 @@ static int tvaudio_remove(struct i2c_client *client)
 
        v4l2_device_unregister_subdev(sd);
        v4l2_ctrl_handler_free(&chip->hdl);
-       kfree(chip);
        return 0;
 }
 
index ab8f3fe..9c6d66a 100644 (file)
@@ -39,7 +39,7 @@
 #include <media/v4l2-device.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-mediabus.h>
-#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-of.h>
 #include <media/v4l2-ctrls.h>
 #include <media/tvp514x.h>
 #include <media/media-entity.h>
@@ -123,6 +123,8 @@ struct tvp514x_decoder {
        /* mc related members */
        struct media_pad pad;
        struct v4l2_mbus_framefmt format;
+
+       struct tvp514x_reg *int_seq;
 };
 
 /* TVP514x default register values */
@@ -543,8 +545,6 @@ static int tvp514x_querystd(struct v4l2_subdev *sd, v4l2_std_id *std_id)
        if (std_id == NULL)
                return -EINVAL;
 
-       *std_id = V4L2_STD_UNKNOWN;
-
        /* To query the standard the TVP514x must power on the ADCs. */
        if (!decoder->streaming) {
                tvp514x_s_stream(sd, 1);
@@ -553,8 +553,10 @@ static int tvp514x_querystd(struct v4l2_subdev *sd, v4l2_std_id *std_id)
 
        /* query the current standard */
        current_std = tvp514x_query_current_std(sd);
-       if (current_std == STD_INVALID)
+       if (current_std == STD_INVALID) {
+               *std_id = V4L2_STD_UNKNOWN;
                return 0;
+       }
 
        input_sel = decoder->input;
 
@@ -595,10 +597,12 @@ static int tvp514x_querystd(struct v4l2_subdev *sd, v4l2_std_id *std_id)
        }
        /* check whether signal is locked */
        sync_lock_status = tvp514x_read_reg(sd, REG_STATUS1);
-       if (lock_mask != (sync_lock_status & lock_mask))
+       if (lock_mask != (sync_lock_status & lock_mask)) {
+               *std_id = V4L2_STD_UNKNOWN;
                return 0;       /* No input detected */
+       }
 
-       *std_id = decoder->std_list[current_std].standard.id;
+       *std_id &= decoder->std_list[current_std].standard.id;
 
        v4l2_dbg(1, debug, sd, "Current STD: %s\n",
                        decoder->std_list[current_std].standard.name);
@@ -862,7 +866,6 @@ tvp514x_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a)
 static int tvp514x_s_stream(struct v4l2_subdev *sd, int enable)
 {
        int err = 0;
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct tvp514x_decoder *decoder = to_decoder(sd);
 
        if (decoder->streaming == enable)
@@ -882,11 +885,8 @@ static int tvp514x_s_stream(struct v4l2_subdev *sd, int enable)
        }
        case 1:
        {
-               struct tvp514x_reg *int_seq = (struct tvp514x_reg *)
-                               client->driver->id_table->driver_data;
-
                /* Power Up Sequence */
-               err = tvp514x_write_regs(sd, int_seq);
+               err = tvp514x_write_regs(sd, decoder->int_seq);
                if (err) {
                        v4l2_err(sd, "Unable to turn on decoder\n");
                        return err;
@@ -1055,6 +1055,42 @@ static struct tvp514x_decoder tvp514x_dev = {
 
 };
 
+static struct tvp514x_platform_data *
+tvp514x_get_pdata(struct i2c_client *client)
+{
+       struct tvp514x_platform_data *pdata;
+       struct v4l2_of_endpoint bus_cfg;
+       struct device_node *endpoint;
+       unsigned int flags;
+
+       if (!IS_ENABLED(CONFIG_OF) || !client->dev.of_node)
+               return client->dev.platform_data;
+
+       endpoint = v4l2_of_get_next_endpoint(client->dev.of_node, NULL);
+       if (!endpoint)
+               return NULL;
+
+       pdata = devm_kzalloc(&client->dev, sizeof(*pdata), GFP_KERNEL);
+       if (!pdata)
+               goto done;
+
+       v4l2_of_parse_endpoint(endpoint, &bus_cfg);
+       flags = bus_cfg.bus.parallel.flags;
+
+       if (flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH)
+               pdata->hs_polarity = 1;
+
+       if (flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH)
+               pdata->vs_polarity = 1;
+
+       if (flags & V4L2_MBUS_PCLK_SAMPLE_RISING)
+               pdata->clk_polarity = 1;
+
+done:
+       of_node_put(endpoint);
+       return pdata;
+}
+
 /**
  * tvp514x_probe() - decoder driver i2c probe handler
  * @client: i2c driver client device structure
@@ -1066,19 +1102,20 @@ static struct tvp514x_decoder tvp514x_dev = {
 static int
 tvp514x_probe(struct i2c_client *client, const struct i2c_device_id *id)
 {
+       struct tvp514x_platform_data *pdata = tvp514x_get_pdata(client);
        struct tvp514x_decoder *decoder;
        struct v4l2_subdev *sd;
        int ret;
 
+       if (pdata == NULL) {
+               dev_err(&client->dev, "No platform data\n");
+               return -EINVAL;
+       }
+
        /* Check if the adapter supports the needed features */
        if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
                return -EIO;
 
-       if (!client->dev.platform_data) {
-               v4l2_err(client, "No platform data!!\n");
-               return -ENODEV;
-       }
-
        decoder = devm_kzalloc(&client->dev, sizeof(*decoder), GFP_KERNEL);
        if (!decoder)
                return -ENOMEM;
@@ -1089,8 +1126,10 @@ tvp514x_probe(struct i2c_client *client, const struct i2c_device_id *id)
        memcpy(decoder->tvp514x_regs, tvp514x_reg_list_default,
                        sizeof(tvp514x_reg_list_default));
 
+       decoder->int_seq = (struct tvp514x_reg *)id->driver_data;
+
        /* Copy board specific information here */
-       decoder->pdata = client->dev.platform_data;
+       decoder->pdata = pdata;
 
        /**
         * Fetch platform specific data, and configure the
@@ -1109,7 +1148,6 @@ tvp514x_probe(struct i2c_client *client, const struct i2c_device_id *id)
        /* Register with V4L2 layer as slave device */
        sd = &decoder->sd;
        v4l2_i2c_subdev_init(sd, client, &tvp514x_ops);
-       strlcpy(sd->name, TVP514X_MODULE_NAME, sizeof(sd->name));
 
 #if defined(CONFIG_MEDIA_CONTROLLER)
        decoder->pad.flags = MEDIA_PAD_FL_SOURCE;
@@ -1120,7 +1158,6 @@ tvp514x_probe(struct i2c_client *client, const struct i2c_device_id *id)
        if (ret < 0) {
                v4l2_err(sd, "%s decoder driver failed to register !!\n",
                         sd->name);
-               kfree(decoder);
                return ret;
        }
 #endif
@@ -1231,8 +1268,20 @@ static const struct i2c_device_id tvp514x_id[] = {
 
 MODULE_DEVICE_TABLE(i2c, tvp514x_id);
 
+#if IS_ENABLED(CONFIG_OF)
+static const struct of_device_id tvp514x_of_match[] = {
+       { .compatible = "ti,tvp5146", },
+       { .compatible = "ti,tvp5146m2", },
+       { .compatible = "ti,tvp5147", },
+       { .compatible = "ti,tvp5147m1", },
+       { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, tvp514x_of_match);
+#endif
+
 static struct i2c_driver tvp514x_driver = {
        .driver = {
+               .of_match_table = of_match_ptr(tvp514x_of_match),
                .owner = THIS_MODULE,
                .name = TVP514X_MODULE_NAME,
        },
index 485159a..89c0b13 100644 (file)
@@ -12,7 +12,6 @@
 #include <linux/module.h>
 #include <media/v4l2-device.h>
 #include <media/tvp5150.h>
-#include <media/v4l2-chip-ident.h>
 #include <media/v4l2-ctrls.h>
 
 #include "tvp5150_reg.h"
@@ -727,13 +726,11 @@ static int tvp5150_set_std(struct v4l2_subdev *sd, v4l2_std_id std)
 
        /* First tests should be against specific std */
 
-       if (std == V4L2_STD_ALL) {
-               fmt = VIDEO_STD_AUTO_SWITCH_BIT;        /* Autodetect mode */
-       } else if (std & V4L2_STD_NTSC_443) {
+       if (std == V4L2_STD_NTSC_443) {
                fmt = VIDEO_STD_NTSC_4_43_BIT;
-       } else if (std & V4L2_STD_PAL_M) {
+       } else if (std == V4L2_STD_PAL_M) {
                fmt = VIDEO_STD_PAL_M_BIT;
-       } else if (std & (V4L2_STD_PAL_N | V4L2_STD_PAL_Nc)) {
+       } else if (std == V4L2_STD_PAL_N || std == V4L2_STD_PAL_Nc) {
                fmt = VIDEO_STD_PAL_COMBINATION_N_BIT;
        } else {
                /* Then, test against generic ones */
@@ -1031,31 +1028,11 @@ static int tvp5150_g_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_f
        return 0;
 }
 
-static int tvp5150_g_chip_ident(struct v4l2_subdev *sd,
-                               struct v4l2_dbg_chip_ident *chip)
-{
-       int rev;
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       rev = tvp5150_read(sd, TVP5150_ROM_MAJOR_VER) << 8 |
-             tvp5150_read(sd, TVP5150_ROM_MINOR_VER);
-
-       return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_TVP5150,
-                                         rev);
-}
-
-
 #ifdef CONFIG_VIDEO_ADV_DEBUG
 static int tvp5150_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
 {
        int res;
 
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       if (!v4l2_chip_match_i2c_client(client, &reg->match))
-               return -EINVAL;
-       if (!capable(CAP_SYS_ADMIN))
-               return -EPERM;
        res = tvp5150_read(sd, reg->reg & 0xff);
        if (res < 0) {
                v4l2_err(sd, "%s: failed with error = %d\n", __func__, res);
@@ -1069,12 +1046,6 @@ static int tvp5150_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *
 
 static int tvp5150_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg)
 {
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       if (!v4l2_chip_match_i2c_client(client, &reg->match))
-               return -EINVAL;
-       if (!capable(CAP_SYS_ADMIN))
-               return -EPERM;
        tvp5150_write(sd, reg->reg & 0xff, reg->val & 0xff);
        return 0;
 }
@@ -1098,7 +1069,6 @@ static const struct v4l2_subdev_core_ops tvp5150_core_ops = {
        .log_status = tvp5150_log_status,
        .s_std = tvp5150_s_std,
        .reset = tvp5150_reset,
-       .g_chip_ident = tvp5150_g_chip_ident,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
        .g_register = tvp5150_g_register,
        .s_register = tvp5150_s_register,
@@ -1152,10 +1122,9 @@ static int tvp5150_probe(struct i2c_client *c,
             I2C_FUNC_SMBUS_READ_BYTE | I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
                return -EIO;
 
-       core = kzalloc(sizeof(struct tvp5150), GFP_KERNEL);
-       if (!core) {
+       core = devm_kzalloc(&c->dev, sizeof(*core), GFP_KERNEL);
+       if (!core)
                return -ENOMEM;
-       }
        sd = &core->sd;
        v4l2_i2c_subdev_init(sd, c, &tvp5150_ops);
 
@@ -1166,7 +1135,7 @@ static int tvp5150_probe(struct i2c_client *c,
        for (i = 0; i < 4; i++) {
                res = tvp5150_read(sd, TVP5150_MSB_DEV_ID + i);
                if (res < 0)
-                       goto free_core;
+                       return res;
                tvp5150_id[i] = res;
        }
 
@@ -1209,7 +1178,7 @@ static int tvp5150_probe(struct i2c_client *c,
        if (core->hdl.error) {
                res = core->hdl.error;
                v4l2_ctrl_handler_free(&core->hdl);
-               goto free_core;
+               return res;
        }
        v4l2_ctrl_handler_setup(&core->hdl);
 
@@ -1225,10 +1194,6 @@ static int tvp5150_probe(struct i2c_client *c,
        if (debug > 1)
                tvp5150_log_status(sd);
        return 0;
-
-free_core:
-       kfree(core);
-       return res;
 }
 
 static int tvp5150_remove(struct i2c_client *c)
@@ -1242,7 +1207,6 @@ static int tvp5150_remove(struct i2c_client *c)
 
        v4l2_device_unregister_subdev(sd);
        v4l2_ctrl_handler_free(&decoder->hdl);
-       kfree(to_tvp5150(sd));
        return 0;
 }
 
index 027809c..a4e4948 100644 (file)
@@ -32,7 +32,6 @@
 #include <linux/v4l2-dv-timings.h>
 #include <media/tvp7002.h>
 #include <media/v4l2-device.h>
-#include <media/v4l2-chip-ident.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-ctrls.h>
 #include "tvp7002_reg.h"
@@ -41,9 +40,6 @@ MODULE_DESCRIPTION("TI TVP7002 Video and Graphics Digitizer driver");
 MODULE_AUTHOR("Santiago Nunez-Corrales <santiago.nunez@ridgerun.com>");
 MODULE_LICENSE("GPL");
 
-/* Module Name */
-#define TVP7002_MODULE_NAME    "tvp7002"
-
 /* I2C retry attempts */
 #define I2C_RETRY_COUNT                (5)
 
@@ -424,6 +420,7 @@ struct tvp7002 {
        int streaming;
 
        const struct tvp7002_timings_definition *current_timings;
+       struct media_pad pad;
 };
 
 /*
@@ -535,29 +532,6 @@ static inline void tvp7002_write_err(struct v4l2_subdev *sd, u8 reg,
 }
 
 /*
- * tvp7002_g_chip_ident() - Get chip identification number
- * @sd: ptr to v4l2_subdev struct
- * @chip: ptr to v4l2_dbg_chip_ident struct
- *
- * Obtains the chip's identification number.
- * Returns zero or -EINVAL if read operation fails.
- */
-static int tvp7002_g_chip_ident(struct v4l2_subdev *sd,
-                                       struct v4l2_dbg_chip_ident *chip)
-{
-       u8 rev;
-       int error;
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       error = tvp7002_read(sd, TVP7002_CHIP_REV, &rev);
-
-       if (error < 0)
-               return error;
-
-       return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_TVP7002, rev);
-}
-
-/*
  * tvp7002_write_inittab() - Write initialization values
  * @sd: ptr to v4l2_subdev struct
  * @regs: ptr to i2c_reg_value struct
@@ -738,23 +712,17 @@ static int tvp7002_query_dv_timings(struct v4l2_subdev *sd,
  *
  * Get the value of a TVP7002 decoder device register.
  * Returns zero when successful, -EINVAL if register read fails or
- * access to I2C client fails, -EPERM if the call is not allowed
- * by disabled CAP_SYS_ADMIN.
+ * access to I2C client fails.
  */
 static int tvp7002_g_register(struct v4l2_subdev *sd,
                                                struct v4l2_dbg_register *reg)
 {
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
        u8 val;
        int ret;
 
-       if (!v4l2_chip_match_i2c_client(client, &reg->match))
-               return -EINVAL;
-       if (!capable(CAP_SYS_ADMIN))
-               return -EPERM;
-
        ret = tvp7002_read(sd, reg->reg & 0xff, &val);
        reg->val = val;
+       reg->size = 1;
        return ret;
 }
 
@@ -764,19 +732,11 @@ static int tvp7002_g_register(struct v4l2_subdev *sd,
  * @reg: ptr to v4l2_dbg_register struct
  *
  * Get the value of a TVP7002 decoder device register.
- * Returns zero when successful, -EINVAL if register read fails or
- * -EPERM if call not allowed.
+ * Returns zero when successful, -EINVAL if register read fails.
  */
 static int tvp7002_s_register(struct v4l2_subdev *sd,
                                                const struct v4l2_dbg_register *reg)
 {
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       if (!v4l2_chip_match_i2c_client(client, &reg->match))
-               return -EINVAL;
-       if (!capable(CAP_SYS_ADMIN))
-               return -EPERM;
-
        return tvp7002_write(sd, reg->reg & 0xff, reg->val & 0xff);
 }
 #endif
@@ -880,9 +840,67 @@ static const struct v4l2_ctrl_ops tvp7002_ctrl_ops = {
        .s_ctrl = tvp7002_s_ctrl,
 };
 
+/*
+ * tvp7002_enum_mbus_code() - Enum supported digital video format on pad
+ * @sd: pointer to standard V4L2 sub-device structure
+ * @fh: file handle for the subdev
+ * @code: pointer to subdev enum mbus code struct
+ *
+ * Enumerate supported digital video formats for pad.
+ */
+static int
+tvp7002_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+                      struct v4l2_subdev_mbus_code_enum *code)
+{
+       /* Check requested format index is within range */
+       if (code->index != 0)
+               return -EINVAL;
+
+       code->code = V4L2_MBUS_FMT_YUYV10_1X20;
+
+       return 0;
+}
+
+/*
+ * tvp7002_get_pad_format() - get video format on pad
+ * @sd: pointer to standard V4L2 sub-device structure
+ * @fh: file handle for the subdev
+ * @fmt: pointer to subdev format struct
+ *
+ * get video format for pad.
+ */
+static int
+tvp7002_get_pad_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+                      struct v4l2_subdev_format *fmt)
+{
+       struct tvp7002 *tvp7002 = to_tvp7002(sd);
+
+       fmt->format.code = V4L2_MBUS_FMT_YUYV10_1X20;
+       fmt->format.width = tvp7002->current_timings->timings.bt.width;
+       fmt->format.height = tvp7002->current_timings->timings.bt.height;
+       fmt->format.field = tvp7002->current_timings->scanmode;
+       fmt->format.colorspace = tvp7002->current_timings->color_space;
+
+       return 0;
+}
+
+/*
+ * tvp7002_set_pad_format() - set video format on pad
+ * @sd: pointer to standard V4L2 sub-device structure
+ * @fh: file handle for the subdev
+ * @fmt: pointer to subdev format struct
+ *
+ * set video format for pad.
+ */
+static int
+tvp7002_set_pad_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+                      struct v4l2_subdev_format *fmt)
+{
+       return tvp7002_get_pad_format(sd, fh, fmt);
+}
+
 /* V4L2 core operation handlers */
 static const struct v4l2_subdev_core_ops tvp7002_core_ops = {
-       .g_chip_ident = tvp7002_g_chip_ident,
        .log_status = tvp7002_log_status,
        .g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
        .try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
@@ -910,10 +928,18 @@ static const struct v4l2_subdev_video_ops tvp7002_video_ops = {
        .enum_mbus_fmt = tvp7002_enum_mbus_fmt,
 };
 
+/* media pad related operation handlers */
+static const struct v4l2_subdev_pad_ops tvp7002_pad_ops = {
+       .enum_mbus_code = tvp7002_enum_mbus_code,
+       .get_fmt = tvp7002_get_pad_format,
+       .set_fmt = tvp7002_set_pad_format,
+};
+
 /* V4L2 top level operation handlers */
 static const struct v4l2_subdev_ops tvp7002_ops = {
        .core = &tvp7002_core_ops,
        .video = &tvp7002_video_ops,
+       .pad = &tvp7002_pad_ops,
 };
 
 /*
@@ -993,19 +1019,34 @@ static int tvp7002_probe(struct i2c_client *c, const struct i2c_device_id *id)
        timings = device->current_timings->timings;
        error = tvp7002_s_dv_timings(sd, &timings);
 
+#if defined(CONFIG_MEDIA_CONTROLLER)
+       device->pad.flags = MEDIA_PAD_FL_SOURCE;
+       device->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+       device->sd.entity.flags |= MEDIA_ENT_T_V4L2_SUBDEV_DECODER;
+
+       error = media_entity_init(&device->sd.entity, 1, &device->pad, 0);
+       if (error < 0)
+               return error;
+#endif
+
        v4l2_ctrl_handler_init(&device->hdl, 1);
        v4l2_ctrl_new_std(&device->hdl, &tvp7002_ctrl_ops,
                        V4L2_CID_GAIN, 0, 255, 1, 0);
        sd->ctrl_handler = &device->hdl;
        if (device->hdl.error) {
-               int err = device->hdl.error;
-
-               v4l2_ctrl_handler_free(&device->hdl);
-               return err;
+               error = device->hdl.error;
+               goto error;
        }
        v4l2_ctrl_handler_setup(&device->hdl);
 
        return 0;
+
+error:
+       v4l2_ctrl_handler_free(&device->hdl);
+#if defined(CONFIG_MEDIA_CONTROLLER)
+       media_entity_cleanup(&device->sd.entity);
+#endif
+       return error;
 }
 
 /*
@@ -1022,7 +1063,9 @@ static int tvp7002_remove(struct i2c_client *c)
 
        v4l2_dbg(1, debug, sd, "Removing tvp7002 adapter"
                                "on address 0x%x\n", c->addr);
-
+#if defined(CONFIG_MEDIA_CONTROLLER)
+       media_entity_cleanup(&device->sd.entity);
+#endif
        v4l2_device_unregister_subdev(sd);
        v4l2_ctrl_handler_free(&device->hdl);
        return 0;
index c5dc2c3..f58607d 100644 (file)
@@ -23,7 +23,6 @@
 #include <linux/slab.h>
 #include <media/v4l2-subdev.h>
 #include <media/v4l2-device.h>
-#include <media/v4l2-chip-ident.h>
 #include <media/v4l2-ctrls.h>
 
 #define TW2804_REG_AUTOGAIN            0x02
@@ -368,8 +367,7 @@ static int tw2804_probe(struct i2c_client *client,
        if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
                return -ENODEV;
 
-       state = kzalloc(sizeof(struct tw2804), GFP_KERNEL);
-
+       state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL);
        if (state == NULL)
                return -ENOMEM;
        sd = &state->sd;
@@ -410,7 +408,6 @@ static int tw2804_probe(struct i2c_client *client,
        err = state->hdl.error;
        if (err) {
                v4l2_ctrl_handler_free(&state->hdl);
-               kfree(state);
                return err;
        }
 
@@ -427,7 +424,6 @@ static int tw2804_remove(struct i2c_client *client)
 
        v4l2_device_unregister_subdev(sd);
        v4l2_ctrl_handler_free(&state->hdl);
-       kfree(state);
        return 0;
 }
 
index 87880b1..285b759 100644 (file)
@@ -215,7 +215,7 @@ static int tw9903_probe(struct i2c_client *client,
        v4l_info(client, "chip found @ 0x%02x (%s)\n",
                        client->addr << 1, client->adapter->name);
 
-       dec = kzalloc(sizeof(struct tw9903), GFP_KERNEL);
+       dec = devm_kzalloc(&client->dev, sizeof(*dec), GFP_KERNEL);
        if (dec == NULL)
                return -ENOMEM;
        sd = &dec->sd;
@@ -233,7 +233,6 @@ static int tw9903_probe(struct i2c_client *client,
                int err = hdl->error;
 
                v4l2_ctrl_handler_free(hdl);
-               kfree(dec);
                return err;
        }
 
@@ -242,7 +241,6 @@ static int tw9903_probe(struct i2c_client *client,
 
        if (write_regs(sd, initial_registers) < 0) {
                v4l2_err(client, "error initializing TW9903\n");
-               kfree(dec);
                return -EINVAL;
        }
 
@@ -255,7 +253,6 @@ static int tw9903_remove(struct i2c_client *client)
 
        v4l2_device_unregister_subdev(sd);
        v4l2_ctrl_handler_free(&to_state(sd)->hdl);
-       kfree(to_state(sd));
        return 0;
 }
 
index accd79e..f6bef25 100644 (file)
@@ -183,7 +183,7 @@ static int tw9906_probe(struct i2c_client *client,
        v4l_info(client, "chip found @ 0x%02x (%s)\n",
                        client->addr << 1, client->adapter->name);
 
-       dec = kzalloc(sizeof(struct tw9906), GFP_KERNEL);
+       dec = devm_kzalloc(&client->dev, sizeof(*dec), GFP_KERNEL);
        if (dec == NULL)
                return -ENOMEM;
        sd = &dec->sd;
@@ -201,7 +201,6 @@ static int tw9906_probe(struct i2c_client *client,
                int err = hdl->error;
 
                v4l2_ctrl_handler_free(hdl);
-               kfree(dec);
                return err;
        }
 
@@ -210,7 +209,6 @@ static int tw9906_probe(struct i2c_client *client,
 
        if (write_regs(sd, initial_registers) < 0) {
                v4l2_err(client, "error initializing TW9906\n");
-               kfree(dec);
                return -EINVAL;
        }
 
@@ -223,7 +221,6 @@ static int tw9906_remove(struct i2c_client *client)
 
        v4l2_device_unregister_subdev(sd);
        v4l2_ctrl_handler_free(&to_state(sd)->hdl);
-       kfree(to_state(sd));
        return 0;
 }
 
index 3af4085..081786d 100644 (file)
@@ -69,7 +69,7 @@ static int uda1342_probe(struct i2c_client *client,
        dev_dbg(&client->dev, "initializing UDA1342 at address %d on %s\n",
                client->addr, adapter->name);
 
-       sd = kzalloc(sizeof(struct v4l2_subdev), GFP_KERNEL);
+       sd = devm_kzalloc(&client->dev, sizeof(*sd), GFP_KERNEL);
        if (sd == NULL)
                return -ENOMEM;
 
@@ -89,7 +89,6 @@ static int uda1342_remove(struct i2c_client *client)
        struct v4l2_subdev *sd = i2c_get_clientdata(client);
 
        v4l2_device_unregister_subdev(sd);
-       kfree(sd);
        return 0;
 }
 
index f0a0921..d248e6a 100644 (file)
@@ -27,7 +27,6 @@
 #include <linux/videodev2.h>
 #include <linux/slab.h>
 #include <media/v4l2-device.h>
-#include <media/v4l2-chip-ident.h>
 #include <media/upd64031a.h>
 
 /* --------------------- read registers functions define -------------------- */
@@ -147,13 +146,6 @@ static int upd64031a_s_routing(struct v4l2_subdev *sd,
        return upd64031a_s_frequency(sd, NULL);
 }
 
-static int upd64031a_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_UPD64031A, 0);
-}
-
 static int upd64031a_log_status(struct v4l2_subdev *sd)
 {
        v4l2_info(sd, "Status: SA00=0x%02x SA01=0x%02x\n",
@@ -164,12 +156,6 @@ static int upd64031a_log_status(struct v4l2_subdev *sd)
 #ifdef CONFIG_VIDEO_ADV_DEBUG
 static int upd64031a_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
 {
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       if (!v4l2_chip_match_i2c_client(client, &reg->match))
-               return -EINVAL;
-       if (!capable(CAP_SYS_ADMIN))
-               return -EPERM;
        reg->val = upd64031a_read(sd, reg->reg & 0xff);
        reg->size = 1;
        return 0;
@@ -177,12 +163,6 @@ static int upd64031a_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register
 
 static int upd64031a_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg)
 {
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       if (!v4l2_chip_match_i2c_client(client, &reg->match))
-               return -EINVAL;
-       if (!capable(CAP_SYS_ADMIN))
-               return -EPERM;
        upd64031a_write(sd, reg->reg & 0xff, reg->val & 0xff);
        return 0;
 }
@@ -192,7 +172,6 @@ static int upd64031a_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_re
 
 static const struct v4l2_subdev_core_ops upd64031a_core_ops = {
        .log_status = upd64031a_log_status,
-       .g_chip_ident = upd64031a_g_chip_ident,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
        .g_register = upd64031a_g_register,
        .s_register = upd64031a_s_register,
@@ -230,7 +209,7 @@ static int upd64031a_probe(struct i2c_client *client,
        v4l_info(client, "chip found @ 0x%x (%s)\n",
                        client->addr << 1, client->adapter->name);
 
-       state = kzalloc(sizeof(struct upd64031a_state), GFP_KERNEL);
+       state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL);
        if (state == NULL)
                return -ENOMEM;
        sd = &state->sd;
@@ -249,7 +228,6 @@ static int upd64031a_remove(struct i2c_client *client)
        struct v4l2_subdev *sd = i2c_get_clientdata(client);
 
        v4l2_device_unregister_subdev(sd);
-       kfree(to_state(sd));
        return 0;
 }
 
index 343e021..3a152ce 100644 (file)
@@ -27,7 +27,6 @@
 #include <linux/videodev2.h>
 #include <linux/slab.h>
 #include <media/v4l2-device.h>
-#include <media/v4l2-chip-ident.h>
 #include <media/upd64083.h>
 
 MODULE_DESCRIPTION("uPD64083 driver");
@@ -122,12 +121,6 @@ static int upd64083_s_routing(struct v4l2_subdev *sd,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
 static int upd64083_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
 {
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       if (!v4l2_chip_match_i2c_client(client, &reg->match))
-               return -EINVAL;
-       if (!capable(CAP_SYS_ADMIN))
-               return -EPERM;
        reg->val = upd64083_read(sd, reg->reg & 0xff);
        reg->size = 1;
        return 0;
@@ -135,24 +128,11 @@ static int upd64083_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register
 
 static int upd64083_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg)
 {
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       if (!v4l2_chip_match_i2c_client(client, &reg->match))
-               return -EINVAL;
-       if (!capable(CAP_SYS_ADMIN))
-               return -EPERM;
        upd64083_write(sd, reg->reg & 0xff, reg->val & 0xff);
        return 0;
 }
 #endif
 
-static int upd64083_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_UPD64083, 0);
-}
-
 static int upd64083_log_status(struct v4l2_subdev *sd)
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
@@ -169,7 +149,6 @@ static int upd64083_log_status(struct v4l2_subdev *sd)
 
 static const struct v4l2_subdev_core_ops upd64083_core_ops = {
        .log_status = upd64083_log_status,
-       .g_chip_ident = upd64083_g_chip_ident,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
        .g_register = upd64083_g_register,
        .s_register = upd64083_s_register,
@@ -202,7 +181,7 @@ static int upd64083_probe(struct i2c_client *client,
        v4l_info(client, "chip found @ 0x%x (%s)\n",
                        client->addr << 1, client->adapter->name);
 
-       state = kzalloc(sizeof(struct upd64083_state), GFP_KERNEL);
+       state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL);
        if (state == NULL)
                return -ENOMEM;
        sd = &state->sd;
@@ -221,7 +200,6 @@ static int upd64083_remove(struct i2c_client *client)
        struct v4l2_subdev *sd = i2c_get_clientdata(client);
 
        v4l2_device_unregister_subdev(sd);
-       kfree(to_state(sd));
        return 0;
 }
 
index e71f139..6a3a3ff 100644 (file)
@@ -29,7 +29,6 @@
 #include <linux/i2c.h>
 #include <linux/videodev2.h>
 #include <media/v4l2-device.h>
-#include <media/v4l2-chip-ident.h>
 
 MODULE_DESCRIPTION("vp27smpx driver");
 MODULE_AUTHOR("Hans Verkuil");
@@ -112,13 +111,6 @@ static int vp27smpx_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
        return 0;
 }
 
-static int vp27smpx_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_VP27SMPX, 0);
-}
-
 static int vp27smpx_log_status(struct v4l2_subdev *sd)
 {
        struct vp27smpx_state *state = to_state(sd);
@@ -132,7 +124,6 @@ static int vp27smpx_log_status(struct v4l2_subdev *sd)
 
 static const struct v4l2_subdev_core_ops vp27smpx_core_ops = {
        .log_status = vp27smpx_log_status,
-       .g_chip_ident = vp27smpx_g_chip_ident,
        .s_std = vp27smpx_s_std,
 };
 
@@ -169,7 +160,7 @@ static int vp27smpx_probe(struct i2c_client *client,
        v4l_info(client, "chip found @ 0x%x (%s)\n",
                        client->addr << 1, client->adapter->name);
 
-       state = kzalloc(sizeof(struct vp27smpx_state), GFP_KERNEL);
+       state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL);
        if (state == NULL)
                return -ENOMEM;
        sd = &state->sd;
@@ -186,7 +177,6 @@ static int vp27smpx_remove(struct i2c_client *client)
        struct v4l2_subdev *sd = i2c_get_clientdata(client);
 
        v4l2_device_unregister_subdev(sd);
-       kfree(to_state(sd));
        return 0;
 }
 
index 2f67b4c..ece90df 100644 (file)
@@ -27,7 +27,6 @@
 #include <linux/i2c.h>
 #include <linux/videodev2.h>
 #include <media/v4l2-device.h>
-#include <media/v4l2-chip-ident.h>
 #include <media/v4l2-ctrls.h>
 
 MODULE_DESCRIPTION("vpx3220a/vpx3216b/vpx3214c video decoder driver");
@@ -49,7 +48,6 @@ struct vpx3220 {
        unsigned char reg[255];
 
        v4l2_std_id norm;
-       int ident;
        int input;
        int enable;
 };
@@ -297,7 +295,7 @@ static int vpx3220_init(struct v4l2_subdev *sd, u32 val)
 static int vpx3220_status(struct v4l2_subdev *sd, u32 *pstatus, v4l2_std_id *pstd)
 {
        int res = V4L2_IN_ST_NO_SIGNAL, status;
-       v4l2_std_id std = 0;
+       v4l2_std_id std = pstd ? *pstd : V4L2_STD_ALL;
 
        status = vpx3220_fp_read(sd, 0x0f3);
 
@@ -314,19 +312,21 @@ static int vpx3220_status(struct v4l2_subdev *sd, u32 *pstatus, v4l2_std_id *pst
                case 0x10:
                case 0x14:
                case 0x18:
-                       std = V4L2_STD_PAL;
+                       std &= V4L2_STD_PAL;
                        break;
 
                case 0x08:
-                       std = V4L2_STD_SECAM;
+                       std &= V4L2_STD_SECAM;
                        break;
 
                case 0x04:
                case 0x0c:
                case 0x1c:
-                       std = V4L2_STD_NTSC;
+                       std &= V4L2_STD_NTSC;
                        break;
                }
+       } else {
+               std = V4L2_STD_UNKNOWN;
        }
        if (pstd)
                *pstd = std;
@@ -442,14 +442,6 @@ static int vpx3220_s_ctrl(struct v4l2_ctrl *ctrl)
        return -EINVAL;
 }
 
-static int vpx3220_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
-{
-       struct vpx3220 *decoder = to_vpx3220(sd);
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       return v4l2_chip_ident_i2c_client(client, chip, decoder->ident, 0);
-}
-
 /* ----------------------------------------------------------------------- */
 
 static const struct v4l2_ctrl_ops vpx3220_ctrl_ops = {
@@ -457,7 +449,6 @@ static const struct v4l2_ctrl_ops vpx3220_ctrl_ops = {
 };
 
 static const struct v4l2_subdev_core_ops vpx3220_core_ops = {
-       .g_chip_ident = vpx3220_g_chip_ident,
        .init = vpx3220_init,
        .g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
        .try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
@@ -499,7 +490,7 @@ static int vpx3220_probe(struct i2c_client *client,
                I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA))
                return -ENODEV;
 
-       decoder = kzalloc(sizeof(struct vpx3220), GFP_KERNEL);
+       decoder = devm_kzalloc(&client->dev, sizeof(*decoder), GFP_KERNEL);
        if (decoder == NULL)
                return -ENOMEM;
        sd = &decoder->sd;
@@ -521,7 +512,6 @@ static int vpx3220_probe(struct i2c_client *client,
                int err = decoder->hdl.error;
 
                v4l2_ctrl_handler_free(&decoder->hdl);
-               kfree(decoder);
                return err;
        }
        v4l2_ctrl_handler_setup(&decoder->hdl);
@@ -529,7 +519,6 @@ static int vpx3220_probe(struct i2c_client *client,
        ver = i2c_smbus_read_byte_data(client, 0x00);
        pn = (i2c_smbus_read_byte_data(client, 0x02) << 8) +
                i2c_smbus_read_byte_data(client, 0x01);
-       decoder->ident = V4L2_IDENT_VPX3220A;
        if (ver == 0xec) {
                switch (pn) {
                case 0x4680:
@@ -537,11 +526,9 @@ static int vpx3220_probe(struct i2c_client *client,
                        break;
                case 0x4260:
                        name = "vpx3216b";
-                       decoder->ident = V4L2_IDENT_VPX3216B;
                        break;
                case 0x4280:
                        name = "vpx3214c";
-                       decoder->ident = V4L2_IDENT_VPX3214C;
                        break;
                }
        }
@@ -566,7 +553,7 @@ static int vpx3220_remove(struct i2c_client *client)
 
        v4l2_device_unregister_subdev(sd);
        v4l2_ctrl_handler_free(&decoder->hdl);
-       kfree(decoder);
+
        return 0;
 }
 
index f366fad..25bdd93 100644 (file)
@@ -27,7 +27,6 @@
 #include <linux/types.h>
 #include <linux/videodev2.h>
 
-#include <media/v4l2-chip-ident.h>
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-mediabus.h>
@@ -722,27 +721,9 @@ static int vs6624_s_stream(struct v4l2_subdev *sd, int enable)
        return 0;
 }
 
-static int vs6624_g_chip_ident(struct v4l2_subdev *sd,
-               struct v4l2_dbg_chip_ident *chip)
-{
-       int rev;
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       rev = (vs6624_read(sd, VS6624_FW_VSN_MAJOR) << 8)
-               | vs6624_read(sd, VS6624_FW_VSN_MINOR);
-
-       return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_VS6624, rev);
-}
-
 #ifdef CONFIG_VIDEO_ADV_DEBUG
 static int vs6624_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
 {
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       if (!v4l2_chip_match_i2c_client(client, &reg->match))
-               return -EINVAL;
-       if (!capable(CAP_SYS_ADMIN))
-               return -EPERM;
        reg->val = vs6624_read(sd, reg->reg & 0xffff);
        reg->size = 1;
        return 0;
@@ -750,12 +731,6 @@ static int vs6624_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *r
 
 static int vs6624_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg)
 {
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       if (!v4l2_chip_match_i2c_client(client, &reg->match))
-               return -EINVAL;
-       if (!capable(CAP_SYS_ADMIN))
-               return -EPERM;
        vs6624_write(sd, reg->reg & 0xffff, reg->val & 0xff);
        return 0;
 }
@@ -766,7 +741,6 @@ static const struct v4l2_ctrl_ops vs6624_ctrl_ops = {
 };
 
 static const struct v4l2_subdev_core_ops vs6624_core_ops = {
-       .g_chip_ident = vs6624_g_chip_ident,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
        .g_register = vs6624_g_register,
        .s_register = vs6624_s_register,
@@ -805,20 +779,18 @@ static int vs6624_probe(struct i2c_client *client,
        if (ce == NULL)
                return -EINVAL;
 
-       ret = gpio_request(*ce, "VS6624 Chip Enable");
+       ret = devm_gpio_request_one(&client->dev, *ce, GPIOF_OUT_INIT_HIGH,
+                                   "VS6624 Chip Enable");
        if (ret) {
                v4l_err(client, "failed to request GPIO %d\n", *ce);
                return ret;
        }
-       gpio_direction_output(*ce, 1);
        /* wait 100ms before any further i2c writes are performed */
        mdelay(100);
 
-       sensor = kzalloc(sizeof(*sensor), GFP_KERNEL);
-       if (sensor == NULL) {
-               gpio_free(*ce);
+       sensor = devm_kzalloc(&client->dev, sizeof(*sensor), GFP_KERNEL);
+       if (sensor == NULL)
                return -ENOMEM;
-       }
 
        sd = &sensor->sd;
        v4l2_i2c_subdev_init(sd, client, &vs6624_ops);
@@ -866,30 +838,22 @@ static int vs6624_probe(struct i2c_client *client,
                int err = hdl->error;
 
                v4l2_ctrl_handler_free(hdl);
-               kfree(sensor);
-               gpio_free(*ce);
                return err;
        }
 
        /* initialize the hardware to the default control values */
        ret = v4l2_ctrl_handler_setup(hdl);
-       if (ret) {
+       if (ret)
                v4l2_ctrl_handler_free(hdl);
-               kfree(sensor);
-               gpio_free(*ce);
-       }
        return ret;
 }
 
 static int vs6624_remove(struct i2c_client *client)
 {
        struct v4l2_subdev *sd = i2c_get_clientdata(client);
-       struct vs6624 *sensor = to_vs6624(sd);
 
        v4l2_device_unregister_subdev(sd);
        v4l2_ctrl_handler_free(sd->ctrl_handler);
-       gpio_free(sensor->ce_pin);
-       kfree(sensor);
        return 0;
 }
 
index 3bb99e9..3be73f6 100644 (file)
@@ -29,7 +29,6 @@
 #include <linux/i2c.h>
 #include <linux/videodev2.h>
 #include <media/v4l2-device.h>
-#include <media/v4l2-chip-ident.h>
 #include <media/v4l2-ctrls.h>
 
 MODULE_DESCRIPTION("wm8739 driver");
@@ -160,13 +159,6 @@ static int wm8739_s_clock_freq(struct v4l2_subdev *sd, u32 audiofreq)
        return 0;
 }
 
-static int wm8739_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_WM8739, 0);
-}
-
 static int wm8739_log_status(struct v4l2_subdev *sd)
 {
        struct wm8739_state *state = to_state(sd);
@@ -184,7 +176,6 @@ static const struct v4l2_ctrl_ops wm8739_ctrl_ops = {
 
 static const struct v4l2_subdev_core_ops wm8739_core_ops = {
        .log_status = wm8739_log_status,
-       .g_chip_ident = wm8739_g_chip_ident,
        .g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
        .try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
        .s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
@@ -220,7 +211,7 @@ static int wm8739_probe(struct i2c_client *client,
        v4l_info(client, "chip found @ 0x%x (%s)\n",
                        client->addr << 1, client->adapter->name);
 
-       state = kzalloc(sizeof(struct wm8739_state), GFP_KERNEL);
+       state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL);
        if (state == NULL)
                return -ENOMEM;
        sd = &state->sd;
@@ -237,7 +228,6 @@ static int wm8739_probe(struct i2c_client *client,
                int err = state->hdl.error;
 
                v4l2_ctrl_handler_free(&state->hdl);
-               kfree(state);
                return err;
        }
        v4l2_ctrl_cluster(3, &state->volume);
@@ -271,7 +261,6 @@ static int wm8739_remove(struct i2c_client *client)
 
        v4l2_device_unregister_subdev(sd);
        v4l2_ctrl_handler_free(&state->hdl);
-       kfree(to_state(sd));
        return 0;
 }
 
index 27c27b4..3f584a7 100644 (file)
@@ -33,7 +33,6 @@
 #include <linux/i2c.h>
 #include <linux/videodev2.h>
 #include <media/v4l2-device.h>
-#include <media/v4l2-chip-ident.h>
 #include <media/v4l2-ctrls.h>
 #include <media/wm8775.h>
 
@@ -158,13 +157,6 @@ static int wm8775_s_ctrl(struct v4l2_ctrl *ctrl)
        return -EINVAL;
 }
 
-static int wm8775_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_WM8775, 0);
-}
-
 static int wm8775_log_status(struct v4l2_subdev *sd)
 {
        struct wm8775_state *state = to_state(sd);
@@ -188,7 +180,6 @@ static const struct v4l2_ctrl_ops wm8775_ctrl_ops = {
 
 static const struct v4l2_subdev_core_ops wm8775_core_ops = {
        .log_status = wm8775_log_status,
-       .g_chip_ident = wm8775_g_chip_ident,
        .g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
        .try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
        .s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
@@ -241,7 +232,7 @@ static int wm8775_probe(struct i2c_client *client,
        v4l_info(client, "chip found @ 0x%02x (%s)\n",
                        client->addr << 1, client->adapter->name);
 
-       state = kzalloc(sizeof(struct wm8775_state), GFP_KERNEL);
+       state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL);
        if (state == NULL)
                return -ENOMEM;
        sd = &state->sd;
@@ -261,7 +252,6 @@ static int wm8775_probe(struct i2c_client *client,
        err = state->hdl.error;
        if (err) {
                v4l2_ctrl_handler_free(&state->hdl);
-               kfree(state);
                return err;
        }
 
@@ -319,7 +309,6 @@ static int wm8775_remove(struct i2c_client *client)
 
        v4l2_device_unregister_subdev(sd);
        v4l2_ctrl_handler_free(&state->hdl);
-       kfree(state);
        return 0;
 }
 
index 1957c0d..d5a7a13 100644 (file)
@@ -142,6 +142,8 @@ static long __media_device_enum_links(struct media_device *mdev,
 
                for (p = 0; p < entity->num_pads; p++) {
                        struct media_pad_desc pad;
+
+                       memset(&pad, 0, sizeof(pad));
                        media_device_kpad_to_upad(&entity->pads[p], &pad);
                        if (copy_to_user(&links->pads[p], &pad, sizeof(pad)))
                                return -EFAULT;
@@ -159,6 +161,7 @@ static long __media_device_enum_links(struct media_device *mdev,
                        if (entity->links[l].source->entity != entity)
                                continue;
 
+                       memset(&link, 0, sizeof(link));
                        media_device_kpad_to_upad(entity->links[l].source,
                                                  &link.source);
                        media_device_kpad_to_upad(entity->links[l].sink,
index e1cd132..cb30ffb 100644 (file)
@@ -429,6 +429,56 @@ media_entity_create_link(struct media_entity *source, u16 source_pad,
 }
 EXPORT_SYMBOL_GPL(media_entity_create_link);
 
+void __media_entity_remove_links(struct media_entity *entity)
+{
+       unsigned int i;
+
+       for (i = 0; i < entity->num_links; i++) {
+               struct media_link *link = &entity->links[i];
+               struct media_entity *remote;
+               unsigned int r = 0;
+
+               if (link->source->entity == entity)
+                       remote = link->sink->entity;
+               else
+                       remote = link->source->entity;
+
+               while (r < remote->num_links) {
+                       struct media_link *rlink = &remote->links[r];
+
+                       if (rlink != link->reverse) {
+                               r++;
+                               continue;
+                       }
+
+                       if (link->source->entity == entity)
+                               remote->num_backlinks--;
+
+                       if (--remote->num_links == 0)
+                               break;
+
+                       /* Insert last entry in place of the dropped link. */
+                       *rlink = remote->links[remote->num_links];
+               }
+       }
+
+       entity->num_links = 0;
+       entity->num_backlinks = 0;
+}
+EXPORT_SYMBOL_GPL(__media_entity_remove_links);
+
+void media_entity_remove_links(struct media_entity *entity)
+{
+       /* Do nothing if the entity is not registered. */
+       if (entity->parent == NULL)
+               return;
+
+       mutex_lock(&entity->parent->graph_mutex);
+       __media_entity_remove_links(entity);
+       mutex_unlock(&entity->parent->graph_mutex);
+}
+EXPORT_SYMBOL_GPL(media_entity_remove_links);
+
 static int __media_entity_setup_link_notify(struct media_link *link, u32 flags)
 {
        int ret;
@@ -496,25 +546,17 @@ int __media_entity_setup_link(struct media_link *link, u32 flags)
 
        mdev = source->parent;
 
-       if ((flags & MEDIA_LNK_FL_ENABLED) && mdev->link_notify) {
-               ret = mdev->link_notify(link->source, link->sink,
-                                       MEDIA_LNK_FL_ENABLED);
+       if (mdev->link_notify) {
+               ret = mdev->link_notify(link, flags,
+                                       MEDIA_DEV_NOTIFY_PRE_LINK_CH);
                if (ret < 0)
                        return ret;
        }
 
        ret = __media_entity_setup_link_notify(link, flags);
-       if (ret < 0)
-               goto err;
-
-       if (!(flags & MEDIA_LNK_FL_ENABLED) && mdev->link_notify)
-               mdev->link_notify(link->source, link->sink, 0);
-
-       return 0;
 
-err:
-       if ((flags & MEDIA_LNK_FL_ENABLED) && mdev->link_notify)
-               mdev->link_notify(link->source, link->sink, 0);
+       if (mdev->link_notify)
+               mdev->link_notify(link, flags, MEDIA_DEV_NOTIFY_POST_LINK_CH);
 
        return ret;
 }
@@ -560,17 +602,16 @@ media_entity_find_link(struct media_pad *source, struct media_pad *sink)
 EXPORT_SYMBOL_GPL(media_entity_find_link);
 
 /**
- * media_entity_remote_source - Find the source pad at the remote end of a link
- * @pad: Sink pad at the local end of the link
+ * media_entity_remote_pad - Find the pad at the remote end of a link
+ * @pad: Pad at the local end of the link
  *
- * Search for a remote source pad connected to the given sink pad by iterating
- * over all links originating or terminating at that pad until an enabled link
- * is found.
+ * Search for a remote pad connected to the given pad by iterating over all
+ * links originating or terminating at that pad until an enabled link is found.
  *
  * Return a pointer to the pad at the remote end of the first found enabled
  * link, or NULL if no enabled link has been found.
  */
-struct media_pad *media_entity_remote_source(struct media_pad *pad)
+struct media_pad *media_entity_remote_pad(struct media_pad *pad)
 {
        unsigned int i;
 
@@ -590,4 +631,4 @@ struct media_pad *media_entity_remote_source(struct media_pad *pad)
        return NULL;
 
 }
-EXPORT_SYMBOL_GPL(media_entity_remote_source);
+EXPORT_SYMBOL_GPL(media_entity_remote_pad);
index 06231b8..d12bd33 100644 (file)
@@ -687,6 +687,7 @@ static int buffer_finish(struct vb2_buffer *vb)
 
        parport_release(qcam->pdev);
        mutex_unlock(&qcam->lock);
+       v4l2_get_timestamp(&vb->v4l2_buf.timestamp);
        if (len != size)
                vb->state = VB2_BUF_STATE_ERROR;
        vb2_set_plane_payload(vb, 0, len);
@@ -964,6 +965,7 @@ static struct qcam *qcam_init(struct parport *port)
        q->drv_priv = qcam;
        q->ops = &qcam_video_qops;
        q->mem_ops = &vb2_vmalloc_memops;
+       q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
        err = vb2_queue_init(q);
        if (err < 0) {
                v4l2_err(v4l2_dev, "couldn't init vb2_queue for %s.\n", port->name);
index d4e2ed3..53196f1 100644 (file)
@@ -1,6 +1,7 @@
+if PCI && MEDIA_SUPPORT
+
 menuconfig MEDIA_PCI_SUPPORT
        bool "Media PCI Adapters"
-       depends on PCI && MEDIA_SUPPORT
        help
          Enable media drivers for PCI/PCIe bus.
          If you have such devices, say Y.
@@ -45,3 +46,4 @@ source "drivers/media/pci/ddbridge/Kconfig"
 endif
 
 endif #MEDIA_PCI_SUPPORT
+endif #PCI
index 44f8fb5..447afbd 100644 (file)
@@ -432,18 +432,7 @@ static struct pci_driver flexcop_pci_driver = {
        .remove   = flexcop_pci_remove,
 };
 
-static int __init flexcop_pci_module_init(void)
-{
-       return pci_register_driver(&flexcop_pci_driver);
-}
-
-static void __exit flexcop_pci_module_exit(void)
-{
-       pci_unregister_driver(&flexcop_pci_driver);
-}
-
-module_init(flexcop_pci_module_init);
-module_exit(flexcop_pci_module_exit);
+module_pci_driver(flexcop_pci_driver);
 
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_NAME);
index b7dc921..e564aac 100644 (file)
@@ -131,7 +131,7 @@ MODULE_PARM_DESC(vsfx,"set VSFX pci config bit "
                 "[yet another chipset flaw workaround]");
 MODULE_PARM_DESC(latency,"pci latency timer");
 MODULE_PARM_DESC(card,"specify TV/grabber card model, see CARDLIST file for a list");
-MODULE_PARM_DESC(pll,"specify installed crystal (0=none, 28=28 MHz, 35=35 MHz)");
+MODULE_PARM_DESC(pll, "specify installed crystal (0=none, 28=28 MHz, 35=35 MHz, 14=14 MHz)");
 MODULE_PARM_DESC(tuner,"specify installed tuner type");
 MODULE_PARM_DESC(autoload, "obsolete option, please do not use anymore");
 MODULE_PARM_DESC(audiodev, "specify audio device:\n"
@@ -2705,7 +2705,7 @@ struct tvcard bttv_tvcards[] = {
                .has_radio      = 1,
                .has_remote     = 1,
        },
-               [BTTV_BOARD_VD012] = {
+       [BTTV_BOARD_VD012] = {
                /* D.Heer@Phytec.de */
                .name           = "PHYTEC VD-012 (bt878)",
                .video_inputs   = 4,
@@ -2718,7 +2718,7 @@ struct tvcard bttv_tvcards[] = {
                .tuner_type     = TUNER_ABSENT,
                .tuner_addr     = ADDR_UNSET,
        },
-               [BTTV_BOARD_VD012_X1] = {
+       [BTTV_BOARD_VD012_X1] = {
                /* D.Heer@Phytec.de */
                .name           = "PHYTEC VD-012-X1 (bt878)",
                .video_inputs   = 4,
@@ -2731,7 +2731,7 @@ struct tvcard bttv_tvcards[] = {
                .tuner_type     = TUNER_ABSENT,
                .tuner_addr     = ADDR_UNSET,
        },
-               [BTTV_BOARD_VD012_X2] = {
+       [BTTV_BOARD_VD012_X2] = {
                /* D.Heer@Phytec.de */
                .name           = "PHYTEC VD-012-X2 (bt878)",
                .video_inputs   = 4,
@@ -2744,7 +2744,7 @@ struct tvcard bttv_tvcards[] = {
                .tuner_type     = TUNER_ABSENT,
                .tuner_addr     = ADDR_UNSET,
        },
-               [BTTV_BOARD_GEOVISION_GV800S] = {
+       [BTTV_BOARD_GEOVISION_GV800S] = {
                /* Bruno Christo <bchristo@inf.ufsm.br>
                 *
                 * GeoVision GV-800(S) has 4 Conexant Fusion 878A:
@@ -2771,7 +2771,7 @@ struct tvcard bttv_tvcards[] = {
                .no_tda7432     = 1,
                .muxsel_hook    = gv800s_muxsel,
        },
-               [BTTV_BOARD_GEOVISION_GV800S_SL] = {
+       [BTTV_BOARD_GEOVISION_GV800S_SL] = {
                /* Bruno Christo <bchristo@inf.ufsm.br>
                 *
                 * GeoVision GV-800(S) has 4 Conexant Fusion 878A:
@@ -2808,6 +2808,7 @@ struct tvcard bttv_tvcards[] = {
                .tuner_type     = TUNER_ABSENT,
                .tuner_addr     = ADDR_UNSET,
        },
+       /* ---- card 0xa0---------------------------------- */
        [BTTV_BOARD_TVT_TD3116] = {
                .name           = "Tongwei Video Technology TD-3116",
                .video_inputs   = 16,
@@ -2825,6 +2826,35 @@ struct tvcard bttv_tvcards[] = {
                .muxsel         = MUXSEL(2, 3, 1, 0),
                .tuner_type     = TUNER_ABSENT,
        },
+       [BTTV_BOARD_ADLINK_MPG24] = {
+               /* Adlink MPG24 */
+               .name           = "Adlink MPG24",
+               .video_inputs   = 1,
+               /* .audio_inputs= 1, */
+               .svhs           = NO_SVHS,
+               .muxsel         = MUXSEL(2, 2, 2, 2),
+               .tuner_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .pll            = PLL_28,
+       },
+       [BTTV_BOARD_BT848_CAP_14] = {
+               .name           = "Bt848 Capture 14MHz",
+               .video_inputs   = 4,
+               .svhs           = 2,
+               .muxsel         = MUXSEL(2, 3, 1, 0),
+               .pll            = PLL_14,
+               .tuner_type     = TUNER_ABSENT,
+       },
+       [BTTV_BOARD_CYBERVISION_CV06] = {
+               .name           = "CyberVision CV06 (SV)",
+               .video_inputs   = 4,
+               /* .audio_inputs= 0, */
+               .svhs           = NO_SVHS,
+               .muxsel         = MUXSEL(2, 3, 1, 0),
+               .pll            = PLL_28,
+               .tuner_type     = TUNER_ABSENT,
+               .tuner_addr     = ADDR_UNSET,
+       },
 
 };
 
@@ -3390,6 +3420,10 @@ void bttv_init_card2(struct bttv *btv)
                        btv->pll.pll_ifreq=35468950;
                        btv->pll.pll_crystal=BT848_IFORM_XT1;
                }
+               if (PLL_14 == bttv_tvcards[btv->c.type].pll) {
+                       btv->pll.pll_ifreq = 14318181;
+                       btv->pll.pll_crystal = BT848_IFORM_XT0;
+               }
                /* insmod options can override */
                switch (pll[btv->c.nr]) {
                case 0: /* none */
@@ -3409,6 +3443,12 @@ void bttv_init_card2(struct bttv *btv)
                        btv->pll.pll_ofreq   = 0;
                        btv->pll.pll_crystal = BT848_IFORM_XT1;
                        break;
+               case 3: /* 14 MHz */
+               case 14:
+                       btv->pll.pll_ifreq   = 14318181;
+                       btv->pll.pll_ofreq   = 0;
+                       btv->pll.pll_crystal = BT848_IFORM_XT0;
+                       break;
                }
        }
        btv->pll.pll_current = -1;
index e7d0884..c6532de 100644 (file)
@@ -50,7 +50,6 @@
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-event.h>
-#include <media/v4l2-chip-ident.h>
 #include <media/tvaudio.h>
 #include <media/msp3400.h>
 
@@ -1761,9 +1760,9 @@ static int bttv_querystd(struct file *file, void *f, v4l2_std_id *id)
        struct bttv *btv = fh->btv;
 
        if (btread(BT848_DSTATUS) & BT848_DSTATUS_NUML)
-               *id = V4L2_STD_625_50;
+               *id &= V4L2_STD_625_50;
        else
-               *id = V4L2_STD_525_60;
+               *id &= V4L2_STD_525_60;
        return 0;
 }
 
@@ -1907,28 +1906,6 @@ static int bttv_log_status(struct file *file, void *f)
        return 0;
 }
 
-static int bttv_g_chip_ident(struct file *file, void *f, struct v4l2_dbg_chip_ident *chip)
-{
-       struct bttv_fh *fh  = f;
-       struct bttv *btv = fh->btv;
-
-       chip->ident = V4L2_IDENT_NONE;
-       chip->revision = 0;
-       if (chip->match.type == V4L2_CHIP_MATCH_HOST) {
-               if (v4l2_chip_match_host(&chip->match)) {
-                       chip->ident = btv->id;
-                       if (chip->ident == PCI_DEVICE_ID_FUSION879)
-                               chip->ident = V4L2_IDENT_BT879;
-               }
-               return 0;
-       }
-       if (chip->match.type != V4L2_CHIP_MATCH_I2C_DRIVER &&
-           chip->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
-               return -EINVAL;
-       /* TODO: is this correct? */
-       return bttv_call_all_err(btv, core, g_chip_ident, chip);
-}
-
 #ifdef CONFIG_VIDEO_ADV_DEBUG
 static int bttv_g_register(struct file *file, void *f,
                                        struct v4l2_dbg_register *reg)
@@ -1936,16 +1913,6 @@ static int bttv_g_register(struct file *file, void *f,
        struct bttv_fh *fh = f;
        struct bttv *btv = fh->btv;
 
-       if (!capable(CAP_SYS_ADMIN))
-               return -EPERM;
-
-       if (!v4l2_chip_match_host(&reg->match)) {
-               /* TODO: subdev errors should not be ignored, this should become a
-                  subdev helper function. */
-               bttv_call_all(btv, core, g_register, reg);
-               return 0;
-       }
-
        /* bt848 has a 12-bit register space */
        reg->reg &= 0xfff;
        reg->val = btread(reg->reg);
@@ -1960,16 +1927,6 @@ static int bttv_s_register(struct file *file, void *f,
        struct bttv_fh *fh = f;
        struct bttv *btv = fh->btv;
 
-       if (!capable(CAP_SYS_ADMIN))
-               return -EPERM;
-
-       if (!v4l2_chip_match_host(&reg->match)) {
-               /* TODO: subdev errors should not be ignored, this should become a
-                  subdev helper function. */
-               bttv_call_all(btv, core, s_register, reg);
-               return 0;
-       }
-
        /* bt848 has a 12-bit register space */
        btwrite(reg->val, reg->reg & 0xfff);
 
@@ -3209,7 +3166,6 @@ static const struct v4l2_ioctl_ops bttv_ioctl_ops = {
        .vidioc_querystd                = bttv_querystd,
        .vidioc_subscribe_event         = v4l2_ctrl_subscribe_event,
        .vidioc_unsubscribe_event       = v4l2_event_unsubscribe,
-       .vidioc_g_chip_ident            = bttv_g_chip_ident,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
        .vidioc_g_register              = bttv_g_register,
        .vidioc_s_register              = bttv_s_register,
index 6139ce2..df578ef 100644 (file)
 #define BTTV_BOARD_PV183                   0x9f
 #define BTTV_BOARD_TVT_TD3116             0xa0
 #define BTTV_BOARD_APOSONIC_WDVR           0xa1
+#define BTTV_BOARD_ADLINK_MPG24            0xa2
+#define BTTV_BOARD_BT848_CAP_14            0xa3
+#define BTTV_BOARD_CYBERVISION_CV06        0xa4
 
 /* more card-specific defines */
 #define PT2254_L_CHANNEL 0x10
@@ -232,6 +235,7 @@ struct tvcard {
 #define PLL_NONE 0
 #define PLL_28   1
 #define PLL_35   2
+#define PLL_14   3
 
        /* i2c audio flags */
        unsigned int no_msp34xx:1;
index 38b1d64..c4890a4 100644 (file)
@@ -22,7 +22,6 @@
  *  02110-1301, USA.
  */
 
-#include <media/v4l2-chip-ident.h>
 #include "cx18-driver.h"
 #include "cx18-io.h"
 #include "cx18-cards.h"
@@ -1231,35 +1230,14 @@ static int cx18_av_log_status(struct v4l2_subdev *sd)
        return 0;
 }
 
-static inline int cx18_av_dbg_match(const struct v4l2_dbg_match *match)
-{
-       return match->type == V4L2_CHIP_MATCH_HOST && match->addr == 1;
-}
-
-static int cx18_av_g_chip_ident(struct v4l2_subdev *sd,
-                               struct v4l2_dbg_chip_ident *chip)
-{
-       struct cx18_av_state *state = to_cx18_av_state(sd);
-
-       if (cx18_av_dbg_match(&chip->match)) {
-               chip->ident = state->id;
-               chip->revision = state->rev;
-       }
-       return 0;
-}
-
 #ifdef CONFIG_VIDEO_ADV_DEBUG
 static int cx18_av_g_register(struct v4l2_subdev *sd,
                              struct v4l2_dbg_register *reg)
 {
        struct cx18 *cx = v4l2_get_subdevdata(sd);
 
-       if (!cx18_av_dbg_match(&reg->match))
-               return -EINVAL;
        if ((reg->reg & 0x3) != 0)
                return -EINVAL;
-       if (!capable(CAP_SYS_ADMIN))
-               return -EPERM;
        reg->size = 4;
        reg->val = cx18_av_read4(cx, reg->reg & 0x00000ffc);
        return 0;
@@ -1270,12 +1248,8 @@ static int cx18_av_s_register(struct v4l2_subdev *sd,
 {
        struct cx18 *cx = v4l2_get_subdevdata(sd);
 
-       if (!cx18_av_dbg_match(&reg->match))
-               return -EINVAL;
        if ((reg->reg & 0x3) != 0)
                return -EINVAL;
-       if (!capable(CAP_SYS_ADMIN))
-               return -EPERM;
        cx18_av_write4(cx, reg->reg & 0x00000ffc, reg->val);
        return 0;
 }
@@ -1286,17 +1260,9 @@ static const struct v4l2_ctrl_ops cx18_av_ctrl_ops = {
 };
 
 static const struct v4l2_subdev_core_ops cx18_av_general_ops = {
-       .g_chip_ident = cx18_av_g_chip_ident,
        .log_status = cx18_av_log_status,
        .load_fw = cx18_av_load_fw,
        .reset = cx18_av_reset,
-       .g_ctrl = v4l2_subdev_g_ctrl,
-       .s_ctrl = v4l2_subdev_s_ctrl,
-       .s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
-       .try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
-       .g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
-       .queryctrl = v4l2_subdev_queryctrl,
-       .querymenu = v4l2_subdev_querymenu,
        .s_std = cx18_av_s_std,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
        .g_register = cx18_av_g_register,
@@ -1344,8 +1310,6 @@ int cx18_av_probe(struct cx18 *cx)
        int err;
 
        state->rev = cx18_av_read4(cx, CXADEC_CHIP_CTRL) & 0xffff;
-       state->id = ((state->rev >> 4) == CXADEC_CHIP_TYPE_MAKO)
-                   ? V4L2_IDENT_CX23418_843 : V4L2_IDENT_UNKNOWN;
 
        state->vid_input = CX18_AV_COMPOSITE7;
        state->aud_input = CX18_AV_AUDIO8;
index e9c69d9..4c559e8 100644 (file)
@@ -104,7 +104,6 @@ struct cx18_av_state {
        enum cx18_av_audio_input aud_input;
        u32 audclk_freq;
        int audmode;
-       u32 id;
        u32 rev;
        int is_initialized;
 
index aee7b6d..1110bcb 100644 (file)
@@ -39,7 +39,6 @@
 #include "cx18-cards.h"
 #include "cx18-av-core.h"
 #include <media/tveeprom.h>
-#include <media/v4l2-chip-ident.h>
 
 u16 cx18_service2vbi(int type)
 {
@@ -362,73 +361,18 @@ static int cx18_s_fmt_sliced_vbi_cap(struct file *file, void *fh,
        return 0;
 }
 
-static int cx18_g_chip_ident(struct file *file, void *fh,
-                               struct v4l2_dbg_chip_ident *chip)
-{
-       struct cx18 *cx = fh2id(fh)->cx;
-       int err = 0;
-
-       chip->ident = V4L2_IDENT_NONE;
-       chip->revision = 0;
-       switch (chip->match.type) {
-       case V4L2_CHIP_MATCH_HOST:
-               switch (chip->match.addr) {
-               case 0:
-                       chip->ident = V4L2_IDENT_CX23418;
-                       chip->revision = cx18_read_reg(cx, 0xC72028);
-                       break;
-               case 1:
-                       /*
-                        * The A/V decoder is always present, but in the rare
-                        * case that the card doesn't have analog, we don't
-                        * use it.  We find it w/o using the cx->sd_av pointer
-                        */
-                       cx18_call_hw(cx, CX18_HW_418_AV,
-                                    core, g_chip_ident, chip);
-                       break;
-               default:
-                       /*
-                        * Could return ident = V4L2_IDENT_UNKNOWN if we had
-                        * other host chips at higher addresses, but we don't
-                        */
-                       err = -EINVAL; /* per V4L2 spec */
-                       break;
-               }
-               break;
-       case V4L2_CHIP_MATCH_I2C_DRIVER:
-               /* If needed, returns V4L2_IDENT_AMBIGUOUS without extra work */
-               cx18_call_all(cx, core, g_chip_ident, chip);
-               break;
-       case V4L2_CHIP_MATCH_I2C_ADDR:
-               /*
-                * We could return V4L2_IDENT_UNKNOWN, but we don't do the work
-                * to look if a chip is at the address with no driver.  That's a
-                * dangerous thing to do with EEPROMs anyway.
-                */
-               cx18_call_all(cx, core, g_chip_ident, chip);
-               break;
-       default:
-               err = -EINVAL;
-               break;
-       }
-       return err;
-}
-
 #ifdef CONFIG_VIDEO_ADV_DEBUG
 static int cx18_g_register(struct file *file, void *fh,
                                struct v4l2_dbg_register *reg)
 {
        struct cx18 *cx = fh2id(fh)->cx;
 
-       if (v4l2_chip_match_host(&reg->match)) {
-               if (reg->reg >= CX18_MEM_OFFSET + CX18_MEM_SIZE)
-                       return -EINVAL;
-               reg->size = 4;
-               reg->val = cx18_read_enc(cx, reg->reg);
-               return 0;
-       }
-       /* FIXME - errors shouldn't be ignored */
-       cx18_call_all(cx, core, g_register, reg);
+       if (reg->reg & 0x3)
+               return -EINVAL;
+       if (reg->reg >= CX18_MEM_OFFSET + CX18_MEM_SIZE)
+               return -EINVAL;
+       reg->size = 4;
+       reg->val = cx18_read_enc(cx, reg->reg);
        return 0;
 }
 
@@ -437,14 +381,11 @@ static int cx18_s_register(struct file *file, void *fh,
 {
        struct cx18 *cx = fh2id(fh)->cx;
 
-       if (v4l2_chip_match_host(&reg->match)) {
-               if (reg->reg >= CX18_MEM_OFFSET + CX18_MEM_SIZE)
-                       return -EINVAL;
-               cx18_write_enc(cx, reg->val, reg->reg);
-               return 0;
-       }
-       /* FIXME - errors shouldn't be ignored */
-       cx18_call_all(cx, core, s_register, reg);
+       if (reg->reg & 0x3)
+               return -EINVAL;
+       if (reg->reg >= CX18_MEM_OFFSET + CX18_MEM_SIZE)
+               return -EINVAL;
+       cx18_write_enc(cx, reg->val, reg->reg);
        return 0;
 }
 #endif
@@ -1162,7 +1103,6 @@ static const struct v4l2_ioctl_ops cx18_ioctl_ops = {
        .vidioc_try_fmt_vbi_cap         = cx18_try_fmt_vbi_cap,
        .vidioc_try_fmt_sliced_vbi_cap  = cx18_try_fmt_sliced_vbi_cap,
        .vidioc_g_sliced_vbi_cap        = cx18_g_sliced_vbi_cap,
-       .vidioc_g_chip_ident            = cx18_g_chip_ident,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
        .vidioc_g_register              = cx18_g_register,
        .vidioc_s_register              = cx18_s_register,
index 6dea11a..e3fc2c7 100644 (file)
@@ -1217,8 +1217,7 @@ static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id)
        struct cx23885_fh  *fh  = file->private_data;
        struct cx23885_dev *dev = fh->dev;
 
-       call_all(dev, core, g_std, id);
-
+       *id = dev->tvnorm;
        return 0;
 }
 
@@ -1661,7 +1660,6 @@ static struct v4l2_file_operations mpeg_fops = {
 };
 
 static const struct v4l2_ioctl_ops mpeg_ioctl_ops = {
-       .vidioc_querystd         = vidioc_g_std,
        .vidioc_g_std            = vidioc_g_std,
        .vidioc_s_std            = vidioc_s_std,
        .vidioc_enum_input       = vidioc_enum_input,
@@ -1690,8 +1688,8 @@ static const struct v4l2_ioctl_ops mpeg_ioctl_ops = {
        .vidioc_log_status       = vidioc_log_status,
        .vidioc_querymenu        = vidioc_querymenu,
        .vidioc_queryctrl        = vidioc_queryctrl,
-       .vidioc_g_chip_ident     = cx23885_g_chip_ident,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
+       .vidioc_g_chip_info      = cx23885_g_chip_info,
        .vidioc_g_register       = cx23885_g_register,
        .vidioc_s_register       = cx23885_s_register,
 #endif
@@ -1702,7 +1700,6 @@ static struct video_device cx23885_mpeg_template = {
        .fops          = &mpeg_fops,
        .ioctl_ops     = &mpeg_ioctl_ops,
        .tvnorms       = CX23885_NORMS,
-       .current_norm  = V4L2_STD_NTSC_M,
 };
 
 void cx23885_417_unregister(struct cx23885_dev *dev)
@@ -1735,7 +1732,7 @@ static struct video_device *cx23885_video_dev_alloc(
        *vfd = *template;
        snprintf(vfd->name, sizeof(vfd->name), "%s (%s)",
                cx23885_boards[tsport->dev->board].name, type);
-       vfd->parent  = &pci->dev;
+       vfd->v4l2_dev = &dev->v4l2_dev;
        vfd->release = video_device_release;
        return vfd;
 }
index acdb6d5..271d69d 100644 (file)
 #include "cx23885.h"
 #include "cx23885-ioctl.h"
 
-#include <media/v4l2-chip-ident.h>
-
-int cx23885_g_chip_ident(struct file *file, void *fh,
-                        struct v4l2_dbg_chip_ident *chip)
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+int cx23885_g_chip_info(struct file *file, void *fh,
+                        struct v4l2_dbg_chip_info *chip)
 {
        struct cx23885_dev *dev = ((struct cx23885_fh *)fh)->dev;
-       int err = 0;
-       u8 rev;
-
-       chip->ident = V4L2_IDENT_NONE;
-       chip->revision = 0;
-       switch (chip->match.type) {
-       case V4L2_CHIP_MATCH_HOST:
-               switch (chip->match.addr) {
-               case 0:
-                       rev = cx_read(RDR_CFG2) & 0xff;
-                       switch (dev->pci->device) {
-                       case 0x8852:
-                               /* rev 0x04 could be '885 or '888. Pick '888. */
-                               if (rev == 0x04)
-                                       chip->ident = V4L2_IDENT_CX23888;
-                               else
-                                       chip->ident = V4L2_IDENT_CX23885;
-                               break;
-                       case 0x8880:
-                               if (rev == 0x0e || rev == 0x0f)
-                                       chip->ident = V4L2_IDENT_CX23887;
-                               else
-                                       chip->ident = V4L2_IDENT_CX23888;
-                               break;
-                       default:
-                               chip->ident = V4L2_IDENT_UNKNOWN;
-                               break;
-                       }
-                       chip->revision = (dev->pci->device << 16) | (rev << 8) |
-                                        (dev->hwrevision & 0xff);
-                       break;
-               case 1:
-                       if (dev->v4l_device != NULL) {
-                               chip->ident = V4L2_IDENT_CX23417;
-                               chip->revision = 0;
-                       }
-                       break;
-               case 2:
-                       /*
-                        * The integrated IR controller on the CX23888 is
-                        * host chip 2.  It may not be used/initialized or sd_ir
-                        * may be pointing at the cx25840 subdevice for the
-                        * IR controller on the CX23885.  Thus we find it
-                        * without using the dev->sd_ir pointer.
-                        */
-                       call_hw(dev, CX23885_HW_888_IR, core, g_chip_ident,
-                               chip);
-                       break;
-               default:
-                       err = -EINVAL; /* per V4L2 spec */
-                       break;
-               }
-               break;
-       case V4L2_CHIP_MATCH_I2C_DRIVER:
-               /* If needed, returns V4L2_IDENT_AMBIGUOUS without extra work */
-               call_all(dev, core, g_chip_ident, chip);
-               break;
-       case V4L2_CHIP_MATCH_I2C_ADDR:
-               /*
-                * We could return V4L2_IDENT_UNKNOWN, but we don't do the work
-                * to look if a chip is at the address with no driver.  That's a
-                * dangerous thing to do with EEPROMs anyway.
-                */
-               call_all(dev, core, g_chip_ident, chip);
-               break;
-       default:
-               err = -EINVAL;
-               break;
-       }
-       return err;
-}
 
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-static int cx23885_g_host_register(struct cx23885_dev *dev,
-                                  struct v4l2_dbg_register *reg)
-{
-       if ((reg->reg & 0x3) != 0 || reg->reg >= pci_resource_len(dev->pci, 0))
+       if (chip->match.addr > 1)
                return -EINVAL;
-
-       reg->size = 4;
-       reg->val = cx_read(reg->reg);
+       if (chip->match.addr == 1) {
+               if (dev->v4l_device == NULL)
+                       return -EINVAL;
+               strlcpy(chip->name, "cx23417", sizeof(chip->name));
+       } else {
+               strlcpy(chip->name, dev->v4l2_dev.name, sizeof(chip->name));
+       }
        return 0;
 }
 
@@ -138,32 +66,16 @@ int cx23885_g_register(struct file *file, void *fh,
 {
        struct cx23885_dev *dev = ((struct cx23885_fh *)fh)->dev;
 
-       if (!capable(CAP_SYS_ADMIN))
-               return -EPERM;
-
-       if (reg->match.type == V4L2_CHIP_MATCH_HOST) {
-               switch (reg->match.addr) {
-               case 0:
-                       return cx23885_g_host_register(dev, reg);
-               case 1:
-                       return cx23417_g_register(dev, reg);
-               default:
-                       break;
-               }
-       }
-
-       /* FIXME - any error returns should not be ignored */
-       call_all(dev, core, g_register, reg);
-       return 0;
-}
+       if (reg->match.addr > 1)
+               return -EINVAL;
+       if (reg->match.addr)
+               return cx23417_g_register(dev, reg);
 
-static int cx23885_s_host_register(struct cx23885_dev *dev,
-                                  const struct v4l2_dbg_register *reg)
-{
        if ((reg->reg & 0x3) != 0 || reg->reg >= pci_resource_len(dev->pci, 0))
                return -EINVAL;
 
-       cx_write(reg->reg, reg->val);
+       reg->size = 4;
+       reg->val = cx_read(reg->reg);
        return 0;
 }
 
@@ -186,22 +98,15 @@ int cx23885_s_register(struct file *file, void *fh,
 {
        struct cx23885_dev *dev = ((struct cx23885_fh *)fh)->dev;
 
-       if (!capable(CAP_SYS_ADMIN))
-               return -EPERM;
-
-       if (reg->match.type == V4L2_CHIP_MATCH_HOST) {
-               switch (reg->match.addr) {
-               case 0:
-                       return cx23885_s_host_register(dev, reg);
-               case 1:
-                       return cx23417_s_register(dev, reg);
-               default:
-                       break;
-               }
-       }
+       if (reg->match.addr > 1)
+               return -EINVAL;
+       if (reg->match.addr)
+               return cx23417_s_register(dev, reg);
+
+       if ((reg->reg & 0x3) != 0 || reg->reg >= pci_resource_len(dev->pci, 0))
+               return -EINVAL;
 
-       /* FIXME - any error returns should not be ignored */
-       call_all(dev, core, s_register, reg);
+       cx_write(reg->reg, reg->val);
        return 0;
 }
 #endif
index a608096..92d9f07 100644 (file)
@@ -24,8 +24,8 @@
 #ifndef _CX23885_IOCTL_H_
 #define _CX23885_IOCTL_H_
 
-int cx23885_g_chip_ident(struct file *file, void *fh,
-                        struct v4l2_dbg_chip_ident *chip);
+int cx23885_g_chip_info(struct file *file, void *fh,
+                        struct v4l2_dbg_chip_info *chip);
 
 #ifdef CONFIG_VIDEO_ADV_DEBUG
 int cx23885_g_register(struct file *file, void *fh,
index ed08c89..e33d1a7 100644 (file)
@@ -1254,8 +1254,7 @@ static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id)
        struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
        dprintk(1, "%s()\n", __func__);
 
-       call_all(dev, core, g_std, id);
-
+       *id = dev->tvnorm;
        return 0;
 }
 
@@ -1743,7 +1742,6 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
        .vidioc_dqbuf         = vidioc_dqbuf,
        .vidioc_s_std         = vidioc_s_std,
        .vidioc_g_std         = vidioc_g_std,
-       .vidioc_querystd      = vidioc_g_std,
        .vidioc_enum_input    = vidioc_enum_input,
        .vidioc_g_input       = vidioc_g_input,
        .vidioc_s_input       = vidioc_s_input,
@@ -1757,8 +1755,8 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
        .vidioc_s_tuner       = vidioc_s_tuner,
        .vidioc_g_frequency   = vidioc_g_frequency,
        .vidioc_s_frequency   = vidioc_s_frequency,
-       .vidioc_g_chip_ident  = cx23885_g_chip_ident,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
+       .vidioc_g_chip_info   = cx23885_g_chip_info,
        .vidioc_g_register    = cx23885_g_register,
        .vidioc_s_register    = cx23885_s_register,
 #endif
@@ -1773,7 +1771,6 @@ static struct video_device cx23885_video_template = {
        .fops                 = &video_fops,
        .ioctl_ops            = &video_ioctl_ops,
        .tvnorms              = CX23885_NORMS,
-       .current_norm         = V4L2_STD_NTSC_M,
 };
 
 static const struct v4l2_file_operations radio_fops = {
@@ -1822,7 +1819,7 @@ int cx23885_video_register(struct cx23885_dev *dev)
        cx23885_vbi_template = cx23885_video_template;
        strcpy(cx23885_vbi_template.name, "cx23885-vbi");
 
-       dev->tvnorm = cx23885_video_template.current_norm;
+       dev->tvnorm = V4L2_STD_NTSC_M;
 
        /* init video dma queues */
        INIT_LIST_HEAD(&dev->vidq.active);
index fa672fe..2c951de 100644 (file)
@@ -25,7 +25,6 @@
 #include <linux/slab.h>
 
 #include <media/v4l2-device.h>
-#include <media/v4l2-chip-ident.h>
 #include <media/rc-core.h>
 
 #include "cx23885.h"
@@ -131,8 +130,6 @@ union cx23888_ir_fifo_rec {
 struct cx23888_ir_state {
        struct v4l2_subdev sd;
        struct cx23885_dev *dev;
-       u32 id;
-       u32 rev;
 
        struct v4l2_subdev_ir_parameters rx_params;
        struct mutex rx_params_lock;
@@ -1086,23 +1083,6 @@ static int cx23888_ir_log_status(struct v4l2_subdev *sd)
        return 0;
 }
 
-static inline int cx23888_ir_dbg_match(const struct v4l2_dbg_match *match)
-{
-       return match->type == V4L2_CHIP_MATCH_HOST && match->addr == 2;
-}
-
-static int cx23888_ir_g_chip_ident(struct v4l2_subdev *sd,
-                                  struct v4l2_dbg_chip_ident *chip)
-{
-       struct cx23888_ir_state *state = to_state(sd);
-
-       if (cx23888_ir_dbg_match(&chip->match)) {
-               chip->ident = state->id;
-               chip->revision = state->rev;
-       }
-       return 0;
-}
-
 #ifdef CONFIG_VIDEO_ADV_DEBUG
 static int cx23888_ir_g_register(struct v4l2_subdev *sd,
                                 struct v4l2_dbg_register *reg)
@@ -1110,14 +1090,10 @@ static int cx23888_ir_g_register(struct v4l2_subdev *sd,
        struct cx23888_ir_state *state = to_state(sd);
        u32 addr = CX23888_IR_REG_BASE + (u32) reg->reg;
 
-       if (!cx23888_ir_dbg_match(&reg->match))
-               return -EINVAL;
        if ((addr & 0x3) != 0)
                return -EINVAL;
        if (addr < CX23888_IR_CNTRL_REG || addr > CX23888_IR_LEARN_REG)
                return -EINVAL;
-       if (!capable(CAP_SYS_ADMIN))
-               return -EPERM;
        reg->size = 4;
        reg->val = cx23888_ir_read4(state->dev, addr);
        return 0;
@@ -1129,21 +1105,16 @@ static int cx23888_ir_s_register(struct v4l2_subdev *sd,
        struct cx23888_ir_state *state = to_state(sd);
        u32 addr = CX23888_IR_REG_BASE + (u32) reg->reg;
 
-       if (!cx23888_ir_dbg_match(&reg->match))
-               return -EINVAL;
        if ((addr & 0x3) != 0)
                return -EINVAL;
        if (addr < CX23888_IR_CNTRL_REG || addr > CX23888_IR_LEARN_REG)
                return -EINVAL;
-       if (!capable(CAP_SYS_ADMIN))
-               return -EPERM;
        cx23888_ir_write4(state->dev, addr, reg->val);
        return 0;
 }
 #endif
 
 static const struct v4l2_subdev_core_ops cx23888_ir_core_ops = {
-       .g_chip_ident = cx23888_ir_g_chip_ident,
        .log_status = cx23888_ir_log_status,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
        .g_register = cx23888_ir_g_register,
@@ -1217,8 +1188,6 @@ int cx23888_ir_probe(struct cx23885_dev *dev)
                return -ENOMEM;
 
        state->dev = dev;
-       state->id = V4L2_IDENT_CX23888_IR;
-       state->rev = 0;
        sd = &state->sd;
 
        v4l2_subdev_init(sd, &cx23888_ir_controller_ops);
index a87a0e1..e18a7ac 100644 (file)
@@ -744,7 +744,7 @@ static const struct cx88_board cx88_boards[] = {
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                /* Some variants use a tda9874 and so need the tvaudio module. */
-               .audio_chip     = V4L2_IDENT_TVAUDIO,
+               .audio_chip     = CX88_AUDIO_TVAUDIO,
                .input          = {{
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
@@ -976,7 +976,7 @@ static const struct cx88_board cx88_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .audio_chip     = V4L2_IDENT_WM8775,
+               .audio_chip     = CX88_AUDIO_WM8775,
                .i2sinputcntl   = 2,
                .input          = {{
                        .type   = CX88_VMUX_DVB,
@@ -1014,7 +1014,7 @@ static const struct cx88_board cx88_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .audio_chip = V4L2_IDENT_WM8775,
+               .audio_chip = CX88_AUDIO_WM8775,
                .input          = {{
                        .type   = CX88_VMUX_DVB,
                        .vmux   = 0,
@@ -1376,7 +1376,7 @@ static const struct cx88_board cx88_boards[] = {
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .tda9887_conf   = TDA9887_PRESENT,
-               .audio_chip     = V4L2_IDENT_WM8775,
+               .audio_chip     = CX88_AUDIO_WM8775,
                .input          = {{
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
@@ -1461,7 +1461,7 @@ static const struct cx88_board cx88_boards[] = {
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .tda9887_conf   = TDA9887_PRESENT,
-               .audio_chip     = V4L2_IDENT_WM8775,
+               .audio_chip     = CX88_AUDIO_WM8775,
                /*
                 * gpio0 as reported by Mike Crash <mike AT mikecrash.com>
                 */
@@ -1929,7 +1929,7 @@ static const struct cx88_board cx88_boards[] = {
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .tda9887_conf   = TDA9887_PRESENT,
-               .audio_chip     = V4L2_IDENT_WM8775,
+               .audio_chip     = CX88_AUDIO_WM8775,
                /*
                 * GPIO0 (WINTV2000)
                 *
index c8f3dcc..ad59dc9 100644 (file)
@@ -1034,7 +1034,14 @@ struct video_device *cx88_vdev_init(struct cx88_core *core,
        if (NULL == vfd)
                return NULL;
        *vfd = *template_;
+       /*
+        * The dev pointer of v4l2_device is NULL, instead we set the
+        * video_device dev_parent pointer to the correct PCI bus device.
+        * This driver is a rare example where there is one v4l2_device,
+        * but the video nodes have different parent (PCI) devices.
+        */
        vfd->v4l2_dev = &core->v4l2_dev;
+       vfd->dev_parent = &pci->dev;
        vfd->release = video_device_release;
        snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)",
                 core->name, type, core->board.name);
index c7a9be1..ecf21d9 100644 (file)
@@ -1353,26 +1353,14 @@ static int vidioc_s_frequency (struct file *file, void *priv,
        return cx88_set_freq(core, f);
 }
 
-static int vidioc_g_chip_ident(struct file *file, void *priv,
-                               struct v4l2_dbg_chip_ident *chip)
-{
-       if (!v4l2_chip_match_host(&chip->match))
-               return -EINVAL;
-       chip->revision = 0;
-       chip->ident = V4L2_IDENT_UNKNOWN;
-       return 0;
-}
-
 #ifdef CONFIG_VIDEO_ADV_DEBUG
 static int vidioc_g_register (struct file *file, void *fh,
                                struct v4l2_dbg_register *reg)
 {
        struct cx88_core *core = ((struct cx8800_fh*)fh)->dev->core;
 
-       if (!v4l2_chip_match_host(&reg->match))
-               return -EINVAL;
        /* cx2388x has a 24-bit register space */
-       reg->val = cx_read(reg->reg & 0xffffff);
+       reg->val = cx_read(reg->reg & 0xfffffc);
        reg->size = 4;
        return 0;
 }
@@ -1382,9 +1370,7 @@ static int vidioc_s_register (struct file *file, void *fh,
 {
        struct cx88_core *core = ((struct cx8800_fh*)fh)->dev->core;
 
-       if (!v4l2_chip_match_host(&reg->match))
-               return -EINVAL;
-       cx_write(reg->reg & 0xffffff, reg->val);
+       cx_write(reg->reg & 0xfffffc, reg->val);
        return 0;
 }
 #endif
@@ -1578,7 +1564,6 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
        .vidioc_s_frequency   = vidioc_s_frequency,
        .vidioc_subscribe_event      = v4l2_ctrl_subscribe_event,
        .vidioc_unsubscribe_event    = v4l2_event_unsubscribe,
-       .vidioc_g_chip_ident  = vidioc_g_chip_ident,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
        .vidioc_g_register    = vidioc_g_register,
        .vidioc_s_register    = vidioc_s_register,
@@ -1612,7 +1597,6 @@ static const struct v4l2_ioctl_ops vbi_ioctl_ops = {
        .vidioc_s_tuner       = vidioc_s_tuner,
        .vidioc_g_frequency   = vidioc_g_frequency,
        .vidioc_s_frequency   = vidioc_s_frequency,
-       .vidioc_g_chip_ident  = vidioc_g_chip_ident,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
        .vidioc_g_register    = vidioc_g_register,
        .vidioc_s_register    = vidioc_s_register,
@@ -1643,7 +1627,6 @@ static const struct v4l2_ioctl_ops radio_ioctl_ops = {
        .vidioc_s_frequency   = vidioc_s_frequency,
        .vidioc_subscribe_event      = v4l2_ctrl_subscribe_event,
        .vidioc_unsubscribe_event    = v4l2_event_unsubscribe,
-       .vidioc_g_chip_ident  = vidioc_g_chip_ident,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
        .vidioc_g_register    = vidioc_g_register,
        .vidioc_s_register    = vidioc_s_register,
@@ -1794,7 +1777,7 @@ static int cx8800_initdev(struct pci_dev *pci_dev,
 
        /* load and configure helper modules */
 
-       if (core->board.audio_chip == V4L2_IDENT_WM8775) {
+       if (core->board.audio_chip == CX88_AUDIO_WM8775) {
                struct i2c_board_info wm8775_info = {
                        .type = "wm8775",
                        .addr = 0x36 >> 1,
@@ -1815,7 +1798,7 @@ static int cx8800_initdev(struct pci_dev *pci_dev,
                }
        }
 
-       if (core->board.audio_chip == V4L2_IDENT_TVAUDIO) {
+       if (core->board.audio_chip == CX88_AUDIO_TVAUDIO) {
                /* This probes for a tda9874 as is used on some
                   Pixelview Ultra boards. */
                v4l2_i2c_new_subdev(&core->v4l2_dev, &core->i2c_adap,
index 51ce2c0..afe0eae 100644 (file)
@@ -30,7 +30,6 @@
 #include <media/tuner.h>
 #include <media/tveeprom.h>
 #include <media/videobuf-dma-sg.h>
-#include <media/v4l2-chip-ident.h>
 #include <media/cx2341x.h>
 #include <media/videobuf-dvb.h>
 #include <media/ir-kbd-i2c.h>
@@ -259,6 +258,11 @@ struct cx88_input {
        unsigned int    audioroute:4;
 };
 
+enum cx88_audio_chip {
+       CX88_AUDIO_WM8775,
+       CX88_AUDIO_TVAUDIO,
+};
+
 struct cx88_board {
        const char              *name;
        unsigned int            tuner_type;
@@ -269,7 +273,7 @@ struct cx88_board {
        struct cx88_input       input[MAX_CX88_INPUT];
        struct cx88_input       radio;
        enum cx88_board_type    mpeg;
-       unsigned int            audio_chip;
+       enum cx88_audio_chip    audio_chip;
        int                     num_frontends;
 
        /* Used for I2S devices */
index 026767b..ab797fe 100644 (file)
@@ -1241,18 +1241,7 @@ static struct pci_driver dm1105_driver = {
        .remove = dm1105_remove,
 };
 
-static int __init dm1105_init(void)
-{
-       return pci_register_driver(&dm1105_driver);
-}
-
-static void __exit dm1105_exit(void)
-{
-       pci_unregister_driver(&dm1105_driver);
-}
-
-module_init(dm1105_init);
-module_exit(dm1105_exit);
+module_pci_driver(dm1105_driver);
 
 MODULE_AUTHOR("Igor M. Liplianin <liplianin@me.by>");
 MODULE_DESCRIPTION("SDMC DM1105 DVB driver");
index b809bc8..c08ae3e 100644 (file)
@@ -58,7 +58,6 @@
 #include <linux/dma-mapping.h>
 #include <media/tveeprom.h>
 #include <media/saa7115.h>
-#include <media/v4l2-chip-ident.h>
 #include "tuner-xc2028.h"
 
 /* If you have already X v4l cards, then set this to X. This way
@@ -968,15 +967,10 @@ static void ivtv_load_and_init_modules(struct ivtv *itv)
        }
 
        if (hw & IVTV_HW_SAA711X) {
-               struct v4l2_dbg_chip_ident v;
-
                /* determine the exact saa711x model */
                itv->hw_flags &= ~IVTV_HW_SAA711X;
 
-               v.match.type = V4L2_CHIP_MATCH_I2C_DRIVER;
-               strlcpy(v.match.name, "saa7115", sizeof(v.match.name));
-               ivtv_call_hw(itv, IVTV_HW_SAA711X, core, g_chip_ident, &v);
-               if (v.ident == V4L2_IDENT_SAA7114) {
+               if (strstr(itv->sd_video->name, "saa7114")) {
                        itv->hw_flags |= IVTV_HW_SAA7114;
                        /* VBI is not yet supported by the saa7114 driver. */
                        itv->v4l2_cap &= ~(V4L2_CAP_SLICED_VBI_CAPTURE|V4L2_CAP_VBI_CAPTURE);
index 9cbbce0..807b275 100644 (file)
@@ -34,7 +34,6 @@
 #include "ivtv-cards.h"
 #include <media/saa7127.h>
 #include <media/tveeprom.h>
-#include <media/v4l2-chip-ident.h>
 #include <media/v4l2-event.h>
 #include <linux/dvb/audio.h>
 
@@ -692,31 +691,13 @@ static int ivtv_s_fmt_vid_out_overlay(struct file *file, void *fh, struct v4l2_f
        return ret;
 }
 
-static int ivtv_g_chip_ident(struct file *file, void *fh, struct v4l2_dbg_chip_ident *chip)
-{
-       struct ivtv *itv = fh2id(fh)->itv;
-
-       chip->ident = V4L2_IDENT_NONE;
-       chip->revision = 0;
-       if (chip->match.type == V4L2_CHIP_MATCH_HOST) {
-               if (v4l2_chip_match_host(&chip->match))
-                       chip->ident = itv->has_cx23415 ? V4L2_IDENT_CX23415 : V4L2_IDENT_CX23416;
-               return 0;
-       }
-       if (chip->match.type != V4L2_CHIP_MATCH_I2C_DRIVER &&
-           chip->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
-               return -EINVAL;
-       /* TODO: is this correct? */
-       return ivtv_call_all_err(itv, core, g_chip_ident, chip);
-}
-
 #ifdef CONFIG_VIDEO_ADV_DEBUG
 static int ivtv_itvc(struct ivtv *itv, bool get, u64 reg, u64 *val)
 {
        volatile u8 __iomem *reg_start;
 
-       if (!capable(CAP_SYS_ADMIN))
-               return -EPERM;
+       if (reg & 0x3)
+               return -EINVAL;
        if (reg >= IVTV_REG_OFFSET && reg < IVTV_REG_OFFSET + IVTV_REG_SIZE)
                reg_start = itv->reg_mem - IVTV_REG_OFFSET;
        else if (itv->has_cx23415 && reg >= IVTV_DECODER_OFFSET &&
@@ -738,29 +719,16 @@ static int ivtv_g_register(struct file *file, void *fh, struct v4l2_dbg_register
 {
        struct ivtv *itv = fh2id(fh)->itv;
 
-       if (v4l2_chip_match_host(&reg->match)) {
-               reg->size = 4;
-               return ivtv_itvc(itv, true, reg->reg, &reg->val);
-       }
-       /* TODO: subdev errors should not be ignored, this should become a
-          subdev helper function. */
-       ivtv_call_all(itv, core, g_register, reg);
-       return 0;
+       reg->size = 4;
+       return ivtv_itvc(itv, true, reg->reg, &reg->val);
 }
 
 static int ivtv_s_register(struct file *file, void *fh, const struct v4l2_dbg_register *reg)
 {
        struct ivtv *itv = fh2id(fh)->itv;
+       u64 val = reg->val;
 
-       if (v4l2_chip_match_host(&reg->match)) {
-               u64 val = reg->val;
-
-               return ivtv_itvc(itv, false, reg->reg, &val);
-       }
-       /* TODO: subdev errors should not be ignored, this should become a
-          subdev helper function. */
-       ivtv_call_all(itv, core, s_register, reg);
-       return 0;
+       return ivtv_itvc(itv, false, reg->reg, &val);
 }
 #endif
 
@@ -1914,7 +1882,6 @@ static const struct v4l2_ioctl_ops ivtv_ioctl_ops = {
        .vidioc_try_fmt_vid_out_overlay     = ivtv_try_fmt_vid_out_overlay,
        .vidioc_try_fmt_sliced_vbi_out      = ivtv_try_fmt_sliced_vbi_out,
        .vidioc_g_sliced_vbi_cap            = ivtv_g_sliced_vbi_cap,
-       .vidioc_g_chip_ident                = ivtv_g_chip_ident,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
        .vidioc_g_register                  = ivtv_g_register,
        .vidioc_s_register                  = ivtv_s_register,
index 6fe9fe5..104914a 100644 (file)
@@ -260,18 +260,7 @@ static struct pci_driver hopper_pci_driver = {
        .remove         = hopper_pci_remove,
 };
 
-static int hopper_init(void)
-{
-       return pci_register_driver(&hopper_pci_driver);
-}
-
-static void hopper_exit(void)
-{
-       return pci_unregister_driver(&hopper_pci_driver);
-}
-
-module_init(hopper_init);
-module_exit(hopper_exit);
+module_pci_driver(hopper_pci_driver);
 
 MODULE_DESCRIPTION("HOPPER driver");
 MODULE_AUTHOR("Manu Abraham");
index 932a0d7..801fc55 100644 (file)
@@ -290,18 +290,7 @@ static struct pci_driver mantis_pci_driver = {
        .remove         = mantis_pci_remove,
 };
 
-static int mantis_init(void)
-{
-       return pci_register_driver(&mantis_pci_driver);
-}
-
-static void mantis_exit(void)
-{
-       return pci_unregister_driver(&mantis_pci_driver);
-}
-
-module_init(mantis_init);
-module_exit(mantis_exit);
+module_pci_driver(mantis_pci_driver);
 
 MODULE_DESCRIPTION("MANTIS driver");
 MODULE_AUTHOR("Manu Abraham");
index 07aa887..07a2074 100644 (file)
@@ -273,7 +273,7 @@ struct stb0899_config vp1041_stb0899_config = {
        .demod_address          = 0x68, /*  0xd0 >> 1 */
 
        .xtal_freq              = 27000000,
-       .inversion              = IQ_SWAP_ON, /* 1 */
+       .inversion              = IQ_SWAP_ON,
 
        .lo_clk                 = 76500000,
        .hi_clk                 = 99000000,
index 2290fae..4938285 100644 (file)
@@ -796,18 +796,7 @@ static struct pci_driver pluto2_driver = {
        .remove = pluto2_remove,
 };
 
-static int __init pluto2_init(void)
-{
-       return pci_register_driver(&pluto2_driver);
-}
-
-static void __exit pluto2_exit(void)
-{
-       pci_unregister_driver(&pluto2_driver);
-}
-
-module_init(pluto2_init);
-module_exit(pluto2_exit);
+module_pci_driver(pluto2_driver);
 
 MODULE_AUTHOR("Andreas Oberritter <obi@linuxtv.org>");
 MODULE_DESCRIPTION("Pluto2 driver");
index e921108..75ce142 100644 (file)
@@ -1225,20 +1225,7 @@ static struct pci_driver pt1_driver = {
        .id_table       = pt1_id_table,
 };
 
-
-static int __init pt1_init(void)
-{
-       return pci_register_driver(&pt1_driver);
-}
-
-
-static void __exit pt1_cleanup(void)
-{
-       pci_unregister_driver(&pt1_driver);
-}
-
-module_init(pt1_init);
-module_exit(pt1_cleanup);
+module_pci_driver(pt1_driver);
 
 MODULE_AUTHOR("Takahito HIRANO <hiranotaka@zng.info>");
 MODULE_DESCRIPTION("Earthsoft PT1/PT2 Driver");
index f147b05..8ac4b1f 100644 (file)
@@ -34,8 +34,8 @@
 #include <linux/types.h>
 #include <linux/videodev2.h>
 #include <media/v4l2-device.h>
+#include <media/v4l2-ctrls.h>
 #include <media/v4l2-common.h>
-#include <media/v4l2-chip-ident.h>
 #include <linux/init.h>
 #include <linux/crc32.h>
 
@@ -92,7 +92,12 @@ static const struct v4l2_format v4l2_format_table[] =
 
 struct saa6752hs_state {
        struct v4l2_subdev            sd;
-       int                           chip;
+       struct v4l2_ctrl_handler      hdl;
+       struct { /* video bitrate mode control cluster */
+               struct v4l2_ctrl *video_bitrate_mode;
+               struct v4l2_ctrl *video_bitrate;
+               struct v4l2_ctrl *video_bitrate_peak;
+       };
        u32                           revision;
        int                           has_ac3;
        struct saa6752hs_mpeg_params  params;
@@ -362,316 +367,72 @@ static int saa6752hs_set_bitrate(struct i2c_client *client,
        return 0;
 }
 
-
-static int get_ctrl(int has_ac3, struct saa6752hs_mpeg_params *params,
-               struct v4l2_ext_control *ctrl)
+static int saa6752hs_try_ctrl(struct v4l2_ctrl *ctrl)
 {
+       struct saa6752hs_state *h =
+               container_of(ctrl->handler, struct saa6752hs_state, hdl);
+
        switch (ctrl->id) {
-       case V4L2_CID_MPEG_STREAM_TYPE:
-               ctrl->value = V4L2_MPEG_STREAM_TYPE_MPEG2_TS;
-               break;
-       case V4L2_CID_MPEG_STREAM_PID_PMT:
-               ctrl->value = params->ts_pid_pmt;
-               break;
-       case V4L2_CID_MPEG_STREAM_PID_AUDIO:
-               ctrl->value = params->ts_pid_audio;
-               break;
-       case V4L2_CID_MPEG_STREAM_PID_VIDEO:
-               ctrl->value = params->ts_pid_video;
-               break;
-       case V4L2_CID_MPEG_STREAM_PID_PCR:
-               ctrl->value = params->ts_pid_pcr;
-               break;
-       case V4L2_CID_MPEG_AUDIO_ENCODING:
-               ctrl->value = params->au_encoding;
-               break;
-       case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
-               ctrl->value = params->au_l2_bitrate;
-               break;
-       case V4L2_CID_MPEG_AUDIO_AC3_BITRATE:
-               if (!has_ac3)
-                       return -EINVAL;
-               ctrl->value = params->au_ac3_bitrate;
-               break;
-       case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
-               ctrl->value = V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000;
-               break;
-       case V4L2_CID_MPEG_VIDEO_ENCODING:
-               ctrl->value = V4L2_MPEG_VIDEO_ENCODING_MPEG_2;
-               break;
-       case V4L2_CID_MPEG_VIDEO_ASPECT:
-               ctrl->value = params->vi_aspect;
-               break;
-       case V4L2_CID_MPEG_VIDEO_BITRATE:
-               ctrl->value = params->vi_bitrate * 1000;
-               break;
-       case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
-               ctrl->value = params->vi_bitrate_peak * 1000;
-               break;
        case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
-               ctrl->value = params->vi_bitrate_mode;
+               /* peak bitrate shall be >= normal bitrate */
+               if (ctrl->val == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR &&
+                   h->video_bitrate_peak->val < h->video_bitrate->val)
+                       h->video_bitrate_peak->val = h->video_bitrate->val;
                break;
-       default:
-               return -EINVAL;
        }
        return 0;
 }
 
-static int handle_ctrl(int has_ac3, struct saa6752hs_mpeg_params *params,
-               struct v4l2_ext_control *ctrl, int set)
+static int saa6752hs_s_ctrl(struct v4l2_ctrl *ctrl)
 {
-       int old = 0, new;
+       struct saa6752hs_state *h =
+               container_of(ctrl->handler, struct saa6752hs_state, hdl);
+       struct saa6752hs_mpeg_params *params = &h->params;
 
-       new = ctrl->value;
        switch (ctrl->id) {
        case V4L2_CID_MPEG_STREAM_TYPE:
-               old = V4L2_MPEG_STREAM_TYPE_MPEG2_TS;
-               if (set && new != old)
-                       return -ERANGE;
-               new = old;
                break;
        case V4L2_CID_MPEG_STREAM_PID_PMT:
-               old = params->ts_pid_pmt;
-               if (set && new > MPEG_PID_MAX)
-                       return -ERANGE;
-               if (new > MPEG_PID_MAX)
-                       new = MPEG_PID_MAX;
-               params->ts_pid_pmt = new;
+               params->ts_pid_pmt = ctrl->val;
                break;
        case V4L2_CID_MPEG_STREAM_PID_AUDIO:
-               old = params->ts_pid_audio;
-               if (set && new > MPEG_PID_MAX)
-                       return -ERANGE;
-               if (new > MPEG_PID_MAX)
-                       new = MPEG_PID_MAX;
-               params->ts_pid_audio = new;
+               params->ts_pid_audio = ctrl->val;
                break;
        case V4L2_CID_MPEG_STREAM_PID_VIDEO:
-               old = params->ts_pid_video;
-               if (set && new > MPEG_PID_MAX)
-                       return -ERANGE;
-               if (new > MPEG_PID_MAX)
-                       new = MPEG_PID_MAX;
-               params->ts_pid_video = new;
+               params->ts_pid_video = ctrl->val;
                break;
        case V4L2_CID_MPEG_STREAM_PID_PCR:
-               old = params->ts_pid_pcr;
-               if (set && new > MPEG_PID_MAX)
-                       return -ERANGE;
-               if (new > MPEG_PID_MAX)
-                       new = MPEG_PID_MAX;
-               params->ts_pid_pcr = new;
+               params->ts_pid_pcr = ctrl->val;
                break;
        case V4L2_CID_MPEG_AUDIO_ENCODING:
-               old = params->au_encoding;
-               if (set && new != V4L2_MPEG_AUDIO_ENCODING_LAYER_2 &&
-                   (!has_ac3 || new != V4L2_MPEG_AUDIO_ENCODING_AC3))
-                       return -ERANGE;
-               params->au_encoding = new;
+               params->au_encoding = ctrl->val;
                break;
        case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
-               old = params->au_l2_bitrate;
-               if (set && new != V4L2_MPEG_AUDIO_L2_BITRATE_256K &&
-                          new != V4L2_MPEG_AUDIO_L2_BITRATE_384K)
-                       return -ERANGE;
-               if (new <= V4L2_MPEG_AUDIO_L2_BITRATE_256K)
-                       new = V4L2_MPEG_AUDIO_L2_BITRATE_256K;
-               else
-                       new = V4L2_MPEG_AUDIO_L2_BITRATE_384K;
-               params->au_l2_bitrate = new;
+               params->au_l2_bitrate = ctrl->val;
                break;
        case V4L2_CID_MPEG_AUDIO_AC3_BITRATE:
-               if (!has_ac3)
-                       return -EINVAL;
-               old = params->au_ac3_bitrate;
-               if (set && new != V4L2_MPEG_AUDIO_AC3_BITRATE_256K &&
-                          new != V4L2_MPEG_AUDIO_AC3_BITRATE_384K)
-                       return -ERANGE;
-               if (new <= V4L2_MPEG_AUDIO_AC3_BITRATE_256K)
-                       new = V4L2_MPEG_AUDIO_AC3_BITRATE_256K;
-               else
-                       new = V4L2_MPEG_AUDIO_AC3_BITRATE_384K;
-               params->au_ac3_bitrate = new;
+               params->au_ac3_bitrate = ctrl->val;
                break;
        case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
-               old = V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000;
-               if (set && new != old)
-                       return -ERANGE;
-               new = old;
                break;
        case V4L2_CID_MPEG_VIDEO_ENCODING:
-               old = V4L2_MPEG_VIDEO_ENCODING_MPEG_2;
-               if (set && new != old)
-                       return -ERANGE;
-               new = old;
                break;
        case V4L2_CID_MPEG_VIDEO_ASPECT:
-               old = params->vi_aspect;
-               if (set && new != V4L2_MPEG_VIDEO_ASPECT_16x9 &&
-                          new != V4L2_MPEG_VIDEO_ASPECT_4x3)
-                       return -ERANGE;
-               if (new != V4L2_MPEG_VIDEO_ASPECT_16x9)
-                       new = V4L2_MPEG_VIDEO_ASPECT_4x3;
-               params->vi_aspect = new;
-               break;
-       case V4L2_CID_MPEG_VIDEO_BITRATE:
-               old = params->vi_bitrate * 1000;
-               new = 1000 * (new / 1000);
-               if (set && new > MPEG_VIDEO_TARGET_BITRATE_MAX * 1000)
-                       return -ERANGE;
-               if (new > MPEG_VIDEO_TARGET_BITRATE_MAX * 1000)
-                       new = MPEG_VIDEO_TARGET_BITRATE_MAX * 1000;
-               params->vi_bitrate = new / 1000;
-               break;
-       case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
-               old = params->vi_bitrate_peak * 1000;
-               new = 1000 * (new / 1000);
-               if (set && new > MPEG_VIDEO_TARGET_BITRATE_MAX * 1000)
-                       return -ERANGE;
-               if (new > MPEG_VIDEO_TARGET_BITRATE_MAX * 1000)
-                       new = MPEG_VIDEO_TARGET_BITRATE_MAX * 1000;
-               params->vi_bitrate_peak = new / 1000;
+               params->vi_aspect = ctrl->val;
                break;
        case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
-               old = params->vi_bitrate_mode;
-               params->vi_bitrate_mode = new;
+               params->vi_bitrate_mode = ctrl->val;
+               params->vi_bitrate = h->video_bitrate->val / 1000;
+               params->vi_bitrate_peak = h->video_bitrate_peak->val / 1000;
+               v4l2_ctrl_activate(h->video_bitrate_peak,
+                               ctrl->val == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR);
                break;
        default:
                return -EINVAL;
        }
-       ctrl->value = new;
        return 0;
 }
 
-
-static int saa6752hs_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qctrl)
-{
-       struct saa6752hs_state *h = to_state(sd);
-       struct saa6752hs_mpeg_params *params = &h->params;
-       int err;
-
-       switch (qctrl->id) {
-       case V4L2_CID_MPEG_AUDIO_ENCODING:
-               return v4l2_ctrl_query_fill(qctrl,
-                               V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
-                               h->has_ac3 ? V4L2_MPEG_AUDIO_ENCODING_AC3 :
-                                       V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
-                               1, V4L2_MPEG_AUDIO_ENCODING_LAYER_2);
-
-       case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
-               return v4l2_ctrl_query_fill(qctrl,
-                               V4L2_MPEG_AUDIO_L2_BITRATE_256K,
-                               V4L2_MPEG_AUDIO_L2_BITRATE_384K, 1,
-                               V4L2_MPEG_AUDIO_L2_BITRATE_256K);
-
-       case V4L2_CID_MPEG_AUDIO_AC3_BITRATE:
-               if (!h->has_ac3)
-                       return -EINVAL;
-               return v4l2_ctrl_query_fill(qctrl,
-                               V4L2_MPEG_AUDIO_AC3_BITRATE_256K,
-                               V4L2_MPEG_AUDIO_AC3_BITRATE_384K, 1,
-                               V4L2_MPEG_AUDIO_AC3_BITRATE_256K);
-
-       case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
-               return v4l2_ctrl_query_fill(qctrl,
-                               V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000,
-                               V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000, 1,
-                               V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000);
-
-       case V4L2_CID_MPEG_VIDEO_ENCODING:
-               return v4l2_ctrl_query_fill(qctrl,
-                               V4L2_MPEG_VIDEO_ENCODING_MPEG_2,
-                               V4L2_MPEG_VIDEO_ENCODING_MPEG_2, 1,
-                               V4L2_MPEG_VIDEO_ENCODING_MPEG_2);
-
-       case V4L2_CID_MPEG_VIDEO_ASPECT:
-               return v4l2_ctrl_query_fill(qctrl,
-                               V4L2_MPEG_VIDEO_ASPECT_4x3,
-                               V4L2_MPEG_VIDEO_ASPECT_16x9, 1,
-                               V4L2_MPEG_VIDEO_ASPECT_4x3);
-
-       case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
-               err = v4l2_ctrl_query_fill(qctrl, 0, 27000000, 1, 8000000);
-               if (err == 0 &&
-                   params->vi_bitrate_mode ==
-                               V4L2_MPEG_VIDEO_BITRATE_MODE_CBR)
-                       qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
-               return err;
-
-       case V4L2_CID_MPEG_STREAM_TYPE:
-               return v4l2_ctrl_query_fill(qctrl,
-                               V4L2_MPEG_STREAM_TYPE_MPEG2_TS,
-                               V4L2_MPEG_STREAM_TYPE_MPEG2_TS, 1,
-                               V4L2_MPEG_STREAM_TYPE_MPEG2_TS);
-
-       case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
-               return v4l2_ctrl_query_fill(qctrl,
-                               V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
-                               V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, 1,
-                               V4L2_MPEG_VIDEO_BITRATE_MODE_VBR);
-       case V4L2_CID_MPEG_VIDEO_BITRATE:
-               return v4l2_ctrl_query_fill(qctrl, 0, 27000000, 1, 6000000);
-       case V4L2_CID_MPEG_STREAM_PID_PMT:
-               return v4l2_ctrl_query_fill(qctrl, 0, (1 << 14) - 1, 1, 16);
-       case V4L2_CID_MPEG_STREAM_PID_AUDIO:
-               return v4l2_ctrl_query_fill(qctrl, 0, (1 << 14) - 1, 1, 260);
-       case V4L2_CID_MPEG_STREAM_PID_VIDEO:
-               return v4l2_ctrl_query_fill(qctrl, 0, (1 << 14) - 1, 1, 256);
-       case V4L2_CID_MPEG_STREAM_PID_PCR:
-               return v4l2_ctrl_query_fill(qctrl, 0, (1 << 14) - 1, 1, 259);
-
-       default:
-               break;
-       }
-       return -EINVAL;
-}
-
-static int saa6752hs_querymenu(struct v4l2_subdev *sd, struct v4l2_querymenu *qmenu)
-{
-       static const u32 mpeg_audio_encoding[] = {
-               V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
-               V4L2_CTRL_MENU_IDS_END
-       };
-       static const u32 mpeg_audio_ac3_encoding[] = {
-               V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
-               V4L2_MPEG_AUDIO_ENCODING_AC3,
-               V4L2_CTRL_MENU_IDS_END
-       };
-       static u32 mpeg_audio_l2_bitrate[] = {
-               V4L2_MPEG_AUDIO_L2_BITRATE_256K,
-               V4L2_MPEG_AUDIO_L2_BITRATE_384K,
-               V4L2_CTRL_MENU_IDS_END
-       };
-       static u32 mpeg_audio_ac3_bitrate[] = {
-               V4L2_MPEG_AUDIO_AC3_BITRATE_256K,
-               V4L2_MPEG_AUDIO_AC3_BITRATE_384K,
-               V4L2_CTRL_MENU_IDS_END
-       };
-       struct saa6752hs_state *h = to_state(sd);
-       struct v4l2_queryctrl qctrl;
-       int err;
-
-       qctrl.id = qmenu->id;
-       err = saa6752hs_queryctrl(sd, &qctrl);
-       if (err)
-               return err;
-       switch (qmenu->id) {
-       case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
-               return v4l2_ctrl_query_menu_valid_items(qmenu,
-                               mpeg_audio_l2_bitrate);
-       case V4L2_CID_MPEG_AUDIO_AC3_BITRATE:
-               if (!h->has_ac3)
-                       return -EINVAL;
-               return v4l2_ctrl_query_menu_valid_items(qmenu,
-                               mpeg_audio_ac3_bitrate);
-       case V4L2_CID_MPEG_AUDIO_ENCODING:
-               return v4l2_ctrl_query_menu_valid_items(qmenu,
-                       h->has_ac3 ? mpeg_audio_ac3_encoding :
-                               mpeg_audio_encoding);
-       }
-       return v4l2_ctrl_query_menu(qmenu, &qctrl, NULL);
-}
-
 static int saa6752hs_init(struct v4l2_subdev *sd, u32 leading_null_bytes)
 {
        unsigned char buf[9], buf2[4];
@@ -793,58 +554,6 @@ static int saa6752hs_init(struct v4l2_subdev *sd, u32 leading_null_bytes)
        return 0;
 }
 
-static int saa6752hs_do_ext_ctrls(struct v4l2_subdev *sd, struct v4l2_ext_controls *ctrls, int set)
-{
-       struct saa6752hs_state *h = to_state(sd);
-       struct saa6752hs_mpeg_params params;
-       int i;
-
-       if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG)
-               return -EINVAL;
-
-       params = h->params;
-       for (i = 0; i < ctrls->count; i++) {
-               int err = handle_ctrl(h->has_ac3, &params, ctrls->controls + i, set);
-
-               if (err) {
-                       ctrls->error_idx = i;
-                       return err;
-               }
-       }
-       if (set)
-               h->params = params;
-       return 0;
-}
-
-static int saa6752hs_s_ext_ctrls(struct v4l2_subdev *sd, struct v4l2_ext_controls *ctrls)
-{
-       return saa6752hs_do_ext_ctrls(sd, ctrls, 1);
-}
-
-static int saa6752hs_try_ext_ctrls(struct v4l2_subdev *sd, struct v4l2_ext_controls *ctrls)
-{
-       return saa6752hs_do_ext_ctrls(sd, ctrls, 0);
-}
-
-static int saa6752hs_g_ext_ctrls(struct v4l2_subdev *sd, struct v4l2_ext_controls *ctrls)
-{
-       struct saa6752hs_state *h = to_state(sd);
-       int i;
-
-       if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG)
-               return -EINVAL;
-
-       for (i = 0; i < ctrls->count; i++) {
-               int err = get_ctrl(h->has_ac3, &h->params, ctrls->controls + i);
-
-               if (err) {
-                       ctrls->error_idx = i;
-                       return err;
-               }
-       }
-       return 0;
-}
-
 static int saa6752hs_g_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *f)
 {
        struct saa6752hs_state *h = to_state(sd);
@@ -859,25 +568,11 @@ static int saa6752hs_g_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefm
        return 0;
 }
 
-static int saa6752hs_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *f)
+static int saa6752hs_try_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *f)
 {
-       struct saa6752hs_state *h = to_state(sd);
        int dist_352, dist_480, dist_720;
 
-       if (f->code != V4L2_MBUS_FMT_FIXED)
-               return -EINVAL;
-
-       /*
-         FIXME: translate and round width/height into EMPRESS
-         subsample type:
-
-         type   |   PAL   |  NTSC
-         ---------------------------
-         SIF    | 352x288 | 352x240
-         1/2 D1 | 352x576 | 352x480
-         2/3 D1 | 480x576 | 480x480
-         D1     | 720x576 | 720x480
-       */
+       f->code = V4L2_MBUS_FMT_FIXED;
 
        dist_352 = abs(f->width - 352);
        dist_480 = abs(f->width - 480);
@@ -885,59 +580,82 @@ static int saa6752hs_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefm
        if (dist_720 < dist_480) {
                f->width = 720;
                f->height = 576;
-               h->video_format = SAA6752HS_VF_D1;
        } else if (dist_480 < dist_352) {
                f->width = 480;
                f->height = 576;
-               h->video_format = SAA6752HS_VF_2_3_D1;
        } else {
                f->width = 352;
-               if (abs(f->height - 576) <
-                   abs(f->height - 288)) {
+               if (abs(f->height - 576) < abs(f->height - 288))
                        f->height = 576;
-                       h->video_format = SAA6752HS_VF_1_2_D1;
-               } else {
+               else
                        f->height = 288;
-                       h->video_format = SAA6752HS_VF_SIF;
-               }
        }
        f->field = V4L2_FIELD_INTERLACED;
        f->colorspace = V4L2_COLORSPACE_SMPTE170M;
        return 0;
 }
 
-static int saa6752hs_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
+static int saa6752hs_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *f)
 {
        struct saa6752hs_state *h = to_state(sd);
 
-       h->standard = std;
+       if (f->code != V4L2_MBUS_FMT_FIXED)
+               return -EINVAL;
+
+       /*
+         FIXME: translate and round width/height into EMPRESS
+         subsample type:
+
+         type   |   PAL   |  NTSC
+         ---------------------------
+         SIF    | 352x288 | 352x240
+         1/2 D1 | 352x576 | 352x480
+         2/3 D1 | 480x576 | 480x480
+         D1     | 720x576 | 720x480
+       */
+
+       saa6752hs_try_mbus_fmt(sd, f);
+       if (f->width == 720)
+               h->video_format = SAA6752HS_VF_D1;
+       else if (f->width == 480)
+               h->video_format = SAA6752HS_VF_2_3_D1;
+       else if (f->height == 576)
+               h->video_format = SAA6752HS_VF_1_2_D1;
+       else
+               h->video_format = SAA6752HS_VF_SIF;
        return 0;
 }
 
-static int saa6752hs_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
+static int saa6752hs_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
 {
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct saa6752hs_state *h = to_state(sd);
 
-       return v4l2_chip_ident_i2c_client(client,
-                       chip, h->chip, h->revision);
+       h->standard = std;
+       return 0;
 }
 
 /* ----------------------------------------------------------------------- */
 
+static const struct v4l2_ctrl_ops saa6752hs_ctrl_ops = {
+       .try_ctrl = saa6752hs_try_ctrl,
+       .s_ctrl = saa6752hs_s_ctrl,
+};
+
 static const struct v4l2_subdev_core_ops saa6752hs_core_ops = {
-       .g_chip_ident = saa6752hs_g_chip_ident,
        .init = saa6752hs_init,
-       .queryctrl = saa6752hs_queryctrl,
-       .querymenu = saa6752hs_querymenu,
-       .g_ext_ctrls = saa6752hs_g_ext_ctrls,
-       .s_ext_ctrls = saa6752hs_s_ext_ctrls,
-       .try_ext_ctrls = saa6752hs_try_ext_ctrls,
+       .g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
+       .try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
+       .s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
+       .g_ctrl = v4l2_subdev_g_ctrl,
+       .s_ctrl = v4l2_subdev_s_ctrl,
+       .queryctrl = v4l2_subdev_queryctrl,
+       .querymenu = v4l2_subdev_querymenu,
        .s_std = saa6752hs_s_std,
 };
 
 static const struct v4l2_subdev_video_ops saa6752hs_video_ops = {
        .s_mbus_fmt = saa6752hs_s_mbus_fmt,
+       .try_mbus_fmt = saa6752hs_try_mbus_fmt,
        .g_mbus_fmt = saa6752hs_g_mbus_fmt,
 };
 
@@ -951,6 +669,7 @@ static int saa6752hs_probe(struct i2c_client *client,
 {
        struct saa6752hs_state *h = kzalloc(sizeof(*h), GFP_KERNEL);
        struct v4l2_subdev *sd;
+       struct v4l2_ctrl_handler *hdl;
        u8 addr = 0x13;
        u8 data[12];
 
@@ -963,15 +682,88 @@ static int saa6752hs_probe(struct i2c_client *client,
 
        i2c_master_send(client, &addr, 1);
        i2c_master_recv(client, data, sizeof(data));
-       h->chip = V4L2_IDENT_SAA6752HS;
        h->revision = (data[8] << 8) | data[9];
        h->has_ac3 = 0;
        if (h->revision == 0x0206) {
-               h->chip = V4L2_IDENT_SAA6752HS_AC3;
                h->has_ac3 = 1;
-               v4l_info(client, "support AC-3\n");
+               v4l_info(client, "supports AC-3\n");
        }
        h->params = param_defaults;
+
+       hdl = &h->hdl;
+       v4l2_ctrl_handler_init(hdl, 14);
+       v4l2_ctrl_new_std_menu(hdl, &saa6752hs_ctrl_ops,
+               V4L2_CID_MPEG_AUDIO_ENCODING,
+               h->has_ac3 ? V4L2_MPEG_AUDIO_ENCODING_AC3 :
+                       V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
+               0x0d, V4L2_MPEG_AUDIO_ENCODING_LAYER_2);
+
+       v4l2_ctrl_new_std_menu(hdl, &saa6752hs_ctrl_ops,
+               V4L2_CID_MPEG_AUDIO_L2_BITRATE,
+               V4L2_MPEG_AUDIO_L2_BITRATE_384K,
+               ~((1 << V4L2_MPEG_AUDIO_L2_BITRATE_256K) |
+                 (1 << V4L2_MPEG_AUDIO_L2_BITRATE_384K)),
+               V4L2_MPEG_AUDIO_L2_BITRATE_256K);
+
+       if (h->has_ac3)
+               v4l2_ctrl_new_std_menu(hdl, &saa6752hs_ctrl_ops,
+                       V4L2_CID_MPEG_AUDIO_AC3_BITRATE,
+                       V4L2_MPEG_AUDIO_AC3_BITRATE_384K,
+                       ~((1 << V4L2_MPEG_AUDIO_AC3_BITRATE_256K) |
+                         (1 << V4L2_MPEG_AUDIO_AC3_BITRATE_384K)),
+                       V4L2_MPEG_AUDIO_AC3_BITRATE_256K);
+
+       v4l2_ctrl_new_std_menu(hdl, &saa6752hs_ctrl_ops,
+               V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ,
+               V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000,
+               ~(1 << V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000),
+               V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000);
+
+       v4l2_ctrl_new_std_menu(hdl, &saa6752hs_ctrl_ops,
+               V4L2_CID_MPEG_VIDEO_ENCODING,
+               V4L2_MPEG_VIDEO_ENCODING_MPEG_2,
+               ~(1 << V4L2_MPEG_VIDEO_ENCODING_MPEG_2),
+               V4L2_MPEG_VIDEO_ENCODING_MPEG_2);
+
+       v4l2_ctrl_new_std_menu(hdl, &saa6752hs_ctrl_ops,
+               V4L2_CID_MPEG_VIDEO_ASPECT,
+               V4L2_MPEG_VIDEO_ASPECT_16x9, 0x01,
+               V4L2_MPEG_VIDEO_ASPECT_4x3);
+
+       h->video_bitrate_peak = v4l2_ctrl_new_std(hdl, &saa6752hs_ctrl_ops,
+               V4L2_CID_MPEG_VIDEO_BITRATE_PEAK,
+               1000000, 27000000, 1000, 8000000);
+
+       v4l2_ctrl_new_std_menu(hdl, &saa6752hs_ctrl_ops,
+               V4L2_CID_MPEG_STREAM_TYPE,
+               V4L2_MPEG_STREAM_TYPE_MPEG2_TS,
+               ~(1 << V4L2_MPEG_STREAM_TYPE_MPEG2_TS),
+               V4L2_MPEG_STREAM_TYPE_MPEG2_TS);
+
+       h->video_bitrate_mode = v4l2_ctrl_new_std_menu(hdl, &saa6752hs_ctrl_ops,
+               V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
+               V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, 0,
+               V4L2_MPEG_VIDEO_BITRATE_MODE_VBR);
+       h->video_bitrate = v4l2_ctrl_new_std(hdl, &saa6752hs_ctrl_ops,
+               V4L2_CID_MPEG_VIDEO_BITRATE, 1000000, 27000000, 1000, 6000000);
+       v4l2_ctrl_new_std(hdl, &saa6752hs_ctrl_ops,
+               V4L2_CID_MPEG_STREAM_PID_PMT, 0, (1 << 14) - 1, 1, 16);
+       v4l2_ctrl_new_std(hdl, &saa6752hs_ctrl_ops,
+               V4L2_CID_MPEG_STREAM_PID_AUDIO, 0, (1 << 14) - 1, 1, 260);
+       v4l2_ctrl_new_std(hdl, &saa6752hs_ctrl_ops,
+               V4L2_CID_MPEG_STREAM_PID_VIDEO, 0, (1 << 14) - 1, 1, 256);
+       v4l2_ctrl_new_std(hdl, &saa6752hs_ctrl_ops,
+               V4L2_CID_MPEG_STREAM_PID_PCR, 0, (1 << 14) - 1, 1, 259);
+       sd->ctrl_handler = hdl;
+       if (hdl->error) {
+               int err = hdl->error;
+
+               v4l2_ctrl_handler_free(hdl);
+               kfree(h);
+               return err;
+       }
+       v4l2_ctrl_cluster(3, &h->video_bitrate_mode);
+       v4l2_ctrl_handler_setup(hdl);
        h->standard = 0; /* Assume 625 input lines */
        return 0;
 }
@@ -981,6 +773,7 @@ static int saa6752hs_remove(struct i2c_client *client)
        struct v4l2_subdev *sd = i2c_get_clientdata(client);
 
        v4l2_device_unregister_subdev(sd);
+       v4l2_ctrl_handler_free(&to_state(sd)->hdl);
        kfree(to_state(sd));
        return 0;
 }
@@ -1002,11 +795,3 @@ static struct i2c_driver saa6752hs_driver = {
 };
 
 module_i2c_driver(saa6752hs_driver);
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
index 66a7081..3022eb2 100644 (file)
@@ -28,7 +28,6 @@
 
 #include <media/saa6752hs.h>
 #include <media/v4l2-common.h>
-#include <media/v4l2-chip-ident.h>
 
 /* ------------------------------------------------------------------ */
 
@@ -213,7 +212,7 @@ static int empress_enum_fmt_vid_cap(struct file *file, void  *priv,
 
        strlcpy(f->description, "MPEG TS", sizeof(f->description));
        f->pixelformat = V4L2_PIX_FMT_MPEG;
-
+       f->flags = V4L2_FMT_FLAG_COMPRESSED;
        return 0;
 }
 
@@ -228,6 +227,8 @@ static int empress_g_fmt_vid_cap(struct file *file, void *priv,
        v4l2_fill_pix_format(&f->fmt.pix, &mbus_fmt);
        f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
        f->fmt.pix.sizeimage    = TS_PACKET_SIZE * dev->ts.nr_packets;
+       f->fmt.pix.bytesperline = 0;
+       f->fmt.pix.priv = 0;
 
        return 0;
 }
@@ -244,6 +245,8 @@ static int empress_s_fmt_vid_cap(struct file *file, void *priv,
 
        f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
        f->fmt.pix.sizeimage    = TS_PACKET_SIZE * dev->ts.nr_packets;
+       f->fmt.pix.bytesperline = 0;
+       f->fmt.pix.priv = 0;
 
        return 0;
 }
@@ -252,9 +255,16 @@ static int empress_try_fmt_vid_cap(struct file *file, void *priv,
                                struct v4l2_format *f)
 {
        struct saa7134_dev *dev = file->private_data;
+       struct v4l2_mbus_framefmt mbus_fmt;
+
+       v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, V4L2_MBUS_FMT_FIXED);
+       saa_call_all(dev, video, try_mbus_fmt, &mbus_fmt);
+       v4l2_fill_pix_format(&f->fmt.pix, &mbus_fmt);
 
        f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
        f->fmt.pix.sizeimage    = TS_PACKET_SIZE * dev->ts.nr_packets;
+       f->fmt.pix.bytesperline = 0;
+       f->fmt.pix.priv = 0;
 
        return 0;
 }
@@ -413,21 +423,6 @@ static int empress_querymenu(struct file *file, void *priv,
        return saa_call_empress(dev, core, querymenu, c);
 }
 
-static int empress_g_chip_ident(struct file *file, void *fh,
-              struct v4l2_dbg_chip_ident *chip)
-{
-       struct saa7134_dev *dev = file->private_data;
-
-       chip->ident = V4L2_IDENT_NONE;
-       chip->revision = 0;
-       if (chip->match.type == V4L2_CHIP_MATCH_I2C_DRIVER &&
-           !strcmp(chip->match.name, "saa6752hs"))
-               return saa_call_empress(dev, core, g_chip_ident, chip);
-       if (chip->match.type == V4L2_CHIP_MATCH_I2C_ADDR)
-               return saa_call_empress(dev, core, g_chip_ident, chip);
-       return -EINVAL;
-}
-
 static int empress_s_std(struct file *file, void *priv, v4l2_std_id id)
 {
        struct saa7134_dev *dev = file->private_data;
@@ -475,7 +470,6 @@ static const struct v4l2_ioctl_ops ts_ioctl_ops = {
        .vidioc_querymenu               = empress_querymenu,
        .vidioc_g_ctrl                  = empress_g_ctrl,
        .vidioc_s_ctrl                  = empress_s_ctrl,
-       .vidioc_g_chip_ident            = empress_g_chip_ident,
        .vidioc_s_std                   = empress_s_std,
        .vidioc_g_std                   = empress_g_std,
 };
@@ -488,7 +482,6 @@ static struct video_device saa7134_empress_template = {
        .ioctl_ops     = &ts_ioctl_ops,
 
        .tvnorms                        = SAA7134_NORMS,
-       .current_norm                   = V4L2_STD_PAL,
 };
 
 static void empress_signal_update(struct work_struct *work)
@@ -518,7 +511,7 @@ static int empress_init(struct saa7134_dev *dev)
        if (NULL == dev->empress_dev)
                return -ENOMEM;
        *(dev->empress_dev) = saa7134_empress_template;
-       dev->empress_dev->parent  = &dev->pci->dev;
+       dev->empress_dev->v4l2_dev  = &dev->v4l2_dev;
        dev->empress_dev->release = video_device_release;
        snprintf(dev->empress_dev->name, sizeof(dev->empress_dev->name),
                 "%s empress (%s)", dev->name,
index cc40938..e12bbd8 100644 (file)
@@ -825,20 +825,22 @@ static int setup_clipping(struct saa7134_dev *dev, struct v4l2_clip *clips,
        return 0;
 }
 
-static int verify_preview(struct saa7134_dev *dev, struct v4l2_window *win)
+static int verify_preview(struct saa7134_dev *dev, struct v4l2_window *win, bool try)
 {
        enum v4l2_field field;
        int maxw, maxh;
 
-       if (NULL == dev->ovbuf.base)
+       if (!try && (dev->ovbuf.base == NULL || dev->ovfmt == NULL))
                return -EINVAL;
-       if (NULL == dev->ovfmt)
-               return -EINVAL;
-       if (win->w.width < 48 || win->w.height <  32)
-               return -EINVAL;
-       if (win->clipcount > 2048)
-               return -EINVAL;
-
+       if (win->w.width < 48)
+               win->w.width = 48;
+       if (win->w.height < 32)
+               win->w.height = 32;
+       if (win->clipcount > 8)
+               win->clipcount = 8;
+
+       win->chromakey = 0;
+       win->global_alpha = 0;
        field = win->field;
        maxw  = dev->crop_current.width;
        maxh  = dev->crop_current.height;
@@ -853,10 +855,9 @@ static int verify_preview(struct saa7134_dev *dev, struct v4l2_window *win)
        case V4L2_FIELD_BOTTOM:
                maxh = maxh / 2;
                break;
-       case V4L2_FIELD_INTERLACED:
-               break;
        default:
-               return -EINVAL;
+               field = V4L2_FIELD_INTERLACED;
+               break;
        }
 
        win->field = field;
@@ -872,20 +873,20 @@ static int start_preview(struct saa7134_dev *dev, struct saa7134_fh *fh)
        unsigned long base,control,bpl;
        int err;
 
-       err = verify_preview(dev,&fh->win);
+       err = verify_preview(dev, &dev->win, false);
        if (0 != err)
                return err;
 
-       dev->ovfield = fh->win.field;
+       dev->ovfield = dev->win.field;
        dprintk("start_preview %dx%d+%d+%d %s field=%s\n",
-               fh->win.w.width,fh->win.w.height,
-               fh->win.w.left,fh->win.w.top,
-               dev->ovfmt->name,v4l2_field_names[dev->ovfield]);
+               dev->win.w.width, dev->win.w.height,
+               dev->win.w.left, dev->win.w.top,
+               dev->ovfmt->name, v4l2_field_names[dev->ovfield]);
 
        /* setup window + clipping */
-       set_size(dev,TASK_B,fh->win.w.width,fh->win.w.height,
+       set_size(dev, TASK_B, dev->win.w.width, dev->win.w.height,
                 V4L2_FIELD_HAS_BOTH(dev->ovfield));
-       setup_clipping(dev,fh->clips,fh->nclips,
+       setup_clipping(dev, dev->clips, dev->nclips,
                       V4L2_FIELD_HAS_BOTH(dev->ovfield));
        if (dev->ovfmt->yuv)
                saa_andorb(SAA7134_DATA_PATH(TASK_B), 0x3f, 0x03);
@@ -895,8 +896,8 @@ static int start_preview(struct saa7134_dev *dev, struct saa7134_fh *fh)
 
        /* dma: setup channel 1 (= Video Task B) */
        base  = (unsigned long)dev->ovbuf.base;
-       base += dev->ovbuf.fmt.bytesperline * fh->win.w.top;
-       base += dev->ovfmt->depth/8         * fh->win.w.left;
+       base += dev->ovbuf.fmt.bytesperline * dev->win.w.top;
+       base += dev->ovfmt->depth/8         * dev->win.w.left;
        bpl   = dev->ovbuf.fmt.bytesperline;
        control = SAA7134_RS_CONTROL_BURST_16;
        if (dev->ovfmt->bswap)
@@ -1024,38 +1025,38 @@ static int buffer_prepare(struct videobuf_queue *q,
        int err;
 
        /* sanity checks */
-       if (NULL == fh->fmt)
+       if (NULL == dev->fmt)
                return -EINVAL;
-       if (fh->width    < 48 ||
-           fh->height   < 32 ||
-           fh->width/4  > dev->crop_current.width  ||
-           fh->height/4 > dev->crop_current.height ||
-           fh->width    > dev->crop_bounds.width  ||
-           fh->height   > dev->crop_bounds.height)
+       if (dev->width    < 48 ||
+           dev->height   < 32 ||
+           dev->width/4  > dev->crop_current.width  ||
+           dev->height/4 > dev->crop_current.height ||
+           dev->width    > dev->crop_bounds.width  ||
+           dev->height   > dev->crop_bounds.height)
                return -EINVAL;
-       size = (fh->width * fh->height * fh->fmt->depth) >> 3;
+       size = (dev->width * dev->height * dev->fmt->depth) >> 3;
        if (0 != buf->vb.baddr  &&  buf->vb.bsize < size)
                return -EINVAL;
 
        dprintk("buffer_prepare [%d,size=%dx%d,bytes=%d,fields=%s,%s]\n",
-               vb->i,fh->width,fh->height,size,v4l2_field_names[field],
-               fh->fmt->name);
-       if (buf->vb.width  != fh->width  ||
-           buf->vb.height != fh->height ||
+               vb->i, dev->width, dev->height, size, v4l2_field_names[field],
+               dev->fmt->name);
+       if (buf->vb.width  != dev->width  ||
+           buf->vb.height != dev->height ||
            buf->vb.size   != size       ||
            buf->vb.field  != field      ||
-           buf->fmt       != fh->fmt) {
+           buf->fmt       != dev->fmt) {
                saa7134_dma_free(q,buf);
        }
 
        if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
                struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
 
-               buf->vb.width  = fh->width;
-               buf->vb.height = fh->height;
+               buf->vb.width  = dev->width;
+               buf->vb.height = dev->height;
                buf->vb.size   = size;
                buf->vb.field  = field;
-               buf->fmt       = fh->fmt;
+               buf->fmt       = dev->fmt;
                buf->pt        = &fh->pt_cap;
                dev->video_q.curr = NULL;
 
@@ -1082,8 +1083,9 @@ static int
 buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size)
 {
        struct saa7134_fh *fh = q->priv_data;
+       struct saa7134_dev *dev = fh->dev;
 
-       *size = fh->fmt->depth * fh->width * fh->height >> 3;
+       *size = dev->fmt->depth * dev->width * dev->height >> 3;
        if (0 == *count)
                *count = gbuffers;
        *count = saa7134_buffer_count(*size,*count);
@@ -1287,15 +1289,17 @@ static int saa7134_s_ctrl(struct file *file, void *f, struct v4l2_control *c)
 
 /* ------------------------------------------------------------------ */
 
-static struct videobuf_queue* saa7134_queue(struct saa7134_fh *fh)
+static struct videobuf_queue *saa7134_queue(struct file *file)
 {
-       struct videobuf_queue* q = NULL;
+       struct video_device *vdev = video_devdata(file);
+       struct saa7134_fh *fh = file->private_data;
+       struct videobuf_queue *q = NULL;
 
-       switch (fh->type) {
-       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+       switch (vdev->vfl_type) {
+       case VFL_TYPE_GRABBER:
                q = &fh->cap;
                break;
-       case V4L2_BUF_TYPE_VBI_CAPTURE:
+       case VFL_TYPE_VBI:
                q = &fh->vbi;
                break;
        default:
@@ -1304,12 +1308,14 @@ static struct videobuf_queue* saa7134_queue(struct saa7134_fh *fh)
        return q;
 }
 
-static int saa7134_resource(struct saa7134_fh *fh)
+static int saa7134_resource(struct file *file)
 {
-       if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+       struct video_device *vdev = video_devdata(file);
+
+       if (vdev->vfl_type == VFL_TYPE_GRABBER)
                return RESOURCE_VIDEO;
 
-       if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE)
+       if (vdev->vfl_type == VFL_TYPE_VBI)
                return RESOURCE_VBI;
 
        BUG();
@@ -1321,23 +1327,6 @@ static int video_open(struct file *file)
        struct video_device *vdev = video_devdata(file);
        struct saa7134_dev *dev = video_drvdata(file);
        struct saa7134_fh *fh;
-       enum v4l2_buf_type type = 0;
-       int radio = 0;
-
-       switch (vdev->vfl_type) {
-       case VFL_TYPE_GRABBER:
-               type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-               break;
-       case VFL_TYPE_VBI:
-               type = V4L2_BUF_TYPE_VBI_CAPTURE;
-               break;
-       case VFL_TYPE_RADIO:
-               radio = 1;
-               break;
-       }
-
-       dprintk("open dev=%s radio=%d type=%s\n", video_device_node_name(vdev),
-               radio, v4l2_type_names[type]);
 
        /* allocate + initialize per filehandle data */
        fh = kzalloc(sizeof(*fh),GFP_KERNEL);
@@ -1347,11 +1336,6 @@ static int video_open(struct file *file)
        v4l2_fh_init(&fh->fh, vdev);
        file->private_data = fh;
        fh->dev      = dev;
-       fh->radio    = radio;
-       fh->type     = type;
-       fh->fmt      = format_by_fourcc(V4L2_PIX_FMT_BGR24);
-       fh->width    = 720;
-       fh->height   = 576;
 
        videobuf_queue_sg_init(&fh->cap, &video_qops,
                            &dev->pci->dev, &dev->slock,
@@ -1368,7 +1352,7 @@ static int video_open(struct file *file)
        saa7134_pgtable_alloc(dev->pci,&fh->pt_cap);
        saa7134_pgtable_alloc(dev->pci,&fh->pt_vbi);
 
-       if (fh->radio) {
+       if (vdev->vfl_type == VFL_TYPE_RADIO) {
                /* switch to radio mode */
                saa7134_tvaudio_setinput(dev,&card(dev).radio);
                saa_call_all(dev, tuner, s_radio);
@@ -1384,19 +1368,20 @@ static int video_open(struct file *file)
 static ssize_t
 video_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
 {
+       struct video_device *vdev = video_devdata(file);
        struct saa7134_fh *fh = file->private_data;
 
-       switch (fh->type) {
-       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+       switch (vdev->vfl_type) {
+       case VFL_TYPE_GRABBER:
                if (res_locked(fh->dev,RESOURCE_VIDEO))
                        return -EBUSY;
-               return videobuf_read_one(saa7134_queue(fh),
+               return videobuf_read_one(saa7134_queue(file),
                                         data, count, ppos,
                                         file->f_flags & O_NONBLOCK);
-       case V4L2_BUF_TYPE_VBI_CAPTURE:
+       case VFL_TYPE_VBI:
                if (!res_get(fh->dev,fh,RESOURCE_VBI))
                        return -EBUSY;
-               return videobuf_read_stream(saa7134_queue(fh),
+               return videobuf_read_stream(saa7134_queue(file),
                                            data, count, ppos, 1,
                                            file->f_flags & O_NONBLOCK);
                break;
@@ -1409,11 +1394,12 @@ video_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
 static unsigned int
 video_poll(struct file *file, struct poll_table_struct *wait)
 {
+       struct video_device *vdev = video_devdata(file);
        struct saa7134_fh *fh = file->private_data;
        struct videobuf_buffer *buf = NULL;
        unsigned int rc = 0;
 
-       if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type)
+       if (vdev->vfl_type == VFL_TYPE_VBI)
                return videobuf_poll_stream(file, &fh->vbi, wait);
 
        if (res_check(fh,RESOURCE_VIDEO)) {
@@ -1451,6 +1437,7 @@ err:
 
 static int video_release(struct file *file)
 {
+       struct video_device *vdev = video_devdata(file);
        struct saa7134_fh  *fh  = file->private_data;
        struct saa7134_dev *dev = fh->dev;
        struct saa6588_command cmd;
@@ -1489,7 +1476,7 @@ static int video_release(struct file *file)
        saa_andorb(SAA7134_OFMT_DATA_B, 0x1f, 0);
 
        saa_call_all(dev, core, s_power, 0);
-       if (fh->radio)
+       if (vdev->vfl_type == VFL_TYPE_RADIO)
                saa_call_all(dev, core, ioctl, SAA6588_CMD_CLOSE, &cmd);
 
        /* free stuff */
@@ -1507,9 +1494,7 @@ static int video_release(struct file *file)
 
 static int video_mmap(struct file *file, struct vm_area_struct * vma)
 {
-       struct saa7134_fh *fh = file->private_data;
-
-       return videobuf_mmap_mapper(saa7134_queue(fh), vma);
+       return videobuf_mmap_mapper(saa7134_queue(file), vma);
 }
 
 static ssize_t radio_read(struct file *file, char __user *data,
@@ -1570,15 +1555,18 @@ static int saa7134_g_fmt_vid_cap(struct file *file, void *priv,
                                struct v4l2_format *f)
 {
        struct saa7134_fh *fh = priv;
+       struct saa7134_dev *dev = fh->dev;
 
-       f->fmt.pix.width        = fh->width;
-       f->fmt.pix.height       = fh->height;
+       f->fmt.pix.width        = dev->width;
+       f->fmt.pix.height       = dev->height;
        f->fmt.pix.field        = fh->cap.field;
-       f->fmt.pix.pixelformat  = fh->fmt->fourcc;
+       f->fmt.pix.pixelformat  = dev->fmt->fourcc;
        f->fmt.pix.bytesperline =
-               (f->fmt.pix.width * fh->fmt->depth) >> 3;
+               (f->fmt.pix.width * dev->fmt->depth) >> 3;
        f->fmt.pix.sizeimage =
                f->fmt.pix.height * f->fmt.pix.bytesperline;
+       f->fmt.pix.colorspace   = V4L2_COLORSPACE_SMPTE170M;
+       f->fmt.pix.priv = 0;
        return 0;
 }
 
@@ -1586,14 +1574,33 @@ static int saa7134_g_fmt_vid_overlay(struct file *file, void *priv,
                                struct v4l2_format *f)
 {
        struct saa7134_fh *fh = priv;
+       struct saa7134_dev *dev = fh->dev;
+       struct v4l2_clip __user *clips = f->fmt.win.clips;
+       u32 clipcount = f->fmt.win.clipcount;
+       int err = 0;
+       int i;
 
        if (saa7134_no_overlay > 0) {
                printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
                return -EINVAL;
        }
-       f->fmt.win = fh->win;
+       mutex_lock(&dev->lock);
+       f->fmt.win = dev->win;
+       f->fmt.win.clips = clips;
+       if (clips == NULL)
+               clipcount = 0;
+       if (dev->nclips < clipcount)
+               clipcount = dev->nclips;
+       f->fmt.win.clipcount = clipcount;
+
+       for (i = 0; !err && i < clipcount; i++) {
+               if (copy_to_user(&f->fmt.win.clips[i].c, &dev->clips[i].c,
+                                       sizeof(struct v4l2_rect)))
+                       err = -EFAULT;
+       }
+       mutex_unlock(&dev->lock);
 
-       return 0;
+       return err;
 }
 
 static int saa7134_try_fmt_vid_cap(struct file *file, void *priv,
@@ -1623,10 +1630,9 @@ static int saa7134_try_fmt_vid_cap(struct file *file, void *priv,
        case V4L2_FIELD_BOTTOM:
                maxh = maxh / 2;
                break;
-       case V4L2_FIELD_INTERLACED:
-               break;
        default:
-               return -EINVAL;
+               field = V4L2_FIELD_INTERLACED;
+               break;
        }
 
        f->fmt.pix.field = field;
@@ -1643,6 +1649,8 @@ static int saa7134_try_fmt_vid_cap(struct file *file, void *priv,
                (f->fmt.pix.width * fmt->depth) >> 3;
        f->fmt.pix.sizeimage =
                f->fmt.pix.height * f->fmt.pix.bytesperline;
+       f->fmt.pix.colorspace   = V4L2_COLORSPACE_SMPTE170M;
+       f->fmt.pix.priv = 0;
 
        return 0;
 }
@@ -1658,22 +1666,25 @@ static int saa7134_try_fmt_vid_overlay(struct file *file, void *priv,
                return -EINVAL;
        }
 
-       return verify_preview(dev, &f->fmt.win);
+       if (f->fmt.win.clips == NULL)
+               f->fmt.win.clipcount = 0;
+       return verify_preview(dev, &f->fmt.win, true);
 }
 
 static int saa7134_s_fmt_vid_cap(struct file *file, void *priv,
                                        struct v4l2_format *f)
 {
        struct saa7134_fh *fh = priv;
+       struct saa7134_dev *dev = fh->dev;
        int err;
 
        err = saa7134_try_fmt_vid_cap(file, priv, f);
        if (0 != err)
                return err;
 
-       fh->fmt       = format_by_fourcc(f->fmt.pix.pixelformat);
-       fh->width     = f->fmt.pix.width;
-       fh->height    = f->fmt.pix.height;
+       dev->fmt       = format_by_fourcc(f->fmt.pix.pixelformat);
+       dev->width     = f->fmt.pix.width;
+       dev->height    = f->fmt.pix.height;
        fh->cap.field = f->fmt.pix.field;
        return 0;
 }
@@ -1690,20 +1701,19 @@ static int saa7134_s_fmt_vid_overlay(struct file *file, void *priv,
                printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
                return -EINVAL;
        }
-       err = verify_preview(dev, &f->fmt.win);
+       if (f->fmt.win.clips == NULL)
+               f->fmt.win.clipcount = 0;
+       err = verify_preview(dev, &f->fmt.win, true);
        if (0 != err)
                return err;
 
        mutex_lock(&dev->lock);
 
-       fh->win    = f->fmt.win;
-       fh->nclips = f->fmt.win.clipcount;
+       dev->win    = f->fmt.win;
+       dev->nclips = f->fmt.win.clipcount;
 
-       if (fh->nclips > 8)
-               fh->nclips = 8;
-
-       if (copy_from_user(fh->clips, f->fmt.win.clips,
-                          sizeof(struct v4l2_clip)*fh->nclips)) {
+       if (copy_from_user(dev->clips, f->fmt.win.clips,
+                          sizeof(struct v4l2_clip) * dev->nclips)) {
                mutex_unlock(&dev->lock);
                return -EFAULT;
        }
@@ -2057,7 +2067,6 @@ static int saa7134_g_frequency(struct file *file, void *priv,
        if (0 != f->tuner)
                return -EINVAL;
 
-       f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
        saa_call_all(dev, tuner, g_frequency, f);
 
        return 0;
@@ -2071,10 +2080,6 @@ static int saa7134_s_frequency(struct file *file, void *priv,
 
        if (0 != f->tuner)
                return -EINVAL;
-       if (0 == fh->radio && V4L2_TUNER_ANALOG_TV != f->type)
-               return -EINVAL;
-       if (1 == fh->radio && V4L2_TUNER_RADIO != f->type)
-               return -EINVAL;
        mutex_lock(&dev->lock);
 
        saa_call_all(dev, tuner, s_frequency, f);
@@ -2186,27 +2191,23 @@ static int saa7134_overlay(struct file *file, void *f, unsigned int on)
 static int saa7134_reqbufs(struct file *file, void *priv,
                                        struct v4l2_requestbuffers *p)
 {
-       struct saa7134_fh *fh = priv;
-       return videobuf_reqbufs(saa7134_queue(fh), p);
+       return videobuf_reqbufs(saa7134_queue(file), p);
 }
 
 static int saa7134_querybuf(struct file *file, void *priv,
                                        struct v4l2_buffer *b)
 {
-       struct saa7134_fh *fh = priv;
-       return videobuf_querybuf(saa7134_queue(fh), b);
+       return videobuf_querybuf(saa7134_queue(file), b);
 }
 
 static int saa7134_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
 {
-       struct saa7134_fh *fh = priv;
-       return videobuf_qbuf(saa7134_queue(fh), b);
+       return videobuf_qbuf(saa7134_queue(file), b);
 }
 
 static int saa7134_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
 {
-       struct saa7134_fh *fh = priv;
-       return videobuf_dqbuf(saa7134_queue(fh), b,
+       return videobuf_dqbuf(saa7134_queue(file), b,
                                file->f_flags & O_NONBLOCK);
 }
 
@@ -2215,7 +2216,7 @@ static int saa7134_streamon(struct file *file, void *priv,
 {
        struct saa7134_fh *fh = priv;
        struct saa7134_dev *dev = fh->dev;
-       int res = saa7134_resource(fh);
+       int res = saa7134_resource(file);
 
        if (!res_get(dev, fh, res))
                return -EBUSY;
@@ -2227,11 +2228,11 @@ static int saa7134_streamon(struct file *file, void *priv,
         * Unfortunately, I lack register-level documentation to check the
         * Linux FIFO setup and confirm the perfect value.
         */
-       pm_qos_add_request(&fh->qos_request,
+       pm_qos_add_request(&dev->qos_request,
                           PM_QOS_CPU_DMA_LATENCY,
                           20);
 
-       return videobuf_streamon(saa7134_queue(fh));
+       return videobuf_streamon(saa7134_queue(file));
 }
 
 static int saa7134_streamoff(struct file *file, void *priv,
@@ -2240,11 +2241,11 @@ static int saa7134_streamoff(struct file *file, void *priv,
        int err;
        struct saa7134_fh *fh = priv;
        struct saa7134_dev *dev = fh->dev;
-       int res = saa7134_resource(fh);
+       int res = saa7134_resource(file);
 
-       pm_qos_remove_request(&fh->qos_request);
+       pm_qos_remove_request(&dev->qos_request);
 
-       err = videobuf_streamoff(saa7134_queue(fh));
+       err = videobuf_streamoff(saa7134_queue(file));
        if (err < 0)
                return err;
        res_free(dev, fh, res);
@@ -2258,9 +2259,7 @@ static int vidioc_g_register (struct file *file, void *priv,
        struct saa7134_fh *fh = priv;
        struct saa7134_dev *dev = fh->dev;
 
-       if (!v4l2_chip_match_host(&reg->match))
-               return -EINVAL;
-       reg->val = saa_readb(reg->reg);
+       reg->val = saa_readb(reg->reg & 0xffffff);
        reg->size = 1;
        return 0;
 }
@@ -2271,9 +2270,7 @@ static int vidioc_s_register (struct file *file, void *priv,
        struct saa7134_fh *fh = priv;
        struct saa7134_dev *dev = fh->dev;
 
-       if (!v4l2_chip_match_host(&reg->match))
-               return -EINVAL;
-       saa_writeb(reg->reg&0xffffff, reg->val);
+       saa_writeb(reg->reg & 0xffffff, reg->val);
        return 0;
 }
 #endif
@@ -2287,9 +2284,7 @@ static int radio_g_tuner(struct file *file, void *priv,
        if (0 != t->index)
                return -EINVAL;
 
-       memset(t, 0, sizeof(*t));
        strcpy(t->name, "Radio");
-       t->type = V4L2_TUNER_RADIO;
 
        saa_call_all(dev, tuner, g_tuner, t);
        t->audmode &= V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO;
@@ -2443,7 +2438,6 @@ struct video_device saa7134_video_template = {
        .fops                           = &video_fops,
        .ioctl_ops                      = &video_ioctl_ops,
        .tvnorms                        = SAA7134_NORMS,
-       .current_norm                   = V4L2_STD_PAL,
 };
 
 struct video_device saa7134_radio_template = {
@@ -2480,6 +2474,16 @@ int saa7134_video_init1(struct saa7134_dev *dev)
        dev->video_q.timeout.function = saa7134_buffer_timeout;
        dev->video_q.timeout.data     = (unsigned long)(&dev->video_q);
        dev->video_q.dev              = dev;
+       dev->fmt = format_by_fourcc(V4L2_PIX_FMT_BGR24);
+       dev->width    = 720;
+       dev->height   = 576;
+       dev->win.w.width = dev->width;
+       dev->win.w.height = dev->height;
+       dev->win.field = V4L2_FIELD_INTERLACED;
+       dev->ovbuf.fmt.width = dev->width;
+       dev->ovbuf.fmt.height = dev->height;
+       dev->ovbuf.fmt.pixelformat = dev->fmt->fourcc;
+       dev->ovbuf.fmt.colorspace = V4L2_COLORSPACE_SMPTE170M;
 
        if (saa7134_boards[dev->board].video_out)
                saa7134_videoport_init(dev);
index d2ad16c..8d1453a 100644 (file)
@@ -471,19 +471,9 @@ struct saa7134_dmaqueue {
 struct saa7134_fh {
        struct v4l2_fh             fh;
        struct saa7134_dev         *dev;
-       unsigned int               radio;
-       enum v4l2_buf_type         type;
        unsigned int               resources;
-       struct pm_qos_request      qos_request;
-
-       /* video overlay */
-       struct v4l2_window         win;
-       struct v4l2_clip           clips[8];
-       unsigned int               nclips;
 
        /* video capture */
-       struct saa7134_format      *fmt;
-       unsigned int               width,height;
        struct videobuf_queue      cap;
        struct saa7134_pgtable     pt_cap;
 
@@ -592,12 +582,19 @@ struct saa7134_dev {
        struct saa7134_format      *ovfmt;
        unsigned int               ovenable;
        enum v4l2_field            ovfield;
+       struct v4l2_window         win;
+       struct v4l2_clip           clips[8];
+       unsigned int               nclips;
+
 
        /* video+ts+vbi capture */
        struct saa7134_dmaqueue    video_q;
        struct saa7134_dmaqueue    vbi_q;
        unsigned int               video_fieldcount;
        unsigned int               vbi_fieldcount;
+       struct saa7134_format      *fmt;
+       unsigned int               width, height;
+       struct pm_qos_request      qos_request;
 
        /* various v4l controls */
        struct saa7134_tvnorm      *tvnorm;              /* video */
index 71e8bea..33abe33 100644 (file)
@@ -669,14 +669,10 @@ static int vidioc_g_register(struct file *file, void *fh, struct v4l2_dbg_regist
 {
        struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
 
-       if (!capable(CAP_SYS_ADMIN))
-               return -EPERM;
-       if (v4l2_chip_match_host(&reg->match)) {
-               reg->val = saa7146_read(dev, reg->reg);
-               reg->size = 4;
-               return 0;
-       }
-       call_all(dev, core, g_register, reg);
+       if (reg->reg > pci_resource_len(dev->pci, 0) - 4)
+               return -EINVAL;
+       reg->val = saa7146_read(dev, reg->reg);
+       reg->size = 4;
        return 0;
 }
 
@@ -684,13 +680,10 @@ static int vidioc_s_register(struct file *file, void *fh, const struct v4l2_dbg_
 {
        struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
 
-       if (!capable(CAP_SYS_ADMIN))
-               return -EPERM;
-       if (v4l2_chip_match_host(&reg->match)) {
-               saa7146_write(dev, reg->reg, reg->val);
-               return 0;
-       }
-       return call_all(dev, core, s_register, reg);
+       if (reg->reg > pci_resource_len(dev->pci, 0) - 4)
+               return -EINVAL;
+       saa7146_write(dev, reg->reg, reg->val);
+       return 0;
 }
 #endif
 
index 7618fda..d37ee37 100644 (file)
@@ -1196,6 +1196,12 @@ static int saa7164_initdev(struct pci_dev *pci_dev,
        if (NULL == dev)
                return -ENOMEM;
 
+       err = v4l2_device_register(&pci_dev->dev, &dev->v4l2_dev);
+       if (err < 0) {
+               dev_err(&pci_dev->dev, "v4l2_device_register failed\n");
+               goto fail_free;
+       }
+
        /* pci init */
        dev->pci = pci_dev;
        if (pci_enable_device(pci_dev)) {
@@ -1367,6 +1373,7 @@ fail_fw:
 fail_irq:
        saa7164_dev_unregister(dev);
 fail_free:
+       v4l2_device_unregister(&dev->v4l2_dev);
        kfree(dev);
        return err;
 }
@@ -1439,6 +1446,7 @@ static void saa7164_finidev(struct pci_dev *pci_dev)
        mutex_unlock(&devlist);
 
        saa7164_dev_unregister(dev);
+       v4l2_device_unregister(&dev->v4l2_dev);
        kfree(dev);
 }
 
index 0b74fb2..9266965 100644 (file)
@@ -228,6 +228,7 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id id)
                return -EINVAL;
 
        port->encodernorm = saa7164_tvnorms[i];
+       port->std = id;
 
        /* Update the audio decoder while is not running in
         * auto detect mode.
@@ -239,6 +240,15 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id id)
        return 0;
 }
 
+static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id)
+{
+       struct saa7164_encoder_fh *fh = file->private_data;
+       struct saa7164_port *port = fh->port;
+
+       *id = port->std;
+       return 0;
+}
+
 static int vidioc_enum_input(struct file *file, void *priv,
        struct v4l2_input *i)
 {
@@ -1288,46 +1298,9 @@ static const struct v4l2_file_operations mpeg_fops = {
        .unlocked_ioctl = video_ioctl2,
 };
 
-static int saa7164_g_chip_ident(struct file *file, void *fh,
-                               struct v4l2_dbg_chip_ident *chip)
-{
-       struct saa7164_port *port = ((struct saa7164_encoder_fh *)fh)->port;
-       struct saa7164_dev *dev = port->dev;
-       dprintk(DBGLVL_ENC, "%s()\n", __func__);
-
-       return 0;
-}
-
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-static int saa7164_g_register(struct file *file, void *fh,
-                             struct v4l2_dbg_register *reg)
-{
-       struct saa7164_port *port = ((struct saa7164_encoder_fh *)fh)->port;
-       struct saa7164_dev *dev = port->dev;
-       dprintk(DBGLVL_ENC, "%s()\n", __func__);
-
-       if (!capable(CAP_SYS_ADMIN))
-               return -EPERM;
-
-       return 0;
-}
-
-static int saa7164_s_register(struct file *file, void *fh,
-                             const struct v4l2_dbg_register *reg)
-{
-       struct saa7164_port *port = ((struct saa7164_encoder_fh *)fh)->port;
-       struct saa7164_dev *dev = port->dev;
-       dprintk(DBGLVL_ENC, "%s()\n", __func__);
-
-       if (!capable(CAP_SYS_ADMIN))
-               return -EPERM;
-
-       return 0;
-}
-#endif
-
 static const struct v4l2_ioctl_ops mpeg_ioctl_ops = {
        .vidioc_s_std            = vidioc_s_std,
+       .vidioc_g_std            = vidioc_g_std,
        .vidioc_enum_input       = vidioc_enum_input,
        .vidioc_g_input          = vidioc_g_input,
        .vidioc_s_input          = vidioc_s_input,
@@ -1346,11 +1319,6 @@ static const struct v4l2_ioctl_ops mpeg_ioctl_ops = {
        .vidioc_s_ext_ctrls      = vidioc_s_ext_ctrls,
        .vidioc_try_ext_ctrls    = vidioc_try_ext_ctrls,
        .vidioc_queryctrl        = vidioc_queryctrl,
-       .vidioc_g_chip_ident     = saa7164_g_chip_ident,
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-       .vidioc_g_register       = saa7164_g_register,
-       .vidioc_s_register       = saa7164_s_register,
-#endif
 };
 
 static struct video_device saa7164_mpeg_template = {
@@ -1359,7 +1327,6 @@ static struct video_device saa7164_mpeg_template = {
        .ioctl_ops     = &mpeg_ioctl_ops,
        .minor         = -1,
        .tvnorms       = SAA7164_NORMS,
-       .current_norm  = V4L2_STD_NTSC_M,
 };
 
 static struct video_device *saa7164_encoder_alloc(
@@ -1381,7 +1348,7 @@ static struct video_device *saa7164_encoder_alloc(
        snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", dev->name,
                type, saa7164_boards[dev->board].name);
 
-       vfd->parent  = &pci->dev;
+       vfd->v4l2_dev  = &dev->v4l2_dev;
        vfd->release = video_device_release;
        return vfd;
 }
@@ -1426,6 +1393,7 @@ int saa7164_encoder_register(struct saa7164_port *port)
        port->encoder_params.ctl_aspect = V4L2_MPEG_VIDEO_ASPECT_4x3;
        port->encoder_params.refdist = 1;
        port->encoder_params.gop_size = SAA7164_ENCODER_DEFAULT_GOP_SIZE;
+       port->std = V4L2_STD_NTSC_M;
 
        if (port->encodernorm.id & V4L2_STD_525_60)
                port->height = 480;
index da224eb..6e025fe 100644 (file)
@@ -200,6 +200,7 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id id)
                return -EINVAL;
 
        port->encodernorm = saa7164_tvnorms[i];
+       port->std = id;
 
        /* Update the audio decoder while is not running in
         * auto detect mode.
@@ -211,6 +212,15 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id id)
        return 0;
 }
 
+static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id)
+{
+       struct saa7164_encoder_fh *fh = file->private_data;
+       struct saa7164_port *port = fh->port;
+
+       *id = port->std;
+       return 0;
+}
+
 static int vidioc_enum_input(struct file *file, void *priv,
        struct v4l2_input *i)
 {
@@ -1236,6 +1246,7 @@ static const struct v4l2_file_operations vbi_fops = {
 
 static const struct v4l2_ioctl_ops vbi_ioctl_ops = {
        .vidioc_s_std            = vidioc_s_std,
+       .vidioc_g_std            = vidioc_g_std,
        .vidioc_enum_input       = vidioc_enum_input,
        .vidioc_g_input          = vidioc_g_input,
        .vidioc_s_input          = vidioc_s_input,
@@ -1254,15 +1265,6 @@ static const struct v4l2_ioctl_ops vbi_ioctl_ops = {
        .vidioc_s_ext_ctrls      = vidioc_s_ext_ctrls,
        .vidioc_try_ext_ctrls    = vidioc_try_ext_ctrls,
        .vidioc_queryctrl        = vidioc_queryctrl,
-#if 0
-       .vidioc_g_chip_ident     = saa7164_g_chip_ident,
-#endif
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-#if 0
-       .vidioc_g_register       = saa7164_g_register,
-       .vidioc_s_register       = saa7164_s_register,
-#endif
-#endif
        .vidioc_g_fmt_vbi_cap    = saa7164_vbi_fmt,
        .vidioc_try_fmt_vbi_cap  = saa7164_vbi_fmt,
        .vidioc_s_fmt_vbi_cap    = saa7164_vbi_fmt,
@@ -1274,7 +1276,6 @@ static struct video_device saa7164_vbi_template = {
        .ioctl_ops     = &vbi_ioctl_ops,
        .minor         = -1,
        .tvnorms       = SAA7164_NORMS,
-       .current_norm  = V4L2_STD_NTSC_M,
 };
 
 static struct video_device *saa7164_vbi_alloc(
@@ -1296,7 +1297,7 @@ static struct video_device *saa7164_vbi_alloc(
        snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", dev->name,
                type, saa7164_boards[dev->board].name);
 
-       vfd->parent  = &pci->dev;
+       vfd->v4l2_dev  = &dev->v4l2_dev;
        vfd->release = video_device_release;
        return vfd;
 }
@@ -1333,6 +1334,7 @@ int saa7164_vbi_register(struct saa7164_port *port)
                goto failed;
        }
 
+       port->std = V4L2_STD_NTSC_M;
        video_set_drvdata(port->v4l_device, port);
        result = video_register_device(port->v4l_device,
                VFL_TYPE_VBI, -1);
index 437284e..8b29e89 100644 (file)
@@ -63,7 +63,7 @@
 #include <dmxdev.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
-#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-device.h>
 
 #include "saa7164-reg.h"
 #include "saa7164-types.h"
@@ -376,6 +376,7 @@ struct saa7164_port {
        /* Encoder */
        /* Defaults established in saa7164-encoder.c */
        struct saa7164_tvnorm encodernorm;
+       v4l2_std_id std;
        u32 height;
        u32 width;
        u32 freq;
@@ -427,6 +428,8 @@ struct saa7164_dev {
        struct list_head        devlist;
        atomic_t                refcount;
 
+       struct v4l2_device v4l2_dev;
+
        /* pci stuff */
        struct pci_dev  *pci;
        unsigned char   pci_rev, pci_lat;
index 7005695..77edc11 100644 (file)
@@ -1047,7 +1047,8 @@ static int sta2x11_vip_init_one(struct pci_dev *pdev,
        ret = sta2x11_vip_init_controls(vip);
        if (ret)
                goto free_mem;
-       if (v4l2_device_register(&pdev->dev, &vip->v4l2_dev))
+       ret = v4l2_device_register(&pdev->dev, &vip->v4l2_dev);
+       if (ret)
                goto free_mem;
 
        dev_dbg(&pdev->dev, "BAR #0 at 0x%lx 0x%lx irq %d\n",
index 1f8b1bb..0ba3875 100644 (file)
@@ -1128,7 +1128,7 @@ static struct stb0899_config knc1_dvbs2_config = {
 //     .ts_pfbit_toggle        = STB0899_MPEG_NORMAL,  /* DirecTV, MPEG toggling seq   */
 
        .xtal_freq              = 27000000,
-       .inversion              = IQ_SWAP_OFF, /* 1 */
+       .inversion              = IQ_SWAP_OFF,
 
        .lo_clk                 = 76500000,
        .hi_clk                 = 90000000,
index 98e5241..0acf920 100644 (file)
@@ -1280,7 +1280,7 @@ static struct stb0899_config tt3200_config = {
        .demod_address          = 0x68,
 
        .xtal_freq              = 27000000,
-       .inversion              = IQ_SWAP_ON, /* 1 */
+       .inversion              = IQ_SWAP_ON,
 
        .lo_clk                 = 76500000,
        .hi_clk                 = 99000000,
index bb53d24..923d59a 100644 (file)
@@ -1050,7 +1050,7 @@ static int zr36057_init (struct zoran *zr)
         *   Now add the template and register the device unit.
         */
        memcpy(zr->video_dev, &zoran_template, sizeof(zoran_template));
-       zr->video_dev->parent = &zr->pci_dev->dev;
+       zr->video_dev->v4l2_dev = &zr->v4l2_dev;
        strcpy(zr->video_dev->name, ZR_DEVNAME(zr));
        /* It's not a mem2mem device, but you can both capture and output from
           one and the same device. This should really be split up into two
index d133c30..e7e9840 100644 (file)
@@ -1456,29 +1456,6 @@ zoran_set_norm (struct zoran *zr,
                return -EINVAL;
        }
 
-       if (norm == V4L2_STD_ALL) {
-               unsigned int status = 0;
-               v4l2_std_id std = 0;
-
-               decoder_call(zr, video, querystd, &std);
-               decoder_call(zr, core, s_std, std);
-
-               /* let changes come into effect */
-               ssleep(2);
-
-               decoder_call(zr, video, g_input_status, &status);
-               if (status & V4L2_IN_ST_NO_SIGNAL) {
-                       dprintk(1,
-                               KERN_ERR
-                               "%s: %s - no norm detected\n",
-                               ZR_DEVNAME(zr), __func__);
-                       /* reset norm */
-                       decoder_call(zr, core, s_std, zr->norm);
-                       return -EIO;
-               }
-
-               norm = std;
-       }
        if (norm & V4L2_STD_SECAM)
                zr->timing = zr->card.tvn[2];
        else if (norm & V4L2_STD_NTSC)
index 25eaf61..08de865 100644 (file)
@@ -36,7 +36,7 @@ source "drivers/media/platform/blackfin/Kconfig"
 config VIDEO_SH_VOU
        tristate "SuperH VOU video output driver"
        depends on MEDIA_CAMERA_SUPPORT
-       depends on VIDEO_DEV && ARCH_SHMOBILE
+       depends on VIDEO_DEV && ARCH_SHMOBILE && I2C
        select VIDEOBUF_DMA_CONTIG
        help
          Support for the Video Output Unit (VOU) on SuperH SoCs.
index 0e55b08..7f838c6 100644 (file)
@@ -32,7 +32,6 @@
 #include <linux/time.h>
 #include <linux/types.h>
 
-#include <media/v4l2-chip-ident.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-device.h>
@@ -649,18 +648,30 @@ static int bcap_s_std(struct file *file, void *priv, v4l2_std_id std)
        return 0;
 }
 
-static int bcap_g_dv_timings(struct file *file, void *priv,
+static int bcap_enum_dv_timings(struct file *file, void *priv,
+                               struct v4l2_enum_dv_timings *timings)
+{
+       struct bcap_device *bcap_dev = video_drvdata(file);
+
+       return v4l2_subdev_call(bcap_dev->sd, video,
+                       enum_dv_timings, timings);
+}
+
+static int bcap_query_dv_timings(struct file *file, void *priv,
                                struct v4l2_dv_timings *timings)
 {
        struct bcap_device *bcap_dev = video_drvdata(file);
-       int ret;
 
-       ret = v4l2_subdev_call(bcap_dev->sd, video,
-                               g_dv_timings, timings);
-       if (ret < 0)
-               return ret;
+       return v4l2_subdev_call(bcap_dev->sd, video,
+                               query_dv_timings, timings);
+}
 
-       bcap_dev->dv_timings = *timings;
+static int bcap_g_dv_timings(struct file *file, void *priv,
+                               struct v4l2_dv_timings *timings)
+{
+       struct bcap_device *bcap_dev = video_drvdata(file);
+
+       *timings = bcap_dev->dv_timings;
        return 0;
 }
 
@@ -864,41 +875,6 @@ static int bcap_s_parm(struct file *file, void *fh,
        return v4l2_subdev_call(bcap_dev->sd, video, s_parm, a);
 }
 
-static int bcap_g_chip_ident(struct file *file, void *priv,
-               struct v4l2_dbg_chip_ident *chip)
-{
-       struct bcap_device *bcap_dev = video_drvdata(file);
-
-       chip->ident = V4L2_IDENT_NONE;
-       chip->revision = 0;
-       if (chip->match.type != V4L2_CHIP_MATCH_I2C_DRIVER &&
-                       chip->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
-               return -EINVAL;
-
-       return v4l2_subdev_call(bcap_dev->sd, core,
-                       g_chip_ident, chip);
-}
-
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-static int bcap_dbg_g_register(struct file *file, void *priv,
-               struct v4l2_dbg_register *reg)
-{
-       struct bcap_device *bcap_dev = video_drvdata(file);
-
-       return v4l2_subdev_call(bcap_dev->sd, core,
-                       g_register, reg);
-}
-
-static int bcap_dbg_s_register(struct file *file, void *priv,
-               const struct v4l2_dbg_register *reg)
-{
-       struct bcap_device *bcap_dev = video_drvdata(file);
-
-       return v4l2_subdev_call(bcap_dev->sd, core,
-                       s_register, reg);
-}
-#endif
-
 static int bcap_log_status(struct file *file, void *priv)
 {
        struct bcap_device *bcap_dev = video_drvdata(file);
@@ -921,6 +897,8 @@ static const struct v4l2_ioctl_ops bcap_ioctl_ops = {
        .vidioc_g_std            = bcap_g_std,
        .vidioc_s_dv_timings     = bcap_s_dv_timings,
        .vidioc_g_dv_timings     = bcap_g_dv_timings,
+       .vidioc_query_dv_timings = bcap_query_dv_timings,
+       .vidioc_enum_dv_timings  = bcap_enum_dv_timings,
        .vidioc_reqbufs          = bcap_reqbufs,
        .vidioc_querybuf         = bcap_querybuf,
        .vidioc_qbuf             = bcap_qbuf,
@@ -929,11 +907,6 @@ static const struct v4l2_ioctl_ops bcap_ioctl_ops = {
        .vidioc_streamoff        = bcap_streamoff,
        .vidioc_g_parm           = bcap_g_parm,
        .vidioc_s_parm           = bcap_s_parm,
-       .vidioc_g_chip_ident     = bcap_g_chip_ident,
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-       .vidioc_g_register       = bcap_dbg_g_register,
-       .vidioc_s_register       = bcap_dbg_s_register,
-#endif
        .vidioc_log_status       = bcap_log_status,
 };
 
@@ -960,7 +933,7 @@ static int bcap_probe(struct platform_device *pdev)
        int ret;
 
        config = pdev->dev.platform_data;
-       if (!config) {
+       if (!config || !config->num_inputs) {
                v4l2_err(pdev->dev.driver, "Unable to get board config\n");
                return -ENODEV;
        }
@@ -1031,7 +1004,9 @@ static int bcap_probe(struct platform_device *pdev)
        q->mem_ops = &vb2_dma_contig_memops;
        q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
 
-       vb2_queue_init(q);
+       ret = vb2_queue_init(q);
+       if (ret)
+               goto err_free_handler;
 
        mutex_init(&bcap_dev->mutex);
        init_completion(&bcap_dev->comp);
@@ -1067,11 +1042,6 @@ static int bcap_probe(struct platform_device *pdev)
                                                 NULL);
        if (bcap_dev->sd) {
                int i;
-               if (!config->num_inputs) {
-                       v4l2_err(&bcap_dev->v4l2_dev,
-                                       "Unable to work without input\n");
-                       goto err_unreg_vdev;
-               }
 
                /* update tvnorms from the sub devices */
                for (i = 0; i < config->num_inputs; i++)
@@ -1079,6 +1049,7 @@ static int bcap_probe(struct platform_device *pdev)
        } else {
                v4l2_err(&bcap_dev->v4l2_dev,
                                "Unable to register sub device\n");
+               ret = -ENODEV;
                goto err_unreg_vdev;
        }
 
index 01b5b50..15e9c2b 100644 (file)
@@ -266,6 +266,18 @@ static int ppi_set_params(struct ppi_if *ppi, struct ppi_params *params)
                bfin_write32(&reg->vcnt, params->height);
                if (params->int_mask)
                        bfin_write32(&reg->imsk, params->int_mask & 0xFF);
+               if (ppi->ppi_control & PORT_DIR) {
+                       u32 hsync_width, vsync_width, vsync_period;
+
+                       hsync_width = params->hsync
+                                       * params->bpp / params->dlen;
+                       vsync_width = params->vsync * samples_per_line;
+                       vsync_period = samples_per_line * params->frame;
+                       bfin_write32(&reg->fs1_wlhb, hsync_width);
+                       bfin_write32(&reg->fs1_paspl, samples_per_line);
+                       bfin_write32(&reg->fs2_wlvb, vsync_width);
+                       bfin_write32(&reg->fs2_palpf, vsync_period);
+               }
                break;
        }
        default:
index 9d1481a..df4ada8 100644 (file)
 
 #define CODA_MAX_FRAMEBUFFERS  2
 
-#define MAX_W          720
-#define MAX_H          576
-#define CODA_MAX_FRAME_SIZE    0x90000
+#define MAX_W          8192
+#define MAX_H          8192
+#define CODA_MAX_FRAME_SIZE    0x100000
 #define FMO_SLICE_SAVE_BUF_SIZE         (32)
 #define CODA_DEFAULT_GAMMA             4096
 
 #define MIN_W 176
 #define MIN_H 144
-#define MAX_W 720
-#define MAX_H 576
 
 #define S_ALIGN                1 /* multiple of 2 */
 #define W_ALIGN                1 /* multiple of 2 */
@@ -67,7 +65,7 @@
 #define fh_to_ctx(__fh)        container_of(__fh, struct coda_ctx, fh)
 
 static int coda_debug;
-module_param(coda_debug, int, 0);
+module_param(coda_debug, int, 0644);
 MODULE_PARM_DESC(coda_debug, "Debug level (0-1)");
 
 enum {
@@ -75,11 +73,6 @@ enum {
        V4L2_M2M_DST = 1,
 };
 
-enum coda_fmt_type {
-       CODA_FMT_ENC,
-       CODA_FMT_RAW,
-};
-
 enum coda_inst_type {
        CODA_INST_ENCODER,
        CODA_INST_DECODER,
@@ -93,14 +86,21 @@ enum coda_product {
 struct coda_fmt {
        char *name;
        u32 fourcc;
-       enum coda_fmt_type type;
+};
+
+struct coda_codec {
+       u32 mode;
+       u32 src_fourcc;
+       u32 dst_fourcc;
+       u32 max_w;
+       u32 max_h;
 };
 
 struct coda_devtype {
        char                    *firmware;
        enum coda_product       product;
-       struct coda_fmt         *formats;
-       unsigned int            num_formats;
+       struct coda_codec       *codecs;
+       unsigned int            num_codecs;
        size_t                  workbuf_size;
 };
 
@@ -109,7 +109,7 @@ struct coda_q_data {
        unsigned int            width;
        unsigned int            height;
        unsigned int            sizeimage;
-       struct coda_fmt *fmt;
+       unsigned int            fourcc;
 };
 
 struct coda_aux_buf {
@@ -137,12 +137,12 @@ struct coda_dev {
 
        spinlock_t              irqlock;
        struct mutex            dev_mutex;
+       struct mutex            coda_mutex;
        struct v4l2_m2m_dev     *m2m_dev;
        struct vb2_alloc_ctx    *alloc_ctx;
        struct list_head        instances;
        unsigned long           instance_mask;
        struct delayed_work     timeout;
-       struct completion       done;
 };
 
 struct coda_params {
@@ -164,11 +164,12 @@ struct coda_ctx {
        struct coda_dev                 *dev;
        struct list_head                list;
        int                             aborting;
-       int                             rawstreamon;
-       int                             compstreamon;
+       int                             streamon_out;
+       int                             streamon_cap;
        u32                             isequence;
        struct coda_q_data              q_data[2];
        enum coda_inst_type             inst_type;
+       struct coda_codec               *codec;
        enum v4l2_colorspace            colorspace;
        struct coda_params              params;
        struct v4l2_m2m_ctx             *m2m_ctx;
@@ -257,62 +258,89 @@ static struct coda_q_data *get_q_data(struct coda_ctx *ctx,
 }
 
 /*
- * Add one array of supported formats for each version of Coda:
- *  i.MX27 -> codadx6
- *  i.MX51 -> coda7
- *  i.MX6  -> coda960
+ * Array of all formats supported by any version of Coda:
  */
-static struct coda_fmt codadx6_formats[] = {
+static struct coda_fmt coda_formats[] = {
        {
-               .name = "YUV 4:2:0 Planar",
+               .name = "YUV 4:2:0 Planar, YCbCr",
                .fourcc = V4L2_PIX_FMT_YUV420,
-               .type = CODA_FMT_RAW,
-       },
-       {
-               .name = "H264 Encoded Stream",
-               .fourcc = V4L2_PIX_FMT_H264,
-               .type = CODA_FMT_ENC,
        },
        {
-               .name = "MPEG4 Encoded Stream",
-               .fourcc = V4L2_PIX_FMT_MPEG4,
-               .type = CODA_FMT_ENC,
-       },
-};
-
-static struct coda_fmt coda7_formats[] = {
-       {
-               .name = "YUV 4:2:0 Planar",
-               .fourcc = V4L2_PIX_FMT_YUV420,
-               .type = CODA_FMT_RAW,
+               .name = "YUV 4:2:0 Planar, YCrCb",
+               .fourcc = V4L2_PIX_FMT_YVU420,
        },
        {
                .name = "H264 Encoded Stream",
                .fourcc = V4L2_PIX_FMT_H264,
-               .type = CODA_FMT_ENC,
        },
        {
                .name = "MPEG4 Encoded Stream",
                .fourcc = V4L2_PIX_FMT_MPEG4,
-               .type = CODA_FMT_ENC,
        },
 };
 
-static struct coda_fmt *find_format(struct coda_dev *dev, struct v4l2_format *f)
+#define CODA_CODEC(mode, src_fourcc, dst_fourcc, max_w, max_h) \
+       { mode, src_fourcc, dst_fourcc, max_w, max_h }
+
+/*
+ * Arrays of codecs supported by each given version of Coda:
+ *  i.MX27 -> codadx6
+ *  i.MX5x -> coda7
+ *  i.MX6  -> coda960
+ * Use V4L2_PIX_FMT_YUV420 as placeholder for all supported YUV 4:2:0 variants
+ */
+static struct coda_codec codadx6_codecs[] = {
+       CODA_CODEC(CODADX6_MODE_ENCODE_H264, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_H264,  720, 576),
+       CODA_CODEC(CODADX6_MODE_ENCODE_MP4,  V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_MPEG4, 720, 576),
+};
+
+static struct coda_codec coda7_codecs[] = {
+       CODA_CODEC(CODA7_MODE_ENCODE_H264, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_H264,   1280, 720),
+       CODA_CODEC(CODA7_MODE_ENCODE_MP4,  V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_MPEG4,  1280, 720),
+};
+
+static bool coda_format_is_yuv(u32 fourcc)
+{
+       switch (fourcc) {
+       case V4L2_PIX_FMT_YUV420:
+       case V4L2_PIX_FMT_YVU420:
+               return true;
+       default:
+               return false;
+       }
+}
+
+/*
+ * Normalize all supported YUV 4:2:0 formats to the value used in the codec
+ * tables.
+ */
+static u32 coda_format_normalize_yuv(u32 fourcc)
+{
+       return coda_format_is_yuv(fourcc) ? V4L2_PIX_FMT_YUV420 : fourcc;
+}
+
+static struct coda_codec *coda_find_codec(struct coda_dev *dev, int src_fourcc,
+                                         int dst_fourcc)
 {
-       struct coda_fmt *formats = dev->devtype->formats;
-       int num_formats = dev->devtype->num_formats;
-       unsigned int k;
+       struct coda_codec *codecs = dev->devtype->codecs;
+       int num_codecs = dev->devtype->num_codecs;
+       int k;
+
+       src_fourcc = coda_format_normalize_yuv(src_fourcc);
+       dst_fourcc = coda_format_normalize_yuv(dst_fourcc);
+       if (src_fourcc == dst_fourcc)
+               return NULL;
 
-       for (k = 0; k < num_formats; k++) {
-               if (formats[k].fourcc == f->fmt.pix.pixelformat)
+       for (k = 0; k < num_codecs; k++) {
+               if (codecs[k].src_fourcc == src_fourcc &&
+                   codecs[k].dst_fourcc == dst_fourcc)
                        break;
        }
 
-       if (k == num_formats)
+       if (k == num_codecs)
                return NULL;
 
-       return &formats[k];
+       return &codecs[k];
 }
 
 /*
@@ -323,7 +351,7 @@ static int vidioc_querycap(struct file *file, void *priv,
 {
        strlcpy(cap->driver, CODA_NAME, sizeof(cap->driver));
        strlcpy(cap->card, CODA_NAME, sizeof(cap->card));
-       strlcpy(cap->bus_info, CODA_NAME, sizeof(cap->bus_info));
+       strlcpy(cap->bus_info, "platform:" CODA_NAME, sizeof(cap->bus_info));
        /*
         * This is only a mem-to-mem video device. The capture and output
         * device capability flags are left only for backward compatibility
@@ -337,17 +365,34 @@ static int vidioc_querycap(struct file *file, void *priv,
 }
 
 static int enum_fmt(void *priv, struct v4l2_fmtdesc *f,
-                       enum coda_fmt_type type)
+                       enum v4l2_buf_type type)
 {
        struct coda_ctx *ctx = fh_to_ctx(priv);
-       struct coda_dev *dev = ctx->dev;
-       struct coda_fmt *formats = dev->devtype->formats;
+       struct coda_codec *codecs = ctx->dev->devtype->codecs;
+       struct coda_fmt *formats = coda_formats;
        struct coda_fmt *fmt;
-       int num_formats = dev->devtype->num_formats;
-       int i, num = 0;
+       int num_codecs = ctx->dev->devtype->num_codecs;
+       int num_formats = ARRAY_SIZE(coda_formats);
+       int i, k, num = 0;
 
        for (i = 0; i < num_formats; i++) {
-               if (formats[i].type == type) {
+               /* Both uncompressed formats are always supported */
+               if (coda_format_is_yuv(formats[i].fourcc)) {
+                       if (num == f->index)
+                               break;
+                       ++num;
+                       continue;
+               }
+               /* Compressed formats may be supported, check the codec list */
+               for (k = 0; k < num_codecs; k++) {
+                       if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+                           formats[i].fourcc == codecs[k].dst_fourcc)
+                               break;
+                       if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
+                           formats[i].fourcc == codecs[k].src_fourcc)
+                               break;
+               }
+               if (k < num_codecs) {
                        if (num == f->index)
                                break;
                        ++num;
@@ -368,13 +413,13 @@ static int enum_fmt(void *priv, struct v4l2_fmtdesc *f,
 static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
                                   struct v4l2_fmtdesc *f)
 {
-       return enum_fmt(priv, f, CODA_FMT_ENC);
+       return enum_fmt(priv, f, V4L2_BUF_TYPE_VIDEO_CAPTURE);
 }
 
 static int vidioc_enum_fmt_vid_out(struct file *file, void *priv,
                                   struct v4l2_fmtdesc *f)
 {
-       return enum_fmt(priv, f, CODA_FMT_RAW);
+       return enum_fmt(priv, f, V4L2_BUF_TYPE_VIDEO_OUTPUT);
 }
 
 static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
@@ -390,10 +435,10 @@ static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
        q_data = get_q_data(ctx, f->type);
 
        f->fmt.pix.field        = V4L2_FIELD_NONE;
-       f->fmt.pix.pixelformat  = q_data->fmt->fourcc;
+       f->fmt.pix.pixelformat  = q_data->fourcc;
        f->fmt.pix.width        = q_data->width;
        f->fmt.pix.height       = q_data->height;
-       if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_YUV420)
+       if (coda_format_is_yuv(f->fmt.pix.pixelformat))
                f->fmt.pix.bytesperline = round_up(f->fmt.pix.width, 2);
        else /* encoded formats h.264/mpeg4 */
                f->fmt.pix.bytesperline = 0;
@@ -404,8 +449,9 @@ static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
        return 0;
 }
 
-static int vidioc_try_fmt(struct coda_dev *dev, struct v4l2_format *f)
+static int vidioc_try_fmt(struct coda_codec *codec, struct v4l2_format *f)
 {
+       unsigned int max_w, max_h;
        enum v4l2_field field;
 
        field = f->fmt.pix.field;
@@ -418,12 +464,21 @@ static int vidioc_try_fmt(struct coda_dev *dev, struct v4l2_format *f)
         * if any of the dimensions is unsupported */
        f->fmt.pix.field = field;
 
-       if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_YUV420) {
-               v4l_bound_align_image(&f->fmt.pix.width, MIN_W, MAX_W,
-                                     W_ALIGN, &f->fmt.pix.height,
-                                     MIN_H, MAX_H, H_ALIGN, S_ALIGN);
-               f->fmt.pix.bytesperline = round_up(f->fmt.pix.width, 2);
-               f->fmt.pix.sizeimage = f->fmt.pix.width *
+       if (codec) {
+               max_w = codec->max_w;
+               max_h = codec->max_h;
+       } else {
+               max_w = MAX_W;
+               max_h = MAX_H;
+       }
+       v4l_bound_align_image(&f->fmt.pix.width, MIN_W, max_w,
+                             W_ALIGN, &f->fmt.pix.height,
+                             MIN_H, max_h, H_ALIGN, S_ALIGN);
+
+       if (coda_format_is_yuv(f->fmt.pix.pixelformat)) {
+               /* Frame stride must be multiple of 8 */
+               f->fmt.pix.bytesperline = round_up(f->fmt.pix.width, 8);
+               f->fmt.pix.sizeimage = f->fmt.pix.bytesperline *
                                        f->fmt.pix.height * 3 / 2;
        } else { /*encoded formats h.264/mpeg4 */
                f->fmt.pix.bytesperline = 0;
@@ -436,57 +491,38 @@ static int vidioc_try_fmt(struct coda_dev *dev, struct v4l2_format *f)
 static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
                                  struct v4l2_format *f)
 {
-       int ret;
-       struct coda_fmt *fmt;
        struct coda_ctx *ctx = fh_to_ctx(priv);
+       struct coda_codec *codec = NULL;
 
-       fmt = find_format(ctx->dev, f);
-       /*
-        * Since decoding support is not implemented yet do not allow
-        * CODA_FMT_RAW formats in the capture interface.
-        */
-       if (!fmt || !(fmt->type == CODA_FMT_ENC))
-               f->fmt.pix.pixelformat = V4L2_PIX_FMT_H264;
+       /* Determine codec by the encoded format */
+       codec = coda_find_codec(ctx->dev, V4L2_PIX_FMT_YUV420,
+                               f->fmt.pix.pixelformat);
 
        f->fmt.pix.colorspace = ctx->colorspace;
 
-       ret = vidioc_try_fmt(ctx->dev, f);
-       if (ret < 0)
-               return ret;
-
-       return 0;
+       return vidioc_try_fmt(codec, f);
 }
 
 static int vidioc_try_fmt_vid_out(struct file *file, void *priv,
                                  struct v4l2_format *f)
 {
        struct coda_ctx *ctx = fh_to_ctx(priv);
-       struct coda_fmt *fmt;
-       int ret;
+       struct coda_codec *codec;
 
-       fmt = find_format(ctx->dev, f);
-       /*
-        * Since decoding support is not implemented yet do not allow
-        * CODA_FMT formats in the capture interface.
-        */
-       if (!fmt || !(fmt->type == CODA_FMT_RAW))
-               f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUV420;
+       /* Determine codec by encoded format, returns NULL if raw or invalid */
+       codec = coda_find_codec(ctx->dev, f->fmt.pix.pixelformat,
+                               V4L2_PIX_FMT_YUV420);
 
        if (!f->fmt.pix.colorspace)
                f->fmt.pix.colorspace = V4L2_COLORSPACE_REC709;
 
-       ret = vidioc_try_fmt(ctx->dev, f);
-       if (ret < 0)
-               return ret;
-
-       return 0;
+       return vidioc_try_fmt(codec, f);
 }
 
 static int vidioc_s_fmt(struct coda_ctx *ctx, struct v4l2_format *f)
 {
        struct coda_q_data *q_data;
        struct vb2_queue *vq;
-       int ret;
 
        vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
        if (!vq)
@@ -501,18 +537,14 @@ static int vidioc_s_fmt(struct coda_ctx *ctx, struct v4l2_format *f)
                return -EBUSY;
        }
 
-       ret = vidioc_try_fmt(ctx->dev, f);
-       if (ret)
-               return ret;
-
-       q_data->fmt = find_format(ctx->dev, f);
+       q_data->fourcc = f->fmt.pix.pixelformat;
        q_data->width = f->fmt.pix.width;
        q_data->height = f->fmt.pix.height;
        q_data->sizeimage = f->fmt.pix.sizeimage;
 
        v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
                "Setting format for type %d, wxh: %dx%d, fmt: %d\n",
-               f->type, q_data->width, q_data->height, q_data->fmt->fourcc);
+               f->type, q_data->width, q_data->height, q_data->fourcc);
 
        return 0;
 }
@@ -520,13 +552,14 @@ static int vidioc_s_fmt(struct coda_ctx *ctx, struct v4l2_format *f)
 static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
                                struct v4l2_format *f)
 {
+       struct coda_ctx *ctx = fh_to_ctx(priv);
        int ret;
 
        ret = vidioc_try_fmt_vid_cap(file, priv, f);
        if (ret)
                return ret;
 
-       return vidioc_s_fmt(fh_to_ctx(priv), f);
+       return vidioc_s_fmt(ctx, f);
 }
 
 static int vidioc_s_fmt_vid_out(struct file *file, void *priv,
@@ -569,6 +602,14 @@ static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
        return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf);
 }
 
+static int vidioc_expbuf(struct file *file, void *priv,
+                        struct v4l2_exportbuffer *eb)
+{
+       struct coda_ctx *ctx = fh_to_ctx(priv);
+
+       return v4l2_m2m_expbuf(file, ctx->m2m_ctx, eb);
+}
+
 static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
 {
        struct coda_ctx *ctx = fh_to_ctx(priv);
@@ -617,6 +658,7 @@ static const struct v4l2_ioctl_ops coda_ioctl_ops = {
        .vidioc_querybuf        = vidioc_querybuf,
 
        .vidioc_qbuf            = vidioc_qbuf,
+       .vidioc_expbuf          = vidioc_expbuf,
        .vidioc_dqbuf           = vidioc_dqbuf,
        .vidioc_create_bufs     = vidioc_create_bufs,
 
@@ -639,11 +681,13 @@ static void coda_device_run(void *m2m_priv)
        u32 pic_stream_buffer_addr, pic_stream_buffer_size;
        u32 dst_fourcc;
 
+       mutex_lock(&dev->coda_mutex);
+
        src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
        dst_buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
        q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
        q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
-       dst_fourcc = q_data_dst->fmt->fourcc;
+       dst_fourcc = q_data_dst->fourcc;
 
        src_buf->v4l2_buf.sequence = ctx->isequence;
        dst_buf->v4l2_buf.sequence = ctx->isequence;
@@ -725,9 +769,20 @@ static void coda_device_run(void *m2m_priv)
 
 
        picture_y = vb2_dma_contig_plane_dma_addr(src_buf, 0);
-       picture_cb = picture_y + q_data_src->width * q_data_src->height;
-       picture_cr = picture_cb + q_data_src->width / 2 *
-                       q_data_src->height / 2;
+       switch (q_data_src->fourcc) {
+       case V4L2_PIX_FMT_YVU420:
+               /* Switch Cb and Cr for YVU420 format */
+               picture_cr = picture_y + q_data_src->width * q_data_src->height;
+               picture_cb = picture_cr + q_data_src->width / 2 *
+                               q_data_src->height / 2;
+               break;
+       case V4L2_PIX_FMT_YUV420:
+       default:
+               picture_cb = picture_y + q_data_src->width * q_data_src->height;
+               picture_cr = picture_cb + q_data_src->width / 2 *
+                               q_data_src->height / 2;
+               break;
+       }
 
        coda_write(dev, picture_y, CODA_CMD_ENC_PIC_SRC_ADDR_Y);
        coda_write(dev, picture_cb, CODA_CMD_ENC_PIC_SRC_ADDR_CB);
@@ -748,7 +803,6 @@ static void coda_device_run(void *m2m_priv)
        /* 1 second timeout in case CODA locks up */
        schedule_delayed_work(&dev->timeout, HZ);
 
-       INIT_COMPLETION(dev->done);
        coda_command_async(ctx, CODA_COMMAND_PIC_RUN);
 }
 
@@ -767,6 +821,12 @@ static int coda_job_ready(void *m2m_priv)
                return 0;
        }
 
+       if (ctx->aborting) {
+               v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
+                        "not ready: aborting\n");
+               return 0;
+       }
+
        v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
                        "job ready\n");
        return 1;
@@ -775,14 +835,11 @@ static int coda_job_ready(void *m2m_priv)
 static void coda_job_abort(void *priv)
 {
        struct coda_ctx *ctx = priv;
-       struct coda_dev *dev = ctx->dev;
 
        ctx->aborting = 1;
 
        v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
                 "Aborting task\n");
-
-       v4l2_m2m_job_finish(dev->m2m_dev, ctx->m2m_ctx);
 }
 
 static void coda_lock(void *m2m_priv)
@@ -809,7 +866,12 @@ static struct v4l2_m2m_ops coda_m2m_ops = {
 
 static void set_default_params(struct coda_ctx *ctx)
 {
-       struct coda_dev *dev = ctx->dev;
+       int max_w;
+       int max_h;
+
+       ctx->codec = &ctx->dev->devtype->codecs[0];
+       max_w = ctx->codec->max_w;
+       max_h = ctx->codec->max_h;
 
        ctx->params.codec_mode = CODA_MODE_INVALID;
        ctx->colorspace = V4L2_COLORSPACE_REC709;
@@ -817,13 +879,13 @@ static void set_default_params(struct coda_ctx *ctx)
        ctx->aborting = 0;
 
        /* Default formats for output and input queues */
-       ctx->q_data[V4L2_M2M_SRC].fmt = &dev->devtype->formats[0];
-       ctx->q_data[V4L2_M2M_DST].fmt = &dev->devtype->formats[1];
-       ctx->q_data[V4L2_M2M_SRC].width = MAX_W;
-       ctx->q_data[V4L2_M2M_SRC].height = MAX_H;
-       ctx->q_data[V4L2_M2M_SRC].sizeimage = (MAX_W * MAX_H * 3) / 2;
-       ctx->q_data[V4L2_M2M_DST].width = MAX_W;
-       ctx->q_data[V4L2_M2M_DST].height = MAX_H;
+       ctx->q_data[V4L2_M2M_SRC].fourcc = ctx->codec->src_fourcc;
+       ctx->q_data[V4L2_M2M_DST].fourcc = ctx->codec->dst_fourcc;
+       ctx->q_data[V4L2_M2M_SRC].width = max_w;
+       ctx->q_data[V4L2_M2M_SRC].height = max_h;
+       ctx->q_data[V4L2_M2M_SRC].sizeimage = (max_w * max_h * 3) / 2;
+       ctx->q_data[V4L2_M2M_DST].width = max_w;
+       ctx->q_data[V4L2_M2M_DST].height = max_h;
        ctx->q_data[V4L2_M2M_DST].sizeimage = CODA_MAX_FRAME_SIZE;
 }
 
@@ -868,8 +930,6 @@ static int coda_buf_prepare(struct vb2_buffer *vb)
                return -EINVAL;
        }
 
-       vb2_set_plane_payload(vb, 0, q_data->sizeimage);
-
        return 0;
 }
 
@@ -906,21 +966,34 @@ static void coda_free_framebuffers(struct coda_ctx *ctx)
        }
 }
 
+static void coda_parabuf_write(struct coda_ctx *ctx, int index, u32 value)
+{
+       struct coda_dev *dev = ctx->dev;
+       u32 *p = ctx->parabuf.vaddr;
+
+       if (dev->devtype->product == CODA_DX6)
+               p[index] = value;
+       else
+               p[index ^ 1] = value;
+}
+
 static int coda_alloc_framebuffers(struct coda_ctx *ctx, struct coda_q_data *q_data, u32 fourcc)
 {
        struct coda_dev *dev = ctx->dev;
 
        int height = q_data->height;
-       int width = q_data->width;
-       u32 *p;
+       dma_addr_t paddr;
+       int ysize;
        int i;
 
+       ysize = round_up(q_data->width, 8) * height;
+
        /* Allocate frame buffers */
        ctx->num_internal_frames = CODA_MAX_FRAMEBUFFERS;
        for (i = 0; i < ctx->num_internal_frames; i++) {
                ctx->internal_frames[i].size = q_data->sizeimage;
                if (fourcc == V4L2_PIX_FMT_H264 && dev->devtype->product != CODA_DX6)
-                       ctx->internal_frames[i].size += width / 2 * height / 2;
+                       ctx->internal_frames[i].size += ysize/4;
                ctx->internal_frames[i].vaddr = dma_alloc_coherent(
                                &dev->plat_dev->dev, ctx->internal_frames[i].size,
                                &ctx->internal_frames[i].paddr, GFP_KERNEL);
@@ -931,32 +1004,14 @@ static int coda_alloc_framebuffers(struct coda_ctx *ctx, struct coda_q_data *q_d
        }
 
        /* Register frame buffers in the parameter buffer */
-       p = ctx->parabuf.vaddr;
+       for (i = 0; i < ctx->num_internal_frames; i++) {
+               paddr = ctx->internal_frames[i].paddr;
+               coda_parabuf_write(ctx, i * 3 + 0, paddr); /* Y */
+               coda_parabuf_write(ctx, i * 3 + 1, paddr + ysize); /* Cb */
+               coda_parabuf_write(ctx, i * 3 + 2, paddr + ysize + ysize/4); /* Cr */
 
-       if (dev->devtype->product == CODA_DX6) {
-               for (i = 0; i < ctx->num_internal_frames; i++) {
-                       p[i * 3] = ctx->internal_frames[i].paddr; /* Y */
-                       p[i * 3 + 1] = p[i * 3] + width * height; /* Cb */
-                       p[i * 3 + 2] = p[i * 3 + 1] + width / 2 * height / 2; /* Cr */
-               }
-       } else {
-               for (i = 0; i < ctx->num_internal_frames; i += 2) {
-                       p[i * 3 + 1] = ctx->internal_frames[i].paddr; /* Y */
-                       p[i * 3] = p[i * 3 + 1] + width * height; /* Cb */
-                       p[i * 3 + 3] = p[i * 3] + (width / 2) * (height / 2); /* Cr */
-
-                       if (fourcc == V4L2_PIX_FMT_H264)
-                               p[96 + i + 1] = p[i * 3 + 3] + (width / 2) * (height / 2);
-
-                       if (i + 1 < ctx->num_internal_frames) {
-                               p[i * 3 + 2] = ctx->internal_frames[i+1].paddr; /* Y */
-                               p[i * 3 + 5] = p[i * 3 + 2] + width * height ; /* Cb */
-                               p[i * 3 + 4] = p[i * 3 + 5] + (width / 2) * (height / 2); /* Cr */
-
-                               if (fourcc == V4L2_PIX_FMT_H264)
-                                       p[96 + i] = p[i * 3 + 4] + (width / 2) * (height / 2);
-                       }
-               }
+               if (dev->devtype->product != CODA_DX6 && fourcc == V4L2_PIX_FMT_H264)
+                       coda_parabuf_write(ctx, 96 + i, ctx->internal_frames[i].paddr + ysize + ysize/4 + ysize/4);
        }
 
        return 0;
@@ -980,6 +1035,28 @@ static int coda_h264_padding(int size, char *p)
        return nal_size;
 }
 
+static int coda_encode_header(struct coda_ctx *ctx, struct vb2_buffer *buf,
+                             int header_code, u8 *header, int *size)
+{
+       struct coda_dev *dev = ctx->dev;
+       int ret;
+
+       coda_write(dev, vb2_dma_contig_plane_dma_addr(buf, 0),
+                  CODA_CMD_ENC_HEADER_BB_START);
+       coda_write(dev, vb2_plane_size(buf, 0), CODA_CMD_ENC_HEADER_BB_SIZE);
+       coda_write(dev, header_code, CODA_CMD_ENC_HEADER_CODE);
+       ret = coda_command_sync(ctx, CODA_COMMAND_ENCODE_HEADER);
+       if (ret < 0) {
+               v4l2_err(&dev->v4l2_dev, "CODA_COMMAND_ENCODE_HEADER timeout\n");
+               return ret;
+       }
+       *size = coda_read(dev, CODA_REG_BIT_WR_PTR(ctx->idx)) -
+               coda_read(dev, CODA_CMD_ENC_HEADER_BB_START);
+       memcpy(header, vb2_plane_vaddr(buf, 0), *size);
+
+       return 0;
+}
+
 static int coda_start_streaming(struct vb2_queue *q, unsigned int count)
 {
        struct coda_ctx *ctx = vb2_get_drv_priv(q);
@@ -990,43 +1067,38 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count)
        struct vb2_buffer *buf;
        u32 dst_fourcc;
        u32 value;
-       int ret;
+       int ret = 0;
 
        if (count < 1)
                return -EINVAL;
 
        if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
-               ctx->rawstreamon = 1;
+               ctx->streamon_out = 1;
        else
-               ctx->compstreamon = 1;
+               ctx->streamon_cap = 1;
+
+       q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+       if (ctx->streamon_out) {
+               if (coda_format_is_yuv(q_data_src->fourcc))
+                       ctx->inst_type = CODA_INST_ENCODER;
+               else
+                       ctx->inst_type = CODA_INST_DECODER;
+       }
 
        /* Don't start the coda unless both queues are on */
-       if (!(ctx->rawstreamon & ctx->compstreamon))
+       if (!(ctx->streamon_out & ctx->streamon_cap))
                return 0;
 
-       if (coda_isbusy(dev))
-               if (wait_for_completion_interruptible_timeout(&dev->done, HZ) <= 0)
-                       return -EBUSY;
-
        ctx->gopcounter = ctx->params.gop_size - 1;
-
-       q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
        buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
        bitstream_buf = vb2_dma_contig_plane_dma_addr(buf, 0);
        q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
        bitstream_size = q_data_dst->sizeimage;
-       dst_fourcc = q_data_dst->fmt->fourcc;
-
-       /* Find out whether coda must encode or decode */
-       if (q_data_src->fmt->type == CODA_FMT_RAW &&
-           q_data_dst->fmt->type == CODA_FMT_ENC) {
-               ctx->inst_type = CODA_INST_ENCODER;
-       } else if (q_data_src->fmt->type == CODA_FMT_ENC &&
-                  q_data_dst->fmt->type == CODA_FMT_RAW) {
-               ctx->inst_type = CODA_INST_DECODER;
-               v4l2_err(v4l2_dev, "decoding not supported.\n");
-               return -EINVAL;
-       } else {
+       dst_fourcc = q_data_dst->fourcc;
+
+       ctx->codec = coda_find_codec(ctx->dev, q_data_src->fourcc,
+                                    q_data_dst->fourcc);
+       if (!ctx->codec) {
                v4l2_err(v4l2_dev, "couldn't tell instance type.\n");
                return -EINVAL;
        }
@@ -1035,6 +1107,9 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count)
                v4l2_err(v4l2_dev, "coda is not initialized.\n");
                return -EFAULT;
        }
+
+       mutex_lock(&dev->coda_mutex);
+
        coda_write(dev, ctx->parabuf.paddr, CODA_REG_BIT_PARA_BUF_ADDR);
        coda_write(dev, bitstream_buf, CODA_REG_BIT_RD_PTR(ctx->idx));
        coda_write(dev, bitstream_buf, CODA_REG_BIT_WR_PTR(ctx->idx));
@@ -1057,38 +1132,31 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count)
        switch (dev->devtype->product) {
        case CODA_DX6:
                value = (q_data_src->width & CODADX6_PICWIDTH_MASK) << CODADX6_PICWIDTH_OFFSET;
+               value |= (q_data_src->height & CODADX6_PICHEIGHT_MASK) << CODA_PICHEIGHT_OFFSET;
                break;
        default:
                value = (q_data_src->width & CODA7_PICWIDTH_MASK) << CODA7_PICWIDTH_OFFSET;
+               value |= (q_data_src->height & CODA7_PICHEIGHT_MASK) << CODA_PICHEIGHT_OFFSET;
        }
-       value |= (q_data_src->height & CODA_PICHEIGHT_MASK) << CODA_PICHEIGHT_OFFSET;
        coda_write(dev, value, CODA_CMD_ENC_SEQ_SRC_SIZE);
        coda_write(dev, ctx->params.framerate,
                   CODA_CMD_ENC_SEQ_SRC_F_RATE);
 
+       ctx->params.codec_mode = ctx->codec->mode;
        switch (dst_fourcc) {
        case V4L2_PIX_FMT_MPEG4:
-               if (dev->devtype->product == CODA_DX6)
-                       ctx->params.codec_mode = CODADX6_MODE_ENCODE_MP4;
-               else
-                       ctx->params.codec_mode = CODA7_MODE_ENCODE_MP4;
-
                coda_write(dev, CODA_STD_MPEG4, CODA_CMD_ENC_SEQ_COD_STD);
                coda_write(dev, 0, CODA_CMD_ENC_SEQ_MP4_PARA);
                break;
        case V4L2_PIX_FMT_H264:
-               if (dev->devtype->product == CODA_DX6)
-                       ctx->params.codec_mode = CODADX6_MODE_ENCODE_H264;
-               else
-                       ctx->params.codec_mode = CODA7_MODE_ENCODE_H264;
-
                coda_write(dev, CODA_STD_H264, CODA_CMD_ENC_SEQ_COD_STD);
                coda_write(dev, 0, CODA_CMD_ENC_SEQ_264_PARA);
                break;
        default:
                v4l2_err(v4l2_dev,
                         "dst format (0x%08x) invalid.\n", dst_fourcc);
-               return -EINVAL;
+               ret = -EINVAL;
+               goto out;
        }
 
        switch (ctx->params.slice_mode) {
@@ -1129,8 +1197,14 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count)
        value = (CODA_DEFAULT_GAMMA & CODA_GAMMA_MASK) << CODA_GAMMA_OFFSET;
        coda_write(dev, value, CODA_CMD_ENC_SEQ_RC_GAMMA);
 
-       value  = (CODA_DEFAULT_GAMMA > 0) << CODA_OPTION_GAMMA_OFFSET;
-       value |= (0 & CODA_OPTION_SLICEREPORT_MASK) << CODA_OPTION_SLICEREPORT_OFFSET;
+       if (CODA_DEFAULT_GAMMA > 0) {
+               if (dev->devtype->product == CODA_DX6)
+                       value  = 1 << CODADX6_OPTION_GAMMA_OFFSET;
+               else
+                       value  = 1 << CODA7_OPTION_GAMMA_OFFSET;
+       } else {
+               value = 0;
+       }
        coda_write(dev, value, CODA_CMD_ENC_SEQ_OPTION);
 
        if (dst_fourcc == V4L2_PIX_FMT_H264) {
@@ -1145,17 +1219,23 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count)
                }
        }
 
-       if (coda_command_sync(ctx, CODA_COMMAND_SEQ_INIT)) {
+       ret = coda_command_sync(ctx, CODA_COMMAND_SEQ_INIT);
+       if (ret < 0) {
                v4l2_err(v4l2_dev, "CODA_COMMAND_SEQ_INIT timeout\n");
-               return -ETIMEDOUT;
+               goto out;
        }
 
-       if (coda_read(dev, CODA_RET_ENC_SEQ_SUCCESS) == 0)
-               return -EFAULT;
+       if (coda_read(dev, CODA_RET_ENC_SEQ_SUCCESS) == 0) {
+               v4l2_err(v4l2_dev, "CODA_COMMAND_SEQ_INIT failed\n");
+               ret = -EFAULT;
+               goto out;
+       }
 
        ret = coda_alloc_framebuffers(ctx, q_data_src, dst_fourcc);
-       if (ret < 0)
-               return ret;
+       if (ret < 0) {
+               v4l2_err(v4l2_dev, "failed to allocate framebuffers\n");
+               goto out;
+       }
 
        coda_write(dev, ctx->num_internal_frames, CODA_CMD_SET_FRAME_BUF_NUM);
        coda_write(dev, round_up(q_data_src->width, 8), CODA_CMD_SET_FRAME_BUF_STRIDE);
@@ -1167,9 +1247,10 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count)
                coda_write(dev, dev->iram_paddr + 68 * 1024, CODA7_CMD_SET_FRAME_AXI_IPACDC_ADDR);
                coda_write(dev, 0x0, CODA7_CMD_SET_FRAME_AXI_OVL_ADDR);
        }
-       if (coda_command_sync(ctx, CODA_COMMAND_SET_FRAME_BUF)) {
+       ret = coda_command_sync(ctx, CODA_COMMAND_SET_FRAME_BUF);
+       if (ret < 0) {
                v4l2_err(v4l2_dev, "CODA_COMMAND_SET_FRAME_BUF timeout\n");
-               return -ETIMEDOUT;
+               goto out;
        }
 
        /* Save stream headers */
@@ -1180,33 +1261,22 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count)
                 * Get SPS in the first frame and copy it to an
                 * intermediate buffer.
                 */
-               coda_write(dev, vb2_dma_contig_plane_dma_addr(buf, 0), CODA_CMD_ENC_HEADER_BB_START);
-               coda_write(dev, bitstream_size, CODA_CMD_ENC_HEADER_BB_SIZE);
-               coda_write(dev, CODA_HEADER_H264_SPS, CODA_CMD_ENC_HEADER_CODE);
-               if (coda_command_sync(ctx, CODA_COMMAND_ENCODE_HEADER)) {
-                       v4l2_err(v4l2_dev, "CODA_COMMAND_ENCODE_HEADER timeout\n");
-                       return -ETIMEDOUT;
-               }
-               ctx->vpu_header_size[0] = coda_read(dev, CODA_REG_BIT_WR_PTR(ctx->idx)) -
-                               coda_read(dev, CODA_CMD_ENC_HEADER_BB_START);
-               memcpy(&ctx->vpu_header[0][0], vb2_plane_vaddr(buf, 0),
-                      ctx->vpu_header_size[0]);
+               ret = coda_encode_header(ctx, buf, CODA_HEADER_H264_SPS,
+                                        &ctx->vpu_header[0][0],
+                                        &ctx->vpu_header_size[0]);
+               if (ret < 0)
+                       goto out;
 
                /*
                 * Get PPS in the first frame and copy it to an
                 * intermediate buffer.
                 */
-               coda_write(dev, vb2_dma_contig_plane_dma_addr(buf, 0), CODA_CMD_ENC_HEADER_BB_START);
-               coda_write(dev, bitstream_size, CODA_CMD_ENC_HEADER_BB_SIZE);
-               coda_write(dev, CODA_HEADER_H264_PPS, CODA_CMD_ENC_HEADER_CODE);
-               if (coda_command_sync(ctx, CODA_COMMAND_ENCODE_HEADER)) {
-                       v4l2_err(v4l2_dev, "CODA_COMMAND_ENCODE_HEADER timeout\n");
-                       return -ETIMEDOUT;
-               }
-               ctx->vpu_header_size[1] = coda_read(dev, CODA_REG_BIT_WR_PTR(ctx->idx)) -
-                               coda_read(dev, CODA_CMD_ENC_HEADER_BB_START);
-               memcpy(&ctx->vpu_header[1][0], vb2_plane_vaddr(buf, 0),
-                      ctx->vpu_header_size[1]);
+               ret = coda_encode_header(ctx, buf, CODA_HEADER_H264_PPS,
+                                        &ctx->vpu_header[1][0],
+                                        &ctx->vpu_header_size[1]);
+               if (ret < 0)
+                       goto out;
+
                /*
                 * Length of H.264 headers is variable and thus it might not be
                 * aligned for the coda to append the encoded frame. In that is
@@ -1222,48 +1292,32 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count)
                 * Get VOS in the first frame and copy it to an
                 * intermediate buffer
                 */
-               coda_write(dev, vb2_dma_contig_plane_dma_addr(buf, 0), CODA_CMD_ENC_HEADER_BB_START);
-               coda_write(dev, bitstream_size, CODA_CMD_ENC_HEADER_BB_SIZE);
-               coda_write(dev, CODA_HEADER_MP4V_VOS, CODA_CMD_ENC_HEADER_CODE);
-               if (coda_command_sync(ctx, CODA_COMMAND_ENCODE_HEADER)) {
-                       v4l2_err(v4l2_dev, "CODA_COMMAND_ENCODE_HEADER timeout\n");
-                       return -ETIMEDOUT;
-               }
-               ctx->vpu_header_size[0] = coda_read(dev, CODA_REG_BIT_WR_PTR(ctx->idx)) -
-                               coda_read(dev, CODA_CMD_ENC_HEADER_BB_START);
-               memcpy(&ctx->vpu_header[0][0], vb2_plane_vaddr(buf, 0),
-                      ctx->vpu_header_size[0]);
-
-               coda_write(dev, vb2_dma_contig_plane_dma_addr(buf, 0), CODA_CMD_ENC_HEADER_BB_START);
-               coda_write(dev, bitstream_size, CODA_CMD_ENC_HEADER_BB_SIZE);
-               coda_write(dev, CODA_HEADER_MP4V_VIS, CODA_CMD_ENC_HEADER_CODE);
-               if (coda_command_sync(ctx, CODA_COMMAND_ENCODE_HEADER)) {
-                       v4l2_err(v4l2_dev, "CODA_COMMAND_ENCODE_HEADER failed\n");
-                       return -ETIMEDOUT;
-               }
-               ctx->vpu_header_size[1] = coda_read(dev, CODA_REG_BIT_WR_PTR(ctx->idx)) -
-                               coda_read(dev, CODA_CMD_ENC_HEADER_BB_START);
-               memcpy(&ctx->vpu_header[1][0], vb2_plane_vaddr(buf, 0),
-                      ctx->vpu_header_size[1]);
-
-               coda_write(dev, vb2_dma_contig_plane_dma_addr(buf, 0), CODA_CMD_ENC_HEADER_BB_START);
-               coda_write(dev, bitstream_size, CODA_CMD_ENC_HEADER_BB_SIZE);
-               coda_write(dev, CODA_HEADER_MP4V_VOL, CODA_CMD_ENC_HEADER_CODE);
-               if (coda_command_sync(ctx, CODA_COMMAND_ENCODE_HEADER)) {
-                       v4l2_err(v4l2_dev, "CODA_COMMAND_ENCODE_HEADER failed\n");
-                       return -ETIMEDOUT;
-               }
-               ctx->vpu_header_size[2] = coda_read(dev, CODA_REG_BIT_WR_PTR(ctx->idx)) -
-                               coda_read(dev, CODA_CMD_ENC_HEADER_BB_START);
-               memcpy(&ctx->vpu_header[2][0], vb2_plane_vaddr(buf, 0),
-                      ctx->vpu_header_size[2]);
+               ret = coda_encode_header(ctx, buf, CODA_HEADER_MP4V_VOS,
+                                        &ctx->vpu_header[0][0],
+                                        &ctx->vpu_header_size[0]);
+               if (ret < 0)
+                       goto out;
+
+               ret = coda_encode_header(ctx, buf, CODA_HEADER_MP4V_VIS,
+                                        &ctx->vpu_header[1][0],
+                                        &ctx->vpu_header_size[1]);
+               if (ret < 0)
+                       goto out;
+
+               ret = coda_encode_header(ctx, buf, CODA_HEADER_MP4V_VOL,
+                                        &ctx->vpu_header[2][0],
+                                        &ctx->vpu_header_size[2]);
+               if (ret < 0)
+                       goto out;
                break;
        default:
                /* No more formats need to save headers at the moment */
                break;
        }
 
-       return 0;
+out:
+       mutex_unlock(&dev->coda_mutex);
+       return ret;
 }
 
 static int coda_stop_streaming(struct vb2_queue *q)
@@ -1274,26 +1328,20 @@ static int coda_stop_streaming(struct vb2_queue *q)
        if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
                v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
                         "%s: output\n", __func__);
-               ctx->rawstreamon = 0;
+               ctx->streamon_out = 0;
        } else {
                v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
                         "%s: capture\n", __func__);
-               ctx->compstreamon = 0;
+               ctx->streamon_cap = 0;
        }
 
        /* Don't stop the coda unless both queues are off */
-       if (ctx->rawstreamon || ctx->compstreamon)
+       if (ctx->streamon_out || ctx->streamon_cap)
                return 0;
 
-       if (coda_isbusy(dev)) {
-               if (wait_for_completion_interruptible_timeout(&dev->done, HZ) <= 0) {
-                       v4l2_warn(&dev->v4l2_dev,
-                                 "%s: timeout, sending SEQ_END anyway\n", __func__);
-               }
-       }
-
        cancel_delayed_work(&dev->timeout);
 
+       mutex_lock(&dev->coda_mutex);
        v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
                 "%s: sent command 'SEQ_END' to coda\n", __func__);
        if (coda_command_sync(ctx, CODA_COMMAND_SEQ_END)) {
@@ -1301,6 +1349,7 @@ static int coda_stop_streaming(struct vb2_queue *q)
                         "CODA_COMMAND_SEQ_END failed\n");
                return -ETIMEDOUT;
        }
+       mutex_unlock(&dev->coda_mutex);
 
        coda_free_framebuffers(ctx);
 
@@ -1431,7 +1480,7 @@ static int coda_queue_init(void *priv, struct vb2_queue *src_vq,
        int ret;
 
        src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
-       src_vq->io_modes = VB2_MMAP | VB2_USERPTR;
+       src_vq->io_modes = VB2_DMABUF | VB2_MMAP | VB2_USERPTR;
        src_vq->drv_priv = ctx;
        src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
        src_vq->ops = &coda_qops;
@@ -1443,7 +1492,7 @@ static int coda_queue_init(void *priv, struct vb2_queue *src_vq,
                return ret;
 
        dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-       dst_vq->io_modes = VB2_MMAP | VB2_USERPTR;
+       dst_vq->io_modes = VB2_DMABUF | VB2_MMAP | VB2_USERPTR;
        dst_vq->drv_priv = ctx;
        dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
        dst_vq->ops = &coda_qops;
@@ -1484,7 +1533,7 @@ static int coda_open(struct file *file)
        ctx->m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx,
                                         &coda_queue_init);
        if (IS_ERR(ctx->m2m_ctx)) {
-               int ret = PTR_ERR(ctx->m2m_ctx);
+               ret = PTR_ERR(ctx->m2m_ctx);
 
                v4l2_err(&dev->v4l2_dev, "%s return error (%d)\n",
                         __func__, ret);
@@ -1596,12 +1645,14 @@ static irqreturn_t coda_irq_handler(int irq, void *data)
        ctx = v4l2_m2m_get_curr_priv(dev->m2m_dev);
        if (ctx == NULL) {
                v4l2_err(&dev->v4l2_dev, "Instance released before the end of transaction\n");
+               mutex_unlock(&dev->coda_mutex);
                return IRQ_HANDLED;
        }
 
        if (ctx->aborting) {
                v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
                         "task has been aborted\n");
+               mutex_unlock(&dev->coda_mutex);
                return IRQ_HANDLED;
        }
 
@@ -1611,8 +1662,6 @@ static irqreturn_t coda_irq_handler(int irq, void *data)
                return IRQ_NONE;
        }
 
-       complete(&dev->done);
-
        src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
        dst_buf = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
 
@@ -1660,6 +1709,8 @@ static irqreturn_t coda_irq_handler(int irq, void *data)
                (dst_buf->v4l2_buf.flags & V4L2_BUF_FLAG_KEYFRAME) ?
                "KEYFRAME" : "PFRAME");
 
+       mutex_unlock(&dev->coda_mutex);
+
        v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->m2m_ctx);
 
        return IRQ_HANDLED;
@@ -1671,12 +1722,7 @@ static void coda_timeout(struct work_struct *work)
        struct coda_dev *dev = container_of(to_delayed_work(work),
                                            struct coda_dev, timeout);
 
-       if (completion_done(&dev->done))
-               return;
-
-       complete(&dev->done);
-
-       v4l2_err(&dev->v4l2_dev, "CODA PIC_RUN timeout, stopping all streams\n");
+       dev_err(&dev->plat_dev->dev, "CODA PIC_RUN timeout, stopping all streams\n");
 
        mutex_lock(&dev->dev_mutex);
        list_for_each_entry(ctx, &dev->instances, list) {
@@ -1684,6 +1730,10 @@ static void coda_timeout(struct work_struct *work)
                v4l2_m2m_streamoff(NULL, ctx->m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
        }
        mutex_unlock(&dev->dev_mutex);
+
+       mutex_unlock(&dev->coda_mutex);
+       ctx = v4l2_m2m_get_curr_priv(dev->m2m_dev);
+       v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->m2m_ctx);
 }
 
 static u32 coda_supported_firmwares[] = {
@@ -1748,6 +1798,10 @@ static int coda_hw_init(struct coda_dev *dev)
                }
        }
 
+       /* Clear registers */
+       for (i = 0; i < 64; i++)
+               coda_write(dev, 0, CODA_REG_BIT_CODE_BUF_ADDR + i * 4);
+
        /* Tell the BIT where to find everything it needs */
        coda_write(dev, dev->workbuf.paddr,
                      CODA_REG_BIT_WORK_BUF_ADDR);
@@ -1911,16 +1965,16 @@ enum coda_platform {
 
 static const struct coda_devtype coda_devdata[] = {
        [CODA_IMX27] = {
-               .firmware    = "v4l-codadx6-imx27.bin",
-               .product     = CODA_DX6,
-               .formats     = codadx6_formats,
-               .num_formats = ARRAY_SIZE(codadx6_formats),
+               .firmware   = "v4l-codadx6-imx27.bin",
+               .product    = CODA_DX6,
+               .codecs     = codadx6_codecs,
+               .num_codecs = ARRAY_SIZE(codadx6_codecs),
        },
        [CODA_IMX53] = {
-               .firmware    = "v4l-coda7541-imx53.bin",
-               .product     = CODA_7541,
-               .formats     = coda7_formats,
-               .num_formats = ARRAY_SIZE(coda7_formats),
+               .firmware   = "v4l-coda7541-imx53.bin",
+               .product    = CODA_7541,
+               .codecs     = coda7_codecs,
+               .num_codecs = ARRAY_SIZE(coda7_codecs),
        },
 };
 
@@ -1962,8 +2016,6 @@ static int coda_probe(struct platform_device *pdev)
        spin_lock_init(&dev->irqlock);
        INIT_LIST_HEAD(&dev->instances);
        INIT_DELAYED_WORK(&dev->timeout, coda_timeout);
-       init_completion(&dev->done);
-       complete(&dev->done);
 
        dev->plat_dev = pdev;
        dev->clk_per = devm_clk_get(&pdev->dev, "per");
@@ -1985,17 +2037,9 @@ static int coda_probe(struct platform_device *pdev)
                return -ENOENT;
        }
 
-       if (devm_request_mem_region(&pdev->dev, res->start,
-                       resource_size(res), CODA_NAME) == NULL) {
-               dev_err(&pdev->dev, "failed to request memory region\n");
-               return -ENOENT;
-       }
-       dev->regs_base = devm_ioremap(&pdev->dev, res->start,
-                                     resource_size(res));
-       if (!dev->regs_base) {
-               dev_err(&pdev->dev, "failed to ioremap address region\n");
-               return -ENOENT;
-       }
+       dev->regs_base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(dev->regs_base))
+               return PTR_ERR(dev->regs_base);
 
        /* IRQ */
        irq = platform_get_irq(pdev, 0);
@@ -2025,6 +2069,7 @@ static int coda_probe(struct platform_device *pdev)
                return ret;
 
        mutex_init(&dev->dev_mutex);
+       mutex_init(&dev->coda_mutex);
 
        pdev_id = of_id ? of_id->data : platform_get_device_id(pdev);
 
index f3f5e43..ace0bf0 100644 (file)
 #define CODA_CMD_ENC_SEQ_BB_START                              0x180
 #define CODA_CMD_ENC_SEQ_BB_SIZE                               0x184
 #define CODA_CMD_ENC_SEQ_OPTION                                0x188
-#define                CODA_OPTION_GAMMA_OFFSET                        7
-#define                CODA_OPTION_GAMMA_MASK                          0x01
+#define                CODA7_OPTION_GAMMA_OFFSET                       8
+#define                CODADX6_OPTION_GAMMA_OFFSET                     7
 #define                CODA_OPTION_LIMITQP_OFFSET                      6
-#define                CODA_OPTION_LIMITQP_MASK                        0x01
 #define                CODA_OPTION_RCINTRAQP_OFFSET                    5
-#define                CODA_OPTION_RCINTRAQP_MASK                      0x01
 #define                CODA_OPTION_FMO_OFFSET                          4
-#define                CODA_OPTION_FMO_MASK                            0x01
 #define                CODA_OPTION_SLICEREPORT_OFFSET                  1
-#define                CODA_OPTION_SLICEREPORT_MASK                    0x01
 #define CODA_CMD_ENC_SEQ_COD_STD                               0x18c
 #define                CODA_STD_MPEG4                                  0
 #define                CODA_STD_H263                                   1
 #define                CODADX6_PICWIDTH_OFFSET                         10
 #define                CODADX6_PICWIDTH_MASK                           0x3ff
 #define                CODA_PICHEIGHT_OFFSET                           0
-#define                CODA_PICHEIGHT_MASK                             0x3ff
+#define                CODADX6_PICHEIGHT_MASK                          0x3ff
+#define                CODA7_PICHEIGHT_MASK                            0xffff
 #define CODA_CMD_ENC_SEQ_SRC_F_RATE                            0x194
 #define CODA_CMD_ENC_SEQ_MP4_PARA                              0x198
 #define                CODA_MP4PARAM_VERID_OFFSET                      6
index d0b375c..e180ff7 100644 (file)
@@ -944,7 +944,7 @@ static int vpbe_display_s_fmt(struct file *file, void *priv,
        cfg->interlaced = vpbe_dev->current_timings.interlaced;
 
        if (V4L2_PIX_FMT_UYVY == pixfmt->pixelformat)
-               cfg->pixfmt = PIXFMT_YCbCrI;
+               cfg->pixfmt = PIXFMT_YCBCRI;
 
        /* Change of the default pixel format for both video windows */
        if (V4L2_PIX_FMT_NV12 == pixfmt->pixelformat) {
@@ -1593,31 +1593,6 @@ static int vpbe_display_release(struct file *file)
        return 0;
 }
 
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-static int vpbe_display_g_register(struct file *file, void *priv,
-                       struct v4l2_dbg_register *reg)
-{
-       struct v4l2_dbg_match *match = &reg->match;
-       struct vpbe_fh *fh = file->private_data;
-       struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
-
-       if (match->type >= 2) {
-               v4l2_subdev_call(vpbe_dev->venc,
-                                core,
-                                g_register,
-                                reg);
-       }
-
-       return 0;
-}
-
-static int vpbe_display_s_register(struct file *file, void *priv,
-                       const struct v4l2_dbg_register *reg)
-{
-       return 0;
-}
-#endif
-
 /* vpbe capture ioctl operations */
 static const struct v4l2_ioctl_ops vpbe_ioctl_ops = {
        .vidioc_querycap         = vpbe_display_querycap,
@@ -1644,10 +1619,6 @@ static const struct v4l2_ioctl_ops vpbe_ioctl_ops = {
        .vidioc_s_dv_timings     = vpbe_display_s_dv_timings,
        .vidioc_g_dv_timings     = vpbe_display_g_dv_timings,
        .vidioc_enum_dv_timings  = vpbe_display_enum_dv_timings,
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-       .vidioc_g_register       = vpbe_display_g_register,
-       .vidioc_s_register       = vpbe_display_s_register,
-#endif
 };
 
 static struct v4l2_file_operations vpbe_fops = {
index 396a51c..6ed82e8 100644 (file)
@@ -119,7 +119,7 @@ static inline u32 osd_modify(struct osd_state *sd, u32 mask, u32 val,
 #define is_rgb_pixfmt(pixfmt) \
        (((pixfmt) == PIXFMT_RGB565) || ((pixfmt) == PIXFMT_RGB888))
 #define is_yc_pixfmt(pixfmt) \
-       (((pixfmt) == PIXFMT_YCbCrI) || ((pixfmt) == PIXFMT_YCrCbI) || \
+       (((pixfmt) == PIXFMT_YCBCRI) || ((pixfmt) == PIXFMT_YCRCBI) || \
        ((pixfmt) == PIXFMT_NV12))
 #define MAX_WIN_SIZE OSD_VIDWIN0XP_V0X
 #define MAX_LINE_LENGTH (OSD_VIDWIN0OFST_V0LO << 5)
@@ -360,8 +360,8 @@ static void _osd_enable_color_key(struct osd_state *sd,
                        osd_write(sd, colorkey & OSD_TRANSPVALL_RGBL,
                                  OSD_TRANSPVALL);
                break;
-       case PIXFMT_YCbCrI:
-       case PIXFMT_YCrCbI:
+       case PIXFMT_YCBCRI:
+       case PIXFMT_YCRCBI:
                if (sd->vpbe_type == VPBE_VERSION_3)
                        osd_modify(sd, OSD_TRANSPVALU_Y, colorkey,
                                   OSD_TRANSPVALU);
@@ -813,8 +813,8 @@ static int try_layer_config(struct osd_state *sd, enum osd_layer layer,
                if (osd->vpbe_type == VPBE_VERSION_1)
                        bad_config = !is_vid_win(layer);
                break;
-       case PIXFMT_YCbCrI:
-       case PIXFMT_YCrCbI:
+       case PIXFMT_YCBCRI:
+       case PIXFMT_YCRCBI:
                bad_config = !is_vid_win(layer);
                break;
        case PIXFMT_RGB888:
@@ -950,9 +950,9 @@ static void _osd_set_cbcr_order(struct osd_state *sd,
         * The caller must ensure that all windows using YC pixfmt use the same
         * Cb/Cr order.
         */
-       if (pixfmt == PIXFMT_YCbCrI)
+       if (pixfmt == PIXFMT_YCBCRI)
                osd_clear(sd, OSD_MODE_CS, OSD_MODE);
-       else if (pixfmt == PIXFMT_YCrCbI)
+       else if (pixfmt == PIXFMT_YCRCBI)
                osd_set(sd, OSD_MODE_CS, OSD_MODE);
 }
 
@@ -981,8 +981,8 @@ static void _osd_set_layer_config(struct osd_state *sd, enum osd_layer layer,
                                winmd |= (2 << OSD_OSDWIN0MD_BMP0MD_SHIFT);
                                _osd_enable_rgb888_pixblend(sd, OSDWIN_OSD0);
                                break;
-                       case PIXFMT_YCbCrI:
-                       case PIXFMT_YCrCbI:
+                       case PIXFMT_YCBCRI:
+                       case PIXFMT_YCRCBI:
                                winmd |= (3 << OSD_OSDWIN0MD_BMP0MD_SHIFT);
                                break;
                        default:
@@ -1128,8 +1128,8 @@ static void _osd_set_layer_config(struct osd_state *sd, enum osd_layer layer,
                                        _osd_enable_rgb888_pixblend(sd,
                                                        OSDWIN_OSD1);
                                        break;
-                               case PIXFMT_YCbCrI:
-                               case PIXFMT_YCrCbI:
+                               case PIXFMT_YCBCRI:
+                               case PIXFMT_YCRCBI:
                                        winmd |=
                                            (3 << OSD_OSDWIN1MD_BMP1MD_SHIFT);
                                        break;
@@ -1508,7 +1508,7 @@ static int osd_initialize(struct osd_state *osd)
        _osd_init(osd);
 
        /* set default Cb/Cr order */
-       osd->yc_pixfmt = PIXFMT_YCbCrI;
+       osd->yc_pixfmt = PIXFMT_YCBCRI;
 
        if (osd->vpbe_type == VPBE_VERSION_3) {
                /*
index ea82a8b..cd08e52 100644 (file)
  * GNU General Public License for more details.
  */
 
+#include <linux/err.h>
 #include <linux/init.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
-#include <linux/spinlock.h>
-#include <linux/kernel.h>
-#include <linux/io.h>
-#include <linux/err.h>
 #include <linux/pm_runtime.h>
+#include <linux/spinlock.h>
 #include <linux/v4l2-dv-timings.h>
 
-#include <mach/hardware.h>
-
 #include "vpif.h"
 
 MODULE_DESCRIPTION("TI DaVinci Video Port Interface driver");
 MODULE_LICENSE("GPL");
 
-#define VPIF_CH0_MAX_MODES     (22)
-#define VPIF_CH1_MAX_MODES     (02)
-#define VPIF_CH2_MAX_MODES     (15)
-#define VPIF_CH3_MAX_MODES     (02)
+#define VPIF_CH0_MAX_MODES     22
+#define VPIF_CH1_MAX_MODES     2
+#define VPIF_CH2_MAX_MODES     15
+#define VPIF_CH3_MAX_MODES     2
 
-static resource_size_t res_len;
-static struct resource *res;
 spinlock_t vpif_lock;
 
 void __iomem *vpif_base;
@@ -423,23 +419,12 @@ EXPORT_SYMBOL(vpif_channel_getfid);
 
 static int vpif_probe(struct platform_device *pdev)
 {
-       int status = 0;
+       static struct resource  *res;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res)
-               return -ENOENT;
-
-       res_len = resource_size(res);
-
-       res = request_mem_region(res->start, res_len, res->name);
-       if (!res)
-               return -EBUSY;
-
-       vpif_base = ioremap(res->start, res_len);
-       if (!vpif_base) {
-               status = -EBUSY;
-               goto fail;
-       }
+       vpif_base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(vpif_base))
+               return PTR_ERR(vpif_base);
 
        pm_runtime_enable(&pdev->dev);
        pm_runtime_get(&pdev->dev);
@@ -447,17 +432,11 @@ static int vpif_probe(struct platform_device *pdev)
        spin_lock_init(&vpif_lock);
        dev_info(&pdev->dev, "vpif probe success\n");
        return 0;
-
-fail:
-       release_mem_region(res->start, res_len);
-       return status;
 }
 
 static int vpif_remove(struct platform_device *pdev)
 {
        pm_runtime_disable(&pdev->dev);
-       iounmap(vpif_base);
-       release_mem_region(res->start, res_len);
        return 0;
 }
 
index 5f98df1..5514175 100644 (file)
  * TODO : add support for VBI & HBI data service
  *       add static buffer allocation
  */
-#include <linux/kernel.h>
-#include <linux/init.h>
+
 #include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/mm.h>
 #include <linux/interrupt.h>
-#include <linux/workqueue.h>
-#include <linux/string.h>
-#include <linux/videodev2.h>
-#include <linux/wait.h>
-#include <linux/time.h>
-#include <linux/i2c.h>
 #include <linux/platform_device.h>
-#include <linux/io.h>
 #include <linux/slab.h>
-#include <media/v4l2-device.h>
+
 #include <media/v4l2-ioctl.h>
-#include <media/v4l2-chip-ident.h>
 
-#include "vpif_capture.h"
 #include "vpif.h"
+#include "vpif_capture.h"
 
 MODULE_DESCRIPTION("TI DaVinci VPIF Capture driver");
 MODULE_LICENSE("GPL");
@@ -1874,66 +1862,6 @@ static int vpif_g_dv_timings(struct file *file, void *priv,
 }
 
 /*
- * vpif_g_chip_ident() - Identify the chip
- * @file: file ptr
- * @priv: file handle
- * @chip: chip identity
- *
- * Returns zero or -EINVAL if read operations fails.
- */
-static int vpif_g_chip_ident(struct file *file, void *priv,
-               struct v4l2_dbg_chip_ident *chip)
-{
-       chip->ident = V4L2_IDENT_NONE;
-       chip->revision = 0;
-       if (chip->match.type != V4L2_CHIP_MATCH_I2C_DRIVER &&
-                       chip->match.type != V4L2_CHIP_MATCH_I2C_ADDR) {
-               vpif_dbg(2, debug, "match_type is invalid.\n");
-               return -EINVAL;
-       }
-
-       return v4l2_device_call_until_err(&vpif_obj.v4l2_dev, 0, core,
-                       g_chip_ident, chip);
-}
-
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-/*
- * vpif_dbg_g_register() - Read register
- * @file: file ptr
- * @priv: file handle
- * @reg: register to be read
- *
- * Debugging only
- * Returns zero or -EINVAL if read operations fails.
- */
-static int vpif_dbg_g_register(struct file *file, void *priv,
-               struct v4l2_dbg_register *reg){
-       struct vpif_fh *fh = priv;
-       struct channel_obj *ch = fh->channel;
-
-       return v4l2_subdev_call(ch->sd, core, g_register, reg);
-}
-
-/*
- * vpif_dbg_s_register() - Write to register
- * @file: file ptr
- * @priv: file handle
- * @reg: register to be modified
- *
- * Debugging only
- * Returns zero or -EINVAL if write operations fails.
- */
-static int vpif_dbg_s_register(struct file *file, void *priv,
-               const struct v4l2_dbg_register *reg)
-{
-       struct vpif_fh *fh = priv;
-       struct channel_obj *ch = fh->channel;
-
-       return v4l2_subdev_call(ch->sd, core, s_register, reg);
-}
-#endif
-
-/*
  * vpif_log_status() - Status information
  * @file: file ptr
  * @priv: file handle
@@ -1974,11 +1902,6 @@ static const struct v4l2_ioctl_ops vpif_ioctl_ops = {
        .vidioc_query_dv_timings        = vpif_query_dv_timings,
        .vidioc_s_dv_timings            = vpif_s_dv_timings,
        .vidioc_g_dv_timings            = vpif_g_dv_timings,
-       .vidioc_g_chip_ident            = vpif_g_chip_ident,
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-       .vidioc_g_register              = vpif_dbg_g_register,
-       .vidioc_s_register              = vpif_dbg_s_register,
-#endif
        .vidioc_log_status              = vpif_log_status,
 };
 
@@ -2092,16 +2015,13 @@ static __init int vpif_probe(struct platform_device *pdev)
        }
 
        while ((res = platform_get_resource(pdev, IORESOURCE_IRQ, res_idx))) {
-               for (i = res->start; i <= res->end; i++) {
-                       if (request_irq(i, vpif_channel_isr, IRQF_SHARED,
-                                       "VPIF_Capture", (void *)
-                                       (&vpif_obj.dev[res_idx]->channel_id))) {
-                               err = -EBUSY;
-                               for (j = 0; j < i; j++)
-                                       free_irq(j, (void *)
-                                       (&vpif_obj.dev[res_idx]->channel_id));
-                               goto vpif_int_err;
-                       }
+               err = devm_request_irq(&pdev->dev, res->start, vpif_channel_isr,
+                                       IRQF_SHARED, "VPIF_Capture",
+                                       (void *)(&vpif_obj.dev[res_idx]->
+                                       channel_id));
+               if (err) {
+                       err = -EINVAL;
+                       goto vpif_unregister;
                }
                res_idx++;
        }
@@ -2117,7 +2037,7 @@ static __init int vpif_probe(struct platform_device *pdev)
                                video_device_release(ch->video_dev);
                        }
                        err = -ENOMEM;
-                       goto vpif_int_err;
+                       goto vpif_unregister;
                }
 
                /* Initialize field of video device */
@@ -2170,6 +2090,7 @@ static __init int vpif_probe(struct platform_device *pdev)
 
                if (!vpif_obj.sd[i]) {
                        vpif_err("Error registering v4l2 subdevice\n");
+                       err = -ENODEV;
                        goto probe_subdev_out;
                }
                v4l2_info(&vpif_obj.v4l2_dev, "registered sub device %s\n",
@@ -2217,13 +2138,9 @@ vpif_sd_error:
                /* Note: does nothing if ch->video_dev == NULL */
                video_device_release(ch->video_dev);
        }
-vpif_int_err:
+vpif_unregister:
        v4l2_device_unregister(&vpif_obj.v4l2_dev);
-       for (i = 0; i < res_idx; i++) {
-               res = platform_get_resource(pdev, IORESOURCE_IRQ, i);
-               for (j = res->start; j <= res->end; j++)
-                       free_irq(j, (void *)(&vpif_obj.dev[i]->channel_id));
-       }
+
        return err;
 }
 
@@ -2235,17 +2152,19 @@ vpif_int_err:
  */
 static int vpif_remove(struct platform_device *device)
 {
-       int i;
        struct channel_obj *ch;
+       int i;
 
        v4l2_device_unregister(&vpif_obj.v4l2_dev);
 
+       kfree(vpif_obj.sd);
        /* un-register device */
        for (i = 0; i < VPIF_CAPTURE_MAX_DEVICES; i++) {
                /* Get the pointer to the channel object */
                ch = vpif_obj.dev[i];
                /* Unregister video device */
                video_unregister_device(ch->video_dev);
+               kfree(vpif_obj.dev[i]);
        }
        return 0;
 }
@@ -2336,47 +2255,4 @@ static __refdata struct platform_driver vpif_driver = {
        .remove = vpif_remove,
 };
 
-/**
- * vpif_init: initialize the vpif driver
- *
- * This function registers device and driver to the kernel, requests irq
- * handler and allocates memory
- * for channel objects
- */
-static __init int vpif_init(void)
-{
-       return platform_driver_register(&vpif_driver);
-}
-
-/**
- * vpif_cleanup : This function clean up the vpif capture resources
- *
- * This will un-registers device and driver to the kernel, frees
- * requested irq handler and de-allocates memory allocated for channel
- * objects.
- */
-static void vpif_cleanup(void)
-{
-       struct platform_device *pdev;
-       struct resource *res;
-       int irq_num;
-       int i = 0;
-
-       pdev = container_of(vpif_dev, struct platform_device, dev);
-       while ((res = platform_get_resource(pdev, IORESOURCE_IRQ, i))) {
-               for (irq_num = res->start; irq_num <= res->end; irq_num++)
-                       free_irq(irq_num,
-                                (void *)(&vpif_obj.dev[i]->channel_id));
-               i++;
-       }
-
-       platform_driver_unregister(&vpif_driver);
-
-       kfree(vpif_obj.sd);
-       for (i = 0; i < VPIF_CAPTURE_MAX_DEVICES; i++)
-               kfree(vpif_obj.dev[i]);
-}
-
-/* Function for module initialization and cleanup */
-module_init(vpif_init);
-module_exit(vpif_cleanup);
+module_platform_driver(vpif_driver);
index 3d3c1e5..0ebb312 100644 (file)
 #ifdef __KERNEL__
 
 /* Header files */
-#include <linux/videodev2.h>
-#include <media/v4l2-common.h>
-#include <media/v4l2-device.h>
 #include <media/videobuf2-dma-contig.h>
-#include <media/davinci/vpif_types.h>
+#include <media/v4l2-device.h>
 
 #include "vpif.h"
 
index 1b3fb5c..e6e5736 100644 (file)
  * GNU General Public License for more details.
  */
 
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/mm.h>
 #include <linux/interrupt.h>
-#include <linux/workqueue.h>
-#include <linux/string.h>
-#include <linux/videodev2.h>
-#include <linux/wait.h>
-#include <linux/time.h>
-#include <linux/i2c.h>
+#include <linux/module.h>
 #include <linux/platform_device.h>
-#include <linux/io.h>
 #include <linux/slab.h>
 
-#include <asm/irq.h>
-#include <asm/page.h>
-
-#include <media/adv7343.h>
-#include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
-#include <media/v4l2-chip-ident.h>
 
-#include "vpif_display.h"
 #include "vpif.h"
+#include "vpif_display.h"
 
 MODULE_DESCRIPTION("TI DaVinci VPIF Display driver");
 MODULE_LICENSE("GPL");
@@ -1518,66 +1500,6 @@ static int vpif_g_dv_timings(struct file *file, void *priv,
 }
 
 /*
- * vpif_g_chip_ident() - Identify the chip
- * @file: file ptr
- * @priv: file handle
- * @chip: chip identity
- *
- * Returns zero or -EINVAL if read operations fails.
- */
-static int vpif_g_chip_ident(struct file *file, void *priv,
-               struct v4l2_dbg_chip_ident *chip)
-{
-       chip->ident = V4L2_IDENT_NONE;
-       chip->revision = 0;
-       if (chip->match.type != V4L2_CHIP_MATCH_I2C_DRIVER &&
-                       chip->match.type != V4L2_CHIP_MATCH_I2C_ADDR) {
-               vpif_dbg(2, debug, "match_type is invalid.\n");
-               return -EINVAL;
-       }
-
-       return v4l2_device_call_until_err(&vpif_obj.v4l2_dev, 0, core,
-                       g_chip_ident, chip);
-}
-
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-/*
- * vpif_dbg_g_register() - Read register
- * @file: file ptr
- * @priv: file handle
- * @reg: register to be read
- *
- * Debugging only
- * Returns zero or -EINVAL if read operations fails.
- */
-static int vpif_dbg_g_register(struct file *file, void *priv,
-               struct v4l2_dbg_register *reg){
-       struct vpif_fh *fh = priv;
-       struct channel_obj *ch = fh->channel;
-
-       return v4l2_subdev_call(ch->sd, core, g_register, reg);
-}
-
-/*
- * vpif_dbg_s_register() - Write to register
- * @file: file ptr
- * @priv: file handle
- * @reg: register to be modified
- *
- * Debugging only
- * Returns zero or -EINVAL if write operations fails.
- */
-static int vpif_dbg_s_register(struct file *file, void *priv,
-               const struct v4l2_dbg_register *reg)
-{
-       struct vpif_fh *fh = priv;
-       struct channel_obj *ch = fh->channel;
-
-       return v4l2_subdev_call(ch->sd, core, s_register, reg);
-}
-#endif
-
-/*
  * vpif_log_status() - Status information
  * @file: file ptr
  * @priv: file handle
@@ -1616,11 +1538,6 @@ static const struct v4l2_ioctl_ops vpif_ioctl_ops = {
        .vidioc_enum_dv_timings         = vpif_enum_dv_timings,
        .vidioc_s_dv_timings            = vpif_s_dv_timings,
        .vidioc_g_dv_timings            = vpif_g_dv_timings,
-       .vidioc_g_chip_ident            = vpif_g_chip_ident,
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-       .vidioc_g_register              = vpif_dbg_g_register,
-       .vidioc_s_register              = vpif_dbg_s_register,
-#endif
        .vidioc_log_status              = vpif_log_status,
 };
 
@@ -1734,16 +1651,14 @@ static __init int vpif_probe(struct platform_device *pdev)
        }
 
        while ((res = platform_get_resource(pdev, IORESOURCE_IRQ, res_idx))) {
-               for (i = res->start; i <= res->end; i++) {
-                       if (request_irq(i, vpif_channel_isr, IRQF_SHARED,
-                                       "VPIF_Display", (void *)
-                                       (&vpif_obj.dev[res_idx]->channel_id))) {
-                               err = -EBUSY;
-                               for (j = 0; j < i; j++)
-                                       free_irq(j, (void *)
-                                       (&vpif_obj.dev[res_idx]->channel_id));
-                               goto vpif_int_err;
-                       }
+               err = devm_request_irq(&pdev->dev, res->start, vpif_channel_isr,
+                                       IRQF_SHARED, "VPIF_Display",
+                                       (void *)(&vpif_obj.dev[res_idx]->
+                                       channel_id));
+               if (err) {
+                       err = -EINVAL;
+                       vpif_err("VPIF IRQ request failed\n");
+                       goto vpif_unregister;
                }
                res_idx++;
        }
@@ -1760,7 +1675,7 @@ static __init int vpif_probe(struct platform_device *pdev)
                                video_device_release(ch->video_dev);
                        }
                        err = -ENOMEM;
-                       goto vpif_int_err;
+                       goto vpif_unregister;
                }
 
                /* Initialize field of video device */
@@ -1813,6 +1728,7 @@ static __init int vpif_probe(struct platform_device *pdev)
                                                NULL);
                if (!vpif_obj.sd[i]) {
                        vpif_err("Error registering v4l2 subdevice\n");
+                       err = -ENODEV;
                        goto probe_subdev_out;
                }
 
@@ -1893,14 +1809,8 @@ vpif_sd_error:
                /* Note: does nothing if ch->video_dev == NULL */
                video_device_release(ch->video_dev);
        }
-vpif_int_err:
+vpif_unregister:
        v4l2_device_unregister(&vpif_obj.v4l2_dev);
-       vpif_err("VPIF IRQ request failed\n");
-       for (i = 0; i < res_idx; i++) {
-               res = platform_get_resource(pdev, IORESOURCE_IRQ, i);
-               for (j = res->start; j <= res->end; j++)
-                       free_irq(j, (void *)(&vpif_obj.dev[i]->channel_id));
-       }
 
        return err;
 }
@@ -1915,6 +1825,7 @@ static int vpif_remove(struct platform_device *device)
 
        v4l2_device_unregister(&vpif_obj.v4l2_dev);
 
+       kfree(vpif_obj.sd);
        /* un-register device */
        for (i = 0; i < VPIF_DISPLAY_MAX_DEVICES; i++) {
                /* Get the pointer to the channel object */
@@ -1923,6 +1834,7 @@ static int vpif_remove(struct platform_device *device)
                video_unregister_device(ch->video_dev);
 
                ch->video_dev = NULL;
+               kfree(vpif_obj.dev[i]);
        }
 
        return 0;
@@ -2008,37 +1920,4 @@ static __refdata struct platform_driver vpif_driver = {
        .remove = vpif_remove,
 };
 
-static __init int vpif_init(void)
-{
-       return platform_driver_register(&vpif_driver);
-}
-
-/*
- * vpif_cleanup: This function un-registers device and driver to the kernel,
- * frees requested irq handler and de-allocates memory allocated for channel
- * objects.
- */
-static void vpif_cleanup(void)
-{
-       struct platform_device *pdev;
-       struct resource *res;
-       int irq_num;
-       int i = 0;
-
-       pdev = container_of(vpif_dev, struct platform_device, dev);
-
-       while ((res = platform_get_resource(pdev, IORESOURCE_IRQ, i))) {
-               for (irq_num = res->start; irq_num <= res->end; irq_num++)
-                       free_irq(irq_num,
-                                (void *)(&vpif_obj.dev[i]->channel_id));
-               i++;
-       }
-
-       platform_driver_unregister(&vpif_driver);
-       kfree(vpif_obj.sd);
-       for (i = 0; i < VPIF_DISPLAY_MAX_DEVICES; i++)
-               kfree(vpif_obj.dev[i]);
-}
-
-module_init(vpif_init);
-module_exit(vpif_cleanup);
+module_platform_driver(vpif_driver);
index a5a18f7..5d87fc8 100644 (file)
 #define DAVINCIHD_DISPLAY_H
 
 /* Header files */
-#include <linux/videodev2.h>
-#include <media/v4l2-common.h>
-#include <media/v4l2-device.h>
 #include <media/videobuf2-dma-contig.h>
-#include <media/davinci/vpif_types.h>
+#include <media/v4l2-device.h>
 
 #include "vpif.h"
 
index 33b5ffc..559fab2 100644 (file)
@@ -988,7 +988,7 @@ static void *gsc_get_drv_data(struct platform_device *pdev)
 
        if (pdev->dev.of_node) {
                const struct of_device_id *match;
-               match = of_match_node(of_match_ptr(exynos_gsc_match),
+               match = of_match_node(exynos_gsc_match,
                                        pdev->dev.of_node);
                if (match)
                        driver_data = (struct gsc_driverdata *)match->data;
index 436a62a..53ad0f0 100644 (file)
@@ -9,12 +9,16 @@ config VIDEO_SAMSUNG_EXYNOS4_IS
 
 if VIDEO_SAMSUNG_EXYNOS4_IS
 
+config VIDEO_EXYNOS4_IS_COMMON
+       tristate
+
 config VIDEO_S5P_FIMC
        tristate "S5P/EXYNOS4 FIMC/CAMIF camera interface driver"
        depends on I2C
        select VIDEOBUF2_DMA_CONTIG
        select V4L2_MEM2MEM_DEV
        select MFD_SYSCON if OF
+       select VIDEO_EXYNOS4_IS_COMMON
        help
          This is a V4L2 driver for Samsung S5P and EXYNOS4 SoC camera host
          interface and video postprocessor (FIMC) devices.
@@ -39,6 +43,7 @@ config VIDEO_EXYNOS_FIMC_LITE
        tristate "EXYNOS FIMC-LITE camera interface driver"
        depends on I2C
        select VIDEOBUF2_DMA_CONTIG
+       select VIDEO_EXYNOS4_IS_COMMON
        help
          This is a V4L2 driver for Samsung EXYNOS4/5 SoC FIMC-LITE camera
          host interface.
index f25f463..c2ff29b 100644 (file)
@@ -1,10 +1,13 @@
 s5p-fimc-objs := fimc-core.o fimc-reg.o fimc-m2m.o fimc-capture.o media-dev.o
 exynos-fimc-lite-objs += fimc-lite-reg.o fimc-lite.o
+s5p-csis-objs := mipi-csis.o
+exynos4-is-common-objs := common.o
+
 exynos-fimc-is-objs := fimc-is.o fimc-isp.o fimc-is-sensor.o fimc-is-regs.o
 exynos-fimc-is-objs += fimc-is-param.o fimc-is-errno.o fimc-is-i2c.o
-s5p-csis-objs := mipi-csis.o
 
 obj-$(CONFIG_VIDEO_S5P_MIPI_CSIS)      += s5p-csis.o
 obj-$(CONFIG_VIDEO_EXYNOS_FIMC_LITE)   += exynos-fimc-lite.o
 obj-$(CONFIG_VIDEO_EXYNOS4_FIMC_IS)    += exynos-fimc-is.o
 obj-$(CONFIG_VIDEO_S5P_FIMC)           += s5p-fimc.o
+obj-$(CONFIG_VIDEO_EXYNOS4_IS_COMMON)  += exynos4-is-common.o
diff --git a/drivers/media/platform/exynos4-is/common.c b/drivers/media/platform/exynos4-is/common.c
new file mode 100644 (file)
index 0000000..0ec210b
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Samsung S5P/EXYNOS4 SoC Camera Subsystem driver
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ * Author: Sylwester Nawrocki <s.nawrocki@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <media/s5p_fimc.h>
+#include "common.h"
+
+/* Called with the media graph mutex held or entity->stream_count > 0. */
+struct v4l2_subdev *fimc_find_remote_sensor(struct media_entity *entity)
+{
+       struct media_pad *pad = &entity->pads[0];
+       struct v4l2_subdev *sd;
+
+       while (pad->flags & MEDIA_PAD_FL_SINK) {
+               /* source pad */
+               pad = media_entity_remote_pad(pad);
+               if (pad == NULL ||
+                   media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
+                       break;
+
+               sd = media_entity_to_v4l2_subdev(pad->entity);
+
+               if (sd->grp_id == GRP_ID_FIMC_IS_SENSOR ||
+                   sd->grp_id == GRP_ID_SENSOR)
+                       return sd;
+               /* sink pad */
+               pad = &sd->entity.pads[0];
+       }
+       return NULL;
+}
+EXPORT_SYMBOL(fimc_find_remote_sensor);
+
+void __fimc_vidioc_querycap(struct device *dev, struct v4l2_capability *cap,
+                                               unsigned int caps)
+{
+       strlcpy(cap->driver, dev->driver->name, sizeof(cap->driver));
+       strlcpy(cap->card, dev->driver->name, sizeof(cap->card));
+       snprintf(cap->bus_info, sizeof(cap->bus_info),
+                               "platform:%s", dev_name(dev));
+       cap->device_caps = caps;
+       cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
+}
+EXPORT_SYMBOL(__fimc_vidioc_querycap);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/platform/exynos4-is/common.h b/drivers/media/platform/exynos4-is/common.h
new file mode 100644 (file)
index 0000000..75b9c71
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * Copyright (C) 2013 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 version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/device.h>
+#include <linux/videodev2.h>
+#include <media/media-entity.h>
+#include <media/v4l2-subdev.h>
+
+struct v4l2_subdev *fimc_find_remote_sensor(struct media_entity *entity);
+void __fimc_vidioc_querycap(struct device *dev, struct v4l2_capability *cap,
+                           unsigned int caps);
index 528f413..fb27ff7 100644 (file)
 #include <media/videobuf2-core.h>
 #include <media/videobuf2-dma-contig.h>
 
-#include "media-dev.h"
+#include "common.h"
 #include "fimc-core.h"
 #include "fimc-reg.h"
+#include "media-dev.h"
 
 static int fimc_capture_hw_init(struct fimc_dev *fimc)
 {
@@ -119,8 +120,7 @@ static int fimc_capture_state_cleanup(struct fimc_dev *fimc, bool suspend)
        spin_unlock_irqrestore(&fimc->slock, flags);
 
        if (streaming)
-               return fimc_pipeline_call(fimc, set_stream,
-                                         &fimc->pipeline, 0);
+               return fimc_pipeline_call(&cap->ve, set_stream, 0);
        else
                return 0;
 }
@@ -178,8 +178,9 @@ static int fimc_capture_config_update(struct fimc_ctx *ctx)
 
 void fimc_capture_irq_handler(struct fimc_dev *fimc, int deq_buf)
 {
-       struct v4l2_subdev *csis = fimc->pipeline.subdevs[IDX_CSIS];
        struct fimc_vid_cap *cap = &fimc->vid_cap;
+       struct fimc_pipeline *p = to_fimc_pipeline(cap->ve.pipe);
+       struct v4l2_subdev *csis = p->subdevs[IDX_CSIS];
        struct fimc_frame *f = &cap->ctx->d_frame;
        struct fimc_vid_buffer *v_buf;
        struct timeval *tv;
@@ -287,8 +288,7 @@ static int start_streaming(struct vb2_queue *q, unsigned int count)
                fimc_activate_capture(ctx);
 
                if (!test_and_set_bit(ST_CAPT_ISP_STREAM, &fimc->state))
-                       return fimc_pipeline_call(fimc, set_stream,
-                                                 &fimc->pipeline, 1);
+                       return fimc_pipeline_call(&vid_cap->ve, set_stream, 1);
        }
 
        return 0;
@@ -312,7 +312,7 @@ int fimc_capture_suspend(struct fimc_dev *fimc)
        int ret = fimc_stop_capture(fimc, suspend);
        if (ret)
                return ret;
-       return fimc_pipeline_call(fimc, close, &fimc->pipeline);
+       return fimc_pipeline_call(&fimc->vid_cap.ve, close);
 }
 
 static void buffer_queue(struct vb2_buffer *vb);
@@ -320,6 +320,7 @@ static void buffer_queue(struct vb2_buffer *vb);
 int fimc_capture_resume(struct fimc_dev *fimc)
 {
        struct fimc_vid_cap *vid_cap = &fimc->vid_cap;
+       struct exynos_video_entity *ve = &vid_cap->ve;
        struct fimc_vid_buffer *buf;
        int i;
 
@@ -328,8 +329,7 @@ int fimc_capture_resume(struct fimc_dev *fimc)
 
        INIT_LIST_HEAD(&fimc->vid_cap.active_buf_q);
        vid_cap->buf_index = 0;
-       fimc_pipeline_call(fimc, open, &fimc->pipeline,
-                          &vid_cap->vfd.entity, false);
+       fimc_pipeline_call(ve, open, &ve->vdev.entity, false);
        fimc_capture_hw_init(fimc);
 
        clear_bit(ST_CAPT_SUSPENDED, &fimc->state);
@@ -397,7 +397,7 @@ static int buffer_prepare(struct vb2_buffer *vb)
                unsigned long size = ctx->d_frame.payload[i];
 
                if (vb2_plane_size(vb, i) < size) {
-                       v4l2_err(&ctx->fimc_dev->vid_cap.vfd,
+                       v4l2_err(&ctx->fimc_dev->vid_cap.ve.vdev,
                                 "User buffer too small (%ld < %ld)\n",
                                 vb2_plane_size(vb, i), size);
                        return -EINVAL;
@@ -415,6 +415,7 @@ static void buffer_queue(struct vb2_buffer *vb)
        struct fimc_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
        struct fimc_dev *fimc = ctx->fimc_dev;
        struct fimc_vid_cap *vid_cap = &fimc->vid_cap;
+       struct exynos_video_entity *ve = &vid_cap->ve;
        unsigned long flags;
        int min_bufs;
 
@@ -452,9 +453,9 @@ static void buffer_queue(struct vb2_buffer *vb)
                if (test_and_set_bit(ST_CAPT_ISP_STREAM, &fimc->state))
                        return;
 
-               ret = fimc_pipeline_call(fimc, set_stream, &fimc->pipeline, 1);
+               ret = fimc_pipeline_call(ve, set_stream, 1);
                if (ret < 0)
-                       v4l2_err(&vid_cap->vfd, "stream on failed: %d\n", ret);
+                       v4l2_err(&ve->vdev, "stream on failed: %d\n", ret);
                return;
        }
        spin_unlock_irqrestore(&fimc->slock, flags);
@@ -470,44 +471,17 @@ static struct vb2_ops fimc_capture_qops = {
        .stop_streaming         = stop_streaming,
 };
 
-/**
- * fimc_capture_ctrls_create - initialize the control handler
- * Initialize the capture video node control handler and fill it
- * with the FIMC controls. Inherit any sensor's controls if the
- * 'user_subdev_api' flag is false (default behaviour).
- * This function need to be called with the graph mutex held.
- */
-int fimc_capture_ctrls_create(struct fimc_dev *fimc)
-{
-       struct fimc_vid_cap *vid_cap = &fimc->vid_cap;
-       struct v4l2_subdev *sensor = fimc->pipeline.subdevs[IDX_SENSOR];
-       int ret;
-
-       if (WARN_ON(vid_cap->ctx == NULL))
-               return -ENXIO;
-       if (vid_cap->ctx->ctrls.ready)
-               return 0;
-
-       ret = fimc_ctrls_create(vid_cap->ctx);
-
-       if (ret || vid_cap->user_subdev_api || !sensor ||
-           !vid_cap->ctx->ctrls.ready)
-               return ret;
-
-       return v4l2_ctrl_add_handler(&vid_cap->ctx->ctrls.handler,
-                                    sensor->ctrl_handler, NULL);
-}
-
 static int fimc_capture_set_default_format(struct fimc_dev *fimc);
 
 static int fimc_capture_open(struct file *file)
 {
        struct fimc_dev *fimc = video_drvdata(file);
+       struct fimc_vid_cap *vc = &fimc->vid_cap;
+       struct exynos_video_entity *ve = &vc->ve;
        int ret = -EBUSY;
 
        dbg("pid: %d, state: 0x%lx", task_pid_nr(current), fimc->state);
 
-       fimc_md_graph_lock(fimc);
        mutex_lock(&fimc->lock);
 
        if (fimc_m2m_active(fimc))
@@ -520,31 +494,42 @@ static int fimc_capture_open(struct file *file)
 
        ret = v4l2_fh_open(file);
        if (ret) {
-               pm_runtime_put(&fimc->pdev->dev);
+               pm_runtime_put_sync(&fimc->pdev->dev);
                goto unlock;
        }
 
        if (v4l2_fh_is_singular_file(file)) {
-               ret = fimc_pipeline_call(fimc, open, &fimc->pipeline,
-                                        &fimc->vid_cap.vfd.entity, true);
+               fimc_md_graph_lock(ve);
 
-               if (!ret && !fimc->vid_cap.user_subdev_api)
-                       ret = fimc_capture_set_default_format(fimc);
+               ret = fimc_pipeline_call(ve, open, &ve->vdev.entity, true);
 
-               if (!ret)
-                       ret = fimc_capture_ctrls_create(fimc);
+               if (ret == 0 && vc->user_subdev_api && vc->inh_sensor_ctrls) {
+                       /*
+                        * Recreate controls of the the video node to drop
+                        * any controls inherited from the sensor subdev.
+                        */
+                       fimc_ctrls_delete(vc->ctx);
+
+                       ret = fimc_ctrls_create(vc->ctx);
+                       if (ret == 0)
+                               vc->inh_sensor_ctrls = false;
+               }
+               if (ret == 0)
+                       ve->vdev.entity.use_count++;
+
+               fimc_md_graph_unlock(ve);
+
+               if (ret == 0)
+                       ret = fimc_capture_set_default_format(fimc);
 
                if (ret < 0) {
                        clear_bit(ST_CAPT_BUSY, &fimc->state);
                        pm_runtime_put_sync(&fimc->pdev->dev);
                        v4l2_fh_release(file);
-               } else {
-                       fimc->vid_cap.refcnt++;
                }
        }
 unlock:
        mutex_unlock(&fimc->lock);
-       fimc_md_graph_unlock(fimc);
        return ret;
 }
 
@@ -552,30 +537,31 @@ static int fimc_capture_release(struct file *file)
 {
        struct fimc_dev *fimc = video_drvdata(file);
        struct fimc_vid_cap *vc = &fimc->vid_cap;
+       bool close = v4l2_fh_is_singular_file(file);
        int ret;
 
        dbg("pid: %d, state: 0x%lx", task_pid_nr(current), fimc->state);
 
        mutex_lock(&fimc->lock);
 
-       if (v4l2_fh_is_singular_file(file)) {
-               if (vc->streaming) {
-                       media_entity_pipeline_stop(&vc->vfd.entity);
-                       vc->streaming = false;
-               }
-               clear_bit(ST_CAPT_BUSY, &fimc->state);
-               fimc_stop_capture(fimc, false);
-               fimc_pipeline_call(fimc, close, &fimc->pipeline);
-               clear_bit(ST_CAPT_SUSPENDED, &fimc->state);
-               fimc->vid_cap.refcnt--;
+       if (close && vc->streaming) {
+               media_entity_pipeline_stop(&vc->ve.vdev.entity);
+               vc->streaming = false;
        }
 
-       pm_runtime_put(&fimc->pdev->dev);
+       ret = vb2_fop_release(file);
 
-       if (v4l2_fh_is_singular_file(file))
-               fimc_ctrls_delete(fimc->vid_cap.ctx);
+       if (close) {
+               clear_bit(ST_CAPT_BUSY, &fimc->state);
+               fimc_pipeline_call(&vc->ve, close);
+               clear_bit(ST_CAPT_SUSPENDED, &fimc->state);
 
-       ret = vb2_fop_release(file);
+               fimc_md_graph_lock(&vc->ve);
+               vc->ve.vdev.entity.use_count--;
+               fimc_md_graph_unlock(&vc->ve);
+       }
+
+       pm_runtime_put_sync(&fimc->pdev->dev);
        mutex_unlock(&fimc->lock);
 
        return ret;
@@ -773,7 +759,7 @@ static struct media_entity *fimc_pipeline_get_head(struct media_entity *me)
        struct media_pad *pad = &me->pads[0];
 
        while (!(pad->flags & MEDIA_PAD_FL_SOURCE)) {
-               pad = media_entity_remote_source(pad);
+               pad = media_entity_remote_pad(pad);
                if (!pad)
                        break;
                me = pad->entity;
@@ -797,7 +783,8 @@ static int fimc_pipeline_try_format(struct fimc_ctx *ctx,
                                    bool set)
 {
        struct fimc_dev *fimc = ctx->fimc_dev;
-       struct v4l2_subdev *sd = fimc->pipeline.subdevs[IDX_SENSOR];
+       struct fimc_pipeline *p = to_fimc_pipeline(fimc->vid_cap.ve.pipe);
+       struct v4l2_subdev *sd = p->subdevs[IDX_SENSOR];
        struct v4l2_subdev_format sfmt;
        struct v4l2_mbus_framefmt *mf = &sfmt.format;
        struct media_entity *me;
@@ -845,7 +832,7 @@ static int fimc_pipeline_try_format(struct fimc_ctx *ctx,
                                        return ret;
                        }
 
-                       pad = media_entity_remote_source(&me->pads[sfmt.pad]);
+                       pad = media_entity_remote_pad(&me->pads[sfmt.pad]);
                        if (!pad)
                                return -EINVAL;
                        me = pad->entity;
@@ -929,57 +916,101 @@ static int fimc_cap_g_fmt_mplane(struct file *file, void *fh,
        return 0;
 }
 
-static int fimc_cap_try_fmt_mplane(struct file *file, void *fh,
-                                  struct v4l2_format *f)
+/*
+ * Try or set format on the fimc.X.capture video node and additionally
+ * on the whole pipeline if @try is false.
+ * Locking: the caller must _not_ hold the graph mutex.
+ */
+static int __video_try_or_set_format(struct fimc_dev *fimc,
+                                    struct v4l2_format *f, bool try,
+                                    struct fimc_fmt **inp_fmt,
+                                    struct fimc_fmt **out_fmt)
 {
        struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp;
-       struct fimc_dev *fimc = video_drvdata(file);
-       struct fimc_ctx *ctx = fimc->vid_cap.ctx;
-       struct v4l2_mbus_framefmt mf;
-       struct fimc_fmt *ffmt = NULL;
+       struct fimc_vid_cap *vc = &fimc->vid_cap;
+       struct exynos_video_entity *ve = &vc->ve;
+       struct fimc_ctx *ctx = vc->ctx;
+       unsigned int width = 0, height = 0;
        int ret = 0;
 
-       fimc_md_graph_lock(fimc);
-       mutex_lock(&fimc->lock);
-
+       /* Pre-configure format at the camera input interface, for JPEG only */
        if (fimc_jpeg_fourcc(pix->pixelformat)) {
                fimc_capture_try_format(ctx, &pix->width, &pix->height,
                                        NULL, &pix->pixelformat,
                                        FIMC_SD_PAD_SINK_CAM);
-               ctx->s_frame.f_width  = pix->width;
-               ctx->s_frame.f_height = pix->height;
+               if (try) {
+                       width = pix->width;
+                       height = pix->height;
+               } else {
+                       ctx->s_frame.f_width = pix->width;
+                       ctx->s_frame.f_height = pix->height;
+               }
        }
-       ffmt = fimc_capture_try_format(ctx, &pix->width, &pix->height,
-                                      NULL, &pix->pixelformat,
-                                      FIMC_SD_PAD_SOURCE);
-       if (!ffmt) {
-               ret = -EINVAL;
-               goto unlock;
+
+       /* Try the format at the scaler and the DMA output */
+       *out_fmt = fimc_capture_try_format(ctx, &pix->width, &pix->height,
+                                         NULL, &pix->pixelformat,
+                                         FIMC_SD_PAD_SOURCE);
+       if (*out_fmt == NULL)
+               return -EINVAL;
+
+       /* Restore image width/height for JPEG (no resizing supported). */
+       if (try && fimc_jpeg_fourcc(pix->pixelformat)) {
+               pix->width = width;
+               pix->height = height;
        }
 
-       if (!fimc->vid_cap.user_subdev_api) {
-               mf.width = pix->width;
-               mf.height = pix->height;
-               mf.code = ffmt->mbus_code;
-               fimc_pipeline_try_format(ctx, &mf, &ffmt, false);
-               pix->width = mf.width;
-               pix->height = mf.height;
-               if (ffmt)
-                       pix->pixelformat = ffmt->fourcc;
+       /* Try to match format at the host and the sensor */
+       if (!vc->user_subdev_api) {
+               struct v4l2_mbus_framefmt mbus_fmt;
+               struct v4l2_mbus_framefmt *mf;
+
+               mf = try ? &mbus_fmt : &fimc->vid_cap.ci_fmt;
+
+               mf->code = (*out_fmt)->mbus_code;
+               mf->width = pix->width;
+               mf->height = pix->height;
+
+               fimc_md_graph_lock(ve);
+               ret = fimc_pipeline_try_format(ctx, mf, inp_fmt, try);
+               fimc_md_graph_unlock(ve);
+
+               if (ret < 0)
+                       return ret;
+
+               pix->width = mf->width;
+               pix->height = mf->height;
        }
 
-       fimc_adjust_mplane_format(ffmt, pix->width, pix->height, pix);
+       fimc_adjust_mplane_format(*out_fmt, pix->width, pix->height, pix);
 
-       if (ffmt->flags & FMT_FLAGS_COMPRESSED)
-               fimc_get_sensor_frame_desc(fimc->pipeline.subdevs[IDX_SENSOR],
-                                       pix->plane_fmt, ffmt->memplanes, true);
-unlock:
-       mutex_unlock(&fimc->lock);
-       fimc_md_graph_unlock(fimc);
+       if ((*out_fmt)->flags & FMT_FLAGS_COMPRESSED) {
+               struct v4l2_subdev *sensor;
+
+               fimc_md_graph_lock(ve);
+
+               sensor = __fimc_md_get_subdev(ve->pipe, IDX_SENSOR);
+               if (sensor)
+                       fimc_get_sensor_frame_desc(sensor, pix->plane_fmt,
+                                                  (*out_fmt)->memplanes, try);
+               else
+                       ret = -EPIPE;
+
+               fimc_md_graph_unlock(ve);
+       }
 
        return ret;
 }
 
+static int fimc_cap_try_fmt_mplane(struct file *file, void *fh,
+                                  struct v4l2_format *f)
+{
+       struct fimc_dev *fimc = video_drvdata(file);
+       struct fimc_fmt *out_fmt = NULL, *inp_fmt = NULL;
+
+       return __video_try_or_set_format(fimc, f, true, &inp_fmt, &out_fmt);
+}
+
 static void fimc_capture_mark_jpeg_xfer(struct fimc_ctx *ctx,
                                        enum fimc_color_fmt color)
 {
@@ -997,57 +1028,23 @@ static void fimc_capture_mark_jpeg_xfer(struct fimc_ctx *ctx,
 static int __fimc_capture_set_format(struct fimc_dev *fimc,
                                     struct v4l2_format *f)
 {
-       struct fimc_ctx *ctx = fimc->vid_cap.ctx;
+       struct fimc_vid_cap *vc = &fimc->vid_cap;
+       struct fimc_ctx *ctx = vc->ctx;
        struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp;
-       struct v4l2_mbus_framefmt *mf = &fimc->vid_cap.ci_fmt;
        struct fimc_frame *ff = &ctx->d_frame;
-       struct fimc_fmt *s_fmt = NULL;
+       struct fimc_fmt *inp_fmt = NULL;
        int ret, i;
 
        if (vb2_is_busy(&fimc->vid_cap.vbq))
                return -EBUSY;
 
-       /* Pre-configure format at camera interface input, for JPEG only */
-       if (fimc_jpeg_fourcc(pix->pixelformat)) {
-               fimc_capture_try_format(ctx, &pix->width, &pix->height,
-                                       NULL, &pix->pixelformat,
-                                       FIMC_SD_PAD_SINK_CAM);
-               ctx->s_frame.f_width  = pix->width;
-               ctx->s_frame.f_height = pix->height;
-       }
-       /* Try the format at the scaler and the DMA output */
-       ff->fmt = fimc_capture_try_format(ctx, &pix->width, &pix->height,
-                                         NULL, &pix->pixelformat,
-                                         FIMC_SD_PAD_SOURCE);
-       if (!ff->fmt)
-               return -EINVAL;
+       ret = __video_try_or_set_format(fimc, f, false, &inp_fmt, &ff->fmt);
+       if (ret < 0)
+               return ret;
 
        /* Update RGB Alpha control state and value range */
        fimc_alpha_ctrl_update(ctx);
 
-       /* Try to match format at the host and the sensor */
-       if (!fimc->vid_cap.user_subdev_api) {
-               mf->code   = ff->fmt->mbus_code;
-               mf->width  = pix->width;
-               mf->height = pix->height;
-               ret = fimc_pipeline_try_format(ctx, mf, &s_fmt, true);
-               if (ret)
-                       return ret;
-
-               pix->width  = mf->width;
-               pix->height = mf->height;
-       }
-
-       fimc_adjust_mplane_format(ff->fmt, pix->width, pix->height, pix);
-
-       if (ff->fmt->flags & FMT_FLAGS_COMPRESSED) {
-               ret = fimc_get_sensor_frame_desc(fimc->pipeline.subdevs[IDX_SENSOR],
-                                       pix->plane_fmt, ff->fmt->memplanes,
-                                       true);
-               if (ret < 0)
-                       return ret;
-       }
-
        for (i = 0; i < ff->fmt->memplanes; i++) {
                ff->bytesperline[i] = pix->plane_fmt[i].bytesperline;
                ff->payload[i] = pix->plane_fmt[i].sizeimage;
@@ -1061,8 +1058,8 @@ static int __fimc_capture_set_format(struct fimc_dev *fimc,
        fimc_capture_mark_jpeg_xfer(ctx, ff->fmt->color);
 
        /* Reset cropping and set format at the camera interface input */
-       if (!fimc->vid_cap.user_subdev_api) {
-               ctx->s_frame.fmt = s_fmt;
+       if (!vc->user_subdev_api) {
+               ctx->s_frame.fmt = inp_fmt;
                set_frame_bounds(&ctx->s_frame, pix->width, pix->height);
                set_frame_crop(&ctx->s_frame, 0, 0, pix->width, pix->height);
        }
@@ -1074,37 +1071,28 @@ static int fimc_cap_s_fmt_mplane(struct file *file, void *priv,
                                 struct v4l2_format *f)
 {
        struct fimc_dev *fimc = video_drvdata(file);
-       int ret;
 
-       fimc_md_graph_lock(fimc);
-       mutex_lock(&fimc->lock);
-       /*
-        * The graph is walked within __fimc_capture_set_format() to set
-        * the format at subdevs thus the graph mutex needs to be held at
-        * this point and acquired before the video mutex, to avoid  AB-BA
-        * deadlock when fimc_md_link_notify() is called by other thread.
-        * Ideally the graph walking and setting format at the whole pipeline
-        * should be removed from this driver and handled in userspace only.
-        */
-       ret = __fimc_capture_set_format(fimc, f);
-
-       mutex_unlock(&fimc->lock);
-       fimc_md_graph_unlock(fimc);
-       return ret;
+       return __fimc_capture_set_format(fimc, f);
 }
 
 static int fimc_cap_enum_input(struct file *file, void *priv,
                               struct v4l2_input *i)
 {
        struct fimc_dev *fimc = video_drvdata(file);
-       struct v4l2_subdev *sd = fimc->pipeline.subdevs[IDX_SENSOR];
+       struct exynos_video_entity *ve = &fimc->vid_cap.ve;
+       struct v4l2_subdev *sd;
 
        if (i->index != 0)
                return -EINVAL;
 
        i->type = V4L2_INPUT_TYPE_CAMERA;
+       fimc_md_graph_lock(ve);
+       sd = __fimc_md_get_subdev(ve->pipe, IDX_SENSOR);
+       fimc_md_graph_unlock(ve);
+
        if (sd)
                strlcpy(i->name, sd->name, sizeof(i->name));
+
        return 0;
 }
 
@@ -1130,6 +1118,7 @@ static int fimc_pipeline_validate(struct fimc_dev *fimc)
        struct v4l2_subdev_format sink_fmt, src_fmt;
        struct fimc_vid_cap *vc = &fimc->vid_cap;
        struct v4l2_subdev *sd = &vc->subdev;
+       struct fimc_pipeline *p = to_fimc_pipeline(vc->ve.pipe);
        struct media_pad *sink_pad, *src_pad;
        int i, ret;
 
@@ -1146,7 +1135,7 @@ static int fimc_pipeline_validate(struct fimc_dev *fimc)
 
                        if (p->flags & MEDIA_PAD_FL_SINK) {
                                sink_pad = p;
-                               src_pad = media_entity_remote_source(sink_pad);
+                               src_pad = media_entity_remote_pad(sink_pad);
                                if (src_pad)
                                        break;
                        }
@@ -1183,7 +1172,7 @@ static int fimc_pipeline_validate(struct fimc_dev *fimc)
                    src_fmt.format.code != sink_fmt.format.code)
                        return -EPIPE;
 
-               if (sd == fimc->pipeline.subdevs[IDX_SENSOR] &&
+               if (sd == p->subdevs[IDX_SENSOR] &&
                    fimc_user_defined_mbus_fmt(src_fmt.format.code)) {
                        struct v4l2_plane_pix_format plane_fmt[FIMC_MAX_PLANES];
                        struct fimc_frame *frame = &vc->ctx->d_frame;
@@ -1207,9 +1196,8 @@ static int fimc_cap_streamon(struct file *file, void *priv,
                             enum v4l2_buf_type type)
 {
        struct fimc_dev *fimc = video_drvdata(file);
-       struct fimc_pipeline *p = &fimc->pipeline;
        struct fimc_vid_cap *vc = &fimc->vid_cap;
-       struct media_entity *entity = &vc->vfd.entity;
+       struct media_entity *entity = &vc->ve.vdev.entity;
        struct fimc_source_info *si = NULL;
        struct v4l2_subdev *sd;
        int ret;
@@ -1217,11 +1205,11 @@ static int fimc_cap_streamon(struct file *file, void *priv,
        if (fimc_capture_active(fimc))
                return -EBUSY;
 
-       ret = media_entity_pipeline_start(entity, p->m_pipeline);
+       ret = media_entity_pipeline_start(entity, &vc->ve.pipe->mp);
        if (ret < 0)
                return ret;
 
-       sd = p->subdevs[IDX_SENSOR];
+       sd = __fimc_md_get_subdev(vc->ve.pipe, IDX_SENSOR);
        if (sd)
                si = v4l2_get_subdev_hostdata(sd);
 
@@ -1259,14 +1247,15 @@ static int fimc_cap_streamoff(struct file *file, void *priv,
                            enum v4l2_buf_type type)
 {
        struct fimc_dev *fimc = video_drvdata(file);
+       struct fimc_vid_cap *vc = &fimc->vid_cap;
        int ret;
 
        ret = vb2_ioctl_streamoff(file, priv, type);
        if (ret < 0)
                return ret;
 
-       media_entity_pipeline_stop(&fimc->vid_cap.vfd.entity);
-       fimc->vid_cap.streaming = false;
+       media_entity_pipeline_stop(&vc->ve.vdev.entity);
+       vc->streaming = false;
        return 0;
 }
 
@@ -1405,6 +1394,8 @@ static int fimc_link_setup(struct media_entity *entity,
 {
        struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
        struct fimc_dev *fimc = v4l2_get_subdevdata(sd);
+       struct fimc_vid_cap *vc = &fimc->vid_cap;
+       struct v4l2_subdev *sensor;
 
        if (media_entity_type(remote->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
                return -EINVAL;
@@ -1416,15 +1407,26 @@ static int fimc_link_setup(struct media_entity *entity,
            local->entity->name, remote->entity->name, flags,
            fimc->vid_cap.input);
 
-       if (flags & MEDIA_LNK_FL_ENABLED) {
-               if (fimc->vid_cap.input != 0)
-                       return -EBUSY;
-               fimc->vid_cap.input = sd->grp_id;
+       if (!(flags & MEDIA_LNK_FL_ENABLED)) {
+               fimc->vid_cap.input = 0;
                return 0;
        }
 
-       fimc->vid_cap.input = 0;
-       return 0;
+       if (vc->input != 0)
+               return -EBUSY;
+
+       vc->input = sd->grp_id;
+
+       if (vc->user_subdev_api || vc->inh_sensor_ctrls)
+               return 0;
+
+       /* Inherit V4L2 controls from the image sensor subdev. */
+       sensor = fimc_find_remote_sensor(&vc->subdev.entity);
+       if (sensor == NULL)
+               return 0;
+
+       return v4l2_ctrl_add_handler(&vc->ctx->ctrls.handler,
+                                    sensor->ctrl_handler, NULL);
 }
 
 static const struct media_entity_operations fimc_sd_media_ops = {
@@ -1720,8 +1722,8 @@ static int fimc_capture_set_default_format(struct fimc_dev *fimc)
        struct v4l2_format fmt = {
                .type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
                .fmt.pix_mp = {
-                       .width          = 640,
-                       .height         = 480,
+                       .width          = FIMC_DEFAULT_WIDTH,
+                       .height         = FIMC_DEFAULT_HEIGHT,
                        .pixelformat    = V4L2_PIX_FMT_YUYV,
                        .field          = V4L2_FIELD_NONE,
                        .colorspace     = V4L2_COLORSPACE_JPEG,
@@ -1735,10 +1737,11 @@ static int fimc_capture_set_default_format(struct fimc_dev *fimc)
 static int fimc_register_capture_device(struct fimc_dev *fimc,
                                 struct v4l2_device *v4l2_dev)
 {
-       struct video_device *vfd = &fimc->vid_cap.vfd;
+       struct video_device *vfd = &fimc->vid_cap.ve.vdev;
        struct vb2_queue *q = &fimc->vid_cap.vbq;
        struct fimc_ctx *ctx;
        struct fimc_vid_cap *vid_cap;
+       struct fimc_fmt *fmt;
        int ret = -ENOMEM;
 
        ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
@@ -1784,22 +1787,34 @@ static int fimc_register_capture_device(struct fimc_dev *fimc,
 
        ret = vb2_queue_init(q);
        if (ret)
-               goto err_ent;
+               goto err_free_ctx;
+
+       /* Default format configuration */
+       fmt = fimc_find_format(NULL, NULL, FMT_FLAGS_CAM, 0);
+       vid_cap->ci_fmt.width = FIMC_DEFAULT_WIDTH;
+       vid_cap->ci_fmt.height = FIMC_DEFAULT_HEIGHT;
+       vid_cap->ci_fmt.code = fmt->mbus_code;
+
+       ctx->s_frame.width = FIMC_DEFAULT_WIDTH;
+       ctx->s_frame.height = FIMC_DEFAULT_HEIGHT;
+       ctx->s_frame.fmt = fmt;
+
+       fmt = fimc_find_format(NULL, NULL, FMT_FLAGS_WRITEBACK, 0);
+       vid_cap->wb_fmt = vid_cap->ci_fmt;
+       vid_cap->wb_fmt.code = fmt->mbus_code;
 
        vid_cap->vd_pad.flags = MEDIA_PAD_FL_SINK;
        ret = media_entity_init(&vfd->entity, 1, &vid_cap->vd_pad, 0);
        if (ret)
-               goto err_ent;
-       /*
-        * For proper order of acquiring/releasing the video
-        * and the graph mutex.
-        */
-       v4l2_disable_ioctl_locking(vfd, VIDIOC_TRY_FMT);
-       v4l2_disable_ioctl_locking(vfd, VIDIOC_S_FMT);
+               goto err_free_ctx;
+
+       ret = fimc_ctrls_create(ctx);
+       if (ret)
+               goto err_me_cleanup;
 
        ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1);
        if (ret)
-               goto err_vd;
+               goto err_ctrl_free;
 
        v4l2_info(v4l2_dev, "Registered %s as /dev/%s\n",
                  vfd->name, video_device_node_name(vfd));
@@ -1807,9 +1822,11 @@ static int fimc_register_capture_device(struct fimc_dev *fimc,
        vfd->ctrl_handler = &ctx->ctrls.handler;
        return 0;
 
-err_vd:
+err_ctrl_free:
+       fimc_ctrls_delete(ctx);
+err_me_cleanup:
        media_entity_cleanup(&vfd->entity);
-err_ent:
+err_free_ctx:
        kfree(ctx);
        return ret;
 }
@@ -1826,12 +1843,12 @@ static int fimc_capture_subdev_registered(struct v4l2_subdev *sd)
        if (ret)
                return ret;
 
-       fimc->pipeline_ops = v4l2_get_subdev_hostdata(sd);
+       fimc->vid_cap.ve.pipe = v4l2_get_subdev_hostdata(sd);
 
        ret = fimc_register_capture_device(fimc, sd->v4l2_dev);
        if (ret) {
                fimc_unregister_m2m_device(fimc);
-               fimc->pipeline_ops = NULL;
+               fimc->vid_cap.ve.pipe = NULL;
        }
 
        return ret;
@@ -1840,19 +1857,26 @@ static int fimc_capture_subdev_registered(struct v4l2_subdev *sd)
 static void fimc_capture_subdev_unregistered(struct v4l2_subdev *sd)
 {
        struct fimc_dev *fimc = v4l2_get_subdevdata(sd);
+       struct video_device *vdev;
 
        if (fimc == NULL)
                return;
 
+       mutex_lock(&fimc->lock);
+
        fimc_unregister_m2m_device(fimc);
+       vdev = &fimc->vid_cap.ve.vdev;
 
-       if (video_is_registered(&fimc->vid_cap.vfd)) {
-               video_unregister_device(&fimc->vid_cap.vfd);
-               media_entity_cleanup(&fimc->vid_cap.vfd.entity);
-               fimc->pipeline_ops = NULL;
+       if (video_is_registered(vdev)) {
+               video_unregister_device(vdev);
+               media_entity_cleanup(&vdev->entity);
+               fimc_ctrls_delete(fimc->vid_cap.ctx);
+               fimc->vid_cap.ve.pipe = NULL;
        }
        kfree(fimc->vid_cap.ctx);
        fimc->vid_cap.ctx = NULL;
+
+       mutex_unlock(&fimc->lock);
 }
 
 static const struct v4l2_subdev_internal_ops fimc_capture_sd_internal_ops = {
index 379a5e9..6489c51 100644 (file)
@@ -213,17 +213,6 @@ struct fimc_fmt *fimc_get_format(unsigned int index)
        return &fimc_formats[index];
 }
 
-void __fimc_vidioc_querycap(struct device *dev, struct v4l2_capability *cap,
-                                               unsigned int caps)
-{
-       strlcpy(cap->driver, dev->driver->name, sizeof(cap->driver));
-       strlcpy(cap->card, dev->driver->name, sizeof(cap->card));
-       snprintf(cap->bus_info, sizeof(cap->bus_info),
-                               "platform:%s", dev_name(dev));
-       cap->device_caps = caps;
-       cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
-}
-
 int fimc_check_scaler_ratio(struct fimc_ctx *ctx, int sw, int sh,
                            int dw, int dh, int rotation)
 {
index 539a3f7..3d376fa 100644 (file)
@@ -48,6 +48,8 @@
 #define FIMC_DEF_MIN_SIZE      16
 #define FIMC_DEF_HEIGHT_ALIGN  2
 #define FIMC_DEF_HOR_OFFS_ALIGN        1
+#define FIMC_DEFAULT_WIDTH     640
+#define FIMC_DEFAULT_HEIGHT    480
 
 /* indices to the clocks array */
 enum {
@@ -283,8 +285,8 @@ struct fimc_m2m_device {
 /**
  * struct fimc_vid_cap - camera capture device information
  * @ctx: hardware context data
- * @vfd: video device node for camera capture mode
  * @subdev: subdev exposing the FIMC processing block
+ * @ve: exynos video device entity structure
  * @vd_pad: fimc video capture node pad
  * @sd_pads: fimc video processing block pads
  * @ci_fmt: image format at the FIMC camera input (and the scaler output)
@@ -298,15 +300,16 @@ struct fimc_m2m_device {
  * @frame_count: the frame counter for statistics
  * @reqbufs_count: the number of buffers requested in REQBUFS ioctl
  * @input_index: input (camera sensor) index
- * @refcnt: driver's private reference counter
  * @input: capture input type, grp_id of the attached subdev
  * @user_subdev_api: true if subdevs are not configured by the host driver
+ * @inh_sensor_ctrls: a flag indicating v4l2 controls are inherited from
+ *                   an image sensor subdev
  */
 struct fimc_vid_cap {
        struct fimc_ctx                 *ctx;
        struct vb2_alloc_ctx            *alloc_ctx;
-       struct video_device             vfd;
        struct v4l2_subdev              subdev;
+       struct exynos_video_entity      ve;
        struct media_pad                vd_pad;
        struct media_pad                sd_pads[FIMC_SD_PADS_NUM];
        struct v4l2_mbus_framefmt       ci_fmt;
@@ -321,9 +324,9 @@ struct fimc_vid_cap {
        unsigned int                    reqbufs_count;
        bool                            streaming;
        int                             input_index;
-       int                             refcnt;
        u32                             input;
        bool                            user_subdev_api;
+       bool                            inh_sensor_ctrls;
 };
 
 /**
@@ -434,8 +437,6 @@ struct fimc_dev {
        struct fimc_vid_cap             vid_cap;
        unsigned long                   state;
        struct vb2_alloc_ctx            *alloc_ctx;
-       struct fimc_pipeline            pipeline;
-       const struct fimc_pipeline_ops  *pipeline_ops;
 };
 
 /**
@@ -620,8 +621,6 @@ static inline struct fimc_frame *ctx_get_frame(struct fimc_ctx *ctx,
 /* fimc-core.c */
 int fimc_vidioc_enum_fmt_mplane(struct file *file, void *priv,
                                struct v4l2_fmtdesc *f);
-void __fimc_vidioc_querycap(struct device *dev, struct v4l2_capability *cap,
-                                               unsigned int caps);
 int fimc_ctrls_create(struct fimc_ctx *ctx);
 void fimc_ctrls_delete(struct fimc_ctx *ctx);
 void fimc_ctrls_activate(struct fimc_ctx *ctx, bool active);
index c397777..617a798 100644 (file)
@@ -96,7 +96,7 @@ static int fimc_is_i2c_resume(struct device *dev)
        return clk_prepare_enable(isp_i2c->clock);
 }
 
-UNIVERSAL_DEV_PM_OPS(fimc_is_i2c_pm_ops, fimc_is_i2c_suspend,
+static UNIVERSAL_DEV_PM_OPS(fimc_is_i2c_pm_ops, fimc_is_i2c_suspend,
                     fimc_is_i2c_resume, NULL);
 
 static const struct of_device_id fimc_is_i2c_of_match[] = {
index 53fe2a2..c7e7f69 100644 (file)
@@ -38,7 +38,7 @@ static void __hw_param_copy(void *dst, void *src)
        memcpy(dst, src, FIMC_IS_PARAM_MAX_SIZE);
 }
 
-void __fimc_is_hw_update_param_global_shotmode(struct fimc_is *is)
+static void __fimc_is_hw_update_param_global_shotmode(struct fimc_is *is)
 {
        struct param_global_shotmode *dst, *src;
 
@@ -47,7 +47,7 @@ void __fimc_is_hw_update_param_global_shotmode(struct fimc_is *is)
        __hw_param_copy(dst, src);
 }
 
-void __fimc_is_hw_update_param_sensor_framerate(struct fimc_is *is)
+static void __fimc_is_hw_update_param_sensor_framerate(struct fimc_is *is)
 {
        struct param_sensor_framerate *dst, *src;
 
@@ -168,8 +168,8 @@ unsigned int __get_pending_param_count(struct fimc_is *is)
        unsigned int count;
 
        spin_lock_irqsave(&is->slock, flags);
-       count = hweight32(config->p_region_index1);
-       count += hweight32(config->p_region_index2);
+       count = hweight32(config->p_region_index[0]);
+       count += hweight32(config->p_region_index[1]);
        spin_unlock_irqrestore(&is->slock, flags);
 
        return count;
@@ -177,31 +177,30 @@ unsigned int __get_pending_param_count(struct fimc_is *is)
 
 int __is_hw_update_params(struct fimc_is *is)
 {
-       unsigned long *p_index1, *p_index2;
+       unsigned long *p_index;
        int i, id, ret = 0;
 
        id = is->config_index;
-       p_index1 = &is->config[id].p_region_index1;
-       p_index2 = &is->config[id].p_region_index2;
+       p_index = &is->config[id].p_region_index[0];
 
-       if (test_bit(PARAM_GLOBAL_SHOTMODE, p_index1))
+       if (test_bit(PARAM_GLOBAL_SHOTMODE, p_index))
                __fimc_is_hw_update_param_global_shotmode(is);
 
-       if (test_bit(PARAM_SENSOR_FRAME_RATE, p_index1))
+       if (test_bit(PARAM_SENSOR_FRAME_RATE, p_index))
                __fimc_is_hw_update_param_sensor_framerate(is);
 
        for (i = PARAM_ISP_CONTROL; i < PARAM_DRC_CONTROL; i++) {
-               if (test_bit(i, p_index1))
+               if (test_bit(i, p_index))
                        ret = __fimc_is_hw_update_param(is, i);
        }
 
        for (i = PARAM_DRC_CONTROL; i < PARAM_SCALERC_CONTROL; i++) {
-               if (test_bit(i, p_index1))
+               if (test_bit(i, p_index))
                        ret = __fimc_is_hw_update_param(is, i);
        }
 
        for (i = PARAM_FD_CONTROL; i <= PARAM_FD_CONFIG; i++) {
-               if (test_bit((i - 32), p_index2))
+               if (test_bit(i, p_index))
                        ret = __fimc_is_hw_update_param(is, i);
        }
 
@@ -243,7 +242,7 @@ void __is_set_frame_size(struct fimc_is *is, struct v4l2_mbus_framefmt *mf)
        fd->otf_input.height = mf->height;
 
        if (test_bit(PARAM_ISP_OTF_INPUT,
-                     &is->config[index].p_region_index1))
+                     &is->config[index].p_region_index[0]))
                return;
 
        /* Update field */
@@ -368,7 +367,7 @@ void __is_set_isp_adjust(struct fimc_is *is, u32 cmd, u32 val)
        unsigned long *p_index;
        struct isp_param *isp;
 
-       p_index = &is->config[index].p_region_index1;
+       p_index = &is->config[index].p_region_index[0];
        isp = &is->config[index].isp;
 
        switch (cmd) {
@@ -415,7 +414,7 @@ void __is_set_isp_metering(struct fimc_is *is, u32 id, u32 val)
        struct isp_param *isp;
        unsigned long *p_index;
 
-       p_index = &is->config[index].p_region_index1;
+       p_index = &is->config[index].p_region_index[0];
        isp = &is->config[index].isp;
 
        switch (id) {
@@ -476,7 +475,7 @@ void __is_set_fd_control(struct fimc_is *is, u32 val)
        struct fd_param *fd;
        unsigned long *p_index;
 
-       p_index = &is->config[index].p_region_index2;
+       p_index = &is->config[index].p_region_index[1];
        fd = &is->config[index].fd;
 
        fd->control.cmd = val;
@@ -491,7 +490,7 @@ void __is_set_fd_config_maxface(struct fimc_is *is, u32 val)
        struct fd_param *fd;
        unsigned long *p_index;
 
-       p_index = &is->config[index].p_region_index2;
+       p_index = &is->config[index].p_region_index[1];
        fd = &is->config[index].fd;
 
        fd->config.max_number = val;
@@ -511,7 +510,7 @@ void __is_set_fd_config_rollangle(struct fimc_is *is, u32 val)
        struct fd_param *fd;
        unsigned long *p_index;
 
-       p_index = &is->config[index].p_region_index2;
+       p_index = &is->config[index].p_region_index[1];
        fd = &is->config[index].fd;
 
        fd->config.roll_angle = val;
@@ -531,7 +530,7 @@ void __is_set_fd_config_yawangle(struct fimc_is *is, u32 val)
        struct fd_param *fd;
        unsigned long *p_index;
 
-       p_index = &is->config[index].p_region_index2;
+       p_index = &is->config[index].p_region_index[1];
        fd = &is->config[index].fd;
 
        fd->config.yaw_angle = val;
@@ -551,7 +550,7 @@ void __is_set_fd_config_smilemode(struct fimc_is *is, u32 val)
        struct fd_param *fd;
        unsigned long *p_index;
 
-       p_index = &is->config[index].p_region_index2;
+       p_index = &is->config[index].p_region_index[1];
        fd = &is->config[index].fd;
 
        fd->config.smile_mode = val;
@@ -571,7 +570,7 @@ void __is_set_fd_config_blinkmode(struct fimc_is *is, u32 val)
        struct fd_param *fd;
        unsigned long *p_index;
 
-       p_index = &is->config[index].p_region_index2;
+       p_index = &is->config[index].p_region_index[1];
        fd = &is->config[index].fd;
 
        fd->config.blink_mode = val;
@@ -591,7 +590,7 @@ void __is_set_fd_config_eyedetect(struct fimc_is *is, u32 val)
        struct fd_param *fd;
        unsigned long *p_index;
 
-       p_index = &is->config[index].p_region_index2;
+       p_index = &is->config[index].p_region_index[1];
        fd = &is->config[index].fd;
 
        fd->config.eye_detect = val;
@@ -611,7 +610,7 @@ void __is_set_fd_config_mouthdetect(struct fimc_is *is, u32 val)
        struct fd_param *fd;
        unsigned long *p_index;
 
-       p_index = &is->config[index].p_region_index2;
+       p_index = &is->config[index].p_region_index[1];
        fd = &is->config[index].fd;
 
        fd->config.mouth_detect = val;
@@ -631,7 +630,7 @@ void __is_set_fd_config_orientation(struct fimc_is *is, u32 val)
        struct fd_param *fd;
        unsigned long *p_index;
 
-       p_index = &is->config[index].p_region_index2;
+       p_index = &is->config[index].p_region_index[1];
        fd = &is->config[index].fd;
 
        fd->config.orientation = val;
@@ -651,7 +650,7 @@ void __is_set_fd_config_orientation_val(struct fimc_is *is, u32 val)
        struct fd_param *fd;
        unsigned long *p_index;
 
-       p_index = &is->config[index].p_region_index2;
+       p_index = &is->config[index].p_region_index[1];
        fd = &is->config[index].fd;
 
        fd->config.orientation_value = val;
@@ -672,7 +671,7 @@ void fimc_is_set_initial_params(struct fimc_is *is)
        struct isp_param *isp;
        struct drc_param *drc;
        struct fd_param *fd;
-       unsigned long *p_index1, *p_index2;
+       unsigned long *p_index;
        unsigned int index;
 
        index = is->config_index;
@@ -681,8 +680,7 @@ void fimc_is_set_initial_params(struct fimc_is *is)
        isp = &is->config[index].isp;
        drc = &is->config[index].drc;
        fd = &is->config[index].fd;
-       p_index1 = &is->config[index].p_region_index1;
-       p_index2 = &is->config[index].p_region_index2;
+       p_index = &is->config[index].p_region_index[0];
 
        /* Global */
        global->shotmode.cmd = 1;
@@ -695,7 +693,7 @@ void fimc_is_set_initial_params(struct fimc_is *is)
        fimc_is_set_param_bit(is, PARAM_ISP_CONTROL);
 
        isp->otf_input.cmd = OTF_INPUT_COMMAND_ENABLE;
-       if (!test_bit(PARAM_ISP_OTF_INPUT, p_index1)) {
+       if (!test_bit(PARAM_ISP_OTF_INPUT, p_index)) {
                isp->otf_input.width = DEFAULT_PREVIEW_STILL_WIDTH;
                isp->otf_input.height = DEFAULT_PREVIEW_STILL_HEIGHT;
                fimc_is_set_param_bit(is, PARAM_ISP_OTF_INPUT);
@@ -738,20 +736,20 @@ void fimc_is_set_initial_params(struct fimc_is *is)
        isp->aa.target = ISP_AA_TARGET_AE | ISP_AA_TARGET_AWB;
        fimc_is_set_param_bit(is, PARAM_ISP_AA);
 
-       if (!test_bit(PARAM_ISP_FLASH, p_index1))
+       if (!test_bit(PARAM_ISP_FLASH, p_index))
                __is_set_isp_flash(is, ISP_FLASH_COMMAND_DISABLE,
                                                ISP_FLASH_REDEYE_DISABLE);
 
-       if (!test_bit(PARAM_ISP_AWB, p_index1))
+       if (!test_bit(PARAM_ISP_AWB, p_index))
                __is_set_isp_awb(is, ISP_AWB_COMMAND_AUTO, 0);
 
-       if (!test_bit(PARAM_ISP_IMAGE_EFFECT, p_index1))
+       if (!test_bit(PARAM_ISP_IMAGE_EFFECT, p_index))
                __is_set_isp_effect(is, ISP_IMAGE_EFFECT_DISABLE);
 
-       if (!test_bit(PARAM_ISP_ISO, p_index1))
+       if (!test_bit(PARAM_ISP_ISO, p_index))
                __is_set_isp_iso(is, ISP_ISO_COMMAND_AUTO, 0);
 
-       if (!test_bit(PARAM_ISP_ADJUST, p_index1)) {
+       if (!test_bit(PARAM_ISP_ADJUST, p_index)) {
                __is_set_isp_adjust(is, ISP_ADJUST_COMMAND_MANUAL_CONTRAST, 0);
                __is_set_isp_adjust(is,
                                ISP_ADJUST_COMMAND_MANUAL_SATURATION, 0);
@@ -762,7 +760,7 @@ void fimc_is_set_initial_params(struct fimc_is *is)
                __is_set_isp_adjust(is, ISP_ADJUST_COMMAND_MANUAL_HUE, 0);
        }
 
-       if (!test_bit(PARAM_ISP_METERING, p_index1)) {
+       if (!test_bit(PARAM_ISP_METERING, p_index)) {
                __is_set_isp_metering(is, 0, ISP_METERING_COMMAND_CENTER);
                __is_set_isp_metering(is, 1, 0);
                __is_set_isp_metering(is, 2, 0);
@@ -770,11 +768,11 @@ void fimc_is_set_initial_params(struct fimc_is *is)
                __is_set_isp_metering(is, 4, 0);
        }
 
-       if (!test_bit(PARAM_ISP_AFC, p_index1))
+       if (!test_bit(PARAM_ISP_AFC, p_index))
                __is_set_isp_afc(is, ISP_AFC_COMMAND_AUTO, 0);
 
        isp->otf_output.cmd = OTF_OUTPUT_COMMAND_ENABLE;
-       if (!test_bit(PARAM_ISP_OTF_OUTPUT, p_index1)) {
+       if (!test_bit(PARAM_ISP_OTF_OUTPUT, p_index)) {
                isp->otf_output.width = DEFAULT_PREVIEW_STILL_WIDTH;
                isp->otf_output.height = DEFAULT_PREVIEW_STILL_HEIGHT;
                fimc_is_set_param_bit(is, PARAM_ISP_OTF_OUTPUT);
@@ -784,7 +782,7 @@ void fimc_is_set_initial_params(struct fimc_is *is)
        isp->otf_output.order = 0;
        isp->otf_output.err = OTF_OUTPUT_ERROR_NONE;
 
-       if (!test_bit(PARAM_ISP_DMA1_OUTPUT, p_index1)) {
+       if (!test_bit(PARAM_ISP_DMA1_OUTPUT, p_index)) {
                isp->dma1_output.cmd = DMA_OUTPUT_COMMAND_DISABLE;
                isp->dma1_output.width = 0;
                isp->dma1_output.height = 0;
@@ -800,7 +798,7 @@ void fimc_is_set_initial_params(struct fimc_is *is)
                fimc_is_set_param_bit(is, PARAM_ISP_DMA1_OUTPUT);
        }
 
-       if (!test_bit(PARAM_ISP_DMA2_OUTPUT, p_index1)) {
+       if (!test_bit(PARAM_ISP_DMA2_OUTPUT, p_index)) {
                isp->dma2_output.cmd = DMA_OUTPUT_COMMAND_DISABLE;
                isp->dma2_output.width = 0;
                isp->dma2_output.height = 0;
@@ -817,7 +815,7 @@ void fimc_is_set_initial_params(struct fimc_is *is)
        }
 
        /* Sensor */
-       if (!test_bit(PARAM_SENSOR_FRAME_RATE, p_index1)) {
+       if (!test_bit(PARAM_SENSOR_FRAME_RATE, p_index)) {
                if (is->config_index == 0)
                        __is_set_sensor(is, 0);
        }
@@ -827,7 +825,7 @@ void fimc_is_set_initial_params(struct fimc_is *is)
        __is_set_drc_control(is, CONTROL_BYPASS_ENABLE);
 
        drc->otf_input.cmd = OTF_INPUT_COMMAND_ENABLE;
-       if (!test_bit(PARAM_DRC_OTF_INPUT, p_index1)) {
+       if (!test_bit(PARAM_DRC_OTF_INPUT, p_index)) {
                drc->otf_input.width = DEFAULT_PREVIEW_STILL_WIDTH;
                drc->otf_input.height = DEFAULT_PREVIEW_STILL_HEIGHT;
                fimc_is_set_param_bit(is, PARAM_DRC_OTF_INPUT);
@@ -850,7 +848,7 @@ void fimc_is_set_initial_params(struct fimc_is *is)
        fimc_is_set_param_bit(is, PARAM_DRC_DMA_INPUT);
 
        drc->otf_output.cmd = OTF_OUTPUT_COMMAND_ENABLE;
-       if (!test_bit(PARAM_DRC_OTF_OUTPUT, p_index1)) {
+       if (!test_bit(PARAM_DRC_OTF_OUTPUT, p_index)) {
                drc->otf_output.width = DEFAULT_PREVIEW_STILL_WIDTH;
                drc->otf_output.height = DEFAULT_PREVIEW_STILL_HEIGHT;
                fimc_is_set_param_bit(is, PARAM_DRC_OTF_OUTPUT);
@@ -865,7 +863,7 @@ void fimc_is_set_initial_params(struct fimc_is *is)
        fd->control.bypass = CONTROL_BYPASS_DISABLE;
 
        fd->otf_input.cmd = OTF_INPUT_COMMAND_ENABLE;
-       if (!test_bit((PARAM_FD_OTF_INPUT - 32), p_index2)) {
+       if (!test_bit(PARAM_FD_OTF_INPUT, p_index)) {
                fd->otf_input.width = DEFAULT_PREVIEW_STILL_WIDTH;
                fd->otf_input.height = DEFAULT_PREVIEW_STILL_HEIGHT;
                fimc_is_set_param_bit(is, PARAM_FD_OTF_INPUT);
index d05eaa2..63c68ec 100644 (file)
@@ -89,8 +89,8 @@ int fimc_is_hw_set_param(struct fimc_is *is)
        mcuctl_write(is->config_index, is, MCUCTL_REG_ISSR(2));
 
        mcuctl_write(param_count, is, MCUCTL_REG_ISSR(3));
-       mcuctl_write(config->p_region_index1, is, MCUCTL_REG_ISSR(4));
-       mcuctl_write(config->p_region_index2, is, MCUCTL_REG_ISSR(5));
+       mcuctl_write(config->p_region_index[0], is, MCUCTL_REG_ISSR(4));
+       mcuctl_write(config->p_region_index[1], is, MCUCTL_REG_ISSR(5));
 
        fimc_is_hw_set_intgr0_gd0(is);
        return 0;
index 0741945..967f6a9 100644 (file)
@@ -129,7 +129,7 @@ static int fimc_is_setup_clocks(struct fimc_is *is)
                                        ATCLK_MCUISP_FREQUENCY);
 }
 
-int fimc_is_enable_clocks(struct fimc_is *is)
+static int fimc_is_enable_clocks(struct fimc_is *is)
 {
        int i, ret;
 
@@ -149,7 +149,7 @@ int fimc_is_enable_clocks(struct fimc_is *is)
        return 0;
 }
 
-void fimc_is_disable_clocks(struct fimc_is *is)
+static void fimc_is_disable_clocks(struct fimc_is *is)
 {
        int i;
 
@@ -527,8 +527,8 @@ static void fimc_is_general_irq_handler(struct fimc_is *is)
                        break;
 
                case HIC_SET_PARAMETER:
-                       is->config[is->config_index].p_region_index1 = 0;
-                       is->config[is->config_index].p_region_index2 = 0;
+                       is->config[is->config_index].p_region_index[0] = 0;
+                       is->config[is->config_index].p_region_index[1] = 0;
                        set_bit(IS_ST_BLOCK_CMD_CLEARED, &is->state);
                        pr_debug("HIC_SET_PARAMETER\n");
                        break;
@@ -587,8 +587,8 @@ static void fimc_is_general_irq_handler(struct fimc_is *is)
 
                switch (is->i2h_cmd.args[0]) {
                case HIC_SET_PARAMETER:
-                       is->config[is->config_index].p_region_index1 = 0;
-                       is->config[is->config_index].p_region_index2 = 0;
+                       is->config[is->config_index].p_region_index[0] = 0;
+                       is->config[is->config_index].p_region_index[1] = 0;
                        set_bit(IS_ST_BLOCK_CMD_CLEARED, &is->state);
                        break;
                }
index d7db133..61bb012 100644 (file)
@@ -33,8 +33,8 @@
 
 #define FIMC_IS_DRV_NAME               "exynos4-fimc-is"
 
-#define FIMC_IS_FW_FILENAME            "fimc_is_fw.bin"
-#define FIMC_IS_SETFILE_6A3            "setfile.bin"
+#define FIMC_IS_FW_FILENAME            "exynos4_fimc_is_fw.bin"
+#define FIMC_IS_SETFILE_6A3            "exynos4_s5k6a3_setfile.bin"
 
 #define FIMC_IS_FW_LOAD_TIMEOUT                1000 /* ms */
 #define FIMC_IS_POWER_ON_TIMEOUT       1000 /* us */
@@ -225,8 +225,7 @@ struct chain_config {
        struct drc_param        drc;
        struct fd_param         fd;
 
-       unsigned long           p_region_index1;
-       unsigned long           p_region_index2;
+       unsigned long           p_region_index[2];
 };
 
 /**
@@ -302,10 +301,7 @@ static inline void fimc_is_set_param_bit(struct fimc_is *is, int num)
 {
        struct chain_config *cfg = &is->config[is->config_index];
 
-       if (num >= 32)
-               set_bit(num - 32, &cfg->p_region_index2);
-       else
-               set_bit(num, &cfg->p_region_index1);
+       set_bit(num, &cfg->p_region_index[0]);
 }
 
 static inline void fimc_is_set_param_ctrl_cmd(struct fimc_is *is, int cmd)
index 7ede30b..cf520a7 100644 (file)
@@ -30,8 +30,8 @@
 #include "fimc-is-regs.h"
 #include "fimc-is.h"
 
-static int debug;
-module_param_named(debug_isp, debug, int, S_IRUGO | S_IWUSR);
+int fimc_isp_debug;
+module_param_named(debug_isp, fimc_isp_debug, int, S_IRUGO | S_IWUSR);
 
 static const struct fimc_fmt fimc_isp_formats[FIMC_ISP_NUM_FORMATS] = {
        {
@@ -128,57 +128,70 @@ static int fimc_isp_subdev_get_fmt(struct v4l2_subdev *sd,
                                   struct v4l2_subdev_format *fmt)
 {
        struct fimc_isp *isp = v4l2_get_subdevdata(sd);
-       struct fimc_is *is = fimc_isp_to_is(isp);
        struct v4l2_mbus_framefmt *mf = &fmt->format;
-       struct v4l2_mbus_framefmt cur_fmt;
 
        if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
-               mf = v4l2_subdev_get_try_format(fh, fmt->pad);
-               fmt->format = *mf;
+               *mf = *v4l2_subdev_get_try_format(fh, fmt->pad);
                return 0;
        }
 
        mf->colorspace = V4L2_COLORSPACE_SRGB;
 
        mutex_lock(&isp->subdev_lock);
-       __is_get_frame_size(is, &cur_fmt);
 
        if (fmt->pad == FIMC_ISP_SD_PAD_SINK) {
-               /* full camera input frame size */
-               mf->width = cur_fmt.width + FIMC_ISP_CAC_MARGIN_WIDTH;
-               mf->height = cur_fmt.height + FIMC_ISP_CAC_MARGIN_HEIGHT;
-               mf->code = V4L2_MBUS_FMT_SGRBG10_1X10;
+               /* ISP OTF input image format */
+               *mf = isp->sink_fmt;
        } else {
-               /* crop size */
-               mf->width = cur_fmt.width;
-               mf->height = cur_fmt.height;
-               mf->code = V4L2_MBUS_FMT_YUV10_1X30;
+               /* ISP OTF output image format */
+               *mf = isp->src_fmt;
+
+               if (fmt->pad == FIMC_ISP_SD_PAD_SRC_FIFO) {
+                       mf->colorspace = V4L2_COLORSPACE_JPEG;
+                       mf->code = V4L2_MBUS_FMT_YUV10_1X30;
+               }
        }
 
        mutex_unlock(&isp->subdev_lock);
 
-       v4l2_dbg(1, debug, sd, "%s: pad%d: fmt: 0x%x, %dx%d\n",
-                __func__, fmt->pad, mf->code, mf->width, mf->height);
+       isp_dbg(1, sd, "%s: pad%d: fmt: 0x%x, %dx%d\n", __func__,
+               fmt->pad, mf->code, mf->width, mf->height);
 
        return 0;
 }
 
 static void __isp_subdev_try_format(struct fimc_isp *isp,
-                                  struct v4l2_subdev_format *fmt)
+                                   struct v4l2_subdev_fh *fh,
+                                   struct v4l2_subdev_format *fmt)
 {
        struct v4l2_mbus_framefmt *mf = &fmt->format;
+       struct v4l2_mbus_framefmt *format;
+
+       mf->colorspace = V4L2_COLORSPACE_SRGB;
 
        if (fmt->pad == FIMC_ISP_SD_PAD_SINK) {
                v4l_bound_align_image(&mf->width, FIMC_ISP_SINK_WIDTH_MIN,
                                FIMC_ISP_SINK_WIDTH_MAX, 0,
                                &mf->height, FIMC_ISP_SINK_HEIGHT_MIN,
                                FIMC_ISP_SINK_HEIGHT_MAX, 0, 0);
-               isp->subdev_fmt = *mf;
+               mf->code = V4L2_MBUS_FMT_SGRBG10_1X10;
        } else {
+               if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
+                       format = v4l2_subdev_get_try_format(fh,
+                                               FIMC_ISP_SD_PAD_SINK);
+               else
+                       format = &isp->sink_fmt;
+
                /* Allow changing format only on sink pad */
-               mf->width = isp->subdev_fmt.width - FIMC_ISP_CAC_MARGIN_WIDTH;
-               mf->height = isp->subdev_fmt.height - FIMC_ISP_CAC_MARGIN_HEIGHT;
-               mf->code = isp->subdev_fmt.code;
+               mf->width = format->width - FIMC_ISP_CAC_MARGIN_WIDTH;
+               mf->height = format->height - FIMC_ISP_CAC_MARGIN_HEIGHT;
+
+               if (fmt->pad == FIMC_ISP_SD_PAD_SRC_FIFO) {
+                       mf->code = V4L2_MBUS_FMT_YUV10_1X30;
+                       mf->colorspace = V4L2_COLORSPACE_JPEG;
+               } else {
+                       mf->code = format->code;
+               }
        }
 }
 
@@ -191,27 +204,50 @@ static int fimc_isp_subdev_set_fmt(struct v4l2_subdev *sd,
        struct v4l2_mbus_framefmt *mf = &fmt->format;
        int ret = 0;
 
-       v4l2_dbg(1, debug, sd, "%s: pad%d: code: 0x%x, %dx%d\n",
+       isp_dbg(1, sd, "%s: pad%d: code: 0x%x, %dx%d\n",
                 __func__, fmt->pad, mf->code, mf->width, mf->height);
 
-       mf->colorspace = V4L2_COLORSPACE_SRGB;
-
        mutex_lock(&isp->subdev_lock);
-       __isp_subdev_try_format(isp, fmt);
+       __isp_subdev_try_format(isp, fh, fmt);
 
        if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
                mf = v4l2_subdev_get_try_format(fh, fmt->pad);
                *mf = fmt->format;
-               mutex_unlock(&isp->subdev_lock);
-               return 0;
+
+               /* Propagate format to the source pads */
+               if (fmt->pad == FIMC_ISP_SD_PAD_SINK) {
+                       struct v4l2_subdev_format format = *fmt;
+                       unsigned int pad;
+
+                       for (pad = FIMC_ISP_SD_PAD_SRC_FIFO;
+                                       pad < FIMC_ISP_SD_PADS_NUM; pad++) {
+                               format.pad = pad;
+                               __isp_subdev_try_format(isp, fh, &format);
+                               mf = v4l2_subdev_get_try_format(fh, pad);
+                               *mf = format.format;
+                       }
+               }
+       } else {
+               if (sd->entity.stream_count == 0) {
+                       if (fmt->pad == FIMC_ISP_SD_PAD_SINK) {
+                               struct v4l2_subdev_format format = *fmt;
+
+                               isp->sink_fmt = *mf;
+
+                               format.pad = FIMC_ISP_SD_PAD_SRC_DMA;
+                               __isp_subdev_try_format(isp, fh, &format);
+
+                               isp->src_fmt = format.format;
+                               __is_set_frame_size(is, &isp->src_fmt);
+                       } else {
+                               isp->src_fmt = *mf;
+                       }
+               } else {
+                       ret = -EBUSY;
+               }
        }
 
-       if (sd->entity.stream_count == 0)
-               __is_set_frame_size(is, mf);
-       else
-               ret = -EBUSY;
        mutex_unlock(&isp->subdev_lock);
-
        return ret;
 }
 
@@ -221,7 +257,7 @@ static int fimc_isp_subdev_s_stream(struct v4l2_subdev *sd, int on)
        struct fimc_is *is = fimc_isp_to_is(isp);
        int ret;
 
-       v4l2_dbg(1, debug, sd, "%s: on: %d\n", __func__, on);
+       isp_dbg(1, sd, "%s: on: %d\n", __func__, on);
 
        if (!test_bit(IS_ST_INIT_DONE, &is->state))
                return -EBUSY;
@@ -235,8 +271,8 @@ static int fimc_isp_subdev_s_stream(struct v4l2_subdev *sd, int on)
                                return ret;
                }
 
-               v4l2_dbg(1, debug, sd, "changing mode to %d\n",
-                                               is->config_index);
+               isp_dbg(1, sd, "changing mode to %d\n", is->config_index);
+
                ret = fimc_is_itf_mode_change(is);
                if (ret)
                        return -EINVAL;
@@ -317,8 +353,8 @@ static int fimc_isp_subdev_s_power(struct v4l2_subdev *sd, int on)
                clear_bit(IS_ST_PWR_ON, &is->state);
                clear_bit(IS_ST_INIT_DONE, &is->state);
                is->state = 0;
-               is->config[is->config_index].p_region_index1 = 0;
-               is->config[is->config_index].p_region_index2 = 0;
+               is->config[is->config_index].p_region_index[0] = 0;
+               is->config[is->config_index].p_region_index[1] = 0;
                set_bit(IS_ST_IDLE, &is->state);
                wmb();
        }
@@ -609,6 +645,22 @@ static const struct v4l2_ctrl_ops fimc_isp_ctrl_ops = {
        .s_ctrl = fimc_is_s_ctrl,
 };
 
+static void __isp_subdev_set_default_format(struct fimc_isp *isp)
+{
+       struct fimc_is *is = fimc_isp_to_is(isp);
+
+       isp->sink_fmt.width = DEFAULT_PREVIEW_STILL_WIDTH +
+                               FIMC_ISP_CAC_MARGIN_WIDTH;
+       isp->sink_fmt.height = DEFAULT_PREVIEW_STILL_HEIGHT +
+                               FIMC_ISP_CAC_MARGIN_HEIGHT;
+       isp->sink_fmt.code = V4L2_MBUS_FMT_SGRBG10_1X10;
+
+       isp->src_fmt.width = DEFAULT_PREVIEW_STILL_WIDTH;
+       isp->src_fmt.height = DEFAULT_PREVIEW_STILL_HEIGHT;
+       isp->src_fmt.code = V4L2_MBUS_FMT_SGRBG10_1X10;
+       __is_set_frame_size(is, &isp->src_fmt);
+}
+
 int fimc_isp_subdev_create(struct fimc_isp *isp)
 {
        const struct v4l2_ctrl_ops *ops = &fimc_isp_ctrl_ops;
@@ -689,6 +741,8 @@ int fimc_isp_subdev_create(struct fimc_isp *isp)
        sd->entity.ops = &fimc_is_subdev_media_ops;
        v4l2_set_subdevdata(sd, isp);
 
+       __isp_subdev_set_default_format(isp);
+
        return 0;
 }
 
index 800aba7..03bf95a 100644 (file)
 #include <media/v4l2-mediabus.h>
 #include <media/s5p_fimc.h>
 
+extern int fimc_isp_debug;
+
+#define isp_dbg(level, dev, fmt, arg...) \
+       v4l2_dbg(level, fimc_isp_debug, dev, fmt, ## arg)
+
 /* FIXME: revisit these constraints */
 #define FIMC_ISP_SINK_WIDTH_MIN                (16 + 8)
 #define FIMC_ISP_SINK_HEIGHT_MIN       (12 + 8)
@@ -118,7 +123,6 @@ struct fimc_is_video {
        unsigned int            frame_count;
        unsigned int            reqbufs_count;
        int                     streaming;
-       unsigned long           payload[FIMC_ISP_MAX_PLANES];
        const struct fimc_fmt   *format;
 };
 
@@ -128,15 +132,9 @@ struct fimc_is_video {
  * @alloc_ctx: videobuf2 memory allocator context
  * @subdev: ISP v4l2_subdev
  * @subdev_pads: the ISP subdev media pads
- * @ctrl_handler: v4l2 controls handler
  * @test_pattern: test pattern controls
- * @pipeline: video capture pipeline data structure
+ * @ctrls: v4l2 controls structure
  * @video_lock: mutex serializing video device and the subdev operations
- * @fmt: pointer to color format description structure
- * @payload: image size in bytes (w x h x bpp)
- * @inp_frame: camera input frame structure
- * @out_frame: DMA output frame structure
- * @source_subdev_grp_id: group id of remote source subdev
  * @cac_margin_x: horizontal CAC margin in pixels
  * @cac_margin_y: vertical CAC margin in pixels
  * @state: driver state flags
@@ -147,17 +145,14 @@ struct fimc_isp {
        struct vb2_alloc_ctx            *alloc_ctx;
        struct v4l2_subdev              subdev;
        struct media_pad                subdev_pads[FIMC_ISP_SD_PADS_NUM];
-       struct v4l2_mbus_framefmt       subdev_fmt;
+       struct v4l2_mbus_framefmt       src_fmt;
+       struct v4l2_mbus_framefmt       sink_fmt;
        struct v4l2_ctrl                *test_pattern;
        struct fimc_isp_ctrls           ctrls;
 
        struct mutex                    video_lock;
        struct mutex                    subdev_lock;
 
-       struct fimc_isp_frame           inp_frame;
-       struct fimc_isp_frame           out_frame;
-       unsigned int                    source_subdev_grp_id;
-
        unsigned int                    cac_margin_x;
        unsigned int                    cac_margin_y;
 
index 8cc0d39..72a343e 100644 (file)
@@ -2,15 +2,16 @@
  * Register interface file for EXYNOS FIMC-LITE (camera interface) driver
  *
  * Copyright (C) 2012 Samsung Electronics Co., Ltd.
- * Sylwester Nawrocki <s.nawrocki@samsung.com>
+ * Author: Sylwester Nawrocki <s.nawrocki@samsung.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
 */
 
-#include <linux/io.h>
+#include <linux/bitops.h>
 #include <linux/delay.h>
+#include <linux/io.h>
 #include <media/s5p_fimc.h>
 
 #include "fimc-lite-reg.h"
@@ -68,7 +69,8 @@ void flite_hw_set_interrupt_mask(struct fimc_lite *dev)
        if (atomic_read(&dev->out_path) == FIMC_IO_DMA) {
                intsrc = FLITE_REG_CIGCTRL_IRQ_OVFEN |
                         FLITE_REG_CIGCTRL_IRQ_LASTEN |
-                        FLITE_REG_CIGCTRL_IRQ_STARTEN;
+                        FLITE_REG_CIGCTRL_IRQ_STARTEN |
+                        FLITE_REG_CIGCTRL_IRQ_ENDEN;
        } else {
                /* An output to the FIMC-IS */
                intsrc = FLITE_REG_CIGCTRL_IRQ_OVFEN |
@@ -137,7 +139,7 @@ void flite_hw_set_source_format(struct fimc_lite *dev, struct flite_frame *f)
        }
 
        if (i == 0 && src_pixfmt_map[i][0] != pixelcode) {
-               v4l2_err(&dev->vfd,
+               v4l2_err(&dev->ve.vdev,
                         "Unsupported pixel code, falling back to %#08x\n",
                         src_pixfmt_map[i][0]);
        }
@@ -215,6 +217,18 @@ void flite_hw_set_camera_bus(struct fimc_lite *dev,
        flite_hw_set_camera_port(dev, si->mux_id);
 }
 
+static void flite_hw_set_pack12(struct fimc_lite *dev, int on)
+{
+       u32 cfg = readl(dev->regs + FLITE_REG_CIODMAFMT);
+
+       cfg &= ~FLITE_REG_CIODMAFMT_PACK12;
+
+       if (on)
+               cfg |= FLITE_REG_CIODMAFMT_PACK12;
+
+       writel(cfg, dev->regs + FLITE_REG_CIODMAFMT);
+}
+
 static void flite_hw_set_out_order(struct fimc_lite *dev, struct flite_frame *f)
 {
        static const u32 pixcode[4][2] = {
@@ -250,6 +264,38 @@ void flite_hw_set_dma_window(struct fimc_lite *dev, struct flite_frame *f)
        writel(cfg, dev->regs + FLITE_REG_CIOOFF);
 }
 
+void flite_hw_set_dma_buffer(struct fimc_lite *dev, struct flite_buffer *buf)
+{
+       unsigned int index;
+       u32 cfg;
+
+       if (dev->dd->max_dma_bufs == 1)
+               index = 0;
+       else
+               index = buf->index;
+
+       if (index == 0)
+               writel(buf->paddr, dev->regs + FLITE_REG_CIOSA);
+       else
+               writel(buf->paddr, dev->regs + FLITE_REG_CIOSAN(index - 1));
+
+       cfg = readl(dev->regs + FLITE_REG_CIFCNTSEQ);
+       cfg |= BIT(index);
+       writel(cfg, dev->regs + FLITE_REG_CIFCNTSEQ);
+}
+
+void flite_hw_mask_dma_buffer(struct fimc_lite *dev, u32 index)
+{
+       u32 cfg;
+
+       if (dev->dd->max_dma_bufs == 1)
+               index = 0;
+
+       cfg = readl(dev->regs + FLITE_REG_CIFCNTSEQ);
+       cfg &= ~BIT(index);
+       writel(cfg, dev->regs + FLITE_REG_CIFCNTSEQ);
+}
+
 /* Enable/disable output DMA, set output pixel size and offsets (composition) */
 void flite_hw_set_output_dma(struct fimc_lite *dev, struct flite_frame *f,
                             bool enable)
@@ -267,6 +313,7 @@ void flite_hw_set_output_dma(struct fimc_lite *dev, struct flite_frame *f,
 
        flite_hw_set_out_order(dev, f);
        flite_hw_set_dma_window(dev, f);
+       flite_hw_set_pack12(dev, 0);
 }
 
 void flite_hw_dump_regs(struct fimc_lite *dev, const char *label)
index 3903839..10a7d7b 100644 (file)
 /* b0: 1 - camera B, 0 - camera A */
 #define FLITE_REG_CIGENERAL_CAM_B              (1 << 0)
 
+#define FLITE_REG_CIFCNTSEQ                    0x100
+#define FLITE_REG_CIOSAN(x)                    (0x200 + (4 * (x)))
+
 /* ----------------------------------------------------------------------------
  * Function declarations
  */
@@ -142,9 +145,12 @@ void flite_hw_set_output_dma(struct fimc_lite *dev, struct flite_frame *f,
 void flite_hw_set_dma_window(struct fimc_lite *dev, struct flite_frame *f);
 void flite_hw_set_test_pattern(struct fimc_lite *dev, bool on);
 void flite_hw_dump_regs(struct fimc_lite *dev, const char *label);
+void flite_hw_set_dma_buffer(struct fimc_lite *dev, struct flite_buffer *buf);
+void flite_hw_mask_dma_buffer(struct fimc_lite *dev, u32 index);
 
-static inline void flite_hw_set_output_addr(struct fimc_lite *dev, u32 paddr)
+static inline void flite_hw_set_dma_buf_mask(struct fimc_lite *dev, u32 mask)
 {
-       writel(paddr, dev->regs + FLITE_REG_CIOSA);
+       writel(mask, dev->regs + FLITE_REG_CIFCNTSEQ);
 }
+
 #endif /* FIMC_LITE_REG_H */
index 14bb7bc..08fbfed 100644 (file)
@@ -1,8 +1,8 @@
 /*
  * Samsung EXYNOS FIMC-LITE (camera host interface) driver
 *
- * Copyright (C) 2012 Samsung Electronics Co., Ltd.
- * Sylwester Nawrocki <s.nawrocki@samsung.com>
+ * Copyright (C) 2012 - 2013 Samsung Electronics Co., Ltd.
+ * Author: Sylwester Nawrocki <s.nawrocki@samsung.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -32,6 +32,7 @@
 #include <media/videobuf2-dma-contig.h>
 #include <media/s5p_fimc.h>
 
+#include "common.h"
 #include "fimc-core.h"
 #include "fimc-lite.h"
 #include "fimc-lite-reg.h"
@@ -43,6 +44,7 @@ static const struct fimc_fmt fimc_lite_formats[] = {
        {
                .name           = "YUV 4:2:2 packed, YCbYCr",
                .fourcc         = V4L2_PIX_FMT_YUYV,
+               .colorspace     = V4L2_COLORSPACE_JPEG,
                .depth          = { 16 },
                .color          = FIMC_FMT_YCBYCR422,
                .memplanes      = 1,
@@ -51,6 +53,7 @@ static const struct fimc_fmt fimc_lite_formats[] = {
        }, {
                .name           = "YUV 4:2:2 packed, CbYCrY",
                .fourcc         = V4L2_PIX_FMT_UYVY,
+               .colorspace     = V4L2_COLORSPACE_JPEG,
                .depth          = { 16 },
                .color          = FIMC_FMT_CBYCRY422,
                .memplanes      = 1,
@@ -59,6 +62,7 @@ static const struct fimc_fmt fimc_lite_formats[] = {
        }, {
                .name           = "YUV 4:2:2 packed, CrYCbY",
                .fourcc         = V4L2_PIX_FMT_VYUY,
+               .colorspace     = V4L2_COLORSPACE_JPEG,
                .depth          = { 16 },
                .color          = FIMC_FMT_CRYCBY422,
                .memplanes      = 1,
@@ -67,6 +71,7 @@ static const struct fimc_fmt fimc_lite_formats[] = {
        }, {
                .name           = "YUV 4:2:2 packed, YCrYCb",
                .fourcc         = V4L2_PIX_FMT_YVYU,
+               .colorspace     = V4L2_COLORSPACE_JPEG,
                .depth          = { 16 },
                .color          = FIMC_FMT_YCRYCB422,
                .memplanes      = 1,
@@ -75,6 +80,7 @@ static const struct fimc_fmt fimc_lite_formats[] = {
        }, {
                .name           = "RAW8 (GRBG)",
                .fourcc         = V4L2_PIX_FMT_SGRBG8,
+               .colorspace     = V4L2_COLORSPACE_SRGB,
                .depth          = { 8 },
                .color          = FIMC_FMT_RAW8,
                .memplanes      = 1,
@@ -83,6 +89,7 @@ static const struct fimc_fmt fimc_lite_formats[] = {
        }, {
                .name           = "RAW10 (GRBG)",
                .fourcc         = V4L2_PIX_FMT_SGRBG10,
+               .colorspace     = V4L2_COLORSPACE_SRGB,
                .depth          = { 10 },
                .color          = FIMC_FMT_RAW10,
                .memplanes      = 1,
@@ -91,6 +98,7 @@ static const struct fimc_fmt fimc_lite_formats[] = {
        }, {
                .name           = "RAW12 (GRBG)",
                .fourcc         = V4L2_PIX_FMT_SGRBG12,
+               .colorspace     = V4L2_COLORSPACE_SRGB,
                .depth          = { 12 },
                .color          = FIMC_FMT_RAW12,
                .memplanes      = 1,
@@ -131,30 +139,6 @@ static const struct fimc_fmt *fimc_lite_find_format(const u32 *pixelformat,
        return def_fmt;
 }
 
-/* Called with the media graph mutex held or @me stream_count > 0. */
-static struct v4l2_subdev *__find_remote_sensor(struct media_entity *me)
-{
-       struct media_pad *pad = &me->pads[0];
-       struct v4l2_subdev *sd;
-
-       while (pad->flags & MEDIA_PAD_FL_SINK) {
-               /* source pad */
-               pad = media_entity_remote_source(pad);
-               if (pad == NULL ||
-                   media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
-                       break;
-
-               sd = media_entity_to_v4l2_subdev(pad->entity);
-
-               if (sd->grp_id == GRP_ID_FIMC_IS_SENSOR ||
-                   sd->grp_id == GRP_ID_SENSOR)
-                       return sd;
-               /* sink pad */
-               pad = &sd->entity.pads[0];
-       }
-       return NULL;
-}
-
 static int fimc_lite_hw_init(struct fimc_lite *fimc, bool isp_output)
 {
        struct fimc_source_info *si;
@@ -176,6 +160,7 @@ static int fimc_lite_hw_init(struct fimc_lite *fimc, bool isp_output)
        flite_hw_set_camera_bus(fimc, si);
        flite_hw_set_source_format(fimc, &fimc->inp_frame);
        flite_hw_set_window_offset(fimc, &fimc->inp_frame);
+       flite_hw_set_dma_buf_mask(fimc, 0);
        flite_hw_set_output_dma(fimc, &fimc->out_frame, !isp_output);
        flite_hw_set_interrupt_mask(fimc);
        flite_hw_set_test_pattern(fimc, fimc->test_pattern->val);
@@ -233,7 +218,7 @@ static int fimc_lite_reinit(struct fimc_lite *fimc, bool suspend)
        if (!streaming)
                return 0;
 
-       return fimc_pipeline_call(fimc, set_stream, &fimc->pipeline, 0);
+       return fimc_pipeline_call(&fimc->ve, set_stream, 0);
 }
 
 static int fimc_lite_stop_capture(struct fimc_lite *fimc, bool suspend)
@@ -299,19 +284,23 @@ static irqreturn_t flite_irq_handler(int irq, void *priv)
 
        if ((intsrc & FLITE_REG_CISTATUS_IRQ_SRC_FRMSTART) &&
            test_bit(ST_FLITE_RUN, &fimc->state) &&
-           !list_empty(&fimc->active_buf_q) &&
            !list_empty(&fimc->pending_buf_q)) {
+               vbuf = fimc_lite_pending_queue_pop(fimc);
+               flite_hw_set_dma_buffer(fimc, vbuf);
+               fimc_lite_active_queue_add(fimc, vbuf);
+       }
+
+       if ((intsrc & FLITE_REG_CISTATUS_IRQ_SRC_FRMEND) &&
+           test_bit(ST_FLITE_RUN, &fimc->state) &&
+           !list_empty(&fimc->active_buf_q)) {
                vbuf = fimc_lite_active_queue_pop(fimc);
                ktime_get_ts(&ts);
                tv = &vbuf->vb.v4l2_buf.timestamp;
                tv->tv_sec = ts.tv_sec;
                tv->tv_usec = ts.tv_nsec / NSEC_PER_USEC;
                vbuf->vb.v4l2_buf.sequence = fimc->frame_count++;
+               flite_hw_mask_dma_buffer(fimc, vbuf->index);
                vb2_buffer_done(&vbuf->vb, VB2_BUF_STATE_DONE);
-
-               vbuf = fimc_lite_pending_queue_pop(fimc);
-               flite_hw_set_output_addr(fimc, vbuf->paddr);
-               fimc_lite_active_queue_add(fimc, vbuf);
        }
 
        if (test_bit(ST_FLITE_CONFIG, &fimc->state))
@@ -330,10 +319,16 @@ done:
 static int start_streaming(struct vb2_queue *q, unsigned int count)
 {
        struct fimc_lite *fimc = q->drv_priv;
+       unsigned long flags;
        int ret;
 
+       spin_lock_irqsave(&fimc->slock, flags);
+
+       fimc->buf_index = 0;
        fimc->frame_count = 0;
 
+       spin_unlock_irqrestore(&fimc->slock, flags);
+
        ret = fimc_lite_hw_init(fimc, false);
        if (ret) {
                fimc_lite_reinit(fimc, false);
@@ -347,8 +342,7 @@ static int start_streaming(struct vb2_queue *q, unsigned int count)
                flite_hw_capture_start(fimc);
 
                if (!test_and_set_bit(ST_SENSOR_STREAM, &fimc->state))
-                       fimc_pipeline_call(fimc, set_stream,
-                                          &fimc->pipeline, 1);
+                       fimc_pipeline_call(&fimc->ve, set_stream, 1);
        }
        if (debug > 0)
                flite_hw_dump_regs(fimc, __func__);
@@ -415,7 +409,7 @@ static int buffer_prepare(struct vb2_buffer *vb)
                unsigned long size = fimc->payload[i];
 
                if (vb2_plane_size(vb, i) < size) {
-                       v4l2_err(&fimc->vfd,
+                       v4l2_err(&fimc->ve.vdev,
                                 "User buffer too small (%ld < %ld)\n",
                                 vb2_plane_size(vb, i), size);
                        return -EINVAL;
@@ -436,10 +430,14 @@ static void buffer_queue(struct vb2_buffer *vb)
        spin_lock_irqsave(&fimc->slock, flags);
        buf->paddr = vb2_dma_contig_plane_dma_addr(vb, 0);
 
+       buf->index = fimc->buf_index++;
+       if (fimc->buf_index >= fimc->reqbufs_count)
+               fimc->buf_index = 0;
+
        if (!test_bit(ST_FLITE_SUSPENDED, &fimc->state) &&
            !test_bit(ST_FLITE_STREAM, &fimc->state) &&
            list_empty(&fimc->active_buf_q)) {
-               flite_hw_set_output_addr(fimc, buf->paddr);
+               flite_hw_set_dma_buffer(fimc, buf);
                fimc_lite_active_queue_add(fimc, buf);
        } else {
                fimc_lite_pending_queue_add(fimc, buf);
@@ -452,8 +450,7 @@ static void buffer_queue(struct vb2_buffer *vb)
                spin_unlock_irqrestore(&fimc->slock, flags);
 
                if (!test_and_set_bit(ST_SENSOR_STREAM, &fimc->state))
-                       fimc_pipeline_call(fimc, set_stream,
-                                          &fimc->pipeline, 1);
+                       fimc_pipeline_call(&fimc->ve, set_stream, 1);
                return;
        }
        spin_unlock_irqrestore(&fimc->slock, flags);
@@ -481,11 +478,9 @@ static void fimc_lite_clear_event_counters(struct fimc_lite *fimc)
 static int fimc_lite_open(struct file *file)
 {
        struct fimc_lite *fimc = video_drvdata(file);
-       struct media_entity *me = &fimc->vfd.entity;
+       struct media_entity *me = &fimc->ve.vdev.entity;
        int ret;
 
-       mutex_lock(&me->parent->graph_mutex);
-
        mutex_lock(&fimc->lock);
        if (atomic_read(&fimc->out_path) != FIMC_IO_DMA) {
                ret = -EBUSY;
@@ -505,11 +500,18 @@ static int fimc_lite_open(struct file *file)
            atomic_read(&fimc->out_path) != FIMC_IO_DMA)
                goto unlock;
 
-       ret = fimc_pipeline_call(fimc, open, &fimc->pipeline,
-                                               me, true);
+       mutex_lock(&me->parent->graph_mutex);
+
+       ret = fimc_pipeline_call(&fimc->ve, open, me, true);
+
+       /* Mark video pipeline ending at this video node as in use. */
+       if (ret == 0)
+               me->use_count++;
+
+       mutex_unlock(&me->parent->graph_mutex);
+
        if (!ret) {
                fimc_lite_clear_event_counters(fimc);
-               fimc->ref_count++;
                goto unlock;
        }
 
@@ -519,26 +521,29 @@ err_pm:
        clear_bit(ST_FLITE_IN_USE, &fimc->state);
 unlock:
        mutex_unlock(&fimc->lock);
-       mutex_unlock(&me->parent->graph_mutex);
        return ret;
 }
 
 static int fimc_lite_release(struct file *file)
 {
        struct fimc_lite *fimc = video_drvdata(file);
+       struct media_entity *entity = &fimc->ve.vdev.entity;
 
        mutex_lock(&fimc->lock);
 
        if (v4l2_fh_is_singular_file(file) &&
            atomic_read(&fimc->out_path) == FIMC_IO_DMA) {
                if (fimc->streaming) {
-                       media_entity_pipeline_stop(&fimc->vfd.entity);
+                       media_entity_pipeline_stop(entity);
                        fimc->streaming = false;
                }
-               clear_bit(ST_FLITE_IN_USE, &fimc->state);
                fimc_lite_stop_capture(fimc, false);
-               fimc_pipeline_call(fimc, close, &fimc->pipeline);
-               fimc->ref_count--;
+               fimc_pipeline_call(&fimc->ve, close);
+               clear_bit(ST_FLITE_IN_USE, &fimc->state);
+
+               mutex_lock(&entity->parent->graph_mutex);
+               entity->use_count--;
+               mutex_unlock(&entity->parent->graph_mutex);
        }
 
        vb2_fop_release(file);
@@ -562,37 +567,54 @@ static const struct v4l2_file_operations fimc_lite_fops = {
  * Format and crop negotiation helpers
  */
 
-static const struct fimc_fmt *fimc_lite_try_format(struct fimc_lite *fimc,
-                                       u32 *width, u32 *height,
-                                       u32 *code, u32 *fourcc, int pad)
+static const struct fimc_fmt *fimc_lite_subdev_try_fmt(struct fimc_lite *fimc,
+                                       struct v4l2_subdev_fh *fh,
+                                       struct v4l2_subdev_format *format)
 {
        struct flite_drvdata *dd = fimc->dd;
-       const struct fimc_fmt *fmt;
-       unsigned int flags = 0;
+       struct v4l2_mbus_framefmt *mf = &format->format;
+       const struct fimc_fmt *fmt = NULL;
+
+       if (format->pad == FLITE_SD_PAD_SINK) {
+               v4l_bound_align_image(&mf->width, 8, dd->max_width,
+                               ffs(dd->out_width_align) - 1,
+                               &mf->height, 0, dd->max_height, 0, 0);
+
+               fmt = fimc_lite_find_format(NULL, &mf->code, 0, 0);
+               if (WARN_ON(!fmt))
+                       return NULL;
 
-       if (pad == FLITE_SD_PAD_SINK) {
-               v4l_bound_align_image(width, 8, dd->max_width,
-                                     ffs(dd->out_width_align) - 1,
-                                     height, 0, dd->max_height, 0, 0);
+               mf->colorspace = fmt->colorspace;
+               mf->code = fmt->mbus_code;
        } else {
-               v4l_bound_align_image(width, 8, fimc->inp_frame.rect.width,
-                                     ffs(dd->out_width_align) - 1,
-                                     height, 0, fimc->inp_frame.rect.height,
-                                     0, 0);
-               flags = fimc->inp_frame.fmt->flags;
-       }
+               struct flite_frame *sink = &fimc->inp_frame;
+               struct v4l2_mbus_framefmt *sink_fmt;
+               struct v4l2_rect *rect;
 
-       fmt = fimc_lite_find_format(fourcc, code, flags, 0);
-       if (WARN_ON(!fmt))
-               return NULL;
+               if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
+                       sink_fmt = v4l2_subdev_get_try_format(fh,
+                                               FLITE_SD_PAD_SINK);
 
-       if (code)
-               *code = fmt->mbus_code;
-       if (fourcc)
-               *fourcc = fmt->fourcc;
+                       mf->code = sink_fmt->code;
+                       mf->colorspace = sink_fmt->colorspace;
 
-       v4l2_dbg(1, debug, &fimc->subdev, "code: 0x%x, %dx%d\n",
-                code ? *code : 0, *width, *height);
+                       rect = v4l2_subdev_get_try_crop(fh,
+                                               FLITE_SD_PAD_SINK);
+               } else {
+                       mf->code = sink->fmt->mbus_code;
+                       mf->colorspace = sink->fmt->colorspace;
+                       rect = &sink->rect;
+               }
+
+               /* Allow changing format only on sink pad */
+               mf->width = rect->width;
+               mf->height = rect->height;
+       }
+
+       mf->field = V4L2_FIELD_NONE;
+
+       v4l2_dbg(1, debug, &fimc->subdev, "code: %#x (%d), %dx%d\n",
+                mf->code, mf->colorspace, mf->width, mf->height);
 
        return fmt;
 }
@@ -637,13 +659,18 @@ static void fimc_lite_try_compose(struct fimc_lite *fimc, struct v4l2_rect *r)
 /*
  * Video node ioctl operations
  */
-static int fimc_vidioc_querycap_capture(struct file *file, void *priv,
+static int fimc_lite_querycap(struct file *file, void *priv,
                                        struct v4l2_capability *cap)
 {
+       struct fimc_lite *fimc = video_drvdata(file);
+
        strlcpy(cap->driver, FIMC_LITE_DRV_NAME, sizeof(cap->driver));
-       cap->bus_info[0] = 0;
-       cap->card[0] = 0;
-       cap->capabilities = V4L2_CAP_STREAMING;
+       strlcpy(cap->card, FIMC_LITE_DRV_NAME, sizeof(cap->card));
+       snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
+                                       dev_name(&fimc->pdev->dev));
+
+       cap->device_caps = V4L2_CAP_STREAMING;
+       cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
        return 0;
 }
 
@@ -679,7 +706,7 @@ static int fimc_lite_g_fmt_mplane(struct file *file, void *fh,
        pixm->width = frame->f_width;
        pixm->height = frame->f_height;
        pixm->field = V4L2_FIELD_NONE;
-       pixm->colorspace = V4L2_COLORSPACE_JPEG;
+       pixm->colorspace = fmt->colorspace;
        return 0;
 }
 
@@ -722,7 +749,7 @@ static int fimc_lite_try_fmt(struct fimc_lite *fimc,
                                                fmt->depth[0]) / 8;
        pixm->num_planes = fmt->memplanes;
        pixm->pixelformat = fmt->fourcc;
-       pixm->colorspace = V4L2_COLORSPACE_JPEG;
+       pixm->colorspace = fmt->colorspace;
        pixm->field = V4L2_FIELD_NONE;
        return 0;
 }
@@ -786,7 +813,7 @@ static int fimc_pipeline_validate(struct fimc_lite *fimc)
                                return -EPIPE;
                }
                /* Retrieve format at the source pad */
-               pad = media_entity_remote_source(pad);
+               pad = media_entity_remote_pad(pad);
                if (pad == NULL ||
                    media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
                        break;
@@ -810,14 +837,13 @@ static int fimc_lite_streamon(struct file *file, void *priv,
                              enum v4l2_buf_type type)
 {
        struct fimc_lite *fimc = video_drvdata(file);
-       struct media_entity *entity = &fimc->vfd.entity;
-       struct fimc_pipeline *p = &fimc->pipeline;
+       struct media_entity *entity = &fimc->ve.vdev.entity;
        int ret;
 
        if (fimc_lite_active(fimc))
                return -EBUSY;
 
-       ret = media_entity_pipeline_start(entity, p->m_pipeline);
+       ret = media_entity_pipeline_start(entity, &fimc->ve.pipe->mp);
        if (ret < 0)
                return ret;
 
@@ -825,7 +851,7 @@ static int fimc_lite_streamon(struct file *file, void *priv,
        if (ret < 0)
                goto err_p_stop;
 
-       fimc->sensor = __find_remote_sensor(&fimc->subdev.entity);
+       fimc->sensor = fimc_find_remote_sensor(&fimc->subdev.entity);
 
        ret = vb2_ioctl_streamon(file, priv, type);
        if (!ret) {
@@ -848,7 +874,7 @@ static int fimc_lite_streamoff(struct file *file, void *priv,
        if (ret < 0)
                return ret;
 
-       media_entity_pipeline_stop(&fimc->vfd.entity);
+       media_entity_pipeline_stop(&fimc->ve.vdev.entity);
        fimc->streaming = false;
        return 0;
 }
@@ -938,7 +964,7 @@ static int fimc_lite_s_selection(struct file *file, void *fh,
 }
 
 static const struct v4l2_ioctl_ops fimc_lite_ioctl_ops = {
-       .vidioc_querycap                = fimc_vidioc_querycap_capture,
+       .vidioc_querycap                = fimc_lite_querycap,
        .vidioc_enum_fmt_vid_cap_mplane = fimc_lite_enum_fmt_mplane,
        .vidioc_try_fmt_vid_cap_mplane  = fimc_lite_try_fmt_mplane,
        .vidioc_s_fmt_vid_cap_mplane    = fimc_lite_s_fmt_mplane,
@@ -972,8 +998,6 @@ static int fimc_lite_link_setup(struct media_entity *entity,
                 __func__, remote->entity->name, local->entity->name,
                 flags, fimc->source_subdev_grp_id);
 
-       mutex_lock(&fimc->lock);
-
        switch (local->index) {
        case FLITE_SD_PAD_SINK:
                if (remote_ent_type != MEDIA_ENT_T_V4L2_SUBDEV) {
@@ -1015,7 +1039,6 @@ static int fimc_lite_link_setup(struct media_entity *entity,
        }
        mb();
 
-       mutex_unlock(&fimc->lock);
        return ret;
 }
 
@@ -1036,6 +1059,15 @@ static int fimc_lite_subdev_enum_mbus_code(struct v4l2_subdev *sd,
        return 0;
 }
 
+static struct v4l2_mbus_framefmt *__fimc_lite_subdev_get_try_fmt(
+                       struct v4l2_subdev_fh *fh, unsigned int pad)
+{
+       if (pad != FLITE_SD_PAD_SINK)
+               pad = FLITE_SD_PAD_SOURCE_DMA;
+
+       return v4l2_subdev_get_try_format(fh, pad);
+}
+
 static int fimc_lite_subdev_get_fmt(struct v4l2_subdev *sd,
                                    struct v4l2_subdev_fh *fh,
                                    struct v4l2_subdev_format *fmt)
@@ -1045,13 +1077,13 @@ static int fimc_lite_subdev_get_fmt(struct v4l2_subdev *sd,
        struct flite_frame *f = &fimc->inp_frame;
 
        if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
-               mf = v4l2_subdev_get_try_format(fh, fmt->pad);
+               mf = __fimc_lite_subdev_get_try_fmt(fh, fmt->pad);
                fmt->format = *mf;
                return 0;
        }
-       mf->colorspace = V4L2_COLORSPACE_JPEG;
 
        mutex_lock(&fimc->lock);
+       mf->colorspace = f->fmt->colorspace;
        mf->code = f->fmt->mbus_code;
 
        if (fmt->pad == FLITE_SD_PAD_SINK) {
@@ -1080,7 +1112,6 @@ static int fimc_lite_subdev_set_fmt(struct v4l2_subdev *sd,
        v4l2_dbg(1, debug, sd, "pad%d: code: 0x%x, %dx%d\n",
                 fmt->pad, mf->code, mf->width, mf->height);
 
-       mf->colorspace = V4L2_COLORSPACE_JPEG;
        mutex_lock(&fimc->lock);
 
        if ((atomic_read(&fimc->out_path) == FIMC_IO_ISP &&
@@ -1091,12 +1122,20 @@ static int fimc_lite_subdev_set_fmt(struct v4l2_subdev *sd,
                return -EBUSY;
        }
 
-       ffmt = fimc_lite_try_format(fimc, &mf->width, &mf->height,
-                                   &mf->code, NULL, fmt->pad);
+       ffmt = fimc_lite_subdev_try_fmt(fimc, fh, fmt);
 
        if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
-               mf = v4l2_subdev_get_try_format(fh, fmt->pad);
+               struct v4l2_mbus_framefmt *src_fmt;
+
+               mf = __fimc_lite_subdev_get_try_fmt(fh, fmt->pad);
                *mf = fmt->format;
+
+               if (fmt->pad == FLITE_SD_PAD_SINK) {
+                       unsigned int pad = FLITE_SD_PAD_SOURCE_DMA;
+                       src_fmt = __fimc_lite_subdev_get_try_fmt(fh, pad);
+                       *src_fmt = *mf;
+               }
+
                mutex_unlock(&fimc->lock);
                return 0;
        }
@@ -1114,11 +1153,6 @@ static int fimc_lite_subdev_set_fmt(struct v4l2_subdev *sd,
                source->rect = sink->rect;
                source->f_width = mf->width;
                source->f_height = mf->height;
-       } else {
-               /* Allow changing format only on sink pad */
-               mf->code = sink->fmt->mbus_code;
-               mf->width = sink->rect.width;
-               mf->height = sink->rect.height;
        }
 
        mutex_unlock(&fimc->lock);
@@ -1207,7 +1241,7 @@ static int fimc_lite_subdev_s_stream(struct v4l2_subdev *sd, int on)
         * The pipeline links are protected through entity.stream_count
         * so there is no need to take the media graph mutex here.
         */
-       fimc->sensor = __find_remote_sensor(&sd->entity);
+       fimc->sensor = fimc_find_remote_sensor(&sd->entity);
 
        if (atomic_read(&fimc->out_path) != FIMC_IO_ISP)
                return -ENOIOCTLCMD;
@@ -1252,13 +1286,10 @@ static int fimc_lite_subdev_registered(struct v4l2_subdev *sd)
 {
        struct fimc_lite *fimc = v4l2_get_subdevdata(sd);
        struct vb2_queue *q = &fimc->vb_queue;
-       struct video_device *vfd = &fimc->vfd;
+       struct video_device *vfd = &fimc->ve.vdev;
        int ret;
 
        memset(vfd, 0, sizeof(*vfd));
-
-       fimc->inp_frame.fmt = &fimc_lite_formats[0];
-       fimc->out_frame.fmt = &fimc_lite_formats[0];
        atomic_set(&fimc->out_path, FIMC_IO_DMA);
 
        snprintf(vfd->name, sizeof(vfd->name), "fimc-lite.%d.capture",
@@ -1295,12 +1326,12 @@ static int fimc_lite_subdev_registered(struct v4l2_subdev *sd)
                return ret;
 
        video_set_drvdata(vfd, fimc);
-       fimc->pipeline_ops = v4l2_get_subdev_hostdata(sd);
+       fimc->ve.pipe = v4l2_get_subdev_hostdata(sd);
 
        ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1);
        if (ret < 0) {
                media_entity_cleanup(&vfd->entity);
-               fimc->pipeline_ops = NULL;
+               fimc->ve.pipe = NULL;
                return ret;
        }
 
@@ -1316,11 +1347,15 @@ static void fimc_lite_subdev_unregistered(struct v4l2_subdev *sd)
        if (fimc == NULL)
                return;
 
-       if (video_is_registered(&fimc->vfd)) {
-               video_unregister_device(&fimc->vfd);
-               media_entity_cleanup(&fimc->vfd.entity);
-               fimc->pipeline_ops = NULL;
+       mutex_lock(&fimc->lock);
+
+       if (video_is_registered(&fimc->ve.vdev)) {
+               video_unregister_device(&fimc->ve.vdev);
+               media_entity_cleanup(&fimc->ve.vdev.entity);
+               fimc->ve.pipe = NULL;
        }
+
+       mutex_unlock(&fimc->lock);
 }
 
 static const struct v4l2_subdev_internal_ops fimc_lite_subdev_internal_ops = {
@@ -1370,6 +1405,23 @@ static const struct v4l2_ctrl_config fimc_lite_ctrl = {
        .step   = 1,
 };
 
+static void fimc_lite_set_default_config(struct fimc_lite *fimc)
+{
+       struct flite_frame *sink = &fimc->inp_frame;
+       struct flite_frame *source = &fimc->out_frame;
+
+       sink->fmt = &fimc_lite_formats[0];
+       sink->f_width = FLITE_DEFAULT_WIDTH;
+       sink->f_height = FLITE_DEFAULT_HEIGHT;
+
+       sink->rect.width = FLITE_DEFAULT_WIDTH;
+       sink->rect.height = FLITE_DEFAULT_HEIGHT;
+       sink->rect.left = 0;
+       sink->rect.top = 0;
+
+       *source = *sink;
+}
+
 static int fimc_lite_create_capture_subdev(struct fimc_lite *fimc)
 {
        struct v4l2_ctrl_handler *handler = &fimc->ctrl_handler;
@@ -1417,12 +1469,12 @@ static void fimc_lite_unregister_capture_subdev(struct fimc_lite *fimc)
 
 static void fimc_lite_clk_put(struct fimc_lite *fimc)
 {
-       if (IS_ERR_OR_NULL(fimc->clock))
+       if (IS_ERR(fimc->clock))
                return;
 
        clk_unprepare(fimc->clock);
        clk_put(fimc->clock);
-       fimc->clock = NULL;
+       fimc->clock = ERR_PTR(-EINVAL);
 }
 
 static int fimc_lite_clk_get(struct fimc_lite *fimc)
@@ -1436,7 +1488,7 @@ static int fimc_lite_clk_get(struct fimc_lite *fimc)
        ret = clk_prepare(fimc->clock);
        if (ret < 0) {
                clk_put(fimc->clock);
-               fimc->clock = NULL;
+               fimc->clock = ERR_PTR(-EINVAL);
        }
        return ret;
 }
@@ -1461,13 +1513,14 @@ static int fimc_lite_probe(struct platform_device *pdev)
                if (of_id)
                        drv_data = (struct flite_drvdata *)of_id->data;
                fimc->index = of_alias_get_id(dev->of_node, "fimc-lite");
-       } else {
-               drv_data = fimc_lite_get_drvdata(pdev);
-               fimc->index = pdev->id;
        }
 
-       if (!drv_data || fimc->index < 0 || fimc->index >= FIMC_LITE_MAX_DEVS)
+       if (!drv_data || fimc->index >= drv_data->num_instances ||
+                                               fimc->index < 0) {
+               dev_err(dev, "Wrong %s node alias\n",
+                                       dev->of_node->full_name);
                return -EINVAL;
+       }
 
        fimc->dd = drv_data;
        fimc->pdev = pdev;
@@ -1514,8 +1567,11 @@ static int fimc_lite_probe(struct platform_device *pdev)
                ret = PTR_ERR(fimc->alloc_ctx);
                goto err_pm;
        }
+
        pm_runtime_put(dev);
 
+       fimc_lite_set_default_config(fimc);
+
        dev_dbg(dev, "FIMC-LITE.%d registered successfully\n",
                fimc->index);
        return 0;
@@ -1565,8 +1621,8 @@ static int fimc_lite_resume(struct device *dev)
                return 0;
 
        INIT_LIST_HEAD(&fimc->active_buf_q);
-       fimc_pipeline_call(fimc, open, &fimc->pipeline,
-                          &fimc->vfd.entity, false);
+       fimc_pipeline_call(&fimc->ve, open,
+                          &fimc->ve.vdev.entity, false);
        fimc_lite_hw_init(fimc, atomic_read(&fimc->out_path) == FIMC_IO_ISP);
        clear_bit(ST_FLITE_SUSPENDED, &fimc->state);
 
@@ -1592,7 +1648,7 @@ static int fimc_lite_suspend(struct device *dev)
        if (ret < 0 || !fimc_lite_active(fimc))
                return ret;
 
-       return fimc_pipeline_call(fimc, close, &fimc->pipeline);
+       return fimc_pipeline_call(&fimc->ve, close);
 }
 #endif /* CONFIG_PM_SLEEP */
 
@@ -1624,22 +1680,30 @@ static struct flite_drvdata fimc_lite_drvdata_exynos4 = {
        .out_width_align        = 8,
        .win_hor_offs_align     = 2,
        .out_hor_offs_align     = 8,
+       .max_dma_bufs           = 1,
+       .num_instances          = 2,
 };
 
-static struct platform_device_id fimc_lite_driver_ids[] = {
-       {
-               .name           = "exynos-fimc-lite",
-               .driver_data    = (unsigned long)&fimc_lite_drvdata_exynos4,
-       },
-       { /* sentinel */ },
+/* EXYNOS5250 */
+static struct flite_drvdata fimc_lite_drvdata_exynos5 = {
+       .max_width              = 8192,
+       .max_height             = 8192,
+       .out_width_align        = 8,
+       .win_hor_offs_align     = 2,
+       .out_hor_offs_align     = 8,
+       .max_dma_bufs           = 32,
+       .num_instances          = 3,
 };
-MODULE_DEVICE_TABLE(platform, fimc_lite_driver_ids);
 
 static const struct of_device_id flite_of_match[] = {
        {
                .compatible = "samsung,exynos4212-fimc-lite",
                .data = &fimc_lite_drvdata_exynos4,
        },
+       {
+               .compatible = "samsung,exynos5250-fimc-lite",
+               .data = &fimc_lite_drvdata_exynos5,
+       },
        { /* sentinel */ },
 };
 MODULE_DEVICE_TABLE(of, flite_of_match);
@@ -1647,7 +1711,6 @@ MODULE_DEVICE_TABLE(of, flite_of_match);
 static struct platform_driver fimc_lite_driver = {
        .probe          = fimc_lite_probe,
        .remove         = fimc_lite_remove,
-       .id_table       = fimc_lite_driver_ids,
        .driver = {
                .of_match_table = flite_of_match,
                .name           = FIMC_LITE_DRV_NAME,
index 47da5e0..7428b2d 100644 (file)
 
 #define FIMC_LITE_DRV_NAME     "exynos-fimc-lite"
 #define FLITE_CLK_NAME         "flite"
-#define FIMC_LITE_MAX_DEVS     2
+#define FIMC_LITE_MAX_DEVS     3
 #define FLITE_REQ_BUFS_MIN     2
+#define FLITE_DEFAULT_WIDTH    640
+#define FLITE_DEFAULT_HEIGHT   480
 
 /* Bit index definitions for struct fimc_lite::state */
 enum {
@@ -48,17 +50,28 @@ enum {
 #define FLITE_SD_PAD_SOURCE_ISP        2
 #define FLITE_SD_PADS_NUM      3
 
+/**
+ * struct flite_drvdata - FIMC-LITE IP variant data structure
+ * @max_width: maximum camera interface input width in pixels
+ * @max_height: maximum camera interface input height in pixels
+ * @out_width_align: minimum output width alignment in pixels
+ * @win_hor_offs_align: minimum camera interface crop window horizontal
+ *                     offset alignment in pixels
+ * @out_hor_offs_align: minimum output DMA compose rectangle horizontal
+ *                     offset alignment in pixels
+ * @max_dma_bufs: number of output DMA buffer start address registers
+ * @num_instances: total number of FIMC-LITE IP instances available
+ */
 struct flite_drvdata {
        unsigned short max_width;
        unsigned short max_height;
        unsigned short out_width_align;
        unsigned short win_hor_offs_align;
        unsigned short out_hor_offs_align;
+       unsigned short max_dma_bufs;
+       unsigned short num_instances;
 };
 
-#define fimc_lite_get_drvdata(_pdev) \
-       ((struct flite_drvdata *) platform_get_device_id(_pdev)->driver_data)
-
 struct fimc_lite_events {
        unsigned int data_overflow;
 };
@@ -83,20 +96,22 @@ struct flite_frame {
  * struct flite_buffer - video buffer structure
  * @vb:    vb2 buffer
  * @list:  list head for the buffers queue
- * @paddr: precalculated physical address
+ * @paddr: DMA buffer start address
+ * @index: DMA start address register's index
  */
 struct flite_buffer {
        struct vb2_buffer vb;
        struct list_head list;
        dma_addr_t paddr;
+       unsigned short index;
 };
 
 /**
  * struct fimc_lite - fimc lite structure
  * @pdev: pointer to FIMC-LITE platform device
  * @dd: SoC specific driver data structure
+ * @ve: exynos video device entity structure
  * @v4l2_dev: pointer to top the level v4l2_device
- * @vfd: video device node
  * @fh: v4l2 file handle
  * @alloc_ctx: videobuf2 memory allocator context
  * @subdev: FIMC-LITE subdev
@@ -122,16 +137,16 @@ struct flite_buffer {
  * @pending_buf_q: pending buffers queue head
  * @active_buf_q: the queue head of buffers scheduled in hardware
  * @vb_queue: vb2 buffers queue
+ * @buf_index: helps to keep track of the DMA start address register index
  * @active_buf_count: number of video buffers scheduled in hardware
  * @frame_count: the captured frames counter
  * @reqbufs_count: the number of buffers requested with REQBUFS ioctl
- * @ref_count: driver's private reference counter
  */
 struct fimc_lite {
        struct platform_device  *pdev;
        struct flite_drvdata    *dd;
+       struct exynos_video_entity ve;
        struct v4l2_device      *v4l2_dev;
-       struct video_device     vfd;
        struct v4l2_fh          fh;
        struct vb2_alloc_ctx    *alloc_ctx;
        struct v4l2_subdev      subdev;
@@ -141,8 +156,6 @@ struct fimc_lite {
        struct v4l2_ctrl_handler ctrl_handler;
        struct v4l2_ctrl        *test_pattern;
        int                     index;
-       struct fimc_pipeline    pipeline;
-       const struct fimc_pipeline_ops *pipeline_ops;
 
        struct mutex            lock;
        spinlock_t              slock;
@@ -161,9 +174,9 @@ struct fimc_lite {
        struct list_head        pending_buf_q;
        struct list_head        active_buf_q;
        struct vb2_queue        vb_queue;
+       unsigned short          buf_index;
        unsigned int            frame_count;
        unsigned int            reqbufs_count;
-       int                     ref_count;
 
        struct fimc_lite_events events;
        bool                    streaming;
index bde1f47..8d33b68 100644 (file)
@@ -27,6 +27,7 @@
 #include <media/videobuf2-core.h>
 #include <media/videobuf2-dma-contig.h>
 
+#include "common.h"
 #include "fimc-core.h"
 #include "fimc-reg.h"
 #include "media-dev.h"
index f079f36..1db8cb4 100644 (file)
@@ -618,7 +618,7 @@ int fimc_hw_set_camera_source(struct fimc_dev *fimc,
                }
 
                if (i == ARRAY_SIZE(pix_desc)) {
-                       v4l2_err(&vc->vfd,
+                       v4l2_err(&vc->ve.vdev,
                                 "Camera color format not supported: %d\n",
                                 vc->ci_fmt.code);
                        return -EINVAL;
@@ -698,7 +698,7 @@ int fimc_hw_set_camera_type(struct fimc_dev *fimc,
                        cfg |= FIMC_REG_CIGCTRL_CAM_JPEG;
                        break;
                default:
-                       v4l2_err(&vid_cap->vfd,
+                       v4l2_err(&vid_cap->ve.vdev,
                                 "Not supported camera pixel format: %#x\n",
                                 vid_cap->ci_fmt.code);
                        return -EINVAL;
@@ -721,7 +721,8 @@ int fimc_hw_set_camera_type(struct fimc_dev *fimc,
                        WARN_ONCE(1, "ISP Writeback input is not supported\n");
                break;
        default:
-               v4l2_err(&vid_cap->vfd, "Invalid FIMC bus type selected: %d\n",
+               v4l2_err(&vid_cap->ve.vdev,
+                        "Invalid FIMC bus type selected: %d\n",
                         source->fimc_bus_type);
                return -EINVAL;
        }
index 15ef8f2..19f556c 100644 (file)
@@ -1,8 +1,8 @@
 /*
  * S5P/EXYNOS4 SoC series camera host interface media device driver
  *
- * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd.
- * Sylwester Nawrocki <s.nawrocki@samsung.com>
+ * Copyright (C) 2011 - 2013 Samsung Electronics Co., Ltd.
+ * Author: Sylwester Nawrocki <s.nawrocki@samsung.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published
 static int __fimc_md_set_camclk(struct fimc_md *fmd,
                                struct fimc_source_info *si,
                                bool on);
+
+/* Set up image sensor subdev -> FIMC capture node notifications. */
+static void __setup_sensor_notification(struct fimc_md *fmd,
+                                       struct v4l2_subdev *sensor,
+                                       struct v4l2_subdev *fimc_sd)
+{
+       struct fimc_source_info *src_inf;
+       struct fimc_sensor_info *md_si;
+       unsigned long flags;
+
+       src_inf = v4l2_get_subdev_hostdata(sensor);
+       if (!src_inf || WARN_ON(fmd == NULL))
+               return;
+
+       md_si = source_to_sensor_info(src_inf);
+       spin_lock_irqsave(&fmd->slock, flags);
+       md_si->host = v4l2_get_subdevdata(fimc_sd);
+       spin_unlock_irqrestore(&fmd->slock, flags);
+}
+
 /**
  * fimc_pipeline_prepare - update pipeline information with subdevice pointers
  * @me: media entity terminating the pipeline
@@ -46,9 +66,11 @@ static int __fimc_md_set_camclk(struct fimc_md *fmd,
  * Caller holds the graph mutex.
  */
 static void fimc_pipeline_prepare(struct fimc_pipeline *p,
-                                 struct media_entity *me)
+                                       struct media_entity *me)
 {
+       struct fimc_md *fmd = entity_to_fimc_mdev(me);
        struct v4l2_subdev *sd;
+       struct v4l2_subdev *sensor = NULL;
        int i;
 
        for (i = 0; i < IDX_MAX; i++)
@@ -62,7 +84,7 @@ static void fimc_pipeline_prepare(struct fimc_pipeline *p,
                        struct media_pad *spad = &me->pads[i];
                        if (!(spad->flags & MEDIA_PAD_FL_SINK))
                                continue;
-                       pad = media_entity_remote_source(spad);
+                       pad = media_entity_remote_pad(spad);
                        if (pad)
                                break;
                }
@@ -73,8 +95,10 @@ static void fimc_pipeline_prepare(struct fimc_pipeline *p,
                sd = media_entity_to_v4l2_subdev(pad->entity);
 
                switch (sd->grp_id) {
-               case GRP_ID_FIMC_IS_SENSOR:
                case GRP_ID_SENSOR:
+                       sensor = sd;
+                       /* fall through */
+               case GRP_ID_FIMC_IS_SENSOR:
                        p->subdevs[IDX_SENSOR] = sd;
                        break;
                case GRP_ID_CSIS:
@@ -84,7 +108,7 @@ static void fimc_pipeline_prepare(struct fimc_pipeline *p,
                        p->subdevs[IDX_FLITE] = sd;
                        break;
                case GRP_ID_FIMC:
-                       /* No need to control FIMC subdev through subdev ops */
+                       p->subdevs[IDX_FIMC] = sd;
                        break;
                case GRP_ID_FIMC_IS:
                        p->subdevs[IDX_IS_ISP] = sd;
@@ -96,6 +120,9 @@ static void fimc_pipeline_prepare(struct fimc_pipeline *p,
                if (me->num_pads == 1)
                        break;
        }
+
+       if (sensor && p->subdevs[IDX_FIMC])
+               __setup_sensor_notification(fmd, sensor, p->subdevs[IDX_FIMC]);
 }
 
 /**
@@ -168,10 +195,11 @@ error:
  *
  * Called with the graph mutex held.
  */
-static int __fimc_pipeline_open(struct fimc_pipeline *p,
+static int __fimc_pipeline_open(struct exynos_media_pipeline *ep,
                                struct media_entity *me, bool prepare)
 {
        struct fimc_md *fmd = entity_to_fimc_mdev(me);
+       struct fimc_pipeline *p = to_fimc_pipeline(ep);
        struct v4l2_subdev *sd;
        int ret;
 
@@ -214,20 +242,21 @@ err_wbclk:
  *
  * Disable power of all subdevs and turn the external sensor clock off.
  */
-static int __fimc_pipeline_close(struct fimc_pipeline *p)
+static int __fimc_pipeline_close(struct exynos_media_pipeline *ep)
 {
+       struct fimc_pipeline *p = to_fimc_pipeline(ep);
        struct v4l2_subdev *sd = p ? p->subdevs[IDX_SENSOR] : NULL;
        struct fimc_md *fmd;
-       int ret = 0;
-
-       if (WARN_ON(sd == NULL))
-               return -EINVAL;
+       int ret;
 
-       if (p->subdevs[IDX_SENSOR]) {
-               ret = fimc_pipeline_s_power(p, 0);
-               fimc_md_set_camclk(sd, false);
+       if (sd == NULL) {
+               pr_warn("%s(): No sensor subdev\n", __func__);
+               return 0;
        }
 
+       ret = fimc_pipeline_s_power(p, 0);
+       fimc_md_set_camclk(sd, false);
+
        fmd = entity_to_fimc_mdev(&sd->entity);
 
        /* Disable PXLASYNC clock if this pipeline includes FIMC-IS */
@@ -242,12 +271,13 @@ static int __fimc_pipeline_close(struct fimc_pipeline *p)
  * @pipeline: video pipeline structure
  * @on: passed as the s_stream() callback argument
  */
-static int __fimc_pipeline_s_stream(struct fimc_pipeline *p, bool on)
+static int __fimc_pipeline_s_stream(struct exynos_media_pipeline *ep, bool on)
 {
        static const u8 seq[2][IDX_MAX] = {
                { IDX_FIMC, IDX_SENSOR, IDX_IS_ISP, IDX_CSIS, IDX_FLITE },
                { IDX_CSIS, IDX_FLITE, IDX_FIMC, IDX_SENSOR, IDX_IS_ISP },
        };
+       struct fimc_pipeline *p = to_fimc_pipeline(ep);
        int i, ret = 0;
 
        if (p->subdevs[IDX_SENSOR] == NULL)
@@ -271,12 +301,38 @@ error:
 }
 
 /* Media pipeline operations for the FIMC/FIMC-LITE video device driver */
-static const struct fimc_pipeline_ops fimc_pipeline_ops = {
+static const struct exynos_media_pipeline_ops fimc_pipeline_ops = {
        .open           = __fimc_pipeline_open,
        .close          = __fimc_pipeline_close,
        .set_stream     = __fimc_pipeline_s_stream,
 };
 
+static struct exynos_media_pipeline *fimc_md_pipeline_create(
+                                               struct fimc_md *fmd)
+{
+       struct fimc_pipeline *p;
+
+       p = kzalloc(sizeof(*p), GFP_KERNEL);
+       if (!p)
+               return NULL;
+
+       list_add_tail(&p->list, &fmd->pipelines);
+
+       p->ep.ops = &fimc_pipeline_ops;
+       return &p->ep;
+}
+
+static void fimc_md_pipelines_free(struct fimc_md *fmd)
+{
+       while (!list_empty(&fmd->pipelines)) {
+               struct fimc_pipeline *p;
+
+               p = list_entry(fmd->pipelines.next, typeof(*p), list);
+               list_del(&p->list);
+               kfree(p);
+       }
+}
+
 /*
  * Sensor subdevice helper functions
  */
@@ -592,6 +648,7 @@ static int register_fimc_lite_entity(struct fimc_md *fmd,
                                     struct fimc_lite *fimc_lite)
 {
        struct v4l2_subdev *sd;
+       struct exynos_media_pipeline *ep;
        int ret;
 
        if (WARN_ON(fimc_lite->index >= FIMC_LITE_MAX_DEVS ||
@@ -600,7 +657,12 @@ static int register_fimc_lite_entity(struct fimc_md *fmd,
 
        sd = &fimc_lite->subdev;
        sd->grp_id = GRP_ID_FLITE;
-       v4l2_set_subdev_hostdata(sd, (void *)&fimc_pipeline_ops);
+
+       ep = fimc_md_pipeline_create(fmd);
+       if (!ep)
+               return -ENOMEM;
+
+       v4l2_set_subdev_hostdata(sd, ep);
 
        ret = v4l2_device_register_subdev(&fmd->v4l2_dev, sd);
        if (!ret)
@@ -614,6 +676,7 @@ static int register_fimc_lite_entity(struct fimc_md *fmd,
 static int register_fimc_entity(struct fimc_md *fmd, struct fimc_dev *fimc)
 {
        struct v4l2_subdev *sd;
+       struct exynos_media_pipeline *ep;
        int ret;
 
        if (WARN_ON(fimc->id >= FIMC_MAX_DEVS || fmd->fimc[fimc->id]))
@@ -621,7 +684,12 @@ static int register_fimc_entity(struct fimc_md *fmd, struct fimc_dev *fimc)
 
        sd = &fimc->vid_cap.subdev;
        sd->grp_id = GRP_ID_FIMC;
-       v4l2_set_subdev_hostdata(sd, (void *)&fimc_pipeline_ops);
+
+       ep = fimc_md_pipeline_create(fmd);
+       if (!ep)
+               return -ENOMEM;
+
+       v4l2_set_subdev_hostdata(sd, ep);
 
        ret = v4l2_device_register_subdev(&fmd->v4l2_dev, sd);
        if (!ret) {
@@ -736,8 +804,6 @@ static int fimc_md_pdev_match(struct device *dev, void *data)
 
        if (!strcmp(pdev->name, CSIS_DRIVER_NAME)) {
                plat_entity = IDX_CSIS;
-       } else if (!strcmp(pdev->name, FIMC_LITE_DRV_NAME)) {
-               plat_entity = IDX_FLITE;
        } else {
                p = strstr(pdev->name, "fimc");
                if (p && *(p + 4) == 0)
@@ -797,17 +863,19 @@ static void fimc_md_unregister_entities(struct fimc_md *fmd)
        int i;
 
        for (i = 0; i < FIMC_MAX_DEVS; i++) {
-               if (fmd->fimc[i] == NULL)
+               struct fimc_dev *dev = fmd->fimc[i];
+               if (dev == NULL)
                        continue;
-               v4l2_device_unregister_subdev(&fmd->fimc[i]->vid_cap.subdev);
-               fmd->fimc[i]->pipeline_ops = NULL;
+               v4l2_device_unregister_subdev(&dev->vid_cap.subdev);
+               dev->vid_cap.ve.pipe = NULL;
                fmd->fimc[i] = NULL;
        }
        for (i = 0; i < FIMC_LITE_MAX_DEVS; i++) {
-               if (fmd->fimc_lite[i] == NULL)
+               struct fimc_lite *dev = fmd->fimc_lite[i];
+               if (dev == NULL)
                        continue;
-               v4l2_device_unregister_subdev(&fmd->fimc_lite[i]->subdev);
-               fmd->fimc_lite[i]->pipeline_ops = NULL;
+               v4l2_device_unregister_subdev(&dev->subdev);
+               dev->ve.pipe = NULL;
                fmd->fimc_lite[i] = NULL;
        }
        for (i = 0; i < CSIS_MAX_ENTITIES; i++) {
@@ -880,18 +948,6 @@ static int __fimc_md_create_fimc_sink_links(struct fimc_md *fmd,
 
                v4l2_info(&fmd->v4l2_dev, "created link [%s] %c> [%s]\n",
                          source->name, flags ? '=' : '-', sink->name);
-
-               if (flags == 0 || sensor == NULL)
-                       continue;
-
-               if (!WARN_ON(si == NULL)) {
-                       unsigned long irq_flags;
-                       struct fimc_sensor_info *inf = source_to_sensor_info(si);
-
-                       spin_lock_irqsave(&fmd->slock, irq_flags);
-                       inf->host = fmd->fimc[i];
-                       spin_unlock_irqrestore(&fmd->slock, irq_flags);
-               }
        }
 
        for (i = 0; i < FIMC_LITE_MAX_DEVS; i++) {
@@ -929,7 +985,7 @@ static int __fimc_md_create_flite_source_links(struct fimc_md *fmd)
                        continue;
 
                source = &fimc->subdev.entity;
-               sink = &fimc->vfd.entity;
+               sink = &fimc->ve.vdev.entity;
                /* FIMC-LITE's subdev and video node */
                ret = media_entity_create_link(source, FLITE_SD_PAD_SOURCE_DMA,
                                               sink, 0, 0);
@@ -1066,7 +1122,7 @@ static int fimc_md_create_links(struct fimc_md *fmd)
                        continue;
 
                source = &fmd->fimc[i]->vid_cap.subdev.entity;
-               sink = &fmd->fimc[i]->vid_cap.vfd.entity;
+               sink = &fmd->fimc[i]->vid_cap.ve.vdev.entity;
 
                ret = media_entity_create_link(source, FIMC_SD_PAD_SOURCE,
                                              sink, 0, flags);
@@ -1231,66 +1287,98 @@ int fimc_md_set_camclk(struct v4l2_subdev *sd, bool on)
        return __fimc_md_set_camclk(fmd, si, on);
 }
 
-static int fimc_md_link_notify(struct media_pad *source,
-                              struct media_pad *sink, u32 flags)
+static int __fimc_md_modify_pipeline(struct media_entity *entity, bool enable)
 {
-       struct fimc_lite *fimc_lite = NULL;
-       struct fimc_dev *fimc = NULL;
-       struct fimc_pipeline *pipeline;
-       struct v4l2_subdev *sd;
-       struct mutex *lock;
-       int i, ret = 0;
-       int ref_count;
+       struct exynos_video_entity *ve;
+       struct fimc_pipeline *p;
+       struct video_device *vdev;
+       int ret;
 
-       if (media_entity_type(sink->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
+       vdev = media_entity_to_video_device(entity);
+       if (vdev->entity.use_count == 0)
                return 0;
 
-       sd = media_entity_to_v4l2_subdev(sink->entity);
-
-       switch (sd->grp_id) {
-       case GRP_ID_FLITE:
-               fimc_lite = v4l2_get_subdevdata(sd);
-               if (WARN_ON(fimc_lite == NULL))
-                       return 0;
-               pipeline = &fimc_lite->pipeline;
-               lock = &fimc_lite->lock;
-               break;
-       case GRP_ID_FIMC:
-               fimc = v4l2_get_subdevdata(sd);
-               if (WARN_ON(fimc == NULL))
-                       return 0;
-               pipeline = &fimc->pipeline;
-               lock = &fimc->lock;
-               break;
-       default:
+       ve = vdev_to_exynos_video_entity(vdev);
+       p = to_fimc_pipeline(ve->pipe);
+       /*
+        * Nothing to do if we are disabling the pipeline, some link
+        * has been disconnected and p->subdevs array is cleared now.
+        */
+       if (!enable && p->subdevs[IDX_SENSOR] == NULL)
                return 0;
+
+       if (enable)
+               ret = __fimc_pipeline_open(ve->pipe, entity, true);
+       else
+               ret = __fimc_pipeline_close(ve->pipe);
+
+       if (ret == 0 && !enable)
+               memset(p->subdevs, 0, sizeof(p->subdevs));
+
+       return ret;
+}
+
+/* Locking: called with entity->parent->graph_mutex mutex held. */
+static int __fimc_md_modify_pipelines(struct media_entity *entity, bool enable)
+{
+       struct media_entity *entity_err = entity;
+       struct media_entity_graph graph;
+       int ret;
+
+       /*
+        * Walk current graph and call the pipeline open/close routine for each
+        * opened video node that belongs to the graph of entities connected
+        * through active links. This is needed as we cannot power on/off the
+        * subdevs in random order.
+        */
+       media_entity_graph_walk_start(&graph, entity);
+
+       while ((entity = media_entity_graph_walk_next(&graph))) {
+               if (media_entity_type(entity) != MEDIA_ENT_T_DEVNODE)
+                       continue;
+
+               ret  = __fimc_md_modify_pipeline(entity, enable);
+
+               if (ret < 0)
+                       goto err;
        }
 
-       mutex_lock(lock);
-       ref_count = fimc ? fimc->vid_cap.refcnt : fimc_lite->ref_count;
+       return 0;
+ err:
+       media_entity_graph_walk_start(&graph, entity_err);
 
-       if (!(flags & MEDIA_LNK_FL_ENABLED)) {
-               if (ref_count > 0) {
-                       ret = __fimc_pipeline_close(pipeline);
-                       if (!ret && fimc)
-                               fimc_ctrls_delete(fimc->vid_cap.ctx);
-               }
-               for (i = 0; i < IDX_MAX; i++)
-                       pipeline->subdevs[i] = NULL;
-       } else if (ref_count > 0) {
-               /*
-                * Link activation. Enable power of pipeline elements only if
-                * the pipeline is already in use, i.e. its video node is open.
-                * Recreate the controls destroyed during the link deactivation.
-                */
-               ret = __fimc_pipeline_open(pipeline,
-                                          source->entity, true);
-               if (!ret && fimc)
-                       ret = fimc_capture_ctrls_create(fimc);
+       while ((entity_err = media_entity_graph_walk_next(&graph))) {
+               if (media_entity_type(entity_err) != MEDIA_ENT_T_DEVNODE)
+                       continue;
+
+               __fimc_md_modify_pipeline(entity_err, !enable);
+
+               if (entity_err == entity)
+                       break;
+       }
+
+       return ret;
+}
+
+static int fimc_md_link_notify(struct media_link *link, unsigned int flags,
+                               unsigned int notification)
+{
+       struct media_entity *sink = link->sink->entity;
+       int ret = 0;
+
+       /* Before link disconnection */
+       if (notification == MEDIA_DEV_NOTIFY_PRE_LINK_CH) {
+               if (!(flags & MEDIA_LNK_FL_ENABLED))
+                       ret = __fimc_md_modify_pipelines(sink, false);
+               else
+                       ; /* TODO: Link state change validation */
+       /* After link activation */
+       } else if (notification == MEDIA_DEV_NOTIFY_POST_LINK_CH &&
+                  (link->flags & MEDIA_LNK_FL_ENABLED)) {
+               ret = __fimc_md_modify_pipelines(sink, true);
        }
 
-       mutex_unlock(lock);
-       return ret ? -EPIPE : ret;
+       return ret ? -EPIPE : 0;
 }
 
 static ssize_t fimc_md_sysfs_show(struct device *dev,
@@ -1370,6 +1458,7 @@ static int fimc_md_probe(struct platform_device *pdev)
 
        spin_lock_init(&fmd->slock);
        fmd->pdev = pdev;
+       INIT_LIST_HEAD(&fmd->pipelines);
 
        strlcpy(fmd->media_dev.model, "SAMSUNG S5P FIMC",
                sizeof(fmd->media_dev.model));
@@ -1457,6 +1546,7 @@ static int fimc_md_remove(struct platform_device *pdev)
                return 0;
        device_remove_file(&pdev->dev, &dev_attr_subdev_conf_mode);
        fimc_md_unregister_entities(fmd);
+       fimc_md_pipelines_free(fmd);
        media_device_unregister(&fmd->media_dev);
        fimc_md_put_clocks(fmd);
        return 0;
index 44d86b6..62599fd 100644 (file)
@@ -18,6 +18,7 @@
 #include <media/media-entity.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-subdev.h>
+#include <media/s5p_fimc.h>
 
 #include "fimc-core.h"
 #include "fimc-lite.h"
@@ -40,6 +41,29 @@ enum {
        FIMC_MAX_WBCLKS
 };
 
+enum fimc_subdev_index {
+       IDX_SENSOR,
+       IDX_CSIS,
+       IDX_FLITE,
+       IDX_IS_ISP,
+       IDX_FIMC,
+       IDX_MAX,
+};
+
+/*
+ * This structure represents a chain of media entities, including a data
+ * source entity (e.g. an image sensor subdevice), a data capture entity
+ * - a video capture device node and any remaining entities.
+ */
+struct fimc_pipeline {
+       struct exynos_media_pipeline ep;
+       struct list_head list;
+       struct media_entity *vdev_entity;
+       struct v4l2_subdev *subdevs[IDX_MAX];
+};
+
+#define to_fimc_pipeline(_ep) container_of(_ep, struct fimc_pipeline, ep)
+
 struct fimc_csis_info {
        struct v4l2_subdev *sd;
        int id;
@@ -104,17 +128,11 @@ struct fimc_md {
                struct pinctrl_state *state_idle;
        } pinctl;
        bool user_subdev_api;
+
        spinlock_t slock;
+       struct list_head pipelines;
 };
 
-#define is_subdev_pad(pad) (pad == NULL || \
-       media_entity_type(pad->entity) == MEDIA_ENT_T_V4L2_SUBDEV)
-
-#define me_subtype(me) \
-       ((me->type) & (MEDIA_ENT_TYPE_MASK | MEDIA_ENT_SUBTYPE_MASK))
-
-#define subdev_has_devnode(__sd) (__sd->flags & V4L2_SUBDEV_FL_HAS_DEVNODE)
-
 static inline
 struct fimc_sensor_info *source_to_sensor_info(struct fimc_source_info *si)
 {
@@ -127,14 +145,14 @@ static inline struct fimc_md *entity_to_fimc_mdev(struct media_entity *me)
                container_of(me->parent, struct fimc_md, media_dev);
 }
 
-static inline void fimc_md_graph_lock(struct fimc_dev *fimc)
+static inline void fimc_md_graph_lock(struct exynos_video_entity *ve)
 {
-       mutex_lock(&fimc->vid_cap.vfd.entity.parent->graph_mutex);
+       mutex_lock(&ve->vdev.entity.parent->graph_mutex);
 }
 
-static inline void fimc_md_graph_unlock(struct fimc_dev *fimc)
+static inline void fimc_md_graph_unlock(struct exynos_video_entity *ve)
 {
-       mutex_unlock(&fimc->vid_cap.vfd.entity.parent->graph_mutex);
+       mutex_unlock(&ve->vdev.entity.parent->graph_mutex);
 }
 
 int fimc_md_set_camclk(struct v4l2_subdev *sd, bool on);
@@ -149,4 +167,16 @@ static inline bool fimc_md_is_isp_available(struct device_node *node)
 #define fimc_md_is_isp_available(node) (false)
 #endif /* CONFIG_OF */
 
+static inline struct v4l2_subdev *__fimc_md_get_subdev(
+                               struct exynos_media_pipeline *ep,
+                               unsigned int index)
+{
+       struct fimc_pipeline *p = to_fimc_pipeline(ep);
+
+       if (!p || index >= IDX_MAX)
+               return NULL;
+       else
+               return p->subdevs[index];
+}
+
 #endif
index 254d70f..0914230 100644 (file)
@@ -1,8 +1,8 @@
 /*
- * Samsung S5P/EXYNOS4 SoC series MIPI-CSI receiver driver
+ * Samsung S5P/EXYNOS SoC series MIPI-CSI receiver driver
  *
- * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd.
- * Sylwester Nawrocki <s.nawrocki@samsung.com>
+ * Copyright (C) 2011 - 2013 Samsung Electronics Co., Ltd.
+ * Author: Sylwester Nawrocki <s.nawrocki@samsung.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -66,11 +66,12 @@ MODULE_PARM_DESC(debug, "Debug level (0-2)");
 
 /* Interrupt mask */
 #define S5PCSIS_INTMSK                 0x10
-#define S5PCSIS_INTMSK_EN_ALL          0xf000103f
 #define S5PCSIS_INTMSK_EVEN_BEFORE     (1 << 31)
 #define S5PCSIS_INTMSK_EVEN_AFTER      (1 << 30)
 #define S5PCSIS_INTMSK_ODD_BEFORE      (1 << 29)
 #define S5PCSIS_INTMSK_ODD_AFTER       (1 << 28)
+#define S5PCSIS_INTMSK_FRAME_START     (1 << 27)
+#define S5PCSIS_INTMSK_FRAME_END       (1 << 26)
 #define S5PCSIS_INTMSK_ERR_SOT_HS      (1 << 12)
 #define S5PCSIS_INTMSK_ERR_LOST_FS     (1 << 5)
 #define S5PCSIS_INTMSK_ERR_LOST_FE     (1 << 4)
@@ -78,6 +79,8 @@ MODULE_PARM_DESC(debug, "Debug level (0-2)");
 #define S5PCSIS_INTMSK_ERR_ECC         (1 << 2)
 #define S5PCSIS_INTMSK_ERR_CRC         (1 << 1)
 #define S5PCSIS_INTMSK_ERR_UNKNOWN     (1 << 0)
+#define S5PCSIS_INTMSK_EXYNOS4_EN_ALL  0xf000103f
+#define S5PCSIS_INTMSK_EXYNOS5_EN_ALL  0xfc00103f
 
 /* Interrupt source */
 #define S5PCSIS_INTSRC                 0x14
@@ -88,6 +91,8 @@ MODULE_PARM_DESC(debug, "Debug level (0-2)");
 #define S5PCSIS_INTSRC_ODD_AFTER       (1 << 28)
 #define S5PCSIS_INTSRC_ODD             (0x3 << 28)
 #define S5PCSIS_INTSRC_NON_IMAGE_DATA  (0xff << 28)
+#define S5PCSIS_INTSRC_FRAME_START     (1 << 27)
+#define S5PCSIS_INTSRC_FRAME_END       (1 << 26)
 #define S5PCSIS_INTSRC_ERR_SOT_HS      (0xf << 12)
 #define S5PCSIS_INTSRC_ERR_LOST_FS     (1 << 5)
 #define S5PCSIS_INTSRC_ERR_LOST_FE     (1 << 4)
@@ -151,6 +156,9 @@ static const struct s5pcsis_event s5pcsis_events[] = {
        { S5PCSIS_INTSRC_EVEN_AFTER,    "Non-image data after even frame" },
        { S5PCSIS_INTSRC_ODD_BEFORE,    "Non-image data before odd frame" },
        { S5PCSIS_INTSRC_ODD_AFTER,     "Non-image data after odd frame" },
+       /* Frame start/end */
+       { S5PCSIS_INTSRC_FRAME_START,   "Frame Start" },
+       { S5PCSIS_INTSRC_FRAME_END,     "Frame End" },
 };
 #define S5PCSIS_NUM_EVENTS ARRAY_SIZE(s5pcsis_events)
 
@@ -159,6 +167,11 @@ struct csis_pktbuf {
        unsigned int len;
 };
 
+struct csis_drvdata {
+       /* Mask of all used interrupts in S5PCSIS_INTMSK register */
+       u32 interrupt_mask;
+};
+
 /**
  * struct csis_state - the driver's internal state data structure
  * @lock: mutex serializing the subdev and power management operations,
@@ -171,6 +184,7 @@ struct csis_pktbuf {
  * @supplies: CSIS regulator supplies
  * @clock: CSIS clocks
  * @irq: requested s5p-mipi-csis irq number
+ * @interrupt_mask: interrupt mask of the all used interrupts
  * @flags: the state variable for power and streaming control
  * @clock_frequency: device bus clock frequency
  * @hs_settle: HS-RX settle time
@@ -193,6 +207,7 @@ struct csis_state {
        struct regulator_bulk_data supplies[CSIS_NUM_SUPPLIES];
        struct clk *clock[NUM_CSIS_CLOCKS];
        int irq;
+       u32 interrupt_mask;
        u32 flags;
 
        u32 clk_frequency;
@@ -274,9 +289,10 @@ static const struct csis_pix_format *find_csis_format(
 static void s5pcsis_enable_interrupts(struct csis_state *state, bool on)
 {
        u32 val = s5pcsis_read(state, S5PCSIS_INTMSK);
-
-       val = on ? val | S5PCSIS_INTMSK_EN_ALL :
-                  val & ~S5PCSIS_INTMSK_EN_ALL;
+       if (on)
+               val |= state->interrupt_mask;
+       else
+               val &= ~state->interrupt_mask;
        s5pcsis_write(state, S5PCSIS_INTMSK, val);
 }
 
@@ -771,8 +787,12 @@ static int s5pcsis_parse_dt(struct platform_device *pdev,
 #define s5pcsis_parse_dt(pdev, state) (-ENOSYS)
 #endif
 
+static const struct of_device_id s5pcsis_of_match[];
+
 static int s5pcsis_probe(struct platform_device *pdev)
 {
+       const struct of_device_id *of_id;
+       const struct csis_drvdata *drv_data;
        struct device *dev = &pdev->dev;
        struct resource *mem_res;
        struct csis_state *state;
@@ -787,10 +807,19 @@ static int s5pcsis_probe(struct platform_device *pdev)
        spin_lock_init(&state->slock);
        state->pdev = pdev;
 
-       if (dev->of_node)
+       if (dev->of_node) {
+               of_id = of_match_node(s5pcsis_of_match, dev->of_node);
+               if (WARN_ON(of_id == NULL))
+                       return -EINVAL;
+
+               drv_data = of_id->data;
+               state->interrupt_mask = drv_data->interrupt_mask;
+
                ret = s5pcsis_parse_dt(pdev, state);
-       else
+       } else {
                ret = s5pcsis_get_platform_data(pdev, state);
+       }
+
        if (ret < 0)
                return ret;
 
@@ -994,9 +1023,25 @@ static const struct dev_pm_ops s5pcsis_pm_ops = {
        SET_SYSTEM_SLEEP_PM_OPS(s5pcsis_suspend, s5pcsis_resume)
 };
 
+static const struct csis_drvdata exynos4_csis_drvdata = {
+       .interrupt_mask = S5PCSIS_INTMSK_EXYNOS4_EN_ALL,
+};
+
+static const struct csis_drvdata exynos5_csis_drvdata = {
+       .interrupt_mask = S5PCSIS_INTMSK_EXYNOS5_EN_ALL,
+};
+
 static const struct of_device_id s5pcsis_of_match[] = {
-       { .compatible = "samsung,s5pv210-csis" },
-       { .compatible = "samsung,exynos4210-csis" },
+       {
+               .compatible = "samsung,s5pv210-csis",
+               .data = &exynos4_csis_drvdata,
+       }, {
+               .compatible = "samsung,exynos4210-csis",
+               .data = &exynos4_csis_drvdata,
+       }, {
+               .compatible = "samsung,exynos5250-csis",
+               .data = &exynos5_csis_drvdata,
+       },
        { /* sentinel */ },
 };
 MODULE_DEVICE_TABLE(of, s5pcsis_of_match);
index 3a6a0dc..221ec42 100644 (file)
@@ -1475,7 +1475,6 @@ static struct video_device viu_template = {
        .release        = video_device_release,
 
        .tvnorms        = V4L2_STD_NTSC_M | V4L2_STD_PAL,
-       .current_norm   = V4L2_STD_NTSC_M,
 };
 
 static int viu_of_probe(struct platform_device *op)
@@ -1546,6 +1545,7 @@ static int viu_of_probe(struct platform_device *op)
        viu_dev->vidq.timeout.function = viu_vid_timeout;
        viu_dev->vidq.timeout.data     = (unsigned long)viu_dev;
        init_timer(&viu_dev->vidq.timeout);
+       viu_dev->std = V4L2_STD_NTSC_M;
        viu_dev->first = 1;
 
        /* Allocate memory for video device */
index 5482363..f1d192b 100644 (file)
@@ -23,7 +23,6 @@
 #include <linux/videodev2.h>
 #include <linux/i2c.h>
 #include <media/v4l2-device.h>
-#include <media/v4l2-chip-ident.h>
 
 #include "indycam.h"
 
@@ -283,20 +282,9 @@ static int indycam_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
 
 /* I2C-interface */
 
-static int indycam_g_chip_ident(struct v4l2_subdev *sd,
-               struct v4l2_dbg_chip_ident *chip)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct indycam *camera = to_indycam(sd);
-
-       return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_INDYCAM,
-                      camera->version);
-}
-
 /* ----------------------------------------------------------------------- */
 
 static const struct v4l2_subdev_core_ops indycam_core_ops = {
-       .g_chip_ident = indycam_g_chip_ident,
        .g_ctrl = indycam_g_ctrl,
        .s_ctrl = indycam_s_ctrl,
 };
index 7585646..540516c 100644 (file)
@@ -1033,6 +1033,7 @@ static int deinterlace_probe(struct platform_device *pdev)
 
        *vfd = deinterlace_videodev;
        vfd->lock = &pcdev->dev_mutex;
+       vfd->v4l2_dev = &pcdev->v4l2_dev;
 
        ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
        if (ret) {
index d030f9b..1f079ff 100644 (file)
@@ -27,7 +27,6 @@
 #include <linux/slab.h>
 #include <linux/videodev2.h>
 #include <media/v4l2-device.h>
-#include <media/v4l2-chip-ident.h>
 #include <linux/device.h>
 #include <linux/wait.h>
 #include <linux/delay.h>
@@ -469,7 +468,7 @@ static int cafe_pci_probe(struct pci_dev *pdev,
                goto out;
        cam->pdev = pdev;
        mcam = &cam->mcam;
-       mcam->chip_id = V4L2_IDENT_CAFE;
+       mcam->chip_id = MCAM_CAFE;
        spin_lock_init(&mcam->dev_lock);
        init_waitqueue_head(&cam->smbus_wait);
        mcam->plat_power_up = cafe_ctlr_power_up;
@@ -501,6 +500,7 @@ static int cafe_pci_probe(struct pci_dev *pdev,
                printk(KERN_ERR "Unable to ioremap cafe-ccic regs\n");
                goto out_disable;
        }
+       mcam->regs_size = pci_resource_len(pdev, 0);
        ret = request_irq(pdev->irq, cafe_irq, IRQF_SHARED, "cafe-ccic", cam);
        if (ret)
                goto out_iounmap;
index 64ab91e..0821ed0 100644 (file)
@@ -23,7 +23,6 @@
 #include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-ctrls.h>
-#include <media/v4l2-chip-ident.h>
 #include <media/ov7670.h>
 #include <media/videobuf2-vmalloc.h>
 #include <media/videobuf2-dma-contig.h>
@@ -336,7 +335,7 @@ static void mcam_ctlr_dma_vmalloc(struct mcam_camera *cam)
                mcam_reg_clear_bit(cam, REG_CTRL1, C1_TWOBUFS);
        } else
                mcam_reg_set_bit(cam, REG_CTRL1, C1_TWOBUFS);
-       if (cam->chip_id == V4L2_IDENT_CAFE)
+       if (cam->chip_id == MCAM_CAFE)
                mcam_reg_write(cam, REG_UBAR, 0); /* 32 bits only */
 }
 
@@ -796,7 +795,6 @@ static int __mcam_cam_reset(struct mcam_camera *cam)
  */
 static int mcam_cam_init(struct mcam_camera *cam)
 {
-       struct v4l2_dbg_chip_ident chip;
        int ret;
 
        mutex_lock(&cam->s_mutex);
@@ -804,24 +802,8 @@ static int mcam_cam_init(struct mcam_camera *cam)
                cam_warn(cam, "Cam init with device in funky state %d",
                                cam->state);
        ret = __mcam_cam_reset(cam);
-       if (ret)
-               goto out;
-       chip.ident = V4L2_IDENT_NONE;
-       chip.match.type = V4L2_CHIP_MATCH_I2C_ADDR;
-       chip.match.addr = cam->sensor_addr;
-       ret = sensor_call(cam, core, g_chip_ident, &chip);
-       if (ret)
-               goto out;
-       cam->sensor_type = chip.ident;
-       if (cam->sensor_type != V4L2_IDENT_OV7670) {
-               cam_err(cam, "Unsupported sensor type 0x%x", cam->sensor_type);
-               ret = -EINVAL;
-               goto out;
-       }
-/* Get/set parameters? */
-       ret = 0;
+       /* Get/set parameters? */
        cam->state = S_IDLE;
-out:
        mcam_ctlr_power_down(cam);
        mutex_unlock(&cam->s_mutex);
        return ret;
@@ -1362,6 +1344,12 @@ static int mcam_vidioc_s_std(struct file *filp, void *priv, v4l2_std_id a)
        return 0;
 }
 
+static int mcam_vidioc_g_std(struct file *filp, void *priv, v4l2_std_id *a)
+{
+       *a = V4L2_STD_NTSC_M;
+       return 0;
+}
+
 /*
  * G/S_PARM.  Most of this is done by the sensor, but we are
  * the level which controls the number of read buffers.
@@ -1392,20 +1380,6 @@ static int mcam_vidioc_s_parm(struct file *filp, void *priv,
        return ret;
 }
 
-static int mcam_vidioc_g_chip_ident(struct file *file, void *priv,
-               struct v4l2_dbg_chip_ident *chip)
-{
-       struct mcam_camera *cam = priv;
-
-       chip->ident = V4L2_IDENT_NONE;
-       chip->revision = 0;
-       if (v4l2_chip_match_host(&chip->match)) {
-               chip->ident = cam->chip_id;
-               return 0;
-       }
-       return sensor_call(cam, core, g_chip_ident, chip);
-}
-
 static int mcam_vidioc_enum_framesizes(struct file *filp, void *priv,
                struct v4l2_frmsizeenum *sizes)
 {
@@ -1436,12 +1410,11 @@ static int mcam_vidioc_g_register(struct file *file, void *priv,
 {
        struct mcam_camera *cam = priv;
 
-       if (v4l2_chip_match_host(&reg->match)) {
-               reg->val = mcam_reg_read(cam, reg->reg);
-               reg->size = 4;
-               return 0;
-       }
-       return sensor_call(cam, core, g_register, reg);
+       if (reg->reg > cam->regs_size - 4)
+               return -EINVAL;
+       reg->val = mcam_reg_read(cam, reg->reg);
+       reg->size = 4;
+       return 0;
 }
 
 static int mcam_vidioc_s_register(struct file *file, void *priv,
@@ -1449,11 +1422,10 @@ static int mcam_vidioc_s_register(struct file *file, void *priv,
 {
        struct mcam_camera *cam = priv;
 
-       if (v4l2_chip_match_host(&reg->match)) {
-               mcam_reg_write(cam, reg->reg, reg->val);
-               return 0;
-       }
-       return sensor_call(cam, core, s_register, reg);
+       if (reg->reg > cam->regs_size - 4)
+               return -EINVAL;
+       mcam_reg_write(cam, reg->reg, reg->val);
+       return 0;
 }
 #endif
 
@@ -1467,6 +1439,7 @@ static const struct v4l2_ioctl_ops mcam_v4l_ioctl_ops = {
        .vidioc_g_input         = mcam_vidioc_g_input,
        .vidioc_s_input         = mcam_vidioc_s_input,
        .vidioc_s_std           = mcam_vidioc_s_std,
+       .vidioc_g_std           = mcam_vidioc_g_std,
        .vidioc_reqbufs         = mcam_vidioc_reqbufs,
        .vidioc_querybuf        = mcam_vidioc_querybuf,
        .vidioc_qbuf            = mcam_vidioc_qbuf,
@@ -1477,7 +1450,6 @@ static const struct v4l2_ioctl_ops mcam_v4l_ioctl_ops = {
        .vidioc_s_parm          = mcam_vidioc_s_parm,
        .vidioc_enum_framesizes = mcam_vidioc_enum_framesizes,
        .vidioc_enum_frameintervals = mcam_vidioc_enum_frameintervals,
-       .vidioc_g_chip_ident    = mcam_vidioc_g_chip_ident,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
        .vidioc_g_register      = mcam_vidioc_g_register,
        .vidioc_s_register      = mcam_vidioc_s_register,
@@ -1593,7 +1565,6 @@ static const struct v4l2_file_operations mcam_v4l_fops = {
 static struct video_device mcam_v4l_template = {
        .name = "mcam",
        .tvnorms = V4L2_STD_NTSC_M,
-       .current_norm = V4L2_STD_NTSC_M,  /* make mplayer happy */
 
        .fops = &mcam_v4l_fops,
        .ioctl_ops = &mcam_v4l_ioctl_ops,
@@ -1695,7 +1666,7 @@ int mccic_register(struct mcam_camera *cam)
        if (buffer_mode >= 0)
                cam->buffer_mode = buffer_mode;
        if (cam->buffer_mode == B_DMA_sg &&
-                       cam->chip_id == V4L2_IDENT_CAFE) {
+                       cam->chip_id == MCAM_CAFE) {
                printk(KERN_ERR "marvell-cam: Cafe can't do S/G I/O, "
                        "attempting vmalloc mode instead\n");
                cam->buffer_mode = B_vmalloc;
index 01dec9e..520c8de 100644 (file)
@@ -53,6 +53,11 @@ enum mcam_buffer_mode {
        B_DMA_sg = 2
 };
 
+enum mcam_chip_id {
+       MCAM_CAFE,
+       MCAM_ARMADA610,
+};
+
 /*
  * Is a given buffer mode supported by the current kernel configuration?
  */
@@ -96,9 +101,10 @@ struct mcam_camera {
         */
        struct i2c_adapter *i2c_adapter;
        unsigned char __iomem *regs;
+       unsigned regs_size; /* size in bytes of the register space */
        spinlock_t dev_lock;
        struct device *dev; /* For messages, dma alloc */
-       unsigned int chip_id;
+       enum mcam_chip_id chip_id;
        short int clock_speed;  /* Sensor clock speed, default 30 */
        short int use_smbus;    /* SMBUS or straight I2c? */
        enum mcam_buffer_mode buffer_mode;
@@ -152,7 +158,6 @@ struct mcam_camera {
        void (*frame_complete)(struct mcam_camera *cam, int frame);
 
        /* Current operating parameters */
-       u32 sensor_type;                /* Currently ov7670 only */
        struct v4l2_pix_format pix_format;
        enum v4l2_mbus_pixelcode mbus_code;
 
index c4c17fe..a634888 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/slab.h>
 #include <linux/videodev2.h>
 #include <media/v4l2-device.h>
-#include <media/v4l2-chip-ident.h>
 #include <media/mmp-camera.h>
 #include <linux/device.h>
 #include <linux/platform_device.h>
@@ -185,7 +184,7 @@ static int mmpcam_probe(struct platform_device *pdev)
        mcam->plat_power_down = mmpcam_power_down;
        mcam->dev = &pdev->dev;
        mcam->use_smbus = 0;
-       mcam->chip_id = V4L2_IDENT_ARMADA610;
+       mcam->chip_id = MCAM_ARMADA610;
        mcam->buffer_mode = B_DMA_sg;
        spin_lock_init(&mcam->dev_lock);
        /*
@@ -203,6 +202,7 @@ static int mmpcam_probe(struct platform_device *pdev)
                ret = -ENODEV;
                goto out_free;
        }
+       mcam->regs_size = resource_size(res);
        /*
         * Power/clock memory is elsewhere; get it too.  Perhaps this
         * should really be managed outside of this driver?
index 4cc7f65..6a17676 100644 (file)
@@ -1051,6 +1051,7 @@ static int m2mtest_probe(struct platform_device *pdev)
 
        *vfd = m2mtest_videodev;
        vfd->lock = &dev->dev_mutex;
+       vfd->v4l2_dev = &dev->v4l2_dev;
 
        ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
        if (ret) {
@@ -1061,7 +1062,7 @@ static int m2mtest_probe(struct platform_device *pdev)
        video_set_drvdata(vfd, dev);
        snprintf(vfd->name, sizeof(vfd->name), "%s", m2mtest_videodev.name);
        dev->vfd = vfd;
-       v4l2_info(&dev->v4l2_dev, MEM2MEM_TEST_MODULE_NAME
+       v4l2_info(&dev->v4l2_dev,
                        "Device registered as /dev/video%d\n", vfd->num);
 
        setup_timer(&dev->timer, device_isr, (long)dev);
index f7440e5..c690435 100644 (file)
@@ -937,6 +937,7 @@ static int emmaprp_probe(struct platform_device *pdev)
 
        *vfd = emmaprp_videodev;
        vfd->lock = &pcdev->dev_mutex;
+       vfd->v4l2_dev = &pcdev->v4l2_dev;
 
        video_set_drvdata(vfd, pcdev);
        snprintf(vfd->name, sizeof(vfd->name), "%s", emmaprp_videodev.name);
index d338b19..dfd0a21 100644 (file)
@@ -335,8 +335,6 @@ static int video_mode_to_dss_mode(struct omap_vout_device *vout)
        ovl = ovid->overlays[0];
 
        switch (pix->pixelformat) {
-       case 0:
-               break;
        case V4L2_PIX_FMT_YUYV:
                mode = OMAP_DSS_COLOR_YUV2;
                break;
@@ -358,6 +356,7 @@ static int video_mode_to_dss_mode(struct omap_vout_device *vout)
                break;
        default:
                mode = -EINVAL;
+               break;
        }
        return mode;
 }
index debb44c..d2b440c 100644 (file)
@@ -1656,7 +1656,7 @@ static int omap24xxcam_device_register(struct v4l2_int_device *s)
        }
        vfd->release = video_device_release;
 
-       vfd->parent = cam->dev;
+       vfd->v4l2_dev = &cam->v4l2_dev;
 
        strlcpy(vfd->name, CAM_NAME, sizeof(vfd->name));
        vfd->fops                = &omap24xxcam_fops;
@@ -1752,6 +1752,11 @@ static int omap24xxcam_probe(struct platform_device *pdev)
 
        cam->dev = &pdev->dev;
 
+       if (v4l2_device_register(&pdev->dev, &cam->v4l2_dev)) {
+               dev_err(&pdev->dev, "v4l2_device_register failed\n");
+               goto err;
+       }
+
        /*
         * Impose a lower limit on the amount of memory allocated for
         * capture. We require at least enough memory to double-buffer
@@ -1849,6 +1854,8 @@ static int omap24xxcam_remove(struct platform_device *pdev)
                cam->mmio_base_phys = 0;
        }
 
+       v4l2_device_unregister(&cam->v4l2_dev);
+
        kfree(cam);
 
        return 0;
index c439595..7f6f791 100644 (file)
@@ -29,6 +29,7 @@
 
 #include <media/videobuf-dma-sg.h>
 #include <media/v4l2-int-device.h>
+#include <media/v4l2-device.h>
 
 /*
  *
@@ -462,6 +463,8 @@ struct omap24xxcam_device {
         */
        struct mutex mutex;
 
+       struct v4l2_device v4l2_dev;
+
        /*** general driver state information ***/
        atomic_t users;
        /*
index 1d7dbd5..df3a0ec 100644 (file)
@@ -792,9 +792,9 @@ int omap3isp_pipeline_pm_use(struct media_entity *entity, int use)
 
 /*
  * isp_pipeline_link_notify - Link management notification callback
- * @source: Pad at the start of the link
- * @sink: Pad at the end of the link
+ * @link: The link
  * @flags: New link flags that will be applied
+ * @notification: The link's state change notification type (MEDIA_DEV_NOTIFY_*)
  *
  * React to link management on powered pipelines by updating the use count of
  * all entities in the source and sink sides of the link. Entities are powered
@@ -804,29 +804,38 @@ int omap3isp_pipeline_pm_use(struct media_entity *entity, int use)
  * off is assumed to never fail. This function will not fail for disconnection
  * events.
  */
-static int isp_pipeline_link_notify(struct media_pad *source,
-                                   struct media_pad *sink, u32 flags)
+static int isp_pipeline_link_notify(struct media_link *link, u32 flags,
+                                   unsigned int notification)
 {
-       int source_use = isp_pipeline_pm_use_count(source->entity);
-       int sink_use = isp_pipeline_pm_use_count(sink->entity);
+       struct media_entity *source = link->source->entity;
+       struct media_entity *sink = link->sink->entity;
+       int source_use = isp_pipeline_pm_use_count(source);
+       int sink_use = isp_pipeline_pm_use_count(sink);
        int ret;
 
-       if (!(flags & MEDIA_LNK_FL_ENABLED)) {
+       if (notification == MEDIA_DEV_NOTIFY_POST_LINK_CH &&
+           !(link->flags & MEDIA_LNK_FL_ENABLED)) {
                /* Powering off entities is assumed to never fail. */
-               isp_pipeline_pm_power(source->entity, -sink_use);
-               isp_pipeline_pm_power(sink->entity, -source_use);
+               isp_pipeline_pm_power(source, -sink_use);
+               isp_pipeline_pm_power(sink, -source_use);
                return 0;
        }
 
-       ret = isp_pipeline_pm_power(source->entity, sink_use);
-       if (ret < 0)
-               return ret;
+       if (notification == MEDIA_DEV_NOTIFY_POST_LINK_CH &&
+               (flags & MEDIA_LNK_FL_ENABLED)) {
 
-       ret = isp_pipeline_pm_power(sink->entity, source_use);
-       if (ret < 0)
-               isp_pipeline_pm_power(source->entity, -sink_use);
+               ret = isp_pipeline_pm_power(source, sink_use);
+               if (ret < 0)
+                       return ret;
 
-       return ret;
+               ret = isp_pipeline_pm_power(sink, source_use);
+               if (ret < 0)
+                       isp_pipeline_pm_power(source, -sink_use);
+
+               return ret;
+       }
+
+       return 0;
 }
 
 /* -----------------------------------------------------------------------------
@@ -877,7 +886,7 @@ static int isp_pipeline_enable(struct isp_pipeline *pipe,
                if (!(pad->flags & MEDIA_PAD_FL_SINK))
                        break;
 
-               pad = media_entity_remote_source(pad);
+               pad = media_entity_remote_pad(pad);
                if (pad == NULL ||
                    media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
                        break;
@@ -967,7 +976,7 @@ static int isp_pipeline_disable(struct isp_pipeline *pipe)
                if (!(pad->flags & MEDIA_PAD_FL_SINK))
                        break;
 
-               pad = media_entity_remote_source(pad);
+               pad = media_entity_remote_pad(pad);
                if (pad == NULL ||
                    media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
                        break;
@@ -1083,7 +1092,7 @@ static int isp_pipeline_is_last(struct media_entity *me)
        pipe = to_isp_pipeline(me);
        if (pipe->stream_state == ISP_PIPELINE_STREAM_STOPPED)
                return 0;
-       pad = media_entity_remote_source(&pipe->output->pad);
+       pad = media_entity_remote_pad(&pipe->output->pad);
        return pad->entity == me;
 }
 
@@ -2249,6 +2258,7 @@ static int isp_probe(struct platform_device *pdev)
        ret = iommu_attach_device(isp->domain, &pdev->dev);
        if (ret) {
                dev_err(&pdev->dev, "can't attach iommu device: %d\n", ret);
+               ret = -EPROBE_DEFER;
                goto free_domain;
        }
 
@@ -2287,12 +2297,11 @@ detach_dev:
        iommu_detach_device(isp->domain, &pdev->dev);
 free_domain:
        iommu_domain_free(isp->domain);
+       isp->domain = NULL;
 error_isp:
        isp_xclk_cleanup(isp);
        omap3isp_put(isp);
 error:
-       platform_set_drvdata(pdev, NULL);
-
        mutex_destroy(&isp->isp_mutex);
 
        return ret;
index 60e60aa..907a205 100644 (file)
@@ -1120,7 +1120,7 @@ static void ccdc_configure(struct isp_ccdc_device *ccdc)
        u32 syn_mode;
        u32 ccdc_pattern;
 
-       pad = media_entity_remote_source(&ccdc->pads[CCDC_PAD_SINK]);
+       pad = media_entity_remote_pad(&ccdc->pads[CCDC_PAD_SINK]);
        sensor = media_entity_to_v4l2_subdev(pad->entity);
        if (ccdc->input == CCDC_INPUT_PARALLEL)
                pdata = &((struct isp_v4l2_subdevs_group *)sensor->host_priv)
index c5d84c9..e716514 100644 (file)
@@ -158,13 +158,17 @@ static void ccp2_pwr_cfg(struct isp_ccp2_device *ccp2)
  * @ccp2: pointer to ISP CCP2 device
  * @enable: enable/disable flag
  */
-static void ccp2_if_enable(struct isp_ccp2_device *ccp2, u8 enable)
+static int ccp2_if_enable(struct isp_ccp2_device *ccp2, u8 enable)
 {
        struct isp_device *isp = to_isp_device(ccp2);
+       int ret;
        int i;
 
-       if (enable && ccp2->vdds_csib)
-               regulator_enable(ccp2->vdds_csib);
+       if (enable && ccp2->vdds_csib) {
+               ret = regulator_enable(ccp2->vdds_csib);
+               if (ret < 0)
+                       return ret;
+       }
 
        /* Enable/Disable all the LCx channels */
        for (i = 0; i < CCP2_LCx_CHANS_NUM; i++)
@@ -179,6 +183,8 @@ static void ccp2_if_enable(struct isp_ccp2_device *ccp2, u8 enable)
 
        if (!enable && ccp2->vdds_csib)
                regulator_disable(ccp2->vdds_csib);
+
+       return 0;
 }
 
 /*
@@ -360,7 +366,7 @@ static int ccp2_if_configure(struct isp_ccp2_device *ccp2)
 
        ccp2_pwr_cfg(ccp2);
 
-       pad = media_entity_remote_source(&ccp2->pads[CCP2_PAD_SINK]);
+       pad = media_entity_remote_pad(&ccp2->pads[CCP2_PAD_SINK]);
        sensor = media_entity_to_v4l2_subdev(pad->entity);
        pdata = sensor->host_priv;
 
@@ -851,7 +857,12 @@ static int ccp2_s_stream(struct v4l2_subdev *sd, int enable)
                ccp2_print_status(ccp2);
 
                /* Enable CSI1/CCP2 interface */
-               ccp2_if_enable(ccp2, 1);
+               ret = ccp2_if_enable(ccp2, 1);
+               if (ret < 0) {
+                       if (ccp2->phy)
+                               omap3isp_csiphy_release(ccp2->phy);
+                       return ret;
+               }
                break;
 
        case ISP_PIPELINE_STREAM_SINGLESHOT:
index 783f4b0..6db245d 100644 (file)
@@ -573,7 +573,7 @@ static int csi2_configure(struct isp_csi2_device *csi2)
        if (csi2->contexts[0].enabled || csi2->ctrl.if_enable)
                return -EBUSY;
 
-       pad = media_entity_remote_source(&csi2->pads[CSI2_PAD_SINK]);
+       pad = media_entity_remote_pad(&csi2->pads[CSI2_PAD_SINK]);
        sensor = media_entity_to_v4l2_subdev(pad->entity);
        pdata = sensor->host_priv;
 
index 908dfd7..3e048ad 100644 (file)
@@ -28,6 +28,7 @@
 
 #include <linux/kernel.h>
 #include <linux/list.h>
+#include <linux/mm_types.h>
 #include <linux/mutex.h>
 #include <linux/videodev2.h>
 #include <linux/wait.h>
index 8dac175..a908d00 100644 (file)
@@ -219,7 +219,7 @@ isp_video_remote_subdev(struct isp_video *video, u32 *pad)
 {
        struct media_pad *remote;
 
-       remote = media_entity_remote_source(&video->pad);
+       remote = media_entity_remote_pad(&video->pad);
 
        if (remote == NULL ||
            media_entity_type(remote->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
@@ -314,7 +314,7 @@ static int isp_video_validate_pipeline(struct isp_pipeline *pipe)
                 * entity can be found, and stop checking the pipeline if the
                 * source entity isn't a subdev.
                 */
-               pad = media_entity_remote_source(pad);
+               pad = media_entity_remote_pad(pad);
                if (pad == NULL)
                        return -EPIPE;
 
@@ -901,7 +901,7 @@ static int isp_video_check_external_subdevs(struct isp_video *video,
                        continue;
 
                /* ISP entities have always sink pad == 0. Find source. */
-               source_pad = media_entity_remote_source(&ents[i]->pads[0]);
+               source_pad = media_entity_remote_pad(&ents[i]->pads[0]);
                if (source_pad == NULL)
                        continue;
 
index 70438a0..40b298a 100644 (file)
@@ -845,7 +845,7 @@ static int camif_pipeline_validate(struct camif_dev *camif)
        int ret;
 
        /* Retrieve format at the sensor subdev source pad */
-       pad = media_entity_remote_source(&camif->pads[0]);
+       pad = media_entity_remote_pad(&camif->pads[0]);
        if (!pad || media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
                return -EPIPE;
 
index 0d0fab1..b385747 100644 (file)
@@ -341,10 +341,11 @@ static void camif_clk_put(struct camif_dev *camif)
        int i;
 
        for (i = 0; i < CLK_MAX_NUM; i++) {
-               if (IS_ERR_OR_NULL(camif->clock[i]))
+               if (IS_ERR(camif->clock[i]))
                        continue;
                clk_unprepare(camif->clock[i]);
                clk_put(camif->clock[i]);
+               camif->clock[i] = ERR_PTR(-EINVAL);
        }
 }
 
@@ -352,6 +353,9 @@ static int camif_clk_get(struct camif_dev *camif)
 {
        int ret, i;
 
+       for (i = 1; i < CLK_MAX_NUM; i++)
+               camif->clock[i] = ERR_PTR(-EINVAL);
+
        for (i = 0; i < CLK_MAX_NUM; i++) {
                camif->clock[i] = clk_get(camif->dev, camif_clocks[i]);
                if (IS_ERR(camif->clock[i])) {
index 1a3b4fc..a9e3b16 100644 (file)
@@ -379,7 +379,7 @@ static void camif_hw_set_prescaler(struct camif_vp *vp)
        camif_write(camif, S3C_CAMIF_REG_CISCPREDST(vp->id, vp->offset), cfg);
 }
 
-void camif_s3c244x_hw_set_scaler(struct camif_vp *vp)
+static void camif_s3c244x_hw_set_scaler(struct camif_vp *vp)
 {
        struct camif_dev *camif = vp->camif;
        struct camif_scaler *scaler = &vp->scaler;
@@ -426,7 +426,7 @@ void camif_s3c244x_hw_set_scaler(struct camif_vp *vp)
                 scaler->main_h_ratio, scaler->main_v_ratio);
 }
 
-void camif_s3c64xx_hw_set_scaler(struct camif_vp *vp)
+static void camif_s3c64xx_hw_set_scaler(struct camif_vp *vp)
 {
        struct camif_dev *camif = vp->camif;
        struct camif_scaler *scaler = &vp->scaler;
@@ -601,6 +601,6 @@ void camif_hw_dump_regs(struct camif_dev *camif, const char *label)
        pr_info("--- %s ---\n", label);
        for (i = 0; i < ARRAY_SIZE(registers); i++) {
                u32 cfg = readl(camif->io_base + registers[i].offset);
-               printk(KERN_INFO "%s:\t0x%08x\n", registers[i].name, cfg);
+               dev_info(camif->dev, "%s:\t0x%08x\n", registers[i].name, cfg);
        }
 }
index d12faa6..a130dcd 100644 (file)
@@ -1424,7 +1424,7 @@ static void *mfc_get_drv_data(struct platform_device *pdev)
 
        if (pdev->dev.of_node) {
                const struct of_device_id *match;
-               match = of_match_node(of_match_ptr(exynos_mfc_match),
+               match = of_match_node(exynos_mfc_match,
                                pdev->dev.of_node);
                if (match)
                        driver_data = (struct s5p_mfc_variant *)match->data;
index 4e86626..1b34c36 100644 (file)
@@ -576,16 +576,22 @@ static int hdmi_s_stream(struct v4l2_subdev *sd, int enable)
        return hdmi_streamoff(hdev);
 }
 
-static void hdmi_resource_poweron(struct hdmi_resources *res)
+static int hdmi_resource_poweron(struct hdmi_resources *res)
 {
+       int ret;
+
        /* turn HDMI power on */
-       regulator_bulk_enable(res->regul_count, res->regul_bulk);
+       ret = regulator_bulk_enable(res->regul_count, res->regul_bulk);
+       if (ret < 0)
+               return ret;
        /* power-on hdmi physical interface */
        clk_enable(res->hdmiphy);
        /* use VPP as parent clock; HDMIPHY is not working yet */
        clk_set_parent(res->sclk_hdmi, res->sclk_pixel);
        /* turn clocks on */
        clk_enable(res->sclk_hdmi);
+
+       return 0;
 }
 
 static void hdmi_resource_poweroff(struct hdmi_resources *res)
@@ -728,11 +734,13 @@ static int hdmi_runtime_resume(struct device *dev)
 {
        struct v4l2_subdev *sd = dev_get_drvdata(dev);
        struct hdmi_device *hdev = sd_to_hdmi_dev(sd);
-       int ret = 0;
+       int ret;
 
        dev_dbg(dev, "%s\n", __func__);
 
-       hdmi_resource_poweron(&hdev->res);
+       ret = hdmi_resource_poweron(&hdev->res);
+       if (ret < 0)
+               return ret;
 
        /* starting MHL */
        ret = v4l2_subdev_call(hdev->mhl_sd, core, s_power, 1);
@@ -755,6 +763,15 @@ static const struct dev_pm_ops hdmi_pm_ops = {
        .runtime_resume  = hdmi_runtime_resume,
 };
 
+static void hdmi_resource_clear_clocks(struct hdmi_resources *res)
+{
+       res->hdmi        = ERR_PTR(-EINVAL);
+       res->sclk_hdmi   = ERR_PTR(-EINVAL);
+       res->sclk_pixel  = ERR_PTR(-EINVAL);
+       res->sclk_hdmiphy = ERR_PTR(-EINVAL);
+       res->hdmiphy     = ERR_PTR(-EINVAL);
+}
+
 static void hdmi_resources_cleanup(struct hdmi_device *hdev)
 {
        struct hdmi_resources *res = &hdev->res;
@@ -765,17 +782,18 @@ static void hdmi_resources_cleanup(struct hdmi_device *hdev)
                regulator_bulk_free(res->regul_count, res->regul_bulk);
        /* kfree is NULL-safe */
        kfree(res->regul_bulk);
-       if (!IS_ERR_OR_NULL(res->hdmiphy))
+       if (!IS_ERR(res->hdmiphy))
                clk_put(res->hdmiphy);
-       if (!IS_ERR_OR_NULL(res->sclk_hdmiphy))
+       if (!IS_ERR(res->sclk_hdmiphy))
                clk_put(res->sclk_hdmiphy);
-       if (!IS_ERR_OR_NULL(res->sclk_pixel))
+       if (!IS_ERR(res->sclk_pixel))
                clk_put(res->sclk_pixel);
-       if (!IS_ERR_OR_NULL(res->sclk_hdmi))
+       if (!IS_ERR(res->sclk_hdmi))
                clk_put(res->sclk_hdmi);
-       if (!IS_ERR_OR_NULL(res->hdmi))
+       if (!IS_ERR(res->hdmi))
                clk_put(res->hdmi);
        memset(res, 0, sizeof(*res));
+       hdmi_resource_clear_clocks(res);
 }
 
 static int hdmi_resources_init(struct hdmi_device *hdev)
@@ -793,8 +811,9 @@ static int hdmi_resources_init(struct hdmi_device *hdev)
        dev_dbg(dev, "HDMI resource init\n");
 
        memset(res, 0, sizeof(*res));
-       /* get clocks, power */
+       hdmi_resource_clear_clocks(res);
 
+       /* get clocks, power */
        res->hdmi = clk_get(dev, "hdmi");
        if (IS_ERR(res->hdmi)) {
                dev_err(dev, "failed to get clock 'hdmi'\n");
index 5733033..51805a5 100644 (file)
@@ -211,6 +211,15 @@ fail:
        return ret;
 }
 
+static void mxr_resource_clear_clocks(struct mxr_resources *res)
+{
+       res->mixer      = ERR_PTR(-EINVAL);
+       res->vp         = ERR_PTR(-EINVAL);
+       res->sclk_mixer = ERR_PTR(-EINVAL);
+       res->sclk_hdmi  = ERR_PTR(-EINVAL);
+       res->sclk_dac   = ERR_PTR(-EINVAL);
+}
+
 static void mxr_release_plat_resources(struct mxr_device *mdev)
 {
        free_irq(mdev->res.irq, mdev);
@@ -222,15 +231,15 @@ static void mxr_release_clocks(struct mxr_device *mdev)
 {
        struct mxr_resources *res = &mdev->res;
 
-       if (!IS_ERR_OR_NULL(res->sclk_dac))
+       if (!IS_ERR(res->sclk_dac))
                clk_put(res->sclk_dac);
-       if (!IS_ERR_OR_NULL(res->sclk_hdmi))
+       if (!IS_ERR(res->sclk_hdmi))
                clk_put(res->sclk_hdmi);
-       if (!IS_ERR_OR_NULL(res->sclk_mixer))
+       if (!IS_ERR(res->sclk_mixer))
                clk_put(res->sclk_mixer);
-       if (!IS_ERR_OR_NULL(res->vp))
+       if (!IS_ERR(res->vp))
                clk_put(res->vp);
-       if (!IS_ERR_OR_NULL(res->mixer))
+       if (!IS_ERR(res->mixer))
                clk_put(res->mixer);
 }
 
@@ -239,6 +248,8 @@ static int mxr_acquire_clocks(struct mxr_device *mdev)
        struct mxr_resources *res = &mdev->res;
        struct device *dev = mdev->dev;
 
+       mxr_resource_clear_clocks(res);
+
        res->mixer = clk_get(dev, "mixer");
        if (IS_ERR(res->mixer)) {
                mxr_err(mdev, "failed to get clock 'mixer'\n");
@@ -299,6 +310,7 @@ static void mxr_release_resources(struct mxr_device *mdev)
        mxr_release_clocks(mdev);
        mxr_release_plat_resources(mdev);
        memset(&mdev->res, 0, sizeof(mdev->res));
+       mxr_resource_clear_clocks(&mdev->res);
 }
 
 static void mxr_release_layers(struct mxr_device *mdev)
index ef0efdf..641b1f0 100644 (file)
@@ -81,8 +81,9 @@ int mxr_acquire_video(struct mxr_device *mdev,
        }
 
        mdev->alloc_ctx = vb2_dma_contig_init_ctx(mdev->dev);
-       if (IS_ERR_OR_NULL(mdev->alloc_ctx)) {
+       if (IS_ERR(mdev->alloc_ctx)) {
                mxr_err(mdev, "could not acquire vb2 allocator\n");
+               ret = PTR_ERR(mdev->alloc_ctx);
                goto fail_v4l2_dev;
        }
 
index ab6f9ef..0afa90f 100644 (file)
@@ -262,11 +262,21 @@ static int sdo_runtime_resume(struct device *dev)
 {
        struct v4l2_subdev *sd = dev_get_drvdata(dev);
        struct sdo_device *sdev = sd_to_sdev(sd);
+       int ret;
 
        dev_info(dev, "resume\n");
-       clk_enable(sdev->sclk_dac);
-       regulator_enable(sdev->vdac);
-       regulator_enable(sdev->vdet);
+
+       ret = clk_enable(sdev->sclk_dac);
+       if (ret < 0)
+               return ret;
+
+       ret = regulator_enable(sdev->vdac);
+       if (ret < 0)
+               goto dac_clk_dis;
+
+       ret = regulator_enable(sdev->vdet);
+       if (ret < 0)
+               goto vdac_r_dis;
 
        /* software reset */
        sdo_write_mask(sdev, SDO_CLKCON, ~0, SDO_TVOUT_SW_RESET);
@@ -285,6 +295,12 @@ static int sdo_runtime_resume(struct device *dev)
                SDO_COMPENSATION_CVBS_COMP_OFF);
        sdo_reg_debug(sdev);
        return 0;
+
+vdac_r_dis:
+       regulator_disable(sdev->vdac);
+dac_clk_dis:
+       clk_disable(sdev->sclk_dac);
+       return ret;
 }
 
 static const struct dev_pm_ops sdo_pm_ops = {
index 39b77d2..3dd762e 100644 (file)
@@ -249,7 +249,9 @@ static int sii9234_runtime_resume(struct device *dev)
        int ret;
 
        dev_info(dev, "resume start\n");
-       regulator_enable(ctx->power);
+       ret = regulator_enable(ctx->power);
+       if (ret < 0)
+               return ret;
 
        ret = sii9234_reset(ctx);
        if (ret)
index 59a9dee..aa4cca3 100644 (file)
@@ -359,10 +359,7 @@ static int sh_veu_context_init(struct sh_veu_dev *veu)
        veu->m2m_ctx = v4l2_m2m_ctx_init(veu->m2m_dev, veu,
                                         sh_veu_queue_init);
 
-       if (IS_ERR(veu->m2m_ctx))
-               return PTR_ERR(veu->m2m_ctx);
-
-       return 0;
+       return PTR_RET(veu->m2m_ctx);
 }
 
 static int sh_veu_querycap(struct file *file, void *priv,
index 7d02350..7a9c5e9 100644 (file)
@@ -1248,32 +1248,6 @@ static unsigned int sh_vou_poll(struct file *file, poll_table *wait)
        return res;
 }
 
-static int sh_vou_g_chip_ident(struct file *file, void *fh,
-                                  struct v4l2_dbg_chip_ident *id)
-{
-       struct sh_vou_device *vou_dev = video_drvdata(file);
-
-       return v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, core, g_chip_ident, id);
-}
-
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-static int sh_vou_g_register(struct file *file, void *fh,
-                                struct v4l2_dbg_register *reg)
-{
-       struct sh_vou_device *vou_dev = video_drvdata(file);
-
-       return v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, core, g_register, reg);
-}
-
-static int sh_vou_s_register(struct file *file, void *fh,
-                                const struct v4l2_dbg_register *reg)
-{
-       struct sh_vou_device *vou_dev = video_drvdata(file);
-
-       return v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, core, s_register, reg);
-}
-#endif
-
 /* sh_vou display ioctl operations */
 static const struct v4l2_ioctl_ops sh_vou_ioctl_ops = {
        .vidioc_querycap                = sh_vou_querycap,
@@ -1292,11 +1266,6 @@ static const struct v4l2_ioctl_ops sh_vou_ioctl_ops = {
        .vidioc_cropcap                 = sh_vou_cropcap,
        .vidioc_g_crop                  = sh_vou_g_crop,
        .vidioc_s_crop                  = sh_vou_s_crop,
-       .vidioc_g_chip_ident            = sh_vou_g_chip_ident,
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-       .vidioc_g_register              = sh_vou_g_register,
-       .vidioc_s_register              = sh_vou_s_register,
-#endif
 };
 
 static const struct v4l2_file_operations sh_vou_fops = {
@@ -1313,7 +1282,6 @@ static const struct video_device sh_vou_video_template = {
        .fops           = &sh_vou_fops,
        .ioctl_ops      = &sh_vou_ioctl_ops,
        .tvnorms        = V4L2_STD_525_60, /* PAL only supported in 8-bit non-bt656 mode */
-       .current_norm   = V4L2_STD_NTSC_M,
        .vfl_dir        = VFL_DIR_TX,
 };
 
@@ -1352,7 +1320,7 @@ static int sh_vou_probe(struct platform_device *pdev)
        pix = &vou_dev->pix;
 
        /* Fill in defaults */
-       vou_dev->std            = sh_vou_video_template.current_norm;
+       vou_dev->std            = V4L2_STD_NTSC_M;
        rect->left              = 0;
        rect->top               = 0;
        rect->width             = VOU_MAX_IMAGE_WIDTH;
index b139b52..626dccc 100644 (file)
@@ -8,6 +8,9 @@ config SOC_CAMERA
          over a bus like PCI or USB. For example some i2c camera connected
          directly to the data bus of an SoC.
 
+config SOC_CAMERA_SCALE_CROP
+       tristate
+
 config SOC_CAMERA_PLATFORM
        tristate "platform camera support"
        depends on SOC_CAMERA
@@ -27,14 +30,10 @@ config VIDEO_MX1
        ---help---
          This is a v4l2 driver for the i.MX1/i.MXL CMOS Sensor Interface
 
-config MX3_VIDEO
-       bool
-
 config VIDEO_MX3
        tristate "i.MX3x Camera Sensor Interface driver"
        depends on VIDEO_DEV && MX3_IPU && SOC_CAMERA
        select VIDEOBUF2_DMA_CONTIG
-       select MX3_VIDEO
        ---help---
          This is a v4l2 driver for the i.MX3x Camera Sensor Interface
 
@@ -55,6 +54,7 @@ config VIDEO_SH_MOBILE_CEU
        tristate "SuperH Mobile CEU Interface driver"
        depends on VIDEO_DEV && SOC_CAMERA && HAS_DMA && HAVE_CLK
        select VIDEOBUF2_DMA_CONTIG
+       select SOC_CAMERA_SCALE_CROP
        ---help---
          This is a v4l2 driver for the SuperH Mobile CEU Interface
 
@@ -66,14 +66,10 @@ config VIDEO_OMAP1
        ---help---
          This is a v4l2 driver for the TI OMAP1 camera interface
 
-config VIDEO_MX2_HOSTSUPPORT
-       bool
-
 config VIDEO_MX2
        tristate "i.MX27 Camera Sensor Interface driver"
        depends on VIDEO_DEV && SOC_CAMERA && MACH_MX27
        select VIDEOBUF2_DMA_CONTIG
-       select VIDEO_MX2_HOSTSUPPORT
        ---help---
          This is a v4l2 driver for the i.MX27 Camera Sensor Interface
 
index 136b7f8..3918622 100644 (file)
@@ -1,4 +1,8 @@
 obj-$(CONFIG_SOC_CAMERA)               += soc_camera.o soc_mediabus.o
+obj-$(CONFIG_SOC_CAMERA_SCALE_CROP)    += soc_scale_crop.o
+
+# a platform subdevice driver stub, allowing to support cameras by adding a
+# couple of callback functions to the board code
 obj-$(CONFIG_SOC_CAMERA_PLATFORM)      += soc_camera_platform.o
 
 # soc-camera host drivers have to be linked after camera drivers
@@ -10,5 +14,3 @@ obj-$(CONFIG_VIDEO_OMAP1)             += omap1_camera.o
 obj-$(CONFIG_VIDEO_PXA27x)             += pxa_camera.o
 obj-$(CONFIG_VIDEO_SH_MOBILE_CEU)      += sh_mobile_ceu_camera.o
 obj-$(CONFIG_VIDEO_SH_MOBILE_CSI2)     += sh_mobile_csi2.o
-
-ccflags-y += -I$(srctree)/drivers/media/i2c/soc_camera
index 1abbb36..1044856 100644 (file)
@@ -102,7 +102,6 @@ struct atmel_isi {
        struct list_head                video_buffer_list;
        struct frame_buffer             *active;
 
-       struct soc_camera_device        *icd;
        struct soc_camera_host          soc_host;
 };
 
@@ -367,7 +366,7 @@ static void start_dma(struct atmel_isi *isi, struct frame_buffer *buffer)
 
        /* Check if already in a frame */
        if (isi_readl(isi, ISI_STATUS) & ISI_CTRL_CDC) {
-               dev_err(isi->icd->parent, "Already in frame handling.\n");
+               dev_err(isi->soc_host.icd->parent, "Already in frame handling.\n");
                return;
        }
 
@@ -746,16 +745,26 @@ static int isi_camera_get_formats(struct soc_camera_device *icd,
        return formats;
 }
 
-/* Called with .host_lock held */
 static int isi_camera_add_device(struct soc_camera_device *icd)
 {
-       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+       dev_dbg(icd->parent, "Atmel ISI Camera driver attached to camera %d\n",
+                icd->devnum);
+
+       return 0;
+}
+
+static void isi_camera_remove_device(struct soc_camera_device *icd)
+{
+       dev_dbg(icd->parent, "Atmel ISI Camera driver detached from camera %d\n",
+                icd->devnum);
+}
+
+/* Called with .host_lock held */
+static int isi_camera_clock_start(struct soc_camera_host *ici)
+{
        struct atmel_isi *isi = ici->priv;
        int ret;
 
-       if (isi->icd)
-               return -EBUSY;
-
        ret = clk_enable(isi->pclk);
        if (ret)
                return ret;
@@ -766,25 +775,16 @@ static int isi_camera_add_device(struct soc_camera_device *icd)
                return ret;
        }
 
-       isi->icd = icd;
-       dev_dbg(icd->parent, "Atmel ISI Camera driver attached to camera %d\n",
-                icd->devnum);
        return 0;
 }
+
 /* Called with .host_lock held */
-static void isi_camera_remove_device(struct soc_camera_device *icd)
+static void isi_camera_clock_stop(struct soc_camera_host *ici)
 {
-       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct atmel_isi *isi = ici->priv;
 
-       BUG_ON(icd != isi->icd);
-
        clk_disable(isi->mck);
        clk_disable(isi->pclk);
-       isi->icd = NULL;
-
-       dev_dbg(icd->parent, "Atmel ISI Camera driver detached from camera %d\n",
-                icd->devnum);
 }
 
 static unsigned int isi_camera_poll(struct file *file, poll_table *pt)
@@ -888,6 +888,8 @@ static struct soc_camera_host_ops isi_soc_camera_host_ops = {
        .owner          = THIS_MODULE,
        .add            = isi_camera_add_device,
        .remove         = isi_camera_remove_device,
+       .clock_start    = isi_camera_clock_start,
+       .clock_stop     = isi_camera_clock_stop,
        .set_fmt        = isi_camera_set_fmt,
        .try_fmt        = isi_camera_try_fmt,
        .get_formats    = isi_camera_get_formats,
index a3fd8d6..fea3e61 100644 (file)
@@ -104,7 +104,6 @@ struct mx1_buffer {
  */
 struct mx1_camera_dev {
        struct soc_camera_host          soc_host;
-       struct soc_camera_device        *icd;
        struct mx1_camera_pdata         *pdata;
        struct mx1_buffer               *active;
        struct resource                 *res;
@@ -220,7 +219,7 @@ out:
 static int mx1_camera_setup_dma(struct mx1_camera_dev *pcdev)
 {
        struct videobuf_buffer *vbuf = &pcdev->active->vb;
-       struct device *dev = pcdev->icd->parent;
+       struct device *dev = pcdev->soc_host.icd->parent;
        int ret;
 
        if (unlikely(!pcdev->active)) {
@@ -331,7 +330,7 @@ static void mx1_camera_wakeup(struct mx1_camera_dev *pcdev,
 static void mx1_camera_dma_irq(int channel, void *data)
 {
        struct mx1_camera_dev *pcdev = data;
-       struct device *dev = pcdev->icd->parent;
+       struct device *dev = pcdev->soc_host.icd->parent;
        struct mx1_buffer *buf;
        struct videobuf_buffer *vb;
        unsigned long flags;
@@ -389,7 +388,7 @@ static int mclk_get_divisor(struct mx1_camera_dev *pcdev)
         */
        div = (lcdclk + 2 * mclk - 1) / (2 * mclk) - 1;
 
-       dev_dbg(pcdev->icd->parent,
+       dev_dbg(pcdev->soc_host.icd->parent,
                "System clock %lukHz, target freq %dkHz, divisor %lu\n",
                lcdclk / 1000, mclk / 1000, div);
 
@@ -400,7 +399,7 @@ static void mx1_camera_activate(struct mx1_camera_dev *pcdev)
 {
        unsigned int csicr1 = CSICR1_EN;
 
-       dev_dbg(pcdev->icd->parent, "Activate device\n");
+       dev_dbg(pcdev->soc_host.v4l2_dev.dev, "Activate device\n");
 
        clk_prepare_enable(pcdev->clk);
 
@@ -416,7 +415,7 @@ static void mx1_camera_activate(struct mx1_camera_dev *pcdev)
 
 static void mx1_camera_deactivate(struct mx1_camera_dev *pcdev)
 {
-       dev_dbg(pcdev->icd->parent, "Deactivate device\n");
+       dev_dbg(pcdev->soc_host.v4l2_dev.dev, "Deactivate device\n");
 
        /* Disable all CSI interface */
        __raw_writel(0x00, pcdev->base + CSICR1);
@@ -424,36 +423,38 @@ static void mx1_camera_deactivate(struct mx1_camera_dev *pcdev)
        clk_disable_unprepare(pcdev->clk);
 }
 
+static int mx1_camera_add_device(struct soc_camera_device *icd)
+{
+       dev_info(icd->parent, "MX1 Camera driver attached to camera %d\n",
+                icd->devnum);
+
+       return 0;
+}
+
+static void mx1_camera_remove_device(struct soc_camera_device *icd)
+{
+       dev_info(icd->parent, "MX1 Camera driver detached from camera %d\n",
+                icd->devnum);
+}
+
 /*
  * The following two functions absolutely depend on the fact, that
  * there can be only one camera on i.MX1/i.MXL camera sensor interface
  */
-static int mx1_camera_add_device(struct soc_camera_device *icd)
+static int mx1_camera_clock_start(struct soc_camera_host *ici)
 {
-       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct mx1_camera_dev *pcdev = ici->priv;
 
-       if (pcdev->icd)
-               return -EBUSY;
-
-       dev_info(icd->parent, "MX1 Camera driver attached to camera %d\n",
-                icd->devnum);
-
        mx1_camera_activate(pcdev);
 
-       pcdev->icd = icd;
-
        return 0;
 }
 
-static void mx1_camera_remove_device(struct soc_camera_device *icd)
+static void mx1_camera_clock_stop(struct soc_camera_host *ici)
 {
-       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct mx1_camera_dev *pcdev = ici->priv;
        unsigned int csicr1;
 
-       BUG_ON(icd != pcdev->icd);
-
        /* disable interrupts */
        csicr1 = __raw_readl(pcdev->base + CSICR1) & ~CSI_IRQ_MASK;
        __raw_writel(csicr1, pcdev->base + CSICR1);
@@ -461,12 +462,7 @@ static void mx1_camera_remove_device(struct soc_camera_device *icd)
        /* Stop DMA engine */
        imx_dma_disable(pcdev->dma_chan);
 
-       dev_info(icd->parent, "MX1 Camera driver detached from camera %d\n",
-                icd->devnum);
-
        mx1_camera_deactivate(pcdev);
-
-       pcdev->icd = NULL;
 }
 
 static int mx1_camera_set_bus_param(struct soc_camera_device *icd)
@@ -679,6 +675,8 @@ static struct soc_camera_host_ops mx1_soc_camera_host_ops = {
        .owner          = THIS_MODULE,
        .add            = mx1_camera_add_device,
        .remove         = mx1_camera_remove_device,
+       .clock_start    = mx1_camera_clock_start,
+       .clock_stop     = mx1_camera_clock_stop,
        .set_bus_param  = mx1_camera_set_bus_param,
        .set_fmt        = mx1_camera_set_fmt,
        .try_fmt        = mx1_camera_try_fmt,
index 5bbeb43..45a0276 100644 (file)
@@ -236,7 +236,6 @@ enum mx2_camera_type {
 struct mx2_camera_dev {
        struct device           *dev;
        struct soc_camera_host  soc_host;
-       struct soc_camera_device *icd;
        struct clk              *clk_emma_ahb, *clk_emma_ipg;
        struct clk              *clk_csi_ahb, *clk_csi_per;
 
@@ -394,8 +393,8 @@ static void mx27_update_emma_buf(struct mx2_camera_dev *pcdev,
                writel(phys, pcdev->base_emma +
                        PRP_DEST_Y_PTR - 0x14 * bufnum);
                if (prp->out_fmt == V4L2_PIX_FMT_YUV420) {
-                       u32 imgsize = pcdev->icd->user_height *
-                                       pcdev->icd->user_width;
+                       u32 imgsize = pcdev->soc_host.icd->user_height *
+                                       pcdev->soc_host.icd->user_width;
 
                        writel(phys + imgsize, pcdev->base_emma +
                                PRP_DEST_CB_PTR - 0x14 * bufnum);
@@ -413,20 +412,30 @@ static void mx2_camera_deactivate(struct mx2_camera_dev *pcdev)
        writel(0, pcdev->base_emma + PRP_CNTL);
 }
 
+static int mx2_camera_add_device(struct soc_camera_device *icd)
+{
+       dev_info(icd->parent, "Camera driver attached to camera %d\n",
+                icd->devnum);
+
+       return 0;
+}
+
+static void mx2_camera_remove_device(struct soc_camera_device *icd)
+{
+       dev_info(icd->parent, "Camera driver detached from camera %d\n",
+                icd->devnum);
+}
+
 /*
  * The following two functions absolutely depend on the fact, that
  * there can be only one camera on mx2 camera sensor interface
  */
-static int mx2_camera_add_device(struct soc_camera_device *icd)
+static int mx2_camera_clock_start(struct soc_camera_host *ici)
 {
-       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct mx2_camera_dev *pcdev = ici->priv;
        int ret;
        u32 csicr1;
 
-       if (pcdev->icd)
-               return -EBUSY;
-
        ret = clk_prepare_enable(pcdev->clk_csi_ahb);
        if (ret < 0)
                return ret;
@@ -441,12 +450,8 @@ static int mx2_camera_add_device(struct soc_camera_device *icd)
        pcdev->csicr1 = csicr1;
        writel(pcdev->csicr1, pcdev->base_csi + CSICR1);
 
-       pcdev->icd = icd;
        pcdev->frame_count = 0;
 
-       dev_info(icd->parent, "Camera driver attached to camera %d\n",
-                icd->devnum);
-
        return 0;
 
 exit_csi_ahb:
@@ -455,19 +460,11 @@ exit_csi_ahb:
        return ret;
 }
 
-static void mx2_camera_remove_device(struct soc_camera_device *icd)
+static void mx2_camera_clock_stop(struct soc_camera_host *ici)
 {
-       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct mx2_camera_dev *pcdev = ici->priv;
 
-       BUG_ON(icd != pcdev->icd);
-
-       dev_info(icd->parent, "Camera driver detached from camera %d\n",
-                icd->devnum);
-
        mx2_camera_deactivate(pcdev);
-
-       pcdev->icd = NULL;
 }
 
 /*
@@ -1280,6 +1277,8 @@ static struct soc_camera_host_ops mx2_soc_camera_host_ops = {
        .owner          = THIS_MODULE,
        .add            = mx2_camera_add_device,
        .remove         = mx2_camera_remove_device,
+       .clock_start    = mx2_camera_clock_start,
+       .clock_stop     = mx2_camera_clock_stop,
        .set_fmt        = mx2_camera_set_fmt,
        .set_crop       = mx2_camera_set_crop,
        .get_formats    = mx2_camera_get_formats,
index 5da3377..1047e3e 100644 (file)
@@ -94,7 +94,6 @@ struct mx3_camera_dev {
         * Interface. If anyone ever builds hardware to enable more than one
         * camera _simultaneously_, they will have to modify this driver too
         */
-       struct soc_camera_device *icd;
        struct clk              *clk;
 
        void __iomem            *base;
@@ -461,8 +460,7 @@ static int mx3_camera_init_videobuf(struct vb2_queue *q,
 }
 
 /* First part of ipu_csi_init_interface() */
-static void mx3_camera_activate(struct mx3_camera_dev *mx3_cam,
-                               struct soc_camera_device *icd)
+static void mx3_camera_activate(struct mx3_camera_dev *mx3_cam)
 {
        u32 conf;
        long rate;
@@ -506,51 +504,49 @@ static void mx3_camera_activate(struct mx3_camera_dev *mx3_cam,
 
        clk_prepare_enable(mx3_cam->clk);
        rate = clk_round_rate(mx3_cam->clk, mx3_cam->mclk);
-       dev_dbg(icd->parent, "Set SENS_CONF to %x, rate %ld\n", conf, rate);
+       dev_dbg(mx3_cam->soc_host.v4l2_dev.dev, "Set SENS_CONF to %x, rate %ld\n", conf, rate);
        if (rate)
                clk_set_rate(mx3_cam->clk, rate);
 }
 
-/* Called with .host_lock held */
 static int mx3_camera_add_device(struct soc_camera_device *icd)
 {
-       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
-       struct mx3_camera_dev *mx3_cam = ici->priv;
+       dev_info(icd->parent, "MX3 Camera driver attached to camera %d\n",
+                icd->devnum);
 
-       if (mx3_cam->icd)
-               return -EBUSY;
+       return 0;
+}
 
-       mx3_camera_activate(mx3_cam, icd);
+static void mx3_camera_remove_device(struct soc_camera_device *icd)
+{
+       dev_info(icd->parent, "MX3 Camera driver detached from camera %d\n",
+                icd->devnum);
+}
 
-       mx3_cam->buf_total = 0;
-       mx3_cam->icd = icd;
+/* Called with .host_lock held */
+static int mx3_camera_clock_start(struct soc_camera_host *ici)
+{
+       struct mx3_camera_dev *mx3_cam = ici->priv;
 
-       dev_info(icd->parent, "MX3 Camera driver attached to camera %d\n",
-                icd->devnum);
+       mx3_camera_activate(mx3_cam);
+
+       mx3_cam->buf_total = 0;
 
        return 0;
 }
 
 /* Called with .host_lock held */
-static void mx3_camera_remove_device(struct soc_camera_device *icd)
+static void mx3_camera_clock_stop(struct soc_camera_host *ici)
 {
-       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct mx3_camera_dev *mx3_cam = ici->priv;
        struct idmac_channel **ichan = &mx3_cam->idmac_channel[0];
 
-       BUG_ON(icd != mx3_cam->icd);
-
        if (*ichan) {
                dma_release_channel(&(*ichan)->dma_chan);
                *ichan = NULL;
        }
 
        clk_disable_unprepare(mx3_cam->clk);
-
-       mx3_cam->icd = NULL;
-
-       dev_info(icd->parent, "MX3 Camera driver detached from camera %d\n",
-                icd->devnum);
 }
 
 static int test_platform_param(struct mx3_camera_dev *mx3_cam,
@@ -1133,6 +1129,8 @@ static struct soc_camera_host_ops mx3_soc_camera_host_ops = {
        .owner          = THIS_MODULE,
        .add            = mx3_camera_add_device,
        .remove         = mx3_camera_remove_device,
+       .clock_start    = mx3_camera_clock_start,
+       .clock_stop     = mx3_camera_clock_stop,
        .set_crop       = mx3_camera_set_crop,
        .set_fmt        = mx3_camera_set_fmt,
        .try_fmt        = mx3_camera_try_fmt,
index 9689a6e..6769193 100644 (file)
@@ -150,7 +150,6 @@ struct omap1_cam_buf {
 
 struct omap1_cam_dev {
        struct soc_camera_host          soc_host;
-       struct soc_camera_device        *icd;
        struct clk                      *clk;
 
        unsigned int                    irq;
@@ -564,7 +563,7 @@ static void videobuf_done(struct omap1_cam_dev *pcdev,
 {
        struct omap1_cam_buf *buf = pcdev->active;
        struct videobuf_buffer *vb;
-       struct device *dev = pcdev->icd->parent;
+       struct device *dev = pcdev->soc_host.icd->parent;
 
        if (WARN_ON(!buf)) {
                suspend_capture(pcdev);
@@ -790,7 +789,7 @@ out:
 static irqreturn_t cam_isr(int irq, void *data)
 {
        struct omap1_cam_dev *pcdev = data;
-       struct device *dev = pcdev->icd->parent;
+       struct device *dev = pcdev->soc_host.icd->parent;
        struct omap1_cam_buf *buf = pcdev->active;
        u32 it_status;
        unsigned long flags;
@@ -894,19 +893,29 @@ static void sensor_reset(struct omap1_cam_dev *pcdev, bool reset)
                CAM_WRITE(pcdev, GPIO, !reset);
 }
 
+static int omap1_cam_add_device(struct soc_camera_device *icd)
+{
+       dev_dbg(icd->parent, "OMAP1 Camera driver attached to camera %d\n",
+                       icd->devnum);
+
+       return 0;
+}
+
+static void omap1_cam_remove_device(struct soc_camera_device *icd)
+{
+       dev_dbg(icd->parent,
+               "OMAP1 Camera driver detached from camera %d\n", icd->devnum);
+}
+
 /*
  * The following two functions absolutely depend on the fact, that
  * there can be only one camera on OMAP1 camera sensor interface
  */
-static int omap1_cam_add_device(struct soc_camera_device *icd)
+static int omap1_cam_clock_start(struct soc_camera_host *ici)
 {
-       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct omap1_cam_dev *pcdev = ici->priv;
        u32 ctrlclock;
 
-       if (pcdev->icd)
-               return -EBUSY;
-
        clk_enable(pcdev->clk);
 
        /* setup sensor clock */
@@ -941,21 +950,14 @@ static int omap1_cam_add_device(struct soc_camera_device *icd)
 
        sensor_reset(pcdev, false);
 
-       pcdev->icd = icd;
-
-       dev_dbg(icd->parent, "OMAP1 Camera driver attached to camera %d\n",
-                       icd->devnum);
        return 0;
 }
 
-static void omap1_cam_remove_device(struct soc_camera_device *icd)
+static void omap1_cam_clock_stop(struct soc_camera_host *ici)
 {
-       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct omap1_cam_dev *pcdev = ici->priv;
        u32 ctrlclock;
 
-       BUG_ON(icd != pcdev->icd);
-
        suspend_capture(pcdev);
        disable_capture(pcdev);
 
@@ -973,11 +975,6 @@ static void omap1_cam_remove_device(struct soc_camera_device *icd)
        CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock & ~MCLK_EN);
 
        clk_disable(pcdev->clk);
-
-       pcdev->icd = NULL;
-
-       dev_dbg(icd->parent,
-               "OMAP1 Camera driver detached from camera %d\n", icd->devnum);
 }
 
 /* Duplicate standard formats based on host capability of byte swapping */
@@ -1535,6 +1532,8 @@ static struct soc_camera_host_ops omap1_host_ops = {
        .owner          = THIS_MODULE,
        .add            = omap1_cam_add_device,
        .remove         = omap1_cam_remove_device,
+       .clock_start    = omap1_cam_clock_start,
+       .clock_stop     = omap1_cam_clock_stop,
        .get_formats    = omap1_cam_get_formats,
        .set_crop       = omap1_cam_set_crop,
        .set_fmt        = omap1_cam_set_fmt,
index d665242..d4df305 100644 (file)
@@ -200,7 +200,6 @@ struct pxa_camera_dev {
         * interface. If anyone ever builds hardware to enable more than
         * one camera, they will have to modify this driver too
         */
-       struct soc_camera_device *icd;
        struct clk              *clk;
 
        unsigned int            irq;
@@ -956,40 +955,39 @@ static irqreturn_t pxa_camera_irq(int irq, void *data)
        return IRQ_HANDLED;
 }
 
+static int pxa_camera_add_device(struct soc_camera_device *icd)
+{
+       dev_info(icd->parent, "PXA Camera driver attached to camera %d\n",
+                icd->devnum);
+
+       return 0;
+}
+
+static void pxa_camera_remove_device(struct soc_camera_device *icd)
+{
+       dev_info(icd->parent, "PXA Camera driver detached from camera %d\n",
+                icd->devnum);
+}
+
 /*
  * The following two functions absolutely depend on the fact, that
  * there can be only one camera on PXA quick capture interface
  * Called with .host_lock held
  */
-static int pxa_camera_add_device(struct soc_camera_device *icd)
+static int pxa_camera_clock_start(struct soc_camera_host *ici)
 {
-       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct pxa_camera_dev *pcdev = ici->priv;
 
-       if (pcdev->icd)
-               return -EBUSY;
-
        pxa_camera_activate(pcdev);
 
-       pcdev->icd = icd;
-
-       dev_info(icd->parent, "PXA Camera driver attached to camera %d\n",
-                icd->devnum);
-
        return 0;
 }
 
 /* Called with .host_lock held */
-static void pxa_camera_remove_device(struct soc_camera_device *icd)
+static void pxa_camera_clock_stop(struct soc_camera_host *ici)
 {
-       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct pxa_camera_dev *pcdev = ici->priv;
 
-       BUG_ON(icd != pcdev->icd);
-
-       dev_info(icd->parent, "PXA Camera driver detached from camera %d\n",
-                icd->devnum);
-
        /* disable capture, disable interrupts */
        __raw_writel(0x3ff, pcdev->base + CICR0);
 
@@ -999,8 +997,6 @@ static void pxa_camera_remove_device(struct soc_camera_device *icd)
        DCSR(pcdev->dma_chans[2]) = 0;
 
        pxa_camera_deactivate(pcdev);
-
-       pcdev->icd = NULL;
 }
 
 static int test_platform_param(struct pxa_camera_dev *pcdev,
@@ -1596,8 +1592,8 @@ static int pxa_camera_suspend(struct device *dev)
        pcdev->save_cicr[i++] = __raw_readl(pcdev->base + CICR3);
        pcdev->save_cicr[i++] = __raw_readl(pcdev->base + CICR4);
 
-       if (pcdev->icd) {
-               struct v4l2_subdev *sd = soc_camera_to_subdev(pcdev->icd);
+       if (pcdev->soc_host.icd) {
+               struct v4l2_subdev *sd = soc_camera_to_subdev(pcdev->soc_host.icd);
                ret = v4l2_subdev_call(sd, core, s_power, 0);
                if (ret == -ENOIOCTLCMD)
                        ret = 0;
@@ -1622,8 +1618,8 @@ static int pxa_camera_resume(struct device *dev)
        __raw_writel(pcdev->save_cicr[i++], pcdev->base + CICR3);
        __raw_writel(pcdev->save_cicr[i++], pcdev->base + CICR4);
 
-       if (pcdev->icd) {
-               struct v4l2_subdev *sd = soc_camera_to_subdev(pcdev->icd);
+       if (pcdev->soc_host.icd) {
+               struct v4l2_subdev *sd = soc_camera_to_subdev(pcdev->soc_host.icd);
                ret = v4l2_subdev_call(sd, core, s_power, 1);
                if (ret == -ENOIOCTLCMD)
                        ret = 0;
@@ -1640,6 +1636,8 @@ static struct soc_camera_host_ops pxa_soc_camera_host_ops = {
        .owner          = THIS_MODULE,
        .add            = pxa_camera_add_device,
        .remove         = pxa_camera_remove_device,
+       .clock_start    = pxa_camera_clock_start,
+       .clock_stop     = pxa_camera_clock_stop,
        .set_crop       = pxa_camera_set_crop,
        .get_formats    = pxa_camera_get_formats,
        .put_formats    = pxa_camera_put_formats,
index 143d29f..f2de006 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/moduleparam.h>
+#include <linux/of.h>
 #include <linux/time.h>
 #include <linux/slab.h>
 #include <linux/device.h>
@@ -35,6 +36,7 @@
 #include <linux/pm_runtime.h>
 #include <linux/sched.h>
 
+#include <media/v4l2-async.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-dev.h>
 #include <media/soc_camera.h>
@@ -44,6 +46,8 @@
 #include <media/v4l2-mediabus.h>
 #include <media/soc_mediabus.h>
 
+#include "soc_scale_crop.h"
+
 /* register offsets for sh7722 / sh7723 */
 
 #define CAPSR  0x00 /* Capture start register */
@@ -95,7 +99,10 @@ struct sh_mobile_ceu_buffer {
 
 struct sh_mobile_ceu_dev {
        struct soc_camera_host ici;
-       struct soc_camera_device *icd;
+       /* Asynchronous CSI2 linking */
+       struct v4l2_async_subdev *csi2_asd;
+       struct v4l2_subdev *csi2_sd;
+       /* Synchronous probing compatibility */
        struct platform_device *csi2_pdev;
 
        unsigned int irq;
@@ -119,6 +126,7 @@ struct sh_mobile_ceu_dev {
 
        enum v4l2_field field;
        int sequence;
+       unsigned long flags;
 
        unsigned int image_mode:1;
        unsigned int is_16bit:1;
@@ -163,7 +171,6 @@ static u32 ceu_read(struct sh_mobile_ceu_dev *priv, unsigned long reg_offs)
 static int sh_mobile_ceu_soft_reset(struct sh_mobile_ceu_dev *pcdev)
 {
        int i, success = 0;
-       struct soc_camera_device *icd = pcdev->icd;
 
        ceu_write(pcdev, CAPSR, 1 << 16); /* reset */
 
@@ -185,9 +192,8 @@ static int sh_mobile_ceu_soft_reset(struct sh_mobile_ceu_dev *pcdev)
                udelay(1);
        }
 
-
        if (2 != success) {
-               dev_warn(icd->pdev, "soft reset time out\n");
+               dev_warn(pcdev->ici.v4l2_dev.dev, "soft reset time out\n");
                return -EIO;
        }
 
@@ -277,7 +283,7 @@ static int sh_mobile_ceu_videobuf_setup(struct vb2_queue *vq,
  */
 static int sh_mobile_ceu_capture(struct sh_mobile_ceu_dev *pcdev)
 {
-       struct soc_camera_device *icd = pcdev->icd;
+       struct soc_camera_device *icd = pcdev->ici.icd;
        dma_addr_t phys_addr_top, phys_addr_bottom;
        unsigned long top1, top2;
        unsigned long bottom1, bottom2;
@@ -534,72 +540,92 @@ static struct v4l2_subdev *find_csi2(struct sh_mobile_ceu_dev *pcdev)
 {
        struct v4l2_subdev *sd;
 
-       if (!pcdev->csi2_pdev)
-               return NULL;
+       if (pcdev->csi2_sd)
+               return pcdev->csi2_sd;
 
-       v4l2_device_for_each_subdev(sd, &pcdev->ici.v4l2_dev)
-               if (&pcdev->csi2_pdev->dev == v4l2_get_subdevdata(sd))
-                       return sd;
+       if (pcdev->csi2_asd) {
+               char name[] = "sh-mobile-csi2";
+               v4l2_device_for_each_subdev(sd, &pcdev->ici.v4l2_dev)
+                       if (!strncmp(name, sd->name, sizeof(name) - 1)) {
+                               pcdev->csi2_sd = sd;
+                               return sd;
+                       }
+       }
 
        return NULL;
 }
 
-/* Called with .host_lock held */
+static struct v4l2_subdev *csi2_subdev(struct sh_mobile_ceu_dev *pcdev,
+                                      struct soc_camera_device *icd)
+{
+       struct v4l2_subdev *sd = pcdev->csi2_sd;
+
+       return sd && sd->grp_id == soc_camera_grp_id(icd) ? sd : NULL;
+}
+
 static int sh_mobile_ceu_add_device(struct soc_camera_device *icd)
 {
        struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct sh_mobile_ceu_dev *pcdev = ici->priv;
-       struct v4l2_subdev *csi2_sd;
+       struct v4l2_subdev *csi2_sd = find_csi2(pcdev);
        int ret;
 
-       if (pcdev->icd)
-               return -EBUSY;
-
-       dev_info(icd->parent,
-                "SuperH Mobile CEU driver attached to camera %d\n",
-                icd->devnum);
-
-       pm_runtime_get_sync(ici->v4l2_dev.dev);
-
-       pcdev->buf_total = 0;
-
-       ret = sh_mobile_ceu_soft_reset(pcdev);
-
-       csi2_sd = find_csi2(pcdev);
        if (csi2_sd) {
                csi2_sd->grp_id = soc_camera_grp_id(icd);
                v4l2_set_subdev_hostdata(csi2_sd, icd);
        }
 
        ret = v4l2_subdev_call(csi2_sd, core, s_power, 1);
-       if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV) {
-               pm_runtime_put(ici->v4l2_dev.dev);
+       if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV)
                return ret;
-       }
 
        /*
         * -ENODEV is special: either csi2_sd == NULL or the CSI-2 driver
         * has not found this soc-camera device among its clients
         */
-       if (ret == -ENODEV && csi2_sd)
+       if (csi2_sd && ret == -ENODEV)
                csi2_sd->grp_id = 0;
-       pcdev->icd = icd;
+
+       dev_info(icd->parent,
+                "SuperH Mobile CEU%s driver attached to camera %d\n",
+                csi2_sd && csi2_sd->grp_id ? "/CSI-2" : "", icd->devnum);
 
        return 0;
 }
 
-/* Called with .host_lock held */
 static void sh_mobile_ceu_remove_device(struct soc_camera_device *icd)
 {
        struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct sh_mobile_ceu_dev *pcdev = ici->priv;
        struct v4l2_subdev *csi2_sd = find_csi2(pcdev);
 
-       BUG_ON(icd != pcdev->icd);
+       dev_info(icd->parent,
+                "SuperH Mobile CEU driver detached from camera %d\n",
+                icd->devnum);
 
        v4l2_subdev_call(csi2_sd, core, s_power, 0);
-       if (csi2_sd)
-               csi2_sd->grp_id = 0;
+}
+
+/* Called with .host_lock held */
+static int sh_mobile_ceu_clock_start(struct soc_camera_host *ici)
+{
+       struct sh_mobile_ceu_dev *pcdev = ici->priv;
+       int ret;
+
+       pm_runtime_get_sync(ici->v4l2_dev.dev);
+
+       pcdev->buf_total = 0;
+
+       ret = sh_mobile_ceu_soft_reset(pcdev);
+
+       return 0;
+}
+
+/* Called with .host_lock held */
+static void sh_mobile_ceu_clock_stop(struct soc_camera_host *ici)
+{
+       struct sh_mobile_ceu_dev *pcdev = ici->priv;
+
        /* disable capture, disable interrupts */
        ceu_write(pcdev, CEIER, 0);
        sh_mobile_ceu_soft_reset(pcdev);
@@ -614,12 +640,6 @@ static void sh_mobile_ceu_remove_device(struct soc_camera_device *icd)
        spin_unlock_irq(&pcdev->lock);
 
        pm_runtime_put(ici->v4l2_dev.dev);
-
-       dev_info(icd->parent,
-                "SuperH Mobile CEU driver detached from camera %d\n",
-                icd->devnum);
-
-       pcdev->icd = NULL;
 }
 
 /*
@@ -705,7 +725,7 @@ static void sh_mobile_ceu_set_rect(struct soc_camera_device *icd)
        }
 
        /* CSI2 special configuration */
-       if (pcdev->pdata->csi2) {
+       if (csi2_subdev(pcdev, icd)) {
                in_width = ((in_width - 2) * 2);
                left_offset *= 2;
        }
@@ -762,13 +782,7 @@ static void capture_restore(struct sh_mobile_ceu_dev *pcdev, u32 capsr)
 static struct v4l2_subdev *find_bus_subdev(struct sh_mobile_ceu_dev *pcdev,
                                           struct soc_camera_device *icd)
 {
-       if (pcdev->csi2_pdev) {
-               struct v4l2_subdev *csi2_sd = find_csi2(pcdev);
-               if (csi2_sd && csi2_sd->grp_id == soc_camera_grp_id(icd))
-                       return csi2_sd;
-       }
-
-       return soc_camera_to_subdev(icd);
+       return csi2_subdev(pcdev, icd) ? : soc_camera_to_subdev(icd);
 }
 
 #define CEU_BUS_FLAGS (V4L2_MBUS_MASTER |      \
@@ -809,7 +823,7 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd)
        /* Make choises, based on platform preferences */
        if ((common_flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) &&
            (common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)) {
-               if (pcdev->pdata->flags & SH_CEU_FLAG_HSYNC_LOW)
+               if (pcdev->flags & SH_CEU_FLAG_HSYNC_LOW)
                        common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_HIGH;
                else
                        common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_LOW;
@@ -817,7 +831,7 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd)
 
        if ((common_flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) &&
            (common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)) {
-               if (pcdev->pdata->flags & SH_CEU_FLAG_VSYNC_LOW)
+               if (pcdev->flags & SH_CEU_FLAG_VSYNC_LOW)
                        common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_HIGH;
                else
                        common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_LOW;
@@ -872,11 +886,11 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd)
        value |= common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW ? 1 << 1 : 0;
        value |= common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW ? 1 << 0 : 0;
 
-       if (pcdev->pdata->csi2) /* CSI2 mode */
+       if (csi2_subdev(pcdev, icd)) /* CSI2 mode */
                value |= 3 << 12;
        else if (pcdev->is_16bit)
                value |= 1 << 12;
-       else if (pcdev->pdata->flags & SH_CEU_FLAG_LOWER_8BIT)
+       else if (pcdev->flags & SH_CEU_FLAG_LOWER_8BIT)
                value |= 2 << 12;
 
        ceu_write(pcdev, CAMCR, value);
@@ -993,8 +1007,6 @@ static bool sh_mobile_ceu_packing_supported(const struct soc_mbus_pixelfmt *fmt)
                 fmt->packing == SOC_MBUS_PACKING_EXTEND16);
 }
 
-static int client_g_rect(struct v4l2_subdev *sd, struct v4l2_rect *rect);
-
 static struct soc_camera_device *ctrl_to_icd(struct v4l2_ctrl *ctrl)
 {
        return container_of(ctrl->handler, struct soc_camera_device,
@@ -1051,7 +1063,7 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, unsigned int
                return 0;
        }
 
-       if (!pcdev->pdata->csi2) {
+       if (!csi2_subdev(pcdev, icd)) {
                /* Are there any restrictions in the CSI-2 case? */
                ret = sh_mobile_ceu_try_bus_param(icd, fmt->bits_per_sample);
                if (ret < 0)
@@ -1072,7 +1084,7 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, unsigned int
                /* FIXME: subwindow is lost between close / open */
 
                /* Cache current client geometry */
-               ret = client_g_rect(sd, &rect);
+               ret = soc_camera_client_g_rect(sd, &rect);
                if (ret < 0)
                        return ret;
 
@@ -1182,334 +1194,8 @@ static void sh_mobile_ceu_put_formats(struct soc_camera_device *icd)
        icd->host_priv = NULL;
 }
 
-/* Check if any dimension of r1 is smaller than respective one of r2 */
-static bool is_smaller(const struct v4l2_rect *r1, const struct v4l2_rect *r2)
-{
-       return r1->width < r2->width || r1->height < r2->height;
-}
-
-/* Check if r1 fails to cover r2 */
-static bool is_inside(const struct v4l2_rect *r1, const struct v4l2_rect *r2)
-{
-       return r1->left > r2->left || r1->top > r2->top ||
-               r1->left + r1->width < r2->left + r2->width ||
-               r1->top + r1->height < r2->top + r2->height;
-}
-
-static unsigned int scale_down(unsigned int size, unsigned int scale)
-{
-       return (size * 4096 + scale / 2) / scale;
-}
-
-static unsigned int calc_generic_scale(unsigned int input, unsigned int output)
-{
-       return (input * 4096 + output / 2) / output;
-}
-
-/* Get and store current client crop */
-static int client_g_rect(struct v4l2_subdev *sd, struct v4l2_rect *rect)
-{
-       struct v4l2_crop crop;
-       struct v4l2_cropcap cap;
-       int ret;
-
-       crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
-       ret = v4l2_subdev_call(sd, video, g_crop, &crop);
-       if (!ret) {
-               *rect = crop.c;
-               return ret;
-       }
-
-       /* Camera driver doesn't support .g_crop(), assume default rectangle */
-       cap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
-       ret = v4l2_subdev_call(sd, video, cropcap, &cap);
-       if (!ret)
-               *rect = cap.defrect;
-
-       return ret;
-}
-
-/* Client crop has changed, update our sub-rectangle to remain within the area */
-static void update_subrect(struct sh_mobile_ceu_cam *cam)
-{
-       struct v4l2_rect *rect = &cam->rect, *subrect = &cam->subrect;
-
-       if (rect->width < subrect->width)
-               subrect->width = rect->width;
-
-       if (rect->height < subrect->height)
-               subrect->height = rect->height;
-
-       if (rect->left > subrect->left)
-               subrect->left = rect->left;
-       else if (rect->left + rect->width >
-                subrect->left + subrect->width)
-               subrect->left = rect->left + rect->width -
-                       subrect->width;
-
-       if (rect->top > subrect->top)
-               subrect->top = rect->top;
-       else if (rect->top + rect->height >
-                subrect->top + subrect->height)
-               subrect->top = rect->top + rect->height -
-                       subrect->height;
-}
-
-/*
- * The common for both scaling and cropping iterative approach is:
- * 1. try if the client can produce exactly what requested by the user
- * 2. if (1) failed, try to double the client image until we get one big enough
- * 3. if (2) failed, try to request the maximum image
- */
-static int client_s_crop(struct soc_camera_device *icd, struct v4l2_crop *crop,
-                        struct v4l2_crop *cam_crop)
-{
-       struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
-       struct v4l2_rect *rect = &crop->c, *cam_rect = &cam_crop->c;
-       struct device *dev = sd->v4l2_dev->dev;
-       struct sh_mobile_ceu_cam *cam = icd->host_priv;
-       struct v4l2_cropcap cap;
-       int ret;
-       unsigned int width, height;
-
-       v4l2_subdev_call(sd, video, s_crop, crop);
-       ret = client_g_rect(sd, cam_rect);
-       if (ret < 0)
-               return ret;
-
-       /*
-        * Now cam_crop contains the current camera input rectangle, and it must
-        * be within camera cropcap bounds
-        */
-       if (!memcmp(rect, cam_rect, sizeof(*rect))) {
-               /* Even if camera S_CROP failed, but camera rectangle matches */
-               dev_dbg(dev, "Camera S_CROP successful for %dx%d@%d:%d\n",
-                       rect->width, rect->height, rect->left, rect->top);
-               cam->rect = *cam_rect;
-               return 0;
-       }
-
-       /* Try to fix cropping, that camera hasn't managed to set */
-       dev_geo(dev, "Fix camera S_CROP for %dx%d@%d:%d to %dx%d@%d:%d\n",
-               cam_rect->width, cam_rect->height,
-               cam_rect->left, cam_rect->top,
-               rect->width, rect->height, rect->left, rect->top);
-
-       /* We need sensor maximum rectangle */
-       ret = v4l2_subdev_call(sd, video, cropcap, &cap);
-       if (ret < 0)
-               return ret;
-
-       /* Put user requested rectangle within sensor bounds */
-       soc_camera_limit_side(&rect->left, &rect->width, cap.bounds.left, 2,
-                             cap.bounds.width);
-       soc_camera_limit_side(&rect->top, &rect->height, cap.bounds.top, 4,
-                             cap.bounds.height);
-
-       /*
-        * Popular special case - some cameras can only handle fixed sizes like
-        * QVGA, VGA,... Take care to avoid infinite loop.
-        */
-       width = max(cam_rect->width, 2);
-       height = max(cam_rect->height, 2);
-
-       /*
-        * Loop as long as sensor is not covering the requested rectangle and
-        * is still within its bounds
-        */
-       while (!ret && (is_smaller(cam_rect, rect) ||
-                       is_inside(cam_rect, rect)) &&
-              (cap.bounds.width > width || cap.bounds.height > height)) {
-
-               width *= 2;
-               height *= 2;
-
-               cam_rect->width = width;
-               cam_rect->height = height;
-
-               /*
-                * We do not know what capabilities the camera has to set up
-                * left and top borders. We could try to be smarter in iterating
-                * them, e.g., if camera current left is to the right of the
-                * target left, set it to the middle point between the current
-                * left and minimum left. But that would add too much
-                * complexity: we would have to iterate each border separately.
-                * Instead we just drop to the left and top bounds.
-                */
-               if (cam_rect->left > rect->left)
-                       cam_rect->left = cap.bounds.left;
-
-               if (cam_rect->left + cam_rect->width < rect->left + rect->width)
-                       cam_rect->width = rect->left + rect->width -
-                               cam_rect->left;
-
-               if (cam_rect->top > rect->top)
-                       cam_rect->top = cap.bounds.top;
-
-               if (cam_rect->top + cam_rect->height < rect->top + rect->height)
-                       cam_rect->height = rect->top + rect->height -
-                               cam_rect->top;
-
-               v4l2_subdev_call(sd, video, s_crop, cam_crop);
-               ret = client_g_rect(sd, cam_rect);
-               dev_geo(dev, "Camera S_CROP %d for %dx%d@%d:%d\n", ret,
-                       cam_rect->width, cam_rect->height,
-                       cam_rect->left, cam_rect->top);
-       }
-
-       /* S_CROP must not modify the rectangle */
-       if (is_smaller(cam_rect, rect) || is_inside(cam_rect, rect)) {
-               /*
-                * The camera failed to configure a suitable cropping,
-                * we cannot use the current rectangle, set to max
-                */
-               *cam_rect = cap.bounds;
-               v4l2_subdev_call(sd, video, s_crop, cam_crop);
-               ret = client_g_rect(sd, cam_rect);
-               dev_geo(dev, "Camera S_CROP %d for max %dx%d@%d:%d\n", ret,
-                       cam_rect->width, cam_rect->height,
-                       cam_rect->left, cam_rect->top);
-       }
-
-       if (!ret) {
-               cam->rect = *cam_rect;
-               update_subrect(cam);
-       }
-
-       return ret;
-}
-
-/* Iterative s_mbus_fmt, also updates cached client crop on success */
-static int client_s_fmt(struct soc_camera_device *icd,
-                       struct v4l2_mbus_framefmt *mf, bool ceu_can_scale)
-{
-       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
-       struct sh_mobile_ceu_dev *pcdev = ici->priv;
-       struct sh_mobile_ceu_cam *cam = icd->host_priv;
-       struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
-       struct device *dev = icd->parent;
-       unsigned int width = mf->width, height = mf->height, tmp_w, tmp_h;
-       unsigned int max_width, max_height;
-       struct v4l2_cropcap cap;
-       bool ceu_1to1;
-       int ret;
-
-       ret = v4l2_device_call_until_err(sd->v4l2_dev,
-                                        soc_camera_grp_id(icd), video,
-                                        s_mbus_fmt, mf);
-       if (ret < 0)
-               return ret;
-
-       dev_geo(dev, "camera scaled to %ux%u\n", mf->width, mf->height);
-
-       if (width == mf->width && height == mf->height) {
-               /* Perfect! The client has done it all. */
-               ceu_1to1 = true;
-               goto update_cache;
-       }
-
-       ceu_1to1 = false;
-       if (!ceu_can_scale)
-               goto update_cache;
-
-       cap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
-       ret = v4l2_subdev_call(sd, video, cropcap, &cap);
-       if (ret < 0)
-               return ret;
-
-       max_width = min(cap.bounds.width, pcdev->max_width);
-       max_height = min(cap.bounds.height, pcdev->max_height);
-
-       /* Camera set a format, but geometry is not precise, try to improve */
-       tmp_w = mf->width;
-       tmp_h = mf->height;
-
-       /* width <= max_width && height <= max_height - guaranteed by try_fmt */
-       while ((width > tmp_w || height > tmp_h) &&
-              tmp_w < max_width && tmp_h < max_height) {
-               tmp_w = min(2 * tmp_w, max_width);
-               tmp_h = min(2 * tmp_h, max_height);
-               mf->width = tmp_w;
-               mf->height = tmp_h;
-               ret = v4l2_device_call_until_err(sd->v4l2_dev,
-                                       soc_camera_grp_id(icd), video,
-                                       s_mbus_fmt, mf);
-               dev_geo(dev, "Camera scaled to %ux%u\n",
-                       mf->width, mf->height);
-               if (ret < 0) {
-                       /* This shouldn't happen */
-                       dev_err(dev, "Client failed to set format: %d\n", ret);
-                       return ret;
-               }
-       }
-
-update_cache:
-       /* Update cache */
-       ret = client_g_rect(sd, &cam->rect);
-       if (ret < 0)
-               return ret;
-
-       if (ceu_1to1)
-               cam->subrect = cam->rect;
-       else
-               update_subrect(cam);
-
-       return 0;
-}
-
-/**
- * @width      - on output: user width, mapped back to input
- * @height     - on output: user height, mapped back to input
- * @mf         - in- / output camera output window
- */
-static int client_scale(struct soc_camera_device *icd,
-                       struct v4l2_mbus_framefmt *mf,
-                       unsigned int *width, unsigned int *height,
-                       bool ceu_can_scale)
-{
-       struct sh_mobile_ceu_cam *cam = icd->host_priv;
-       struct device *dev = icd->parent;
-       struct v4l2_mbus_framefmt mf_tmp = *mf;
-       unsigned int scale_h, scale_v;
-       int ret;
-
-       /*
-        * 5. Apply iterative camera S_FMT for camera user window (also updates
-        *    client crop cache and the imaginary sub-rectangle).
-        */
-       ret = client_s_fmt(icd, &mf_tmp, ceu_can_scale);
-       if (ret < 0)
-               return ret;
-
-       dev_geo(dev, "5: camera scaled to %ux%u\n",
-               mf_tmp.width, mf_tmp.height);
-
-       /* 6. Retrieve camera output window (g_fmt) */
-
-       /* unneeded - it is already in "mf_tmp" */
-
-       /* 7. Calculate new client scales. */
-       scale_h = calc_generic_scale(cam->rect.width, mf_tmp.width);
-       scale_v = calc_generic_scale(cam->rect.height, mf_tmp.height);
-
-       mf->width       = mf_tmp.width;
-       mf->height      = mf_tmp.height;
-       mf->colorspace  = mf_tmp.colorspace;
-
-       /*
-        * 8. Calculate new CEU crop - apply camera scales to previously
-        *    updated "effective" crop.
-        */
-       *width = scale_down(cam->subrect.width, scale_h);
-       *height = scale_down(cam->subrect.height, scale_v);
-
-       dev_geo(dev, "8: new client sub-window %ux%u\n", *width, *height);
-
-       return 0;
-}
+#define scale_down(size, scale) soc_camera_shift_scale(size, 12, scale)
+#define calc_generic_scale(in, out) soc_camera_calc_scale(in, 12, out)
 
 /*
  * CEU can scale and crop, but we don't want to waste bandwidth and kill the
@@ -1547,7 +1233,8 @@ static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd,
         * 1. - 2. Apply iterative camera S_CROP for new input window, read back
         * actual camera rectangle.
         */
-       ret = client_s_crop(icd, &a_writable, &cam_crop);
+       ret = soc_camera_client_s_crop(sd, &a_writable, &cam_crop,
+                                      &cam->rect, &cam->subrect);
        if (ret < 0)
                return ret;
 
@@ -1666,55 +1353,6 @@ static int sh_mobile_ceu_get_crop(struct soc_camera_device *icd,
        return 0;
 }
 
-/*
- * Calculate real client output window by applying new scales to the current
- * client crop. New scales are calculated from the requested output format and
- * CEU crop, mapped backed onto the client input (subrect).
- */
-static void calculate_client_output(struct soc_camera_device *icd,
-               const struct v4l2_pix_format *pix, struct v4l2_mbus_framefmt *mf)
-{
-       struct sh_mobile_ceu_cam *cam = icd->host_priv;
-       struct device *dev = icd->parent;
-       struct v4l2_rect *cam_subrect = &cam->subrect;
-       unsigned int scale_v, scale_h;
-
-       if (cam_subrect->width == cam->rect.width &&
-           cam_subrect->height == cam->rect.height) {
-               /* No sub-cropping */
-               mf->width       = pix->width;
-               mf->height      = pix->height;
-               return;
-       }
-
-       /* 1.-2. Current camera scales and subwin - cached. */
-
-       dev_geo(dev, "2: subwin %ux%u@%u:%u\n",
-               cam_subrect->width, cam_subrect->height,
-               cam_subrect->left, cam_subrect->top);
-
-       /*
-        * 3. Calculate new combined scales from input sub-window to requested
-        *    user window.
-        */
-
-       /*
-        * TODO: CEU cannot scale images larger than VGA to smaller than SubQCIF
-        * (128x96) or larger than VGA
-        */
-       scale_h = calc_generic_scale(cam_subrect->width, pix->width);
-       scale_v = calc_generic_scale(cam_subrect->height, pix->height);
-
-       dev_geo(dev, "3: scales %u:%u\n", scale_h, scale_v);
-
-       /*
-        * 4. Calculate desired client output window by applying combined scales
-        *    to client (real) input window.
-        */
-       mf->width       = scale_down(cam->rect.width, scale_h);
-       mf->height      = scale_down(cam->rect.height, scale_v);
-}
-
 /* Similar to set_crop multistage iterative algorithm */
 static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd,
                                 struct v4l2_format *f)
@@ -1727,8 +1365,8 @@ static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd,
        struct v4l2_mbus_framefmt mf;
        __u32 pixfmt = pix->pixelformat;
        const struct soc_camera_format_xlate *xlate;
-       /* Keep Compiler Happy */
-       unsigned int ceu_sub_width = 0, ceu_sub_height = 0;
+       unsigned int ceu_sub_width = pcdev->max_width,
+               ceu_sub_height = pcdev->max_height;
        u16 scale_v, scale_h;
        int ret;
        bool image_mode;
@@ -1755,7 +1393,7 @@ static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd,
        }
 
        /* 1.-4. Calculate desired client output geometry */
-       calculate_client_output(icd, pix, &mf);
+       soc_camera_calc_client_output(icd, &cam->rect, &cam->subrect, pix, &mf, 12);
        mf.field        = pix->field;
        mf.colorspace   = pix->colorspace;
        mf.code         = xlate->code;
@@ -1777,8 +1415,9 @@ static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd,
        dev_geo(dev, "4: request camera output %ux%u\n", mf.width, mf.height);
 
        /* 5. - 9. */
-       ret = client_scale(icd, &mf, &ceu_sub_width, &ceu_sub_height,
-                          image_mode && V4L2_FIELD_NONE == field);
+       ret = soc_camera_client_scale(icd, &cam->rect, &cam->subrect,
+                               &mf, &ceu_sub_width, &ceu_sub_height,
+                               image_mode && V4L2_FIELD_NONE == field, 12);
 
        dev_geo(dev, "5-9: client scale return %d\n", ret);
 
@@ -2036,6 +1675,8 @@ static struct soc_camera_host_ops sh_mobile_ceu_host_ops = {
        .owner          = THIS_MODULE,
        .add            = sh_mobile_ceu_add_device,
        .remove         = sh_mobile_ceu_remove_device,
+       .clock_start    = sh_mobile_ceu_clock_start,
+       .clock_stop     = sh_mobile_ceu_clock_stop,
        .get_formats    = sh_mobile_ceu_get_formats,
        .put_formats    = sh_mobile_ceu_put_formats,
        .get_crop       = sh_mobile_ceu_get_crop,
@@ -2079,7 +1720,7 @@ static int sh_mobile_ceu_probe(struct platform_device *pdev)
        struct resource *res;
        void __iomem *base;
        unsigned int irq;
-       int err = 0;
+       int err, i;
        struct bus_wait wait = {
                .completion = COMPLETION_INITIALIZER_ONSTACK(wait.completion),
                .notifier.notifier_call = bus_notify,
@@ -2104,13 +1745,36 @@ static int sh_mobile_ceu_probe(struct platform_device *pdev)
        init_completion(&pcdev->complete);
 
        pcdev->pdata = pdev->dev.platform_data;
-       if (!pcdev->pdata) {
+       if (!pcdev->pdata && !pdev->dev.of_node) {
                dev_err(&pdev->dev, "CEU platform data not set.\n");
                return -EINVAL;
        }
 
-       pcdev->max_width = pcdev->pdata->max_width ? : 2560;
-       pcdev->max_height = pcdev->pdata->max_height ? : 1920;
+       /* TODO: implement per-device bus flags */
+       if (pcdev->pdata) {
+               pcdev->max_width = pcdev->pdata->max_width;
+               pcdev->max_height = pcdev->pdata->max_height;
+               pcdev->flags = pcdev->pdata->flags;
+       }
+
+       if (!pcdev->max_width) {
+               unsigned int v;
+               err = of_property_read_u32(pdev->dev.of_node, "renesas,max-width", &v);
+               if (!err)
+                       pcdev->max_width = v;
+
+               if (!pcdev->max_width)
+                       pcdev->max_width = 2560;
+       }
+       if (!pcdev->max_height) {
+               unsigned int v;
+               err = of_property_read_u32(pdev->dev.of_node, "renesas,max-height", &v);
+               if (!err)
+                       pcdev->max_height = v;
+
+               if (!pcdev->max_height)
+                       pcdev->max_height = 1920;
+       }
 
        base = devm_ioremap_resource(&pdev->dev, res);
        if (IS_ERR(base))
@@ -2160,31 +1824,60 @@ static int sh_mobile_ceu_probe(struct platform_device *pdev)
                goto exit_free_clk;
        }
 
-       err = soc_camera_host_register(&pcdev->ici);
-       if (err)
-               goto exit_free_ctx;
+       if (pcdev->pdata && pcdev->pdata->asd_sizes) {
+               struct v4l2_async_subdev **asd;
+               char name[] = "sh-mobile-csi2";
+               int j;
+
+               /*
+                * CSI2 interfacing: several groups can use CSI2, pick up the
+                * first one
+                */
+               asd = pcdev->pdata->asd;
+               for (j = 0; pcdev->pdata->asd_sizes[j]; j++) {
+                       for (i = 0; i < pcdev->pdata->asd_sizes[j]; i++, asd++) {
+                               dev_dbg(&pdev->dev, "%s(): subdev #%d, type %u\n",
+                                       __func__, i, (*asd)->bus_type);
+                               if ((*asd)->bus_type == V4L2_ASYNC_BUS_PLATFORM &&
+                                   !strncmp(name, (*asd)->match.platform.name,
+                                            sizeof(name) - 1)) {
+                                       pcdev->csi2_asd = *asd;
+                                       break;
+                               }
+                       }
+                       if (pcdev->csi2_asd)
+                               break;
+               }
 
-       /* CSI2 interfacing */
-       csi2 = pcdev->pdata->csi2;
+               pcdev->ici.asd = pcdev->pdata->asd;
+               pcdev->ici.asd_sizes = pcdev->pdata->asd_sizes;
+       }
+
+       /* Legacy CSI2 interfacing */
+       csi2 = pcdev->pdata ? pcdev->pdata->csi2 : NULL;
        if (csi2) {
+               /*
+                * TODO: remove this once all users are converted to
+                * asynchronous CSI2 probing. If it has to be kept, csi2
+                * platform device resources have to be added, using
+                * platform_device_add_resources()
+                */
                struct platform_device *csi2_pdev =
                        platform_device_alloc("sh-mobile-csi2", csi2->id);
                struct sh_csi2_pdata *csi2_pdata = csi2->platform_data;
 
                if (!csi2_pdev) {
                        err = -ENOMEM;
-                       goto exit_host_unregister;
+                       goto exit_free_ctx;
                }
 
                pcdev->csi2_pdev                = csi2_pdev;
 
-               err = platform_device_add_data(csi2_pdev, csi2_pdata, sizeof(*csi2_pdata));
+               err = platform_device_add_data(csi2_pdev, csi2_pdata,
+                                              sizeof(*csi2_pdata));
                if (err < 0)
                        goto exit_pdev_put;
 
-               csi2_pdata                      = csi2_pdev->dev.platform_data;
-               csi2_pdata->v4l2_dev            = &pcdev->ici.v4l2_dev;
-
                csi2_pdev->resource             = csi2->resource;
                csi2_pdev->num_resources        = csi2->num_resources;
 
@@ -2226,17 +1919,38 @@ static int sh_mobile_ceu_probe(struct platform_device *pdev)
                        err = -ENODEV;
                        goto exit_pdev_unregister;
                }
+
+               pcdev->csi2_sd = platform_get_drvdata(csi2_pdev);
+       }
+
+       err = soc_camera_host_register(&pcdev->ici);
+       if (err)
+               goto exit_csi2_unregister;
+
+       if (csi2) {
+               err = v4l2_device_register_subdev(&pcdev->ici.v4l2_dev,
+                                                 pcdev->csi2_sd);
+               dev_dbg(&pdev->dev, "%s(): ret(register_subdev) = %d\n",
+                       __func__, err);
+               if (err < 0)
+                       goto exit_host_unregister;
+               /* v4l2_device_register_subdev() took a reference too */
+               module_put(pcdev->csi2_sd->owner);
        }
 
        return 0;
 
-exit_pdev_unregister:
-       platform_device_del(pcdev->csi2_pdev);
-exit_pdev_put:
-       pcdev->csi2_pdev->resource = NULL;
-       platform_device_put(pcdev->csi2_pdev);
 exit_host_unregister:
        soc_camera_host_unregister(&pcdev->ici);
+exit_csi2_unregister:
+       if (csi2) {
+               module_put(pcdev->csi2_pdev->dev.driver->owner);
+exit_pdev_unregister:
+               platform_device_del(pcdev->csi2_pdev);
+exit_pdev_put:
+               pcdev->csi2_pdev->resource = NULL;
+               platform_device_put(pcdev->csi2_pdev);
+       }
 exit_free_ctx:
        vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx);
 exit_free_clk:
@@ -2287,10 +2001,18 @@ static const struct dev_pm_ops sh_mobile_ceu_dev_pm_ops = {
        .runtime_resume = sh_mobile_ceu_runtime_nop,
 };
 
+static const struct of_device_id sh_mobile_ceu_of_match[] = {
+       { .compatible = "renesas,sh-mobile-ceu" },
+       { }
+};
+MODULE_DEVICE_TABLE(of, sh_mobile_ceu_of_match);
+
 static struct platform_driver sh_mobile_ceu_driver = {
        .driver         = {
                .name   = "sh_mobile_ceu",
+               .owner  = THIS_MODULE,
                .pm     = &sh_mobile_ceu_dev_pm_ops,
+               .of_match_table = sh_mobile_ceu_of_match,
        },
        .probe          = sh_mobile_ceu_probe,
        .remove         = sh_mobile_ceu_remove,
@@ -2314,5 +2036,5 @@ module_exit(sh_mobile_ceu_exit);
 MODULE_DESCRIPTION("SuperH Mobile CEU driver");
 MODULE_AUTHOR("Magnus Damm");
 MODULE_LICENSE("GPL");
-MODULE_VERSION("0.0.6");
+MODULE_VERSION("0.1.0");
 MODULE_ALIAS("platform:sh_mobile_ceu");
index 09cb4fc..05dd21a 100644 (file)
@@ -36,7 +36,6 @@
 
 struct sh_csi2 {
        struct v4l2_subdev              subdev;
-       struct list_head                list;
        unsigned int                    irq;
        unsigned long                   mipi_flags;
        void __iomem                    *base;
@@ -44,6 +43,8 @@ struct sh_csi2 {
        struct sh_csi2_client_config    *client;
 };
 
+static void sh_csi2_hwinit(struct sh_csi2 *priv);
+
 static int sh_csi2_try_fmt(struct v4l2_subdev *sd,
                           struct v4l2_mbus_framefmt *mf)
 {
@@ -132,10 +133,58 @@ static int sh_csi2_s_fmt(struct v4l2_subdev *sd,
 static int sh_csi2_g_mbus_config(struct v4l2_subdev *sd,
                                 struct v4l2_mbus_config *cfg)
 {
-       cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING |
-               V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_HIGH |
-               V4L2_MBUS_MASTER | V4L2_MBUS_DATA_ACTIVE_HIGH;
-       cfg->type = V4L2_MBUS_PARALLEL;
+       struct sh_csi2 *priv = container_of(sd, struct sh_csi2, subdev);
+
+       if (!priv->mipi_flags) {
+               struct soc_camera_device *icd = v4l2_get_subdev_hostdata(sd);
+               struct v4l2_subdev *client_sd = soc_camera_to_subdev(icd);
+               struct sh_csi2_pdata *pdata = priv->pdev->dev.platform_data;
+               unsigned long common_flags, csi2_flags;
+               struct v4l2_mbus_config client_cfg = {.type = V4L2_MBUS_CSI2,};
+               int ret;
+
+               /* Check if we can support this camera */
+               csi2_flags = V4L2_MBUS_CSI2_CONTINUOUS_CLOCK |
+                       V4L2_MBUS_CSI2_1_LANE;
+
+               switch (pdata->type) {
+               case SH_CSI2C:
+                       if (priv->client->lanes != 1)
+                               csi2_flags |= V4L2_MBUS_CSI2_2_LANE;
+                       break;
+               case SH_CSI2I:
+                       switch (priv->client->lanes) {
+                       default:
+                               csi2_flags |= V4L2_MBUS_CSI2_4_LANE;
+                       case 3:
+                               csi2_flags |= V4L2_MBUS_CSI2_3_LANE;
+                       case 2:
+                               csi2_flags |= V4L2_MBUS_CSI2_2_LANE;
+                       }
+               }
+
+               ret = v4l2_subdev_call(client_sd, video, g_mbus_config, &client_cfg);
+               if (ret == -ENOIOCTLCMD)
+                       common_flags = csi2_flags;
+               else if (!ret)
+                       common_flags = soc_mbus_config_compatible(&client_cfg,
+                                                                 csi2_flags);
+               else
+                       common_flags = 0;
+
+               if (!common_flags)
+                       return -EINVAL;
+
+               /* All good: camera MIPI configuration supported */
+               priv->mipi_flags = common_flags;
+       }
+
+       if (cfg) {
+               cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING |
+                       V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_HIGH |
+                       V4L2_MBUS_MASTER | V4L2_MBUS_DATA_ACTIVE_HIGH;
+               cfg->type = V4L2_MBUS_PARALLEL;
+       }
 
        return 0;
 }
@@ -146,8 +195,17 @@ static int sh_csi2_s_mbus_config(struct v4l2_subdev *sd,
        struct sh_csi2 *priv = container_of(sd, struct sh_csi2, subdev);
        struct soc_camera_device *icd = v4l2_get_subdev_hostdata(sd);
        struct v4l2_subdev *client_sd = soc_camera_to_subdev(icd);
-       struct v4l2_mbus_config client_cfg = {.type = V4L2_MBUS_CSI2,
-                                             .flags = priv->mipi_flags};
+       struct v4l2_mbus_config client_cfg = {.type = V4L2_MBUS_CSI2,};
+       int ret = sh_csi2_g_mbus_config(sd, NULL);
+
+       if (ret < 0)
+               return ret;
+
+       pm_runtime_get_sync(&priv->pdev->dev);
+
+       sh_csi2_hwinit(priv);
+
+       client_cfg.flags = priv->mipi_flags;
 
        return v4l2_subdev_call(client_sd, video, s_mbus_config, &client_cfg);
 }
@@ -202,19 +260,19 @@ static void sh_csi2_hwinit(struct sh_csi2 *priv)
 
 static int sh_csi2_client_connect(struct sh_csi2 *priv)
 {
-       struct sh_csi2_pdata *pdata = priv->pdev->dev.platform_data;
-       struct soc_camera_device *icd = v4l2_get_subdev_hostdata(&priv->subdev);
-       struct v4l2_subdev *client_sd = soc_camera_to_subdev(icd);
        struct device *dev = v4l2_get_subdevdata(&priv->subdev);
-       struct v4l2_mbus_config cfg;
-       unsigned long common_flags, csi2_flags;
-       int i, ret;
+       struct sh_csi2_pdata *pdata = dev->platform_data;
+       struct soc_camera_device *icd = v4l2_get_subdev_hostdata(&priv->subdev);
+       int i;
 
        if (priv->client)
                return -EBUSY;
 
        for (i = 0; i < pdata->num_clients; i++)
-               if (&pdata->clients[i].pdev->dev == icd->pdev)
+               if ((pdata->clients[i].pdev &&
+                    &pdata->clients[i].pdev->dev == icd->pdev) ||
+                   (icd->control &&
+                    strcmp(pdata->clients[i].name, dev_name(icd->control))))
                        break;
 
        dev_dbg(dev, "%s(%p): found #%d\n", __func__, dev, i);
@@ -222,46 +280,8 @@ static int sh_csi2_client_connect(struct sh_csi2 *priv)
        if (i == pdata->num_clients)
                return -ENODEV;
 
-       /* Check if we can support this camera */
-       csi2_flags = V4L2_MBUS_CSI2_CONTINUOUS_CLOCK | V4L2_MBUS_CSI2_1_LANE;
-
-       switch (pdata->type) {
-       case SH_CSI2C:
-               if (pdata->clients[i].lanes != 1)
-                       csi2_flags |= V4L2_MBUS_CSI2_2_LANE;
-               break;
-       case SH_CSI2I:
-               switch (pdata->clients[i].lanes) {
-               default:
-                       csi2_flags |= V4L2_MBUS_CSI2_4_LANE;
-               case 3:
-                       csi2_flags |= V4L2_MBUS_CSI2_3_LANE;
-               case 2:
-                       csi2_flags |= V4L2_MBUS_CSI2_2_LANE;
-               }
-       }
-
-       cfg.type = V4L2_MBUS_CSI2;
-       ret = v4l2_subdev_call(client_sd, video, g_mbus_config, &cfg);
-       if (ret == -ENOIOCTLCMD)
-               common_flags = csi2_flags;
-       else if (!ret)
-               common_flags = soc_mbus_config_compatible(&cfg,
-                                                         csi2_flags);
-       else
-               common_flags = 0;
-
-       if (!common_flags)
-               return -EINVAL;
-
-       /* All good: camera MIPI configuration supported */
-       priv->mipi_flags = common_flags;
        priv->client = pdata->clients + i;
 
-       pm_runtime_get_sync(dev);
-
-       sh_csi2_hwinit(priv);
-
        return 0;
 }
 
@@ -304,11 +324,18 @@ static int sh_csi2_probe(struct platform_device *pdev)
        /* Platform data specify the PHY, lanes, ECC, CRC */
        struct sh_csi2_pdata *pdata = pdev->dev.platform_data;
 
+       if (!pdata)
+               return -EINVAL;
+
+       priv = devm_kzalloc(&pdev->dev, sizeof(struct sh_csi2), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        /* Interrupt unused so far */
        irq = platform_get_irq(pdev, 0);
 
-       if (!res || (int)irq <= 0 || !pdata) {
+       if (!res || (int)irq <= 0) {
                dev_err(&pdev->dev, "Not enough CSI2 platform resources.\n");
                return -ENODEV;
        }
@@ -319,10 +346,6 @@ static int sh_csi2_probe(struct platform_device *pdev)
                return -EINVAL;
        }
 
-       priv = devm_kzalloc(&pdev->dev, sizeof(struct sh_csi2), GFP_KERNEL);
-       if (!priv)
-               return -ENOMEM;
-
        priv->irq = irq;
 
        priv->base = devm_ioremap_resource(&pdev->dev, res);
@@ -330,37 +353,35 @@ static int sh_csi2_probe(struct platform_device *pdev)
                return PTR_ERR(priv->base);
 
        priv->pdev = pdev;
-       platform_set_drvdata(pdev, priv);
+       priv->subdev.owner = THIS_MODULE;
+       priv->subdev.dev = &pdev->dev;
+       platform_set_drvdata(pdev, &priv->subdev);
 
        v4l2_subdev_init(&priv->subdev, &sh_csi2_subdev_ops);
        v4l2_set_subdevdata(&priv->subdev, &pdev->dev);
 
        snprintf(priv->subdev.name, V4L2_SUBDEV_NAME_SIZE, "%s.mipi-csi",
-                dev_name(pdata->v4l2_dev->dev));
-       ret = v4l2_device_register_subdev(pdata->v4l2_dev, &priv->subdev);
-       dev_dbg(&pdev->dev, "%s(%p): ret(register_subdev) = %d\n", __func__, priv, ret);
+                dev_name(&pdev->dev));
+
+       ret = v4l2_async_register_subdev(&priv->subdev);
        if (ret < 0)
-               goto esdreg;
+               return ret;
 
        pm_runtime_enable(&pdev->dev);
 
        dev_dbg(&pdev->dev, "CSI2 probed.\n");
 
        return 0;
-
-esdreg:
-       platform_set_drvdata(pdev, NULL);
-
-       return ret;
 }
 
 static int sh_csi2_remove(struct platform_device *pdev)
 {
-       struct sh_csi2 *priv = platform_get_drvdata(pdev);
+       struct v4l2_subdev *subdev = platform_get_drvdata(pdev);
+       struct sh_csi2 *priv = container_of(subdev, struct sh_csi2, subdev);
 
-       v4l2_device_unregister_subdev(&priv->subdev);
+       v4l2_async_unregister_subdev(&priv->subdev);
+       v4l2_device_unregister_subdev(subdev);
        pm_runtime_disable(&pdev->dev);
-       platform_set_drvdata(pdev, NULL);
 
        return 0;
 }
index 3a4efbd..2dd0e52 100644 (file)
 #include <linux/i2c.h>
 #include <linux/init.h>
 #include <linux/list.h>
-#include <linux/mutex.h>
 #include <linux/module.h>
+#include <linux/mutex.h>
 #include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
 #include <linux/regulator/consumer.h>
 #include <linux/slab.h>
-#include <linux/pm_runtime.h>
 #include <linux/vmalloc.h>
 
 #include <media/soc_camera.h>
+#include <media/soc_mediabus.h>
+#include <media/v4l2-async.h>
+#include <media/v4l2-clk.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-dev.h>
 #include <media/videobuf-core.h>
 #include <media/videobuf2-core.h>
-#include <media/soc_mediabus.h>
 
 /* Default to VGA resolution */
 #define DEFAULT_WIDTH  640
         (icd)->vb_vidq.streaming :                     \
         vb2_is_streaming(&(icd)->vb2_vidq))
 
+#define MAP_MAX_NUM 32
+static DECLARE_BITMAP(device_map, MAP_MAX_NUM);
 static LIST_HEAD(hosts);
 static LIST_HEAD(devices);
-static DEFINE_MUTEX(list_lock);                /* Protects the list of hosts */
+/*
+ * Protects lists and bitmaps of hosts and devices.
+ * Lock nesting: Ok to take ->host_lock under list_lock.
+ */
+static DEFINE_MUTEX(list_lock);
+
+struct soc_camera_async_client {
+       struct v4l2_async_subdev *sensor;
+       struct v4l2_async_notifier notifier;
+       struct platform_device *pdev;
+       struct list_head list;          /* needed for clean up */
+};
+
+static int soc_camera_video_start(struct soc_camera_device *icd);
+static int video_dev_create(struct soc_camera_device *icd);
 
-int soc_camera_power_on(struct device *dev, struct soc_camera_subdev_desc *ssdd)
+int soc_camera_power_on(struct device *dev, struct soc_camera_subdev_desc *ssdd,
+                       struct v4l2_clk *clk)
 {
-       int ret = regulator_bulk_enable(ssdd->num_regulators,
+       int ret = clk ? v4l2_clk_enable(clk) : 0;
+       if (ret < 0) {
+               dev_err(dev, "Cannot enable clock: %d\n", ret);
+               return ret;
+       }
+       ret = regulator_bulk_enable(ssdd->num_regulators,
                                        ssdd->regulators);
        if (ret < 0) {
                dev_err(dev, "Cannot enable regulators\n");
-               return ret;
+               goto eregenable;
        }
 
        if (ssdd->power) {
@@ -64,16 +88,25 @@ int soc_camera_power_on(struct device *dev, struct soc_camera_subdev_desc *ssdd)
                if (ret < 0) {
                        dev_err(dev,
                                "Platform failed to power-on the camera.\n");
-                       regulator_bulk_disable(ssdd->num_regulators,
-                                              ssdd->regulators);
+                       goto epwron;
                }
        }
 
+       return 0;
+
+epwron:
+       regulator_bulk_disable(ssdd->num_regulators,
+                              ssdd->regulators);
+eregenable:
+       if (clk)
+               v4l2_clk_disable(clk);
+
        return ret;
 }
 EXPORT_SYMBOL(soc_camera_power_on);
 
-int soc_camera_power_off(struct device *dev, struct soc_camera_subdev_desc *ssdd)
+int soc_camera_power_off(struct device *dev, struct soc_camera_subdev_desc *ssdd,
+                        struct v4l2_clk *clk)
 {
        int ret = 0;
        int err;
@@ -94,10 +127,21 @@ int soc_camera_power_off(struct device *dev, struct soc_camera_subdev_desc *ssdd
                ret = ret ? : err;
        }
 
+       if (clk)
+               v4l2_clk_disable(clk);
+
        return ret;
 }
 EXPORT_SYMBOL(soc_camera_power_off);
 
+int soc_camera_power_init(struct device *dev, struct soc_camera_subdev_desc *ssdd)
+{
+
+       return devm_regulator_bulk_get(dev, ssdd->num_regulators,
+                                      ssdd->regulators);
+}
+EXPORT_SYMBOL(soc_camera_power_init);
+
 static int __soc_camera_power_on(struct soc_camera_device *icd)
 {
        struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
@@ -235,7 +279,6 @@ static int soc_camera_enum_input(struct file *file, void *priv,
 
        /* default is camera */
        inp->type = V4L2_INPUT_TYPE_CAMERA;
-       inp->std  = V4L2_STD_UNKNOWN;
        strcpy(inp->name, "Camera");
 
        return 0;
@@ -505,6 +548,58 @@ static int soc_camera_set_fmt(struct soc_camera_device *icd,
        return ici->ops->set_bus_param(icd);
 }
 
+static int soc_camera_add_device(struct soc_camera_device *icd)
+{
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+       int ret;
+
+       if (ici->icd)
+               return -EBUSY;
+
+       if (!icd->clk) {
+               mutex_lock(&ici->clk_lock);
+               ret = ici->ops->clock_start(ici);
+               mutex_unlock(&ici->clk_lock);
+               if (ret < 0)
+                       return ret;
+       }
+
+       if (ici->ops->add) {
+               ret = ici->ops->add(icd);
+               if (ret < 0)
+                       goto eadd;
+       }
+
+       ici->icd = icd;
+
+       return 0;
+
+eadd:
+       if (!icd->clk) {
+               mutex_lock(&ici->clk_lock);
+               ici->ops->clock_stop(ici);
+               mutex_unlock(&ici->clk_lock);
+       }
+       return ret;
+}
+
+static void soc_camera_remove_device(struct soc_camera_device *icd)
+{
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+
+       if (WARN_ON(icd != ici->icd))
+               return;
+
+       if (ici->ops->remove)
+               ici->ops->remove(icd);
+       if (!icd->clk) {
+               mutex_lock(&ici->clk_lock);
+               ici->ops->clock_stop(ici);
+               mutex_unlock(&ici->clk_lock);
+       }
+       ici->icd = NULL;
+}
+
 static int soc_camera_open(struct file *file)
 {
        struct video_device *vdev = video_devdata(file);
@@ -525,7 +620,7 @@ static int soc_camera_open(struct file *file)
                return -ENODEV;
        }
 
-       icd = dev_get_drvdata(vdev->parent);
+       icd = video_get_drvdata(vdev);
        ici = to_soc_camera_host(icd->parent);
 
        ret = try_module_get(ici->ops->owner) ? 0 : -ENODEV;
@@ -568,7 +663,7 @@ static int soc_camera_open(struct file *file)
                if (sdesc->subdev_desc.reset)
                        sdesc->subdev_desc.reset(icd->pdev);
 
-               ret = ici->ops->add(icd);
+               ret = soc_camera_add_device(icd);
                if (ret < 0) {
                        dev_err(icd->pdev, "Couldn't activate the camera: %d\n", ret);
                        goto eiciadd;
@@ -610,8 +705,8 @@ static int soc_camera_open(struct file *file)
        return 0;
 
        /*
-        * First four errors are entered with the .host_lock held
-        * and use_count == 1
+        * All errors are entered with the .host_lock held, first four also
+        * with use_count == 1
         */
 einitvb:
 esfmt:
@@ -619,7 +714,7 @@ esfmt:
 eresume:
        __soc_camera_power_off(icd);
 epower:
-       ici->ops->remove(icd);
+       soc_camera_remove_device(icd);
 eiciadd:
        icd->use_count--;
        mutex_unlock(&ici->host_lock);
@@ -645,7 +740,7 @@ static int soc_camera_close(struct file *file)
                        vb2_queue_release(&icd->vb2_vidq);
                __soc_camera_power_off(icd);
 
-               ici->ops->remove(icd);
+               soc_camera_remove_device(icd);
        }
 
        if (icd->streamer == file)
@@ -1036,76 +1131,225 @@ static int soc_camera_s_parm(struct file *file, void *fh,
        return -ENOIOCTLCMD;
 }
 
-static int soc_camera_g_chip_ident(struct file *file, void *fh,
-                                  struct v4l2_dbg_chip_ident *id)
+static int soc_camera_probe(struct soc_camera_host *ici,
+                           struct soc_camera_device *icd);
+
+/* So far this function cannot fail */
+static void scan_add_host(struct soc_camera_host *ici)
 {
-       struct soc_camera_device *icd = file->private_data;
-       struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+       struct soc_camera_device *icd;
+
+       mutex_lock(&list_lock);
+
+       list_for_each_entry(icd, &devices, list)
+               if (icd->iface == ici->nr) {
+                       struct soc_camera_desc *sdesc = to_soc_camera_desc(icd);
+                       struct soc_camera_subdev_desc *ssdd = &sdesc->subdev_desc;
+
+                       /* The camera could have been already on, try to reset */
+                       if (ssdd->reset)
+                               ssdd->reset(icd->pdev);
 
-       return v4l2_subdev_call(sd, core, g_chip_ident, id);
+                       icd->parent = ici->v4l2_dev.dev;
+
+                       /* Ignore errors */
+                       soc_camera_probe(ici, icd);
+               }
+
+       mutex_unlock(&list_lock);
 }
 
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-static int soc_camera_g_register(struct file *file, void *fh,
-                                struct v4l2_dbg_register *reg)
+/*
+ * It is invalid to call v4l2_clk_enable() after a successful probing
+ * asynchronously outside of V4L2 operations, i.e. with .host_lock not held.
+ */
+static int soc_camera_clk_enable(struct v4l2_clk *clk)
 {
-       struct soc_camera_device *icd = file->private_data;
-       struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+       struct soc_camera_device *icd = clk->priv;
+       struct soc_camera_host *ici;
+       int ret;
+
+       if (!icd || !icd->parent)
+               return -ENODEV;
+
+       ici = to_soc_camera_host(icd->parent);
+
+       if (!try_module_get(ici->ops->owner))
+               return -ENODEV;
 
-       return v4l2_subdev_call(sd, core, g_register, reg);
+       /*
+        * If a different client is currently being probed, the host will tell
+        * you to go
+        */
+       mutex_lock(&ici->clk_lock);
+       ret = ici->ops->clock_start(ici);
+       mutex_unlock(&ici->clk_lock);
+       return ret;
 }
 
-static int soc_camera_s_register(struct file *file, void *fh,
-                                const struct v4l2_dbg_register *reg)
+static void soc_camera_clk_disable(struct v4l2_clk *clk)
 {
-       struct soc_camera_device *icd = file->private_data;
-       struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+       struct soc_camera_device *icd = clk->priv;
+       struct soc_camera_host *ici;
+
+       if (!icd || !icd->parent)
+               return;
+
+       ici = to_soc_camera_host(icd->parent);
+
+       mutex_lock(&ici->clk_lock);
+       ici->ops->clock_stop(ici);
+       mutex_unlock(&ici->clk_lock);
 
-       return v4l2_subdev_call(sd, core, s_register, reg);
+       module_put(ici->ops->owner);
 }
-#endif
 
-static int soc_camera_probe(struct soc_camera_device *icd);
+/*
+ * Eventually, it would be more logical to make the respective host the clock
+ * owner, but then we would have to copy this struct for each ici. Besides, it
+ * would introduce the circular dependency problem, unless we port all client
+ * drivers to release the clock, when not in use.
+ */
+static const struct v4l2_clk_ops soc_camera_clk_ops = {
+       .owner = THIS_MODULE,
+       .enable = soc_camera_clk_enable,
+       .disable = soc_camera_clk_disable,
+};
 
-/* So far this function cannot fail */
-static void scan_add_host(struct soc_camera_host *ici)
+static int soc_camera_dyn_pdev(struct soc_camera_desc *sdesc,
+                              struct soc_camera_async_client *sasc)
 {
-       struct soc_camera_device *icd;
+       struct platform_device *pdev;
+       int ret, i;
 
        mutex_lock(&list_lock);
+       i = find_first_zero_bit(device_map, MAP_MAX_NUM);
+       if (i < MAP_MAX_NUM)
+               set_bit(i, device_map);
+       mutex_unlock(&list_lock);
+       if (i >= MAP_MAX_NUM)
+               return -ENOMEM;
 
-       list_for_each_entry(icd, &devices, list) {
-               if (icd->iface == ici->nr) {
-                       icd->parent = ici->v4l2_dev.dev;
-                       soc_camera_probe(icd);
-               }
+       pdev = platform_device_alloc("soc-camera-pdrv", i);
+       if (!pdev)
+               return -ENOMEM;
+
+       ret = platform_device_add_data(pdev, sdesc, sizeof(*sdesc));
+       if (ret < 0) {
+               platform_device_put(pdev);
+               return ret;
        }
 
-       mutex_unlock(&list_lock);
+       sasc->pdev = pdev;
+
+       return 0;
+}
+
+static struct soc_camera_device *soc_camera_add_pdev(struct soc_camera_async_client *sasc)
+{
+       struct platform_device *pdev = sasc->pdev;
+       int ret;
+
+       ret = platform_device_add(pdev);
+       if (ret < 0 || !pdev->dev.driver)
+               return NULL;
+
+       return platform_get_drvdata(pdev);
+}
+
+/* Locking: called with .host_lock held */
+static int soc_camera_probe_finish(struct soc_camera_device *icd)
+{
+       struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+       struct v4l2_mbus_framefmt mf;
+       int ret;
+
+       sd->grp_id = soc_camera_grp_id(icd);
+       v4l2_set_subdev_hostdata(sd, icd);
+
+       ret = v4l2_ctrl_add_handler(&icd->ctrl_handler, sd->ctrl_handler, NULL);
+       if (ret < 0)
+               return ret;
+
+       ret = soc_camera_add_device(icd);
+       if (ret < 0) {
+               dev_err(icd->pdev, "Couldn't activate the camera: %d\n", ret);
+               return ret;
+       }
+
+       /* At this point client .probe() should have run already */
+       ret = soc_camera_init_user_formats(icd);
+       if (ret < 0)
+               goto eusrfmt;
+
+       icd->field = V4L2_FIELD_ANY;
+
+       ret = soc_camera_video_start(icd);
+       if (ret < 0)
+               goto evidstart;
+
+       /* Try to improve our guess of a reasonable window format */
+       if (!v4l2_subdev_call(sd, video, g_mbus_fmt, &mf)) {
+               icd->user_width         = mf.width;
+               icd->user_height        = mf.height;
+               icd->colorspace         = mf.colorspace;
+               icd->field              = mf.field;
+       }
+       soc_camera_remove_device(icd);
+
+       return 0;
+
+evidstart:
+       soc_camera_free_user_formats(icd);
+eusrfmt:
+       soc_camera_remove_device(icd);
+
+       return ret;
 }
 
 #ifdef CONFIG_I2C_BOARDINFO
-static int soc_camera_init_i2c(struct soc_camera_device *icd,
+static int soc_camera_i2c_init(struct soc_camera_device *icd,
                               struct soc_camera_desc *sdesc)
 {
        struct i2c_client *client;
-       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+       struct soc_camera_host *ici;
        struct soc_camera_host_desc *shd = &sdesc->host_desc;
-       struct i2c_adapter *adap = i2c_get_adapter(shd->i2c_adapter_id);
+       struct i2c_adapter *adap;
        struct v4l2_subdev *subdev;
+       char clk_name[V4L2_SUBDEV_NAME_SIZE];
+       int ret;
 
+       /* First find out how we link the main client */
+       if (icd->sasc) {
+               /* Async non-OF probing handled by the subdevice list */
+               return -EPROBE_DEFER;
+       }
+
+       ici = to_soc_camera_host(icd->parent);
+       adap = i2c_get_adapter(shd->i2c_adapter_id);
        if (!adap) {
                dev_err(icd->pdev, "Cannot get I2C adapter #%d. No driver?\n",
                        shd->i2c_adapter_id);
-               goto ei2cga;
+               return -ENODEV;
        }
 
        shd->board_info->platform_data = &sdesc->subdev_desc;
 
+       snprintf(clk_name, sizeof(clk_name), "%d-%04x",
+                shd->i2c_adapter_id, shd->board_info->addr);
+
+       icd->clk = v4l2_clk_register(&soc_camera_clk_ops, clk_name, "mclk", icd);
+       if (IS_ERR(icd->clk)) {
+               ret = PTR_ERR(icd->clk);
+               goto eclkreg;
+       }
+
        subdev = v4l2_i2c_new_subdev_board(&ici->v4l2_dev, adap,
                                shd->board_info, NULL);
-       if (!subdev)
+       if (!subdev) {
+               ret = -ENODEV;
                goto ei2cnd;
+       }
 
        client = v4l2_get_subdevdata(subdev);
 
@@ -1114,39 +1358,203 @@ static int soc_camera_init_i2c(struct soc_camera_device *icd,
 
        return 0;
 ei2cnd:
+       v4l2_clk_unregister(icd->clk);
+eclkreg:
+       icd->clk = NULL;
        i2c_put_adapter(adap);
-ei2cga:
-       return -ENODEV;
+       return ret;
 }
 
-static void soc_camera_free_i2c(struct soc_camera_device *icd)
+static void soc_camera_i2c_free(struct soc_camera_device *icd)
 {
        struct i2c_client *client =
                to_i2c_client(to_soc_camera_control(icd));
-       struct i2c_adapter *adap = client->adapter;
+       struct i2c_adapter *adap;
 
        icd->control = NULL;
+       if (icd->sasc)
+               return;
+
+       adap = client->adapter;
        v4l2_device_unregister_subdev(i2c_get_clientdata(client));
        i2c_unregister_device(client);
        i2c_put_adapter(adap);
+       v4l2_clk_unregister(icd->clk);
+       icd->clk = NULL;
+}
+
+/*
+ * V4L2 asynchronous notifier callbacks. They are all called under a v4l2-async
+ * internal global mutex, therefore cannot race against other asynchronous
+ * events. Until notifier->complete() (soc_camera_async_complete()) is called,
+ * the video device node is not registered and no V4L fops can occur. Unloading
+ * of the host driver also calls a v4l2-async function, so also there we're
+ * protected.
+ */
+static int soc_camera_async_bound(struct v4l2_async_notifier *notifier,
+                                 struct v4l2_subdev *sd,
+                                 struct v4l2_async_subdev *asd)
+{
+       struct soc_camera_async_client *sasc = container_of(notifier,
+                                       struct soc_camera_async_client, notifier);
+       struct soc_camera_device *icd = platform_get_drvdata(sasc->pdev);
+
+       if (asd == sasc->sensor && !WARN_ON(icd->control)) {
+               struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+               /*
+                * Only now we get subdevice-specific information like
+                * regulators, flags, callbacks, etc.
+                */
+               if (client) {
+                       struct soc_camera_desc *sdesc = to_soc_camera_desc(icd);
+                       struct soc_camera_subdev_desc *ssdd =
+                               soc_camera_i2c_to_desc(client);
+                       if (ssdd) {
+                               memcpy(&sdesc->subdev_desc, ssdd,
+                                      sizeof(sdesc->subdev_desc));
+                               if (ssdd->reset)
+                                       ssdd->reset(icd->pdev);
+                       }
+
+                       icd->control = &client->dev;
+               }
+       }
+
+       return 0;
+}
+
+static void soc_camera_async_unbind(struct v4l2_async_notifier *notifier,
+                                   struct v4l2_subdev *sd,
+                                   struct v4l2_async_subdev *asd)
+{
+       struct soc_camera_async_client *sasc = container_of(notifier,
+                                       struct soc_camera_async_client, notifier);
+       struct soc_camera_device *icd = platform_get_drvdata(sasc->pdev);
+
+       if (icd->clk) {
+               v4l2_clk_unregister(icd->clk);
+               icd->clk = NULL;
+       }
+}
+
+static int soc_camera_async_complete(struct v4l2_async_notifier *notifier)
+{
+       struct soc_camera_async_client *sasc = container_of(notifier,
+                                       struct soc_camera_async_client, notifier);
+       struct soc_camera_device *icd = platform_get_drvdata(sasc->pdev);
+
+       if (to_soc_camera_control(icd)) {
+               struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+               int ret;
+
+               mutex_lock(&list_lock);
+               ret = soc_camera_probe(ici, icd);
+               mutex_unlock(&list_lock);
+               if (ret < 0)
+                       return ret;
+       }
+
+       return 0;
+}
+
+static int scan_async_group(struct soc_camera_host *ici,
+                           struct v4l2_async_subdev **asd, unsigned int size)
+{
+       struct soc_camera_async_subdev *sasd;
+       struct soc_camera_async_client *sasc;
+       struct soc_camera_device *icd;
+       struct soc_camera_desc sdesc = {.host_desc.bus_id = ici->nr,};
+       char clk_name[V4L2_SUBDEV_NAME_SIZE];
+       int ret, i;
+
+       /* First look for a sensor */
+       for (i = 0; i < size; i++) {
+               sasd = container_of(asd[i], struct soc_camera_async_subdev, asd);
+               if (sasd->role == SOCAM_SUBDEV_DATA_SOURCE)
+                       break;
+       }
+
+       if (i == size || asd[i]->bus_type != V4L2_ASYNC_BUS_I2C) {
+               /* All useless */
+               dev_err(ici->v4l2_dev.dev, "No I2C data source found!\n");
+               return -ENODEV;
+       }
+
+       /* Or shall this be managed by the soc-camera device? */
+       sasc = devm_kzalloc(ici->v4l2_dev.dev, sizeof(*sasc), GFP_KERNEL);
+       if (!sasc)
+               return -ENOMEM;
+
+       /* HACK: just need a != NULL */
+       sdesc.host_desc.board_info = ERR_PTR(-ENODATA);
+
+       ret = soc_camera_dyn_pdev(&sdesc, sasc);
+       if (ret < 0)
+               return ret;
+
+       sasc->sensor = &sasd->asd;
+
+       icd = soc_camera_add_pdev(sasc);
+       if (!icd) {
+               platform_device_put(sasc->pdev);
+               return -ENOMEM;
+       }
+
+       sasc->notifier.subdev = asd;
+       sasc->notifier.num_subdevs = size;
+       sasc->notifier.bound = soc_camera_async_bound;
+       sasc->notifier.unbind = soc_camera_async_unbind;
+       sasc->notifier.complete = soc_camera_async_complete;
+
+       icd->sasc = sasc;
+       icd->parent = ici->v4l2_dev.dev;
+
+       snprintf(clk_name, sizeof(clk_name), "%d-%04x",
+                sasd->asd.match.i2c.adapter_id, sasd->asd.match.i2c.address);
+
+       icd->clk = v4l2_clk_register(&soc_camera_clk_ops, clk_name, "mclk", icd);
+       if (IS_ERR(icd->clk)) {
+               ret = PTR_ERR(icd->clk);
+               goto eclkreg;
+       }
+
+       ret = v4l2_async_notifier_register(&ici->v4l2_dev, &sasc->notifier);
+       if (!ret)
+               return 0;
+
+       v4l2_clk_unregister(icd->clk);
+eclkreg:
+       icd->clk = NULL;
+       platform_device_unregister(sasc->pdev);
+       dev_err(ici->v4l2_dev.dev, "group probe failed: %d\n", ret);
+
+       return ret;
+}
+
+static void scan_async_host(struct soc_camera_host *ici)
+{
+       struct v4l2_async_subdev **asd;
+       int j;
+
+       for (j = 0, asd = ici->asd; ici->asd_sizes[j]; j++) {
+               scan_async_group(ici, asd, ici->asd_sizes[j]);
+               asd += ici->asd_sizes[j];
+       }
 }
 #else
-#define soc_camera_init_i2c(icd, sdesc)        (-ENODEV)
-#define soc_camera_free_i2c(icd)       do {} while (0)
+#define soc_camera_i2c_init(icd, sdesc)        (-ENODEV)
+#define soc_camera_i2c_free(icd)       do {} while (0)
+#define scan_async_host(ici)           do {} while (0)
 #endif
 
-static int soc_camera_video_start(struct soc_camera_device *icd);
-static int video_dev_create(struct soc_camera_device *icd);
 /* Called during host-driver probe */
-static int soc_camera_probe(struct soc_camera_device *icd)
+static int soc_camera_probe(struct soc_camera_host *ici,
+                           struct soc_camera_device *icd)
 {
-       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct soc_camera_desc *sdesc = to_soc_camera_desc(icd);
        struct soc_camera_host_desc *shd = &sdesc->host_desc;
-       struct soc_camera_subdev_desc *ssdd = &sdesc->subdev_desc;
        struct device *control = NULL;
-       struct v4l2_subdev *sd;
-       struct v4l2_mbus_framefmt mf;
        int ret;
 
        dev_info(icd->pdev, "Probing %s\n", dev_name(icd->pdev));
@@ -1162,30 +1570,32 @@ static int soc_camera_probe(struct soc_camera_device *icd)
        if (ret < 0)
                return ret;
 
-       /* The camera could have been already on, try to reset */
-       if (ssdd->reset)
-               ssdd->reset(icd->pdev);
-
-       mutex_lock(&ici->host_lock);
-       ret = ici->ops->add(icd);
-       mutex_unlock(&ici->host_lock);
-       if (ret < 0)
-               goto eadd;
-
        /* Must have icd->vdev before registering the device */
        ret = video_dev_create(icd);
        if (ret < 0)
                goto evdc;
 
+       /*
+        * ..._video_start() will create a device node, video_register_device()
+        * itself is protected against concurrent open() calls, but we also have
+        * to protect our data also during client probing.
+        */
+
        /* Non-i2c cameras, e.g., soc_camera_platform, have no board_info */
        if (shd->board_info) {
-               ret = soc_camera_init_i2c(icd, sdesc);
-               if (ret < 0)
-                       goto eadddev;
+               ret = soc_camera_i2c_init(icd, sdesc);
+               if (ret < 0 && ret != -EPROBE_DEFER)
+                       goto eadd;
        } else if (!shd->add_device || !shd->del_device) {
                ret = -EINVAL;
-               goto eadddev;
+               goto eadd;
        } else {
+               mutex_lock(&ici->clk_lock);
+               ret = ici->ops->clock_start(ici);
+               mutex_unlock(&ici->clk_lock);
+               if (ret < 0)
+                       goto eadd;
+
                if (shd->module_name)
                        ret = request_module(shd->module_name);
 
@@ -1206,81 +1616,49 @@ static int soc_camera_probe(struct soc_camera_device *icd)
                }
        }
 
-       sd = soc_camera_to_subdev(icd);
-       sd->grp_id = soc_camera_grp_id(icd);
-       v4l2_set_subdev_hostdata(sd, icd);
-
-       ret = v4l2_ctrl_add_handler(&icd->ctrl_handler, sd->ctrl_handler, NULL);
-       if (ret < 0)
-               goto ectrl;
-
-       /* At this point client .probe() should have run already */
-       ret = soc_camera_init_user_formats(icd);
-       if (ret < 0)
-               goto eiufmt;
-
-       icd->field = V4L2_FIELD_ANY;
-
-       /*
-        * ..._video_start() will create a device node, video_register_device()
-        * itself is protected against concurrent open() calls, but we also have
-        * to protect our data.
-        */
        mutex_lock(&ici->host_lock);
-
-       ret = soc_camera_video_start(icd);
-       if (ret < 0)
-               goto evidstart;
-
-       /* Try to improve our guess of a reasonable window format */
-       if (!v4l2_subdev_call(sd, video, g_mbus_fmt, &mf)) {
-               icd->user_width         = mf.width;
-               icd->user_height        = mf.height;
-               icd->colorspace         = mf.colorspace;
-               icd->field              = mf.field;
-       }
-
-       ici->ops->remove(icd);
-
+       ret = soc_camera_probe_finish(icd);
        mutex_unlock(&ici->host_lock);
+       if (ret < 0)
+               goto efinish;
 
        return 0;
 
-evidstart:
-       mutex_unlock(&ici->host_lock);
-       soc_camera_free_user_formats(icd);
-eiufmt:
-ectrl:
+efinish:
        if (shd->board_info) {
-               soc_camera_free_i2c(icd);
+               soc_camera_i2c_free(icd);
        } else {
                shd->del_device(icd);
                module_put(control->driver->owner);
-       }
 enodrv:
 eadddev:
+               mutex_lock(&ici->clk_lock);
+               ici->ops->clock_stop(ici);
+               mutex_unlock(&ici->clk_lock);
+       }
+eadd:
        video_device_release(icd->vdev);
        icd->vdev = NULL;
+       if (icd->vdev) {
+               video_device_release(icd->vdev);
+               icd->vdev = NULL;
+       }
 evdc:
-       mutex_lock(&ici->host_lock);
-       ici->ops->remove(icd);
-       mutex_unlock(&ici->host_lock);
-eadd:
        v4l2_ctrl_handler_free(&icd->ctrl_handler);
        return ret;
 }
 
 /*
  * This is called on device_unregister, which only means we have to disconnect
- * from the host, but not remove ourselves from the device list
+ * from the host, but not remove ourselves from the device list. With
+ * asynchronous client probing this can also be called without
+ * soc_camera_probe_finish() having run. Careful with clean up.
  */
 static int soc_camera_remove(struct soc_camera_device *icd)
 {
        struct soc_camera_desc *sdesc = to_soc_camera_desc(icd);
        struct video_device *vdev = icd->vdev;
 
-       BUG_ON(!icd->parent);
-
        v4l2_ctrl_handler_free(&icd->ctrl_handler);
        if (vdev) {
                video_unregister_device(vdev);
@@ -1288,15 +1666,27 @@ static int soc_camera_remove(struct soc_camera_device *icd)
        }
 
        if (sdesc->host_desc.board_info) {
-               soc_camera_free_i2c(icd);
+               soc_camera_i2c_free(icd);
        } else {
-               struct device_driver *drv = to_soc_camera_control(icd)->driver;
+               struct device *dev = to_soc_camera_control(icd);
+               struct device_driver *drv = dev ? dev->driver : NULL;
                if (drv) {
                        sdesc->host_desc.del_device(icd);
                        module_put(drv->owner);
                }
        }
-       soc_camera_free_user_formats(icd);
+
+       if (icd->num_user_formats)
+               soc_camera_free_user_formats(icd);
+
+       if (icd->clk) {
+               /* For the synchronous case */
+               v4l2_clk_unregister(icd->clk);
+               icd->clk = NULL;
+       }
+
+       if (icd->sasc)
+               platform_device_unregister(icd->sasc->pdev);
 
        return 0;
 }
@@ -1372,8 +1762,8 @@ int soc_camera_host_register(struct soc_camera_host *ici)
            ((!ici->ops->init_videobuf ||
              !ici->ops->reqbufs) &&
             !ici->ops->init_videobuf2) ||
-           !ici->ops->add ||
-           !ici->ops->remove ||
+           !ici->ops->clock_start ||
+           !ici->ops->clock_stop ||
            !ici->ops->poll ||
            !ici->v4l2_dev.dev)
                return -EINVAL;
@@ -1407,7 +1797,18 @@ int soc_camera_host_register(struct soc_camera_host *ici)
        mutex_unlock(&list_lock);
 
        mutex_init(&ici->host_lock);
-       scan_add_host(ici);
+       mutex_init(&ici->clk_lock);
+
+       if (ici->asd_sizes)
+               /*
+                * No OF, host with a list of subdevices. Don't try to mix
+                * modes by initialising some groups statically and some
+                * dynamically!
+                */
+               scan_async_host(ici);
+       else
+               /* Legacy: static platform devices from board data */
+               scan_add_host(ici);
 
        return 0;
 
@@ -1420,13 +1821,30 @@ EXPORT_SYMBOL(soc_camera_host_register);
 /* Unregister all clients! */
 void soc_camera_host_unregister(struct soc_camera_host *ici)
 {
-       struct soc_camera_device *icd;
+       struct soc_camera_device *icd, *tmp;
+       struct soc_camera_async_client *sasc;
+       LIST_HEAD(notifiers);
 
        mutex_lock(&list_lock);
-
        list_del(&ici->list);
        list_for_each_entry(icd, &devices, list)
-               if (icd->iface == ici->nr && to_soc_camera_control(icd))
+               if (icd->iface == ici->nr && icd->sasc) {
+                       /* as long as we hold the device, sasc won't be freed */
+                       get_device(icd->pdev);
+                       list_add(&icd->sasc->list, &notifiers);
+               }
+       mutex_unlock(&list_lock);
+
+       list_for_each_entry(sasc, &notifiers, list) {
+               /* Must call unlocked to avoid AB-BA dead-lock */
+               v4l2_async_notifier_unregister(&sasc->notifier);
+               put_device(&sasc->pdev->dev);
+       }
+
+       mutex_lock(&list_lock);
+
+       list_for_each_entry_safe(icd, tmp, &devices, list)
+               if (icd->iface == ici->nr)
                        soc_camera_remove(icd);
 
        mutex_unlock(&list_lock);
@@ -1441,6 +1859,7 @@ static int soc_camera_device_register(struct soc_camera_device *icd)
        struct soc_camera_device *ix;
        int num = -1, i;
 
+       mutex_lock(&list_lock);
        for (i = 0; i < 256 && num < 0; i++) {
                num = i;
                /* Check if this index is available on this interface */
@@ -1452,18 +1871,34 @@ static int soc_camera_device_register(struct soc_camera_device *icd)
                }
        }
 
-       if (num < 0)
+       if (num < 0) {
                /*
                 * ok, we have 256 cameras on this host...
                 * man, stay reasonable...
                 */
+               mutex_unlock(&list_lock);
                return -ENOMEM;
+       }
 
        icd->devnum             = num;
        icd->use_count          = 0;
        icd->host_priv          = NULL;
 
+       /*
+        * Dynamically allocated devices set the bit earlier, but it doesn't hurt setting
+        * it again
+        */
+       i = to_platform_device(icd->pdev)->id;
+       if (i < 0)
+               /* One static (legacy) soc-camera platform device */
+               i = 0;
+       if (i >= MAP_MAX_NUM) {
+               mutex_unlock(&list_lock);
+               return -EBUSY;
+       }
+       set_bit(i, device_map);
        list_add_tail(&icd->list, &devices);
+       mutex_unlock(&list_lock);
 
        return 0;
 }
@@ -1495,11 +1930,6 @@ static const struct v4l2_ioctl_ops soc_camera_ioctl_ops = {
        .vidioc_s_selection      = soc_camera_s_selection,
        .vidioc_g_parm           = soc_camera_g_parm,
        .vidioc_s_parm           = soc_camera_s_parm,
-       .vidioc_g_chip_ident     = soc_camera_g_chip_ident,
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-       .vidioc_g_register       = soc_camera_g_register,
-       .vidioc_s_register       = soc_camera_s_register,
-#endif
 };
 
 static int video_dev_create(struct soc_camera_device *icd)
@@ -1512,12 +1942,10 @@ static int video_dev_create(struct soc_camera_device *icd)
 
        strlcpy(vdev->name, ici->drv_name, sizeof(vdev->name));
 
-       vdev->parent            = icd->pdev;
-       vdev->current_norm      = V4L2_STD_UNKNOWN;
+       vdev->v4l2_dev          = &ici->v4l2_dev;
        vdev->fops              = &soc_camera_fops;
        vdev->ioctl_ops         = &soc_camera_ioctl_ops;
        vdev->release           = video_device_release;
-       vdev->tvnorms           = V4L2_STD_UNKNOWN;
        vdev->ctrl_handler      = &icd->ctrl_handler;
        vdev->lock              = &ici->host_lock;
 
@@ -1537,6 +1965,7 @@ static int soc_camera_video_start(struct soc_camera_device *icd)
        if (!icd->parent)
                return -ENODEV;
 
+       video_set_drvdata(icd->vdev, icd);
        ret = video_register_device(icd->vdev, VFL_TYPE_GRABBER, -1);
        if (ret < 0) {
                dev_err(icd->pdev, "video_register_device failed: %d\n", ret);
@@ -1563,6 +1992,12 @@ static int soc_camera_pdrv_probe(struct platform_device *pdev)
        if (!icd)
                return -ENOMEM;
 
+       /*
+        * In the asynchronous case ssdd->num_regulators == 0 yet, so, the below
+        * regulator allocation is a dummy. They will be really requested later
+        * in soc_camera_async_bind(). Also note, that in that case regulators
+        * are attached to the I2C device and not to the camera platform device.
+        */
        ret = devm_regulator_bulk_get(&pdev->dev, ssdd->num_regulators,
                                      ssdd->regulators);
        if (ret < 0)
@@ -1587,11 +2022,25 @@ static int soc_camera_pdrv_probe(struct platform_device *pdev)
 static int soc_camera_pdrv_remove(struct platform_device *pdev)
 {
        struct soc_camera_device *icd = platform_get_drvdata(pdev);
+       int i;
 
        if (!icd)
                return -EINVAL;
 
-       list_del(&icd->list);
+       i = pdev->id;
+       if (i < 0)
+               i = 0;
+
+       /*
+        * In synchronous mode with static platform devices this is called in a
+        * loop from drivers/base/dd.c::driver_detach(), no parallel execution,
+        * no need to lock. In asynchronous case the caller -
+        * soc_camera_host_unregister() - already holds the lock
+        */
+       if (test_bit(i, device_map)) {
+               clear_bit(i, device_map);
+               list_del(&icd->list);
+       }
 
        return 0;
 }
index 1b7a88c..ceaddfb 100644 (file)
@@ -54,7 +54,7 @@ static int soc_camera_platform_s_power(struct v4l2_subdev *sd, int on)
 {
        struct soc_camera_platform_info *p = v4l2_get_subdevdata(sd);
 
-       return soc_camera_set_power(p->icd->control, &p->icd->sdesc->subdev_desc, on);
+       return soc_camera_set_power(p->icd->control, &p->icd->sdesc->subdev_desc, NULL, on);
 }
 
 static struct v4l2_subdev_core_ops platform_subdev_core_ops = {
@@ -137,7 +137,6 @@ static int soc_camera_platform_probe(struct platform_device *pdev)
        struct soc_camera_platform_priv *priv;
        struct soc_camera_platform_info *p = pdev->dev.platform_data;
        struct soc_camera_device *icd;
-       int ret;
 
        if (!p)
                return -EINVAL;
@@ -165,15 +164,7 @@ static int soc_camera_platform_probe(struct platform_device *pdev)
        v4l2_set_subdevdata(&priv->subdev, p);
        strncpy(priv->subdev.name, dev_name(&pdev->dev), V4L2_SUBDEV_NAME_SIZE);
 
-       ret = v4l2_device_register_subdev(&ici->v4l2_dev, &priv->subdev);
-       if (ret)
-               goto evdrs;
-
-       return ret;
-
-evdrs:
-       platform_set_drvdata(pdev, NULL);
-       return ret;
+       return v4l2_device_register_subdev(&ici->v4l2_dev, &priv->subdev);
 }
 
 static int soc_camera_platform_remove(struct platform_device *pdev)
@@ -183,7 +174,6 @@ static int soc_camera_platform_remove(struct platform_device *pdev)
 
        p->icd->control = NULL;
        v4l2_device_unregister_subdev(&priv->subdev);
-       platform_set_drvdata(pdev, NULL);
        return 0;
 }
 
diff --git a/drivers/media/platform/soc_camera/soc_scale_crop.c b/drivers/media/platform/soc_camera/soc_scale_crop.c
new file mode 100644 (file)
index 0000000..cbd3a34
--- /dev/null
@@ -0,0 +1,402 @@
+/*
+ * soc-camera generic scaling-cropping manipulation functions
+ *
+ * Copyright (C) 2013 Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/device.h>
+#include <linux/module.h>
+
+#include <media/soc_camera.h>
+#include <media/v4l2-common.h>
+
+#include "soc_scale_crop.h"
+
+#ifdef DEBUG_GEOMETRY
+#define dev_geo        dev_info
+#else
+#define dev_geo        dev_dbg
+#endif
+
+/* Check if any dimension of r1 is smaller than respective one of r2 */
+static bool is_smaller(const struct v4l2_rect *r1, const struct v4l2_rect *r2)
+{
+       return r1->width < r2->width || r1->height < r2->height;
+}
+
+/* Check if r1 fails to cover r2 */
+static bool is_inside(const struct v4l2_rect *r1, const struct v4l2_rect *r2)
+{
+       return r1->left > r2->left || r1->top > r2->top ||
+               r1->left + r1->width < r2->left + r2->width ||
+               r1->top + r1->height < r2->top + r2->height;
+}
+
+/* Get and store current client crop */
+int soc_camera_client_g_rect(struct v4l2_subdev *sd, struct v4l2_rect *rect)
+{
+       struct v4l2_crop crop;
+       struct v4l2_cropcap cap;
+       int ret;
+
+       crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+       ret = v4l2_subdev_call(sd, video, g_crop, &crop);
+       if (!ret) {
+               *rect = crop.c;
+               return ret;
+       }
+
+       /* Camera driver doesn't support .g_crop(), assume default rectangle */
+       cap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+       ret = v4l2_subdev_call(sd, video, cropcap, &cap);
+       if (!ret)
+               *rect = cap.defrect;
+
+       return ret;
+}
+EXPORT_SYMBOL(soc_camera_client_g_rect);
+
+/* Client crop has changed, update our sub-rectangle to remain within the area */
+static void update_subrect(struct v4l2_rect *rect, struct v4l2_rect *subrect)
+{
+       if (rect->width < subrect->width)
+               subrect->width = rect->width;
+
+       if (rect->height < subrect->height)
+               subrect->height = rect->height;
+
+       if (rect->left > subrect->left)
+               subrect->left = rect->left;
+       else if (rect->left + rect->width >
+                subrect->left + subrect->width)
+               subrect->left = rect->left + rect->width -
+                       subrect->width;
+
+       if (rect->top > subrect->top)
+               subrect->top = rect->top;
+       else if (rect->top + rect->height >
+                subrect->top + subrect->height)
+               subrect->top = rect->top + rect->height -
+                       subrect->height;
+}
+
+/*
+ * The common for both scaling and cropping iterative approach is:
+ * 1. try if the client can produce exactly what requested by the user
+ * 2. if (1) failed, try to double the client image until we get one big enough
+ * 3. if (2) failed, try to request the maximum image
+ */
+int soc_camera_client_s_crop(struct v4l2_subdev *sd,
+                       struct v4l2_crop *crop, struct v4l2_crop *cam_crop,
+                       struct v4l2_rect *target_rect, struct v4l2_rect *subrect)
+{
+       struct v4l2_rect *rect = &crop->c, *cam_rect = &cam_crop->c;
+       struct device *dev = sd->v4l2_dev->dev;
+       struct v4l2_cropcap cap;
+       int ret;
+       unsigned int width, height;
+
+       v4l2_subdev_call(sd, video, s_crop, crop);
+       ret = soc_camera_client_g_rect(sd, cam_rect);
+       if (ret < 0)
+               return ret;
+
+       /*
+        * Now cam_crop contains the current camera input rectangle, and it must
+        * be within camera cropcap bounds
+        */
+       if (!memcmp(rect, cam_rect, sizeof(*rect))) {
+               /* Even if camera S_CROP failed, but camera rectangle matches */
+               dev_dbg(dev, "Camera S_CROP successful for %dx%d@%d:%d\n",
+                       rect->width, rect->height, rect->left, rect->top);
+               *target_rect = *cam_rect;
+               return 0;
+       }
+
+       /* Try to fix cropping, that camera hasn't managed to set */
+       dev_geo(dev, "Fix camera S_CROP for %dx%d@%d:%d to %dx%d@%d:%d\n",
+               cam_rect->width, cam_rect->height,
+               cam_rect->left, cam_rect->top,
+               rect->width, rect->height, rect->left, rect->top);
+
+       /* We need sensor maximum rectangle */
+       ret = v4l2_subdev_call(sd, video, cropcap, &cap);
+       if (ret < 0)
+               return ret;
+
+       /* Put user requested rectangle within sensor bounds */
+       soc_camera_limit_side(&rect->left, &rect->width, cap.bounds.left, 2,
+                             cap.bounds.width);
+       soc_camera_limit_side(&rect->top, &rect->height, cap.bounds.top, 4,
+                             cap.bounds.height);
+
+       /*
+        * Popular special case - some cameras can only handle fixed sizes like
+        * QVGA, VGA,... Take care to avoid infinite loop.
+        */
+       width = max(cam_rect->width, 2);
+       height = max(cam_rect->height, 2);
+
+       /*
+        * Loop as long as sensor is not covering the requested rectangle and
+        * is still within its bounds
+        */
+       while (!ret && (is_smaller(cam_rect, rect) ||
+                       is_inside(cam_rect, rect)) &&
+              (cap.bounds.width > width || cap.bounds.height > height)) {
+
+               width *= 2;
+               height *= 2;
+
+               cam_rect->width = width;
+               cam_rect->height = height;
+
+               /*
+                * We do not know what capabilities the camera has to set up
+                * left and top borders. We could try to be smarter in iterating
+                * them, e.g., if camera current left is to the right of the
+                * target left, set it to the middle point between the current
+                * left and minimum left. But that would add too much
+                * complexity: we would have to iterate each border separately.
+                * Instead we just drop to the left and top bounds.
+                */
+               if (cam_rect->left > rect->left)
+                       cam_rect->left = cap.bounds.left;
+
+               if (cam_rect->left + cam_rect->width < rect->left + rect->width)
+                       cam_rect->width = rect->left + rect->width -
+                               cam_rect->left;
+
+               if (cam_rect->top > rect->top)
+                       cam_rect->top = cap.bounds.top;
+
+               if (cam_rect->top + cam_rect->height < rect->top + rect->height)
+                       cam_rect->height = rect->top + rect->height -
+                               cam_rect->top;
+
+               v4l2_subdev_call(sd, video, s_crop, cam_crop);
+               ret = soc_camera_client_g_rect(sd, cam_rect);
+               dev_geo(dev, "Camera S_CROP %d for %dx%d@%d:%d\n", ret,
+                       cam_rect->width, cam_rect->height,
+                       cam_rect->left, cam_rect->top);
+       }
+
+       /* S_CROP must not modify the rectangle */
+       if (is_smaller(cam_rect, rect) || is_inside(cam_rect, rect)) {
+               /*
+                * The camera failed to configure a suitable cropping,
+                * we cannot use the current rectangle, set to max
+                */
+               *cam_rect = cap.bounds;
+               v4l2_subdev_call(sd, video, s_crop, cam_crop);
+               ret = soc_camera_client_g_rect(sd, cam_rect);
+               dev_geo(dev, "Camera S_CROP %d for max %dx%d@%d:%d\n", ret,
+                       cam_rect->width, cam_rect->height,
+                       cam_rect->left, cam_rect->top);
+       }
+
+       if (!ret) {
+               *target_rect = *cam_rect;
+               update_subrect(target_rect, subrect);
+       }
+
+       return ret;
+}
+EXPORT_SYMBOL(soc_camera_client_s_crop);
+
+/* Iterative s_mbus_fmt, also updates cached client crop on success */
+static int client_s_fmt(struct soc_camera_device *icd,
+                       struct v4l2_rect *rect, struct v4l2_rect *subrect,
+                       unsigned int max_width, unsigned int max_height,
+                       struct v4l2_mbus_framefmt *mf, bool host_can_scale)
+{
+       struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+       struct device *dev = icd->parent;
+       unsigned int width = mf->width, height = mf->height, tmp_w, tmp_h;
+       struct v4l2_cropcap cap;
+       bool host_1to1;
+       int ret;
+
+       ret = v4l2_device_call_until_err(sd->v4l2_dev,
+                                        soc_camera_grp_id(icd), video,
+                                        s_mbus_fmt, mf);
+       if (ret < 0)
+               return ret;
+
+       dev_geo(dev, "camera scaled to %ux%u\n", mf->width, mf->height);
+
+       if (width == mf->width && height == mf->height) {
+               /* Perfect! The client has done it all. */
+               host_1to1 = true;
+               goto update_cache;
+       }
+
+       host_1to1 = false;
+       if (!host_can_scale)
+               goto update_cache;
+
+       cap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+       ret = v4l2_subdev_call(sd, video, cropcap, &cap);
+       if (ret < 0)
+               return ret;
+
+       if (max_width > cap.bounds.width)
+               max_width = cap.bounds.width;
+       if (max_height > cap.bounds.height)
+               max_height = cap.bounds.height;
+
+       /* Camera set a format, but geometry is not precise, try to improve */
+       tmp_w = mf->width;
+       tmp_h = mf->height;
+
+       /* width <= max_width && height <= max_height - guaranteed by try_fmt */
+       while ((width > tmp_w || height > tmp_h) &&
+              tmp_w < max_width && tmp_h < max_height) {
+               tmp_w = min(2 * tmp_w, max_width);
+               tmp_h = min(2 * tmp_h, max_height);
+               mf->width = tmp_w;
+               mf->height = tmp_h;
+               ret = v4l2_device_call_until_err(sd->v4l2_dev,
+                                       soc_camera_grp_id(icd), video,
+                                       s_mbus_fmt, mf);
+               dev_geo(dev, "Camera scaled to %ux%u\n",
+                       mf->width, mf->height);
+               if (ret < 0) {
+                       /* This shouldn't happen */
+                       dev_err(dev, "Client failed to set format: %d\n", ret);
+                       return ret;
+               }
+       }
+
+update_cache:
+       /* Update cache */
+       ret = soc_camera_client_g_rect(sd, rect);
+       if (ret < 0)
+               return ret;
+
+       if (host_1to1)
+               *subrect = *rect;
+       else
+               update_subrect(rect, subrect);
+
+       return 0;
+}
+
+/**
+ * @icd                - soc-camera device
+ * @rect       - camera cropping window
+ * @subrect    - part of rect, sent to the user
+ * @mf         - in- / output camera output window
+ * @width      - on input: max host input width
+ *               on output: user width, mapped back to input
+ * @height     - on input: max host input height
+ *               on output: user height, mapped back to input
+ * @host_can_scale - host can scale this pixel format
+ * @shift      - shift, used for scaling
+ */
+int soc_camera_client_scale(struct soc_camera_device *icd,
+                       struct v4l2_rect *rect, struct v4l2_rect *subrect,
+                       struct v4l2_mbus_framefmt *mf,
+                       unsigned int *width, unsigned int *height,
+                       bool host_can_scale, unsigned int shift)
+{
+       struct device *dev = icd->parent;
+       struct v4l2_mbus_framefmt mf_tmp = *mf;
+       unsigned int scale_h, scale_v;
+       int ret;
+
+       /*
+        * 5. Apply iterative camera S_FMT for camera user window (also updates
+        *    client crop cache and the imaginary sub-rectangle).
+        */
+       ret = client_s_fmt(icd, rect, subrect, *width, *height,
+                          &mf_tmp, host_can_scale);
+       if (ret < 0)
+               return ret;
+
+       dev_geo(dev, "5: camera scaled to %ux%u\n",
+               mf_tmp.width, mf_tmp.height);
+
+       /* 6. Retrieve camera output window (g_fmt) */
+
+       /* unneeded - it is already in "mf_tmp" */
+
+       /* 7. Calculate new client scales. */
+       scale_h = soc_camera_calc_scale(rect->width, shift, mf_tmp.width);
+       scale_v = soc_camera_calc_scale(rect->height, shift, mf_tmp.height);
+
+       mf->width       = mf_tmp.width;
+       mf->height      = mf_tmp.height;
+       mf->colorspace  = mf_tmp.colorspace;
+
+       /*
+        * 8. Calculate new host crop - apply camera scales to previously
+        *    updated "effective" crop.
+        */
+       *width = soc_camera_shift_scale(subrect->width, shift, scale_h);
+       *height = soc_camera_shift_scale(subrect->height, shift, scale_v);
+
+       dev_geo(dev, "8: new client sub-window %ux%u\n", *width, *height);
+
+       return 0;
+}
+EXPORT_SYMBOL(soc_camera_client_scale);
+
+/*
+ * Calculate real client output window by applying new scales to the current
+ * client crop. New scales are calculated from the requested output format and
+ * host crop, mapped backed onto the client input (subrect).
+ */
+void soc_camera_calc_client_output(struct soc_camera_device *icd,
+               struct v4l2_rect *rect, struct v4l2_rect *subrect,
+               const struct v4l2_pix_format *pix, struct v4l2_mbus_framefmt *mf,
+               unsigned int shift)
+{
+       struct device *dev = icd->parent;
+       unsigned int scale_v, scale_h;
+
+       if (subrect->width == rect->width &&
+           subrect->height == rect->height) {
+               /* No sub-cropping */
+               mf->width       = pix->width;
+               mf->height      = pix->height;
+               return;
+       }
+
+       /* 1.-2. Current camera scales and subwin - cached. */
+
+       dev_geo(dev, "2: subwin %ux%u@%u:%u\n",
+               subrect->width, subrect->height,
+               subrect->left, subrect->top);
+
+       /*
+        * 3. Calculate new combined scales from input sub-window to requested
+        *    user window.
+        */
+
+       /*
+        * TODO: CEU cannot scale images larger than VGA to smaller than SubQCIF
+        * (128x96) or larger than VGA. This and similar limitations have to be
+        * taken into account here.
+        */
+       scale_h = soc_camera_calc_scale(subrect->width, shift, pix->width);
+       scale_v = soc_camera_calc_scale(subrect->height, shift, pix->height);
+
+       dev_geo(dev, "3: scales %u:%u\n", scale_h, scale_v);
+
+       /*
+        * 4. Calculate desired client output window by applying combined scales
+        *    to client (real) input window.
+        */
+       mf->width = soc_camera_shift_scale(rect->width, shift, scale_h);
+       mf->height = soc_camera_shift_scale(rect->height, shift, scale_v);
+}
+EXPORT_SYMBOL(soc_camera_calc_client_output);
diff --git a/drivers/media/platform/soc_camera/soc_scale_crop.h b/drivers/media/platform/soc_camera/soc_scale_crop.h
new file mode 100644 (file)
index 0000000..184a30d
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * soc-camera generic scaling-cropping manipulation functions
+ *
+ * Copyright (C) 2013 Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef SOC_SCALE_CROP_H
+#define SOC_SCALE_CROP_H
+
+#include <linux/kernel.h>
+
+struct soc_camera_device;
+
+struct v4l2_crop;
+struct v4l2_mbus_framefmt;
+struct v4l2_pix_format;
+struct v4l2_rect;
+struct v4l2_subdev;
+
+static inline unsigned int soc_camera_shift_scale(unsigned int size,
+                               unsigned int shift, unsigned int scale)
+{
+       return DIV_ROUND_CLOSEST(size << shift, scale);
+}
+
+#define soc_camera_calc_scale(in, shift, out) soc_camera_shift_scale(in, shift, out)
+
+int soc_camera_client_g_rect(struct v4l2_subdev *sd, struct v4l2_rect *rect);
+int soc_camera_client_s_crop(struct v4l2_subdev *sd,
+                       struct v4l2_crop *crop, struct v4l2_crop *cam_crop,
+                       struct v4l2_rect *target_rect, struct v4l2_rect *subrect);
+int soc_camera_client_scale(struct soc_camera_device *icd,
+                       struct v4l2_rect *rect, struct v4l2_rect *subrect,
+                       struct v4l2_mbus_framefmt *mf,
+                       unsigned int *width, unsigned int *height,
+                       bool host_can_scale, unsigned int shift);
+void soc_camera_calc_client_output(struct soc_camera_device *icd,
+               struct v4l2_rect *rect, struct v4l2_rect *subrect,
+               const struct v4l2_pix_format *pix, struct v4l2_mbus_framefmt *mf,
+               unsigned int shift);
+
+#endif
index a2f7bdd..b557caf 100644 (file)
@@ -239,13 +239,12 @@ static int timblogiw_querycap(struct file *file, void  *priv,
        struct video_device *vdev = video_devdata(file);
 
        dev_dbg(&vdev->dev, "%s: Entry\n",  __func__);
-       memset(cap, 0, sizeof(*cap));
        strncpy(cap->card, TIMBLOGIWIN_NAME, sizeof(cap->card)-1);
        strncpy(cap->driver, DRIVER_NAME, sizeof(cap->driver) - 1);
-       strlcpy(cap->bus_info, vdev->name, sizeof(cap->bus_info));
-       cap->version = TIMBLOGIW_VERSION_CODE;
-       cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING |
+       snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", vdev->name);
+       cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING |
                V4L2_CAP_READWRITE;
+       cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
 
        return 0;
 }
@@ -834,11 +833,9 @@ static int timblogiw_probe(struct platform_device *pdev)
                goto err_request;
        }
 
-
        return 0;
 
 err_request:
-       platform_set_drvdata(pdev, NULL);
        v4l2_device_unregister(&lw->v4l2_dev);
 err_register:
        kfree(lw);
@@ -858,8 +855,6 @@ static int timblogiw_remove(struct platform_device *pdev)
 
        kfree(lw);
 
-       platform_set_drvdata(pdev, NULL);
-
        return 0;
 }
 
index a794cd6..b4f9d03 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/videodev2.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
-#include <media/v4l2-chip-ident.h>
 #include <media/v4l2-ctrls.h>
 #include <media/ov7670.h>
 #include <media/videobuf-dma-sg.h>
@@ -805,20 +804,6 @@ static const struct v4l2_file_operations viacam_fops = {
  * The long list of v4l2 ioctl ops
  */
 
-static int viacam_g_chip_ident(struct file *file, void *priv,
-               struct v4l2_dbg_chip_ident *ident)
-{
-       struct via_camera *cam = priv;
-
-       ident->ident = V4L2_IDENT_NONE;
-       ident->revision = 0;
-       if (v4l2_chip_match_host(&ident->match)) {
-               ident->ident = V4L2_IDENT_VIA_VX855;
-               return 0;
-       }
-       return sensor_call(cam, core, g_chip_ident, ident);
-}
-
 /*
  * Only one input.
  */
@@ -852,6 +837,12 @@ static int viacam_s_std(struct file *filp, void *priv, v4l2_std_id std)
        return 0;
 }
 
+static int viacam_g_std(struct file *filp, void *priv, v4l2_std_id *std)
+{
+       *std = V4L2_STD_NTSC_M;
+       return 0;
+}
+
 /*
  * Video format stuff. Here is our default format until
  * user space messes with things.
@@ -1174,11 +1165,11 @@ static int viacam_enum_frameintervals(struct file *filp, void *priv,
 
 
 static const struct v4l2_ioctl_ops viacam_ioctl_ops = {
-       .vidioc_g_chip_ident    = viacam_g_chip_ident,
        .vidioc_enum_input      = viacam_enum_input,
        .vidioc_g_input         = viacam_g_input,
        .vidioc_s_input         = viacam_s_input,
        .vidioc_s_std           = viacam_s_std,
+       .vidioc_g_std           = viacam_g_std,
        .vidioc_enum_fmt_vid_cap = viacam_enum_fmt_vid_cap,
        .vidioc_try_fmt_vid_cap = viacam_try_fmt_vid_cap,
        .vidioc_g_fmt_vid_cap   = viacam_g_fmt_vid_cap,
@@ -1266,7 +1257,6 @@ static struct video_device viacam_v4l_template = {
        .name           = "via-camera",
        .minor          = -1,
        .tvnorms        = V4L2_STD_NTSC_M,
-       .current_norm   = V4L2_STD_NTSC_M,
        .fops           = &viacam_fops,
        .ioctl_ops      = &viacam_ioctl_ops,
        .release        = video_device_release_empty, /* Check this */
index 4c9ae76..21db23b 100644 (file)
@@ -93,7 +93,7 @@ static int keene_cmd_main(struct keene_device *radio, unsigned freq, bool play)
        /* If bit 4 is set, then tune to the frequency.
           If bit 3 is set, then unmute; if bit 2 is set, then mute.
           If bit 1 is set, then enter idle mode; if bit 0 is set,
-          then enter transit mode.
+          then enter transmit mode.
         */
        radio->buffer[5] = (radio->muted ? 4 : 8) | (play ? 1 : 2) |
                                                        (freq ? 0x10 : 0);
@@ -350,7 +350,6 @@ static int usb_keene_probe(struct usb_interface *intf,
        radio->pa = 118;
        radio->tx = 0x32;
        radio->stereo = true;
-       radio->curfreq = 95.16 * FREQ_MUL;
        if (hdl->error) {
                retval = hdl->error;
 
@@ -383,6 +382,10 @@ static int usb_keene_probe(struct usb_interface *intf,
        video_set_drvdata(&radio->vdev, radio);
        set_bit(V4L2_FL_USE_FH_PRIO, &radio->vdev.flags);
 
+       /* at least 11ms is needed in order to settle hardware */
+       msleep(20);
+       keene_cmd_main(radio, 95.16 * FREQ_MUL, false);
+
        retval = video_register_device(&radio->vdev, VFL_TYPE_RADIO, -1);
        if (retval < 0) {
                dev_err(&intf->dev, "could not register video device\n");
index adfcc61..6f4318f 100644 (file)
@@ -27,6 +27,8 @@
 #include <linux/io.h>          /* outb, outb_p                 */
 #include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-event.h>
 #include "lm7000.h"
 
 MODULE_AUTHOR("Petr Vandrovec, vandrove@vc.cvut.cz and M. Kirkwood");
@@ -44,10 +46,11 @@ module_param(radio_nr, int, 0);
 struct fmi
 {
        struct v4l2_device v4l2_dev;
+       struct v4l2_ctrl_handler hdl;
        struct video_device vdev;
        int io;
        bool mute;
-       unsigned long curfreq; /* freq in kHz */
+       u32 curfreq; /* freq in kHz */
        struct mutex lock;
 };
 
@@ -55,8 +58,8 @@ static struct fmi fmi_card;
 static struct pnp_dev *dev;
 bool pnp_attached;
 
-#define RSF16_MINFREQ (87 * 16000)
-#define RSF16_MAXFREQ (108 * 16000)
+#define RSF16_MINFREQ (87U * 16000)
+#define RSF16_MAXFREQ (108U * 16000)
 
 #define FMI_BIT_TUN_CE         (1 << 0)
 #define FMI_BIT_TUN_CLK                (1 << 1)
@@ -115,13 +118,22 @@ static inline int fmi_getsigstr(struct fmi *fmi)
        return (res & 2) ? 0 : 0xFFFF;
 }
 
+static void fmi_set_freq(struct fmi *fmi)
+{
+       fmi->curfreq = clamp(fmi->curfreq, RSF16_MINFREQ, RSF16_MAXFREQ);
+       /* rounding in steps of 800 to match the freq
+          that will be used */
+       lm7000_set_freq((fmi->curfreq / 800) * 800, fmi, fmi_set_pins);
+}
+
 static int vidioc_querycap(struct file *file, void  *priv,
                                        struct v4l2_capability *v)
 {
        strlcpy(v->driver, "radio-sf16fmi", sizeof(v->driver));
        strlcpy(v->card, "SF16-FMI/FMP/FMD radio", sizeof(v->card));
-       strlcpy(v->bus_info, "ISA", sizeof(v->bus_info));
-       v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
+       strlcpy(v->bus_info, "ISA:radio-sf16fmi", sizeof(v->bus_info));
+       v->device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
+       v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS;
        return 0;
 }
 
@@ -157,12 +169,10 @@ static int vidioc_s_frequency(struct file *file, void *priv,
 
        if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
                return -EINVAL;
-       if (f->frequency < RSF16_MINFREQ ||
-                       f->frequency > RSF16_MAXFREQ)
-               return -EINVAL;
-       /* rounding in steps of 800 to match the freq
-          that will be used */
-       lm7000_set_freq((f->frequency / 800) * 800, fmi, fmi_set_pins);
+
+       fmi->curfreq = f->frequency;
+       fmi_set_freq(fmi);
+
        return 0;
 }
 
@@ -178,74 +188,31 @@ static int vidioc_g_frequency(struct file *file, void *priv,
        return 0;
 }
 
-static int vidioc_queryctrl(struct file *file, void *priv,
-                                       struct v4l2_queryctrl *qc)
+static int fmi_s_ctrl(struct v4l2_ctrl *ctrl)
 {
-       switch (qc->id) {
-       case V4L2_CID_AUDIO_MUTE:
-               return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
-       }
-       return -EINVAL;
-}
-
-static int vidioc_g_ctrl(struct file *file, void *priv,
-                                       struct v4l2_control *ctrl)
-{
-       struct fmi *fmi = video_drvdata(file);
+       struct fmi *fmi = container_of(ctrl->handler, struct fmi, hdl);
 
        switch (ctrl->id) {
        case V4L2_CID_AUDIO_MUTE:
-               ctrl->value = fmi->mute;
-               return 0;
-       }
-       return -EINVAL;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
-                                       struct v4l2_control *ctrl)
-{
-       struct fmi *fmi = video_drvdata(file);
-
-       switch (ctrl->id) {
-       case V4L2_CID_AUDIO_MUTE:
-               if (ctrl->value)
+               if (ctrl->val)
                        fmi_mute(fmi);
                else
                        fmi_unmute(fmi);
-               fmi->mute = ctrl->value;
+               fmi->mute = ctrl->val;
                return 0;
        }
        return -EINVAL;
 }
 
-static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
-{
-       *i = 0;
-       return 0;
-}
-
-static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
-{
-       return i ? -EINVAL : 0;
-}
-
-static int vidioc_g_audio(struct file *file, void *priv,
-                                       struct v4l2_audio *a)
-{
-       a->index = 0;
-       strlcpy(a->name, "Radio", sizeof(a->name));
-       a->capability = V4L2_AUDCAP_STEREO;
-       return 0;
-}
-
-static int vidioc_s_audio(struct file *file, void *priv,
-                                       const struct v4l2_audio *a)
-{
-       return a->index ? -EINVAL : 0;
-}
+static const struct v4l2_ctrl_ops fmi_ctrl_ops = {
+       .s_ctrl = fmi_s_ctrl,
+};
 
 static const struct v4l2_file_operations fmi_fops = {
        .owner          = THIS_MODULE,
+       .open           = v4l2_fh_open,
+       .release        = v4l2_fh_release,
+       .poll           = v4l2_ctrl_poll,
        .unlocked_ioctl = video_ioctl2,
 };
 
@@ -253,15 +220,11 @@ static const struct v4l2_ioctl_ops fmi_ioctl_ops = {
        .vidioc_querycap    = vidioc_querycap,
        .vidioc_g_tuner     = vidioc_g_tuner,
        .vidioc_s_tuner     = vidioc_s_tuner,
-       .vidioc_g_audio     = vidioc_g_audio,
-       .vidioc_s_audio     = vidioc_s_audio,
-       .vidioc_g_input     = vidioc_g_input,
-       .vidioc_s_input     = vidioc_s_input,
        .vidioc_g_frequency = vidioc_g_frequency,
        .vidioc_s_frequency = vidioc_s_frequency,
-       .vidioc_queryctrl   = vidioc_queryctrl,
-       .vidioc_g_ctrl      = vidioc_g_ctrl,
-       .vidioc_s_ctrl      = vidioc_s_ctrl,
+       .vidioc_log_status  = v4l2_ctrl_log_status,
+       .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+       .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
 };
 
 /* ladis: this is my card. does any other types exist? */
@@ -311,6 +274,7 @@ static int __init fmi_init(void)
 {
        struct fmi *fmi = &fmi_card;
        struct v4l2_device *v4l2_dev = &fmi->v4l2_dev;
+       struct v4l2_ctrl_handler *hdl = &fmi->hdl;
        int res, i;
        int probe_ports[] = { 0, 0x284, 0x384 };
 
@@ -363,19 +327,35 @@ static int __init fmi_init(void)
                return res;
        }
 
+       v4l2_ctrl_handler_init(hdl, 1);
+       v4l2_ctrl_new_std(hdl, &fmi_ctrl_ops,
+                       V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1);
+       v4l2_dev->ctrl_handler = hdl;
+       if (hdl->error) {
+               res = hdl->error;
+               v4l2_err(v4l2_dev, "Could not register controls\n");
+               v4l2_ctrl_handler_free(hdl);
+               v4l2_device_unregister(v4l2_dev);
+               return res;
+       }
+
        strlcpy(fmi->vdev.name, v4l2_dev->name, sizeof(fmi->vdev.name));
        fmi->vdev.v4l2_dev = v4l2_dev;
        fmi->vdev.fops = &fmi_fops;
        fmi->vdev.ioctl_ops = &fmi_ioctl_ops;
        fmi->vdev.release = video_device_release_empty;
+       set_bit(V4L2_FL_USE_FH_PRIO, &fmi->vdev.flags);
        video_set_drvdata(&fmi->vdev, fmi);
 
        mutex_init(&fmi->lock);
 
-       /* mute card - prevents noisy bootups */
-       fmi_mute(fmi);
+       /* mute card and set default frequency */
+       fmi->mute = 1;
+       fmi->curfreq = RSF16_MINFREQ;
+       fmi_set_freq(fmi);
 
        if (video_register_device(&fmi->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
+               v4l2_ctrl_handler_free(hdl);
                v4l2_device_unregister(v4l2_dev);
                release_region(fmi->io, 2);
                if (pnp_attached)
@@ -391,6 +371,7 @@ static void __exit fmi_exit(void)
 {
        struct fmi *fmi = &fmi_card;
 
+       v4l2_ctrl_handler_free(&fmi->hdl);
        video_unregister_device(&fmi->vdev);
        v4l2_device_unregister(&fmi->v4l2_dev);
        release_region(fmi->io, 2);
index 9dc8baf..9c9084c 100644 (file)
@@ -1018,16 +1018,6 @@ static int si476x_radio_s_ctrl(struct v4l2_ctrl *ctrl)
        return retval;
 }
 
-static int si476x_radio_g_chip_ident(struct file *file, void *fh,
-                                    struct v4l2_dbg_chip_ident *chip)
-{
-       if (chip->match.type == V4L2_CHIP_MATCH_HOST &&
-           v4l2_chip_match_host(&chip->match))
-               return 0;
-       return -EINVAL;
-}
-
-
 #ifdef CONFIG_VIDEO_ADV_DEBUG
 static int si476x_radio_g_register(struct file *file, void *fh,
                                   struct v4l2_dbg_register *reg)
@@ -1203,7 +1193,6 @@ static const struct v4l2_ioctl_ops si4761_ioctl_ops = {
        .vidioc_subscribe_event         = v4l2_ctrl_subscribe_event,
        .vidioc_unsubscribe_event       = v4l2_event_unsubscribe,
 
-       .vidioc_g_chip_ident            = si476x_radio_g_chip_ident,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
        .vidioc_g_register              = si476x_radio_g_register,
        .vidioc_s_register              = si476x_radio_s_register,
index 38d563d..036e2f5 100644 (file)
@@ -39,6 +39,9 @@
 #include <linux/i2c.h>                 /* I2C                          */
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-event.h>
 
 #define DRIVER_VERSION "0.0.2"
 
@@ -57,8 +60,8 @@
 
 /* Frequency limits in MHz -- these are European values.  For Japanese
 devices, that would be 76000 and 91000.  */
-#define FREQ_MIN  87500
-#define FREQ_MAX 108000
+#define FREQ_MIN  87500U
+#define FREQ_MAX 108000U
 #define FREQ_MUL 16
 
 /* TEA5764 registers */
@@ -138,8 +141,10 @@ static int radio_nr = -1;
 static int use_xtal = RADIO_TEA5764_XTAL;
 
 struct tea5764_device {
+       struct v4l2_device              v4l2_dev;
+       struct v4l2_ctrl_handler        ctrl_handler;
        struct i2c_client               *i2c_client;
-       struct video_device             *videodev;
+       struct video_device             vdev;
        struct tea5764_regs             regs;
        struct mutex                    mutex;
 };
@@ -187,18 +192,6 @@ static int tea5764_i2c_write(struct tea5764_device *radio)
        return 0;
 }
 
-/* V4L2 code related */
-static struct v4l2_queryctrl radio_qctrl[] = {
-       {
-               .id            = V4L2_CID_AUDIO_MUTE,
-               .name          = "Mute",
-               .minimum       = 0,
-               .maximum       = 1,
-               .default_value = 1,
-               .type          = V4L2_CTRL_TYPE_BOOLEAN,
-       }
-};
-
 static void tea5764_power_up(struct tea5764_device *radio)
 {
        struct tea5764_regs *r = &radio->regs;
@@ -291,23 +284,19 @@ static void tea5764_mute(struct tea5764_device *radio, int on)
                tea5764_i2c_write(radio);
 }
 
-static int tea5764_is_muted(struct tea5764_device *radio)
-{
-       return radio->regs.tnctrl & TEA5764_TNCTRL_MU;
-}
-
 /* V4L2 vidioc */
 static int vidioc_querycap(struct file *file, void  *priv,
                                        struct v4l2_capability *v)
 {
        struct tea5764_device *radio = video_drvdata(file);
-       struct video_device *dev = radio->videodev;
+       struct video_device *dev = &radio->vdev;
 
        strlcpy(v->driver, dev->dev.driver->name, sizeof(v->driver));
        strlcpy(v->card, dev->name, sizeof(v->card));
        snprintf(v->bus_info, sizeof(v->bus_info),
                 "I2C:%s", dev_name(&dev->dev));
-       v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
+       v->device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
+       v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS;
        return 0;
 }
 
@@ -320,8 +309,7 @@ static int vidioc_g_tuner(struct file *file, void *priv,
        if (v->index > 0)
                return -EINVAL;
 
-       memset(v, 0, sizeof(*v));
-       strcpy(v->name, "FM");
+       strlcpy(v->name, "FM", sizeof(v->name));
        v->type = V4L2_TUNER_RADIO;
        tea5764_i2c_read(radio);
        v->rangelow   = FREQ_MIN * FREQ_MUL;
@@ -354,19 +342,23 @@ static int vidioc_s_frequency(struct file *file, void *priv,
                                const struct v4l2_frequency *f)
 {
        struct tea5764_device *radio = video_drvdata(file);
+       unsigned freq = f->frequency;
 
        if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
                return -EINVAL;
-       if (f->frequency == 0) {
+       if (freq == 0) {
                /* We special case this as a power down control. */
                tea5764_power_down(radio);
-       }
-       if (f->frequency < (FREQ_MIN * FREQ_MUL))
-               return -EINVAL;
-       if (f->frequency > (FREQ_MAX * FREQ_MUL))
+               /* Yes, that's what is returned in this case. This
+                  whole special case is non-compliant and should really
+                  be replaced with something better, but changing this
+                  might well break code that depends on this behavior.
+                  So we keep it as-is. */
                return -EINVAL;
+       }
+       clamp(freq, FREQ_MIN * FREQ_MUL, FREQ_MAX * FREQ_MUL);
        tea5764_power_up(radio);
-       tea5764_tune(radio, (f->frequency * 125) / 2);
+       tea5764_tune(radio, (freq * 125) / 2);
        return 0;
 }
 
@@ -379,7 +371,6 @@ static int vidioc_g_frequency(struct file *file, void *priv,
        if (f->tuner != 0)
                return -EINVAL;
        tea5764_i2c_read(radio);
-       memset(f, 0, sizeof(*f));
        f->type = V4L2_TUNER_RADIO;
        if (r->tnctrl & TEA5764_TNCTRL_PUPD0)
                f->frequency = (tea5764_get_freq(radio) * 2) / 125;
@@ -389,83 +380,29 @@ static int vidioc_g_frequency(struct file *file, void *priv,
        return 0;
 }
 
-static int vidioc_queryctrl(struct file *file, void *priv,
-                           struct v4l2_queryctrl *qc)
+static int tea5764_s_ctrl(struct v4l2_ctrl *ctrl)
 {
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
-               if (qc->id && qc->id == radio_qctrl[i].id) {
-                       memcpy(qc, &(radio_qctrl[i]), sizeof(*qc));
-                       return 0;
-               }
-       }
-       return -EINVAL;
-}
-
-static int vidioc_g_ctrl(struct file *file, void *priv,
-                           struct v4l2_control *ctrl)
-{
-       struct tea5764_device *radio = video_drvdata(file);
-
-       switch (ctrl->id) {
-       case V4L2_CID_AUDIO_MUTE:
-               tea5764_i2c_read(radio);
-               ctrl->value = tea5764_is_muted(radio) ? 1 : 0;
-               return 0;
-       }
-       return -EINVAL;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
-                           struct v4l2_control *ctrl)
-{
-       struct tea5764_device *radio = video_drvdata(file);
+       struct tea5764_device *radio =
+               container_of(ctrl->handler, struct tea5764_device, ctrl_handler);
 
        switch (ctrl->id) {
        case V4L2_CID_AUDIO_MUTE:
-               tea5764_mute(radio, ctrl->value);
+               tea5764_mute(radio, ctrl->val);
                return 0;
        }
        return -EINVAL;
 }
 
-static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
-{
-       *i = 0;
-       return 0;
-}
-
-static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
-{
-       if (i != 0)
-               return -EINVAL;
-       return 0;
-}
-
-static int vidioc_g_audio(struct file *file, void *priv,
-                          struct v4l2_audio *a)
-{
-       if (a->index > 1)
-               return -EINVAL;
-
-       strcpy(a->name, "Radio");
-       a->capability = V4L2_AUDCAP_STEREO;
-       return 0;
-}
-
-static int vidioc_s_audio(struct file *file, void *priv,
-                          const struct v4l2_audio *a)
-{
-       if (a->index != 0)
-               return -EINVAL;
-
-       return 0;
-}
+static const struct v4l2_ctrl_ops tea5764_ctrl_ops = {
+       .s_ctrl = tea5764_s_ctrl,
+};
 
 /* File system interface */
 static const struct v4l2_file_operations tea5764_fops = {
        .owner          = THIS_MODULE,
+       .open           = v4l2_fh_open,
+       .release        = v4l2_fh_release,
+       .poll           = v4l2_ctrl_poll,
        .unlocked_ioctl = video_ioctl2,
 };
 
@@ -473,15 +410,11 @@ static const struct v4l2_ioctl_ops tea5764_ioctl_ops = {
        .vidioc_querycap    = vidioc_querycap,
        .vidioc_g_tuner     = vidioc_g_tuner,
        .vidioc_s_tuner     = vidioc_s_tuner,
-       .vidioc_g_audio     = vidioc_g_audio,
-       .vidioc_s_audio     = vidioc_s_audio,
-       .vidioc_g_input     = vidioc_g_input,
-       .vidioc_s_input     = vidioc_s_input,
        .vidioc_g_frequency = vidioc_g_frequency,
        .vidioc_s_frequency = vidioc_s_frequency,
-       .vidioc_queryctrl   = vidioc_queryctrl,
-       .vidioc_g_ctrl      = vidioc_g_ctrl,
-       .vidioc_s_ctrl      = vidioc_s_ctrl,
+       .vidioc_log_status  = v4l2_ctrl_log_status,
+       .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+       .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
 };
 
 /* V4L2 interface */
@@ -489,7 +422,7 @@ static struct video_device tea5764_radio_template = {
        .name           = "TEA5764 FM-Radio",
        .fops           = &tea5764_fops,
        .ioctl_ops      = &tea5764_ioctl_ops,
-       .release        = video_device_release,
+       .release        = video_device_release_empty,
 };
 
 /* I2C probe: check if the device exists and register with v4l if it is */
@@ -497,6 +430,8 @@ static int tea5764_i2c_probe(struct i2c_client *client,
                             const struct i2c_device_id *id)
 {
        struct tea5764_device *radio;
+       struct v4l2_device *v4l2_dev;
+       struct v4l2_ctrl_handler *hdl;
        struct tea5764_regs *r;
        int ret;
 
@@ -505,31 +440,45 @@ static int tea5764_i2c_probe(struct i2c_client *client,
        if (!radio)
                return -ENOMEM;
 
+       v4l2_dev = &radio->v4l2_dev;
+       ret = v4l2_device_register(&client->dev, v4l2_dev);
+       if (ret < 0) {
+               v4l2_err(v4l2_dev, "could not register v4l2_device\n");
+               goto errfr;
+       }
+
+       hdl = &radio->ctrl_handler;
+       v4l2_ctrl_handler_init(hdl, 1);
+       v4l2_ctrl_new_std(hdl, &tea5764_ctrl_ops,
+                       V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1);
+       v4l2_dev->ctrl_handler = hdl;
+       if (hdl->error) {
+               ret = hdl->error;
+               v4l2_err(v4l2_dev, "Could not register controls\n");
+               goto errunreg;
+       }
+
        mutex_init(&radio->mutex);
        radio->i2c_client = client;
        ret = tea5764_i2c_read(radio);
        if (ret)
-               goto errfr;
+               goto errunreg;
        r = &radio->regs;
        PDEBUG("chipid = %04X, manid = %04X", r->chipid, r->manid);
        if (r->chipid != TEA5764_CHIPID ||
                (r->manid & 0x0fff) != TEA5764_MANID) {
                PWARN("This chip is not a TEA5764!");
                ret = -EINVAL;
-               goto errfr;
+               goto errunreg;
        }
 
-       radio->videodev = video_device_alloc();
-       if (!(radio->videodev)) {
-               ret = -ENOMEM;
-               goto errfr;
-       }
-       memcpy(radio->videodev, &tea5764_radio_template,
-               sizeof(tea5764_radio_template));
+       radio->vdev = tea5764_radio_template;
 
        i2c_set_clientdata(client, radio);
-       video_set_drvdata(radio->videodev, radio);
-       radio->videodev->lock = &radio->mutex;
+       video_set_drvdata(&radio->vdev, radio);
+       radio->vdev.lock = &radio->mutex;
+       radio->vdev.v4l2_dev = v4l2_dev;
+       set_bit(V4L2_FL_USE_FH_PRIO, &radio->vdev.flags);
 
        /* initialize and power off the chip */
        tea5764_i2c_read(radio);
@@ -537,16 +486,17 @@ static int tea5764_i2c_probe(struct i2c_client *client,
        tea5764_mute(radio, 1);
        tea5764_power_down(radio);
 
-       ret = video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr);
+       ret = video_register_device(&radio->vdev, VFL_TYPE_RADIO, radio_nr);
        if (ret < 0) {
                PWARN("Could not register video device!");
-               goto errrel;
+               goto errunreg;
        }
 
        PINFO("registered.");
        return 0;
-errrel:
-       video_device_release(radio->videodev);
+errunreg:
+       v4l2_ctrl_handler_free(hdl);
+       v4l2_device_unregister(v4l2_dev);
 errfr:
        kfree(radio);
        return ret;
@@ -559,7 +509,9 @@ static int tea5764_i2c_remove(struct i2c_client *client)
        PDEBUG("remove");
        if (radio) {
                tea5764_power_down(radio);
-               video_unregister_device(radio->videodev);
+               video_unregister_device(&radio->vdev);
+               v4l2_ctrl_handler_free(&radio->ctrl_handler);
+               v4l2_device_unregister(&radio->v4l2_dev);
                kfree(radio);
        }
        return 0;
index bb7b143..0817964 100644 (file)
@@ -19,6 +19,8 @@
 #include <linux/io.h>
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-device.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-event.h>
 #include <linux/platform_device.h>
 #include <linux/interrupt.h>
 #include <linux/slab.h>
@@ -44,7 +46,8 @@ static int timbradio_vidioc_querycap(struct file *file, void  *priv,
        strlcpy(v->driver, DRIVER_NAME, sizeof(v->driver));
        strlcpy(v->card, "Timberdale Radio", sizeof(v->card));
        snprintf(v->bus_info, sizeof(v->bus_info), "platform:"DRIVER_NAME);
-       v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
+       v->device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
+       v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS;
        return 0;
 }
 
@@ -62,34 +65,6 @@ static int timbradio_vidioc_s_tuner(struct file *file, void *priv,
        return v4l2_subdev_call(tr->sd_tuner, tuner, s_tuner, v);
 }
 
-static int timbradio_vidioc_g_input(struct file *filp, void *priv,
-       unsigned int *i)
-{
-       *i = 0;
-       return 0;
-}
-
-static int timbradio_vidioc_s_input(struct file *filp, void *priv,
-       unsigned int i)
-{
-       return i ? -EINVAL : 0;
-}
-
-static int timbradio_vidioc_g_audio(struct file *file, void *priv,
-       struct v4l2_audio *a)
-{
-       a->index = 0;
-       strlcpy(a->name, "Radio", sizeof(a->name));
-       a->capability = V4L2_AUDCAP_STEREO;
-       return 0;
-}
-
-static int timbradio_vidioc_s_audio(struct file *file, void *priv,
-       const struct v4l2_audio *a)
-{
-       return a->index ? -EINVAL : 0;
-}
-
 static int timbradio_vidioc_s_frequency(struct file *file, void *priv,
        const struct v4l2_frequency *f)
 {
@@ -104,44 +79,22 @@ static int timbradio_vidioc_g_frequency(struct file *file, void *priv,
        return v4l2_subdev_call(tr->sd_tuner, tuner, g_frequency, f);
 }
 
-static int timbradio_vidioc_queryctrl(struct file *file, void *priv,
-       struct v4l2_queryctrl *qc)
-{
-       struct timbradio *tr = video_drvdata(file);
-       return v4l2_subdev_call(tr->sd_dsp, core, queryctrl, qc);
-}
-
-static int timbradio_vidioc_g_ctrl(struct file *file, void *priv,
-       struct v4l2_control *ctrl)
-{
-       struct timbradio *tr = video_drvdata(file);
-       return v4l2_subdev_call(tr->sd_dsp, core, g_ctrl, ctrl);
-}
-
-static int timbradio_vidioc_s_ctrl(struct file *file, void *priv,
-       struct v4l2_control *ctrl)
-{
-       struct timbradio *tr = video_drvdata(file);
-       return v4l2_subdev_call(tr->sd_dsp, core, s_ctrl, ctrl);
-}
-
 static const struct v4l2_ioctl_ops timbradio_ioctl_ops = {
        .vidioc_querycap        = timbradio_vidioc_querycap,
        .vidioc_g_tuner         = timbradio_vidioc_g_tuner,
        .vidioc_s_tuner         = timbradio_vidioc_s_tuner,
        .vidioc_g_frequency     = timbradio_vidioc_g_frequency,
        .vidioc_s_frequency     = timbradio_vidioc_s_frequency,
-       .vidioc_g_input         = timbradio_vidioc_g_input,
-       .vidioc_s_input         = timbradio_vidioc_s_input,
-       .vidioc_g_audio         = timbradio_vidioc_g_audio,
-       .vidioc_s_audio         = timbradio_vidioc_s_audio,
-       .vidioc_queryctrl       = timbradio_vidioc_queryctrl,
-       .vidioc_g_ctrl          = timbradio_vidioc_g_ctrl,
-       .vidioc_s_ctrl          = timbradio_vidioc_s_ctrl
+       .vidioc_log_status      = v4l2_ctrl_log_status,
+       .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+       .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
 };
 
 static const struct v4l2_file_operations timbradio_fops = {
        .owner          = THIS_MODULE,
+       .open           = v4l2_fh_open,
+       .release        = v4l2_fh_release,
+       .poll           = v4l2_ctrl_poll,
        .unlocked_ioctl = video_ioctl2,
 };
 
@@ -173,6 +126,7 @@ static int timbradio_probe(struct platform_device *pdev)
        tr->video_dev.release = video_device_release_empty;
        tr->video_dev.minor = -1;
        tr->video_dev.lock = &tr->lock;
+       set_bit(V4L2_FL_USE_FH_PRIO, &tr->video_dev.flags);
 
        strlcpy(tr->v4l2_dev.name, DRIVER_NAME, sizeof(tr->v4l2_dev.name));
        err = v4l2_device_register(NULL, &tr->v4l2_dev);
@@ -181,6 +135,15 @@ static int timbradio_probe(struct platform_device *pdev)
 
        tr->video_dev.v4l2_dev = &tr->v4l2_dev;
 
+       tr->sd_tuner = v4l2_i2c_new_subdev_board(&tr->v4l2_dev,
+               i2c_get_adapter(pdata->i2c_adapter), pdata->tuner, NULL);
+       tr->sd_dsp = v4l2_i2c_new_subdev_board(&tr->v4l2_dev,
+               i2c_get_adapter(pdata->i2c_adapter), pdata->dsp, NULL);
+       if (tr->sd_tuner == NULL || tr->sd_dsp == NULL)
+               goto err_video_req;
+
+       tr->v4l2_dev.ctrl_handler = tr->sd_dsp->ctrl_handler;
+
        err = video_register_device(&tr->video_dev, VFL_TYPE_RADIO, -1);
        if (err) {
                dev_err(&pdev->dev, "Error reg video\n");
@@ -193,7 +156,6 @@ static int timbradio_probe(struct platform_device *pdev)
        return 0;
 
 err_video_req:
-       video_device_release_empty(&tr->video_dev);
        v4l2_device_unregister(&tr->v4l2_dev);
 err:
        dev_err(&pdev->dev, "Failed to register: %d\n", err);
@@ -206,10 +168,7 @@ static int timbradio_remove(struct platform_device *pdev)
        struct timbradio *tr = platform_get_drvdata(pdev);
 
        video_unregister_device(&tr->video_dev);
-       video_device_release_empty(&tr->video_dev);
-
        v4l2_device_unregister(&tr->v4l2_dev);
-
        return 0;
 }
 
index 06c06cc..ec805b0 100644 (file)
@@ -25,7 +25,7 @@
 #include <linux/i2c.h>
 #include <linux/slab.h>
 #include <media/v4l2-device.h>
-#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-ctrls.h>
 
 #define DRIVER_NAME "saa7706h"
 
 
 struct saa7706h_state {
        struct v4l2_subdev sd;
+       struct v4l2_ctrl_handler hdl;
        unsigned muted;
 };
 
@@ -317,51 +318,32 @@ static int saa7706h_mute(struct v4l2_subdev *sd)
        return err;
 }
 
-static int saa7706h_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
+static int saa7706h_s_ctrl(struct v4l2_ctrl *ctrl)
 {
-       switch (qc->id) {
-       case V4L2_CID_AUDIO_MUTE:
-               return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
-       }
-       return -EINVAL;
-}
-
-static int saa7706h_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
-{
-       struct saa7706h_state *state = to_state(sd);
+       struct saa7706h_state *state =
+               container_of(ctrl->handler, struct saa7706h_state, hdl);
 
        switch (ctrl->id) {
        case V4L2_CID_AUDIO_MUTE:
-               ctrl->value = state->muted;
-               return 0;
+               if (ctrl->val)
+                       return saa7706h_mute(&state->sd);
+               return saa7706h_unmute(&state->sd);
        }
        return -EINVAL;
 }
 
-static int saa7706h_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
-{
-       switch (ctrl->id) {
-       case V4L2_CID_AUDIO_MUTE:
-               if (ctrl->value)
-                       return saa7706h_mute(sd);
-               return saa7706h_unmute(sd);
-       }
-       return -EINVAL;
-}
-
-static int saa7706h_g_chip_ident(struct v4l2_subdev *sd,
-       struct v4l2_dbg_chip_ident *chip)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_SAA7706H, 0);
-}
+static const struct v4l2_ctrl_ops saa7706h_ctrl_ops = {
+       .s_ctrl = saa7706h_s_ctrl,
+};
 
 static const struct v4l2_subdev_core_ops saa7706h_core_ops = {
-       .g_chip_ident = saa7706h_g_chip_ident,
-       .queryctrl = saa7706h_queryctrl,
-       .g_ctrl = saa7706h_g_ctrl,
-       .s_ctrl = saa7706h_s_ctrl,
+       .g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
+       .try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
+       .s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
+       .g_ctrl = v4l2_subdev_g_ctrl,
+       .s_ctrl = v4l2_subdev_s_ctrl,
+       .queryctrl = v4l2_subdev_queryctrl,
+       .querymenu = v4l2_subdev_querymenu,
 };
 
 static const struct v4l2_subdev_ops saa7706h_ops = {
@@ -393,13 +375,20 @@ static int saa7706h_probe(struct i2c_client *client,
        sd = &state->sd;
        v4l2_i2c_subdev_init(sd, client, &saa7706h_ops);
 
+       v4l2_ctrl_handler_init(&state->hdl, 4);
+       v4l2_ctrl_new_std(&state->hdl, &saa7706h_ctrl_ops,
+                       V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1);
+       sd->ctrl_handler = &state->hdl;
+       err = state->hdl.error;
+       if (err)
+               goto err;
+
        /* check the rom versions */
        err = saa7706h_get_reg16(sd, SAA7706H_DSP1_ROM_VER);
        if (err < 0)
                goto err;
        if (err != SUPPORTED_DSP1_ROM_VER)
                v4l2_warn(sd, "Unknown DSP1 ROM code version: 0x%x\n", err);
-
        state->muted = 1;
 
        /* startup in a muted state */
@@ -411,6 +400,7 @@ static int saa7706h_probe(struct i2c_client *client,
 
 err:
        v4l2_device_unregister_subdev(sd);
+       v4l2_ctrl_handler_free(&state->hdl);
        kfree(to_state(sd));
 
        printk(KERN_ERR DRIVER_NAME ": Failed to probe: %d\n", err);
@@ -421,9 +411,11 @@ err:
 static int saa7706h_remove(struct i2c_client *client)
 {
        struct v4l2_subdev *sd = i2c_get_clientdata(client);
+       struct saa7706h_state *state = to_state(sd);
 
        saa7706h_mute(sd);
        v4l2_device_unregister_subdev(sd);
+       v4l2_ctrl_handler_free(&state->hdl);
        kfree(to_state(sd));
        return 0;
 }
index 82c6c94..06ac692 100644 (file)
 #include <linux/slab.h>
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-device.h>
-#include <media/v4l2-chip-ident.h>
 
 #define DRIVER_NAME "tef6862"
 
 #define FREQ_MUL 16000
 
-#define TEF6862_LO_FREQ (875 * FREQ_MUL / 10)
-#define TEF6862_HI_FREQ (108 * FREQ_MUL)
+#define TEF6862_LO_FREQ (875U * FREQ_MUL / 10)
+#define TEF6862_HI_FREQ (108U * FREQ_MUL)
 
 /* Write mode sub addresses */
 #define WM_SUB_BANDWIDTH       0x0
@@ -105,6 +104,7 @@ static int tef6862_s_frequency(struct v4l2_subdev *sd, const struct v4l2_frequen
 {
        struct tef6862_state *state = to_state(sd);
        struct i2c_client *client = v4l2_get_subdevdata(sd);
+       unsigned freq = f->frequency;
        u16 pll;
        u8 i2cmsg[3];
        int err;
@@ -112,7 +112,8 @@ static int tef6862_s_frequency(struct v4l2_subdev *sd, const struct v4l2_frequen
        if (f->tuner != 0)
                return -EINVAL;
 
-       pll = 1964 + ((f->frequency - TEF6862_LO_FREQ) * 20) / FREQ_MUL;
+       clamp(freq, TEF6862_LO_FREQ, TEF6862_HI_FREQ);
+       pll = 1964 + ((freq - TEF6862_LO_FREQ) * 20) / FREQ_MUL;
        i2cmsg[0] = (MODE_PRESET << MODE_SHIFT) | WM_SUB_PLLM;
        i2cmsg[1] = (pll >> 8) & 0xff;
        i2cmsg[2] = pll & 0xff;
@@ -121,7 +122,7 @@ static int tef6862_s_frequency(struct v4l2_subdev *sd, const struct v4l2_frequen
        if (err != sizeof(i2cmsg))
                return err < 0 ? err : -EIO;
 
-       state->freq = f->frequency;
+       state->freq = freq;
        return 0;
 }
 
@@ -136,14 +137,6 @@ static int tef6862_g_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f)
        return 0;
 }
 
-static int tef6862_g_chip_ident(struct v4l2_subdev *sd,
-       struct v4l2_dbg_chip_ident *chip)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_TEF6862, 0);
-}
-
 static const struct v4l2_subdev_tuner_ops tef6862_tuner_ops = {
        .g_tuner = tef6862_g_tuner,
        .s_tuner = tef6862_s_tuner,
@@ -151,12 +144,7 @@ static const struct v4l2_subdev_tuner_ops tef6862_tuner_ops = {
        .g_frequency = tef6862_g_frequency,
 };
 
-static const struct v4l2_subdev_core_ops tef6862_core_ops = {
-       .g_chip_ident = tef6862_g_chip_ident,
-};
-
 static const struct v4l2_subdev_ops tef6862_ops = {
-       .core = &tef6862_core_ops,
        .tuner = &tef6862_tuner_ops,
 };
 
index aac0f02..a587c9b 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/timer.h>
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
 #include <media/v4l2-ctrls.h>
 
 #define FM_DRV_VERSION            "0.1.1"
@@ -202,6 +203,7 @@ struct fmtx_data {
 /* FM driver operation structure */
 struct fmdev {
        struct video_device *radio_dev; /* V4L2 video device pointer */
+       struct v4l2_device v4l2_dev;    /* V4L2 top level struct */
        struct snd_card *card;  /* Card which holds FM mixer controls */
        u16 asci_id;
        spinlock_t rds_buff_lock; /* To protect access to RDS buffer */
index a002234..253f307 100644 (file)
@@ -715,7 +715,7 @@ static void fm_irq_handle_rdsdata_getcmd_resp(struct fmdev *fmdev)
        struct fm_rdsdata_format rds_fmt;
        struct fm_rds *rds = &fmdev->rx.rds;
        unsigned long group_idx, flags;
-       u8 *rds_data, meta_data, tmpbuf[3];
+       u8 *rds_data, meta_data, tmpbuf[FM_RDS_BLK_SIZE];
        u8 type, blk_idx;
        u16 cur_picode;
        u32 rds_len;
@@ -1073,6 +1073,7 @@ int fmc_transfer_rds_from_internal_buff(struct fmdev *fmdev, struct file *file,
                u8 __user *buf, size_t count)
 {
        u32 block_count;
+       u8 tmpbuf[FM_RDS_BLK_SIZE];
        unsigned long flags;
        int ret;
 
@@ -1087,29 +1088,32 @@ int fmc_transfer_rds_from_internal_buff(struct fmdev *fmdev, struct file *file,
        }
 
        /* Calculate block count from byte count */
-       count /= 3;
+       count /= FM_RDS_BLK_SIZE;
        block_count = 0;
        ret = 0;
 
-       spin_lock_irqsave(&fmdev->rds_buff_lock, flags);
-
        while (block_count < count) {
-               if (fmdev->rx.rds.wr_idx == fmdev->rx.rds.rd_idx)
-                       break;
+               spin_lock_irqsave(&fmdev->rds_buff_lock, flags);
 
-               if (copy_to_user(buf, &fmdev->rx.rds.buff[fmdev->rx.rds.rd_idx],
-                                       FM_RDS_BLK_SIZE))
+               if (fmdev->rx.rds.wr_idx == fmdev->rx.rds.rd_idx) {
+                       spin_unlock_irqrestore(&fmdev->rds_buff_lock, flags);
                        break;
-
+               }
+               memcpy(tmpbuf, &fmdev->rx.rds.buff[fmdev->rx.rds.rd_idx],
+                                       FM_RDS_BLK_SIZE);
                fmdev->rx.rds.rd_idx += FM_RDS_BLK_SIZE;
                if (fmdev->rx.rds.rd_idx >= fmdev->rx.rds.buf_size)
                        fmdev->rx.rds.rd_idx = 0;
 
+               spin_unlock_irqrestore(&fmdev->rds_buff_lock, flags);
+
+               if (copy_to_user(buf, tmpbuf, FM_RDS_BLK_SIZE))
+                       break;
+
                block_count++;
                buf += FM_RDS_BLK_SIZE;
                ret += FM_RDS_BLK_SIZE;
        }
-       spin_unlock_irqrestore(&fmdev->rds_buff_lock, flags);
        return ret;
 }
 
index 5dec323..b55012c 100644 (file)
@@ -533,6 +533,11 @@ int fm_v4l2_init_video_device(struct fmdev *fmdev, int radio_nr)
        struct v4l2_ctrl *ctrl;
        int ret;
 
+       strlcpy(fmdev->v4l2_dev.name, FM_DRV_NAME, sizeof(fmdev->v4l2_dev.name));
+       ret = v4l2_device_register(NULL, &fmdev->v4l2_dev);
+       if (ret < 0)
+               return ret;
+
        /* Init mutex for core locking */
        mutex_init(&fmdev->mutex);
 
@@ -549,6 +554,7 @@ int fm_v4l2_init_video_device(struct fmdev *fmdev, int radio_nr)
        video_set_drvdata(gradio_dev, fmdev);
 
        gradio_dev->lock = &fmdev->mutex;
+       gradio_dev->v4l2_dev = &fmdev->v4l2_dev;
 
        /* Register with V4L2 subsystem as RADIO device */
        if (video_register_device(gradio_dev, VFL_TYPE_RADIO, radio_nr)) {
@@ -611,5 +617,7 @@ void *fm_v4l2_deinit_video_device(void)
        /* Unregister RADIO device from V4L2 subsystem */
        video_unregister_device(gradio_dev);
 
+       v4l2_device_unregister(&fmdev->v4l2_dev);
+
        return fmdev;
 }
index 8b82ae9..07aacfa 100644 (file)
@@ -178,7 +178,6 @@ static int gpio_ir_recv_probe(struct platform_device *pdev)
        return 0;
 
 err_request_irq:
-       platform_set_drvdata(pdev, NULL);
        rc_unregister_device(rcdev);
        rcdev = NULL;
 err_register_rc_device:
@@ -196,7 +195,6 @@ static int gpio_ir_recv_remove(struct platform_device *pdev)
        struct gpio_rc_dev *gpio_dev = platform_get_drvdata(pdev);
 
        free_irq(gpio_to_irq(gpio_dev->gpio_nr), gpio_dev);
-       platform_set_drvdata(pdev, NULL);
        rc_unregister_device(gpio_dev->rcdev);
        gpio_free(gpio_dev->gpio_nr);
        kfree(gpio_dev);
index 5ab94ea..b1cde8c 100644 (file)
@@ -20,6 +20,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \
                        rc-budget-ci-old.o \
                        rc-cinergy-1400.o \
                        rc-cinergy.o \
+                       rc-delock-61959.o \
                        rc-dib0700-nec.o \
                        rc-dib0700-rc5.o \
                        rc-digitalnow-tinytwin.o \
diff --git a/drivers/media/rc/keymaps/rc-delock-61959.c b/drivers/media/rc/keymaps/rc-delock-61959.c
new file mode 100644 (file)
index 0000000..01bed86
--- /dev/null
@@ -0,0 +1,83 @@
+/* rc-delock-61959.c - Keytable for Delock
+ *
+ * Copyright (c) 2013 by Jakob Haufe <sur5r@sur5r.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+#include <linux/module.h>
+
+/*
+ * Keytable for remote provided with Delock 61959
+ */
+static struct rc_map_table delock_61959[] = {
+       { 0x866b16, KEY_POWER2 },       /* Power */
+       { 0x866b0c, KEY_POWER },        /* Shut Down */
+
+       { 0x866b00, KEY_1},
+       { 0x866b01, KEY_2},
+       { 0x866b02, KEY_3},
+       { 0x866b03, KEY_4},
+       { 0x866b04, KEY_5},
+       { 0x866b05, KEY_6},
+       { 0x866b06, KEY_7},
+       { 0x866b07, KEY_8},
+       { 0x866b08, KEY_9},
+       { 0x866b14, KEY_0},
+
+       { 0x866b0a, KEY_ZOOM},          /* Full Screen */
+       { 0x866b10, KEY_CAMERA},        /* Photo */
+       { 0x866b0e, KEY_CHANNEL},       /* circular arrow / Recall */
+       { 0x866b13, KEY_ESC},           /* Back */
+
+       { 0x866b20, KEY_UP},
+       { 0x866b21, KEY_DOWN},
+       { 0x866b42, KEY_LEFT},
+       { 0x866b43, KEY_RIGHT},
+       { 0x866b0b, KEY_OK},
+
+       { 0x866b11, KEY_CHANNELUP},
+       { 0x866b1b, KEY_CHANNELDOWN},
+
+       { 0x866b12, KEY_VOLUMEUP},
+       { 0x866b48, KEY_VOLUMEDOWN},
+       { 0x866b44, KEY_MUTE},
+
+       { 0x866b1a, KEY_RECORD},
+       { 0x866b41, KEY_PLAY},
+       { 0x866b40, KEY_STOP},
+       { 0x866b19, KEY_PAUSE},
+       { 0x866b1c, KEY_FASTFORWARD},   /* >> / FWD */
+       { 0x866b1e, KEY_REWIND},        /* << / REW */
+
+};
+
+static struct rc_map_list delock_61959_map = {
+       .map = {
+               .scan    = delock_61959,
+               .size    = ARRAY_SIZE(delock_61959),
+               .rc_type = RC_TYPE_NEC,
+               .name    = RC_MAP_DELOCK_61959,
+       }
+};
+
+static int __init init_rc_map_delock_61959(void)
+{
+       return rc_map_register(&delock_61959_map);
+}
+
+static void __exit exit_rc_map_delock_61959(void)
+{
+       rc_map_unregister(&delock_61959_map);
+}
+
+module_init(init_rc_map_delock_61959)
+module_exit(exit_rc_map_delock_61959)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jakob Haufe <sur5r@sur5r.net>");
+MODULE_DESCRIPTION("Delock 61959 remote keytable");
index 4835021..1c23666 100644 (file)
@@ -364,8 +364,8 @@ static void shadow_store(struct r820t_priv *priv, u8 reg, const u8 *val,
        }
        if (len <= 0)
                return;
-       if (len > NUM_REGS)
-               len = NUM_REGS;
+       if (len > NUM_REGS - r)
+               len = NUM_REGS - r;
 
        tuner_dbg("%s: prev  reg=%02x len=%d: %*ph\n",
                  __func__, r + REG_SHADOW_START, len, len, val);
@@ -1857,9 +1857,9 @@ static int r820t_imr(struct r820t_priv *priv, unsigned imr_mem, bool im_flag)
        int reg18, reg19, reg1f;
 
        if (priv->cfg->xtal > 24000000)
-               ring_ref = priv->cfg->xtal / 2;
+               ring_ref = priv->cfg->xtal / 2000;
        else
-               ring_ref = priv->cfg->xtal;
+               ring_ref = priv->cfg->xtal / 1000;
 
        n_ring = 15;
        for (n = 0; n < 16; n++) {
@@ -2256,7 +2256,6 @@ static int r820t_release(struct dvb_frontend *fe)
 
        mutex_unlock(&r820t_list_mutex);
 
-       kfree(fe->tuner_priv);
        fe->tuner_priv = NULL;
 
        return 0;
@@ -2311,8 +2310,6 @@ struct dvb_frontend *r820t_attach(struct dvb_frontend *fe,
                break;
        }
 
-       memcpy(&fe->ops.tuner_ops, &r820t_tuner_ops, sizeof(r820t_tuner_ops));
-
        if (fe->ops.i2c_gate_ctrl)
                fe->ops.i2c_gate_ctrl(fe, 1);
 
@@ -2327,15 +2324,14 @@ struct dvb_frontend *r820t_attach(struct dvb_frontend *fe,
 
        tuner_info("Rafael Micro r820t successfully identified\n");
 
-       fe->tuner_priv = priv;
-       memcpy(&fe->ops.tuner_ops, &r820t_tuner_ops,
-                       sizeof(struct dvb_tuner_ops));
-
        if (fe->ops.i2c_gate_ctrl)
                fe->ops.i2c_gate_ctrl(fe, 0);
 
        mutex_unlock(&r820t_list_mutex);
 
+       memcpy(&fe->ops.tuner_ops, &r820t_tuner_ops,
+                       sizeof(struct dvb_tuner_ops));
+
        return fe;
 err:
        if (fe->ops.i2c_gate_ctrl)
index 0a7d520..cfe8056 100644 (file)
@@ -1,6 +1,7 @@
+if USB && MEDIA_SUPPORT
+
 menuconfig MEDIA_USB_SUPPORT
        bool "Media USB Adapters"
-       depends on USB && MEDIA_SUPPORT
        help
          Enable media drivers for USB bus.
          If you have such devices, say Y.
@@ -17,6 +18,7 @@ source "drivers/media/usb/zr364xx/Kconfig"
 source "drivers/media/usb/stkwebcam/Kconfig"
 source "drivers/media/usb/s2255/Kconfig"
 source "drivers/media/usb/sn9c102/Kconfig"
+source "drivers/media/usb/usbtv/Kconfig"
 endif
 
 if MEDIA_ANALOG_TV_SUPPORT
@@ -52,3 +54,4 @@ source "drivers/media/usb/em28xx/Kconfig"
 endif
 
 endif #MEDIA_USB_SUPPORT
+endif #USB
index 7f51d7e..0935f47 100644 (file)
@@ -20,3 +20,4 @@ obj-$(CONFIG_VIDEO_STK1160) += stk1160/
 obj-$(CONFIG_VIDEO_CX231XX) += cx231xx/
 obj-$(CONFIG_VIDEO_TM6000) += tm6000/
 obj-$(CONFIG_VIDEO_EM28XX) += em28xx/
+obj-$(CONFIG_VIDEO_USBTV) += usbtv/
index 75ac994..f615454 100644 (file)
@@ -36,7 +36,6 @@
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-event.h>
-#include <media/v4l2-chip-ident.h>
 #include <media/tuner.h>
 #include "au0828.h"
 #include "au0828-reg.h"
@@ -1638,26 +1637,6 @@ static int vidioc_g_fmt_vbi_cap(struct file *file, void *priv,
        return 0;
 }
 
-static int vidioc_g_chip_ident(struct file *file, void *priv,
-              struct v4l2_dbg_chip_ident *chip)
-{
-       struct au0828_fh *fh = priv;
-       struct au0828_dev *dev = fh->dev;
-       chip->ident = V4L2_IDENT_NONE;
-       chip->revision = 0;
-
-       if (v4l2_chip_match_host(&chip->match)) {
-               chip->ident = V4L2_IDENT_AU0828;
-               return 0;
-       }
-
-       v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_chip_ident, chip);
-       if (chip->ident == V4L2_IDENT_NONE)
-               return -EINVAL;
-
-       return 0;
-}
-
 static int vidioc_cropcap(struct file *file, void *priv,
                          struct v4l2_cropcap *cc)
 {
@@ -1779,16 +1758,8 @@ static int vidioc_g_register(struct file *file, void *priv,
        struct au0828_fh *fh = priv;
        struct au0828_dev *dev = fh->dev;
 
-       switch (reg->match.type) {
-       case V4L2_CHIP_MATCH_I2C_DRIVER:
-               v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_register, reg);
-               return 0;
-       default:
-               if (!v4l2_chip_match_host(&reg->match))
-                       return -EINVAL;
-       }
-
        reg->val = au0828_read(dev, reg->reg);
+       reg->size = 1;
        return 0;
 }
 
@@ -1798,14 +1769,6 @@ static int vidioc_s_register(struct file *file, void *priv,
        struct au0828_fh *fh = priv;
        struct au0828_dev *dev = fh->dev;
 
-       switch (reg->match.type) {
-       case V4L2_CHIP_MATCH_I2C_DRIVER:
-               v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_register, reg);
-               return 0;
-       default:
-               if (!v4l2_chip_match_host(&reg->match))
-                       return -EINVAL;
-       }
        return au0828_writereg(dev, reg->reg, reg->val);
 }
 #endif
@@ -1943,7 +1906,6 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
        .vidioc_g_register          = vidioc_g_register,
        .vidioc_s_register          = vidioc_s_register,
 #endif
-       .vidioc_g_chip_ident        = vidioc_g_chip_ident,
        .vidioc_log_status          = vidioc_log_status,
        .vidioc_subscribe_event     = v4l2_ctrl_subscribe_event,
        .vidioc_unsubscribe_event   = v4l2_event_unsubscribe,
index f548db8..2f63029 100644 (file)
@@ -1840,7 +1840,6 @@ static const struct v4l2_ioctl_ops mpeg_ioctl_ops = {
        .vidioc_streamon         = vidioc_streamon,
        .vidioc_streamoff        = vidioc_streamoff,
        .vidioc_log_status       = vidioc_log_status,
-       .vidioc_g_chip_ident     = cx231xx_g_chip_ident,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
        .vidioc_g_register       = cx231xx_g_register,
        .vidioc_s_register       = cx231xx_s_register,
index 235ba65..89de00b 100644 (file)
@@ -35,7 +35,6 @@
 
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
-#include <media/v4l2-chip-ident.h>
 
 #include "cx231xx.h"
 #include "cx231xx-dif.h"
index 13249e5..27948e1 100644 (file)
@@ -29,7 +29,6 @@
 #include <media/tuner.h>
 #include <media/tveeprom.h>
 #include <media/v4l2-common.h>
-#include <media/v4l2-chip-ident.h>
 
 #include <media/cx25840.h>
 #include "dvb-usb-ids.h"
index 1340ff2..c027942 100644 (file)
@@ -32,7 +32,6 @@
 
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
-#include <media/v4l2-chip-ident.h>
 #include <media/msp3400.h>
 #include <media/tuner.h>
 
index cd22147..9906261 100644 (file)
@@ -36,7 +36,6 @@
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-event.h>
-#include <media/v4l2-chip-ident.h>
 #include <media/msp3400.h>
 #include <media/tuner.h>
 
@@ -1228,179 +1227,93 @@ int cx231xx_s_frequency(struct file *file, void *priv,
        return rc;
 }
 
-int cx231xx_g_chip_ident(struct file *file, void *fh,
-                       struct v4l2_dbg_chip_ident *chip)
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+
+int cx231xx_g_chip_info(struct file *file, void *fh,
+                       struct v4l2_dbg_chip_info *chip)
 {
-       chip->ident = V4L2_IDENT_NONE;
-       chip->revision = 0;
-       if (chip->match.type == V4L2_CHIP_MATCH_HOST) {
-               if (v4l2_chip_match_host(&chip->match))
-                       chip->ident = V4L2_IDENT_CX23100;
+       switch (chip->match.addr) {
+       case 0: /* Cx231xx - internal registers */
+               return 0;
+       case 1: /* AFE - read byte */
+               strlcpy(chip->name, "AFE (byte)", sizeof(chip->name));
+               return 0;
+       case 2: /* Video Block - read byte */
+               strlcpy(chip->name, "Video (byte)", sizeof(chip->name));
+               return 0;
+       case 3: /* I2S block - read byte */
+               strlcpy(chip->name, "I2S (byte)", sizeof(chip->name));
+               return 0;
+       case 4: /* AFE - read dword */
+               strlcpy(chip->name, "AFE (dword)", sizeof(chip->name));
+               return 0;
+       case 5: /* Video Block - read dword */
+               strlcpy(chip->name, "Video (dword)", sizeof(chip->name));
+               return 0;
+       case 6: /* I2S Block - read dword */
+               strlcpy(chip->name, "I2S (dword)", sizeof(chip->name));
                return 0;
        }
        return -EINVAL;
 }
 
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-
-/*
-  -R, --list-registers=type=<host/i2cdrv/i2caddr>,
-                               chip=<chip>[,min=<addr>,max=<addr>]
-                    dump registers from <min> to <max> [VIDIOC_DBG_G_REGISTER]
-  -r, --set-register=type=<host/i2cdrv/i2caddr>,
-                               chip=<chip>,reg=<addr>,val=<val>
-                    set the register [VIDIOC_DBG_S_REGISTER]
-
-  if type == host, then <chip> is the hosts chip ID (default 0)
-  if type == i2cdrv (default), then <chip> is the I2C driver name or ID
-  if type == i2caddr, then <chip> is the 7-bit I2C address
-*/
-
 int cx231xx_g_register(struct file *file, void *priv,
                             struct v4l2_dbg_register *reg)
 {
        struct cx231xx_fh *fh = priv;
        struct cx231xx *dev = fh->dev;
-       int ret = 0;
+       int ret;
        u8 value[4] = { 0, 0, 0, 0 };
        u32 data = 0;
 
-       switch (reg->match.type) {
-       case V4L2_CHIP_MATCH_HOST:
-               switch (reg->match.addr) {
-               case 0: /* Cx231xx - internal registers */
-                       ret = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER,
-                                                 (u16)reg->reg, value, 4);
-                       reg->val = value[0] | value[1] << 8 |
-                                  value[2] << 16 | value[3] << 24;
-                       break;
-               case 1: /* AFE - read byte */
-                       ret = cx231xx_read_i2c_data(dev, AFE_DEVICE_ADDRESS,
-                                                 (u16)reg->reg, 2, &data, 1);
-                       reg->val = le32_to_cpu(data & 0xff);
-                       break;
-               case 14: /* AFE - read dword */
-                       ret = cx231xx_read_i2c_data(dev, AFE_DEVICE_ADDRESS,
-                                                 (u16)reg->reg, 2, &data, 4);
-                       reg->val = le32_to_cpu(data);
-                       break;
-               case 2: /* Video Block - read byte */
-                       ret = cx231xx_read_i2c_data(dev, VID_BLK_I2C_ADDRESS,
-                                                 (u16)reg->reg, 2, &data, 1);
-                       reg->val = le32_to_cpu(data & 0xff);
-                       break;
-               case 24: /* Video Block - read dword */
-                       ret = cx231xx_read_i2c_data(dev, VID_BLK_I2C_ADDRESS,
-                                                 (u16)reg->reg, 2, &data, 4);
-                       reg->val = le32_to_cpu(data);
-                       break;
-               case 3: /* I2S block - read byte */
-                       ret = cx231xx_read_i2c_data(dev,
-                                                   I2S_BLK_DEVICE_ADDRESS,
-                                                   (u16)reg->reg, 1,
-                                                   &data, 1);
-                       reg->val = le32_to_cpu(data & 0xff);
-                       break;
-               case 34: /* I2S Block - read dword */
-                       ret =
-                           cx231xx_read_i2c_data(dev, I2S_BLK_DEVICE_ADDRESS,
-                                                 (u16)reg->reg, 1, &data, 4);
-                       reg->val = le32_to_cpu(data);
-                       break;
-               }
-               return ret < 0 ? ret : 0;
-
-       case V4L2_CHIP_MATCH_I2C_DRIVER:
-               call_all(dev, core, g_register, reg);
-               return 0;
-       case V4L2_CHIP_MATCH_I2C_ADDR:/*for register debug*/
-               switch (reg->match.addr) {
-               case 0: /* Cx231xx - internal registers */
-                       ret = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER,
-                                                 (u16)reg->reg, value, 4);
-                       reg->val = value[0] | value[1] << 8 |
-                                  value[2] << 16 | value[3] << 24;
-
-                       break;
-               case 0x600:/* AFE - read byte */
-                       ret = cx231xx_read_i2c_master(dev, AFE_DEVICE_ADDRESS,
-                                                (u16)reg->reg, 2,
-                                                &data, 1 , 0);
-                       reg->val = le32_to_cpu(data & 0xff);
-                       break;
-
-               case 0x880:/* Video Block - read byte */
-                       if (reg->reg < 0x0b) {
-                               ret = cx231xx_read_i2c_master(dev,
-                                               VID_BLK_I2C_ADDRESS,
-                                                (u16)reg->reg, 2,
-                                                &data, 1 , 0);
-                               reg->val = le32_to_cpu(data & 0xff);
-                       } else {
-                               ret = cx231xx_read_i2c_master(dev,
-                                               VID_BLK_I2C_ADDRESS,
-                                                (u16)reg->reg, 2,
-                                                &data, 4 , 0);
-                               reg->val = le32_to_cpu(data);
-                       }
-                       break;
-               case 0x980:
-                       ret = cx231xx_read_i2c_master(dev,
-                                               I2S_BLK_DEVICE_ADDRESS,
-                                               (u16)reg->reg, 1,
-                                               &data, 1 , 0);
-                       reg->val = le32_to_cpu(data & 0xff);
-                       break;
-               case 0x400:
-                       ret =
-                           cx231xx_read_i2c_master(dev, 0x40,
-                                                 (u16)reg->reg, 1,
-                                                &data, 1 , 0);
-                       reg->val = le32_to_cpu(data & 0xff);
-                       break;
-               case 0xc01:
-                       ret =
-                               cx231xx_read_i2c_master(dev, 0xc0,
-                                               (u16)reg->reg, 2,
-                                                &data, 38, 1);
-                       reg->val = le32_to_cpu(data);
-                       break;
-               case 0x022:
-                       ret =
-                               cx231xx_read_i2c_master(dev, 0x02,
-                                               (u16)reg->reg, 1,
-                                                &data, 1, 2);
-                       reg->val = le32_to_cpu(data & 0xff);
-                       break;
-               case 0x322:
-                       ret = cx231xx_read_i2c_master(dev,
-                                               0x32,
-                                                (u16)reg->reg, 1,
-                                                &data, 4 , 2);
-                               reg->val = le32_to_cpu(data);
-                       break;
-               case 0x342:
-                       ret = cx231xx_read_i2c_master(dev,
-                                               0x34,
-                                                (u16)reg->reg, 1,
-                                                &data, 4 , 2);
-                               reg->val = le32_to_cpu(data);
-                       break;
-
-               default:
-                       cx231xx_info("no match device address!!\n");
-                       break;
-                       }
-               return ret < 0 ? ret : 0;
-               /*return -EINVAL;*/
+       switch (reg->match.addr) {
+       case 0: /* Cx231xx - internal registers */
+               ret = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER,
+                               (u16)reg->reg, value, 4);
+               reg->val = value[0] | value[1] << 8 |
+                       value[2] << 16 | value[3] << 24;
+               reg->size = 4;
+               break;
+       case 1: /* AFE - read byte */
+               ret = cx231xx_read_i2c_data(dev, AFE_DEVICE_ADDRESS,
+                               (u16)reg->reg, 2, &data, 1);
+               reg->val = data;
+               reg->size = 1;
+               break;
+       case 2: /* Video Block - read byte */
+               ret = cx231xx_read_i2c_data(dev, VID_BLK_I2C_ADDRESS,
+                               (u16)reg->reg, 2, &data, 1);
+               reg->val = data;
+               reg->size = 1;
+               break;
+       case 3: /* I2S block - read byte */
+               ret = cx231xx_read_i2c_data(dev, I2S_BLK_DEVICE_ADDRESS,
+                               (u16)reg->reg, 1, &data, 1);
+               reg->val = data;
+               reg->size = 1;
+               break;
+       case 4: /* AFE - read dword */
+               ret = cx231xx_read_i2c_data(dev, AFE_DEVICE_ADDRESS,
+                               (u16)reg->reg, 2, &data, 4);
+               reg->val = data;
+               reg->size = 4;
+               break;
+       case 5: /* Video Block - read dword */
+               ret = cx231xx_read_i2c_data(dev, VID_BLK_I2C_ADDRESS,
+                               (u16)reg->reg, 2, &data, 4);
+               reg->val = data;
+               reg->size = 4;
+               break;
+       case 6: /* I2S Block - read dword */
+               ret = cx231xx_read_i2c_data(dev, I2S_BLK_DEVICE_ADDRESS,
+                               (u16)reg->reg, 1, &data, 4);
+               reg->val = data;
+               reg->size = 4;
+               break;
        default:
-               if (!v4l2_chip_match_host(&reg->match))
-                       return -EINVAL;
+               return -EINVAL;
        }
-
-       call_all(dev, core, g_register, reg);
-
-       return ret;
+       return ret < 0 ? ret : 0;
 }
 
 int cx231xx_s_register(struct file *file, void *priv,
@@ -1408,165 +1321,46 @@ int cx231xx_s_register(struct file *file, void *priv,
 {
        struct cx231xx_fh *fh = priv;
        struct cx231xx *dev = fh->dev;
-       int ret = 0;
-       __le64 buf;
-       u32 value;
+       int ret;
        u8 data[4] = { 0, 0, 0, 0 };
 
-       buf = cpu_to_le64(reg->val);
-
-       switch (reg->match.type) {
-       case V4L2_CHIP_MATCH_HOST:
-               {
-                       value = (u32) buf & 0xffffffff;
-
-                       switch (reg->match.addr) {
-                       case 0: /* cx231xx internal registers */
-                               data[0] = (u8) value;
-                               data[1] = (u8) (value >> 8);
-                               data[2] = (u8) (value >> 16);
-                               data[3] = (u8) (value >> 24);
-                               ret = cx231xx_write_ctrl_reg(dev,
-                                                          VRT_SET_REGISTER,
-                                                          (u16)reg->reg, data,
-                                                          4);
-                               break;
-                       case 1: /* AFE - read byte */
-                               ret = cx231xx_write_i2c_data(dev,
-                                                       AFE_DEVICE_ADDRESS,
-                                                       (u16)reg->reg, 2,
-                                                       value, 1);
-                               break;
-                       case 14: /* AFE - read dword */
-                               ret = cx231xx_write_i2c_data(dev,
-                                                       AFE_DEVICE_ADDRESS,
-                                                       (u16)reg->reg, 2,
-                                                       value, 4);
-                               break;
-                       case 2: /* Video Block - read byte */
-                               ret =
-                                   cx231xx_write_i2c_data(dev,
-                                                       VID_BLK_I2C_ADDRESS,
-                                                       (u16)reg->reg, 2,
-                                                       value, 1);
-                               break;
-                       case 24: /* Video Block - read dword */
-                               ret =
-                                   cx231xx_write_i2c_data(dev,
-                                                       VID_BLK_I2C_ADDRESS,
-                                                       (u16)reg->reg, 2,
-                                                       value, 4);
-                               break;
-                       case 3: /* I2S block - read byte */
-                               ret =
-                                   cx231xx_write_i2c_data(dev,
-                                                       I2S_BLK_DEVICE_ADDRESS,
-                                                       (u16)reg->reg, 1,
-                                                       value, 1);
-                               break;
-                       case 34: /* I2S block - read dword */
-                               ret =
-                                   cx231xx_write_i2c_data(dev,
-                                                       I2S_BLK_DEVICE_ADDRESS,
-                                                       (u16)reg->reg, 1,
-                                                       value, 4);
-                               break;
-                       }
-               }
-               return ret < 0 ? ret : 0;
-       case V4L2_CHIP_MATCH_I2C_ADDR:
-               {
-                       value = (u32) buf & 0xffffffff;
-
-                       switch (reg->match.addr) {
-                       case 0:/*cx231xx internal registers*/
-                                       data[0] = (u8) value;
-                                       data[1] = (u8) (value >> 8);
-                                       data[2] = (u8) (value >> 16);
-                                       data[3] = (u8) (value >> 24);
-                                       ret = cx231xx_write_ctrl_reg(dev,
-                                                          VRT_SET_REGISTER,
-                                                          (u16)reg->reg, data,
-                                                          4);
-                                       break;
-                       case 0x600:/* AFE - read byte */
-                                       ret = cx231xx_write_i2c_master(dev,
-                                                       AFE_DEVICE_ADDRESS,
-                                                       (u16)reg->reg, 2,
-                                                       value, 1 , 0);
-                                       break;
-
-                       case 0x880:/* Video Block - read byte */
-                                       if (reg->reg < 0x0b)
-                                               cx231xx_write_i2c_master(dev,
-                                                       VID_BLK_I2C_ADDRESS,
-                                                       (u16)reg->reg, 2,
-                                                       value, 1, 0);
-                                       else
-                                               cx231xx_write_i2c_master(dev,
-                                                       VID_BLK_I2C_ADDRESS,
-                                                       (u16)reg->reg, 2,
-                                                       value, 4, 0);
-                                       break;
-                       case 0x980:
-                                       ret =
-                                               cx231xx_write_i2c_master(dev,
-                                                       I2S_BLK_DEVICE_ADDRESS,
-                                                       (u16)reg->reg, 1,
-                                                       value, 1, 0);
-                                       break;
-                       case 0x400:
-                                       ret =
-                                               cx231xx_write_i2c_master(dev,
-                                                       0x40,
-                                                       (u16)reg->reg, 1,
-                                                       value, 1, 0);
-                                       break;
-                       case 0xc01:
-                                       ret =
-                                               cx231xx_write_i2c_master(dev,
-                                                        0xc0,
-                                                        (u16)reg->reg, 1,
-                                                        value, 1, 1);
-                                       break;
-
-                       case 0x022:
-                                       ret =
-                                               cx231xx_write_i2c_master(dev,
-                                                       0x02,
-                                                       (u16)reg->reg, 1,
-                                                       value, 1, 2);
-                                       break;
-                       case 0x322:
-                                       ret =
-                                               cx231xx_write_i2c_master(dev,
-                                                       0x32,
-                                                       (u16)reg->reg, 1,
-                                                       value, 4, 2);
-                                       break;
-
-                       case 0x342:
-                                       ret =
-                                               cx231xx_write_i2c_master(dev,
-                                                       0x34,
-                                                       (u16)reg->reg, 1,
-                                                       value, 4, 2);
-                                       break;
-                       default:
-                               cx231xx_info("no match device address, "
-                                       "the value is %x\n", reg->match.addr);
-                                       break;
-
-                                       }
-
-               }
-       default:
+       switch (reg->match.addr) {
+       case 0: /* cx231xx internal registers */
+               data[0] = (u8) reg->val;
+               data[1] = (u8) (reg->val >> 8);
+               data[2] = (u8) (reg->val >> 16);
+               data[3] = (u8) (reg->val >> 24);
+               ret = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
+                               (u16)reg->reg, data, 4);
+               break;
+       case 1: /* AFE - write byte */
+               ret = cx231xx_write_i2c_data(dev, AFE_DEVICE_ADDRESS,
+                               (u16)reg->reg, 2, reg->val, 1);
+               break;
+       case 2: /* Video Block - write byte */
+               ret = cx231xx_write_i2c_data(dev, VID_BLK_I2C_ADDRESS,
+                               (u16)reg->reg, 2, reg->val, 1);
+               break;
+       case 3: /* I2S block - write byte */
+               ret = cx231xx_write_i2c_data(dev, I2S_BLK_DEVICE_ADDRESS,
+                               (u16)reg->reg, 1, reg->val, 1);
+               break;
+       case 4: /* AFE - write dword */
+               ret = cx231xx_write_i2c_data(dev, AFE_DEVICE_ADDRESS,
+                               (u16)reg->reg, 2, reg->val, 4);
+               break;
+       case 5: /* Video Block - write dword */
+               ret = cx231xx_write_i2c_data(dev, VID_BLK_I2C_ADDRESS,
+                               (u16)reg->reg, 2, reg->val, 4);
                break;
+       case 6: /* I2S block - write dword */
+               ret = cx231xx_write_i2c_data(dev, I2S_BLK_DEVICE_ADDRESS,
+                               (u16)reg->reg, 1, reg->val, 4);
+               break;
+       default:
+               return -EINVAL;
        }
-
-       call_all(dev, core, s_register, reg);
-
-       return ret;
+       return ret < 0 ? ret : 0;
 }
 #endif
 
@@ -2208,8 +2002,8 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
        .vidioc_s_tuner                = cx231xx_s_tuner,
        .vidioc_g_frequency            = cx231xx_g_frequency,
        .vidioc_s_frequency            = cx231xx_s_frequency,
-       .vidioc_g_chip_ident           = cx231xx_g_chip_ident,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
+       .vidioc_g_chip_info            = cx231xx_g_chip_info,
        .vidioc_g_register             = cx231xx_g_register,
        .vidioc_s_register             = cx231xx_s_register,
 #endif
@@ -2240,8 +2034,8 @@ static const struct v4l2_ioctl_ops radio_ioctl_ops = {
        .vidioc_s_tuner     = radio_s_tuner,
        .vidioc_g_frequency = cx231xx_g_frequency,
        .vidioc_s_frequency = cx231xx_s_frequency,
-       .vidioc_g_chip_ident = cx231xx_g_chip_ident,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
+       .vidioc_g_chip_info = cx231xx_g_chip_info,
        .vidioc_g_register  = cx231xx_g_register,
        .vidioc_s_register  = cx231xx_s_register,
 #endif
index 5ad9fd6..e812119 100644 (file)
@@ -945,7 +945,7 @@ int cx231xx_enum_input(struct file *file, void *priv,
                             struct v4l2_input *i);
 int cx231xx_g_input(struct file *file, void *priv, unsigned int *i);
 int cx231xx_s_input(struct file *file, void *priv, unsigned int i);
-int cx231xx_g_chip_ident(struct file *file, void *fh, struct v4l2_dbg_chip_ident *chip);
+int cx231xx_g_chip_info(struct file *file, void *fh, struct v4l2_dbg_chip_info *chip);
 int cx231xx_g_register(struct file *file, void *priv,
                             struct v4l2_dbg_register *reg);
 int cx231xx_s_register(struct file *file, void *priv,
index b638fc1..1ea17dc 100644 (file)
@@ -55,7 +55,7 @@ static int af9035_ctrl_msg(struct dvb_usb_device *d, struct usb_req *req)
        if (req->wlen > (BUF_LEN - REQ_HDR_LEN - CHECKSUM_LEN) ||
                        req->rlen > (BUF_LEN - ACK_HDR_LEN - CHECKSUM_LEN)) {
                dev_err(&d->udev->dev, "%s: too much data wlen=%d rlen=%d\n",
-                               __func__, req->wlen, req->rlen);
+                               KBUILD_MODNAME, req->wlen, req->rlen);
                ret = -EINVAL;
                goto exit;
        }
@@ -91,9 +91,10 @@ static int af9035_ctrl_msg(struct dvb_usb_device *d, struct usb_req *req)
        checksum = af9035_checksum(state->buf, rlen - 2);
        tmp_checksum = (state->buf[rlen - 2] << 8) | state->buf[rlen - 1];
        if (tmp_checksum != checksum) {
-               dev_err(&d->udev->dev, "%s: command=%02x checksum mismatch " \
-                               "(%04x != %04x)\n", KBUILD_MODNAME, req->cmd,
-                               tmp_checksum, checksum);
+               dev_err(&d->udev->dev,
+                               "%s: command=%02x checksum mismatch (%04x != %04x)\n",
+                               KBUILD_MODNAME, req->cmd, tmp_checksum,
+                               checksum);
                ret = -EIO;
                goto exit;
        }
@@ -268,11 +269,29 @@ static int af9035_i2c_master_xfer(struct i2c_adapter *adap,
                        memcpy(&buf[5], msg[0].buf, msg[0].len);
                        ret = af9035_ctrl_msg(d, &req);
                }
+       } else if (num == 1 && (msg[0].flags & I2C_M_RD)) {
+               if (msg[0].len > 40) {
+                       /* TODO: correct limits > 40 */
+                       ret = -EOPNOTSUPP;
+               } else {
+                       /* I2C */
+                       u8 buf[5];
+                       struct usb_req req = { CMD_I2C_RD, 0, sizeof(buf),
+                                       buf, msg[0].len, msg[0].buf };
+                       req.mbox |= ((msg[0].addr & 0x80)  >>  3);
+                       buf[0] = msg[0].len;
+                       buf[1] = msg[0].addr << 1;
+                       buf[2] = 0x00; /* reg addr len */
+                       buf[3] = 0x00; /* reg addr MSB */
+                       buf[4] = 0x00; /* reg addr LSB */
+                       ret = af9035_ctrl_msg(d, &req);
+               }
        } else {
                /*
-                * We support only two kind of I2C transactions:
-                * 1) 1 x read + 1 x write
+                * We support only three kind of I2C transactions:
+                * 1) 1 x read + 1 x write (repeated start)
                 * 2) 1 x write
+                * 3) 1 x read
                 */
                ret = -EOPNOTSUPP;
        }
@@ -317,8 +336,8 @@ static int af9035_identify_state(struct dvb_usb_device *d, const char **name)
 
        dev_info(&d->udev->dev,
                        "%s: prechip_version=%02x chip_version=%02x chip_type=%04x\n",
-                       __func__, state->prechip_version, state->chip_version,
-                       state->chip_type);
+                       KBUILD_MODNAME, state->prechip_version,
+                       state->chip_version, state->chip_type);
 
        if (state->chip_type == 0x9135) {
                if (state->chip_version == 0x02)
@@ -382,9 +401,10 @@ static int af9035_download_firmware_old(struct dvb_usb_device *d,
                hdr_checksum = fw->data[fw->size - i + 5] << 8;
                hdr_checksum |= fw->data[fw->size - i + 6] << 0;
 
-               dev_dbg(&d->udev->dev, "%s: core=%d addr=%04x data_len=%d " \
-                               "checksum=%04x\n", __func__, hdr_core, hdr_addr,
-                               hdr_data_len, hdr_checksum);
+               dev_dbg(&d->udev->dev,
+                               "%s: core=%d addr=%04x data_len=%d checksum=%04x\n",
+                               __func__, hdr_core, hdr_addr, hdr_data_len,
+                               hdr_checksum);
 
                if (((hdr_core != 1) && (hdr_core != 2)) ||
                                (hdr_data_len > i)) {
@@ -489,7 +509,7 @@ static int af9035_download_firmware(struct dvb_usb_device *d,
        u8 rbuf[4];
        u8 tmp;
        struct usb_req req = { 0, 0, 0, NULL, 0, NULL };
-       struct usb_req req_fw_ver = { CMD_FW_QUERYINFO, 0, 1, wbuf, 4, rbuf } ;
+       struct usb_req req_fw_ver = { CMD_FW_QUERYINFO, 0, 1, wbuf, 4, rbuf };
        dev_dbg(&d->udev->dev, "%s:\n", __func__);
 
        /*
@@ -498,11 +518,11 @@ static int af9035_download_firmware(struct dvb_usb_device *d,
         * which is done by master demod.
         * Master feeds also clock and controls power via GPIO.
         */
-       ret = af9035_rd_reg(d, state->eeprom_addr + EEPROM_DUAL_MODE, &tmp);
+       ret = af9035_rd_reg(d, state->eeprom_addr + EEPROM_TS_MODE, &tmp);
        if (ret < 0)
                goto err;
 
-       if (tmp) {
+       if (tmp == 1 || tmp == 3) {
                /* configure gpioh1, reset & power slave demod */
                ret = af9035_wr_reg_mask(d, 0x00d8b0, 0x01, 0x01);
                if (ret < 0)
@@ -620,13 +640,15 @@ static int af9035_read_config(struct dvb_usb_device *d)
        }
 
        /* check if there is dual tuners */
-       ret = af9035_rd_reg(d, state->eeprom_addr + EEPROM_DUAL_MODE, &tmp);
+       ret = af9035_rd_reg(d, state->eeprom_addr + EEPROM_TS_MODE, &tmp);
        if (ret < 0)
                goto err;
 
-       state->dual_mode = tmp;
-       dev_dbg(&d->udev->dev, "%s: dual mode=%d\n", __func__,
-                       state->dual_mode);
+       if (tmp == 1 || tmp == 3)
+               state->dual_mode = true;
+
+       dev_dbg(&d->udev->dev, "%s: ts mode=%d dual mode=%d\n", __func__,
+                       tmp, state->dual_mode);
 
        if (state->dual_mode) {
                /* read 2nd demodulator I2C address */
@@ -1200,9 +1222,9 @@ static int af9035_init(struct dvb_usb_device *d)
                { 0x80f9a4, 0x00, 0x01 },
        };
 
-       dev_dbg(&d->udev->dev, "%s: USB speed=%d frame_size=%04x " \
-                       "packet_size=%02x\n", __func__,
-                       d->udev->speed, frame_size, packet_size);
+       dev_dbg(&d->udev->dev,
+                       "%s: USB speed=%d frame_size=%04x packet_size=%02x\n",
+                       __func__, d->udev->speed, frame_size, packet_size);
 
        /* init endpoints */
        for (i = 0; i < ARRAY_SIZE(tab); i++) {
@@ -1477,7 +1499,7 @@ static const struct usb_device_id af9035_id_table[] = {
                &af9035_props, "AVerMedia Twinstar (A825)", NULL) },
        { DVB_USB_DEVICE(USB_VID_ASUS, USB_PID_ASUS_U3100MINI_PLUS,
                &af9035_props, "Asus U3100Mini Plus", NULL) },
-        { DVB_USB_DEVICE(USB_VID_TERRATEC, 0x00aa,
+       { DVB_USB_DEVICE(USB_VID_TERRATEC, 0x00aa,
                &af9035_props, "TerraTec Cinergy T Stick (rev. 2)", NULL) },
        /* IT9135 devices */
 #if 0
index b5827ca..a1c68d8 100644 (file)
@@ -100,8 +100,13 @@ static const u32 clock_lut_it9135[] = {
  * eeprom is memory mapped as read only. Writing that memory mapped address
  * will not corrupt eeprom.
  *
- * eeprom has value 0x00 single mode and 0x03 for dual mode as far as I have
- * seen to this day.
+ * TS mode:
+ * 0  TS
+ * 1  DCA + PIP
+ * 3  PIP
+ * n  DCA
+ *
+ * Values 0 and 3 are seen to this day. 0 for single TS and 3 for dual TS.
  */
 
 #define EEPROM_BASE_AF9035        0x42fd
@@ -109,7 +114,7 @@ static const u32 clock_lut_it9135[] = {
 #define EEPROM_SHIFT                0x10
 
 #define EEPROM_IR_MODE              0x10
-#define EEPROM_DUAL_MODE            0x29
+#define EEPROM_TS_MODE              0x29
 #define EEPROM_2ND_DEMOD_ADDR       0x2a
 #define EEPROM_IR_TYPE              0x2c
 #define EEPROM_1_IF_L               0x30
index 658c6d4..399916b 100644 (file)
@@ -140,7 +140,7 @@ struct dvb_usb_rc {
        int (*change_protocol)(struct rc_dev *dev, u64 *rc_type);
        int (*query) (struct dvb_usb_device *d);
        unsigned int interval;
-       const enum rc_driver_type driver_type;
+       enum rc_driver_type driver_type;
        bool bulk_mode;
 };
 
index e48cdeb..1cb6899 100644 (file)
@@ -45,7 +45,7 @@ MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able)).");
 
 static int dvb_usb_it913x_firmware;
 module_param_named(firmware, dvb_usb_it913x_firmware, int, 0644);
-MODULE_PARM_DESC(firmware, "set firmware 0=auto"\
+MODULE_PARM_DESC(firmware, "set firmware 0=auto "\
        "1=IT9137 2=IT9135 V1 3=IT9135 V2");
 #define FW_IT9137 "dvb-usb-it9137-01.fw"
 #define FW_IT9135_V1 "dvb-usb-it9135-01.fw"
@@ -796,6 +796,9 @@ static const struct usb_device_id it913x_id_table[] = {
        { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A835B_4835,
                &it913x_properties, "Avermedia A835B(4835)",
                        RC_MAP_IT913X_V2) },
+       { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_CTVDIGDUAL_V2,
+               &it913x_properties, "Digital Dual TV Receiver CTVDIGDUAL_V2",
+                       RC_MAP_IT913X_V1) },
        {}              /* Terminating entry */
 };
 
index ef4c65f..879c529 100644 (file)
@@ -31,8 +31,6 @@ MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able)).");
        if (mxl111sf_tuner_debug) \
                mxl_printk(KERN_DEBUG, fmt, ##arg)
 
-#define err pr_err
-
 /* ------------------------------------------------------------------------ */
 
 struct mxl111sf_tuner_state {
@@ -113,7 +111,7 @@ static struct mxl111sf_reg_ctrl_info *mxl111sf_calc_phy_tune_regs(u32 freq,
                filt_bw = 63;
                break;
        default:
-               err("%s: invalid bandwidth setting!", __func__);
+               pr_err("%s: invalid bandwidth setting!", __func__);
                return NULL;
        }
 
@@ -304,12 +302,12 @@ static int mxl111sf_tuner_set_params(struct dvb_frontend *fe)
                        bw = 8;
                        break;
                default:
-                       err("%s: bandwidth not set!", __func__);
+                       pr_err("%s: bandwidth not set!", __func__);
                        return -EINVAL;
                }
                break;
        default:
-               err("%s: modulation type not supported!", __func__);
+               pr_err("%s: modulation type not supported!", __func__);
                return -EINVAL;
        }
        ret = mxl1x1sf_tune_rf(fe, c->frequency, bw);
index efdcb15..e97964e 100644 (file)
@@ -52,12 +52,6 @@ MODULE_PARM_DESC(rfswitch, "force rf switch position (0=auto, 1=ext, 2=int).");
 
 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
 
-#define deb_info pr_debug
-#define deb_reg pr_debug
-#define deb_adv pr_debug
-#define err pr_err
-#define info pr_info
-
 int mxl111sf_ctrl_msg(struct dvb_usb_device *d,
                      u8 cmd, u8 *wbuf, int wlen, u8 *rbuf, int rlen)
 {
@@ -65,7 +59,7 @@ int mxl111sf_ctrl_msg(struct dvb_usb_device *d,
        int ret;
        u8 sndbuf[1+wlen];
 
-       deb_adv("%s(wlen = %d, rlen = %d)\n", __func__, wlen, rlen);
+       pr_debug("%s(wlen = %d, rlen = %d)\n", __func__, wlen, rlen);
 
        memset(sndbuf, 0, 1+wlen);
 
@@ -98,12 +92,12 @@ int mxl111sf_read_reg(struct mxl111sf_state *state, u8 addr, u8 *data)
        if (buf[0] == addr)
                *data = buf[1];
        else {
-               err("invalid response reading reg: 0x%02x != 0x%02x, 0x%02x",
+               pr_err("invalid response reading reg: 0x%02x != 0x%02x, 0x%02x",
                    addr, buf[0], buf[1]);
                ret = -EINVAL;
        }
 
-       deb_reg("R: (0x%02x, 0x%02x)\n", addr, *data);
+       pr_debug("R: (0x%02x, 0x%02x)\n", addr, *data);
 fail:
        return ret;
 }
@@ -113,11 +107,11 @@ int mxl111sf_write_reg(struct mxl111sf_state *state, u8 addr, u8 data)
        u8 buf[] = { addr, data };
        int ret;
 
-       deb_reg("W: (0x%02x, 0x%02x)\n", addr, data);
+       pr_debug("W: (0x%02x, 0x%02x)\n", addr, data);
 
        ret = mxl111sf_ctrl_msg(state->d, MXL_CMD_REG_WRITE, buf, 2, NULL, 0);
        if (mxl_fail(ret))
-               err("error writing reg: 0x%02x, val: 0x%02x", addr, data);
+               pr_err("error writing reg: 0x%02x, val: 0x%02x", addr, data);
        return ret;
 }
 
@@ -134,7 +128,7 @@ int mxl111sf_write_reg_mask(struct mxl111sf_state *state,
 #if 1
                /* dont know why this usually errors out on the first try */
                if (mxl_fail(ret))
-                       err("error writing addr: 0x%02x, mask: 0x%02x, "
+                       pr_err("error writing addr: 0x%02x, mask: 0x%02x, "
                            "data: 0x%02x, retrying...", addr, mask, data);
 
                ret = mxl111sf_read_reg(state, addr, &val);
@@ -167,7 +161,7 @@ int mxl111sf_ctrl_program_regs(struct mxl111sf_state *state,
                                              ctrl_reg_info[i].mask,
                                              ctrl_reg_info[i].data);
                if (mxl_fail(ret)) {
-                       err("failed on reg #%d (0x%02x)", i,
+                       pr_err("failed on reg #%d (0x%02x)", i,
                            ctrl_reg_info[i].addr);
                        break;
                }
@@ -225,7 +219,7 @@ static int mxl1x1sf_get_chip_info(struct mxl111sf_state *state)
                mxl_rev = "UNKNOWN REVISION";
                break;
        }
-       info("%s detected, %s (0x%x)", mxl_chip, mxl_rev, ver);
+       pr_info("%s detected, %s (0x%x)", mxl_chip, mxl_rev, ver);
 fail:
        return ret;
 }
@@ -239,7 +233,7 @@ fail:
                          " on first probe attempt");                   \
                ___ret = mxl1x1sf_get_chip_info(state);                 \
                if (mxl_fail(___ret))                                   \
-                       err("failed to get chip info during probe");    \
+                       pr_err("failed to get chip info during probe"); \
                else                                                    \
                        mxl_debug("probe needed a retry "               \
                                  "in order to succeed.");              \
@@ -270,14 +264,14 @@ static int mxl111sf_adap_fe_init(struct dvb_frontend *fe)
                goto fail;
        }
 
-       deb_info("%s()\n", __func__);
+       pr_debug("%s()\n", __func__);
 
        mutex_lock(&state->fe_lock);
 
        state->alt_mode = adap_state->alt_mode;
 
        if (usb_set_interface(d->udev, 0, state->alt_mode) < 0)
-               err("set interface failed");
+               pr_err("set interface failed");
 
        err = mxl1x1sf_soft_reset(state);
        mxl_fail(err);
@@ -326,7 +320,7 @@ static int mxl111sf_adap_fe_sleep(struct dvb_frontend *fe)
                goto fail;
        }
 
-       deb_info("%s()\n", __func__);
+       pr_debug("%s()\n", __func__);
 
        err = (adap_state->fe_sleep) ? adap_state->fe_sleep(fe) : 0;
 
@@ -344,7 +338,7 @@ static int mxl111sf_ep6_streaming_ctrl(struct dvb_frontend *fe, int onoff)
        struct mxl111sf_adap_state *adap_state = &state->adap_state[fe->id];
        int ret = 0;
 
-       deb_info("%s(%d)\n", __func__, onoff);
+       pr_debug("%s(%d)\n", __func__, onoff);
 
        if (onoff) {
                ret = mxl111sf_enable_usb_output(state);
@@ -368,7 +362,7 @@ static int mxl111sf_ep5_streaming_ctrl(struct dvb_frontend *fe, int onoff)
        struct mxl111sf_state *state = fe_to_priv(fe);
        int ret = 0;
 
-       deb_info("%s(%d)\n", __func__, onoff);
+       pr_debug("%s(%d)\n", __func__, onoff);
 
        if (onoff) {
                ret = mxl111sf_enable_usb_output(state);
@@ -394,7 +388,7 @@ static int mxl111sf_ep4_streaming_ctrl(struct dvb_frontend *fe, int onoff)
        struct mxl111sf_state *state = fe_to_priv(fe);
        int ret = 0;
 
-       deb_info("%s(%d)\n", __func__, onoff);
+       pr_debug("%s(%d)\n", __func__, onoff);
 
        if (onoff) {
                ret = mxl111sf_enable_usb_output(state);
@@ -424,7 +418,7 @@ static int mxl111sf_lgdt3305_frontend_attach(struct dvb_usb_adapter *adap, u8 fe
        struct mxl111sf_adap_state *adap_state = &state->adap_state[fe_id];
        int ret;
 
-       deb_adv("%s()\n", __func__);
+       pr_debug("%s()\n", __func__);
 
        /* save a pointer to the dvb_usb_device in device state */
        state->d = d;
@@ -432,7 +426,7 @@ static int mxl111sf_lgdt3305_frontend_attach(struct dvb_usb_adapter *adap, u8 fe
        state->alt_mode = adap_state->alt_mode;
 
        if (usb_set_interface(d->udev, 0, state->alt_mode) < 0)
-               err("set interface failed");
+               pr_err("set interface failed");
 
        state->gpio_mode = MXL111SF_GPIO_MOD_ATSC;
        adap_state->gpio_mode = state->gpio_mode;
@@ -495,7 +489,7 @@ static int mxl111sf_lg2160_frontend_attach(struct dvb_usb_adapter *adap, u8 fe_i
        struct mxl111sf_adap_state *adap_state = &state->adap_state[fe_id];
        int ret;
 
-       deb_adv("%s()\n", __func__);
+       pr_debug("%s()\n", __func__);
 
        /* save a pointer to the dvb_usb_device in device state */
        state->d = d;
@@ -503,7 +497,7 @@ static int mxl111sf_lg2160_frontend_attach(struct dvb_usb_adapter *adap, u8 fe_i
        state->alt_mode = adap_state->alt_mode;
 
        if (usb_set_interface(d->udev, 0, state->alt_mode) < 0)
-               err("set interface failed");
+               pr_err("set interface failed");
 
        state->gpio_mode = MXL111SF_GPIO_MOD_MH;
        adap_state->gpio_mode = state->gpio_mode;
@@ -580,7 +574,7 @@ static int mxl111sf_lg2161_frontend_attach(struct dvb_usb_adapter *adap, u8 fe_i
        struct mxl111sf_adap_state *adap_state = &state->adap_state[fe_id];
        int ret;
 
-       deb_adv("%s()\n", __func__);
+       pr_debug("%s()\n", __func__);
 
        /* save a pointer to the dvb_usb_device in device state */
        state->d = d;
@@ -588,7 +582,7 @@ static int mxl111sf_lg2161_frontend_attach(struct dvb_usb_adapter *adap, u8 fe_i
        state->alt_mode = adap_state->alt_mode;
 
        if (usb_set_interface(d->udev, 0, state->alt_mode) < 0)
-               err("set interface failed");
+               pr_err("set interface failed");
 
        state->gpio_mode = MXL111SF_GPIO_MOD_MH;
        adap_state->gpio_mode = state->gpio_mode;
@@ -667,7 +661,7 @@ static int mxl111sf_lg2161_ep6_frontend_attach(struct dvb_usb_adapter *adap, u8
        struct mxl111sf_adap_state *adap_state = &state->adap_state[fe_id];
        int ret;
 
-       deb_adv("%s()\n", __func__);
+       pr_debug("%s()\n", __func__);
 
        /* save a pointer to the dvb_usb_device in device state */
        state->d = d;
@@ -675,7 +669,7 @@ static int mxl111sf_lg2161_ep6_frontend_attach(struct dvb_usb_adapter *adap, u8
        state->alt_mode = adap_state->alt_mode;
 
        if (usb_set_interface(d->udev, 0, state->alt_mode) < 0)
-               err("set interface failed");
+               pr_err("set interface failed");
 
        state->gpio_mode = MXL111SF_GPIO_MOD_MH;
        adap_state->gpio_mode = state->gpio_mode;
@@ -742,7 +736,7 @@ static int mxl111sf_attach_demod(struct dvb_usb_adapter *adap, u8 fe_id)
        struct mxl111sf_adap_state *adap_state = &state->adap_state[fe_id];
        int ret;
 
-       deb_adv("%s()\n", __func__);
+       pr_debug("%s()\n", __func__);
 
        /* save a pointer to the dvb_usb_device in device state */
        state->d = d;
@@ -750,7 +744,7 @@ static int mxl111sf_attach_demod(struct dvb_usb_adapter *adap, u8 fe_id)
        state->alt_mode = adap_state->alt_mode;
 
        if (usb_set_interface(d->udev, 0, state->alt_mode) < 0)
-               err("set interface failed");
+               pr_err("set interface failed");
 
        state->gpio_mode = MXL111SF_GPIO_MOD_DVBT;
        adap_state->gpio_mode = state->gpio_mode;
@@ -802,7 +796,7 @@ static inline int mxl111sf_set_ant_path(struct mxl111sf_state *state,
 }
 
 #define DbgAntHunt(x, pwr0, pwr1, pwr2, pwr3) \
-       err("%s(%d) FINAL input set to %s rxPwr:%d|%d|%d|%d\n", \
+       pr_err("%s(%d) FINAL input set to %s rxPwr:%d|%d|%d|%d\n", \
            __func__, __LINE__, \
            (ANT_PATH_EXTERNAL == x) ? "EXTERNAL" : "INTERNAL", \
            pwr0, pwr1, pwr2, pwr3)
@@ -868,7 +862,7 @@ static int mxl111sf_attach_tuner(struct dvb_usb_adapter *adap)
        struct mxl111sf_state *state = adap_to_priv(adap);
        int i;
 
-       deb_adv("%s()\n", __func__);
+       pr_debug("%s()\n", __func__);
 
        for (i = 0; i < state->num_frontends; i++) {
                if (dvb_attach(mxl111sf_tuner_attach, adap->fe[i], state,
@@ -902,7 +896,7 @@ static int mxl111sf_init(struct dvb_usb_device *d)
 
        ret = get_chip_info(state);
        if (mxl_fail(ret))
-               err("failed to get chip info during probe");
+               pr_err("failed to get chip info during probe");
 
        mutex_init(&state->fe_lock);
 
@@ -950,7 +944,7 @@ static int mxl111sf_frontend_attach_mh(struct dvb_usb_adapter *adap)
 static int mxl111sf_frontend_attach_atsc_mh(struct dvb_usb_adapter *adap)
 {
        int ret;
-       deb_info("%s\n", __func__);
+       pr_debug("%s\n", __func__);
 
        ret = mxl111sf_lgdt3305_frontend_attach(adap, 0);
        if (ret < 0)
@@ -970,7 +964,7 @@ static int mxl111sf_frontend_attach_atsc_mh(struct dvb_usb_adapter *adap)
 static int mxl111sf_frontend_attach_mercury(struct dvb_usb_adapter *adap)
 {
        int ret;
-       deb_info("%s\n", __func__);
+       pr_debug("%s\n", __func__);
 
        ret = mxl111sf_lgdt3305_frontend_attach(adap, 0);
        if (ret < 0)
@@ -990,7 +984,7 @@ static int mxl111sf_frontend_attach_mercury(struct dvb_usb_adapter *adap)
 static int mxl111sf_frontend_attach_mercury_mh(struct dvb_usb_adapter *adap)
 {
        int ret;
-       deb_info("%s\n", __func__);
+       pr_debug("%s\n", __func__);
 
        ret = mxl111sf_attach_demod(adap, 0);
        if (ret < 0)
@@ -1006,7 +1000,7 @@ static int mxl111sf_frontend_attach_mercury_mh(struct dvb_usb_adapter *adap)
 
 static void mxl111sf_stream_config_bulk(struct usb_data_stream_properties *stream, u8 endpoint)
 {
-       deb_info("%s: endpoint=%d size=8192\n", __func__, endpoint);
+       pr_debug("%s: endpoint=%d size=8192\n", __func__, endpoint);
        stream->type = USB_BULK;
        stream->count = 5;
        stream->endpoint = endpoint;
@@ -1016,7 +1010,7 @@ static void mxl111sf_stream_config_bulk(struct usb_data_stream_properties *strea
 static void mxl111sf_stream_config_isoc(struct usb_data_stream_properties *stream,
                u8 endpoint, int framesperurb, int framesize)
 {
-       deb_info("%s: endpoint=%d size=%d\n", __func__, endpoint,
+       pr_debug("%s: endpoint=%d size=%d\n", __func__, endpoint,
                        framesperurb * framesize);
        stream->type = USB_ISOC;
        stream->count = 5;
@@ -1035,7 +1029,7 @@ static void mxl111sf_stream_config_isoc(struct usb_data_stream_properties *strea
 static int mxl111sf_get_stream_config_dvbt(struct dvb_frontend *fe,
                u8 *ts_type, struct usb_data_stream_properties *stream)
 {
-       deb_info("%s: fe=%d\n", __func__, fe->id);
+       pr_debug("%s: fe=%d\n", __func__, fe->id);
 
        *ts_type = DVB_USB_FE_TS_TYPE_188;
        if (dvb_usb_mxl111sf_isoc)
@@ -1076,7 +1070,7 @@ static struct dvb_usb_device_properties mxl111sf_props_dvbt = {
 static int mxl111sf_get_stream_config_atsc(struct dvb_frontend *fe,
                u8 *ts_type, struct usb_data_stream_properties *stream)
 {
-       deb_info("%s: fe=%d\n", __func__, fe->id);
+       pr_debug("%s: fe=%d\n", __func__, fe->id);
 
        *ts_type = DVB_USB_FE_TS_TYPE_188;
        if (dvb_usb_mxl111sf_isoc)
@@ -1117,7 +1111,7 @@ static struct dvb_usb_device_properties mxl111sf_props_atsc = {
 static int mxl111sf_get_stream_config_mh(struct dvb_frontend *fe,
                u8 *ts_type, struct usb_data_stream_properties *stream)
 {
-       deb_info("%s: fe=%d\n", __func__, fe->id);
+       pr_debug("%s: fe=%d\n", __func__, fe->id);
 
        *ts_type = DVB_USB_FE_TS_TYPE_RAW;
        if (dvb_usb_mxl111sf_isoc)
@@ -1158,7 +1152,7 @@ static struct dvb_usb_device_properties mxl111sf_props_mh = {
 static int mxl111sf_get_stream_config_atsc_mh(struct dvb_frontend *fe,
                u8 *ts_type, struct usb_data_stream_properties *stream)
 {
-       deb_info("%s: fe=%d\n", __func__, fe->id);
+       pr_debug("%s: fe=%d\n", __func__, fe->id);
 
        if (fe->id == 0) {
                *ts_type = DVB_USB_FE_TS_TYPE_188;
@@ -1184,7 +1178,7 @@ static int mxl111sf_get_stream_config_atsc_mh(struct dvb_frontend *fe,
 
 static int mxl111sf_streaming_ctrl_atsc_mh(struct dvb_frontend *fe, int onoff)
 {
-       deb_info("%s: fe=%d onoff=%d\n", __func__, fe->id, onoff);
+       pr_debug("%s: fe=%d onoff=%d\n", __func__, fe->id, onoff);
 
        if (fe->id == 0)
                return mxl111sf_ep6_streaming_ctrl(fe, onoff);
@@ -1228,7 +1222,7 @@ static struct dvb_usb_device_properties mxl111sf_props_atsc_mh = {
 static int mxl111sf_get_stream_config_mercury(struct dvb_frontend *fe,
                u8 *ts_type, struct usb_data_stream_properties *stream)
 {
-       deb_info("%s: fe=%d\n", __func__, fe->id);
+       pr_debug("%s: fe=%d\n", __func__, fe->id);
 
        if (fe->id == 0) {
                *ts_type = DVB_USB_FE_TS_TYPE_188;
@@ -1260,7 +1254,7 @@ static int mxl111sf_get_stream_config_mercury(struct dvb_frontend *fe,
 
 static int mxl111sf_streaming_ctrl_mercury(struct dvb_frontend *fe, int onoff)
 {
-       deb_info("%s: fe=%d onoff=%d\n", __func__, fe->id, onoff);
+       pr_debug("%s: fe=%d onoff=%d\n", __func__, fe->id, onoff);
 
        if (fe->id == 0)
                return mxl111sf_ep6_streaming_ctrl(fe, onoff);
@@ -1306,7 +1300,7 @@ static struct dvb_usb_device_properties mxl111sf_props_mercury = {
 static int mxl111sf_get_stream_config_mercury_mh(struct dvb_frontend *fe,
                u8 *ts_type, struct usb_data_stream_properties *stream)
 {
-       deb_info("%s: fe=%d\n", __func__, fe->id);
+       pr_debug("%s: fe=%d\n", __func__, fe->id);
 
        if (fe->id == 0) {
                *ts_type = DVB_USB_FE_TS_TYPE_188;
@@ -1332,7 +1326,7 @@ static int mxl111sf_get_stream_config_mercury_mh(struct dvb_frontend *fe,
 
 static int mxl111sf_streaming_ctrl_mercury_mh(struct dvb_frontend *fe, int onoff)
 {
-       deb_info("%s: fe=%d onoff=%d\n", __func__, fe->id, onoff);
+       pr_debug("%s: fe=%d onoff=%d\n", __func__, fe->id, onoff);
 
        if (fe->id == 0)
                return mxl111sf_ep4_streaming_ctrl(fe, onoff);
index 2cc8ec7..c0cd084 100644 (file)
@@ -1041,67 +1041,34 @@ err:
 static int rtl2832u_power_ctrl(struct dvb_usb_device *d, int onoff)
 {
        int ret;
-       u8 val;
 
        dev_dbg(&d->udev->dev, "%s: onoff=%d\n", __func__, onoff);
 
        if (onoff) {
-               /* set output values */
-               ret = rtl28xx_rd_reg(d, SYS_GPIO_OUT_VAL, &val);
+               /* GPIO3=1, GPIO4=0 */
+               ret = rtl28xx_wr_reg_mask(d, SYS_GPIO_OUT_VAL, 0x08, 0x18);
                if (ret)
                        goto err;
 
-               val |= 0x08;
-               val &= 0xef;
-
-               ret = rtl28xx_wr_reg(d, SYS_GPIO_OUT_VAL, val);
+               /* suspend? */
+               ret = rtl28xx_wr_reg_mask(d, SYS_DEMOD_CTL1, 0x00, 0x10);
                if (ret)
                        goto err;
 
-               /* demod_ctl_1 */
-               ret = rtl28xx_rd_reg(d, SYS_DEMOD_CTL1, &val);
+               /* enable PLL */
+               ret = rtl28xx_wr_reg_mask(d, SYS_DEMOD_CTL, 0x80, 0x80);
                if (ret)
                        goto err;
 
-               val &= 0xef;
-
-               ret = rtl28xx_wr_reg(d, SYS_DEMOD_CTL1, val);
-               if (ret)
-                       goto err;
-
-               /* demod control */
-               /* PLL enable */
-               ret = rtl28xx_rd_reg(d, SYS_DEMOD_CTL, &val);
-               if (ret)
-                       goto err;
-
-               /* bit 7 to 1 */
-               val |= 0x80;
-
-               ret = rtl28xx_wr_reg(d, SYS_DEMOD_CTL, val);
-               if (ret)
-                       goto err;
-
-               ret = rtl28xx_rd_reg(d, SYS_DEMOD_CTL, &val);
-               if (ret)
-                       goto err;
-
-               val |= 0x20;
-
-               ret = rtl28xx_wr_reg(d, SYS_DEMOD_CTL, val);
+               /* disable reset */
+               ret = rtl28xx_wr_reg_mask(d, SYS_DEMOD_CTL, 0x20, 0x20);
                if (ret)
                        goto err;
 
                mdelay(5);
 
-               /*enable ADC_Q and ADC_I */
-               ret = rtl28xx_rd_reg(d, SYS_DEMOD_CTL, &val);
-               if (ret)
-                       goto err;
-
-               val |= 0x48;
-
-               ret = rtl28xx_wr_reg(d, SYS_DEMOD_CTL, val);
+               /* enable ADC */
+               ret = rtl28xx_wr_reg_mask(d, SYS_DEMOD_CTL, 0x48, 0x48);
                if (ret)
                        goto err;
 
@@ -1114,36 +1081,18 @@ static int rtl2832u_power_ctrl(struct dvb_usb_device *d, int onoff)
                if (ret)
                        goto err;
        } else {
-               /* demod_ctl_1 */
-               ret = rtl28xx_rd_reg(d, SYS_DEMOD_CTL1, &val);
-               if (ret)
-                       goto err;
-
-               val |= 0x0c;
-
-               ret = rtl28xx_wr_reg(d, SYS_DEMOD_CTL1, val);
-               if (ret)
-                       goto err;
-
-               /* set output values */
-               ret = rtl28xx_rd_reg(d, SYS_GPIO_OUT_VAL, &val);
-               if (ret)
-                               goto err;
-
-               val |= 0x10;
-
-               ret = rtl28xx_wr_reg(d, SYS_GPIO_OUT_VAL, val);
+               /* GPIO4=1 */
+               ret = rtl28xx_wr_reg_mask(d, SYS_GPIO_OUT_VAL, 0x10, 0x10);
                if (ret)
                        goto err;
 
-               /* demod control */
-               ret = rtl28xx_rd_reg(d, SYS_DEMOD_CTL, &val);
+               /* disable ADC */
+               ret = rtl28xx_wr_reg_mask(d, SYS_DEMOD_CTL, 0x00, 0x48);
                if (ret)
                        goto err;
 
-               val &= 0x37;
-
-               ret = rtl28xx_wr_reg(d, SYS_DEMOD_CTL, val);
+               /* disable PLL */
+               ret = rtl28xx_wr_reg_mask(d, SYS_DEMOD_CTL, 0x00, 0x80);
                if (ret)
                        goto err;
 
@@ -1242,42 +1191,47 @@ static int rtl2831u_get_rc_config(struct dvb_usb_device *d,
 
        return 0;
 }
-#else
-       #define rtl2831u_get_rc_config NULL
-#endif
 
-#if IS_ENABLED(CONFIG_RC_CORE)
 static int rtl2832u_rc_query(struct dvb_usb_device *d)
 {
-       int ret, i;
+       int ret, i, len;
        struct rtl28xxu_priv *priv = d->priv;
+       struct ir_raw_event ev;
        u8 buf[128];
-       int len;
-       struct rtl28xxu_reg_val rc_nec_tab[] = {
-               { IR_RX_CTRL,             0x20 },
-               { IR_RX_BUF_CTRL,         0x80 },
-               { IR_RX_IF,               0xff },
-               { IR_RX_IE,               0xff },
-               { IR_MAX_DURATION0,       0xd0 },
-               { IR_MAX_DURATION1,       0x07 },
-               { IR_IDLE_LEN0,           0xc0 },
-               { IR_IDLE_LEN1,           0x00 },
-               { IR_GLITCH_LEN,          0x03 },
-               { IR_RX_CLK,              0x09 },
-               { IR_RX_CFG,              0x1c },
-               { IR_MAX_H_TOL_LEN,       0x1e },
-               { IR_MAX_L_TOL_LEN,       0x1e },
-               { IR_RX_CTRL,             0x80 },
+       static const struct rtl28xxu_reg_val_mask refresh_tab[] = {
+               {IR_RX_IF,               0x03, 0xff},
+               {IR_RX_BUF_CTRL,         0x80, 0xff},
+               {IR_RX_CTRL,             0x80, 0xff},
        };
 
        /* init remote controller */
        if (!priv->rc_active) {
-               for (i = 0; i < ARRAY_SIZE(rc_nec_tab); i++) {
-                       ret = rtl28xx_wr_reg(d, rc_nec_tab[i].reg,
-                                       rc_nec_tab[i].val);
+               static const struct rtl28xxu_reg_val_mask init_tab[] = {
+                       {SYS_DEMOD_CTL1,         0x00, 0x04},
+                       {SYS_DEMOD_CTL1,         0x00, 0x08},
+                       {USB_CTRL,               0x20, 0x20},
+                       {SYS_GPIO_DIR,           0x00, 0x08},
+                       {SYS_GPIO_OUT_EN,        0x08, 0x08},
+                       {SYS_GPIO_OUT_VAL,       0x08, 0x08},
+                       {IR_MAX_DURATION0,       0xd0, 0xff},
+                       {IR_MAX_DURATION1,       0x07, 0xff},
+                       {IR_IDLE_LEN0,           0xc0, 0xff},
+                       {IR_IDLE_LEN1,           0x00, 0xff},
+                       {IR_GLITCH_LEN,          0x03, 0xff},
+                       {IR_RX_CLK,              0x09, 0xff},
+                       {IR_RX_CFG,              0x1c, 0xff},
+                       {IR_MAX_H_TOL_LEN,       0x1e, 0xff},
+                       {IR_MAX_L_TOL_LEN,       0x1e, 0xff},
+                       {IR_RX_CTRL,             0x80, 0xff},
+               };
+
+               for (i = 0; i < ARRAY_SIZE(init_tab); i++) {
+                       ret = rtl28xx_wr_reg_mask(d, init_tab[i].reg,
+                                       init_tab[i].val, init_tab[i].mask);
                        if (ret)
                                goto err;
                }
+
                priv->rc_active = true;
        }
 
@@ -1293,14 +1247,32 @@ static int rtl2832u_rc_query(struct dvb_usb_device *d)
                goto err;
 
        len = buf[0];
+
+       /* read raw code from hw */
        ret = rtl2831_rd_regs(d, IR_RX_BUF, buf, len);
+       if (ret)
+               goto err;
 
-       /* TODO: pass raw IR to Kernel IR decoder */
+       /* let hw receive new code */
+       for (i = 0; i < ARRAY_SIZE(refresh_tab); i++) {
+               ret = rtl28xx_wr_reg_mask(d, refresh_tab[i].reg,
+                               refresh_tab[i].val, refresh_tab[i].mask);
+               if (ret)
+                       goto err;
+       }
 
-       ret = rtl28xx_wr_reg(d, IR_RX_IF, 0x03);
-       ret = rtl28xx_wr_reg(d, IR_RX_BUF_CTRL, 0x80);
-       ret = rtl28xx_wr_reg(d, IR_RX_CTRL, 0x80);
+       /* pass data to Kernel IR decoder */
+       init_ir_raw_event(&ev);
 
+       for (i = 0; i < len; i++) {
+               ev.pulse = buf[i] >> 7;
+               ev.duration = 50800 * (buf[i] & 0x7f);
+               ir_raw_event_store_with_filter(d->rc_dev, &ev);
+       }
+
+       /* 'flush' ir_raw_event_store_with_filter() */
+       ir_raw_event_set_idle(d->rc_dev, true);
+       ir_raw_event_handle(d->rc_dev);
 exit:
        return ret;
 err:
@@ -1311,15 +1283,19 @@ err:
 static int rtl2832u_get_rc_config(struct dvb_usb_device *d,
                struct dvb_usb_rc *rc)
 {
-       rc->map_name = RC_MAP_EMPTY;
-       rc->allowed_protos = RC_BIT_NEC;
+       /* load empty to enable rc */
+       if (!rc->map_name)
+               rc->map_name = RC_MAP_EMPTY;
+       rc->allowed_protos = RC_BIT_ALL;
+       rc->driver_type = RC_DRIVER_IR_RAW;
        rc->query = rtl2832u_rc_query;
        rc->interval = 400;
 
        return 0;
 }
 #else
-       #define rtl2832u_get_rc_config NULL
+#define rtl2831u_get_rc_config NULL
+#define rtl2832u_get_rc_config NULL
 #endif
 
 static const struct dvb_usb_device_properties rtl2831u_props = {
@@ -1379,7 +1355,7 @@ static const struct usb_device_id rtl28xxu_id_table[] = {
        { DVB_USB_DEVICE(USB_VID_REALTEK, 0x2838,
                &rtl2832u_props, "Realtek RTL2832U reference design", NULL) },
        { DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_STICK_BLACK_REV1,
-               &rtl2832u_props, "TerraTec Cinergy T Stick Black", NULL) },
+               &rtl2832u_props, "TerraTec Cinergy T Stick Black", RC_MAP_TERRATEC_SLIM) },
        { DVB_USB_DEVICE(USB_VID_GTEK, USB_PID_DELOCK_USB2_DVBT,
                &rtl2832u_props, "G-Tek Electronics Group Lifeview LV5TDLX DVB-T", NULL) },
        { DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_NOXON_DAB_STICK,
@@ -1403,11 +1379,15 @@ static const struct usb_device_id rtl28xxu_id_table[] = {
        { DVB_USB_DEVICE(USB_VID_KWORLD_2, 0xd393,
                &rtl2832u_props, "GIGABYTE U7300", NULL) },
        { DVB_USB_DEVICE(USB_VID_DEXATEK, 0x1104,
-               &rtl2832u_props, "Digivox Micro Hd", NULL) },
+               &rtl2832u_props, "MSI DIGIVOX Micro HD", NULL) },
        { DVB_USB_DEVICE(USB_VID_COMPRO, 0x0620,
                &rtl2832u_props, "Compro VideoMate U620F", NULL) },
        { DVB_USB_DEVICE(USB_VID_KWORLD_2, 0xd394,
                &rtl2832u_props, "MaxMedia HU394-T", NULL) },
+       { DVB_USB_DEVICE(USB_VID_LEADTEK, 0x6a03,
+               &rtl2832u_props, "Leadtek WinFast DTV Dongle mini", NULL) },
+       { DVB_USB_DEVICE(USB_VID_GTEK, USB_PID_CPYTO_REDI_PC50A,
+               &rtl2832u_props, "Crypto ReDi PC 50 A", NULL) },
        { }
 };
 MODULE_DEVICE_TABLE(usb, rtl28xxu_id_table);
index 533a331..729b354 100644 (file)
@@ -97,6 +97,12 @@ struct rtl28xxu_reg_val {
        u8 val;
 };
 
+struct rtl28xxu_reg_val_mask {
+       u16 reg;
+       u8 val;
+       u8 mask;
+};
+
 /*
  * memory map
  *
index 91e0119..ea2d5ee 100644 (file)
@@ -264,7 +264,7 @@ struct stb0899_config az6027_stb0899_config = {
        .demod_address          = 0xd0, /* 0x68, 0xd0 >> 1 */
 
        .xtal_freq              = 27000000,
-       .inversion              = IQ_SWAP_ON, /* 1 */
+       .inversion              = IQ_SWAP_ON,
 
        .lo_clk                 = 76500000,
        .hi_clk                 = 99000000,
index d1ddfa1..449a996 100644 (file)
@@ -828,7 +828,7 @@ static struct stb0899_config stb0899_config = {
        .block_sync_mode = STB0899_SYNC_FORCED, /* ? */
 
        .xtal_freq       = 27000000,     /* Assume Hz ? */
-       .inversion       = IQ_SWAP_ON,       /* ? */
+       .inversion       = IQ_SWAP_ON,
 
        .lo_clk   = 76500000,
        .hi_clk   = 99000000,
index 83bfbe4..dc65742 100644 (file)
@@ -37,7 +37,6 @@
 #include <media/i2c-addr.h>
 #include <media/tveeprom.h>
 #include <media/v4l2-common.h>
-#include <media/v4l2-chip-ident.h>
 
 #include "em28xx.h"
 
@@ -83,26 +82,26 @@ static void em28xx_pre_card_setup(struct em28xx *dev);
 
 /* Reset for the most [analog] boards */
 static struct em28xx_reg_seq default_analog[] = {
-       {EM28XX_R08_GPIO,       0x6d,   ~EM_GPIO_4,     10},
+       {EM2820_R08_GPIO_CTRL,  0x6d,   ~EM_GPIO_4,     10},
        {       -1,             -1,     -1,             -1},
 };
 
 /* Reset for the most [digital] boards */
 static struct em28xx_reg_seq default_digital[] = {
-       {EM28XX_R08_GPIO,       0x6e,   ~EM_GPIO_4,     10},
+       {EM2820_R08_GPIO_CTRL,  0x6e,   ~EM_GPIO_4,     10},
        {       -1,             -1,     -1,             -1},
 };
 
 /* Board Hauppauge WinTV HVR 900 analog */
 static struct em28xx_reg_seq hauppauge_wintv_hvr_900_analog[] = {
-       {EM28XX_R08_GPIO,       0x2d,   ~EM_GPIO_4,     10},
+       {EM2820_R08_GPIO_CTRL,  0x2d,   ~EM_GPIO_4,     10},
        {0x05,                  0xff,   0x10,           10},
        {  -1,                  -1,     -1,             -1},
 };
 
 /* Board Hauppauge WinTV HVR 900 digital */
 static struct em28xx_reg_seq hauppauge_wintv_hvr_900_digital[] = {
-       {EM28XX_R08_GPIO,       0x2e,   ~EM_GPIO_4,     10},
+       {EM2820_R08_GPIO_CTRL,  0x2e,   ~EM_GPIO_4,     10},
        {EM2880_R04_GPO,        0x04,   0x0f,           10},
        {EM2880_R04_GPO,        0x0c,   0x0f,           10},
        { -1,                   -1,     -1,             -1},
@@ -110,14 +109,14 @@ static struct em28xx_reg_seq hauppauge_wintv_hvr_900_digital[] = {
 
 /* Board Hauppauge WinTV HVR 900 (R2) digital */
 static struct em28xx_reg_seq hauppauge_wintv_hvr_900R2_digital[] = {
-       {EM28XX_R08_GPIO,       0x2e,   ~EM_GPIO_4,     10},
+       {EM2820_R08_GPIO_CTRL,  0x2e,   ~EM_GPIO_4,     10},
        {EM2880_R04_GPO,        0x0c,   0x0f,           10},
        { -1,                   -1,     -1,             -1},
 };
 
 /* Boards - EM2880 MSI DIGIVOX AD and EM2880_BOARD_MSI_DIGIVOX_AD_II */
 static struct em28xx_reg_seq em2880_msi_digivox_ad_analog[] = {
-       {EM28XX_R08_GPIO,       0x69,   ~EM_GPIO_4,      10},
+       {EM2820_R08_GPIO_CTRL,       0x69,   ~EM_GPIO_4,         10},
        {       -1,             -1,     -1,              -1},
 };
 
@@ -128,11 +127,11 @@ static struct em28xx_reg_seq em2880_msi_digivox_ad_analog[] = {
 
 /* Board - EM2882 Kworld 315U digital */
 static struct em28xx_reg_seq em2882_kworld_315u_digital[] = {
-       {EM28XX_R08_GPIO,       0xff,   0xff,           10},
-       {EM28XX_R08_GPIO,       0xfe,   0xff,           10},
+       {EM2820_R08_GPIO_CTRL,  0xff,   0xff,           10},
+       {EM2820_R08_GPIO_CTRL,  0xfe,   0xff,           10},
        {EM2880_R04_GPO,        0x04,   0xff,           10},
        {EM2880_R04_GPO,        0x0c,   0xff,           10},
-       {EM28XX_R08_GPIO,       0x7e,   0xff,           10},
+       {EM2820_R08_GPIO_CTRL,  0x7e,   0xff,           10},
        {  -1,                  -1,     -1,             -1},
 };
 
@@ -145,13 +144,13 @@ static struct em28xx_reg_seq em2882_kworld_315u_tuner_gpio[] = {
 };
 
 static struct em28xx_reg_seq kworld_330u_analog[] = {
-       {EM28XX_R08_GPIO,       0x6d,   ~EM_GPIO_4,     10},
+       {EM2820_R08_GPIO_CTRL,  0x6d,   ~EM_GPIO_4,     10},
        {EM2880_R04_GPO,        0x00,   0xff,           10},
        { -1,                   -1,     -1,             -1},
 };
 
 static struct em28xx_reg_seq kworld_330u_digital[] = {
-       {EM28XX_R08_GPIO,       0x6e,   ~EM_GPIO_4,     10},
+       {EM2820_R08_GPIO_CTRL,  0x6e,   ~EM_GPIO_4,     10},
        {EM2880_R04_GPO,        0x08,   0xff,           10},
        { -1,                   -1,     -1,             -1},
 };
@@ -163,12 +162,12 @@ static struct em28xx_reg_seq kworld_330u_digital[] = {
    GOP3  - s5h1409 reset
  */
 static struct em28xx_reg_seq evga_indtube_analog[] = {
-       {EM28XX_R08_GPIO,       0x79,   0xff,           60},
+       {EM2820_R08_GPIO_CTRL,  0x79,   0xff,           60},
        {       -1,             -1,     -1,             -1},
 };
 
 static struct em28xx_reg_seq evga_indtube_digital[] = {
-       {EM28XX_R08_GPIO,       0x7a,   0xff,            1},
+       {EM2820_R08_GPIO_CTRL,  0x7a,   0xff,            1},
        {EM2880_R04_GPO,        0x04,   0xff,           10},
        {EM2880_R04_GPO,        0x0c,   0xff,            1},
        { -1,                   -1,     -1,             -1},
@@ -186,31 +185,31 @@ static struct em28xx_reg_seq evga_indtube_digital[] = {
  * EM_GPIO_7 - currently unknown
  */
 static struct em28xx_reg_seq kworld_a340_digital[] = {
-       {EM28XX_R08_GPIO,       0x6d,           ~EM_GPIO_4,     10},
+       {EM2820_R08_GPIO_CTRL,  0x6d,           ~EM_GPIO_4,     10},
        { -1,                   -1,             -1,             -1},
 };
 
 /* Pinnacle Hybrid Pro eb1a:2881 */
 static struct em28xx_reg_seq pinnacle_hybrid_pro_analog[] = {
-       {EM28XX_R08_GPIO,       0xfd,   ~EM_GPIO_4,     10},
+       {EM2820_R08_GPIO_CTRL,  0xfd,   ~EM_GPIO_4,     10},
        {       -1,             -1,     -1,             -1},
 };
 
 static struct em28xx_reg_seq pinnacle_hybrid_pro_digital[] = {
-       {EM28XX_R08_GPIO,       0x6e,   ~EM_GPIO_4,     10},
+       {EM2820_R08_GPIO_CTRL,  0x6e,   ~EM_GPIO_4,     10},
        {EM2880_R04_GPO,        0x04,   0xff,          100},/* zl10353 reset */
        {EM2880_R04_GPO,        0x0c,   0xff,            1},
        {       -1,             -1,     -1,             -1},
 };
 
 static struct em28xx_reg_seq terratec_cinergy_USB_XS_FR_analog[] = {
-       {EM28XX_R08_GPIO,       0x6d,   ~EM_GPIO_4,     10},
+       {EM2820_R08_GPIO_CTRL,  0x6d,   ~EM_GPIO_4,     10},
        {EM2880_R04_GPO,        0x00,   0xff,           10},
        { -1,                   -1,     -1,             -1},
 };
 
 static struct em28xx_reg_seq terratec_cinergy_USB_XS_FR_digital[] = {
-       {EM28XX_R08_GPIO,       0x6e,   ~EM_GPIO_4,     10},
+       {EM2820_R08_GPIO_CTRL,  0x6e,   ~EM_GPIO_4,     10},
        {EM2880_R04_GPO,        0x08,   0xff,           10},
        { -1,                   -1,     -1,             -1},
 };
@@ -219,66 +218,66 @@ static struct em28xx_reg_seq terratec_cinergy_USB_XS_FR_digital[] = {
    GPIO4 - CU1216L NIM
    Other GPIOs seems to be don't care. */
 static struct em28xx_reg_seq reddo_dvb_c_usb_box[] = {
-       {EM28XX_R08_GPIO,       0xfe,   0xff,           10},
-       {EM28XX_R08_GPIO,       0xde,   0xff,           10},
-       {EM28XX_R08_GPIO,       0xfe,   0xff,           10},
-       {EM28XX_R08_GPIO,       0xff,   0xff,           10},
-       {EM28XX_R08_GPIO,       0x7f,   0xff,           10},
-       {EM28XX_R08_GPIO,       0x6f,   0xff,           10},
-       {EM28XX_R08_GPIO,       0xff,   0xff,           10},
+       {EM2820_R08_GPIO_CTRL,  0xfe,   0xff,           10},
+       {EM2820_R08_GPIO_CTRL,  0xde,   0xff,           10},
+       {EM2820_R08_GPIO_CTRL,  0xfe,   0xff,           10},
+       {EM2820_R08_GPIO_CTRL,  0xff,   0xff,           10},
+       {EM2820_R08_GPIO_CTRL,  0x7f,   0xff,           10},
+       {EM2820_R08_GPIO_CTRL,  0x6f,   0xff,           10},
+       {EM2820_R08_GPIO_CTRL,  0xff,   0xff,           10},
        {-1,                    -1,     -1,             -1},
 };
 
 /* Callback for the most boards */
 static struct em28xx_reg_seq default_tuner_gpio[] = {
-       {EM28XX_R08_GPIO,       EM_GPIO_4,      EM_GPIO_4,      10},
-       {EM28XX_R08_GPIO,       0,              EM_GPIO_4,      10},
-       {EM28XX_R08_GPIO,       EM_GPIO_4,      EM_GPIO_4,      10},
+       {EM2820_R08_GPIO_CTRL,  EM_GPIO_4,      EM_GPIO_4,      10},
+       {EM2820_R08_GPIO_CTRL,  0,              EM_GPIO_4,      10},
+       {EM2820_R08_GPIO_CTRL,  EM_GPIO_4,      EM_GPIO_4,      10},
        {  -1,                  -1,             -1,             -1},
 };
 
 /* Mute/unmute */
 static struct em28xx_reg_seq compro_unmute_tv_gpio[] = {
-       {EM28XX_R08_GPIO,       5,              7,              10},
+       {EM2820_R08_GPIO_CTRL,  5,              7,              10},
        {  -1,                  -1,             -1,             -1},
 };
 
 static struct em28xx_reg_seq compro_unmute_svid_gpio[] = {
-       {EM28XX_R08_GPIO,       4,              7,              10},
+       {EM2820_R08_GPIO_CTRL,  4,              7,              10},
        {  -1,                  -1,             -1,             -1},
 };
 
 static struct em28xx_reg_seq compro_mute_gpio[] = {
-       {EM28XX_R08_GPIO,       6,              7,              10},
+       {EM2820_R08_GPIO_CTRL,  6,              7,              10},
        {  -1,                  -1,             -1,             -1},
 };
 
 /* Terratec AV350 */
 static struct em28xx_reg_seq terratec_av350_mute_gpio[] = {
-       {EM28XX_R08_GPIO,       0xff,   0x7f,           10},
+       {EM2820_R08_GPIO_CTRL,  0xff,   0x7f,           10},
        {       -1,             -1,     -1,             -1},
 };
 
 static struct em28xx_reg_seq terratec_av350_unmute_gpio[] = {
-       {EM28XX_R08_GPIO,       0xff,   0xff,           10},
+       {EM2820_R08_GPIO_CTRL,  0xff,   0xff,           10},
        {       -1,             -1,     -1,             -1},
 };
 
 static struct em28xx_reg_seq silvercrest_reg_seq[] = {
-       {EM28XX_R08_GPIO,       0xff,   0xff,           10},
-       {EM28XX_R08_GPIO,       0x01,   0xf7,           10},
+       {EM2820_R08_GPIO_CTRL,  0xff,   0xff,           10},
+       {EM2820_R08_GPIO_CTRL,  0x01,   0xf7,           10},
        {       -1,             -1,     -1,             -1},
 };
 
 static struct em28xx_reg_seq vc211a_enable[] = {
-       {EM28XX_R08_GPIO,       0xff,   0x07,           10},
-       {EM28XX_R08_GPIO,       0xff,   0x0f,           10},
-       {EM28XX_R08_GPIO,       0xff,   0x0b,           10},
+       {EM2820_R08_GPIO_CTRL,  0xff,   0x07,           10},
+       {EM2820_R08_GPIO_CTRL,  0xff,   0x0f,           10},
+       {EM2820_R08_GPIO_CTRL,  0xff,   0x0b,           10},
        {       -1,             -1,     -1,             -1},
 };
 
 static struct em28xx_reg_seq dikom_dk300_digital[] = {
-       {EM28XX_R08_GPIO,       0x6e,   ~EM_GPIO_4,     10},
+       {EM2820_R08_GPIO_CTRL,  0x6e,   ~EM_GPIO_4,     10},
        {EM2880_R04_GPO,        0x08,   0xff,           10},
        { -1,                   -1,     -1,             -1},
 };
@@ -286,14 +285,14 @@ static struct em28xx_reg_seq dikom_dk300_digital[] = {
 
 /* Reset for the most [digital] boards */
 static struct em28xx_reg_seq leadership_digital[] = {
-       {EM2874_R80_GPIO,       0x70,   0xff,   10},
+       {EM2874_R80_GPIO_P0_CTRL,       0x70,   0xff,   10},
        {       -1,             -1,     -1,     -1},
 };
 
 static struct em28xx_reg_seq leadership_reset[] = {
-       {EM2874_R80_GPIO,       0xf0,   0xff,   10},
-       {EM2874_R80_GPIO,       0xb0,   0xff,   10},
-       {EM2874_R80_GPIO,       0xf0,   0xff,   10},
+       {EM2874_R80_GPIO_P0_CTRL,       0xf0,   0xff,   10},
+       {EM2874_R80_GPIO_P0_CTRL,       0xb0,   0xff,   10},
+       {EM2874_R80_GPIO_P0_CTRL,       0xf0,   0xff,   10},
        {       -1,             -1,     -1,     -1},
 };
 
@@ -302,25 +301,25 @@ static struct em28xx_reg_seq leadership_reset[] = {
  * GPIO_7 - LED
  */
 static struct em28xx_reg_seq pctv_290e[] = {
-       {EM2874_R80_GPIO,       0x00,   0xff,           80},
-       {EM2874_R80_GPIO,       0x40,   0xff,           80}, /* GPIO_6 = 1 */
-       {EM2874_R80_GPIO,       0xc0,   0xff,           80}, /* GPIO_7 = 1 */
+       {EM2874_R80_GPIO_P0_CTRL,       0x00,   0xff,   80},
+       {EM2874_R80_GPIO_P0_CTRL,       0x40,   0xff,   80}, /* GPIO_6 = 1 */
+       {EM2874_R80_GPIO_P0_CTRL,       0xc0,   0xff,   80}, /* GPIO_7 = 1 */
        {-1,                    -1,     -1,             -1},
 };
 
 #if 0
 static struct em28xx_reg_seq terratec_h5_gpio[] = {
-       {EM28XX_R08_GPIO,       0xff,   0xff,   10},
-       {EM2874_R80_GPIO,       0xf6,   0xff,   100},
-       {EM2874_R80_GPIO,       0xf2,   0xff,   50},
-       {EM2874_R80_GPIO,       0xf6,   0xff,   50},
+       {EM2820_R08_GPIO_CTRL,          0xff,   0xff,   10},
+       {EM2874_R80_GPIO_P0_CTRL,       0xf6,   0xff,   100},
+       {EM2874_R80_GPIO_P0_CTRL,       0xf2,   0xff,   50},
+       {EM2874_R80_GPIO_P0_CTRL,       0xf6,   0xff,   50},
        { -1,                   -1,     -1,     -1},
 };
 
 static struct em28xx_reg_seq terratec_h5_digital[] = {
-       {EM2874_R80_GPIO,       0xf6,   0xff,   10},
-       {EM2874_R80_GPIO,       0xe6,   0xff,   100},
-       {EM2874_R80_GPIO,       0xa6,   0xff,   10},
+       {EM2874_R80_GPIO_P0_CTRL,       0xf6,   0xff,   10},
+       {EM2874_R80_GPIO_P0_CTRL,       0xe6,   0xff,   100},
+       {EM2874_R80_GPIO_P0_CTRL,       0xa6,   0xff,   10},
        { -1,                   -1,     -1,     -1},
 };
 #endif
@@ -336,51 +335,52 @@ static struct em28xx_reg_seq terratec_h5_digital[] = {
  * GPIO_7 - LED (green LED)
  */
 static struct em28xx_reg_seq pctv_460e[] = {
-       {EM2874_R80_GPIO, 0x01, 0xff,  50},
+       {EM2874_R80_GPIO_P0_CTRL, 0x01, 0xff,  50},
        {0x0d,            0xff, 0xff,  50},
-       {EM2874_R80_GPIO, 0x41, 0xff,  50}, /* GPIO_6=1 */
+       {EM2874_R80_GPIO_P0_CTRL, 0x41, 0xff,  50}, /* GPIO_6=1 */
        {0x0d,            0x42, 0xff,  50},
-       {EM2874_R80_GPIO, 0x61, 0xff,  50}, /* GPIO_5=1 */
+       {EM2874_R80_GPIO_P0_CTRL, 0x61, 0xff,  50}, /* GPIO_5=1 */
        {             -1,   -1,   -1,  -1},
 };
 
 static struct em28xx_reg_seq c3tech_digital_duo_digital[] = {
-       {EM2874_R80_GPIO,       0xff,   0xff,   10},
-       {EM2874_R80_GPIO,       0xfd,   0xff,   10}, /* xc5000 reset */
-       {EM2874_R80_GPIO,       0xf9,   0xff,   35},
-       {EM2874_R80_GPIO,       0xfd,   0xff,   10},
-       {EM2874_R80_GPIO,       0xff,   0xff,   10},
-       {EM2874_R80_GPIO,       0xfe,   0xff,   10},
-       {EM2874_R80_GPIO,       0xbe,   0xff,   10},
-       {EM2874_R80_GPIO,       0xfe,   0xff,   20},
+       {EM2874_R80_GPIO_P0_CTRL,       0xff,   0xff,   10},
+       {EM2874_R80_GPIO_P0_CTRL,       0xfd,   0xff,   10}, /* xc5000 reset */
+       {EM2874_R80_GPIO_P0_CTRL,       0xf9,   0xff,   35},
+       {EM2874_R80_GPIO_P0_CTRL,       0xfd,   0xff,   10},
+       {EM2874_R80_GPIO_P0_CTRL,       0xff,   0xff,   10},
+       {EM2874_R80_GPIO_P0_CTRL,       0xfe,   0xff,   10},
+       {EM2874_R80_GPIO_P0_CTRL,       0xbe,   0xff,   10},
+       {EM2874_R80_GPIO_P0_CTRL,       0xfe,   0xff,   20},
        { -1,                   -1,     -1,     -1},
 };
 
 #if 0
 static struct em28xx_reg_seq hauppauge_930c_gpio[] = {
-       {EM2874_R80_GPIO,       0x6f,   0xff,   10},
-       {EM2874_R80_GPIO,       0x4f,   0xff,   10}, /* xc5000 reset */
-       {EM2874_R80_GPIO,       0x6f,   0xff,   10},
-       {EM2874_R80_GPIO,       0x4f,   0xff,   10},
+       {EM2874_R80_GPIO_P0_CTRL,       0x6f,   0xff,   10},
+       {EM2874_R80_GPIO_P0_CTRL,       0x4f,   0xff,   10}, /* xc5000 reset */
+       {EM2874_R80_GPIO_P0_CTRL,       0x6f,   0xff,   10},
+       {EM2874_R80_GPIO_P0_CTRL,       0x4f,   0xff,   10},
        { -1,                   -1,     -1,     -1},
 };
 
 static struct em28xx_reg_seq hauppauge_930c_digital[] = {
-       {EM2874_R80_GPIO,       0xf6,   0xff,   10},
-       {EM2874_R80_GPIO,       0xe6,   0xff,   100},
-       {EM2874_R80_GPIO,       0xa6,   0xff,   10},
+       {EM2874_R80_GPIO_P0_CTRL,       0xf6,   0xff,   10},
+       {EM2874_R80_GPIO_P0_CTRL,       0xe6,   0xff,   100},
+       {EM2874_R80_GPIO_P0_CTRL,       0xa6,   0xff,   10},
        { -1,                   -1,     -1,     -1},
 };
 #endif
 
 /* 1b80:e425 MaxMedia UB425-TC
+ * 1b80:e1cc Delock 61959
  * GPIO_6 - demod reset, 0=active
  * GPIO_7 - LED, 0=active
  */
 static struct em28xx_reg_seq maxmedia_ub425_tc[] = {
-       {EM2874_R80_GPIO,  0x83,  0xff,  100},
-       {EM2874_R80_GPIO,  0xc3,  0xff,  100}, /* GPIO_6 = 1 */
-       {EM2874_R80_GPIO,  0x43,  0xff,  000}, /* GPIO_7 = 0 */
+       {EM2874_R80_GPIO_P0_CTRL,  0x83,  0xff,  100},
+       {EM2874_R80_GPIO_P0_CTRL,  0xc3,  0xff,  100}, /* GPIO_6 = 1 */
+       {EM2874_R80_GPIO_P0_CTRL,  0x43,  0xff,  000}, /* GPIO_7 = 0 */
        {-1,                 -1,    -1,   -1},
 };
 
@@ -391,9 +391,9 @@ static struct em28xx_reg_seq maxmedia_ub425_tc[] = {
  * GPIO_7: LED, 1=active
  */
 static struct em28xx_reg_seq pctv_510e[] = {
-       {EM2874_R80_GPIO, 0x10, 0xff, 100},
-       {EM2874_R80_GPIO, 0x14, 0xff, 100}, /* GPIO_2 = 1 */
-       {EM2874_R80_GPIO, 0x54, 0xff, 050}, /* GPIO_6 = 1 */
+       {EM2874_R80_GPIO_P0_CTRL, 0x10, 0xff, 100},
+       {EM2874_R80_GPIO_P0_CTRL, 0x14, 0xff, 100}, /* GPIO_2 = 1 */
+       {EM2874_R80_GPIO_P0_CTRL, 0x54, 0xff, 050}, /* GPIO_6 = 1 */
        {             -1,   -1,   -1,  -1},
 };
 
@@ -404,10 +404,10 @@ static struct em28xx_reg_seq pctv_510e[] = {
  * GPIO_7: LED, 1=active
  */
 static struct em28xx_reg_seq pctv_520e[] = {
-       {EM2874_R80_GPIO, 0x10, 0xff, 100},
-       {EM2874_R80_GPIO, 0x14, 0xff, 100}, /* GPIO_2 = 1 */
-       {EM2874_R80_GPIO, 0x54, 0xff, 050}, /* GPIO_6 = 1 */
-       {EM2874_R80_GPIO, 0xd4, 0xff, 000}, /* GPIO_7 = 1 */
+       {EM2874_R80_GPIO_P0_CTRL, 0x10, 0xff, 100},
+       {EM2874_R80_GPIO_P0_CTRL, 0x14, 0xff, 100}, /* GPIO_2 = 1 */
+       {EM2874_R80_GPIO_P0_CTRL, 0x54, 0xff, 050}, /* GPIO_6 = 1 */
+       {EM2874_R80_GPIO_P0_CTRL, 0xd4, 0xff, 000}, /* GPIO_7 = 1 */
        {             -1,   -1,   -1,  -1},
 };
 
@@ -2017,6 +2017,19 @@ struct em28xx_board em28xx_boards[] = {
                .i2c_speed    = EM28XX_I2C_CLK_WAIT_ENABLE |
                                EM28XX_I2C_FREQ_400_KHZ,
        },
+       /* 1b80:e1cc Delock 61959
+        * Empia EM2874B + Micronas DRX 3913KA2 + NXP TDA18271HDC2
+         * mostly the same as MaxMedia UB-425-TC but different remote */
+       [EM2874_BOARD_DELOCK_61959] = {
+               .name          = "Delock 61959",
+               .tuner_type    = TUNER_ABSENT,
+               .tuner_gpio    = maxmedia_ub425_tc,
+               .has_dvb       = 1,
+               .ir_codes      = RC_MAP_DELOCK_61959,
+               .def_i2c_bus   = 1,
+               .i2c_speed     = EM28XX_I2C_CLK_WAIT_ENABLE |
+                               EM28XX_I2C_FREQ_400_KHZ,
+       },
 };
 const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards);
 
@@ -2178,6 +2191,8 @@ struct usb_device_id em28xx_id_table[] = {
                        .driver_info = EM2884_BOARD_PCTV_510E },
        { USB_DEVICE(0x2013, 0x0251),
                        .driver_info = EM2884_BOARD_PCTV_520E },
+       { USB_DEVICE(0x1b80, 0xe1cc),
+                       .driver_info = EM2874_BOARD_DELOCK_61959 },
        { },
 };
 MODULE_DEVICE_TABLE(usb, em28xx_id_table);
@@ -2284,9 +2299,9 @@ static void em28xx_pre_card_setup(struct em28xx *dev)
                break;
        case EM2861_BOARD_KWORLD_PVRTV_300U:
        case EM2880_BOARD_KWORLD_DVB_305U:
-               em28xx_write_reg(dev, EM28XX_R08_GPIO, 0x6d);
+               em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0x6d);
                msleep(10);
-               em28xx_write_reg(dev, EM28XX_R08_GPIO, 0x7d);
+               em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0x7d);
                msleep(10);
                break;
        case EM2870_BOARD_COMPRO_VIDEOMATE:
@@ -2296,45 +2311,45 @@ static void em28xx_pre_card_setup(struct em28xx *dev)
                msleep(10);
                em28xx_write_reg(dev, EM2880_R04_GPO, 0x01);
                msleep(10);
-               em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfd);
+               em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xfd);
                mdelay(70);
-               em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfc);
+               em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xfc);
                mdelay(70);
-               em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xdc);
+               em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xdc);
                mdelay(70);
-               em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfc);
+               em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xfc);
                mdelay(70);
                break;
        case EM2870_BOARD_TERRATEC_XS_MT2060:
                /* this device needs some gpio writes to get the DVB-T
                   demod work */
-               em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfe);
+               em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xfe);
                mdelay(70);
-               em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xde);
+               em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xde);
                mdelay(70);
-               em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfe);
+               em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xfe);
                mdelay(70);
                break;
        case EM2870_BOARD_PINNACLE_PCTV_DVB:
                /* this device needs some gpio writes to get the
                   DVB-T demod work */
-               em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfe);
+               em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xfe);
                mdelay(70);
-               em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xde);
+               em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xde);
                mdelay(70);
-               em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfe);
+               em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xfe);
                mdelay(70);
                break;
        case EM2820_BOARD_GADMEI_UTV310:
        case EM2820_BOARD_MSI_VOX_USB_2:
                /* enables audio for that devices */
-               em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfd);
+               em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xfd);
                break;
 
        case EM2882_BOARD_KWORLD_ATSC_315U:
-               em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xff);
+               em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xff);
                msleep(10);
-               em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfe);
+               em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xfe);
                msleep(10);
                em28xx_write_reg(dev, EM2880_R04_GPO, 0x00);
                msleep(10);
@@ -2360,13 +2375,13 @@ static void em28xx_pre_card_setup(struct em28xx *dev)
                break;
 
        case EM2820_BOARD_IODATA_GVMVP_SZ:
-               em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xff);
+               em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xff);
                msleep(70);
-               em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xf7);
+               em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xf7);
                msleep(10);
-               em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfe);
+               em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xfe);
                msleep(70);
-               em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfd);
+               em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xfd);
                msleep(70);
                break;
        }
@@ -2653,7 +2668,7 @@ static void em28xx_card_setup(struct em28xx *dev)
 
                dev->tuner_type = tv.tuner_type;
 
-               if (tv.audio_processor == V4L2_IDENT_MSPX4XX) {
+               if (tv.audio_processor == TVEEPROM_AUDPROC_MSP) {
                        dev->i2s_speed = 2048000;
                        dev->board.has_msp34xx = 1;
                }
@@ -2662,12 +2677,12 @@ static void em28xx_card_setup(struct em28xx *dev)
        case EM2882_BOARD_KWORLD_ATSC_315U:
                em28xx_write_reg(dev, 0x0d, 0x42);
                msleep(10);
-               em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfd);
+               em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xfd);
                msleep(10);
                break;
        case EM2820_BOARD_KWORLD_PVRTV2800RF:
                /* GPIO enables sound on KWORLD PVR TV 2800RF */
-               em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xf9);
+               em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xf9);
                break;
        case EM2820_BOARD_UNKNOWN:
        case EM2800_BOARD_UNKNOWN:
@@ -2881,10 +2896,6 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
 
        em28xx_set_model(dev);
 
-       /* Set the default GPO/GPIO for legacy devices */
-       dev->reg_gpo_num = EM2880_R04_GPO;
-       dev->reg_gpio_num = EM28XX_R08_GPIO;
-
        dev->wait_after_write = 5;
 
        /* Based on the Chip ID, set the device configuration */
@@ -2932,13 +2943,11 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
                        break;
                case CHIP_ID_EM2874:
                        chip_name = "em2874";
-                       dev->reg_gpio_num = EM2874_R80_GPIO;
                        dev->wait_after_write = 0;
                        dev->eeprom_addrwidth_16bit = 1;
                        break;
                case CHIP_ID_EM28174:
                        chip_name = "em28174";
-                       dev->reg_gpio_num = EM2874_R80_GPIO;
                        dev->wait_after_write = 0;
                        dev->eeprom_addrwidth_16bit = 1;
                        break;
@@ -2948,7 +2957,6 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
                        break;
                case CHIP_ID_EM2884:
                        chip_name = "em2884";
-                       dev->reg_gpio_num = EM2874_R80_GPIO;
                        dev->wait_after_write = 0;
                        dev->eeprom_addrwidth_16bit = 1;
                        break;
@@ -2977,11 +2985,6 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
                return 0;
        }
 
-       /* Prepopulate cached GPO register content */
-       retval = em28xx_read_reg(dev, dev->reg_gpo_num);
-       if (retval >= 0)
-               dev->reg_gpo = retval;
-
        em28xx_pre_card_setup(dev);
 
        if (!dev->board.is_em2800) {
@@ -3071,7 +3074,7 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
 
        if (dev->board.has_msp34xx) {
                /* Send a reset to other chips via gpio */
-               retval = em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xf7);
+               retval = em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xf7);
                if (retval < 0) {
                        em28xx_errdev("%s: em28xx_write_reg - "
                                      "msp34xx(1) failed! error [%d]\n",
@@ -3080,7 +3083,7 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
                }
                msleep(3);
 
-               retval = em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xff);
+               retval = em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xff);
                if (retval < 0) {
                        em28xx_errdev("%s: em28xx_write_reg - "
                                      "msp34xx(2) failed! error [%d]\n",
index a802128..fc157af 100644 (file)
@@ -193,23 +193,7 @@ int em28xx_write_regs_req(struct em28xx *dev, u8 req, u16 reg, char *buf,
 
 int em28xx_write_regs(struct em28xx *dev, u16 reg, char *buf, int len)
 {
-       int rc;
-
-       rc = em28xx_write_regs_req(dev, USB_REQ_GET_STATUS, reg, buf, len);
-
-       /* Stores GPO/GPIO values at the cache, if changed
-          Only write values should be stored, since input on a GPIO
-          register will return the input bits.
-          Not sure what happens on reading GPO register.
-        */
-       if (rc >= 0) {
-               if (reg == dev->reg_gpo_num)
-                       dev->reg_gpo = buf[0];
-               else if (reg == dev->reg_gpio_num)
-                       dev->reg_gpio = buf[0];
-       }
-
-       return rc;
+       return em28xx_write_regs_req(dev, USB_REQ_GET_STATUS, reg, buf, len);
 }
 EXPORT_SYMBOL_GPL(em28xx_write_regs);
 
@@ -231,14 +215,7 @@ int em28xx_write_reg_bits(struct em28xx *dev, u16 reg, u8 val,
        int oldval;
        u8 newval;
 
-       /* Uses cache for gpo/gpio registers */
-       if (reg == dev->reg_gpo_num)
-               oldval = dev->reg_gpo;
-       else if (reg == dev->reg_gpio_num)
-               oldval = dev->reg_gpio;
-       else
-               oldval = em28xx_read_reg(dev, reg);
-
+       oldval = em28xx_read_reg(dev, reg);
        if (oldval < 0)
                return oldval;
 
index b22f8fe..bb1e8dc 100644 (file)
@@ -421,23 +421,23 @@ static void hauppauge_hvr930c_init(struct em28xx *dev)
        int i;
 
        struct em28xx_reg_seq hauppauge_hvr930c_init[] = {
-               {EM2874_R80_GPIO,       0xff,   0xff,   0x65},
-               {EM2874_R80_GPIO,       0xfb,   0xff,   0x32},
-               {EM2874_R80_GPIO,       0xff,   0xff,   0xb8},
+               {EM2874_R80_GPIO_P0_CTRL,       0xff,   0xff,   0x65},
+               {EM2874_R80_GPIO_P0_CTRL,       0xfb,   0xff,   0x32},
+               {EM2874_R80_GPIO_P0_CTRL,       0xff,   0xff,   0xb8},
                { -1,                   -1,     -1,     -1},
        };
        struct em28xx_reg_seq hauppauge_hvr930c_end[] = {
-               {EM2874_R80_GPIO,       0xef,   0xff,   0x01},
-               {EM2874_R80_GPIO,       0xaf,   0xff,   0x65},
-               {EM2874_R80_GPIO,       0xef,   0xff,   0x76},
-               {EM2874_R80_GPIO,       0xef,   0xff,   0x01},
-               {EM2874_R80_GPIO,       0xcf,   0xff,   0x0b},
-               {EM2874_R80_GPIO,       0xef,   0xff,   0x40},
-
-               {EM2874_R80_GPIO,       0xcf,   0xff,   0x65},
-               {EM2874_R80_GPIO,       0xef,   0xff,   0x65},
-               {EM2874_R80_GPIO,       0xcf,   0xff,   0x0b},
-               {EM2874_R80_GPIO,       0xef,   0xff,   0x65},
+               {EM2874_R80_GPIO_P0_CTRL,       0xef,   0xff,   0x01},
+               {EM2874_R80_GPIO_P0_CTRL,       0xaf,   0xff,   0x65},
+               {EM2874_R80_GPIO_P0_CTRL,       0xef,   0xff,   0x76},
+               {EM2874_R80_GPIO_P0_CTRL,       0xef,   0xff,   0x01},
+               {EM2874_R80_GPIO_P0_CTRL,       0xcf,   0xff,   0x0b},
+               {EM2874_R80_GPIO_P0_CTRL,       0xef,   0xff,   0x40},
+
+               {EM2874_R80_GPIO_P0_CTRL,       0xcf,   0xff,   0x65},
+               {EM2874_R80_GPIO_P0_CTRL,       0xef,   0xff,   0x65},
+               {EM2874_R80_GPIO_P0_CTRL,       0xcf,   0xff,   0x0b},
+               {EM2874_R80_GPIO_P0_CTRL,       0xef,   0xff,   0x65},
 
                { -1,                   -1,     -1,     -1},
        };
@@ -487,16 +487,16 @@ static void terratec_h5_init(struct em28xx *dev)
 {
        int i;
        struct em28xx_reg_seq terratec_h5_init[] = {
-               {EM28XX_R08_GPIO,       0xff,   0xff,   10},
-               {EM2874_R80_GPIO,       0xf6,   0xff,   100},
-               {EM2874_R80_GPIO,       0xf2,   0xff,   50},
-               {EM2874_R80_GPIO,       0xf6,   0xff,   100},
+               {EM2820_R08_GPIO_CTRL,          0xff,   0xff,   10},
+               {EM2874_R80_GPIO_P0_CTRL,       0xf6,   0xff,   100},
+               {EM2874_R80_GPIO_P0_CTRL,       0xf2,   0xff,   50},
+               {EM2874_R80_GPIO_P0_CTRL,       0xf6,   0xff,   100},
                { -1,                   -1,     -1,     -1},
        };
        struct em28xx_reg_seq terratec_h5_end[] = {
-               {EM2874_R80_GPIO,       0xe6,   0xff,   100},
-               {EM2874_R80_GPIO,       0xa6,   0xff,   50},
-               {EM2874_R80_GPIO,       0xe6,   0xff,   100},
+               {EM2874_R80_GPIO_P0_CTRL,       0xe6,   0xff,   100},
+               {EM2874_R80_GPIO_P0_CTRL,       0xa6,   0xff,   50},
+               {EM2874_R80_GPIO_P0_CTRL,       0xe6,   0xff,   100},
                { -1,                   -1,     -1,     -1},
        };
        struct {
@@ -543,15 +543,15 @@ static void terratec_htc_stick_init(struct em28xx *dev)
         * 0xb6: unknown (does not affect DVB-T).
         */
        struct em28xx_reg_seq terratec_htc_stick_init[] = {
-               {EM28XX_R08_GPIO,       0xff,   0xff,   10},
-               {EM2874_R80_GPIO,       0xf6,   0xff,   100},
-               {EM2874_R80_GPIO,       0xe6,   0xff,   50},
-               {EM2874_R80_GPIO,       0xf6,   0xff,   100},
+               {EM2820_R08_GPIO_CTRL,          0xff,   0xff,   10},
+               {EM2874_R80_GPIO_P0_CTRL,       0xf6,   0xff,   100},
+               {EM2874_R80_GPIO_P0_CTRL,       0xe6,   0xff,   50},
+               {EM2874_R80_GPIO_P0_CTRL,       0xf6,   0xff,   100},
                { -1,                   -1,     -1,     -1},
        };
        struct em28xx_reg_seq terratec_htc_stick_end[] = {
-               {EM2874_R80_GPIO,       0xb6,   0xff,   100},
-               {EM2874_R80_GPIO,       0xf6,   0xff,   50},
+               {EM2874_R80_GPIO_P0_CTRL,       0xb6,   0xff,   100},
+               {EM2874_R80_GPIO_P0_CTRL,       0xf6,   0xff,   50},
                { -1,                   -1,     -1,     -1},
        };
 
@@ -590,16 +590,16 @@ static void terratec_htc_usb_xs_init(struct em28xx *dev)
        int i;
 
        struct em28xx_reg_seq terratec_htc_usb_xs_init[] = {
-               {EM28XX_R08_GPIO,       0xff,   0xff,   10},
-               {EM2874_R80_GPIO,       0xb2,   0xff,   100},
-               {EM2874_R80_GPIO,       0xb2,   0xff,   50},
-               {EM2874_R80_GPIO,       0xb6,   0xff,   100},
+               {EM2820_R08_GPIO_CTRL,          0xff,   0xff,   10},
+               {EM2874_R80_GPIO_P0_CTRL,       0xb2,   0xff,   100},
+               {EM2874_R80_GPIO_P0_CTRL,       0xb2,   0xff,   50},
+               {EM2874_R80_GPIO_P0_CTRL,       0xb6,   0xff,   100},
                { -1,                   -1,     -1,     -1},
        };
        struct em28xx_reg_seq terratec_htc_usb_xs_end[] = {
-               {EM2874_R80_GPIO,       0xa6,   0xff,   100},
-               {EM2874_R80_GPIO,       0xa6,   0xff,   50},
-               {EM2874_R80_GPIO,       0xe6,   0xff,   100},
+               {EM2874_R80_GPIO_P0_CTRL,       0xa6,   0xff,   100},
+               {EM2874_R80_GPIO_P0_CTRL,       0xa6,   0xff,   50},
+               {EM2874_R80_GPIO_P0_CTRL,       0xe6,   0xff,   100},
                { -1,                   -1,     -1,     -1},
        };
 
@@ -1216,6 +1216,7 @@ static int em28xx_dvb_init(struct em28xx *dev)
                        dvb_attach(a8293_attach, dvb->fe[0], &dev->i2c_adap[dev->def_i2c_bus],
                                &em28xx_a8293_config);
                break;
+       case EM2874_BOARD_DELOCK_61959:
        case EM2874_BOARD_MAXMEDIA_UB425_TC:
                /* attach demodulator */
                dvb->fe[0] = dvb_attach(drxk_attach, &maxmedia_ub425_tc_drxk,
@@ -1235,8 +1236,8 @@ static int em28xx_dvb_init(struct em28xx *dev)
                }
 
                /* TODO: we need drx-3913k firmware in order to support DVB-T */
-               em28xx_info("MaxMedia UB425-TC: only DVB-C supported by that " \
-                               "driver version\n");
+               em28xx_info("MaxMedia UB425-TC/Delock 61959: only DVB-C " \
+                               "supported by that driver version\n");
 
                break;
        case EM2884_BOARD_PCTV_510E:
index 466b19d..ea181e4 100644 (file)
@@ -32,7 +32,6 @@
 
 #define EM28XX_SNAPSHOT_KEY KEY_CAMERA
 #define EM28XX_SBUTTON_QUERY_INTERVAL 500
-#define EM28XX_R0C_USBSUSP_SNAPSHOT 0x20
 
 static unsigned int ir_debug;
 module_param(ir_debug, int, 0644);
index 622871d..0e04778 100644 (file)
@@ -49,8 +49,9 @@
 
 
 /* GPIO/GPO registers */
-#define EM2880_R04_GPO 0x04    /* em2880-em2883 only */
-#define EM28XX_R08_GPIO        0x08    /* em2820 or upper */
+#define EM2880_R04_GPO         0x04    /* em2880-em2883 only */
+#define EM2820_R08_GPIO_CTRL   0x08    /* em2820-em2873/83 only */
+#define EM2820_R09_GPIO_STATE  0x09    /* em2820-em2873/83 only */
 
 #define EM28XX_R06_I2C_CLK     0x06
 
@@ -67,7 +68,8 @@
 
 
 #define EM28XX_R0A_CHIPID      0x0a
-#define EM28XX_R0C_USBSUSP     0x0c    /* */
+#define EM28XX_R0C_USBSUSP     0x0c
+#define   EM28XX_R0C_USBSUSP_SNAPSHOT  0x20 /* 1=button pressed, needs reset */
 
 #define EM28XX_R0E_AUDIOSRC    0x0e
 #define EM28XX_R0F_XCLK        0x0f
 #define EM2874_R50_IR_CONFIG    0x50
 #define EM2874_R51_IR           0x51
 #define EM2874_R5F_TS_ENABLE    0x5f
-#define EM2874_R80_GPIO         0x80
+
+/* em2874/174/84, em25xx, em276x/7x/8x GPIO registers */
+/*
+ * NOTE: not all ports are bonded out;
+ * Some ports are multiplexed with special function I/O
+ */
+#define EM2874_R80_GPIO_P0_CTRL    0x80
+#define EM2874_R81_GPIO_P1_CTRL    0x81
+#define EM2874_R82_GPIO_P2_CTRL    0x82
+#define EM2874_R83_GPIO_P3_CTRL    0x83
+#define EM2874_R84_GPIO_P0_STATE   0x84
+#define EM2874_R85_GPIO_P1_STATE   0x85
+#define EM2874_R86_GPIO_P2_STATE   0x86
+#define EM2874_R87_GPIO_P3_STATE   0x87
 
 /* em2874 IR config register (0x50) */
 #define EM2874_IR_NEC           0x00
index 32d60e5..1a577ed 100644 (file)
@@ -41,7 +41,6 @@
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-event.h>
-#include <media/v4l2-chip-ident.h>
 #include <media/msp3400.h>
 #include <media/tuner.h>
 
@@ -1309,28 +1308,6 @@ static int vidioc_s_frequency(struct file *file, void *priv,
        return 0;
 }
 
-static int vidioc_g_chip_ident(struct file *file, void *priv,
-              struct v4l2_dbg_chip_ident *chip)
-{
-       struct em28xx_fh      *fh  = priv;
-       struct em28xx         *dev = fh->dev;
-
-       chip->ident = V4L2_IDENT_NONE;
-       chip->revision = 0;
-       if (chip->match.type == V4L2_CHIP_MATCH_BRIDGE) {
-               if (chip->match.addr > 1)
-                       return -EINVAL;
-               return 0;
-       }
-       if (chip->match.type != V4L2_CHIP_MATCH_I2C_DRIVER &&
-           chip->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
-               return -EINVAL;
-
-       v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_chip_ident, chip);
-
-       return 0;
-}
-
 #ifdef CONFIG_VIDEO_ADV_DEBUG
 static int vidioc_g_chip_info(struct file *file, void *priv,
               struct v4l2_dbg_chip_info *chip)
@@ -1366,14 +1343,9 @@ static int vidioc_g_register(struct file *file, void *priv,
        struct em28xx         *dev = fh->dev;
        int ret;
 
-       switch (reg->match.type) {
-       case V4L2_CHIP_MATCH_BRIDGE:
-               if (reg->match.addr > 1)
-                       return -EINVAL;
-               if (!reg->match.addr)
-                       break;
-               /* fall-through */
-       case V4L2_CHIP_MATCH_AC97:
+       if (reg->match.addr > 1)
+               return -EINVAL;
+       if (reg->match.addr) {
                ret = em28xx_read_ac97(dev, reg->reg);
                if (ret < 0)
                        return ret;
@@ -1381,15 +1353,6 @@ static int vidioc_g_register(struct file *file, void *priv,
                reg->val = ret;
                reg->size = 1;
                return 0;
-       case V4L2_CHIP_MATCH_I2C_DRIVER:
-               v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_register, reg);
-               return 0;
-       case V4L2_CHIP_MATCH_I2C_ADDR:
-               /* TODO: is this correct? */
-               v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_register, reg);
-               return 0;
-       default:
-               return -EINVAL;
        }
 
        /* Match host */
@@ -1421,25 +1384,10 @@ static int vidioc_s_register(struct file *file, void *priv,
        struct em28xx         *dev = fh->dev;
        __le16 buf;
 
-       switch (reg->match.type) {
-       case V4L2_CHIP_MATCH_BRIDGE:
-               if (reg->match.addr > 1)
-                       return -EINVAL;
-               if (!reg->match.addr)
-                       break;
-               /* fall-through */
-       case V4L2_CHIP_MATCH_AC97:
-               return em28xx_write_ac97(dev, reg->reg, reg->val);
-       case V4L2_CHIP_MATCH_I2C_DRIVER:
-               v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_register, reg);
-               return 0;
-       case V4L2_CHIP_MATCH_I2C_ADDR:
-               /* TODO: is this correct? */
-               v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_register, reg);
-               return 0;
-       default:
+       if (reg->match.addr > 1)
                return -EINVAL;
-       }
+       if (reg->match.addr)
+               return em28xx_write_ac97(dev, reg->reg, reg->val);
 
        /* Match host */
        buf = cpu_to_le16(reg->val);
@@ -1795,7 +1743,6 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
        .vidioc_s_frequency         = vidioc_s_frequency,
        .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
        .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
-       .vidioc_g_chip_ident        = vidioc_g_chip_ident,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
        .vidioc_g_chip_info         = vidioc_g_chip_info,
        .vidioc_g_register          = vidioc_g_register,
@@ -1826,7 +1773,6 @@ static const struct v4l2_ioctl_ops radio_ioctl_ops = {
        .vidioc_s_frequency   = vidioc_s_frequency,
        .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
        .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
-       .vidioc_g_chip_ident  = vidioc_g_chip_ident,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
        .vidioc_g_chip_info   = vidioc_g_chip_info,
        .vidioc_g_register    = vidioc_g_register,
index a9323b6..205e903 100644 (file)
 #define EM2884_BOARD_PCTV_520E                   86
 #define EM2884_BOARD_TERRATEC_HTC_USB_XS         87
 #define EM2884_BOARD_C3TECH_DIGITAL_DUO                  88
+#define EM2874_BOARD_DELOCK_61959                89
 
 /* Limits minimum and default number of buffers */
 #define EM28XX_MIN_BUF 4
@@ -636,12 +637,6 @@ struct em28xx {
 
        enum em28xx_mode mode;
 
-       /* register numbers for GPO/GPIO registers */
-       u16 reg_gpo_num, reg_gpio_num;
-
-       /* Caches GPO and GPIO registers */
-       unsigned char   reg_gpo, reg_gpio;
-
        /* Snapshot button */
        char snapshot_button_path[30];  /* path of the input dev */
        struct input_dev *sbutton_input_dev;
index 5995ec4..b7ae872 100644 (file)
@@ -1029,33 +1029,35 @@ static int gspca_get_mode(struct gspca_dev *gspca_dev,
 }
 
 #ifdef CONFIG_VIDEO_ADV_DEBUG
-static int vidioc_g_register(struct file *file, void *priv,
-                       struct v4l2_dbg_register *reg)
+static int vidioc_g_chip_info(struct file *file, void *priv,
+                               struct v4l2_dbg_chip_info *chip)
 {
        struct gspca_dev *gspca_dev = video_drvdata(file);
 
        gspca_dev->usb_err = 0;
-       return gspca_dev->sd_desc->get_register(gspca_dev, reg);
+       if (gspca_dev->sd_desc->get_chip_info)
+               return gspca_dev->sd_desc->get_chip_info(gspca_dev, chip);
+       return chip->match.addr ? -EINVAL : 0;
 }
 
-static int vidioc_s_register(struct file *file, void *priv,
-                       const struct v4l2_dbg_register *reg)
+static int vidioc_g_register(struct file *file, void *priv,
+               struct v4l2_dbg_register *reg)
 {
        struct gspca_dev *gspca_dev = video_drvdata(file);
 
        gspca_dev->usb_err = 0;
-       return gspca_dev->sd_desc->set_register(gspca_dev, reg);
+       return gspca_dev->sd_desc->get_register(gspca_dev, reg);
 }
-#endif
 
-static int vidioc_g_chip_ident(struct file *file, void *priv,
-                       struct v4l2_dbg_chip_ident *chip)
+static int vidioc_s_register(struct file *file, void *priv,
+               const struct v4l2_dbg_register *reg)
 {
        struct gspca_dev *gspca_dev = video_drvdata(file);
 
        gspca_dev->usb_err = 0;
-       return gspca_dev->sd_desc->get_chip_ident(gspca_dev, chip);
+       return gspca_dev->sd_desc->set_register(gspca_dev, reg);
 }
+#endif
 
 static int vidioc_enum_fmt_vid_cap(struct file *file, void  *priv,
                                struct v4l2_fmtdesc *fmtdesc)
@@ -1974,10 +1976,10 @@ static const struct v4l2_ioctl_ops dev_ioctl_ops = {
        .vidioc_enum_framesizes = vidioc_enum_framesizes,
        .vidioc_enum_frameintervals = vidioc_enum_frameintervals,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
+       .vidioc_g_chip_info     = vidioc_g_chip_info,
        .vidioc_g_register      = vidioc_g_register,
        .vidioc_s_register      = vidioc_s_register,
 #endif
-       .vidioc_g_chip_ident    = vidioc_g_chip_ident,
        .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
        .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
 };
@@ -2086,14 +2088,10 @@ int gspca_dev_probe2(struct usb_interface *intf,
        v4l2_disable_ioctl_locking(&gspca_dev->vdev, VIDIOC_DQBUF);
        v4l2_disable_ioctl_locking(&gspca_dev->vdev, VIDIOC_QBUF);
        v4l2_disable_ioctl_locking(&gspca_dev->vdev, VIDIOC_QUERYBUF);
-       if (!gspca_dev->sd_desc->get_chip_ident)
-               v4l2_disable_ioctl(&gspca_dev->vdev, VIDIOC_DBG_G_CHIP_IDENT);
 #ifdef CONFIG_VIDEO_ADV_DEBUG
-       if (!gspca_dev->sd_desc->get_chip_ident ||
-           !gspca_dev->sd_desc->get_register)
+       if (!gspca_dev->sd_desc->get_register)
                v4l2_disable_ioctl(&gspca_dev->vdev, VIDIOC_DBG_G_REGISTER);
-       if (!gspca_dev->sd_desc->get_chip_ident ||
-           !gspca_dev->sd_desc->set_register)
+       if (!gspca_dev->sd_desc->set_register)
                v4l2_disable_ioctl(&gspca_dev->vdev, VIDIOC_DBG_S_REGISTER);
 #endif
        if (!gspca_dev->sd_desc->get_jcomp)
index ef8efeb..ac0b11f 100644 (file)
@@ -78,8 +78,8 @@ typedef int (*cam_get_reg_op) (struct gspca_dev *,
                                struct v4l2_dbg_register *);
 typedef int (*cam_set_reg_op) (struct gspca_dev *,
                                const struct v4l2_dbg_register *);
-typedef int (*cam_ident_op) (struct gspca_dev *,
-                               struct v4l2_dbg_chip_ident *);
+typedef int (*cam_chip_info_op) (struct gspca_dev *,
+                               struct v4l2_dbg_chip_info *);
 typedef void (*cam_streamparm_op) (struct gspca_dev *,
                                  struct v4l2_streamparm *);
 typedef void (*cam_pkt_op) (struct gspca_dev *gspca_dev,
@@ -112,8 +112,8 @@ struct sd_desc {
 #ifdef CONFIG_VIDEO_ADV_DEBUG
        cam_set_reg_op set_register;
        cam_get_reg_op get_register;
+       cam_chip_info_op get_chip_info;
 #endif
-       cam_ident_op get_chip_ident;
 #if IS_ENABLED(CONFIG_INPUT)
        cam_int_pkt_op int_pkt_scan;
        /* other_input makes the gspca core create gspca_dev->input even when
index 6008c8d..a915096 100644 (file)
@@ -93,7 +93,6 @@
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
 #include <linux/input.h>
-#include <media/v4l2-chip-ident.h>
 #include "gspca.h"
 /* Include pac common sof detection functions */
 #include "pac_common.h"
@@ -849,8 +848,7 @@ static int sd_dbg_s_register(struct gspca_dev *gspca_dev,
         * reg->reg: bit0..15: reserved for register index (wIndex is 16bit
         *                     long on the USB bus)
         */
-       if (reg->match.type == V4L2_CHIP_MATCH_HOST &&
-           reg->match.addr == 0 &&
+       if (reg->match.addr == 0 &&
            (reg->reg < 0x000000ff) &&
            (reg->val <= 0x000000ff)
        ) {
@@ -871,20 +869,6 @@ static int sd_dbg_s_register(struct gspca_dev *gspca_dev,
        }
        return gspca_dev->usb_err;
 }
-
-static int sd_chip_ident(struct gspca_dev *gspca_dev,
-                       struct v4l2_dbg_chip_ident *chip)
-{
-       int ret = -EINVAL;
-
-       if (chip->match.type == V4L2_CHIP_MATCH_HOST &&
-           chip->match.addr == 0) {
-               chip->revision = 0;
-               chip->ident = V4L2_IDENT_UNKNOWN;
-               ret = 0;
-       }
-       return ret;
-}
 #endif
 
 #if IS_ENABLED(CONFIG_INPUT)
@@ -931,7 +915,6 @@ static const struct sd_desc sd_desc = {
        .dq_callback = do_autogain,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
        .set_register = sd_dbg_s_register,
-       .get_chip_ident = sd_chip_ident,
 #endif
 #if IS_ENABLED(CONFIG_INPUT)
        .int_pkt_scan = sd_int_pkt_scan,
index ead9a1f..f4453d5 100644 (file)
@@ -27,7 +27,6 @@
 #include "gspca.h"
 #include "jpeg.h"
 
-#include <media/v4l2-chip-ident.h>
 #include <linux/dmi.h>
 
 MODULE_AUTHOR("Brian Johnson <brijohn@gmail.com>, "
@@ -582,22 +581,6 @@ static const s16 hsv_blue_y[] = {
        4,   2,   0,  -1,  -3,  -5,  -7,  -9, -11
 };
 
-static const u16 i2c_ident[] = {
-       V4L2_IDENT_OV9650,
-       V4L2_IDENT_OV9655,
-       V4L2_IDENT_SOI968,
-       V4L2_IDENT_OV7660,
-       V4L2_IDENT_OV7670,
-       V4L2_IDENT_MT9V011,
-       V4L2_IDENT_MT9V111,
-       V4L2_IDENT_MT9V112,
-       V4L2_IDENT_MT9M001C12ST,
-       V4L2_IDENT_MT9M111,
-       V4L2_IDENT_MT9M112,
-       V4L2_IDENT_HV7131R,
-[SENSOR_MT9VPRB] = V4L2_IDENT_UNKNOWN,
-};
-
 static const u16 bridge_init[][2] = {
        {0x1000, 0x78}, {0x1001, 0x40}, {0x1002, 0x1c},
        {0x1020, 0x80}, {0x1061, 0x01}, {0x1067, 0x40},
@@ -1574,21 +1557,19 @@ static int sd_dbg_g_register(struct gspca_dev *gspca_dev,
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
-       switch (reg->match.type) {
-       case V4L2_CHIP_MATCH_HOST:
-               if (reg->match.addr != 0)
-                       return -EINVAL;
+       reg->size = 1;
+       switch (reg->match.addr) {
+       case 0:
                if (reg->reg < 0x1000 || reg->reg > 0x11ff)
                        return -EINVAL;
                reg_r(gspca_dev, reg->reg, 1);
                reg->val = gspca_dev->usb_buf[0];
                return gspca_dev->usb_err;
-       case V4L2_CHIP_MATCH_I2C_ADDR:
-               if (reg->match.addr != sd->i2c_addr)
-                       return -EINVAL;
+       case 1:
                if (sd->sensor >= SENSOR_MT9V011 &&
                    sd->sensor <= SENSOR_MT9M112) {
                        i2c_r2(gspca_dev, reg->reg, (u16 *) &reg->val);
+                       reg->size = 2;
                } else {
                        i2c_r1(gspca_dev, reg->reg, (u8 *) &reg->val);
                }
@@ -1602,17 +1583,13 @@ static int sd_dbg_s_register(struct gspca_dev *gspca_dev,
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
-       switch (reg->match.type) {
-       case V4L2_CHIP_MATCH_HOST:
-               if (reg->match.addr != 0)
-                       return -EINVAL;
+       switch (reg->match.addr) {
+       case 0:
                if (reg->reg < 0x1000 || reg->reg > 0x11ff)
                        return -EINVAL;
                reg_w1(gspca_dev, reg->reg, reg->val);
                return gspca_dev->usb_err;
-       case V4L2_CHIP_MATCH_I2C_ADDR:
-               if (reg->match.addr != sd->i2c_addr)
-                       return -EINVAL;
+       case 1:
                if (sd->sensor >= SENSOR_MT9V011 &&
                    sd->sensor <= SENSOR_MT9M112) {
                        i2c_w2(gspca_dev, reg->reg, reg->val);
@@ -1623,29 +1600,17 @@ static int sd_dbg_s_register(struct gspca_dev *gspca_dev,
        }
        return -EINVAL;
 }
-#endif
 
-static int sd_chip_ident(struct gspca_dev *gspca_dev,
-                       struct v4l2_dbg_chip_ident *chip)
+static int sd_chip_info(struct gspca_dev *gspca_dev,
+                       struct v4l2_dbg_chip_info *chip)
 {
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       switch (chip->match.type) {
-       case V4L2_CHIP_MATCH_HOST:
-               if (chip->match.addr != 0)
-                       return -EINVAL;
-               chip->revision = 0;
-               chip->ident = V4L2_IDENT_SN9C20X;
-               return 0;
-       case V4L2_CHIP_MATCH_I2C_ADDR:
-               if (chip->match.addr != sd->i2c_addr)
-                       return -EINVAL;
-               chip->revision = 0;
-               chip->ident = i2c_ident[sd->sensor];
-               return 0;
-       }
-       return -EINVAL;
+       if (chip->match.addr > 1)
+               return -EINVAL;
+       if (chip->match.addr == 1)
+               strlcpy(chip->name, "sensor", sizeof(chip->name));
+       return 0;
 }
+#endif
 
 static int sd_config(struct gspca_dev *gspca_dev,
                        const struct usb_device_id *id)
@@ -2356,8 +2321,8 @@ static const struct sd_desc sd_desc = {
 #ifdef CONFIG_VIDEO_ADV_DEBUG
        .set_register = sd_dbg_s_register,
        .get_register = sd_dbg_g_register,
+       .get_chip_info = sd_chip_info,
 #endif
-       .get_chip_ident = sd_chip_ident,
 };
 
 #define SN9C20X(sensor, i2c_addr, flags) \
index de247f3..d73d9a1 100644 (file)
@@ -1,7 +1,7 @@
 
 config VIDEO_HDPVR
        tristate "Hauppauge HD PVR support"
-       depends on VIDEO_DEV
+       depends on VIDEO_DEV && VIDEO_V4L2
        ---help---
          This is a video4linux driver for Hauppauge's HD PVR USB device.
 
index ae8f229..6053661 100644 (file)
@@ -45,20 +45,11 @@ int hdpvr_config_call(struct hdpvr_device *dev, uint value, u8 valbuf)
        return ret < 0 ? ret : 0;
 }
 
-struct hdpvr_video_info *get_video_info(struct hdpvr_device *dev)
+int get_video_info(struct hdpvr_device *dev, struct hdpvr_video_info *vidinf)
 {
-       struct hdpvr_video_info *vidinf = NULL;
-#ifdef HDPVR_DEBUG
-       char print_buf[15];
-#endif
        int ret;
 
-       vidinf = kzalloc(sizeof(struct hdpvr_video_info), GFP_KERNEL);
-       if (!vidinf) {
-               v4l2_err(&dev->v4l2_dev, "out of memory\n");
-               goto err;
-       }
-
+       vidinf->valid = false;
        mutex_lock(&dev->usbc_mutex);
        ret = usb_control_msg(dev->udev,
                              usb_rcvctrlpipe(dev->udev, 0),
@@ -66,14 +57,10 @@ struct hdpvr_video_info *get_video_info(struct hdpvr_device *dev)
                              0x1400, 0x0003,
                              dev->usbc_buf, 5,
                              1000);
-       if (ret == 5) {
-               vidinf->width   = dev->usbc_buf[1] << 8 | dev->usbc_buf[0];
-               vidinf->height  = dev->usbc_buf[3] << 8 | dev->usbc_buf[2];
-               vidinf->fps     = dev->usbc_buf[4];
-       }
 
 #ifdef HDPVR_DEBUG
        if (hdpvr_debug & MSG_INFO) {
+               char print_buf[15];
                hex_dump_to_buffer(dev->usbc_buf, 5, 16, 1, print_buf,
                                   sizeof(print_buf), 0);
                v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
@@ -82,12 +69,15 @@ struct hdpvr_video_info *get_video_info(struct hdpvr_device *dev)
 #endif
        mutex_unlock(&dev->usbc_mutex);
 
-       if (!vidinf->width || !vidinf->height || !vidinf->fps) {
-               kfree(vidinf);
-               vidinf = NULL;
-       }
-err:
-       return vidinf;
+       if (ret < 0)
+               return ret;
+
+       vidinf->width   = dev->usbc_buf[1] << 8 | dev->usbc_buf[0];
+       vidinf->height  = dev->usbc_buf[3] << 8 | dev->usbc_buf[2];
+       vidinf->fps     = dev->usbc_buf[4];
+       vidinf->valid   = vidinf->width && vidinf->height && vidinf->fps;
+
+       return 0;
 }
 
 int get_input_lines_info(struct hdpvr_device *dev)
index 8247c19..cb69405 100644 (file)
@@ -220,7 +220,6 @@ static int hdpvr_device_init(struct hdpvr_device *dev)
 {
        int ret;
        u8 *buf;
-       struct hdpvr_video_info *vidinf;
 
        if (device_authorization(dev))
                return -EACCES;
@@ -242,13 +241,6 @@ static int hdpvr_device_init(struct hdpvr_device *dev)
                 "control request returned %d\n", ret);
        mutex_unlock(&dev->usbc_mutex);
 
-       vidinf = get_video_info(dev);
-       if (!vidinf)
-               v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
-                       "no valid video signal or device init failed\n");
-       else
-               kfree(vidinf);
-
        /* enable fan and bling leds */
        mutex_lock(&dev->usbc_mutex);
        buf[0] = 0x1;
index 774ba0e..4f8567a 100644 (file)
@@ -277,44 +277,50 @@ error:
 static int hdpvr_start_streaming(struct hdpvr_device *dev)
 {
        int ret;
-       struct hdpvr_video_info *vidinf;
+       struct hdpvr_video_info vidinf;
 
        if (dev->status == STATUS_STREAMING)
                return 0;
-       else if (dev->status != STATUS_IDLE)
+       if (dev->status != STATUS_IDLE)
                return -EAGAIN;
 
-       vidinf = get_video_info(dev);
+       ret = get_video_info(dev, &vidinf);
+       if (ret < 0)
+               return ret;
 
-       if (vidinf) {
-               v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev,
-                        "video signal: %dx%d@%dhz\n", vidinf->width,
-                        vidinf->height, vidinf->fps);
-               kfree(vidinf);
-
-               /* start streaming 2 request */
-               ret = usb_control_msg(dev->udev,
-                                     usb_sndctrlpipe(dev->udev, 0),
-                                     0xb8, 0x38, 0x1, 0, NULL, 0, 8000);
-               v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev,
-                        "encoder start control request returned %d\n", ret);
+       if (!vidinf.valid) {
+               msleep(250);
+               v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
+                               "no video signal at input %d\n", dev->options.video_input);
+               return -EAGAIN;
+       }
 
-               hdpvr_config_call(dev, CTRL_START_STREAMING_VALUE, 0x00);
+       v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev,
+                       "video signal: %dx%d@%dhz\n", vidinf.width,
+                       vidinf.height, vidinf.fps);
 
-               dev->status = STATUS_STREAMING;
+       /* start streaming 2 request */
+       ret = usb_control_msg(dev->udev,
+                       usb_sndctrlpipe(dev->udev, 0),
+                       0xb8, 0x38, 0x1, 0, NULL, 0, 8000);
+       v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev,
+                       "encoder start control request returned %d\n", ret);
+       if (ret < 0)
+               return ret;
 
-               INIT_WORK(&dev->worker, hdpvr_transmit_buffers);
-               queue_work(dev->workqueue, &dev->worker);
+       ret = hdpvr_config_call(dev, CTRL_START_STREAMING_VALUE, 0x00);
+       if (ret)
+               return ret;
 
-               v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev,
-                        "streaming started\n");
+       dev->status = STATUS_STREAMING;
 
-               return 0;
-       }
-       msleep(250);
-       v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
-                "no video signal at input %d\n", dev->options.video_input);
-       return -EAGAIN;
+       INIT_WORK(&dev->worker, hdpvr_transmit_buffers);
+       queue_work(dev->workqueue, &dev->worker);
+
+       v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev,
+                       "streaming started\n");
+
+       return 0;
 }
 
 
@@ -606,22 +612,20 @@ static int vidioc_g_std(struct file *file, void *_fh,
 static int vidioc_querystd(struct file *file, void *_fh, v4l2_std_id *a)
 {
        struct hdpvr_device *dev = video_drvdata(file);
-       struct hdpvr_video_info *vid_info;
+       struct hdpvr_video_info vid_info;
        struct hdpvr_fh *fh = _fh;
+       int ret;
 
-       *a = V4L2_STD_ALL;
+       *a = V4L2_STD_UNKNOWN;
        if (dev->options.video_input == HDPVR_COMPONENT)
                return fh->legacy_mode ? 0 : -ENODATA;
-       vid_info = get_video_info(dev);
-       if (vid_info == NULL)
-               return 0;
-       if (vid_info->width == 720 &&
-           (vid_info->height == 480 || vid_info->height == 576)) {
-               *a = (vid_info->height == 480) ?
+       ret = get_video_info(dev, &vid_info);
+       if (vid_info.valid && vid_info.width == 720 &&
+           (vid_info.height == 480 || vid_info.height == 576)) {
+               *a = (vid_info.height == 480) ?
                        V4L2_STD_525_60 : V4L2_STD_625_50;
        }
-       kfree(vid_info);
-       return 0;
+       return ret;
 }
 
 static int vidioc_s_dv_timings(struct file *file, void *_fh,
@@ -665,7 +669,7 @@ static int vidioc_query_dv_timings(struct file *file, void *_fh,
 {
        struct hdpvr_device *dev = video_drvdata(file);
        struct hdpvr_fh *fh = _fh;
-       struct hdpvr_video_info *vid_info;
+       struct hdpvr_video_info vid_info;
        bool interlaced;
        int ret = 0;
        int i;
@@ -673,10 +677,12 @@ static int vidioc_query_dv_timings(struct file *file, void *_fh,
        fh->legacy_mode = false;
        if (dev->options.video_input)
                return -ENODATA;
-       vid_info = get_video_info(dev);
-       if (vid_info == NULL)
+       ret = get_video_info(dev, &vid_info);
+       if (ret)
+               return ret;
+       if (!vid_info.valid)
                return -ENOLCK;
-       interlaced = vid_info->fps <= 30;
+       interlaced = vid_info.fps <= 30;
        for (i = 0; i < ARRAY_SIZE(hdpvr_dv_timings); i++) {
                const struct v4l2_bt_timings *bt = &hdpvr_dv_timings[i].bt;
                unsigned hsize;
@@ -688,17 +694,17 @@ static int vidioc_query_dv_timings(struct file *file, void *_fh,
                        bt->il_vfrontporch + bt->il_vsync + bt->il_vbackporch +
                        bt->height;
                fps = (unsigned)bt->pixelclock / (hsize * vsize);
-               if (bt->width != vid_info->width ||
-                   bt->height != vid_info->height ||
+               if (bt->width != vid_info.width ||
+                   bt->height != vid_info.height ||
                    bt->interlaced != interlaced ||
-                   (fps != vid_info->fps && fps + 1 != vid_info->fps))
+                   (fps != vid_info.fps && fps + 1 != vid_info.fps))
                        continue;
                *timings = hdpvr_dv_timings[i];
                break;
        }
        if (i == ARRAY_SIZE(hdpvr_dv_timings))
                ret = -ERANGE;
-       kfree(vid_info);
+
        return ret;
 }
 
@@ -988,6 +994,7 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *_fh,
 {
        struct hdpvr_device *dev = video_drvdata(file);
        struct hdpvr_fh *fh = _fh;
+       int ret;
 
        /*
         * The original driver would always returns the current detected
@@ -1000,14 +1007,15 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *_fh,
         * last set format.
         */
        if (fh->legacy_mode) {
-               struct hdpvr_video_info *vid_info;
+               struct hdpvr_video_info vid_info;
 
-               vid_info = get_video_info(dev);
-               if (!vid_info)
+               ret = get_video_info(dev, &vid_info);
+               if (ret < 0)
+                       return ret;
+               if (!vid_info.valid)
                        return -EFAULT;
-               f->fmt.pix.width = vid_info->width;
-               f->fmt.pix.height = vid_info->height;
-               kfree(vid_info);
+               f->fmt.pix.width = vid_info.width;
+               f->fmt.pix.height = vid_info.height;
        } else {
                f->fmt.pix.width = dev->width;
                f->fmt.pix.height = dev->height;
index 1478f3d..dc685d4 100644 (file)
@@ -154,6 +154,7 @@ struct hdpvr_video_info {
        u16     width;
        u16     height;
        u8      fps;
+       bool    valid;
 };
 
 enum {
@@ -303,7 +304,7 @@ int hdpvr_set_audio(struct hdpvr_device *dev, u8 input,
 int hdpvr_config_call(struct hdpvr_device *dev, uint value,
                      unsigned char valbuf);
 
-struct hdpvr_video_info *get_video_info(struct hdpvr_device *dev);
+int get_video_info(struct hdpvr_device *dev, struct hdpvr_video_info *vid_info);
 
 /* :0 s b8 81 1800 0003 0003 3 < */
 /* :0 0 3 = 0301ff */
index e11267f..c4d51d7 100644 (file)
@@ -2704,6 +2704,10 @@ static void pvr2_hdw_remove_usb_stuff(struct pvr2_hdw *hdw)
        pvr2_hdw_render_useless(hdw);
 }
 
+void pvr2_hdw_set_v4l2_dev(struct pvr2_hdw *hdw, struct video_device *vdev)
+{
+       vdev->v4l2_dev = &hdw->v4l2_dev;
+}
 
 /* Destroy hardware interaction structure */
 void pvr2_hdw_destroy(struct pvr2_hdw *hdw)
@@ -5162,41 +5166,3 @@ static int pvr2_hdw_get_eeprom_addr(struct pvr2_hdw *hdw)
        } while(0); LOCK_GIVE(hdw->ctl_lock);
        return result;
 }
-
-
-int pvr2_hdw_register_access(struct pvr2_hdw *hdw,
-                            const struct v4l2_dbg_match *match, u64 reg_id,
-                            int setFl, u64 *val_ptr)
-{
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-       struct v4l2_dbg_register req;
-       int stat = 0;
-       int okFl = 0;
-
-       if (!capable(CAP_SYS_ADMIN)) return -EPERM;
-
-       req.match = *match;
-       req.reg = reg_id;
-       if (setFl) req.val = *val_ptr;
-       /* It would be nice to know if a sub-device answered the request */
-       v4l2_device_call_all(&hdw->v4l2_dev, 0, core, g_register, &req);
-       if (!setFl) *val_ptr = req.val;
-       if (okFl) {
-               return stat;
-       }
-       return -EINVAL;
-#else
-       return -ENOSYS;
-#endif
-}
-
-
-/*
-  Stuff for Emacs to see, in order to encourage consistent editing style:
-  *** Local Variables: ***
-  *** mode: c ***
-  *** fill-column: 75 ***
-  *** tab-width: 8 ***
-  *** c-basic-offset: 8 ***
-  *** End: ***
-  */
index 91bae93..4184707 100644 (file)
@@ -22,6 +22,7 @@
 
 #include <linux/usb.h>
 #include <linux/videodev2.h>
+#include <media/v4l2-dev.h>
 #include "pvrusb2-io.h"
 #include "pvrusb2-ctrl.h"
 
@@ -138,6 +139,9 @@ const char *pvr2_hdw_get_device_identifier(struct pvr2_hdw *);
 /* Called when hardware has been unplugged */
 void pvr2_hdw_disconnect(struct pvr2_hdw *);
 
+/* Sets v4l2_dev of a video_device struct */
+void pvr2_hdw_set_v4l2_dev(struct pvr2_hdw *, struct video_device *);
+
 /* Get the number of defined controls */
 unsigned int pvr2_hdw_get_ctrl_count(struct pvr2_hdw *);
 
@@ -234,15 +238,6 @@ int pvr2_hdw_v4l_get_minor_number(struct pvr2_hdw *,enum pvr2_v4l_type index);
 void pvr2_hdw_v4l_store_minor_number(struct pvr2_hdw *,
                                     enum pvr2_v4l_type index,int);
 
-/* Direct read/write access to chip's registers:
-   match - specify criteria to identify target chip (this is a v4l dbg struct)
-   reg_id  - register number to access
-   setFl   - true to set the register, false to read it
-   val_ptr - storage location for source / result. */
-int pvr2_hdw_register_access(struct pvr2_hdw *,
-                            const struct v4l2_dbg_match *match, u64 reg_id,
-                            int setFl, u64 *val_ptr);
-
 /* The following entry points are all lower level things you normally don't
    want to worry about. */
 
index 20b6ae0..1e35474 100644 (file)
@@ -354,9 +354,9 @@ static int pvr2_stream_buffer_count(struct pvr2_stream *sp,unsigned int cnt)
                if (scnt < sp->buffer_slot_count) {
                        struct pvr2_buffer **nb = NULL;
                        if (scnt) {
-                               nb = kmalloc(scnt * sizeof(*nb),GFP_KERNEL);
+                               nb = kmemdup(sp->buffers, scnt * sizeof(*nb),
+                                            GFP_KERNEL);
                                if (!nb) return -ENOMEM;
-                               memcpy(nb,sp->buffers,scnt * sizeof(*nb));
                        }
                        kfree(sp->buffers);
                        sp->buffers = nb;
index a8a65fa..7c280f3 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/videodev2.h>
 #include <linux/module.h>
 #include <media/v4l2-dev.h>
+#include <media/v4l2-device.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
 
@@ -800,36 +801,6 @@ static int pvr2_log_status(struct file *file, void *priv)
        return 0;
 }
 
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-static int pvr2_g_register(struct file *file, void *priv, struct v4l2_dbg_register *req)
-{
-       struct pvr2_v4l2_fh *fh = file->private_data;
-       struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
-       u64 val;
-       int ret;
-
-       ret = pvr2_hdw_register_access(
-                       hdw, &req->match, req->reg,
-                       0, &val);
-       req->val = val;
-       return ret;
-}
-
-static int pvr2_s_register(struct file *file, void *priv, const struct v4l2_dbg_register *req)
-{
-       struct pvr2_v4l2_fh *fh = file->private_data;
-       struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
-       u64 val;
-       int ret;
-
-       val = req->val;
-       ret = pvr2_hdw_register_access(
-                       hdw, &req->match, req->reg,
-                       1, &val);
-       return ret;
-}
-#endif
-
 static const struct v4l2_ioctl_ops pvr2_ioctl_ops = {
        .vidioc_querycap                    = pvr2_querycap,
        .vidioc_g_priority                  = pvr2_g_priority,
@@ -864,10 +835,6 @@ static const struct v4l2_ioctl_ops pvr2_ioctl_ops = {
        .vidioc_g_ext_ctrls                 = pvr2_g_ext_ctrls,
        .vidioc_s_ext_ctrls                 = pvr2_s_ext_ctrls,
        .vidioc_try_ext_ctrls               = pvr2_try_ext_ctrls,
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-       .vidioc_g_register                  = pvr2_g_register,
-       .vidioc_s_register                  = pvr2_s_register,
-#endif
 };
 
 static void pvr2_v4l2_dev_destroy(struct pvr2_v4l2_dev *dip)
@@ -904,8 +871,8 @@ static void pvr2_v4l2_dev_destroy(struct pvr2_v4l2_dev *dip)
 static void pvr2_v4l2_dev_disassociate_parent(struct pvr2_v4l2_dev *dip)
 {
        if (!dip) return;
-       if (!dip->devbase.parent) return;
-       dip->devbase.parent = NULL;
+       if (!dip->devbase.v4l2_dev->dev) return;
+       dip->devbase.v4l2_dev->dev = NULL;
        device_move(&dip->devbase.dev, NULL, DPM_ORDER_NONE);
 }
 
@@ -1298,7 +1265,6 @@ static void pvr2_v4l2_dev_init(struct pvr2_v4l2_dev *dip,
                               struct pvr2_v4l2 *vp,
                               int v4l_type)
 {
-       struct usb_device *usbdev;
        int mindevnum;
        int unit_number;
        struct pvr2_hdw *hdw;
@@ -1306,7 +1272,6 @@ static void pvr2_v4l2_dev_init(struct pvr2_v4l2_dev *dip,
        dip->v4lp = vp;
 
        hdw = vp->channel.mc_head->hdw;
-       usbdev = pvr2_hdw_get_dev(hdw);
        dip->v4l_type = v4l_type;
        switch (v4l_type) {
        case VFL_TYPE_GRABBER:
@@ -1355,7 +1320,7 @@ static void pvr2_v4l2_dev_init(struct pvr2_v4l2_dev *dip,
        if (nr_ptr && (unit_number >= 0) && (unit_number < PVR_NUM)) {
                mindevnum = nr_ptr[unit_number];
        }
-       dip->devbase.parent = &usbdev->dev;
+       pvr2_hdw_set_v4l2_dev(hdw, &dip->devbase);
        if ((video_register_device(&dip->devbase,
                                   dip->v4l_type, mindevnum) < 0) &&
            (video_register_device(&dip->devbase,
index 2bc153e..8a917f0 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/videodev2.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
+#include <media/v4l2-device.h>
 #include <linux/device.h>
 #include <linux/list.h>
 #include <linux/spinlock.h>
@@ -100,6 +101,8 @@ static DECLARE_RWSEM(sn9c102_dev_lock);
 struct sn9c102_device {
        struct video_device* v4ldev;
 
+       struct v4l2_device v4l2_dev;
+
        enum sn9c102_bridge bridge;
        struct sn9c102_sensor sensor;
 
index c957e9a..2cb44de 100644 (file)
@@ -1737,6 +1737,7 @@ static void sn9c102_release_resources(struct kref *kref)
            video_device_node_name(cam->v4ldev));
        video_set_drvdata(cam->v4ldev, NULL);
        video_unregister_device(cam->v4ldev);
+       v4l2_device_unregister(&cam->v4l2_dev);
        usb_put_dev(cam->usbdev);
        kfree(cam->control_buffer);
        kfree(cam);
@@ -3254,6 +3255,13 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
 
        cam->usbdev = udev;
 
+       /* register v4l2_device early so it can be used for printks */
+       if (v4l2_device_register(&intf->dev, &cam->v4l2_dev)) {
+               dev_err(&intf->dev, "v4l2_device_register failed\n");
+               err = -ENOMEM;
+               goto fail;
+       }
+
        if (!(cam->control_buffer = kzalloc(8, GFP_KERNEL))) {
                DBG(1, "kzalloc() failed");
                err = -ENOMEM;
@@ -3325,7 +3333,7 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
        strcpy(cam->v4ldev->name, "SN9C1xx PC Camera");
        cam->v4ldev->fops = &sn9c102_fops;
        cam->v4ldev->release = video_device_release;
-       cam->v4ldev->parent = &udev->dev;
+       cam->v4ldev->v4l2_dev = &cam->v4l2_dev;
 
        init_completion(&cam->probe);
 
@@ -3377,6 +3385,7 @@ fail:
                kfree(cam->control_buffer);
                if (cam->v4ldev)
                        video_device_release(cam->v4ldev);
+               v4l2_device_unregister(&cam->v4l2_dev);
                kfree(cam);
        }
        return err;
@@ -3407,6 +3416,8 @@ static void sn9c102_usb_disconnect(struct usb_interface* intf)
 
        wake_up_interruptible_all(&cam->wait_open);
 
+       v4l2_device_disconnect(&cam->v4l2_dev);
+
        kref_put(&cam->kref, sn9c102_release_resources);
 
        up_write(&sn9c102_dev_lock);
index a59153d..876fc26 100644 (file)
@@ -31,7 +31,6 @@
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-fh.h>
 #include <media/v4l2-event.h>
-#include <media/v4l2-chip-ident.h>
 #include <media/videobuf2-vmalloc.h>
 
 #include <media/saa7115.h>
@@ -454,19 +453,6 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
        return 0;
 }
 
-static int vidioc_g_chip_ident(struct file *file, void *priv,
-              struct v4l2_dbg_chip_ident *chip)
-{
-       switch (chip->match.type) {
-       case V4L2_CHIP_MATCH_BRIDGE:
-               chip->ident = V4L2_IDENT_NONE;
-               chip->revision = 0;
-               return 0;
-       default:
-               return -EINVAL;
-       }
-}
-
 #ifdef CONFIG_VIDEO_ADV_DEBUG
 static int vidioc_g_register(struct file *file, void *priv,
                             struct v4l2_dbg_register *reg)
@@ -475,19 +461,6 @@ static int vidioc_g_register(struct file *file, void *priv,
        int rc;
        u8 val;
 
-       switch (reg->match.type) {
-       case V4L2_CHIP_MATCH_I2C_DRIVER:
-               v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_register, reg);
-               return 0;
-       case V4L2_CHIP_MATCH_I2C_ADDR:
-               /* TODO: is this correct? */
-               v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_register, reg);
-               return 0;
-       default:
-               if (!v4l2_chip_match_host(&reg->match))
-                       return -EINVAL;
-       }
-
        /* Match host */
        rc = stk1160_read_reg(dev, reg->reg, &val);
        reg->val = val;
@@ -501,19 +474,6 @@ static int vidioc_s_register(struct file *file, void *priv,
 {
        struct stk1160 *dev = video_drvdata(file);
 
-       switch (reg->match.type) {
-       case V4L2_CHIP_MATCH_I2C_DRIVER:
-               v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_register, reg);
-               return 0;
-       case V4L2_CHIP_MATCH_I2C_ADDR:
-               /* TODO: is this correct? */
-               v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_register, reg);
-               return 0;
-       default:
-               if (!v4l2_chip_match_host(&reg->match))
-                       return -EINVAL;
-       }
-
        /* Match host */
        return stk1160_write_reg(dev, reg->reg, cpu_to_le16(reg->val));
 }
@@ -543,7 +503,6 @@ static const struct v4l2_ioctl_ops stk1160_ioctl_ops = {
        .vidioc_log_status  = v4l2_ctrl_log_status,
        .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
        .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
-       .vidioc_g_chip_ident = vidioc_g_chip_ident,
 
 #ifdef CONFIG_VIDEO_ADV_DEBUG
        .vidioc_g_register = vidioc_g_register,
index 307d8c5..1ccaadd 100644 (file)
@@ -1114,7 +1114,7 @@ static int tm6000_init_dev(struct tm6000_core *dev)
        /* Default values for STD and resolutions */
        dev->width = 720;
        dev->height = 480;
-       dev->norm = V4L2_STD_PAL_M;
+       dev->norm = V4L2_STD_NTSC_M;
 
        /* Configure tuner */
        tm6000_config_tuner(dev);
index a78de1d..cc1aa14 100644 (file)
@@ -1076,6 +1076,15 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id norm)
        return 0;
 }
 
+static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *norm)
+{
+       struct tm6000_fh *fh = priv;
+       struct tm6000_core *dev = fh->dev;
+
+       *norm = dev->norm;
+       return 0;
+}
+
 static const char *iname[] = {
        [TM6000_INPUT_TV] = "Television",
        [TM6000_INPUT_COMPOSITE1] = "Composite 1",
@@ -1134,7 +1143,7 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
 
        dev->input = i;
 
-       rc = vidioc_s_std(file, priv, dev->vfd->current_norm);
+       rc = vidioc_s_std(file, priv, dev->norm);
 
        return rc;
 }
@@ -1547,6 +1556,7 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
        .vidioc_try_fmt_vid_cap   = vidioc_try_fmt_vid_cap,
        .vidioc_s_fmt_vid_cap     = vidioc_s_fmt_vid_cap,
        .vidioc_s_std             = vidioc_s_std,
+       .vidioc_g_std             = vidioc_g_std,
        .vidioc_enum_input        = vidioc_enum_input,
        .vidioc_g_input           = vidioc_g_input,
        .vidioc_s_input           = vidioc_s_input,
@@ -1570,7 +1580,6 @@ static struct video_device tm6000_template = {
        .ioctl_ops      = &video_ioctl_ops,
        .release        = video_device_release,
        .tvnorms        = TM6000_STD,
-       .current_norm   = V4L2_STD_NTSC_M,
 };
 
 static const struct v4l2_file_operations radio_fops = {
index 21b9049..f8a60c1 100644 (file)
@@ -1768,6 +1768,8 @@ err_i2c_del_adapter:
        i2c_del_adapter(&ttusb->i2c_adap);
 err_unregister_adapter:
        dvb_unregister_adapter (&ttusb->adapter);
+       ttusb_free_iso_urbs(ttusb);
+       kfree(ttusb);
        return result;
 }
 
diff --git a/drivers/media/usb/usbtv/Kconfig b/drivers/media/usb/usbtv/Kconfig
new file mode 100644 (file)
index 0000000..8864436
--- /dev/null
@@ -0,0 +1,10 @@
+config VIDEO_USBTV
+        tristate "USBTV007 video capture support"
+        depends on VIDEO_DEV
+        select VIDEOBUF2_VMALLOC
+
+        ---help---
+          This is a video4linux2 driver for USBTV007 based video capture devices.
+
+          To compile this driver as a module, choose M here: the
+          module will be called usbtv
diff --git a/drivers/media/usb/usbtv/Makefile b/drivers/media/usb/usbtv/Makefile
new file mode 100644 (file)
index 0000000..28b872f
--- /dev/null
@@ -0,0 +1 @@
+obj-$(CONFIG_VIDEO_USBTV) += usbtv.o
diff --git a/drivers/media/usb/usbtv/usbtv.c b/drivers/media/usb/usbtv/usbtv.c
new file mode 100644 (file)
index 0000000..bf43f87
--- /dev/null
@@ -0,0 +1,696 @@
+/*
+ * Fushicai USBTV007 Video Grabber Driver
+ *
+ * Product web site:
+ * http://www.fushicai.com/products_detail/&productId=d05449ee-b690-42f9-a661-aa7353894bed.html
+ *
+ * Following LWN articles were very useful in construction of this driver:
+ * Video4Linux2 API series: http://lwn.net/Articles/203924/
+ * videobuf2 API explanation: http://lwn.net/Articles/447435/
+ * Thanks go to Jonathan Corbet for providing this quality documentation.
+ * He is awesome.
+ *
+ * Copyright (c) 2013 Lubomir Rintel
+ * All rights reserved.
+ * No physical hardware was harmed running Windows during the
+ * reverse-engineering activity
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL").
+ */
+
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+#include <linux/version.h>
+#include <linux/videodev2.h>
+
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-vmalloc.h>
+
+/* Hardware. */
+#define USBTV_VIDEO_ENDP       0x81
+#define USBTV_BASE             0xc000
+#define USBTV_REQUEST_REG      12
+
+/* Number of concurrent isochronous urbs submitted.
+ * Higher numbers was seen to overly saturate the USB bus. */
+#define USBTV_ISOC_TRANSFERS   16
+#define USBTV_ISOC_PACKETS     8
+
+#define USBTV_WIDTH            720
+#define USBTV_HEIGHT           480
+
+#define USBTV_CHUNK_SIZE       256
+#define USBTV_CHUNK            240
+#define USBTV_CHUNKS           (USBTV_WIDTH * USBTV_HEIGHT \
+                                       / 2 / USBTV_CHUNK)
+
+/* Chunk header. */
+#define USBTV_MAGIC_OK(chunk)  ((be32_to_cpu(chunk[0]) & 0xff000000) \
+                                                       == 0x88000000)
+#define USBTV_FRAME_ID(chunk)  ((be32_to_cpu(chunk[0]) & 0x00ff0000) >> 16)
+#define USBTV_ODD(chunk)       ((be32_to_cpu(chunk[0]) & 0x0000f000) >> 15)
+#define USBTV_CHUNK_NO(chunk)  (be32_to_cpu(chunk[0]) & 0x00000fff)
+
+/* A single videobuf2 frame buffer. */
+struct usbtv_buf {
+       struct vb2_buffer vb;
+       struct list_head list;
+};
+
+/* Per-device structure. */
+struct usbtv {
+       struct device *dev;
+       struct usb_device *udev;
+       struct v4l2_device v4l2_dev;
+       struct video_device vdev;
+       struct vb2_queue vb2q;
+       struct mutex v4l2_lock;
+       struct mutex vb2q_lock;
+
+       /* List of videobuf2 buffers protected by a lock. */
+       spinlock_t buflock;
+       struct list_head bufs;
+
+       /* Number of currently processed frame, useful find
+        * out when a new one begins. */
+       u32 frame_id;
+
+       int iso_size;
+       unsigned int sequence;
+       struct urb *isoc_urbs[USBTV_ISOC_TRANSFERS];
+};
+
+static int usbtv_setup_capture(struct usbtv *usbtv)
+{
+       int ret;
+       int pipe = usb_rcvctrlpipe(usbtv->udev, 0);
+       int i;
+       static const u16 protoregs[][2] = {
+               /* These seem to enable the device. */
+               { USBTV_BASE + 0x0008, 0x0001 },
+               { USBTV_BASE + 0x01d0, 0x00ff },
+               { USBTV_BASE + 0x01d9, 0x0002 },
+
+               /* These seem to influence color parameters, such as
+                * brightness, etc. */
+               { USBTV_BASE + 0x0239, 0x0040 },
+               { USBTV_BASE + 0x0240, 0x0000 },
+               { USBTV_BASE + 0x0241, 0x0000 },
+               { USBTV_BASE + 0x0242, 0x0002 },
+               { USBTV_BASE + 0x0243, 0x0080 },
+               { USBTV_BASE + 0x0244, 0x0012 },
+               { USBTV_BASE + 0x0245, 0x0090 },
+               { USBTV_BASE + 0x0246, 0x0000 },
+
+               { USBTV_BASE + 0x0278, 0x002d },
+               { USBTV_BASE + 0x0279, 0x000a },
+               { USBTV_BASE + 0x027a, 0x0032 },
+               { 0xf890, 0x000c },
+               { 0xf894, 0x0086 },
+
+               { USBTV_BASE + 0x00ac, 0x00c0 },
+               { USBTV_BASE + 0x00ad, 0x0000 },
+               { USBTV_BASE + 0x00a2, 0x0012 },
+               { USBTV_BASE + 0x00a3, 0x00e0 },
+               { USBTV_BASE + 0x00a4, 0x0028 },
+               { USBTV_BASE + 0x00a5, 0x0082 },
+               { USBTV_BASE + 0x00a7, 0x0080 },
+               { USBTV_BASE + 0x0000, 0x0014 },
+               { USBTV_BASE + 0x0006, 0x0003 },
+               { USBTV_BASE + 0x0090, 0x0099 },
+               { USBTV_BASE + 0x0091, 0x0090 },
+               { USBTV_BASE + 0x0094, 0x0068 },
+               { USBTV_BASE + 0x0095, 0x0070 },
+               { USBTV_BASE + 0x009c, 0x0030 },
+               { USBTV_BASE + 0x009d, 0x00c0 },
+               { USBTV_BASE + 0x009e, 0x00e0 },
+               { USBTV_BASE + 0x0019, 0x0006 },
+               { USBTV_BASE + 0x008c, 0x00ba },
+               { USBTV_BASE + 0x0101, 0x00ff },
+               { USBTV_BASE + 0x010c, 0x00b3 },
+               { USBTV_BASE + 0x01b2, 0x0080 },
+               { USBTV_BASE + 0x01b4, 0x00a0 },
+               { USBTV_BASE + 0x014c, 0x00ff },
+               { USBTV_BASE + 0x014d, 0x00ca },
+               { USBTV_BASE + 0x0113, 0x0053 },
+               { USBTV_BASE + 0x0119, 0x008a },
+               { USBTV_BASE + 0x013c, 0x0003 },
+               { USBTV_BASE + 0x0150, 0x009c },
+               { USBTV_BASE + 0x0151, 0x0071 },
+               { USBTV_BASE + 0x0152, 0x00c6 },
+               { USBTV_BASE + 0x0153, 0x0084 },
+               { USBTV_BASE + 0x0154, 0x00bc },
+               { USBTV_BASE + 0x0155, 0x00a0 },
+               { USBTV_BASE + 0x0156, 0x00a0 },
+               { USBTV_BASE + 0x0157, 0x009c },
+               { USBTV_BASE + 0x0158, 0x001f },
+               { USBTV_BASE + 0x0159, 0x0006 },
+               { USBTV_BASE + 0x015d, 0x0000 },
+
+               { USBTV_BASE + 0x0284, 0x0088 },
+               { USBTV_BASE + 0x0003, 0x0004 },
+               { USBTV_BASE + 0x001a, 0x0079 },
+               { USBTV_BASE + 0x0100, 0x00d3 },
+               { USBTV_BASE + 0x010e, 0x0068 },
+               { USBTV_BASE + 0x010f, 0x009c },
+               { USBTV_BASE + 0x0112, 0x00f0 },
+               { USBTV_BASE + 0x0115, 0x0015 },
+               { USBTV_BASE + 0x0117, 0x0000 },
+               { USBTV_BASE + 0x0118, 0x00fc },
+               { USBTV_BASE + 0x012d, 0x0004 },
+               { USBTV_BASE + 0x012f, 0x0008 },
+               { USBTV_BASE + 0x0220, 0x002e },
+               { USBTV_BASE + 0x0225, 0x0008 },
+               { USBTV_BASE + 0x024e, 0x0002 },
+               { USBTV_BASE + 0x024f, 0x0001 },
+               { USBTV_BASE + 0x0254, 0x005f },
+               { USBTV_BASE + 0x025a, 0x0012 },
+               { USBTV_BASE + 0x025b, 0x0001 },
+               { USBTV_BASE + 0x0263, 0x001c },
+               { USBTV_BASE + 0x0266, 0x0011 },
+               { USBTV_BASE + 0x0267, 0x0005 },
+               { USBTV_BASE + 0x024e, 0x0002 },
+               { USBTV_BASE + 0x024f, 0x0002 },
+       };
+
+       for (i = 0; i < ARRAY_SIZE(protoregs); i++) {
+               u16 index = protoregs[i][0];
+               u16 value = protoregs[i][1];
+
+               ret = usb_control_msg(usbtv->udev, pipe, USBTV_REQUEST_REG,
+                       USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                       value, index, NULL, 0, 0);
+               if (ret < 0)
+                       return ret;
+       }
+
+       return 0;
+}
+
+/* Called for each 256-byte image chunk.
+ * First word identifies the chunk, followed by 240 words of image
+ * data and padding. */
+static void usbtv_image_chunk(struct usbtv *usbtv, u32 *chunk)
+{
+       int frame_id, odd, chunk_no;
+       u32 *frame;
+       struct usbtv_buf *buf;
+       unsigned long flags;
+
+       /* Ignore corrupted lines. */
+       if (!USBTV_MAGIC_OK(chunk))
+               return;
+       frame_id = USBTV_FRAME_ID(chunk);
+       odd = USBTV_ODD(chunk);
+       chunk_no = USBTV_CHUNK_NO(chunk);
+
+       /* Deinterlace. TODO: Use interlaced frame format. */
+       chunk_no = (chunk_no - chunk_no % 3) * 2 + chunk_no % 3;
+       chunk_no += !odd * 3;
+
+       if (chunk_no >= USBTV_CHUNKS)
+               return;
+
+       /* Beginning of a frame. */
+       if (chunk_no == 0)
+               usbtv->frame_id = frame_id;
+
+       spin_lock_irqsave(&usbtv->buflock, flags);
+       if (list_empty(&usbtv->bufs)) {
+               /* No free buffers. Userspace likely too slow. */
+               spin_unlock_irqrestore(&usbtv->buflock, flags);
+               return;
+       }
+
+       /* First available buffer. */
+       buf = list_first_entry(&usbtv->bufs, struct usbtv_buf, list);
+       frame = vb2_plane_vaddr(&buf->vb, 0);
+
+       /* Copy the chunk. */
+       memcpy(&frame[chunk_no * USBTV_CHUNK], &chunk[1],
+                       USBTV_CHUNK * sizeof(chunk[1]));
+
+       /* Last chunk in a frame, signalling an end */
+       if (usbtv->frame_id && chunk_no == USBTV_CHUNKS-1) {
+               int size = vb2_plane_size(&buf->vb, 0);
+
+               buf->vb.v4l2_buf.field = V4L2_FIELD_INTERLACED;
+               buf->vb.v4l2_buf.sequence = usbtv->sequence++;
+               v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp);
+               vb2_set_plane_payload(&buf->vb, 0, size);
+               vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE);
+               list_del(&buf->list);
+       }
+
+       spin_unlock_irqrestore(&usbtv->buflock, flags);
+}
+
+/* Got image data. Each packet contains a number of 256-word chunks we
+ * compose the image from. */
+static void usbtv_iso_cb(struct urb *ip)
+{
+       int ret;
+       int i;
+       struct usbtv *usbtv = (struct usbtv *)ip->context;
+
+       switch (ip->status) {
+       /* All fine. */
+       case 0:
+               break;
+       /* Device disconnected or capture stopped? */
+       case -ENODEV:
+       case -ENOENT:
+       case -ECONNRESET:
+       case -ESHUTDOWN:
+               return;
+       /* Unknown error. Retry. */
+       default:
+               dev_warn(usbtv->dev, "Bad response for ISO request.\n");
+               goto resubmit;
+       }
+
+       for (i = 0; i < ip->number_of_packets; i++) {
+               int size = ip->iso_frame_desc[i].actual_length;
+               unsigned char *data = ip->transfer_buffer +
+                               ip->iso_frame_desc[i].offset;
+               int offset;
+
+               for (offset = 0; USBTV_CHUNK_SIZE * offset < size; offset++)
+                       usbtv_image_chunk(usbtv,
+                               (u32 *)&data[USBTV_CHUNK_SIZE * offset]);
+       }
+
+resubmit:
+       ret = usb_submit_urb(ip, GFP_ATOMIC);
+       if (ret < 0)
+               dev_warn(usbtv->dev, "Could not resubmit ISO URB\n");
+}
+
+static struct urb *usbtv_setup_iso_transfer(struct usbtv *usbtv)
+{
+       struct urb *ip;
+       int size = usbtv->iso_size;
+       int i;
+
+       ip = usb_alloc_urb(USBTV_ISOC_PACKETS, GFP_KERNEL);
+       if (ip == NULL)
+               return NULL;
+
+       ip->dev = usbtv->udev;
+       ip->context = usbtv;
+       ip->pipe = usb_rcvisocpipe(usbtv->udev, USBTV_VIDEO_ENDP);
+       ip->interval = 1;
+       ip->transfer_flags = URB_ISO_ASAP;
+       ip->transfer_buffer = kzalloc(size * USBTV_ISOC_PACKETS,
+                                               GFP_KERNEL);
+       ip->complete = usbtv_iso_cb;
+       ip->number_of_packets = USBTV_ISOC_PACKETS;
+       ip->transfer_buffer_length = size * USBTV_ISOC_PACKETS;
+       for (i = 0; i < USBTV_ISOC_PACKETS; i++) {
+               ip->iso_frame_desc[i].offset = size * i;
+               ip->iso_frame_desc[i].length = size;
+       }
+
+       return ip;
+}
+
+static void usbtv_stop(struct usbtv *usbtv)
+{
+       int i;
+       unsigned long flags;
+
+       /* Cancel running transfers. */
+       for (i = 0; i < USBTV_ISOC_TRANSFERS; i++) {
+               struct urb *ip = usbtv->isoc_urbs[i];
+               if (ip == NULL)
+                       continue;
+               usb_kill_urb(ip);
+               kfree(ip->transfer_buffer);
+               usb_free_urb(ip);
+               usbtv->isoc_urbs[i] = NULL;
+       }
+
+       /* Return buffers to userspace. */
+       spin_lock_irqsave(&usbtv->buflock, flags);
+       while (!list_empty(&usbtv->bufs)) {
+               struct usbtv_buf *buf = list_first_entry(&usbtv->bufs,
+                                               struct usbtv_buf, list);
+               vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+               list_del(&buf->list);
+       }
+       spin_unlock_irqrestore(&usbtv->buflock, flags);
+}
+
+static int usbtv_start(struct usbtv *usbtv)
+{
+       int i;
+       int ret;
+
+       ret = usb_set_interface(usbtv->udev, 0, 0);
+       if (ret < 0)
+               return ret;
+
+       ret = usbtv_setup_capture(usbtv);
+       if (ret < 0)
+               return ret;
+
+       ret = usb_set_interface(usbtv->udev, 0, 1);
+       if (ret < 0)
+               return ret;
+
+       for (i = 0; i < USBTV_ISOC_TRANSFERS; i++) {
+               struct urb *ip;
+
+               ip = usbtv_setup_iso_transfer(usbtv);
+               if (ip == NULL) {
+                       ret = -ENOMEM;
+                       goto start_fail;
+               }
+               usbtv->isoc_urbs[i] = ip;
+
+               ret = usb_submit_urb(ip, GFP_KERNEL);
+               if (ret < 0)
+                       goto start_fail;
+       }
+
+       return 0;
+
+start_fail:
+       usbtv_stop(usbtv);
+       return ret;
+}
+
+struct usb_device_id usbtv_id_table[] = {
+       { USB_DEVICE(0x1b71, 0x3002) },
+       {}
+};
+MODULE_DEVICE_TABLE(usb, usbtv_id_table);
+
+static int usbtv_querycap(struct file *file, void *priv,
+                               struct v4l2_capability *cap)
+{
+       struct usbtv *dev = video_drvdata(file);
+
+       strlcpy(cap->driver, "usbtv", sizeof(cap->driver));
+       strlcpy(cap->card, "usbtv", sizeof(cap->card));
+       usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
+       cap->device_caps = V4L2_CAP_VIDEO_CAPTURE;
+       cap->device_caps |= V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
+       cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
+       return 0;
+}
+
+static int usbtv_enum_input(struct file *file, void *priv,
+                                       struct v4l2_input *i)
+{
+       if (i->index > 0)
+               return -EINVAL;
+
+       strlcpy(i->name, "Composite", sizeof(i->name));
+       i->type = V4L2_INPUT_TYPE_CAMERA;
+       i->std = V4L2_STD_525_60;
+       return 0;
+}
+
+static int usbtv_enum_fmt_vid_cap(struct file *file, void  *priv,
+                                       struct v4l2_fmtdesc *f)
+{
+       if (f->index > 0)
+               return -EINVAL;
+
+       strlcpy(f->description, "16 bpp YUY2, 4:2:2, packed",
+                                       sizeof(f->description));
+       f->pixelformat = V4L2_PIX_FMT_YUYV;
+       return 0;
+}
+
+static int usbtv_fmt_vid_cap(struct file *file, void *priv,
+                                       struct v4l2_format *f)
+{
+       f->fmt.pix.width = USBTV_WIDTH;
+       f->fmt.pix.height = USBTV_HEIGHT;
+       f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
+       f->fmt.pix.field = V4L2_FIELD_INTERLACED;
+       f->fmt.pix.bytesperline = USBTV_WIDTH * 2;
+       f->fmt.pix.sizeimage = (f->fmt.pix.bytesperline * f->fmt.pix.height);
+       f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+       f->fmt.pix.priv = 0;
+       return 0;
+}
+
+static int usbtv_g_std(struct file *file, void *priv, v4l2_std_id *norm)
+{
+       *norm = V4L2_STD_525_60;
+       return 0;
+}
+
+static int usbtv_g_input(struct file *file, void *priv, unsigned int *i)
+{
+       *i = 0;
+       return 0;
+}
+
+static int usbtv_s_input(struct file *file, void *priv, unsigned int i)
+{
+       if (i > 0)
+               return -EINVAL;
+       return 0;
+}
+
+static int usbtv_s_std(struct file *file, void *priv, v4l2_std_id norm)
+{
+       if (norm & V4L2_STD_525_60)
+               return 0;
+       return -EINVAL;
+}
+
+struct v4l2_ioctl_ops usbtv_ioctl_ops = {
+       .vidioc_querycap = usbtv_querycap,
+       .vidioc_enum_input = usbtv_enum_input,
+       .vidioc_enum_fmt_vid_cap = usbtv_enum_fmt_vid_cap,
+       .vidioc_g_fmt_vid_cap = usbtv_fmt_vid_cap,
+       .vidioc_try_fmt_vid_cap = usbtv_fmt_vid_cap,
+       .vidioc_s_fmt_vid_cap = usbtv_fmt_vid_cap,
+       .vidioc_g_std = usbtv_g_std,
+       .vidioc_s_std = usbtv_s_std,
+       .vidioc_g_input = usbtv_g_input,
+       .vidioc_s_input = usbtv_s_input,
+
+       .vidioc_reqbufs = vb2_ioctl_reqbufs,
+       .vidioc_prepare_buf = vb2_ioctl_prepare_buf,
+       .vidioc_querybuf = vb2_ioctl_querybuf,
+       .vidioc_create_bufs = vb2_ioctl_create_bufs,
+       .vidioc_qbuf = vb2_ioctl_qbuf,
+       .vidioc_dqbuf = vb2_ioctl_dqbuf,
+       .vidioc_streamon = vb2_ioctl_streamon,
+       .vidioc_streamoff = vb2_ioctl_streamoff,
+};
+
+struct v4l2_file_operations usbtv_fops = {
+       .owner = THIS_MODULE,
+       .unlocked_ioctl = video_ioctl2,
+       .mmap = vb2_fop_mmap,
+       .open = v4l2_fh_open,
+       .release = vb2_fop_release,
+       .read = vb2_fop_read,
+       .poll = vb2_fop_poll,
+};
+
+static int usbtv_queue_setup(struct vb2_queue *vq,
+       const struct v4l2_format *v4l_fmt, unsigned int *nbuffers,
+       unsigned int *nplanes, unsigned int sizes[], void *alloc_ctxs[])
+{
+       if (*nbuffers < 2)
+               *nbuffers = 2;
+       *nplanes = 1;
+       sizes[0] = USBTV_CHUNK * USBTV_CHUNKS * sizeof(u32);
+
+       return 0;
+}
+
+static void usbtv_buf_queue(struct vb2_buffer *vb)
+{
+       struct usbtv *usbtv = vb2_get_drv_priv(vb->vb2_queue);
+       struct usbtv_buf *buf = container_of(vb, struct usbtv_buf, vb);
+       unsigned long flags;
+
+       if (usbtv->udev == NULL) {
+               vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
+               return;
+       }
+
+       spin_lock_irqsave(&usbtv->buflock, flags);
+       list_add_tail(&buf->list, &usbtv->bufs);
+       spin_unlock_irqrestore(&usbtv->buflock, flags);
+}
+
+static int usbtv_start_streaming(struct vb2_queue *vq, unsigned int count)
+{
+       struct usbtv *usbtv = vb2_get_drv_priv(vq);
+
+       if (usbtv->udev == NULL)
+               return -ENODEV;
+
+       return usbtv_start(usbtv);
+}
+
+static int usbtv_stop_streaming(struct vb2_queue *vq)
+{
+       struct usbtv *usbtv = vb2_get_drv_priv(vq);
+
+       if (usbtv->udev == NULL)
+               return -ENODEV;
+
+       usbtv_stop(usbtv);
+       return 0;
+}
+
+struct vb2_ops usbtv_vb2_ops = {
+       .queue_setup = usbtv_queue_setup,
+       .buf_queue = usbtv_buf_queue,
+       .start_streaming = usbtv_start_streaming,
+       .stop_streaming = usbtv_stop_streaming,
+};
+
+static void usbtv_release(struct v4l2_device *v4l2_dev)
+{
+       struct usbtv *usbtv = container_of(v4l2_dev, struct usbtv, v4l2_dev);
+
+       v4l2_device_unregister(&usbtv->v4l2_dev);
+       vb2_queue_release(&usbtv->vb2q);
+       kfree(usbtv);
+}
+
+static int usbtv_probe(struct usb_interface *intf,
+       const struct usb_device_id *id)
+{
+       int ret;
+       int size;
+       struct device *dev = &intf->dev;
+       struct usbtv *usbtv;
+
+       /* Checks that the device is what we think it is. */
+       if (intf->num_altsetting != 2)
+               return -ENODEV;
+       if (intf->altsetting[1].desc.bNumEndpoints != 4)
+               return -ENODEV;
+
+       /* Packet size is split into 11 bits of base size and count of
+        * extra multiplies of it.*/
+       size = usb_endpoint_maxp(&intf->altsetting[1].endpoint[0].desc);
+       size = (size & 0x07ff) * (((size & 0x1800) >> 11) + 1);
+
+       /* Device structure */
+       usbtv = kzalloc(sizeof(struct usbtv), GFP_KERNEL);
+       if (usbtv == NULL)
+               return -ENOMEM;
+       usbtv->dev = dev;
+       usbtv->udev = usb_get_dev(interface_to_usbdev(intf));
+       usbtv->iso_size = size;
+       spin_lock_init(&usbtv->buflock);
+       mutex_init(&usbtv->v4l2_lock);
+       mutex_init(&usbtv->vb2q_lock);
+       INIT_LIST_HEAD(&usbtv->bufs);
+
+       /* videobuf2 structure */
+       usbtv->vb2q.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       usbtv->vb2q.io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ;
+       usbtv->vb2q.drv_priv = usbtv;
+       usbtv->vb2q.buf_struct_size = sizeof(struct usbtv_buf);
+       usbtv->vb2q.ops = &usbtv_vb2_ops;
+       usbtv->vb2q.mem_ops = &vb2_vmalloc_memops;
+       usbtv->vb2q.timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+       usbtv->vb2q.lock = &usbtv->vb2q_lock;
+       ret = vb2_queue_init(&usbtv->vb2q);
+       if (ret < 0) {
+               dev_warn(dev, "Could not initialize videobuf2 queue\n");
+               goto usbtv_fail;
+       }
+
+       /* v4l2 structure */
+       usbtv->v4l2_dev.release = usbtv_release;
+       ret = v4l2_device_register(dev, &usbtv->v4l2_dev);
+       if (ret < 0) {
+               dev_warn(dev, "Could not register v4l2 device\n");
+               goto v4l2_fail;
+       }
+
+       usb_set_intfdata(intf, usbtv);
+
+       /* Video structure */
+       strlcpy(usbtv->vdev.name, "usbtv", sizeof(usbtv->vdev.name));
+       usbtv->vdev.v4l2_dev = &usbtv->v4l2_dev;
+       usbtv->vdev.release = video_device_release_empty;
+       usbtv->vdev.fops = &usbtv_fops;
+       usbtv->vdev.ioctl_ops = &usbtv_ioctl_ops;
+       usbtv->vdev.tvnorms = V4L2_STD_525_60;
+       usbtv->vdev.queue = &usbtv->vb2q;
+       usbtv->vdev.lock = &usbtv->v4l2_lock;
+       set_bit(V4L2_FL_USE_FH_PRIO, &usbtv->vdev.flags);
+       video_set_drvdata(&usbtv->vdev, usbtv);
+       ret = video_register_device(&usbtv->vdev, VFL_TYPE_GRABBER, -1);
+       if (ret < 0) {
+               dev_warn(dev, "Could not register video device\n");
+               goto vdev_fail;
+       }
+
+       dev_info(dev, "Fushicai USBTV007 Video Grabber\n");
+       return 0;
+
+vdev_fail:
+       v4l2_device_unregister(&usbtv->v4l2_dev);
+v4l2_fail:
+       vb2_queue_release(&usbtv->vb2q);
+usbtv_fail:
+       kfree(usbtv);
+
+       return ret;
+}
+
+static void usbtv_disconnect(struct usb_interface *intf)
+{
+       struct usbtv *usbtv = usb_get_intfdata(intf);
+
+       mutex_lock(&usbtv->vb2q_lock);
+       mutex_lock(&usbtv->v4l2_lock);
+
+       usbtv_stop(usbtv);
+       usb_set_intfdata(intf, NULL);
+       video_unregister_device(&usbtv->vdev);
+       v4l2_device_disconnect(&usbtv->v4l2_dev);
+       usb_put_dev(usbtv->udev);
+       usbtv->udev = NULL;
+
+       mutex_unlock(&usbtv->v4l2_lock);
+       mutex_unlock(&usbtv->vb2q_lock);
+
+       v4l2_device_put(&usbtv->v4l2_dev);
+}
+
+MODULE_AUTHOR("Lubomir Rintel");
+MODULE_DESCRIPTION("Fushicai USBTV007 Video Grabber Driver");
+MODULE_LICENSE("Dual BSD/GPL");
+
+struct usb_driver usbtv_usb_driver = {
+       .name = "usbtv",
+       .id_table = usbtv_id_table,
+       .probe = usbtv_probe,
+       .disconnect = usbtv_disconnect,
+};
+
+module_usb_driver(usbtv_usb_driver);
index d34c2af..5c9e312 100644 (file)
@@ -467,8 +467,6 @@ static int vidioc_g_register(struct file *file, void *priv,
        struct usb_usbvision *usbvision = video_drvdata(file);
        int err_code;
 
-       if (!v4l2_chip_match_host(&reg->match))
-               return -EINVAL;
        /* NT100x has a 8-bit register space */
        err_code = usbvision_read_reg(usbvision, reg->reg&0xff);
        if (err_code < 0) {
@@ -488,8 +486,6 @@ static int vidioc_s_register(struct file *file, void *priv,
        struct usb_usbvision *usbvision = video_drvdata(file);
        int err_code;
 
-       if (!v4l2_chip_match_host(&reg->match))
-               return -EINVAL;
        /* NT100x has a 8-bit register space */
        err_code = usbvision_write_reg(usbvision, reg->reg & 0xff, reg->val);
        if (err_code < 0) {
@@ -608,6 +604,14 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id id)
        return 0;
 }
 
+static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id)
+{
+       struct usb_usbvision *usbvision = video_drvdata(file);
+
+       *id = usbvision->tvnorm_id;
+       return 0;
+}
+
 static int vidioc_g_tuner(struct file *file, void *priv,
                                struct v4l2_tuner *vt)
 {
@@ -1248,6 +1252,7 @@ static const struct v4l2_ioctl_ops usbvision_ioctl_ops = {
        .vidioc_qbuf          = vidioc_qbuf,
        .vidioc_dqbuf         = vidioc_dqbuf,
        .vidioc_s_std         = vidioc_s_std,
+       .vidioc_g_std         = vidioc_g_std,
        .vidioc_enum_input    = vidioc_enum_input,
        .vidioc_g_input       = vidioc_g_input,
        .vidioc_s_input       = vidioc_s_input,
@@ -1274,7 +1279,6 @@ static struct video_device usbvision_video_template = {
        .name           = "usbvision-video",
        .release        = video_device_release,
        .tvnorms        = USBVISION_NORMS,
-       .current_norm   = V4L2_STD_PAL
 };
 
 
@@ -1307,9 +1311,6 @@ static struct video_device usbvision_radio_template = {
        .name           = "usbvision-radio",
        .release        = video_device_release,
        .ioctl_ops      = &usbvision_radio_ioctl_ops,
-
-       .tvnorms              = USBVISION_NORMS,
-       .current_norm         = V4L2_STD_PAL
 };
 
 
@@ -1459,6 +1460,7 @@ static void usbvision_release(struct usb_usbvision *usbvision)
 
        usbvision_remove_sysfs(usbvision->vdev);
        usbvision_unregister_video(usbvision);
+       kfree(usbvision->alt_max_pkt_size);
 
        usb_free_urb(usbvision->ctrl_urb);
 
@@ -1574,6 +1576,7 @@ static int usbvision_probe(struct usb_interface *intf,
        usbvision->alt_max_pkt_size = kmalloc(32 * usbvision->num_alt, GFP_KERNEL);
        if (usbvision->alt_max_pkt_size == NULL) {
                dev_err(&intf->dev, "usbvision: out of memory!\n");
+               usbvision_release(usbvision);
                return -ENOMEM;
        }
 
index 541c9f1..6ed85ef 100644 (file)
@@ -1,5 +1,6 @@
 config USB_VIDEO_CLASS
        tristate "USB Video Class (UVC)"
+       depends on VIDEO_V4L2
        select VIDEOBUF2_VMALLOC
        ---help---
          Support for the USB Video Class (UVC).  Currently only video
index 5dbefa6..81695d4 100644 (file)
@@ -1836,8 +1836,8 @@ static int uvc_probe(struct usb_interface *intf,
        INIT_LIST_HEAD(&dev->chains);
        INIT_LIST_HEAD(&dev->streams);
        atomic_set(&dev->nstreams, 0);
-       atomic_set(&dev->users, 0);
        atomic_set(&dev->nmappings, 0);
+       mutex_init(&dev->lock);
 
        dev->udev = usb_get_dev(udev);
        dev->intf = usb_get_intf(intf);
@@ -1950,8 +1950,13 @@ static int uvc_suspend(struct usb_interface *intf, pm_message_t message)
 
        /* Controls are cached on the fly so they don't need to be saved. */
        if (intf->cur_altsetting->desc.bInterfaceSubClass ==
-           UVC_SC_VIDEOCONTROL)
-               return uvc_status_suspend(dev);
+           UVC_SC_VIDEOCONTROL) {
+               mutex_lock(&dev->lock);
+               if (dev->users)
+                       uvc_status_stop(dev);
+               mutex_unlock(&dev->lock);
+               return 0;
+       }
 
        list_for_each_entry(stream, &dev->streams, list) {
                if (stream->intf == intf)
@@ -1973,14 +1978,20 @@ static int __uvc_resume(struct usb_interface *intf, int reset)
 
        if (intf->cur_altsetting->desc.bInterfaceSubClass ==
            UVC_SC_VIDEOCONTROL) {
-               if (reset) {
-                       int ret = uvc_ctrl_resume_device(dev);
+               int ret = 0;
 
+               if (reset) {
+                       ret = uvc_ctrl_resume_device(dev);
                        if (ret < 0)
                                return ret;
                }
 
-               return uvc_status_resume(dev);
+               mutex_lock(&dev->lock);
+               if (dev->users)
+                       ret = uvc_status_start(dev, GFP_NOIO);
+               mutex_unlock(&dev->lock);
+
+               return ret;
        }
 
        list_for_each_entry(stream, &dev->streams, list) {
@@ -2163,6 +2174,24 @@ static struct usb_device_id uvc_ids[] = {
          .bInterfaceSubClass   = 1,
          .bInterfaceProtocol   = 0,
          .driver_info          = UVC_QUIRK_PROBE_DEF },
+       /* Dell Alienware X51 */
+       { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
+                               | USB_DEVICE_ID_MATCH_INT_INFO,
+         .idVendor             = 0x05a9,
+         .idProduct            = 0x2643,
+         .bInterfaceClass      = USB_CLASS_VIDEO,
+         .bInterfaceSubClass   = 1,
+         .bInterfaceProtocol   = 0,
+         .driver_info  = UVC_QUIRK_PROBE_DEF },
+       /* Dell Studio Hybrid 140g (OmniVision webcam) */
+       { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
+                               | USB_DEVICE_ID_MATCH_INT_INFO,
+         .idVendor             = 0x05a9,
+         .idProduct            = 0x264a,
+         .bInterfaceClass      = USB_CLASS_VIDEO,
+         .bInterfaceSubClass   = 1,
+         .bInterfaceProtocol   = 0,
+         .driver_info          = UVC_QUIRK_PROBE_DEF },
        /* Apple Built-In iSight */
        { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
                                | USB_DEVICE_ID_MATCH_INT_INFO,
index b749277..f552ab9 100644 (file)
@@ -206,32 +206,15 @@ void uvc_status_cleanup(struct uvc_device *dev)
        uvc_input_cleanup(dev);
 }
 
-int uvc_status_start(struct uvc_device *dev)
+int uvc_status_start(struct uvc_device *dev, gfp_t flags)
 {
        if (dev->int_urb == NULL)
                return 0;
 
-       return usb_submit_urb(dev->int_urb, GFP_KERNEL);
+       return usb_submit_urb(dev->int_urb, flags);
 }
 
 void uvc_status_stop(struct uvc_device *dev)
 {
        usb_kill_urb(dev->int_urb);
 }
-
-int uvc_status_suspend(struct uvc_device *dev)
-{
-       if (atomic_read(&dev->users))
-               usb_kill_urb(dev->int_urb);
-
-       return 0;
-}
-
-int uvc_status_resume(struct uvc_device *dev)
-{
-       if (dev->int_urb == NULL || atomic_read(&dev->users) == 0)
-               return 0;
-
-       return usb_submit_urb(dev->int_urb, GFP_NOIO);
-}
-
index b2dc326..3afff92 100644 (file)
@@ -498,16 +498,20 @@ static int uvc_v4l2_open(struct file *file)
                return -ENOMEM;
        }
 
-       if (atomic_inc_return(&stream->dev->users) == 1) {
-               ret = uvc_status_start(stream->dev);
+       mutex_lock(&stream->dev->lock);
+       if (stream->dev->users == 0) {
+               ret = uvc_status_start(stream->dev, GFP_KERNEL);
                if (ret < 0) {
-                       atomic_dec(&stream->dev->users);
+                       mutex_unlock(&stream->dev->lock);
                        usb_autopm_put_interface(stream->dev->intf);
                        kfree(handle);
                        return ret;
                }
        }
 
+       stream->dev->users++;
+       mutex_unlock(&stream->dev->lock);
+
        v4l2_fh_init(&handle->vfh, stream->vdev);
        v4l2_fh_add(&handle->vfh);
        handle->chain = stream->chain;
@@ -538,8 +542,10 @@ static int uvc_v4l2_release(struct file *file)
        kfree(handle);
        file->private_data = NULL;
 
-       if (atomic_dec_return(&stream->dev->users) == 0)
+       mutex_lock(&stream->dev->lock);
+       if (--stream->dev->users == 0)
                uvc_status_stop(stream->dev);
+       mutex_unlock(&stream->dev->lock);
 
        usb_autopm_put_interface(stream->dev->intf);
        return 0;
index af505fd..9e35982 100644 (file)
@@ -514,7 +514,8 @@ struct uvc_device {
        char name[32];
 
        enum uvc_device_state state;
-       atomic_t users;
+       struct mutex lock;              /* Protects users */
+       unsigned int users;
        atomic_t nmappings;
 
        /* Video control interface */
@@ -660,10 +661,8 @@ void uvc_video_clock_update(struct uvc_streaming *stream,
 /* Status */
 extern int uvc_status_init(struct uvc_device *dev);
 extern void uvc_status_cleanup(struct uvc_device *dev);
-extern int uvc_status_start(struct uvc_device *dev);
+extern int uvc_status_start(struct uvc_device *dev, gfp_t flags);
 extern void uvc_status_stop(struct uvc_device *dev);
-extern int uvc_status_suspend(struct uvc_device *dev);
-extern int uvc_status_resume(struct uvc_device *dev);
 
 /* Controls */
 extern const struct v4l2_subscribed_event_ops uvc_ctrl_sub_ev_ops;
index aa50c46..4c33b8d 100644 (file)
@@ -5,7 +5,8 @@
 tuner-objs     :=      tuner-core.o
 
 videodev-objs  :=      v4l2-dev.o v4l2-ioctl.o v4l2-device.o v4l2-fh.o \
-                       v4l2-event.o v4l2-ctrls.o v4l2-subdev.o
+                       v4l2-event.o v4l2-ctrls.o v4l2-subdev.o v4l2-clk.o \
+                       v4l2-async.o
 ifeq ($(CONFIG_COMPAT),y)
   videodev-objs += v4l2-compat-ioctl32.o
 endif
diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
new file mode 100644 (file)
index 0000000..aae2417
--- /dev/null
@@ -0,0 +1,284 @@
+/*
+ * V4L2 asynchronous subdevice registration API
+ *
+ * Copyright (C) 2012-2013, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+#include <media/v4l2-async.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+
+static bool match_i2c(struct device *dev, struct v4l2_async_subdev *asd)
+{
+#if IS_ENABLED(CONFIG_I2C)
+       struct i2c_client *client = i2c_verify_client(dev);
+       return client &&
+               asd->bus_type == V4L2_ASYNC_BUS_I2C &&
+               asd->match.i2c.adapter_id == client->adapter->nr &&
+               asd->match.i2c.address == client->addr;
+#else
+       return false;
+#endif
+}
+
+static bool match_platform(struct device *dev, struct v4l2_async_subdev *asd)
+{
+       return asd->bus_type == V4L2_ASYNC_BUS_PLATFORM &&
+               !strcmp(asd->match.platform.name, dev_name(dev));
+}
+
+static LIST_HEAD(subdev_list);
+static LIST_HEAD(notifier_list);
+static DEFINE_MUTEX(list_lock);
+
+static struct v4l2_async_subdev *v4l2_async_belongs(struct v4l2_async_notifier *notifier,
+                                                   struct v4l2_async_subdev_list *asdl)
+{
+       struct v4l2_subdev *sd = v4l2_async_to_subdev(asdl);
+       struct v4l2_async_subdev *asd;
+       bool (*match)(struct device *,
+                     struct v4l2_async_subdev *);
+
+       list_for_each_entry(asd, &notifier->waiting, list) {
+               /* bus_type has been verified valid before */
+               switch (asd->bus_type) {
+               case V4L2_ASYNC_BUS_CUSTOM:
+                       match = asd->match.custom.match;
+                       if (!match)
+                               /* Match always */
+                               return asd;
+                       break;
+               case V4L2_ASYNC_BUS_PLATFORM:
+                       match = match_platform;
+                       break;
+               case V4L2_ASYNC_BUS_I2C:
+                       match = match_i2c;
+                       break;
+               default:
+                       /* Cannot happen, unless someone breaks us */
+                       WARN_ON(true);
+                       return NULL;
+               }
+
+               /* match cannot be NULL here */
+               if (match(sd->dev, asd))
+                       return asd;
+       }
+
+       return NULL;
+}
+
+static int v4l2_async_test_notify(struct v4l2_async_notifier *notifier,
+                                 struct v4l2_async_subdev_list *asdl,
+                                 struct v4l2_async_subdev *asd)
+{
+       struct v4l2_subdev *sd = v4l2_async_to_subdev(asdl);
+       int ret;
+
+       /* Remove from the waiting list */
+       list_del(&asd->list);
+       asdl->asd = asd;
+       asdl->notifier = notifier;
+
+       if (notifier->bound) {
+               ret = notifier->bound(notifier, sd, asd);
+               if (ret < 0)
+                       return ret;
+       }
+       /* Move from the global subdevice list to notifier's done */
+       list_move(&asdl->list, &notifier->done);
+
+       ret = v4l2_device_register_subdev(notifier->v4l2_dev, sd);
+       if (ret < 0) {
+               if (notifier->unbind)
+                       notifier->unbind(notifier, sd, asd);
+               return ret;
+       }
+
+       if (list_empty(&notifier->waiting) && notifier->complete)
+               return notifier->complete(notifier);
+
+       return 0;
+}
+
+static void v4l2_async_cleanup(struct v4l2_async_subdev_list *asdl)
+{
+       struct v4l2_subdev *sd = v4l2_async_to_subdev(asdl);
+
+       v4l2_device_unregister_subdev(sd);
+       /* Subdevice driver will reprobe and put asdl back onto the list */
+       list_del_init(&asdl->list);
+       asdl->asd = NULL;
+       sd->dev = NULL;
+}
+
+int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
+                                struct v4l2_async_notifier *notifier)
+{
+       struct v4l2_async_subdev_list *asdl, *tmp;
+       struct v4l2_async_subdev *asd;
+       int i;
+
+       if (!notifier->num_subdevs || notifier->num_subdevs > V4L2_MAX_SUBDEVS)
+               return -EINVAL;
+
+       notifier->v4l2_dev = v4l2_dev;
+       INIT_LIST_HEAD(&notifier->waiting);
+       INIT_LIST_HEAD(&notifier->done);
+
+       for (i = 0; i < notifier->num_subdevs; i++) {
+               asd = notifier->subdev[i];
+
+               switch (asd->bus_type) {
+               case V4L2_ASYNC_BUS_CUSTOM:
+               case V4L2_ASYNC_BUS_PLATFORM:
+               case V4L2_ASYNC_BUS_I2C:
+                       break;
+               default:
+                       dev_err(notifier->v4l2_dev ? notifier->v4l2_dev->dev : NULL,
+                               "Invalid bus-type %u on %p\n",
+                               asd->bus_type, asd);
+                       return -EINVAL;
+               }
+               list_add_tail(&asd->list, &notifier->waiting);
+       }
+
+       mutex_lock(&list_lock);
+
+       /* Keep also completed notifiers on the list */
+       list_add(&notifier->list, &notifier_list);
+
+       list_for_each_entry_safe(asdl, tmp, &subdev_list, list) {
+               int ret;
+
+               asd = v4l2_async_belongs(notifier, asdl);
+               if (!asd)
+                       continue;
+
+               ret = v4l2_async_test_notify(notifier, asdl, asd);
+               if (ret < 0) {
+                       mutex_unlock(&list_lock);
+                       return ret;
+               }
+       }
+
+       mutex_unlock(&list_lock);
+
+       return 0;
+}
+EXPORT_SYMBOL(v4l2_async_notifier_register);
+
+void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier)
+{
+       struct v4l2_async_subdev_list *asdl, *tmp;
+       unsigned int notif_n_subdev = notifier->num_subdevs;
+       unsigned int n_subdev = min(notif_n_subdev, V4L2_MAX_SUBDEVS);
+       struct device *dev[n_subdev];
+       int i = 0;
+
+       mutex_lock(&list_lock);
+
+       list_del(&notifier->list);
+
+       list_for_each_entry_safe(asdl, tmp, &notifier->done, list) {
+               struct v4l2_subdev *sd = v4l2_async_to_subdev(asdl);
+
+               dev[i] = get_device(sd->dev);
+
+               v4l2_async_cleanup(asdl);
+
+               /* If we handled USB devices, we'd have to lock the parent too */
+               device_release_driver(dev[i++]);
+
+               if (notifier->unbind)
+                       notifier->unbind(notifier, sd, sd->asdl.asd);
+       }
+
+       mutex_unlock(&list_lock);
+
+       while (i--) {
+               struct device *d = dev[i];
+
+               if (d && device_attach(d) < 0) {
+                       const char *name = "(none)";
+                       int lock = device_trylock(d);
+
+                       if (lock && d->driver)
+                               name = d->driver->name;
+                       dev_err(d, "Failed to re-probe to %s\n", name);
+                       if (lock)
+                               device_unlock(d);
+               }
+               put_device(d);
+       }
+       /*
+        * Don't care about the waiting list, it is initialised and populated
+        * upon notifier registration.
+        */
+}
+EXPORT_SYMBOL(v4l2_async_notifier_unregister);
+
+int v4l2_async_register_subdev(struct v4l2_subdev *sd)
+{
+       struct v4l2_async_subdev_list *asdl = &sd->asdl;
+       struct v4l2_async_notifier *notifier;
+
+       mutex_lock(&list_lock);
+
+       INIT_LIST_HEAD(&asdl->list);
+
+       list_for_each_entry(notifier, &notifier_list, list) {
+               struct v4l2_async_subdev *asd = v4l2_async_belongs(notifier, asdl);
+               if (asd) {
+                       int ret = v4l2_async_test_notify(notifier, asdl, asd);
+                       mutex_unlock(&list_lock);
+                       return ret;
+               }
+       }
+
+       /* None matched, wait for hot-plugging */
+       list_add(&asdl->list, &subdev_list);
+
+       mutex_unlock(&list_lock);
+
+       return 0;
+}
+EXPORT_SYMBOL(v4l2_async_register_subdev);
+
+void v4l2_async_unregister_subdev(struct v4l2_subdev *sd)
+{
+       struct v4l2_async_subdev_list *asdl = &sd->asdl;
+       struct v4l2_async_notifier *notifier = asdl->notifier;
+
+       if (!asdl->asd) {
+               if (!list_empty(&asdl->list))
+                       v4l2_async_cleanup(asdl);
+               return;
+       }
+
+       mutex_lock(&list_lock);
+
+       list_add(&asdl->asd->list, &notifier->waiting);
+
+       v4l2_async_cleanup(asdl);
+
+       if (notifier->unbind)
+               notifier->unbind(notifier, sd, sd->asdl.asd);
+
+       mutex_unlock(&list_lock);
+}
+EXPORT_SYMBOL(v4l2_async_unregister_subdev);
diff --git a/drivers/media/v4l2-core/v4l2-clk.c b/drivers/media/v4l2-core/v4l2-clk.c
new file mode 100644 (file)
index 0000000..b67de86
--- /dev/null
@@ -0,0 +1,242 @@
+/*
+ * V4L2 clock service
+ *
+ * Copyright (C) 2012-2013, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/atomic.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+
+#include <media/v4l2-clk.h>
+#include <media/v4l2-subdev.h>
+
+static DEFINE_MUTEX(clk_lock);
+static LIST_HEAD(clk_list);
+
+static struct v4l2_clk *v4l2_clk_find(const char *dev_id, const char *id)
+{
+       struct v4l2_clk *clk;
+
+       list_for_each_entry(clk, &clk_list, list) {
+               if (strcmp(dev_id, clk->dev_id))
+                       continue;
+
+               if (!id || !clk->id || !strcmp(clk->id, id))
+                       return clk;
+       }
+
+       return ERR_PTR(-ENODEV);
+}
+
+struct v4l2_clk *v4l2_clk_get(struct device *dev, const char *id)
+{
+       struct v4l2_clk *clk;
+
+       mutex_lock(&clk_lock);
+       clk = v4l2_clk_find(dev_name(dev), id);
+
+       if (!IS_ERR(clk))
+               atomic_inc(&clk->use_count);
+       mutex_unlock(&clk_lock);
+
+       return clk;
+}
+EXPORT_SYMBOL(v4l2_clk_get);
+
+void v4l2_clk_put(struct v4l2_clk *clk)
+{
+       struct v4l2_clk *tmp;
+
+       if (IS_ERR(clk))
+               return;
+
+       mutex_lock(&clk_lock);
+
+       list_for_each_entry(tmp, &clk_list, list)
+               if (tmp == clk)
+                       atomic_dec(&clk->use_count);
+
+       mutex_unlock(&clk_lock);
+}
+EXPORT_SYMBOL(v4l2_clk_put);
+
+static int v4l2_clk_lock_driver(struct v4l2_clk *clk)
+{
+       struct v4l2_clk *tmp;
+       int ret = -ENODEV;
+
+       mutex_lock(&clk_lock);
+
+       list_for_each_entry(tmp, &clk_list, list)
+               if (tmp == clk) {
+                       ret = !try_module_get(clk->ops->owner);
+                       if (ret)
+                               ret = -EFAULT;
+                       break;
+               }
+
+       mutex_unlock(&clk_lock);
+
+       return ret;
+}
+
+static void v4l2_clk_unlock_driver(struct v4l2_clk *clk)
+{
+       module_put(clk->ops->owner);
+}
+
+int v4l2_clk_enable(struct v4l2_clk *clk)
+{
+       int ret = v4l2_clk_lock_driver(clk);
+
+       if (ret < 0)
+               return ret;
+
+       mutex_lock(&clk->lock);
+
+       if (++clk->enable == 1 && clk->ops->enable) {
+               ret = clk->ops->enable(clk);
+               if (ret < 0)
+                       clk->enable--;
+       }
+
+       mutex_unlock(&clk->lock);
+
+       return ret;
+}
+EXPORT_SYMBOL(v4l2_clk_enable);
+
+/*
+ * You might Oops if you try to disabled a disabled clock, because then the
+ * driver isn't locked and could have been unloaded by now, so, don't do that
+ */
+void v4l2_clk_disable(struct v4l2_clk *clk)
+{
+       int enable;
+
+       mutex_lock(&clk->lock);
+
+       enable = --clk->enable;
+       if (WARN(enable < 0, "Unbalanced %s() on %s:%s!\n", __func__,
+                clk->dev_id, clk->id))
+               clk->enable++;
+       else if (!enable && clk->ops->disable)
+               clk->ops->disable(clk);
+
+       mutex_unlock(&clk->lock);
+
+       v4l2_clk_unlock_driver(clk);
+}
+EXPORT_SYMBOL(v4l2_clk_disable);
+
+unsigned long v4l2_clk_get_rate(struct v4l2_clk *clk)
+{
+       int ret = v4l2_clk_lock_driver(clk);
+
+       if (ret < 0)
+               return ret;
+
+       mutex_lock(&clk->lock);
+       if (!clk->ops->get_rate)
+               ret = -ENOSYS;
+       else
+               ret = clk->ops->get_rate(clk);
+       mutex_unlock(&clk->lock);
+
+       v4l2_clk_unlock_driver(clk);
+
+       return ret;
+}
+EXPORT_SYMBOL(v4l2_clk_get_rate);
+
+int v4l2_clk_set_rate(struct v4l2_clk *clk, unsigned long rate)
+{
+       int ret = v4l2_clk_lock_driver(clk);
+
+       if (ret < 0)
+               return ret;
+
+       mutex_lock(&clk->lock);
+       if (!clk->ops->set_rate)
+               ret = -ENOSYS;
+       else
+               ret = clk->ops->set_rate(clk, rate);
+       mutex_unlock(&clk->lock);
+
+       v4l2_clk_unlock_driver(clk);
+
+       return ret;
+}
+EXPORT_SYMBOL(v4l2_clk_set_rate);
+
+struct v4l2_clk *v4l2_clk_register(const struct v4l2_clk_ops *ops,
+                                  const char *dev_id,
+                                  const char *id, void *priv)
+{
+       struct v4l2_clk *clk;
+       int ret;
+
+       if (!ops || !dev_id)
+               return ERR_PTR(-EINVAL);
+
+       clk = kzalloc(sizeof(struct v4l2_clk), GFP_KERNEL);
+       if (!clk)
+               return ERR_PTR(-ENOMEM);
+
+       clk->id = kstrdup(id, GFP_KERNEL);
+       clk->dev_id = kstrdup(dev_id, GFP_KERNEL);
+       if ((id && !clk->id) || !clk->dev_id) {
+               ret = -ENOMEM;
+               goto ealloc;
+       }
+       clk->ops = ops;
+       clk->priv = priv;
+       atomic_set(&clk->use_count, 0);
+       mutex_init(&clk->lock);
+
+       mutex_lock(&clk_lock);
+       if (!IS_ERR(v4l2_clk_find(dev_id, id))) {
+               mutex_unlock(&clk_lock);
+               ret = -EEXIST;
+               goto eexist;
+       }
+       list_add_tail(&clk->list, &clk_list);
+       mutex_unlock(&clk_lock);
+
+       return clk;
+
+eexist:
+ealloc:
+       kfree(clk->id);
+       kfree(clk->dev_id);
+       kfree(clk);
+       return ERR_PTR(ret);
+}
+EXPORT_SYMBOL(v4l2_clk_register);
+
+void v4l2_clk_unregister(struct v4l2_clk *clk)
+{
+       if (WARN(atomic_read(&clk->use_count),
+                "%s(): Refusing to unregister ref-counted %s:%s clock!\n",
+                __func__, clk->dev_id, clk->id))
+               return;
+
+       mutex_lock(&clk_lock);
+       list_del(&clk->list);
+       mutex_unlock(&clk_lock);
+
+       kfree(clk->id);
+       kfree(clk->dev_id);
+       kfree(clk);
+}
+EXPORT_SYMBOL(v4l2_clk_unregister);
index 3fed63f..a95e5e2 100644 (file)
@@ -61,7 +61,6 @@
 #include <media/v4l2-common.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-ctrls.h>
-#include <media/v4l2-chip-ident.h>
 
 #include <linux/videodev2.h>
 
@@ -227,62 +226,9 @@ u32 v4l2_ctrl_next(const u32 * const * ctrl_classes, u32 id)
 }
 EXPORT_SYMBOL(v4l2_ctrl_next);
 
-int v4l2_chip_match_host(const struct v4l2_dbg_match *match)
-{
-       switch (match->type) {
-       case V4L2_CHIP_MATCH_BRIDGE:
-               return match->addr == 0;
-       default:
-               return 0;
-       }
-}
-EXPORT_SYMBOL(v4l2_chip_match_host);
-
-#if IS_ENABLED(CONFIG_I2C)
-int v4l2_chip_match_i2c_client(struct i2c_client *c, const struct v4l2_dbg_match *match)
-{
-       int len;
-
-       if (c == NULL || match == NULL)
-               return 0;
-
-       switch (match->type) {
-       case V4L2_CHIP_MATCH_I2C_DRIVER:
-               if (c->driver == NULL || c->driver->driver.name == NULL)
-                       return 0;
-               len = strlen(c->driver->driver.name);
-               return len && !strncmp(c->driver->driver.name, match->name, len);
-       case V4L2_CHIP_MATCH_I2C_ADDR:
-               return c->addr == match->addr;
-       case V4L2_CHIP_MATCH_SUBDEV:
-               return 1;
-       default:
-               return 0;
-       }
-}
-EXPORT_SYMBOL(v4l2_chip_match_i2c_client);
-
-int v4l2_chip_ident_i2c_client(struct i2c_client *c, struct v4l2_dbg_chip_ident *chip,
-               u32 ident, u32 revision)
-{
-       if (!v4l2_chip_match_i2c_client(c, &chip->match))
-               return 0;
-       if (chip->ident == V4L2_IDENT_NONE) {
-               chip->ident = ident;
-               chip->revision = revision;
-       }
-       else {
-               chip->ident = V4L2_IDENT_AMBIGUOUS;
-               chip->revision = 0;
-       }
-       return 0;
-}
-EXPORT_SYMBOL(v4l2_chip_ident_i2c_client);
-
-/* ----------------------------------------------------------------- */
-
 /* I2C Helper functions */
 
+#if IS_ENABLED(CONFIG_I2C)
 
 void v4l2_i2c_subdev_init(struct v4l2_subdev *sd, struct i2c_client *client,
                const struct v4l2_subdev_ops *ops)
@@ -291,6 +237,7 @@ void v4l2_i2c_subdev_init(struct v4l2_subdev *sd, struct i2c_client *client,
        sd->flags |= V4L2_SUBDEV_FL_IS_I2C;
        /* the owner is the same as the i2c_client's driver owner */
        sd->owner = client->driver->driver.owner;
+       sd->dev = &client->dev;
        /* i2c_client and v4l2_subdev point to one another */
        v4l2_set_subdevdata(sd, client);
        i2c_set_clientdata(client, sd);
@@ -301,8 +248,6 @@ void v4l2_i2c_subdev_init(struct v4l2_subdev *sd, struct i2c_client *client,
 }
 EXPORT_SYMBOL_GPL(v4l2_i2c_subdev_init);
 
-
-
 /* Load an i2c sub-device. */
 struct v4l2_subdev *v4l2_i2c_new_subdev_board(struct v4l2_device *v4l2_dev,
                struct i2c_adapter *adapter, struct i2c_board_info *info,
@@ -426,6 +371,7 @@ void v4l2_spi_subdev_init(struct v4l2_subdev *sd, struct spi_device *spi,
        sd->flags |= V4L2_SUBDEV_FL_IS_SPI;
        /* the owner is the same as the spi_device's driver owner */
        sd->owner = spi->dev.driver->owner;
+       sd->dev = &spi->dev;
        /* spi_device and v4l2_subdev point to one another */
        v4l2_set_subdevdata(sd, spi);
        spi_set_drvdata(spi, sd);
index f129551..8f7a6a4 100644 (file)
@@ -1074,7 +1074,6 @@ long v4l2_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg)
        case VIDIOC_TRY_DECODER_CMD:
        case VIDIOC_DBG_S_REGISTER:
        case VIDIOC_DBG_G_REGISTER:
-       case VIDIOC_DBG_G_CHIP_IDENT:
        case VIDIOC_S_HW_FREQ_SEEK:
        case VIDIOC_S_DV_TIMINGS:
        case VIDIOC_G_DV_TIMINGS:
index 5923c5d..c8859d6 100644 (file)
@@ -495,8 +495,8 @@ static const struct file_operations v4l2_fops = {
 };
 
 /**
- * get_index - assign stream index number based on parent device
- * @vdev: video_device to assign index number to, vdev->parent should be assigned
+ * get_index - assign stream index number based on v4l2_dev
+ * @vdev: video_device to assign index number to, vdev->v4l2_dev should be assigned
  *
  * Note that when this is called the new device has not yet been registered
  * in the video_device array, but it was able to obtain a minor number.
@@ -514,15 +514,11 @@ static int get_index(struct video_device *vdev)
        static DECLARE_BITMAP(used, VIDEO_NUM_DEVICES);
        int i;
 
-       /* Some drivers do not set the parent. In that case always return 0. */
-       if (vdev->parent == NULL)
-               return 0;
-
        bitmap_zero(used, VIDEO_NUM_DEVICES);
 
        for (i = 0; i < VIDEO_NUM_DEVICES; i++) {
                if (video_device[i] != NULL &&
-                   video_device[i]->parent == vdev->parent) {
+                   video_device[i]->v4l2_dev == vdev->v4l2_dev) {
                        set_bit(video_device[i]->index, used);
                }
        }
@@ -596,7 +592,6 @@ static void determine_valid_ioctls(struct video_device *vdev)
        set_bit(_IOC_NR(VIDIOC_DBG_G_REGISTER), valid_ioctls);
        set_bit(_IOC_NR(VIDIOC_DBG_S_REGISTER), valid_ioctls);
 #endif
-       SET_VALID_IOCTL(ops, VIDIOC_DBG_G_CHIP_IDENT, vidioc_g_chip_ident);
        /* yes, really vidioc_subscribe_event */
        SET_VALID_IOCTL(ops, VIDIOC_DQEVENT, vidioc_subscribe_event);
        SET_VALID_IOCTL(ops, VIDIOC_SUBSCRIBE_EVENT, vidioc_subscribe_event);
@@ -675,9 +670,8 @@ static void determine_valid_ioctls(struct video_device *vdev)
                SET_VALID_IOCTL(ops, VIDIOC_PREPARE_BUF, vidioc_prepare_buf);
                if (ops->vidioc_s_std)
                        set_bit(_IOC_NR(VIDIOC_ENUMSTD), valid_ioctls);
-               if (ops->vidioc_g_std || vdev->current_norm)
-                       set_bit(_IOC_NR(VIDIOC_G_STD), valid_ioctls);
                SET_VALID_IOCTL(ops, VIDIOC_S_STD, vidioc_s_std);
+               SET_VALID_IOCTL(ops, VIDIOC_G_STD, vidioc_g_std);
                if (is_rx) {
                        SET_VALID_IOCTL(ops, VIDIOC_QUERYSTD, vidioc_querystd);
                        SET_VALID_IOCTL(ops, VIDIOC_ENUMINPUT, vidioc_enum_input);
@@ -705,7 +699,7 @@ static void determine_valid_ioctls(struct video_device *vdev)
                if (ops->vidioc_cropcap || ops->vidioc_g_selection)
                        set_bit(_IOC_NR(VIDIOC_CROPCAP), valid_ioctls);
                if (ops->vidioc_g_parm || (vdev->vfl_type == VFL_TYPE_GRABBER &&
-                                       (ops->vidioc_g_std || vdev->current_norm)))
+                                       ops->vidioc_g_std))
                        set_bit(_IOC_NR(VIDIOC_G_PARM), valid_ioctls);
                SET_VALID_IOCTL(ops, VIDIOC_S_PARM, vidioc_s_parm);
                SET_VALID_IOCTL(ops, VIDIOC_S_DV_TIMINGS, vidioc_s_dv_timings);
@@ -777,6 +771,9 @@ int __video_register_device(struct video_device *vdev, int type, int nr,
        /* the release callback MUST be present */
        if (WARN_ON(!vdev->release))
                return -EINVAL;
+       /* the v4l2_dev pointer MUST be present */
+       if (WARN_ON(!vdev->v4l2_dev))
+               return -EINVAL;
 
        /* v4l2_fh support */
        spin_lock_init(&vdev->fh_lock);
@@ -804,16 +801,14 @@ int __video_register_device(struct video_device *vdev, int type, int nr,
 
        vdev->vfl_type = type;
        vdev->cdev = NULL;
-       if (vdev->v4l2_dev) {
-               if (vdev->v4l2_dev->dev)
-                       vdev->parent = vdev->v4l2_dev->dev;
-               if (vdev->ctrl_handler == NULL)
-                       vdev->ctrl_handler = vdev->v4l2_dev->ctrl_handler;
-               /* If the prio state pointer is NULL, then use the v4l2_device
-                  prio state. */
-               if (vdev->prio == NULL)
-                       vdev->prio = &vdev->v4l2_dev->prio;
-       }
+       if (vdev->dev_parent == NULL)
+               vdev->dev_parent = vdev->v4l2_dev->dev;
+       if (vdev->ctrl_handler == NULL)
+               vdev->ctrl_handler = vdev->v4l2_dev->ctrl_handler;
+       /* If the prio state pointer is NULL, then use the v4l2_device
+          prio state. */
+       if (vdev->prio == NULL)
+               vdev->prio = &vdev->v4l2_dev->prio;
 
        /* Part 2: find a free minor, device node number and device index. */
 #ifdef CONFIG_VIDEO_FIXED_MINOR_RANGES
@@ -898,8 +893,7 @@ int __video_register_device(struct video_device *vdev, int type, int nr,
        /* Part 4: register the device with sysfs */
        vdev->dev.class = &video_class;
        vdev->dev.devt = MKDEV(VIDEO_MAJOR, vdev->minor);
-       if (vdev->parent)
-               vdev->dev.parent = vdev->parent;
+       vdev->dev.parent = vdev->dev_parent;
        dev_set_name(&vdev->dev, "%s%d", name_base, vdev->num);
        ret = device_register(&vdev->dev);
        if (ret < 0) {
index 8ed5da2..02d1b63 100644 (file)
@@ -44,7 +44,8 @@ int v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev)
        v4l2_dev->dev = dev;
        if (dev == NULL) {
                /* If dev == NULL, then name must be filled in by the caller */
-               WARN_ON(!v4l2_dev->name[0]);
+               if (WARN_ON(!v4l2_dev->name[0]))
+                       return -EINVAL;
                return 0;
        }
 
@@ -105,7 +106,9 @@ void v4l2_device_unregister(struct v4l2_device *v4l2_dev)
 {
        struct v4l2_subdev *sd, *next;
 
-       if (v4l2_dev == NULL)
+       /* Just return if v4l2_dev is NULL or if it was already
+        * unregistered before. */
+       if (v4l2_dev == NULL || !v4l2_dev->name[0])
                return;
        v4l2_device_disconnect(v4l2_dev);
 
@@ -135,6 +138,8 @@ void v4l2_device_unregister(struct v4l2_device *v4l2_dev)
                }
 #endif
        }
+       /* Mark as unregistered, thus preventing duplicate unregistrations */
+       v4l2_dev->name[0] = '\0';
 }
 EXPORT_SYMBOL_GPL(v4l2_device_unregister);
 
@@ -269,8 +274,10 @@ void v4l2_device_unregister_subdev(struct v4l2_subdev *sd)
        sd->v4l2_dev = NULL;
 
 #if defined(CONFIG_MEDIA_CONTROLLER)
-       if (v4l2_dev->mdev)
+       if (v4l2_dev->mdev) {
+               media_entity_remove_links(&sd->entity);
                media_device_unregister_entity(&sd->entity);
+       }
 #endif
        video_unregister_device(sd->devnode);
        module_put(sd->owner);
index 7658586..68e6b5e 100644 (file)
@@ -26,7 +26,6 @@
 #include <media/v4l2-fh.h>
 #include <media/v4l2-event.h>
 #include <media/v4l2-device.h>
-#include <media/v4l2-chip-ident.h>
 #include <media/videobuf2-core.h>
 
 /* Zero out the end of the struct pointed to by p.  Everything after, but
@@ -619,20 +618,6 @@ static void v4l_print_decoder_cmd(const void *arg, bool write_only)
                pr_info("pts=%llu\n", p->stop.pts);
 }
 
-static void v4l_print_dbg_chip_ident(const void *arg, bool write_only)
-{
-       const struct v4l2_dbg_chip_ident *p = arg;
-
-       pr_cont("type=%u, ", p->match.type);
-       if (p->match.type == V4L2_CHIP_MATCH_I2C_DRIVER)
-               pr_cont("name=%.*s, ",
-                               (int)sizeof(p->match.name), p->match.name);
-       else
-               pr_cont("addr=%u, ", p->match.addr);
-       pr_cont("chip_ident=%u, revision=0x%x\n",
-                       p->ident, p->revision);
-}
-
 static void v4l_print_dbg_chip_info(const void *arg, bool write_only)
 {
        const struct v4l2_dbg_chip_info *p = arg;
@@ -1359,40 +1344,18 @@ static int v4l_enumstd(const struct v4l2_ioctl_ops *ops,
        return 0;
 }
 
-static int v4l_g_std(const struct v4l2_ioctl_ops *ops,
-                               struct file *file, void *fh, void *arg)
-{
-       struct video_device *vfd = video_devdata(file);
-       v4l2_std_id *id = arg;
-
-       /* Calls the specific handler */
-       if (ops->vidioc_g_std)
-               return ops->vidioc_g_std(file, fh, arg);
-       if (vfd->current_norm) {
-               *id = vfd->current_norm;
-               return 0;
-       }
-       return -ENOTTY;
-}
-
 static int v4l_s_std(const struct v4l2_ioctl_ops *ops,
                                struct file *file, void *fh, void *arg)
 {
        struct video_device *vfd = video_devdata(file);
        v4l2_std_id id = *(v4l2_std_id *)arg, norm;
-       int ret;
 
        norm = id & vfd->tvnorms;
        if (vfd->tvnorms && !norm)      /* Check if std is supported */
                return -EINVAL;
 
        /* Calls the specific handler */
-       ret = ops->vidioc_s_std(file, fh, norm);
-
-       /* Updates standard information */
-       if (ret >= 0)
-               vfd->current_norm = norm;
-       return ret;
+       return ops->vidioc_s_std(file, fh, norm);
 }
 
 static int v4l_querystd(const struct v4l2_ioctl_ops *ops,
@@ -1402,10 +1365,10 @@ static int v4l_querystd(const struct v4l2_ioctl_ops *ops,
        v4l2_std_id *p = arg;
 
        /*
-        * If nothing detected, it should return all supported
-        * standard.
-        * Drivers just need to mask the std argument, in order
-        * to remove the standards that don't apply from the mask.
+        * If no signal is detected, then the driver should return
+        * V4L2_STD_UNKNOWN. Otherwise it should return tvnorms with
+        * any standards that do not apply removed.
+        *
         * This means that tuners, audio and video decoders can join
         * their efforts to improve the standards detection.
         */
@@ -1495,7 +1458,6 @@ static int v4l_prepare_buf(const struct v4l2_ioctl_ops *ops,
 static int v4l_g_parm(const struct v4l2_ioctl_ops *ops,
                                struct file *file, void *fh, void *arg)
 {
-       struct video_device *vfd = video_devdata(file);
        struct v4l2_streamparm *p = arg;
        v4l2_std_id std;
        int ret = check_fmt(file, p->type);
@@ -1504,16 +1466,13 @@ static int v4l_g_parm(const struct v4l2_ioctl_ops *ops,
                return ret;
        if (ops->vidioc_g_parm)
                return ops->vidioc_g_parm(file, fh, p);
-       std = vfd->current_norm;
        if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
            p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
                return -EINVAL;
        p->parm.capture.readbuffers = 2;
-       if (is_valid_ioctl(vfd, VIDIOC_G_STD) && ops->vidioc_g_std)
-               ret = ops->vidioc_g_std(file, fh, &std);
+       ret = ops->vidioc_g_std(file, fh, &std);
        if (ret == 0)
-               v4l2_video_std_frame_period(std,
-                           &p->parm.capture.timeperframe);
+               v4l2_video_std_frame_period(std, &p->parm.capture.timeperframe);
        return ret;
 }
 
@@ -1802,7 +1761,8 @@ static int v4l_dbg_g_register(const struct v4l2_ioctl_ops *ops,
                                return v4l2_subdev_call(sd, core, g_register, p);
                return -EINVAL;
        }
-       if (ops->vidioc_g_register)
+       if (ops->vidioc_g_register && p->match.type == V4L2_CHIP_MATCH_BRIDGE &&
+           (ops->vidioc_g_chip_info || p->match.addr == 0))
                return ops->vidioc_g_register(file, fh, p);
        return -EINVAL;
 #else
@@ -1829,7 +1789,8 @@ static int v4l_dbg_s_register(const struct v4l2_ioctl_ops *ops,
                                return v4l2_subdev_call(sd, core, s_register, p);
                return -EINVAL;
        }
-       if (ops->vidioc_s_register)
+       if (ops->vidioc_s_register && p->match.type == V4L2_CHIP_MATCH_BRIDGE &&
+           (ops->vidioc_g_chip_info || p->match.addr == 0))
                return ops->vidioc_s_register(file, fh, p);
        return -EINVAL;
 #else
@@ -1837,18 +1798,6 @@ static int v4l_dbg_s_register(const struct v4l2_ioctl_ops *ops,
 #endif
 }
 
-static int v4l_dbg_g_chip_ident(const struct v4l2_ioctl_ops *ops,
-                               struct file *file, void *fh, void *arg)
-{
-       struct v4l2_dbg_chip_ident *p = arg;
-
-       p->ident = V4L2_IDENT_NONE;
-       p->revision = 0;
-       if (p->match.type == V4L2_CHIP_MATCH_SUBDEV)
-               return -EINVAL;
-       return ops->vidioc_g_chip_ident(file, fh, p);
-}
-
 static int v4l_dbg_g_chip_info(const struct v4l2_ioctl_ops *ops,
                                struct file *file, void *fh, void *arg)
 {
@@ -1864,12 +1813,7 @@ static int v4l_dbg_g_chip_info(const struct v4l2_ioctl_ops *ops,
                        p->flags |= V4L2_CHIP_FL_WRITABLE;
                if (ops->vidioc_g_register)
                        p->flags |= V4L2_CHIP_FL_READABLE;
-               if (vfd->v4l2_dev)
-                       strlcpy(p->name, vfd->v4l2_dev->name, sizeof(p->name));
-               else if (vfd->parent)
-                       strlcpy(p->name, vfd->parent->driver->name, sizeof(p->name));
-               else
-                       strlcpy(p->name, "bridge", sizeof(p->name));
+               strlcpy(p->name, vfd->v4l2_dev->name, sizeof(p->name));
                if (ops->vidioc_g_chip_info)
                        return ops->vidioc_g_chip_info(file, fh, arg);
                if (p->match.addr)
@@ -2048,7 +1992,7 @@ static struct v4l2_ioctl_info v4l2_ioctls[] = {
        IOCTL_INFO_FNC(VIDIOC_STREAMOFF, v4l_streamoff, v4l_print_buftype, INFO_FL_PRIO | INFO_FL_QUEUE),
        IOCTL_INFO_FNC(VIDIOC_G_PARM, v4l_g_parm, v4l_print_streamparm, INFO_FL_CLEAR(v4l2_streamparm, type)),
        IOCTL_INFO_FNC(VIDIOC_S_PARM, v4l_s_parm, v4l_print_streamparm, INFO_FL_PRIO),
-       IOCTL_INFO_FNC(VIDIOC_G_STD, v4l_g_std, v4l_print_std, 0),
+       IOCTL_INFO_STD(VIDIOC_G_STD, vidioc_g_std, v4l_print_std, 0),
        IOCTL_INFO_FNC(VIDIOC_S_STD, v4l_s_std, v4l_print_std, INFO_FL_PRIO),
        IOCTL_INFO_FNC(VIDIOC_ENUMSTD, v4l_enumstd, v4l_print_standard, INFO_FL_CLEAR(v4l2_standard, index)),
        IOCTL_INFO_FNC(VIDIOC_ENUMINPUT, v4l_enuminput, v4l_print_enuminput, INFO_FL_CLEAR(v4l2_input, index)),
@@ -2098,7 +2042,6 @@ static struct v4l2_ioctl_info v4l2_ioctls[] = {
        IOCTL_INFO_STD(VIDIOC_TRY_DECODER_CMD, vidioc_try_decoder_cmd, v4l_print_decoder_cmd, 0),
        IOCTL_INFO_FNC(VIDIOC_DBG_S_REGISTER, v4l_dbg_s_register, v4l_print_dbg_register, 0),
        IOCTL_INFO_FNC(VIDIOC_DBG_G_REGISTER, v4l_dbg_g_register, v4l_print_dbg_register, 0),
-       IOCTL_INFO_FNC(VIDIOC_DBG_G_CHIP_IDENT, v4l_dbg_g_chip_ident, v4l_print_dbg_chip_ident, 0),
        IOCTL_INFO_FNC(VIDIOC_S_HW_FREQ_SEEK, v4l_s_hw_freq_seek, v4l_print_hw_freq_seek, INFO_FL_PRIO),
        IOCTL_INFO_STD(VIDIOC_S_DV_TIMINGS, vidioc_s_dv_timings, v4l_print_dv_timings, INFO_FL_PRIO),
        IOCTL_INFO_STD(VIDIOC_G_DV_TIMINGS, vidioc_g_dv_timings, v4l_print_dv_timings, 0),
index 67f572c..65411ad 100644 (file)
@@ -66,11 +66,14 @@ static void __videobuf_dc_free(struct device *dev,
 static void videobuf_vm_open(struct vm_area_struct *vma)
 {
        struct videobuf_mapping *map = vma->vm_private_data;
+       struct videobuf_queue *q = map->q;
 
-       dev_dbg(map->q->dev, "vm_open %p [count=%u,vma=%08lx-%08lx]\n",
+       dev_dbg(q->dev, "vm_open %p [count=%u,vma=%08lx-%08lx]\n",
                map, map->count, vma->vm_start, vma->vm_end);
 
+       videobuf_queue_lock(q);
        map->count++;
+       videobuf_queue_unlock(q);
 }
 
 static void videobuf_vm_close(struct vm_area_struct *vma)
@@ -82,12 +85,11 @@ static void videobuf_vm_close(struct vm_area_struct *vma)
        dev_dbg(q->dev, "vm_close %p [count=%u,vma=%08lx-%08lx]\n",
                map, map->count, vma->vm_start, vma->vm_end);
 
-       map->count--;
-       if (0 == map->count) {
+       videobuf_queue_lock(q);
+       if (!--map->count) {
                struct videobuf_dma_contig_memory *mem;
 
                dev_dbg(q->dev, "munmap %p q=%p\n", map, q);
-               videobuf_queue_lock(q);
 
                /* We need first to cancel streams, before unmapping */
                if (q->streaming)
@@ -126,8 +128,8 @@ static void videobuf_vm_close(struct vm_area_struct *vma)
 
                kfree(map);
 
-               videobuf_queue_unlock(q);
        }
+       videobuf_queue_unlock(q);
 }
 
 static const struct vm_operations_struct videobuf_vm_ops = {
@@ -303,14 +305,9 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q,
                goto error;
 
        /* Try to remap memory */
-
        size = vma->vm_end - vma->vm_start;
-       size = (size < mem->size) ? size : mem->size;
-
        vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
-       retval = remap_pfn_range(vma, vma->vm_start,
-                                mem->dma_handle >> PAGE_SHIFT,
-                                size, vma->vm_page_prot);
+       retval = vm_iomap_memory(vma, vma->vm_start, size);
        if (retval) {
                dev_err(q->dev, "mmap: remap failed with error %d. ",
                        retval);
index 828e7c1..9db674c 100644 (file)
@@ -338,11 +338,14 @@ EXPORT_SYMBOL_GPL(videobuf_dma_free);
 static void videobuf_vm_open(struct vm_area_struct *vma)
 {
        struct videobuf_mapping *map = vma->vm_private_data;
+       struct videobuf_queue *q = map->q;
 
        dprintk(2, "vm_open %p [count=%d,vma=%08lx-%08lx]\n", map,
                map->count, vma->vm_start, vma->vm_end);
 
+       videobuf_queue_lock(q);
        map->count++;
+       videobuf_queue_unlock(q);
 }
 
 static void videobuf_vm_close(struct vm_area_struct *vma)
@@ -355,10 +358,9 @@ static void videobuf_vm_close(struct vm_area_struct *vma)
        dprintk(2, "vm_close %p [count=%d,vma=%08lx-%08lx]\n", map,
                map->count, vma->vm_start, vma->vm_end);
 
-       map->count--;
-       if (0 == map->count) {
+       videobuf_queue_lock(q);
+       if (!--map->count) {
                dprintk(1, "munmap %p q=%p\n", map, q);
-               videobuf_queue_lock(q);
                for (i = 0; i < VIDEO_MAX_FRAME; i++) {
                        if (NULL == q->bufs[i])
                                continue;
@@ -374,9 +376,9 @@ static void videobuf_vm_close(struct vm_area_struct *vma)
                        q->bufs[i]->baddr = 0;
                        q->ops->buf_release(q, q->bufs[i]);
                }
-               videobuf_queue_unlock(q);
                kfree(map);
        }
+       videobuf_queue_unlock(q);
        return;
 }
 
index 2ff7fcc..1365c65 100644 (file)
@@ -54,11 +54,14 @@ MODULE_LICENSE("GPL");
 static void videobuf_vm_open(struct vm_area_struct *vma)
 {
        struct videobuf_mapping *map = vma->vm_private_data;
+       struct videobuf_queue *q = map->q;
 
        dprintk(2, "vm_open %p [count=%u,vma=%08lx-%08lx]\n", map,
                map->count, vma->vm_start, vma->vm_end);
 
+       videobuf_queue_lock(q);
        map->count++;
+       videobuf_queue_unlock(q);
 }
 
 static void videobuf_vm_close(struct vm_area_struct *vma)
@@ -70,12 +73,11 @@ static void videobuf_vm_close(struct vm_area_struct *vma)
        dprintk(2, "vm_close %p [count=%u,vma=%08lx-%08lx]\n", map,
                map->count, vma->vm_start, vma->vm_end);
 
-       map->count--;
-       if (0 == map->count) {
+       videobuf_queue_lock(q);
+       if (!--map->count) {
                struct videobuf_vmalloc_memory *mem;
 
                dprintk(1, "munmap %p q=%p\n", map, q);
-               videobuf_queue_lock(q);
 
                /* We need first to cancel streams, before unmapping */
                if (q->streaming)
@@ -114,8 +116,8 @@ static void videobuf_vm_close(struct vm_area_struct *vma)
 
                kfree(map);
 
-               videobuf_queue_unlock(q);
        }
+       videobuf_queue_unlock(q);
 
        return;
 }
index e3bdc3b..9fc4bab 100644 (file)
@@ -2194,8 +2194,10 @@ static int __vb2_init_fileio(struct vb2_queue *q, int read)
         */
        for (i = 0; i < q->num_buffers; i++) {
                fileio->bufs[i].vaddr = vb2_plane_vaddr(q->bufs[i], 0);
-               if (fileio->bufs[i].vaddr == NULL)
+               if (fileio->bufs[i].vaddr == NULL) {
+                       ret = -EINVAL;
                        goto err_reqbufs;
+               }
                fileio->bufs[i].size = vb2_plane_size(q->bufs[i], 0);
        }
 
index 582bda5..6c95483 100644 (file)
 
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/err.h>
 #include <linux/i2c.h>
 #include <linux/mfd/core.h>
 #include <linux/mfd/88pm80x.h>
 #include <linux/slab.h>
 
-#define PM800_CHIP_ID                  (0x00)
-
 /* Interrupt Registers */
 #define PM800_INT_STATUS1              (0x05)
 #define PM800_ONKEY_INT_STS1           (1 << 0)
@@ -113,20 +112,11 @@ enum {
        PM800_MAX_IRQ,
 };
 
-enum {
-       /* Procida */
-       PM800_CHIP_A0  = 0x60,
-       PM800_CHIP_A1  = 0x61,
-       PM800_CHIP_B0  = 0x62,
-       PM800_CHIP_C0  = 0x63,
-       PM800_CHIP_END = PM800_CHIP_C0,
-
-       /* Make sure to update this to the last stepping */
-       PM8XXX_CHIP_END = PM800_CHIP_END
-};
+/* PM800: generation identification number */
+#define PM800_CHIP_GEN_ID_NUM  0x3
 
 static const struct i2c_device_id pm80x_id_table[] = {
-       {"88PM800", CHIP_PM800},
+       {"88PM800", 0},
        {} /* NULL terminated */
 };
 MODULE_DEVICE_TABLE(i2c, pm80x_id_table);
@@ -167,6 +157,13 @@ static struct mfd_cell onkey_devs[] = {
         },
 };
 
+static struct mfd_cell regulator_devs[] = {
+       {
+        .name = "88pm80x-regulator",
+        .id = -1,
+       },
+};
+
 static const struct regmap_irq pm800_irqs[] = {
        /* INT0 */
        [PM800_IRQ_ONKEY] = {
@@ -315,10 +312,59 @@ out:
        return ret;
 }
 
+static int device_onkey_init(struct pm80x_chip *chip,
+                               struct pm80x_platform_data *pdata)
+{
+       int ret;
+
+       ret = mfd_add_devices(chip->dev, 0, &onkey_devs[0],
+                             ARRAY_SIZE(onkey_devs), &onkey_resources[0], 0,
+                             NULL);
+       if (ret) {
+               dev_err(chip->dev, "Failed to add onkey subdev\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static int device_rtc_init(struct pm80x_chip *chip,
+                               struct pm80x_platform_data *pdata)
+{
+       int ret;
+
+       rtc_devs[0].platform_data = pdata->rtc;
+       rtc_devs[0].pdata_size =
+                       pdata->rtc ? sizeof(struct pm80x_rtc_pdata) : 0;
+       ret = mfd_add_devices(chip->dev, 0, &rtc_devs[0],
+                             ARRAY_SIZE(rtc_devs), NULL, 0, NULL);
+       if (ret) {
+               dev_err(chip->dev, "Failed to add rtc subdev\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static int device_regulator_init(struct pm80x_chip *chip,
+                                          struct pm80x_platform_data *pdata)
+{
+       int ret;
+
+       ret = mfd_add_devices(chip->dev, 0, &regulator_devs[0],
+                             ARRAY_SIZE(regulator_devs), NULL, 0, NULL);
+       if (ret) {
+               dev_err(chip->dev, "Failed to add regulator subdev\n");
+               return ret;
+       }
+
+       return 0;
+}
+
 static int device_irq_init_800(struct pm80x_chip *chip)
 {
        struct regmap *map = chip->regmap;
-       unsigned long flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT;
+       unsigned long flags = IRQF_ONESHOT;
        int data, mask, ret = -EINVAL;
 
        if (!map || !chip->irq) {
@@ -362,6 +408,7 @@ static struct regmap_irq_chip pm800_irq_chip = {
        .status_base = PM800_INT_STATUS1,
        .mask_base = PM800_INT_ENA_1,
        .ack_base = PM800_INT_STATUS1,
+       .mask_invert = 1,
 };
 
 static int pm800_pages_init(struct pm80x_chip *chip)
@@ -369,77 +416,72 @@ static int pm800_pages_init(struct pm80x_chip *chip)
        struct pm80x_subchip *subchip;
        struct i2c_client *client = chip->client;
 
+       int ret = 0;
+
        subchip = chip->subchip;
-       /* PM800 block power: i2c addr 0x31 */
-       if (subchip->power_page_addr) {
-               subchip->power_page =
-                   i2c_new_dummy(client->adapter, subchip->power_page_addr);
-               subchip->regmap_power =
-                   devm_regmap_init_i2c(subchip->power_page,
-                                        &pm80x_regmap_config);
-               i2c_set_clientdata(subchip->power_page, chip);
-       } else
-               dev_info(chip->dev,
-                        "PM800 block power 0x31: No power_page_addr\n");
-
-       /* PM800 block GPADC: i2c addr 0x32 */
-       if (subchip->gpadc_page_addr) {
-               subchip->gpadc_page = i2c_new_dummy(client->adapter,
-                                                   subchip->gpadc_page_addr);
-               subchip->regmap_gpadc =
-                   devm_regmap_init_i2c(subchip->gpadc_page,
-                                        &pm80x_regmap_config);
-               i2c_set_clientdata(subchip->gpadc_page, chip);
-       } else
-               dev_info(chip->dev,
-                        "PM800 block GPADC 0x32: No gpadc_page_addr\n");
+       if (!subchip || !subchip->power_page_addr || !subchip->gpadc_page_addr)
+               return -ENODEV;
+
+       /* PM800 block power page */
+       subchip->power_page = i2c_new_dummy(client->adapter,
+                                           subchip->power_page_addr);
+       if (subchip->power_page == NULL) {
+               ret = -ENODEV;
+               goto out;
+       }
 
-       return 0;
+       subchip->regmap_power = devm_regmap_init_i2c(subchip->power_page,
+                                                    &pm80x_regmap_config);
+       if (IS_ERR(subchip->regmap_power)) {
+               ret = PTR_ERR(subchip->regmap_power);
+               dev_err(chip->dev,
+                       "Failed to allocate regmap_power: %d\n", ret);
+               goto out;
+       }
+
+       i2c_set_clientdata(subchip->power_page, chip);
+
+       /* PM800 block GPADC */
+       subchip->gpadc_page = i2c_new_dummy(client->adapter,
+                                           subchip->gpadc_page_addr);
+       if (subchip->gpadc_page == NULL) {
+               ret = -ENODEV;
+               goto out;
+       }
+
+       subchip->regmap_gpadc = devm_regmap_init_i2c(subchip->gpadc_page,
+                                                    &pm80x_regmap_config);
+       if (IS_ERR(subchip->regmap_gpadc)) {
+               ret = PTR_ERR(subchip->regmap_gpadc);
+               dev_err(chip->dev,
+                       "Failed to allocate regmap_gpadc: %d\n", ret);
+               goto out;
+       }
+       i2c_set_clientdata(subchip->gpadc_page, chip);
+
+out:
+       return ret;
 }
 
 static void pm800_pages_exit(struct pm80x_chip *chip)
 {
        struct pm80x_subchip *subchip;
 
-       regmap_exit(chip->regmap);
-       i2c_unregister_device(chip->client);
-
        subchip = chip->subchip;
-       if (subchip->power_page) {
-               regmap_exit(subchip->regmap_power);
+
+       if (subchip && subchip->power_page)
                i2c_unregister_device(subchip->power_page);
-       }
-       if (subchip->gpadc_page) {
-               regmap_exit(subchip->regmap_gpadc);
+
+       if (subchip && subchip->gpadc_page)
                i2c_unregister_device(subchip->gpadc_page);
-       }
 }
 
 static int device_800_init(struct pm80x_chip *chip,
                                     struct pm80x_platform_data *pdata)
 {
-       int ret, pmic_id;
+       int ret;
        unsigned int val;
 
-       ret = regmap_read(chip->regmap, PM800_CHIP_ID, &val);
-       if (ret < 0) {
-               dev_err(chip->dev, "Failed to read CHIP ID: %d\n", ret);
-               goto out;
-       }
-
-       pmic_id = val & PM80X_VERSION_MASK;
-
-       if ((pmic_id >= PM800_CHIP_A0) && (pmic_id <= PM800_CHIP_END)) {
-               chip->version = val;
-               dev_info(chip->dev,
-                        "88PM80x:Marvell 88PM800 (ID:0x%x) detected\n", val);
-       } else {
-               dev_err(chip->dev,
-                       "Failed to detect Marvell 88PM800:ChipID[0x%x]\n", val);
-               ret = -EINVAL;
-               goto out;
-       }
-
        /*
         * alarm wake up bit will be clear in device_irq_init(),
         * read before that
@@ -468,27 +510,22 @@ static int device_800_init(struct pm80x_chip *chip,
                goto out;
        }
 
-       ret =
-           mfd_add_devices(chip->dev, 0, &onkey_devs[0],
-                           ARRAY_SIZE(onkey_devs), &onkey_resources[0], 0,
-                           NULL);
-       if (ret < 0) {
+       ret = device_onkey_init(chip, pdata);
+       if (ret) {
                dev_err(chip->dev, "Failed to add onkey subdev\n");
                goto out_dev;
-       } else
-               dev_info(chip->dev, "[%s]:Added mfd onkey_devs\n", __func__);
-
-       if (pdata && pdata->rtc) {
-               rtc_devs[0].platform_data = pdata->rtc;
-               rtc_devs[0].pdata_size = sizeof(struct pm80x_rtc_pdata);
-               ret = mfd_add_devices(chip->dev, 0, &rtc_devs[0],
-                                     ARRAY_SIZE(rtc_devs), NULL, 0, NULL);
-               if (ret < 0) {
-                       dev_err(chip->dev, "Failed to add rtc subdev\n");
-                       goto out_dev;
-               } else
-                       dev_info(chip->dev,
-                                "[%s]:Added mfd rtc_devs\n", __func__);
+       }
+
+       ret = device_rtc_init(chip, pdata);
+       if (ret) {
+               dev_err(chip->dev, "Failed to add rtc subdev\n");
+               goto out;
+       }
+
+       ret = device_regulator_init(chip, pdata);
+       if (ret) {
+               dev_err(chip->dev, "Failed to add regulators subdev\n");
+               goto out;
        }
 
        return 0;
@@ -507,7 +544,7 @@ static int pm800_probe(struct i2c_client *client,
        struct pm80x_platform_data *pdata = client->dev.platform_data;
        struct pm80x_subchip *subchip;
 
-       ret = pm80x_init(client, id);
+       ret = pm80x_init(client);
        if (ret) {
                dev_err(&client->dev, "pm800_init fail\n");
                goto out_init;
@@ -524,28 +561,31 @@ static int pm800_probe(struct i2c_client *client,
                goto err_subchip_alloc;
        }
 
-       subchip->power_page_addr = pdata->power_page_addr;
-       subchip->gpadc_page_addr = pdata->gpadc_page_addr;
+       /* pm800 has 2 addtional pages to support power and gpadc. */
+       subchip->power_page_addr = client->addr + 1;
+       subchip->gpadc_page_addr = client->addr + 2;
        chip->subchip = subchip;
 
-       ret = device_800_init(chip, pdata);
-       if (ret) {
-               dev_err(chip->dev, "%s id 0x%x failed!\n", __func__, chip->id);
-               goto err_subchip_alloc;
-       }
-
        ret = pm800_pages_init(chip);
        if (ret) {
                dev_err(&client->dev, "pm800_pages_init failed!\n");
                goto err_page_init;
        }
 
+       ret = device_800_init(chip, pdata);
+       if (ret) {
+               dev_err(chip->dev, "Failed to initialize 88pm800 devices\n");
+               goto err_device_init;
+       }
+
        if (pdata->plat_config)
                pdata->plat_config(chip, pdata);
 
+       return 0;
+
+err_device_init:
+       pm800_pages_exit(chip);
 err_page_init:
-       mfd_remove_devices(chip->dev);
-       device_irq_exit_800(chip);
 err_subchip_alloc:
        pm80x_deinit();
 out_init:
@@ -567,7 +607,7 @@ static int pm800_remove(struct i2c_client *client)
 
 static struct i2c_driver pm800_driver = {
        .driver = {
-               .name = "88PM80X",
+               .name = "88PM800",
                .owner = THIS_MODULE,
                .pm = &pm80x_pm_ops,
                },
index 65d7ac0..5216022 100644 (file)
 #include <linux/slab.h>
 #include <linux/delay.h>
 
-#define PM805_CHIP_ID                  (0x00)
-
 static const struct i2c_device_id pm80x_id_table[] = {
-       {"88PM805", CHIP_PM805},
+       {"88PM805", 0},
        {} /* NULL terminated */
 };
 MODULE_DEVICE_TABLE(i2c, pm80x_id_table);
@@ -138,7 +136,7 @@ static struct regmap_irq pm805_irqs[] = {
 static int device_irq_init_805(struct pm80x_chip *chip)
 {
        struct regmap *map = chip->regmap;
-       unsigned long flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT;
+       unsigned long flags = IRQF_ONESHOT;
        int data, mask, ret = -EINVAL;
 
        if (!map || !chip->irq) {
@@ -192,7 +190,6 @@ static struct regmap_irq_chip pm805_irq_chip = {
 static int device_805_init(struct pm80x_chip *chip)
 {
        int ret = 0;
-       unsigned int val;
        struct regmap *map = chip->regmap;
 
        if (!map) {
@@ -200,13 +197,6 @@ static int device_805_init(struct pm80x_chip *chip)
                return -EINVAL;
        }
 
-       ret = regmap_read(map, PM805_CHIP_ID, &val);
-       if (ret < 0) {
-               dev_err(chip->dev, "Failed to read CHIP ID: %d\n", ret);
-               goto out_irq_init;
-       }
-       chip->version = val;
-
        chip->regmap_irq_chip = &pm805_irq_chip;
 
        ret = device_irq_init_805(chip);
@@ -239,7 +229,7 @@ static int pm805_probe(struct i2c_client *client,
        struct pm80x_chip *chip;
        struct pm80x_platform_data *pdata = client->dev.platform_data;
 
-       ret = pm80x_init(client, id);
+       ret = pm80x_init(client);
        if (ret) {
                dev_err(&client->dev, "pm805_init fail!\n");
                goto out_init;
@@ -249,7 +239,7 @@ static int pm805_probe(struct i2c_client *client,
 
        ret = device_805_init(chip);
        if (ret) {
-               dev_err(chip->dev, "%s id 0x%x failed!\n", __func__, chip->id);
+               dev_err(chip->dev, "Failed to initialize 88pm805 devices\n");
                goto err_805_init;
        }
 
@@ -276,7 +266,7 @@ static int pm805_remove(struct i2c_client *client)
 
 static struct i2c_driver pm805_driver = {
        .driver = {
-               .name = "88PM80X",
+               .name = "88PM805",
                .owner = THIS_MODULE,
                .pm = &pm80x_pm_ops,
                },
index f736a46..5e72f65 100644 (file)
 #include <linux/uaccess.h>
 #include <linux/err.h>
 
+/* 88pm80x chips have same definition for chip id register. */
+#define PM80X_CHIP_ID                  (0x00)
+#define PM80X_CHIP_ID_NUM(x)           (((x) >> 5) & 0x7)
+#define PM80X_CHIP_ID_REVISION(x)      ((x) & 0x1F)
+
+struct pm80x_chip_mapping {
+       unsigned int    id;
+       int             type;
+};
+
+static struct pm80x_chip_mapping chip_mapping[] = {
+       /* 88PM800 chip id number */
+       {0x3,   CHIP_PM800},
+       /* 88PM805 chip id number */
+       {0x0,   CHIP_PM805},
+};
+
 /*
  * workaround: some registers needed by pm805 are defined in pm800, so
  * need to use this global variable to maintain the relation between
@@ -31,12 +48,13 @@ const struct regmap_config pm80x_regmap_config = {
 };
 EXPORT_SYMBOL_GPL(pm80x_regmap_config);
 
-int pm80x_init(struct i2c_client *client,
-                                const struct i2c_device_id *id)
+
+int pm80x_init(struct i2c_client *client)
 {
        struct pm80x_chip *chip;
        struct regmap *map;
-       int ret = 0;
+       unsigned int val;
+       int i, ret = 0;
 
        chip =
            devm_kzalloc(&client->dev, sizeof(struct pm80x_chip), GFP_KERNEL);
@@ -51,10 +69,6 @@ int pm80x_init(struct i2c_client *client,
                return ret;
        }
 
-       chip->id = id->driver_data;
-       if (chip->id < CHIP_PM800 || chip->id > CHIP_PM805)
-               return -EINVAL;
-
        chip->client = client;
        chip->regmap = map;
 
@@ -64,6 +78,25 @@ int pm80x_init(struct i2c_client *client,
        dev_set_drvdata(chip->dev, chip);
        i2c_set_clientdata(chip->client, chip);
 
+       ret = regmap_read(chip->regmap, PM80X_CHIP_ID, &val);
+       if (ret < 0) {
+               dev_err(chip->dev, "Failed to read CHIP ID: %d\n", ret);
+               return ret;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(chip_mapping); i++) {
+               if (chip_mapping[i].id == PM80X_CHIP_ID_NUM(val)) {
+                       chip->type = chip_mapping[i].type;
+                       break;
+               }
+       }
+
+       if (i == ARRAY_SIZE(chip_mapping)) {
+               dev_err(chip->dev,
+                       "Failed to detect Marvell 88PM800:ChipID[0x%x]\n", val);
+               return -EINVAL;
+       }
+
        device_init_wakeup(&client->dev, 1);
 
        /*
index 31ca555..eeb481d 100644 (file)
@@ -1150,17 +1150,17 @@ static int pm860x_probe(struct i2c_client *client,
                return -EINVAL;
        }
 
-       chip = kzalloc(sizeof(struct pm860x_chip), GFP_KERNEL);
+       chip = devm_kzalloc(&client->dev,
+                           sizeof(struct pm860x_chip), GFP_KERNEL);
        if (chip == NULL)
                return -ENOMEM;
 
        chip->id = verify_addr(client);
-       chip->regmap = regmap_init_i2c(client, &pm860x_regmap_config);
+       chip->regmap = devm_regmap_init_i2c(client, &pm860x_regmap_config);
        if (IS_ERR(chip->regmap)) {
                ret = PTR_ERR(chip->regmap);
                dev_err(&client->dev, "Failed to allocate register map: %d\n",
                                ret);
-               kfree(chip);
                return ret;
        }
        chip->client = client;
@@ -1203,8 +1203,6 @@ static int pm860x_remove(struct i2c_client *client)
                regmap_exit(chip->regmap_companion);
                i2c_unregister_device(chip->companion);
        }
-       regmap_exit(chip->regmap);
-       kfree(chip);
        return 0;
 }
 
index d54e985..aecd6dd 100644 (file)
@@ -53,7 +53,7 @@ config MFD_CROS_EC
        help
          If you say Y here you get support for the ChromeOS Embedded
          Controller (EC) providing keyboard, battery and power services.
-         You also ned to enable the driver for the bus you are using. The
+         You also need to enable the driver for the bus you are using. The
          protocol for talking to the EC is defined by the bus driver.
 
 config MFD_CROS_EC_I2C
@@ -242,6 +242,27 @@ config MFD_JZ4740_ADC
          Say yes here if you want support for the ADC unit in the JZ4740 SoC.
          This driver is necessary for jz4740-battery and jz4740-hwmon driver.
 
+config MFD_KEMPLD
+       tristate "Kontron module PLD device"
+       select MFD_CORE
+       help
+         This is the core driver for the PLD (Programmable Logic Device) found
+         on some Kontron ETX and COMexpress (ETXexpress) modules. The PLD
+         device may provide functions like watchdog, GPIO, UART and I2C bus.
+
+         The following modules are supported:
+               * COMe-bIP#
+               * COMe-bPC2 (ETXexpress-PC)
+               * COMe-bSC# (ETXexpress-SC T#)
+               * COMe-cCT6
+               * COMe-cDC2 (microETXexpress-DC)
+               * COMe-cPC2 (microETXexpress-PC)
+               * COMe-mCT10
+               * ETX-OH
+
+         This driver can also be built as a module. If so, the module
+         will be called kempld-core.
+
 config MFD_88PM800
        tristate "Marvell 88PM800"
        depends on I2C=y && GENERIC_HARDIRQS
@@ -342,6 +363,7 @@ config MFD_MAX8998
        bool "Maxim Semiconductor MAX8998/National LP3974 PMIC Support"
        depends on I2C=y && GENERIC_HARDIRQS
        select MFD_CORE
+       select IRQ_DOMAIN
        help
          Say yes here to support for Maxim Semiconductor MAX8998 and
          National Semiconductor LP3974. This is a Power Management IC.
@@ -419,7 +441,8 @@ config MFD_PM8XXX
 
 config MFD_PM8921_CORE
        tristate "Qualcomm PM8921 PMIC chip"
-       depends on SSBI && BROKEN
+       depends on (ARCH_MSM || HEXAGON)
+       depends on BROKEN
        select MFD_CORE
        select MFD_PM8XXX
        help
@@ -1046,6 +1069,12 @@ config MFD_WM5110
        help
          Support for Wolfson Microelectronics WM5110 low power audio SoC
 
+config MFD_WM8997
+       bool "Support Wolfson Microelectronics WM8997"
+       depends on MFD_ARIZONA
+       help
+         Support for Wolfson Microelectronics WM8997 low power audio SoC
+
 config MFD_WM8400
        bool "Wolfson Microelectronics WM8400"
        select MFD_CORE
@@ -1144,7 +1173,8 @@ config MCP_UCB1200_TS
 endmenu
 
 config VEXPRESS_CONFIG
-       bool
+       bool "ARM Versatile Express platform infrastructure"
+       depends on ARM || ARM64
        help
          Platform configuration infrastructure for the ARM Ltd.
          Versatile Express.
index 718e94a..3c90051 100644 (file)
@@ -43,6 +43,9 @@ endif
 ifneq ($(CONFIG_MFD_WM5110),n)
 obj-$(CONFIG_MFD_ARIZONA)      += wm5110-tables.o
 endif
+ifneq ($(CONFIG_MFD_WM8997),n)
+obj-$(CONFIG_MFD_ARIZONA)      += wm8997-tables.o
+endif
 obj-$(CONFIG_MFD_WM8400)       += wm8400-core.o
 wm831x-objs                    := wm831x-core.o wm831x-irq.o wm831x-otp.o
 wm831x-objs                    += wm831x-auxadc.o
@@ -126,6 +129,7 @@ obj-$(CONFIG_MFD_DB8500_PRCMU)      += db8500-prcmu.o
 obj-$(CONFIG_AB8500_CORE)      += ab8500-core.o ab8500-sysctrl.o
 obj-$(CONFIG_MFD_TIMBERDALE)    += timberdale.o
 obj-$(CONFIG_PMIC_ADP5520)     += adp5520.o
+obj-$(CONFIG_MFD_KEMPLD)       += kempld-core.o
 obj-$(CONFIG_LPC_SCH)          += lpc_sch.o
 obj-$(CONFIG_LPC_ICH)          += lpc_ich.o
 obj-$(CONFIG_MFD_RDC321X)      += rdc321x-southbridge.o
@@ -140,7 +144,7 @@ obj-$(CONFIG_MFD_SI476X_CORE)       += si476x-core.o
 
 obj-$(CONFIG_MFD_CS5535)       += cs5535-mfd.o
 obj-$(CONFIG_MFD_OMAP_USB_HOST)        += omap-usb-host.o omap-usb-tll.o
-obj-$(CONFIG_MFD_PM8921_CORE)  += pm8921-core.o
+obj-$(CONFIG_MFD_PM8921_CORE)  += pm8921-core.o ssbi.o
 obj-$(CONFIG_MFD_PM8XXX_IRQ)   += pm8xxx-irq.o
 obj-$(CONFIG_TPS65911_COMPARATOR)      += tps65911-comparator.o
 obj-$(CONFIG_MFD_TPS65090)     += tps65090.o
index dfdb0a2..d4f5945 100644 (file)
@@ -312,8 +312,9 @@ static ssize_t aat2870_reg_write_file(struct file *file,
        while (*start == ' ')
                start++;
 
-       if (strict_strtoul(start, 16, &val))
-               return -EINVAL;
+       ret = kstrtoul(start, 16, &val);
+       if (ret)
+               return ret;
 
        ret = aat2870->write(aat2870, (u8)addr, (u8)val);
        if (ret)
index a9bb140..ddc669d 100644 (file)
@@ -491,7 +491,7 @@ static ssize_t ab3100_get_set_reg(struct file *file,
        char buf[32];
        ssize_t buf_size;
        int regp;
-       unsigned long user_reg;
+       u8 user_reg;
        int err;
        int i = 0;
 
@@ -514,34 +514,29 @@ static ssize_t ab3100_get_set_reg(struct file *file,
        /*
         * Advance pointer to end of string then terminate
         * the register string. This is needed to satisfy
-        * the strict_strtoul() function.
+        * the kstrtou8() function.
         */
        while ((i < buf_size) && (buf[i] != ' '))
                i++;
        buf[i] = '\0';
 
-       err = strict_strtoul(&buf[regp], 16, &user_reg);
+       err = kstrtou8(&buf[regp], 16, &user_reg);
        if (err)
                return err;
-       if (user_reg > 0xff)
-               return -EINVAL;
 
        /* Either we read or we write a register here */
        if (!priv->mode) {
                /* Reading */
-               u8 reg = (u8) user_reg;
                u8 regvalue;
 
-               ab3100_get_register_interruptible(ab3100, reg, &regvalue);
+               ab3100_get_register_interruptible(ab3100, user_reg, &regvalue);
 
                dev_info(ab3100->dev,
                         "debug read AB3100 reg[0x%02x]: 0x%02x\n",
-                        reg, regvalue);
+                        user_reg, regvalue);
        } else {
                int valp;
-               unsigned long user_value;
-               u8 reg = (u8) user_reg;
-               u8 value;
+               u8 user_value;
                u8 regvalue;
 
                /*
@@ -557,20 +552,17 @@ static ssize_t ab3100_get_set_reg(struct file *file,
                        i++;
                buf[i] = '\0';
 
-               err = strict_strtoul(&buf[valp], 16, &user_value);
+               err = kstrtou8(&buf[valp], 16, &user_value);
                if (err)
                        return err;
-               if (user_reg > 0xff)
-                       return -EINVAL;
 
-               value = (u8) user_value;
-               ab3100_set_register_interruptible(ab3100, reg, value);
-               ab3100_get_register_interruptible(ab3100, reg, &regvalue);
+               ab3100_set_register_interruptible(ab3100, user_reg, user_value);
+               ab3100_get_register_interruptible(ab3100, user_reg, &regvalue);
 
                dev_info(ab3100->dev,
                         "debug write reg[0x%02x] with 0x%02x, "
                         "after readback: 0x%02x\n",
-                        reg, value, regvalue);
+                        user_reg, user_value, regvalue);
        }
        return buf_size;
 }
index d7ce016..c9af16c 100644 (file)
@@ -187,7 +187,7 @@ static int __init ab3100_otp_probe(struct platform_device *pdev)
        int err = 0;
        int i;
 
-       otp = kzalloc(sizeof(struct ab3100_otp), GFP_KERNEL);
+       otp = devm_kzalloc(&pdev->dev, sizeof(struct ab3100_otp), GFP_KERNEL);
        if (!otp) {
                dev_err(&pdev->dev, "could not allocate AB3100 OTP device\n");
                return -ENOMEM;
@@ -199,7 +199,7 @@ static int __init ab3100_otp_probe(struct platform_device *pdev)
 
        err = ab3100_otp_read(otp);
        if (err)
-               goto err_otp_read;
+               return err;
 
        dev_info(&pdev->dev, "AB3100 OTP readout registered\n");
 
@@ -208,22 +208,19 @@ static int __init ab3100_otp_probe(struct platform_device *pdev)
                err = device_create_file(&pdev->dev,
                                         &ab3100_otp_attrs[i]);
                if (err)
-                       goto err_create_file;
+                       goto err;
        }
 
        /* debugfs entries */
        err = ab3100_otp_init_debugfs(&pdev->dev, otp);
        if (err)
-               goto err_init_debugfs;
+               goto err;
 
        return 0;
 
-err_init_debugfs:
-err_create_file:
+err:
        while (--i >= 0)
                device_remove_file(&pdev->dev, &ab3100_otp_attrs[i]);
-err_otp_read:
-       kfree(otp);
        return err;
 }
 
@@ -236,7 +233,6 @@ static int __exit ab3100_otp_remove(struct platform_device *pdev)
                device_remove_file(&pdev->dev,
                                   &ab3100_otp_attrs[i]);
        ab3100_otp_exit_debugfs(otp);
-       kfree(otp);
        return 0;
 }
 
index 258b367..b6c2cdc 100644 (file)
@@ -650,6 +650,21 @@ static struct resource ab8500_rtc_resources[] = {
        },
 };
 
+static struct resource ab8540_rtc_resources[] = {
+       {
+               .name   = "1S",
+               .start  = AB8540_INT_RTC_1S,
+               .end    = AB8540_INT_RTC_1S,
+               .flags  = IORESOURCE_IRQ,
+       },
+       {
+               .name   = "ALARM",
+               .start  = AB8500_INT_RTC_ALARM,
+               .end    = AB8500_INT_RTC_ALARM,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
 static struct resource ab8500_poweronkey_db_resources[] = {
        {
                .name   = "ONKEY_DBF",
@@ -1051,6 +1066,10 @@ static struct mfd_cell ab8500_devs[] = {
                .of_compatible = "stericsson,ab8500-sysctrl",
        },
        {
+               .name = "ab8500-ext-regulator",
+               .of_compatible = "stericsson,ab8500-ext-regulator",
+       },
+       {
                .name = "ab8500-regulator",
                .of_compatible = "stericsson,ab8500-regulator",
        },
@@ -1099,10 +1118,6 @@ static struct mfd_cell ab8500_devs[] = {
                .id = 3,
        },
        {
-               .name = "ab8500-leds",
-               .of_compatible = "stericsson,ab8500-leds",
-       },
-       {
                .name = "ab8500-denc",
                .of_compatible = "stericsson,ab8500-denc",
        },
@@ -1124,6 +1139,7 @@ static struct mfd_cell ab8500_devs[] = {
        },
        {
                .name = "ab8500-codec",
+               .of_compatible = "stericsson,ab8500-codec",
        },
 };
 
@@ -1139,6 +1155,9 @@ static struct mfd_cell ab9540_devs[] = {
                .name = "ab8500-sysctrl",
        },
        {
+               .name = "ab8500-ext-regulator",
+       },
+       {
                .name = "ab8500-regulator",
        },
        {
@@ -1171,9 +1190,6 @@ static struct mfd_cell ab9540_devs[] = {
                .id = 1,
        },
        {
-               .name = "ab8500-leds",
-       },
-       {
                .name = "abx500-temp",
                .num_resources = ARRAY_SIZE(ab8500_temp_resources),
                .resources = ab8500_temp_resources,
@@ -1242,9 +1258,6 @@ static struct mfd_cell ab8505_devs[] = {
                .id = 1,
        },
        {
-               .name = "ab8500-leds",
-       },
-       {
                .name = "pinctrl-ab8505",
        },
        {
@@ -1274,6 +1287,9 @@ static struct mfd_cell ab8540_devs[] = {
                .name = "ab8500-sysctrl",
        },
        {
+               .name = "ab8500-ext-regulator",
+       },
+       {
                .name = "ab8500-regulator",
        },
        {
@@ -1287,11 +1303,6 @@ static struct mfd_cell ab8540_devs[] = {
                .resources = ab8505_gpadc_resources,
        },
        {
-               .name = "ab8500-rtc",
-               .num_resources = ARRAY_SIZE(ab8500_rtc_resources),
-               .resources = ab8500_rtc_resources,
-       },
-       {
                .name = "ab8500-acc-det",
                .num_resources = ARRAY_SIZE(ab8500_av_acc_detect_resources),
                .resources = ab8500_av_acc_detect_resources,
@@ -1306,9 +1317,6 @@ static struct mfd_cell ab8540_devs[] = {
                .id = 1,
        },
        {
-               .name = "ab8500-leds",
-       },
-       {
                .name = "abx500-temp",
                .num_resources = ARRAY_SIZE(ab8500_temp_resources),
                .resources = ab8500_temp_resources,
@@ -1331,6 +1339,24 @@ static struct mfd_cell ab8540_devs[] = {
        },
 };
 
+static struct mfd_cell ab8540_cut1_devs[] = {
+       {
+               .name = "ab8500-rtc",
+               .of_compatible = "stericsson,ab8500-rtc",
+               .num_resources = ARRAY_SIZE(ab8500_rtc_resources),
+               .resources = ab8500_rtc_resources,
+       },
+};
+
+static struct mfd_cell ab8540_cut2_devs[] = {
+       {
+               .name = "ab8540-rtc",
+               .of_compatible = "stericsson,ab8540-rtc",
+               .num_resources = ARRAY_SIZE(ab8540_rtc_resources),
+               .resources = ab8540_rtc_resources,
+       },
+};
+
 static ssize_t show_chip_id(struct device *dev,
                                struct device_attribute *attr, char *buf)
 {
@@ -1734,11 +1760,22 @@ static int ab8500_probe(struct platform_device *pdev)
                ret = mfd_add_devices(ab8500->dev, 0, ab9540_devs,
                                ARRAY_SIZE(ab9540_devs), NULL,
                                ab8500->irq_base, ab8500->domain);
-       else if (is_ab8540(ab8500))
+       else if (is_ab8540(ab8500)) {
                ret = mfd_add_devices(ab8500->dev, 0, ab8540_devs,
                              ARRAY_SIZE(ab8540_devs), NULL,
-                             ab8500->irq_base, ab8500->domain);
-       else if (is_ab8505(ab8500))
+                             ab8500->irq_base, NULL);
+               if (ret)
+                       return ret;
+
+               if (is_ab8540_1p2_or_earlier(ab8500))
+                       ret = mfd_add_devices(ab8500->dev, 0, ab8540_cut1_devs,
+                             ARRAY_SIZE(ab8540_cut1_devs), NULL,
+                             ab8500->irq_base, NULL);
+               else /* ab8540 >= cut2 */
+                       ret = mfd_add_devices(ab8500->dev, 0, ab8540_cut2_devs,
+                             ARRAY_SIZE(ab8540_cut2_devs), NULL,
+                             ab8500->irq_base, NULL);
+       } else if (is_ab8505(ab8500))
                ret = mfd_add_devices(ab8500->dev, 0, ab8505_devs,
                              ARRAY_SIZE(ab8505_devs), NULL,
                              ab8500->irq_base, ab8500->domain);
index 37b7ce4..7d1f1b0 100644 (file)
@@ -2757,7 +2757,7 @@ static ssize_t show_irq(struct device *dev,
        unsigned int irq_index;
        int err;
 
-       err = strict_strtoul(attr->attr.name, 0, &name);
+       err = kstrtoul(attr->attr.name, 0, &name);
        if (err)
                return err;
 
@@ -2937,7 +2937,6 @@ static struct dentry *ab8500_gpadc_dir;
 static int ab8500_debug_probe(struct platform_device *plf)
 {
        struct dentry *file;
-       int ret = -ENOMEM;
        struct ab8500 *ab8500;
        struct resource *res;
        debug_bank = AB8500_MISC;
@@ -2946,24 +2945,26 @@ static int ab8500_debug_probe(struct platform_device *plf)
        ab8500 = dev_get_drvdata(plf->dev.parent);
        num_irqs = ab8500->mask_size;
 
-       irq_count = kzalloc(sizeof(*irq_count)*num_irqs, GFP_KERNEL);
+       irq_count = devm_kzalloc(&plf->dev,
+                                sizeof(*irq_count)*num_irqs, GFP_KERNEL);
        if (!irq_count)
                return -ENOMEM;
 
-       dev_attr = kzalloc(sizeof(*dev_attr)*num_irqs,GFP_KERNEL);
+       dev_attr = devm_kzalloc(&plf->dev,
+                               sizeof(*dev_attr)*num_irqs,GFP_KERNEL);
        if (!dev_attr)
-               goto out_freeirq_count;
+               return -ENOMEM;
 
-       event_name = kzalloc(sizeof(*event_name)*num_irqs, GFP_KERNEL);
+       event_name = devm_kzalloc(&plf->dev,
+                                 sizeof(*event_name)*num_irqs, GFP_KERNEL);
        if (!event_name)
-               goto out_freedev_attr;
+               return -ENOMEM;
 
        res = platform_get_resource_byname(plf, 0, "IRQ_AB8500");
        if (!res) {
                dev_err(&plf->dev, "AB8500 irq not found, err %d\n",
                        irq_first);
-               ret = -ENXIO;
-               goto out_freeevent_name;
+               return ENXIO;
        }
        irq_ab8500 = res->start;
 
@@ -2971,16 +2972,14 @@ static int ab8500_debug_probe(struct platform_device *plf)
        if (irq_first < 0) {
                dev_err(&plf->dev, "First irq not found, err %d\n",
                        irq_first);
-               ret = irq_first;
-               goto out_freeevent_name;
+               return irq_first;
        }
 
        irq_last = platform_get_irq_byname(plf, "IRQ_LAST");
        if (irq_last < 0) {
                dev_err(&plf->dev, "Last irq not found, err %d\n",
                        irq_last);
-               ret = irq_last;
-               goto out_freeevent_name;
+               return irq_last;
        }
 
        ab8500_dir = debugfs_create_dir(AB8500_NAME_STRING, NULL);
@@ -3189,22 +3188,13 @@ err:
        if (ab8500_dir)
                debugfs_remove_recursive(ab8500_dir);
        dev_err(&plf->dev, "failed to create debugfs entries.\n");
-out_freeevent_name:
-       kfree(event_name);
-out_freedev_attr:
-       kfree(dev_attr);
-out_freeirq_count:
-       kfree(irq_count);
 
-       return ret;
+       return -ENOMEM;
 }
 
 static int ab8500_debug_remove(struct platform_device *plf)
 {
        debugfs_remove_recursive(ab8500_dir);
-       kfree(event_name);
-       kfree(dev_attr);
-       kfree(irq_count);
 
        return 0;
 }
index 3598b0e..7623e91 100644 (file)
@@ -919,7 +919,7 @@ static int ab8500_gpadc_probe(struct platform_device *pdev)
        int ret = 0;
        struct ab8500_gpadc *gpadc;
 
-       gpadc = kzalloc(sizeof(struct ab8500_gpadc), GFP_KERNEL);
+       gpadc = devm_kzalloc(&pdev->dev, sizeof(struct ab8500_gpadc), GFP_KERNEL);
        if (!gpadc) {
                dev_err(&pdev->dev, "Error: No memory\n");
                return -ENOMEM;
@@ -999,8 +999,6 @@ fail_irq:
        free_irq(gpadc->irq_sw, gpadc);
        free_irq(gpadc->irq_hw, gpadc);
 fail:
-       kfree(gpadc);
-       gpadc = NULL;
        return ret;
 }
 
@@ -1025,8 +1023,6 @@ static int ab8500_gpadc_remove(struct platform_device *pdev)
 
        pm_runtime_put_noidle(gpadc->dev);
 
-       kfree(gpadc);
-       gpadc = NULL;
        return 0;
 }
 
index 3714acb..f3a15aa 100644 (file)
@@ -36,7 +36,9 @@ int abx500_register_ops(struct device *dev, struct abx500_ops *ops)
 {
        struct abx500_device_entry *dev_entry;
 
-       dev_entry = kzalloc(sizeof(struct abx500_device_entry), GFP_KERNEL);
+       dev_entry = devm_kzalloc(dev,
+                                sizeof(struct abx500_device_entry),
+                                GFP_KERNEL);
        if (!dev_entry) {
                dev_err(dev, "register_ops kzalloc failed");
                return -ENOMEM;
@@ -54,12 +56,8 @@ void abx500_remove_ops(struct device *dev)
        struct abx500_device_entry *dev_entry, *tmp;
 
        list_for_each_entry_safe(dev_entry, tmp, &abx500_list, list)
-       {
-               if (dev_entry->dev == dev) {
+               if (dev_entry->dev == dev)
                        list_del(&dev_entry->list);
-                       kfree(dev_entry);
-               }
-       }
 }
 EXPORT_SYMBOL(abx500_remove_ops);
 
index 0d2eba0..28346ad 100644 (file)
@@ -223,7 +223,7 @@ static int adp5520_probe(struct i2c_client *client,
                return -ENODEV;
        }
 
-       chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+       chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
        if (!chip)
                return -ENOMEM;
 
@@ -244,7 +244,7 @@ static int adp5520_probe(struct i2c_client *client,
                if (ret) {
                        dev_err(&client->dev, "failed to request irq %d\n",
                                        chip->irq);
-                       goto out_free_chip;
+                       return ret;
                }
        }
 
@@ -302,9 +302,6 @@ out_free_irq:
        if (chip->irq)
                free_irq(chip->irq, chip);
 
-out_free_chip:
-       kfree(chip);
-
        return ret;
 }
 
@@ -317,7 +314,6 @@ static int adp5520_remove(struct i2c_client *client)
 
        adp5520_remove_subdevs(chip);
        adp5520_write(chip->dev, ADP5520_MODE_STATUS, 0);
-       kfree(chip);
        return 0;
 }
 
index 74b4481..89a1153 100644 (file)
@@ -554,6 +554,7 @@ static int arizona_of_get_core_pdata(struct arizona *arizona)
 const struct of_device_id arizona_of_match[] = {
        { .compatible = "wlf,wm5102", .data = (void *)WM5102 },
        { .compatible = "wlf,wm5110", .data = (void *)WM5110 },
+       { .compatible = "wlf,wm8997", .data = (void *)WM8997 },
        {},
 };
 EXPORT_SYMBOL_GPL(arizona_of_match);
@@ -586,6 +587,15 @@ static struct mfd_cell wm5110_devs[] = {
        { .name = "wm5110-codec" },
 };
 
+static struct mfd_cell wm8997_devs[] = {
+       { .name = "arizona-micsupp" },
+       { .name = "arizona-extcon" },
+       { .name = "arizona-gpio" },
+       { .name = "arizona-haptics" },
+       { .name = "arizona-pwm" },
+       { .name = "wm8997-codec" },
+};
+
 int arizona_dev_init(struct arizona *arizona)
 {
        struct device *dev = arizona->dev;
@@ -608,6 +618,7 @@ int arizona_dev_init(struct arizona *arizona)
        switch (arizona->type) {
        case WM5102:
        case WM5110:
+       case WM8997:
                for (i = 0; i < ARRAY_SIZE(wm5102_core_supplies); i++)
                        arizona->core_supplies[i].supply
                                = wm5102_core_supplies[i];
@@ -683,6 +694,7 @@ int arizona_dev_init(struct arizona *arizona)
        switch (reg) {
        case 0x5102:
        case 0x5110:
+       case 0x8997:
                break;
        default:
                dev_err(arizona->dev, "Unknown device ID: %x\n", reg);
@@ -768,6 +780,17 @@ int arizona_dev_init(struct arizona *arizona)
                apply_patch = wm5110_patch;
                break;
 #endif
+#ifdef CONFIG_MFD_WM8997
+       case 0x8997:
+               type_name = "WM8997";
+               if (arizona->type != WM8997) {
+                       dev_err(arizona->dev, "WM8997 registered as %d\n",
+                               arizona->type);
+                       arizona->type = WM8997;
+               }
+               apply_patch = wm8997_patch;
+               break;
+#endif
        default:
                dev_err(arizona->dev, "Unknown device ID %x\n", reg);
                goto err_reset;
@@ -934,6 +957,10 @@ int arizona_dev_init(struct arizona *arizona)
                ret = mfd_add_devices(arizona->dev, -1, wm5110_devs,
                                      ARRAY_SIZE(wm5110_devs), NULL, 0, NULL);
                break;
+       case WM8997:
+               ret = mfd_add_devices(arizona->dev, -1, wm8997_devs,
+                                     ARRAY_SIZE(wm8997_devs), NULL, 0, NULL);
+               break;
        }
 
        if (ret != 0) {
index deb267e..51dbabf 100644 (file)
@@ -45,6 +45,11 @@ static int arizona_i2c_probe(struct i2c_client *i2c,
                regmap_config = &wm5110_i2c_regmap;
                break;
 #endif
+#ifdef CONFIG_MFD_WM8997
+       case WM8997:
+               regmap_config = &wm8997_i2c_regmap;
+               break;
+#endif
        default:
                dev_err(&i2c->dev, "Unknown device type %ld\n",
                        id->driver_data);
@@ -80,6 +85,7 @@ static int arizona_i2c_remove(struct i2c_client *i2c)
 static const struct i2c_device_id arizona_i2c_id[] = {
        { "wm5102", WM5102 },
        { "wm5110", WM5110 },
+       { "wm8997", WM8997 },
        { }
 };
 MODULE_DEVICE_TABLE(i2c, arizona_i2c_id);
index 64cd9b6..88758ab 100644 (file)
@@ -208,6 +208,14 @@ int arizona_irq_init(struct arizona *arizona)
                ctrlif_error = false;
                break;
 #endif
+#ifdef CONFIG_MFD_WM8997
+       case WM8997:
+               aod = &wm8997_aod;
+               irq = &wm8997_irq;
+
+               ctrlif_error = false;
+               break;
+#endif
        default:
                BUG_ON("Unknown Arizona class device" == NULL);
                return -EINVAL;
index db55d98..b4cef77 100644 (file)
@@ -25,6 +25,8 @@ extern const struct regmap_config wm5102_spi_regmap;
 extern const struct regmap_config wm5110_i2c_regmap;
 extern const struct regmap_config wm5110_spi_regmap;
 
+extern const struct regmap_config wm8997_i2c_regmap;
+
 extern const struct dev_pm_ops arizona_pm_ops;
 
 extern const struct of_device_id arizona_of_match[];
@@ -35,6 +37,9 @@ extern const struct regmap_irq_chip wm5102_irq;
 extern const struct regmap_irq_chip wm5110_aod;
 extern const struct regmap_irq_chip wm5110_irq;
 
+extern const struct regmap_irq_chip wm8997_aod;
+extern const struct regmap_irq_chip wm8997_irq;
+
 int arizona_dev_init(struct arizona *arizona);
 int arizona_dev_exit(struct arizona *arizona);
 int arizona_irq_init(struct arizona *arizona);
index 1b15986..9532f74 100644 (file)
@@ -958,7 +958,8 @@ static int __init asic3_probe(struct platform_device *pdev)
        unsigned long clksel;
        int ret = 0;
 
-       asic = kzalloc(sizeof(struct asic3), GFP_KERNEL);
+       asic = devm_kzalloc(&pdev->dev,
+                           sizeof(struct asic3), GFP_KERNEL);
        if (asic == NULL) {
                printk(KERN_ERR "kzalloc failed\n");
                return -ENOMEM;
@@ -970,16 +971,14 @@ static int __init asic3_probe(struct platform_device *pdev)
 
        mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!mem) {
-               ret = -ENOMEM;
                dev_err(asic->dev, "no MEM resource\n");
-               goto out_free;
+               return -ENOMEM;
        }
 
        asic->mapping = ioremap(mem->start, resource_size(mem));
        if (!asic->mapping) {
-               ret = -ENOMEM;
                dev_err(asic->dev, "Couldn't ioremap\n");
-               goto out_free;
+               return -ENOMEM;
        }
 
        asic->irq_base = pdata->irq_base;
@@ -1033,9 +1032,6 @@ static int __init asic3_probe(struct platform_device *pdev)
  out_unmap:
        iounmap(asic->mapping);
 
- out_free:
-       kfree(asic);
-
        return ret;
 }
 
@@ -1058,8 +1054,6 @@ static int asic3_remove(struct platform_device *pdev)
 
        iounmap(asic->mapping);
 
-       kfree(asic);
-
        return 0;
 }
 
index 10cd14e..1f36885 100644 (file)
@@ -104,23 +104,19 @@ int cros_ec_register(struct cros_ec_device *ec_dev)
        ec_dev->command_sendrecv = cros_ec_command_sendrecv;
 
        if (ec_dev->din_size) {
-               ec_dev->din = kmalloc(ec_dev->din_size, GFP_KERNEL);
-               if (!ec_dev->din) {
-                       err = -ENOMEM;
-                       goto fail_din;
-               }
+               ec_dev->din = devm_kzalloc(dev, ec_dev->din_size, GFP_KERNEL);
+               if (!ec_dev->din)
+                       return -ENOMEM;
        }
        if (ec_dev->dout_size) {
-               ec_dev->dout = kmalloc(ec_dev->dout_size, GFP_KERNEL);
-               if (!ec_dev->dout) {
-                       err = -ENOMEM;
-                       goto fail_dout;
-               }
+               ec_dev->dout = devm_kzalloc(dev, ec_dev->dout_size, GFP_KERNEL);
+               if (!ec_dev->dout)
+                       return -ENOMEM;
        }
 
        if (!ec_dev->irq) {
                dev_dbg(dev, "no valid IRQ: %d\n", ec_dev->irq);
-               goto fail_irq;
+               return err;
        }
 
        err = request_threaded_irq(ec_dev->irq, NULL, ec_irq_thread,
@@ -128,7 +124,7 @@ int cros_ec_register(struct cros_ec_device *ec_dev)
                                   "chromeos-ec", ec_dev);
        if (err) {
                dev_err(dev, "request irq %d: error %d\n", ec_dev->irq, err);
-               goto fail_irq;
+               return err;
        }
 
        err = mfd_add_devices(dev, 0, cros_devs,
@@ -145,11 +141,7 @@ int cros_ec_register(struct cros_ec_device *ec_dev)
 
 fail_mfd:
        free_irq(ec_dev->irq, ec_dev);
-fail_irq:
-       kfree(ec_dev->dout);
-fail_dout:
-       kfree(ec_dev->din);
-fail_din:
+
        return err;
 }
 EXPORT_SYMBOL(cros_ec_register);
@@ -158,8 +150,6 @@ int cros_ec_remove(struct cros_ec_device *ec_dev)
 {
        mfd_remove_devices(ec_dev->dev);
        free_irq(ec_dev->irq, ec_dev);
-       kfree(ec_dev->dout);
-       kfree(ec_dev->din);
 
        return 0;
 }
index c60ab0c..fb64398 100644 (file)
@@ -46,56 +46,39 @@ void davinci_vc_write(struct davinci_vc *davinci_vc,
 static int __init davinci_vc_probe(struct platform_device *pdev)
 {
        struct davinci_vc *davinci_vc;
-       struct resource *res, *mem;
+       struct resource *res;
        struct mfd_cell *cell = NULL;
        int ret;
 
-       davinci_vc = kzalloc(sizeof(struct davinci_vc), GFP_KERNEL);
+       davinci_vc = devm_kzalloc(&pdev->dev,
+                                 sizeof(struct davinci_vc), GFP_KERNEL);
        if (!davinci_vc) {
                dev_dbg(&pdev->dev,
                            "could not allocate memory for private data\n");
                return -ENOMEM;
        }
 
-       davinci_vc->clk = clk_get(&pdev->dev, NULL);
+       davinci_vc->clk = devm_clk_get(&pdev->dev, NULL);
        if (IS_ERR(davinci_vc->clk)) {
                dev_dbg(&pdev->dev,
                            "could not get the clock for voice codec\n");
-               ret = -ENODEV;
-               goto fail1;
+               return -ENODEV;
        }
        clk_enable(davinci_vc->clk);
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res) {
-               dev_err(&pdev->dev, "no mem resource\n");
-               ret = -ENODEV;
-               goto fail2;
-       }
 
-       davinci_vc->pbase = res->start;
-       davinci_vc->base_size = resource_size(res);
-
-       mem = request_mem_region(davinci_vc->pbase, davinci_vc->base_size,
-                                pdev->name);
-       if (!mem) {
-               dev_err(&pdev->dev, "VCIF region already claimed\n");
-               ret = -EBUSY;
-               goto fail2;
-       }
-
-       davinci_vc->base = ioremap(davinci_vc->pbase, davinci_vc->base_size);
-       if (!davinci_vc->base) {
-               dev_err(&pdev->dev, "can't ioremap mem resource.\n");
-               ret = -ENOMEM;
-               goto fail3;
+       davinci_vc->base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(davinci_vc->base)) {
+               ret = PTR_ERR(davinci_vc->base);
+               goto fail;
        }
 
        res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
        if (!res) {
                dev_err(&pdev->dev, "no DMA resource\n");
                ret = -ENXIO;
-               goto fail4;
+               goto fail;
        }
 
        davinci_vc->davinci_vcif.dma_tx_channel = res->start;
@@ -106,7 +89,7 @@ static int __init davinci_vc_probe(struct platform_device *pdev)
        if (!res) {
                dev_err(&pdev->dev, "no DMA resource\n");
                ret = -ENXIO;
-               goto fail4;
+               goto fail;
        }
 
        davinci_vc->davinci_vcif.dma_rx_channel = res->start;
@@ -132,21 +115,13 @@ static int __init davinci_vc_probe(struct platform_device *pdev)
                              DAVINCI_VC_CELLS, NULL, 0, NULL);
        if (ret != 0) {
                dev_err(&pdev->dev, "fail to register client devices\n");
-               goto fail4;
+               goto fail;
        }
 
        return 0;
 
-fail4:
-       iounmap(davinci_vc->base);
-fail3:
-       release_mem_region(davinci_vc->pbase, davinci_vc->base_size);
-fail2:
+fail:
        clk_disable(davinci_vc->clk);
-       clk_put(davinci_vc->clk);
-       davinci_vc->clk = NULL;
-fail1:
-       kfree(davinci_vc);
 
        return ret;
 }
@@ -157,14 +132,7 @@ static int davinci_vc_remove(struct platform_device *pdev)
 
        mfd_remove_devices(&pdev->dev);
 
-       iounmap(davinci_vc->base);
-       release_mem_region(davinci_vc->pbase, davinci_vc->base_size);
-
        clk_disable(davinci_vc->clk);
-       clk_put(davinci_vc->clk);
-       davinci_vc->clk = NULL;
-
-       kfree(davinci_vc);
 
        return 0;
 }
index ca355dd..4f6f0fa 100644 (file)
@@ -16,8 +16,8 @@
 #define BITS(_start, _end) ((BIT(_end) - BIT(_start)) + BIT(_end))
 
 #define PRCM_ACLK_MGT          (0x004)
-#define PRCM_SVACLK_MGT                (0x008)
-#define PRCM_SIACLK_MGT                (0x00C)
+#define PRCM_SVAMMCSPCLK_MGT   (0x008)
+#define PRCM_SIAMMDSPCLK_MGT   (0x00C)
 #define PRCM_SGACLK_MGT                (0x014)
 #define PRCM_UARTCLK_MGT       (0x018)
 #define PRCM_MSP02CLK_MGT      (0x01C)
index bbaec0c..26aca54 100644 (file)
@@ -270,7 +270,7 @@ static int __init egpio_probe(struct platform_device *pdev)
        int               ret;
 
        /* Initialize ei data structure. */
-       ei = kzalloc(sizeof(*ei), GFP_KERNEL);
+       ei = devm_kzalloc(&pdev->dev, sizeof(*ei), GFP_KERNEL);
        if (!ei)
                return -ENOMEM;
 
@@ -286,7 +286,8 @@ static int __init egpio_probe(struct platform_device *pdev)
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!res)
                goto fail;
-       ei->base_addr = ioremap_nocache(res->start, resource_size(res));
+       ei->base_addr = devm_ioremap_nocache(&pdev->dev, res->start,
+                                            resource_size(res));
        if (!ei->base_addr)
                goto fail;
        pr_debug("EGPIO phys=%08x virt=%p\n", (u32)res->start, ei->base_addr);
@@ -306,7 +307,9 @@ static int __init egpio_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, ei);
 
        ei->nchips = pdata->num_chips;
-       ei->chip = kzalloc(sizeof(struct egpio_chip) * ei->nchips, GFP_KERNEL);
+       ei->chip = devm_kzalloc(&pdev->dev,
+                               sizeof(struct egpio_chip) * ei->nchips,
+                               GFP_KERNEL);
        if (!ei->chip) {
                ret = -ENOMEM;
                goto fail;
@@ -361,7 +364,6 @@ static int __init egpio_probe(struct platform_device *pdev)
 
 fail:
        printk(KERN_ERR "EGPIO failed to setup\n");
-       kfree(ei);
        return ret;
 }
 
@@ -379,9 +381,6 @@ static int __exit egpio_remove(struct platform_device *pdev)
                irq_set_chained_handler(ei->chained_irq, NULL);
                device_init_wakeup(&pdev->dev, 0);
        }
-       iounmap(ei->base_addr);
-       kfree(ei->chip);
-       kfree(ei);
 
        return 0;
 }
index 324187c..c9dfce6 100644 (file)
@@ -514,8 +514,8 @@ static int htcpld_setup_chips(struct platform_device *pdev)
 
        /* Setup each chip's output GPIOs */
        htcpld->nchips = pdata->num_chip;
-       htcpld->chip = kzalloc(sizeof(struct htcpld_chip) * htcpld->nchips,
-                              GFP_KERNEL);
+       htcpld->chip = devm_kzalloc(dev, sizeof(struct htcpld_chip) * htcpld->nchips,
+                                   GFP_KERNEL);
        if (!htcpld->chip) {
                dev_warn(dev, "Unable to allocate memory for chips\n");
                return -ENOMEM;
@@ -580,12 +580,11 @@ static int htcpld_core_probe(struct platform_device *pdev)
                return -ENXIO;
        }
 
-       htcpld = kzalloc(sizeof(struct htcpld_data), GFP_KERNEL);
+       htcpld = devm_kzalloc(dev, sizeof(struct htcpld_data), GFP_KERNEL);
        if (!htcpld)
                return -ENOMEM;
 
        /* Find chained irq */
-       ret = -EINVAL;
        res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
        if (res) {
                int flags;
@@ -598,7 +597,7 @@ static int htcpld_core_probe(struct platform_device *pdev)
                                           flags, pdev->name, htcpld);
                if (ret) {
                        dev_warn(dev, "Unable to setup chained irq handler: %d\n", ret);
-                       goto fail;
+                       return ret;
                } else
                        device_init_wakeup(dev, 0);
        }
@@ -609,7 +608,7 @@ static int htcpld_core_probe(struct platform_device *pdev)
        /* Setup the htcpld chips */
        ret = htcpld_setup_chips(pdev);
        if (ret)
-               goto fail;
+               return ret;
 
        /* Request the GPIO(s) for the int reset and set them up */
        if (pdata->int_reset_gpio_hi) {
@@ -644,10 +643,6 @@ static int htcpld_core_probe(struct platform_device *pdev)
 
        dev_info(dev, "Initialized successfully\n");
        return 0;
-
-fail:
-       kfree(htcpld);
-       return ret;
 }
 
 /* The I2C Driver -- used internally */
index 0285fce..0a5e85f 100644 (file)
@@ -147,7 +147,7 @@ static int __init pasic3_probe(struct platform_device *pdev)
        if (!request_mem_region(r->start, resource_size(r), "pasic3"))
                return -EBUSY;
 
-       asic = kzalloc(sizeof(struct pasic3_data), GFP_KERNEL);
+       asic = devm_kzalloc(dev, sizeof(struct pasic3_data), GFP_KERNEL);
        if (!asic)
                return -ENOMEM;
 
@@ -156,7 +156,6 @@ static int __init pasic3_probe(struct platform_device *pdev)
        asic->mapping = ioremap(r->start, resource_size(r));
        if (!asic->mapping) {
                dev_err(dev, "couldn't ioremap PASIC3\n");
-               kfree(asic);
                return -ENOMEM;
        }
 
@@ -195,7 +194,6 @@ static int pasic3_remove(struct platform_device *pdev)
        iounmap(asic->mapping);
        r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        release_mem_region(r->start, resource_size(r));
-       kfree(asic);
        return 0;
 }
 
index d8d5137..4f2462f 100644 (file)
@@ -438,7 +438,6 @@ static int intel_msic_remove(struct platform_device *pdev)
        struct intel_msic *msic = platform_get_drvdata(pdev);
 
        intel_msic_remove_devices(msic);
-       platform_set_drvdata(pdev, NULL);
 
        return 0;
 }
index 45ece11..fcbb2e9 100644 (file)
@@ -183,11 +183,10 @@ static int cmodio_pci_probe(struct pci_dev *dev,
        struct cmodio_device *priv;
        int ret;
 
-       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+       priv = devm_kzalloc(&dev->dev, sizeof(*priv), GFP_KERNEL);
        if (!priv) {
                dev_err(&dev->dev, "unable to allocate private data\n");
-               ret = -ENOMEM;
-               goto out_return;
+               return -ENOMEM;
        }
 
        pci_set_drvdata(dev, priv);
@@ -197,7 +196,7 @@ static int cmodio_pci_probe(struct pci_dev *dev,
        ret = pci_enable_device(dev);
        if (ret) {
                dev_err(&dev->dev, "unable to enable device\n");
-               goto out_free_priv;
+               return ret;
        }
 
        pci_set_master(dev);
@@ -248,9 +247,7 @@ out_pci_release_regions:
        pci_release_regions(dev);
 out_pci_disable_device:
        pci_disable_device(dev);
-out_free_priv:
-       kfree(priv);
-out_return:
+
        return ret;
 }
 
@@ -263,7 +260,6 @@ static void cmodio_pci_remove(struct pci_dev *dev)
        iounmap(priv->ctrl);
        pci_release_regions(dev);
        pci_disable_device(dev);
-       kfree(priv);
 }
 
 #define PCI_VENDOR_ID_JANZ             0x13c3
index e80587f..3c0e8cf 100644 (file)
@@ -86,13 +86,13 @@ static void jz4740_adc_irq_demux(unsigned int irq, struct irq_desc *desc)
 static inline void jz4740_adc_clk_enable(struct jz4740_adc *adc)
 {
        if (atomic_inc_return(&adc->clk_ref) == 1)
-               clk_enable(adc->clk);
+               clk_prepare_enable(adc->clk);
 }
 
 static inline void jz4740_adc_clk_disable(struct jz4740_adc *adc)
 {
        if (atomic_dec_return(&adc->clk_ref) == 0)
-               clk_disable(adc->clk);
+               clk_disable_unprepare(adc->clk);
 }
 
 static inline void jz4740_adc_set_enabled(struct jz4740_adc *adc, int engine,
@@ -294,7 +294,6 @@ static int jz4740_adc_probe(struct platform_device *pdev)
 err_clk_put:
        clk_put(adc->clk);
 err_iounmap:
-       platform_set_drvdata(pdev, NULL);
        iounmap(adc->base);
 err_release_mem_region:
        release_mem_region(adc->mem->start, resource_size(adc->mem));
@@ -317,8 +316,6 @@ static int jz4740_adc_remove(struct platform_device *pdev)
 
        clk_put(adc->clk);
 
-       platform_set_drvdata(pdev, NULL);
-
        return 0;
 }
 
diff --git a/drivers/mfd/kempld-core.c b/drivers/mfd/kempld-core.c
new file mode 100644 (file)
index 0000000..686a456
--- /dev/null
@@ -0,0 +1,641 @@
+/*
+ * Kontron PLD MFD core driver
+ *
+ * Copyright (c) 2010-2013 Kontron Europe GmbH
+ * Author: Michael Brunner <michael.brunner@kontron.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License 2 as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/kempld.h>
+#include <linux/module.h>
+#include <linux/dmi.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+
+#define MAX_ID_LEN 4
+static char force_device_id[MAX_ID_LEN + 1] = "";
+module_param_string(force_device_id, force_device_id, sizeof(force_device_id), 0);
+MODULE_PARM_DESC(force_device_id, "Override detected product");
+
+/*
+ * Get hardware mutex to block firmware from accessing the pld.
+ * It is possible for the firmware may hold the mutex for an extended length of
+ * time. This function will block until access has been granted.
+ */
+static void kempld_get_hardware_mutex(struct kempld_device_data *pld)
+{
+       /* The mutex bit will read 1 until access has been granted */
+       while (ioread8(pld->io_index) & KEMPLD_MUTEX_KEY)
+               msleep(1);
+}
+
+static void kempld_release_hardware_mutex(struct kempld_device_data *pld)
+{
+       /* The harware mutex is released when 1 is written to the mutex bit. */
+       iowrite8(KEMPLD_MUTEX_KEY, pld->io_index);
+}
+
+static int kempld_get_info_generic(struct kempld_device_data *pld)
+{
+       u16 version;
+       u8 spec;
+
+       kempld_get_mutex(pld);
+
+       version = kempld_read16(pld, KEMPLD_VERSION);
+       spec = kempld_read8(pld, KEMPLD_SPEC);
+       pld->info.buildnr = kempld_read16(pld, KEMPLD_BUILDNR);
+
+       pld->info.minor = KEMPLD_VERSION_GET_MINOR(version);
+       pld->info.major = KEMPLD_VERSION_GET_MAJOR(version);
+       pld->info.number = KEMPLD_VERSION_GET_NUMBER(version);
+       pld->info.type = KEMPLD_VERSION_GET_TYPE(version);
+
+       if (spec == 0xff) {
+               pld->info.spec_minor = 0;
+               pld->info.spec_major = 1;
+       } else {
+               pld->info.spec_minor = KEMPLD_SPEC_GET_MINOR(spec);
+               pld->info.spec_major = KEMPLD_SPEC_GET_MAJOR(spec);
+       }
+
+       if (pld->info.spec_major > 0)
+               pld->feature_mask = kempld_read16(pld, KEMPLD_FEATURE);
+       else
+               pld->feature_mask = 0;
+
+       kempld_release_mutex(pld);
+
+       return 0;
+}
+
+enum kempld_cells {
+       KEMPLD_I2C = 0,
+       KEMPLD_WDT,
+       KEMPLD_GPIO,
+       KEMPLD_UART,
+};
+
+static struct mfd_cell kempld_devs[] = {
+       [KEMPLD_I2C] = {
+               .name = "kempld-i2c",
+       },
+       [KEMPLD_WDT] = {
+               .name = "kempld-wdt",
+       },
+       [KEMPLD_GPIO] = {
+               .name = "kempld-gpio",
+       },
+       [KEMPLD_UART] = {
+               .name = "kempld-uart",
+       },
+};
+
+#define KEMPLD_MAX_DEVS        ARRAY_SIZE(kempld_devs)
+
+static int kempld_register_cells_generic(struct kempld_device_data *pld)
+{
+       struct mfd_cell devs[KEMPLD_MAX_DEVS];
+       int i = 0;
+
+       if (pld->feature_mask & KEMPLD_FEATURE_BIT_I2C)
+               devs[i++] = kempld_devs[KEMPLD_I2C];
+
+       if (pld->feature_mask & KEMPLD_FEATURE_BIT_WATCHDOG)
+               devs[i++] = kempld_devs[KEMPLD_WDT];
+
+       if (pld->feature_mask & KEMPLD_FEATURE_BIT_GPIO)
+               devs[i++] = kempld_devs[KEMPLD_GPIO];
+
+       if (pld->feature_mask & KEMPLD_FEATURE_MASK_UART)
+               devs[i++] = kempld_devs[KEMPLD_UART];
+
+       return mfd_add_devices(pld->dev, -1, devs, i, NULL, 0, NULL);
+}
+
+static struct resource kempld_ioresource = {
+       .start  = KEMPLD_IOINDEX,
+       .end    = KEMPLD_IODATA,
+       .flags  = IORESOURCE_IO,
+};
+
+static const struct kempld_platform_data kempld_platform_data_generic = {
+       .pld_clock              = KEMPLD_CLK,
+       .ioresource             = &kempld_ioresource,
+       .get_hardware_mutex     = kempld_get_hardware_mutex,
+       .release_hardware_mutex = kempld_release_hardware_mutex,
+       .get_info               = kempld_get_info_generic,
+       .register_cells         = kempld_register_cells_generic,
+};
+
+static struct platform_device *kempld_pdev;
+
+static int kempld_create_platform_device(const struct dmi_system_id *id)
+{
+       struct kempld_platform_data *pdata = id->driver_data;
+       int ret;
+
+       kempld_pdev = platform_device_alloc("kempld", -1);
+       if (!kempld_pdev)
+               return -ENOMEM;
+
+       ret = platform_device_add_data(kempld_pdev, pdata, sizeof(*pdata));
+       if (ret)
+               goto err;
+
+       ret = platform_device_add_resources(kempld_pdev, pdata->ioresource, 1);
+       if (ret)
+               goto err;
+
+       ret = platform_device_add(kempld_pdev);
+       if (ret)
+               goto err;
+
+       return 0;
+err:
+       platform_device_put(kempld_pdev);
+       return ret;
+}
+
+/**
+ * kempld_read8 - read 8 bit register
+ * @pld: kempld_device_data structure describing the PLD
+ * @index: register index on the chip
+ *
+ * kempld_get_mutex must be called prior to calling this function.
+ */
+u8 kempld_read8(struct kempld_device_data *pld, u8 index)
+{
+       iowrite8(index, pld->io_index);
+       return ioread8(pld->io_data);
+}
+EXPORT_SYMBOL_GPL(kempld_read8);
+
+/**
+ * kempld_write8 - write 8 bit register
+ * @pld: kempld_device_data structure describing the PLD
+ * @index: register index on the chip
+ * @data: new register value
+ *
+ * kempld_get_mutex must be called prior to calling this function.
+ */
+void kempld_write8(struct kempld_device_data *pld, u8 index, u8 data)
+{
+       iowrite8(index, pld->io_index);
+       iowrite8(data, pld->io_data);
+}
+EXPORT_SYMBOL_GPL(kempld_write8);
+
+/**
+ * kempld_read16 - read 16 bit register
+ * @pld: kempld_device_data structure describing the PLD
+ * @index: register index on the chip
+ *
+ * kempld_get_mutex must be called prior to calling this function.
+ */
+u16 kempld_read16(struct kempld_device_data *pld, u8 index)
+{
+       return kempld_read8(pld, index) | kempld_read8(pld, index + 1) << 8;
+}
+EXPORT_SYMBOL_GPL(kempld_read16);
+
+/**
+ * kempld_write16 - write 16 bit register
+ * @pld: kempld_device_data structure describing the PLD
+ * @index: register index on the chip
+ * @data: new register value
+ *
+ * kempld_get_mutex must be called prior to calling this function.
+ */
+void kempld_write16(struct kempld_device_data *pld, u8 index, u16 data)
+{
+       kempld_write8(pld, index, (u8)data);
+       kempld_write8(pld, index + 1, (u8)(data >> 8));
+}
+EXPORT_SYMBOL_GPL(kempld_write16);
+
+/**
+ * kempld_read32 - read 32 bit register
+ * @pld: kempld_device_data structure describing the PLD
+ * @index: register index on the chip
+ *
+ * kempld_get_mutex must be called prior to calling this function.
+ */
+u32 kempld_read32(struct kempld_device_data *pld, u8 index)
+{
+       return kempld_read16(pld, index) | kempld_read16(pld, index + 2) << 16;
+}
+EXPORT_SYMBOL_GPL(kempld_read32);
+
+/**
+ * kempld_write32 - write 32 bit register
+ * @pld: kempld_device_data structure describing the PLD
+ * @index: register index on the chip
+ * @data: new register value
+ *
+ * kempld_get_mutex must be called prior to calling this function.
+ */
+void kempld_write32(struct kempld_device_data *pld, u8 index, u32 data)
+{
+       kempld_write16(pld, index, (u16)data);
+       kempld_write16(pld, index + 2, (u16)(data >> 16));
+}
+EXPORT_SYMBOL_GPL(kempld_write32);
+
+/**
+ * kempld_get_mutex - acquire PLD mutex
+ * @pld: kempld_device_data structure describing the PLD
+ */
+void kempld_get_mutex(struct kempld_device_data *pld)
+{
+       struct kempld_platform_data *pdata = pld->dev->platform_data;
+
+       mutex_lock(&pld->lock);
+       pdata->get_hardware_mutex(pld);
+}
+EXPORT_SYMBOL_GPL(kempld_get_mutex);
+
+/**
+ * kempld_release_mutex - release PLD mutex
+ * @pld: kempld_device_data structure describing the PLD
+ */
+void kempld_release_mutex(struct kempld_device_data *pld)
+{
+       struct kempld_platform_data *pdata = pld->dev->platform_data;
+
+       pdata->release_hardware_mutex(pld);
+       mutex_unlock(&pld->lock);
+}
+EXPORT_SYMBOL_GPL(kempld_release_mutex);
+
+/**
+ * kempld_get_info - update device specific information
+ * @pld: kempld_device_data structure describing the PLD
+ *
+ * This function calls the configured board specific kempld_get_info_XXXX
+ * function which is responsible for gathering information about the specific
+ * hardware. The information is then stored within the pld structure.
+ */
+static int kempld_get_info(struct kempld_device_data *pld)
+{
+       struct kempld_platform_data *pdata = pld->dev->platform_data;
+
+       return pdata->get_info(pld);
+}
+
+/*
+ * kempld_register_cells - register cell drivers
+ *
+ * This function registers cell drivers for the detected hardware by calling
+ * the configured kempld_register_cells_XXXX function which is responsible
+ * to detect and register the needed cell drivers.
+ */
+static int kempld_register_cells(struct kempld_device_data *pld)
+{
+       struct kempld_platform_data *pdata = pld->dev->platform_data;
+
+       return pdata->register_cells(pld);
+}
+
+static int kempld_detect_device(struct kempld_device_data *pld)
+{
+       char *version_type;
+       u8 index_reg;
+       int ret;
+
+       mutex_lock(&pld->lock);
+
+       /* Check for empty IO space */
+       index_reg = ioread8(pld->io_index);
+       if (index_reg == 0xff && ioread8(pld->io_data) == 0xff) {
+               mutex_unlock(&pld->lock);
+               return -ENODEV;
+       }
+
+       /* Release hardware mutex if aquired */
+       if (!(index_reg & KEMPLD_MUTEX_KEY))
+               iowrite8(KEMPLD_MUTEX_KEY, pld->io_index);
+
+       mutex_unlock(&pld->lock);
+
+       ret = kempld_get_info(pld);
+       if (ret)
+               return ret;
+
+       switch (pld->info.type) {
+       case 0:
+               version_type = "release";
+               break;
+       case 1:
+               version_type = "debug";
+               break;
+       case 2:
+               version_type = "custom";
+               break;
+       default:
+               version_type = "unspecified";
+       }
+
+       dev_info(pld->dev, "Found Kontron PLD %d\n", pld->info.number);
+       dev_info(pld->dev, "%s version %d.%d build %d, specification %d.%d\n",
+                version_type, pld->info.major, pld->info.minor,
+                pld->info.buildnr, pld->info.spec_major,
+                pld->info.spec_minor);
+
+       return kempld_register_cells(pld);
+}
+
+static int kempld_probe(struct platform_device *pdev)
+{
+       struct kempld_platform_data *pdata = pdev->dev.platform_data;
+       struct device *dev = &pdev->dev;
+       struct kempld_device_data *pld;
+       struct resource *ioport;
+       int ret;
+
+       pld = devm_kzalloc(dev, sizeof(*pld), GFP_KERNEL);
+       if (!pld)
+               return -ENOMEM;
+
+       ioport = platform_get_resource(pdev, IORESOURCE_IO, 0);
+       if (!ioport)
+               return -EINVAL;
+
+       pld->io_base = devm_ioport_map(dev, ioport->start,
+                                       ioport->end - ioport->start);
+       if (!pld->io_base)
+               return -ENOMEM;
+
+       pld->io_index = pld->io_base;
+       pld->io_data = pld->io_base + 1;
+       pld->pld_clock = pdata->pld_clock;
+       pld->dev = dev;
+
+       mutex_init(&pld->lock);
+       platform_set_drvdata(pdev, pld);
+
+       ret = kempld_detect_device(pld);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+static int kempld_remove(struct platform_device *pdev)
+{
+       struct kempld_device_data *pld = platform_get_drvdata(pdev);
+       struct kempld_platform_data *pdata = pld->dev->platform_data;
+
+       mfd_remove_devices(&pdev->dev);
+       pdata->release_hardware_mutex(pld);
+
+       return 0;
+}
+
+static struct platform_driver kempld_driver = {
+       .driver         = {
+               .name   = "kempld",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = kempld_probe,
+       .remove         = kempld_remove,
+};
+
+static struct dmi_system_id __initdata kempld_dmi_table[] = {
+       {
+               .ident = "CCR2",
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
+                       DMI_MATCH(DMI_BOARD_NAME, "COMe-bIP2"),
+               },
+               .driver_data = (void *)&kempld_platform_data_generic,
+               .callback = kempld_create_platform_device,
+       }, {
+               .ident = "CCR6",
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
+                       DMI_MATCH(DMI_BOARD_NAME, "COMe-bIP6"),
+               },
+               .driver_data = (void *)&kempld_platform_data_generic,
+               .callback = kempld_create_platform_device,
+       }, {
+               .ident = "CHR2",
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
+                       DMI_MATCH(DMI_BOARD_NAME, "ETXexpress-SC T2"),
+               },
+               .driver_data = (void *)&kempld_platform_data_generic,
+               .callback = kempld_create_platform_device,
+       }, {
+               .ident = "CHR2",
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
+                       DMI_MATCH(DMI_BOARD_NAME, "ETXe-SC T2"),
+               },
+               .driver_data = (void *)&kempld_platform_data_generic,
+               .callback = kempld_create_platform_device,
+       }, {
+               .ident = "CHR2",
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
+                       DMI_MATCH(DMI_BOARD_NAME, "COMe-bSC2"),
+               },
+               .driver_data = (void *)&kempld_platform_data_generic,
+               .callback = kempld_create_platform_device,
+       }, {
+               .ident = "CHR6",
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
+                       DMI_MATCH(DMI_BOARD_NAME, "ETXexpress-SC T6"),
+               },
+               .driver_data = (void *)&kempld_platform_data_generic,
+               .callback = kempld_create_platform_device,
+       }, {
+               .ident = "CHR6",
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
+                       DMI_MATCH(DMI_BOARD_NAME, "ETXe-SC T6"),
+               },
+               .driver_data = (void *)&kempld_platform_data_generic,
+               .callback = kempld_create_platform_device,
+       }, {
+               .ident = "CHR6",
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
+                       DMI_MATCH(DMI_BOARD_NAME, "COMe-bSC6"),
+               },
+               .driver_data = (void *)&kempld_platform_data_generic,
+               .callback = kempld_create_platform_device,
+       }, {
+               .ident = "CNTG",
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
+                       DMI_MATCH(DMI_BOARD_NAME, "ETXexpress-PC"),
+               },
+               .driver_data = (void *)&kempld_platform_data_generic,
+               .callback = kempld_create_platform_device,
+       }, {
+               .ident = "CNTG",
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
+                       DMI_MATCH(DMI_BOARD_NAME, "COMe-bPC2"),
+               },
+               .driver_data = (void *)&kempld_platform_data_generic,
+               .callback = kempld_create_platform_device,
+       }, {
+               .ident = "CNTX",
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
+                       DMI_MATCH(DMI_BOARD_NAME, "PXT"),
+               },
+               .driver_data = (void *)&kempld_platform_data_generic,
+               .callback = kempld_create_platform_device,
+       }, {
+               .ident = "FRI2",
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
+                       DMI_MATCH(DMI_BIOS_VERSION, "FRI2"),
+               },
+               .driver_data = (void *)&kempld_platform_data_generic,
+               .callback = kempld_create_platform_device,
+       }, {
+               .ident = "FRI2",
+               .matches = {
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Fish River Island II"),
+               },
+               .driver_data = (void *)&kempld_platform_data_generic,
+               .callback = kempld_create_platform_device,
+       }, {
+               .ident = "MBR1",
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
+                       DMI_MATCH(DMI_BOARD_NAME, "ETX-OH"),
+               },
+               .driver_data = (void *)&kempld_platform_data_generic,
+               .callback = kempld_create_platform_device,
+       }, {
+               .ident = "NTC1",
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
+                       DMI_MATCH(DMI_BOARD_NAME, "nanoETXexpress-TT"),
+               },
+               .driver_data = (void *)&kempld_platform_data_generic,
+               .callback = kempld_create_platform_device,
+       }, {
+               .ident = "NTC1",
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
+                       DMI_MATCH(DMI_BOARD_NAME, "nETXe-TT"),
+               },
+               .driver_data = (void *)&kempld_platform_data_generic,
+               .callback = kempld_create_platform_device,
+       }, {
+               .ident = "NTC1",
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
+                       DMI_MATCH(DMI_BOARD_NAME, "COMe-mTT"),
+               },
+               .driver_data = (void *)&kempld_platform_data_generic,
+               .callback = kempld_create_platform_device,
+       }, {
+               .ident = "NUP1",
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
+                       DMI_MATCH(DMI_BOARD_NAME, "COMe-mCT"),
+               },
+               .driver_data = (void *)&kempld_platform_data_generic,
+               .callback = kempld_create_platform_device,
+       }, {
+               .ident = "UNP1",
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
+                       DMI_MATCH(DMI_BOARD_NAME, "microETXexpress-DC"),
+               },
+               .driver_data = (void *)&kempld_platform_data_generic,
+               .callback = kempld_create_platform_device,
+       }, {
+               .ident = "UNP1",
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
+                       DMI_MATCH(DMI_BOARD_NAME, "COMe-cDC2"),
+               },
+               .driver_data = (void *)&kempld_platform_data_generic,
+               .callback = kempld_create_platform_device,
+       }, {
+               .ident = "UNTG",
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
+                       DMI_MATCH(DMI_BOARD_NAME, "microETXexpress-PC"),
+               },
+               .driver_data = (void *)&kempld_platform_data_generic,
+               .callback = kempld_create_platform_device,
+       }, {
+               .ident = "UNTG",
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
+                       DMI_MATCH(DMI_BOARD_NAME, "COMe-cPC2"),
+               },
+               .driver_data = (void *)&kempld_platform_data_generic,
+               .callback = kempld_create_platform_device,
+       }, {
+               .ident = "UUP6",
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
+                       DMI_MATCH(DMI_BOARD_NAME, "COMe-cCT6"),
+               },
+               .driver_data = (void *)&kempld_platform_data_generic,
+               .callback = kempld_create_platform_device,
+       },
+       {}
+};
+MODULE_DEVICE_TABLE(dmi, kempld_dmi_table);
+
+static int __init kempld_init(void)
+{
+       const struct dmi_system_id *id;
+       int ret;
+
+       if (force_device_id[0]) {
+               for (id = kempld_dmi_table; id->matches[0].slot != DMI_NONE; id++)
+                       if (strstr(id->ident, force_device_id))
+                               if (id->callback && id->callback(id))
+                                       break;
+               if (id->matches[0].slot == DMI_NONE)
+                       return -ENODEV;
+       } else {
+               if (!dmi_check_system(kempld_dmi_table))
+                       return -ENODEV;
+       }
+
+       ret = platform_driver_register(&kempld_driver);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+static void __exit kempld_exit(void)
+{
+       if (kempld_pdev)
+               platform_device_unregister(kempld_pdev);
+
+       platform_driver_unregister(&kempld_driver);
+}
+
+module_init(kempld_init);
+module_exit(kempld_exit);
+
+MODULE_DESCRIPTION("KEM PLD Core Driver");
+MODULE_AUTHOR("Michael Brunner <michael.brunner@kontron.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:kempld-core");
index 9f12f91..2403332 100644 (file)
@@ -51,6 +51,8 @@
  *     document number TBD : Lynx Point
  *     document number TBD : Lynx Point-LP
  *     document number TBD : Wellsburg
+ *     document number TBD : Avoton SoC
+ *     document number TBD : Coleto Creek
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -207,6 +209,8 @@ enum lpc_chipsets {
        LPC_LPT,        /* Lynx Point */
        LPC_LPT_LP,     /* Lynx Point-LP */
        LPC_WBG,        /* Wellsburg */
+       LPC_AVN,        /* Avoton SoC */
+       LPC_COLETO,     /* Coleto Creek */
 };
 
 struct lpc_ich_info lpc_chipset_info[] = {
@@ -491,6 +495,14 @@ struct lpc_ich_info lpc_chipset_info[] = {
                .name = "Wellsburg",
                .iTCO_version = 2,
        },
+       [LPC_AVN] = {
+               .name = "Avoton SoC",
+               .iTCO_version = 1,
+       },
+       [LPC_COLETO] = {
+               .name = "Coleto Creek",
+               .iTCO_version = 2,
+       },
 };
 
 /*
@@ -704,6 +716,11 @@ static DEFINE_PCI_DEVICE_TABLE(lpc_ich_ids) = {
        { PCI_VDEVICE(INTEL, 0x8d5d), LPC_WBG},
        { PCI_VDEVICE(INTEL, 0x8d5e), LPC_WBG},
        { PCI_VDEVICE(INTEL, 0x8d5f), LPC_WBG},
+       { PCI_VDEVICE(INTEL, 0x1f38), LPC_AVN},
+       { PCI_VDEVICE(INTEL, 0x1f39), LPC_AVN},
+       { PCI_VDEVICE(INTEL, 0x1f3a), LPC_AVN},
+       { PCI_VDEVICE(INTEL, 0x1f3b), LPC_AVN},
+       { PCI_VDEVICE(INTEL, 0x2390), LPC_COLETO},
        { 0, },                 /* End of list */
 };
 MODULE_DEVICE_TABLE(pci, lpc_ich_ids);
@@ -973,18 +990,7 @@ static struct pci_driver lpc_ich_driver = {
        .remove         = lpc_ich_remove,
 };
 
-static int __init lpc_ich_init(void)
-{
-       return pci_register_driver(&lpc_ich_driver);
-}
-
-static void __exit lpc_ich_exit(void)
-{
-       pci_unregister_driver(&lpc_ich_driver);
-}
-
-module_init(lpc_ich_init);
-module_exit(lpc_ich_exit);
+module_pci_driver(lpc_ich_driver);
 
 MODULE_AUTHOR("Aaron Sierra <asierra@xes-inc.com>");
 MODULE_DESCRIPTION("LPC interface for Intel ICH");
index 1cbb176..f27a218 100644 (file)
@@ -37,6 +37,7 @@
 static struct mfd_cell max77686_devs[] = {
        { .name = "max77686-pmic", },
        { .name = "max77686-rtc", },
+       { .name = "max77686-clk", },
 };
 
 static struct regmap_config max77686_regmap_config = {
@@ -84,12 +85,12 @@ static int max77686_i2c_probe(struct i2c_client *i2c,
                pdata = max77686_i2c_parse_dt_pdata(&i2c->dev);
 
        if (!pdata) {
-               ret = -EIO;
                dev_err(&i2c->dev, "No platform data found.\n");
-               goto err;
+               return -EIO;
        }
 
-       max77686 = kzalloc(sizeof(struct max77686_dev), GFP_KERNEL);
+       max77686 = devm_kzalloc(&i2c->dev,
+                               sizeof(struct max77686_dev), GFP_KERNEL);
        if (max77686 == NULL)
                return -ENOMEM;
 
@@ -107,7 +108,6 @@ static int max77686_i2c_probe(struct i2c_client *i2c,
                ret = PTR_ERR(max77686->regmap);
                dev_err(max77686->dev, "Failed to allocate register map: %d\n",
                                ret);
-               kfree(max77686);
                return ret;
        }
 
@@ -115,8 +115,7 @@ static int max77686_i2c_probe(struct i2c_client *i2c,
                         MAX77686_REG_DEVICE_ID, &data) < 0) {
                dev_err(max77686->dev,
                        "device not found on this channel (this is not an error)\n");
-               ret = -ENODEV;
-               goto err;
+               return -ENODEV;
        } else
                dev_info(max77686->dev, "device found\n");
 
@@ -127,17 +126,11 @@ static int max77686_i2c_probe(struct i2c_client *i2c,
 
        ret = mfd_add_devices(max77686->dev, -1, max77686_devs,
                              ARRAY_SIZE(max77686_devs), NULL, 0, NULL);
+       if (ret < 0) {
+               mfd_remove_devices(max77686->dev);
+               i2c_unregister_device(max77686->rtc);
+       }
 
-       if (ret < 0)
-               goto err_mfd;
-
-       return ret;
-
-err_mfd:
-       mfd_remove_devices(max77686->dev);
-       i2c_unregister_device(max77686->rtc);
-err:
-       kfree(max77686);
        return ret;
 }
 
@@ -147,7 +140,6 @@ static int max77686_i2c_remove(struct i2c_client *i2c)
 
        mfd_remove_devices(max77686->dev);
        i2c_unregister_device(max77686->rtc);
-       kfree(max77686);
 
        return 0;
 }
index 92bbebd..8042b32 100644 (file)
@@ -170,7 +170,8 @@ static int max8925_probe(struct i2c_client *client,
                return -EINVAL;
        }
 
-       chip = kzalloc(sizeof(struct max8925_chip), GFP_KERNEL);
+       chip = devm_kzalloc(&client->dev,
+                           sizeof(struct max8925_chip), GFP_KERNEL);
        if (chip == NULL)
                return -ENOMEM;
        chip->i2c = client;
@@ -199,7 +200,6 @@ static int max8925_remove(struct i2c_client *client)
        max8925_device_exit(chip);
        i2c_unregister_device(chip->adc);
        i2c_unregister_device(chip->rtc);
-       kfree(chip);
        return 0;
 }
 
index 5919710..c469477 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/device.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
+#include <linux/irqdomain.h>
 #include <linux/mfd/max8998-private.h>
 
 struct max8998_irq_data {
@@ -99,7 +100,8 @@ static struct max8998_irq_data max8998_irqs[] = {
 static inline struct max8998_irq_data *
 irq_to_max8998_irq(struct max8998_dev *max8998, int irq)
 {
-       return &max8998_irqs[irq - max8998->irq_base];
+       struct irq_data *data = irq_get_irq_data(irq);
+       return &max8998_irqs[data->hwirq];
 }
 
 static void max8998_irq_lock(struct irq_data *data)
@@ -176,8 +178,14 @@ static irqreturn_t max8998_irq_thread(int irq, void *data)
 
        /* Report */
        for (i = 0; i < MAX8998_IRQ_NR; i++) {
-               if (irq_reg[max8998_irqs[i].reg - 1] & max8998_irqs[i].mask)
-                       handle_nested_irq(max8998->irq_base + i);
+               if (irq_reg[max8998_irqs[i].reg - 1] & max8998_irqs[i].mask) {
+                       irq = irq_find_mapping(max8998->irq_domain, i);
+                       if (WARN_ON(!irq)) {
+                               disable_irq_nosync(max8998->irq);
+                               return IRQ_NONE;
+                       }
+                       handle_nested_irq(irq);
+               }
        }
 
        return IRQ_HANDLED;
@@ -185,27 +193,40 @@ static irqreturn_t max8998_irq_thread(int irq, void *data)
 
 int max8998_irq_resume(struct max8998_dev *max8998)
 {
-       if (max8998->irq && max8998->irq_base)
-               max8998_irq_thread(max8998->irq_base, max8998);
+       if (max8998->irq && max8998->irq_domain)
+               max8998_irq_thread(max8998->irq, max8998);
+       return 0;
+}
+
+static int max8998_irq_domain_map(struct irq_domain *d, unsigned int irq,
+                                       irq_hw_number_t hw)
+{
+       struct max8997_dev *max8998 = d->host_data;
+
+       irq_set_chip_data(irq, max8998);
+       irq_set_chip_and_handler(irq, &max8998_irq_chip, handle_edge_irq);
+       irq_set_nested_thread(irq, 1);
+#ifdef CONFIG_ARM
+       set_irq_flags(irq, IRQF_VALID);
+#else
+       irq_set_noprobe(irq);
+#endif
        return 0;
 }
 
+static struct irq_domain_ops max8998_irq_domain_ops = {
+       .map = max8998_irq_domain_map,
+};
+
 int max8998_irq_init(struct max8998_dev *max8998)
 {
        int i;
-       int cur_irq;
        int ret;
+       struct irq_domain *domain;
 
        if (!max8998->irq) {
                dev_warn(max8998->dev,
                         "No interrupt specified, no interrupts\n");
-               max8998->irq_base = 0;
-               return 0;
-       }
-
-       if (!max8998->irq_base) {
-               dev_err(max8998->dev,
-                       "No interrupt base specified, no interrupts\n");
                return 0;
        }
 
@@ -221,19 +242,13 @@ int max8998_irq_init(struct max8998_dev *max8998)
        max8998_write_reg(max8998->i2c, MAX8998_REG_STATUSM1, 0xff);
        max8998_write_reg(max8998->i2c, MAX8998_REG_STATUSM2, 0xff);
 
-       /* register with genirq */
-       for (i = 0; i < MAX8998_IRQ_NR; i++) {
-               cur_irq = i + max8998->irq_base;
-               irq_set_chip_data(cur_irq, max8998);
-               irq_set_chip_and_handler(cur_irq, &max8998_irq_chip,
-                                        handle_edge_irq);
-               irq_set_nested_thread(cur_irq, 1);
-#ifdef CONFIG_ARM
-               set_irq_flags(cur_irq, IRQF_VALID);
-#else
-               irq_set_noprobe(cur_irq);
-#endif
+       domain = irq_domain_add_simple(NULL, MAX8998_IRQ_NR,
+                       max8998->irq_base, &max8998_irq_domain_ops, max8998);
+       if (!domain) {
+               dev_err(max8998->dev, "could not create irq domain\n");
+               return -ENODEV;
        }
+       max8998->irq_domain = domain;
 
        ret = request_threaded_irq(max8998->irq, NULL, max8998_irq_thread,
                                   IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
index d7218cc..21af51a 100644 (file)
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
+#include <linux/err.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/i2c.h>
 #include <linux/interrupt.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
 #include <linux/pm_runtime.h>
 #include <linux/mutex.h>
 #include <linux/mfd/core.h>
@@ -128,6 +131,56 @@ int max8998_update_reg(struct i2c_client *i2c, u8 reg, u8 val, u8 mask)
 }
 EXPORT_SYMBOL(max8998_update_reg);
 
+#ifdef CONFIG_OF
+static struct of_device_id max8998_dt_match[] = {
+       { .compatible = "maxim,max8998", .data = (void *)TYPE_MAX8998 },
+       { .compatible = "national,lp3974", .data = (void *)TYPE_LP3974 },
+       { .compatible = "ti,lp3974", .data = (void *)TYPE_LP3974 },
+       {},
+};
+MODULE_DEVICE_TABLE(of, max8998_dt_match);
+#endif
+
+/*
+ * Only the common platform data elements for max8998 are parsed here from the
+ * device tree. Other sub-modules of max8998 such as pmic, rtc and others have
+ * to parse their own platform data elements from device tree.
+ *
+ * The max8998 platform data structure is instantiated here and the drivers for
+ * the sub-modules need not instantiate another instance while parsing their
+ * platform data.
+ */
+static struct max8998_platform_data *max8998_i2c_parse_dt_pdata(
+                                                       struct device *dev)
+{
+       struct max8998_platform_data *pd;
+
+       pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
+       if (!pd)
+               return ERR_PTR(-ENOMEM);
+
+       pd->ono = irq_of_parse_and_map(dev->of_node, 1);
+
+       /*
+        * ToDo: the 'wakeup' member in the platform data is more of a linux
+        * specfic information. Hence, there is no binding for that yet and
+        * not parsed here.
+        */
+       return pd;
+}
+
+static inline int max8998_i2c_get_driver_data(struct i2c_client *i2c,
+                                               const struct i2c_device_id *id)
+{
+       if (IS_ENABLED(CONFIG_OF) && i2c->dev.of_node) {
+               const struct of_device_id *match;
+               match = of_match_node(max8998_dt_match, i2c->dev.of_node);
+               return (int)match->data;
+       }
+
+       return (int)id->driver_data;
+}
+
 static int max8998_i2c_probe(struct i2c_client *i2c,
                            const struct i2c_device_id *id)
 {
@@ -139,11 +192,20 @@ static int max8998_i2c_probe(struct i2c_client *i2c,
        if (max8998 == NULL)
                return -ENOMEM;
 
+       if (IS_ENABLED(CONFIG_OF) && i2c->dev.of_node) {
+               pdata = max8998_i2c_parse_dt_pdata(&i2c->dev);
+               if (IS_ERR(pdata)) {
+                       ret = PTR_ERR(pdata);
+                       goto err;
+               }
+       }
+
        i2c_set_clientdata(i2c, max8998);
        max8998->dev = &i2c->dev;
        max8998->i2c = i2c;
        max8998->irq = i2c->irq;
-       max8998->type = id->driver_data;
+       max8998->type = max8998_i2c_get_driver_data(i2c, id);
+       max8998->pdata = pdata;
        if (pdata) {
                max8998->ono = pdata->ono;
                max8998->irq_base = pdata->irq_base;
@@ -158,7 +220,7 @@ static int max8998_i2c_probe(struct i2c_client *i2c,
 
        pm_runtime_set_active(max8998->dev);
 
-       switch (id->driver_data) {
+       switch (max8998->type) {
        case TYPE_LP3974:
                ret = mfd_add_devices(max8998->dev, -1,
                                      lp3974_devs, ARRAY_SIZE(lp3974_devs),
@@ -314,6 +376,7 @@ static struct i2c_driver max8998_i2c_driver = {
                   .name = "max8998",
                   .owner = THIS_MODULE,
                   .pm = &max8998_pm,
+                  .of_match_table = of_match_ptr(max8998_dt_match),
        },
        .probe = max8998_i2c_probe,
        .remove = max8998_i2c_remove,
index f99d629..13198d9 100644 (file)
@@ -225,8 +225,6 @@ static int mcp_sa11x0_probe(struct platform_device *dev)
        if (ret == 0)
                return 0;
 
-       platform_set_drvdata(dev, NULL);
-
  err_ioremap:
        iounmap(m->base1);
        iounmap(m->base0);
@@ -252,7 +250,6 @@ static int mcp_sa11x0_remove(struct platform_device *dev)
        mem0 = platform_get_resource(dev, IORESOURCE_MEM, 0);
        mem1 = platform_get_resource(dev, IORESOURCE_MEM, 1);
 
-       platform_set_drvdata(dev, NULL);
        mcp_host_del(mcp);
        iounmap(m->base1);
        iounmap(m->base0);
index 53e9fe6..e4d1c70 100644 (file)
 #include <linux/err.h>
 #include <linux/mfd/core.h>
 #include <linux/mfd/palmas.h>
-#include <linux/of_platform.h>
-
-enum palmas_ids {
-       PALMAS_PMIC_ID,
-       PALMAS_GPIO_ID,
-       PALMAS_LEDS_ID,
-       PALMAS_WDT_ID,
-       PALMAS_RTC_ID,
-       PALMAS_PWRBUTTON_ID,
-       PALMAS_GPADC_ID,
-       PALMAS_RESOURCE_ID,
-       PALMAS_CLK_ID,
-       PALMAS_PWM_ID,
-       PALMAS_USB_ID,
-};
-
-static struct resource palmas_rtc_resources[] = {
-       {
-               .start  = PALMAS_RTC_ALARM_IRQ,
-               .end    = PALMAS_RTC_ALARM_IRQ,
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-static const struct mfd_cell palmas_children[] = {
-       {
-               .name = "palmas-pmic",
-               .id = PALMAS_PMIC_ID,
-       },
-       {
-               .name = "palmas-gpio",
-               .id = PALMAS_GPIO_ID,
-       },
-       {
-               .name = "palmas-leds",
-               .id = PALMAS_LEDS_ID,
-       },
-       {
-               .name = "palmas-wdt",
-               .id = PALMAS_WDT_ID,
-       },
-       {
-               .name = "palmas-rtc",
-               .id = PALMAS_RTC_ID,
-               .resources = &palmas_rtc_resources[0],
-               .num_resources = ARRAY_SIZE(palmas_rtc_resources),
-       },
-       {
-               .name = "palmas-pwrbutton",
-               .id = PALMAS_PWRBUTTON_ID,
-       },
-       {
-               .name = "palmas-gpadc",
-               .id = PALMAS_GPADC_ID,
-       },
-       {
-               .name = "palmas-resource",
-               .id = PALMAS_RESOURCE_ID,
-       },
-       {
-               .name = "palmas-clk",
-               .id = PALMAS_CLK_ID,
-       },
-       {
-               .name = "palmas-pwm",
-               .id = PALMAS_PWM_ID,
-       },
-       {
-               .name = "palmas-usb",
-               .id = PALMAS_USB_ID,
-       }
-};
+#include <linux/of_device.h>
 
 static const struct regmap_config palmas_regmap_config[PALMAS_NUM_CLIENTS] = {
        {
@@ -302,6 +231,21 @@ static void palmas_dt_to_pdata(struct i2c_client *i2c,
                palmas_set_pdata_irq_flag(i2c, pdata);
 }
 
+static unsigned int palmas_features = PALMAS_PMIC_FEATURE_SMPS10_BOOST;
+static unsigned int tps659038_features;
+
+static const struct of_device_id of_palmas_match_tbl[] = {
+       {
+               .compatible = "ti,palmas",
+               .data = &palmas_features,
+       },
+       {
+               .compatible = "ti,tps659038",
+               .data = &tps659038_features,
+       },
+       { },
+};
+
 static int palmas_i2c_probe(struct i2c_client *i2c,
                            const struct i2c_device_id *id)
 {
@@ -309,9 +253,9 @@ static int palmas_i2c_probe(struct i2c_client *i2c,
        struct palmas_platform_data *pdata;
        struct device_node *node = i2c->dev.of_node;
        int ret = 0, i;
-       unsigned int reg, addr;
+       unsigned int reg, addr, *features;
        int slave;
-       struct mfd_cell *children;
+       const struct of_device_id *match;
 
        pdata = dev_get_platdata(&i2c->dev);
 
@@ -333,9 +277,16 @@ static int palmas_i2c_probe(struct i2c_client *i2c,
 
        i2c_set_clientdata(i2c, palmas);
        palmas->dev = &i2c->dev;
-       palmas->id = id->driver_data;
        palmas->irq = i2c->irq;
 
+       match = of_match_device(of_match_ptr(of_palmas_match_tbl), &i2c->dev);
+
+       if (!match)
+               return -ENODATA;
+
+       features = (unsigned int *)match->data;
+       palmas->features = *features;
+
        for (i = 0; i < PALMAS_NUM_CLIENTS; i++) {
                if (i == 0)
                        palmas->i2c_clients[i] = i2c;
@@ -362,6 +313,11 @@ static int palmas_i2c_probe(struct i2c_client *i2c,
                }
        }
 
+       if (!palmas->irq) {
+               dev_warn(palmas->dev, "IRQ missing: skipping irq request\n");
+               goto no_irq;
+       }
+
        /* Change interrupt line output polarity */
        if (pdata->irq_flags & IRQ_TYPE_LEVEL_HIGH)
                reg = PALMAS_POLARITY_CTRL_INT_POLARITY;
@@ -388,6 +344,7 @@ static int palmas_i2c_probe(struct i2c_client *i2c,
        if (ret < 0)
                goto err;
 
+no_irq:
        slave = PALMAS_BASE_TO_SLAVE(PALMAS_PU_PD_OD_BASE);
        addr = PALMAS_BASE_TO_REG(PALMAS_PU_PD_OD_BASE,
                        PALMAS_PRIMARY_SECONDARY_PAD1);
@@ -472,42 +429,8 @@ static int palmas_i2c_probe(struct i2c_client *i2c,
                        return ret;
        }
 
-       children = kmemdup(palmas_children, sizeof(palmas_children),
-                          GFP_KERNEL);
-       if (!children) {
-               ret = -ENOMEM;
-               goto err_irq;
-       }
-
-       children[PALMAS_PMIC_ID].platform_data = pdata->pmic_pdata;
-       children[PALMAS_PMIC_ID].pdata_size = sizeof(*pdata->pmic_pdata);
-
-       children[PALMAS_GPADC_ID].platform_data = pdata->gpadc_pdata;
-       children[PALMAS_GPADC_ID].pdata_size = sizeof(*pdata->gpadc_pdata);
-
-       children[PALMAS_RESOURCE_ID].platform_data = pdata->resource_pdata;
-       children[PALMAS_RESOURCE_ID].pdata_size =
-                       sizeof(*pdata->resource_pdata);
-
-       children[PALMAS_USB_ID].platform_data = pdata->usb_pdata;
-       children[PALMAS_USB_ID].pdata_size = sizeof(*pdata->usb_pdata);
-
-       children[PALMAS_CLK_ID].platform_data = pdata->clk_pdata;
-       children[PALMAS_CLK_ID].pdata_size = sizeof(*pdata->clk_pdata);
-
-       ret = mfd_add_devices(palmas->dev, -1,
-                             children, ARRAY_SIZE(palmas_children),
-                             NULL, 0,
-                             regmap_irq_get_domain(palmas->irq_data));
-       kfree(children);
-
-       if (ret < 0)
-               goto err_devices;
-
        return ret;
 
-err_devices:
-       mfd_remove_devices(palmas->dev);
 err_irq:
        regmap_del_irq_chip(palmas->irq, palmas->irq_data);
 err:
@@ -533,11 +456,6 @@ static const struct i2c_device_id palmas_i2c_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, palmas_i2c_id);
 
-static struct of_device_id of_palmas_match_tbl[] = {
-       { .compatible = "ti,palmas", },
-       { /* end */ }
-};
-
 static struct i2c_driver palmas_i2c_driver = {
        .driver = {
                   .name = "palmas",
index 2a2d316..c436bf2 100644 (file)
@@ -35,12 +35,33 @@ static u8 rtl8411_get_ic_version(struct rtsx_pcr *pcr)
        return val & 0x0F;
 }
 
+static int rtl8411b_is_qfn48(struct rtsx_pcr *pcr)
+{
+       u8 val = 0;
+
+       rtsx_pci_read_register(pcr, RTL8411B_PACKAGE_MODE, &val);
+
+       if (val & 0x2)
+               return 1;
+       else
+               return 0;
+}
+
 static int rtl8411_extra_init_hw(struct rtsx_pcr *pcr)
 {
        return rtsx_pci_write_register(pcr, CD_PAD_CTL,
                        CD_DISABLE_MASK | CD_AUTO_DISABLE, CD_ENABLE);
 }
 
+static int rtl8411b_extra_init_hw(struct rtsx_pcr *pcr)
+{
+       if (rtl8411b_is_qfn48(pcr))
+               rtsx_pci_write_register(pcr, CARD_PULL_CTL3, 0xFF, 0xF5);
+
+       return rtsx_pci_write_register(pcr, CD_PAD_CTL,
+                       CD_DISABLE_MASK | CD_AUTO_DISABLE, CD_ENABLE);
+}
+
 static int rtl8411_turn_on_led(struct rtsx_pcr *pcr)
 {
        return rtsx_pci_write_register(pcr, CARD_GPIO, 0x01, 0x00);
@@ -214,6 +235,20 @@ static const struct pcr_ops rtl8411_pcr_ops = {
        .conv_clk_and_div_n = rtl8411_conv_clk_and_div_n,
 };
 
+static const struct pcr_ops rtl8411b_pcr_ops = {
+       .extra_init_hw = rtl8411b_extra_init_hw,
+       .optimize_phy = NULL,
+       .turn_on_led = rtl8411_turn_on_led,
+       .turn_off_led = rtl8411_turn_off_led,
+       .enable_auto_blink = rtl8411_enable_auto_blink,
+       .disable_auto_blink = rtl8411_disable_auto_blink,
+       .card_power_on = rtl8411_card_power_on,
+       .card_power_off = rtl8411_card_power_off,
+       .switch_output_voltage = rtl8411_switch_output_voltage,
+       .cd_deglitch = rtl8411_cd_deglitch,
+       .conv_clk_and_div_n = rtl8411_conv_clk_and_div_n,
+};
+
 /* SD Pull Control Enable:
  *     SD_DAT[3:0] ==> pull up
  *     SD_CD       ==> pull up
@@ -276,6 +311,74 @@ static const u32 rtl8411_ms_pull_ctl_disable_tbl[] = {
        0,
 };
 
+static const u32 rtl8411b_qfn64_sd_pull_ctl_enable_tbl[] = {
+       RTSX_REG_PAIR(CARD_PULL_CTL1, 0xAA),
+       RTSX_REG_PAIR(CARD_PULL_CTL2, 0xAA),
+       RTSX_REG_PAIR(CARD_PULL_CTL3, 0x09 | 0xD0),
+       RTSX_REG_PAIR(CARD_PULL_CTL4, 0x09 | 0x50),
+       RTSX_REG_PAIR(CARD_PULL_CTL5, 0x05 | 0x50),
+       RTSX_REG_PAIR(CARD_PULL_CTL6, 0x04 | 0x11),
+       0,
+};
+
+static const u32 rtl8411b_qfn48_sd_pull_ctl_enable_tbl[] = {
+       RTSX_REG_PAIR(CARD_PULL_CTL2, 0xAA),
+       RTSX_REG_PAIR(CARD_PULL_CTL3, 0x69 | 0x90),
+       RTSX_REG_PAIR(CARD_PULL_CTL6, 0x08 | 0x11),
+       0,
+};
+
+static const u32 rtl8411b_qfn64_sd_pull_ctl_disable_tbl[] = {
+       RTSX_REG_PAIR(CARD_PULL_CTL1, 0x65),
+       RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55),
+       RTSX_REG_PAIR(CARD_PULL_CTL3, 0x05 | 0xD0),
+       RTSX_REG_PAIR(CARD_PULL_CTL4, 0x09 | 0x50),
+       RTSX_REG_PAIR(CARD_PULL_CTL5, 0x05 | 0x50),
+       RTSX_REG_PAIR(CARD_PULL_CTL6, 0x04 | 0x11),
+       0,
+};
+
+static const u32 rtl8411b_qfn48_sd_pull_ctl_disable_tbl[] = {
+       RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55),
+       RTSX_REG_PAIR(CARD_PULL_CTL3, 0x65 | 0x90),
+       RTSX_REG_PAIR(CARD_PULL_CTL6, 0x04 | 0x11),
+       0,
+};
+
+static const u32 rtl8411b_qfn64_ms_pull_ctl_enable_tbl[] = {
+       RTSX_REG_PAIR(CARD_PULL_CTL1, 0x65),
+       RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55),
+       RTSX_REG_PAIR(CARD_PULL_CTL3, 0x05 | 0xD0),
+       RTSX_REG_PAIR(CARD_PULL_CTL4, 0x05 | 0x50),
+       RTSX_REG_PAIR(CARD_PULL_CTL5, 0x05 | 0x50),
+       RTSX_REG_PAIR(CARD_PULL_CTL6, 0x04 | 0x11),
+       0,
+};
+
+static const u32 rtl8411b_qfn48_ms_pull_ctl_enable_tbl[] = {
+       RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55),
+       RTSX_REG_PAIR(CARD_PULL_CTL3, 0x65 | 0x90),
+       RTSX_REG_PAIR(CARD_PULL_CTL6, 0x04 | 0x11),
+       0,
+};
+
+static const u32 rtl8411b_qfn64_ms_pull_ctl_disable_tbl[] = {
+       RTSX_REG_PAIR(CARD_PULL_CTL1, 0x65),
+       RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55),
+       RTSX_REG_PAIR(CARD_PULL_CTL3, 0x05 | 0xD0),
+       RTSX_REG_PAIR(CARD_PULL_CTL4, 0x09 | 0x50),
+       RTSX_REG_PAIR(CARD_PULL_CTL5, 0x05 | 0x50),
+       RTSX_REG_PAIR(CARD_PULL_CTL6, 0x04 | 0x11),
+       0,
+};
+
+static const u32 rtl8411b_qfn48_ms_pull_ctl_disable_tbl[] = {
+       RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55),
+       RTSX_REG_PAIR(CARD_PULL_CTL3, 0x65 | 0x90),
+       RTSX_REG_PAIR(CARD_PULL_CTL6, 0x04 | 0x11),
+       0,
+};
+
 void rtl8411_init_params(struct rtsx_pcr *pcr)
 {
        pcr->extra_caps = EXTRA_CAPS_SD_SDR50 | EXTRA_CAPS_SD_SDR104;
@@ -288,3 +391,32 @@ void rtl8411_init_params(struct rtsx_pcr *pcr)
        pcr->ms_pull_ctl_enable_tbl = rtl8411_ms_pull_ctl_enable_tbl;
        pcr->ms_pull_ctl_disable_tbl = rtl8411_ms_pull_ctl_disable_tbl;
 }
+
+void rtl8411b_init_params(struct rtsx_pcr *pcr)
+{
+       pcr->extra_caps = EXTRA_CAPS_SD_SDR50 | EXTRA_CAPS_SD_SDR104;
+       pcr->num_slots = 2;
+       pcr->ops = &rtl8411b_pcr_ops;
+
+       pcr->ic_version = rtl8411_get_ic_version(pcr);
+
+       if (rtl8411b_is_qfn48(pcr)) {
+               pcr->sd_pull_ctl_enable_tbl =
+                       rtl8411b_qfn48_sd_pull_ctl_enable_tbl;
+               pcr->sd_pull_ctl_disable_tbl =
+                       rtl8411b_qfn48_sd_pull_ctl_disable_tbl;
+               pcr->ms_pull_ctl_enable_tbl =
+                       rtl8411b_qfn48_ms_pull_ctl_enable_tbl;
+               pcr->ms_pull_ctl_disable_tbl =
+                       rtl8411b_qfn48_ms_pull_ctl_disable_tbl;
+       } else {
+               pcr->sd_pull_ctl_enable_tbl =
+                       rtl8411b_qfn64_sd_pull_ctl_enable_tbl;
+               pcr->sd_pull_ctl_disable_tbl =
+                       rtl8411b_qfn64_sd_pull_ctl_disable_tbl;
+               pcr->ms_pull_ctl_enable_tbl =
+                       rtl8411b_qfn64_ms_pull_ctl_enable_tbl;
+               pcr->ms_pull_ctl_disable_tbl =
+                       rtl8411b_qfn64_ms_pull_ctl_disable_tbl;
+       }
+}
index e968c01..dd186c4 100644 (file)
@@ -57,6 +57,7 @@ static DEFINE_PCI_DEVICE_TABLE(rtsx_pci_ids) = {
        { PCI_DEVICE(0x10EC, 0x5289), PCI_CLASS_OTHERS << 16, 0xFF0000 },
        { PCI_DEVICE(0x10EC, 0x5227), PCI_CLASS_OTHERS << 16, 0xFF0000 },
        { PCI_DEVICE(0x10EC, 0x5249), PCI_CLASS_OTHERS << 16, 0xFF0000 },
+       { PCI_DEVICE(0x10EC, 0x5287), PCI_CLASS_OTHERS << 16, 0xFF0000 },
        { 0, }
 };
 
@@ -1038,6 +1039,10 @@ static int rtsx_pci_init_chip(struct rtsx_pcr *pcr)
        case 0x5249:
                rts5249_init_params(pcr);
                break;
+
+       case 0x5287:
+               rtl8411b_init_params(pcr);
+               break;
        }
 
        dev_dbg(&(pcr->pci->dev), "PID: 0x%04x, IC version: 0x%02x\n",
index 55fcfc2..c0cac7e 100644 (file)
@@ -33,5 +33,6 @@ void rts5229_init_params(struct rtsx_pcr *pcr);
 void rtl8411_init_params(struct rtsx_pcr *pcr);
 void rts5227_init_params(struct rtsx_pcr *pcr);
 void rts5249_init_params(struct rtsx_pcr *pcr);
+void rtl8411b_init_params(struct rtsx_pcr *pcr);
 
 #endif
index 77ee26e..7976768 100644 (file)
@@ -25,6 +25,9 @@
 #include <linux/mfd/samsung/core.h>
 #include <linux/mfd/samsung/irq.h>
 #include <linux/mfd/samsung/rtc.h>
+#include <linux/mfd/samsung/s2mps11.h>
+#include <linux/mfd/samsung/s5m8763.h>
+#include <linux/mfd/samsung/s5m8767.h>
 #include <linux/regmap.h>
 
 static struct mfd_cell s5m8751_devs[] = {
@@ -105,6 +108,26 @@ static struct regmap_config sec_regmap_config = {
        .val_bits = 8,
 };
 
+static struct regmap_config s2mps11_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+
+       .max_register = S2MPS11_REG_L38CTRL,
+};
+
+static struct regmap_config s5m8763_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+
+       .max_register = S5M8763_REG_LBCNFG2,
+};
+
+static struct regmap_config s5m8767_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+
+       .max_register = S5M8767_REG_LDO28CTRL,
+};
 
 #ifdef CONFIG_OF
 /*
@@ -160,6 +183,7 @@ static int sec_pmic_probe(struct i2c_client *i2c,
                            const struct i2c_device_id *id)
 {
        struct sec_platform_data *pdata = i2c->dev.platform_data;
+       const struct regmap_config *regmap;
        struct sec_pmic_dev *sec_pmic;
        int ret;
 
@@ -190,7 +214,22 @@ static int sec_pmic_probe(struct i2c_client *i2c,
                sec_pmic->pdata = pdata;
        }
 
-       sec_pmic->regmap = devm_regmap_init_i2c(i2c, &sec_regmap_config);
+       switch (sec_pmic->device_type) {
+       case S2MPS11X:
+               regmap = &s2mps11_regmap_config;
+               break;
+       case S5M8763X:
+               regmap = &s5m8763_regmap_config;
+               break;
+       case S5M8767X:
+               regmap = &s5m8767_regmap_config;
+               break;
+       default:
+               regmap = &sec_regmap_config;
+               break;
+       }
+
+       sec_pmic->regmap = devm_regmap_init_i2c(i2c, regmap);
        if (IS_ERR(sec_pmic->regmap)) {
                ret = PTR_ERR(sec_pmic->regmap);
                dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
@@ -230,13 +269,12 @@ static int sec_pmic_probe(struct i2c_client *i2c,
                BUG();
        }
 
-       if (ret < 0)
+       if (ret)
                goto err;
 
        return ret;
 
 err:
-       mfd_remove_devices(sec_pmic->dev);
        sec_irq_exit(sec_pmic);
        i2c_unregister_device(sec_pmic->rtc);
        return ret;
similarity index 100%
rename from drivers/ssbi/ssbi.c
rename to drivers/mfd/ssbi.c
index b32940e..a21bff2 100644 (file)
@@ -422,7 +422,6 @@ static int t7l66xb_remove(struct platform_device *dev)
        iounmap(t7l66xb->scr);
        release_resource(&t7l66xb->rscr);
        mfd_remove_devices(&dev->dev);
-       platform_set_drvdata(dev, NULL);
        kfree(t7l66xb);
 
        return ret;
index 366f7b9..65c425a 100644 (file)
@@ -217,7 +217,6 @@ static int tc6387xb_remove(struct platform_device *dev)
        release_resource(&tc6387xb->rscr);
        clk_disable(tc6387xb->clk32k);
        clk_put(tc6387xb->clk32k);
-       platform_set_drvdata(dev, NULL);
        kfree(tc6387xb);
 
        return 0;
index 15e1463..a563dfa 100644 (file)
@@ -756,7 +756,6 @@ static int tc6393xb_remove(struct platform_device *dev)
        clk_disable(tc6393xb->clk);
        iounmap(tc6393xb->scr);
        release_resource(&tc6393xb->rscr);
-       platform_set_drvdata(dev, NULL);
        clk_put(tc6393xb->clk);
        kfree(tc6393xb);
 
index e9f3fb5..b003a16 100644 (file)
 #include <linux/regmap.h>
 #include <linux/mfd/core.h>
 #include <linux/pm_runtime.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 #include <linux/mfd/ti_am335x_tscadc.h>
-#include <linux/input/ti_am335x_tsc.h>
-#include <linux/platform_data/ti_am335x_adc.h>
 
 static unsigned int tscadc_readl(struct ti_tscadc_dev *tsadc, unsigned int reg)
 {
@@ -48,6 +48,32 @@ static const struct regmap_config tscadc_regmap_config = {
        .val_bits = 32,
 };
 
+void am335x_tsc_se_update(struct ti_tscadc_dev *tsadc)
+{
+       tscadc_writel(tsadc, REG_SE, tsadc->reg_se_cache);
+}
+EXPORT_SYMBOL_GPL(am335x_tsc_se_update);
+
+void am335x_tsc_se_set(struct ti_tscadc_dev *tsadc, u32 val)
+{
+       spin_lock(&tsadc->reg_lock);
+       tsadc->reg_se_cache |= val;
+       spin_unlock(&tsadc->reg_lock);
+
+       am335x_tsc_se_update(tsadc);
+}
+EXPORT_SYMBOL_GPL(am335x_tsc_se_set);
+
+void am335x_tsc_se_clr(struct ti_tscadc_dev *tsadc, u32 val)
+{
+       spin_lock(&tsadc->reg_lock);
+       tsadc->reg_se_cache &= ~val;
+       spin_unlock(&tsadc->reg_lock);
+
+       am335x_tsc_se_update(tsadc);
+}
+EXPORT_SYMBOL_GPL(am335x_tsc_se_clr);
+
 static void tscadc_idle_config(struct ti_tscadc_dev *config)
 {
        unsigned int idleconfig;
@@ -63,27 +89,48 @@ static      int ti_tscadc_probe(struct platform_device *pdev)
        struct ti_tscadc_dev    *tscadc;
        struct resource         *res;
        struct clk              *clk;
-       struct mfd_tscadc_board *pdata = pdev->dev.platform_data;
+       struct device_node      *node = pdev->dev.of_node;
        struct mfd_cell         *cell;
+       struct property         *prop;
+       const __be32            *cur;
+       u32                     val;
        int                     err, ctrl;
        int                     clk_value, clock_rate;
-       int                     tsc_wires, adc_channels = 0, total_channels;
+       int                     tsc_wires = 0, adc_channels = 0, total_channels;
+       int                     readouts = 0;
 
-       if (!pdata) {
-               dev_err(&pdev->dev, "Could not find platform data\n");
+       if (!pdev->dev.of_node) {
+               dev_err(&pdev->dev, "Could not find valid DT data.\n");
                return -EINVAL;
        }
 
-       if (pdata->adc_init)
-               adc_channels = pdata->adc_init->adc_channels;
-
-       tsc_wires = pdata->tsc_init->wires;
+       node = of_get_child_by_name(pdev->dev.of_node, "tsc");
+       of_property_read_u32(node, "ti,wires", &tsc_wires);
+       of_property_read_u32(node, "ti,coordiante-readouts", &readouts);
+
+       node = of_get_child_by_name(pdev->dev.of_node, "adc");
+       of_property_for_each_u32(node, "ti,adc-channels", prop, cur, val) {
+               adc_channels++;
+               if (val > 7) {
+                       dev_err(&pdev->dev, " PIN numbers are 0..7 (not %d)\n",
+                                       val);
+                       return -EINVAL;
+               }
+       }
        total_channels = tsc_wires + adc_channels;
-
        if (total_channels > 8) {
                dev_err(&pdev->dev, "Number of i/p channels more than 8\n");
                return -EINVAL;
        }
+       if (total_channels == 0) {
+               dev_err(&pdev->dev, "Need atleast one channel.\n");
+               return -EINVAL;
+       }
+
+       if (readouts * 2 + 2 + adc_channels > 16) {
+               dev_err(&pdev->dev, "Too many step configurations requested\n");
+               return -EINVAL;
+       }
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!res) {
@@ -129,6 +176,7 @@ static      int ti_tscadc_probe(struct platform_device *pdev)
                goto ret;
        }
 
+       spin_lock_init(&tscadc->reg_lock);
        pm_runtime_enable(&pdev->dev);
        pm_runtime_get_sync(&pdev->dev);
 
@@ -173,26 +221,37 @@ static    int ti_tscadc_probe(struct platform_device *pdev)
        ctrl |= CNTRLREG_TSCSSENB;
        tscadc_writel(tscadc, REG_CTRL, ctrl);
 
+       tscadc->used_cells = 0;
+       tscadc->tsc_cell = -1;
+       tscadc->adc_cell = -1;
+
        /* TSC Cell */
-       cell = &tscadc->cells[TSC_CELL];
-       cell->name = "tsc";
-       cell->platform_data = tscadc;
-       cell->pdata_size = sizeof(*tscadc);
+       if (tsc_wires > 0) {
+               tscadc->tsc_cell = tscadc->used_cells;
+               cell = &tscadc->cells[tscadc->used_cells++];
+               cell->name = "TI-am335x-tsc";
+               cell->of_compatible = "ti,am3359-tsc";
+               cell->platform_data = &tscadc;
+               cell->pdata_size = sizeof(tscadc);
+       }
 
        /* ADC Cell */
-       cell = &tscadc->cells[ADC_CELL];
-       cell->name = "tiadc";
-       cell->platform_data = tscadc;
-       cell->pdata_size = sizeof(*tscadc);
+       if (adc_channels > 0) {
+               tscadc->adc_cell = tscadc->used_cells;
+               cell = &tscadc->cells[tscadc->used_cells++];
+               cell->name = "TI-am335x-adc";
+               cell->of_compatible = "ti,am3359-adc";
+               cell->platform_data = &tscadc;
+               cell->pdata_size = sizeof(tscadc);
+       }
 
        err = mfd_add_devices(&pdev->dev, pdev->id, tscadc->cells,
-                       TSCADC_CELLS, NULL, 0, NULL);
+                       tscadc->used_cells, NULL, 0, NULL);
        if (err < 0)
                goto err_disable_clk;
 
        device_init_wakeup(&pdev->dev, true);
        platform_set_drvdata(pdev, tscadc);
-
        return 0;
 
 err_disable_clk:
@@ -239,7 +298,7 @@ static int tscadc_resume(struct device *dev)
                        CNTRLREG_STEPID | CNTRLREG_4WIRE;
        tscadc_writel(tscadc_dev, REG_CTRL, ctrl);
        tscadc_idle_config(tscadc_dev);
-       tscadc_writel(tscadc_dev, REG_SE, STPENB_STEPENB);
+       am335x_tsc_se_update(tscadc_dev);
        restore = tscadc_readl(tscadc_dev, REG_CTRL);
        tscadc_writel(tscadc_dev, REG_CTRL,
                        (restore | CNTRLREG_TSCSSENB));
@@ -256,11 +315,18 @@ static const struct dev_pm_ops tscadc_pm_ops = {
 #define TSCADC_PM_OPS NULL
 #endif
 
+static const struct of_device_id ti_tscadc_dt_ids[] = {
+       { .compatible = "ti,am3359-tscadc", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, ti_tscadc_dt_ids);
+
 static struct platform_driver ti_tscadc_driver = {
        .driver = {
-               .name   = "ti_tscadc",
+               .name   = "ti_am3359-tscadc",
                .owner  = THIS_MODULE,
                .pm     = TSCADC_PM_OPS,
+               .of_match_table = of_match_ptr(ti_tscadc_dt_ids),
        },
        .probe  = ti_tscadc_probe,
        .remove = ti_tscadc_remove,
index aeb8e40..479886a 100644 (file)
@@ -162,7 +162,6 @@ int tps65912_device_init(struct tps65912 *tps65912)
 err:
        kfree(init_data);
        mfd_remove_devices(tps65912->dev);
-       kfree(tps65912);
        return ret;
 }
 
@@ -170,7 +169,6 @@ void tps65912_device_exit(struct tps65912 *tps65912)
 {
        mfd_remove_devices(tps65912->dev);
        tps65912_irq_exit(tps65912);
-       kfree(tps65912);
 }
 
 MODULE_AUTHOR("Margarita Olaya <magi@slimlogic.co.uk>");
index c041f2c..6a6343e 100644 (file)
@@ -77,7 +77,8 @@ static int tps65912_i2c_probe(struct i2c_client *i2c,
 {
        struct tps65912 *tps65912;
 
-       tps65912 = kzalloc(sizeof(struct tps65912), GFP_KERNEL);
+       tps65912 = devm_kzalloc(&i2c->dev,
+                               sizeof(struct tps65912), GFP_KERNEL);
        if (tps65912 == NULL)
                return -ENOMEM;
 
index b45f460..69a5178 100644 (file)
@@ -85,7 +85,8 @@ static int tps65912_spi_probe(struct spi_device *spi)
 {
        struct tps65912 *tps65912;
 
-       tps65912 = kzalloc(sizeof(struct tps65912), GFP_KERNEL);
+       tps65912 = devm_kzalloc(&spi->dev,
+                               sizeof(struct tps65912), GFP_KERNEL);
        if (tps65912 == NULL)
                return -ENOMEM;
 
index 89ab4d9..7f150d9 100644 (file)
 #define TWL6030_BASEADD_GASGAUGE       0x00C0
 #define TWL6030_BASEADD_PIH            0x00D0
 #define TWL6030_BASEADD_CHARGER                0x00E0
-#define TWL6025_BASEADD_CHARGER                0x00DA
+#define TWL6032_BASEADD_CHARGER                0x00DA
 #define TWL6030_BASEADD_LED            0x00F4
 
 /* subchip/slave 2 0x4A - DFT */
@@ -718,9 +718,9 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base,
                                        | REGULATOR_CHANGE_STATUS,
                        };
 
-                       if (features & TWL6025_SUBCLASS) {
+                       if (features & TWL6032_SUBCLASS) {
                                usb3v3.supply = "ldousb";
-                               regulator = TWL6025_REG_LDOUSB;
+                               regulator = TWL6032_REG_LDOUSB;
                        } else {
                                usb3v3.supply = "vusb";
                                regulator = TWL6030_REG_VUSB;
@@ -747,8 +747,8 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base,
                        usb3v3.dev_name = dev_name(child);
        } else if (IS_ENABLED(CONFIG_REGULATOR_TWL4030) &&
                   twl_class_is_6030()) {
-               if (features & TWL6025_SUBCLASS)
-                       child = add_regulator(TWL6025_REG_LDOUSB,
+               if (features & TWL6032_SUBCLASS)
+                       child = add_regulator(TWL6032_REG_LDOUSB,
                                                pdata->ldousb, features);
                else
                        child = add_regulator(TWL6030_REG_VUSB,
@@ -872,7 +872,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base,
 
        /* twl6030 regulators */
        if (IS_ENABLED(CONFIG_REGULATOR_TWL4030) && twl_class_is_6030() &&
-                       !(features & TWL6025_SUBCLASS)) {
+                       !(features & TWL6032_SUBCLASS)) {
                child = add_regulator(TWL6030_REG_VDD1, pdata->vdd1,
                                        features);
                if (IS_ERR(child))
@@ -952,60 +952,60 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base,
                        return PTR_ERR(child);
        }
 
-       /* twl6025 regulators */
+       /* twl6032 regulators */
        if (IS_ENABLED(CONFIG_REGULATOR_TWL4030) && twl_class_is_6030() &&
-                       (features & TWL6025_SUBCLASS)) {
-               child = add_regulator(TWL6025_REG_LDO5, pdata->ldo5,
+                       (features & TWL6032_SUBCLASS)) {
+               child = add_regulator(TWL6032_REG_LDO5, pdata->ldo5,
                                        features);
                if (IS_ERR(child))
                        return PTR_ERR(child);
 
-               child = add_regulator(TWL6025_REG_LDO1, pdata->ldo1,
+               child = add_regulator(TWL6032_REG_LDO1, pdata->ldo1,
                                        features);
                if (IS_ERR(child))
                        return PTR_ERR(child);
 
-               child = add_regulator(TWL6025_REG_LDO7, pdata->ldo7,
+               child = add_regulator(TWL6032_REG_LDO7, pdata->ldo7,
                                        features);
                if (IS_ERR(child))
                        return PTR_ERR(child);
 
-               child = add_regulator(TWL6025_REG_LDO6, pdata->ldo6,
+               child = add_regulator(TWL6032_REG_LDO6, pdata->ldo6,
                                        features);
                if (IS_ERR(child))
                        return PTR_ERR(child);
 
-               child = add_regulator(TWL6025_REG_LDOLN, pdata->ldoln,
+               child = add_regulator(TWL6032_REG_LDOLN, pdata->ldoln,
                                        features);
                if (IS_ERR(child))
                        return PTR_ERR(child);
 
-               child = add_regulator(TWL6025_REG_LDO2, pdata->ldo2,
+               child = add_regulator(TWL6032_REG_LDO2, pdata->ldo2,
                                        features);
                if (IS_ERR(child))
                        return PTR_ERR(child);
 
-               child = add_regulator(TWL6025_REG_LDO4, pdata->ldo4,
+               child = add_regulator(TWL6032_REG_LDO4, pdata->ldo4,
                                        features);
                if (IS_ERR(child))
                        return PTR_ERR(child);
 
-               child = add_regulator(TWL6025_REG_LDO3, pdata->ldo3,
+               child = add_regulator(TWL6032_REG_LDO3, pdata->ldo3,
                                        features);
                if (IS_ERR(child))
                        return PTR_ERR(child);
 
-               child = add_regulator(TWL6025_REG_SMPS3, pdata->smps3,
+               child = add_regulator(TWL6032_REG_SMPS3, pdata->smps3,
                                        features);
                if (IS_ERR(child))
                        return PTR_ERR(child);
 
-               child = add_regulator(TWL6025_REG_SMPS4, pdata->smps4,
+               child = add_regulator(TWL6032_REG_SMPS4, pdata->smps4,
                                        features);
                if (IS_ERR(child))
                        return PTR_ERR(child);
 
-               child = add_regulator(TWL6025_REG_VIO, pdata->vio6025,
+               child = add_regulator(TWL6032_REG_VIO, pdata->vio6025,
                                        features);
                if (IS_ERR(child))
                        return PTR_ERR(child);
@@ -1023,6 +1023,14 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base,
                        return PTR_ERR(child);
        }
 
+       if (IS_ENABLED(CONFIG_TWL4030_POWER) && pdata->power) {
+               child = add_child(TWL_MODULE_PM_MASTER, "twl4030_power",
+                                 pdata->power, sizeof(*pdata->power), false,
+                                 0, 0);
+               if (IS_ERR(child))
+                       return PTR_ERR(child);
+       }
+
        return 0;
 }
 
@@ -1176,10 +1184,10 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
        if ((id->driver_data) & TWL6030_CLASS) {
                twl_priv->twl_id = TWL6030_CLASS_ID;
                twl_priv->twl_map = &twl6030_map[0];
-               /* The charger base address is different in twl6025 */
-               if ((id->driver_data) & TWL6025_SUBCLASS)
+               /* The charger base address is different in twl6032 */
+               if ((id->driver_data) & TWL6032_SUBCLASS)
                        twl_priv->twl_map[TWL_MODULE_MAIN_CHARGE].base =
-                                                       TWL6025_BASEADD_CHARGER;
+                                                       TWL6032_BASEADD_CHARGER;
                twl_regmap_config = twl6030_regmap_config;
        } else {
                twl_priv->twl_id = TWL4030_CLASS_ID;
@@ -1234,10 +1242,6 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
                WARN(status < 0, "Error: reading twl_idcode register value\n");
        }
 
-       /* load power event scripts */
-       if (IS_ENABLED(CONFIG_TWL4030_POWER) && pdata && pdata->power)
-               twl4030_power_init(pdata->power);
-
        /* Maybe init the T2 Interrupt subsystem */
        if (client->irq) {
                if (twl_class_is_4030()) {
@@ -1292,7 +1296,7 @@ static const struct i2c_device_id twl_ids[] = {
        { "tps65921", TPS_SUBSET },     /* fewer LDOs; no codec, no LED
                                           and vibrator. Charger in USB module*/
        { "twl6030", TWL6030_CLASS },   /* "Phoenix power chip" */
-       { "twl6025", TWL6030_CLASS | TWL6025_SUBCLASS }, /* "Phoenix lite" */
+       { "twl6032", TWL6030_CLASS | TWL6032_SUBCLASS }, /* "Phoenix lite" */
        { /* end of list */ },
 };
 MODULE_DEVICE_TABLE(i2c, twl_ids);
@@ -1305,17 +1309,7 @@ static struct i2c_driver twl_driver = {
        .remove         = twl_remove,
 };
 
-static int __init twl_init(void)
-{
-       return i2c_add_driver(&twl_driver);
-}
-subsys_initcall(twl_init);
-
-static void __exit twl_exit(void)
-{
-       i2c_del_driver(&twl_driver);
-}
-module_exit(twl_exit);
+module_i2c_driver(twl_driver);
 
 MODULE_AUTHOR("Texas Instruments, Inc.");
 MODULE_DESCRIPTION("I2C Core interface for TWL");
index d2ab222..a31fba9 100644 (file)
@@ -261,10 +261,8 @@ static int twl4030_audio_probe(struct platform_device *pdev)
                ret = -ENODEV;
        }
 
-       if (ret) {
-               platform_set_drvdata(pdev, NULL);
+       if (ret)
                twl4030_audio_dev = NULL;
-       }
 
        return ret;
 }
@@ -272,7 +270,6 @@ static int twl4030_audio_probe(struct platform_device *pdev)
 static int twl4030_audio_remove(struct platform_device *pdev)
 {
        mfd_remove_devices(&pdev->dev);
-       platform_set_drvdata(pdev, NULL);
        twl4030_audio_dev = NULL;
 
        return 0;
index 9d2d1ba..9aa6d1e 100644 (file)
@@ -570,6 +570,7 @@ static struct irq_chip twl4030_sih_irq_chip = {
        .irq_set_type   = twl4030_sih_set_type,
        .irq_bus_lock   = twl4030_sih_bus_lock,
        .irq_bus_sync_unlock = twl4030_sih_bus_sync_unlock,
+       .flags          = IRQCHIP_SKIP_SET_WAKE,
 };
 
 /*----------------------------------------------------------------------*/
index 42bd3ea..1ea54d4 100644 (file)
@@ -775,12 +775,10 @@ static int twl4030_madc_probe(struct platform_device *pdev)
                                   IRQF_TRIGGER_RISING, "twl4030_madc", madc);
        if (ret) {
                dev_dbg(&pdev->dev, "could not request irq\n");
-               goto err_irq;
+               goto err_i2c;
        }
        twl4030_madc = madc;
        return 0;
-err_irq:
-       platform_set_drvdata(pdev, NULL);
 err_i2c:
        twl4030_madc_set_current_generator(madc, 0, 0);
 err_current_generator:
@@ -796,7 +794,6 @@ static int twl4030_madc_remove(struct platform_device *pdev)
        struct twl4030_madc_data *madc = platform_get_drvdata(pdev);
 
        free_irq(platform_get_irq(pdev, 0), madc);
-       platform_set_drvdata(pdev, NULL);
        twl4030_madc_set_current_generator(madc, 0, 0);
        twl4030_madc_set_power(madc, 0);
        kfree(madc);
index dd362c1..a5fd3c7 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/pm.h>
 #include <linux/i2c/twl.h>
 #include <linux/platform_device.h>
+#include <linux/of.h>
 
 #include <asm/mach-types.h>
 
@@ -492,6 +493,39 @@ int twl4030_remove_script(u8 flags)
        return err;
 }
 
+int twl4030_power_configure_scripts(struct twl4030_power_data *pdata)
+{
+       int err;
+       int i;
+       u8 address = twl4030_start_script_address;
+
+       for (i = 0; i < pdata->num; i++) {
+               err = load_twl4030_script(pdata->scripts[i], address);
+               if (err)
+                       return err;
+               address += pdata->scripts[i]->size;
+       }
+
+       return 0;
+}
+
+int twl4030_power_configure_resources(struct twl4030_power_data *pdata)
+{
+       struct twl4030_resconfig *resconfig = pdata->resource_config;
+       int err;
+
+       if (resconfig) {
+               while (resconfig->resource) {
+                       err = twl4030_configure_resource(resconfig);
+                       if (err)
+                               return err;
+                       resconfig++;
+               }
+       }
+
+       return 0;
+}
+
 /*
  * In master mode, start the power off sequence.
  * After a successful execution, TWL shuts down the power to the SoC
@@ -507,43 +541,58 @@ void twl4030_power_off(void)
                pr_err("TWL4030 Unable to power off\n");
 }
 
-void twl4030_power_init(struct twl4030_power_data *twl4030_scripts)
+static bool twl4030_power_use_poweroff(struct twl4030_power_data *pdata,
+                                       struct device_node *node)
 {
+       if (pdata && pdata->use_poweroff)
+               return true;
+
+       if (of_property_read_bool(node, "ti,use_poweroff"))
+               return true;
+
+       return false;
+}
+
+int twl4030_power_probe(struct platform_device *pdev)
+{
+       struct twl4030_power_data *pdata = pdev->dev.platform_data;
+       struct device_node *node = pdev->dev.of_node;
        int err = 0;
-       int i;
-       struct twl4030_resconfig *resconfig;
-       u8 val, address = twl4030_start_script_address;
+       int err2 = 0;
+       u8 val;
+
+       if (!pdata && !node) {
+               dev_err(&pdev->dev, "Platform data is missing\n");
+               return -EINVAL;
+       }
 
        err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, TWL4030_PM_MASTER_KEY_CFG1,
                               TWL4030_PM_MASTER_PROTECT_KEY);
-       if (err)
-               goto unlock;
-
-       err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, TWL4030_PM_MASTER_KEY_CFG2,
+       err |= twl_i2c_write_u8(TWL_MODULE_PM_MASTER,
+                              TWL4030_PM_MASTER_KEY_CFG2,
                               TWL4030_PM_MASTER_PROTECT_KEY);
-       if (err)
-               goto unlock;
 
-       for (i = 0; i < twl4030_scripts->num; i++) {
-               err = load_twl4030_script(twl4030_scripts->scripts[i], address);
-               if (err)
-                       goto load;
-               address += twl4030_scripts->scripts[i]->size;
+       if (err) {
+               pr_err("TWL4030 Unable to unlock registers\n");
+               return err;
        }
 
-       resconfig = twl4030_scripts->resource_config;
-       if (resconfig) {
-               while (resconfig->resource) {
-                       err = twl4030_configure_resource(resconfig);
-                       if (err)
-                               goto resource;
-                       resconfig++;
-
+       if (pdata) {
+               /* TODO: convert to device tree */
+               err = twl4030_power_configure_scripts(pdata);
+               if (err) {
+                       pr_err("TWL4030 failed to load scripts\n");
+                       goto relock;
+               }
+               err = twl4030_power_configure_resources(pdata);
+               if (err) {
+                       pr_err("TWL4030 failed to configure resource\n");
+                       goto relock;
                }
        }
 
        /* Board has to be wired properly to use this feature */
-       if (twl4030_scripts->use_poweroff && !pm_power_off) {
+       if (twl4030_power_use_poweroff(pdata, node) && !pm_power_off) {
                /* Default for SEQ_OFFSYNC is set, lets ensure this */
                err = twl_i2c_read_u8(TWL_MODULE_PM_MASTER, &val,
                                      TWL4030_PM_MASTER_CFG_P123_TRANSITION);
@@ -564,22 +613,43 @@ void twl4030_power_init(struct twl4030_power_data *twl4030_scripts)
        }
 
 relock:
-       err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, 0,
+       err2 = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, 0,
                               TWL4030_PM_MASTER_PROTECT_KEY);
-       if (err)
+       if (err2) {
                pr_err("TWL4030 Unable to relock registers\n");
-       return;
+               return err2;
+       }
 
-unlock:
-       if (err)
-               pr_err("TWL4030 Unable to unlock registers\n");
-       return;
-load:
-       if (err)
-               pr_err("TWL4030 failed to load scripts\n");
-       return;
-resource:
-       if (err)
-               pr_err("TWL4030 failed to configure resource\n");
-       return;
+       return err;
 }
+
+static int twl4030_power_remove(struct platform_device *pdev)
+{
+       return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id twl4030_power_of_match[] = {
+       {.compatible = "ti,twl4030-power", },
+       { },
+};
+MODULE_DEVICE_TABLE(of, twl4030_power_of_match);
+#endif
+
+static struct platform_driver twl4030_power_driver = {
+       .driver = {
+               .name   = "twl4030_power",
+               .owner  = THIS_MODULE,
+               .of_match_table = of_match_ptr(twl4030_power_of_match),
+       },
+       .probe          = twl4030_power_probe,
+       .remove         = twl4030_power_remove,
+};
+
+module_platform_driver(twl4030_power_driver);
+
+MODULE_AUTHOR("Nokia Corporation");
+MODULE_AUTHOR("Texas Instruments, Inc.");
+MODULE_DESCRIPTION("Power management for TWL4030");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:twl4030_power");
index 96a020b..981bef4 100644 (file)
@@ -351,6 +351,8 @@ void __init vexpress_sysreg_of_early_init(void)
 }
 
 
+#ifdef CONFIG_GPIOLIB
+
 #define VEXPRESS_SYSREG_GPIO(_name, _reg, _value) \
        [VEXPRESS_GPIO_##_name] = { \
                .reg = _reg, \
@@ -445,6 +447,8 @@ struct gpio_led_platform_data vexpress_sysreg_leds_pdata = {
        .leds = vexpress_sysreg_leds,
 };
 
+#endif
+
 
 static ssize_t vexpress_sysreg_sys_id_show(struct device *dev,
                struct device_attribute *attr, char *buf)
@@ -480,6 +484,9 @@ static int vexpress_sysreg_probe(struct platform_device *pdev)
        setup_timer(&vexpress_sysreg_config_timer,
                        vexpress_sysreg_config_complete, 0);
 
+       vexpress_sysreg_dev = &pdev->dev;
+
+#ifdef CONFIG_GPIOLIB
        vexpress_sysreg_gpio_chip.dev = &pdev->dev;
        err = gpiochip_add(&vexpress_sysreg_gpio_chip);
        if (err) {
@@ -490,11 +497,10 @@ static int vexpress_sysreg_probe(struct platform_device *pdev)
                return err;
        }
 
-       vexpress_sysreg_dev = &pdev->dev;
-
        platform_device_register_data(vexpress_sysreg_dev, "leds-gpio",
                        PLATFORM_DEVID_AUTO, &vexpress_sysreg_leds_pdata,
                        sizeof(vexpress_sysreg_leds_pdata));
+#endif
 
        device_create_file(vexpress_sysreg_dev, &dev_attr_sys_id);
 
index 00e4fe2..781115e 100644 (file)
@@ -259,20 +259,6 @@ static int wm8994_suspend(struct device *dev)
                break;
        }
 
-       switch (wm8994->type) {
-       case WM1811:
-               ret = wm8994_reg_read(wm8994, WM8994_ANTIPOP_2);
-               if (ret < 0) {
-                       dev_err(dev, "Failed to read jackdet: %d\n", ret);
-               } else if (ret & WM1811_JACKDET_MODE_MASK) {
-                       dev_dbg(dev, "CODEC still active, ignoring suspend\n");
-                       return 0;
-               }
-               break;
-       default:
-               break;
-       }
-
        /* Disable LDO pulldowns while the device is suspended if we
         * don't know that something will be driving them. */
        if (!wm8994->ldo_ena_always_driven)
@@ -652,6 +638,17 @@ static int wm8994_device_init(struct wm8994 *wm8994, int irq)
                return ret;
        }
 
+       /* Explicitly put the device into reset in case regulators
+        * don't get disabled in order to ensure we know the device
+        * state.
+        */
+       ret = wm8994_reg_write(wm8994, WM8994_SOFTWARE_RESET,
+                              wm8994_reg_read(wm8994, WM8994_SOFTWARE_RESET));
+       if (ret != 0) {
+               dev_err(wm8994->dev, "Failed to reset device: %d\n", ret);
+               return ret;
+       }
+
        if (regmap_patch) {
                ret = regmap_register_patch(wm8994->regmap, regmap_patch,
                                            patch_regs);
index a050e56..d3a184a 100644 (file)
 
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/gpio.h>
 #include <linux/i2c.h>
 #include <linux/irq.h>
 #include <linux/mfd/core.h>
 #include <linux/interrupt.h>
+#include <linux/irqdomain.h>
 #include <linux/regmap.h>
 
 #include <linux/mfd/wm8994/core.h>
@@ -138,6 +140,55 @@ static struct regmap_irq_chip wm8994_irq_chip = {
        .runtime_pm = true,
 };
 
+static void wm8994_edge_irq_enable(struct irq_data *data)
+{
+}
+
+static void wm8994_edge_irq_disable(struct irq_data *data)
+{
+}
+
+static struct irq_chip wm8994_edge_irq_chip = {
+       .name                   = "wm8994_edge",
+       .irq_disable            = wm8994_edge_irq_disable,
+       .irq_enable             = wm8994_edge_irq_enable,
+};
+
+static irqreturn_t wm8994_edge_irq(int irq, void *data)
+{
+       struct wm8994 *wm8994 = data;
+
+       while (gpio_get_value_cansleep(wm8994->pdata.irq_gpio))
+               handle_nested_irq(irq_create_mapping(wm8994->edge_irq, 0));
+
+       return IRQ_HANDLED;
+}
+
+static int wm8994_edge_irq_map(struct irq_domain *h, unsigned int virq,
+                              irq_hw_number_t hw)
+{
+       struct wm8994 *wm8994 = h->host_data;
+
+       irq_set_chip_data(virq, wm8994);
+       irq_set_chip_and_handler(virq, &wm8994_edge_irq_chip, handle_edge_irq);
+       irq_set_nested_thread(virq, 1);
+
+       /* ARM needs us to explicitly flag the IRQ as valid
+        * and will set them noprobe when we do so. */
+#ifdef CONFIG_ARM
+       set_irq_flags(virq, IRQF_VALID);
+#else
+       irq_set_noprobe(virq);
+#endif
+
+       return 0;
+}
+
+static struct irq_domain_ops wm8994_edge_irq_ops = {
+       .map    = wm8994_edge_irq_map,
+       .xlate  = irq_domain_xlate_twocell,
+};
+
 int wm8994_irq_init(struct wm8994 *wm8994)
 {
        int ret;
@@ -156,10 +207,51 @@ int wm8994_irq_init(struct wm8994 *wm8994)
        if (pdata->irq_flags)
                irqflags = pdata->irq_flags;
 
-       ret = regmap_add_irq_chip(wm8994->regmap, wm8994->irq,
-                                 irqflags,
-                                 wm8994->irq_base, &wm8994_irq_chip,
-                                 &wm8994->irq_data);
+       /* use a GPIO for edge triggered controllers */
+       if (irqflags & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) {
+               if (gpio_to_irq(pdata->irq_gpio) != wm8994->irq) {
+                       dev_warn(wm8994->dev, "IRQ %d is not GPIO %d (%d)\n",
+                                wm8994->irq, pdata->irq_gpio,
+                                gpio_to_irq(pdata->irq_gpio));
+                       wm8994->irq = gpio_to_irq(pdata->irq_gpio);
+               }
+
+               ret = devm_gpio_request_one(wm8994->dev, pdata->irq_gpio,
+                                           GPIOF_IN, "WM8994 IRQ");
+
+               if (ret != 0) {
+                       dev_err(wm8994->dev, "Failed to get IRQ GPIO: %d\n",
+                               ret);
+                       return ret;
+               }
+
+               wm8994->edge_irq = irq_domain_add_linear(NULL, 1,
+                                                        &wm8994_edge_irq_ops,
+                                                        wm8994);
+
+               ret = regmap_add_irq_chip(wm8994->regmap,
+                                         irq_create_mapping(wm8994->edge_irq,
+                                                            0),
+                                         IRQF_ONESHOT,
+                                         wm8994->irq_base, &wm8994_irq_chip,
+                                         &wm8994->irq_data);
+               if (ret != 0) {
+                       dev_err(wm8994->dev, "Failed to get IRQ: %d\n",
+                               ret);
+                       return ret;
+               }
+
+               ret = request_threaded_irq(wm8994->irq,
+                                          NULL, wm8994_edge_irq,
+                                          irqflags,
+                                          "WM8994 edge", wm8994);
+       } else {
+               ret = regmap_add_irq_chip(wm8994->regmap, wm8994->irq,
+                                         irqflags,
+                                         wm8994->irq_base, &wm8994_irq_chip,
+                                         &wm8994->irq_data);
+       }
+
        if (ret != 0) {
                dev_err(wm8994->dev, "Failed to register IRQ chip: %d\n", ret);
                return ret;
diff --git a/drivers/mfd/wm8997-tables.c b/drivers/mfd/wm8997-tables.c
new file mode 100644 (file)
index 0000000..5aa8076
--- /dev/null
@@ -0,0 +1,1525 @@
+/*
+ * wm8997-tables.c  --  WM8997 data tables
+ *
+ * Copyright 2012 Wolfson Microelectronics plc
+ *
+ * Author: Charles Keepax <ckeepax@opensource.wolfsonmicro.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/mfd/arizona/core.h>
+#include <linux/mfd/arizona/registers.h>
+
+#include "arizona.h"
+
+static const struct reg_default wm8997_reva_patch[] = {
+       { 0x80, 0x0003 },
+       { 0x214, 0x0008 },
+       { 0x458, 0x0000 },
+       { 0x0081, 0xE022 },
+       { 0x294, 0x0000 },
+       { 0x80, 0x0000 },
+       { 0x171, 0x0000 },
+};
+
+/* We use a function so we can use ARRAY_SIZE() */
+int wm8997_patch(struct arizona *arizona)
+{
+       switch (arizona->rev) {
+       case 0:
+               return regmap_register_patch(arizona->regmap,
+                                            wm8997_reva_patch,
+                                            ARRAY_SIZE(wm8997_reva_patch));
+       default:
+               return 0;
+       }
+}
+EXPORT_SYMBOL_GPL(wm8997_patch);
+
+static const struct regmap_irq wm8997_aod_irqs[ARIZONA_NUM_IRQ] = {
+       [ARIZONA_IRQ_GP5_FALL] = { .mask = ARIZONA_GP5_FALL_EINT1 },
+       [ARIZONA_IRQ_GP5_RISE] = { .mask = ARIZONA_GP5_RISE_EINT1 },
+       [ARIZONA_IRQ_JD_FALL] = { .mask = ARIZONA_JD1_FALL_EINT1 },
+       [ARIZONA_IRQ_JD_RISE] = { .mask = ARIZONA_JD1_RISE_EINT1 },
+};
+
+const struct regmap_irq_chip wm8997_aod = {
+       .name = "wm8997 AOD",
+       .status_base = ARIZONA_AOD_IRQ1,
+       .mask_base = ARIZONA_AOD_IRQ_MASK_IRQ1,
+       .ack_base = ARIZONA_AOD_IRQ1,
+       .num_regs = 1,
+       .irqs = wm8997_aod_irqs,
+       .num_irqs = ARRAY_SIZE(wm8997_aod_irqs),
+};
+EXPORT_SYMBOL_GPL(wm8997_aod);
+
+static const struct regmap_irq wm8997_irqs[ARIZONA_NUM_IRQ] = {
+       [ARIZONA_IRQ_GP4] = { .reg_offset = 0, .mask = ARIZONA_GP4_EINT1 },
+       [ARIZONA_IRQ_GP3] = { .reg_offset = 0, .mask = ARIZONA_GP3_EINT1 },
+       [ARIZONA_IRQ_GP2] = { .reg_offset = 0, .mask = ARIZONA_GP2_EINT1 },
+       [ARIZONA_IRQ_GP1] = { .reg_offset = 0, .mask = ARIZONA_GP1_EINT1 },
+
+       [ARIZONA_IRQ_SPK_SHUTDOWN_WARN] = {
+               .reg_offset = 2, .mask = ARIZONA_SPK_SHUTDOWN_WARN_EINT1
+       },
+       [ARIZONA_IRQ_SPK_SHUTDOWN] = {
+               .reg_offset = 2, .mask = ARIZONA_SPK_SHUTDOWN_EINT1
+       },
+       [ARIZONA_IRQ_HPDET] = {
+               .reg_offset = 2, .mask = ARIZONA_HPDET_EINT1
+       },
+       [ARIZONA_IRQ_MICDET] = {
+               .reg_offset = 2, .mask = ARIZONA_MICDET_EINT1
+       },
+       [ARIZONA_IRQ_WSEQ_DONE] = {
+               .reg_offset = 2, .mask = ARIZONA_WSEQ_DONE_EINT1
+       },
+       [ARIZONA_IRQ_DRC1_SIG_DET] = {
+               .reg_offset = 2, .mask = ARIZONA_DRC1_SIG_DET_EINT1
+       },
+       [ARIZONA_IRQ_UNDERCLOCKED] = {
+               .reg_offset = 2, .mask = ARIZONA_UNDERCLOCKED_EINT1
+       },
+       [ARIZONA_IRQ_OVERCLOCKED] = {
+               .reg_offset = 2, .mask = ARIZONA_OVERCLOCKED_EINT1
+       },
+       [ARIZONA_IRQ_FLL2_LOCK] = {
+               .reg_offset = 2, .mask = ARIZONA_FLL2_LOCK_EINT1
+       },
+       [ARIZONA_IRQ_FLL1_LOCK] = {
+               .reg_offset = 2, .mask = ARIZONA_FLL1_LOCK_EINT1
+       },
+       [ARIZONA_IRQ_CLKGEN_ERR] = {
+               .reg_offset = 2, .mask = ARIZONA_CLKGEN_ERR_EINT1
+       },
+       [ARIZONA_IRQ_CLKGEN_ERR_ASYNC] = {
+               .reg_offset = 2, .mask = ARIZONA_CLKGEN_ERR_ASYNC_EINT1
+       },
+
+       [ARIZONA_IRQ_AIF2_ERR] = {
+               .reg_offset = 3, .mask = ARIZONA_AIF2_ERR_EINT1
+       },
+       [ARIZONA_IRQ_AIF1_ERR] = {
+               .reg_offset = 3, .mask = ARIZONA_AIF1_ERR_EINT1
+       },
+       [ARIZONA_IRQ_CTRLIF_ERR] = {
+               .reg_offset = 3, .mask = ARIZONA_CTRLIF_ERR_EINT1
+       },
+       [ARIZONA_IRQ_MIXER_DROPPED_SAMPLES] = {
+               .reg_offset = 3, .mask = ARIZONA_MIXER_DROPPED_SAMPLE_EINT1
+       },
+       [ARIZONA_IRQ_ASYNC_CLK_ENA_LOW] = {
+               .reg_offset = 3, .mask = ARIZONA_ASYNC_CLK_ENA_LOW_EINT1
+       },
+       [ARIZONA_IRQ_SYSCLK_ENA_LOW] = {
+               .reg_offset = 3, .mask = ARIZONA_SYSCLK_ENA_LOW_EINT1
+       },
+       [ARIZONA_IRQ_ISRC1_CFG_ERR] = {
+               .reg_offset = 3, .mask = ARIZONA_ISRC1_CFG_ERR_EINT1
+       },
+       [ARIZONA_IRQ_ISRC2_CFG_ERR] = {
+               .reg_offset = 3, .mask = ARIZONA_ISRC2_CFG_ERR_EINT1
+       },
+
+       [ARIZONA_IRQ_BOOT_DONE] = {
+               .reg_offset = 4, .mask = ARIZONA_BOOT_DONE_EINT1
+       },
+       [ARIZONA_IRQ_DCS_DAC_DONE] = {
+               .reg_offset = 4, .mask = ARIZONA_DCS_DAC_DONE_EINT1
+       },
+       [ARIZONA_IRQ_DCS_HP_DONE] = {
+               .reg_offset = 4, .mask = ARIZONA_DCS_HP_DONE_EINT1
+       },
+       [ARIZONA_IRQ_FLL2_CLOCK_OK] = {
+               .reg_offset = 4, .mask = ARIZONA_FLL2_CLOCK_OK_EINT1
+       },
+       [ARIZONA_IRQ_FLL1_CLOCK_OK] = {
+               .reg_offset = 4, .mask = ARIZONA_FLL1_CLOCK_OK_EINT1
+       },
+};
+
+const struct regmap_irq_chip wm8997_irq = {
+       .name = "wm8997 IRQ",
+       .status_base = ARIZONA_INTERRUPT_STATUS_1,
+       .mask_base = ARIZONA_INTERRUPT_STATUS_1_MASK,
+       .ack_base = ARIZONA_INTERRUPT_STATUS_1,
+       .num_regs = 5,
+       .irqs = wm8997_irqs,
+       .num_irqs = ARRAY_SIZE(wm8997_irqs),
+};
+EXPORT_SYMBOL_GPL(wm8997_irq);
+
+static const struct reg_default wm8997_reg_default[] = {
+       { 0x00000009, 0x0001 },    /* R9     - Ctrl IF I2C1 CFG 1 */
+       { 0x00000016, 0x0000 },    /* R22    - Write Sequencer Ctrl 0 */
+       { 0x00000017, 0x0000 },    /* R23    - Write Sequencer Ctrl 1 */
+       { 0x00000018, 0x0000 },    /* R24    - Write Sequencer Ctrl 2 */
+       { 0x00000020, 0x0000 },    /* R32    - Tone Generator 1 */
+       { 0x00000021, 0x1000 },    /* R33    - Tone Generator 2 */
+       { 0x00000022, 0x0000 },    /* R34    - Tone Generator 3 */
+       { 0x00000023, 0x1000 },    /* R35    - Tone Generator 4 */
+       { 0x00000024, 0x0000 },    /* R36    - Tone Generator 5 */
+       { 0x00000030, 0x0000 },    /* R48    - PWM Drive 1 */
+       { 0x00000031, 0x0100 },    /* R49    - PWM Drive 2 */
+       { 0x00000032, 0x0100 },    /* R50    - PWM Drive 3 */
+       { 0x00000040, 0x0000 },    /* R64    - Wake control */
+       { 0x00000041, 0x0000 },    /* R65    - Sequence control */
+       { 0x00000061, 0x01FF },    /* R97    - Sample Rate Sequence Select 1 */
+       { 0x00000062, 0x01FF },    /* R98    - Sample Rate Sequence Select 2 */
+       { 0x00000063, 0x01FF },    /* R99    - Sample Rate Sequence Select 3 */
+       { 0x00000064, 0x01FF },    /* R100   - Sample Rate Sequence Select 4 */
+       { 0x00000068, 0x01FF },    /* R104   - Always On Triggers Sequence Select 1 */
+       { 0x00000069, 0x01FF },    /* R105   - Always On Triggers Sequence Select 2 */
+       { 0x0000006A, 0x01FF },    /* R106   - Always On Triggers Sequence Select 3 */
+       { 0x0000006B, 0x01FF },    /* R107   - Always On Triggers Sequence Select 4 */
+       { 0x00000070, 0x0000 },    /* R112   - Comfort Noise Generator */
+       { 0x00000090, 0x0000 },    /* R144   - Haptics Control 1 */
+       { 0x00000091, 0x7FFF },    /* R145   - Haptics Control 2 */
+       { 0x00000092, 0x0000 },    /* R146   - Haptics phase 1 intensity */
+       { 0x00000093, 0x0000 },    /* R147   - Haptics phase 1 duration */
+       { 0x00000094, 0x0000 },    /* R148   - Haptics phase 2 intensity */
+       { 0x00000095, 0x0000 },    /* R149   - Haptics phase 2 duration */
+       { 0x00000096, 0x0000 },    /* R150   - Haptics phase 3 intensity */
+       { 0x00000097, 0x0000 },    /* R151   - Haptics phase 3 duration */
+       { 0x00000100, 0x0002 },    /* R256   - Clock 32k 1 */
+       { 0x00000101, 0x0304 },    /* R257   - System Clock 1 */
+       { 0x00000102, 0x0011 },    /* R258   - Sample rate 1 */
+       { 0x00000103, 0x0011 },    /* R259   - Sample rate 2 */
+       { 0x00000104, 0x0011 },    /* R260   - Sample rate 3 */
+       { 0x00000112, 0x0305 },    /* R274   - Async clock 1 */
+       { 0x00000113, 0x0011 },    /* R275   - Async sample rate 1 */
+       { 0x00000149, 0x0000 },    /* R329   - Output system clock */
+       { 0x0000014A, 0x0000 },    /* R330   - Output async clock */
+       { 0x00000152, 0x0000 },    /* R338   - Rate Estimator 1 */
+       { 0x00000153, 0x0000 },    /* R339   - Rate Estimator 2 */
+       { 0x00000154, 0x0000 },    /* R340   - Rate Estimator 3 */
+       { 0x00000155, 0x0000 },    /* R341   - Rate Estimator 4 */
+       { 0x00000156, 0x0000 },    /* R342   - Rate Estimator 5 */
+       { 0x00000161, 0x0000 },    /* R353   - Dynamic Frequency Scaling 1 */
+       { 0x00000171, 0x0000 },    /* R369   - FLL1 Control 1 */
+       { 0x00000172, 0x0008 },    /* R370   - FLL1 Control 2 */
+       { 0x00000173, 0x0018 },    /* R371   - FLL1 Control 3 */
+       { 0x00000174, 0x007D },    /* R372   - FLL1 Control 4 */
+       { 0x00000175, 0x0004 },    /* R373   - FLL1 Control 5 */
+       { 0x00000176, 0x0000 },    /* R374   - FLL1 Control 6 */
+       { 0x00000177, 0x0181 },    /* R375   - FLL1 Loop Filter Test 1 */
+       { 0x00000181, 0x0000 },    /* R385   - FLL1 Synchroniser 1 */
+       { 0x00000182, 0x0000 },    /* R386   - FLL1 Synchroniser 2 */
+       { 0x00000183, 0x0000 },    /* R387   - FLL1 Synchroniser 3 */
+       { 0x00000184, 0x0000 },    /* R388   - FLL1 Synchroniser 4 */
+       { 0x00000185, 0x0000 },    /* R389   - FLL1 Synchroniser 5 */
+       { 0x00000186, 0x0000 },    /* R390   - FLL1 Synchroniser 6 */
+       { 0x00000189, 0x0000 },    /* R393   - FLL1 Spread Spectrum */
+       { 0x0000018A, 0x0004 },    /* R394   - FLL1 GPIO Clock */
+       { 0x00000191, 0x0000 },    /* R401   - FLL2 Control 1 */
+       { 0x00000192, 0x0008 },    /* R402   - FLL2 Control 2 */
+       { 0x00000193, 0x0018 },    /* R403   - FLL2 Control 3 */
+       { 0x00000194, 0x007D },    /* R404   - FLL2 Control 4 */
+       { 0x00000195, 0x0004 },    /* R405   - FLL2 Control 5 */
+       { 0x00000196, 0x0000 },    /* R406   - FLL2 Control 6 */
+       { 0x00000197, 0x0000 },    /* R407   - FLL2 Loop Filter Test 1 */
+       { 0x000001A1, 0x0000 },    /* R417   - FLL2 Synchroniser 1 */
+       { 0x000001A2, 0x0000 },    /* R418   - FLL2 Synchroniser 2 */
+       { 0x000001A3, 0x0000 },    /* R419   - FLL2 Synchroniser 3 */
+       { 0x000001A4, 0x0000 },    /* R420   - FLL2 Synchroniser 4 */
+       { 0x000001A5, 0x0000 },    /* R421   - FLL2 Synchroniser 5 */
+       { 0x000001A6, 0x0000 },    /* R422   - FLL2 Synchroniser 6 */
+       { 0x000001A9, 0x0000 },    /* R425   - FLL2 Spread Spectrum */
+       { 0x000001AA, 0x0004 },    /* R426   - FLL2 GPIO Clock */
+       { 0x00000200, 0x0006 },    /* R512   - Mic Charge Pump 1 */
+       { 0x00000210, 0x00D4 },    /* R528   - LDO1 Control 1 */
+       { 0x00000212, 0x0000 },    /* R530   - LDO1 Control 2 */
+       { 0x00000213, 0x0344 },    /* R531   - LDO2 Control 1 */
+       { 0x00000218, 0x01A6 },    /* R536   - Mic Bias Ctrl 1 */
+       { 0x00000219, 0x01A6 },    /* R537   - Mic Bias Ctrl 2 */
+       { 0x0000021A, 0x01A6 },    /* R538   - Mic Bias Ctrl 3 */
+       { 0x00000293, 0x0000 },    /* R659   - Accessory Detect Mode 1 */
+       { 0x0000029B, 0x0020 },    /* R667   - Headphone Detect 1 */
+       { 0x000002A3, 0x1102 },    /* R675   - Mic Detect 1 */
+       { 0x000002A4, 0x009F },    /* R676   - Mic Detect 2 */
+       { 0x000002A5, 0x0000 },    /* R677   - Mic Detect 3 */
+       { 0x000002C3, 0x0000 },    /* R707   - Mic noise mix control 1 */
+       { 0x000002CB, 0x0000 },    /* R715   - Isolation control */
+       { 0x000002D3, 0x0000 },    /* R723   - Jack detect analogue */
+       { 0x00000300, 0x0000 },    /* R768   - Input Enables */
+       { 0x00000308, 0x0000 },    /* R776   - Input Rate */
+       { 0x00000309, 0x0022 },    /* R777   - Input Volume Ramp */
+       { 0x00000310, 0x2080 },    /* R784   - IN1L Control */
+       { 0x00000311, 0x0180 },    /* R785   - ADC Digital Volume 1L */
+       { 0x00000312, 0x0000 },    /* R786   - DMIC1L Control */
+       { 0x00000314, 0x0080 },    /* R788   - IN1R Control */
+       { 0x00000315, 0x0180 },    /* R789   - ADC Digital Volume 1R */
+       { 0x00000316, 0x0000 },    /* R790   - DMIC1R Control */
+       { 0x00000318, 0x2080 },    /* R792   - IN2L Control */
+       { 0x00000319, 0x0180 },    /* R793   - ADC Digital Volume 2L */
+       { 0x0000031A, 0x0000 },    /* R794   - DMIC2L Control */
+       { 0x0000031C, 0x0080 },    /* R796   - IN2R Control */
+       { 0x0000031D, 0x0180 },    /* R797   - ADC Digital Volume 2R */
+       { 0x0000031E, 0x0000 },    /* R798   - DMIC2R Control */
+       { 0x00000400, 0x0000 },    /* R1024  - Output Enables 1 */
+       { 0x00000408, 0x0000 },    /* R1032  - Output Rate 1 */
+       { 0x00000409, 0x0022 },    /* R1033  - Output Volume Ramp */
+       { 0x00000410, 0x0080 },    /* R1040  - Output Path Config 1L */
+       { 0x00000411, 0x0180 },    /* R1041  - DAC Digital Volume 1L */
+       { 0x00000412, 0x0080 },    /* R1042  - DAC Volume Limit 1L */
+       { 0x00000413, 0x0001 },    /* R1043  - Noise Gate Select 1L */
+       { 0x00000414, 0x0080 },    /* R1044  - Output Path Config 1R */
+       { 0x00000415, 0x0180 },    /* R1045  - DAC Digital Volume 1R */
+       { 0x00000416, 0x0080 },    /* R1046  - DAC Volume Limit 1R */
+       { 0x00000417, 0x0002 },    /* R1047  - Noise Gate Select 1R */
+       { 0x00000420, 0x0080 },    /* R1056  - Output Path Config 3L */
+       { 0x00000421, 0x0180 },    /* R1057  - DAC Digital Volume 3L */
+       { 0x00000422, 0x0080 },    /* R1058  - DAC Volume Limit 3L */
+       { 0x00000423, 0x0010 },    /* R1059  - Noise Gate Select 3L */
+       { 0x00000428, 0x0000 },    /* R1064  - Output Path Config 4L */
+       { 0x00000429, 0x0180 },    /* R1065  - DAC Digital Volume 4L */
+       { 0x0000042A, 0x0080 },    /* R1066  - Out Volume 4L */
+       { 0x0000042B, 0x0040 },    /* R1067  - Noise Gate Select 4L */
+       { 0x00000430, 0x0000 },    /* R1072  - Output Path Config 5L */
+       { 0x00000431, 0x0180 },    /* R1073  - DAC Digital Volume 5L */
+       { 0x00000432, 0x0080 },    /* R1074  - DAC Volume Limit 5L */
+       { 0x00000433, 0x0100 },    /* R1075  - Noise Gate Select 5L */
+       { 0x00000435, 0x0180 },    /* R1077  - DAC Digital Volume 5R */
+       { 0x00000436, 0x0080 },    /* R1078  - DAC Volume Limit 5R */
+       { 0x00000437, 0x0200 },    /* R1079  - Noise Gate Select 5R */
+       { 0x00000450, 0x0000 },    /* R1104  - DAC AEC Control 1 */
+       { 0x00000458, 0x0000 },    /* R1112  - Noise Gate Control */
+       { 0x00000490, 0x0069 },    /* R1168  - PDM SPK1 CTRL 1 */
+       { 0x00000491, 0x0000 },    /* R1169  - PDM SPK1 CTRL 2 */
+       { 0x00000500, 0x000C },    /* R1280  - AIF1 BCLK Ctrl */
+       { 0x00000501, 0x0008 },    /* R1281  - AIF1 Tx Pin Ctrl */
+       { 0x00000502, 0x0000 },    /* R1282  - AIF1 Rx Pin Ctrl */
+       { 0x00000503, 0x0000 },    /* R1283  - AIF1 Rate Ctrl */
+       { 0x00000504, 0x0000 },    /* R1284  - AIF1 Format */
+       { 0x00000505, 0x0040 },    /* R1285  - AIF1 Tx BCLK Rate */
+       { 0x00000506, 0x0040 },    /* R1286  - AIF1 Rx BCLK Rate */
+       { 0x00000507, 0x1818 },    /* R1287  - AIF1 Frame Ctrl 1 */
+       { 0x00000508, 0x1818 },    /* R1288  - AIF1 Frame Ctrl 2 */
+       { 0x00000509, 0x0000 },    /* R1289  - AIF1 Frame Ctrl 3 */
+       { 0x0000050A, 0x0001 },    /* R1290  - AIF1 Frame Ctrl 4 */
+       { 0x0000050B, 0x0002 },    /* R1291  - AIF1 Frame Ctrl 5 */
+       { 0x0000050C, 0x0003 },    /* R1292  - AIF1 Frame Ctrl 6 */
+       { 0x0000050D, 0x0004 },    /* R1293  - AIF1 Frame Ctrl 7 */
+       { 0x0000050E, 0x0005 },    /* R1294  - AIF1 Frame Ctrl 8 */
+       { 0x0000050F, 0x0006 },    /* R1295  - AIF1 Frame Ctrl 9 */
+       { 0x00000510, 0x0007 },    /* R1296  - AIF1 Frame Ctrl 10 */
+       { 0x00000511, 0x0000 },    /* R1297  - AIF1 Frame Ctrl 11 */
+       { 0x00000512, 0x0001 },    /* R1298  - AIF1 Frame Ctrl 12 */
+       { 0x00000513, 0x0002 },    /* R1299  - AIF1 Frame Ctrl 13 */
+       { 0x00000514, 0x0003 },    /* R1300  - AIF1 Frame Ctrl 14 */
+       { 0x00000515, 0x0004 },    /* R1301  - AIF1 Frame Ctrl 15 */
+       { 0x00000516, 0x0005 },    /* R1302  - AIF1 Frame Ctrl 16 */
+       { 0x00000517, 0x0006 },    /* R1303  - AIF1 Frame Ctrl 17 */
+       { 0x00000518, 0x0007 },    /* R1304  - AIF1 Frame Ctrl 18 */
+       { 0x00000519, 0x0000 },    /* R1305  - AIF1 Tx Enables */
+       { 0x0000051A, 0x0000 },    /* R1306  - AIF1 Rx Enables */
+       { 0x00000540, 0x000C },    /* R1344  - AIF2 BCLK Ctrl */
+       { 0x00000541, 0x0008 },    /* R1345  - AIF2 Tx Pin Ctrl */
+       { 0x00000542, 0x0000 },    /* R1346  - AIF2 Rx Pin Ctrl */
+       { 0x00000543, 0x0000 },    /* R1347  - AIF2 Rate Ctrl */
+       { 0x00000544, 0x0000 },    /* R1348  - AIF2 Format */
+       { 0x00000545, 0x0040 },    /* R1349  - AIF2 Tx BCLK Rate */
+       { 0x00000546, 0x0040 },    /* R1350  - AIF2 Rx BCLK Rate */
+       { 0x00000547, 0x1818 },    /* R1351  - AIF2 Frame Ctrl 1 */
+       { 0x00000548, 0x1818 },    /* R1352  - AIF2 Frame Ctrl 2 */
+       { 0x00000549, 0x0000 },    /* R1353  - AIF2 Frame Ctrl 3 */
+       { 0x0000054A, 0x0001 },    /* R1354  - AIF2 Frame Ctrl 4 */
+       { 0x00000551, 0x0000 },    /* R1361  - AIF2 Frame Ctrl 11 */
+       { 0x00000552, 0x0001 },    /* R1362  - AIF2 Frame Ctrl 12 */
+       { 0x00000559, 0x0000 },    /* R1369  - AIF2 Tx Enables */
+       { 0x0000055A, 0x0000 },    /* R1370  - AIF2 Rx Enables */
+       { 0x000005E3, 0x0004 },    /* R1507  - SLIMbus Framer Ref Gear */
+       { 0x000005E5, 0x0000 },    /* R1509  - SLIMbus Rates 1 */
+       { 0x000005E6, 0x0000 },    /* R1510  - SLIMbus Rates 2 */
+       { 0x000005E7, 0x0000 },    /* R1511  - SLIMbus Rates 3 */
+       { 0x000005E8, 0x0000 },    /* R1512  - SLIMbus Rates 4 */
+       { 0x000005E9, 0x0000 },    /* R1513  - SLIMbus Rates 5 */
+       { 0x000005EA, 0x0000 },    /* R1514  - SLIMbus Rates 6 */
+       { 0x000005EB, 0x0000 },    /* R1515  - SLIMbus Rates 7 */
+       { 0x000005EC, 0x0000 },    /* R1516  - SLIMbus Rates 8 */
+       { 0x000005F5, 0x0000 },    /* R1525  - SLIMbus RX Channel Enable */
+       { 0x000005F6, 0x0000 },    /* R1526  - SLIMbus TX Channel Enable */
+       { 0x00000640, 0x0000 },    /* R1600  - PWM1MIX Input 1 Source */
+       { 0x00000641, 0x0080 },    /* R1601  - PWM1MIX Input 1 Volume */
+       { 0x00000642, 0x0000 },    /* R1602  - PWM1MIX Input 2 Source */
+       { 0x00000643, 0x0080 },    /* R1603  - PWM1MIX Input 2 Volume */
+       { 0x00000644, 0x0000 },    /* R1604  - PWM1MIX Input 3 Source */
+       { 0x00000645, 0x0080 },    /* R1605  - PWM1MIX Input 3 Volume */
+       { 0x00000646, 0x0000 },    /* R1606  - PWM1MIX Input 4 Source */
+       { 0x00000647, 0x0080 },    /* R1607  - PWM1MIX Input 4 Volume */
+       { 0x00000648, 0x0000 },    /* R1608  - PWM2MIX Input 1 Source */
+       { 0x00000649, 0x0080 },    /* R1609  - PWM2MIX Input 1 Volume */
+       { 0x0000064A, 0x0000 },    /* R1610  - PWM2MIX Input 2 Source */
+       { 0x0000064B, 0x0080 },    /* R1611  - PWM2MIX Input 2 Volume */
+       { 0x0000064C, 0x0000 },    /* R1612  - PWM2MIX Input 3 Source */
+       { 0x0000064D, 0x0080 },    /* R1613  - PWM2MIX Input 3 Volume */
+       { 0x0000064E, 0x0000 },    /* R1614  - PWM2MIX Input 4 Source */
+       { 0x0000064F, 0x0080 },    /* R1615  - PWM2MIX Input 4 Volume */
+       { 0x00000660, 0x0000 },    /* R1632  - MICMIX Input 1 Source */
+       { 0x00000661, 0x0080 },    /* R1633  - MICMIX Input 1 Volume */
+       { 0x00000662, 0x0000 },    /* R1634  - MICMIX Input 2 Source */
+       { 0x00000663, 0x0080 },    /* R1635  - MICMIX Input 2 Volume */
+       { 0x00000664, 0x0000 },    /* R1636  - MICMIX Input 3 Source */
+       { 0x00000665, 0x0080 },    /* R1637  - MICMIX Input 3 Volume */
+       { 0x00000666, 0x0000 },    /* R1638  - MICMIX Input 4 Source */
+       { 0x00000667, 0x0080 },    /* R1639  - MICMIX Input 4 Volume */
+       { 0x00000668, 0x0000 },    /* R1640  - NOISEMIX Input 1 Source */
+       { 0x00000669, 0x0080 },    /* R1641  - NOISEMIX Input 1 Volume */
+       { 0x0000066A, 0x0000 },    /* R1642  - NOISEMIX Input 2 Source */
+       { 0x0000066B, 0x0080 },    /* R1643  - NOISEMIX Input 2 Volume */
+       { 0x0000066C, 0x0000 },    /* R1644  - NOISEMIX Input 3 Source */
+       { 0x0000066D, 0x0080 },    /* R1645  - NOISEMIX Input 3 Volume */
+       { 0x0000066E, 0x0000 },    /* R1646  - NOISEMIX Input 4 Source */
+       { 0x0000066F, 0x0080 },    /* R1647  - NOISEMIX Input 4 Volume */
+       { 0x00000680, 0x0000 },    /* R1664  - OUT1LMIX Input 1 Source */
+       { 0x00000681, 0x0080 },    /* R1665  - OUT1LMIX Input 1 Volume */
+       { 0x00000682, 0x0000 },    /* R1666  - OUT1LMIX Input 2 Source */
+       { 0x00000683, 0x0080 },    /* R1667  - OUT1LMIX Input 2 Volume */
+       { 0x00000684, 0x0000 },    /* R1668  - OUT1LMIX Input 3 Source */
+       { 0x00000685, 0x0080 },    /* R1669  - OUT1LMIX Input 3 Volume */
+       { 0x00000686, 0x0000 },    /* R1670  - OUT1LMIX Input 4 Source */
+       { 0x00000687, 0x0080 },    /* R1671  - OUT1LMIX Input 4 Volume */
+       { 0x00000688, 0x0000 },    /* R1672  - OUT1RMIX Input 1 Source */
+       { 0x00000689, 0x0080 },    /* R1673  - OUT1RMIX Input 1 Volume */
+       { 0x0000068A, 0x0000 },    /* R1674  - OUT1RMIX Input 2 Source */
+       { 0x0000068B, 0x0080 },    /* R1675  - OUT1RMIX Input 2 Volume */
+       { 0x0000068C, 0x0000 },    /* R1676  - OUT1RMIX Input 3 Source */
+       { 0x0000068D, 0x0080 },    /* R1677  - OUT1RMIX Input 3 Volume */
+       { 0x0000068E, 0x0000 },    /* R1678  - OUT1RMIX Input 4 Source */
+       { 0x0000068F, 0x0080 },    /* R1679  - OUT1RMIX Input 4 Volume */
+       { 0x000006A0, 0x0000 },    /* R1696  - OUT3LMIX Input 1 Source */
+       { 0x000006A1, 0x0080 },    /* R1697  - OUT3LMIX Input 1 Volume */
+       { 0x000006A2, 0x0000 },    /* R1698  - OUT3LMIX Input 2 Source */
+       { 0x000006A3, 0x0080 },    /* R1699  - OUT3LMIX Input 2 Volume */
+       { 0x000006A4, 0x0000 },    /* R1700  - OUT3LMIX Input 3 Source */
+       { 0x000006A5, 0x0080 },    /* R1701  - OUT3LMIX Input 3 Volume */
+       { 0x000006A6, 0x0000 },    /* R1702  - OUT3LMIX Input 4 Source */
+       { 0x000006A7, 0x0080 },    /* R1703  - OUT3LMIX Input 4 Volume */
+       { 0x000006B0, 0x0000 },    /* R1712  - OUT4LMIX Input 1 Source */
+       { 0x000006B1, 0x0080 },    /* R1713  - OUT4LMIX Input 1 Volume */
+       { 0x000006B2, 0x0000 },    /* R1714  - OUT4LMIX Input 2 Source */
+       { 0x000006B3, 0x0080 },    /* R1715  - OUT4LMIX Input 2 Volume */
+       { 0x000006B4, 0x0000 },    /* R1716  - OUT4LMIX Input 3 Source */
+       { 0x000006B5, 0x0080 },    /* R1717  - OUT4LMIX Input 3 Volume */
+       { 0x000006B6, 0x0000 },    /* R1718  - OUT4LMIX Input 4 Source */
+       { 0x000006B7, 0x0080 },    /* R1719  - OUT4LMIX Input 4 Volume */
+       { 0x000006C0, 0x0000 },    /* R1728  - OUT5LMIX Input 1 Source */
+       { 0x000006C1, 0x0080 },    /* R1729  - OUT5LMIX Input 1 Volume */
+       { 0x000006C2, 0x0000 },    /* R1730  - OUT5LMIX Input 2 Source */
+       { 0x000006C3, 0x0080 },    /* R1731  - OUT5LMIX Input 2 Volume */
+       { 0x000006C4, 0x0000 },    /* R1732  - OUT5LMIX Input 3 Source */
+       { 0x000006C5, 0x0080 },    /* R1733  - OUT5LMIX Input 3 Volume */
+       { 0x000006C6, 0x0000 },    /* R1734  - OUT5LMIX Input 4 Source */
+       { 0x000006C7, 0x0080 },    /* R1735  - OUT5LMIX Input 4 Volume */
+       { 0x000006C8, 0x0000 },    /* R1736  - OUT5RMIX Input 1 Source */
+       { 0x000006C9, 0x0080 },    /* R1737  - OUT5RMIX Input 1 Volume */
+       { 0x000006CA, 0x0000 },    /* R1738  - OUT5RMIX Input 2 Source */
+       { 0x000006CB, 0x0080 },    /* R1739  - OUT5RMIX Input 2 Volume */
+       { 0x000006CC, 0x0000 },    /* R1740  - OUT5RMIX Input 3 Source */
+       { 0x000006CD, 0x0080 },    /* R1741  - OUT5RMIX Input 3 Volume */
+       { 0x000006CE, 0x0000 },    /* R1742  - OUT5RMIX Input 4 Source */
+       { 0x000006CF, 0x0080 },    /* R1743  - OUT5RMIX Input 4 Volume */
+       { 0x00000700, 0x0000 },    /* R1792  - AIF1TX1MIX Input 1 Source */
+       { 0x00000701, 0x0080 },    /* R1793  - AIF1TX1MIX Input 1 Volume */
+       { 0x00000702, 0x0000 },    /* R1794  - AIF1TX1MIX Input 2 Source */
+       { 0x00000703, 0x0080 },    /* R1795  - AIF1TX1MIX Input 2 Volume */
+       { 0x00000704, 0x0000 },    /* R1796  - AIF1TX1MIX Input 3 Source */
+       { 0x00000705, 0x0080 },    /* R1797  - AIF1TX1MIX Input 3 Volume */
+       { 0x00000706, 0x0000 },    /* R1798  - AIF1TX1MIX Input 4 Source */
+       { 0x00000707, 0x0080 },    /* R1799  - AIF1TX1MIX Input 4 Volume */
+       { 0x00000708, 0x0000 },    /* R1800  - AIF1TX2MIX Input 1 Source */
+       { 0x00000709, 0x0080 },    /* R1801  - AIF1TX2MIX Input 1 Volume */
+       { 0x0000070A, 0x0000 },    /* R1802  - AIF1TX2MIX Input 2 Source */
+       { 0x0000070B, 0x0080 },    /* R1803  - AIF1TX2MIX Input 2 Volume */
+       { 0x0000070C, 0x0000 },    /* R1804  - AIF1TX2MIX Input 3 Source */
+       { 0x0000070D, 0x0080 },    /* R1805  - AIF1TX2MIX Input 3 Volume */
+       { 0x0000070E, 0x0000 },    /* R1806  - AIF1TX2MIX Input 4 Source */
+       { 0x0000070F, 0x0080 },    /* R1807  - AIF1TX2MIX Input 4 Volume */
+       { 0x00000710, 0x0000 },    /* R1808  - AIF1TX3MIX Input 1 Source */
+       { 0x00000711, 0x0080 },    /* R1809  - AIF1TX3MIX Input 1 Volume */
+       { 0x00000712, 0x0000 },    /* R1810  - AIF1TX3MIX Input 2 Source */
+       { 0x00000713, 0x0080 },    /* R1811  - AIF1TX3MIX Input 2 Volume */
+       { 0x00000714, 0x0000 },    /* R1812  - AIF1TX3MIX Input 3 Source */
+       { 0x00000715, 0x0080 },    /* R1813  - AIF1TX3MIX Input 3 Volume */
+       { 0x00000716, 0x0000 },    /* R1814  - AIF1TX3MIX Input 4 Source */
+       { 0x00000717, 0x0080 },    /* R1815  - AIF1TX3MIX Input 4 Volume */
+       { 0x00000718, 0x0000 },    /* R1816  - AIF1TX4MIX Input 1 Source */
+       { 0x00000719, 0x0080 },    /* R1817  - AIF1TX4MIX Input 1 Volume */
+       { 0x0000071A, 0x0000 },    /* R1818  - AIF1TX4MIX Input 2 Source */
+       { 0x0000071B, 0x0080 },    /* R1819  - AIF1TX4MIX Input 2 Volume */
+       { 0x0000071C, 0x0000 },    /* R1820  - AIF1TX4MIX Input 3 Source */
+       { 0x0000071D, 0x0080 },    /* R1821  - AIF1TX4MIX Input 3 Volume */
+       { 0x0000071E, 0x0000 },    /* R1822  - AIF1TX4MIX Input 4 Source */
+       { 0x0000071F, 0x0080 },    /* R1823  - AIF1TX4MIX Input 4 Volume */
+       { 0x00000720, 0x0000 },    /* R1824  - AIF1TX5MIX Input 1 Source */
+       { 0x00000721, 0x0080 },    /* R1825  - AIF1TX5MIX Input 1 Volume */
+       { 0x00000722, 0x0000 },    /* R1826  - AIF1TX5MIX Input 2 Source */
+       { 0x00000723, 0x0080 },    /* R1827  - AIF1TX5MIX Input 2 Volume */
+       { 0x00000724, 0x0000 },    /* R1828  - AIF1TX5MIX Input 3 Source */
+       { 0x00000725, 0x0080 },    /* R1829  - AIF1TX5MIX Input 3 Volume */
+       { 0x00000726, 0x0000 },    /* R1830  - AIF1TX5MIX Input 4 Source */
+       { 0x00000727, 0x0080 },    /* R1831  - AIF1TX5MIX Input 4 Volume */
+       { 0x00000728, 0x0000 },    /* R1832  - AIF1TX6MIX Input 1 Source */
+       { 0x00000729, 0x0080 },    /* R1833  - AIF1TX6MIX Input 1 Volume */
+       { 0x0000072A, 0x0000 },    /* R1834  - AIF1TX6MIX Input 2 Source */
+       { 0x0000072B, 0x0080 },    /* R1835  - AIF1TX6MIX Input 2 Volume */
+       { 0x0000072C, 0x0000 },    /* R1836  - AIF1TX6MIX Input 3 Source */
+       { 0x0000072D, 0x0080 },    /* R1837  - AIF1TX6MIX Input 3 Volume */
+       { 0x0000072E, 0x0000 },    /* R1838  - AIF1TX6MIX Input 4 Source */
+       { 0x0000072F, 0x0080 },    /* R1839  - AIF1TX6MIX Input 4 Volume */
+       { 0x00000730, 0x0000 },    /* R1840  - AIF1TX7MIX Input 1 Source */
+       { 0x00000731, 0x0080 },    /* R1841  - AIF1TX7MIX Input 1 Volume */
+       { 0x00000732, 0x0000 },    /* R1842  - AIF1TX7MIX Input 2 Source */
+       { 0x00000733, 0x0080 },    /* R1843  - AIF1TX7MIX Input 2 Volume */
+       { 0x00000734, 0x0000 },    /* R1844  - AIF1TX7MIX Input 3 Source */
+       { 0x00000735, 0x0080 },    /* R1845  - AIF1TX7MIX Input 3 Volume */
+       { 0x00000736, 0x0000 },    /* R1846  - AIF1TX7MIX Input 4 Source */
+       { 0x00000737, 0x0080 },    /* R1847  - AIF1TX7MIX Input 4 Volume */
+       { 0x00000738, 0x0000 },    /* R1848  - AIF1TX8MIX Input 1 Source */
+       { 0x00000739, 0x0080 },    /* R1849  - AIF1TX8MIX Input 1 Volume */
+       { 0x0000073A, 0x0000 },    /* R1850  - AIF1TX8MIX Input 2 Source */
+       { 0x0000073B, 0x0080 },    /* R1851  - AIF1TX8MIX Input 2 Volume */
+       { 0x0000073C, 0x0000 },    /* R1852  - AIF1TX8MIX Input 3 Source */
+       { 0x0000073D, 0x0080 },    /* R1853  - AIF1TX8MIX Input 3 Volume */
+       { 0x0000073E, 0x0000 },    /* R1854  - AIF1TX8MIX Input 4 Source */
+       { 0x0000073F, 0x0080 },    /* R1855  - AIF1TX8MIX Input 4 Volume */
+       { 0x00000740, 0x0000 },    /* R1856  - AIF2TX1MIX Input 1 Source */
+       { 0x00000741, 0x0080 },    /* R1857  - AIF2TX1MIX Input 1 Volume */
+       { 0x00000742, 0x0000 },    /* R1858  - AIF2TX1MIX Input 2 Source */
+       { 0x00000743, 0x0080 },    /* R1859  - AIF2TX1MIX Input 2 Volume */
+       { 0x00000744, 0x0000 },    /* R1860  - AIF2TX1MIX Input 3 Source */
+       { 0x00000745, 0x0080 },    /* R1861  - AIF2TX1MIX Input 3 Volume */
+       { 0x00000746, 0x0000 },    /* R1862  - AIF2TX1MIX Input 4 Source */
+       { 0x00000747, 0x0080 },    /* R1863  - AIF2TX1MIX Input 4 Volume */
+       { 0x00000748, 0x0000 },    /* R1864  - AIF2TX2MIX Input 1 Source */
+       { 0x00000749, 0x0080 },    /* R1865  - AIF2TX2MIX Input 1 Volume */
+       { 0x0000074A, 0x0000 },    /* R1866  - AIF2TX2MIX Input 2 Source */
+       { 0x0000074B, 0x0080 },    /* R1867  - AIF2TX2MIX Input 2 Volume */
+       { 0x0000074C, 0x0000 },    /* R1868  - AIF2TX2MIX Input 3 Source */
+       { 0x0000074D, 0x0080 },    /* R1869  - AIF2TX2MIX Input 3 Volume */
+       { 0x0000074E, 0x0000 },    /* R1870  - AIF2TX2MIX Input 4 Source */
+       { 0x0000074F, 0x0080 },    /* R1871  - AIF2TX2MIX Input 4 Volume */
+       { 0x000007C0, 0x0000 },    /* R1984  - SLIMTX1MIX Input 1 Source */
+       { 0x000007C1, 0x0080 },    /* R1985  - SLIMTX1MIX Input 1 Volume */
+       { 0x000007C2, 0x0000 },    /* R1986  - SLIMTX1MIX Input 2 Source */
+       { 0x000007C3, 0x0080 },    /* R1987  - SLIMTX1MIX Input 2 Volume */
+       { 0x000007C4, 0x0000 },    /* R1988  - SLIMTX1MIX Input 3 Source */
+       { 0x000007C5, 0x0080 },    /* R1989  - SLIMTX1MIX Input 3 Volume */
+       { 0x000007C6, 0x0000 },    /* R1990  - SLIMTX1MIX Input 4 Source */
+       { 0x000007C7, 0x0080 },    /* R1991  - SLIMTX1MIX Input 4 Volume */
+       { 0x000007C8, 0x0000 },    /* R1992  - SLIMTX2MIX Input 1 Source */
+       { 0x000007C9, 0x0080 },    /* R1993  - SLIMTX2MIX Input 1 Volume */
+       { 0x000007CA, 0x0000 },    /* R1994  - SLIMTX2MIX Input 2 Source */
+       { 0x000007CB, 0x0080 },    /* R1995  - SLIMTX2MIX Input 2 Volume */
+       { 0x000007CC, 0x0000 },    /* R1996  - SLIMTX2MIX Input 3 Source */
+       { 0x000007CD, 0x0080 },    /* R1997  - SLIMTX2MIX Input 3 Volume */
+       { 0x000007CE, 0x0000 },    /* R1998  - SLIMTX2MIX Input 4 Source */
+       { 0x000007CF, 0x0080 },    /* R1999  - SLIMTX2MIX Input 4 Volume */
+       { 0x000007D0, 0x0000 },    /* R2000  - SLIMTX3MIX Input 1 Source */
+       { 0x000007D1, 0x0080 },    /* R2001  - SLIMTX3MIX Input 1 Volume */
+       { 0x000007D2, 0x0000 },    /* R2002  - SLIMTX3MIX Input 2 Source */
+       { 0x000007D3, 0x0080 },    /* R2003  - SLIMTX3MIX Input 2 Volume */
+       { 0x000007D4, 0x0000 },    /* R2004  - SLIMTX3MIX Input 3 Source */
+       { 0x000007D5, 0x0080 },    /* R2005  - SLIMTX3MIX Input 3 Volume */
+       { 0x000007D6, 0x0000 },    /* R2006  - SLIMTX3MIX Input 4 Source */
+       { 0x000007D7, 0x0080 },    /* R2007  - SLIMTX3MIX Input 4 Volume */
+       { 0x000007D8, 0x0000 },    /* R2008  - SLIMTX4MIX Input 1 Source */
+       { 0x000007D9, 0x0080 },    /* R2009  - SLIMTX4MIX Input 1 Volume */
+       { 0x000007DA, 0x0000 },    /* R2010  - SLIMTX4MIX Input 2 Source */
+       { 0x000007DB, 0x0080 },    /* R2011  - SLIMTX4MIX Input 2 Volume */
+       { 0x000007DC, 0x0000 },    /* R2012  - SLIMTX4MIX Input 3 Source */
+       { 0x000007DD, 0x0080 },    /* R2013  - SLIMTX4MIX Input 3 Volume */
+       { 0x000007DE, 0x0000 },    /* R2014  - SLIMTX4MIX Input 4 Source */
+       { 0x000007DF, 0x0080 },    /* R2015  - SLIMTX4MIX Input 4 Volume */
+       { 0x000007E0, 0x0000 },    /* R2016  - SLIMTX5MIX Input 1 Source */
+       { 0x000007E1, 0x0080 },    /* R2017  - SLIMTX5MIX Input 1 Volume */
+       { 0x000007E2, 0x0000 },    /* R2018  - SLIMTX5MIX Input 2 Source */
+       { 0x000007E3, 0x0080 },    /* R2019  - SLIMTX5MIX Input 2 Volume */
+       { 0x000007E4, 0x0000 },    /* R2020  - SLIMTX5MIX Input 3 Source */
+       { 0x000007E5, 0x0080 },    /* R2021  - SLIMTX5MIX Input 3 Volume */
+       { 0x000007E6, 0x0000 },    /* R2022  - SLIMTX5MIX Input 4 Source */
+       { 0x000007E7, 0x0080 },    /* R2023  - SLIMTX5MIX Input 4 Volume */
+       { 0x000007E8, 0x0000 },    /* R2024  - SLIMTX6MIX Input 1 Source */
+       { 0x000007E9, 0x0080 },    /* R2025  - SLIMTX6MIX Input 1 Volume */
+       { 0x000007EA, 0x0000 },    /* R2026  - SLIMTX6MIX Input 2 Source */
+       { 0x000007EB, 0x0080 },    /* R2027  - SLIMTX6MIX Input 2 Volume */
+       { 0x000007EC, 0x0000 },    /* R2028  - SLIMTX6MIX Input 3 Source */
+       { 0x000007ED, 0x0080 },    /* R2029  - SLIMTX6MIX Input 3 Volume */
+       { 0x000007EE, 0x0000 },    /* R2030  - SLIMTX6MIX Input 4 Source */
+       { 0x000007EF, 0x0080 },    /* R2031  - SLIMTX6MIX Input 4 Volume */
+       { 0x000007F0, 0x0000 },    /* R2032  - SLIMTX7MIX Input 1 Source */
+       { 0x000007F1, 0x0080 },    /* R2033  - SLIMTX7MIX Input 1 Volume */
+       { 0x000007F2, 0x0000 },    /* R2034  - SLIMTX7MIX Input 2 Source */
+       { 0x000007F3, 0x0080 },    /* R2035  - SLIMTX7MIX Input 2 Volume */
+       { 0x000007F4, 0x0000 },    /* R2036  - SLIMTX7MIX Input 3 Source */
+       { 0x000007F5, 0x0080 },    /* R2037  - SLIMTX7MIX Input 3 Volume */
+       { 0x000007F6, 0x0000 },    /* R2038  - SLIMTX7MIX Input 4 Source */
+       { 0x000007F7, 0x0080 },    /* R2039  - SLIMTX7MIX Input 4 Volume */
+       { 0x000007F8, 0x0000 },    /* R2040  - SLIMTX8MIX Input 1 Source */
+       { 0x000007F9, 0x0080 },    /* R2041  - SLIMTX8MIX Input 1 Volume */
+       { 0x000007FA, 0x0000 },    /* R2042  - SLIMTX8MIX Input 2 Source */
+       { 0x000007FB, 0x0080 },    /* R2043  - SLIMTX8MIX Input 2 Volume */
+       { 0x000007FC, 0x0000 },    /* R2044  - SLIMTX8MIX Input 3 Source */
+       { 0x000007FD, 0x0080 },    /* R2045  - SLIMTX8MIX Input 3 Volume */
+       { 0x000007FE, 0x0000 },    /* R2046  - SLIMTX8MIX Input 4 Source */
+       { 0x000007FF, 0x0080 },    /* R2047  - SLIMTX8MIX Input 4 Volume */
+       { 0x00000880, 0x0000 },    /* R2176  - EQ1MIX Input 1 Source */
+       { 0x00000881, 0x0080 },    /* R2177  - EQ1MIX Input 1 Volume */
+       { 0x00000882, 0x0000 },    /* R2178  - EQ1MIX Input 2 Source */
+       { 0x00000883, 0x0080 },    /* R2179  - EQ1MIX Input 2 Volume */
+       { 0x00000884, 0x0000 },    /* R2180  - EQ1MIX Input 3 Source */
+       { 0x00000885, 0x0080 },    /* R2181  - EQ1MIX Input 3 Volume */
+       { 0x00000886, 0x0000 },    /* R2182  - EQ1MIX Input 4 Source */
+       { 0x00000887, 0x0080 },    /* R2183  - EQ1MIX Input 4 Volume */
+       { 0x00000888, 0x0000 },    /* R2184  - EQ2MIX Input 1 Source */
+       { 0x00000889, 0x0080 },    /* R2185  - EQ2MIX Input 1 Volume */
+       { 0x0000088A, 0x0000 },    /* R2186  - EQ2MIX Input 2 Source */
+       { 0x0000088B, 0x0080 },    /* R2187  - EQ2MIX Input 2 Volume */
+       { 0x0000088C, 0x0000 },    /* R2188  - EQ2MIX Input 3 Source */
+       { 0x0000088D, 0x0080 },    /* R2189  - EQ2MIX Input 3 Volume */
+       { 0x0000088E, 0x0000 },    /* R2190  - EQ2MIX Input 4 Source */
+       { 0x0000088F, 0x0080 },    /* R2191  - EQ2MIX Input 4 Volume */
+       { 0x00000890, 0x0000 },    /* R2192  - EQ3MIX Input 1 Source */
+       { 0x00000891, 0x0080 },    /* R2193  - EQ3MIX Input 1 Volume */
+       { 0x00000892, 0x0000 },    /* R2194  - EQ3MIX Input 2 Source */
+       { 0x00000893, 0x0080 },    /* R2195  - EQ3MIX Input 2 Volume */
+       { 0x00000894, 0x0000 },    /* R2196  - EQ3MIX Input 3 Source */
+       { 0x00000895, 0x0080 },    /* R2197  - EQ3MIX Input 3 Volume */
+       { 0x00000896, 0x0000 },    /* R2198  - EQ3MIX Input 4 Source */
+       { 0x00000897, 0x0080 },    /* R2199  - EQ3MIX Input 4 Volume */
+       { 0x00000898, 0x0000 },    /* R2200  - EQ4MIX Input 1 Source */
+       { 0x00000899, 0x0080 },    /* R2201  - EQ4MIX Input 1 Volume */
+       { 0x0000089A, 0x0000 },    /* R2202  - EQ4MIX Input 2 Source */
+       { 0x0000089B, 0x0080 },    /* R2203  - EQ4MIX Input 2 Volume */
+       { 0x0000089C, 0x0000 },    /* R2204  - EQ4MIX Input 3 Source */
+       { 0x0000089D, 0x0080 },    /* R2205  - EQ4MIX Input 3 Volume */
+       { 0x0000089E, 0x0000 },    /* R2206  - EQ4MIX Input 4 Source */
+       { 0x0000089F, 0x0080 },    /* R2207  - EQ4MIX Input 4 Volume */
+       { 0x000008C0, 0x0000 },    /* R2240  - DRC1LMIX Input 1 Source */
+       { 0x000008C1, 0x0080 },    /* R2241  - DRC1LMIX Input 1 Volume */
+       { 0x000008C2, 0x0000 },    /* R2242  - DRC1LMIX Input 2 Source */
+       { 0x000008C3, 0x0080 },    /* R2243  - DRC1LMIX Input 2 Volume */
+       { 0x000008C4, 0x0000 },    /* R2244  - DRC1LMIX Input 3 Source */
+       { 0x000008C5, 0x0080 },    /* R2245  - DRC1LMIX Input 3 Volume */
+       { 0x000008C6, 0x0000 },    /* R2246  - DRC1LMIX Input 4 Source */
+       { 0x000008C7, 0x0080 },    /* R2247  - DRC1LMIX Input 4 Volume */
+       { 0x000008C8, 0x0000 },    /* R2248  - DRC1RMIX Input 1 Source */
+       { 0x000008C9, 0x0080 },    /* R2249  - DRC1RMIX Input 1 Volume */
+       { 0x000008CA, 0x0000 },    /* R2250  - DRC1RMIX Input 2 Source */
+       { 0x000008CB, 0x0080 },    /* R2251  - DRC1RMIX Input 2 Volume */
+       { 0x000008CC, 0x0000 },    /* R2252  - DRC1RMIX Input 3 Source */
+       { 0x000008CD, 0x0080 },    /* R2253  - DRC1RMIX Input 3 Volume */
+       { 0x000008CE, 0x0000 },    /* R2254  - DRC1RMIX Input 4 Source */
+       { 0x000008CF, 0x0080 },    /* R2255  - DRC1RMIX Input 4 Volume */
+       { 0x00000900, 0x0000 },    /* R2304  - HPLP1MIX Input 1 Source */
+       { 0x00000901, 0x0080 },    /* R2305  - HPLP1MIX Input 1 Volume */
+       { 0x00000902, 0x0000 },    /* R2306  - HPLP1MIX Input 2 Source */
+       { 0x00000903, 0x0080 },    /* R2307  - HPLP1MIX Input 2 Volume */
+       { 0x00000904, 0x0000 },    /* R2308  - HPLP1MIX Input 3 Source */
+       { 0x00000905, 0x0080 },    /* R2309  - HPLP1MIX Input 3 Volume */
+       { 0x00000906, 0x0000 },    /* R2310  - HPLP1MIX Input 4 Source */
+       { 0x00000907, 0x0080 },    /* R2311  - HPLP1MIX Input 4 Volume */
+       { 0x00000908, 0x0000 },    /* R2312  - HPLP2MIX Input 1 Source */
+       { 0x00000909, 0x0080 },    /* R2313  - HPLP2MIX Input 1 Volume */
+       { 0x0000090A, 0x0000 },    /* R2314  - HPLP2MIX Input 2 Source */
+       { 0x0000090B, 0x0080 },    /* R2315  - HPLP2MIX Input 2 Volume */
+       { 0x0000090C, 0x0000 },    /* R2316  - HPLP2MIX Input 3 Source */
+       { 0x0000090D, 0x0080 },    /* R2317  - HPLP2MIX Input 3 Volume */
+       { 0x0000090E, 0x0000 },    /* R2318  - HPLP2MIX Input 4 Source */
+       { 0x0000090F, 0x0080 },    /* R2319  - HPLP2MIX Input 4 Volume */
+       { 0x00000910, 0x0000 },    /* R2320  - HPLP3MIX Input 1 Source */
+       { 0x00000911, 0x0080 },    /* R2321  - HPLP3MIX Input 1 Volume */
+       { 0x00000912, 0x0000 },    /* R2322  - HPLP3MIX Input 2 Source */
+       { 0x00000913, 0x0080 },    /* R2323  - HPLP3MIX Input 2 Volume */
+       { 0x00000914, 0x0000 },    /* R2324  - HPLP3MIX Input 3 Source */
+       { 0x00000915, 0x0080 },    /* R2325  - HPLP3MIX Input 3 Volume */
+       { 0x00000916, 0x0000 },    /* R2326  - HPLP3MIX Input 4 Source */
+       { 0x00000917, 0x0080 },    /* R2327  - HPLP3MIX Input 4 Volume */
+       { 0x00000918, 0x0000 },    /* R2328  - HPLP4MIX Input 1 Source */
+       { 0x00000919, 0x0080 },    /* R2329  - HPLP4MIX Input 1 Volume */
+       { 0x0000091A, 0x0000 },    /* R2330  - HPLP4MIX Input 2 Source */
+       { 0x0000091B, 0x0080 },    /* R2331  - HPLP4MIX Input 2 Volume */
+       { 0x0000091C, 0x0000 },    /* R2332  - HPLP4MIX Input 3 Source */
+       { 0x0000091D, 0x0080 },    /* R2333  - HPLP4MIX Input 3 Volume */
+       { 0x0000091E, 0x0000 },    /* R2334  - HPLP4MIX Input 4 Source */
+       { 0x0000091F, 0x0080 },    /* R2335  - HPLP4MIX Input 4 Volume */
+       { 0x00000B00, 0x0000 },    /* R2816  - ISRC1DEC1MIX Input 1 Source */
+       { 0x00000B08, 0x0000 },    /* R2824  - ISRC1DEC2MIX Input 1 Source */
+       { 0x00000B20, 0x0000 },    /* R2848  - ISRC1INT1MIX Input 1 Source */
+       { 0x00000B28, 0x0000 },    /* R2856  - ISRC1INT2MIX Input 1 Source */
+       { 0x00000B40, 0x0000 },    /* R2880  - ISRC2DEC1MIX Input 1 Source */
+       { 0x00000B48, 0x0000 },    /* R2888  - ISRC2DEC2MIX Input 1 Source */
+       { 0x00000B60, 0x0000 },    /* R2912  - ISRC2INT1MIX Input 1 Source */
+       { 0x00000B68, 0x0000 },    /* R2920  - ISRC2INT2MIX Input 1 Source */
+       { 0x00000C00, 0xA101 },    /* R3072  - GPIO1 CTRL */
+       { 0x00000C01, 0xA101 },    /* R3073  - GPIO2 CTRL */
+       { 0x00000C02, 0xA101 },    /* R3074  - GPIO3 CTRL */
+       { 0x00000C03, 0xA101 },    /* R3075  - GPIO4 CTRL */
+       { 0x00000C04, 0xA101 },    /* R3076  - GPIO5 CTRL */
+       { 0x00000C0F, 0x0400 },    /* R3087  - IRQ CTRL 1 */
+       { 0x00000C10, 0x1000 },    /* R3088  - GPIO Debounce Config */
+       { 0x00000C20, 0x8002 },    /* R3104  - Misc Pad Ctrl 1 */
+       { 0x00000C21, 0x0001 },    /* R3105  - Misc Pad Ctrl 2 */
+       { 0x00000C22, 0x0000 },    /* R3106  - Misc Pad Ctrl 3 */
+       { 0x00000C23, 0x0000 },    /* R3107  - Misc Pad Ctrl 4 */
+       { 0x00000C24, 0x0000 },    /* R3108  - Misc Pad Ctrl 5 */
+       { 0x00000D08, 0xFFFF },    /* R3336  - Interrupt Status 1 Mask */
+       { 0x00000D0A, 0xFFFF },    /* R3338  - Interrupt Status 3 Mask */
+       { 0x00000D0B, 0xFFFF },    /* R3339  - Interrupt Status 4 Mask */
+       { 0x00000D0C, 0xFEFF },    /* R3340  - Interrupt Status 5 Mask */
+       { 0x00000D0F, 0x0000 },    /* R3343  - Interrupt Control */
+       { 0x00000D18, 0xFFFF },    /* R3352  - IRQ2 Status 1 Mask */
+       { 0x00000D1A, 0xFFFF },    /* R3354  - IRQ2 Status 3 Mask */
+       { 0x00000D1B, 0xFFFF },    /* R3355  - IRQ2 Status 4 Mask */
+       { 0x00000D1C, 0xFFFF },    /* R3356  - IRQ2 Status 5 Mask */
+       { 0x00000D1F, 0x0000 },    /* R3359  - IRQ2 Control */
+       { 0x00000D53, 0xFFFF },    /* R3411  - AOD IRQ Mask IRQ1 */
+       { 0x00000D54, 0xFFFF },    /* R3412  - AOD IRQ Mask IRQ2 */
+       { 0x00000D56, 0x0000 },    /* R3414  - Jack detect debounce */
+       { 0x00000E00, 0x0000 },    /* R3584  - FX_Ctrl1 */
+       { 0x00000E01, 0x0000 },    /* R3585  - FX_Ctrl2 */
+       { 0x00000E10, 0x6318 },    /* R3600  - EQ1_1 */
+       { 0x00000E11, 0x6300 },    /* R3601  - EQ1_2 */
+       { 0x00000E12, 0x0FC8 },    /* R3602  - EQ1_3 */
+       { 0x00000E13, 0x03FE },    /* R3603  - EQ1_4 */
+       { 0x00000E14, 0x00E0 },    /* R3604  - EQ1_5 */
+       { 0x00000E15, 0x1EC4 },    /* R3605  - EQ1_6 */
+       { 0x00000E16, 0xF136 },    /* R3606  - EQ1_7 */
+       { 0x00000E17, 0x0409 },    /* R3607  - EQ1_8 */
+       { 0x00000E18, 0x04CC },    /* R3608  - EQ1_9 */
+       { 0x00000E19, 0x1C9B },    /* R3609  - EQ1_10 */
+       { 0x00000E1A, 0xF337 },    /* R3610  - EQ1_11 */
+       { 0x00000E1B, 0x040B },    /* R3611  - EQ1_12 */
+       { 0x00000E1C, 0x0CBB },    /* R3612  - EQ1_13 */
+       { 0x00000E1D, 0x16F8 },    /* R3613  - EQ1_14 */
+       { 0x00000E1E, 0xF7D9 },    /* R3614  - EQ1_15 */
+       { 0x00000E1F, 0x040A },    /* R3615  - EQ1_16 */
+       { 0x00000E20, 0x1F14 },    /* R3616  - EQ1_17 */
+       { 0x00000E21, 0x058C },    /* R3617  - EQ1_18 */
+       { 0x00000E22, 0x0563 },    /* R3618  - EQ1_19 */
+       { 0x00000E23, 0x4000 },    /* R3619  - EQ1_20 */
+       { 0x00000E24, 0x0B75 },    /* R3620  - EQ1_21 */
+       { 0x00000E26, 0x6318 },    /* R3622  - EQ2_1 */
+       { 0x00000E27, 0x6300 },    /* R3623  - EQ2_2 */
+       { 0x00000E28, 0x0FC8 },    /* R3624  - EQ2_3 */
+       { 0x00000E29, 0x03FE },    /* R3625  - EQ2_4 */
+       { 0x00000E2A, 0x00E0 },    /* R3626  - EQ2_5 */
+       { 0x00000E2B, 0x1EC4 },    /* R3627  - EQ2_6 */
+       { 0x00000E2C, 0xF136 },    /* R3628  - EQ2_7 */
+       { 0x00000E2D, 0x0409 },    /* R3629  - EQ2_8 */
+       { 0x00000E2E, 0x04CC },    /* R3630  - EQ2_9 */
+       { 0x00000E2F, 0x1C9B },    /* R3631  - EQ2_10 */
+       { 0x00000E30, 0xF337 },    /* R3632  - EQ2_11 */
+       { 0x00000E31, 0x040B },    /* R3633  - EQ2_12 */
+       { 0x00000E32, 0x0CBB },    /* R3634  - EQ2_13 */
+       { 0x00000E33, 0x16F8 },    /* R3635  - EQ2_14 */
+       { 0x00000E34, 0xF7D9 },    /* R3636  - EQ2_15 */
+       { 0x00000E35, 0x040A },    /* R3637  - EQ2_16 */
+       { 0x00000E36, 0x1F14 },    /* R3638  - EQ2_17 */
+       { 0x00000E37, 0x058C },    /* R3639  - EQ2_18 */
+       { 0x00000E38, 0x0563 },    /* R3640  - EQ2_19 */
+       { 0x00000E39, 0x4000 },    /* R3641  - EQ2_20 */
+       { 0x00000E3A, 0x0B75 },    /* R3642  - EQ2_21 */
+       { 0x00000E3C, 0x6318 },    /* R3644  - EQ3_1 */
+       { 0x00000E3D, 0x6300 },    /* R3645  - EQ3_2 */
+       { 0x00000E3E, 0x0FC8 },    /* R3646  - EQ3_3 */
+       { 0x00000E3F, 0x03FE },    /* R3647  - EQ3_4 */
+       { 0x00000E40, 0x00E0 },    /* R3648  - EQ3_5 */
+       { 0x00000E41, 0x1EC4 },    /* R3649  - EQ3_6 */
+       { 0x00000E42, 0xF136 },    /* R3650  - EQ3_7 */
+       { 0x00000E43, 0x0409 },    /* R3651  - EQ3_8 */
+       { 0x00000E44, 0x04CC },    /* R3652  - EQ3_9 */
+       { 0x00000E45, 0x1C9B },    /* R3653  - EQ3_10 */
+       { 0x00000E46, 0xF337 },    /* R3654  - EQ3_11 */
+       { 0x00000E47, 0x040B },    /* R3655  - EQ3_12 */
+       { 0x00000E48, 0x0CBB },    /* R3656  - EQ3_13 */
+       { 0x00000E49, 0x16F8 },    /* R3657  - EQ3_14 */
+       { 0x00000E4A, 0xF7D9 },    /* R3658  - EQ3_15 */
+       { 0x00000E4B, 0x040A },    /* R3659  - EQ3_16 */
+       { 0x00000E4C, 0x1F14 },    /* R3660  - EQ3_17 */
+       { 0x00000E4D, 0x058C },    /* R3661  - EQ3_18 */
+       { 0x00000E4E, 0x0563 },    /* R3662  - EQ3_19 */
+       { 0x00000E4F, 0x4000 },    /* R3663  - EQ3_20 */
+       { 0x00000E50, 0x0B75 },    /* R3664  - EQ3_21 */
+       { 0x00000E52, 0x6318 },    /* R3666  - EQ4_1 */
+       { 0x00000E53, 0x6300 },    /* R3667  - EQ4_2 */
+       { 0x00000E54, 0x0FC8 },    /* R3668  - EQ4_3 */
+       { 0x00000E55, 0x03FE },    /* R3669  - EQ4_4 */
+       { 0x00000E56, 0x00E0 },    /* R3670  - EQ4_5 */
+       { 0x00000E57, 0x1EC4 },    /* R3671  - EQ4_6 */
+       { 0x00000E58, 0xF136 },    /* R3672  - EQ4_7 */
+       { 0x00000E59, 0x0409 },    /* R3673  - EQ4_8 */
+       { 0x00000E5A, 0x04CC },    /* R3674  - EQ4_9 */
+       { 0x00000E5B, 0x1C9B },    /* R3675  - EQ4_10 */
+       { 0x00000E5C, 0xF337 },    /* R3676  - EQ4_11 */
+       { 0x00000E5D, 0x040B },    /* R3677  - EQ4_12 */
+       { 0x00000E5E, 0x0CBB },    /* R3678  - EQ4_13 */
+       { 0x00000E5F, 0x16F8 },    /* R3679  - EQ4_14 */
+       { 0x00000E60, 0xF7D9 },    /* R3680  - EQ4_15 */
+       { 0x00000E61, 0x040A },    /* R3681  - EQ4_16 */
+       { 0x00000E62, 0x1F14 },    /* R3682  - EQ4_17 */
+       { 0x00000E63, 0x058C },    /* R3683  - EQ4_18 */
+       { 0x00000E64, 0x0563 },    /* R3684  - EQ4_19 */
+       { 0x00000E65, 0x4000 },    /* R3685  - EQ4_20 */
+       { 0x00000E66, 0x0B75 },    /* R3686  - EQ4_21 */
+       { 0x00000E80, 0x0018 },    /* R3712  - DRC1 ctrl1 */
+       { 0x00000E81, 0x0933 },    /* R3713  - DRC1 ctrl2 */
+       { 0x00000E82, 0x0018 },    /* R3714  - DRC1 ctrl3 */
+       { 0x00000E83, 0x0000 },    /* R3715  - DRC1 ctrl4 */
+       { 0x00000E84, 0x0000 },    /* R3716  - DRC1 ctrl5 */
+       { 0x00000EC0, 0x0000 },    /* R3776  - HPLPF1_1 */
+       { 0x00000EC1, 0x0000 },    /* R3777  - HPLPF1_2 */
+       { 0x00000EC4, 0x0000 },    /* R3780  - HPLPF2_1 */
+       { 0x00000EC5, 0x0000 },    /* R3781  - HPLPF2_2 */
+       { 0x00000EC8, 0x0000 },    /* R3784  - HPLPF3_1 */
+       { 0x00000EC9, 0x0000 },    /* R3785  - HPLPF3_2 */
+       { 0x00000ECC, 0x0000 },    /* R3788  - HPLPF4_1 */
+       { 0x00000ECD, 0x0000 },    /* R3789  - HPLPF4_2 */
+       { 0x00000EF0, 0x0000 },    /* R3824  - ISRC 1 CTRL 1 */
+       { 0x00000EF1, 0x0000 },    /* R3825  - ISRC 1 CTRL 2 */
+       { 0x00000EF2, 0x0000 },    /* R3826  - ISRC 1 CTRL 3 */
+       { 0x00000EF3, 0x0000 },    /* R3827  - ISRC 2 CTRL 1 */
+       { 0x00000EF4, 0x0000 },    /* R3828  - ISRC 2 CTRL 2 */
+       { 0x00000EF5, 0x0000 },    /* R3829  - ISRC 2 CTRL 3 */
+       { 0x00001100, 0x0010 },    /* R4352  - DSP1 Control 1 */
+       { 0x00001101, 0x0000 },    /* R4353  - DSP1 Clocking 1 */
+};
+
+static bool wm8997_readable_register(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case ARIZONA_SOFTWARE_RESET:
+       case ARIZONA_DEVICE_REVISION:
+       case ARIZONA_CTRL_IF_I2C1_CFG_1:
+       case ARIZONA_WRITE_SEQUENCER_CTRL_0:
+       case ARIZONA_WRITE_SEQUENCER_CTRL_1:
+       case ARIZONA_WRITE_SEQUENCER_CTRL_2:
+       case ARIZONA_TONE_GENERATOR_1:
+       case ARIZONA_TONE_GENERATOR_2:
+       case ARIZONA_TONE_GENERATOR_3:
+       case ARIZONA_TONE_GENERATOR_4:
+       case ARIZONA_TONE_GENERATOR_5:
+       case ARIZONA_PWM_DRIVE_1:
+       case ARIZONA_PWM_DRIVE_2:
+       case ARIZONA_PWM_DRIVE_3:
+       case ARIZONA_WAKE_CONTROL:
+       case ARIZONA_SEQUENCE_CONTROL:
+       case ARIZONA_SAMPLE_RATE_SEQUENCE_SELECT_1:
+       case ARIZONA_SAMPLE_RATE_SEQUENCE_SELECT_2:
+       case ARIZONA_SAMPLE_RATE_SEQUENCE_SELECT_3:
+       case ARIZONA_SAMPLE_RATE_SEQUENCE_SELECT_4:
+       case ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_1:
+       case ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_2:
+       case ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_3:
+       case ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_4:
+       case ARIZONA_COMFORT_NOISE_GENERATOR:
+       case ARIZONA_HAPTICS_CONTROL_1:
+       case ARIZONA_HAPTICS_CONTROL_2:
+       case ARIZONA_HAPTICS_PHASE_1_INTENSITY:
+       case ARIZONA_HAPTICS_PHASE_1_DURATION:
+       case ARIZONA_HAPTICS_PHASE_2_INTENSITY:
+       case ARIZONA_HAPTICS_PHASE_2_DURATION:
+       case ARIZONA_HAPTICS_PHASE_3_INTENSITY:
+       case ARIZONA_HAPTICS_PHASE_3_DURATION:
+       case ARIZONA_HAPTICS_STATUS:
+       case ARIZONA_CLOCK_32K_1:
+       case ARIZONA_SYSTEM_CLOCK_1:
+       case ARIZONA_SAMPLE_RATE_1:
+       case ARIZONA_SAMPLE_RATE_2:
+       case ARIZONA_SAMPLE_RATE_3:
+       case ARIZONA_SAMPLE_RATE_1_STATUS:
+       case ARIZONA_SAMPLE_RATE_2_STATUS:
+       case ARIZONA_SAMPLE_RATE_3_STATUS:
+       case ARIZONA_ASYNC_CLOCK_1:
+       case ARIZONA_ASYNC_SAMPLE_RATE_1:
+       case ARIZONA_ASYNC_SAMPLE_RATE_1_STATUS:
+       case ARIZONA_OUTPUT_SYSTEM_CLOCK:
+       case ARIZONA_OUTPUT_ASYNC_CLOCK:
+       case ARIZONA_RATE_ESTIMATOR_1:
+       case ARIZONA_RATE_ESTIMATOR_2:
+       case ARIZONA_RATE_ESTIMATOR_3:
+       case ARIZONA_RATE_ESTIMATOR_4:
+       case ARIZONA_RATE_ESTIMATOR_5:
+       case ARIZONA_FLL1_CONTROL_1:
+       case ARIZONA_FLL1_CONTROL_2:
+       case ARIZONA_FLL1_CONTROL_3:
+       case ARIZONA_FLL1_CONTROL_4:
+       case ARIZONA_FLL1_CONTROL_5:
+       case ARIZONA_FLL1_CONTROL_6:
+       case ARIZONA_FLL1_LOOP_FILTER_TEST_1:
+       case ARIZONA_FLL1_NCO_TEST_0:
+       case ARIZONA_FLL1_SYNCHRONISER_1:
+       case ARIZONA_FLL1_SYNCHRONISER_2:
+       case ARIZONA_FLL1_SYNCHRONISER_3:
+       case ARIZONA_FLL1_SYNCHRONISER_4:
+       case ARIZONA_FLL1_SYNCHRONISER_5:
+       case ARIZONA_FLL1_SYNCHRONISER_6:
+       case ARIZONA_FLL1_SPREAD_SPECTRUM:
+       case ARIZONA_FLL1_GPIO_CLOCK:
+       case ARIZONA_FLL2_CONTROL_1:
+       case ARIZONA_FLL2_CONTROL_2:
+       case ARIZONA_FLL2_CONTROL_3:
+       case ARIZONA_FLL2_CONTROL_4:
+       case ARIZONA_FLL2_CONTROL_5:
+       case ARIZONA_FLL2_CONTROL_6:
+       case ARIZONA_FLL2_LOOP_FILTER_TEST_1:
+       case ARIZONA_FLL2_NCO_TEST_0:
+       case ARIZONA_FLL2_SYNCHRONISER_1:
+       case ARIZONA_FLL2_SYNCHRONISER_2:
+       case ARIZONA_FLL2_SYNCHRONISER_3:
+       case ARIZONA_FLL2_SYNCHRONISER_4:
+       case ARIZONA_FLL2_SYNCHRONISER_5:
+       case ARIZONA_FLL2_SYNCHRONISER_6:
+       case ARIZONA_FLL2_SPREAD_SPECTRUM:
+       case ARIZONA_FLL2_GPIO_CLOCK:
+       case ARIZONA_MIC_CHARGE_PUMP_1:
+       case ARIZONA_LDO1_CONTROL_1:
+       case ARIZONA_LDO2_CONTROL_1:
+       case ARIZONA_MIC_BIAS_CTRL_1:
+       case ARIZONA_MIC_BIAS_CTRL_2:
+       case ARIZONA_MIC_BIAS_CTRL_3:
+       case ARIZONA_ACCESSORY_DETECT_MODE_1:
+       case ARIZONA_HEADPHONE_DETECT_1:
+       case ARIZONA_HEADPHONE_DETECT_2:
+       case ARIZONA_MIC_DETECT_1:
+       case ARIZONA_MIC_DETECT_2:
+       case ARIZONA_MIC_DETECT_3:
+       case ARIZONA_MIC_NOISE_MIX_CONTROL_1:
+       case ARIZONA_ISOLATION_CONTROL:
+       case ARIZONA_JACK_DETECT_ANALOGUE:
+       case ARIZONA_INPUT_ENABLES:
+       case ARIZONA_INPUT_ENABLES_STATUS:
+       case ARIZONA_INPUT_RATE:
+       case ARIZONA_INPUT_VOLUME_RAMP:
+       case ARIZONA_IN1L_CONTROL:
+       case ARIZONA_ADC_DIGITAL_VOLUME_1L:
+       case ARIZONA_DMIC1L_CONTROL:
+       case ARIZONA_IN1R_CONTROL:
+       case ARIZONA_ADC_DIGITAL_VOLUME_1R:
+       case ARIZONA_DMIC1R_CONTROL:
+       case ARIZONA_IN2L_CONTROL:
+       case ARIZONA_ADC_DIGITAL_VOLUME_2L:
+       case ARIZONA_DMIC2L_CONTROL:
+       case ARIZONA_IN2R_CONTROL:
+       case ARIZONA_ADC_DIGITAL_VOLUME_2R:
+       case ARIZONA_DMIC2R_CONTROL:
+       case ARIZONA_OUTPUT_ENABLES_1:
+       case ARIZONA_OUTPUT_STATUS_1:
+       case ARIZONA_RAW_OUTPUT_STATUS_1:
+       case ARIZONA_OUTPUT_RATE_1:
+       case ARIZONA_OUTPUT_VOLUME_RAMP:
+       case ARIZONA_OUTPUT_PATH_CONFIG_1L:
+       case ARIZONA_DAC_DIGITAL_VOLUME_1L:
+       case ARIZONA_DAC_VOLUME_LIMIT_1L:
+       case ARIZONA_NOISE_GATE_SELECT_1L:
+       case ARIZONA_OUTPUT_PATH_CONFIG_1R:
+       case ARIZONA_DAC_DIGITAL_VOLUME_1R:
+       case ARIZONA_DAC_VOLUME_LIMIT_1R:
+       case ARIZONA_NOISE_GATE_SELECT_1R:
+       case ARIZONA_OUTPUT_PATH_CONFIG_3L:
+       case ARIZONA_DAC_DIGITAL_VOLUME_3L:
+       case ARIZONA_DAC_VOLUME_LIMIT_3L:
+       case ARIZONA_NOISE_GATE_SELECT_3L:
+       case ARIZONA_OUTPUT_PATH_CONFIG_4L:
+       case ARIZONA_DAC_DIGITAL_VOLUME_4L:
+       case ARIZONA_OUT_VOLUME_4L:
+       case ARIZONA_NOISE_GATE_SELECT_4L:
+       case ARIZONA_OUTPUT_PATH_CONFIG_5L:
+       case ARIZONA_DAC_DIGITAL_VOLUME_5L:
+       case ARIZONA_DAC_VOLUME_LIMIT_5L:
+       case ARIZONA_NOISE_GATE_SELECT_5L:
+       case ARIZONA_DAC_DIGITAL_VOLUME_5R:
+       case ARIZONA_DAC_VOLUME_LIMIT_5R:
+       case ARIZONA_NOISE_GATE_SELECT_5R:
+       case ARIZONA_DAC_AEC_CONTROL_1:
+       case ARIZONA_NOISE_GATE_CONTROL:
+       case ARIZONA_PDM_SPK1_CTRL_1:
+       case ARIZONA_PDM_SPK1_CTRL_2:
+       case ARIZONA_AIF1_BCLK_CTRL:
+       case ARIZONA_AIF1_TX_PIN_CTRL:
+       case ARIZONA_AIF1_RX_PIN_CTRL:
+       case ARIZONA_AIF1_RATE_CTRL:
+       case ARIZONA_AIF1_FORMAT:
+       case ARIZONA_AIF1_TX_BCLK_RATE:
+       case ARIZONA_AIF1_RX_BCLK_RATE:
+       case ARIZONA_AIF1_FRAME_CTRL_1:
+       case ARIZONA_AIF1_FRAME_CTRL_2:
+       case ARIZONA_AIF1_FRAME_CTRL_3:
+       case ARIZONA_AIF1_FRAME_CTRL_4:
+       case ARIZONA_AIF1_FRAME_CTRL_5:
+       case ARIZONA_AIF1_FRAME_CTRL_6:
+       case ARIZONA_AIF1_FRAME_CTRL_7:
+       case ARIZONA_AIF1_FRAME_CTRL_8:
+       case ARIZONA_AIF1_FRAME_CTRL_9:
+       case ARIZONA_AIF1_FRAME_CTRL_10:
+       case ARIZONA_AIF1_FRAME_CTRL_11:
+       case ARIZONA_AIF1_FRAME_CTRL_12:
+       case ARIZONA_AIF1_FRAME_CTRL_13:
+       case ARIZONA_AIF1_FRAME_CTRL_14:
+       case ARIZONA_AIF1_FRAME_CTRL_15:
+       case ARIZONA_AIF1_FRAME_CTRL_16:
+       case ARIZONA_AIF1_FRAME_CTRL_17:
+       case ARIZONA_AIF1_FRAME_CTRL_18:
+       case ARIZONA_AIF1_TX_ENABLES:
+       case ARIZONA_AIF1_RX_ENABLES:
+       case ARIZONA_AIF2_BCLK_CTRL:
+       case ARIZONA_AIF2_TX_PIN_CTRL:
+       case ARIZONA_AIF2_RX_PIN_CTRL:
+       case ARIZONA_AIF2_RATE_CTRL:
+       case ARIZONA_AIF2_FORMAT:
+       case ARIZONA_AIF2_TX_BCLK_RATE:
+       case ARIZONA_AIF2_RX_BCLK_RATE:
+       case ARIZONA_AIF2_FRAME_CTRL_1:
+       case ARIZONA_AIF2_FRAME_CTRL_2:
+       case ARIZONA_AIF2_FRAME_CTRL_3:
+       case ARIZONA_AIF2_FRAME_CTRL_4:
+       case ARIZONA_AIF2_FRAME_CTRL_11:
+       case ARIZONA_AIF2_FRAME_CTRL_12:
+       case ARIZONA_AIF2_TX_ENABLES:
+       case ARIZONA_AIF2_RX_ENABLES:
+       case ARIZONA_SLIMBUS_FRAMER_REF_GEAR:
+       case ARIZONA_SLIMBUS_RATES_1:
+       case ARIZONA_SLIMBUS_RATES_2:
+       case ARIZONA_SLIMBUS_RATES_3:
+       case ARIZONA_SLIMBUS_RATES_4:
+       case ARIZONA_SLIMBUS_RATES_5:
+       case ARIZONA_SLIMBUS_RATES_6:
+       case ARIZONA_SLIMBUS_RATES_7:
+       case ARIZONA_SLIMBUS_RATES_8:
+       case ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE:
+       case ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE:
+       case ARIZONA_SLIMBUS_RX_PORT_STATUS:
+       case ARIZONA_SLIMBUS_TX_PORT_STATUS:
+       case ARIZONA_PWM1MIX_INPUT_1_SOURCE:
+       case ARIZONA_PWM1MIX_INPUT_1_VOLUME:
+       case ARIZONA_PWM1MIX_INPUT_2_SOURCE:
+       case ARIZONA_PWM1MIX_INPUT_2_VOLUME:
+       case ARIZONA_PWM1MIX_INPUT_3_SOURCE:
+       case ARIZONA_PWM1MIX_INPUT_3_VOLUME:
+       case ARIZONA_PWM1MIX_INPUT_4_SOURCE:
+       case ARIZONA_PWM1MIX_INPUT_4_VOLUME:
+       case ARIZONA_PWM2MIX_INPUT_1_SOURCE:
+       case ARIZONA_PWM2MIX_INPUT_1_VOLUME:
+       case ARIZONA_PWM2MIX_INPUT_2_SOURCE:
+       case ARIZONA_PWM2MIX_INPUT_2_VOLUME:
+       case ARIZONA_PWM2MIX_INPUT_3_SOURCE:
+       case ARIZONA_PWM2MIX_INPUT_3_VOLUME:
+       case ARIZONA_PWM2MIX_INPUT_4_SOURCE:
+       case ARIZONA_PWM2MIX_INPUT_4_VOLUME:
+       case ARIZONA_MICMIX_INPUT_1_SOURCE:
+       case ARIZONA_MICMIX_INPUT_1_VOLUME:
+       case ARIZONA_MICMIX_INPUT_2_SOURCE:
+       case ARIZONA_MICMIX_INPUT_2_VOLUME:
+       case ARIZONA_MICMIX_INPUT_3_SOURCE:
+       case ARIZONA_MICMIX_INPUT_3_VOLUME:
+       case ARIZONA_MICMIX_INPUT_4_SOURCE:
+       case ARIZONA_MICMIX_INPUT_4_VOLUME:
+       case ARIZONA_NOISEMIX_INPUT_1_SOURCE:
+       case ARIZONA_NOISEMIX_INPUT_1_VOLUME:
+       case ARIZONA_NOISEMIX_INPUT_2_SOURCE:
+       case ARIZONA_NOISEMIX_INPUT_2_VOLUME:
+       case ARIZONA_NOISEMIX_INPUT_3_SOURCE:
+       case ARIZONA_NOISEMIX_INPUT_3_VOLUME:
+       case ARIZONA_NOISEMIX_INPUT_4_SOURCE:
+       case ARIZONA_NOISEMIX_INPUT_4_VOLUME:
+       case ARIZONA_OUT1LMIX_INPUT_1_SOURCE:
+       case ARIZONA_OUT1LMIX_INPUT_1_VOLUME:
+       case ARIZONA_OUT1LMIX_INPUT_2_SOURCE:
+       case ARIZONA_OUT1LMIX_INPUT_2_VOLUME:
+       case ARIZONA_OUT1LMIX_INPUT_3_SOURCE:
+       case ARIZONA_OUT1LMIX_INPUT_3_VOLUME:
+       case ARIZONA_OUT1LMIX_INPUT_4_SOURCE:
+       case ARIZONA_OUT1LMIX_INPUT_4_VOLUME:
+       case ARIZONA_OUT1RMIX_INPUT_1_SOURCE:
+       case ARIZONA_OUT1RMIX_INPUT_1_VOLUME:
+       case ARIZONA_OUT1RMIX_INPUT_2_SOURCE:
+       case ARIZONA_OUT1RMIX_INPUT_2_VOLUME:
+       case ARIZONA_OUT1RMIX_INPUT_3_SOURCE:
+       case ARIZONA_OUT1RMIX_INPUT_3_VOLUME:
+       case ARIZONA_OUT1RMIX_INPUT_4_SOURCE:
+       case ARIZONA_OUT1RMIX_INPUT_4_VOLUME:
+       case ARIZONA_OUT3LMIX_INPUT_1_SOURCE:
+       case ARIZONA_OUT3LMIX_INPUT_1_VOLUME:
+       case ARIZONA_OUT3LMIX_INPUT_2_SOURCE:
+       case ARIZONA_OUT3LMIX_INPUT_2_VOLUME:
+       case ARIZONA_OUT3LMIX_INPUT_3_SOURCE:
+       case ARIZONA_OUT3LMIX_INPUT_3_VOLUME:
+       case ARIZONA_OUT3LMIX_INPUT_4_SOURCE:
+       case ARIZONA_OUT3LMIX_INPUT_4_VOLUME:
+       case ARIZONA_OUT4LMIX_INPUT_1_SOURCE:
+       case ARIZONA_OUT4LMIX_INPUT_1_VOLUME:
+       case ARIZONA_OUT4LMIX_INPUT_2_SOURCE:
+       case ARIZONA_OUT4LMIX_INPUT_2_VOLUME:
+       case ARIZONA_OUT4LMIX_INPUT_3_SOURCE:
+       case ARIZONA_OUT4LMIX_INPUT_3_VOLUME:
+       case ARIZONA_OUT4LMIX_INPUT_4_SOURCE:
+       case ARIZONA_OUT4LMIX_INPUT_4_VOLUME:
+       case ARIZONA_OUT5LMIX_INPUT_1_SOURCE:
+       case ARIZONA_OUT5LMIX_INPUT_1_VOLUME:
+       case ARIZONA_OUT5LMIX_INPUT_2_SOURCE:
+       case ARIZONA_OUT5LMIX_INPUT_2_VOLUME:
+       case ARIZONA_OUT5LMIX_INPUT_3_SOURCE:
+       case ARIZONA_OUT5LMIX_INPUT_3_VOLUME:
+       case ARIZONA_OUT5LMIX_INPUT_4_SOURCE:
+       case ARIZONA_OUT5LMIX_INPUT_4_VOLUME:
+       case ARIZONA_OUT5RMIX_INPUT_1_SOURCE:
+       case ARIZONA_OUT5RMIX_INPUT_1_VOLUME:
+       case ARIZONA_OUT5RMIX_INPUT_2_SOURCE:
+       case ARIZONA_OUT5RMIX_INPUT_2_VOLUME:
+       case ARIZONA_OUT5RMIX_INPUT_3_SOURCE:
+       case ARIZONA_OUT5RMIX_INPUT_3_VOLUME:
+       case ARIZONA_OUT5RMIX_INPUT_4_SOURCE:
+       case ARIZONA_OUT5RMIX_INPUT_4_VOLUME:
+       case ARIZONA_AIF1TX1MIX_INPUT_1_SOURCE:
+       case ARIZONA_AIF1TX1MIX_INPUT_1_VOLUME:
+       case ARIZONA_AIF1TX1MIX_INPUT_2_SOURCE:
+       case ARIZONA_AIF1TX1MIX_INPUT_2_VOLUME:
+       case ARIZONA_AIF1TX1MIX_INPUT_3_SOURCE:
+       case ARIZONA_AIF1TX1MIX_INPUT_3_VOLUME:
+       case ARIZONA_AIF1TX1MIX_INPUT_4_SOURCE:
+       case ARIZONA_AIF1TX1MIX_INPUT_4_VOLUME:
+       case ARIZONA_AIF1TX2MIX_INPUT_1_SOURCE:
+       case ARIZONA_AIF1TX2MIX_INPUT_1_VOLUME:
+       case ARIZONA_AIF1TX2MIX_INPUT_2_SOURCE:
+       case ARIZONA_AIF1TX2MIX_INPUT_2_VOLUME:
+       case ARIZONA_AIF1TX2MIX_INPUT_3_SOURCE:
+       case ARIZONA_AIF1TX2MIX_INPUT_3_VOLUME:
+       case ARIZONA_AIF1TX2MIX_INPUT_4_SOURCE:
+       case ARIZONA_AIF1TX2MIX_INPUT_4_VOLUME:
+       case ARIZONA_AIF1TX3MIX_INPUT_1_SOURCE:
+       case ARIZONA_AIF1TX3MIX_INPUT_1_VOLUME:
+       case ARIZONA_AIF1TX3MIX_INPUT_2_SOURCE:
+       case ARIZONA_AIF1TX3MIX_INPUT_2_VOLUME:
+       case ARIZONA_AIF1TX3MIX_INPUT_3_SOURCE:
+       case ARIZONA_AIF1TX3MIX_INPUT_3_VOLUME:
+       case ARIZONA_AIF1TX3MIX_INPUT_4_SOURCE:
+       case ARIZONA_AIF1TX3MIX_INPUT_4_VOLUME:
+       case ARIZONA_AIF1TX4MIX_INPUT_1_SOURCE:
+       case ARIZONA_AIF1TX4MIX_INPUT_1_VOLUME:
+       case ARIZONA_AIF1TX4MIX_INPUT_2_SOURCE:
+       case ARIZONA_AIF1TX4MIX_INPUT_2_VOLUME:
+       case ARIZONA_AIF1TX4MIX_INPUT_3_SOURCE:
+       case ARIZONA_AIF1TX4MIX_INPUT_3_VOLUME:
+       case ARIZONA_AIF1TX4MIX_INPUT_4_SOURCE:
+       case ARIZONA_AIF1TX4MIX_INPUT_4_VOLUME:
+       case ARIZONA_AIF1TX5MIX_INPUT_1_SOURCE:
+       case ARIZONA_AIF1TX5MIX_INPUT_1_VOLUME:
+       case ARIZONA_AIF1TX5MIX_INPUT_2_SOURCE:
+       case ARIZONA_AIF1TX5MIX_INPUT_2_VOLUME:
+       case ARIZONA_AIF1TX5MIX_INPUT_3_SOURCE:
+       case ARIZONA_AIF1TX5MIX_INPUT_3_VOLUME:
+       case ARIZONA_AIF1TX5MIX_INPUT_4_SOURCE:
+       case ARIZONA_AIF1TX5MIX_INPUT_4_VOLUME:
+       case ARIZONA_AIF1TX6MIX_INPUT_1_SOURCE:
+       case ARIZONA_AIF1TX6MIX_INPUT_1_VOLUME:
+       case ARIZONA_AIF1TX6MIX_INPUT_2_SOURCE:
+       case ARIZONA_AIF1TX6MIX_INPUT_2_VOLUME:
+       case ARIZONA_AIF1TX6MIX_INPUT_3_SOURCE:
+       case ARIZONA_AIF1TX6MIX_INPUT_3_VOLUME:
+       case ARIZONA_AIF1TX6MIX_INPUT_4_SOURCE:
+       case ARIZONA_AIF1TX6MIX_INPUT_4_VOLUME:
+       case ARIZONA_AIF1TX7MIX_INPUT_1_SOURCE:
+       case ARIZONA_AIF1TX7MIX_INPUT_1_VOLUME:
+       case ARIZONA_AIF1TX7MIX_INPUT_2_SOURCE:
+       case ARIZONA_AIF1TX7MIX_INPUT_2_VOLUME:
+       case ARIZONA_AIF1TX7MIX_INPUT_3_SOURCE:
+       case ARIZONA_AIF1TX7MIX_INPUT_3_VOLUME:
+       case ARIZONA_AIF1TX7MIX_INPUT_4_SOURCE:
+       case ARIZONA_AIF1TX7MIX_INPUT_4_VOLUME:
+       case ARIZONA_AIF1TX8MIX_INPUT_1_SOURCE:
+       case ARIZONA_AIF1TX8MIX_INPUT_1_VOLUME:
+       case ARIZONA_AIF1TX8MIX_INPUT_2_SOURCE:
+       case ARIZONA_AIF1TX8MIX_INPUT_2_VOLUME:
+       case ARIZONA_AIF1TX8MIX_INPUT_3_SOURCE:
+       case ARIZONA_AIF1TX8MIX_INPUT_3_VOLUME:
+       case ARIZONA_AIF1TX8MIX_INPUT_4_SOURCE:
+       case ARIZONA_AIF1TX8MIX_INPUT_4_VOLUME:
+       case ARIZONA_AIF2TX1MIX_INPUT_1_SOURCE:
+       case ARIZONA_AIF2TX1MIX_INPUT_1_VOLUME:
+       case ARIZONA_AIF2TX1MIX_INPUT_2_SOURCE:
+       case ARIZONA_AIF2TX1MIX_INPUT_2_VOLUME:
+       case ARIZONA_AIF2TX1MIX_INPUT_3_SOURCE:
+       case ARIZONA_AIF2TX1MIX_INPUT_3_VOLUME:
+       case ARIZONA_AIF2TX1MIX_INPUT_4_SOURCE:
+       case ARIZONA_AIF2TX1MIX_INPUT_4_VOLUME:
+       case ARIZONA_AIF2TX2MIX_INPUT_1_SOURCE:
+       case ARIZONA_AIF2TX2MIX_INPUT_1_VOLUME:
+       case ARIZONA_AIF2TX2MIX_INPUT_2_SOURCE:
+       case ARIZONA_AIF2TX2MIX_INPUT_2_VOLUME:
+       case ARIZONA_AIF2TX2MIX_INPUT_3_SOURCE:
+       case ARIZONA_AIF2TX2MIX_INPUT_3_VOLUME:
+       case ARIZONA_AIF2TX2MIX_INPUT_4_SOURCE:
+       case ARIZONA_AIF2TX2MIX_INPUT_4_VOLUME:
+       case ARIZONA_SLIMTX1MIX_INPUT_1_SOURCE:
+       case ARIZONA_SLIMTX1MIX_INPUT_1_VOLUME:
+       case ARIZONA_SLIMTX1MIX_INPUT_2_SOURCE:
+       case ARIZONA_SLIMTX1MIX_INPUT_2_VOLUME:
+       case ARIZONA_SLIMTX1MIX_INPUT_3_SOURCE:
+       case ARIZONA_SLIMTX1MIX_INPUT_3_VOLUME:
+       case ARIZONA_SLIMTX1MIX_INPUT_4_SOURCE:
+       case ARIZONA_SLIMTX1MIX_INPUT_4_VOLUME:
+       case ARIZONA_SLIMTX2MIX_INPUT_1_SOURCE:
+       case ARIZONA_SLIMTX2MIX_INPUT_1_VOLUME:
+       case ARIZONA_SLIMTX2MIX_INPUT_2_SOURCE:
+       case ARIZONA_SLIMTX2MIX_INPUT_2_VOLUME:
+       case ARIZONA_SLIMTX2MIX_INPUT_3_SOURCE:
+       case ARIZONA_SLIMTX2MIX_INPUT_3_VOLUME:
+       case ARIZONA_SLIMTX2MIX_INPUT_4_SOURCE:
+       case ARIZONA_SLIMTX2MIX_INPUT_4_VOLUME:
+       case ARIZONA_SLIMTX3MIX_INPUT_1_SOURCE:
+       case ARIZONA_SLIMTX3MIX_INPUT_1_VOLUME:
+       case ARIZONA_SLIMTX3MIX_INPUT_2_SOURCE:
+       case ARIZONA_SLIMTX3MIX_INPUT_2_VOLUME:
+       case ARIZONA_SLIMTX3MIX_INPUT_3_SOURCE:
+       case ARIZONA_SLIMTX3MIX_INPUT_3_VOLUME:
+       case ARIZONA_SLIMTX3MIX_INPUT_4_SOURCE:
+       case ARIZONA_SLIMTX3MIX_INPUT_4_VOLUME:
+       case ARIZONA_SLIMTX4MIX_INPUT_1_SOURCE:
+       case ARIZONA_SLIMTX4MIX_INPUT_1_VOLUME:
+       case ARIZONA_SLIMTX4MIX_INPUT_2_SOURCE:
+       case ARIZONA_SLIMTX4MIX_INPUT_2_VOLUME:
+       case ARIZONA_SLIMTX4MIX_INPUT_3_SOURCE:
+       case ARIZONA_SLIMTX4MIX_INPUT_3_VOLUME:
+       case ARIZONA_SLIMTX4MIX_INPUT_4_SOURCE:
+       case ARIZONA_SLIMTX4MIX_INPUT_4_VOLUME:
+       case ARIZONA_SLIMTX5MIX_INPUT_1_SOURCE:
+       case ARIZONA_SLIMTX5MIX_INPUT_1_VOLUME:
+       case ARIZONA_SLIMTX5MIX_INPUT_2_SOURCE:
+       case ARIZONA_SLIMTX5MIX_INPUT_2_VOLUME:
+       case ARIZONA_SLIMTX5MIX_INPUT_3_SOURCE:
+       case ARIZONA_SLIMTX5MIX_INPUT_3_VOLUME:
+       case ARIZONA_SLIMTX5MIX_INPUT_4_SOURCE:
+       case ARIZONA_SLIMTX5MIX_INPUT_4_VOLUME:
+       case ARIZONA_SLIMTX6MIX_INPUT_1_SOURCE:
+       case ARIZONA_SLIMTX6MIX_INPUT_1_VOLUME:
+       case ARIZONA_SLIMTX6MIX_INPUT_2_SOURCE:
+       case ARIZONA_SLIMTX6MIX_INPUT_2_VOLUME:
+       case ARIZONA_SLIMTX6MIX_INPUT_3_SOURCE:
+       case ARIZONA_SLIMTX6MIX_INPUT_3_VOLUME:
+       case ARIZONA_SLIMTX6MIX_INPUT_4_SOURCE:
+       case ARIZONA_SLIMTX6MIX_INPUT_4_VOLUME:
+       case ARIZONA_SLIMTX7MIX_INPUT_1_SOURCE:
+       case ARIZONA_SLIMTX7MIX_INPUT_1_VOLUME:
+       case ARIZONA_SLIMTX7MIX_INPUT_2_SOURCE:
+       case ARIZONA_SLIMTX7MIX_INPUT_2_VOLUME:
+       case ARIZONA_SLIMTX7MIX_INPUT_3_SOURCE:
+       case ARIZONA_SLIMTX7MIX_INPUT_3_VOLUME:
+       case ARIZONA_SLIMTX7MIX_INPUT_4_SOURCE:
+       case ARIZONA_SLIMTX7MIX_INPUT_4_VOLUME:
+       case ARIZONA_SLIMTX8MIX_INPUT_1_SOURCE:
+       case ARIZONA_SLIMTX8MIX_INPUT_1_VOLUME:
+       case ARIZONA_SLIMTX8MIX_INPUT_2_SOURCE:
+       case ARIZONA_SLIMTX8MIX_INPUT_2_VOLUME:
+       case ARIZONA_SLIMTX8MIX_INPUT_3_SOURCE:
+       case ARIZONA_SLIMTX8MIX_INPUT_3_VOLUME:
+       case ARIZONA_SLIMTX8MIX_INPUT_4_SOURCE:
+       case ARIZONA_SLIMTX8MIX_INPUT_4_VOLUME:
+       case ARIZONA_EQ1MIX_INPUT_1_SOURCE:
+       case ARIZONA_EQ1MIX_INPUT_1_VOLUME:
+       case ARIZONA_EQ1MIX_INPUT_2_SOURCE:
+       case ARIZONA_EQ1MIX_INPUT_2_VOLUME:
+       case ARIZONA_EQ1MIX_INPUT_3_SOURCE:
+       case ARIZONA_EQ1MIX_INPUT_3_VOLUME:
+       case ARIZONA_EQ1MIX_INPUT_4_SOURCE:
+       case ARIZONA_EQ1MIX_INPUT_4_VOLUME:
+       case ARIZONA_EQ2MIX_INPUT_1_SOURCE:
+       case ARIZONA_EQ2MIX_INPUT_1_VOLUME:
+       case ARIZONA_EQ2MIX_INPUT_2_SOURCE:
+       case ARIZONA_EQ2MIX_INPUT_2_VOLUME:
+       case ARIZONA_EQ2MIX_INPUT_3_SOURCE:
+       case ARIZONA_EQ2MIX_INPUT_3_VOLUME:
+       case ARIZONA_EQ2MIX_INPUT_4_SOURCE:
+       case ARIZONA_EQ2MIX_INPUT_4_VOLUME:
+       case ARIZONA_EQ3MIX_INPUT_1_SOURCE:
+       case ARIZONA_EQ3MIX_INPUT_1_VOLUME:
+       case ARIZONA_EQ3MIX_INPUT_2_SOURCE:
+       case ARIZONA_EQ3MIX_INPUT_2_VOLUME:
+       case ARIZONA_EQ3MIX_INPUT_3_SOURCE:
+       case ARIZONA_EQ3MIX_INPUT_3_VOLUME:
+       case ARIZONA_EQ3MIX_INPUT_4_SOURCE:
+       case ARIZONA_EQ3MIX_INPUT_4_VOLUME:
+       case ARIZONA_EQ4MIX_INPUT_1_SOURCE:
+       case ARIZONA_EQ4MIX_INPUT_1_VOLUME:
+       case ARIZONA_EQ4MIX_INPUT_2_SOURCE:
+       case ARIZONA_EQ4MIX_INPUT_2_VOLUME:
+       case ARIZONA_EQ4MIX_INPUT_3_SOURCE:
+       case ARIZONA_EQ4MIX_INPUT_3_VOLUME:
+       case ARIZONA_EQ4MIX_INPUT_4_SOURCE:
+       case ARIZONA_EQ4MIX_INPUT_4_VOLUME:
+       case ARIZONA_DRC1LMIX_INPUT_1_SOURCE:
+       case ARIZONA_DRC1LMIX_INPUT_1_VOLUME:
+       case ARIZONA_DRC1LMIX_INPUT_2_SOURCE:
+       case ARIZONA_DRC1LMIX_INPUT_2_VOLUME:
+       case ARIZONA_DRC1LMIX_INPUT_3_SOURCE:
+       case ARIZONA_DRC1LMIX_INPUT_3_VOLUME:
+       case ARIZONA_DRC1LMIX_INPUT_4_SOURCE:
+       case ARIZONA_DRC1LMIX_INPUT_4_VOLUME:
+       case ARIZONA_DRC1RMIX_INPUT_1_SOURCE:
+       case ARIZONA_DRC1RMIX_INPUT_1_VOLUME:
+       case ARIZONA_DRC1RMIX_INPUT_2_SOURCE:
+       case ARIZONA_DRC1RMIX_INPUT_2_VOLUME:
+       case ARIZONA_DRC1RMIX_INPUT_3_SOURCE:
+       case ARIZONA_DRC1RMIX_INPUT_3_VOLUME:
+       case ARIZONA_DRC1RMIX_INPUT_4_SOURCE:
+       case ARIZONA_DRC1RMIX_INPUT_4_VOLUME:
+       case ARIZONA_HPLP1MIX_INPUT_1_SOURCE:
+       case ARIZONA_HPLP1MIX_INPUT_1_VOLUME:
+       case ARIZONA_HPLP1MIX_INPUT_2_SOURCE:
+       case ARIZONA_HPLP1MIX_INPUT_2_VOLUME:
+       case ARIZONA_HPLP1MIX_INPUT_3_SOURCE:
+       case ARIZONA_HPLP1MIX_INPUT_3_VOLUME:
+       case ARIZONA_HPLP1MIX_INPUT_4_SOURCE:
+       case ARIZONA_HPLP1MIX_INPUT_4_VOLUME:
+       case ARIZONA_HPLP2MIX_INPUT_1_SOURCE:
+       case ARIZONA_HPLP2MIX_INPUT_1_VOLUME:
+       case ARIZONA_HPLP2MIX_INPUT_2_SOURCE:
+       case ARIZONA_HPLP2MIX_INPUT_2_VOLUME:
+       case ARIZONA_HPLP2MIX_INPUT_3_SOURCE:
+       case ARIZONA_HPLP2MIX_INPUT_3_VOLUME:
+       case ARIZONA_HPLP2MIX_INPUT_4_SOURCE:
+       case ARIZONA_HPLP2MIX_INPUT_4_VOLUME:
+       case ARIZONA_HPLP3MIX_INPUT_1_SOURCE:
+       case ARIZONA_HPLP3MIX_INPUT_1_VOLUME:
+       case ARIZONA_HPLP3MIX_INPUT_2_SOURCE:
+       case ARIZONA_HPLP3MIX_INPUT_2_VOLUME:
+       case ARIZONA_HPLP3MIX_INPUT_3_SOURCE:
+       case ARIZONA_HPLP3MIX_INPUT_3_VOLUME:
+       case ARIZONA_HPLP3MIX_INPUT_4_SOURCE:
+       case ARIZONA_HPLP3MIX_INPUT_4_VOLUME:
+       case ARIZONA_HPLP4MIX_INPUT_1_SOURCE:
+       case ARIZONA_HPLP4MIX_INPUT_1_VOLUME:
+       case ARIZONA_HPLP4MIX_INPUT_2_SOURCE:
+       case ARIZONA_HPLP4MIX_INPUT_2_VOLUME:
+       case ARIZONA_HPLP4MIX_INPUT_3_SOURCE:
+       case ARIZONA_HPLP4MIX_INPUT_3_VOLUME:
+       case ARIZONA_HPLP4MIX_INPUT_4_SOURCE:
+       case ARIZONA_HPLP4MIX_INPUT_4_VOLUME:
+       case ARIZONA_ISRC1DEC1MIX_INPUT_1_SOURCE:
+       case ARIZONA_ISRC1DEC2MIX_INPUT_1_SOURCE:
+       case ARIZONA_ISRC1INT1MIX_INPUT_1_SOURCE:
+       case ARIZONA_ISRC1INT2MIX_INPUT_1_SOURCE:
+       case ARIZONA_ISRC2DEC1MIX_INPUT_1_SOURCE:
+       case ARIZONA_ISRC2DEC2MIX_INPUT_1_SOURCE:
+       case ARIZONA_ISRC2INT1MIX_INPUT_1_SOURCE:
+       case ARIZONA_ISRC2INT2MIX_INPUT_1_SOURCE:
+       case ARIZONA_GPIO1_CTRL:
+       case ARIZONA_GPIO2_CTRL:
+       case ARIZONA_GPIO3_CTRL:
+       case ARIZONA_GPIO4_CTRL:
+       case ARIZONA_GPIO5_CTRL:
+       case ARIZONA_IRQ_CTRL_1:
+       case ARIZONA_GPIO_DEBOUNCE_CONFIG:
+       case ARIZONA_MISC_PAD_CTRL_1:
+       case ARIZONA_MISC_PAD_CTRL_2:
+       case ARIZONA_MISC_PAD_CTRL_3:
+       case ARIZONA_MISC_PAD_CTRL_4:
+       case ARIZONA_MISC_PAD_CTRL_5:
+       case ARIZONA_INTERRUPT_STATUS_1:
+       case ARIZONA_INTERRUPT_STATUS_2:
+       case ARIZONA_INTERRUPT_STATUS_3:
+       case ARIZONA_INTERRUPT_STATUS_4:
+       case ARIZONA_INTERRUPT_STATUS_5:
+       case ARIZONA_INTERRUPT_STATUS_1_MASK:
+       case ARIZONA_INTERRUPT_STATUS_3_MASK:
+       case ARIZONA_INTERRUPT_STATUS_4_MASK:
+       case ARIZONA_INTERRUPT_STATUS_5_MASK:
+       case ARIZONA_INTERRUPT_CONTROL:
+       case ARIZONA_IRQ2_STATUS_1:
+       case ARIZONA_IRQ2_STATUS_3:
+       case ARIZONA_IRQ2_STATUS_4:
+       case ARIZONA_IRQ2_STATUS_5:
+       case ARIZONA_IRQ2_STATUS_1_MASK:
+       case ARIZONA_IRQ2_STATUS_3_MASK:
+       case ARIZONA_IRQ2_STATUS_4_MASK:
+       case ARIZONA_IRQ2_STATUS_5_MASK:
+       case ARIZONA_IRQ2_CONTROL:
+       case ARIZONA_INTERRUPT_RAW_STATUS_3:
+       case ARIZONA_INTERRUPT_RAW_STATUS_4:
+       case ARIZONA_INTERRUPT_RAW_STATUS_5:
+       case ARIZONA_INTERRUPT_RAW_STATUS_6:
+       case ARIZONA_INTERRUPT_RAW_STATUS_7:
+       case ARIZONA_INTERRUPT_RAW_STATUS_8:
+       case ARIZONA_IRQ_PIN_STATUS:
+       case ARIZONA_AOD_WKUP_AND_TRIG:
+       case ARIZONA_AOD_IRQ1:
+       case ARIZONA_AOD_IRQ2:
+       case ARIZONA_AOD_IRQ_MASK_IRQ1:
+       case ARIZONA_AOD_IRQ_MASK_IRQ2:
+       case ARIZONA_AOD_IRQ_RAW_STATUS:
+       case ARIZONA_JACK_DETECT_DEBOUNCE:
+       case ARIZONA_FX_CTRL1:
+       case ARIZONA_FX_CTRL2:
+       case ARIZONA_EQ1_1:
+       case ARIZONA_EQ1_2:
+       case ARIZONA_EQ1_3:
+       case ARIZONA_EQ1_4:
+       case ARIZONA_EQ1_5:
+       case ARIZONA_EQ1_6:
+       case ARIZONA_EQ1_7:
+       case ARIZONA_EQ1_8:
+       case ARIZONA_EQ1_9:
+       case ARIZONA_EQ1_10:
+       case ARIZONA_EQ1_11:
+       case ARIZONA_EQ1_12:
+       case ARIZONA_EQ1_13:
+       case ARIZONA_EQ1_14:
+       case ARIZONA_EQ1_15:
+       case ARIZONA_EQ1_16:
+       case ARIZONA_EQ1_17:
+       case ARIZONA_EQ1_18:
+       case ARIZONA_EQ1_19:
+       case ARIZONA_EQ1_20:
+       case ARIZONA_EQ1_21:
+       case ARIZONA_EQ2_1:
+       case ARIZONA_EQ2_2:
+       case ARIZONA_EQ2_3:
+       case ARIZONA_EQ2_4:
+       case ARIZONA_EQ2_5:
+       case ARIZONA_EQ2_6:
+       case ARIZONA_EQ2_7:
+       case ARIZONA_EQ2_8:
+       case ARIZONA_EQ2_9:
+       case ARIZONA_EQ2_10:
+       case ARIZONA_EQ2_11:
+       case ARIZONA_EQ2_12:
+       case ARIZONA_EQ2_13:
+       case ARIZONA_EQ2_14:
+       case ARIZONA_EQ2_15:
+       case ARIZONA_EQ2_16:
+       case ARIZONA_EQ2_17:
+       case ARIZONA_EQ2_18:
+       case ARIZONA_EQ2_19:
+       case ARIZONA_EQ2_20:
+       case ARIZONA_EQ2_21:
+       case ARIZONA_EQ3_1:
+       case ARIZONA_EQ3_2:
+       case ARIZONA_EQ3_3:
+       case ARIZONA_EQ3_4:
+       case ARIZONA_EQ3_5:
+       case ARIZONA_EQ3_6:
+       case ARIZONA_EQ3_7:
+       case ARIZONA_EQ3_8:
+       case ARIZONA_EQ3_9:
+       case ARIZONA_EQ3_10:
+       case ARIZONA_EQ3_11:
+       case ARIZONA_EQ3_12:
+       case ARIZONA_EQ3_13:
+       case ARIZONA_EQ3_14:
+       case ARIZONA_EQ3_15:
+       case ARIZONA_EQ3_16:
+       case ARIZONA_EQ3_17:
+       case ARIZONA_EQ3_18:
+       case ARIZONA_EQ3_19:
+       case ARIZONA_EQ3_20:
+       case ARIZONA_EQ3_21:
+       case ARIZONA_EQ4_1:
+       case ARIZONA_EQ4_2:
+       case ARIZONA_EQ4_3:
+       case ARIZONA_EQ4_4:
+       case ARIZONA_EQ4_5:
+       case ARIZONA_EQ4_6:
+       case ARIZONA_EQ4_7:
+       case ARIZONA_EQ4_8:
+       case ARIZONA_EQ4_9:
+       case ARIZONA_EQ4_10:
+       case ARIZONA_EQ4_11:
+       case ARIZONA_EQ4_12:
+       case ARIZONA_EQ4_13:
+       case ARIZONA_EQ4_14:
+       case ARIZONA_EQ4_15:
+       case ARIZONA_EQ4_16:
+       case ARIZONA_EQ4_17:
+       case ARIZONA_EQ4_18:
+       case ARIZONA_EQ4_19:
+       case ARIZONA_EQ4_20:
+       case ARIZONA_EQ4_21:
+       case ARIZONA_DRC1_CTRL1:
+       case ARIZONA_DRC1_CTRL2:
+       case ARIZONA_DRC1_CTRL3:
+       case ARIZONA_DRC1_CTRL4:
+       case ARIZONA_DRC1_CTRL5:
+       case ARIZONA_HPLPF1_1:
+       case ARIZONA_HPLPF1_2:
+       case ARIZONA_HPLPF2_1:
+       case ARIZONA_HPLPF2_2:
+       case ARIZONA_HPLPF3_1:
+       case ARIZONA_HPLPF3_2:
+       case ARIZONA_HPLPF4_1:
+       case ARIZONA_HPLPF4_2:
+       case ARIZONA_ISRC_1_CTRL_1:
+       case ARIZONA_ISRC_1_CTRL_2:
+       case ARIZONA_ISRC_1_CTRL_3:
+       case ARIZONA_ISRC_2_CTRL_1:
+       case ARIZONA_ISRC_2_CTRL_2:
+       case ARIZONA_ISRC_2_CTRL_3:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static bool wm8997_volatile_register(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case ARIZONA_SOFTWARE_RESET:
+       case ARIZONA_DEVICE_REVISION:
+       case ARIZONA_HAPTICS_STATUS:
+       case ARIZONA_SAMPLE_RATE_1_STATUS:
+       case ARIZONA_SAMPLE_RATE_2_STATUS:
+       case ARIZONA_SAMPLE_RATE_3_STATUS:
+       case ARIZONA_ASYNC_SAMPLE_RATE_1_STATUS:
+       case ARIZONA_MIC_DETECT_3:
+       case ARIZONA_HEADPHONE_DETECT_2:
+       case ARIZONA_INPUT_ENABLES_STATUS:
+       case ARIZONA_OUTPUT_STATUS_1:
+       case ARIZONA_RAW_OUTPUT_STATUS_1:
+       case ARIZONA_SLIMBUS_RX_PORT_STATUS:
+       case ARIZONA_SLIMBUS_TX_PORT_STATUS:
+       case ARIZONA_INTERRUPT_STATUS_1:
+       case ARIZONA_INTERRUPT_STATUS_2:
+       case ARIZONA_INTERRUPT_STATUS_3:
+       case ARIZONA_INTERRUPT_STATUS_4:
+       case ARIZONA_INTERRUPT_STATUS_5:
+       case ARIZONA_IRQ2_STATUS_1:
+       case ARIZONA_IRQ2_STATUS_3:
+       case ARIZONA_IRQ2_STATUS_4:
+       case ARIZONA_IRQ2_STATUS_5:
+       case ARIZONA_INTERRUPT_RAW_STATUS_3:
+       case ARIZONA_INTERRUPT_RAW_STATUS_4:
+       case ARIZONA_INTERRUPT_RAW_STATUS_5:
+       case ARIZONA_INTERRUPT_RAW_STATUS_6:
+       case ARIZONA_INTERRUPT_RAW_STATUS_7:
+       case ARIZONA_INTERRUPT_RAW_STATUS_8:
+       case ARIZONA_IRQ_PIN_STATUS:
+       case ARIZONA_AOD_WKUP_AND_TRIG:
+       case ARIZONA_AOD_IRQ1:
+       case ARIZONA_AOD_IRQ2:
+       case ARIZONA_AOD_IRQ_RAW_STATUS:
+       case ARIZONA_FX_CTRL2:
+               return true;
+       default:
+               return false;
+       }
+}
+
+#define WM8997_MAX_REGISTER 0x31ff
+
+const struct regmap_config wm8997_i2c_regmap = {
+       .reg_bits = 32,
+       .val_bits = 16,
+
+       .max_register = WM8997_MAX_REGISTER,
+       .readable_reg = wm8997_readable_register,
+       .volatile_reg = wm8997_volatile_register,
+
+       .cache_type = REGCACHE_RBTREE,
+       .reg_defaults = wm8997_reg_default,
+       .num_reg_defaults = ARRAY_SIZE(wm8997_reg_default),
+};
+EXPORT_SYMBOL_GPL(wm8997_i2c_regmap);
index dd27b07..cd0b7f4 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/delay.h>
 #include <linux/capability.h>
 #include <linux/compat.h>
+#include <linux/pm_runtime.h>
 
 #include <linux/mmc/ioctl.h>
 #include <linux/mmc/card.h>
@@ -58,6 +59,8 @@ MODULE_ALIAS("mmc:block");
 #define INAND_CMD38_ARG_SECTRIM1 0x81
 #define INAND_CMD38_ARG_SECTRIM2 0x88
 #define MMC_BLK_TIMEOUT_MS  (10 * 60 * 1000)        /* 10 minute timeout */
+#define MMC_SANITIZE_REQ_TIMEOUT 240000
+#define MMC_EXTRACT_INDEX_FROM_ARG(x) ((x & 0x00FF0000) >> 16)
 
 #define mmc_req_rel_wr(req)    (((req->cmd_flags & REQ_FUA) || \
                                  (req->cmd_flags & REQ_META)) && \
@@ -222,7 +225,7 @@ static ssize_t power_ro_lock_store(struct device *dev,
        md = mmc_blk_get(dev_to_disk(dev));
        card = md->queue.card;
 
-       mmc_claim_host(card->host);
+       mmc_get_card(card);
 
        ret = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BOOT_WP,
                                card->ext_csd.boot_ro_lock |
@@ -233,7 +236,7 @@ static ssize_t power_ro_lock_store(struct device *dev,
        else
                card->ext_csd.boot_ro_lock |= EXT_CSD_BOOT_WP_B_PWR_WP_EN;
 
-       mmc_release_host(card->host);
+       mmc_put_card(card);
 
        if (!ret) {
                pr_info("%s: Locking boot partition ro until next power on\n",
@@ -408,6 +411,35 @@ static int ioctl_rpmb_card_status_poll(struct mmc_card *card, u32 *status,
        return err;
 }
 
+static int ioctl_do_sanitize(struct mmc_card *card)
+{
+       int err;
+
+       if (!(mmc_can_sanitize(card) &&
+             (card->host->caps2 & MMC_CAP2_SANITIZE))) {
+                       pr_warn("%s: %s - SANITIZE is not supported\n",
+                               mmc_hostname(card->host), __func__);
+                       err = -EOPNOTSUPP;
+                       goto out;
+       }
+
+       pr_debug("%s: %s - SANITIZE IN PROGRESS...\n",
+               mmc_hostname(card->host), __func__);
+
+       err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+                                       EXT_CSD_SANITIZE_START, 1,
+                                       MMC_SANITIZE_REQ_TIMEOUT);
+
+       if (err)
+               pr_err("%s: %s - EXT_CSD_SANITIZE_START failed. err=%d\n",
+                      mmc_hostname(card->host), __func__, err);
+
+       pr_debug("%s: %s - SANITIZE COMPLETED\n", mmc_hostname(card->host),
+                                            __func__);
+out:
+       return err;
+}
+
 static int mmc_blk_ioctl_cmd(struct block_device *bdev,
        struct mmc_ioc_cmd __user *ic_ptr)
 {
@@ -491,7 +523,7 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev,
 
        mrq.cmd = &cmd;
 
-       mmc_claim_host(card->host);
+       mmc_get_card(card);
 
        err = mmc_blk_part_switch(card, md);
        if (err)
@@ -510,6 +542,17 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev,
                        goto cmd_rel_host;
        }
 
+       if ((MMC_EXTRACT_INDEX_FROM_ARG(cmd.arg) == EXT_CSD_SANITIZE_START) &&
+           (cmd.opcode == MMC_SWITCH)) {
+               err = ioctl_do_sanitize(card);
+
+               if (err)
+                       pr_err("%s: ioctl_do_sanitize() failed. err = %d",
+                              __func__, err);
+
+               goto cmd_rel_host;
+       }
+
        mmc_wait_for_req(card->host, &mrq);
 
        if (cmd.error) {
@@ -558,7 +601,7 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev,
        }
 
 cmd_rel_host:
-       mmc_release_host(card->host);
+       mmc_put_card(card);
 
 cmd_done:
        mmc_blk_put(md);
@@ -939,10 +982,10 @@ static int mmc_blk_issue_secdiscard_rq(struct mmc_queue *mq,
 {
        struct mmc_blk_data *md = mq->data;
        struct mmc_card *card = md->queue.card;
-       unsigned int from, nr, arg, trim_arg, erase_arg;
+       unsigned int from, nr, arg;
        int err = 0, type = MMC_BLK_SECDISCARD;
 
-       if (!(mmc_can_secure_erase_trim(card) || mmc_can_sanitize(card))) {
+       if (!(mmc_can_secure_erase_trim(card))) {
                err = -EOPNOTSUPP;
                goto out;
        }
@@ -950,23 +993,11 @@ static int mmc_blk_issue_secdiscard_rq(struct mmc_queue *mq,
        from = blk_rq_pos(req);
        nr = blk_rq_sectors(req);
 
-       /* The sanitize operation is supported at v4.5 only */
-       if (mmc_can_sanitize(card)) {
-               erase_arg = MMC_ERASE_ARG;
-               trim_arg = MMC_TRIM_ARG;
-       } else {
-               erase_arg = MMC_SECURE_ERASE_ARG;
-               trim_arg = MMC_SECURE_TRIM1_ARG;
-       }
+       if (mmc_can_trim(card) && !mmc_erase_group_aligned(card, from, nr))
+               arg = MMC_SECURE_TRIM1_ARG;
+       else
+               arg = MMC_SECURE_ERASE_ARG;
 
-       if (mmc_erase_group_aligned(card, from, nr))
-               arg = erase_arg;
-       else if (mmc_can_trim(card))
-               arg = trim_arg;
-       else {
-               err = -EINVAL;
-               goto out;
-       }
 retry:
        if (card->quirks & MMC_QUIRK_INAND_CMD38) {
                err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
@@ -1002,9 +1033,6 @@ retry:
                        goto out;
        }
 
-       if (mmc_can_sanitize(card))
-               err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-                                EXT_CSD_SANITIZE_START, 1, 0);
 out_retry:
        if (err && !mmc_blk_reset(md, card->host, type))
                goto retry;
@@ -1895,7 +1923,7 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
 
        if (req && !mq->mqrq_prev->req)
                /* claim host only for the first request */
-               mmc_claim_host(card->host);
+               mmc_get_card(card);
 
        ret = mmc_blk_part_switch(card, md);
        if (ret) {
@@ -1939,7 +1967,7 @@ out:
                 * In case sepecial request, there is no reentry to
                 * the 'mmc_blk_issue_rq' with 'mqrq_prev->req'.
                 */
-               mmc_release_host(card->host);
+               mmc_put_card(card);
        return ret;
 }
 
@@ -2158,6 +2186,14 @@ static void mmc_blk_remove_req(struct mmc_blk_data *md)
        struct mmc_card *card;
 
        if (md) {
+               /*
+                * Flush remaining requests and free queues. It
+                * is freeing the queue that stops new requests
+                * from being accepted.
+                */
+               mmc_cleanup_queue(&md->queue);
+               if (md->flags & MMC_BLK_PACKED_CMD)
+                       mmc_packed_clean(&md->queue);
                card = md->queue.card;
                if (md->disk->flags & GENHD_FL_UP) {
                        device_remove_file(disk_to_dev(md->disk), &md->force_ro);
@@ -2166,14 +2202,8 @@ static void mmc_blk_remove_req(struct mmc_blk_data *md)
                                device_remove_file(disk_to_dev(md->disk),
                                        &md->power_ro_lock);
 
-                       /* Stop new requests from getting into the queue */
                        del_gendisk(md->disk);
                }
-
-               /* Then flush out any already in there */
-               mmc_cleanup_queue(&md->queue);
-               if (md->flags & MMC_BLK_PACKED_CMD)
-                       mmc_packed_clean(&md->queue);
                mmc_blk_put(md);
        }
 }
@@ -2336,6 +2366,19 @@ static int mmc_blk_probe(struct mmc_card *card)
                if (mmc_add_disk(part_md))
                        goto out;
        }
+
+       pm_runtime_set_autosuspend_delay(&card->dev, 3000);
+       pm_runtime_use_autosuspend(&card->dev);
+
+       /*
+        * Don't enable runtime PM for SD-combo cards here. Leave that
+        * decision to be taken during the SDIO init sequence instead.
+        */
+       if (card->type != MMC_TYPE_SD_COMBO) {
+               pm_runtime_set_active(&card->dev);
+               pm_runtime_enable(&card->dev);
+       }
+
        return 0;
 
  out:
@@ -2349,20 +2392,24 @@ static void mmc_blk_remove(struct mmc_card *card)
        struct mmc_blk_data *md = mmc_get_drvdata(card);
 
        mmc_blk_remove_parts(card, md);
+       pm_runtime_get_sync(&card->dev);
        mmc_claim_host(card->host);
        mmc_blk_part_switch(card, md);
        mmc_release_host(card->host);
+       if (card->type != MMC_TYPE_SD_COMBO)
+               pm_runtime_disable(&card->dev);
+       pm_runtime_put_noidle(&card->dev);
        mmc_blk_remove_req(md);
        mmc_set_drvdata(card, NULL);
 }
 
-#ifdef CONFIG_PM
-static int mmc_blk_suspend(struct mmc_card *card)
+static int _mmc_blk_suspend(struct mmc_card *card)
 {
        struct mmc_blk_data *part_md;
        struct mmc_blk_data *md = mmc_get_drvdata(card);
 
        if (md) {
+               pm_runtime_get_sync(&card->dev);
                mmc_queue_suspend(&md->queue);
                list_for_each_entry(part_md, &md->part, part) {
                        mmc_queue_suspend(&part_md->queue);
@@ -2371,6 +2418,17 @@ static int mmc_blk_suspend(struct mmc_card *card)
        return 0;
 }
 
+static void mmc_blk_shutdown(struct mmc_card *card)
+{
+       _mmc_blk_suspend(card);
+}
+
+#ifdef CONFIG_PM
+static int mmc_blk_suspend(struct mmc_card *card)
+{
+       return _mmc_blk_suspend(card);
+}
+
 static int mmc_blk_resume(struct mmc_card *card)
 {
        struct mmc_blk_data *part_md;
@@ -2386,6 +2444,7 @@ static int mmc_blk_resume(struct mmc_card *card)
                list_for_each_entry(part_md, &md->part, part) {
                        mmc_queue_resume(&part_md->queue);
                }
+               pm_runtime_put(&card->dev);
        }
        return 0;
 }
@@ -2402,6 +2461,7 @@ static struct mmc_driver mmc_driver = {
        .remove         = mmc_blk_remove,
        .suspend        = mmc_blk_suspend,
        .resume         = mmc_blk_resume,
+       .shutdown       = mmc_blk_shutdown,
 };
 
 static int __init mmc_blk_init(void)
index 759714e..a69df52 100644 (file)
@@ -3025,12 +3025,17 @@ static void mmc_test_remove(struct mmc_card *card)
        mmc_test_free_dbgfs_file(card);
 }
 
+static void mmc_test_shutdown(struct mmc_card *card)
+{
+}
+
 static struct mmc_driver mmc_driver = {
        .drv            = {
                .name   = "mmc_test",
        },
        .probe          = mmc_test_probe,
        .remove         = mmc_test_remove,
+       .shutdown       = mmc_test_shutdown,
 };
 
 static int __init mmc_test_init(void)
index 9447a0e..fa9632e 100644 (file)
@@ -173,7 +173,7 @@ static void mmc_queue_setup_discard(struct request_queue *q,
        /* granularity must not be greater than max. discard */
        if (card->pref_erase > max_discard)
                q->limits.discard_granularity = 0;
-       if (mmc_can_secure_erase_trim(card) || mmc_can_sanitize(card))
+       if (mmc_can_secure_erase_trim(card))
                queue_flag_set_unlocked(QUEUE_FLAG_SECDISCARD, q);
 }
 
index 9d5c711..704bf66 100644 (file)
@@ -122,15 +122,39 @@ static int mmc_bus_remove(struct device *dev)
        return 0;
 }
 
+static void mmc_bus_shutdown(struct device *dev)
+{
+       struct mmc_driver *drv = to_mmc_driver(dev->driver);
+       struct mmc_card *card = mmc_dev_to_card(dev);
+       struct mmc_host *host = card->host;
+       int ret;
+
+       if (dev->driver && drv->shutdown)
+               drv->shutdown(card);
+
+       if (host->bus_ops->shutdown) {
+               ret = host->bus_ops->shutdown(host);
+               if (ret)
+                       pr_warn("%s: error %d during shutdown\n",
+                               mmc_hostname(host), ret);
+       }
+}
+
 #ifdef CONFIG_PM_SLEEP
 static int mmc_bus_suspend(struct device *dev)
 {
        struct mmc_driver *drv = to_mmc_driver(dev->driver);
        struct mmc_card *card = mmc_dev_to_card(dev);
-       int ret = 0;
+       struct mmc_host *host = card->host;
+       int ret;
 
-       if (dev->driver && drv->suspend)
+       if (dev->driver && drv->suspend) {
                ret = drv->suspend(card);
+               if (ret)
+                       return ret;
+       }
+
+       ret = host->bus_ops->suspend(host);
        return ret;
 }
 
@@ -138,10 +162,17 @@ static int mmc_bus_resume(struct device *dev)
 {
        struct mmc_driver *drv = to_mmc_driver(dev->driver);
        struct mmc_card *card = mmc_dev_to_card(dev);
-       int ret = 0;
+       struct mmc_host *host = card->host;
+       int ret;
+
+       ret = host->bus_ops->resume(host);
+       if (ret)
+               pr_warn("%s: error %d during resume (card was removed?)\n",
+                       mmc_hostname(host), ret);
 
        if (dev->driver && drv->resume)
                ret = drv->resume(card);
+
        return ret;
 }
 #endif
@@ -151,15 +182,25 @@ static int mmc_bus_resume(struct device *dev)
 static int mmc_runtime_suspend(struct device *dev)
 {
        struct mmc_card *card = mmc_dev_to_card(dev);
+       struct mmc_host *host = card->host;
+       int ret = 0;
+
+       if (host->bus_ops->runtime_suspend)
+               ret = host->bus_ops->runtime_suspend(host);
 
-       return mmc_power_save_host(card->host);
+       return ret;
 }
 
 static int mmc_runtime_resume(struct device *dev)
 {
        struct mmc_card *card = mmc_dev_to_card(dev);
+       struct mmc_host *host = card->host;
+       int ret = 0;
+
+       if (host->bus_ops->runtime_resume)
+               ret = host->bus_ops->runtime_resume(host);
 
-       return mmc_power_restore_host(card->host);
+       return ret;
 }
 
 static int mmc_runtime_idle(struct device *dev)
@@ -182,6 +223,7 @@ static struct bus_type mmc_bus_type = {
        .uevent         = mmc_bus_uevent,
        .probe          = mmc_bus_probe,
        .remove         = mmc_bus_remove,
+       .shutdown       = mmc_bus_shutdown,
        .pm             = &mmc_bus_pm_ops,
 };
 
index c40396f..49a5bca 100644 (file)
@@ -402,6 +402,7 @@ static int mmc_wait_for_data_req_done(struct mmc_host *host,
                        context_info->is_done_rcv = false;
                        context_info->is_new_req = false;
                        cmd = mrq->cmd;
+
                        if (!cmd->error || !cmd->retries ||
                            mmc_card_removed(host->card)) {
                                err = host->areq->err_check(host->card,
@@ -436,6 +437,24 @@ static void mmc_wait_for_req_done(struct mmc_host *host,
                wait_for_completion(&mrq->completion);
 
                cmd = mrq->cmd;
+
+               /*
+                * If host has timed out waiting for the sanitize
+                * to complete, card might be still in programming state
+                * so let's try to bring the card out of programming
+                * state.
+                */
+               if (cmd->sanitize_busy && cmd->error == -ETIMEDOUT) {
+                       if (!mmc_interrupt_hpi(host->card)) {
+                               pr_warning("%s: %s: Interrupted sanitize\n",
+                                          mmc_hostname(host), __func__);
+                               cmd->error = 0;
+                               break;
+                       } else {
+                               pr_err("%s: %s: Failed to interrupt sanitize\n",
+                                      mmc_hostname(host), __func__);
+                       }
+               }
                if (!cmd->error || !cmd->retries ||
                    mmc_card_removed(host->card))
                        break;
@@ -952,6 +971,29 @@ void mmc_release_host(struct mmc_host *host)
 EXPORT_SYMBOL(mmc_release_host);
 
 /*
+ * This is a helper function, which fetches a runtime pm reference for the
+ * card device and also claims the host.
+ */
+void mmc_get_card(struct mmc_card *card)
+{
+       pm_runtime_get_sync(&card->dev);
+       mmc_claim_host(card->host);
+}
+EXPORT_SYMBOL(mmc_get_card);
+
+/*
+ * This is a helper function, which releases the host and drops the runtime
+ * pm reference for the card device.
+ */
+void mmc_put_card(struct mmc_card *card)
+{
+       mmc_release_host(card->host);
+       pm_runtime_mark_last_busy(&card->dev);
+       pm_runtime_put_autosuspend(&card->dev);
+}
+EXPORT_SYMBOL(mmc_put_card);
+
+/*
  * Internal function that does the actual ios call to the host driver,
  * optionally printing some debug output.
  */
@@ -1459,7 +1501,7 @@ void mmc_set_driver_type(struct mmc_host *host, unsigned int drv_type)
  * If a host does all the power sequencing itself, ignore the
  * initial MMC_POWER_UP stage.
  */
-static void mmc_power_up(struct mmc_host *host)
+void mmc_power_up(struct mmc_host *host)
 {
        int bit;
 
@@ -2325,14 +2367,13 @@ int mmc_detect_card_removed(struct mmc_host *host)
         * The card will be considered unchanged unless we have been asked to
         * detect a change or host requires polling to provide card detection.
         */
-       if (!host->detect_change && !(host->caps & MMC_CAP_NEEDS_POLL) &&
-           !(host->caps2 & MMC_CAP2_DETECT_ON_ERR))
+       if (!host->detect_change && !(host->caps & MMC_CAP_NEEDS_POLL))
                return ret;
 
        host->detect_change = 0;
        if (!ret) {
                ret = _mmc_detect_card_removed(host);
-               if (ret && (host->caps2 & MMC_CAP2_DETECT_ON_ERR)) {
+               if (ret && (host->caps & MMC_CAP_NEEDS_POLL)) {
                        /*
                         * Schedule a detect work as soon as possible to let a
                         * rescan handle the card removal.
@@ -2442,9 +2483,7 @@ void mmc_stop_host(struct mmc_host *host)
        mmc_bus_get(host);
        if (host->bus_ops && !host->bus_dead) {
                /* Calling bus_ops->remove() with a claimed host can deadlock */
-               if (host->bus_ops->remove)
-                       host->bus_ops->remove(host);
-
+               host->bus_ops->remove(host);
                mmc_claim_host(host);
                mmc_detach_bus(host);
                mmc_power_off(host);
@@ -2509,52 +2548,6 @@ int mmc_power_restore_host(struct mmc_host *host)
 }
 EXPORT_SYMBOL(mmc_power_restore_host);
 
-int mmc_card_awake(struct mmc_host *host)
-{
-       int err = -ENOSYS;
-
-       if (host->caps2 & MMC_CAP2_NO_SLEEP_CMD)
-               return 0;
-
-       mmc_bus_get(host);
-
-       if (host->bus_ops && !host->bus_dead && host->bus_ops->awake)
-               err = host->bus_ops->awake(host);
-
-       mmc_bus_put(host);
-
-       return err;
-}
-EXPORT_SYMBOL(mmc_card_awake);
-
-int mmc_card_sleep(struct mmc_host *host)
-{
-       int err = -ENOSYS;
-
-       if (host->caps2 & MMC_CAP2_NO_SLEEP_CMD)
-               return 0;
-
-       mmc_bus_get(host);
-
-       if (host->bus_ops && !host->bus_dead && host->bus_ops->sleep)
-               err = host->bus_ops->sleep(host);
-
-       mmc_bus_put(host);
-
-       return err;
-}
-EXPORT_SYMBOL(mmc_card_sleep);
-
-int mmc_card_can_sleep(struct mmc_host *host)
-{
-       struct mmc_card *card = host->card;
-
-       if (card && mmc_card_mmc(card) && card->ext_csd.rev >= 3)
-               return 1;
-       return 0;
-}
-EXPORT_SYMBOL(mmc_card_can_sleep);
-
 /*
  * Flush the cache to the non-volatile storage.
  */
@@ -2626,48 +2619,9 @@ EXPORT_SYMBOL(mmc_cache_ctrl);
  */
 int mmc_suspend_host(struct mmc_host *host)
 {
-       int err = 0;
-
-       cancel_delayed_work(&host->detect);
-       mmc_flush_scheduled_work();
-
-       mmc_bus_get(host);
-       if (host->bus_ops && !host->bus_dead) {
-               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) {
-                       /*
-                        * We simply "remove" the card in this case.
-                        * It will be redetected on resume.  (Calling
-                        * bus_ops->remove() with a claimed host can
-                        * deadlock.)
-                        */
-                       if (host->bus_ops->remove)
-                               host->bus_ops->remove(host);
-                       mmc_claim_host(host);
-                       mmc_detach_bus(host);
-                       mmc_power_off(host);
-                       mmc_release_host(host);
-                       host->pm_flags = 0;
-                       err = 0;
-               }
-       }
-       mmc_bus_put(host);
-
-       if (!err && !mmc_card_keep_power(host))
-               mmc_power_off(host);
-
-out:
-       return err;
+       /* This function is deprecated */
+       return 0;
 }
-
 EXPORT_SYMBOL(mmc_suspend_host);
 
 /**
@@ -2676,39 +2630,8 @@ EXPORT_SYMBOL(mmc_suspend_host);
  */
 int mmc_resume_host(struct mmc_host *host)
 {
-       int err = 0;
-
-       mmc_bus_get(host);
-       if (host->bus_ops && !host->bus_dead) {
-               if (!mmc_card_keep_power(host)) {
-                       mmc_power_up(host);
-                       mmc_select_voltage(host, host->ocr);
-                       /*
-                        * Tell runtime PM core we just powered up the card,
-                        * since it still believes the card is powered off.
-                        * Note that currently runtime PM is only enabled
-                        * for SDIO cards that are MMC_CAP_POWER_OFF_CARD
-                        */
-                       if (mmc_card_sdio(host->card) &&
-                           (host->caps & MMC_CAP_POWER_OFF_CARD)) {
-                               pm_runtime_disable(&host->card->dev);
-                               pm_runtime_set_active(&host->card->dev);
-                               pm_runtime_enable(&host->card->dev);
-                       }
-               }
-               BUG_ON(!host->bus_ops->resume);
-               err = host->bus_ops->resume(host);
-               if (err) {
-                       pr_warning("%s: error %d during resume "
-                                           "(card was removed?)\n",
-                                           mmc_hostname(host), err);
-                       err = 0;
-               }
-       }
-       host->pm_flags &= ~MMC_PM_KEEP_POWER;
-       mmc_bus_put(host);
-
-       return err;
+       /* This function is deprecated */
+       return 0;
 }
 EXPORT_SYMBOL(mmc_resume_host);
 
@@ -2727,29 +2650,22 @@ int mmc_pm_notify(struct notifier_block *notify_block,
        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;
                spin_unlock_irqrestore(&host->lock, flags);
                cancel_delayed_work_sync(&host->detect);
 
-               if (!host->bus_ops || host->bus_ops->suspend)
+               if (!host->bus_ops)
                        break;
 
-               /* Calling bus_ops->remove() with a claimed host can deadlock */
-               if (host->bus_ops->remove)
-                       host->bus_ops->remove(host);
+               /* Validate prerequisites for suspend */
+               if (host->bus_ops->pre_suspend)
+                       err = host->bus_ops->pre_suspend(host);
+               if (!err && host->bus_ops->suspend)
+                       break;
 
+               /* Calling bus_ops->remove() with a claimed host can deadlock */
+               host->bus_ops->remove(host);
                mmc_claim_host(host);
                mmc_detach_bus(host);
                mmc_power_off(host);
index b9f18a2..5345d15 100644 (file)
 #define MMC_CMD_RETRIES        3
 
 struct mmc_bus_ops {
-       int (*awake)(struct mmc_host *);
-       int (*sleep)(struct mmc_host *);
        void (*remove)(struct mmc_host *);
        void (*detect)(struct mmc_host *);
+       int (*pre_suspend)(struct mmc_host *);
        int (*suspend)(struct mmc_host *);
        int (*resume)(struct mmc_host *);
+       int (*runtime_suspend)(struct mmc_host *);
+       int (*runtime_resume)(struct mmc_host *);
        int (*power_save)(struct mmc_host *);
        int (*power_restore)(struct mmc_host *);
        int (*alive)(struct mmc_host *);
+       int (*shutdown)(struct mmc_host *);
 };
 
 void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops);
@@ -44,6 +46,7 @@ int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage);
 int __mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage);
 void mmc_set_timing(struct mmc_host *host, unsigned int timing);
 void mmc_set_driver_type(struct mmc_host *host, unsigned int drv_type);
+void mmc_power_up(struct mmc_host *host);
 void mmc_power_off(struct mmc_host *host);
 void mmc_power_cycle(struct mmc_host *host);
 
index 35c2f85..54829c0 100644 (file)
@@ -258,13 +258,13 @@ static int mmc_dbg_card_status_get(void *data, u64 *val)
        u32             status;
        int             ret;
 
-       mmc_claim_host(card->host);
+       mmc_get_card(card);
 
        ret = mmc_send_status(data, &status);
        if (!ret)
                *val = status;
 
-       mmc_release_host(card->host);
+       mmc_put_card(card);
 
        return ret;
 }
@@ -291,9 +291,9 @@ static int mmc_ext_csd_open(struct inode *inode, struct file *filp)
                goto out_free;
        }
 
-       mmc_claim_host(card->host);
+       mmc_get_card(card);
        err = mmc_send_ext_csd(card, ext_csd);
-       mmc_release_host(card->host);
+       mmc_put_card(card);
        if (err)
                goto out_free;
 
index 2a3593d..6fb6f77 100644 (file)
@@ -306,7 +306,7 @@ static inline void mmc_host_clk_sysfs_init(struct mmc_host *host)
  * parse the properties and set respective generic mmc-host flags and
  * parameters.
  */
-void mmc_of_parse(struct mmc_host *host)
+int mmc_of_parse(struct mmc_host *host)
 {
        struct device_node *np;
        u32 bus_width;
@@ -315,7 +315,7 @@ void mmc_of_parse(struct mmc_host *host)
        int len, ret, gpio;
 
        if (!host->parent || !host->parent->of_node)
-               return;
+               return 0;
 
        np = host->parent->of_node;
 
@@ -338,6 +338,7 @@ void mmc_of_parse(struct mmc_host *host)
        default:
                dev_err(host->parent,
                        "Invalid \"bus-width\" value %ud!\n", bus_width);
+               return -EINVAL;
        }
 
        /* f_max is obtained from the optional "max-frequency" property */
@@ -367,18 +368,22 @@ void mmc_of_parse(struct mmc_host *host)
                        host->caps |= MMC_CAP_NEEDS_POLL;
 
                gpio = of_get_named_gpio_flags(np, "cd-gpios", 0, &flags);
+               if (gpio == -EPROBE_DEFER)
+                       return gpio;
                if (gpio_is_valid(gpio)) {
                        if (!(flags & OF_GPIO_ACTIVE_LOW))
                                gpio_inv_cd = true;
 
                        ret = mmc_gpio_request_cd(host, gpio);
-                       if (ret < 0)
+                       if (ret < 0) {
                                dev_err(host->parent,
                                        "Failed to request CD GPIO #%d: %d!\n",
                                        gpio, ret);
-                       else
+                               return ret;
+                       } else {
                                dev_info(host->parent, "Got CD GPIO #%d.\n",
                                         gpio);
+                       }
                }
 
                if (explicit_inv_cd ^ gpio_inv_cd)
@@ -389,14 +394,23 @@ void mmc_of_parse(struct mmc_host *host)
        explicit_inv_wp = of_property_read_bool(np, "wp-inverted");
 
        gpio = of_get_named_gpio_flags(np, "wp-gpios", 0, &flags);
+       if (gpio == -EPROBE_DEFER) {
+               ret = -EPROBE_DEFER;
+               goto out;
+       }
        if (gpio_is_valid(gpio)) {
                if (!(flags & OF_GPIO_ACTIVE_LOW))
                        gpio_inv_wp = true;
 
                ret = mmc_gpio_request_ro(host, gpio);
-               if (ret < 0)
+               if (ret < 0) {
                        dev_err(host->parent,
                                "Failed to request WP GPIO: %d!\n", ret);
+                       goto out;
+               } else {
+                               dev_info(host->parent, "Got WP GPIO #%d.\n",
+                                        gpio);
+               }
        }
        if (explicit_inv_wp ^ gpio_inv_wp)
                host->caps2 |= MMC_CAP2_RO_ACTIVE_HIGH;
@@ -409,10 +423,18 @@ void mmc_of_parse(struct mmc_host *host)
                host->caps |= MMC_CAP_POWER_OFF_CARD;
        if (of_find_property(np, "cap-sdio-irq", &len))
                host->caps |= MMC_CAP_SDIO_IRQ;
+       if (of_find_property(np, "full-pwr-cycle", &len))
+               host->caps2 |= MMC_CAP2_FULL_PWR_CYCLE;
        if (of_find_property(np, "keep-power-in-suspend", &len))
                host->pm_caps |= MMC_PM_KEEP_POWER;
        if (of_find_property(np, "enable-sdio-wakeup", &len))
                host->pm_caps |= MMC_PM_WAKE_SDIO_IRQ;
+
+       return 0;
+
+out:
+       mmc_gpio_free_cd(host);
+       return ret;
 }
 
 EXPORT_SYMBOL(mmc_of_parse);
index 0cbd1ef..6d02012 100644 (file)
@@ -293,7 +293,7 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
        }
 
        card->ext_csd.rev = ext_csd[EXT_CSD_REV];
-       if (card->ext_csd.rev > 6) {
+       if (card->ext_csd.rev > 7) {
                pr_err("%s: unrecognised EXT_CSD revision %d\n",
                        mmc_hostname(card->host), card->ext_csd.rev);
                err = -EINVAL;
@@ -461,9 +461,31 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
                 */
                card->ext_csd.boot_ro_lock = ext_csd[EXT_CSD_BOOT_WP];
                card->ext_csd.boot_ro_lockable = true;
+
+               /* Save power class values */
+               card->ext_csd.raw_pwr_cl_52_195 =
+                       ext_csd[EXT_CSD_PWR_CL_52_195];
+               card->ext_csd.raw_pwr_cl_26_195 =
+                       ext_csd[EXT_CSD_PWR_CL_26_195];
+               card->ext_csd.raw_pwr_cl_52_360 =
+                       ext_csd[EXT_CSD_PWR_CL_52_360];
+               card->ext_csd.raw_pwr_cl_26_360 =
+                       ext_csd[EXT_CSD_PWR_CL_26_360];
+               card->ext_csd.raw_pwr_cl_200_195 =
+                       ext_csd[EXT_CSD_PWR_CL_200_195];
+               card->ext_csd.raw_pwr_cl_200_360 =
+                       ext_csd[EXT_CSD_PWR_CL_200_360];
+               card->ext_csd.raw_pwr_cl_ddr_52_195 =
+                       ext_csd[EXT_CSD_PWR_CL_DDR_52_195];
+               card->ext_csd.raw_pwr_cl_ddr_52_360 =
+                       ext_csd[EXT_CSD_PWR_CL_DDR_52_360];
        }
 
        if (card->ext_csd.rev >= 5) {
+               /* Adjust production date as per JEDEC JESD84-B451 */
+               if (card->cid.year < 2010)
+                       card->cid.year += 16;
+
                /* check whether the eMMC card supports BKOPS */
                if (ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1) {
                        card->ext_csd.bkops = 1;
@@ -607,7 +629,23 @@ static int mmc_compare_ext_csds(struct mmc_card *card, unsigned bus_width)
                (card->ext_csd.raw_sectors[2] ==
                        bw_ext_csd[EXT_CSD_SEC_CNT + 2]) &&
                (card->ext_csd.raw_sectors[3] ==
-                       bw_ext_csd[EXT_CSD_SEC_CNT + 3]));
+                       bw_ext_csd[EXT_CSD_SEC_CNT + 3]) &&
+               (card->ext_csd.raw_pwr_cl_52_195 ==
+                       bw_ext_csd[EXT_CSD_PWR_CL_52_195]) &&
+               (card->ext_csd.raw_pwr_cl_26_195 ==
+                       bw_ext_csd[EXT_CSD_PWR_CL_26_195]) &&
+               (card->ext_csd.raw_pwr_cl_52_360 ==
+                       bw_ext_csd[EXT_CSD_PWR_CL_52_360]) &&
+               (card->ext_csd.raw_pwr_cl_26_360 ==
+                       bw_ext_csd[EXT_CSD_PWR_CL_26_360]) &&
+               (card->ext_csd.raw_pwr_cl_200_195 ==
+                       bw_ext_csd[EXT_CSD_PWR_CL_200_195]) &&
+               (card->ext_csd.raw_pwr_cl_200_360 ==
+                       bw_ext_csd[EXT_CSD_PWR_CL_200_360]) &&
+               (card->ext_csd.raw_pwr_cl_ddr_52_195 ==
+                       bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_195]) &&
+               (card->ext_csd.raw_pwr_cl_ddr_52_360 ==
+                       bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_360]));
        if (err)
                err = -EINVAL;
 
@@ -676,11 +714,10 @@ static struct device_type mmc_type = {
  * mmc_switch command.
  */
 static int mmc_select_powerclass(struct mmc_card *card,
-               unsigned int bus_width, u8 *ext_csd)
+               unsigned int bus_width)
 {
        int err = 0;
-       unsigned int pwrclass_val;
-       unsigned int index = 0;
+       unsigned int pwrclass_val = 0;
        struct mmc_host *host;
 
        BUG_ON(!card);
@@ -688,9 +725,6 @@ static int mmc_select_powerclass(struct mmc_card *card,
        host = card->host;
        BUG_ON(!host);
 
-       if (ext_csd == NULL)
-               return 0;
-
        /* Power class selection is supported for versions >= 4.0 */
        if (card->csd.mmca_vsn < CSD_SPEC_VER_4)
                return 0;
@@ -702,13 +736,13 @@ static int mmc_select_powerclass(struct mmc_card *card,
        switch (1 << host->ios.vdd) {
        case MMC_VDD_165_195:
                if (host->ios.clock <= 26000000)
-                       index = EXT_CSD_PWR_CL_26_195;
+                       pwrclass_val = card->ext_csd.raw_pwr_cl_26_195;
                else if (host->ios.clock <= 52000000)
-                       index = (bus_width <= EXT_CSD_BUS_WIDTH_8) ?
-                               EXT_CSD_PWR_CL_52_195 :
-                               EXT_CSD_PWR_CL_DDR_52_195;
+                       pwrclass_val = (bus_width <= EXT_CSD_BUS_WIDTH_8) ?
+                               card->ext_csd.raw_pwr_cl_52_195 :
+                               card->ext_csd.raw_pwr_cl_ddr_52_195;
                else if (host->ios.clock <= 200000000)
-                       index = EXT_CSD_PWR_CL_200_195;
+                       pwrclass_val = card->ext_csd.raw_pwr_cl_200_195;
                break;
        case MMC_VDD_27_28:
        case MMC_VDD_28_29:
@@ -720,13 +754,13 @@ static int mmc_select_powerclass(struct mmc_card *card,
        case MMC_VDD_34_35:
        case MMC_VDD_35_36:
                if (host->ios.clock <= 26000000)
-                       index = EXT_CSD_PWR_CL_26_360;
+                       pwrclass_val = card->ext_csd.raw_pwr_cl_26_360;
                else if (host->ios.clock <= 52000000)
-                       index = (bus_width <= EXT_CSD_BUS_WIDTH_8) ?
-                               EXT_CSD_PWR_CL_52_360 :
-                               EXT_CSD_PWR_CL_DDR_52_360;
+                       pwrclass_val = (bus_width <= EXT_CSD_BUS_WIDTH_8) ?
+                               card->ext_csd.raw_pwr_cl_52_360 :
+                               card->ext_csd.raw_pwr_cl_ddr_52_360;
                else if (host->ios.clock <= 200000000)
-                       index = EXT_CSD_PWR_CL_200_360;
+                       pwrclass_val = card->ext_csd.raw_pwr_cl_200_360;
                break;
        default:
                pr_warning("%s: Voltage range not supported "
@@ -734,8 +768,6 @@ static int mmc_select_powerclass(struct mmc_card *card,
                return -EINVAL;
        }
 
-       pwrclass_val = ext_csd[index];
-
        if (bus_width & (EXT_CSD_BUS_WIDTH_8 | EXT_CSD_DDR_BUS_WIDTH_8))
                pwrclass_val = (pwrclass_val & EXT_CSD_PWR_CL_8BIT_MASK) >>
                                EXT_CSD_PWR_CL_8BIT_SHIFT;
@@ -1013,11 +1045,9 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
        }
 
        /*
-        * If the host supports the power_off_notify capability then
-        * set the notification byte in the ext_csd register of device
+        * Enable power_off_notification byte in the ext_csd register
         */
-       if ((host->caps2 & MMC_CAP2_POWEROFF_NOTIFY) &&
-           (card->ext_csd.rev >= 6)) {
+       if (card->ext_csd.rev >= 6) {
                err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
                                 EXT_CSD_POWER_OFF_NOTIFICATION,
                                 EXT_CSD_POWER_ON,
@@ -1131,7 +1161,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 
                ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
                                EXT_CSD_BUS_WIDTH_8 : EXT_CSD_BUS_WIDTH_4;
-               err = mmc_select_powerclass(card, ext_csd_bits, ext_csd);
+               err = mmc_select_powerclass(card, ext_csd_bits);
                if (err)
                        pr_warning("%s: power class selection to bus width %d"
                                   " failed\n", mmc_hostname(card->host),
@@ -1164,8 +1194,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
                        bus_width = bus_widths[idx];
                        if (bus_width == MMC_BUS_WIDTH_1)
                                ddr = 0; /* no DDR for 1-bit width */
-                       err = mmc_select_powerclass(card, ext_csd_bits[idx][0],
-                                                   ext_csd);
+                       err = mmc_select_powerclass(card, ext_csd_bits[idx][0]);
                        if (err)
                                pr_warning("%s: power class selection to "
                                           "bus width %d failed\n",
@@ -1195,8 +1224,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
                }
 
                if (!err && ddr) {
-                       err = mmc_select_powerclass(card, ext_csd_bits[idx][1],
-                                                   ext_csd);
+                       err = mmc_select_powerclass(card, ext_csd_bits[idx][1]);
                        if (err)
                                pr_warning("%s: power class selection to "
                                           "bus width %d ddr %d failed\n",
@@ -1321,6 +1349,45 @@ err:
        return err;
 }
 
+static int mmc_can_sleep(struct mmc_card *card)
+{
+       return (card && card->ext_csd.rev >= 3);
+}
+
+static int mmc_sleep(struct mmc_host *host)
+{
+       struct mmc_command cmd = {0};
+       struct mmc_card *card = host->card;
+       int err;
+
+       if (host->caps2 & MMC_CAP2_NO_SLEEP_CMD)
+               return 0;
+
+       err = mmc_deselect_cards(host);
+       if (err)
+               return err;
+
+       cmd.opcode = MMC_SLEEP_AWAKE;
+       cmd.arg = card->rca << 16;
+       cmd.arg |= 1 << 15;
+
+       cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
+       err = mmc_wait_for_cmd(host, &cmd, 0);
+       if (err)
+               return err;
+
+       /*
+        * If the host does not wait while the card signals busy, then we will
+        * will have to wait the sleep/awake timeout.  Note, we cannot use the
+        * SEND_STATUS command to poll the status because that command (and most
+        * others) is invalid while the card sleeps.
+        */
+       if (!(host->caps & MMC_CAP_WAIT_WHILE_BUSY))
+               mmc_delay(DIV_ROUND_UP(card->ext_csd.sa_timeout, 10000));
+
+       return err;
+}
+
 static int mmc_can_poweroff_notify(const struct mmc_card *card)
 {
        return card &&
@@ -1380,14 +1447,14 @@ static void mmc_detect(struct mmc_host *host)
        BUG_ON(!host);
        BUG_ON(!host->card);
 
-       mmc_claim_host(host);
+       mmc_get_card(host->card);
 
        /*
         * Just check if our card has been removed.
         */
        err = _mmc_detect_card_removed(host);
 
-       mmc_release_host(host);
+       mmc_put_card(host->card);
 
        if (err) {
                mmc_remove(host);
@@ -1399,36 +1466,60 @@ static void mmc_detect(struct mmc_host *host)
        }
 }
 
-/*
- * Suspend callback from host.
- */
-static int mmc_suspend(struct mmc_host *host)
+static int _mmc_suspend(struct mmc_host *host, bool is_suspend)
 {
        int err = 0;
+       unsigned int notify_type = is_suspend ? EXT_CSD_POWER_OFF_SHORT :
+                                       EXT_CSD_POWER_OFF_LONG;
 
        BUG_ON(!host);
        BUG_ON(!host->card);
 
        mmc_claim_host(host);
 
+       if (mmc_card_doing_bkops(host->card)) {
+               err = mmc_stop_bkops(host->card);
+               if (err)
+                       goto out;
+       }
+
        err = mmc_cache_ctrl(host, 0);
        if (err)
                goto out;
 
-       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 (mmc_can_poweroff_notify(host->card) &&
+               ((host->caps2 & MMC_CAP2_FULL_PWR_CYCLE) || !is_suspend))
+               err = mmc_poweroff_notify(host->card, notify_type);
+       else if (mmc_can_sleep(host->card))
+               err = mmc_sleep(host);
        else if (!mmc_host_is_spi(host))
                err = mmc_deselect_cards(host);
        host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_200);
 
+       if (!err)
+               mmc_power_off(host);
 out:
        mmc_release_host(host);
        return err;
 }
 
 /*
+ * Suspend callback from host.
+ */
+static int mmc_suspend(struct mmc_host *host)
+{
+       return _mmc_suspend(host, true);
+}
+
+/*
+ * Shutdown callback
+ */
+static int mmc_shutdown(struct mmc_host *host)
+{
+       return _mmc_suspend(host, false);
+}
+
+/*
  * Resume callback from host.
  *
  * This function tries to determine if the same card is still present
@@ -1442,74 +1533,94 @@ static int mmc_resume(struct mmc_host *host)
        BUG_ON(!host->card);
 
        mmc_claim_host(host);
+       mmc_power_up(host);
+       mmc_select_voltage(host, host->ocr);
        err = mmc_init_card(host, host->ocr, host->card);
        mmc_release_host(host);
 
        return err;
 }
 
-static int mmc_power_restore(struct mmc_host *host)
+
+/*
+ * Callback for runtime_suspend.
+ */
+static int mmc_runtime_suspend(struct mmc_host *host)
 {
-       int ret;
+       int err;
+
+       if (!(host->caps & MMC_CAP_AGGRESSIVE_PM))
+               return 0;
 
-       host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_200);
        mmc_claim_host(host);
-       ret = mmc_init_card(host, host->ocr, host->card);
-       mmc_release_host(host);
 
-       return ret;
+       err = mmc_suspend(host);
+       if (err) {
+               pr_err("%s: error %d doing aggessive suspend\n",
+                       mmc_hostname(host), err);
+               goto out;
+       }
+       mmc_power_off(host);
+
+out:
+       mmc_release_host(host);
+       return err;
 }
 
-static int mmc_sleep(struct mmc_host *host)
+/*
+ * Callback for runtime_resume.
+ */
+static int mmc_runtime_resume(struct mmc_host *host)
 {
-       struct mmc_card *card = host->card;
-       int err = -ENOSYS;
+       int err;
 
-       if (card && card->ext_csd.rev >= 3) {
-               err = mmc_card_sleepawake(host, 1);
-               if (err < 0)
-                       pr_debug("%s: Error %d while putting card into sleep",
-                                mmc_hostname(host), err);
-       }
+       if (!(host->caps & MMC_CAP_AGGRESSIVE_PM))
+               return 0;
 
-       return err;
+       mmc_claim_host(host);
+
+       mmc_power_up(host);
+       err = mmc_resume(host);
+       if (err)
+               pr_err("%s: error %d doing aggessive resume\n",
+                       mmc_hostname(host), err);
+
+       mmc_release_host(host);
+       return 0;
 }
 
-static int mmc_awake(struct mmc_host *host)
+static int mmc_power_restore(struct mmc_host *host)
 {
-       struct mmc_card *card = host->card;
-       int err = -ENOSYS;
+       int ret;
 
-       if (card && card->ext_csd.rev >= 3) {
-               err = mmc_card_sleepawake(host, 0);
-               if (err < 0)
-                       pr_debug("%s: Error %d while awaking sleeping card",
-                                mmc_hostname(host), err);
-       }
+       host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_200);
+       mmc_claim_host(host);
+       ret = mmc_init_card(host, host->ocr, host->card);
+       mmc_release_host(host);
 
-       return err;
+       return ret;
 }
 
 static const struct mmc_bus_ops mmc_ops = {
-       .awake = mmc_awake,
-       .sleep = mmc_sleep,
        .remove = mmc_remove,
        .detect = mmc_detect,
        .suspend = NULL,
        .resume = NULL,
        .power_restore = mmc_power_restore,
        .alive = mmc_alive,
+       .shutdown = mmc_shutdown,
 };
 
 static const struct mmc_bus_ops mmc_ops_unsafe = {
-       .awake = mmc_awake,
-       .sleep = mmc_sleep,
        .remove = mmc_remove,
        .detect = mmc_detect,
        .suspend = mmc_suspend,
        .resume = mmc_resume,
+       .runtime_suspend = mmc_runtime_suspend,
+       .runtime_resume = mmc_runtime_resume,
        .power_restore = mmc_power_restore,
        .alive = mmc_alive,
+       .shutdown = mmc_shutdown,
 };
 
 static void mmc_attach_bus_ops(struct mmc_host *host)
index 49f04bc..837fc73 100644 (file)
@@ -59,40 +59,6 @@ int mmc_deselect_cards(struct mmc_host *host)
        return _mmc_select_card(host, NULL);
 }
 
-int mmc_card_sleepawake(struct mmc_host *host, int sleep)
-{
-       struct mmc_command cmd = {0};
-       struct mmc_card *card = host->card;
-       int err;
-
-       if (sleep)
-               mmc_deselect_cards(host);
-
-       cmd.opcode = MMC_SLEEP_AWAKE;
-       cmd.arg = card->rca << 16;
-       if (sleep)
-               cmd.arg |= 1 << 15;
-
-       cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
-       err = mmc_wait_for_cmd(host, &cmd, 0);
-       if (err)
-               return err;
-
-       /*
-        * If the host does not wait while the card signals busy, then we will
-        * will have to wait the sleep/awake timeout.  Note, we cannot use the
-        * SEND_STATUS command to poll the status because that command (and most
-        * others) is invalid while the card sleeps.
-        */
-       if (!(host->caps & MMC_CAP_WAIT_WHILE_BUSY))
-               mmc_delay(DIV_ROUND_UP(card->ext_csd.sa_timeout, 10000));
-
-       if (!sleep)
-               err = mmc_select_card(card);
-
-       return err;
-}
-
 int mmc_go_idle(struct mmc_host *host)
 {
        int err;
@@ -431,6 +397,8 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
 
 
        cmd.cmd_timeout_ms = timeout_ms;
+       if (index == EXT_CSD_SANITIZE_START)
+               cmd.sanitize_busy = true;
 
        err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES);
        if (err)
index 3dd8941..80ae9f4 100644 (file)
@@ -24,7 +24,6 @@ int mmc_send_status(struct mmc_card *card, u32 *status);
 int mmc_send_cid(struct mmc_host *host, u32 *cid);
 int mmc_spi_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp);
 int mmc_spi_set_crc(struct mmc_host *host, int use_crc);
-int mmc_card_sleepawake(struct mmc_host *host, int sleep);
 int mmc_bus_test(struct mmc_card *card, u8 bus_width);
 int mmc_send_hpi_cmd(struct mmc_card *card, u32 *status);
 
index 9e645e1..176d125 100644 (file)
@@ -646,8 +646,13 @@ static int mmc_sd_init_uhs_card(struct mmc_card *card)
        if (err)
                goto out;
 
-       /* SPI mode doesn't define CMD19 */
-       if (!mmc_host_is_spi(card->host) && card->host->ops->execute_tuning) {
+       /*
+        * SPI mode doesn't define CMD19 and tuning is only valid for SDR50 and
+        * SDR104 mode SD-cards. Note that tuning is mandatory for SDR104.
+        */
+       if (!mmc_host_is_spi(card->host) && card->host->ops->execute_tuning &&
+                       (card->sd_bus_speed == UHS_SDR50_BUS_SPEED ||
+                        card->sd_bus_speed == UHS_SDR104_BUS_SPEED)) {
                mmc_host_clk_hold(card->host);
                err = card->host->ops->execute_tuning(card->host,
                                                      MMC_SEND_TUNING_BLOCK);
@@ -1037,14 +1042,14 @@ static void mmc_sd_detect(struct mmc_host *host)
        BUG_ON(!host);
        BUG_ON(!host->card);
 
-       mmc_claim_host(host);
+       mmc_get_card(host->card);
 
        /*
         * Just check if our card has been removed.
         */
        err = _mmc_detect_card_removed(host);
 
-       mmc_release_host(host);
+       mmc_put_card(host->card);
 
        if (err) {
                mmc_sd_remove(host);
@@ -1070,6 +1075,8 @@ static int mmc_sd_suspend(struct mmc_host *host)
        if (!mmc_host_is_spi(host))
                err = mmc_deselect_cards(host);
        host->card->state &= ~MMC_STATE_HIGHSPEED;
+       if (!err)
+               mmc_power_off(host);
        mmc_release_host(host);
 
        return err;
@@ -1089,12 +1096,61 @@ static int mmc_sd_resume(struct mmc_host *host)
        BUG_ON(!host->card);
 
        mmc_claim_host(host);
+       mmc_power_up(host);
+       mmc_select_voltage(host, host->ocr);
        err = mmc_sd_init_card(host, host->ocr, host->card);
        mmc_release_host(host);
 
        return err;
 }
 
+/*
+ * Callback for runtime_suspend.
+ */
+static int mmc_sd_runtime_suspend(struct mmc_host *host)
+{
+       int err;
+
+       if (!(host->caps & MMC_CAP_AGGRESSIVE_PM))
+               return 0;
+
+       mmc_claim_host(host);
+
+       err = mmc_sd_suspend(host);
+       if (err) {
+               pr_err("%s: error %d doing aggessive suspend\n",
+                       mmc_hostname(host), err);
+               goto out;
+       }
+       mmc_power_off(host);
+
+out:
+       mmc_release_host(host);
+       return err;
+}
+
+/*
+ * Callback for runtime_resume.
+ */
+static int mmc_sd_runtime_resume(struct mmc_host *host)
+{
+       int err;
+
+       if (!(host->caps & MMC_CAP_AGGRESSIVE_PM))
+               return 0;
+
+       mmc_claim_host(host);
+
+       mmc_power_up(host);
+       err = mmc_sd_resume(host);
+       if (err)
+               pr_err("%s: error %d doing aggessive resume\n",
+                       mmc_hostname(host), err);
+
+       mmc_release_host(host);
+       return 0;
+}
+
 static int mmc_sd_power_restore(struct mmc_host *host)
 {
        int ret;
@@ -1114,15 +1170,19 @@ static const struct mmc_bus_ops mmc_sd_ops = {
        .resume = NULL,
        .power_restore = mmc_sd_power_restore,
        .alive = mmc_sd_alive,
+       .shutdown = mmc_sd_suspend,
 };
 
 static const struct mmc_bus_ops mmc_sd_ops_unsafe = {
        .remove = mmc_sd_remove,
        .detect = mmc_sd_detect,
+       .runtime_suspend = mmc_sd_runtime_suspend,
+       .runtime_resume = mmc_sd_runtime_resume,
        .suspend = mmc_sd_suspend,
        .resume = mmc_sd_resume,
        .power_restore = mmc_sd_power_restore,
        .alive = mmc_sd_alive,
+       .shutdown = mmc_sd_suspend,
 };
 
 static void mmc_sd_attach_bus_ops(struct mmc_host *host)
index 6889a82..80d89cf 100644 (file)
@@ -563,10 +563,18 @@ static int mmc_sdio_init_uhs_card(struct mmc_card *card)
        if (err)
                goto out;
 
-       /* Initialize and start re-tuning timer */
-       if (!mmc_host_is_spi(card->host) && card->host->ops->execute_tuning)
+       /*
+        * SPI mode doesn't define CMD19 and tuning is only valid for SDR50 and
+        * SDR104 mode SD-cards. Note that tuning is mandatory for SDR104.
+        */
+       if (!mmc_host_is_spi(card->host) && card->host->ops->execute_tuning &&
+                       ((card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR50) ||
+                        (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR104))) {
+               mmc_host_clk_hold(card->host);
                err = card->host->ops->execute_tuning(card->host,
                                                      MMC_SEND_TUNING_BLOCK);
+               mmc_host_clk_release(card->host);
+       }
 
 out:
 
@@ -902,11 +910,11 @@ out:
 }
 
 /*
- * SDIO suspend.  We need to suspend all functions separately.
+ * SDIO pre_suspend.  We need to suspend all functions separately.
  * Therefore all registered functions must have drivers with suspend
  * and resume methods.  Failing that we simply remove the whole card.
  */
-static int mmc_sdio_suspend(struct mmc_host *host)
+static int mmc_sdio_pre_suspend(struct mmc_host *host)
 {
        int i, err = 0;
 
@@ -917,8 +925,26 @@ static int mmc_sdio_suspend(struct mmc_host *host)
                        if (!pmops || !pmops->suspend || !pmops->resume) {
                                /* force removal of entire card in that case */
                                err = -ENOSYS;
-                       } else
-                               err = pmops->suspend(&func->dev);
+                               break;
+                       }
+               }
+       }
+
+       return err;
+}
+
+/*
+ * SDIO suspend.  Suspend all functions separately.
+ */
+static int mmc_sdio_suspend(struct mmc_host *host)
+{
+       int i, err = 0;
+
+       for (i = 0; i < host->card->sdio_funcs; i++) {
+               struct sdio_func *func = host->card->sdio_func[i];
+               if (func && sdio_func_present(func) && func->dev.driver) {
+                       const struct dev_pm_ops *pmops = func->dev.driver->pm;
+                       err = pmops->suspend(&func->dev);
                        if (err)
                                break;
                }
@@ -937,6 +963,9 @@ static int mmc_sdio_suspend(struct mmc_host *host)
                mmc_release_host(host);
        }
 
+       if (!err && !mmc_card_keep_power(host))
+               mmc_power_off(host);
+
        return err;
 }
 
@@ -950,6 +979,23 @@ static int mmc_sdio_resume(struct mmc_host *host)
        /* Basic card reinitialization. */
        mmc_claim_host(host);
 
+       /* Restore power if needed */
+       if (!mmc_card_keep_power(host)) {
+               mmc_power_up(host);
+               mmc_select_voltage(host, host->ocr);
+               /*
+                * Tell runtime PM core we just powered up the card,
+                * since it still believes the card is powered off.
+                * Note that currently runtime PM is only enabled
+                * for SDIO cards that are MMC_CAP_POWER_OFF_CARD
+                */
+               if (host->caps & MMC_CAP_POWER_OFF_CARD) {
+                       pm_runtime_disable(&host->card->dev);
+                       pm_runtime_set_active(&host->card->dev);
+                       pm_runtime_enable(&host->card->dev);
+               }
+       }
+
        /* No need to reinitialize powered-resumed nonremovable cards */
        if (mmc_card_is_removable(host) || !mmc_card_keep_power(host)) {
                sdio_reset(host);
@@ -987,6 +1033,7 @@ static int mmc_sdio_resume(struct mmc_host *host)
                }
        }
 
+       host->pm_flags &= ~MMC_PM_KEEP_POWER;
        return err;
 }
 
@@ -1051,11 +1098,28 @@ out:
        return ret;
 }
 
+static int mmc_sdio_runtime_suspend(struct mmc_host *host)
+{
+       /* No references to the card, cut the power to it. */
+       mmc_power_off(host);
+       return 0;
+}
+
+static int mmc_sdio_runtime_resume(struct mmc_host *host)
+{
+       /* Restore power and re-initialize. */
+       mmc_power_up(host);
+       return mmc_sdio_power_restore(host);
+}
+
 static const struct mmc_bus_ops mmc_sdio_ops = {
        .remove = mmc_sdio_remove,
        .detect = mmc_sdio_detect,
+       .pre_suspend = mmc_sdio_pre_suspend,
        .suspend = mmc_sdio_suspend,
        .resume = mmc_sdio_resume,
+       .runtime_suspend = mmc_sdio_runtime_suspend,
+       .runtime_resume = mmc_sdio_runtime_resume,
        .power_restore = mmc_sdio_power_restore,
        .alive = mmc_sdio_alive,
 };
index 9ab8f8d..8a4c066 100644 (file)
@@ -249,6 +249,17 @@ config MMC_SDHCI_S3C_DMA
 
          YMMV.
 
+config MMC_SDHCI_BCM_KONA
+       tristate "SDHCI support on Broadcom KONA platform"
+       depends on ARCH_BCM
+       select MMC_SDHCI_PLTFM
+       help
+         This selects the Broadcom Kona Secure Digital Host Controller
+         Interface(SDHCI) support.
+         This is used in Broadcom mobile SoCs.
+
+         If you have a controller with this interface, say Y or M here.
+
 config MMC_SDHCI_BCM2835
        tristate "SDHCI platform support for the BCM2835 SD/MMC Controller"
        depends on ARCH_BCM2835
@@ -556,6 +567,14 @@ config MMC_DW_EXYNOS
          Synopsys DesignWare Memory Card Interface driver. Select this option
          for platforms based on Exynos4 and Exynos5 SoC's.
 
+config MMC_DW_SOCFPGA
+       tristate "SOCFPGA specific extensions for Synopsys DW Memory Card Interface"
+       depends on MMC_DW
+       select MMC_DW_PLTFM
+       help
+         This selects support for Altera SoCFPGA specific extensions to the
+         Synopsys DesignWare Memory Card Interface driver.
+
 config MMC_DW_PCI
        tristate "Synopsys Designware MCI support on PCI bus"
        depends on MMC_DW && PCI
index cd32280..d422e21 100644 (file)
@@ -42,6 +42,7 @@ 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_SOCFPGA)   += dw_mmc-socfpga.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
@@ -60,6 +61,7 @@ obj-$(CONFIG_MMC_SDHCI_DOVE)          += sdhci-dove.o
 obj-$(CONFIG_MMC_SDHCI_TEGRA)          += sdhci-tegra.o
 obj-$(CONFIG_MMC_SDHCI_OF_ESDHC)       += sdhci-of-esdhc.o
 obj-$(CONFIG_MMC_SDHCI_OF_HLWD)                += sdhci-of-hlwd.o
+obj-$(CONFIG_MMC_SDHCI_BCM_KONA)       += sdhci-bcm-kona.o
 obj-$(CONFIG_MMC_SDHCI_BCM2835)                += sdhci-bcm2835.o
 
 ifeq ($(CONFIG_CB710_DEBUG),y)
index 7780c14..8b4e20a 100644 (file)
@@ -546,8 +546,6 @@ static int goldfish_mmc_remove(struct platform_device *pdev)
 {
        struct goldfish_mmc_host *host = platform_get_drvdata(pdev);
 
-       platform_set_drvdata(pdev, NULL);
-
        BUG_ON(host == NULL);
 
        mmc_remove_host(host->mmc);
index aca59d9..bdb84da 100644 (file)
@@ -40,8 +40,6 @@
 #include <asm/io.h>
 #include <asm/unaligned.h>
 
-#include <mach/cpu.h>
-
 #include "atmel-mci-regs.h"
 
 #define ATMCI_DATA_ERROR_FLAGS (ATMCI_DCRCE | ATMCI_DTOE | ATMCI_OVRE | ATMCI_UNRE)
@@ -2475,8 +2473,6 @@ static int __exit atmci_remove(struct platform_device *pdev)
        struct atmel_mci        *host = platform_get_drvdata(pdev);
        unsigned int            i;
 
-       platform_set_drvdata(pdev, NULL);
-
        if (host->buffer)
                dma_free_coherent(&pdev->dev, host->buf_size,
                                  host->buffer, host->buf_phys_addr);
@@ -2504,7 +2500,7 @@ static int __exit atmci_remove(struct platform_device *pdev)
        return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int atmci_suspend(struct device *dev)
 {
        struct atmel_mci *host = dev_get_drvdata(dev);
@@ -2559,17 +2555,15 @@ static int atmci_resume(struct device *dev)
 
        return ret;
 }
-static SIMPLE_DEV_PM_OPS(atmci_pm, atmci_suspend, atmci_resume);
-#define ATMCI_PM_OPS   (&atmci_pm)
-#else
-#define ATMCI_PM_OPS   NULL
 #endif
 
+static SIMPLE_DEV_PM_OPS(atmci_pm, atmci_suspend, atmci_resume);
+
 static struct platform_driver atmci_driver = {
        .remove         = __exit_p(atmci_remove),
        .driver         = {
                .name           = "atmel_mci",
-               .pm             = ATMCI_PM_OPS,
+               .pm             = &atmci_pm,
                .of_match_table = of_match_ptr(atmci_dt_ids),
        },
 };
index 127a8fa..df9becd 100644 (file)
@@ -1149,7 +1149,6 @@ static int au1xmmc_remove(struct platform_device *pdev)
                kfree(host->ioarea);
 
                mmc_free_host(host->mmc);
-               platform_set_drvdata(pdev, NULL);
        }
        return 0;
 }
index fb4348c..94fae2f 100644 (file)
@@ -621,8 +621,6 @@ static int sdh_remove(struct platform_device *pdev)
 {
        struct mmc_host *mmc = platform_get_drvdata(pdev);
 
-       platform_set_drvdata(pdev, NULL);
-
        if (mmc) {
                struct sdh_host *host = mmc_priv(mmc);
 
index 777ca20..9d6e2b8 100644 (file)
@@ -703,7 +703,7 @@ static int cb710_mmc_init(struct platform_device *pdev)
        if (!mmc)
                return -ENOMEM;
 
-       dev_set_drvdata(&pdev->dev, mmc);
+       platform_set_drvdata(pdev, mmc);
 
        /* harmless (maybe) magic */
        pci_read_config_dword(chip->pdev, 0x48, &val);
index e845c77..8984ec8 100644 (file)
@@ -24,7 +24,7 @@ struct cb710_mmc_reader {
 
 static inline struct mmc_host *cb710_slot_to_mmc(struct cb710_slot *slot)
 {
-       return dev_get_drvdata(&slot->pdev.dev);
+       return platform_get_drvdata(&slot->pdev);
 }
 
 static inline struct cb710_slot *cb710_mmc_to_slot(struct mmc_host *mmc)
index 5dfb70c..e9fa87d 100644 (file)
@@ -1407,7 +1407,6 @@ static int __exit davinci_mmcsd_remove(struct platform_device *pdev)
 {
        struct mmc_davinci_host *host = platform_get_drvdata(pdev);
 
-       platform_set_drvdata(pdev, NULL);
        if (host) {
                mmc_davinci_cpufreq_deregister(host);
 
index f013e7e..866edef 100644 (file)
@@ -31,8 +31,6 @@
                                        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
 
index 083fcd2..b456b0c 100644 (file)
@@ -21,7 +21,6 @@
 #include "dw_mmc.h"
 
 #define PCI_BAR_NO 2
-#define COMPLETE_BAR 0
 #define SYNOPSYS_DW_MCI_VENDOR_ID 0x700
 #define SYNOPSYS_DW_MCI_DEVICE_ID 0x1107
 /* Defining the Capabilities */
@@ -38,51 +37,37 @@ static struct dw_mci_board pci_board_data = {
 };
 
 static int dw_mci_pci_probe(struct pci_dev *pdev,
-                                 const struct pci_device_id *entries)
+                           const struct pci_device_id *entries)
 {
        struct dw_mci *host;
        int ret;
 
-       ret = pci_enable_device(pdev);
+       ret = pcim_enable_device(pdev);
        if (ret)
                return ret;
-       if (pci_request_regions(pdev, "dw_mmc_pci")) {
-               ret = -ENODEV;
-               goto err_disable_dev;
-       }
 
-       host = kzalloc(sizeof(struct dw_mci), GFP_KERNEL);
-       if (!host) {
-               ret = -ENOMEM;
-               goto err_release;
-       }
+       host = devm_kzalloc(&pdev->dev, sizeof(struct dw_mci), GFP_KERNEL);
+       if (!host)
+               return -ENOMEM;
 
        host->irq = pdev->irq;
        host->irq_flags = IRQF_SHARED;
        host->dev = &pdev->dev;
        host->pdata = &pci_board_data;
 
-       host->regs = pci_iomap(pdev, PCI_BAR_NO, COMPLETE_BAR);
-       if (!host->regs) {
-               ret = -EIO;
-               goto err_unmap;
-       }
+       ret = pcim_iomap_regions(pdev, 1 << PCI_BAR_NO, pci_name(pdev));
+       if (ret)
+               return ret;
+
+       host->regs = pcim_iomap_table(pdev)[0];
 
-       pci_set_drvdata(pdev, host);
        ret = dw_mci_probe(host);
        if (ret)
-               goto err_probe_failed;
-       return ret;
-
-err_probe_failed:
-       pci_iounmap(pdev, host->regs);
-err_unmap:
-       kfree(host);
-err_release:
-       pci_release_regions(pdev);
-err_disable_dev:
-       pci_disable_device(pdev);
-       return ret;
+               return ret;
+
+       pci_set_drvdata(pdev, host);
+
+       return 0;
 }
 
 static void dw_mci_pci_remove(struct pci_dev *pdev)
@@ -90,32 +75,23 @@ static void dw_mci_pci_remove(struct pci_dev *pdev)
        struct dw_mci *host = pci_get_drvdata(pdev);
 
        dw_mci_remove(host);
-       pci_set_drvdata(pdev, NULL);
-       pci_release_regions(pdev);
-       pci_iounmap(pdev, host->regs);
-       kfree(host);
-       pci_disable_device(pdev);
 }
 
 #ifdef CONFIG_PM_SLEEP
 static int dw_mci_pci_suspend(struct device *dev)
 {
-       int ret;
        struct pci_dev *pdev = to_pci_dev(dev);
        struct dw_mci *host = pci_get_drvdata(pdev);
 
-       ret = dw_mci_suspend(host);
-       return ret;
+       return dw_mci_suspend(host);
 }
 
 static int dw_mci_pci_resume(struct device *dev)
 {
-       int ret;
        struct pci_dev *pdev = to_pci_dev(dev);
        struct dw_mci *host = pci_get_drvdata(pdev);
 
-       ret = dw_mci_resume(host);
-       return ret;
+       return dw_mci_resume(host);
 }
 #else
 #define dw_mci_pci_suspend     NULL
index 41c27b7..ee52556 100644 (file)
 
 #include "dw_mmc.h"
 
+static void dw_mci_rockchip_prepare_command(struct dw_mci *host, u32 *cmdr)
+{
+       *cmdr |= SDMMC_CMD_USE_HOLD_REG;
+}
+
+static const struct dw_mci_drv_data rockchip_drv_data = {
+       .prepare_command        = dw_mci_rockchip_prepare_command,
+};
+
 int dw_mci_pltfm_register(struct platform_device *pdev,
-                               const struct dw_mci_drv_data *drv_data)
+                         const struct dw_mci_drv_data *drv_data)
 {
        struct dw_mci *host;
        struct resource *regs;
@@ -35,10 +44,6 @@ int dw_mci_pltfm_register(struct platform_device *pdev,
        if (!host)
                return -ENOMEM;
 
-       regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!regs)
-               return -ENXIO;
-
        host->irq = platform_get_irq(pdev, 0);
        if (host->irq < 0)
                return host->irq;
@@ -47,6 +52,8 @@ int dw_mci_pltfm_register(struct platform_device *pdev,
        host->dev = &pdev->dev;
        host->irq_flags = 0;
        host->pdata = pdev->dev.platform_data;
+
+       regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        host->regs = devm_ioremap_resource(&pdev->dev, regs);
        if (IS_ERR(host->regs))
                return PTR_ERR(host->regs);
@@ -58,52 +65,26 @@ int dw_mci_pltfm_register(struct platform_device *pdev,
        }
 
        platform_set_drvdata(pdev, host);
-       ret = dw_mci_probe(host);
-       return ret;
+       return dw_mci_probe(host);
 }
 EXPORT_SYMBOL_GPL(dw_mci_pltfm_register);
 
-static int dw_mci_pltfm_probe(struct platform_device *pdev)
-{
-       return dw_mci_pltfm_register(pdev, NULL);
-}
-
-static int 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);
-       return 0;
-}
-EXPORT_SYMBOL_GPL(dw_mci_pltfm_remove);
-
 #ifdef CONFIG_PM_SLEEP
 /*
  * TODO: we should probably disable the clock to the card in the suspend path.
  */
 static int dw_mci_pltfm_suspend(struct device *dev)
 {
-       int ret;
        struct dw_mci *host = dev_get_drvdata(dev);
 
-       ret = dw_mci_suspend(host);
-       if (ret)
-               return ret;
-
-       return 0;
+       return dw_mci_suspend(host);
 }
 
 static int dw_mci_pltfm_resume(struct device *dev)
 {
-       int ret;
        struct dw_mci *host = dev_get_drvdata(dev);
 
-       ret = dw_mci_resume(host);
-       if (ret)
-               return ret;
-
-       return 0;
+       return dw_mci_resume(host);
 }
 #else
 #define dw_mci_pltfm_suspend   NULL
@@ -115,10 +96,34 @@ EXPORT_SYMBOL_GPL(dw_mci_pltfm_pmops);
 
 static const struct of_device_id dw_mci_pltfm_match[] = {
        { .compatible = "snps,dw-mshc", },
+       { .compatible = "rockchip,rk2928-dw-mshc",
+               .data = &rockchip_drv_data },
        {},
 };
 MODULE_DEVICE_TABLE(of, dw_mci_pltfm_match);
 
+static int dw_mci_pltfm_probe(struct platform_device *pdev)
+{
+       const struct dw_mci_drv_data *drv_data = NULL;
+       const struct of_device_id *match;
+
+       if (pdev->dev.of_node) {
+               match = of_match_node(dw_mci_pltfm_match, pdev->dev.of_node);
+               drv_data = match->data;
+       }
+
+       return dw_mci_pltfm_register(pdev, drv_data);
+}
+
+int dw_mci_pltfm_remove(struct platform_device *pdev)
+{
+       struct dw_mci *host = platform_get_drvdata(pdev);
+
+       dw_mci_remove(host);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(dw_mci_pltfm_remove);
+
 static struct platform_driver dw_mci_pltfm_driver = {
        .probe          = dw_mci_pltfm_probe,
        .remove         = dw_mci_pltfm_remove,
diff --git a/drivers/mmc/host/dw_mmc-socfpga.c b/drivers/mmc/host/dw_mmc-socfpga.c
new file mode 100644 (file)
index 0000000..14b5961
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ * Altera SoCFPGA Specific Extensions for Synopsys DW Multimedia Card Interface
+ * driver
+ *
+ *  Copyright (C) 2012, Samsung Electronics Co., Ltd.
+ *  Copyright (C) 2013 Altera Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Taken from dw_mmc-exynos.c
+ */
+#include <linux/clk.h>
+#include <linux/mfd/syscon.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/dw_mmc.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#include "dw_mmc.h"
+#include "dw_mmc-pltfm.h"
+
+#define SYSMGR_SDMMCGRP_CTRL_OFFSET            0x108
+#define DRV_CLK_PHASE_SHIFT_SEL_MASK   0x7
+#define SYSMGR_SDMMC_CTRL_SET(smplsel, drvsel)          \
+       ((((smplsel) & 0x7) << 3) | (((drvsel) & 0x7) << 0))
+
+/* SOCFPGA implementation specific driver private data */
+struct dw_mci_socfpga_priv_data {
+       u8      ciu_div; /* card interface unit divisor */
+       u32     hs_timing; /* bitmask for CIU clock phase shift */
+       struct regmap   *sysreg; /* regmap for system manager register */
+};
+
+static int dw_mci_socfpga_priv_init(struct dw_mci *host)
+{
+       struct dw_mci_socfpga_priv_data *priv;
+
+       priv = devm_kzalloc(host->dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv) {
+               dev_err(host->dev, "mem alloc failed for private data\n");
+               return -ENOMEM;
+       }
+
+       priv->sysreg = syscon_regmap_lookup_by_compatible("altr,sys-mgr");
+       if (IS_ERR(priv->sysreg)) {
+               dev_err(host->dev, "regmap for altr,sys-mgr lookup failed.\n");
+               return PTR_ERR(priv->sysreg);
+       }
+       host->priv = priv;
+
+       return 0;
+}
+
+static int dw_mci_socfpga_setup_clock(struct dw_mci *host)
+{
+       struct dw_mci_socfpga_priv_data *priv = host->priv;
+
+       clk_disable_unprepare(host->ciu_clk);
+       regmap_write(priv->sysreg, SYSMGR_SDMMCGRP_CTRL_OFFSET,
+               priv->hs_timing);
+       clk_prepare_enable(host->ciu_clk);
+
+       host->bus_hz /= (priv->ciu_div + 1);
+       return 0;
+}
+
+static void dw_mci_socfpga_prepare_command(struct dw_mci *host, u32 *cmdr)
+{
+       struct dw_mci_socfpga_priv_data *priv = host->priv;
+
+       if (priv->hs_timing & DRV_CLK_PHASE_SHIFT_SEL_MASK)
+               *cmdr |= SDMMC_CMD_USE_HOLD_REG;
+}
+
+static int dw_mci_socfpga_parse_dt(struct dw_mci *host)
+{
+       struct dw_mci_socfpga_priv_data *priv = host->priv;
+       struct device_node *np = host->dev->of_node;
+       u32 timing[2];
+       u32 div = 0;
+       int ret;
+
+       ret = of_property_read_u32(np, "altr,dw-mshc-ciu-div", &div);
+       if (ret)
+               dev_info(host->dev, "No dw-mshc-ciu-div specified, assuming 1");
+       priv->ciu_div = div;
+
+       ret = of_property_read_u32_array(np,
+                       "altr,dw-mshc-sdr-timing", timing, 2);
+       if (ret)
+               return ret;
+
+       priv->hs_timing = SYSMGR_SDMMC_CTRL_SET(timing[0], timing[1]);
+       return 0;
+}
+
+static const struct dw_mci_drv_data socfpga_drv_data = {
+       .init                   = dw_mci_socfpga_priv_init,
+       .setup_clock            = dw_mci_socfpga_setup_clock,
+       .prepare_command        = dw_mci_socfpga_prepare_command,
+       .parse_dt               = dw_mci_socfpga_parse_dt,
+};
+
+static const struct of_device_id dw_mci_socfpga_match[] = {
+       { .compatible = "altr,socfpga-dw-mshc",
+                       .data = &socfpga_drv_data, },
+       {},
+};
+MODULE_DEVICE_TABLE(of, dw_mci_socfpga_match);
+
+int dw_mci_socfpga_probe(struct platform_device *pdev)
+{
+       const struct dw_mci_drv_data *drv_data;
+       const struct of_device_id *match;
+
+       match = of_match_node(dw_mci_socfpga_match, pdev->dev.of_node);
+       drv_data = match->data;
+       return dw_mci_pltfm_register(pdev, drv_data);
+}
+
+static struct platform_driver dw_mci_socfpga_pltfm_driver = {
+       .probe          = dw_mci_socfpga_probe,
+       .remove         = __exit_p(dw_mci_pltfm_remove),
+       .driver         = {
+               .name           = "dwmmc_socfpga",
+               .of_match_table = of_match_ptr(dw_mci_socfpga_match),
+               .pm             = &dw_mci_pltfm_pmops,
+       },
+};
+
+module_platform_driver(dw_mci_socfpga_pltfm_driver);
+
+MODULE_DESCRIPTION("Altera SOCFPGA Specific DW-MSHC Driver Extension");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:dwmmc-socfpga");
index bc3a1bc..ee5f167 100644 (file)
@@ -39,7 +39,7 @@
 #include "dw_mmc.h"
 
 /* Common flag combinations */
-#define DW_MCI_DATA_ERROR_FLAGS        (SDMMC_INT_DTO | SDMMC_INT_DCRC | \
+#define DW_MCI_DATA_ERROR_FLAGS        (SDMMC_INT_DRTO | SDMMC_INT_DCRC | \
                                 SDMMC_INT_HTO | SDMMC_INT_SBE  | \
                                 SDMMC_INT_EBE)
 #define DW_MCI_CMD_ERROR_FLAGS (SDMMC_INT_RTO | SDMMC_INT_RCRC | \
 #define DW_MCI_DMA_THRESHOLD   16
 
 #ifdef CONFIG_MMC_DW_IDMAC
+#define IDMAC_INT_CLR          (SDMMC_IDMAC_INT_AI | SDMMC_IDMAC_INT_NI | \
+                                SDMMC_IDMAC_INT_CES | SDMMC_IDMAC_INT_DU | \
+                                SDMMC_IDMAC_INT_FBE | SDMMC_IDMAC_INT_RI | \
+                                SDMMC_IDMAC_INT_TI)
+
 struct idmac_desc {
        u32             des0;   /* Control Descriptor */
 #define IDMAC_DES0_DIC BIT(1)
@@ -433,6 +438,7 @@ static int dw_mci_idmac_init(struct dw_mci *host)
        mci_writel(host, BMOD, SDMMC_IDMAC_SWRESET);
 
        /* Mask out interrupts - get Tx & Rx complete only */
+       mci_writel(host, IDSTS, IDMAC_INT_CLR);
        mci_writel(host, IDINTEN, SDMMC_IDMAC_INT_NI | SDMMC_IDMAC_INT_RI |
                   SDMMC_IDMAC_INT_TI);
 
@@ -1087,7 +1093,7 @@ static void dw_mci_tasklet_func(unsigned long priv)
                        status = host->data_status;
 
                        if (status & DW_MCI_DATA_ERROR_FLAGS) {
-                               if (status & SDMMC_INT_DTO) {
+                               if (status & SDMMC_INT_DRTO) {
                                        data->error = -ETIMEDOUT;
                                } else if (status & SDMMC_INT_DCRC) {
                                        data->error = -EILSEQ;
@@ -1985,19 +1991,6 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
 #endif /* CONFIG_MMC_DW_IDMAC */
        }
 
-       host->vmmc = devm_regulator_get(mmc_dev(mmc), "vmmc");
-       if (IS_ERR(host->vmmc)) {
-               pr_info("%s: no vmmc regulator found\n", mmc_hostname(mmc));
-               host->vmmc = NULL;
-       } else {
-               ret = regulator_enable(host->vmmc);
-               if (ret) {
-                       dev_err(host->dev,
-                               "failed to enable regulator: %d\n", ret);
-                       goto err_setup_bus;
-               }
-       }
-
        if (dw_mci_get_cd(mmc))
                set_bit(DW_MMC_CARD_PRESENT, &slot->flags);
        else
@@ -2124,6 +2117,7 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
        struct device_node *np = dev->of_node;
        const struct dw_mci_drv_data *drv_data = host->drv_data;
        int idx, ret;
+       u32 clock_frequency;
 
        pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
        if (!pdata) {
@@ -2150,6 +2144,9 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
 
        of_property_read_u32(np, "card-detect-delay", &pdata->detect_delay_ms);
 
+       if (!of_property_read_u32(np, "clock-frequency", &clock_frequency))
+               pdata->bus_hz = clock_frequency;
+
        if (drv_data && drv_data->parse_dt) {
                ret = drv_data->parse_dt(host);
                if (ret)
@@ -2207,18 +2204,23 @@ int dw_mci_probe(struct dw_mci *host)
        host->ciu_clk = devm_clk_get(host->dev, "ciu");
        if (IS_ERR(host->ciu_clk)) {
                dev_dbg(host->dev, "ciu clock not available\n");
+               host->bus_hz = host->pdata->bus_hz;
        } else {
                ret = clk_prepare_enable(host->ciu_clk);
                if (ret) {
                        dev_err(host->dev, "failed to enable ciu clock\n");
                        goto err_clk_biu;
                }
-       }
 
-       if (IS_ERR(host->ciu_clk))
-               host->bus_hz = host->pdata->bus_hz;
-       else
+               if (host->pdata->bus_hz) {
+                       ret = clk_set_rate(host->ciu_clk, host->pdata->bus_hz);
+                       if (ret)
+                               dev_warn(host->dev,
+                                        "Unable to set bus rate to %ul\n",
+                                        host->pdata->bus_hz);
+               }
                host->bus_hz = clk_get_rate(host->ciu_clk);
+       }
 
        if (drv_data && drv_data->setup_clock) {
                ret = drv_data->setup_clock(host);
@@ -2229,11 +2231,29 @@ int dw_mci_probe(struct dw_mci *host)
                }
        }
 
+       host->vmmc = devm_regulator_get(host->dev, "vmmc");
+       if (IS_ERR(host->vmmc)) {
+               ret = PTR_ERR(host->vmmc);
+               if (ret == -EPROBE_DEFER)
+                       goto err_clk_ciu;
+
+               dev_info(host->dev, "no vmmc regulator found: %d\n", ret);
+               host->vmmc = NULL;
+       } else {
+               ret = regulator_enable(host->vmmc);
+               if (ret) {
+                       if (ret != -EPROBE_DEFER)
+                               dev_err(host->dev,
+                                       "regulator_enable fail: %d\n", ret);
+                       goto err_clk_ciu;
+               }
+       }
+
        if (!host->bus_hz) {
                dev_err(host->dev,
                        "Platform data must supply bus speed\n");
                ret = -ENODEV;
-               goto err_clk_ciu;
+               goto err_regulator;
        }
 
        host->quirks = host->pdata->quirks;
@@ -2321,8 +2341,10 @@ int dw_mci_probe(struct dw_mci *host)
        tasklet_init(&host->tasklet, dw_mci_tasklet_func, (unsigned long)host);
        host->card_workqueue = alloc_workqueue("dw-mci-card",
                        WQ_MEM_RECLAIM | WQ_NON_REENTRANT, 1);
-       if (!host->card_workqueue)
+       if (!host->card_workqueue) {
+               ret = -ENOMEM;
                goto err_dmaunmap;
+       }
        INIT_WORK(&host->card_work, dw_mci_work_routine_card);
        ret = devm_request_irq(host->dev, host->irq, dw_mci_interrupt,
                               host->irq_flags, "dw-mci", host);
@@ -2378,6 +2400,7 @@ err_dmaunmap:
        if (host->use_dma && host->dma_ops->exit)
                host->dma_ops->exit(host);
 
+err_regulator:
        if (host->vmmc)
                regulator_disable(host->vmmc);
 
index 0b74189..81b2994 100644 (file)
@@ -98,7 +98,7 @@
 #define SDMMC_INT_HLE                  BIT(12)
 #define SDMMC_INT_FRUN                 BIT(11)
 #define SDMMC_INT_HTO                  BIT(10)
-#define SDMMC_INT_DTO                  BIT(9)
+#define SDMMC_INT_DRTO                 BIT(9)
 #define SDMMC_INT_RTO                  BIT(8)
 #define SDMMC_INT_DCRC                 BIT(7)
 #define SDMMC_INT_RCRC                 BIT(6)
 #define SDMMC_INT_ERROR                        0xbfc2
 /* Command register defines */
 #define SDMMC_CMD_START                        BIT(31)
+#define SDMMC_CMD_USE_HOLD_REG BIT(29)
 #define SDMMC_CMD_CCS_EXP              BIT(23)
 #define SDMMC_CMD_CEATA_RD             BIT(22)
 #define SDMMC_CMD_UPD_CLK              BIT(21)
index 2391c6b..0308c9f 100644 (file)
@@ -14,6 +14,7 @@
  */
 
 #include <linux/mmc/host.h>
+#include <linux/mmc/slot-gpio.h>
 #include <linux/err.h>
 #include <linux/io.h>
 #include <linux/irq.h>
@@ -120,7 +121,6 @@ struct jz4740_mmc_host {
        int irq;
        int card_detect_irq;
 
-       struct resource *mem;
        void __iomem *base;
        struct mmc_request *req;
        struct mmc_command *cmd;
@@ -231,6 +231,14 @@ static void jz4740_mmc_transfer_check_state(struct jz4740_mmc_host *host,
                        host->req->cmd->error = -EIO;
                        data->error = -EIO;
                }
+       } else if (status & JZ_MMC_STATUS_READ_ERROR_MASK) {
+               if (status & (JZ_MMC_STATUS_TIMEOUT_READ)) {
+                       host->req->cmd->error = -ETIMEDOUT;
+                       data->error = -ETIMEDOUT;
+               } else {
+                       host->req->cmd->error = -EIO;
+                       data->error = -EIO;
+               }
        }
 }
 
@@ -560,11 +568,6 @@ static irqreturn_t jz_mmc_irq(int irq, void *devid)
                                        if (cmd->data)
                                                        cmd->data->error = -EIO;
                                        cmd->error = -EIO;
-                       } else if (status & (JZ_MMC_STATUS_CRC_READ_ERROR |
-                                       JZ_MMC_STATUS_CRC_WRITE_ERROR)) {
-                                       if (cmd->data)
-                                                       cmd->data->error = -EIO;
-                                       cmd->error = -EIO;
                        }
 
                        jz4740_mmc_set_irq_enabled(host, irq_reg, false);
@@ -626,7 +629,7 @@ static void jz4740_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
                        gpio_set_value(host->pdata->gpio_power,
                                        !host->pdata->power_active_low);
                host->cmdat |= JZ_MMC_CMDAT_INIT;
-               clk_enable(host->clk);
+               clk_prepare_enable(host->clk);
                break;
        case MMC_POWER_ON:
                break;
@@ -634,7 +637,7 @@ static void jz4740_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
                if (gpio_is_valid(host->pdata->gpio_power))
                        gpio_set_value(host->pdata->gpio_power,
                                        host->pdata->power_active_low);
-               clk_disable(host->clk);
+               clk_disable_unprepare(host->clk);
                break;
        }
 
@@ -650,35 +653,6 @@ static void jz4740_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
        }
 }
 
-static int jz4740_mmc_get_ro(struct mmc_host *mmc)
-{
-       struct jz4740_mmc_host *host = mmc_priv(mmc);
-       if (!gpio_is_valid(host->pdata->gpio_read_only))
-               return -ENOSYS;
-
-       return gpio_get_value(host->pdata->gpio_read_only) ^
-               host->pdata->read_only_active_low;
-}
-
-static int jz4740_mmc_get_cd(struct mmc_host *mmc)
-{
-       struct jz4740_mmc_host *host = mmc_priv(mmc);
-       if (!gpio_is_valid(host->pdata->gpio_card_detect))
-               return -ENOSYS;
-
-       return gpio_get_value(host->pdata->gpio_card_detect) ^
-                       host->pdata->card_detect_active_low;
-}
-
-static irqreturn_t jz4740_mmc_card_detect_irq(int irq, void *devid)
-{
-       struct jz4740_mmc_host *host = devid;
-
-       mmc_detect_change(host->mmc, HZ / 2);
-
-       return IRQ_HANDLED;
-}
-
 static void jz4740_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable)
 {
        struct jz4740_mmc_host *host = mmc_priv(mmc);
@@ -688,8 +662,8 @@ static void jz4740_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable)
 static const struct mmc_host_ops jz4740_mmc_ops = {
        .request        = jz4740_mmc_request,
        .set_ios        = jz4740_mmc_set_ios,
-       .get_ro         = jz4740_mmc_get_ro,
-       .get_cd         = jz4740_mmc_get_cd,
+       .get_ro         = mmc_gpio_get_ro,
+       .get_cd         = mmc_gpio_get_cd,
        .enable_sdio_irq = jz4740_mmc_enable_sdio_irq,
 };
 
@@ -724,58 +698,34 @@ static int jz4740_mmc_request_gpio(struct device *dev, int gpio,
        return 0;
 }
 
-static int jz4740_mmc_request_gpios(struct platform_device *pdev)
+static int jz4740_mmc_request_gpios(struct mmc_host *mmc,
+       struct platform_device *pdev)
 {
-       int ret;
        struct jz4740_mmc_platform_data *pdata = pdev->dev.platform_data;
+       int ret = 0;
 
        if (!pdata)
                return 0;
 
-       ret = jz4740_mmc_request_gpio(&pdev->dev, pdata->gpio_card_detect,
-                       "MMC detect change", false, 0);
-       if (ret)
-               goto err;
-
-       ret = jz4740_mmc_request_gpio(&pdev->dev, pdata->gpio_read_only,
-                       "MMC read only", false, 0);
-       if (ret)
-               goto err_free_gpio_card_detect;
-
-       ret = jz4740_mmc_request_gpio(&pdev->dev, pdata->gpio_power,
-                       "MMC read only", true, pdata->power_active_low);
-       if (ret)
-               goto err_free_gpio_read_only;
-
-       return 0;
-
-err_free_gpio_read_only:
-       if (gpio_is_valid(pdata->gpio_read_only))
-               gpio_free(pdata->gpio_read_only);
-err_free_gpio_card_detect:
-       if (gpio_is_valid(pdata->gpio_card_detect))
-               gpio_free(pdata->gpio_card_detect);
-err:
-       return ret;
-}
-
-static int jz4740_mmc_request_cd_irq(struct platform_device *pdev,
-       struct jz4740_mmc_host *host)
-{
-       struct jz4740_mmc_platform_data *pdata = pdev->dev.platform_data;
+       if (!pdata->card_detect_active_low)
+               mmc->caps2 |= MMC_CAP2_CD_ACTIVE_HIGH;
+       if (!pdata->read_only_active_low)
+               mmc->caps2 |= MMC_CAP2_RO_ACTIVE_HIGH;
 
-       if (!gpio_is_valid(pdata->gpio_card_detect))
-               return 0;
+       if (gpio_is_valid(pdata->gpio_card_detect)) {
+               ret = mmc_gpio_request_cd(mmc, pdata->gpio_card_detect);
+               if (ret)
+                       return ret;
+       }
 
-       host->card_detect_irq = gpio_to_irq(pdata->gpio_card_detect);
-       if (host->card_detect_irq < 0) {
-               dev_warn(&pdev->dev, "Failed to get card detect irq\n");
-               return 0;
+       if (gpio_is_valid(pdata->gpio_read_only)) {
+               ret = mmc_gpio_request_ro(mmc, pdata->gpio_read_only);
+               if (ret)
+                       return ret;
        }
 
-       return request_irq(host->card_detect_irq, jz4740_mmc_card_detect_irq,
-                       IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
-                       "MMC card detect", host);
+       return jz4740_mmc_request_gpio(&pdev->dev, pdata->gpio_power,
+                       "MMC read only", true, pdata->power_active_low);
 }
 
 static void jz4740_mmc_free_gpios(struct platform_device *pdev)
@@ -787,10 +737,6 @@ static void jz4740_mmc_free_gpios(struct platform_device *pdev)
 
        if (gpio_is_valid(pdata->gpio_power))
                gpio_free(pdata->gpio_power);
-       if (gpio_is_valid(pdata->gpio_read_only))
-               gpio_free(pdata->gpio_read_only);
-       if (gpio_is_valid(pdata->gpio_card_detect))
-               gpio_free(pdata->gpio_card_detect);
 }
 
 static inline size_t jz4740_mmc_num_pins(struct jz4740_mmc_host *host)
@@ -808,6 +754,7 @@ static int jz4740_mmc_probe(struct platform_device* pdev)
        struct mmc_host *mmc;
        struct jz4740_mmc_host *host;
        struct jz4740_mmc_platform_data *pdata;
+       struct resource *res;
 
        pdata = pdev->dev.platform_data;
 
@@ -827,42 +774,28 @@ static int jz4740_mmc_probe(struct platform_device* pdev)
                goto err_free_host;
        }
 
-       host->clk = clk_get(&pdev->dev, "mmc");
+       host->clk = devm_clk_get(&pdev->dev, "mmc");
        if (IS_ERR(host->clk)) {
                ret = PTR_ERR(host->clk);
                dev_err(&pdev->dev, "Failed to get mmc clock\n");
                goto err_free_host;
        }
 
-       host->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!host->mem) {
-               ret = -ENOENT;
-               dev_err(&pdev->dev, "Failed to get base platform memory\n");
-               goto err_clk_put;
-       }
-
-       host->mem = request_mem_region(host->mem->start,
-                                       resource_size(host->mem), pdev->name);
-       if (!host->mem) {
-               ret = -EBUSY;
-               dev_err(&pdev->dev, "Failed to request base memory region\n");
-               goto err_clk_put;
-       }
-
-       host->base = ioremap_nocache(host->mem->start, resource_size(host->mem));
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       host->base = devm_ioremap_resource(&pdev->dev, res);
        if (!host->base) {
                ret = -EBUSY;
                dev_err(&pdev->dev, "Failed to ioremap base memory\n");
-               goto err_release_mem_region;
+               goto err_free_host;
        }
 
        ret = jz_gpio_bulk_request(jz4740_mmc_pins, jz4740_mmc_num_pins(host));
        if (ret) {
                dev_err(&pdev->dev, "Failed to request mmc pins: %d\n", ret);
-               goto err_iounmap;
+               goto err_free_host;
        }
 
-       ret = jz4740_mmc_request_gpios(pdev);
+       ret = jz4740_mmc_request_gpios(mmc, pdev);
        if (ret)
                goto err_gpio_bulk_free;
 
@@ -885,17 +818,11 @@ static int jz4740_mmc_probe(struct platform_device* pdev)
        spin_lock_init(&host->lock);
        host->irq_mask = 0xffff;
 
-       ret = jz4740_mmc_request_cd_irq(pdev, host);
-       if (ret) {
-               dev_err(&pdev->dev, "Failed to request card detect irq\n");
-               goto err_free_gpios;
-       }
-
        ret = request_threaded_irq(host->irq, jz_mmc_irq, jz_mmc_irq_worker, 0,
                        dev_name(&pdev->dev), host);
        if (ret) {
                dev_err(&pdev->dev, "Failed to request irq: %d\n", ret);
-               goto err_free_card_detect_irq;
+               goto err_free_gpios;
        }
 
        jz4740_mmc_reset(host);
@@ -918,21 +845,11 @@ static int jz4740_mmc_probe(struct platform_device* pdev)
 
 err_free_irq:
        free_irq(host->irq, host);
-err_free_card_detect_irq:
-       if (host->card_detect_irq >= 0)
-               free_irq(host->card_detect_irq, host);
 err_free_gpios:
        jz4740_mmc_free_gpios(pdev);
 err_gpio_bulk_free:
        jz_gpio_bulk_free(jz4740_mmc_pins, jz4740_mmc_num_pins(host));
-err_iounmap:
-       iounmap(host->base);
-err_release_mem_region:
-       release_mem_region(host->mem->start, resource_size(host->mem));
-err_clk_put:
-       clk_put(host->clk);
 err_free_host:
-       platform_set_drvdata(pdev, NULL);
        mmc_free_host(mmc);
 
        return ret;
@@ -949,24 +866,16 @@ static int jz4740_mmc_remove(struct platform_device *pdev)
        mmc_remove_host(host->mmc);
 
        free_irq(host->irq, host);
-       if (host->card_detect_irq >= 0)
-               free_irq(host->card_detect_irq, host);
 
        jz4740_mmc_free_gpios(pdev);
        jz_gpio_bulk_free(jz4740_mmc_pins, jz4740_mmc_num_pins(host));
 
-       iounmap(host->base);
-       release_mem_region(host->mem->start, resource_size(host->mem));
-
-       clk_put(host->clk);
-
-       platform_set_drvdata(pdev, NULL);
        mmc_free_host(host->mmc);
 
        return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 
 static int jz4740_mmc_suspend(struct device *dev)
 {
@@ -990,13 +899,8 @@ static int jz4740_mmc_resume(struct device *dev)
        return 0;
 }
 
-const struct dev_pm_ops jz4740_mmc_pm_ops = {
-       .suspend        = jz4740_mmc_suspend,
-       .resume         = jz4740_mmc_resume,
-       .poweroff       = jz4740_mmc_suspend,
-       .restore        = jz4740_mmc_resume,
-};
-
+static SIMPLE_DEV_PM_OPS(jz4740_mmc_pm_ops, jz4740_mmc_suspend,
+       jz4740_mmc_resume);
 #define JZ4740_MMC_PM_OPS (&jz4740_mmc_pm_ops)
 #else
 #define JZ4740_MMC_PM_OPS NULL
index 8960fc8..4ddd83f 100644 (file)
@@ -35,7 +35,7 @@
 
 #define DRIVER_NAME    "mvsdio"
 
-static int maxfreq = MVSD_CLOCKRATE_MAX;
+static int maxfreq;
 static int nodma;
 
 struct mvsd_host {
@@ -685,7 +685,6 @@ static int __init mvsd_probe(struct platform_device *pdev)
        const struct mbus_dram_target_info *dram;
        struct resource *r;
        int ret, irq;
-       int gpio_card_detect, gpio_write_protect;
        struct pinctrl *pinctrl;
 
        r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -718,6 +717,20 @@ static int __init mvsd_probe(struct platform_device *pdev)
        if (!IS_ERR(host->clk))
                clk_prepare_enable(host->clk);
 
+       mmc->ops = &mvsd_ops;
+
+       mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
+
+       mmc->f_min = DIV_ROUND_UP(host->base_clock, MVSD_BASE_DIV_MAX);
+       mmc->f_max = MVSD_CLOCKRATE_MAX;
+
+       mmc->max_blk_size = 2048;
+       mmc->max_blk_count = 65535;
+
+       mmc->max_segs = 1;
+       mmc->max_seg_size = mmc->max_blk_size * mmc->max_blk_count;
+       mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
+
        if (np) {
                if (IS_ERR(host->clk)) {
                        dev_err(&pdev->dev, "DT platforms must have a clock associated\n");
@@ -726,35 +739,38 @@ static int __init mvsd_probe(struct platform_device *pdev)
                }
 
                host->base_clock = clk_get_rate(host->clk) / 2;
-               gpio_card_detect = of_get_named_gpio(np, "cd-gpios", 0);
-               gpio_write_protect = of_get_named_gpio(np, "wp-gpios", 0);
+               ret = mmc_of_parse(mmc);
+               if (ret < 0)
+                       goto out;
        } else {
                const struct mvsdio_platform_data *mvsd_data;
+
                mvsd_data = pdev->dev.platform_data;
                if (!mvsd_data) {
                        ret = -ENXIO;
                        goto out;
                }
+               mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ |
+                           MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED;
                host->base_clock = mvsd_data->clock / 2;
-               gpio_card_detect = mvsd_data->gpio_card_detect ? : -EINVAL;
-               gpio_write_protect = mvsd_data->gpio_write_protect ? : -EINVAL;
-       }
-
-       mmc->ops = &mvsd_ops;
-
-       mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
-       mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ |
-                   MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED;
-
-       mmc->f_min = DIV_ROUND_UP(host->base_clock, MVSD_BASE_DIV_MAX);
-       mmc->f_max = maxfreq;
+               /* GPIO 0 regarded as invalid for backward compatibility */
+               if (mvsd_data->gpio_card_detect &&
+                   gpio_is_valid(mvsd_data->gpio_card_detect)) {
+                       ret = mmc_gpio_request_cd(mmc,
+                                                 mvsd_data->gpio_card_detect);
+                       if (ret)
+                               goto out;
+               } else {
+                       mmc->caps |= MMC_CAP_NEEDS_POLL;
+               }
 
-       mmc->max_blk_size = 2048;
-       mmc->max_blk_count = 65535;
+               if (mvsd_data->gpio_write_protect &&
+                   gpio_is_valid(mvsd_data->gpio_write_protect))
+                       mmc_gpio_request_ro(mmc, mvsd_data->gpio_write_protect);
+       }
 
-       mmc->max_segs = 1;
-       mmc->max_seg_size = mmc->max_blk_size * mmc->max_blk_count;
-       mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
+       if (maxfreq)
+               mmc->f_max = maxfreq;
 
        spin_lock_init(&host->lock);
 
@@ -777,15 +793,6 @@ static int __init mvsd_probe(struct platform_device *pdev)
                goto out;
        }
 
-       if (gpio_is_valid(gpio_card_detect)) {
-               ret = mmc_gpio_request_cd(mmc, gpio_card_detect);
-               if (ret)
-                       goto out;
-       } else
-               mmc->caps |= MMC_CAP_NEEDS_POLL;
-
-       mmc_gpio_request_ro(mmc, gpio_write_protect);
-
        setup_timer(&host->timer, mvsd_timeout_timer, (unsigned long)host);
        platform_set_drvdata(pdev, mmc);
        ret = mmc_add_host(mmc);
@@ -793,10 +800,10 @@ static int __init mvsd_probe(struct platform_device *pdev)
                goto out;
 
        if (!(mmc->caps & MMC_CAP_NEEDS_POLL))
-               dev_notice(&pdev->dev, "using GPIO %d for card detection\n",
-                          gpio_card_detect);
+               dev_notice(&pdev->dev, "using GPIO for card detection\n");
        else
-               dev_notice(&pdev->dev, "lacking card detect (fall back to polling)\n");
+               dev_notice(&pdev->dev,
+                          "lacking card detect (fall back to polling)\n");
        return 0;
 
 out:
@@ -827,7 +834,6 @@ static int __exit mvsd_remove(struct platform_device *pdev)
                clk_disable_unprepare(host->clk);
        mmc_free_host(mmc);
 
-       platform_set_drvdata(pdev, NULL);
        return 0;
 }
 
index d503635..c174c6a 100644 (file)
@@ -1067,7 +1067,9 @@ static int mxcmci_probe(struct platform_device *pdev)
                goto out_release_mem;
        }
 
-       mmc_of_parse(mmc);
+       ret = mmc_of_parse(mmc);
+       if (ret)
+               goto out_free;
        mmc->ops = &mxcmci_ops;
 
        /* For devicetree parsing, the bus width is read from devicetree */
@@ -1219,8 +1221,6 @@ static int mxcmci_remove(struct platform_device *pdev)
        struct mmc_host *mmc = platform_get_drvdata(pdev);
        struct mxcmci_host *host = mmc_priv(mmc);
 
-       platform_set_drvdata(pdev, NULL);
-
        mmc_remove_host(mmc);
 
        if (host->vcc)
index 4278a17..f38d75f 100644 (file)
@@ -41,7 +41,6 @@
 #include <linux/gpio.h>
 #include <linux/regulator/consumer.h>
 #include <linux/module.h>
-#include <linux/pinctrl/consumer.h>
 #include <linux/stmp_device.h>
 #include <linux/spi/mxs-spi.h>
 
@@ -580,7 +579,6 @@ static int mxs_mmc_probe(struct platform_device *pdev)
        struct mxs_mmc_host *host;
        struct mmc_host *mmc;
        struct resource *iores;
-       struct pinctrl *pinctrl;
        int ret = 0, irq_err;
        struct regulator *reg_vmmc;
        enum of_gpio_flags flags;
@@ -620,12 +618,6 @@ static int mxs_mmc_probe(struct platform_device *pdev)
                }
        }
 
-       pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
-       if (IS_ERR(pinctrl)) {
-               ret = PTR_ERR(pinctrl);
-               goto out_mmc_free;
-       }
-
        ssp->clk = clk_get(&pdev->dev, NULL);
        if (IS_ERR(ssp->clk)) {
                ret = PTR_ERR(ssp->clk);
@@ -639,6 +631,7 @@ static int mxs_mmc_probe(struct platform_device *pdev)
        if (!ssp->dmach) {
                dev_err(mmc_dev(host->mmc),
                        "%s: failed to request dma\n", __func__);
+               ret = -ENODEV;
                goto out_clk_put;
        }
 
@@ -708,8 +701,6 @@ static int mxs_mmc_remove(struct platform_device *pdev)
 
        mmc_remove_host(mmc);
 
-       platform_set_drvdata(pdev, NULL);
-
        if (ssp->dmach)
                dma_release_channel(ssp->dmach);
 
index 4254975..b94f38e 100644 (file)
@@ -1413,33 +1413,17 @@ static int mmc_omap_probe(struct platform_device *pdev)
        else
                sig = host->id == 0 ? OMAP_DMA_MMC_TX : OMAP_DMA_MMC2_TX;
        host->dma_tx = dma_request_channel(mask, omap_dma_filter_fn, &sig);
-#if 0
-       if (!host->dma_tx) {
-               dev_err(host->dev, "unable to obtain TX DMA engine channel %u\n",
-                       sig);
-               goto err_dma;
-       }
-#else
        if (!host->dma_tx)
                dev_warn(host->dev, "unable to obtain TX DMA engine channel %u\n",
                        sig);
-#endif
        if (mmc_omap2())
                sig = host->id == 0 ? OMAP24XX_DMA_MMC1_RX : OMAP24XX_DMA_MMC2_RX;
        else
                sig = host->id == 0 ? OMAP_DMA_MMC_RX : OMAP_DMA_MMC2_RX;
        host->dma_rx = dma_request_channel(mask, omap_dma_filter_fn, &sig);
-#if 0
-       if (!host->dma_rx) {
-               dev_err(host->dev, "unable to obtain RX DMA engine channel %u\n",
-                       sig);
-               goto err_dma;
-       }
-#else
        if (!host->dma_rx)
                dev_warn(host->dev, "unable to obtain RX DMA engine channel %u\n",
                        sig);
-#endif
 
        ret = request_irq(host->irq, mmc_omap_irq, 0, DRIVER_NAME, host);
        if (ret)
@@ -1500,8 +1484,6 @@ static int mmc_omap_remove(struct platform_device *pdev)
        struct mmc_omap_host *host = platform_get_drvdata(pdev);
        int i;
 
-       platform_set_drvdata(pdev, NULL);
-
        BUG_ON(host == NULL);
 
        for (i = 0; i < host->nr_slots; i++)
index eccedc7..1865321 100644 (file)
@@ -2047,7 +2047,6 @@ err_irq:
        }
 err1:
        iounmap(host->base);
-       platform_set_drvdata(pdev, NULL);
        mmc_free_host(mmc);
 err_alloc:
        omap_hsmmc_gpio_free(pdata);
@@ -2093,7 +2092,6 @@ static int omap_hsmmc_remove(struct platform_device *pdev)
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (res)
                release_mem_region(res->start, resource_size(res));
-       platform_set_drvdata(pdev, NULL);
 
        return 0;
 }
index 2b2f65a..847b199 100644 (file)
@@ -834,8 +834,6 @@ static int pxamci_remove(struct platform_device *pdev)
        struct mmc_host *mmc = platform_get_drvdata(pdev);
        int gpio_cd = -1, gpio_ro = -1, gpio_power = -1;
 
-       platform_set_drvdata(pdev, NULL);
-
        if (mmc) {
                struct pxamci_host *host = mmc_priv(mmc);
 
index ad13f42..82a35b9 100644 (file)
@@ -1316,8 +1316,6 @@ static int rtsx_pci_sdmmc_drv_remove(struct platform_device *pdev)
        mmc_remove_host(mmc);
        mmc_free_host(mmc);
 
-       platform_set_drvdata(pdev, NULL);
-
        dev_dbg(&(pdev->dev),
                ": Realtek PCI-E SDMMC controller has been removed\n");
 
index 706d9cb..cdd4ce0 100644 (file)
 #include <linux/bitops.h>
 #include <linux/types.h>
 #include <linux/err.h>
+#include <linux/gpio.h>
 #include <linux/interrupt.h>
 #include <linux/acpi.h>
+#include <linux/acpi_gpio.h>
 #include <linux/pm.h>
 #include <linux/pm_runtime.h>
+#include <linux/delay.h>
 
 #include <linux/mmc/host.h>
 #include <linux/mmc/pm.h>
@@ -83,12 +86,37 @@ static int sdhci_acpi_enable_dma(struct sdhci_host *host)
        return 0;
 }
 
+static void sdhci_acpi_int_hw_reset(struct sdhci_host *host)
+{
+       u8 reg;
+
+       reg = sdhci_readb(host, SDHCI_POWER_CONTROL);
+       reg |= 0x10;
+       sdhci_writeb(host, reg, SDHCI_POWER_CONTROL);
+       /* For eMMC, minimum is 1us but give it 9us for good measure */
+       udelay(9);
+       reg &= ~0x10;
+       sdhci_writeb(host, reg, SDHCI_POWER_CONTROL);
+       /* For eMMC, minimum is 200us but give it 300us for good measure */
+       usleep_range(300, 1000);
+}
+
 static const struct sdhci_ops sdhci_acpi_ops_dflt = {
        .enable_dma = sdhci_acpi_enable_dma,
 };
 
+static const struct sdhci_ops sdhci_acpi_ops_int = {
+       .enable_dma = sdhci_acpi_enable_dma,
+       .hw_reset   = sdhci_acpi_int_hw_reset,
+};
+
+static const struct sdhci_acpi_chip sdhci_acpi_chip_int = {
+       .ops = &sdhci_acpi_ops_int,
+};
+
 static const struct sdhci_acpi_slot sdhci_acpi_slot_int_emmc = {
-       .caps    = MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE,
+       .chip    = &sdhci_acpi_chip_int,
+       .caps    = MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE | MMC_CAP_HW_RESET,
        .caps2   = MMC_CAP2_HC_ERASE_SZ,
        .flags   = SDHCI_ACPI_RUNTIME_PM,
 };
@@ -101,6 +129,8 @@ static const struct sdhci_acpi_slot sdhci_acpi_slot_int_sdio = {
 };
 
 static const struct sdhci_acpi_slot sdhci_acpi_slot_int_sd = {
+       .flags   = SDHCI_ACPI_SD_CD | SDHCI_ACPI_RUNTIME_PM,
+       .quirks2 = SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON,
 };
 
 struct sdhci_acpi_uid_slot {
@@ -161,6 +191,59 @@ static const struct sdhci_acpi_slot *sdhci_acpi_get_slot(acpi_handle handle,
        return slot;
 }
 
+#ifdef CONFIG_PM_RUNTIME
+
+static irqreturn_t sdhci_acpi_sd_cd(int irq, void *dev_id)
+{
+       mmc_detect_change(dev_id, msecs_to_jiffies(200));
+       return IRQ_HANDLED;
+}
+
+static int sdhci_acpi_add_own_cd(struct device *dev, int gpio,
+                                struct mmc_host *mmc)
+{
+       unsigned long flags;
+       int err, irq;
+
+       if (gpio < 0) {
+               err = gpio;
+               goto out;
+       }
+
+       err = devm_gpio_request_one(dev, gpio, GPIOF_DIR_IN, "sd_cd");
+       if (err)
+               goto out;
+
+       irq = gpio_to_irq(gpio);
+       if (irq < 0) {
+               err = irq;
+               goto out_free;
+       }
+
+       flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING;
+       err = devm_request_irq(dev, irq, sdhci_acpi_sd_cd, flags, "sd_cd", mmc);
+       if (err)
+               goto out_free;
+
+       return 0;
+
+out_free:
+       devm_gpio_free(dev, gpio);
+out:
+       dev_warn(dev, "failed to setup card detect wake up\n");
+       return err;
+}
+
+#else
+
+static int sdhci_acpi_add_own_cd(struct device *dev, int gpio,
+                                struct mmc_host *mmc)
+{
+       return 0;
+}
+
+#endif
+
 static int sdhci_acpi_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
@@ -171,7 +254,7 @@ static int sdhci_acpi_probe(struct platform_device *pdev)
        struct resource *iomem;
        resource_size_t len;
        const char *hid;
-       int err;
+       int err, gpio;
 
        if (acpi_bus_get_device(handle, &device))
                return -ENODEV;
@@ -196,6 +279,8 @@ static int sdhci_acpi_probe(struct platform_device *pdev)
        if (IS_ERR(host))
                return PTR_ERR(host);
 
+       gpio = acpi_get_gpio_by_index(dev, 0, NULL);
+
        c = sdhci_priv(host);
        c->host = host;
        c->slot = sdhci_acpi_get_slot(handle, hid);
@@ -251,6 +336,11 @@ static int sdhci_acpi_probe(struct platform_device *pdev)
        if (err)
                goto err_free;
 
+       if (sdhci_acpi_flag(c, SDHCI_ACPI_SD_CD)) {
+               if (sdhci_acpi_add_own_cd(dev, gpio, host->mmc))
+                       c->use_runtime_pm = false;
+       }
+
        if (c->use_runtime_pm) {
                pm_runtime_set_active(dev);
                pm_suspend_ignore_children(dev, 1);
@@ -262,7 +352,6 @@ static int sdhci_acpi_probe(struct platform_device *pdev)
        return 0;
 
 err_free:
-       platform_set_drvdata(pdev, NULL);
        sdhci_free_host(c->host);
        return err;
 }
@@ -281,7 +370,6 @@ static int sdhci_acpi_remove(struct platform_device *pdev)
 
        dead = (sdhci_readl(c->host, SDHCI_INT_STATUS) == ~0);
        sdhci_remove_host(c->host, dead);
-       platform_set_drvdata(pdev, NULL);
        sdhci_free_host(c->host);
 
        return 0;
diff --git a/drivers/mmc/host/sdhci-bcm-kona.c b/drivers/mmc/host/sdhci-bcm-kona.c
new file mode 100644 (file)
index 0000000..87175f9
--- /dev/null
@@ -0,0 +1,348 @@
+/*
+ * Copyright (C) 2013 Broadcom 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 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/kernel.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/highmem.h>
+#include <linux/platform_device.h>
+#include <linux/mmc/host.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <linux/clk.h>
+#include <linux/regulator/consumer.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/version.h>
+#include <linux/mmc/slot-gpio.h>
+
+#include "sdhci-pltfm.h"
+#include "sdhci.h"
+
+#define SDHCI_SOFT_RESET                       0x01000000
+#define KONA_SDHOST_CORECTRL                   0x8000
+#define KONA_SDHOST_CD_PINCTRL                 0x00000008
+#define KONA_SDHOST_STOP_HCLK                  0x00000004
+#define KONA_SDHOST_RESET                      0x00000002
+#define KONA_SDHOST_EN                         0x00000001
+
+#define KONA_SDHOST_CORESTAT                   0x8004
+#define KONA_SDHOST_WP                         0x00000002
+#define KONA_SDHOST_CD_SW                      0x00000001
+
+#define KONA_SDHOST_COREIMR                    0x8008
+#define KONA_SDHOST_IP                         0x00000001
+
+#define KONA_SDHOST_COREISR                    0x800C
+#define KONA_SDHOST_COREIMSR                   0x8010
+#define KONA_SDHOST_COREDBG1                   0x8014
+#define KONA_SDHOST_COREGPO_MASK               0x8018
+
+#define SD_DETECT_GPIO_DEBOUNCE_128MS          128
+
+#define KONA_MMC_AUTOSUSPEND_DELAY             (50)
+
+struct sdhci_bcm_kona_dev {
+       struct mutex    write_lock; /* protect back to back writes */
+};
+
+
+static int sdhci_bcm_kona_sd_reset(struct sdhci_host *host)
+{
+       unsigned int val;
+       unsigned long timeout;
+
+       /* This timeout should be sufficent for core to reset */
+       timeout = jiffies + msecs_to_jiffies(100);
+
+       /* reset the host using the top level reset */
+       val = sdhci_readl(host, KONA_SDHOST_CORECTRL);
+       val |= KONA_SDHOST_RESET;
+       sdhci_writel(host, val, KONA_SDHOST_CORECTRL);
+
+       while (!(sdhci_readl(host, KONA_SDHOST_CORECTRL) & KONA_SDHOST_RESET)) {
+               if (time_is_before_jiffies(timeout)) {
+                       pr_err("Error: sd host is stuck in reset!!!\n");
+                       return -EFAULT;
+               }
+       }
+
+       /* bring the host out of reset */
+       val = sdhci_readl(host, KONA_SDHOST_CORECTRL);
+       val &= ~KONA_SDHOST_RESET;
+
+       /*
+        * Back-to-Back register write needs a delay of 1ms at bootup (min 10uS)
+        * Back-to-Back writes to same register needs delay when SD bus clock
+        * is very low w.r.t AHB clock, mainly during boot-time and during card
+        * insert-removal.
+        */
+       usleep_range(1000, 5000);
+       sdhci_writel(host, val, KONA_SDHOST_CORECTRL);
+
+       return 0;
+}
+
+static void sdhci_bcm_kona_sd_init(struct sdhci_host *host)
+{
+       unsigned int val;
+
+       /* enable the interrupt from the IP core */
+       val = sdhci_readl(host, KONA_SDHOST_COREIMR);
+       val |= KONA_SDHOST_IP;
+       sdhci_writel(host, val, KONA_SDHOST_COREIMR);
+
+       /* Enable the AHB clock gating module to the host */
+       val = sdhci_readl(host, KONA_SDHOST_CORECTRL);
+       val |= KONA_SDHOST_EN;
+
+       /*
+        * Back-to-Back register write needs a delay of 1ms at bootup (min 10uS)
+        * Back-to-Back writes to same register needs delay when SD bus clock
+        * is very low w.r.t AHB clock, mainly during boot-time and during card
+        * insert-removal.
+        */
+       usleep_range(1000, 5000);
+       sdhci_writel(host, val, KONA_SDHOST_CORECTRL);
+}
+
+/*
+ * Software emulation of the SD card insertion/removal. Set insert=1 for insert
+ * and insert=0 for removal. The card detection is done by GPIO. For Broadcom
+ * IP to function properly the bit 0 of CORESTAT register needs to be set/reset
+ * to generate the CD IRQ handled in sdhci.c which schedules card_tasklet.
+ */
+static int sdhci_bcm_kona_sd_card_emulate(struct sdhci_host *host, int insert)
+{
+       struct sdhci_pltfm_host *pltfm_priv = sdhci_priv(host);
+       struct sdhci_bcm_kona_dev *kona_dev = sdhci_pltfm_priv(pltfm_priv);
+       u32 val;
+
+       /*
+        * Back-to-Back register write needs a delay of min 10uS.
+        * Back-to-Back writes to same register needs delay when SD bus clock
+        * is very low w.r.t AHB clock, mainly during boot-time and during card
+        * insert-removal.
+        * We keep 20uS
+        */
+       mutex_lock(&kona_dev->write_lock);
+       udelay(20);
+       val = sdhci_readl(host, KONA_SDHOST_CORESTAT);
+
+       if (insert) {
+               int ret;
+
+               ret = mmc_gpio_get_ro(host->mmc);
+               if (ret >= 0)
+                       val = (val & ~KONA_SDHOST_WP) |
+                               ((ret) ? KONA_SDHOST_WP : 0);
+
+               val |= KONA_SDHOST_CD_SW;
+               sdhci_writel(host, val, KONA_SDHOST_CORESTAT);
+       } else {
+               val &= ~KONA_SDHOST_CD_SW;
+               sdhci_writel(host, val, KONA_SDHOST_CORESTAT);
+       }
+       mutex_unlock(&kona_dev->write_lock);
+
+       return 0;
+}
+
+/*
+ * SD card interrupt event callback
+ */
+void sdhci_bcm_kona_card_event(struct sdhci_host *host)
+{
+       if (mmc_gpio_get_cd(host->mmc) > 0) {
+               dev_dbg(mmc_dev(host->mmc),
+                       "card inserted\n");
+               sdhci_bcm_kona_sd_card_emulate(host, 1);
+       } else {
+               dev_dbg(mmc_dev(host->mmc),
+                       "card removed\n");
+               sdhci_bcm_kona_sd_card_emulate(host, 0);
+       }
+}
+
+/*
+ * Get the base clock. Use central clock source for now. Not sure if different
+ * clock speed to each dev is allowed
+ */
+static unsigned int sdhci_bcm_kona_get_max_clk(struct sdhci_host *host)
+{
+       struct sdhci_bcm_kona_dev *kona_dev;
+       struct sdhci_pltfm_host *pltfm_priv = sdhci_priv(host);
+       kona_dev = sdhci_pltfm_priv(pltfm_priv);
+
+       return host->mmc->f_max;
+}
+
+static unsigned int sdhci_bcm_kona_get_timeout_clock(struct sdhci_host *host)
+{
+       return sdhci_bcm_kona_get_max_clk(host);
+}
+
+static void sdhci_bcm_kona_init_74_clocks(struct sdhci_host *host,
+                               u8 power_mode)
+{
+       /*
+        *  JEDEC and SD spec specify supplying 74 continuous clocks to
+        * device after power up. With minimum bus (100KHz) that
+        * that translates to 740us
+        */
+       if (power_mode != MMC_POWER_OFF)
+               udelay(740);
+}
+
+static struct sdhci_ops sdhci_bcm_kona_ops = {
+       .get_max_clock = sdhci_bcm_kona_get_max_clk,
+       .get_timeout_clock = sdhci_bcm_kona_get_timeout_clock,
+       .platform_send_init_74_clocks = sdhci_bcm_kona_init_74_clocks,
+       .card_event = sdhci_bcm_kona_card_event,
+};
+
+static struct sdhci_pltfm_data sdhci_pltfm_data_kona = {
+       .ops    = &sdhci_bcm_kona_ops,
+       .quirks = SDHCI_QUIRK_NO_CARD_NO_RESET |
+               SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | SDHCI_QUIRK_32BIT_DMA_ADDR |
+               SDHCI_QUIRK_32BIT_DMA_SIZE | SDHCI_QUIRK_32BIT_ADMA_SIZE |
+               SDHCI_QUIRK_FORCE_BLK_SZ_2048 |
+               SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN,
+};
+
+static const struct of_device_id sdhci_bcm_kona_of_match[] __initdata = {
+       { .compatible = "bcm,kona-sdhci"},
+       {}
+};
+MODULE_DEVICE_TABLE(of, sdhci_bcm_kona_of_match);
+
+static int __init sdhci_bcm_kona_probe(struct platform_device *pdev)
+{
+       struct sdhci_bcm_kona_dev *kona_dev = NULL;
+       struct sdhci_pltfm_host *pltfm_priv;
+       struct device *dev = &pdev->dev;
+       struct sdhci_host *host;
+       int ret;
+
+       ret = 0;
+
+       host = sdhci_pltfm_init(pdev, &sdhci_pltfm_data_kona,
+                       sizeof(*kona_dev));
+       if (IS_ERR(host))
+               return PTR_ERR(host);
+
+       dev_dbg(dev, "%s: inited. IOADDR=%p\n", __func__, host->ioaddr);
+
+       pltfm_priv = sdhci_priv(host);
+
+       kona_dev = sdhci_pltfm_priv(pltfm_priv);
+       mutex_init(&kona_dev->write_lock);
+
+       mmc_of_parse(host->mmc);
+
+       if (!host->mmc->f_max) {
+               dev_err(&pdev->dev, "Missing max-freq for SDHCI cfg\n");
+               ret = -ENXIO;
+               goto err_pltfm_free;
+       }
+
+       dev_dbg(dev, "non-removable=%c\n",
+               (host->mmc->caps & MMC_CAP_NONREMOVABLE) ? 'Y' : 'N');
+       dev_dbg(dev, "cd_gpio %c, wp_gpio %c\n",
+               (mmc_gpio_get_cd(host->mmc) != -ENOSYS) ? 'Y' : 'N',
+               (mmc_gpio_get_ro(host->mmc) != -ENOSYS) ? 'Y' : 'N');
+
+       if (host->mmc->caps | MMC_CAP_NONREMOVABLE)
+               host->quirks |= SDHCI_QUIRK_BROKEN_CARD_DETECTION;
+
+       dev_dbg(dev, "is_8bit=%c\n",
+               (host->mmc->caps | MMC_CAP_8_BIT_DATA) ? 'Y' : 'N');
+
+       ret = sdhci_bcm_kona_sd_reset(host);
+       if (ret)
+               goto err_pltfm_free;
+
+       sdhci_bcm_kona_sd_init(host);
+
+       ret = sdhci_add_host(host);
+       if (ret) {
+               dev_err(dev, "Failed sdhci_add_host\n");
+               goto err_reset;
+       }
+
+       /* if device is eMMC, emulate card insert right here */
+       if (host->mmc->caps | MMC_CAP_NONREMOVABLE) {
+               ret = sdhci_bcm_kona_sd_card_emulate(host, 1);
+               if (ret) {
+                       dev_err(dev,
+                               "unable to emulate card insertion\n");
+                       goto err_remove_host;
+               }
+       }
+       /*
+        * Since the card detection GPIO interrupt is configured to be
+        * edge sensitive, check the initial GPIO value here, emulate
+        * only if the card is present
+        */
+       if (mmc_gpio_get_cd(host->mmc) > 0)
+               sdhci_bcm_kona_sd_card_emulate(host, 1);
+
+       dev_dbg(dev, "initialized properly\n");
+       return 0;
+
+err_remove_host:
+       sdhci_remove_host(host, 0);
+
+err_reset:
+       sdhci_bcm_kona_sd_reset(host);
+
+err_pltfm_free:
+       sdhci_pltfm_free(pdev);
+
+       dev_err(dev, "Probing of sdhci-pltfm failed: %d\n", ret);
+       return ret;
+}
+
+static int __exit sdhci_bcm_kona_remove(struct platform_device *pdev)
+{
+       struct sdhci_host *host = platform_get_drvdata(pdev);
+       int dead;
+       u32 scratch;
+
+       dead = 0;
+       scratch = readl(host->ioaddr + SDHCI_INT_STATUS);
+       if (scratch == (u32)-1)
+               dead = 1;
+       sdhci_remove_host(host, dead);
+
+       sdhci_free_host(host);
+
+       return 0;
+}
+
+static struct platform_driver sdhci_bcm_kona_driver = {
+       .driver         = {
+               .name   = "sdhci-kona",
+               .owner  = THIS_MODULE,
+               .pm     = SDHCI_PLTFM_PMOPS,
+               .of_match_table = of_match_ptr(sdhci_bcm_kona_of_match),
+       },
+       .probe          = sdhci_bcm_kona_probe,
+       .remove         = __exit_p(sdhci_bcm_kona_remove),
+};
+module_platform_driver(sdhci_bcm_kona_driver);
+
+MODULE_DESCRIPTION("SDHCI driver for Broadcom Kona platform");
+MODULE_AUTHOR("Broadcom");
+MODULE_LICENSE("GPL v2");
index d49bc95..0584a1c 100644 (file)
@@ -148,7 +148,7 @@ static int bcm2835_sdhci_probe(struct platform_device *pdev)
        struct sdhci_pltfm_host *pltfm_host;
        int ret;
 
-       host = sdhci_pltfm_init(pdev, &bcm2835_sdhci_pdata);
+       host = sdhci_pltfm_init(pdev, &bcm2835_sdhci_pdata, 0);
        if (IS_ERR(host))
                return PTR_ERR(host);
 
index 8ebb6b6..f2cc266 100644 (file)
@@ -96,7 +96,7 @@ static const struct sdhci_pltfm_data sdhci_cns3xxx_pdata = {
 
 static int sdhci_cns3xxx_probe(struct platform_device *pdev)
 {
-       return sdhci_pltfm_register(pdev, &sdhci_cns3xxx_pdata);
+       return sdhci_pltfm_register(pdev, &sdhci_cns3xxx_pdata, 0);
 }
 
 static int sdhci_cns3xxx_remove(struct platform_device *pdev)
index 15e7803..8424839 100644 (file)
@@ -130,7 +130,7 @@ static int sdhci_dove_probe(struct platform_device *pdev)
                gpio_direction_input(priv->gpio_cd);
        }
 
-       host = sdhci_pltfm_init(pdev, &sdhci_dove_pdata);
+       host = sdhci_pltfm_init(pdev, &sdhci_dove_pdata, 0);
        if (IS_ERR(host)) {
                ret = PTR_ERR(host);
                goto err_sdhci_pltfm_init;
index d5f0d59..1dd5ba8 100644 (file)
@@ -384,6 +384,20 @@ static void esdhc_writeb_le(struct sdhci_host *host, u8 val, int reg)
        }
 }
 
+static unsigned int esdhc_pltfm_get_max_clock(struct sdhci_host *host)
+{
+       struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+       struct pltfm_imx_data *imx_data = pltfm_host->priv;
+       struct esdhc_platform_data *boarddata = &imx_data->boarddata;
+
+       u32 f_host = clk_get_rate(pltfm_host->clk);
+
+       if (boarddata->f_max && (boarddata->f_max < f_host))
+               return boarddata->f_max;
+       else
+               return f_host;
+}
+
 static unsigned int esdhc_pltfm_get_min_clock(struct sdhci_host *host)
 {
        struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
@@ -391,6 +405,14 @@ static unsigned int esdhc_pltfm_get_min_clock(struct sdhci_host *host)
        return clk_get_rate(pltfm_host->clk) / 256 / 16;
 }
 
+static inline void esdhc_pltfm_set_clock(struct sdhci_host *host,
+                                        unsigned int clock)
+{
+       struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+
+       esdhc_set_clock(host, clock, clk_get_rate(pltfm_host->clk));
+}
+
 static unsigned int esdhc_pltfm_get_ro(struct sdhci_host *host)
 {
        struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
@@ -438,8 +460,8 @@ static const struct sdhci_ops sdhci_esdhc_ops = {
        .write_l = esdhc_writel_le,
        .write_w = esdhc_writew_le,
        .write_b = esdhc_writeb_le,
-       .set_clock = esdhc_set_clock,
-       .get_max_clock = sdhci_pltfm_clk_get_max_clock,
+       .set_clock = esdhc_pltfm_set_clock,
+       .get_max_clock = esdhc_pltfm_get_max_clock,
        .get_min_clock = esdhc_pltfm_get_min_clock,
        .get_ro = esdhc_pltfm_get_ro,
        .platform_bus_width = esdhc_pltfm_bus_width,
@@ -482,6 +504,8 @@ sdhci_esdhc_imx_probe_dt(struct platform_device *pdev,
 
        of_property_read_u32(np, "bus-width", &boarddata->max_bus_width);
 
+       of_property_read_u32(np, "max-frequency", &boarddata->f_max);
+
        return 0;
 }
 #else
@@ -503,7 +527,7 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
        int err;
        struct pltfm_imx_data *imx_data;
 
-       host = sdhci_pltfm_init(pdev, &sdhci_esdhc_imx_pdata);
+       host = sdhci_pltfm_init(pdev, &sdhci_esdhc_imx_pdata, 0);
        if (IS_ERR(host))
                return PTR_ERR(host);
 
index d25f9ab..a2a0642 100644 (file)
 /* pltfm-specific */
 #define ESDHC_HOST_CONTROL_LE  0x20
 
+/*
+ * P2020 interpretation of the SDHCI_HOST_CONTROL register
+ */
+#define ESDHC_CTRL_4BITBUS          (0x1 << 1)
+#define ESDHC_CTRL_8BITBUS          (0x2 << 1)
+#define ESDHC_CTRL_BUSWIDTH_MASK    (0x3 << 1)
+
 /* OF-specific */
 #define ESDHC_DMA_SYSCTL       0x40c
 #define ESDHC_DMA_SNOOP                0x00000040
 
 #define ESDHC_HOST_CONTROL_RES 0x05
 
-static inline void esdhc_set_clock(struct sdhci_host *host, unsigned int clock)
+static inline void esdhc_set_clock(struct sdhci_host *host, unsigned int clock,
+                                  unsigned int host_clock)
 {
        int pre_div = 2;
        int div = 1;
@@ -56,14 +64,14 @@ static inline void esdhc_set_clock(struct sdhci_host *host, unsigned int clock)
                | ESDHC_CLOCK_MASK);
        sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL);
 
-       while (host->max_clk / pre_div / 16 > clock && pre_div < 256)
+       while (host_clock / pre_div / 16 > clock && pre_div < 256)
                pre_div *= 2;
 
-       while (host->max_clk / pre_div / div > clock && div < 16)
+       while (host_clock / pre_div / div > clock && div < 16)
                div++;
 
        dev_dbg(mmc_dev(host->mmc), "desired SD clock: %d, actual: %d\n",
-               clock, host->max_clk / pre_div / div);
+               clock, host_clock / pre_div / div);
 
        pre_div >>= 1;
        div--;
index 5e68adc..15039e2 100644 (file)
@@ -13,6 +13,7 @@
  * your option) any later version.
  */
 
+#include <linux/err.h>
 #include <linux/io.h>
 #include <linux/of.h>
 #include <linux/delay.h>
@@ -120,6 +121,13 @@ static void esdhc_writeb(struct sdhci_host *host, u8 val, int reg)
        if (reg == SDHCI_HOST_CONTROL) {
                u32 dma_bits;
 
+               /*
+                * If host control register is not standard, exit
+                * this function
+                */
+               if (host->quirks2 & SDHCI_QUIRK2_BROKEN_HOST_CONTROL)
+                       return;
+
                /* DMA select is 22,23 bits in Protocol Control Register */
                dma_bits = (val & SDHCI_CTRL_DMA_MASK) << 5;
                clrsetbits_be32(host->ioaddr + reg , SDHCI_CTRL_DMA_MASK << 5,
@@ -200,7 +208,7 @@ static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock)
        }
 
        /* Set the clock */
-       esdhc_set_clock(host, clock);
+       esdhc_set_clock(host, clock, host->max_clk);
 }
 
 #ifdef CONFIG_PM
@@ -230,6 +238,30 @@ static void esdhc_of_platform_init(struct sdhci_host *host)
                host->quirks &= ~SDHCI_QUIRK_NO_BUSY_IRQ;
 }
 
+static int esdhc_pltfm_bus_width(struct sdhci_host *host, int width)
+{
+       u32 ctrl;
+
+       switch (width) {
+       case MMC_BUS_WIDTH_8:
+               ctrl = ESDHC_CTRL_8BITBUS;
+               break;
+
+       case MMC_BUS_WIDTH_4:
+               ctrl = ESDHC_CTRL_4BITBUS;
+               break;
+
+       default:
+               ctrl = 0;
+               break;
+       }
+
+       clrsetbits_be32(host->ioaddr + SDHCI_HOST_CONTROL,
+                       ESDHC_CTRL_BUSWIDTH_MASK, ctrl);
+
+       return 0;
+}
+
 static const struct sdhci_ops sdhci_esdhc_ops = {
        .read_l = esdhc_readl,
        .read_w = esdhc_readw,
@@ -247,6 +279,7 @@ static const struct sdhci_ops sdhci_esdhc_ops = {
        .platform_resume = esdhc_of_resume,
 #endif
        .adma_workaround = esdhci_of_adma_workaround,
+       .platform_bus_width = esdhc_pltfm_bus_width,
 };
 
 static const struct sdhci_pltfm_data sdhci_esdhc_pdata = {
@@ -262,7 +295,33 @@ static const struct sdhci_pltfm_data sdhci_esdhc_pdata = {
 
 static int sdhci_esdhc_probe(struct platform_device *pdev)
 {
-       return sdhci_pltfm_register(pdev, &sdhci_esdhc_pdata);
+       struct sdhci_host *host;
+       struct device_node *np;
+       int ret;
+
+       host = sdhci_pltfm_init(pdev, &sdhci_esdhc_pdata, 0);
+       if (IS_ERR(host))
+               return PTR_ERR(host);
+
+       sdhci_get_of_property(pdev);
+
+       np = pdev->dev.of_node;
+       if (of_device_is_compatible(np, "fsl,p2020-esdhc")) {
+               /*
+                * Freescale messed up with P2020 as it has a non-standard
+                * host control register
+                */
+               host->quirks2 |= SDHCI_QUIRK2_BROKEN_HOST_CONTROL;
+       }
+
+       /* call to generic mmc_of_parse to support additional capabilities */
+       mmc_of_parse(host->mmc);
+
+       ret = sdhci_add_host(host);
+       if (ret)
+               sdhci_pltfm_free(pdev);
+
+       return ret;
 }
 
 static int sdhci_esdhc_remove(struct platform_device *pdev)
index 200a6a9..57c514a 100644 (file)
@@ -68,7 +68,7 @@ static const struct sdhci_pltfm_data sdhci_hlwd_pdata = {
 
 static int sdhci_hlwd_probe(struct platform_device *pdev)
 {
-       return sdhci_pltfm_register(pdev, &sdhci_hlwd_pdata);
+       return sdhci_pltfm_register(pdev, &sdhci_hlwd_pdata, 0);
 }
 
 static int sdhci_hlwd_remove(struct platform_device *pdev)
index 701d06d..d7d6bc8 100644 (file)
@@ -36,6 +36,7 @@
 #define PCI_DEVICE_ID_INTEL_BYT_EMMC   0x0f14
 #define PCI_DEVICE_ID_INTEL_BYT_SDIO   0x0f15
 #define PCI_DEVICE_ID_INTEL_BYT_SD     0x0f16
+#define PCI_DEVICE_ID_INTEL_BYT_EMMC2  0x0f50
 
 /*
  * PCI registers
@@ -77,6 +78,8 @@ struct sdhci_pci_slot {
        int                     rst_n_gpio;
        int                     cd_gpio;
        int                     cd_irq;
+
+       void (*hw_reset)(struct sdhci_host *host);
 };
 
 struct sdhci_pci_chip {
@@ -307,10 +310,27 @@ static const struct sdhci_pci_fixes sdhci_intel_pch_sdio = {
        .probe_slot     = pch_hc_probe_slot,
 };
 
+static void sdhci_pci_int_hw_reset(struct sdhci_host *host)
+{
+       u8 reg;
+
+       reg = sdhci_readb(host, SDHCI_POWER_CONTROL);
+       reg |= 0x10;
+       sdhci_writeb(host, reg, SDHCI_POWER_CONTROL);
+       /* For eMMC, minimum is 1us but give it 9us for good measure */
+       udelay(9);
+       reg &= ~0x10;
+       sdhci_writeb(host, reg, SDHCI_POWER_CONTROL);
+       /* For eMMC, minimum is 200us but give it 300us for good measure */
+       usleep_range(300, 1000);
+}
+
 static int byt_emmc_probe_slot(struct sdhci_pci_slot *slot)
 {
-       slot->host->mmc->caps |= MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE;
+       slot->host->mmc->caps |= MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE |
+                                MMC_CAP_HW_RESET;
        slot->host->mmc->caps2 |= MMC_CAP2_HC_ERASE_SZ;
+       slot->hw_reset = sdhci_pci_int_hw_reset;
        return 0;
 }
 
@@ -332,6 +352,8 @@ static const struct sdhci_pci_fixes sdhci_intel_byt_sdio = {
 };
 
 static const struct sdhci_pci_fixes sdhci_intel_byt_sd = {
+       .quirks2        = SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON,
+       .allow_runtime_pm = true,
 };
 
 /* O2Micro extra registers */
@@ -910,6 +932,14 @@ static const struct pci_device_id pci_ids[] = {
        },
 
        {
+               .vendor         = PCI_VENDOR_ID_INTEL,
+               .device         = PCI_DEVICE_ID_INTEL_BYT_EMMC2,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .driver_data    = (kernel_ulong_t)&sdhci_intel_byt_emmc,
+       },
+
+       {
                .vendor         = PCI_VENDOR_ID_O2,
                .device         = PCI_DEVICE_ID_O2_8120,
                .subvendor      = PCI_ANY_ID,
@@ -1014,7 +1044,7 @@ static int sdhci_pci_bus_width(struct sdhci_host *host, int width)
        return 0;
 }
 
-static void sdhci_pci_hw_reset(struct sdhci_host *host)
+static void sdhci_pci_gpio_hw_reset(struct sdhci_host *host)
 {
        struct sdhci_pci_slot *slot = sdhci_priv(host);
        int rst_n_gpio = slot->rst_n_gpio;
@@ -1029,6 +1059,14 @@ static void sdhci_pci_hw_reset(struct sdhci_host *host)
        usleep_range(300, 1000);
 }
 
+static void sdhci_pci_hw_reset(struct sdhci_host *host)
+{
+       struct sdhci_pci_slot *slot = sdhci_priv(host);
+
+       if (slot->hw_reset)
+               slot->hw_reset(host);
+}
+
 static const struct sdhci_ops sdhci_pci_ops = {
        .enable_dma     = sdhci_pci_enable_dma,
        .platform_bus_width     = sdhci_pci_bus_width,
@@ -1326,6 +1364,7 @@ static struct sdhci_pci_slot *sdhci_pci_probe_slot(
                if (!gpio_request(slot->rst_n_gpio, "eMMC_reset")) {
                        gpio_direction_output(slot->rst_n_gpio, 1);
                        slot->host->mmc->caps |= MMC_CAP_HW_RESET;
+                       slot->hw_reset = sdhci_pci_gpio_hw_reset;
                } else {
                        dev_warn(&pdev->dev, "failed to request rst_n_gpio\n");
                        slot->rst_n_gpio = -EINVAL;
index cd0f1f6..e2065a4 100644 (file)
@@ -115,10 +115,10 @@ void sdhci_get_of_property(struct platform_device *pdev) {}
 EXPORT_SYMBOL_GPL(sdhci_get_of_property);
 
 struct sdhci_host *sdhci_pltfm_init(struct platform_device *pdev,
-                                   const struct sdhci_pltfm_data *pdata)
+                                   const struct sdhci_pltfm_data *pdata,
+                                   size_t priv_size)
 {
        struct sdhci_host *host;
-       struct sdhci_pltfm_host *pltfm_host;
        struct device_node *np = pdev->dev.of_node;
        struct resource *iomem;
        int ret;
@@ -134,24 +134,27 @@ struct sdhci_host *sdhci_pltfm_init(struct platform_device *pdev,
 
        /* Some PCI-based MFD need the parent here */
        if (pdev->dev.parent != &platform_bus && !np)
-               host = sdhci_alloc_host(pdev->dev.parent, sizeof(*pltfm_host));
+               host = sdhci_alloc_host(pdev->dev.parent,
+                       sizeof(struct sdhci_pltfm_host) + priv_size);
        else
-               host = sdhci_alloc_host(&pdev->dev, sizeof(*pltfm_host));
+               host = sdhci_alloc_host(&pdev->dev,
+                       sizeof(struct sdhci_pltfm_host) + priv_size);
 
        if (IS_ERR(host)) {
                ret = PTR_ERR(host);
                goto err;
        }
 
-       pltfm_host = sdhci_priv(host);
-
        host->hw_name = dev_name(&pdev->dev);
        if (pdata && pdata->ops)
                host->ops = pdata->ops;
        else
                host->ops = &sdhci_pltfm_ops;
-       if (pdata)
+       if (pdata) {
                host->quirks = pdata->quirks;
+               host->quirks2 = pdata->quirks2;
+       }
+
        host->irq = platform_get_irq(pdev, 0);
 
        if (!request_mem_region(iomem->start, resource_size(iomem),
@@ -197,17 +200,17 @@ void sdhci_pltfm_free(struct platform_device *pdev)
        iounmap(host->ioaddr);
        release_mem_region(iomem->start, resource_size(iomem));
        sdhci_free_host(host);
-       platform_set_drvdata(pdev, NULL);
 }
 EXPORT_SYMBOL_GPL(sdhci_pltfm_free);
 
 int sdhci_pltfm_register(struct platform_device *pdev,
-                        const struct sdhci_pltfm_data *pdata)
+                       const struct sdhci_pltfm_data *pdata,
+                       size_t priv_size)
 {
        struct sdhci_host *host;
        int ret = 0;
 
-       host = sdhci_pltfm_init(pdev, pdata);
+       host = sdhci_pltfm_init(pdev, pdata, priv_size);
        if (IS_ERR(host))
                return PTR_ERR(host);
 
index 1210ed1..e15ced7 100644 (file)
@@ -18,6 +18,7 @@
 struct sdhci_pltfm_data {
        const struct sdhci_ops *ops;
        unsigned int quirks;
+       unsigned int quirks2;
 };
 
 struct sdhci_pltfm_host {
@@ -27,6 +28,8 @@ struct sdhci_pltfm_host {
        /* migrate from sdhci_of_host */
        unsigned int clock;
        u16 xfer_mode_shadow;
+
+       unsigned long private[0] ____cacheline_aligned;
 };
 
 #ifdef CONFIG_MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER
@@ -91,15 +94,22 @@ static inline void sdhci_be32bs_writeb(struct sdhci_host *host, u8 val, int reg)
 extern void sdhci_get_of_property(struct platform_device *pdev);
 
 extern struct sdhci_host *sdhci_pltfm_init(struct platform_device *pdev,
-                                         const struct sdhci_pltfm_data *pdata);
+                                         const struct sdhci_pltfm_data *pdata,
+                                         size_t priv_size);
 extern void sdhci_pltfm_free(struct platform_device *pdev);
 
 extern int sdhci_pltfm_register(struct platform_device *pdev,
-                               const struct sdhci_pltfm_data *pdata);
+                               const struct sdhci_pltfm_data *pdata,
+                               size_t priv_size);
 extern int sdhci_pltfm_unregister(struct platform_device *pdev);
 
 extern unsigned int sdhci_pltfm_clk_get_max_clock(struct sdhci_host *host);
 
+static inline void *sdhci_pltfm_priv(struct sdhci_pltfm_host *host)
+{
+       return (void *)host->private;
+}
+
 #ifdef CONFIG_PM
 extern const struct dev_pm_ops sdhci_pltfm_pmops;
 #define SDHCI_PLTFM_PMOPS (&sdhci_pltfm_pmops)
index 6a3f702..d51e061 100644 (file)
@@ -175,7 +175,7 @@ static int sdhci_pxav2_probe(struct platform_device *pdev)
        if (!pxa)
                return -ENOMEM;
 
-       host = sdhci_pltfm_init(pdev, NULL);
+       host = sdhci_pltfm_init(pdev, NULL, 0);
        if (IS_ERR(host)) {
                kfree(pxa);
                return PTR_ERR(host);
@@ -253,8 +253,6 @@ static int sdhci_pxav2_remove(struct platform_device *pdev)
        sdhci_pltfm_free(pdev);
        kfree(pxa);
 
-       platform_set_drvdata(pdev, NULL);
-
        return 0;
 }
 
index 1ae358e..bf99359 100644 (file)
@@ -230,7 +230,7 @@ static int sdhci_pxav3_probe(struct platform_device *pdev)
        if (!pxa)
                return -ENOMEM;
 
-       host = sdhci_pltfm_init(pdev, &sdhci_pxav3_pdata);
+       host = sdhci_pltfm_init(pdev, &sdhci_pxav3_pdata, 0);
        if (IS_ERR(host)) {
                kfree(pxa);
                return PTR_ERR(host);
@@ -252,7 +252,9 @@ static int sdhci_pxav3_probe(struct platform_device *pdev)
 
        match = of_match_device(of_match_ptr(sdhci_pxav3_of_match), &pdev->dev);
        if (match) {
-               mmc_of_parse(host->mmc);
+               ret = mmc_of_parse(host->mmc);
+               if (ret)
+                       goto err_of_parse;
                sdhci_get_of_property(pdev);
                pdata = pxav3_get_mmc_pdata(dev);
        } else if (pdata) {
@@ -285,18 +287,15 @@ static int sdhci_pxav3_probe(struct platform_device *pdev)
                }
        }
 
-       pm_runtime_set_active(&pdev->dev);
        pm_runtime_enable(&pdev->dev);
+       pm_runtime_get_sync(&pdev->dev);
        pm_runtime_set_autosuspend_delay(&pdev->dev, PXAV3_RPM_DELAY_MS);
        pm_runtime_use_autosuspend(&pdev->dev);
        pm_suspend_ignore_children(&pdev->dev, 1);
-       pm_runtime_get_noresume(&pdev->dev);
 
        ret = sdhci_add_host(host);
        if (ret) {
                dev_err(&pdev->dev, "failed to add host\n");
-               pm_runtime_forbid(&pdev->dev);
-               pm_runtime_disable(&pdev->dev);
                goto err_add_host;
        }
 
@@ -313,10 +312,13 @@ static int sdhci_pxav3_probe(struct platform_device *pdev)
 
        return 0;
 
+err_of_parse:
+err_cd_req:
 err_add_host:
+       pm_runtime_put_sync(&pdev->dev);
+       pm_runtime_disable(&pdev->dev);
        clk_disable_unprepare(clk);
        clk_put(clk);
-err_cd_req:
 err_clk_get:
        sdhci_pltfm_free(pdev);
        kfree(pxa);
@@ -339,8 +341,6 @@ static int sdhci_pxav3_remove(struct platform_device *pdev)
        sdhci_pltfm_free(pdev);
        kfree(pxa);
 
-       platform_set_drvdata(pdev, NULL);
-
        return 0;
 }
 
index c6f6246..926aaf6 100644 (file)
@@ -745,7 +745,6 @@ static int sdhci_s3c_remove(struct platform_device *pdev)
        clk_disable_unprepare(sc->clk_io);
 
        sdhci_free_host(host);
-       platform_set_drvdata(pdev, NULL);
 
        return 0;
 }
index 09805af..62a4a83 100644 (file)
@@ -13,7 +13,6 @@
 #include <linux/of.h>
 #include <linux/of_gpio.h>
 #include <linux/mmc/slot-gpio.h>
-#include <linux/pinctrl/consumer.h>
 #include "sdhci-pltfm.h"
 
 struct sdhci_sirf_priv {
@@ -24,7 +23,7 @@ struct sdhci_sirf_priv {
 static unsigned int sdhci_sirf_get_max_clk(struct sdhci_host *host)
 {
        struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
-       struct sdhci_sirf_priv *priv = pltfm_host->priv;
+       struct sdhci_sirf_priv *priv = sdhci_pltfm_priv(pltfm_host);
        return clk_get_rate(priv->clk);
 }
 
@@ -46,47 +45,35 @@ static int sdhci_sirf_probe(struct platform_device *pdev)
        struct sdhci_host *host;
        struct sdhci_pltfm_host *pltfm_host;
        struct sdhci_sirf_priv *priv;
-       struct pinctrl *pinctrl;
+       struct clk *clk;
+       int gpio_cd;
        int ret;
 
-       pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
-       if (IS_ERR(pinctrl)) {
-               dev_err(&pdev->dev, "unable to get pinmux");
-               return PTR_ERR(pinctrl);
-       }
-
-       priv = devm_kzalloc(&pdev->dev, sizeof(struct sdhci_sirf_priv),
-               GFP_KERNEL);
-       if (!priv) {
-               dev_err(&pdev->dev, "unable to allocate private data");
-               return -ENOMEM;
-       }
-
-       priv->clk = devm_clk_get(&pdev->dev, NULL);
-       if (IS_ERR(priv->clk)) {
+       clk = devm_clk_get(&pdev->dev, NULL);
+       if (IS_ERR(clk)) {
                dev_err(&pdev->dev, "unable to get clock");
-               return PTR_ERR(priv->clk);
+               return PTR_ERR(clk);
        }
 
-       if (pdev->dev.of_node) {
-               priv->gpio_cd = of_get_named_gpio(pdev->dev.of_node,
-                       "cd-gpios", 0);
-       } else {
-               priv->gpio_cd = -EINVAL;
-       }
+       if (pdev->dev.of_node)
+               gpio_cd = of_get_named_gpio(pdev->dev.of_node, "cd-gpios", 0);
+       else
+               gpio_cd = -EINVAL;
 
-       host = sdhci_pltfm_init(pdev, &sdhci_sirf_pdata);
-       if (IS_ERR(host)) {
-               ret = PTR_ERR(host);
-               goto err_sdhci_pltfm_init;
-       }
+       host = sdhci_pltfm_init(pdev, &sdhci_sirf_pdata, sizeof(struct sdhci_sirf_priv));
+       if (IS_ERR(host))
+               return PTR_ERR(host);
 
        pltfm_host = sdhci_priv(host);
-       pltfm_host->priv = priv;
+       priv = sdhci_pltfm_priv(pltfm_host);
+       priv->clk = clk;
+       priv->gpio_cd = gpio_cd;
 
        sdhci_get_of_property(pdev);
 
-       clk_prepare_enable(priv->clk);
+       ret = clk_prepare_enable(priv->clk);
+       if (ret)
+               goto err_clk_prepare;
 
        ret = sdhci_add_host(host);
        if (ret)
@@ -111,8 +98,8 @@ err_request_cd:
        sdhci_remove_host(host, 0);
 err_sdhci_add:
        clk_disable_unprepare(priv->clk);
+err_clk_prepare:
        sdhci_pltfm_free(pdev);
-err_sdhci_pltfm_init:
        return ret;
 }
 
@@ -120,7 +107,7 @@ static int sdhci_sirf_remove(struct platform_device *pdev)
 {
        struct sdhci_host *host = platform_get_drvdata(pdev);
        struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
-       struct sdhci_sirf_priv *priv = pltfm_host->priv;
+       struct sdhci_sirf_priv *priv = sdhci_pltfm_priv(pltfm_host);
 
        sdhci_pltfm_unregister(pdev);
 
@@ -136,7 +123,7 @@ static int sdhci_sirf_suspend(struct device *dev)
 {
        struct sdhci_host *host = dev_get_drvdata(dev);
        struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
-       struct sdhci_sirf_priv *priv = pltfm_host->priv;
+       struct sdhci_sirf_priv *priv = sdhci_pltfm_priv(pltfm_host);
        int ret;
 
        ret = sdhci_suspend_host(host);
@@ -152,7 +139,7 @@ static int sdhci_sirf_resume(struct device *dev)
 {
        struct sdhci_host *host = dev_get_drvdata(dev);
        struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
-       struct sdhci_sirf_priv *priv = pltfm_host->priv;
+       struct sdhci_sirf_priv *priv = sdhci_pltfm_priv(pltfm_host);
        int ret;
 
        ret = clk_enable(priv->clk);
index 7ae5b3a..2dba9f8 100644 (file)
@@ -258,7 +258,6 @@ static int sdhci_probe(struct platform_device *pdev)
        return 0;
 
 set_drvdata:
-       platform_set_drvdata(pdev, NULL);
        sdhci_remove_host(host, 1);
 free_host:
        sdhci_free_host(host);
@@ -278,7 +277,6 @@ static int sdhci_remove(struct platform_device *pdev)
        int dead = 0;
        u32 scratch;
 
-       platform_set_drvdata(pdev, NULL);
        scratch = readl(host->ioaddr + SDHCI_INT_STATUS);
        if (scratch == (u32)-1)
                dead = 1;
index e0dba74..5b7b2eb 100644 (file)
@@ -205,7 +205,7 @@ static const struct of_device_id sdhci_tegra_dt_match[] = {
 };
 MODULE_DEVICE_TABLE(of, sdhci_tegra_dt_match);
 
-static void sdhci_tegra_parse_dt(struct device *dev)
+static int sdhci_tegra_parse_dt(struct device *dev)
 {
        struct device_node *np = dev->of_node;
        struct sdhci_host *host = dev_get_drvdata(dev);
@@ -213,7 +213,7 @@ static void sdhci_tegra_parse_dt(struct device *dev)
        struct sdhci_tegra *tegra_host = pltfm_host->priv;
 
        tegra_host->power_gpio = of_get_named_gpio(np, "power-gpios", 0);
-       mmc_of_parse(host->mmc);
+       return mmc_of_parse(host->mmc);
 }
 
 static int sdhci_tegra_probe(struct platform_device *pdev)
@@ -231,7 +231,7 @@ static int sdhci_tegra_probe(struct platform_device *pdev)
                return -EINVAL;
        soc_data = match->data;
 
-       host = sdhci_pltfm_init(pdev, soc_data->pdata);
+       host = sdhci_pltfm_init(pdev, soc_data->pdata, 0);
        if (IS_ERR(host))
                return PTR_ERR(host);
        pltfm_host = sdhci_priv(host);
@@ -245,7 +245,9 @@ static int sdhci_tegra_probe(struct platform_device *pdev)
        tegra_host->soc_data = soc_data;
        pltfm_host->priv = tegra_host;
 
-       sdhci_tegra_parse_dt(&pdev->dev);
+       rc = sdhci_tegra_parse_dt(&pdev->dev);
+       if (rc)
+               goto err_parse_dt;
 
        if (gpio_is_valid(tegra_host->power_gpio)) {
                rc = gpio_request(tegra_host->power_gpio, "sdhci_power");
@@ -279,6 +281,7 @@ err_clk_get:
        if (gpio_is_valid(tegra_host->power_gpio))
                gpio_free(tegra_host->power_gpio);
 err_power_req:
+err_parse_dt:
 err_alloc_tegra_host:
        sdhci_pltfm_free(pdev);
        return rc;
index 2ea429c..a78bd4f 100644 (file)
@@ -58,6 +58,8 @@ static void sdhci_enable_preset_value(struct sdhci_host *host, bool enable);
 #ifdef CONFIG_PM_RUNTIME
 static int sdhci_runtime_pm_get(struct sdhci_host *host);
 static int sdhci_runtime_pm_put(struct sdhci_host *host);
+static void sdhci_runtime_pm_bus_on(struct sdhci_host *host);
+static void sdhci_runtime_pm_bus_off(struct sdhci_host *host);
 #else
 static inline int sdhci_runtime_pm_get(struct sdhci_host *host)
 {
@@ -67,6 +69,12 @@ static inline int sdhci_runtime_pm_put(struct sdhci_host *host)
 {
        return 0;
 }
+static void sdhci_runtime_pm_bus_on(struct sdhci_host *host)
+{
+}
+static void sdhci_runtime_pm_bus_off(struct sdhci_host *host)
+{
+}
 #endif
 
 static void sdhci_dumpregs(struct sdhci_host *host)
@@ -192,8 +200,12 @@ static void sdhci_reset(struct sdhci_host *host, u8 mask)
 
        sdhci_writeb(host, mask, SDHCI_SOFTWARE_RESET);
 
-       if (mask & SDHCI_RESET_ALL)
+       if (mask & SDHCI_RESET_ALL) {
                host->clock = 0;
+               /* Reset-all turns off SD Bus Power */
+               if (host->quirks2 & SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON)
+                       sdhci_runtime_pm_bus_off(host);
+       }
 
        /* Wait max 100 ms */
        timeout = 100;
@@ -1268,6 +1280,8 @@ static int sdhci_set_power(struct sdhci_host *host, unsigned short power)
 
        if (pwr == 0) {
                sdhci_writeb(host, 0, SDHCI_POWER_CONTROL);
+               if (host->quirks2 & SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON)
+                       sdhci_runtime_pm_bus_off(host);
                return 0;
        }
 
@@ -1289,6 +1303,9 @@ static int sdhci_set_power(struct sdhci_host *host, unsigned short power)
 
        sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL);
 
+       if (host->quirks2 & SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON)
+               sdhci_runtime_pm_bus_on(host);
+
        /*
         * Some controllers need an extra 10ms delay of 10ms before they
         * can apply clock after applying power
@@ -1526,16 +1543,15 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
                        ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
                        /* Select Bus Speed Mode for host */
                        ctrl_2 &= ~SDHCI_CTRL_UHS_MASK;
-                       if (ios->timing == MMC_TIMING_MMC_HS200)
-                               ctrl_2 |= SDHCI_CTRL_HS_SDR200;
+                       if ((ios->timing == MMC_TIMING_MMC_HS200) ||
+                           (ios->timing == MMC_TIMING_UHS_SDR104))
+                               ctrl_2 |= SDHCI_CTRL_UHS_SDR104;
                        else if (ios->timing == MMC_TIMING_UHS_SDR12)
                                ctrl_2 |= SDHCI_CTRL_UHS_SDR12;
                        else if (ios->timing == MMC_TIMING_UHS_SDR25)
                                ctrl_2 |= SDHCI_CTRL_UHS_SDR25;
                        else if (ios->timing == MMC_TIMING_UHS_SDR50)
                                ctrl_2 |= SDHCI_CTRL_UHS_SDR50;
-                       else if (ios->timing == MMC_TIMING_UHS_SDR104)
-                               ctrl_2 |= SDHCI_CTRL_UHS_SDR104;
                        else if (ios->timing == MMC_TIMING_UHS_DDR50)
                                ctrl_2 |= SDHCI_CTRL_UHS_DDR50;
                        sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
@@ -1846,7 +1862,7 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
         */
        if (((ctrl & SDHCI_CTRL_UHS_MASK) == SDHCI_CTRL_UHS_SDR50) &&
            (host->flags & SDHCI_SDR50_NEEDS_TUNING ||
-            host->flags & SDHCI_HS200_NEEDS_TUNING))
+            host->flags & SDHCI_SDR104_NEEDS_TUNING))
                requires_tuning_nonuhs = true;
 
        if (((ctrl & SDHCI_CTRL_UHS_MASK) == SDHCI_CTRL_UHS_SDR104) ||
@@ -2046,11 +2062,14 @@ static void sdhci_card_event(struct mmc_host *mmc)
        struct sdhci_host *host = mmc_priv(mmc);
        unsigned long flags;
 
+       /* First check if client has provided their own card event */
+       if (host->ops->card_event)
+               host->ops->card_event(host);
+
        spin_lock_irqsave(&host->lock, flags);
 
        /* Check host->mrq first in case we are runtime suspended */
-       if (host->mrq &&
-           !(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT)) {
+       if (host->mrq && !sdhci_do_get_cd(host)) {
                pr_err("%s: Card removed during transfer!\n",
                        mmc_hostname(host->mmc));
                pr_err("%s: Resetting controller.\n",
@@ -2625,6 +2644,22 @@ static int sdhci_runtime_pm_put(struct sdhci_host *host)
        return pm_runtime_put_autosuspend(host->mmc->parent);
 }
 
+static void sdhci_runtime_pm_bus_on(struct sdhci_host *host)
+{
+       if (host->runtime_suspended || host->bus_on)
+               return;
+       host->bus_on = true;
+       pm_runtime_get_noresume(host->mmc->parent);
+}
+
+static void sdhci_runtime_pm_bus_off(struct sdhci_host *host)
+{
+       if (host->runtime_suspended || !host->bus_on)
+               return;
+       host->bus_on = false;
+       pm_runtime_put_noidle(host->mmc->parent);
+}
+
 int sdhci_runtime_suspend_host(struct sdhci_host *host)
 {
        unsigned long flags;
@@ -2962,9 +2997,13 @@ int sdhci_add_host(struct sdhci_host *host)
                mmc->caps |= MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25;
 
        /* SDR104 supports also implies SDR50 support */
-       if (caps[1] & SDHCI_SUPPORT_SDR104)
+       if (caps[1] & SDHCI_SUPPORT_SDR104) {
                mmc->caps |= MMC_CAP_UHS_SDR104 | MMC_CAP_UHS_SDR50;
-       else if (caps[1] & SDHCI_SUPPORT_SDR50)
+               /* SD3.0: SDR104 is supported so (for eMMC) the caps2
+                * field can be promoted to support HS200.
+                */
+               mmc->caps2 |= MMC_CAP2_HS200;
+       } else if (caps[1] & SDHCI_SUPPORT_SDR50)
                mmc->caps |= MMC_CAP_UHS_SDR50;
 
        if (caps[1] & SDHCI_SUPPORT_DDR50)
@@ -2974,9 +3013,9 @@ int sdhci_add_host(struct sdhci_host *host)
        if (caps[1] & SDHCI_USE_SDR50_TUNING)
                host->flags |= SDHCI_SDR50_NEEDS_TUNING;
 
-       /* Does the host need tuning for HS200? */
+       /* Does the host need tuning for SDR104 / HS200? */
        if (mmc->caps2 & MMC_CAP2_HS200)
-               host->flags |= SDHCI_HS200_NEEDS_TUNING;
+               host->flags |= SDHCI_SDR104_NEEDS_TUNING;
 
        /* Driver Type(s) (A, C, D) supported by the host */
        if (caps[1] & SDHCI_DRIVER_TYPE_A)
index 379e09d..b037f18 100644 (file)
@@ -294,6 +294,7 @@ struct sdhci_ops {
        void    (*platform_resume)(struct sdhci_host *host);
        void    (*adma_workaround)(struct sdhci_host *host, u32 intmask);
        void    (*platform_init)(struct sdhci_host *host);
+       void    (*card_event)(struct sdhci_host *host);
 };
 
 #ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
index ba76a53..6706b5e 100644 (file)
@@ -1244,7 +1244,8 @@ static irqreturn_t sh_mmcif_intr(int irq, void *dev_id)
        u32 state;
 
        state = sh_mmcif_readl(host->addr, MMCIF_CE_INT);
-       sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~state);
+       sh_mmcif_writel(host->addr, MMCIF_CE_INT,
+                       ~(state & sh_mmcif_readl(host->addr, MMCIF_CE_INT_MASK)));
        sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, state & MASK_CLEAN);
 
        if (state & ~MASK_CLEAN)
@@ -1369,7 +1370,11 @@ static int sh_mmcif_probe(struct platform_device *pdev)
                ret = -ENOMEM;
                goto ealloch;
        }
-       mmc_of_parse(mmc);
+
+       ret = mmc_of_parse(mmc);
+       if (ret < 0)
+               goto eofparse;
+
        host            = mmc_priv(mmc);
        host->mmc       = mmc;
        host->addr      = reg;
@@ -1464,6 +1469,7 @@ eclkupdate:
        clk_put(host->hclk);
 eclkget:
        pm_runtime_disable(&pdev->dev);
+eofparse:
        mmc_free_host(mmc);
 ealloch:
        iounmap(reg);
@@ -1501,8 +1507,6 @@ static int sh_mmcif_remove(struct platform_device *pdev)
        if (irq[1] >= 0)
                free_irq(irq[1], host);
 
-       platform_set_drvdata(pdev, NULL);
-
        clk_disable(host->hclk);
        mmc_free_host(host->mmc);
        pm_runtime_put_sync(&pdev->dev);
index fe90853..ebea749 100644 (file)
@@ -46,14 +46,12 @@ static const struct sh_mobile_sdhi_of_data sh_mobile_sdhi_of_cfg[] = {
 struct sh_mobile_sdhi {
        struct clk *clk;
        struct tmio_mmc_data mmc_data;
-       struct sh_dmae_slave param_tx;
-       struct sh_dmae_slave param_rx;
        struct tmio_mmc_dma dma_priv;
 };
 
 static int sh_mobile_sdhi_clk_enable(struct platform_device *pdev, unsigned int *f)
 {
-       struct mmc_host *mmc = dev_get_drvdata(&pdev->dev);
+       struct mmc_host *mmc = platform_get_drvdata(pdev);
        struct tmio_mmc_host *host = mmc_priv(mmc);
        struct sh_mobile_sdhi *priv = container_of(host->pdata, struct sh_mobile_sdhi, mmc_data);
        int ret = clk_enable(priv->clk);
@@ -66,7 +64,7 @@ static int sh_mobile_sdhi_clk_enable(struct platform_device *pdev, unsigned int
 
 static void sh_mobile_sdhi_clk_disable(struct platform_device *pdev)
 {
-       struct mmc_host *mmc = dev_get_drvdata(&pdev->dev);
+       struct mmc_host *mmc = platform_get_drvdata(pdev);
        struct tmio_mmc_host *host = mmc_priv(mmc);
        struct sh_mobile_sdhi *priv = container_of(host->pdata, struct sh_mobile_sdhi, mmc_data);
        clk_disable(priv->clk);
@@ -121,7 +119,7 @@ static int sh_mobile_sdhi_write16_hook(struct tmio_mmc_host *host, int addr)
 
 static void sh_mobile_sdhi_cd_wakeup(const struct platform_device *pdev)
 {
-       mmc_detect_change(dev_get_drvdata(&pdev->dev), msecs_to_jiffies(100));
+       mmc_detect_change(platform_get_drvdata(pdev), msecs_to_jiffies(100));
 }
 
 static const struct sh_mobile_sdhi_ops sdhi_ops = {
@@ -146,6 +144,7 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev)
        struct tmio_mmc_host *host;
        int irq, ret, i = 0;
        bool multiplexed_isr = true;
+       struct tmio_mmc_dma *dma_priv;
 
        priv = devm_kzalloc(&pdev->dev, sizeof(struct sh_mobile_sdhi), GFP_KERNEL);
        if (priv == NULL) {
@@ -154,6 +153,7 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev)
        }
 
        mmc_data = &priv->mmc_data;
+       dma_priv = &priv->dma_priv;
 
        if (p) {
                if (p->init) {
@@ -186,15 +186,23 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev)
                        mmc_data->get_cd = sh_mobile_sdhi_get_cd;
 
                if (p->dma_slave_tx > 0 && p->dma_slave_rx > 0) {
-                       priv->param_tx.shdma_slave.slave_id = p->dma_slave_tx;
-                       priv->param_rx.shdma_slave.slave_id = p->dma_slave_rx;
-                       priv->dma_priv.chan_priv_tx = &priv->param_tx.shdma_slave;
-                       priv->dma_priv.chan_priv_rx = &priv->param_rx.shdma_slave;
-                       priv->dma_priv.alignment_shift = 1; /* 2-byte alignment */
-                       mmc_data->dma = &priv->dma_priv;
+                       /*
+                        * Yes, we have to provide slave IDs twice to TMIO:
+                        * once as a filter parameter and once for channel
+                        * configuration as an explicit slave ID
+                        */
+                       dma_priv->chan_priv_tx = (void *)p->dma_slave_tx;
+                       dma_priv->chan_priv_rx = (void *)p->dma_slave_rx;
+                       dma_priv->slave_id_tx = p->dma_slave_tx;
+                       dma_priv->slave_id_rx = p->dma_slave_rx;
                }
        }
 
+       dma_priv->alignment_shift = 1; /* 2-byte alignment */
+       dma_priv->filter = shdma_chan_filter;
+
+       mmc_data->dma = dma_priv;
+
        /*
         * All SDHI blocks support 2-byte and larger block sizes in 4-bit
         * bus width mode.
@@ -265,8 +273,10 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev)
                }
 
                /* There must be at least one IRQ source */
-               if (!i)
+               if (!i) {
+                       ret = irq;
                        goto eirq;
+               }
        }
 
        dev_info(&pdev->dev, "%s base at 0x%08lx clock rate %u MHz\n",
index 139212e..8860d4d 100644 (file)
@@ -112,8 +112,6 @@ static int tmio_mmc_remove(struct platform_device *pdev)
        const struct mfd_cell *cell = mfd_get_cell(pdev);
        struct mmc_host *mmc = platform_get_drvdata(pdev);
 
-       platform_set_drvdata(pdev, NULL);
-
        if (mmc) {
                struct tmio_mmc_host *host = mmc_priv(mmc);
                free_irq(platform_get_irq(pdev, 0), host);
index d857f5c..86fd21e 100644 (file)
 
 struct tmio_mmc_data;
 
+/*
+ * We differentiate between the following 3 power states:
+ * 1. card slot powered off, controller stopped. This is used, when either there
+ *    is no card in the slot, or the card really has to be powered down.
+ * 2. card slot powered on, controller stopped. This is used, when a card is in
+ *    the slot, but no activity is currently taking place. This is a power-
+ *    saving mode with card-state preserved. This state can be entered, e.g.
+ *    when MMC clock-gating is used.
+ * 3. card slot powered on, controller running. This is the actual active state.
+ */
+enum tmio_mmc_power {
+       TMIO_MMC_OFF_STOP,      /* card power off, controller stopped */
+       TMIO_MMC_ON_STOP,       /* card power on, controller stopped */
+       TMIO_MMC_ON_RUN,        /* card power on, controller running */
+};
+
 struct tmio_mmc_host {
        void __iomem *ctl;
        unsigned long bus_shift;
@@ -48,8 +64,8 @@ struct tmio_mmc_host {
        struct mmc_data         *data;
        struct mmc_host         *mmc;
 
-       /* Controller power state */
-       bool                    power;
+       /* Controller and card power state */
+       enum tmio_mmc_power     power;
 
        /* Callbacks for clock / power control */
        void (*set_pwr)(struct platform_device *host, int state);
@@ -85,6 +101,7 @@ struct tmio_mmc_host {
        unsigned long           last_req_ts;
        struct mutex            ios_lock;       /* protect set_ios() context */
        bool                    native_hotplug;
+       bool                    resuming;
 };
 
 int tmio_mmc_host_probe(struct tmio_mmc_host **host,
index fff9286..47bdb8f 100644 (file)
@@ -261,42 +261,62 @@ out:
        spin_unlock_irq(&host->lock);
 }
 
-/* It might be necessary to make filter MFD specific */
-static bool tmio_mmc_filter(struct dma_chan *chan, void *arg)
-{
-       dev_dbg(chan->device->dev, "%s: slave data %p\n", __func__, arg);
-       chan->private = arg;
-       return true;
-}
-
 void tmio_mmc_request_dma(struct tmio_mmc_host *host, struct tmio_mmc_data *pdata)
 {
        /* We can only either use DMA for both Tx and Rx or not use it at all */
-       if (!pdata->dma)
+       if (!pdata->dma || (!host->pdev->dev.of_node &&
+               (!pdata->dma->chan_priv_tx || !pdata->dma->chan_priv_rx)))
                return;
 
        if (!host->chan_tx && !host->chan_rx) {
+               struct resource *res = platform_get_resource(host->pdev,
+                                                            IORESOURCE_MEM, 0);
+               struct dma_slave_config cfg = {};
                dma_cap_mask_t mask;
+               int ret;
+
+               if (!res)
+                       return;
 
                dma_cap_zero(mask);
                dma_cap_set(DMA_SLAVE, mask);
 
-               host->chan_tx = dma_request_channel(mask, tmio_mmc_filter,
-                                                   pdata->dma->chan_priv_tx);
+               host->chan_tx = dma_request_slave_channel_compat(mask,
+                                       pdata->dma->filter, pdata->dma->chan_priv_tx,
+                                       &host->pdev->dev, "tx");
                dev_dbg(&host->pdev->dev, "%s: TX: got channel %p\n", __func__,
                        host->chan_tx);
 
                if (!host->chan_tx)
                        return;
 
-               host->chan_rx = dma_request_channel(mask, tmio_mmc_filter,
-                                                   pdata->dma->chan_priv_rx);
+               if (pdata->dma->chan_priv_tx)
+                       cfg.slave_id = pdata->dma->slave_id_tx;
+               cfg.direction = DMA_MEM_TO_DEV;
+               cfg.dst_addr = res->start + (CTL_SD_DATA_PORT << host->bus_shift);
+               cfg.src_addr = 0;
+               ret = dmaengine_slave_config(host->chan_tx, &cfg);
+               if (ret < 0)
+                       goto ecfgtx;
+
+               host->chan_rx = dma_request_slave_channel_compat(mask,
+                                       pdata->dma->filter, pdata->dma->chan_priv_rx,
+                                       &host->pdev->dev, "rx");
                dev_dbg(&host->pdev->dev, "%s: RX: got channel %p\n", __func__,
                        host->chan_rx);
 
                if (!host->chan_rx)
                        goto ereqrx;
 
+               if (pdata->dma->chan_priv_rx)
+                       cfg.slave_id = pdata->dma->slave_id_rx;
+               cfg.direction = DMA_DEV_TO_MEM;
+               cfg.src_addr = cfg.dst_addr;
+               cfg.dst_addr = 0;
+               ret = dmaengine_slave_config(host->chan_rx, &cfg);
+               if (ret < 0)
+                       goto ecfgrx;
+
                host->bounce_buf = (u8 *)__get_free_page(GFP_KERNEL | GFP_DMA);
                if (!host->bounce_buf)
                        goto ebouncebuf;
@@ -310,9 +330,11 @@ void tmio_mmc_request_dma(struct tmio_mmc_host *host, struct tmio_mmc_data *pdat
        return;
 
 ebouncebuf:
+ecfgrx:
        dma_release_channel(host->chan_rx);
        host->chan_rx = NULL;
 ereqrx:
+ecfgtx:
        dma_release_channel(host->chan_tx);
        host->chan_tx = NULL;
 }
index f508ecb..b72edb7 100644 (file)
@@ -859,32 +859,45 @@ static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
         * is kept positive, so no suspending actually takes place.
         */
        if (ios->power_mode == MMC_POWER_ON && ios->clock) {
-               if (!host->power) {
+               if (host->power != TMIO_MMC_ON_RUN) {
                        tmio_mmc_clk_update(mmc);
                        pm_runtime_get_sync(dev);
+                       if (host->resuming) {
+                               tmio_mmc_reset(host);
+                               host->resuming = false;
+                       }
                }
+               if (host->power == TMIO_MMC_OFF_STOP)
+                       tmio_mmc_reset(host);
                tmio_mmc_set_clock(host, ios->clock);
-               if (!host->power) {
+               if (host->power == TMIO_MMC_OFF_STOP)
                        /* power up SD card and the bus */
                        tmio_mmc_power_on(host, ios->vdd);
-                       host->power = true;
-               }
+               host->power = TMIO_MMC_ON_RUN;
                /* start bus clock */
                tmio_mmc_clk_start(host);
        } else if (ios->power_mode != MMC_POWER_UP) {
-               if (host->power) {
-                       struct tmio_mmc_data *pdata = host->pdata;
-                       if (ios->power_mode == MMC_POWER_OFF)
+               struct tmio_mmc_data *pdata = host->pdata;
+               unsigned int old_power = host->power;
+
+               if (old_power != TMIO_MMC_OFF_STOP) {
+                       if (ios->power_mode == MMC_POWER_OFF) {
                                tmio_mmc_power_off(host);
+                               host->power = TMIO_MMC_OFF_STOP;
+                       } else {
+                               host->power = TMIO_MMC_ON_STOP;
+                       }
+               }
+
+               if (old_power == TMIO_MMC_ON_RUN) {
                        tmio_mmc_clk_stop(host);
-                       host->power = false;
                        pm_runtime_put(dev);
                        if (pdata->clk_disable)
                                pdata->clk_disable(host->pdev);
                }
        }
 
-       if (host->power) {
+       if (host->power != TMIO_MMC_OFF_STOP) {
                switch (ios->bus_width) {
                case MMC_BUS_WIDTH_1:
                        sd_ctrl_write16(host, CTL_SD_MEM_CARD_OPT, 0x80e0);
@@ -988,7 +1001,9 @@ int tmio_mmc_host_probe(struct tmio_mmc_host **host,
        if (!mmc)
                return -ENOMEM;
 
-       mmc_of_parse(mmc);
+       ret = mmc_of_parse(mmc);
+       if (ret < 0)
+               goto host_free;
 
        pdata->dev = &pdev->dev;
        _host = mmc_priv(mmc);
@@ -1025,7 +1040,7 @@ int tmio_mmc_host_probe(struct tmio_mmc_host **host,
                                  mmc->caps & MMC_CAP_NONREMOVABLE ||
                                  mmc->slot.cd_irq >= 0);
 
-       _host->power = false;
+       _host->power = TMIO_MMC_OFF_STOP;
        pm_runtime_enable(&pdev->dev);
        ret = pm_runtime_resume(&pdev->dev);
        if (ret < 0)
@@ -1154,10 +1169,10 @@ int tmio_mmc_host_resume(struct device *dev)
        struct mmc_host *mmc = dev_get_drvdata(dev);
        struct tmio_mmc_host *host = mmc_priv(mmc);
 
-       tmio_mmc_reset(host);
        tmio_mmc_enable_dma(host, true);
 
        /* The MMC core will perform the complete set up */
+       host->resuming = true;
        return mmc_resume_host(mmc);
 }
 EXPORT_SYMBOL(tmio_mmc_host_resume);
@@ -1175,7 +1190,6 @@ int tmio_mmc_host_runtime_resume(struct device *dev)
        struct mmc_host *mmc = dev_get_drvdata(dev);
        struct tmio_mmc_host *host = mmc_priv(mmc);
 
-       tmio_mmc_reset(host);
        tmio_mmc_enable_dma(host, true);
 
        return 0;
index 442f576..34231d5 100644 (file)
@@ -927,8 +927,6 @@ static int wmt_mci_remove(struct platform_device *pdev)
 
        mmc_free_host(mmc);
 
-       platform_set_drvdata(pdev, NULL);
-
        dev_info(&pdev->dev, "WMT MCI device removed\n");
 
        return 0;
index b918c73..c6f838d 100644 (file)
@@ -32,7 +32,6 @@
 #include <linux/clk.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
-#include <linux/pinctrl/consumer.h>
 
 #include <linux/can/dev.h>
 
@@ -114,7 +113,6 @@ static int c_can_plat_probe(struct platform_device *pdev)
        struct c_can_priv *priv;
        const struct of_device_id *match;
        const struct platform_device_id *id;
-       struct pinctrl *pinctrl;
        struct resource *mem, *res;
        int irq;
        struct clk *clk;
@@ -131,11 +129,6 @@ static int c_can_plat_probe(struct platform_device *pdev)
                id = platform_get_device_id(pdev);
        }
 
-       pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
-       if (IS_ERR(pinctrl))
-               dev_warn(&pdev->dev,
-                       "failed to configure pins from driver\n");
-
        /* get the appropriate clk */
        clk = clk_get(&pdev->dev, NULL);
        if (IS_ERR(clk)) {
index 42aa54a..b710c6b 100644 (file)
@@ -185,6 +185,8 @@ static int __init dummy_init_module(void)
 
        rtnl_lock();
        err = __rtnl_link_register(&dummy_link_ops);
+       if (err < 0)
+               goto out;
 
        for (i = 0; i < numdummies && !err; i++) {
                err = dummy_init_one();
@@ -192,6 +194,8 @@ static int __init dummy_init_module(void)
        }
        if (err < 0)
                __rtnl_link_unregister(&dummy_link_ops);
+
+out:
        rtnl_unlock();
 
        return err;
index 0e0b242..027398e 100644 (file)
@@ -1245,6 +1245,8 @@ static int alx_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 
        SET_NETDEV_DEV(netdev, &pdev->dev);
        alx = netdev_priv(netdev);
+       spin_lock_init(&alx->hw.mdio_lock);
+       spin_lock_init(&alx->irq_lock);
        alx->dev = netdev;
        alx->hw.pdev = pdev;
        alx->msg_enable = NETIF_MSG_LINK | NETIF_MSG_HW | NETIF_MSG_IFUP |
@@ -1327,9 +1329,6 @@ static int alx_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 
        INIT_WORK(&alx->link_check_wk, alx_link_check);
        INIT_WORK(&alx->reset_wk, alx_reset);
-       spin_lock_init(&alx->hw.mdio_lock);
-       spin_lock_init(&alx->irq_lock);
-
        netif_carrier_off(netdev);
 
        err = register_netdev(netdev);
index 895f537..6d1a62a 100644 (file)
@@ -1665,8 +1665,8 @@ check_sum:
        return 0;
 }
 
-static void atl1e_tx_map(struct atl1e_adapter *adapter,
-                     struct sk_buff *skb, struct atl1e_tpd_desc *tpd)
+static int atl1e_tx_map(struct atl1e_adapter *adapter,
+                       struct sk_buff *skb, struct atl1e_tpd_desc *tpd)
 {
        struct atl1e_tpd_desc *use_tpd = NULL;
        struct atl1e_tx_buffer *tx_buffer = NULL;
@@ -1677,6 +1677,7 @@ static void atl1e_tx_map(struct atl1e_adapter *adapter,
        u16 nr_frags;
        u16 f;
        int segment;
+       int ring_start = adapter->tx_ring.next_to_use;
 
        nr_frags = skb_shinfo(skb)->nr_frags;
        segment = (tpd->word3 >> TPD_SEGMENT_EN_SHIFT) & TPD_SEGMENT_EN_MASK;
@@ -1689,6 +1690,9 @@ static void atl1e_tx_map(struct atl1e_adapter *adapter,
                tx_buffer->length = map_len;
                tx_buffer->dma = pci_map_single(adapter->pdev,
                                        skb->data, hdr_len, PCI_DMA_TODEVICE);
+               if (dma_mapping_error(&adapter->pdev->dev, tx_buffer->dma))
+                       return -ENOSPC;
+
                ATL1E_SET_PCIMAP_TYPE(tx_buffer, ATL1E_TX_PCIMAP_SINGLE);
                mapped_len += map_len;
                use_tpd->buffer_addr = cpu_to_le64(tx_buffer->dma);
@@ -1715,6 +1719,13 @@ static void atl1e_tx_map(struct atl1e_adapter *adapter,
                tx_buffer->dma =
                        pci_map_single(adapter->pdev, skb->data + mapped_len,
                                        map_len, PCI_DMA_TODEVICE);
+
+               if (dma_mapping_error(&adapter->pdev->dev, tx_buffer->dma)) {
+                       /* Reset the tx rings next pointer */
+                       adapter->tx_ring.next_to_use = ring_start;
+                       return -ENOSPC;
+               }
+
                ATL1E_SET_PCIMAP_TYPE(tx_buffer, ATL1E_TX_PCIMAP_SINGLE);
                mapped_len  += map_len;
                use_tpd->buffer_addr = cpu_to_le64(tx_buffer->dma);
@@ -1750,6 +1761,13 @@ static void atl1e_tx_map(struct atl1e_adapter *adapter,
                                                          (i * MAX_TX_BUF_LEN),
                                                          tx_buffer->length,
                                                          DMA_TO_DEVICE);
+
+                       if (dma_mapping_error(&adapter->pdev->dev, tx_buffer->dma)) {
+                               /* Reset the ring next to use pointer */
+                               adapter->tx_ring.next_to_use = ring_start;
+                               return -ENOSPC;
+                       }
+
                        ATL1E_SET_PCIMAP_TYPE(tx_buffer, ATL1E_TX_PCIMAP_PAGE);
                        use_tpd->buffer_addr = cpu_to_le64(tx_buffer->dma);
                        use_tpd->word2 = (use_tpd->word2 & (~TPD_BUFLEN_MASK)) |
@@ -1767,6 +1785,7 @@ static void atl1e_tx_map(struct atl1e_adapter *adapter,
        /* The last buffer info contain the skb address,
           so it will be free after unmap */
        tx_buffer->skb = skb;
+       return 0;
 }
 
 static void atl1e_tx_queue(struct atl1e_adapter *adapter, u16 count,
@@ -1834,10 +1853,13 @@ static netdev_tx_t atl1e_xmit_frame(struct sk_buff *skb,
                return NETDEV_TX_OK;
        }
 
-       atl1e_tx_map(adapter, skb, tpd);
+       if (atl1e_tx_map(adapter, skb, tpd))
+               goto out;
+
        atl1e_tx_queue(adapter, tpd_req, tpd);
 
        netdev->trans_start = jiffies; /* NETIF_F_LLTX driver :( */
+out:
        spin_unlock_irqrestore(&adapter->tx_lock, flags);
        return NETDEV_TX_OK;
 }
index ec3aa1d..ee350bd 100644 (file)
@@ -24,7 +24,7 @@
 #include <net/tcp.h>
 #include <net/ipv6.h>
 #include <net/ip6_checksum.h>
-#include <net/ll_poll.h>
+#include <net/busy_poll.h>
 #include <linux/prefetch.h>
 #include "bnx2x_cmn.h"
 #include "bnx2x_init.h"
@@ -990,7 +990,7 @@ reuse_rx:
                        __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q),
                                               le16_to_cpu(cqe_fp->vlan_tag));
 
-               skb_mark_ll(skb, &fp->napi);
+               skb_mark_napi_id(skb, &fp->napi);
 
                if (bnx2x_fp_ll_polling(fp))
                        netif_receive_skb(skb);
@@ -3543,9 +3543,9 @@ static void bnx2x_update_pbds_gso_enc(struct sk_buff *skb,
        /* outer IP header info */
        if (xmit_type & XMIT_CSUM_V4) {
                struct iphdr *iph = ip_hdr(skb);
-               u16 csum = (__force u16)(~iph->check) -
-                          (__force u16)iph->tot_len -
-                          (__force u16)iph->frag_off;
+               u32 csum = (__force u32)(~iph->check) -
+                          (__force u32)iph->tot_len -
+                          (__force u32)iph->frag_off;
 
                pbd2->fw_ip_csum_wo_len_flags_frag =
                        bswab16(csum_fold((__force __wsum)csum));
index 15a528b..e5da078 100644 (file)
@@ -12027,7 +12027,7 @@ static const struct net_device_ops bnx2x_netdev_ops = {
 #endif
 
 #ifdef CONFIG_NET_LL_RX_POLL
-       .ndo_ll_poll            = bnx2x_low_latency_recv,
+       .ndo_busy_poll          = bnx2x_low_latency_recv,
 #endif
 };
 
index 3f19571..bb5d63f 100644 (file)
@@ -29,7 +29,6 @@
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/of_net.h>
-#include <linux/pinctrl/consumer.h>
 
 #include "macb.h"
 
@@ -309,7 +308,6 @@ static int __init at91ether_probe(struct platform_device *pdev)
        struct resource *regs;
        struct net_device *dev;
        struct phy_device *phydev;
-       struct pinctrl *pinctrl;
        struct macb *lp;
        int res;
        u32 reg;
@@ -319,15 +317,6 @@ static int __init at91ether_probe(struct platform_device *pdev)
        if (!regs)
                return -ENOENT;
 
-       pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
-       if (IS_ERR(pinctrl)) {
-               res = PTR_ERR(pinctrl);
-               if (res == -EPROBE_DEFER)
-                       return res;
-
-               dev_warn(&pdev->dev, "No pinctrl provided\n");
-       }
-
        dev = alloc_etherdev(sizeof(struct macb));
        if (!dev)
                return -ENOMEM;
index fb098b4..7be725c 100644 (file)
@@ -52,7 +52,7 @@
 #include <linux/dca.h>
 #endif
 
-#include <net/ll_poll.h>
+#include <net/busy_poll.h>
 
 #ifdef CONFIG_NET_LL_RX_POLL
 #define LL_EXTENDED_STATS
index 047ebaa..bad8f14 100644 (file)
@@ -1978,7 +1978,7 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
                }
 
 #endif /* IXGBE_FCOE */
-               skb_mark_ll(skb, &q_vector->napi);
+               skb_mark_napi_id(skb, &q_vector->napi);
                ixgbe_rx_skb(q_vector, skb);
 
                /* update budget accounting */
@@ -7228,7 +7228,7 @@ static const struct net_device_ops ixgbe_netdev_ops = {
        .ndo_poll_controller    = ixgbe_netpoll,
 #endif
 #ifdef CONFIG_NET_LL_RX_POLL
-       .ndo_ll_poll            = ixgbe_low_latency_recv,
+       .ndo_busy_poll          = ixgbe_low_latency_recv,
 #endif
 #ifdef IXGBE_FCOE
        .ndo_fcoe_ddp_setup = ixgbe_fcoe_ddp_get,
index bcdbc14..8cf7563 100644 (file)
@@ -19,5 +19,6 @@ config NET_VENDOR_MELLANOX
 if NET_VENDOR_MELLANOX
 
 source "drivers/net/ethernet/mellanox/mlx4/Kconfig"
+source "drivers/net/ethernet/mellanox/mlx5/core/Kconfig"
 
 endif # NET_VENDOR_MELLANOX
index 37afb96..38fe32e 100644 (file)
@@ -3,3 +3,4 @@
 #
 
 obj-$(CONFIG_MLX4_CORE) += mlx4/
+obj-$(CONFIG_MLX5_CORE) += mlx5/core/
index caf2047..5eac871 100644 (file)
@@ -38,7 +38,7 @@
 #include <linux/slab.h>
 #include <linux/hash.h>
 #include <net/ip.h>
-#include <net/ll_poll.h>
+#include <net/busy_poll.h>
 
 #include <linux/mlx4/driver.h>
 #include <linux/mlx4/device.h>
@@ -2141,7 +2141,7 @@ static const struct net_device_ops mlx4_netdev_ops = {
        .ndo_rx_flow_steer      = mlx4_en_filter_rfs,
 #endif
 #ifdef CONFIG_NET_LL_RX_POLL
-       .ndo_ll_poll            = mlx4_en_low_latency_recv,
+       .ndo_busy_poll          = mlx4_en_low_latency_recv,
 #endif
 };
 
index 76997b9..dec455c 100644 (file)
@@ -31,7 +31,7 @@
  *
  */
 
-#include <net/ll_poll.h>
+#include <net/busy_poll.h>
 #include <linux/mlx4/cq.h>
 #include <linux/slab.h>
 #include <linux/mlx4/qp.h>
@@ -767,7 +767,7 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud
                                               timestamp);
                }
 
-               skb_mark_ll(skb, &cq->napi);
+               skb_mark_napi_id(skb, &cq->napi);
 
                /* Push it up the stack */
                netif_receive_skb(skb);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/Kconfig b/drivers/net/ethernet/mellanox/mlx5/core/Kconfig
new file mode 100644 (file)
index 0000000..2196282
--- /dev/null
@@ -0,0 +1,18 @@
+#
+# Mellanox driver configuration
+#
+
+config MLX5_CORE
+       tristate
+       depends on PCI && X86
+       default n
+
+config MLX5_DEBUG
+       bool "Verbose debugging output" if (MLX5_CORE && EXPERT)
+       depends on MLX5_CORE
+       default y
+       ---help---
+         This option causes debugging code to be compiled into the
+         mlx5_core driver.  The output can be turned on via the
+         debug_mask module parameter (which can also be set after
+         the driver is loaded through sysfs).
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/Makefile b/drivers/net/ethernet/mellanox/mlx5/core/Makefile
new file mode 100644 (file)
index 0000000..105780b
--- /dev/null
@@ -0,0 +1,5 @@
+obj-$(CONFIG_MLX5_CORE)                += mlx5_core.o
+
+mlx5_core-y := main.o cmd.o debugfs.o fw.o eq.o uar.o pagealloc.o \
+               health.o mcg.o cq.o srq.o alloc.o qp.o port.o mr.o pd.o   \
+               mad.o
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/alloc.c b/drivers/net/ethernet/mellanox/mlx5/core/alloc.c
new file mode 100644 (file)
index 0000000..b215742
--- /dev/null
@@ -0,0 +1,238 @@
+/*
+ * Copyright (c) 2013, Mellanox Technologies inc.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/export.h>
+#include <linux/bitmap.h>
+#include <linux/dma-mapping.h>
+#include <linux/vmalloc.h>
+#include <linux/mlx5/driver.h>
+
+#include "mlx5_core.h"
+
+/* Handling for queue buffers -- we allocate a bunch of memory and
+ * register it in a memory region at HCA virtual address 0.  If the
+ * requested size is > max_direct, we split the allocation into
+ * multiple pages, so we don't require too much contiguous memory.
+ */
+
+int mlx5_buf_alloc(struct mlx5_core_dev *dev, int size, int max_direct,
+                  struct mlx5_buf *buf)
+{
+       dma_addr_t t;
+
+       buf->size = size;
+       if (size <= max_direct) {
+               buf->nbufs        = 1;
+               buf->npages       = 1;
+               buf->page_shift   = get_order(size) + PAGE_SHIFT;
+               buf->direct.buf   = dma_zalloc_coherent(&dev->pdev->dev,
+                                                       size, &t, GFP_KERNEL);
+               if (!buf->direct.buf)
+                       return -ENOMEM;
+
+               buf->direct.map = t;
+
+               while (t & ((1 << buf->page_shift) - 1)) {
+                       --buf->page_shift;
+                       buf->npages *= 2;
+               }
+       } else {
+               int i;
+
+               buf->direct.buf  = NULL;
+               buf->nbufs       = (size + PAGE_SIZE - 1) / PAGE_SIZE;
+               buf->npages      = buf->nbufs;
+               buf->page_shift  = PAGE_SHIFT;
+               buf->page_list   = kcalloc(buf->nbufs, sizeof(*buf->page_list),
+                                          GFP_KERNEL);
+               if (!buf->page_list)
+                       return -ENOMEM;
+
+               for (i = 0; i < buf->nbufs; i++) {
+                       buf->page_list[i].buf =
+                               dma_zalloc_coherent(&dev->pdev->dev, PAGE_SIZE,
+                                                   &t, GFP_KERNEL);
+                       if (!buf->page_list[i].buf)
+                               goto err_free;
+
+                       buf->page_list[i].map = t;
+               }
+
+               if (BITS_PER_LONG == 64) {
+                       struct page **pages;
+                       pages = kmalloc(sizeof(*pages) * buf->nbufs, GFP_KERNEL);
+                       if (!pages)
+                               goto err_free;
+                       for (i = 0; i < buf->nbufs; i++)
+                               pages[i] = virt_to_page(buf->page_list[i].buf);
+                       buf->direct.buf = vmap(pages, buf->nbufs, VM_MAP, PAGE_KERNEL);
+                       kfree(pages);
+                       if (!buf->direct.buf)
+                               goto err_free;
+               }
+       }
+
+       return 0;
+
+err_free:
+       mlx5_buf_free(dev, buf);
+
+       return -ENOMEM;
+}
+EXPORT_SYMBOL_GPL(mlx5_buf_alloc);
+
+void mlx5_buf_free(struct mlx5_core_dev *dev, struct mlx5_buf *buf)
+{
+       int i;
+
+       if (buf->nbufs == 1)
+               dma_free_coherent(&dev->pdev->dev, buf->size, buf->direct.buf,
+                                 buf->direct.map);
+       else {
+               if (BITS_PER_LONG == 64 && buf->direct.buf)
+                       vunmap(buf->direct.buf);
+
+               for (i = 0; i < buf->nbufs; i++)
+                       if (buf->page_list[i].buf)
+                               dma_free_coherent(&dev->pdev->dev, PAGE_SIZE,
+                                                 buf->page_list[i].buf,
+                                                 buf->page_list[i].map);
+               kfree(buf->page_list);
+       }
+}
+EXPORT_SYMBOL_GPL(mlx5_buf_free);
+
+static struct mlx5_db_pgdir *mlx5_alloc_db_pgdir(struct device *dma_device)
+{
+       struct mlx5_db_pgdir *pgdir;
+
+       pgdir = kzalloc(sizeof(*pgdir), GFP_KERNEL);
+       if (!pgdir)
+               return NULL;
+
+       bitmap_fill(pgdir->bitmap, MLX5_DB_PER_PAGE);
+       pgdir->db_page = dma_alloc_coherent(dma_device, PAGE_SIZE,
+                                           &pgdir->db_dma, GFP_KERNEL);
+       if (!pgdir->db_page) {
+               kfree(pgdir);
+               return NULL;
+       }
+
+       return pgdir;
+}
+
+static int mlx5_alloc_db_from_pgdir(struct mlx5_db_pgdir *pgdir,
+                                   struct mlx5_db *db)
+{
+       int offset;
+       int i;
+
+       i = find_first_bit(pgdir->bitmap, MLX5_DB_PER_PAGE);
+       if (i >= MLX5_DB_PER_PAGE)
+               return -ENOMEM;
+
+       __clear_bit(i, pgdir->bitmap);
+
+       db->u.pgdir = pgdir;
+       db->index   = i;
+       offset = db->index * L1_CACHE_BYTES;
+       db->db      = pgdir->db_page + offset / sizeof(*pgdir->db_page);
+       db->dma     = pgdir->db_dma  + offset;
+
+       return 0;
+}
+
+int mlx5_db_alloc(struct mlx5_core_dev *dev, struct mlx5_db *db)
+{
+       struct mlx5_db_pgdir *pgdir;
+       int ret = 0;
+
+       mutex_lock(&dev->priv.pgdir_mutex);
+
+       list_for_each_entry(pgdir, &dev->priv.pgdir_list, list)
+               if (!mlx5_alloc_db_from_pgdir(pgdir, db))
+                       goto out;
+
+       pgdir = mlx5_alloc_db_pgdir(&(dev->pdev->dev));
+       if (!pgdir) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       list_add(&pgdir->list, &dev->priv.pgdir_list);
+
+       /* This should never fail -- we just allocated an empty page: */
+       WARN_ON(mlx5_alloc_db_from_pgdir(pgdir, db));
+
+out:
+       mutex_unlock(&dev->priv.pgdir_mutex);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(mlx5_db_alloc);
+
+void mlx5_db_free(struct mlx5_core_dev *dev, struct mlx5_db *db)
+{
+       mutex_lock(&dev->priv.pgdir_mutex);
+
+       __set_bit(db->index, db->u.pgdir->bitmap);
+
+       if (bitmap_full(db->u.pgdir->bitmap, MLX5_DB_PER_PAGE)) {
+               dma_free_coherent(&(dev->pdev->dev), PAGE_SIZE,
+                                 db->u.pgdir->db_page, db->u.pgdir->db_dma);
+               list_del(&db->u.pgdir->list);
+               kfree(db->u.pgdir);
+       }
+
+       mutex_unlock(&dev->priv.pgdir_mutex);
+}
+EXPORT_SYMBOL_GPL(mlx5_db_free);
+
+
+void mlx5_fill_page_array(struct mlx5_buf *buf, __be64 *pas)
+{
+       u64 addr;
+       int i;
+
+       for (i = 0; i < buf->npages; i++) {
+               if (buf->nbufs == 1)
+                       addr = buf->direct.map + (i << buf->page_shift);
+               else
+                       addr = buf->page_list[i].map;
+
+               pas[i] = cpu_to_be64(addr);
+       }
+}
+EXPORT_SYMBOL_GPL(mlx5_fill_page_array);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c
new file mode 100644 (file)
index 0000000..205753a
--- /dev/null
@@ -0,0 +1,1515 @@
+/*
+ * Copyright (c) 2013, Mellanox Technologies inc.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <asm-generic/kmap_types.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/random.h>
+#include <linux/io-mapping.h>
+#include <linux/mlx5/driver.h>
+#include <linux/debugfs.h>
+
+#include "mlx5_core.h"
+
+enum {
+       CMD_IF_REV = 3,
+};
+
+enum {
+       CMD_MODE_POLLING,
+       CMD_MODE_EVENTS
+};
+
+enum {
+       NUM_LONG_LISTS    = 2,
+       NUM_MED_LISTS     = 64,
+       LONG_LIST_SIZE    = (2ULL * 1024 * 1024 * 1024 / PAGE_SIZE) * 8 + 16 +
+                               MLX5_CMD_DATA_BLOCK_SIZE,
+       MED_LIST_SIZE     = 16 + MLX5_CMD_DATA_BLOCK_SIZE,
+};
+
+enum {
+       MLX5_CMD_DELIVERY_STAT_OK                       = 0x0,
+       MLX5_CMD_DELIVERY_STAT_SIGNAT_ERR               = 0x1,
+       MLX5_CMD_DELIVERY_STAT_TOK_ERR                  = 0x2,
+       MLX5_CMD_DELIVERY_STAT_BAD_BLK_NUM_ERR          = 0x3,
+       MLX5_CMD_DELIVERY_STAT_OUT_PTR_ALIGN_ERR        = 0x4,
+       MLX5_CMD_DELIVERY_STAT_IN_PTR_ALIGN_ERR         = 0x5,
+       MLX5_CMD_DELIVERY_STAT_FW_ERR                   = 0x6,
+       MLX5_CMD_DELIVERY_STAT_IN_LENGTH_ERR            = 0x7,
+       MLX5_CMD_DELIVERY_STAT_OUT_LENGTH_ERR           = 0x8,
+       MLX5_CMD_DELIVERY_STAT_RES_FLD_NOT_CLR_ERR      = 0x9,
+       MLX5_CMD_DELIVERY_STAT_CMD_DESCR_ERR            = 0x10,
+};
+
+enum {
+       MLX5_CMD_STAT_OK                        = 0x0,
+       MLX5_CMD_STAT_INT_ERR                   = 0x1,
+       MLX5_CMD_STAT_BAD_OP_ERR                = 0x2,
+       MLX5_CMD_STAT_BAD_PARAM_ERR             = 0x3,
+       MLX5_CMD_STAT_BAD_SYS_STATE_ERR         = 0x4,
+       MLX5_CMD_STAT_BAD_RES_ERR               = 0x5,
+       MLX5_CMD_STAT_RES_BUSY                  = 0x6,
+       MLX5_CMD_STAT_LIM_ERR                   = 0x8,
+       MLX5_CMD_STAT_BAD_RES_STATE_ERR         = 0x9,
+       MLX5_CMD_STAT_IX_ERR                    = 0xa,
+       MLX5_CMD_STAT_NO_RES_ERR                = 0xf,
+       MLX5_CMD_STAT_BAD_INP_LEN_ERR           = 0x50,
+       MLX5_CMD_STAT_BAD_OUTP_LEN_ERR          = 0x51,
+       MLX5_CMD_STAT_BAD_QP_STATE_ERR          = 0x10,
+       MLX5_CMD_STAT_BAD_PKT_ERR               = 0x30,
+       MLX5_CMD_STAT_BAD_SIZE_OUTS_CQES_ERR    = 0x40,
+};
+
+static struct mlx5_cmd_work_ent *alloc_cmd(struct mlx5_cmd *cmd,
+                                          struct mlx5_cmd_msg *in,
+                                          struct mlx5_cmd_msg *out,
+                                          mlx5_cmd_cbk_t cbk,
+                                          void *context, int page_queue)
+{
+       gfp_t alloc_flags = cbk ? GFP_ATOMIC : GFP_KERNEL;
+       struct mlx5_cmd_work_ent *ent;
+
+       ent = kzalloc(sizeof(*ent), alloc_flags);
+       if (!ent)
+               return ERR_PTR(-ENOMEM);
+
+       ent->in         = in;
+       ent->out        = out;
+       ent->callback   = cbk;
+       ent->context    = context;
+       ent->cmd        = cmd;
+       ent->page_queue = page_queue;
+
+       return ent;
+}
+
+static u8 alloc_token(struct mlx5_cmd *cmd)
+{
+       u8 token;
+
+       spin_lock(&cmd->token_lock);
+       token = cmd->token++ % 255 + 1;
+       spin_unlock(&cmd->token_lock);
+
+       return token;
+}
+
+static int alloc_ent(struct mlx5_cmd *cmd)
+{
+       unsigned long flags;
+       int ret;
+
+       spin_lock_irqsave(&cmd->alloc_lock, flags);
+       ret = find_first_bit(&cmd->bitmask, cmd->max_reg_cmds);
+       if (ret < cmd->max_reg_cmds)
+               clear_bit(ret, &cmd->bitmask);
+       spin_unlock_irqrestore(&cmd->alloc_lock, flags);
+
+       return ret < cmd->max_reg_cmds ? ret : -ENOMEM;
+}
+
+static void free_ent(struct mlx5_cmd *cmd, int idx)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&cmd->alloc_lock, flags);
+       set_bit(idx, &cmd->bitmask);
+       spin_unlock_irqrestore(&cmd->alloc_lock, flags);
+}
+
+static struct mlx5_cmd_layout *get_inst(struct mlx5_cmd *cmd, int idx)
+{
+       return cmd->cmd_buf + (idx << cmd->log_stride);
+}
+
+static u8 xor8_buf(void *buf, int len)
+{
+       u8 *ptr = buf;
+       u8 sum = 0;
+       int i;
+
+       for (i = 0; i < len; i++)
+               sum ^= ptr[i];
+
+       return sum;
+}
+
+static int verify_block_sig(struct mlx5_cmd_prot_block *block)
+{
+       if (xor8_buf(block->rsvd0, sizeof(*block) - sizeof(block->data) - 1) != 0xff)
+               return -EINVAL;
+
+       if (xor8_buf(block, sizeof(*block)) != 0xff)
+               return -EINVAL;
+
+       return 0;
+}
+
+static void calc_block_sig(struct mlx5_cmd_prot_block *block, u8 token)
+{
+       block->token = token;
+       block->ctrl_sig = ~xor8_buf(block->rsvd0, sizeof(*block) - sizeof(block->data) - 2);
+       block->sig = ~xor8_buf(block, sizeof(*block) - 1);
+}
+
+static void calc_chain_sig(struct mlx5_cmd_msg *msg, u8 token)
+{
+       struct mlx5_cmd_mailbox *next = msg->next;
+
+       while (next) {
+               calc_block_sig(next->buf, token);
+               next = next->next;
+       }
+}
+
+static void set_signature(struct mlx5_cmd_work_ent *ent)
+{
+       ent->lay->sig = ~xor8_buf(ent->lay, sizeof(*ent->lay));
+       calc_chain_sig(ent->in, ent->token);
+       calc_chain_sig(ent->out, ent->token);
+}
+
+static void poll_timeout(struct mlx5_cmd_work_ent *ent)
+{
+       unsigned long poll_end = jiffies + msecs_to_jiffies(MLX5_CMD_TIMEOUT_MSEC + 1000);
+       u8 own;
+
+       do {
+               own = ent->lay->status_own;
+               if (!(own & CMD_OWNER_HW)) {
+                       ent->ret = 0;
+                       return;
+               }
+               usleep_range(5000, 10000);
+       } while (time_before(jiffies, poll_end));
+
+       ent->ret = -ETIMEDOUT;
+}
+
+static void free_cmd(struct mlx5_cmd_work_ent *ent)
+{
+       kfree(ent);
+}
+
+
+static int verify_signature(struct mlx5_cmd_work_ent *ent)
+{
+       struct mlx5_cmd_mailbox *next = ent->out->next;
+       int err;
+       u8 sig;
+
+       sig = xor8_buf(ent->lay, sizeof(*ent->lay));
+       if (sig != 0xff)
+               return -EINVAL;
+
+       while (next) {
+               err = verify_block_sig(next->buf);
+               if (err)
+                       return err;
+
+               next = next->next;
+       }
+
+       return 0;
+}
+
+static void dump_buf(void *buf, int size, int data_only, int offset)
+{
+       __be32 *p = buf;
+       int i;
+
+       for (i = 0; i < size; i += 16) {
+               pr_debug("%03x: %08x %08x %08x %08x\n", offset, be32_to_cpu(p[0]),
+                        be32_to_cpu(p[1]), be32_to_cpu(p[2]),
+                        be32_to_cpu(p[3]));
+               p += 4;
+               offset += 16;
+       }
+       if (!data_only)
+               pr_debug("\n");
+}
+
+const char *mlx5_command_str(int command)
+{
+       switch (command) {
+       case MLX5_CMD_OP_QUERY_HCA_CAP:
+               return "QUERY_HCA_CAP";
+
+       case MLX5_CMD_OP_SET_HCA_CAP:
+               return "SET_HCA_CAP";
+
+       case MLX5_CMD_OP_QUERY_ADAPTER:
+               return "QUERY_ADAPTER";
+
+       case MLX5_CMD_OP_INIT_HCA:
+               return "INIT_HCA";
+
+       case MLX5_CMD_OP_TEARDOWN_HCA:
+               return "TEARDOWN_HCA";
+
+       case MLX5_CMD_OP_QUERY_PAGES:
+               return "QUERY_PAGES";
+
+       case MLX5_CMD_OP_MANAGE_PAGES:
+               return "MANAGE_PAGES";
+
+       case MLX5_CMD_OP_CREATE_MKEY:
+               return "CREATE_MKEY";
+
+       case MLX5_CMD_OP_QUERY_MKEY:
+               return "QUERY_MKEY";
+
+       case MLX5_CMD_OP_DESTROY_MKEY:
+               return "DESTROY_MKEY";
+
+       case MLX5_CMD_OP_QUERY_SPECIAL_CONTEXTS:
+               return "QUERY_SPECIAL_CONTEXTS";
+
+       case MLX5_CMD_OP_CREATE_EQ:
+               return "CREATE_EQ";
+
+       case MLX5_CMD_OP_DESTROY_EQ:
+               return "DESTROY_EQ";
+
+       case MLX5_CMD_OP_QUERY_EQ:
+               return "QUERY_EQ";
+
+       case MLX5_CMD_OP_CREATE_CQ:
+               return "CREATE_CQ";
+
+       case MLX5_CMD_OP_DESTROY_CQ:
+               return "DESTROY_CQ";
+
+       case MLX5_CMD_OP_QUERY_CQ:
+               return "QUERY_CQ";
+
+       case MLX5_CMD_OP_MODIFY_CQ:
+               return "MODIFY_CQ";
+
+       case MLX5_CMD_OP_CREATE_QP:
+               return "CREATE_QP";
+
+       case MLX5_CMD_OP_DESTROY_QP:
+               return "DESTROY_QP";
+
+       case MLX5_CMD_OP_RST2INIT_QP:
+               return "RST2INIT_QP";
+
+       case MLX5_CMD_OP_INIT2RTR_QP:
+               return "INIT2RTR_QP";
+
+       case MLX5_CMD_OP_RTR2RTS_QP:
+               return "RTR2RTS_QP";
+
+       case MLX5_CMD_OP_RTS2RTS_QP:
+               return "RTS2RTS_QP";
+
+       case MLX5_CMD_OP_SQERR2RTS_QP:
+               return "SQERR2RTS_QP";
+
+       case MLX5_CMD_OP_2ERR_QP:
+               return "2ERR_QP";
+
+       case MLX5_CMD_OP_RTS2SQD_QP:
+               return "RTS2SQD_QP";
+
+       case MLX5_CMD_OP_SQD2RTS_QP:
+               return "SQD2RTS_QP";
+
+       case MLX5_CMD_OP_2RST_QP:
+               return "2RST_QP";
+
+       case MLX5_CMD_OP_QUERY_QP:
+               return "QUERY_QP";
+
+       case MLX5_CMD_OP_CONF_SQP:
+               return "CONF_SQP";
+
+       case MLX5_CMD_OP_MAD_IFC:
+               return "MAD_IFC";
+
+       case MLX5_CMD_OP_INIT2INIT_QP:
+               return "INIT2INIT_QP";
+
+       case MLX5_CMD_OP_SUSPEND_QP:
+               return "SUSPEND_QP";
+
+       case MLX5_CMD_OP_UNSUSPEND_QP:
+               return "UNSUSPEND_QP";
+
+       case MLX5_CMD_OP_SQD2SQD_QP:
+               return "SQD2SQD_QP";
+
+       case MLX5_CMD_OP_ALLOC_QP_COUNTER_SET:
+               return "ALLOC_QP_COUNTER_SET";
+
+       case MLX5_CMD_OP_DEALLOC_QP_COUNTER_SET:
+               return "DEALLOC_QP_COUNTER_SET";
+
+       case MLX5_CMD_OP_QUERY_QP_COUNTER_SET:
+               return "QUERY_QP_COUNTER_SET";
+
+       case MLX5_CMD_OP_CREATE_PSV:
+               return "CREATE_PSV";
+
+       case MLX5_CMD_OP_DESTROY_PSV:
+               return "DESTROY_PSV";
+
+       case MLX5_CMD_OP_QUERY_PSV:
+               return "QUERY_PSV";
+
+       case MLX5_CMD_OP_QUERY_SIG_RULE_TABLE:
+               return "QUERY_SIG_RULE_TABLE";
+
+       case MLX5_CMD_OP_QUERY_BLOCK_SIZE_TABLE:
+               return "QUERY_BLOCK_SIZE_TABLE";
+
+       case MLX5_CMD_OP_CREATE_SRQ:
+               return "CREATE_SRQ";
+
+       case MLX5_CMD_OP_DESTROY_SRQ:
+               return "DESTROY_SRQ";
+
+       case MLX5_CMD_OP_QUERY_SRQ:
+               return "QUERY_SRQ";
+
+       case MLX5_CMD_OP_ARM_RQ:
+               return "ARM_RQ";
+
+       case MLX5_CMD_OP_RESIZE_SRQ:
+               return "RESIZE_SRQ";
+
+       case MLX5_CMD_OP_ALLOC_PD:
+               return "ALLOC_PD";
+
+       case MLX5_CMD_OP_DEALLOC_PD:
+               return "DEALLOC_PD";
+
+       case MLX5_CMD_OP_ALLOC_UAR:
+               return "ALLOC_UAR";
+
+       case MLX5_CMD_OP_DEALLOC_UAR:
+               return "DEALLOC_UAR";
+
+       case MLX5_CMD_OP_ATTACH_TO_MCG:
+               return "ATTACH_TO_MCG";
+
+       case MLX5_CMD_OP_DETACH_FROM_MCG:
+               return "DETACH_FROM_MCG";
+
+       case MLX5_CMD_OP_ALLOC_XRCD:
+               return "ALLOC_XRCD";
+
+       case MLX5_CMD_OP_DEALLOC_XRCD:
+               return "DEALLOC_XRCD";
+
+       case MLX5_CMD_OP_ACCESS_REG:
+               return "MLX5_CMD_OP_ACCESS_REG";
+
+       default: return "unknown command opcode";
+       }
+}
+
+static void dump_command(struct mlx5_core_dev *dev,
+                        struct mlx5_cmd_work_ent *ent, int input)
+{
+       u16 op = be16_to_cpu(((struct mlx5_inbox_hdr *)(ent->lay->in))->opcode);
+       struct mlx5_cmd_msg *msg = input ? ent->in : ent->out;
+       struct mlx5_cmd_mailbox *next = msg->next;
+       int data_only;
+       int offset = 0;
+       int dump_len;
+
+       data_only = !!(mlx5_core_debug_mask & (1 << MLX5_CMD_DATA));
+
+       if (data_only)
+               mlx5_core_dbg_mask(dev, 1 << MLX5_CMD_DATA,
+                                  "dump command data %s(0x%x) %s\n",
+                                  mlx5_command_str(op), op,
+                                  input ? "INPUT" : "OUTPUT");
+       else
+               mlx5_core_dbg(dev, "dump command %s(0x%x) %s\n",
+                             mlx5_command_str(op), op,
+                             input ? "INPUT" : "OUTPUT");
+
+       if (data_only) {
+               if (input) {
+                       dump_buf(ent->lay->in, sizeof(ent->lay->in), 1, offset);
+                       offset += sizeof(ent->lay->in);
+               } else {
+                       dump_buf(ent->lay->out, sizeof(ent->lay->out), 1, offset);
+                       offset += sizeof(ent->lay->out);
+               }
+       } else {
+               dump_buf(ent->lay, sizeof(*ent->lay), 0, offset);
+               offset += sizeof(*ent->lay);
+       }
+
+       while (next && offset < msg->len) {
+               if (data_only) {
+                       dump_len = min_t(int, MLX5_CMD_DATA_BLOCK_SIZE, msg->len - offset);
+                       dump_buf(next->buf, dump_len, 1, offset);
+                       offset += MLX5_CMD_DATA_BLOCK_SIZE;
+               } else {
+                       mlx5_core_dbg(dev, "command block:\n");
+                       dump_buf(next->buf, sizeof(struct mlx5_cmd_prot_block), 0, offset);
+                       offset += sizeof(struct mlx5_cmd_prot_block);
+               }
+               next = next->next;
+       }
+
+       if (data_only)
+               pr_debug("\n");
+}
+
+static void cmd_work_handler(struct work_struct *work)
+{
+       struct mlx5_cmd_work_ent *ent = container_of(work, struct mlx5_cmd_work_ent, work);
+       struct mlx5_cmd *cmd = ent->cmd;
+       struct mlx5_core_dev *dev = container_of(cmd, struct mlx5_core_dev, cmd);
+       struct mlx5_cmd_layout *lay;
+       struct semaphore *sem;
+
+       sem = ent->page_queue ? &cmd->pages_sem : &cmd->sem;
+       down(sem);
+       if (!ent->page_queue) {
+               ent->idx = alloc_ent(cmd);
+               if (ent->idx < 0) {
+                       mlx5_core_err(dev, "failed to allocate command entry\n");
+                       up(sem);
+                       return;
+               }
+       } else {
+               ent->idx = cmd->max_reg_cmds;
+       }
+
+       ent->token = alloc_token(cmd);
+       cmd->ent_arr[ent->idx] = ent;
+       lay = get_inst(cmd, ent->idx);
+       ent->lay = lay;
+       memset(lay, 0, sizeof(*lay));
+       memcpy(lay->in, ent->in->first.data, sizeof(lay->in));
+       if (ent->in->next)
+               lay->in_ptr = cpu_to_be64(ent->in->next->dma);
+       lay->inlen = cpu_to_be32(ent->in->len);
+       if (ent->out->next)
+               lay->out_ptr = cpu_to_be64(ent->out->next->dma);
+       lay->outlen = cpu_to_be32(ent->out->len);
+       lay->type = MLX5_PCI_CMD_XPORT;
+       lay->token = ent->token;
+       lay->status_own = CMD_OWNER_HW;
+       if (!cmd->checksum_disabled)
+               set_signature(ent);
+       dump_command(dev, ent, 1);
+       ktime_get_ts(&ent->ts1);
+
+       /* ring doorbell after the descriptor is valid */
+       wmb();
+       iowrite32be(1 << ent->idx, &dev->iseg->cmd_dbell);
+       mlx5_core_dbg(dev, "write 0x%x to command doorbell\n", 1 << ent->idx);
+       mmiowb();
+       if (cmd->mode == CMD_MODE_POLLING) {
+               poll_timeout(ent);
+               /* make sure we read the descriptor after ownership is SW */
+               rmb();
+               mlx5_cmd_comp_handler(dev, 1UL << ent->idx);
+       }
+}
+
+static const char *deliv_status_to_str(u8 status)
+{
+       switch (status) {
+       case MLX5_CMD_DELIVERY_STAT_OK:
+               return "no errors";
+       case MLX5_CMD_DELIVERY_STAT_SIGNAT_ERR:
+               return "signature error";
+       case MLX5_CMD_DELIVERY_STAT_TOK_ERR:
+               return "token error";
+       case MLX5_CMD_DELIVERY_STAT_BAD_BLK_NUM_ERR:
+               return "bad block number";
+       case MLX5_CMD_DELIVERY_STAT_OUT_PTR_ALIGN_ERR:
+               return "output pointer not aligned to block size";
+       case MLX5_CMD_DELIVERY_STAT_IN_PTR_ALIGN_ERR:
+               return "input pointer not aligned to block size";
+       case MLX5_CMD_DELIVERY_STAT_FW_ERR:
+               return "firmware internal error";
+       case MLX5_CMD_DELIVERY_STAT_IN_LENGTH_ERR:
+               return "command input length error";
+       case MLX5_CMD_DELIVERY_STAT_OUT_LENGTH_ERR:
+               return "command ouput length error";
+       case MLX5_CMD_DELIVERY_STAT_RES_FLD_NOT_CLR_ERR:
+               return "reserved fields not cleared";
+       case MLX5_CMD_DELIVERY_STAT_CMD_DESCR_ERR:
+               return "bad command descriptor type";
+       default:
+               return "unknown status code";
+       }
+}
+
+static u16 msg_to_opcode(struct mlx5_cmd_msg *in)
+{
+       struct mlx5_inbox_hdr *hdr = (struct mlx5_inbox_hdr *)(in->first.data);
+
+       return be16_to_cpu(hdr->opcode);
+}
+
+static int wait_func(struct mlx5_core_dev *dev, struct mlx5_cmd_work_ent *ent)
+{
+       unsigned long timeout = msecs_to_jiffies(MLX5_CMD_TIMEOUT_MSEC);
+       struct mlx5_cmd *cmd = &dev->cmd;
+       int err;
+
+       if (cmd->mode == CMD_MODE_POLLING) {
+               wait_for_completion(&ent->done);
+               err = ent->ret;
+       } else {
+               if (!wait_for_completion_timeout(&ent->done, timeout))
+                       err = -ETIMEDOUT;
+               else
+                       err = 0;
+       }
+       if (err == -ETIMEDOUT) {
+               mlx5_core_warn(dev, "%s(0x%x) timeout. Will cause a leak of a command resource\n",
+                              mlx5_command_str(msg_to_opcode(ent->in)),
+                              msg_to_opcode(ent->in));
+       }
+       mlx5_core_dbg(dev, "err %d, delivery status %s(%d)\n", err,
+                     deliv_status_to_str(ent->status), ent->status);
+
+       return err;
+}
+
+/*  Notes:
+ *    1. Callback functions may not sleep
+ *    2. page queue commands do not support asynchrous completion
+ */
+static int mlx5_cmd_invoke(struct mlx5_core_dev *dev, struct mlx5_cmd_msg *in,
+                          struct mlx5_cmd_msg *out, mlx5_cmd_cbk_t callback,
+                          void *context, int page_queue, u8 *status)
+{
+       struct mlx5_cmd *cmd = &dev->cmd;
+       struct mlx5_cmd_work_ent *ent;
+       ktime_t t1, t2, delta;
+       struct mlx5_cmd_stats *stats;
+       int err = 0;
+       s64 ds;
+       u16 op;
+
+       if (callback && page_queue)
+               return -EINVAL;
+
+       ent = alloc_cmd(cmd, in, out, callback, context, page_queue);
+       if (IS_ERR(ent))
+               return PTR_ERR(ent);
+
+       if (!callback)
+               init_completion(&ent->done);
+
+       INIT_WORK(&ent->work, cmd_work_handler);
+       if (page_queue) {
+               cmd_work_handler(&ent->work);
+       } else if (!queue_work(cmd->wq, &ent->work)) {
+               mlx5_core_warn(dev, "failed to queue work\n");
+               err = -ENOMEM;
+               goto out_free;
+       }
+
+       if (!callback) {
+               err = wait_func(dev, ent);
+               if (err == -ETIMEDOUT)
+                       goto out;
+
+               t1 = timespec_to_ktime(ent->ts1);
+               t2 = timespec_to_ktime(ent->ts2);
+               delta = ktime_sub(t2, t1);
+               ds = ktime_to_ns(delta);
+               op = be16_to_cpu(((struct mlx5_inbox_hdr *)in->first.data)->opcode);
+               if (op < ARRAY_SIZE(cmd->stats)) {
+                       stats = &cmd->stats[op];
+                       spin_lock(&stats->lock);
+                       stats->sum += ds;
+                       ++stats->n;
+                       spin_unlock(&stats->lock);
+               }
+               mlx5_core_dbg_mask(dev, 1 << MLX5_CMD_TIME,
+                                  "fw exec time for %s is %lld nsec\n",
+                                  mlx5_command_str(op), ds);
+               *status = ent->status;
+               free_cmd(ent);
+       }
+
+       return err;
+
+out_free:
+       free_cmd(ent);
+out:
+       return err;
+}
+
+static ssize_t dbg_write(struct file *filp, const char __user *buf,
+                        size_t count, loff_t *pos)
+{
+       struct mlx5_core_dev *dev = filp->private_data;
+       struct mlx5_cmd_debug *dbg = &dev->cmd.dbg;
+       char lbuf[3];
+       int err;
+
+       if (!dbg->in_msg || !dbg->out_msg)
+               return -ENOMEM;
+
+       if (copy_from_user(lbuf, buf, sizeof(lbuf)))
+               return -EFAULT;
+
+       lbuf[sizeof(lbuf) - 1] = 0;
+
+       if (strcmp(lbuf, "go"))
+               return -EINVAL;
+
+       err = mlx5_cmd_exec(dev, dbg->in_msg, dbg->inlen, dbg->out_msg, dbg->outlen);
+
+       return err ? err : count;
+}
+
+
+static const struct file_operations fops = {
+       .owner  = THIS_MODULE,
+       .open   = simple_open,
+       .write  = dbg_write,
+};
+
+static int mlx5_copy_to_msg(struct mlx5_cmd_msg *to, void *from, int size)
+{
+       struct mlx5_cmd_prot_block *block;
+       struct mlx5_cmd_mailbox *next;
+       int copy;
+
+       if (!to || !from)
+               return -ENOMEM;
+
+       copy = min_t(int, size, sizeof(to->first.data));
+       memcpy(to->first.data, from, copy);
+       size -= copy;
+       from += copy;
+
+       next = to->next;
+       while (size) {
+               if (!next) {
+                       /* this is a BUG */
+                       return -ENOMEM;
+               }
+
+               copy = min_t(int, size, MLX5_CMD_DATA_BLOCK_SIZE);
+               block = next->buf;
+               memcpy(block->data, from, copy);
+               from += copy;
+               size -= copy;
+               next = next->next;
+       }
+
+       return 0;
+}
+
+static int mlx5_copy_from_msg(void *to, struct mlx5_cmd_msg *from, int size)
+{
+       struct mlx5_cmd_prot_block *block;
+       struct mlx5_cmd_mailbox *next;
+       int copy;
+
+       if (!to || !from)
+               return -ENOMEM;
+
+       copy = min_t(int, size, sizeof(from->first.data));
+       memcpy(to, from->first.data, copy);
+       size -= copy;
+       to += copy;
+
+       next = from->next;
+       while (size) {
+               if (!next) {
+                       /* this is a BUG */
+                       return -ENOMEM;
+               }
+
+               copy = min_t(int, size, MLX5_CMD_DATA_BLOCK_SIZE);
+               block = next->buf;
+               if (xor8_buf(block, sizeof(*block)) != 0xff)
+                       return -EINVAL;
+
+               memcpy(to, block->data, copy);
+               to += copy;
+               size -= copy;
+               next = next->next;
+       }
+
+       return 0;
+}
+
+static struct mlx5_cmd_mailbox *alloc_cmd_box(struct mlx5_core_dev *dev,
+                                             gfp_t flags)
+{
+       struct mlx5_cmd_mailbox *mailbox;
+
+       mailbox = kmalloc(sizeof(*mailbox), flags);
+       if (!mailbox)
+               return ERR_PTR(-ENOMEM);
+
+       mailbox->buf = pci_pool_alloc(dev->cmd.pool, flags,
+                                     &mailbox->dma);
+       if (!mailbox->buf) {
+               mlx5_core_dbg(dev, "failed allocation\n");
+               kfree(mailbox);
+               return ERR_PTR(-ENOMEM);
+       }
+       memset(mailbox->buf, 0, sizeof(struct mlx5_cmd_prot_block));
+       mailbox->next = NULL;
+
+       return mailbox;
+}
+
+static void free_cmd_box(struct mlx5_core_dev *dev,
+                        struct mlx5_cmd_mailbox *mailbox)
+{
+       pci_pool_free(dev->cmd.pool, mailbox->buf, mailbox->dma);
+       kfree(mailbox);
+}
+
+static struct mlx5_cmd_msg *mlx5_alloc_cmd_msg(struct mlx5_core_dev *dev,
+                                              gfp_t flags, int size)
+{
+       struct mlx5_cmd_mailbox *tmp, *head = NULL;
+       struct mlx5_cmd_prot_block *block;
+       struct mlx5_cmd_msg *msg;
+       int blen;
+       int err;
+       int n;
+       int i;
+
+       msg = kzalloc(sizeof(*msg), GFP_KERNEL);
+       if (!msg)
+               return ERR_PTR(-ENOMEM);
+
+       blen = size - min_t(int, sizeof(msg->first.data), size);
+       n = (blen + MLX5_CMD_DATA_BLOCK_SIZE - 1) / MLX5_CMD_DATA_BLOCK_SIZE;
+
+       for (i = 0; i < n; i++) {
+               tmp = alloc_cmd_box(dev, flags);
+               if (IS_ERR(tmp)) {
+                       mlx5_core_warn(dev, "failed allocating block\n");
+                       err = PTR_ERR(tmp);
+                       goto err_alloc;
+               }
+
+               block = tmp->buf;
+               tmp->next = head;
+               block->next = cpu_to_be64(tmp->next ? tmp->next->dma : 0);
+               block->block_num = cpu_to_be32(n - i - 1);
+               head = tmp;
+       }
+       msg->next = head;
+       msg->len = size;
+       return msg;
+
+err_alloc:
+       while (head) {
+               tmp = head->next;
+               free_cmd_box(dev, head);
+               head = tmp;
+       }
+       kfree(msg);
+
+       return ERR_PTR(err);
+}
+
+static void mlx5_free_cmd_msg(struct mlx5_core_dev *dev,
+                                 struct mlx5_cmd_msg *msg)
+{
+       struct mlx5_cmd_mailbox *head = msg->next;
+       struct mlx5_cmd_mailbox *next;
+
+       while (head) {
+               next = head->next;
+               free_cmd_box(dev, head);
+               head = next;
+       }
+       kfree(msg);
+}
+
+static ssize_t data_write(struct file *filp, const char __user *buf,
+                         size_t count, loff_t *pos)
+{
+       struct mlx5_core_dev *dev = filp->private_data;
+       struct mlx5_cmd_debug *dbg = &dev->cmd.dbg;
+       void *ptr;
+       int err;
+
+       if (*pos != 0)
+               return -EINVAL;
+
+       kfree(dbg->in_msg);
+       dbg->in_msg = NULL;
+       dbg->inlen = 0;
+
+       ptr = kzalloc(count, GFP_KERNEL);
+       if (!ptr)
+               return -ENOMEM;
+
+       if (copy_from_user(ptr, buf, count)) {
+               err = -EFAULT;
+               goto out;
+       }
+       dbg->in_msg = ptr;
+       dbg->inlen = count;
+
+       *pos = count;
+
+       return count;
+
+out:
+       kfree(ptr);
+       return err;
+}
+
+static ssize_t data_read(struct file *filp, char __user *buf, size_t count,
+                        loff_t *pos)
+{
+       struct mlx5_core_dev *dev = filp->private_data;
+       struct mlx5_cmd_debug *dbg = &dev->cmd.dbg;
+       int copy;
+
+       if (*pos)
+               return 0;
+
+       if (!dbg->out_msg)
+               return -ENOMEM;
+
+       copy = min_t(int, count, dbg->outlen);
+       if (copy_to_user(buf, dbg->out_msg, copy))
+               return -EFAULT;
+
+       *pos += copy;
+
+       return copy;
+}
+
+static const struct file_operations dfops = {
+       .owner  = THIS_MODULE,
+       .open   = simple_open,
+       .write  = data_write,
+       .read   = data_read,
+};
+
+static ssize_t outlen_read(struct file *filp, char __user *buf, size_t count,
+                          loff_t *pos)
+{
+       struct mlx5_core_dev *dev = filp->private_data;
+       struct mlx5_cmd_debug *dbg = &dev->cmd.dbg;
+       char outlen[8];
+       int err;
+
+       if (*pos)
+               return 0;
+
+       err = snprintf(outlen, sizeof(outlen), "%d", dbg->outlen);
+       if (err < 0)
+               return err;
+
+       if (copy_to_user(buf, &outlen, err))
+               return -EFAULT;
+
+       *pos += err;
+
+       return err;
+}
+
+static ssize_t outlen_write(struct file *filp, const char __user *buf,
+                           size_t count, loff_t *pos)
+{
+       struct mlx5_core_dev *dev = filp->private_data;
+       struct mlx5_cmd_debug *dbg = &dev->cmd.dbg;
+       char outlen_str[8];
+       int outlen;
+       void *ptr;
+       int err;
+
+       if (*pos != 0 || count > 6)
+               return -EINVAL;
+
+       kfree(dbg->out_msg);
+       dbg->out_msg = NULL;
+       dbg->outlen = 0;
+
+       if (copy_from_user(outlen_str, buf, count))
+               return -EFAULT;
+
+       outlen_str[7] = 0;
+
+       err = sscanf(outlen_str, "%d", &outlen);
+       if (err < 0)
+               return err;
+
+       ptr = kzalloc(outlen, GFP_KERNEL);
+       if (!ptr)
+               return -ENOMEM;
+
+       dbg->out_msg = ptr;
+       dbg->outlen = outlen;
+
+       *pos = count;
+
+       return count;
+}
+
+static const struct file_operations olfops = {
+       .owner  = THIS_MODULE,
+       .open   = simple_open,
+       .write  = outlen_write,
+       .read   = outlen_read,
+};
+
+static void set_wqname(struct mlx5_core_dev *dev)
+{
+       struct mlx5_cmd *cmd = &dev->cmd;
+
+       snprintf(cmd->wq_name, sizeof(cmd->wq_name), "mlx5_cmd_%s",
+                dev_name(&dev->pdev->dev));
+}
+
+static void clean_debug_files(struct mlx5_core_dev *dev)
+{
+       struct mlx5_cmd_debug *dbg = &dev->cmd.dbg;
+
+       if (!mlx5_debugfs_root)
+               return;
+
+       mlx5_cmdif_debugfs_cleanup(dev);
+       debugfs_remove_recursive(dbg->dbg_root);
+}
+
+static int create_debugfs_files(struct mlx5_core_dev *dev)
+{
+       struct mlx5_cmd_debug *dbg = &dev->cmd.dbg;
+       int err = -ENOMEM;
+
+       if (!mlx5_debugfs_root)
+               return 0;
+
+       dbg->dbg_root = debugfs_create_dir("cmd", dev->priv.dbg_root);
+       if (!dbg->dbg_root)
+               return err;
+
+       dbg->dbg_in = debugfs_create_file("in", 0400, dbg->dbg_root,
+                                         dev, &dfops);
+       if (!dbg->dbg_in)
+               goto err_dbg;
+
+       dbg->dbg_out = debugfs_create_file("out", 0200, dbg->dbg_root,
+                                          dev, &dfops);
+       if (!dbg->dbg_out)
+               goto err_dbg;
+
+       dbg->dbg_outlen = debugfs_create_file("out_len", 0600, dbg->dbg_root,
+                                             dev, &olfops);
+       if (!dbg->dbg_outlen)
+               goto err_dbg;
+
+       dbg->dbg_status = debugfs_create_u8("status", 0600, dbg->dbg_root,
+                                           &dbg->status);
+       if (!dbg->dbg_status)
+               goto err_dbg;
+
+       dbg->dbg_run = debugfs_create_file("run", 0200, dbg->dbg_root, dev, &fops);
+       if (!dbg->dbg_run)
+               goto err_dbg;
+
+       mlx5_cmdif_debugfs_init(dev);
+
+       return 0;
+
+err_dbg:
+       clean_debug_files(dev);
+       return err;
+}
+
+void mlx5_cmd_use_events(struct mlx5_core_dev *dev)
+{
+       struct mlx5_cmd *cmd = &dev->cmd;
+       int i;
+
+       for (i = 0; i < cmd->max_reg_cmds; i++)
+               down(&cmd->sem);
+
+       down(&cmd->pages_sem);
+
+       flush_workqueue(cmd->wq);
+
+       cmd->mode = CMD_MODE_EVENTS;
+
+       up(&cmd->pages_sem);
+       for (i = 0; i < cmd->max_reg_cmds; i++)
+               up(&cmd->sem);
+}
+
+void mlx5_cmd_use_polling(struct mlx5_core_dev *dev)
+{
+       struct mlx5_cmd *cmd = &dev->cmd;
+       int i;
+
+       for (i = 0; i < cmd->max_reg_cmds; i++)
+               down(&cmd->sem);
+
+       down(&cmd->pages_sem);
+
+       flush_workqueue(cmd->wq);
+       cmd->mode = CMD_MODE_POLLING;
+
+       up(&cmd->pages_sem);
+       for (i = 0; i < cmd->max_reg_cmds; i++)
+               up(&cmd->sem);
+}
+
+void mlx5_cmd_comp_handler(struct mlx5_core_dev *dev, unsigned long vector)
+{
+       struct mlx5_cmd *cmd = &dev->cmd;
+       struct mlx5_cmd_work_ent *ent;
+       mlx5_cmd_cbk_t callback;
+       void *context;
+       int err;
+       int i;
+
+       for (i = 0; i < (1 << cmd->log_sz); i++) {
+               if (test_bit(i, &vector)) {
+                       ent = cmd->ent_arr[i];
+                       ktime_get_ts(&ent->ts2);
+                       memcpy(ent->out->first.data, ent->lay->out, sizeof(ent->lay->out));
+                       dump_command(dev, ent, 0);
+                       if (!ent->ret) {
+                               if (!cmd->checksum_disabled)
+                                       ent->ret = verify_signature(ent);
+                               else
+                                       ent->ret = 0;
+                               ent->status = ent->lay->status_own >> 1;
+                               mlx5_core_dbg(dev, "command completed. ret 0x%x, delivery status %s(0x%x)\n",
+                                             ent->ret, deliv_status_to_str(ent->status), ent->status);
+                       }
+                       free_ent(cmd, ent->idx);
+                       if (ent->callback) {
+                               callback = ent->callback;
+                               context = ent->context;
+                               err = ent->ret;
+                               free_cmd(ent);
+                               callback(err, context);
+                       } else {
+                               complete(&ent->done);
+                       }
+                       if (ent->page_queue)
+                               up(&cmd->pages_sem);
+                       else
+                               up(&cmd->sem);
+               }
+       }
+}
+EXPORT_SYMBOL(mlx5_cmd_comp_handler);
+
+static int status_to_err(u8 status)
+{
+       return status ? -1 : 0; /* TBD more meaningful codes */
+}
+
+static struct mlx5_cmd_msg *alloc_msg(struct mlx5_core_dev *dev, int in_size)
+{
+       struct mlx5_cmd_msg *msg = ERR_PTR(-ENOMEM);
+       struct mlx5_cmd *cmd = &dev->cmd;
+       struct cache_ent *ent = NULL;
+
+       if (in_size > MED_LIST_SIZE && in_size <= LONG_LIST_SIZE)
+               ent = &cmd->cache.large;
+       else if (in_size > 16 && in_size <= MED_LIST_SIZE)
+               ent = &cmd->cache.med;
+
+       if (ent) {
+               spin_lock(&ent->lock);
+               if (!list_empty(&ent->head)) {
+                       msg = list_entry(ent->head.next, typeof(*msg), list);
+                       /* For cached lists, we must explicitly state what is
+                        * the real size
+                        */
+                       msg->len = in_size;
+                       list_del(&msg->list);
+               }
+               spin_unlock(&ent->lock);
+       }
+
+       if (IS_ERR(msg))
+               msg = mlx5_alloc_cmd_msg(dev, GFP_KERNEL, in_size);
+
+       return msg;
+}
+
+static void free_msg(struct mlx5_core_dev *dev, struct mlx5_cmd_msg *msg)
+{
+       if (msg->cache) {
+               spin_lock(&msg->cache->lock);
+               list_add_tail(&msg->list, &msg->cache->head);
+               spin_unlock(&msg->cache->lock);
+       } else {
+               mlx5_free_cmd_msg(dev, msg);
+       }
+}
+
+static int is_manage_pages(struct mlx5_inbox_hdr *in)
+{
+       return be16_to_cpu(in->opcode) == MLX5_CMD_OP_MANAGE_PAGES;
+}
+
+int mlx5_cmd_exec(struct mlx5_core_dev *dev, void *in, int in_size, void *out,
+                 int out_size)
+{
+       struct mlx5_cmd_msg *inb;
+       struct mlx5_cmd_msg *outb;
+       int pages_queue;
+       int err;
+       u8 status = 0;
+
+       pages_queue = is_manage_pages(in);
+
+       inb = alloc_msg(dev, in_size);
+       if (IS_ERR(inb)) {
+               err = PTR_ERR(inb);
+               return err;
+       }
+
+       err = mlx5_copy_to_msg(inb, in, in_size);
+       if (err) {
+               mlx5_core_warn(dev, "err %d\n", err);
+               goto out_in;
+       }
+
+       outb = mlx5_alloc_cmd_msg(dev, GFP_KERNEL, out_size);
+       if (IS_ERR(outb)) {
+               err = PTR_ERR(outb);
+               goto out_in;
+       }
+
+       err = mlx5_cmd_invoke(dev, inb, outb, NULL, NULL, pages_queue, &status);
+       if (err)
+               goto out_out;
+
+       mlx5_core_dbg(dev, "err %d, status %d\n", err, status);
+       if (status) {
+               err = status_to_err(status);
+               goto out_out;
+       }
+
+       err = mlx5_copy_from_msg(out, outb, out_size);
+
+out_out:
+       mlx5_free_cmd_msg(dev, outb);
+
+out_in:
+       free_msg(dev, inb);
+       return err;
+}
+EXPORT_SYMBOL(mlx5_cmd_exec);
+
+static void destroy_msg_cache(struct mlx5_core_dev *dev)
+{
+       struct mlx5_cmd *cmd = &dev->cmd;
+       struct mlx5_cmd_msg *msg;
+       struct mlx5_cmd_msg *n;
+
+       list_for_each_entry_safe(msg, n, &cmd->cache.large.head, list) {
+               list_del(&msg->list);
+               mlx5_free_cmd_msg(dev, msg);
+       }
+
+       list_for_each_entry_safe(msg, n, &cmd->cache.med.head, list) {
+               list_del(&msg->list);
+               mlx5_free_cmd_msg(dev, msg);
+       }
+}
+
+static int create_msg_cache(struct mlx5_core_dev *dev)
+{
+       struct mlx5_cmd *cmd = &dev->cmd;
+       struct mlx5_cmd_msg *msg;
+       int err;
+       int i;
+
+       spin_lock_init(&cmd->cache.large.lock);
+       INIT_LIST_HEAD(&cmd->cache.large.head);
+       spin_lock_init(&cmd->cache.med.lock);
+       INIT_LIST_HEAD(&cmd->cache.med.head);
+
+       for (i = 0; i < NUM_LONG_LISTS; i++) {
+               msg = mlx5_alloc_cmd_msg(dev, GFP_KERNEL, LONG_LIST_SIZE);
+               if (IS_ERR(msg)) {
+                       err = PTR_ERR(msg);
+                       goto ex_err;
+               }
+               msg->cache = &cmd->cache.large;
+               list_add_tail(&msg->list, &cmd->cache.large.head);
+       }
+
+       for (i = 0; i < NUM_MED_LISTS; i++) {
+               msg = mlx5_alloc_cmd_msg(dev, GFP_KERNEL, MED_LIST_SIZE);
+               if (IS_ERR(msg)) {
+                       err = PTR_ERR(msg);
+                       goto ex_err;
+               }
+               msg->cache = &cmd->cache.med;
+               list_add_tail(&msg->list, &cmd->cache.med.head);
+       }
+
+       return 0;
+
+ex_err:
+       destroy_msg_cache(dev);
+       return err;
+}
+
+int mlx5_cmd_init(struct mlx5_core_dev *dev)
+{
+       int size = sizeof(struct mlx5_cmd_prot_block);
+       int align = roundup_pow_of_two(size);
+       struct mlx5_cmd *cmd = &dev->cmd;
+       u32 cmd_h, cmd_l;
+       u16 cmd_if_rev;
+       int err;
+       int i;
+
+       cmd_if_rev = cmdif_rev(dev);
+       if (cmd_if_rev != CMD_IF_REV) {
+               dev_err(&dev->pdev->dev,
+                       "Driver cmdif rev(%d) differs from firmware's(%d)\n",
+                       CMD_IF_REV, cmd_if_rev);
+               return -EINVAL;
+       }
+
+       cmd->pool = pci_pool_create("mlx5_cmd", dev->pdev, size, align, 0);
+       if (!cmd->pool)
+               return -ENOMEM;
+
+       cmd->cmd_buf = (void *)__get_free_pages(GFP_ATOMIC, 0);
+       if (!cmd->cmd_buf) {
+               err = -ENOMEM;
+               goto err_free_pool;
+       }
+       cmd->dma = dma_map_single(&dev->pdev->dev, cmd->cmd_buf, PAGE_SIZE,
+                                 DMA_BIDIRECTIONAL);
+       if (dma_mapping_error(&dev->pdev->dev, cmd->dma)) {
+               err = -ENOMEM;
+               goto err_free;
+       }
+
+       cmd_l = ioread32be(&dev->iseg->cmdq_addr_l_sz) & 0xff;
+       cmd->log_sz = cmd_l >> 4 & 0xf;
+       cmd->log_stride = cmd_l & 0xf;
+       if (1 << cmd->log_sz > MLX5_MAX_COMMANDS) {
+               dev_err(&dev->pdev->dev, "firmware reports too many outstanding commands %d\n",
+                       1 << cmd->log_sz);
+               err = -EINVAL;
+               goto err_map;
+       }
+
+       if (cmd->log_sz + cmd->log_stride > PAGE_SHIFT) {
+               dev_err(&dev->pdev->dev, "command queue size overflow\n");
+               err = -EINVAL;
+               goto err_map;
+       }
+
+       cmd->max_reg_cmds = (1 << cmd->log_sz) - 1;
+       cmd->bitmask = (1 << cmd->max_reg_cmds) - 1;
+
+       cmd->cmdif_rev = ioread32be(&dev->iseg->cmdif_rev_fw_sub) >> 16;
+       if (cmd->cmdif_rev > CMD_IF_REV) {
+               dev_err(&dev->pdev->dev, "driver does not support command interface version. driver %d, firmware %d\n",
+                       CMD_IF_REV, cmd->cmdif_rev);
+               err = -ENOTSUPP;
+               goto err_map;
+       }
+
+       spin_lock_init(&cmd->alloc_lock);
+       spin_lock_init(&cmd->token_lock);
+       for (i = 0; i < ARRAY_SIZE(cmd->stats); i++)
+               spin_lock_init(&cmd->stats[i].lock);
+
+       sema_init(&cmd->sem, cmd->max_reg_cmds);
+       sema_init(&cmd->pages_sem, 1);
+
+       cmd_h = (u32)((u64)(cmd->dma) >> 32);
+       cmd_l = (u32)(cmd->dma);
+       if (cmd_l & 0xfff) {
+               dev_err(&dev->pdev->dev, "invalid command queue address\n");
+               err = -ENOMEM;
+               goto err_map;
+       }
+
+       iowrite32be(cmd_h, &dev->iseg->cmdq_addr_h);
+       iowrite32be(cmd_l, &dev->iseg->cmdq_addr_l_sz);
+
+       /* Make sure firmware sees the complete address before we proceed */
+       wmb();
+
+       mlx5_core_dbg(dev, "descriptor at dma 0x%llx\n", (unsigned long long)(cmd->dma));
+
+       cmd->mode = CMD_MODE_POLLING;
+
+       err = create_msg_cache(dev);
+       if (err) {
+               dev_err(&dev->pdev->dev, "failed to create command cache\n");
+               goto err_map;
+       }
+
+       set_wqname(dev);
+       cmd->wq = create_singlethread_workqueue(cmd->wq_name);
+       if (!cmd->wq) {
+               dev_err(&dev->pdev->dev, "failed to create command workqueue\n");
+               err = -ENOMEM;
+               goto err_cache;
+       }
+
+       err = create_debugfs_files(dev);
+       if (err) {
+               err = -ENOMEM;
+               goto err_wq;
+       }
+
+       return 0;
+
+err_wq:
+       destroy_workqueue(cmd->wq);
+
+err_cache:
+       destroy_msg_cache(dev);
+
+err_map:
+       dma_unmap_single(&dev->pdev->dev, cmd->dma, PAGE_SIZE,
+                        DMA_BIDIRECTIONAL);
+err_free:
+       free_pages((unsigned long)cmd->cmd_buf, 0);
+
+err_free_pool:
+       pci_pool_destroy(cmd->pool);
+
+       return err;
+}
+EXPORT_SYMBOL(mlx5_cmd_init);
+
+void mlx5_cmd_cleanup(struct mlx5_core_dev *dev)
+{
+       struct mlx5_cmd *cmd = &dev->cmd;
+
+       clean_debug_files(dev);
+       destroy_workqueue(cmd->wq);
+       destroy_msg_cache(dev);
+       dma_unmap_single(&dev->pdev->dev, cmd->dma, PAGE_SIZE,
+                        DMA_BIDIRECTIONAL);
+       free_pages((unsigned long)cmd->cmd_buf, 0);
+       pci_pool_destroy(cmd->pool);
+}
+EXPORT_SYMBOL(mlx5_cmd_cleanup);
+
+static const char *cmd_status_str(u8 status)
+{
+       switch (status) {
+       case MLX5_CMD_STAT_OK:
+               return "OK";
+       case MLX5_CMD_STAT_INT_ERR:
+               return "internal error";
+       case MLX5_CMD_STAT_BAD_OP_ERR:
+               return "bad operation";
+       case MLX5_CMD_STAT_BAD_PARAM_ERR:
+               return "bad parameter";
+       case MLX5_CMD_STAT_BAD_SYS_STATE_ERR:
+               return "bad system state";
+       case MLX5_CMD_STAT_BAD_RES_ERR:
+               return "bad resource";
+       case MLX5_CMD_STAT_RES_BUSY:
+               return "resource busy";
+       case MLX5_CMD_STAT_LIM_ERR:
+               return "limits exceeded";
+       case MLX5_CMD_STAT_BAD_RES_STATE_ERR:
+               return "bad resource state";
+       case MLX5_CMD_STAT_IX_ERR:
+               return "bad index";
+       case MLX5_CMD_STAT_NO_RES_ERR:
+               return "no resources";
+       case MLX5_CMD_STAT_BAD_INP_LEN_ERR:
+               return "bad input length";
+       case MLX5_CMD_STAT_BAD_OUTP_LEN_ERR:
+               return "bad output length";
+       case MLX5_CMD_STAT_BAD_QP_STATE_ERR:
+               return "bad QP state";
+       case MLX5_CMD_STAT_BAD_PKT_ERR:
+               return "bad packet (discarded)";
+       case MLX5_CMD_STAT_BAD_SIZE_OUTS_CQES_ERR:
+               return "bad size too many outstanding CQEs";
+       default:
+               return "unknown status";
+       }
+}
+
+int mlx5_cmd_status_to_err(struct mlx5_outbox_hdr *hdr)
+{
+       if (!hdr->status)
+               return 0;
+
+       pr_warn("command failed, status %s(0x%x), syndrome 0x%x\n",
+               cmd_status_str(hdr->status), hdr->status,
+               be32_to_cpu(hdr->syndrome));
+
+       switch (hdr->status) {
+       case MLX5_CMD_STAT_OK:                          return 0;
+       case MLX5_CMD_STAT_INT_ERR:                     return -EIO;
+       case MLX5_CMD_STAT_BAD_OP_ERR:                  return -EINVAL;
+       case MLX5_CMD_STAT_BAD_PARAM_ERR:               return -EINVAL;
+       case MLX5_CMD_STAT_BAD_SYS_STATE_ERR:           return -EIO;
+       case MLX5_CMD_STAT_BAD_RES_ERR:                 return -EINVAL;
+       case MLX5_CMD_STAT_RES_BUSY:                    return -EBUSY;
+       case MLX5_CMD_STAT_LIM_ERR:                     return -EINVAL;
+       case MLX5_CMD_STAT_BAD_RES_STATE_ERR:           return -EINVAL;
+       case MLX5_CMD_STAT_IX_ERR:                      return -EINVAL;
+       case MLX5_CMD_STAT_NO_RES_ERR:                  return -EAGAIN;
+       case MLX5_CMD_STAT_BAD_INP_LEN_ERR:             return -EIO;
+       case MLX5_CMD_STAT_BAD_OUTP_LEN_ERR:            return -EIO;
+       case MLX5_CMD_STAT_BAD_QP_STATE_ERR:            return -EINVAL;
+       case MLX5_CMD_STAT_BAD_PKT_ERR:                 return -EINVAL;
+       case MLX5_CMD_STAT_BAD_SIZE_OUTS_CQES_ERR:      return -EINVAL;
+       default:                                        return -EIO;
+       }
+}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/cq.c b/drivers/net/ethernet/mellanox/mlx5/core/cq.c
new file mode 100644 (file)
index 0000000..c2d660b
--- /dev/null
@@ -0,0 +1,224 @@
+/*
+ * Copyright (c) 2013, Mellanox Technologies inc.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/hardirq.h>
+#include <linux/mlx5/driver.h>
+#include <linux/mlx5/cmd.h>
+#include <rdma/ib_verbs.h>
+#include <linux/mlx5/cq.h>
+#include "mlx5_core.h"
+
+void mlx5_cq_completion(struct mlx5_core_dev *dev, u32 cqn)
+{
+       struct mlx5_core_cq *cq;
+       struct mlx5_cq_table *table = &dev->priv.cq_table;
+
+       spin_lock(&table->lock);
+       cq = radix_tree_lookup(&table->tree, cqn);
+       if (likely(cq))
+               atomic_inc(&cq->refcount);
+       spin_unlock(&table->lock);
+
+       if (!cq) {
+               mlx5_core_warn(dev, "Completion event for bogus CQ 0x%x\n", cqn);
+               return;
+       }
+
+       ++cq->arm_sn;
+
+       cq->comp(cq);
+
+       if (atomic_dec_and_test(&cq->refcount))
+               complete(&cq->free);
+}
+
+void mlx5_cq_event(struct mlx5_core_dev *dev, u32 cqn, int event_type)
+{
+       struct mlx5_cq_table *table = &dev->priv.cq_table;
+       struct mlx5_core_cq *cq;
+
+       spin_lock(&table->lock);
+
+       cq = radix_tree_lookup(&table->tree, cqn);
+       if (cq)
+               atomic_inc(&cq->refcount);
+
+       spin_unlock(&table->lock);
+
+       if (!cq) {
+               mlx5_core_warn(dev, "Async event for bogus CQ 0x%x\n", cqn);
+               return;
+       }
+
+       cq->event(cq, event_type);
+
+       if (atomic_dec_and_test(&cq->refcount))
+               complete(&cq->free);
+}
+
+
+int mlx5_core_create_cq(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq,
+                       struct mlx5_create_cq_mbox_in *in, int inlen)
+{
+       int err;
+       struct mlx5_cq_table *table = &dev->priv.cq_table;
+       struct mlx5_create_cq_mbox_out out;
+       struct mlx5_destroy_cq_mbox_in din;
+       struct mlx5_destroy_cq_mbox_out dout;
+
+       in->hdr.opcode = cpu_to_be16(MLX5_CMD_OP_CREATE_CQ);
+       memset(&out, 0, sizeof(out));
+       err = mlx5_cmd_exec(dev, in, inlen, &out, sizeof(out));
+       if (err)
+               return err;
+
+       if (out.hdr.status)
+               return mlx5_cmd_status_to_err(&out.hdr);
+
+       cq->cqn = be32_to_cpu(out.cqn) & 0xffffff;
+       cq->cons_index = 0;
+       cq->arm_sn     = 0;
+       atomic_set(&cq->refcount, 1);
+       init_completion(&cq->free);
+
+       spin_lock_irq(&table->lock);
+       err = radix_tree_insert(&table->tree, cq->cqn, cq);
+       spin_unlock_irq(&table->lock);
+       if (err)
+               goto err_cmd;
+
+       cq->pid = current->pid;
+       err = mlx5_debug_cq_add(dev, cq);
+       if (err)
+               mlx5_core_dbg(dev, "failed adding CP 0x%x to debug file system\n",
+                             cq->cqn);
+
+       return 0;
+
+err_cmd:
+       memset(&din, 0, sizeof(din));
+       memset(&dout, 0, sizeof(dout));
+       din.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_DESTROY_CQ);
+       mlx5_cmd_exec(dev, &din, sizeof(din), &dout, sizeof(dout));
+       return err;
+}
+EXPORT_SYMBOL(mlx5_core_create_cq);
+
+int mlx5_core_destroy_cq(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq)
+{
+       struct mlx5_cq_table *table = &dev->priv.cq_table;
+       struct mlx5_destroy_cq_mbox_in in;
+       struct mlx5_destroy_cq_mbox_out out;
+       struct mlx5_core_cq *tmp;
+       int err;
+
+       spin_lock_irq(&table->lock);
+       tmp = radix_tree_delete(&table->tree, cq->cqn);
+       spin_unlock_irq(&table->lock);
+       if (!tmp) {
+               mlx5_core_warn(dev, "cq 0x%x not found in tree\n", cq->cqn);
+               return -EINVAL;
+       }
+       if (tmp != cq) {
+               mlx5_core_warn(dev, "corruption on srqn 0x%x\n", cq->cqn);
+               return -EINVAL;
+       }
+
+       memset(&in, 0, sizeof(in));
+       memset(&out, 0, sizeof(out));
+       in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_DESTROY_CQ);
+       in.cqn = cpu_to_be32(cq->cqn);
+       err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out));
+       if (err)
+               return err;
+
+       if (out.hdr.status)
+               return mlx5_cmd_status_to_err(&out.hdr);
+
+       synchronize_irq(cq->irqn);
+
+       mlx5_debug_cq_remove(dev, cq);
+       if (atomic_dec_and_test(&cq->refcount))
+               complete(&cq->free);
+       wait_for_completion(&cq->free);
+
+       return 0;
+}
+EXPORT_SYMBOL(mlx5_core_destroy_cq);
+
+int mlx5_core_query_cq(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq,
+                      struct mlx5_query_cq_mbox_out *out)
+{
+       struct mlx5_query_cq_mbox_in in;
+       int err;
+
+       memset(&in, 0, sizeof(in));
+       memset(out, 0, sizeof(*out));
+
+       in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_QUERY_CQ);
+       in.cqn = cpu_to_be32(cq->cqn);
+       err = mlx5_cmd_exec(dev, &in, sizeof(in), out, sizeof(*out));
+       if (err)
+               return err;
+
+       if (out->hdr.status)
+               return mlx5_cmd_status_to_err(&out->hdr);
+
+       return err;
+}
+EXPORT_SYMBOL(mlx5_core_query_cq);
+
+
+int mlx5_core_modify_cq(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq,
+                       int type, struct mlx5_cq_modify_params *params)
+{
+       return -ENOSYS;
+}
+
+int mlx5_init_cq_table(struct mlx5_core_dev *dev)
+{
+       struct mlx5_cq_table *table = &dev->priv.cq_table;
+       int err;
+
+       spin_lock_init(&table->lock);
+       INIT_RADIX_TREE(&table->tree, GFP_ATOMIC);
+       err = mlx5_cq_debugfs_init(dev);
+
+       return err;
+}
+
+void mlx5_cleanup_cq_table(struct mlx5_core_dev *dev)
+{
+       mlx5_cq_debugfs_cleanup(dev);
+}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/debugfs.c b/drivers/net/ethernet/mellanox/mlx5/core/debugfs.c
new file mode 100644 (file)
index 0000000..4273c06
--- /dev/null
@@ -0,0 +1,583 @@
+/*
+ * Copyright (c) 2013, Mellanox Technologies inc.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/module.h>
+#include <linux/debugfs.h>
+#include <linux/mlx5/qp.h>
+#include <linux/mlx5/cq.h>
+#include <linux/mlx5/driver.h>
+#include "mlx5_core.h"
+
+enum {
+       QP_PID,
+       QP_STATE,
+       QP_XPORT,
+       QP_MTU,
+       QP_N_RECV,
+       QP_RECV_SZ,
+       QP_N_SEND,
+       QP_LOG_PG_SZ,
+       QP_RQPN,
+};
+
+static char *qp_fields[] = {
+       [QP_PID]        = "pid",
+       [QP_STATE]      = "state",
+       [QP_XPORT]      = "transport",
+       [QP_MTU]        = "mtu",
+       [QP_N_RECV]     = "num_recv",
+       [QP_RECV_SZ]    = "rcv_wqe_sz",
+       [QP_N_SEND]     = "num_send",
+       [QP_LOG_PG_SZ]  = "log2_page_sz",
+       [QP_RQPN]       = "remote_qpn",
+};
+
+enum {
+       EQ_NUM_EQES,
+       EQ_INTR,
+       EQ_LOG_PG_SZ,
+};
+
+static char *eq_fields[] = {
+       [EQ_NUM_EQES]   = "num_eqes",
+       [EQ_INTR]       = "intr",
+       [EQ_LOG_PG_SZ]  = "log_page_size",
+};
+
+enum {
+       CQ_PID,
+       CQ_NUM_CQES,
+       CQ_LOG_PG_SZ,
+};
+
+static char *cq_fields[] = {
+       [CQ_PID]        = "pid",
+       [CQ_NUM_CQES]   = "num_cqes",
+       [CQ_LOG_PG_SZ]  = "log_page_size",
+};
+
+struct dentry *mlx5_debugfs_root;
+EXPORT_SYMBOL(mlx5_debugfs_root);
+
+void mlx5_register_debugfs(void)
+{
+       mlx5_debugfs_root = debugfs_create_dir("mlx5", NULL);
+       if (IS_ERR_OR_NULL(mlx5_debugfs_root))
+               mlx5_debugfs_root = NULL;
+}
+
+void mlx5_unregister_debugfs(void)
+{
+       debugfs_remove(mlx5_debugfs_root);
+}
+
+int mlx5_qp_debugfs_init(struct mlx5_core_dev *dev)
+{
+       if (!mlx5_debugfs_root)
+               return 0;
+
+       atomic_set(&dev->num_qps, 0);
+
+       dev->priv.qp_debugfs = debugfs_create_dir("QPs",  dev->priv.dbg_root);
+       if (!dev->priv.qp_debugfs)
+               return -ENOMEM;
+
+       return 0;
+}
+
+void mlx5_qp_debugfs_cleanup(struct mlx5_core_dev *dev)
+{
+       if (!mlx5_debugfs_root)
+               return;
+
+       debugfs_remove_recursive(dev->priv.qp_debugfs);
+}
+
+int mlx5_eq_debugfs_init(struct mlx5_core_dev *dev)
+{
+       if (!mlx5_debugfs_root)
+               return 0;
+
+       dev->priv.eq_debugfs = debugfs_create_dir("EQs",  dev->priv.dbg_root);
+       if (!dev->priv.eq_debugfs)
+               return -ENOMEM;
+
+       return 0;
+}
+
+void mlx5_eq_debugfs_cleanup(struct mlx5_core_dev *dev)
+{
+       if (!mlx5_debugfs_root)
+               return;
+
+       debugfs_remove_recursive(dev->priv.eq_debugfs);
+}
+
+static ssize_t average_read(struct file *filp, char __user *buf, size_t count,
+                           loff_t *pos)
+{
+       struct mlx5_cmd_stats *stats;
+       u64 field = 0;
+       int ret;
+       char tbuf[22];
+
+       if (*pos)
+               return 0;
+
+       stats = filp->private_data;
+       spin_lock(&stats->lock);
+       if (stats->n)
+               field = stats->sum / stats->n;
+       spin_unlock(&stats->lock);
+       ret = snprintf(tbuf, sizeof(tbuf), "%llu\n", field);
+       if (ret > 0) {
+               if (copy_to_user(buf, tbuf, ret))
+                       return -EFAULT;
+       }
+
+       *pos += ret;
+       return ret;
+}
+
+
+static ssize_t average_write(struct file *filp, const char __user *buf,
+                            size_t count, loff_t *pos)
+{
+       struct mlx5_cmd_stats *stats;
+
+       stats = filp->private_data;
+       spin_lock(&stats->lock);
+       stats->sum = 0;
+       stats->n = 0;
+       spin_unlock(&stats->lock);
+
+       *pos += count;
+
+       return count;
+}
+
+static const struct file_operations stats_fops = {
+       .owner  = THIS_MODULE,
+       .open   = simple_open,
+       .read   = average_read,
+       .write  = average_write,
+};
+
+int mlx5_cmdif_debugfs_init(struct mlx5_core_dev *dev)
+{
+       struct mlx5_cmd_stats *stats;
+       struct dentry **cmd;
+       const char *namep;
+       int err;
+       int i;
+
+       if (!mlx5_debugfs_root)
+               return 0;
+
+       cmd = &dev->priv.cmdif_debugfs;
+       *cmd = debugfs_create_dir("commands", dev->priv.dbg_root);
+       if (!*cmd)
+               return -ENOMEM;
+
+       for (i = 0; i < ARRAY_SIZE(dev->cmd.stats); i++) {
+               stats = &dev->cmd.stats[i];
+               namep = mlx5_command_str(i);
+               if (strcmp(namep, "unknown command opcode")) {
+                       stats->root = debugfs_create_dir(namep, *cmd);
+                       if (!stats->root) {
+                               mlx5_core_warn(dev, "failed adding command %d\n",
+                                              i);
+                               err = -ENOMEM;
+                               goto out;
+                       }
+
+                       stats->avg = debugfs_create_file("average", 0400,
+                                                        stats->root, stats,
+                                                        &stats_fops);
+                       if (!stats->avg) {
+                               mlx5_core_warn(dev, "failed creating debugfs file\n");
+                               err = -ENOMEM;
+                               goto out;
+                       }
+
+                       stats->count = debugfs_create_u64("n", 0400,
+                                                         stats->root,
+                                                         &stats->n);
+                       if (!stats->count) {
+                               mlx5_core_warn(dev, "failed creating debugfs file\n");
+                               err = -ENOMEM;
+                               goto out;
+                       }
+               }
+       }
+
+       return 0;
+out:
+       debugfs_remove_recursive(dev->priv.cmdif_debugfs);
+       return err;
+}
+
+void mlx5_cmdif_debugfs_cleanup(struct mlx5_core_dev *dev)
+{
+       if (!mlx5_debugfs_root)
+               return;
+
+       debugfs_remove_recursive(dev->priv.cmdif_debugfs);
+}
+
+int mlx5_cq_debugfs_init(struct mlx5_core_dev *dev)
+{
+       if (!mlx5_debugfs_root)
+               return 0;
+
+       dev->priv.cq_debugfs = debugfs_create_dir("CQs",  dev->priv.dbg_root);
+       if (!dev->priv.cq_debugfs)
+               return -ENOMEM;
+
+       return 0;
+}
+
+void mlx5_cq_debugfs_cleanup(struct mlx5_core_dev *dev)
+{
+       if (!mlx5_debugfs_root)
+               return;
+
+       debugfs_remove_recursive(dev->priv.cq_debugfs);
+}
+
+static u64 qp_read_field(struct mlx5_core_dev *dev, struct mlx5_core_qp *qp,
+                        int index)
+{
+       struct mlx5_query_qp_mbox_out *out;
+       struct mlx5_qp_context *ctx;
+       u64 param = 0;
+       int err;
+       int no_sq;
+
+       out = kzalloc(sizeof(*out), GFP_KERNEL);
+       if (!out)
+               return param;
+
+       err = mlx5_core_qp_query(dev, qp, out, sizeof(*out));
+       if (err) {
+               mlx5_core_warn(dev, "failed to query qp\n");
+               goto out;
+       }
+
+       ctx = &out->ctx;
+       switch (index) {
+       case QP_PID:
+               param = qp->pid;
+               break;
+       case QP_STATE:
+               param = be32_to_cpu(ctx->flags) >> 28;
+               break;
+       case QP_XPORT:
+               param = (be32_to_cpu(ctx->flags) >> 16) & 0xff;
+               break;
+       case QP_MTU:
+               param = ctx->mtu_msgmax >> 5;
+               break;
+       case QP_N_RECV:
+               param = 1 << ((ctx->rq_size_stride >> 3) & 0xf);
+               break;
+       case QP_RECV_SZ:
+               param = 1 << ((ctx->rq_size_stride & 7) + 4);
+               break;
+       case QP_N_SEND:
+               no_sq = be16_to_cpu(ctx->sq_crq_size) >> 15;
+               if (!no_sq)
+                       param = 1 << (be16_to_cpu(ctx->sq_crq_size) >> 11);
+               else
+                       param = 0;
+               break;
+       case QP_LOG_PG_SZ:
+               param = (be32_to_cpu(ctx->log_pg_sz_remote_qpn) >> 24) & 0x1f;
+               param += 12;
+               break;
+       case QP_RQPN:
+               param = be32_to_cpu(ctx->log_pg_sz_remote_qpn) & 0xffffff;
+               break;
+       }
+
+out:
+       kfree(out);
+       return param;
+}
+
+static u64 eq_read_field(struct mlx5_core_dev *dev, struct mlx5_eq *eq,
+                        int index)
+{
+       struct mlx5_query_eq_mbox_out *out;
+       struct mlx5_eq_context *ctx;
+       u64 param = 0;
+       int err;
+
+       out = kzalloc(sizeof(*out), GFP_KERNEL);
+       if (!out)
+               return param;
+
+       ctx = &out->ctx;
+
+       err = mlx5_core_eq_query(dev, eq, out, sizeof(*out));
+       if (err) {
+               mlx5_core_warn(dev, "failed to query eq\n");
+               goto out;
+       }
+
+       switch (index) {
+       case EQ_NUM_EQES:
+               param = 1 << ((be32_to_cpu(ctx->log_sz_usr_page) >> 24) & 0x1f);
+               break;
+       case EQ_INTR:
+               param = ctx->intr;
+               break;
+       case EQ_LOG_PG_SZ:
+               param = (ctx->log_page_size & 0x1f) + 12;
+               break;
+       }
+
+out:
+       kfree(out);
+       return param;
+}
+
+static u64 cq_read_field(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq,
+                        int index)
+{
+       struct mlx5_query_cq_mbox_out *out;
+       struct mlx5_cq_context *ctx;
+       u64 param = 0;
+       int err;
+
+       out = kzalloc(sizeof(*out), GFP_KERNEL);
+       if (!out)
+               return param;
+
+       ctx = &out->ctx;
+
+       err = mlx5_core_query_cq(dev, cq, out);
+       if (err) {
+               mlx5_core_warn(dev, "failed to query cq\n");
+               goto out;
+       }
+
+       switch (index) {
+       case CQ_PID:
+               param = cq->pid;
+               break;
+       case CQ_NUM_CQES:
+               param = 1 << ((be32_to_cpu(ctx->log_sz_usr_page) >> 24) & 0x1f);
+               break;
+       case CQ_LOG_PG_SZ:
+               param = (ctx->log_pg_sz & 0x1f) + 12;
+               break;
+       }
+
+out:
+       kfree(out);
+       return param;
+}
+
+static ssize_t dbg_read(struct file *filp, char __user *buf, size_t count,
+                       loff_t *pos)
+{
+       struct mlx5_field_desc *desc;
+       struct mlx5_rsc_debug *d;
+       char tbuf[18];
+       u64 field;
+       int ret;
+
+       if (*pos)
+               return 0;
+
+       desc = filp->private_data;
+       d = (void *)(desc - desc->i) - sizeof(*d);
+       switch (d->type) {
+       case MLX5_DBG_RSC_QP:
+               field = qp_read_field(d->dev, d->object, desc->i);
+               break;
+
+       case MLX5_DBG_RSC_EQ:
+               field = eq_read_field(d->dev, d->object, desc->i);
+               break;
+
+       case MLX5_DBG_RSC_CQ:
+               field = cq_read_field(d->dev, d->object, desc->i);
+               break;
+
+       default:
+               mlx5_core_warn(d->dev, "invalid resource type %d\n", d->type);
+               return -EINVAL;
+       }
+
+       ret = snprintf(tbuf, sizeof(tbuf), "0x%llx\n", field);
+       if (ret > 0) {
+               if (copy_to_user(buf, tbuf, ret))
+                       return -EFAULT;
+       }
+
+       *pos += ret;
+       return ret;
+}
+
+static const struct file_operations fops = {
+       .owner  = THIS_MODULE,
+       .open   = simple_open,
+       .read   = dbg_read,
+};
+
+static int add_res_tree(struct mlx5_core_dev *dev, enum dbg_rsc_type type,
+                       struct dentry *root, struct mlx5_rsc_debug **dbg,
+                       int rsn, char **field, int nfile, void *data)
+{
+       struct mlx5_rsc_debug *d;
+       char resn[32];
+       int err;
+       int i;
+
+       d = kzalloc(sizeof(*d) + nfile * sizeof(d->fields[0]), GFP_KERNEL);
+       if (!d)
+               return -ENOMEM;
+
+       d->dev = dev;
+       d->object = data;
+       d->type = type;
+       sprintf(resn, "0x%x", rsn);
+       d->root = debugfs_create_dir(resn,  root);
+       if (!d->root) {
+               err = -ENOMEM;
+               goto out_free;
+       }
+
+       for (i = 0; i < nfile; i++) {
+               d->fields[i].i = i;
+               d->fields[i].dent = debugfs_create_file(field[i], 0400,
+                                                       d->root, &d->fields[i],
+                                                       &fops);
+               if (!d->fields[i].dent) {
+                       err = -ENOMEM;
+                       goto out_rem;
+               }
+       }
+       *dbg = d;
+
+       return 0;
+out_rem:
+       debugfs_remove_recursive(d->root);
+
+out_free:
+       kfree(d);
+       return err;
+}
+
+static void rem_res_tree(struct mlx5_rsc_debug *d)
+{
+       debugfs_remove_recursive(d->root);
+       kfree(d);
+}
+
+int mlx5_debug_qp_add(struct mlx5_core_dev *dev, struct mlx5_core_qp *qp)
+{
+       int err;
+
+       if (!mlx5_debugfs_root)
+               return 0;
+
+       err = add_res_tree(dev, MLX5_DBG_RSC_QP, dev->priv.qp_debugfs,
+                          &qp->dbg, qp->qpn, qp_fields,
+                          ARRAY_SIZE(qp_fields), qp);
+       if (err)
+               qp->dbg = NULL;
+
+       return err;
+}
+
+void mlx5_debug_qp_remove(struct mlx5_core_dev *dev, struct mlx5_core_qp *qp)
+{
+       if (!mlx5_debugfs_root)
+               return;
+
+       if (qp->dbg)
+               rem_res_tree(qp->dbg);
+}
+
+
+int mlx5_debug_eq_add(struct mlx5_core_dev *dev, struct mlx5_eq *eq)
+{
+       int err;
+
+       if (!mlx5_debugfs_root)
+               return 0;
+
+       err = add_res_tree(dev, MLX5_DBG_RSC_EQ, dev->priv.eq_debugfs,
+                          &eq->dbg, eq->eqn, eq_fields,
+                          ARRAY_SIZE(eq_fields), eq);
+       if (err)
+               eq->dbg = NULL;
+
+       return err;
+}
+
+void mlx5_debug_eq_remove(struct mlx5_core_dev *dev, struct mlx5_eq *eq)
+{
+       if (!mlx5_debugfs_root)
+               return;
+
+       if (eq->dbg)
+               rem_res_tree(eq->dbg);
+}
+
+int mlx5_debug_cq_add(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq)
+{
+       int err;
+
+       if (!mlx5_debugfs_root)
+               return 0;
+
+       err = add_res_tree(dev, MLX5_DBG_RSC_CQ, dev->priv.cq_debugfs,
+                          &cq->dbg, cq->cqn, cq_fields,
+                          ARRAY_SIZE(cq_fields), cq);
+       if (err)
+               cq->dbg = NULL;
+
+       return err;
+}
+
+void mlx5_debug_cq_remove(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq)
+{
+       if (!mlx5_debugfs_root)
+               return;
+
+       if (cq->dbg)
+               rem_res_tree(cq->dbg);
+}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eq.c b/drivers/net/ethernet/mellanox/mlx5/core/eq.c
new file mode 100644 (file)
index 0000000..c02cbcf
--- /dev/null
@@ -0,0 +1,521 @@
+/*
+ * Copyright (c) 2013, Mellanox Technologies inc.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/mlx5/driver.h>
+#include <linux/mlx5/cmd.h>
+#include "mlx5_core.h"
+
+enum {
+       MLX5_EQE_SIZE           = sizeof(struct mlx5_eqe),
+       MLX5_EQE_OWNER_INIT_VAL = 0x1,
+};
+
+enum {
+       MLX5_EQ_STATE_ARMED             = 0x9,
+       MLX5_EQ_STATE_FIRED             = 0xa,
+       MLX5_EQ_STATE_ALWAYS_ARMED      = 0xb,
+};
+
+enum {
+       MLX5_NUM_SPARE_EQE      = 0x80,
+       MLX5_NUM_ASYNC_EQE      = 0x100,
+       MLX5_NUM_CMD_EQE        = 32,
+};
+
+enum {
+       MLX5_EQ_DOORBEL_OFFSET  = 0x40,
+};
+
+#define MLX5_ASYNC_EVENT_MASK ((1ull << MLX5_EVENT_TYPE_PATH_MIG)          | \
+                              (1ull << MLX5_EVENT_TYPE_COMM_EST)           | \
+                              (1ull << MLX5_EVENT_TYPE_SQ_DRAINED)         | \
+                              (1ull << MLX5_EVENT_TYPE_CQ_ERROR)           | \
+                              (1ull << MLX5_EVENT_TYPE_WQ_CATAS_ERROR)     | \
+                              (1ull << MLX5_EVENT_TYPE_PATH_MIG_FAILED)    | \
+                              (1ull << MLX5_EVENT_TYPE_WQ_INVAL_REQ_ERROR) | \
+                              (1ull << MLX5_EVENT_TYPE_WQ_ACCESS_ERROR)    | \
+                              (1ull << MLX5_EVENT_TYPE_PORT_CHANGE)        | \
+                              (1ull << MLX5_EVENT_TYPE_SRQ_CATAS_ERROR)    | \
+                              (1ull << MLX5_EVENT_TYPE_SRQ_LAST_WQE)       | \
+                              (1ull << MLX5_EVENT_TYPE_SRQ_RQ_LIMIT))
+
+struct map_eq_in {
+       u64     mask;
+       u32     reserved;
+       u32     unmap_eqn;
+};
+
+struct cre_des_eq {
+       u8      reserved[15];
+       u8      eqn;
+};
+
+static int mlx5_cmd_destroy_eq(struct mlx5_core_dev *dev, u8 eqn)
+{
+       struct mlx5_destroy_eq_mbox_in in;
+       struct mlx5_destroy_eq_mbox_out out;
+       int err;
+
+       memset(&in, 0, sizeof(in));
+       memset(&out, 0, sizeof(out));
+       in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_DESTROY_EQ);
+       in.eqn = eqn;
+       err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out));
+       if (!err)
+               goto ex;
+
+       if (out.hdr.status)
+               err = mlx5_cmd_status_to_err(&out.hdr);
+
+ex:
+       return err;
+}
+
+static struct mlx5_eqe *get_eqe(struct mlx5_eq *eq, u32 entry)
+{
+       return mlx5_buf_offset(&eq->buf, entry * MLX5_EQE_SIZE);
+}
+
+static struct mlx5_eqe *next_eqe_sw(struct mlx5_eq *eq)
+{
+       struct mlx5_eqe *eqe = get_eqe(eq, eq->cons_index & (eq->nent - 1));
+
+       return ((eqe->owner & 1) ^ !!(eq->cons_index & eq->nent)) ? NULL : eqe;
+}
+
+static const char *eqe_type_str(u8 type)
+{
+       switch (type) {
+       case MLX5_EVENT_TYPE_COMP:
+               return "MLX5_EVENT_TYPE_COMP";
+       case MLX5_EVENT_TYPE_PATH_MIG:
+               return "MLX5_EVENT_TYPE_PATH_MIG";
+       case MLX5_EVENT_TYPE_COMM_EST:
+               return "MLX5_EVENT_TYPE_COMM_EST";
+       case MLX5_EVENT_TYPE_SQ_DRAINED:
+               return "MLX5_EVENT_TYPE_SQ_DRAINED";
+       case MLX5_EVENT_TYPE_SRQ_LAST_WQE:
+               return "MLX5_EVENT_TYPE_SRQ_LAST_WQE";
+       case MLX5_EVENT_TYPE_SRQ_RQ_LIMIT:
+               return "MLX5_EVENT_TYPE_SRQ_RQ_LIMIT";
+       case MLX5_EVENT_TYPE_CQ_ERROR:
+               return "MLX5_EVENT_TYPE_CQ_ERROR";
+       case MLX5_EVENT_TYPE_WQ_CATAS_ERROR:
+               return "MLX5_EVENT_TYPE_WQ_CATAS_ERROR";
+       case MLX5_EVENT_TYPE_PATH_MIG_FAILED:
+               return "MLX5_EVENT_TYPE_PATH_MIG_FAILED";
+       case MLX5_EVENT_TYPE_WQ_INVAL_REQ_ERROR:
+               return "MLX5_EVENT_TYPE_WQ_INVAL_REQ_ERROR";
+       case MLX5_EVENT_TYPE_WQ_ACCESS_ERROR:
+               return "MLX5_EVENT_TYPE_WQ_ACCESS_ERROR";
+       case MLX5_EVENT_TYPE_SRQ_CATAS_ERROR:
+               return "MLX5_EVENT_TYPE_SRQ_CATAS_ERROR";
+       case MLX5_EVENT_TYPE_INTERNAL_ERROR:
+               return "MLX5_EVENT_TYPE_INTERNAL_ERROR";
+       case MLX5_EVENT_TYPE_PORT_CHANGE:
+               return "MLX5_EVENT_TYPE_PORT_CHANGE";
+       case MLX5_EVENT_TYPE_GPIO_EVENT:
+               return "MLX5_EVENT_TYPE_GPIO_EVENT";
+       case MLX5_EVENT_TYPE_REMOTE_CONFIG:
+               return "MLX5_EVENT_TYPE_REMOTE_CONFIG";
+       case MLX5_EVENT_TYPE_DB_BF_CONGESTION:
+               return "MLX5_EVENT_TYPE_DB_BF_CONGESTION";
+       case MLX5_EVENT_TYPE_STALL_EVENT:
+               return "MLX5_EVENT_TYPE_STALL_EVENT";
+       case MLX5_EVENT_TYPE_CMD:
+               return "MLX5_EVENT_TYPE_CMD";
+       case MLX5_EVENT_TYPE_PAGE_REQUEST:
+               return "MLX5_EVENT_TYPE_PAGE_REQUEST";
+       default:
+               return "Unrecognized event";
+       }
+}
+
+static enum mlx5_dev_event port_subtype_event(u8 subtype)
+{
+       switch (subtype) {
+       case MLX5_PORT_CHANGE_SUBTYPE_DOWN:
+               return MLX5_DEV_EVENT_PORT_DOWN;
+       case MLX5_PORT_CHANGE_SUBTYPE_ACTIVE:
+               return MLX5_DEV_EVENT_PORT_UP;
+       case MLX5_PORT_CHANGE_SUBTYPE_INITIALIZED:
+               return MLX5_DEV_EVENT_PORT_INITIALIZED;
+       case MLX5_PORT_CHANGE_SUBTYPE_LID:
+               return MLX5_DEV_EVENT_LID_CHANGE;
+       case MLX5_PORT_CHANGE_SUBTYPE_PKEY:
+               return MLX5_DEV_EVENT_PKEY_CHANGE;
+       case MLX5_PORT_CHANGE_SUBTYPE_GUID:
+               return MLX5_DEV_EVENT_GUID_CHANGE;
+       case MLX5_PORT_CHANGE_SUBTYPE_CLIENT_REREG:
+               return MLX5_DEV_EVENT_CLIENT_REREG;
+       }
+       return -1;
+}
+
+static void eq_update_ci(struct mlx5_eq *eq, int arm)
+{
+       __be32 __iomem *addr = eq->doorbell + (arm ? 0 : 2);
+       u32 val = (eq->cons_index & 0xffffff) | (eq->eqn << 24);
+       __raw_writel((__force u32) cpu_to_be32(val), addr);
+       /* We still want ordering, just not swabbing, so add a barrier */
+       mb();
+}
+
+static int mlx5_eq_int(struct mlx5_core_dev *dev, struct mlx5_eq *eq)
+{
+       struct mlx5_eqe *eqe;
+       int eqes_found = 0;
+       int set_ci = 0;
+       u32 cqn;
+       u32 srqn;
+       u8 port;
+
+       while ((eqe = next_eqe_sw(eq))) {
+               /*
+                * Make sure we read EQ entry contents after we've
+                * checked the ownership bit.
+                */
+               rmb();
+
+               mlx5_core_dbg(eq->dev, "eqn %d, eqe type %s\n", eq->eqn, eqe_type_str(eqe->type));
+               switch (eqe->type) {
+               case MLX5_EVENT_TYPE_COMP:
+                       cqn = be32_to_cpu(eqe->data.comp.cqn) & 0xffffff;
+                       mlx5_cq_completion(dev, cqn);
+                       break;
+
+               case MLX5_EVENT_TYPE_PATH_MIG:
+               case MLX5_EVENT_TYPE_COMM_EST:
+               case MLX5_EVENT_TYPE_SQ_DRAINED:
+               case MLX5_EVENT_TYPE_SRQ_LAST_WQE:
+               case MLX5_EVENT_TYPE_WQ_CATAS_ERROR:
+               case MLX5_EVENT_TYPE_PATH_MIG_FAILED:
+               case MLX5_EVENT_TYPE_WQ_INVAL_REQ_ERROR:
+               case MLX5_EVENT_TYPE_WQ_ACCESS_ERROR:
+                       mlx5_core_dbg(dev, "event %s(%d) arrived\n",
+                                     eqe_type_str(eqe->type), eqe->type);
+                       mlx5_qp_event(dev, be32_to_cpu(eqe->data.qp_srq.qp_srq_n) & 0xffffff,
+                                     eqe->type);
+                       break;
+
+               case MLX5_EVENT_TYPE_SRQ_RQ_LIMIT:
+               case MLX5_EVENT_TYPE_SRQ_CATAS_ERROR:
+                       srqn = be32_to_cpu(eqe->data.qp_srq.qp_srq_n) & 0xffffff;
+                       mlx5_core_dbg(dev, "SRQ event %s(%d): srqn 0x%x\n",
+                                     eqe_type_str(eqe->type), eqe->type, srqn);
+                       mlx5_srq_event(dev, srqn, eqe->type);
+                       break;
+
+               case MLX5_EVENT_TYPE_CMD:
+                       mlx5_cmd_comp_handler(dev, be32_to_cpu(eqe->data.cmd.vector));
+                       break;
+
+               case MLX5_EVENT_TYPE_PORT_CHANGE:
+                       port = (eqe->data.port.port >> 4) & 0xf;
+                       switch (eqe->sub_type) {
+                       case MLX5_PORT_CHANGE_SUBTYPE_DOWN:
+                       case MLX5_PORT_CHANGE_SUBTYPE_ACTIVE:
+                       case MLX5_PORT_CHANGE_SUBTYPE_LID:
+                       case MLX5_PORT_CHANGE_SUBTYPE_PKEY:
+                       case MLX5_PORT_CHANGE_SUBTYPE_GUID:
+                       case MLX5_PORT_CHANGE_SUBTYPE_CLIENT_REREG:
+                       case MLX5_PORT_CHANGE_SUBTYPE_INITIALIZED:
+                               dev->event(dev, port_subtype_event(eqe->sub_type), &port);
+                               break;
+                       default:
+                               mlx5_core_warn(dev, "Port event with unrecognized subtype: port %d, sub_type %d\n",
+                                              port, eqe->sub_type);
+                       }
+                       break;
+               case MLX5_EVENT_TYPE_CQ_ERROR:
+                       cqn = be32_to_cpu(eqe->data.cq_err.cqn) & 0xffffff;
+                       mlx5_core_warn(dev, "CQ error on CQN 0x%x, syndrom 0x%x\n",
+                                      cqn, eqe->data.cq_err.syndrome);
+                       mlx5_cq_event(dev, cqn, eqe->type);
+                       break;
+
+               case MLX5_EVENT_TYPE_PAGE_REQUEST:
+                       {
+                               u16 func_id = be16_to_cpu(eqe->data.req_pages.func_id);
+                               s16 npages = be16_to_cpu(eqe->data.req_pages.num_pages);
+
+                               mlx5_core_dbg(dev, "page request for func 0x%x, napges %d\n", func_id, npages);
+                               mlx5_core_req_pages_handler(dev, func_id, npages);
+                       }
+                       break;
+
+
+               default:
+                       mlx5_core_warn(dev, "Unhandled event 0x%x on EQ 0x%x\n", eqe->type, eq->eqn);
+                       break;
+               }
+
+               ++eq->cons_index;
+               eqes_found = 1;
+               ++set_ci;
+
+               /* The HCA will think the queue has overflowed if we
+                * don't tell it we've been processing events.  We
+                * create our EQs with MLX5_NUM_SPARE_EQE extra
+                * entries, so we must update our consumer index at
+                * least that often.
+                */
+               if (unlikely(set_ci >= MLX5_NUM_SPARE_EQE)) {
+                       eq_update_ci(eq, 0);
+                       set_ci = 0;
+               }
+       }
+
+       eq_update_ci(eq, 1);
+
+       return eqes_found;
+}
+
+static irqreturn_t mlx5_msix_handler(int irq, void *eq_ptr)
+{
+       struct mlx5_eq *eq = eq_ptr;
+       struct mlx5_core_dev *dev = eq->dev;
+
+       mlx5_eq_int(dev, eq);
+
+       /* MSI-X vectors always belong to us */
+       return IRQ_HANDLED;
+}
+
+static void init_eq_buf(struct mlx5_eq *eq)
+{
+       struct mlx5_eqe *eqe;
+       int i;
+
+       for (i = 0; i < eq->nent; i++) {
+               eqe = get_eqe(eq, i);
+               eqe->owner = MLX5_EQE_OWNER_INIT_VAL;
+       }
+}
+
+int mlx5_create_map_eq(struct mlx5_core_dev *dev, struct mlx5_eq *eq, u8 vecidx,
+                      int nent, u64 mask, const char *name, struct mlx5_uar *uar)
+{
+       struct mlx5_eq_table *table = &dev->priv.eq_table;
+       struct mlx5_create_eq_mbox_in *in;
+       struct mlx5_create_eq_mbox_out out;
+       int err;
+       int inlen;
+
+       eq->nent = roundup_pow_of_two(nent + MLX5_NUM_SPARE_EQE);
+       err = mlx5_buf_alloc(dev, eq->nent * MLX5_EQE_SIZE, 2 * PAGE_SIZE,
+                            &eq->buf);
+       if (err)
+               return err;
+
+       init_eq_buf(eq);
+
+       inlen = sizeof(*in) + sizeof(in->pas[0]) * eq->buf.npages;
+       in = mlx5_vzalloc(inlen);
+       if (!in) {
+               err = -ENOMEM;
+               goto err_buf;
+       }
+       memset(&out, 0, sizeof(out));
+
+       mlx5_fill_page_array(&eq->buf, in->pas);
+
+       in->hdr.opcode = cpu_to_be16(MLX5_CMD_OP_CREATE_EQ);
+       in->ctx.log_sz_usr_page = cpu_to_be32(ilog2(eq->nent) << 24 | uar->index);
+       in->ctx.intr = vecidx;
+       in->ctx.log_page_size = PAGE_SHIFT - 12;
+       in->events_mask = cpu_to_be64(mask);
+
+       err = mlx5_cmd_exec(dev, in, inlen, &out, sizeof(out));
+       if (err)
+               goto err_in;
+
+       if (out.hdr.status) {
+               err = mlx5_cmd_status_to_err(&out.hdr);
+               goto err_in;
+       }
+
+       eq->eqn = out.eq_number;
+       err = request_irq(table->msix_arr[vecidx].vector, mlx5_msix_handler, 0,
+                         name, eq);
+       if (err)
+               goto err_eq;
+
+       eq->irqn = vecidx;
+       eq->dev = dev;
+       eq->doorbell = uar->map + MLX5_EQ_DOORBEL_OFFSET;
+
+       err = mlx5_debug_eq_add(dev, eq);
+       if (err)
+               goto err_irq;
+
+       /* EQs are created in ARMED state
+        */
+       eq_update_ci(eq, 1);
+
+       mlx5_vfree(in);
+       return 0;
+
+err_irq:
+       free_irq(table->msix_arr[vecidx].vector, eq);
+
+err_eq:
+       mlx5_cmd_destroy_eq(dev, eq->eqn);
+
+err_in:
+       mlx5_vfree(in);
+
+err_buf:
+       mlx5_buf_free(dev, &eq->buf);
+       return err;
+}
+EXPORT_SYMBOL_GPL(mlx5_create_map_eq);
+
+int mlx5_destroy_unmap_eq(struct mlx5_core_dev *dev, struct mlx5_eq *eq)
+{
+       struct mlx5_eq_table *table = &dev->priv.eq_table;
+       int err;
+
+       mlx5_debug_eq_remove(dev, eq);
+       free_irq(table->msix_arr[eq->irqn].vector, eq);
+       err = mlx5_cmd_destroy_eq(dev, eq->eqn);
+       if (err)
+               mlx5_core_warn(dev, "failed to destroy a previously created eq: eqn %d\n",
+                              eq->eqn);
+       mlx5_buf_free(dev, &eq->buf);
+
+       return err;
+}
+EXPORT_SYMBOL_GPL(mlx5_destroy_unmap_eq);
+
+int mlx5_eq_init(struct mlx5_core_dev *dev)
+{
+       int err;
+
+       spin_lock_init(&dev->priv.eq_table.lock);
+
+       err = mlx5_eq_debugfs_init(dev);
+
+       return err;
+}
+
+
+void mlx5_eq_cleanup(struct mlx5_core_dev *dev)
+{
+       mlx5_eq_debugfs_cleanup(dev);
+}
+
+int mlx5_start_eqs(struct mlx5_core_dev *dev)
+{
+       struct mlx5_eq_table *table = &dev->priv.eq_table;
+       int err;
+
+       err = mlx5_create_map_eq(dev, &table->cmd_eq, MLX5_EQ_VEC_CMD,
+                                MLX5_NUM_CMD_EQE, 1ull << MLX5_EVENT_TYPE_CMD,
+                                "mlx5_cmd_eq", &dev->priv.uuari.uars[0]);
+       if (err) {
+               mlx5_core_warn(dev, "failed to create cmd EQ %d\n", err);
+               return err;
+       }
+
+       mlx5_cmd_use_events(dev);
+
+       err = mlx5_create_map_eq(dev, &table->async_eq, MLX5_EQ_VEC_ASYNC,
+                                MLX5_NUM_ASYNC_EQE, MLX5_ASYNC_EVENT_MASK,
+                                "mlx5_async_eq", &dev->priv.uuari.uars[0]);
+       if (err) {
+               mlx5_core_warn(dev, "failed to create async EQ %d\n", err);
+               goto err1;
+       }
+
+       err = mlx5_create_map_eq(dev, &table->pages_eq,
+                                MLX5_EQ_VEC_PAGES,
+                                dev->caps.max_vf + 1,
+                                1 << MLX5_EVENT_TYPE_PAGE_REQUEST, "mlx5_pages_eq",
+                                &dev->priv.uuari.uars[0]);
+       if (err) {
+               mlx5_core_warn(dev, "failed to create pages EQ %d\n", err);
+               goto err2;
+       }
+
+       return err;
+
+err2:
+       mlx5_destroy_unmap_eq(dev, &table->async_eq);
+
+err1:
+       mlx5_cmd_use_polling(dev);
+       mlx5_destroy_unmap_eq(dev, &table->cmd_eq);
+       return err;
+}
+
+int mlx5_stop_eqs(struct mlx5_core_dev *dev)
+{
+       struct mlx5_eq_table *table = &dev->priv.eq_table;
+       int err;
+
+       err = mlx5_destroy_unmap_eq(dev, &table->pages_eq);
+       if (err)
+               return err;
+
+       mlx5_destroy_unmap_eq(dev, &table->async_eq);
+       mlx5_cmd_use_polling(dev);
+
+       err = mlx5_destroy_unmap_eq(dev, &table->cmd_eq);
+       if (err)
+               mlx5_cmd_use_events(dev);
+
+       return err;
+}
+
+int mlx5_core_eq_query(struct mlx5_core_dev *dev, struct mlx5_eq *eq,
+                      struct mlx5_query_eq_mbox_out *out, int outlen)
+{
+       struct mlx5_query_eq_mbox_in in;
+       int err;
+
+       memset(&in, 0, sizeof(in));
+       memset(out, 0, outlen);
+       in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_QUERY_EQ);
+       in.eqn = eq->eqn;
+       err = mlx5_cmd_exec(dev, &in, sizeof(in), out, outlen);
+       if (err)
+               return err;
+
+       if (out->hdr.status)
+               err = mlx5_cmd_status_to_err(&out->hdr);
+
+       return err;
+}
+EXPORT_SYMBOL_GPL(mlx5_core_eq_query);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fw.c b/drivers/net/ethernet/mellanox/mlx5/core/fw.c
new file mode 100644 (file)
index 0000000..72a5222
--- /dev/null
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 2013, Mellanox Technologies inc.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/mlx5/driver.h>
+#include <linux/mlx5/cmd.h>
+#include <linux/module.h>
+#include "mlx5_core.h"
+
+int mlx5_cmd_query_adapter(struct mlx5_core_dev *dev)
+{
+       struct mlx5_cmd_query_adapter_mbox_out *out;
+       struct mlx5_cmd_query_adapter_mbox_in in;
+       int err;
+
+       out = kzalloc(sizeof(*out), GFP_KERNEL);
+       if (!out)
+               return -ENOMEM;
+
+       memset(&in, 0, sizeof(in));
+       in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_QUERY_ADAPTER);
+       err = mlx5_cmd_exec(dev, &in, sizeof(in), out, sizeof(*out));
+       if (err)
+               goto out_out;
+
+       if (out->hdr.status) {
+               err = mlx5_cmd_status_to_err(&out->hdr);
+               goto out_out;
+       }
+
+       memcpy(dev->board_id, out->vsd_psid, sizeof(out->vsd_psid));
+
+out_out:
+       kfree(out);
+
+       return err;
+}
+
+int mlx5_cmd_query_hca_cap(struct mlx5_core_dev *dev,
+                          struct mlx5_caps *caps)
+{
+       struct mlx5_cmd_query_hca_cap_mbox_out *out;
+       struct mlx5_cmd_query_hca_cap_mbox_in in;
+       struct mlx5_query_special_ctxs_mbox_out ctx_out;
+       struct mlx5_query_special_ctxs_mbox_in ctx_in;
+       int err;
+       u16 t16;
+
+       out = kzalloc(sizeof(*out), GFP_KERNEL);
+       if (!out)
+               return -ENOMEM;
+
+       memset(&in, 0, sizeof(in));
+       in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_QUERY_HCA_CAP);
+       in.hdr.opmod  = cpu_to_be16(0x1);
+       err = mlx5_cmd_exec(dev, &in, sizeof(in), out, sizeof(*out));
+       if (err)
+               goto out_out;
+
+       if (out->hdr.status) {
+               err = mlx5_cmd_status_to_err(&out->hdr);
+               goto out_out;
+       }
+
+
+       caps->log_max_eq = out->hca_cap.log_max_eq & 0xf;
+       caps->max_cqes = 1 << out->hca_cap.log_max_cq_sz;
+       caps->max_wqes = 1 << out->hca_cap.log_max_qp_sz;
+       caps->max_sq_desc_sz = be16_to_cpu(out->hca_cap.max_desc_sz_sq);
+       caps->max_rq_desc_sz = be16_to_cpu(out->hca_cap.max_desc_sz_rq);
+       caps->flags = be64_to_cpu(out->hca_cap.flags);
+       caps->stat_rate_support = be16_to_cpu(out->hca_cap.stat_rate_support);
+       caps->log_max_msg = out->hca_cap.log_max_msg & 0x1f;
+       caps->num_ports = out->hca_cap.num_ports & 0xf;
+       caps->log_max_cq = out->hca_cap.log_max_cq & 0x1f;
+       if (caps->num_ports > MLX5_MAX_PORTS) {
+               mlx5_core_err(dev, "device has %d ports while the driver supports max %d ports\n",
+                             caps->num_ports, MLX5_MAX_PORTS);
+               err = -EINVAL;
+               goto out_out;
+       }
+       caps->log_max_qp = out->hca_cap.log_max_qp & 0x1f;
+       caps->log_max_mkey = out->hca_cap.log_max_mkey & 0x3f;
+       caps->log_max_pd = out->hca_cap.log_max_pd & 0x1f;
+       caps->log_max_srq = out->hca_cap.log_max_srqs & 0x1f;
+       caps->local_ca_ack_delay = out->hca_cap.local_ca_ack_delay & 0x1f;
+       caps->log_max_mcg = out->hca_cap.log_max_mcg;
+       caps->max_qp_mcg = be16_to_cpu(out->hca_cap.max_qp_mcg);
+       caps->max_ra_res_qp = 1 << (out->hca_cap.log_max_ra_res_qp & 0x3f);
+       caps->max_ra_req_qp = 1 << (out->hca_cap.log_max_ra_req_qp & 0x3f);
+       caps->max_srq_wqes = 1 << out->hca_cap.log_max_srq_sz;
+       t16 = be16_to_cpu(out->hca_cap.bf_log_bf_reg_size);
+       if (t16 & 0x8000) {
+               caps->bf_reg_size = 1 << (t16 & 0x1f);
+               caps->bf_regs_per_page = MLX5_BF_REGS_PER_PAGE;
+       } else {
+               caps->bf_reg_size = 0;
+               caps->bf_regs_per_page = 0;
+       }
+       caps->min_page_sz = ~(u32)((1 << out->hca_cap.log_pg_sz) - 1);
+
+       memset(&ctx_in, 0, sizeof(ctx_in));
+       memset(&ctx_out, 0, sizeof(ctx_out));
+       ctx_in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_QUERY_SPECIAL_CONTEXTS);
+       err = mlx5_cmd_exec(dev, &ctx_in, sizeof(ctx_in),
+                                &ctx_out, sizeof(ctx_out));
+       if (err)
+               goto out_out;
+
+       if (ctx_out.hdr.status)
+               err = mlx5_cmd_status_to_err(&ctx_out.hdr);
+
+       caps->reserved_lkey = be32_to_cpu(ctx_out.reserved_lkey);
+
+out_out:
+       kfree(out);
+
+       return err;
+}
+
+int mlx5_cmd_init_hca(struct mlx5_core_dev *dev)
+{
+       struct mlx5_cmd_init_hca_mbox_in in;
+       struct mlx5_cmd_init_hca_mbox_out out;
+       int err;
+
+       memset(&in, 0, sizeof(in));
+       memset(&out, 0, sizeof(out));
+       in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_INIT_HCA);
+       err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out));
+       if (err)
+               return err;
+
+       if (out.hdr.status)
+               err = mlx5_cmd_status_to_err(&out.hdr);
+
+       return err;
+}
+
+int mlx5_cmd_teardown_hca(struct mlx5_core_dev *dev)
+{
+       struct mlx5_cmd_teardown_hca_mbox_in in;
+       struct mlx5_cmd_teardown_hca_mbox_out out;
+       int err;
+
+       memset(&in, 0, sizeof(in));
+       memset(&out, 0, sizeof(out));
+       in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_TEARDOWN_HCA);
+       err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out));
+       if (err)
+               return err;
+
+       if (out.hdr.status)
+               err = mlx5_cmd_status_to_err(&out.hdr);
+
+       return err;
+}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/health.c b/drivers/net/ethernet/mellanox/mlx5/core/health.c
new file mode 100644 (file)
index 0000000..748f10a
--- /dev/null
@@ -0,0 +1,227 @@
+/*
+ * Copyright (c) 2013, Mellanox Technologies inc.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/random.h>
+#include <linux/vmalloc.h>
+#include <linux/mlx5/driver.h>
+#include <linux/mlx5/cmd.h>
+#include "mlx5_core.h"
+
+enum {
+       MLX5_HEALTH_POLL_INTERVAL       = 2 * HZ,
+       MAX_MISSES                      = 3,
+};
+
+enum {
+       MLX5_HEALTH_SYNDR_FW_ERR                = 0x1,
+       MLX5_HEALTH_SYNDR_IRISC_ERR             = 0x7,
+       MLX5_HEALTH_SYNDR_CRC_ERR               = 0x9,
+       MLX5_HEALTH_SYNDR_FETCH_PCI_ERR         = 0xa,
+       MLX5_HEALTH_SYNDR_HW_FTL_ERR            = 0xb,
+       MLX5_HEALTH_SYNDR_ASYNC_EQ_OVERRUN_ERR  = 0xc,
+       MLX5_HEALTH_SYNDR_EQ_ERR                = 0xd,
+       MLX5_HEALTH_SYNDR_FFSER_ERR             = 0xf,
+};
+
+static DEFINE_SPINLOCK(health_lock);
+
+static LIST_HEAD(health_list);
+static struct work_struct health_work;
+
+static health_handler_t reg_handler;
+int mlx5_register_health_report_handler(health_handler_t handler)
+{
+       spin_lock_irq(&health_lock);
+       if (reg_handler) {
+               spin_unlock_irq(&health_lock);
+               return -EEXIST;
+       }
+       reg_handler = handler;
+       spin_unlock_irq(&health_lock);
+
+       return 0;
+}
+EXPORT_SYMBOL(mlx5_register_health_report_handler);
+
+void mlx5_unregister_health_report_handler(void)
+{
+       spin_lock_irq(&health_lock);
+       reg_handler = NULL;
+       spin_unlock_irq(&health_lock);
+}
+EXPORT_SYMBOL(mlx5_unregister_health_report_handler);
+
+static void health_care(struct work_struct *work)
+{
+       struct mlx5_core_health *health, *n;
+       struct mlx5_core_dev *dev;
+       struct mlx5_priv *priv;
+       LIST_HEAD(tlist);
+
+       spin_lock_irq(&health_lock);
+       list_splice_init(&health_list, &tlist);
+
+       spin_unlock_irq(&health_lock);
+
+       list_for_each_entry_safe(health, n, &tlist, list) {
+               priv = container_of(health, struct mlx5_priv, health);
+               dev = container_of(priv, struct mlx5_core_dev, priv);
+               mlx5_core_warn(dev, "handling bad device here\n");
+               spin_lock_irq(&health_lock);
+               if (reg_handler)
+                       reg_handler(dev->pdev, health->health,
+                                   sizeof(health->health));
+
+               list_del_init(&health->list);
+               spin_unlock_irq(&health_lock);
+       }
+}
+
+static const char *hsynd_str(u8 synd)
+{
+       switch (synd) {
+       case MLX5_HEALTH_SYNDR_FW_ERR:
+               return "firmware internal error";
+       case MLX5_HEALTH_SYNDR_IRISC_ERR:
+               return "irisc not responding";
+       case MLX5_HEALTH_SYNDR_CRC_ERR:
+               return "firmware CRC error";
+       case MLX5_HEALTH_SYNDR_FETCH_PCI_ERR:
+               return "ICM fetch PCI error";
+       case MLX5_HEALTH_SYNDR_HW_FTL_ERR:
+               return "HW fatal error\n";
+       case MLX5_HEALTH_SYNDR_ASYNC_EQ_OVERRUN_ERR:
+               return "async EQ buffer overrun";
+       case MLX5_HEALTH_SYNDR_EQ_ERR:
+               return "EQ error";
+       case MLX5_HEALTH_SYNDR_FFSER_ERR:
+               return "FFSER error";
+       default:
+               return "unrecognized error";
+       }
+}
+
+static u16 read_be16(__be16 __iomem *p)
+{
+       return swab16(readl((__force u16 __iomem *) p));
+}
+
+static u32 read_be32(__be32 __iomem *p)
+{
+       return swab32(readl((__force u32 __iomem *) p));
+}
+
+static void print_health_info(struct mlx5_core_dev *dev)
+{
+       struct mlx5_core_health *health = &dev->priv.health;
+       struct health_buffer __iomem *h = health->health;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(h->assert_var); i++)
+               pr_info("assert_var[%d] 0x%08x\n", i, read_be32(h->assert_var + i));
+
+       pr_info("assert_exit_ptr 0x%08x\n", read_be32(&h->assert_exit_ptr));
+       pr_info("assert_callra 0x%08x\n", read_be32(&h->assert_callra));
+       pr_info("fw_ver 0x%08x\n", read_be32(&h->fw_ver));
+       pr_info("hw_id 0x%08x\n", read_be32(&h->hw_id));
+       pr_info("irisc_index %d\n", readb(&h->irisc_index));
+       pr_info("synd 0x%x: %s\n", readb(&h->synd), hsynd_str(readb(&h->synd)));
+       pr_info("ext_sync 0x%04x\n", read_be16(&h->ext_sync));
+}
+
+static void poll_health(unsigned long data)
+{
+       struct mlx5_core_dev *dev = (struct mlx5_core_dev *)data;
+       struct mlx5_core_health *health = &dev->priv.health;
+       unsigned long next;
+       u32 count;
+
+       count = ioread32be(health->health_counter);
+       if (count == health->prev)
+               ++health->miss_counter;
+       else
+               health->miss_counter = 0;
+
+       health->prev = count;
+       if (health->miss_counter == MAX_MISSES) {
+               mlx5_core_err(dev, "device's health compromised\n");
+               print_health_info(dev);
+               spin_lock_irq(&health_lock);
+               list_add_tail(&health->list, &health_list);
+               spin_unlock_irq(&health_lock);
+
+               queue_work(mlx5_core_wq, &health_work);
+       } else {
+               get_random_bytes(&next, sizeof(next));
+               next %= HZ;
+               next += jiffies + MLX5_HEALTH_POLL_INTERVAL;
+               mod_timer(&health->timer, next);
+       }
+}
+
+void mlx5_start_health_poll(struct mlx5_core_dev *dev)
+{
+       struct mlx5_core_health *health = &dev->priv.health;
+
+       INIT_LIST_HEAD(&health->list);
+       init_timer(&health->timer);
+       health->health = &dev->iseg->health;
+       health->health_counter = &dev->iseg->health_counter;
+
+       health->timer.data = (unsigned long)dev;
+       health->timer.function = poll_health;
+       health->timer.expires = round_jiffies(jiffies + MLX5_HEALTH_POLL_INTERVAL);
+       add_timer(&health->timer);
+}
+
+void mlx5_stop_health_poll(struct mlx5_core_dev *dev)
+{
+       struct mlx5_core_health *health = &dev->priv.health;
+
+       del_timer_sync(&health->timer);
+
+       spin_lock_irq(&health_lock);
+       if (!list_empty(&health->list))
+               list_del_init(&health->list);
+       spin_unlock_irq(&health_lock);
+}
+
+void mlx5_health_cleanup(void)
+{
+}
+
+void  __init mlx5_health_init(void)
+{
+       INIT_WORK(&health_work, health_care);
+}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/mad.c b/drivers/net/ethernet/mellanox/mlx5/core/mad.c
new file mode 100644 (file)
index 0000000..18d6fd5
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2013, Mellanox Technologies inc.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mlx5/driver.h>
+#include <linux/mlx5/cmd.h>
+#include "mlx5_core.h"
+
+int mlx5_core_mad_ifc(struct mlx5_core_dev *dev, void *inb, void *outb,
+                     u16 opmod, int port)
+{
+       struct mlx5_mad_ifc_mbox_in *in = NULL;
+       struct mlx5_mad_ifc_mbox_out *out = NULL;
+       int err;
+
+       in = kzalloc(sizeof(*in), GFP_KERNEL);
+       if (!in)
+               return -ENOMEM;
+
+       out = kzalloc(sizeof(*out), GFP_KERNEL);
+       if (!out) {
+               err = -ENOMEM;
+               goto out;
+       }
+
+       in->hdr.opcode = cpu_to_be16(MLX5_CMD_OP_MAD_IFC);
+       in->hdr.opmod = cpu_to_be16(opmod);
+       in->port = port;
+
+       memcpy(in->data, inb, sizeof(in->data));
+
+       err = mlx5_cmd_exec(dev, in, sizeof(*in), out, sizeof(*out));
+       if (err)
+               goto out;
+
+       if (out->hdr.status) {
+               err = mlx5_cmd_status_to_err(&out->hdr);
+               goto out;
+       }
+
+       memcpy(outb, out->data, sizeof(out->data));
+
+out:
+       kfree(out);
+       kfree(in);
+       return err;
+}
+EXPORT_SYMBOL_GPL(mlx5_core_mad_ifc);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c
new file mode 100644 (file)
index 0000000..12242de
--- /dev/null
@@ -0,0 +1,475 @@
+/*
+ * Copyright (c) 2013, Mellanox Technologies inc.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <asm-generic/kmap_types.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <linux/io-mapping.h>
+#include <linux/mlx5/driver.h>
+#include <linux/mlx5/cq.h>
+#include <linux/mlx5/qp.h>
+#include <linux/mlx5/srq.h>
+#include <linux/debugfs.h>
+#include "mlx5_core.h"
+
+#define DRIVER_NAME "mlx5_core"
+#define DRIVER_VERSION "1.0"
+#define DRIVER_RELDATE "June 2013"
+
+MODULE_AUTHOR("Eli Cohen <eli@mellanox.com>");
+MODULE_DESCRIPTION("Mellanox ConnectX-IB HCA core library");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_VERSION(DRIVER_VERSION);
+
+int mlx5_core_debug_mask;
+module_param_named(debug_mask, mlx5_core_debug_mask, int, 0644);
+MODULE_PARM_DESC(debug_mask, "debug mask: 1 = dump cmd data, 2 = dump cmd exec time, 3 = both. Default=0");
+
+struct workqueue_struct *mlx5_core_wq;
+
+static int set_dma_caps(struct pci_dev *pdev)
+{
+       int err;
+
+       err = pci_set_dma_mask(pdev, DMA_BIT_MASK(64));
+       if (err) {
+               dev_warn(&pdev->dev, "Warning: couldn't set 64-bit PCI DMA mask.\n");
+               err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+               if (err) {
+                       dev_err(&pdev->dev, "Can't set PCI DMA mask, aborting.\n");
+                       return err;
+               }
+       }
+
+       err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
+       if (err) {
+               dev_warn(&pdev->dev,
+                        "Warning: couldn't set 64-bit consistent PCI DMA mask.\n");
+               err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
+               if (err) {
+                       dev_err(&pdev->dev,
+                               "Can't set consistent PCI DMA mask, aborting.\n");
+                       return err;
+               }
+       }
+
+       dma_set_max_seg_size(&pdev->dev, 2u * 1024 * 1024 * 1024);
+       return err;
+}
+
+static int request_bar(struct pci_dev *pdev)
+{
+       int err = 0;
+
+       if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
+               dev_err(&pdev->dev, "Missing registers BAR, aborting.\n");
+               return -ENODEV;
+       }
+
+       err = pci_request_regions(pdev, DRIVER_NAME);
+       if (err)
+               dev_err(&pdev->dev, "Couldn't get PCI resources, aborting\n");
+
+       return err;
+}
+
+static void release_bar(struct pci_dev *pdev)
+{
+       pci_release_regions(pdev);
+}
+
+static int mlx5_enable_msix(struct mlx5_core_dev *dev)
+{
+       struct mlx5_eq_table *table = &dev->priv.eq_table;
+       int num_eqs = 1 << dev->caps.log_max_eq;
+       int nvec;
+       int err;
+       int i;
+
+       nvec = dev->caps.num_ports * num_online_cpus() + MLX5_EQ_VEC_COMP_BASE;
+       nvec = min_t(int, nvec, num_eqs);
+       if (nvec <= MLX5_EQ_VEC_COMP_BASE)
+               return -ENOMEM;
+
+       table->msix_arr = kzalloc(nvec * sizeof(*table->msix_arr), GFP_KERNEL);
+       if (!table->msix_arr)
+               return -ENOMEM;
+
+       for (i = 0; i < nvec; i++)
+               table->msix_arr[i].entry = i;
+
+retry:
+       table->num_comp_vectors = nvec - MLX5_EQ_VEC_COMP_BASE;
+       err = pci_enable_msix(dev->pdev, table->msix_arr, nvec);
+       if (err <= 0) {
+               return err;
+       } else if (err > 2) {
+               nvec = err;
+               goto retry;
+       }
+
+       mlx5_core_dbg(dev, "received %d MSI vectors out of %d requested\n", err, nvec);
+
+       return 0;
+}
+
+static void mlx5_disable_msix(struct mlx5_core_dev *dev)
+{
+       struct mlx5_eq_table *table = &dev->priv.eq_table;
+
+       pci_disable_msix(dev->pdev);
+       kfree(table->msix_arr);
+}
+
+struct mlx5_reg_host_endianess {
+       u8      he;
+       u8      rsvd[15];
+};
+
+static int handle_hca_cap(struct mlx5_core_dev *dev)
+{
+       struct mlx5_cmd_query_hca_cap_mbox_out *query_out = NULL;
+       struct mlx5_cmd_set_hca_cap_mbox_in *set_ctx = NULL;
+       struct mlx5_cmd_query_hca_cap_mbox_in query_ctx;
+       struct mlx5_cmd_set_hca_cap_mbox_out set_out;
+       struct mlx5_profile *prof = dev->profile;
+       u64 flags;
+       int csum = 1;
+       int err;
+
+       memset(&query_ctx, 0, sizeof(query_ctx));
+       query_out = kzalloc(sizeof(*query_out), GFP_KERNEL);
+       if (!query_out)
+               return -ENOMEM;
+
+       set_ctx = kzalloc(sizeof(*set_ctx), GFP_KERNEL);
+       if (!set_ctx) {
+               err = -ENOMEM;
+               goto query_ex;
+       }
+
+       query_ctx.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_QUERY_HCA_CAP);
+       query_ctx.hdr.opmod  = cpu_to_be16(0x1);
+       err = mlx5_cmd_exec(dev, &query_ctx, sizeof(query_ctx),
+                                query_out, sizeof(*query_out));
+       if (err)
+               goto query_ex;
+
+       err = mlx5_cmd_status_to_err(&query_out->hdr);
+       if (err) {
+               mlx5_core_warn(dev, "query hca cap failed, %d\n", err);
+               goto query_ex;
+       }
+
+       memcpy(&set_ctx->hca_cap, &query_out->hca_cap,
+              sizeof(set_ctx->hca_cap));
+
+       if (prof->mask & MLX5_PROF_MASK_CMDIF_CSUM) {
+               csum = !!prof->cmdif_csum;
+               flags = be64_to_cpu(set_ctx->hca_cap.flags);
+               if (csum)
+                       flags |= MLX5_DEV_CAP_FLAG_CMDIF_CSUM;
+               else
+                       flags &= ~MLX5_DEV_CAP_FLAG_CMDIF_CSUM;
+
+               set_ctx->hca_cap.flags = cpu_to_be64(flags);
+       }
+
+       if (dev->profile->mask & MLX5_PROF_MASK_QP_SIZE)
+               set_ctx->hca_cap.log_max_qp = dev->profile->log_max_qp;
+
+       memset(&set_out, 0, sizeof(set_out));
+       set_ctx->hca_cap.log_uar_page_sz = cpu_to_be16(PAGE_SHIFT - 12);
+       set_ctx->hdr.opcode = cpu_to_be16(MLX5_CMD_OP_SET_HCA_CAP);
+       err = mlx5_cmd_exec(dev, set_ctx, sizeof(*set_ctx),
+                                &set_out, sizeof(set_out));
+       if (err) {
+               mlx5_core_warn(dev, "set hca cap failed, %d\n", err);
+               goto query_ex;
+       }
+
+       err = mlx5_cmd_status_to_err(&set_out.hdr);
+       if (err)
+               goto query_ex;
+
+       if (!csum)
+               dev->cmd.checksum_disabled = 1;
+
+query_ex:
+       kfree(query_out);
+       kfree(set_ctx);
+
+       return err;
+}
+
+static int set_hca_ctrl(struct mlx5_core_dev *dev)
+{
+       struct mlx5_reg_host_endianess he_in;
+       struct mlx5_reg_host_endianess he_out;
+       int err;
+
+       memset(&he_in, 0, sizeof(he_in));
+       he_in.he = MLX5_SET_HOST_ENDIANNESS;
+       err = mlx5_core_access_reg(dev, &he_in,  sizeof(he_in),
+                                       &he_out, sizeof(he_out),
+                                       MLX5_REG_HOST_ENDIANNESS, 0, 1);
+       return err;
+}
+
+int mlx5_dev_init(struct mlx5_core_dev *dev, struct pci_dev *pdev)
+{
+       struct mlx5_priv *priv = &dev->priv;
+       int err;
+
+       dev->pdev = pdev;
+       pci_set_drvdata(dev->pdev, dev);
+       strncpy(priv->name, dev_name(&pdev->dev), MLX5_MAX_NAME_LEN);
+       priv->name[MLX5_MAX_NAME_LEN - 1] = 0;
+
+       mutex_init(&priv->pgdir_mutex);
+       INIT_LIST_HEAD(&priv->pgdir_list);
+       spin_lock_init(&priv->mkey_lock);
+
+       priv->dbg_root = debugfs_create_dir(dev_name(&pdev->dev), mlx5_debugfs_root);
+       if (!priv->dbg_root)
+               return -ENOMEM;
+
+       err = pci_enable_device(pdev);
+       if (err) {
+               dev_err(&pdev->dev, "Cannot enable PCI device, aborting.\n");
+               goto err_dbg;
+       }
+
+       err = request_bar(pdev);
+       if (err) {
+               dev_err(&pdev->dev, "error requesting BARs, aborting.\n");
+               goto err_disable;
+       }
+
+       pci_set_master(pdev);
+
+       err = set_dma_caps(pdev);
+       if (err) {
+               dev_err(&pdev->dev, "Failed setting DMA capabilities mask, aborting\n");
+               goto err_clr_master;
+       }
+
+       dev->iseg_base = pci_resource_start(dev->pdev, 0);
+       dev->iseg = ioremap(dev->iseg_base, sizeof(*dev->iseg));
+       if (!dev->iseg) {
+               err = -ENOMEM;
+               dev_err(&pdev->dev, "Failed mapping initialization segment, aborting\n");
+               goto err_clr_master;
+       }
+       dev_info(&pdev->dev, "firmware version: %d.%d.%d\n", fw_rev_maj(dev),
+                fw_rev_min(dev), fw_rev_sub(dev));
+
+       err = mlx5_cmd_init(dev);
+       if (err) {
+               dev_err(&pdev->dev, "Failed initializing command interface, aborting\n");
+               goto err_unmap;
+       }
+
+       mlx5_pagealloc_init(dev);
+       err = set_hca_ctrl(dev);
+       if (err) {
+               dev_err(&pdev->dev, "set_hca_ctrl failed\n");
+               goto err_pagealloc_cleanup;
+       }
+
+       err = handle_hca_cap(dev);
+       if (err) {
+               dev_err(&pdev->dev, "handle_hca_cap failed\n");
+               goto err_pagealloc_cleanup;
+       }
+
+       err = mlx5_satisfy_startup_pages(dev);
+       if (err) {
+               dev_err(&pdev->dev, "failed to allocate startup pages\n");
+               goto err_pagealloc_cleanup;
+       }
+
+       err = mlx5_pagealloc_start(dev);
+       if (err) {
+               dev_err(&pdev->dev, "mlx5_pagealloc_start failed\n");
+               goto err_reclaim_pages;
+       }
+
+       err = mlx5_cmd_init_hca(dev);
+       if (err) {
+               dev_err(&pdev->dev, "init hca failed\n");
+               goto err_pagealloc_stop;
+       }
+
+       mlx5_start_health_poll(dev);
+
+       err = mlx5_cmd_query_hca_cap(dev, &dev->caps);
+       if (err) {
+               dev_err(&pdev->dev, "query hca failed\n");
+               goto err_stop_poll;
+       }
+
+       err = mlx5_cmd_query_adapter(dev);
+       if (err) {
+               dev_err(&pdev->dev, "query adapter failed\n");
+               goto err_stop_poll;
+       }
+
+       err = mlx5_enable_msix(dev);
+       if (err) {
+               dev_err(&pdev->dev, "enable msix failed\n");
+               goto err_stop_poll;
+       }
+
+       err = mlx5_eq_init(dev);
+       if (err) {
+               dev_err(&pdev->dev, "failed to initialize eq\n");
+               goto disable_msix;
+       }
+
+       err = mlx5_alloc_uuars(dev, &priv->uuari);
+       if (err) {
+               dev_err(&pdev->dev, "Failed allocating uar, aborting\n");
+               goto err_eq_cleanup;
+       }
+
+       err = mlx5_start_eqs(dev);
+       if (err) {
+               dev_err(&pdev->dev, "Failed to start pages and async EQs\n");
+               goto err_free_uar;
+       }
+
+       MLX5_INIT_DOORBELL_LOCK(&priv->cq_uar_lock);
+
+       mlx5_init_cq_table(dev);
+       mlx5_init_qp_table(dev);
+       mlx5_init_srq_table(dev);
+
+       return 0;
+
+err_free_uar:
+       mlx5_free_uuars(dev, &priv->uuari);
+
+err_eq_cleanup:
+       mlx5_eq_cleanup(dev);
+
+disable_msix:
+       mlx5_disable_msix(dev);
+
+err_stop_poll:
+       mlx5_stop_health_poll(dev);
+       mlx5_cmd_teardown_hca(dev);
+
+err_pagealloc_stop:
+       mlx5_pagealloc_stop(dev);
+
+err_reclaim_pages:
+       mlx5_reclaim_startup_pages(dev);
+
+err_pagealloc_cleanup:
+       mlx5_pagealloc_cleanup(dev);
+       mlx5_cmd_cleanup(dev);
+
+err_unmap:
+       iounmap(dev->iseg);
+
+err_clr_master:
+       pci_clear_master(dev->pdev);
+       release_bar(dev->pdev);
+
+err_disable:
+       pci_disable_device(dev->pdev);
+
+err_dbg:
+       debugfs_remove(priv->dbg_root);
+       return err;
+}
+EXPORT_SYMBOL(mlx5_dev_init);
+
+void mlx5_dev_cleanup(struct mlx5_core_dev *dev)
+{
+       struct mlx5_priv *priv = &dev->priv;
+
+       mlx5_cleanup_srq_table(dev);
+       mlx5_cleanup_qp_table(dev);
+       mlx5_cleanup_cq_table(dev);
+       mlx5_stop_eqs(dev);
+       mlx5_free_uuars(dev, &priv->uuari);
+       mlx5_eq_cleanup(dev);
+       mlx5_disable_msix(dev);
+       mlx5_stop_health_poll(dev);
+       mlx5_cmd_teardown_hca(dev);
+       mlx5_pagealloc_stop(dev);
+       mlx5_reclaim_startup_pages(dev);
+       mlx5_pagealloc_cleanup(dev);
+       mlx5_cmd_cleanup(dev);
+       iounmap(dev->iseg);
+       pci_clear_master(dev->pdev);
+       release_bar(dev->pdev);
+       pci_disable_device(dev->pdev);
+       debugfs_remove(priv->dbg_root);
+}
+EXPORT_SYMBOL(mlx5_dev_cleanup);
+
+static int __init init(void)
+{
+       int err;
+
+       mlx5_register_debugfs();
+       mlx5_core_wq = create_singlethread_workqueue("mlx5_core_wq");
+       if (!mlx5_core_wq) {
+               err = -ENOMEM;
+               goto err_debug;
+       }
+       mlx5_health_init();
+
+       return 0;
+
+       mlx5_health_cleanup();
+err_debug:
+       mlx5_unregister_debugfs();
+       return err;
+}
+
+static void __exit cleanup(void)
+{
+       mlx5_health_cleanup();
+       destroy_workqueue(mlx5_core_wq);
+       mlx5_unregister_debugfs();
+}
+
+module_init(init);
+module_exit(cleanup);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/mcg.c b/drivers/net/ethernet/mellanox/mlx5/core/mcg.c
new file mode 100644 (file)
index 0000000..4483764
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2013, Mellanox Technologies inc.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mlx5/driver.h>
+#include <linux/mlx5/cmd.h>
+#include <rdma/ib_verbs.h>
+#include "mlx5_core.h"
+
+struct mlx5_attach_mcg_mbox_in {
+       struct mlx5_inbox_hdr   hdr;
+       __be32                  qpn;
+       __be32                  rsvd;
+       u8                      gid[16];
+};
+
+struct mlx5_attach_mcg_mbox_out {
+       struct mlx5_outbox_hdr  hdr;
+       u8                      rsvf[8];
+};
+
+struct mlx5_detach_mcg_mbox_in {
+       struct mlx5_inbox_hdr   hdr;
+       __be32                  qpn;
+       __be32                  rsvd;
+       u8                      gid[16];
+};
+
+struct mlx5_detach_mcg_mbox_out {
+       struct mlx5_outbox_hdr  hdr;
+       u8                      rsvf[8];
+};
+
+int mlx5_core_attach_mcg(struct mlx5_core_dev *dev, union ib_gid *mgid, u32 qpn)
+{
+       struct mlx5_attach_mcg_mbox_in in;
+       struct mlx5_attach_mcg_mbox_out out;
+       int err;
+
+       memset(&in, 0, sizeof(in));
+       memset(&out, 0, sizeof(out));
+       in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_ATTACH_TO_MCG);
+       memcpy(in.gid, mgid, sizeof(*mgid));
+       in.qpn = cpu_to_be32(qpn);
+       err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out));
+       if (err)
+               return err;
+
+       if (out.hdr.status)
+               err = mlx5_cmd_status_to_err(&out.hdr);
+
+       return err;
+}
+EXPORT_SYMBOL(mlx5_core_attach_mcg);
+
+int mlx5_core_detach_mcg(struct mlx5_core_dev *dev, union ib_gid *mgid, u32 qpn)
+{
+       struct mlx5_detach_mcg_mbox_in in;
+       struct mlx5_detach_mcg_mbox_out out;
+       int err;
+
+       memset(&in, 0, sizeof(in));
+       memset(&out, 0, sizeof(out));
+       in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_DETACH_FROM_MCG);
+       memcpy(in.gid, mgid, sizeof(*mgid));
+       in.qpn = cpu_to_be32(qpn);
+       err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out));
+       if (err)
+               return err;
+
+       if (out.hdr.status)
+               err = mlx5_cmd_status_to_err(&out.hdr);
+
+       return err;
+}
+EXPORT_SYMBOL(mlx5_core_detach_mcg);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
new file mode 100644 (file)
index 0000000..68b74e1
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2013, Mellanox Technologies inc.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef __MLX5_CORE_H__
+#define __MLX5_CORE_H__
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+
+extern int mlx5_core_debug_mask;
+
+#define mlx5_core_dbg(dev, format, arg...)                                    \
+pr_debug("%s:%s:%d:(pid %d): " format, (dev)->priv.name, __func__, __LINE__,   \
+        current->pid, ##arg)
+
+#define mlx5_core_dbg_mask(dev, mask, format, arg...)                         \
+do {                                                                          \
+       if ((mask) & mlx5_core_debug_mask)                                     \
+               pr_debug("%s:%s:%d:(pid %d): " format, (dev)->priv.name,       \
+                        __func__, __LINE__, current->pid, ##arg);             \
+} while (0)
+
+#define mlx5_core_err(dev, format, arg...) \
+pr_err("%s:%s:%d:(pid %d): " format, (dev)->priv.name, __func__, __LINE__,     \
+       current->pid, ##arg)
+
+#define mlx5_core_warn(dev, format, arg...) \
+pr_warn("%s:%s:%d:(pid %d): " format, (dev)->priv.name, __func__, __LINE__,    \
+       current->pid, ##arg)
+
+enum {
+       MLX5_CMD_DATA, /* print command payload only */
+       MLX5_CMD_TIME, /* print command execution time */
+};
+
+
+int mlx5_cmd_query_hca_cap(struct mlx5_core_dev *dev,
+                          struct mlx5_caps *caps);
+int mlx5_cmd_query_adapter(struct mlx5_core_dev *dev);
+int mlx5_cmd_init_hca(struct mlx5_core_dev *dev);
+int mlx5_cmd_teardown_hca(struct mlx5_core_dev *dev);
+
+#endif /* __MLX5_CORE_H__ */
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/mr.c b/drivers/net/ethernet/mellanox/mlx5/core/mr.c
new file mode 100644 (file)
index 0000000..5b44e2e
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2013, Mellanox Technologies inc.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mlx5/driver.h>
+#include <linux/mlx5/cmd.h>
+#include "mlx5_core.h"
+
+int mlx5_core_create_mkey(struct mlx5_core_dev *dev, struct mlx5_core_mr *mr,
+                         struct mlx5_create_mkey_mbox_in *in, int inlen)
+{
+       struct mlx5_create_mkey_mbox_out out;
+       int err;
+       u8 key;
+
+       memset(&out, 0, sizeof(out));
+       spin_lock(&dev->priv.mkey_lock);
+       key = dev->priv.mkey_key++;
+       spin_unlock(&dev->priv.mkey_lock);
+       in->seg.qpn_mkey7_0 |= cpu_to_be32(key);
+       in->hdr.opcode = cpu_to_be16(MLX5_CMD_OP_CREATE_MKEY);
+       err = mlx5_cmd_exec(dev, in, inlen, &out, sizeof(out));
+       if (err) {
+               mlx5_core_dbg(dev, "cmd exec faile %d\n", err);
+               return err;
+       }
+
+       if (out.hdr.status) {
+               mlx5_core_dbg(dev, "status %d\n", out.hdr.status);
+               return mlx5_cmd_status_to_err(&out.hdr);
+       }
+
+       mr->key = mlx5_idx_to_mkey(be32_to_cpu(out.mkey) & 0xffffff) | key;
+       mlx5_core_dbg(dev, "out 0x%x, key 0x%x, mkey 0x%x\n", be32_to_cpu(out.mkey), key, mr->key);
+
+       return err;
+}
+EXPORT_SYMBOL(mlx5_core_create_mkey);
+
+int mlx5_core_destroy_mkey(struct mlx5_core_dev *dev, struct mlx5_core_mr *mr)
+{
+       struct mlx5_destroy_mkey_mbox_in in;
+       struct mlx5_destroy_mkey_mbox_out out;
+       int err;
+
+       memset(&in, 0, sizeof(in));
+       memset(&out, 0, sizeof(out));
+
+       in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_DESTROY_MKEY);
+       in.mkey = cpu_to_be32(mlx5_mkey_to_idx(mr->key));
+       err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out));
+       if (err)
+               return err;
+
+       if (out.hdr.status)
+               return mlx5_cmd_status_to_err(&out.hdr);
+
+       return err;
+}
+EXPORT_SYMBOL(mlx5_core_destroy_mkey);
+
+int mlx5_core_query_mkey(struct mlx5_core_dev *dev, struct mlx5_core_mr *mr,
+                        struct mlx5_query_mkey_mbox_out *out, int outlen)
+{
+       struct mlx5_destroy_mkey_mbox_in in;
+       int err;
+
+       memset(&in, 0, sizeof(in));
+       memset(out, 0, outlen);
+
+       in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_QUERY_MKEY);
+       in.mkey = cpu_to_be32(mlx5_mkey_to_idx(mr->key));
+       err = mlx5_cmd_exec(dev, &in, sizeof(in), out, outlen);
+       if (err)
+               return err;
+
+       if (out->hdr.status)
+               return mlx5_cmd_status_to_err(&out->hdr);
+
+       return err;
+}
+EXPORT_SYMBOL(mlx5_core_query_mkey);
+
+int mlx5_core_dump_fill_mkey(struct mlx5_core_dev *dev, struct mlx5_core_mr *mr,
+                            u32 *mkey)
+{
+       struct mlx5_query_special_ctxs_mbox_in in;
+       struct mlx5_query_special_ctxs_mbox_out out;
+       int err;
+
+       memset(&in, 0, sizeof(in));
+       memset(&out, 0, sizeof(out));
+
+       in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_QUERY_SPECIAL_CONTEXTS);
+       err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out));
+       if (err)
+               return err;
+
+       if (out.hdr.status)
+               return mlx5_cmd_status_to_err(&out.hdr);
+
+       *mkey = be32_to_cpu(out.dump_fill_mkey);
+
+       return err;
+}
+EXPORT_SYMBOL(mlx5_core_dump_fill_mkey);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c b/drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c
new file mode 100644 (file)
index 0000000..f0bf463
--- /dev/null
@@ -0,0 +1,435 @@
+/*
+ * Copyright (c) 2013, Mellanox Technologies inc.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <asm-generic/kmap_types.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mlx5/driver.h>
+#include <linux/mlx5/cmd.h>
+#include "mlx5_core.h"
+
+enum {
+       MLX5_PAGES_CANT_GIVE    = 0,
+       MLX5_PAGES_GIVE         = 1,
+       MLX5_PAGES_TAKE         = 2
+};
+
+struct mlx5_pages_req {
+       struct mlx5_core_dev *dev;
+       u32     func_id;
+       s16     npages;
+       struct work_struct work;
+};
+
+struct fw_page {
+       struct rb_node  rb_node;
+       u64             addr;
+       struct page     *page;
+       u16             func_id;
+};
+
+struct mlx5_query_pages_inbox {
+       struct mlx5_inbox_hdr   hdr;
+       u8                      rsvd[8];
+};
+
+struct mlx5_query_pages_outbox {
+       struct mlx5_outbox_hdr  hdr;
+       u8                      reserved[2];
+       __be16                  func_id;
+       __be16                  init_pages;
+       __be16                  num_pages;
+};
+
+struct mlx5_manage_pages_inbox {
+       struct mlx5_inbox_hdr   hdr;
+       __be16                  rsvd0;
+       __be16                  func_id;
+       __be16                  rsvd1;
+       __be16                  num_entries;
+       u8                      rsvd2[16];
+       __be64                  pas[0];
+};
+
+struct mlx5_manage_pages_outbox {
+       struct mlx5_outbox_hdr  hdr;
+       u8                      rsvd0[2];
+       __be16                  num_entries;
+       u8                      rsvd1[20];
+       __be64                  pas[0];
+};
+
+static int insert_page(struct mlx5_core_dev *dev, u64 addr, struct page *page, u16 func_id)
+{
+       struct rb_root *root = &dev->priv.page_root;
+       struct rb_node **new = &root->rb_node;
+       struct rb_node *parent = NULL;
+       struct fw_page *nfp;
+       struct fw_page *tfp;
+
+       while (*new) {
+               parent = *new;
+               tfp = rb_entry(parent, struct fw_page, rb_node);
+               if (tfp->addr < addr)
+                       new = &parent->rb_left;
+               else if (tfp->addr > addr)
+                       new = &parent->rb_right;
+               else
+                       return -EEXIST;
+       }
+
+       nfp = kmalloc(sizeof(*nfp), GFP_KERNEL);
+       if (!nfp)
+               return -ENOMEM;
+
+       nfp->addr = addr;
+       nfp->page = page;
+       nfp->func_id = func_id;
+
+       rb_link_node(&nfp->rb_node, parent, new);
+       rb_insert_color(&nfp->rb_node, root);
+
+       return 0;
+}
+
+static struct page *remove_page(struct mlx5_core_dev *dev, u64 addr)
+{
+       struct rb_root *root = &dev->priv.page_root;
+       struct rb_node *tmp = root->rb_node;
+       struct page *result = NULL;
+       struct fw_page *tfp;
+
+       while (tmp) {
+               tfp = rb_entry(tmp, struct fw_page, rb_node);
+               if (tfp->addr < addr) {
+                       tmp = tmp->rb_left;
+               } else if (tfp->addr > addr) {
+                       tmp = tmp->rb_right;
+               } else {
+                       rb_erase(&tfp->rb_node, root);
+                       result = tfp->page;
+                       kfree(tfp);
+                       break;
+               }
+       }
+
+       return result;
+}
+
+static int mlx5_cmd_query_pages(struct mlx5_core_dev *dev, u16 *func_id,
+                               s16 *pages, s16 *init_pages)
+{
+       struct mlx5_query_pages_inbox   in;
+       struct mlx5_query_pages_outbox  out;
+       int err;
+
+       memset(&in, 0, sizeof(in));
+       memset(&out, 0, sizeof(out));
+       in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_QUERY_PAGES);
+       err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out));
+       if (err)
+               return err;
+
+       if (out.hdr.status)
+               return mlx5_cmd_status_to_err(&out.hdr);
+
+       if (pages)
+               *pages = be16_to_cpu(out.num_pages);
+       if (init_pages)
+               *init_pages = be16_to_cpu(out.init_pages);
+       *func_id = be16_to_cpu(out.func_id);
+
+       return err;
+}
+
+static int give_pages(struct mlx5_core_dev *dev, u16 func_id, int npages,
+                     int notify_fail)
+{
+       struct mlx5_manage_pages_inbox *in;
+       struct mlx5_manage_pages_outbox out;
+       struct page *page;
+       int inlen;
+       u64 addr;
+       int err;
+       int i;
+
+       inlen = sizeof(*in) + npages * sizeof(in->pas[0]);
+       in = mlx5_vzalloc(inlen);
+       if (!in) {
+               mlx5_core_warn(dev, "vzalloc failed %d\n", inlen);
+               return -ENOMEM;
+       }
+       memset(&out, 0, sizeof(out));
+
+       for (i = 0; i < npages; i++) {
+               page = alloc_page(GFP_HIGHUSER);
+               if (!page) {
+                       err = -ENOMEM;
+                       mlx5_core_warn(dev, "failed to allocate page\n");
+                       goto out_alloc;
+               }
+               addr = dma_map_page(&dev->pdev->dev, page, 0,
+                                   PAGE_SIZE, DMA_BIDIRECTIONAL);
+               if (dma_mapping_error(&dev->pdev->dev, addr)) {
+                       mlx5_core_warn(dev, "failed dma mapping page\n");
+                       __free_page(page);
+                       err = -ENOMEM;
+                       goto out_alloc;
+               }
+               err = insert_page(dev, addr, page, func_id);
+               if (err) {
+                       mlx5_core_err(dev, "failed to track allocated page\n");
+                       dma_unmap_page(&dev->pdev->dev, addr, PAGE_SIZE, DMA_BIDIRECTIONAL);
+                       __free_page(page);
+                       err = -ENOMEM;
+                       goto out_alloc;
+               }
+               in->pas[i] = cpu_to_be64(addr);
+       }
+
+       in->hdr.opcode = cpu_to_be16(MLX5_CMD_OP_MANAGE_PAGES);
+       in->hdr.opmod = cpu_to_be16(MLX5_PAGES_GIVE);
+       in->func_id = cpu_to_be16(func_id);
+       in->num_entries = cpu_to_be16(npages);
+       err = mlx5_cmd_exec(dev, in, inlen, &out, sizeof(out));
+       mlx5_core_dbg(dev, "err %d\n", err);
+       if (err) {
+               mlx5_core_warn(dev, "func_id 0x%x, npages %d, err %d\n", func_id, npages, err);
+               goto out_alloc;
+       }
+       dev->priv.fw_pages += npages;
+
+       if (out.hdr.status) {
+               err = mlx5_cmd_status_to_err(&out.hdr);
+               if (err) {
+                       mlx5_core_warn(dev, "func_id 0x%x, npages %d, status %d\n", func_id, npages, out.hdr.status);
+                       goto out_alloc;
+               }
+       }
+
+       mlx5_core_dbg(dev, "err %d\n", err);
+
+       goto out_free;
+
+out_alloc:
+       if (notify_fail) {
+               memset(in, 0, inlen);
+               memset(&out, 0, sizeof(out));
+               in->hdr.opcode = cpu_to_be16(MLX5_CMD_OP_MANAGE_PAGES);
+               in->hdr.opmod = cpu_to_be16(MLX5_PAGES_CANT_GIVE);
+               if (mlx5_cmd_exec(dev, in, sizeof(*in), &out, sizeof(out)))
+                       mlx5_core_warn(dev, "\n");
+       }
+       for (i--; i >= 0; i--) {
+               addr = be64_to_cpu(in->pas[i]);
+               page = remove_page(dev, addr);
+               if (!page) {
+                       mlx5_core_err(dev, "BUG: can't remove page at addr 0x%llx\n",
+                                     addr);
+                       continue;
+               }
+               dma_unmap_page(&dev->pdev->dev, addr, PAGE_SIZE, DMA_BIDIRECTIONAL);
+               __free_page(page);
+       }
+
+out_free:
+       mlx5_vfree(in);
+       return err;
+}
+
+static int reclaim_pages(struct mlx5_core_dev *dev, u32 func_id, int npages,
+                        int *nclaimed)
+{
+       struct mlx5_manage_pages_inbox   in;
+       struct mlx5_manage_pages_outbox *out;
+       struct page *page;
+       int num_claimed;
+       int outlen;
+       u64 addr;
+       int err;
+       int i;
+
+       memset(&in, 0, sizeof(in));
+       outlen = sizeof(*out) + npages * sizeof(out->pas[0]);
+       out = mlx5_vzalloc(outlen);
+       if (!out)
+               return -ENOMEM;
+
+       in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_MANAGE_PAGES);
+       in.hdr.opmod = cpu_to_be16(MLX5_PAGES_TAKE);
+       in.func_id = cpu_to_be16(func_id);
+       in.num_entries = cpu_to_be16(npages);
+       mlx5_core_dbg(dev, "npages %d, outlen %d\n", npages, outlen);
+       err = mlx5_cmd_exec(dev, &in, sizeof(in), out, outlen);
+       if (err) {
+               mlx5_core_err(dev, "failed recliaming pages\n");
+               goto out_free;
+       }
+       dev->priv.fw_pages -= npages;
+
+       if (out->hdr.status) {
+               err = mlx5_cmd_status_to_err(&out->hdr);
+               goto out_free;
+       }
+
+       num_claimed = be16_to_cpu(out->num_entries);
+       if (nclaimed)
+               *nclaimed = num_claimed;
+
+       for (i = 0; i < num_claimed; i++) {
+               addr = be64_to_cpu(out->pas[i]);
+               page = remove_page(dev, addr);
+               if (!page) {
+                       mlx5_core_warn(dev, "FW reported unknown DMA address 0x%llx\n", addr);
+               } else {
+                       dma_unmap_page(&dev->pdev->dev, addr, PAGE_SIZE, DMA_BIDIRECTIONAL);
+                       __free_page(page);
+               }
+       }
+
+out_free:
+       mlx5_vfree(out);
+       return err;
+}
+
+static void pages_work_handler(struct work_struct *work)
+{
+       struct mlx5_pages_req *req = container_of(work, struct mlx5_pages_req, work);
+       struct mlx5_core_dev *dev = req->dev;
+       int err = 0;
+
+       if (req->npages < 0)
+               err = reclaim_pages(dev, req->func_id, -1 * req->npages, NULL);
+       else if (req->npages > 0)
+               err = give_pages(dev, req->func_id, req->npages, 1);
+
+       if (err)
+               mlx5_core_warn(dev, "%s fail %d\n", req->npages < 0 ?
+                              "reclaim" : "give", err);
+
+       kfree(req);
+}
+
+void mlx5_core_req_pages_handler(struct mlx5_core_dev *dev, u16 func_id,
+                                s16 npages)
+{
+       struct mlx5_pages_req *req;
+
+       req = kzalloc(sizeof(*req), GFP_ATOMIC);
+       if (!req) {
+               mlx5_core_warn(dev, "failed to allocate pages request\n");
+               return;
+       }
+
+       req->dev = dev;
+       req->func_id = func_id;
+       req->npages = npages;
+       INIT_WORK(&req->work, pages_work_handler);
+       queue_work(dev->priv.pg_wq, &req->work);
+}
+
+int mlx5_satisfy_startup_pages(struct mlx5_core_dev *dev)
+{
+       s16 uninitialized_var(init_pages);
+       u16 uninitialized_var(func_id);
+       int err;
+
+       err = mlx5_cmd_query_pages(dev, &func_id, NULL, &init_pages);
+       if (err)
+               return err;
+
+       mlx5_core_dbg(dev, "requested %d init pages for func_id 0x%x\n", init_pages, func_id);
+
+       return give_pages(dev, func_id, init_pages, 0);
+}
+
+static int optimal_reclaimed_pages(void)
+{
+       struct mlx5_cmd_prot_block *block;
+       struct mlx5_cmd_layout *lay;
+       int ret;
+
+       ret = (sizeof(lay->in) + sizeof(block->data) -
+              sizeof(struct mlx5_manage_pages_outbox)) / 8;
+
+       return ret;
+}
+
+int mlx5_reclaim_startup_pages(struct mlx5_core_dev *dev)
+{
+       unsigned long end = jiffies + msecs_to_jiffies(5000);
+       struct fw_page *fwp;
+       struct rb_node *p;
+       int err;
+
+       do {
+               p = rb_first(&dev->priv.page_root);
+               if (p) {
+                       fwp = rb_entry(p, struct fw_page, rb_node);
+                       err = reclaim_pages(dev, fwp->func_id, optimal_reclaimed_pages(), NULL);
+                       if (err) {
+                               mlx5_core_warn(dev, "failed reclaiming pages (%d)\n", err);
+                               return err;
+                       }
+               }
+               if (time_after(jiffies, end)) {
+                       mlx5_core_warn(dev, "FW did not return all pages. giving up...\n");
+                       break;
+               }
+       } while (p);
+
+       return 0;
+}
+
+void mlx5_pagealloc_init(struct mlx5_core_dev *dev)
+{
+       dev->priv.page_root = RB_ROOT;
+}
+
+void mlx5_pagealloc_cleanup(struct mlx5_core_dev *dev)
+{
+       /* nothing */
+}
+
+int mlx5_pagealloc_start(struct mlx5_core_dev *dev)
+{
+       dev->priv.pg_wq = create_singlethread_workqueue("mlx5_page_allocator");
+       if (!dev->priv.pg_wq)
+               return -ENOMEM;
+
+       return 0;
+}
+
+void mlx5_pagealloc_stop(struct mlx5_core_dev *dev)
+{
+       destroy_workqueue(dev->priv.pg_wq);
+}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/pd.c b/drivers/net/ethernet/mellanox/mlx5/core/pd.c
new file mode 100644 (file)
index 0000000..790da5c
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2013, Mellanox Technologies inc.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mlx5/driver.h>
+#include <linux/mlx5/cmd.h>
+#include "mlx5_core.h"
+
+struct mlx5_alloc_pd_mbox_in {
+       struct mlx5_inbox_hdr   hdr;
+       u8                      rsvd[8];
+};
+
+struct mlx5_alloc_pd_mbox_out {
+       struct mlx5_outbox_hdr  hdr;
+       __be32                  pdn;
+       u8                      rsvd[4];
+};
+
+struct mlx5_dealloc_pd_mbox_in {
+       struct mlx5_inbox_hdr   hdr;
+       __be32                  pdn;
+       u8                      rsvd[4];
+};
+
+struct mlx5_dealloc_pd_mbox_out {
+       struct mlx5_outbox_hdr  hdr;
+       u8                      rsvd[8];
+};
+
+int mlx5_core_alloc_pd(struct mlx5_core_dev *dev, u32 *pdn)
+{
+       struct mlx5_alloc_pd_mbox_in    in;
+       struct mlx5_alloc_pd_mbox_out   out;
+       int err;
+
+       memset(&in, 0, sizeof(in));
+       memset(&out, 0, sizeof(out));
+       in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_ALLOC_PD);
+       err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out));
+       if (err)
+               return err;
+
+       if (out.hdr.status)
+               return mlx5_cmd_status_to_err(&out.hdr);
+
+       *pdn = be32_to_cpu(out.pdn) & 0xffffff;
+       return err;
+}
+EXPORT_SYMBOL(mlx5_core_alloc_pd);
+
+int mlx5_core_dealloc_pd(struct mlx5_core_dev *dev, u32 pdn)
+{
+       struct mlx5_dealloc_pd_mbox_in  in;
+       struct mlx5_dealloc_pd_mbox_out out;
+       int err;
+
+       memset(&in, 0, sizeof(in));
+       memset(&out, 0, sizeof(out));
+       in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_DEALLOC_PD);
+       in.pdn = cpu_to_be32(pdn);
+       err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out));
+       if (err)
+               return err;
+
+       if (out.hdr.status)
+               return mlx5_cmd_status_to_err(&out.hdr);
+
+       return err;
+}
+EXPORT_SYMBOL(mlx5_core_dealloc_pd);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/port.c b/drivers/net/ethernet/mellanox/mlx5/core/port.c
new file mode 100644 (file)
index 0000000..f6afe7b
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2013, Mellanox Technologies inc.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/module.h>
+#include <linux/mlx5/driver.h>
+#include <linux/mlx5/cmd.h>
+#include "mlx5_core.h"
+
+int mlx5_core_access_reg(struct mlx5_core_dev *dev, void *data_in,
+                        int size_in, void *data_out, int size_out,
+                        u16 reg_num, int arg, int write)
+{
+       struct mlx5_access_reg_mbox_in *in = NULL;
+       struct mlx5_access_reg_mbox_out *out = NULL;
+       int err = -ENOMEM;
+
+       in = mlx5_vzalloc(sizeof(*in) + size_in);
+       if (!in)
+               return -ENOMEM;
+
+       out = mlx5_vzalloc(sizeof(*out) + size_out);
+       if (!out)
+               goto ex1;
+
+       memcpy(in->data, data_in, size_in);
+       in->hdr.opcode = cpu_to_be16(MLX5_CMD_OP_ACCESS_REG);
+       in->hdr.opmod = cpu_to_be16(!write);
+       in->arg = cpu_to_be32(arg);
+       in->register_id = cpu_to_be16(reg_num);
+       err = mlx5_cmd_exec(dev, in, sizeof(*in) + size_in, out,
+                           sizeof(out) + size_out);
+       if (err)
+               goto ex2;
+
+       if (out->hdr.status)
+               err = mlx5_cmd_status_to_err(&out->hdr);
+
+       if (!err)
+               memcpy(data_out, out->data, size_out);
+
+ex2:
+       mlx5_vfree(out);
+ex1:
+       mlx5_vfree(in);
+       return err;
+}
+EXPORT_SYMBOL_GPL(mlx5_core_access_reg);
+
+
+struct mlx5_reg_pcap {
+       u8                      rsvd0;
+       u8                      port_num;
+       u8                      rsvd1[2];
+       __be32                  caps_127_96;
+       __be32                  caps_95_64;
+       __be32                  caps_63_32;
+       __be32                  caps_31_0;
+};
+
+int mlx5_set_port_caps(struct mlx5_core_dev *dev, int port_num, u32 caps)
+{
+       struct mlx5_reg_pcap in;
+       struct mlx5_reg_pcap out;
+       int err;
+
+       memset(&in, 0, sizeof(in));
+       in.caps_127_96 = cpu_to_be32(caps);
+       in.port_num = port_num;
+
+       err = mlx5_core_access_reg(dev, &in, sizeof(in), &out,
+                                  sizeof(out), MLX5_REG_PCAP, 0, 1);
+
+       return err;
+}
+EXPORT_SYMBOL_GPL(mlx5_set_port_caps);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/qp.c b/drivers/net/ethernet/mellanox/mlx5/core/qp.c
new file mode 100644 (file)
index 0000000..54faf8b
--- /dev/null
@@ -0,0 +1,301 @@
+/*
+ * Copyright (c) 2013, Mellanox Technologies inc.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+
+#include <linux/gfp.h>
+#include <linux/export.h>
+#include <linux/mlx5/cmd.h>
+#include <linux/mlx5/qp.h>
+#include <linux/mlx5/driver.h>
+
+#include "mlx5_core.h"
+
+void mlx5_qp_event(struct mlx5_core_dev *dev, u32 qpn, int event_type)
+{
+       struct mlx5_qp_table *table = &dev->priv.qp_table;
+       struct mlx5_core_qp *qp;
+
+       spin_lock(&table->lock);
+
+       qp = radix_tree_lookup(&table->tree, qpn);
+       if (qp)
+               atomic_inc(&qp->refcount);
+
+       spin_unlock(&table->lock);
+
+       if (!qp) {
+               mlx5_core_warn(dev, "Async event for bogus QP 0x%x\n", qpn);
+               return;
+       }
+
+       qp->event(qp, event_type);
+
+       if (atomic_dec_and_test(&qp->refcount))
+               complete(&qp->free);
+}
+
+int mlx5_core_create_qp(struct mlx5_core_dev *dev,
+                       struct mlx5_core_qp *qp,
+                       struct mlx5_create_qp_mbox_in *in,
+                       int inlen)
+{
+       struct mlx5_qp_table *table = &dev->priv.qp_table;
+       struct mlx5_create_qp_mbox_out out;
+       struct mlx5_destroy_qp_mbox_in din;
+       struct mlx5_destroy_qp_mbox_out dout;
+       int err;
+
+       memset(&dout, 0, sizeof(dout));
+       in->hdr.opcode = cpu_to_be16(MLX5_CMD_OP_CREATE_QP);
+
+       err = mlx5_cmd_exec(dev, in, inlen, &out, sizeof(out));
+       if (err) {
+               mlx5_core_warn(dev, "ret %d", err);
+               return err;
+       }
+
+       if (out.hdr.status) {
+               pr_warn("current num of QPs 0x%x\n", atomic_read(&dev->num_qps));
+               return mlx5_cmd_status_to_err(&out.hdr);
+       }
+
+       qp->qpn = be32_to_cpu(out.qpn) & 0xffffff;
+       mlx5_core_dbg(dev, "qpn = 0x%x\n", qp->qpn);
+
+       spin_lock_irq(&table->lock);
+       err = radix_tree_insert(&table->tree, qp->qpn, qp);
+       spin_unlock_irq(&table->lock);
+       if (err) {
+               mlx5_core_warn(dev, "err %d", err);
+               goto err_cmd;
+       }
+
+       err = mlx5_debug_qp_add(dev, qp);
+       if (err)
+               mlx5_core_dbg(dev, "failed adding QP 0x%x to debug file system\n",
+                             qp->qpn);
+
+       qp->pid = current->pid;
+       atomic_set(&qp->refcount, 1);
+       atomic_inc(&dev->num_qps);
+       init_completion(&qp->free);
+
+       return 0;
+
+err_cmd:
+       memset(&din, 0, sizeof(din));
+       memset(&dout, 0, sizeof(dout));
+       din.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_DESTROY_QP);
+       din.qpn = cpu_to_be32(qp->qpn);
+       mlx5_cmd_exec(dev, &din, sizeof(din), &out, sizeof(dout));
+
+       return err;
+}
+EXPORT_SYMBOL_GPL(mlx5_core_create_qp);
+
+int mlx5_core_destroy_qp(struct mlx5_core_dev *dev,
+                        struct mlx5_core_qp *qp)
+{
+       struct mlx5_destroy_qp_mbox_in in;
+       struct mlx5_destroy_qp_mbox_out out;
+       struct mlx5_qp_table *table = &dev->priv.qp_table;
+       unsigned long flags;
+       int err;
+
+       mlx5_debug_qp_remove(dev, qp);
+
+       spin_lock_irqsave(&table->lock, flags);
+       radix_tree_delete(&table->tree, qp->qpn);
+       spin_unlock_irqrestore(&table->lock, flags);
+
+       if (atomic_dec_and_test(&qp->refcount))
+               complete(&qp->free);
+       wait_for_completion(&qp->free);
+
+       memset(&in, 0, sizeof(in));
+       memset(&out, 0, sizeof(out));
+       in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_DESTROY_QP);
+       in.qpn = cpu_to_be32(qp->qpn);
+       err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out));
+       if (err)
+               return err;
+
+       if (out.hdr.status)
+               return mlx5_cmd_status_to_err(&out.hdr);
+
+       atomic_dec(&dev->num_qps);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(mlx5_core_destroy_qp);
+
+int mlx5_core_qp_modify(struct mlx5_core_dev *dev, enum mlx5_qp_state cur_state,
+                       enum mlx5_qp_state new_state,
+                       struct mlx5_modify_qp_mbox_in *in, int sqd_event,
+                       struct mlx5_core_qp *qp)
+{
+       static const u16 optab[MLX5_QP_NUM_STATE][MLX5_QP_NUM_STATE] = {
+               [MLX5_QP_STATE_RST] = {
+                       [MLX5_QP_STATE_RST]     = MLX5_CMD_OP_2RST_QP,
+                       [MLX5_QP_STATE_ERR]     = MLX5_CMD_OP_2ERR_QP,
+                       [MLX5_QP_STATE_INIT]    = MLX5_CMD_OP_RST2INIT_QP,
+               },
+               [MLX5_QP_STATE_INIT]  = {
+                       [MLX5_QP_STATE_RST]     = MLX5_CMD_OP_2RST_QP,
+                       [MLX5_QP_STATE_ERR]     = MLX5_CMD_OP_2ERR_QP,
+                       [MLX5_QP_STATE_INIT]    = MLX5_CMD_OP_INIT2INIT_QP,
+                       [MLX5_QP_STATE_RTR]     = MLX5_CMD_OP_INIT2RTR_QP,
+               },
+               [MLX5_QP_STATE_RTR]   = {
+                       [MLX5_QP_STATE_RST]     = MLX5_CMD_OP_2RST_QP,
+                       [MLX5_QP_STATE_ERR]     = MLX5_CMD_OP_2ERR_QP,
+                       [MLX5_QP_STATE_RTS]     = MLX5_CMD_OP_RTR2RTS_QP,
+               },
+               [MLX5_QP_STATE_RTS]   = {
+                       [MLX5_QP_STATE_RST]     = MLX5_CMD_OP_2RST_QP,
+                       [MLX5_QP_STATE_ERR]     = MLX5_CMD_OP_2ERR_QP,
+                       [MLX5_QP_STATE_RTS]     = MLX5_CMD_OP_RTS2RTS_QP,
+                       [MLX5_QP_STATE_SQD]     = MLX5_CMD_OP_RTS2SQD_QP,
+               },
+               [MLX5_QP_STATE_SQD] = {
+                       [MLX5_QP_STATE_RST]     = MLX5_CMD_OP_2RST_QP,
+                       [MLX5_QP_STATE_ERR]     = MLX5_CMD_OP_2ERR_QP,
+                       [MLX5_QP_STATE_RTS]     = MLX5_CMD_OP_SQD2RTS_QP,
+                       [MLX5_QP_STATE_SQD]     = MLX5_CMD_OP_SQD2SQD_QP,
+               },
+               [MLX5_QP_STATE_SQER] = {
+                       [MLX5_QP_STATE_RST]     = MLX5_CMD_OP_2RST_QP,
+                       [MLX5_QP_STATE_ERR]     = MLX5_CMD_OP_2ERR_QP,
+                       [MLX5_QP_STATE_RTS]     = MLX5_CMD_OP_SQERR2RTS_QP,
+               },
+               [MLX5_QP_STATE_ERR] = {
+                       [MLX5_QP_STATE_RST]     = MLX5_CMD_OP_2RST_QP,
+                       [MLX5_QP_STATE_ERR]     = MLX5_CMD_OP_2ERR_QP,
+               }
+       };
+
+       struct mlx5_modify_qp_mbox_out out;
+       int err = 0;
+       u16 op;
+
+       if (cur_state >= MLX5_QP_NUM_STATE || new_state >= MLX5_QP_NUM_STATE ||
+           !optab[cur_state][new_state])
+               return -EINVAL;
+
+       memset(&out, 0, sizeof(out));
+       op = optab[cur_state][new_state];
+       in->hdr.opcode = cpu_to_be16(op);
+       in->qpn = cpu_to_be32(qp->qpn);
+       err = mlx5_cmd_exec(dev, in, sizeof(*in), &out, sizeof(out));
+       if (err)
+               return err;
+
+       return mlx5_cmd_status_to_err(&out.hdr);
+}
+EXPORT_SYMBOL_GPL(mlx5_core_qp_modify);
+
+void mlx5_init_qp_table(struct mlx5_core_dev *dev)
+{
+       struct mlx5_qp_table *table = &dev->priv.qp_table;
+
+       spin_lock_init(&table->lock);
+       INIT_RADIX_TREE(&table->tree, GFP_ATOMIC);
+       mlx5_qp_debugfs_init(dev);
+}
+
+void mlx5_cleanup_qp_table(struct mlx5_core_dev *dev)
+{
+       mlx5_qp_debugfs_cleanup(dev);
+}
+
+int mlx5_core_qp_query(struct mlx5_core_dev *dev, struct mlx5_core_qp *qp,
+                      struct mlx5_query_qp_mbox_out *out, int outlen)
+{
+       struct mlx5_query_qp_mbox_in in;
+       int err;
+
+       memset(&in, 0, sizeof(in));
+       memset(out, 0, outlen);
+       in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_QUERY_QP);
+       in.qpn = cpu_to_be32(qp->qpn);
+       err = mlx5_cmd_exec(dev, &in, sizeof(in), out, outlen);
+       if (err)
+               return err;
+
+       if (out->hdr.status)
+               return mlx5_cmd_status_to_err(&out->hdr);
+
+       return err;
+}
+EXPORT_SYMBOL_GPL(mlx5_core_qp_query);
+
+int mlx5_core_xrcd_alloc(struct mlx5_core_dev *dev, u32 *xrcdn)
+{
+       struct mlx5_alloc_xrcd_mbox_in in;
+       struct mlx5_alloc_xrcd_mbox_out out;
+       int err;
+
+       memset(&in, 0, sizeof(in));
+       memset(&out, 0, sizeof(out));
+       in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_ALLOC_XRCD);
+       err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out));
+       if (err)
+               return err;
+
+       if (out.hdr.status)
+               err = mlx5_cmd_status_to_err(&out.hdr);
+       else
+               *xrcdn = be32_to_cpu(out.xrcdn);
+
+       return err;
+}
+EXPORT_SYMBOL_GPL(mlx5_core_xrcd_alloc);
+
+int mlx5_core_xrcd_dealloc(struct mlx5_core_dev *dev, u32 xrcdn)
+{
+       struct mlx5_dealloc_xrcd_mbox_in in;
+       struct mlx5_dealloc_xrcd_mbox_out out;
+       int err;
+
+       memset(&in, 0, sizeof(in));
+       memset(&out, 0, sizeof(out));
+       in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_DEALLOC_XRCD);
+       in.xrcdn = cpu_to_be32(xrcdn);
+       err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out));
+       if (err)
+               return err;
+
+       if (out.hdr.status)
+               err = mlx5_cmd_status_to_err(&out.hdr);
+
+       return err;
+}
+EXPORT_SYMBOL_GPL(mlx5_core_xrcd_dealloc);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/srq.c b/drivers/net/ethernet/mellanox/mlx5/core/srq.c
new file mode 100644 (file)
index 0000000..38bce93
--- /dev/null
@@ -0,0 +1,223 @@
+/*
+ * Copyright (c) 2013, Mellanox Technologies inc.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mlx5/driver.h>
+#include <linux/mlx5/cmd.h>
+#include <linux/mlx5/srq.h>
+#include <rdma/ib_verbs.h>
+#include "mlx5_core.h"
+
+void mlx5_srq_event(struct mlx5_core_dev *dev, u32 srqn, int event_type)
+{
+       struct mlx5_srq_table *table = &dev->priv.srq_table;
+       struct mlx5_core_srq *srq;
+
+       spin_lock(&table->lock);
+
+       srq = radix_tree_lookup(&table->tree, srqn);
+       if (srq)
+               atomic_inc(&srq->refcount);
+
+       spin_unlock(&table->lock);
+
+       if (!srq) {
+               mlx5_core_warn(dev, "Async event for bogus SRQ 0x%08x\n", srqn);
+               return;
+       }
+
+       srq->event(srq, event_type);
+
+       if (atomic_dec_and_test(&srq->refcount))
+               complete(&srq->free);
+}
+
+struct mlx5_core_srq *mlx5_core_get_srq(struct mlx5_core_dev *dev, u32 srqn)
+{
+       struct mlx5_srq_table *table = &dev->priv.srq_table;
+       struct mlx5_core_srq *srq;
+
+       spin_lock(&table->lock);
+
+       srq = radix_tree_lookup(&table->tree, srqn);
+       if (srq)
+               atomic_inc(&srq->refcount);
+
+       spin_unlock(&table->lock);
+
+       return srq;
+}
+EXPORT_SYMBOL(mlx5_core_get_srq);
+
+int mlx5_core_create_srq(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq,
+                        struct mlx5_create_srq_mbox_in *in, int inlen)
+{
+       struct mlx5_create_srq_mbox_out out;
+       struct mlx5_srq_table *table = &dev->priv.srq_table;
+       struct mlx5_destroy_srq_mbox_in din;
+       struct mlx5_destroy_srq_mbox_out dout;
+       int err;
+
+       memset(&out, 0, sizeof(out));
+       in->hdr.opcode = cpu_to_be16(MLX5_CMD_OP_CREATE_SRQ);
+       err = mlx5_cmd_exec(dev, in, inlen, &out, sizeof(out));
+       if (err)
+               return err;
+
+       if (out.hdr.status)
+               return mlx5_cmd_status_to_err(&out.hdr);
+
+       srq->srqn = be32_to_cpu(out.srqn) & 0xffffff;
+
+       atomic_set(&srq->refcount, 1);
+       init_completion(&srq->free);
+
+       spin_lock_irq(&table->lock);
+       err = radix_tree_insert(&table->tree, srq->srqn, srq);
+       spin_unlock_irq(&table->lock);
+       if (err) {
+               mlx5_core_warn(dev, "err %d, srqn 0x%x\n", err, srq->srqn);
+               goto err_cmd;
+       }
+
+       return 0;
+
+err_cmd:
+       memset(&din, 0, sizeof(din));
+       memset(&dout, 0, sizeof(dout));
+       din.srqn = cpu_to_be32(srq->srqn);
+       din.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_DESTROY_SRQ);
+       mlx5_cmd_exec(dev, &din, sizeof(din), &dout, sizeof(dout));
+       return err;
+}
+EXPORT_SYMBOL(mlx5_core_create_srq);
+
+int mlx5_core_destroy_srq(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq)
+{
+       struct mlx5_destroy_srq_mbox_in in;
+       struct mlx5_destroy_srq_mbox_out out;
+       struct mlx5_srq_table *table = &dev->priv.srq_table;
+       struct mlx5_core_srq *tmp;
+       int err;
+
+       spin_lock_irq(&table->lock);
+       tmp = radix_tree_delete(&table->tree, srq->srqn);
+       spin_unlock_irq(&table->lock);
+       if (!tmp) {
+               mlx5_core_warn(dev, "srq 0x%x not found in tree\n", srq->srqn);
+               return -EINVAL;
+       }
+       if (tmp != srq) {
+               mlx5_core_warn(dev, "corruption on srqn 0x%x\n", srq->srqn);
+               return -EINVAL;
+       }
+
+       memset(&in, 0, sizeof(in));
+       memset(&out, 0, sizeof(out));
+       in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_DESTROY_SRQ);
+       in.srqn = cpu_to_be32(srq->srqn);
+       err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out));
+       if (err)
+               return err;
+
+       if (out.hdr.status)
+               return mlx5_cmd_status_to_err(&out.hdr);
+
+       if (atomic_dec_and_test(&srq->refcount))
+               complete(&srq->free);
+       wait_for_completion(&srq->free);
+
+       return 0;
+}
+EXPORT_SYMBOL(mlx5_core_destroy_srq);
+
+int mlx5_core_query_srq(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq,
+                       struct mlx5_query_srq_mbox_out *out)
+{
+       struct mlx5_query_srq_mbox_in in;
+       int err;
+
+       memset(&in, 0, sizeof(in));
+       memset(out, 0, sizeof(*out));
+
+       in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_QUERY_SRQ);
+       in.srqn = cpu_to_be32(srq->srqn);
+       err = mlx5_cmd_exec(dev, &in, sizeof(in), out, sizeof(*out));
+       if (err)
+               return err;
+
+       if (out->hdr.status)
+               return mlx5_cmd_status_to_err(&out->hdr);
+
+       return err;
+}
+EXPORT_SYMBOL(mlx5_core_query_srq);
+
+int mlx5_core_arm_srq(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq,
+                     u16 lwm, int is_srq)
+{
+       struct mlx5_arm_srq_mbox_in     in;
+       struct mlx5_arm_srq_mbox_out    out;
+       int err;
+
+       memset(&in, 0, sizeof(in));
+       memset(&out, 0, sizeof(out));
+
+       in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_ARM_RQ);
+       in.hdr.opmod = cpu_to_be16(!!is_srq);
+       in.srqn = cpu_to_be32(srq->srqn);
+       in.lwm = cpu_to_be16(lwm);
+
+       err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out));
+       if (err)
+               return err;
+
+       if (out.hdr.status)
+               return mlx5_cmd_status_to_err(&out.hdr);
+
+       return err;
+}
+EXPORT_SYMBOL(mlx5_core_arm_srq);
+
+void mlx5_init_srq_table(struct mlx5_core_dev *dev)
+{
+       struct mlx5_srq_table *table = &dev->priv.srq_table;
+
+       spin_lock_init(&table->lock);
+       INIT_RADIX_TREE(&table->tree, GFP_ATOMIC);
+}
+
+void mlx5_cleanup_srq_table(struct mlx5_core_dev *dev)
+{
+       /* nothing */
+}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/uar.c b/drivers/net/ethernet/mellanox/mlx5/core/uar.c
new file mode 100644 (file)
index 0000000..71d4a39
--- /dev/null
@@ -0,0 +1,223 @@
+/*
+ * Copyright (c) 2013, Mellanox Technologies inc.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mlx5/driver.h>
+#include <linux/mlx5/cmd.h>
+#include "mlx5_core.h"
+
+enum {
+       NUM_DRIVER_UARS         = 4,
+       NUM_LOW_LAT_UUARS       = 4,
+};
+
+
+struct mlx5_alloc_uar_mbox_in {
+       struct mlx5_inbox_hdr   hdr;
+       u8                      rsvd[8];
+};
+
+struct mlx5_alloc_uar_mbox_out {
+       struct mlx5_outbox_hdr  hdr;
+       __be32                  uarn;
+       u8                      rsvd[4];
+};
+
+struct mlx5_free_uar_mbox_in {
+       struct mlx5_inbox_hdr   hdr;
+       __be32                  uarn;
+       u8                      rsvd[4];
+};
+
+struct mlx5_free_uar_mbox_out {
+       struct mlx5_outbox_hdr  hdr;
+       u8                      rsvd[8];
+};
+
+int mlx5_cmd_alloc_uar(struct mlx5_core_dev *dev, u32 *uarn)
+{
+       struct mlx5_alloc_uar_mbox_in   in;
+       struct mlx5_alloc_uar_mbox_out  out;
+       int err;
+
+       memset(&in, 0, sizeof(in));
+       memset(&out, 0, sizeof(out));
+       in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_ALLOC_UAR);
+       err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out));
+       if (err)
+               goto ex;
+
+       if (out.hdr.status) {
+               err = mlx5_cmd_status_to_err(&out.hdr);
+               goto ex;
+       }
+
+       *uarn = be32_to_cpu(out.uarn) & 0xffffff;
+
+ex:
+       return err;
+}
+EXPORT_SYMBOL(mlx5_cmd_alloc_uar);
+
+int mlx5_cmd_free_uar(struct mlx5_core_dev *dev, u32 uarn)
+{
+       struct mlx5_free_uar_mbox_in    in;
+       struct mlx5_free_uar_mbox_out   out;
+       int err;
+
+       memset(&in, 0, sizeof(in));
+       in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_DEALLOC_UAR);
+       in.uarn = cpu_to_be32(uarn);
+       err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out));
+       if (err)
+               goto ex;
+
+       if (out.hdr.status)
+               err = mlx5_cmd_status_to_err(&out.hdr);
+
+ex:
+       return err;
+}
+EXPORT_SYMBOL(mlx5_cmd_free_uar);
+
+static int need_uuar_lock(int uuarn)
+{
+       int tot_uuars = NUM_DRIVER_UARS * MLX5_BF_REGS_PER_PAGE;
+
+       if (uuarn == 0 || tot_uuars - NUM_LOW_LAT_UUARS)
+               return 0;
+
+       return 1;
+}
+
+int mlx5_alloc_uuars(struct mlx5_core_dev *dev, struct mlx5_uuar_info *uuari)
+{
+       int tot_uuars = NUM_DRIVER_UARS * MLX5_BF_REGS_PER_PAGE;
+       struct mlx5_bf *bf;
+       phys_addr_t addr;
+       int err;
+       int i;
+
+       uuari->num_uars = NUM_DRIVER_UARS;
+       uuari->num_low_latency_uuars = NUM_LOW_LAT_UUARS;
+
+       mutex_init(&uuari->lock);
+       uuari->uars = kcalloc(uuari->num_uars, sizeof(*uuari->uars), GFP_KERNEL);
+       if (!uuari->uars)
+               return -ENOMEM;
+
+       uuari->bfs = kcalloc(tot_uuars, sizeof(*uuari->bfs), GFP_KERNEL);
+       if (!uuari->bfs) {
+               err = -ENOMEM;
+               goto out_uars;
+       }
+
+       uuari->bitmap = kcalloc(BITS_TO_LONGS(tot_uuars), sizeof(*uuari->bitmap),
+                               GFP_KERNEL);
+       if (!uuari->bitmap) {
+               err = -ENOMEM;
+               goto out_bfs;
+       }
+
+       uuari->count = kcalloc(tot_uuars, sizeof(*uuari->count), GFP_KERNEL);
+       if (!uuari->count) {
+               err = -ENOMEM;
+               goto out_bitmap;
+       }
+
+       for (i = 0; i < uuari->num_uars; i++) {
+               err = mlx5_cmd_alloc_uar(dev, &uuari->uars[i].index);
+               if (err)
+                       goto out_count;
+
+               addr = dev->iseg_base + ((phys_addr_t)(uuari->uars[i].index) << PAGE_SHIFT);
+               uuari->uars[i].map = ioremap(addr, PAGE_SIZE);
+               if (!uuari->uars[i].map) {
+                       mlx5_cmd_free_uar(dev, uuari->uars[i].index);
+                       goto out_count;
+               }
+               mlx5_core_dbg(dev, "allocated uar index 0x%x, mmaped at %p\n",
+                             uuari->uars[i].index, uuari->uars[i].map);
+       }
+
+       for (i = 0; i < tot_uuars; i++) {
+               bf = &uuari->bfs[i];
+
+               bf->buf_size = dev->caps.bf_reg_size / 2;
+               bf->uar = &uuari->uars[i / MLX5_BF_REGS_PER_PAGE];
+               bf->regreg = uuari->uars[i / MLX5_BF_REGS_PER_PAGE].map;
+               bf->reg = NULL; /* Add WC support */
+               bf->offset = (i % MLX5_BF_REGS_PER_PAGE) * dev->caps.bf_reg_size +
+                       MLX5_BF_OFFSET;
+               bf->need_lock = need_uuar_lock(i);
+               spin_lock_init(&bf->lock);
+               spin_lock_init(&bf->lock32);
+               bf->uuarn = i;
+       }
+
+       return 0;
+
+out_count:
+       for (i--; i >= 0; i--) {
+               iounmap(uuari->uars[i].map);
+               mlx5_cmd_free_uar(dev, uuari->uars[i].index);
+       }
+       kfree(uuari->count);
+
+out_bitmap:
+       kfree(uuari->bitmap);
+
+out_bfs:
+       kfree(uuari->bfs);
+
+out_uars:
+       kfree(uuari->uars);
+       return err;
+}
+
+int mlx5_free_uuars(struct mlx5_core_dev *dev, struct mlx5_uuar_info *uuari)
+{
+       int i = uuari->num_uars;
+
+       for (i--; i >= 0; i--) {
+               iounmap(uuari->uars[i].map);
+               mlx5_cmd_free_uar(dev, uuari->uars[i].index);
+       }
+
+       kfree(uuari->count);
+       kfree(uuari->bitmap);
+       kfree(uuari->bfs);
+       kfree(uuari->uars);
+
+       return 0;
+}
index 3de52ff..a7aa280 100644 (file)
@@ -4,7 +4,7 @@
 
 config OCTEON_MGMT_ETHERNET
        tristate "Octeon Management port ethernet driver (CN5XXX, CN6XXX)"
-       depends on  CPU_CAVIUM_OCTEON
+       depends on CAVIUM_OCTEON_SOC
        select PHYLIB
        select MDIO_OCTEON
        default y
index 393f961..4106a74 100644 (file)
@@ -46,6 +46,7 @@
 #define FIRMWARE_8105E_1       "rtl_nic/rtl8105e-1.fw"
 #define FIRMWARE_8402_1                "rtl_nic/rtl8402-1.fw"
 #define FIRMWARE_8411_1                "rtl_nic/rtl8411-1.fw"
+#define FIRMWARE_8411_2                "rtl_nic/rtl8411-2.fw"
 #define FIRMWARE_8106E_1       "rtl_nic/rtl8106e-1.fw"
 #define FIRMWARE_8106E_2       "rtl_nic/rtl8106e-2.fw"
 #define FIRMWARE_8168G_2       "rtl_nic/rtl8168g-2.fw"
@@ -144,6 +145,7 @@ enum mac_version {
        RTL_GIGA_MAC_VER_41,
        RTL_GIGA_MAC_VER_42,
        RTL_GIGA_MAC_VER_43,
+       RTL_GIGA_MAC_VER_44,
        RTL_GIGA_MAC_NONE   = 0xff,
 };
 
@@ -276,6 +278,9 @@ static const struct {
        [RTL_GIGA_MAC_VER_43] =
                _R("RTL8106e",          RTL_TD_1, FIRMWARE_8106E_2,
                                                        JUMBO_1K, true),
+       [RTL_GIGA_MAC_VER_44] =
+               _R("RTL8411",           RTL_TD_1, FIRMWARE_8411_2,
+                                                       JUMBO_9K, false),
 };
 #undef _R
 
@@ -394,6 +399,7 @@ enum rtl8168_8101_registers {
 #define CSIAR_FUNC_CARD                        0x00000000
 #define CSIAR_FUNC_SDIO                        0x00010000
 #define CSIAR_FUNC_NIC                 0x00020000
+#define CSIAR_FUNC_NIC2                        0x00010000
        PMCH                    = 0x6f,
        EPHYAR                  = 0x80,
 #define        EPHYAR_FLAG                     0x80000000
@@ -826,6 +832,7 @@ MODULE_FIRMWARE(FIRMWARE_8168F_1);
 MODULE_FIRMWARE(FIRMWARE_8168F_2);
 MODULE_FIRMWARE(FIRMWARE_8402_1);
 MODULE_FIRMWARE(FIRMWARE_8411_1);
+MODULE_FIRMWARE(FIRMWARE_8411_2);
 MODULE_FIRMWARE(FIRMWARE_8106E_1);
 MODULE_FIRMWARE(FIRMWARE_8106E_2);
 MODULE_FIRMWARE(FIRMWARE_8168G_2);
@@ -2051,6 +2058,7 @@ static void rtl8169_get_mac_version(struct rtl8169_private *tp,
                int mac_version;
        } mac_info[] = {
                /* 8168G family. */
+               { 0x7cf00000, 0x5c800000,       RTL_GIGA_MAC_VER_44 },
                { 0x7cf00000, 0x50900000,       RTL_GIGA_MAC_VER_42 },
                { 0x7cf00000, 0x4c100000,       RTL_GIGA_MAC_VER_41 },
                { 0x7cf00000, 0x4c000000,       RTL_GIGA_MAC_VER_40 },
@@ -3651,6 +3659,7 @@ static void rtl_hw_phy_config(struct net_device *dev)
                break;
        case RTL_GIGA_MAC_VER_42:
        case RTL_GIGA_MAC_VER_43:
+       case RTL_GIGA_MAC_VER_44:
                rtl8168g_2_hw_phy_config(tp);
                break;
 
@@ -3863,6 +3872,7 @@ static void rtl_init_mdio_ops(struct rtl8169_private *tp)
        case RTL_GIGA_MAC_VER_41:
        case RTL_GIGA_MAC_VER_42:
        case RTL_GIGA_MAC_VER_43:
+       case RTL_GIGA_MAC_VER_44:
                ops->write      = r8168g_mdio_write;
                ops->read       = r8168g_mdio_read;
                break;
@@ -3916,6 +3926,7 @@ static void rtl_wol_suspend_quirk(struct rtl8169_private *tp)
        case RTL_GIGA_MAC_VER_41:
        case RTL_GIGA_MAC_VER_42:
        case RTL_GIGA_MAC_VER_43:
+       case RTL_GIGA_MAC_VER_44:
                RTL_W32(RxConfig, RTL_R32(RxConfig) |
                        AcceptBroadcast | AcceptMulticast | AcceptMyPhys);
                break;
@@ -4178,6 +4189,7 @@ static void rtl_init_pll_power_ops(struct rtl8169_private *tp)
        case RTL_GIGA_MAC_VER_40:
        case RTL_GIGA_MAC_VER_41:
        case RTL_GIGA_MAC_VER_42:
+       case RTL_GIGA_MAC_VER_44:
                ops->down       = r8168_pll_power_down;
                ops->up         = r8168_pll_power_up;
                break;
@@ -4224,6 +4236,7 @@ static void rtl_init_rxcfg(struct rtl8169_private *tp)
        case RTL_GIGA_MAC_VER_41:
        case RTL_GIGA_MAC_VER_42:
        case RTL_GIGA_MAC_VER_43:
+       case RTL_GIGA_MAC_VER_44:
                RTL_W32(RxConfig, RX128_INT_EN | RX_DMA_BURST | RX_EARLY_OFF);
                break;
        default:
@@ -4384,6 +4397,7 @@ static void rtl_init_jumbo_ops(struct rtl8169_private *tp)
        case RTL_GIGA_MAC_VER_41:
        case RTL_GIGA_MAC_VER_42:
        case RTL_GIGA_MAC_VER_43:
+       case RTL_GIGA_MAC_VER_44:
        default:
                ops->disable    = NULL;
                ops->enable     = NULL;
@@ -4493,6 +4507,7 @@ static void rtl8169_hw_reset(struct rtl8169_private *tp)
                   tp->mac_version == RTL_GIGA_MAC_VER_41 ||
                   tp->mac_version == RTL_GIGA_MAC_VER_42 ||
                   tp->mac_version == RTL_GIGA_MAC_VER_43 ||
+                  tp->mac_version == RTL_GIGA_MAC_VER_44 ||
                   tp->mac_version == RTL_GIGA_MAC_VER_38) {
                RTL_W8(ChipCmd, RTL_R8(ChipCmd) | StopReq);
                rtl_udelay_loop_wait_high(tp, &rtl_txcfg_empty_cond, 100, 666);
@@ -4782,6 +4797,29 @@ static u32 r8402_csi_read(struct rtl8169_private *tp, int addr)
                RTL_R32(CSIDR) : ~0;
 }
 
+static void r8411_csi_write(struct rtl8169_private *tp, int addr, int value)
+{
+       void __iomem *ioaddr = tp->mmio_addr;
+
+       RTL_W32(CSIDR, value);
+       RTL_W32(CSIAR, CSIAR_WRITE_CMD | (addr & CSIAR_ADDR_MASK) |
+               CSIAR_BYTE_ENABLE << CSIAR_BYTE_ENABLE_SHIFT |
+               CSIAR_FUNC_NIC2);
+
+       rtl_udelay_loop_wait_low(tp, &rtl_csiar_cond, 10, 100);
+}
+
+static u32 r8411_csi_read(struct rtl8169_private *tp, int addr)
+{
+       void __iomem *ioaddr = tp->mmio_addr;
+
+       RTL_W32(CSIAR, (addr & CSIAR_ADDR_MASK) | CSIAR_FUNC_NIC2 |
+               CSIAR_BYTE_ENABLE << CSIAR_BYTE_ENABLE_SHIFT);
+
+       return rtl_udelay_loop_wait_high(tp, &rtl_csiar_cond, 10, 100) ?
+               RTL_R32(CSIDR) : ~0;
+}
+
 static void rtl_init_csi_ops(struct rtl8169_private *tp)
 {
        struct csi_ops *ops = &tp->csi_ops;
@@ -4811,6 +4849,11 @@ static void rtl_init_csi_ops(struct rtl8169_private *tp)
                ops->read       = r8402_csi_read;
                break;
 
+       case RTL_GIGA_MAC_VER_44:
+               ops->write      = r8411_csi_write;
+               ops->read       = r8411_csi_read;
+               break;
+
        default:
                ops->write      = r8169_csi_write;
                ops->read       = r8169_csi_read;
@@ -5255,6 +5298,25 @@ static void rtl_hw_start_8168g_2(struct rtl8169_private *tp)
        rtl_ephy_init(tp, e_info_8168g_2, ARRAY_SIZE(e_info_8168g_2));
 }
 
+static void rtl_hw_start_8411_2(struct rtl8169_private *tp)
+{
+       void __iomem *ioaddr = tp->mmio_addr;
+       static const struct ephy_info e_info_8411_2[] = {
+               { 0x00, 0x0000, 0x0008 },
+               { 0x0c, 0x3df0, 0x0200 },
+               { 0x0f, 0xffff, 0x5200 },
+               { 0x19, 0x0020, 0x0000 },
+               { 0x1e, 0x0000, 0x2000 }
+       };
+
+       rtl_hw_start_8168g_1(tp);
+
+       /* disable aspm and clock request before access ephy */
+       RTL_W8(Config2, RTL_R8(Config2) & ~ClkReqEn);
+       RTL_W8(Config5, RTL_R8(Config5) & ~ASPM_en);
+       rtl_ephy_init(tp, e_info_8411_2, ARRAY_SIZE(e_info_8411_2));
+}
+
 static void rtl_hw_start_8168(struct net_device *dev)
 {
        struct rtl8169_private *tp = netdev_priv(dev);
@@ -5361,6 +5423,10 @@ static void rtl_hw_start_8168(struct net_device *dev)
                rtl_hw_start_8168g_2(tp);
                break;
 
+       case RTL_GIGA_MAC_VER_44:
+               rtl_hw_start_8411_2(tp);
+               break;
+
        default:
                printk(KERN_ERR PFX "%s: unknown chipset (mac_version = %d).\n",
                        dev->name, tp->mac_version);
@@ -6877,6 +6943,7 @@ static void rtl_hw_initialize(struct rtl8169_private *tp)
        case RTL_GIGA_MAC_VER_41:
        case RTL_GIGA_MAC_VER_42:
        case RTL_GIGA_MAC_VER_43:
+       case RTL_GIGA_MAC_VER_44:
                rtl_hw_init_8168g(tp);
                break;
 
index 544514e..19a8a04 100644 (file)
@@ -4,6 +4,7 @@
 
 config SH_ETH
        tristate "Renesas SuperH Ethernet support"
+       depends on HAS_DMA
        select CRC32
        select MII
        select MDIO_BITBANG
index 1df0ff3..3df5684 100644 (file)
@@ -1239,6 +1239,8 @@ static int vnet_port_remove(struct vio_dev *vdev)
                dev_set_drvdata(&vdev->dev, NULL);
 
                kfree(port);
+
+               unregister_netdev(vp->dev);
        }
        return 0;
 }
index ca98aca..b75eb9e 100644 (file)
@@ -1171,7 +1171,11 @@ static void alloc_rbufs(struct net_device *dev)
                rp->rx_skbuff_dma[i] =
                        pci_map_single(rp->pdev, skb->data, rp->rx_buf_sz,
                                       PCI_DMA_FROMDEVICE);
-
+               if (dma_mapping_error(&rp->pdev->dev, rp->rx_skbuff_dma[i])) {
+                       rp->rx_skbuff_dma[i] = 0;
+                       dev_kfree_skb(skb);
+                       break;
+               }
                rp->rx_ring[i].addr = cpu_to_le32(rp->rx_skbuff_dma[i]);
                rp->rx_ring[i].rx_status = cpu_to_le32(DescOwn);
        }
@@ -1687,6 +1691,12 @@ static netdev_tx_t rhine_start_tx(struct sk_buff *skb,
                rp->tx_skbuff_dma[entry] =
                        pci_map_single(rp->pdev, skb->data, skb->len,
                                       PCI_DMA_TODEVICE);
+               if (dma_mapping_error(&rp->pdev->dev, rp->tx_skbuff_dma[entry])) {
+                       dev_kfree_skb(skb);
+                       rp->tx_skbuff_dma[entry] = 0;
+                       dev->stats.tx_dropped++;
+                       return NETDEV_TX_OK;
+               }
                rp->tx_ring[entry].addr = cpu_to_le32(rp->tx_skbuff_dma[entry]);
        }
 
@@ -1961,6 +1971,11 @@ static int rhine_rx(struct net_device *dev, int limit)
                                pci_map_single(rp->pdev, skb->data,
                                               rp->rx_buf_sz,
                                               PCI_DMA_FROMDEVICE);
+                       if (dma_mapping_error(&rp->pdev->dev, rp->rx_skbuff_dma[entry])) {
+                               dev_kfree_skb(skb);
+                               rp->rx_skbuff_dma[entry] = 0;
+                               break;
+                       }
                        rp->rx_ring[entry].addr = cpu_to_le32(rp->rx_skbuff_dma[entry]);
                }
                rp->rx_ring[entry].rx_status = cpu_to_le32(DescOwn);
index ede3ce4..42e6dee 100644 (file)
@@ -22,7 +22,6 @@
 #include <linux/spi/spi.h>
 #include <linux/interrupt.h>
 #include <linux/module.h>
-#include <linux/pinctrl/consumer.h>
 #include <net/wpan-phy.h>
 #include <net/mac802154.h>
 #include <net/ieee802154.h>
@@ -627,7 +626,6 @@ static int mrf24j40_probe(struct spi_device *spi)
        int ret = -ENOMEM;
        u8 val;
        struct mrf24j40 *devrec;
-       struct pinctrl *pinctrl;
 
        printk(KERN_INFO "mrf24j40: probe(). IRQ: %d\n", spi->irq);
 
@@ -638,11 +636,6 @@ static int mrf24j40_probe(struct spi_device *spi)
        if (!devrec->buf)
                goto err_buf;
 
-       pinctrl = devm_pinctrl_get_select_default(&spi->dev);
-       if (IS_ERR(pinctrl))
-               dev_warn(&spi->dev,
-                       "pinctrl pins are not configured from the driver");
-
        spi->mode = SPI_MODE_0; /* TODO: Is this appropriate for right here? */
        if (spi->max_speed_hz > MAX_SPI_SPEED_HZ)
                spi->max_speed_hz = MAX_SPI_SPEED_HZ;
index dc9f6a4..a3bed28 100644 (file)
@@ -291,11 +291,17 @@ static int __init ifb_init_module(void)
 
        rtnl_lock();
        err = __rtnl_link_register(&ifb_link_ops);
+       if (err < 0)
+               goto out;
 
-       for (i = 0; i < numifbs && !err; i++)
+       for (i = 0; i < numifbs && !err; i++) {
                err = ifb_init_one(i);
+               cond_resched();
+       }
        if (err)
                __rtnl_link_unregister(&ifb_link_ops);
+
+out:
        rtnl_unlock();
 
        return err;
index f2c4a3b..876c722 100644 (file)
@@ -712,6 +712,7 @@ static ssize_t macvtap_get_user(struct macvtap_queue *q, struct msghdr *m,
        int vnet_hdr_len = 0;
        int copylen = 0;
        bool zerocopy = false;
+       size_t linear;
 
        if (q->flags & IFF_VNET_HDR) {
                vnet_hdr_len = q->vnet_hdr_sz;
@@ -766,11 +767,14 @@ static ssize_t macvtap_get_user(struct macvtap_queue *q, struct msghdr *m,
                        copylen = vnet_hdr.hdr_len;
                if (!copylen)
                        copylen = GOODCOPY_LEN;
-       } else
+               linear = copylen;
+       } else {
                copylen = len;
+               linear = vnet_hdr.hdr_len;
+       }
 
        skb = macvtap_alloc_skb(&q->sk, NET_IP_ALIGN, copylen,
-                               vnet_hdr.hdr_len, noblock, &err);
+                               linear, noblock, &err);
        if (!skb)
                goto err;
 
index 3a316b3..342561a 100644 (file)
@@ -135,7 +135,7 @@ config MDIO_GPIO
 
 config MDIO_OCTEON
        tristate "Support for MDIO buses on Octeon SOCs"
-       depends on  CPU_CAVIUM_OCTEON
+       depends on CAVIUM_OCTEON_SOC
        default y
        help
 
index 1f7091b..ac22283 100644 (file)
@@ -217,6 +217,7 @@ module_exit(atheros_exit);
 
 static struct mdio_device_id __maybe_unused atheros_tbl[] = {
        { 0x004dd076, 0xffffffef },
+       { 0x004dd074, 0xffffffef },
        { 0x004dd072, 0xffffffef },
        { }
 };
index 7eab5fc..5cdcf92 100644 (file)
@@ -1042,7 +1042,7 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
 {
        struct tun_pi pi = { 0, cpu_to_be16(ETH_P_IP) };
        struct sk_buff *skb;
-       size_t len = total_len, align = NET_SKB_PAD;
+       size_t len = total_len, align = NET_SKB_PAD, linear;
        struct virtio_net_hdr gso = { 0 };
        int offset = 0;
        int copylen;
@@ -1106,10 +1106,13 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
                        copylen = gso.hdr_len;
                if (!copylen)
                        copylen = GOODCOPY_LEN;
-       } else
+               linear = copylen;
+       } else {
                copylen = len;
+               linear = gso.hdr_len;
+       }
 
-       skb = tun_alloc_skb(tfile, align, copylen, gso.hdr_len, noblock);
+       skb = tun_alloc_skb(tfile, align, copylen, linear, noblock);
        if (IS_ERR(skb)) {
                if (PTR_ERR(skb) != -EAGAIN)
                        tun->dev->stats.rx_dropped++;
index 9ab5c9d..e817178 100644 (file)
@@ -11,7 +11,7 @@ obj-$(CONFIG_USB_HSO)         += hso.o
 obj-$(CONFIG_USB_NET_AX8817X)  += asix.o
 asix-y := asix_devices.o asix_common.o ax88172a.o
 obj-$(CONFIG_USB_NET_AX88179_178A)      += ax88179_178a.o
-obj-$(CONFIG_USB_NET_CDCETHER) += cdc_ether.o
+obj-$(CONFIG_USB_NET_CDCETHER) += cdc_ether.o r815x.o
 obj-$(CONFIG_USB_NET_CDC_EEM)  += cdc_eem.o
 obj-$(CONFIG_USB_NET_DM9601)   += dm9601.o
 obj-$(CONFIG_USB_NET_SMSC75XX) += smsc75xx.o
index 4393f14..03ad4dc 100644 (file)
@@ -646,13 +646,18 @@ static const struct usb_device_id products [] = {
 },
 
 /* Realtek RTL8152 Based USB 2.0 Ethernet Adapters */
-#if defined(CONFIG_USB_RTL8152) || defined(CONFIG_USB_RTL8152_MODULE)
 {
        USB_DEVICE_AND_INTERFACE_INFO(REALTEK_VENDOR_ID, 0x8152, USB_CLASS_COMM,
                        USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE),
        .driver_info = 0,
 },
-#endif
+
+/* Realtek RTL8153 Based USB 3.0 Ethernet Adapters */
+{
+       USB_DEVICE_AND_INTERFACE_INFO(REALTEK_VENDOR_ID, 0x8153, USB_CLASS_COMM,
+                       USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE),
+       .driver_info = 0,
+},
 
 /*
  * WHITELIST!!!
index d02bac8..ee13f9e 100644 (file)
@@ -934,7 +934,8 @@ static netdev_tx_t rtl8152_start_xmit(struct sk_buff *skb,
        struct r8152 *tp = netdev_priv(netdev);
        struct net_device_stats *stats = rtl8152_get_stats(netdev);
        struct tx_desc *tx_desc;
-       int len, res;
+       unsigned int len;
+       int res;
 
        netif_stop_queue(netdev);
        len = skb->len;
diff --git a/drivers/net/usb/r815x.c b/drivers/net/usb/r815x.c
new file mode 100644 (file)
index 0000000..8523922
--- /dev/null
@@ -0,0 +1,234 @@
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/mii.h>
+#include <linux/usb.h>
+#include <linux/usb/cdc.h>
+#include <linux/usb/usbnet.h>
+
+#define RTL815x_REQT_READ      0xc0
+#define RTL815x_REQT_WRITE     0x40
+#define RTL815x_REQ_GET_REGS   0x05
+#define RTL815x_REQ_SET_REGS   0x05
+
+#define MCU_TYPE_PLA           0x0100
+#define OCP_BASE               0xe86c
+#define BASE_MII               0xa400
+
+#define BYTE_EN_DWORD          0xff
+#define BYTE_EN_WORD           0x33
+#define BYTE_EN_BYTE           0x11
+
+#define R815x_PHY_ID           32
+#define REALTEK_VENDOR_ID      0x0bda
+
+
+static int pla_read_word(struct usb_device *udev, u16 index)
+{
+       int data, ret;
+       u8 shift = index & 2;
+       __le32 ocp_data;
+
+       index &= ~3;
+
+       ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+                             RTL815x_REQ_GET_REGS, RTL815x_REQT_READ,
+                             index, MCU_TYPE_PLA, &ocp_data, sizeof(ocp_data),
+                             500);
+       if (ret < 0)
+               return ret;
+
+       data = __le32_to_cpu(ocp_data);
+       data >>= (shift * 8);
+       data &= 0xffff;
+
+       return data;
+}
+
+static int pla_write_word(struct usb_device *udev, u16 index, u32 data)
+{
+       __le32 ocp_data;
+       u32 mask = 0xffff;
+       u16 byen = BYTE_EN_WORD;
+       u8 shift = index & 2;
+       int ret;
+
+       data &= mask;
+
+       if (shift) {
+               byen <<= shift;
+               mask <<= (shift * 8);
+               data <<= (shift * 8);
+               index &= ~3;
+       }
+
+       ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+                             RTL815x_REQ_GET_REGS, RTL815x_REQT_READ,
+                             index, MCU_TYPE_PLA, &ocp_data, sizeof(ocp_data),
+                             500);
+       if (ret < 0)
+               return ret;
+
+       data |= __le32_to_cpu(ocp_data) & ~mask;
+       ocp_data = __cpu_to_le32(data);
+
+       ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+                             RTL815x_REQ_SET_REGS, RTL815x_REQT_WRITE,
+                             index, MCU_TYPE_PLA | byen, &ocp_data,
+                             sizeof(ocp_data), 500);
+
+       return ret;
+}
+
+static int ocp_reg_read(struct usbnet *dev, u16 addr)
+{
+       u16 ocp_base, ocp_index;
+       int ret;
+
+       ocp_base = addr & 0xf000;
+       ret = pla_write_word(dev->udev, OCP_BASE, ocp_base);
+       if (ret < 0)
+               goto out;
+
+       ocp_index = (addr & 0x0fff) | 0xb000;
+       ret = pla_read_word(dev->udev, ocp_index);
+
+out:
+       return ret;
+}
+
+static int ocp_reg_write(struct usbnet *dev, u16 addr, u16 data)
+{
+       u16 ocp_base, ocp_index;
+       int ret;
+
+       ocp_base = addr & 0xf000;
+       ret = pla_write_word(dev->udev, OCP_BASE, ocp_base);
+       if (ret < 0)
+               goto out1;
+
+       ocp_index = (addr & 0x0fff) | 0xb000;
+       ret = pla_write_word(dev->udev, ocp_index, data);
+
+out1:
+       return ret;
+}
+
+static int r815x_mdio_read(struct net_device *netdev, int phy_id, int reg)
+{
+       struct usbnet *dev = netdev_priv(netdev);
+
+       if (phy_id != R815x_PHY_ID)
+               return -EINVAL;
+
+       return ocp_reg_read(dev, BASE_MII + reg * 2);
+}
+
+static
+void r815x_mdio_write(struct net_device *netdev, int phy_id, int reg, int val)
+{
+       struct usbnet *dev = netdev_priv(netdev);
+
+       if (phy_id != R815x_PHY_ID)
+               return;
+
+       ocp_reg_write(dev, BASE_MII + reg * 2, val);
+}
+
+static int r8153_bind(struct usbnet *dev, struct usb_interface *intf)
+{
+       int status;
+
+       status = usbnet_cdc_bind(dev, intf);
+       if (status < 0)
+               return status;
+
+       dev->mii.dev = dev->net;
+       dev->mii.mdio_read = r815x_mdio_read;
+       dev->mii.mdio_write = r815x_mdio_write;
+       dev->mii.phy_id_mask = 0x3f;
+       dev->mii.reg_num_mask = 0x1f;
+       dev->mii.phy_id = R815x_PHY_ID;
+       dev->mii.supports_gmii = 1;
+
+       return 0;
+}
+
+static int r8152_bind(struct usbnet *dev, struct usb_interface *intf)
+{
+       int status;
+
+       status = usbnet_cdc_bind(dev, intf);
+       if (status < 0)
+               return status;
+
+       dev->mii.dev = dev->net;
+       dev->mii.mdio_read = r815x_mdio_read;
+       dev->mii.mdio_write = r815x_mdio_write;
+       dev->mii.phy_id_mask = 0x3f;
+       dev->mii.reg_num_mask = 0x1f;
+       dev->mii.phy_id = R815x_PHY_ID;
+       dev->mii.supports_gmii = 0;
+
+       return 0;
+}
+
+static const struct driver_info r8152_info = {
+       .description =  "RTL8152 ECM Device",
+       .flags =        FLAG_ETHER | FLAG_POINTTOPOINT,
+       .bind =         r8152_bind,
+       .unbind =       usbnet_cdc_unbind,
+       .status =       usbnet_cdc_status,
+       .manage_power = usbnet_manage_power,
+};
+
+static const struct driver_info r8153_info = {
+       .description =  "RTL8153 ECM Device",
+       .flags =        FLAG_ETHER | FLAG_POINTTOPOINT,
+       .bind =         r8153_bind,
+       .unbind =       usbnet_cdc_unbind,
+       .status =       usbnet_cdc_status,
+       .manage_power = usbnet_manage_power,
+};
+
+static const struct usb_device_id products[] = {
+{
+       USB_DEVICE_AND_INTERFACE_INFO(REALTEK_VENDOR_ID, 0x8152, USB_CLASS_COMM,
+                       USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE),
+#if defined(CONFIG_USB_RTL8152) || defined(CONFIG_USB_RTL8152_MODULE)
+       .driver_info = 0,
+#else
+       .driver_info = (unsigned long) &r8152_info,
+#endif
+},
+
+{
+       USB_DEVICE_AND_INTERFACE_INFO(REALTEK_VENDOR_ID, 0x8153, USB_CLASS_COMM,
+                       USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE),
+#if defined(CONFIG_USB_RTL8153) || defined(CONFIG_USB_RTL8153_MODULE)
+       .driver_info = 0,
+#else
+       .driver_info = (unsigned long) &r8153_info,
+#endif
+},
+
+       { },            /* END */
+};
+MODULE_DEVICE_TABLE(usb, products);
+
+static struct usb_driver r815x_driver = {
+       .name =         "r815x",
+       .id_table =     products,
+       .probe =        usbnet_probe,
+       .disconnect =   usbnet_disconnect,
+       .suspend =      usbnet_suspend,
+       .resume =       usbnet_resume,
+       .reset_resume = usbnet_resume,
+       .supports_autosuspend = 1,
+       .disable_hub_initiated_lpm = 1,
+};
+
+module_usb_driver(r815x_driver);
+
+MODULE_AUTHOR("Hayes Wang");
+MODULE_DESCRIPTION("Realtek USB ECM device");
+MODULE_LICENSE("GPL");
index 42d670a..3d2a90a 100644 (file)
@@ -902,7 +902,6 @@ static int virtnet_set_queues(struct virtnet_info *vi, u16 queue_pairs)
        struct scatterlist sg;
        struct virtio_net_ctrl_mq s;
        struct net_device *dev = vi->dev;
-       int i;
 
        if (!vi->has_cvq || !virtio_has_feature(vi->vdev, VIRTIO_NET_F_MQ))
                return 0;
@@ -916,10 +915,8 @@ static int virtnet_set_queues(struct virtnet_info *vi, u16 queue_pairs)
                         queue_pairs);
                return -EINVAL;
        } else {
-               for (i = vi->curr_queue_pairs; i < queue_pairs; i++)
-                       if (!try_fill_recv(&vi->rq[i], GFP_KERNEL))
-                               schedule_delayed_work(&vi->refill, 0);
                vi->curr_queue_pairs = queue_pairs;
+               schedule_delayed_work(&vi->refill, 0);
        }
 
        return 0;
index 227b54a..0ba1e7e 100644 (file)
@@ -1916,9 +1916,9 @@ late_initcall(vxlan_init_module);
 
 static void __exit vxlan_cleanup_module(void)
 {
-       unregister_pernet_device(&vxlan_net_ops);
        rtnl_link_unregister(&vxlan_link_ops);
        destroy_workqueue(vxlan_wq);
+       unregister_pernet_device(&vxlan_net_ops);
        rcu_barrier();
 }
 module_exit(vxlan_cleanup_module);
index 1f05913..19f6f70 100644 (file)
@@ -613,6 +613,54 @@ truncate_pat_collision(struct resource *root, struct resource *new)
        return 0;       /* truncation successful */
 }
 
+/*
+ * extend_lmmio_len: extend lmmio range to maximum length
+ *
+ * This is needed at least on C8000 systems to get the ATI FireGL card
+ * working. On other systems we will currently not extend the lmmio space.
+ */
+static unsigned long
+extend_lmmio_len(unsigned long start, unsigned long end, unsigned long lba_len)
+{
+       struct resource *tmp;
+
+       pr_debug("LMMIO mismatch: PAT length = 0x%lx, MASK register = 0x%lx\n",
+               end - start, lba_len);
+
+       lba_len = min(lba_len+1, 256UL*1024*1024); /* limit to 256 MB */
+
+       pr_debug("LBA: lmmio_space [0x%lx-0x%lx] - original\n", start, end);
+
+       if (boot_cpu_data.cpu_type < mako) {
+               pr_info("LBA: Not a C8000 system - not extending LMMIO range.\n");
+               return end;
+       }
+
+       end += lba_len;
+       if (end < start) /* fix overflow */
+               end = -1ULL;
+
+       pr_debug("LBA: lmmio_space [0x%lx-0x%lx] - current\n", start, end);
+
+       /* first overlap */
+       for (tmp = iomem_resource.child; tmp; tmp = tmp->sibling) {
+               pr_debug("LBA: testing %pR\n", tmp);
+               if (tmp->start == start)
+                       continue; /* ignore ourself */
+               if (tmp->end < start)
+                       continue;
+               if (tmp->start > end)
+                       continue;
+               if (end >= tmp->start)
+                       end = tmp->start - 1;
+       }
+
+       pr_info("LBA: lmmio_space [0x%lx-0x%lx] - new\n", start, end);
+
+       /* return new end */
+       return end;
+}
+
 #else
 #define truncate_pat_collision(r,n)  (0)
 #endif
@@ -994,6 +1042,14 @@ lba_pat_resources(struct parisc_device *pa_dev, struct lba_device *lba_dev)
                case PAT_LMMIO:
                        /* used to fix up pre-initialized MEM BARs */
                        if (!lba_dev->hba.lmmio_space.flags) {
+                               unsigned long lba_len;
+
+                               lba_len = ~READ_REG32(lba_dev->hba.base_addr
+                                               + LBA_LMMIO_MASK);
+                               if ((p->end - p->start) != lba_len)
+                                       p->end = extend_lmmio_len(p->start,
+                                               p->end, lba_len);
+
                                sprintf(lba_dev->hba.lmmio_name,
                                                "PCI%02x LMMIO",
                                                (int)lba_dev->hba.bus_num.start);
index 8577261..36a9e60 100644 (file)
@@ -176,6 +176,7 @@ config FUJITSU_TABLET
 config AMILO_RFKILL
        tristate "Fujitsu-Siemens Amilo rfkill support"
        depends on RFKILL
+       depends on SERIO_I8042
        ---help---
          This is a driver for enabling wifi on some Fujitsu-Siemens Amilo
          laptops.
@@ -591,6 +592,7 @@ config ACPI_TOSHIBA
        depends on BACKLIGHT_CLASS_DEVICE
        depends on INPUT
        depends on RFKILL || RFKILL = n
+       depends on SERIO_I8042 || SERIO_I8042 = n
        select INPUT_POLLDEV
        select INPUT_SPARSEKMAP
        ---help---
@@ -781,6 +783,32 @@ config APPLE_GMUX
          graphics as well as the backlight. Currently only backlight
          control is supported by the driver.
 
+config INTEL_RST
+        tristate "Intel Rapid Start Technology Driver"
+       depends on ACPI
+       ---help---
+         This driver provides support for modifying paramaters on systems
+         equipped with Intel's Rapid Start Technology. When put in an ACPI
+         sleep state, these devices will wake after either a configured
+         timeout or when the system battery reaches a critical state,
+         automatically copying memory contents to disk. On resume, the
+         firmware will copy the memory contents back to RAM and resume the OS
+         as usual.
+
+config INTEL_SMARTCONNECT
+        tristate "Intel Smart Connect disabling driver"
+       depends on ACPI
+       ---help---
+         Intel Smart Connect is a technology intended to permit devices to
+         update state by resuming for a short period of time at regular
+         intervals. If a user enables this functionality under Windows and
+         then reboots into Linux, the system may remain configured to resume
+         on suspend. In the absence of any userspace to support it, the system
+         will then remain awake until something triggers another suspend.
+
+         This driver checks to determine whether the device has Intel Smart
+         Connect enabled, and if so disables it.
+
 config PVPANIC
        tristate "pvpanic device support"
        depends on ACPI
index ef0ec74..5dbe193 100644 (file)
@@ -51,5 +51,7 @@ obj-$(CONFIG_INTEL_OAKTRAIL)  += intel_oaktrail.o
 obj-$(CONFIG_SAMSUNG_Q10)      += samsung-q10.o
 obj-$(CONFIG_APPLE_GMUX)       += apple-gmux.o
 obj-$(CONFIG_CHROMEOS_LAPTOP)  += chromeos_laptop.o
+obj-$(CONFIG_INTEL_RST)                += intel-rst.o
+obj-$(CONFIG_INTEL_SMARTCONNECT)       += intel-smartconnect.o
 
 obj-$(CONFIG_PVPANIC)           += pvpanic.o
index 0eea09c..8e268da 100644 (file)
@@ -1935,7 +1935,6 @@ fail_input:
 fail_backlight:
        asus_platform_exit(asus);
 fail_platform:
-       kfree(asus->name);
        kfree(asus);
 
        return result;
index 8fcb41e..563f59e 100644 (file)
@@ -180,6 +180,24 @@ static struct dmi_system_id asus_quirks[] = {
                },
                .driver_data = &quirk_asus_x401u,
        },
+       {
+               .callback = dmi_matched,
+               .ident = "ASUSTeK COMPUTER INC. 1015E",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "1015E"),
+               },
+               .driver_data = &quirk_asus_x401u,
+       },
+       {
+               .callback = dmi_matched,
+               .ident = "ASUSTeK COMPUTER INC. 1015U",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "1015U"),
+               },
+               .driver_data = &quirk_asus_x401u,
+       },
        {},
 };
 
@@ -256,6 +274,7 @@ static const struct key_entry asus_nb_wmi_keymap[] = {
        { KE_KEY, 0xB5, { KEY_CALC } },
        { KE_KEY, 0xC4, { KEY_KBDILLUMUP } },
        { KE_KEY, 0xC5, { KEY_KBDILLUMDOWN } },
+       { KE_IGNORE, 0xC6, },  /* Ambient Light Sensor notification */
        { KE_END, 0},
 };
 
index c11b242..19c313b 100644 (file)
@@ -558,7 +558,7 @@ static int asus_wmi_led_init(struct asus_wmi *asus)
                        goto error;
        }
 
-       if (wlan_led_presence(asus)) {
+       if (wlan_led_presence(asus) && (asus->driver->quirks->wapf == 4)) {
                INIT_WORK(&asus->wlan_led_work, wlan_led_update);
 
                asus->wlan_led.name = "asus::wlan";
@@ -886,7 +886,8 @@ static int asus_new_rfkill(struct asus_wmi *asus,
        if (!*rfkill)
                return -EINVAL;
 
-       if (dev_id == ASUS_WMI_DEVID_WLAN)
+       if ((dev_id == ASUS_WMI_DEVID_WLAN) &&
+                       (asus->driver->quirks->wapf == 4))
                rfkill_set_led_trigger_name(*rfkill, "asus-wlan");
 
        rfkill_init_sw_state(*rfkill, !result);
@@ -1045,7 +1046,7 @@ static ssize_t asus_hwmon_pwm1(struct device *dev,
        else if (value == 3)
                value = 255;
        else if (value != 0) {
-               pr_err("Unknown fan speed %#x", value);
+               pr_err("Unknown fan speed %#x\n", value);
                value = -1;
        }
 
@@ -1557,11 +1558,11 @@ static int asus_wmi_platform_init(struct asus_wmi *asus)
 
        /* INIT enable hotkeys on some models */
        if (!asus_wmi_evaluate_method(ASUS_WMI_METHODID_INIT, 0, 0, &rv))
-               pr_info("Initialization: %#x", rv);
+               pr_info("Initialization: %#x\n", rv);
 
        /* We don't know yet what to do with this version... */
        if (!asus_wmi_evaluate_method(ASUS_WMI_METHODID_SPEC, 0, 0x9, &rv)) {
-               pr_info("BIOS WMI version: %d.%d", rv >> 16, rv & 0xFF);
+               pr_info("BIOS WMI version: %d.%d\n", rv >> 16, rv & 0xFF);
                asus->spec = rv;
        }
 
@@ -1572,7 +1573,7 @@ static int asus_wmi_platform_init(struct asus_wmi *asus)
         * The significance of others is yet to be found.
         */
        if (!asus_wmi_evaluate_method(ASUS_WMI_METHODID_SFUN, 0, 0, &rv)) {
-               pr_info("SFUN value: %#x", rv);
+               pr_info("SFUN value: %#x\n", rv);
                asus->sfun = rv;
        }
 
@@ -1712,7 +1713,7 @@ static int asus_wmi_debugfs_init(struct asus_wmi *asus)
 
        asus->debug.root = debugfs_create_dir(asus->driver->name, NULL);
        if (!asus->debug.root) {
-               pr_err("failed to create debugfs directory");
+               pr_err("failed to create debugfs directory\n");
                goto error_debugfs;
        }
 
@@ -1985,17 +1986,17 @@ EXPORT_SYMBOL_GPL(asus_wmi_unregister_driver);
 static int __init asus_wmi_init(void)
 {
        if (!wmi_has_guid(ASUS_WMI_MGMT_GUID)) {
-               pr_info("Asus Management GUID not found");
+               pr_info("Asus Management GUID not found\n");
                return -ENODEV;
        }
 
-       pr_info("ASUS WMI generic driver loaded");
+       pr_info("ASUS WMI generic driver loaded\n");
        return 0;
 }
 
 static void __exit asus_wmi_exit(void)
 {
-       pr_info("ASUS WMI generic driver unloaded");
+       pr_info("ASUS WMI generic driver unloaded\n");
 }
 
 module_init(asus_wmi_init);
index 1134119..bb77e18 100644 (file)
@@ -551,9 +551,10 @@ static int __init dell_init(void)
         * is passed to SMI handler.
         */
        bufferpage = alloc_page(GFP_KERNEL | GFP_DMA32);
-
-       if (!bufferpage)
+       if (!bufferpage) {
+               ret = -ENOMEM;
                goto fail_buffer;
+       }
        buffer = page_address(bufferpage);
 
        if (quirks && quirks->touchpad_led)
index d111c86..97bb05e 100644 (file)
@@ -53,8 +53,10 @@ MODULE_ALIAS("wmi:5FB7F034-2C63-45e9-BE91-3D44E2C707E4");
 #define HPWMI_ALS_QUERY 0x3
 #define HPWMI_HARDWARE_QUERY 0x4
 #define HPWMI_WIRELESS_QUERY 0x5
+#define HPWMI_BIOS_QUERY 0x9
 #define HPWMI_HOTKEY_QUERY 0xc
 #define HPWMI_WIRELESS2_QUERY 0x1b
+#define HPWMI_POSTCODEERROR_QUERY 0x2a
 
 enum hp_wmi_radio {
        HPWMI_WIFI = 0,
@@ -291,6 +293,19 @@ static int hp_wmi_tablet_state(void)
        return (state & 0x4) ? 1 : 0;
 }
 
+static int hp_wmi_enable_hotkeys(void)
+{
+       int ret;
+       int query = 0x6e;
+
+       ret = hp_wmi_perform_query(HPWMI_BIOS_QUERY, 1, &query, sizeof(query),
+                                  0);
+
+       if (ret)
+               return -EINVAL;
+       return 0;
+}
+
 static int hp_wmi_set_block(void *data, bool blocked)
 {
        enum hp_wmi_radio r = (enum hp_wmi_radio) data;
@@ -386,6 +401,16 @@ static int hp_wmi_rfkill2_refresh(void)
        return 0;
 }
 
+static int hp_wmi_post_code_state(void)
+{
+       int state = 0;
+       int ret = hp_wmi_perform_query(HPWMI_POSTCODEERROR_QUERY, 0, &state,
+                                      sizeof(state), sizeof(state));
+       if (ret)
+               return -EINVAL;
+       return state;
+}
+
 static ssize_t show_display(struct device *dev, struct device_attribute *attr,
                            char *buf)
 {
@@ -431,6 +456,16 @@ static ssize_t show_tablet(struct device *dev, struct device_attribute *attr,
        return sprintf(buf, "%d\n", value);
 }
 
+static ssize_t show_postcode(struct device *dev, struct device_attribute *attr,
+                        char *buf)
+{
+       /* Get the POST error code of previous boot failure. */
+       int value = hp_wmi_post_code_state();
+       if (value < 0)
+               return -EINVAL;
+       return sprintf(buf, "0x%x\n", value);
+}
+
 static ssize_t set_als(struct device *dev, struct device_attribute *attr,
                       const char *buf, size_t count)
 {
@@ -443,11 +478,33 @@ static ssize_t set_als(struct device *dev, struct device_attribute *attr,
        return count;
 }
 
+static ssize_t set_postcode(struct device *dev, struct device_attribute *attr,
+                      const char *buf, size_t count)
+{
+       int ret;
+       u32 tmp;
+       long unsigned int tmp2;
+
+       ret = kstrtoul(buf, 10, &tmp2);
+       if (ret || tmp2 != 1)
+               return -EINVAL;
+
+       /* Clear the POST error code. It is kept until until cleared. */
+       tmp = (u32) tmp2;
+       ret = hp_wmi_perform_query(HPWMI_POSTCODEERROR_QUERY, 1, &tmp,
+                                      sizeof(tmp), sizeof(tmp));
+       if (ret)
+               return -EINVAL;
+
+       return count;
+}
+
 static DEVICE_ATTR(display, S_IRUGO, show_display, NULL);
 static DEVICE_ATTR(hddtemp, S_IRUGO, show_hddtemp, NULL);
 static DEVICE_ATTR(als, S_IRUGO | S_IWUSR, show_als, set_als);
 static DEVICE_ATTR(dock, S_IRUGO, show_dock, NULL);
 static DEVICE_ATTR(tablet, S_IRUGO, show_tablet, NULL);
+static DEVICE_ATTR(postcode, S_IRUGO | S_IWUSR, show_postcode, set_postcode);
 
 static void hp_wmi_notify(u32 value, void *context)
 {
@@ -628,6 +685,7 @@ static void cleanup_sysfs(struct platform_device *device)
        device_remove_file(&device->dev, &dev_attr_als);
        device_remove_file(&device->dev, &dev_attr_dock);
        device_remove_file(&device->dev, &dev_attr_tablet);
+       device_remove_file(&device->dev, &dev_attr_postcode);
 }
 
 static int hp_wmi_rfkill_setup(struct platform_device *device)
@@ -845,6 +903,9 @@ static int __init hp_wmi_bios_setup(struct platform_device *device)
        err = device_create_file(&device->dev, &dev_attr_tablet);
        if (err)
                goto add_sysfs_error;
+       err = device_create_file(&device->dev, &dev_attr_postcode);
+       if (err)
+               goto add_sysfs_error;
        return 0;
 
 add_sysfs_error:
@@ -948,6 +1009,8 @@ static int __init hp_wmi_init(void)
                err = hp_wmi_input_setup();
                if (err)
                        return err;
+
+               hp_wmi_enable_hotkeys();
        }
 
        if (bios_capable) {
diff --git a/drivers/platform/x86/intel-rst.c b/drivers/platform/x86/intel-rst.c
new file mode 100644 (file)
index 0000000..9385afd
--- /dev/null
@@ -0,0 +1,209 @@
+/*
+ *  Copyright 2013 Matthew Garrett <mjg59@srcf.ucam.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <acpi/acpi_drivers.h>
+
+MODULE_LICENSE("GPL");
+
+static ssize_t irst_show_wakeup_events(struct device *dev,
+                                      struct device_attribute *attr,
+                                      char *buf)
+{
+       struct acpi_device *acpi;
+       struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
+       union acpi_object *result;
+       acpi_status status;
+
+       acpi = to_acpi_device(dev);
+
+       status = acpi_evaluate_object(acpi->handle, "GFFS", NULL, &output);
+       if (!ACPI_SUCCESS(status))
+               return -EINVAL;
+
+       result = output.pointer;
+
+       if (result->type != ACPI_TYPE_INTEGER) {
+               kfree(result);
+               return -EINVAL;
+       }
+
+       return sprintf(buf, "%lld\n", result->integer.value);
+}
+
+static ssize_t irst_store_wakeup_events(struct device *dev,
+                                       struct device_attribute *attr,
+                                       const char *buf, size_t count)
+{
+       struct acpi_device *acpi;
+       struct acpi_object_list input;
+       union acpi_object param;
+       acpi_status status;
+       unsigned long value;
+       int error;
+
+       acpi = to_acpi_device(dev);
+
+       error = kstrtoul(buf, 0, &value);
+
+       if (error)
+               return error;
+
+       param.type = ACPI_TYPE_INTEGER;
+       param.integer.value = value;
+
+       input.count = 1;
+       input.pointer = &param;
+
+       status = acpi_evaluate_object(acpi->handle, "SFFS", &input, NULL);
+
+       if (!ACPI_SUCCESS(status))
+               return -EINVAL;
+
+       return count;
+}
+
+static struct device_attribute irst_wakeup_attr = {
+       .attr = { .name = "wakeup_events", .mode = 0600 },
+       .show = irst_show_wakeup_events,
+       .store = irst_store_wakeup_events
+};
+
+static ssize_t irst_show_wakeup_time(struct device *dev,
+                                    struct device_attribute *attr, char *buf)
+{
+       struct acpi_device *acpi;
+       struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
+       union acpi_object *result;
+       acpi_status status;
+
+       acpi = to_acpi_device(dev);
+
+       status = acpi_evaluate_object(acpi->handle, "GFTV", NULL, &output);
+       if (!ACPI_SUCCESS(status))
+               return -EINVAL;
+
+       result = output.pointer;
+
+       if (result->type != ACPI_TYPE_INTEGER) {
+               kfree(result);
+               return -EINVAL;
+       }
+
+       return sprintf(buf, "%lld\n", result->integer.value);
+}
+
+static ssize_t irst_store_wakeup_time(struct device *dev,
+                                     struct device_attribute *attr,
+                                     const char *buf, size_t count)
+{
+       struct acpi_device *acpi;
+       struct acpi_object_list input;
+       union acpi_object param;
+       acpi_status status;
+       unsigned long value;
+       int error;
+
+       acpi = to_acpi_device(dev);
+
+       error = kstrtoul(buf, 0, &value);
+
+       if (error)
+               return error;
+
+       param.type = ACPI_TYPE_INTEGER;
+       param.integer.value = value;
+
+       input.count = 1;
+       input.pointer = &param;
+
+       status = acpi_evaluate_object(acpi->handle, "SFTV", &input, NULL);
+
+       if (!ACPI_SUCCESS(status))
+               return -EINVAL;
+
+       return count;
+}
+
+static struct device_attribute irst_timeout_attr = {
+       .attr = { .name = "wakeup_time", .mode = 0600 },
+       .show = irst_show_wakeup_time,
+       .store = irst_store_wakeup_time
+};
+
+static int irst_add(struct acpi_device *acpi)
+{
+       int error = 0;
+
+       error = device_create_file(&acpi->dev, &irst_timeout_attr);
+       if (error)
+               goto out;
+
+       error = device_create_file(&acpi->dev, &irst_wakeup_attr);
+       if (error)
+               goto out_timeout;
+
+       return 0;
+
+out_timeout:
+       device_remove_file(&acpi->dev, &irst_timeout_attr);
+out:
+       return error;
+}
+
+static int irst_remove(struct acpi_device *acpi)
+{
+       device_remove_file(&acpi->dev, &irst_wakeup_attr);
+       device_remove_file(&acpi->dev, &irst_timeout_attr);
+
+       return 0;
+}
+
+static const struct acpi_device_id irst_ids[] = {
+       {"INT3392", 0},
+       {"", 0}
+};
+
+static struct acpi_driver irst_driver = {
+       .owner = THIS_MODULE,
+       .name = "intel_rapid_start",
+       .class = "intel_rapid_start",
+       .ids = irst_ids,
+       .ops = {
+               .add = irst_add,
+               .remove = irst_remove,
+       },
+};
+
+static int irst_init(void)
+{
+       return acpi_bus_register_driver(&irst_driver);
+}
+
+static void irst_exit(void)
+{
+       acpi_bus_unregister_driver(&irst_driver);
+}
+
+module_init(irst_init);
+module_exit(irst_exit);
+
+MODULE_DEVICE_TABLE(acpi, irst_ids);
diff --git a/drivers/platform/x86/intel-smartconnect.c b/drivers/platform/x86/intel-smartconnect.c
new file mode 100644 (file)
index 0000000..f74e93d
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ *  Copyright 2013 Matthew Garrett <mjg59@srcf.ucam.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <acpi/acpi_drivers.h>
+
+MODULE_LICENSE("GPL");
+
+static int smartconnect_acpi_init(struct acpi_device *acpi)
+{
+       struct acpi_object_list input;
+       struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
+       union acpi_object *result;
+       union acpi_object param;
+       acpi_status status;
+
+       status = acpi_evaluate_object(acpi->handle, "GAOS", NULL, &output);
+       if (!ACPI_SUCCESS(status))
+               return -EINVAL;
+
+       result = output.pointer;
+
+       if (result->type != ACPI_TYPE_INTEGER) {
+               kfree(result);
+               return -EINVAL;
+       }
+
+       if (result->integer.value & 0x1) {
+               param.type = ACPI_TYPE_INTEGER;
+               param.integer.value = 0;
+
+               input.count = 1;
+               input.pointer = &param;
+
+               dev_info(&acpi->dev, "Disabling Intel Smart Connect\n");
+               status = acpi_evaluate_object(acpi->handle, "SAOS", &input,
+                                             NULL);
+       }
+
+       kfree(result);
+
+       return 0;
+}
+
+static const struct acpi_device_id smartconnect_ids[] = {
+       {"INT33A0", 0},
+       {"", 0}
+};
+
+static struct acpi_driver smartconnect_driver = {
+       .owner = THIS_MODULE,
+       .name = "intel_smart_connect",
+       .class = "intel_smart_connect",
+       .ids = smartconnect_ids,
+       .ops = {
+               .add = smartconnect_acpi_init,
+       },
+};
+
+static int smartconnect_init(void)
+{
+       return acpi_bus_register_driver(&smartconnect_driver);
+}
+
+static void smartconnect_exit(void)
+{
+       acpi_bus_unregister_driver(&smartconnect_driver);
+}
+
+module_init(smartconnect_init);
+module_exit(smartconnect_exit);
+
+MODULE_DEVICE_TABLE(acpi, smartconnect_ids);
index 5051aa9..18dcb58 100644 (file)
@@ -1731,18 +1731,7 @@ static struct pci_driver ips_pci_driver = {
        .shutdown = ips_shutdown,
 };
 
-static int __init ips_init(void)
-{
-       return pci_register_driver(&ips_pci_driver);
-}
-module_init(ips_init);
-
-static void ips_exit(void)
-{
-       pci_unregister_driver(&ips_pci_driver);
-       return;
-}
-module_exit(ips_exit);
+module_pci_driver(ips_pci_driver);
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Jesse Barnes <jbarnes@virtuousgeek.org>");
index 6f4b728..2805988 100644 (file)
@@ -288,7 +288,7 @@ static int platform_pmic_gpio_probe(struct platform_device *pdev)
        retval = request_irq(pg->irq, pmic_irq_handler, 0, "pmic", pg);
        if (retval) {
                pr_warn("Interrupt request failed\n");
-               goto err;
+               goto fail_request_irq;
        }
 
        for (i = 0; i < 8; i++) {
@@ -299,6 +299,10 @@ static int platform_pmic_gpio_probe(struct platform_device *pdev)
                irq_set_chip_data(i + pg->irq_base, pg);
        }
        return 0;
+
+fail_request_irq:
+       if (gpiochip_remove(&pg->chip))
+               pr_err("gpiochip_remove failed\n");
 err:
        iounmap(pg->gpiointr);
 err2:
index 6b22938..62f8030 100644 (file)
@@ -1098,29 +1098,29 @@ static int __init msi_init(void)
 
        ret = platform_device_add(msipf_device);
        if (ret)
-               goto fail_platform_device1;
+               goto fail_device_add;
 
        if (quirks->load_scm_model && (load_scm_model_init(msipf_device) < 0)) {
                ret = -EINVAL;
-               goto fail_platform_device1;
+               goto fail_scm_model_init;
        }
 
        ret = sysfs_create_group(&msipf_device->dev.kobj,
                                 &msipf_attribute_group);
        if (ret)
-               goto fail_platform_device2;
+               goto fail_create_group;
 
        if (!quirks->old_ec_model) {
                if (threeg_exists)
                        ret = device_create_file(&msipf_device->dev,
                                                &dev_attr_threeg);
                if (ret)
-                       goto fail_platform_device2;
+                       goto fail_create_attr;
        } else {
                ret = sysfs_create_group(&msipf_device->dev.kobj,
                                         &msipf_old_attribute_group);
                if (ret)
-                       goto fail_platform_device2;
+                       goto fail_create_attr;
 
                /* Disable automatic brightness control by default because
                 * this module was probably loaded to do brightness control in
@@ -1134,26 +1134,22 @@ static int __init msi_init(void)
 
        return 0;
 
-fail_platform_device2:
-
+fail_create_attr:
+       sysfs_remove_group(&msipf_device->dev.kobj, &msipf_attribute_group);
+fail_create_group:
        if (quirks->load_scm_model) {
                i8042_remove_filter(msi_laptop_i8042_filter);
                cancel_delayed_work_sync(&msi_rfkill_dwork);
                cancel_work_sync(&msi_rfkill_work);
                rfkill_cleanup();
        }
+fail_scm_model_init:
        platform_device_del(msipf_device);
-
-fail_platform_device1:
-
+fail_device_add:
        platform_device_put(msipf_device);
-
 fail_platform_driver:
-
        platform_driver_unregister(&msipf_driver);
-
 fail_backlight:
-
        backlight_device_unregister(msibl_device);
 
        return ret;
index d338c1c..dfcda3a 100644 (file)
@@ -992,7 +992,6 @@ static int pm860x_battery_remove(struct platform_device *pdev)
        free_irq(info->irq_batt, info);
        free_irq(info->irq_cc, info);
        power_supply_unregister(&info->battery);
-       platform_set_drvdata(pdev, NULL);
        return 0;
 }
 
index 36fb4b5..ffff66b 100644 (file)
@@ -722,7 +722,6 @@ static int pm860x_charger_remove(struct platform_device *pdev)
        struct pm860x_charger_info *info = platform_get_drvdata(pdev);
        int i;
 
-       platform_set_drvdata(pdev, NULL);
        power_supply_unregister(&info->usb);
        free_irq(info->irq[0], info);
        for (i = 0; i < info->irq_nums; i++)
index d412d34..7f9a454 100644 (file)
@@ -1045,7 +1045,6 @@ static int ab8500_btemp_remove(struct platform_device *pdev)
 
        flush_scheduled_work();
        power_supply_unregister(&di->btemp_psy);
-       platform_set_drvdata(pdev, NULL);
 
        return 0;
 }
index a558318..f098fda 100644 (file)
@@ -3425,8 +3425,6 @@ static int ab8500_charger_remove(struct platform_device *pdev)
        if (di->ac_chg.enabled && !di->ac_chg.external)
                power_supply_unregister(&di->ac_chg.psy);
 
-       platform_set_drvdata(pdev, NULL);
-
        return 0;
 }
 
index c5391f5..7549707 100644 (file)
@@ -2465,9 +2465,9 @@ static ssize_t charge_full_store(struct ab8500_fg *di, const char *buf,
                                 size_t count)
 {
        unsigned long charge_full;
-       ssize_t ret = -EINVAL;
+       ssize_t ret;
 
-       ret = strict_strtoul(buf, 10, &charge_full);
+       ret = kstrtoul(buf, 10, &charge_full);
 
        dev_dbg(di->dev, "Ret %zd charge_full %lu", ret, charge_full);
 
@@ -2489,7 +2489,7 @@ static ssize_t charge_now_store(struct ab8500_fg *di, const char *buf,
        unsigned long charge_now;
        ssize_t ret;
 
-       ret = strict_strtoul(buf, 10, &charge_now);
+       ret = kstrtoul(buf, 10, &charge_now);
 
        dev_dbg(di->dev, "Ret %zd charge_now %lu was %d",
                ret, charge_now, di->bat_cap.prev_mah);
@@ -3070,7 +3070,6 @@ static int ab8500_fg_remove(struct platform_device *pdev)
        flush_scheduled_work();
        ab8500_fg_sysfs_psy_remove_attrs(di->fg_psy.dev);
        power_supply_unregister(&di->fg_psy);
-       platform_set_drvdata(pdev, NULL);
        return ret;
 }
 
index 9863e42..6d27236 100644 (file)
@@ -2035,7 +2035,6 @@ static int abx500_chargalg_remove(struct platform_device *pdev)
        destroy_workqueue(di->chargalg_wq);
 
        power_supply_unregister(&di->chargalg_psy);
-       platform_set_drvdata(pdev, NULL);
 
        return 0;
 }
index 26037ca..b309713 100644 (file)
@@ -966,7 +966,6 @@ static int bq27000_battery_probe(struct platform_device *pdev)
        return 0;
 
 err_free:
-       platform_set_drvdata(pdev, NULL);
        kfree(di);
 
        return ret;
@@ -978,7 +977,6 @@ static int bq27000_battery_remove(struct platform_device *pdev)
 
        bq27x00_powersupply_unregister(di);
 
-       platform_set_drvdata(pdev, NULL);
        kfree(di);
 
        return 0;
index fefc39f..e30e847 100644 (file)
@@ -12,6 +12,8 @@
  * published by the Free Software Foundation.
 **/
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/io.h>
 #include <linux/module.h>
 #include <linux/irq.h>
@@ -195,8 +197,8 @@ static bool is_charging(struct charger_manager *cm)
                                cm->charger_stat[i],
                                POWER_SUPPLY_PROP_ONLINE, &val);
                if (ret) {
-                       dev_warn(cm->dev, "Cannot read ONLINE value from %s.\n",
-                                       cm->desc->psy_charger_stat[i]);
+                       dev_warn(cm->dev, "Cannot read ONLINE value from %s\n",
+                                cm->desc->psy_charger_stat[i]);
                        continue;
                }
                if (val.intval == 0)
@@ -210,8 +212,8 @@ static bool is_charging(struct charger_manager *cm)
                                cm->charger_stat[i],
                                POWER_SUPPLY_PROP_STATUS, &val);
                if (ret) {
-                       dev_warn(cm->dev, "Cannot read STATUS value from %s.\n",
-                                       cm->desc->psy_charger_stat[i]);
+                       dev_warn(cm->dev, "Cannot read STATUS value from %s\n",
+                                cm->desc->psy_charger_stat[i]);
                        continue;
                }
                if (val.intval == POWER_SUPPLY_STATUS_FULL ||
@@ -289,7 +291,7 @@ static bool is_polling_required(struct charger_manager *cm)
                return is_charging(cm);
        default:
                dev_warn(cm->dev, "Incorrect polling_mode (%d)\n",
-                       cm->desc->polling_mode);
+                        cm->desc->polling_mode);
        }
 
        return false;
@@ -331,9 +333,8 @@ static int try_charger_enable(struct charger_manager *cm, bool enable)
 
                        err = regulator_enable(desc->charger_regulators[i].consumer);
                        if (err < 0) {
-                               dev_warn(cm->dev,
-                                       "Cannot enable %s regulator\n",
-                                       desc->charger_regulators[i].regulator_name);
+                               dev_warn(cm->dev, "Cannot enable %s regulator\n",
+                                        desc->charger_regulators[i].regulator_name);
                        }
                }
        } else {
@@ -350,9 +351,8 @@ static int try_charger_enable(struct charger_manager *cm, bool enable)
 
                        err = regulator_disable(desc->charger_regulators[i].consumer);
                        if (err < 0) {
-                               dev_warn(cm->dev,
-                                       "Cannot disable %s regulator\n",
-                                       desc->charger_regulators[i].regulator_name);
+                               dev_warn(cm->dev, "Cannot disable %s regulator\n",
+                                        desc->charger_regulators[i].regulator_name);
                        }
                }
 
@@ -365,9 +365,8 @@ static int try_charger_enable(struct charger_manager *cm, bool enable)
                                    desc->charger_regulators[i].consumer)) {
                                regulator_force_disable(
                                        desc->charger_regulators[i].consumer);
-                               dev_warn(cm->dev,
-                                       "Disable regulator(%s) forcibly.\n",
-                                       desc->charger_regulators[i].regulator_name);
+                               dev_warn(cm->dev, "Disable regulator(%s) forcibly\n",
+                                        desc->charger_regulators[i].regulator_name);
                        }
                }
        }
@@ -450,7 +449,7 @@ static void uevent_notify(struct charger_manager *cm, const char *event)
        strncpy(env_str, event, UEVENT_BUF_SIZE);
        kobject_uevent(&cm->dev->kobj, KOBJ_CHANGE);
 
-       dev_info(cm->dev, event);
+       dev_info(cm->dev, "%s\n", event);
 }
 
 /**
@@ -478,7 +477,7 @@ static void fullbatt_vchk(struct work_struct *work)
 
        err = get_batt_uV(cm, &batt_uV);
        if (err) {
-               dev_err(cm->dev, "%s: get_batt_uV error(%d).\n", __func__, err);
+               dev_err(cm->dev, "%s: get_batt_uV error(%d)\n", __func__, err);
                return;
        }
 
@@ -486,7 +485,7 @@ static void fullbatt_vchk(struct work_struct *work)
        if (diff < 0)
                return;
 
-       dev_info(cm->dev, "VBATT dropped %duV after full-batt.\n", diff);
+       dev_info(cm->dev, "VBATT dropped %duV after full-batt\n", diff);
 
        if (diff > desc->fullbatt_vchkdrop_uV) {
                try_charger_restart(cm);
@@ -519,7 +518,7 @@ static int check_charging_duration(struct charger_manager *cm)
                duration = curr - cm->charging_start_time;
 
                if (duration > desc->charging_max_duration_ms) {
-                       dev_info(cm->dev, "Charging duration exceed %lldms",
+                       dev_info(cm->dev, "Charging duration exceed %lldms\n",
                                 desc->charging_max_duration_ms);
                        uevent_notify(cm, "Discharging");
                        try_charger_enable(cm, false);
@@ -530,9 +529,9 @@ static int check_charging_duration(struct charger_manager *cm)
 
                if (duration > desc->charging_max_duration_ms &&
                                is_ext_pwr_online(cm)) {
-                       dev_info(cm->dev, "DisCharging duration exceed %lldms",
+                       dev_info(cm->dev, "Discharging duration exceed %lldms\n",
                                 desc->discharging_max_duration_ms);
-                       uevent_notify(cm, "Recharing");
+                       uevent_notify(cm, "Recharging");
                        try_charger_enable(cm, true);
                        ret = true;
                }
@@ -579,7 +578,7 @@ static bool _cm_monitor(struct charger_manager *cm)
         */
        } else if (!cm->emergency_stop && check_charging_duration(cm)) {
                dev_dbg(cm->dev,
-                       "Charging/Discharging duration is out of range");
+                       "Charging/Discharging duration is out of range\n");
        /*
         * Check dropped voltage of battery. If battery voltage is more
         * dropped than fullbatt_vchkdrop_uV after fully charged state,
@@ -595,7 +594,7 @@ static bool _cm_monitor(struct charger_manager *cm)
         */
        } else if (!cm->emergency_stop && is_full_charged(cm) &&
                        cm->charger_enabled) {
-               dev_info(cm->dev, "EVENT_HANDLE: Battery Fully Charged.\n");
+               dev_info(cm->dev, "EVENT_HANDLE: Battery Fully Charged\n");
                uevent_notify(cm, default_event_names[CM_EVENT_BATT_FULL]);
 
                try_charger_enable(cm, false);
@@ -725,7 +724,7 @@ static void fullbatt_handler(struct charger_manager *cm)
                cm->fullbatt_vchk_jiffies_at = 1;
 
 out:
-       dev_info(cm->dev, "EVENT_HANDLE: Battery Fully Charged.\n");
+       dev_info(cm->dev, "EVENT_HANDLE: Battery Fully Charged\n");
        uevent_notify(cm, default_event_names[CM_EVENT_BATT_FULL]);
 }
 
@@ -972,7 +971,7 @@ static bool cm_setup_timer(void)
        mutex_unlock(&cm_list_mtx);
 
        if (wakeup_ms < UINT_MAX && wakeup_ms > 0) {
-               pr_info("Charger Manager wakeup timer: %u ms.\n", wakeup_ms);
+               pr_info("Charger Manager wakeup timer: %u ms\n", wakeup_ms);
                if (rtc_dev) {
                        struct rtc_wkalrm tmp;
                        unsigned long time, now;
@@ -1005,8 +1004,7 @@ static bool cm_setup_timer(void)
                                ret = false;
                        }
 
-                       pr_info("Waking up after %lu secs.\n",
-                                       time - now);
+                       pr_info("Waking up after %lu secs\n", time - now);
 
                        rtc_time_to_tm(time, &tmp.time);
                        rtc_set_alarm(rtc_dev, &tmp);
@@ -1101,7 +1099,7 @@ int setup_charger_manager(struct charger_global_desc *gd)
        g_desc = NULL;
 
        if (!gd->rtc_only_wakeup) {
-               pr_err("The callback rtc_only_wakeup is not given.\n");
+               pr_err("The callback rtc_only_wakeup is not given\n");
                return -EINVAL;
        }
 
@@ -1112,7 +1110,7 @@ int setup_charger_manager(struct charger_global_desc *gd)
                        /* Retry at probe. RTC may be not registered yet */
                }
        } else {
-               pr_warn("No wakeup timer is given for charger manager."
+               pr_warn("No wakeup timer is given for charger manager.  "
                        "In-suspend monitoring won't work.\n");
        }
 
@@ -1138,13 +1136,13 @@ static void charger_extcon_work(struct work_struct *work)
                                        cable->min_uA, cable->max_uA);
                if (ret < 0) {
                        pr_err("Cannot set current limit of %s (%s)\n",
-                               cable->charger->regulator_name, cable->name);
+                              cable->charger->regulator_name, cable->name);
                        return;
                }
 
                pr_info("Set current limit of %s : %duA ~ %duA\n",
-                                       cable->charger->regulator_name,
-                                       cable->min_uA, cable->max_uA);
+                       cable->charger->regulator_name,
+                       cable->min_uA, cable->max_uA);
        }
 
        try_charger_enable(cable->cm, cable->attached);
@@ -1210,9 +1208,8 @@ static int charger_extcon_init(struct charger_manager *cm,
        ret = extcon_register_interest(&cable->extcon_dev,
                        cable->extcon_name, cable->name, &cable->nb);
        if (ret < 0) {
-               pr_info("Cannot register extcon_dev for %s(cable: %s).\n",
-                               cable->extcon_name,
-                               cable->name);
+               pr_info("Cannot register extcon_dev for %s(cable: %s)\n",
+                       cable->extcon_name, cable->name);
                ret = -EINVAL;
        }
 
@@ -1242,11 +1239,10 @@ static int charger_manager_register_extcon(struct charger_manager *cm)
 
                charger->consumer = regulator_get(cm->dev,
                                        charger->regulator_name);
-               if (charger->consumer == NULL) {
-                       dev_err(cm->dev, "Cannot find charger(%s)n",
-                                       charger->regulator_name);
-                       ret = -EINVAL;
-                       goto err;
+               if (IS_ERR(charger->consumer)) {
+                       dev_err(cm->dev, "Cannot find charger(%s)\n",
+                               charger->regulator_name);
+                       return PTR_ERR(charger->consumer);
                }
                charger->cm = cm;
 
@@ -1255,8 +1251,8 @@ static int charger_manager_register_extcon(struct charger_manager *cm)
 
                        ret = charger_extcon_init(cm, cable);
                        if (ret < 0) {
-                               dev_err(cm->dev, "Cannot initialize charger(%s)n",
-                                               charger->regulator_name);
+                               dev_err(cm->dev, "Cannot initialize charger(%s)\n",
+                                       charger->regulator_name);
                                goto err;
                        }
                        cable->charger = charger;
@@ -1347,10 +1343,8 @@ static ssize_t charger_externally_control_store(struct device *dev,
                }
        } else {
                dev_warn(cm->dev,
-                       "'%s' regulator should be controlled "
-                       "in charger-manager because charger-manager "
-                       "must need at least one charger for charging\n",
-                       charger->regulator_name);
+                        "'%s' regulator should be controlled in charger-manager because charger-manager must need at least one charger for charging\n",
+                        charger->regulator_name);
        }
 
        return count;
@@ -1386,8 +1380,6 @@ static int charger_manager_register_sysfs(struct charger_manager *cm)
                snprintf(buf, 10, "charger.%d", i);
                str = kzalloc(sizeof(char) * (strlen(buf) + 1), GFP_KERNEL);
                if (!str) {
-                       dev_err(cm->dev, "Cannot allocate memory: %s\n",
-                                       charger->regulator_name);
                        ret = -ENOMEM;
                        goto err;
                }
@@ -1423,26 +1415,21 @@ static int charger_manager_register_sysfs(struct charger_manager *cm)
                                !chargers_externally_control)
                        chargers_externally_control = 0;
 
-               dev_info(cm->dev, "'%s' regulator's externally_control"
-                               "is %d\n", charger->regulator_name,
-                               charger->externally_control);
+               dev_info(cm->dev, "'%s' regulator's externally_control is %d\n",
+                        charger->regulator_name, charger->externally_control);
 
                ret = sysfs_create_group(&cm->charger_psy.dev->kobj,
                                        &charger->attr_g);
                if (ret < 0) {
-                       dev_err(cm->dev, "Cannot create sysfs entry"
-                                       "of %s regulator\n",
-                                       charger->regulator_name);
+                       dev_err(cm->dev, "Cannot create sysfs entry of %s regulator\n",
+                               charger->regulator_name);
                        ret = -EINVAL;
                        goto err;
                }
        }
 
        if (chargers_externally_control) {
-               dev_err(cm->dev, "Cannot register regulator because "
-                               "charger-manager must need at least "
-                               "one charger for charging battery\n");
-
+               dev_err(cm->dev, "Cannot register regulator because charger-manager must need at least one charger for charging battery\n");
                ret = -EINVAL;
                goto err;
        }
@@ -1463,7 +1450,7 @@ static int charger_manager_probe(struct platform_device *pdev)
                rtc_dev = rtc_class_open(g_desc->rtc_name);
                if (IS_ERR_OR_NULL(rtc_dev)) {
                        rtc_dev = NULL;
-                       dev_err(&pdev->dev, "Cannot get RTC %s.\n",
+                       dev_err(&pdev->dev, "Cannot get RTC %s\n",
                                g_desc->rtc_name);
                        ret = -ENODEV;
                        goto err_alloc;
@@ -1471,14 +1458,13 @@ static int charger_manager_probe(struct platform_device *pdev)
        }
 
        if (!desc) {
-               dev_err(&pdev->dev, "No platform data (desc) found.\n");
+               dev_err(&pdev->dev, "No platform data (desc) found\n");
                ret = -ENODEV;
                goto err_alloc;
        }
 
        cm = kzalloc(sizeof(struct charger_manager), GFP_KERNEL);
        if (!cm) {
-               dev_err(&pdev->dev, "Cannot allocate memory.\n");
                ret = -ENOMEM;
                goto err_alloc;
        }
@@ -1487,7 +1473,6 @@ static int charger_manager_probe(struct platform_device *pdev)
        cm->dev = &pdev->dev;
        cm->desc = kmemdup(desc, sizeof(struct charger_desc), GFP_KERNEL);
        if (!cm->desc) {
-               dev_err(&pdev->dev, "Cannot allocate memory.\n");
                ret = -ENOMEM;
                goto err_alloc_desc;
        }
@@ -1498,33 +1483,28 @@ static int charger_manager_probe(struct platform_device *pdev)
         * Users may intentionally ignore those two features.
         */
        if (desc->fullbatt_uV == 0) {
-               dev_info(&pdev->dev, "Ignoring full-battery voltage threshold"
-                                       " as it is not supplied.");
+               dev_info(&pdev->dev, "Ignoring full-battery voltage threshold as it is not supplied\n");
        }
        if (!desc->fullbatt_vchkdrop_ms || !desc->fullbatt_vchkdrop_uV) {
-               dev_info(&pdev->dev, "Disabling full-battery voltage drop "
-                               "checking mechanism as it is not supplied.");
+               dev_info(&pdev->dev, "Disabling full-battery voltage drop checking mechanism as it is not supplied\n");
                desc->fullbatt_vchkdrop_ms = 0;
                desc->fullbatt_vchkdrop_uV = 0;
        }
        if (desc->fullbatt_soc == 0) {
-               dev_info(&pdev->dev, "Ignoring full-battery soc(state of"
-                                       " charge) threshold as it is not"
-                                       " supplied.");
+               dev_info(&pdev->dev, "Ignoring full-battery soc(state of charge) threshold as it is not supplied\n");
        }
        if (desc->fullbatt_full_capacity == 0) {
-               dev_info(&pdev->dev, "Ignoring full-battery full capacity"
-                                       " threshold as it is not supplied.");
+               dev_info(&pdev->dev, "Ignoring full-battery full capacity threshold as it is not supplied\n");
        }
 
        if (!desc->charger_regulators || desc->num_charger_regulators < 1) {
                ret = -EINVAL;
-               dev_err(&pdev->dev, "charger_regulators undefined.\n");
+               dev_err(&pdev->dev, "charger_regulators undefined\n");
                goto err_no_charger;
        }
 
        if (!desc->psy_charger_stat || !desc->psy_charger_stat[0]) {
-               dev_err(&pdev->dev, "No power supply defined.\n");
+               dev_err(&pdev->dev, "No power supply defined\n");
                ret = -EINVAL;
                goto err_no_charger_stat;
        }
@@ -1544,9 +1524,8 @@ static int charger_manager_probe(struct platform_device *pdev)
                cm->charger_stat[i] = power_supply_get_by_name(
                                        desc->psy_charger_stat[i]);
                if (!cm->charger_stat[i]) {
-                       dev_err(&pdev->dev, "Cannot find power supply "
-                                       "\"%s\"\n",
-                                       desc->psy_charger_stat[i]);
+                       dev_err(&pdev->dev, "Cannot find power supply \"%s\"\n",
+                               desc->psy_charger_stat[i]);
                        ret = -ENODEV;
                        goto err_chg_stat;
                }
@@ -1555,7 +1534,7 @@ static int charger_manager_probe(struct platform_device *pdev)
        cm->fuel_gauge = power_supply_get_by_name(desc->psy_fuel_gauge);
        if (!cm->fuel_gauge) {
                dev_err(&pdev->dev, "Cannot find power supply \"%s\"\n",
-                               desc->psy_fuel_gauge);
+                       desc->psy_fuel_gauge);
                ret = -ENODEV;
                goto err_chg_stat;
        }
@@ -1575,9 +1554,7 @@ static int charger_manager_probe(struct platform_device *pdev)
 
        if (!desc->charging_max_duration_ms ||
                        !desc->discharging_max_duration_ms) {
-               dev_info(&pdev->dev, "Cannot limit charging duration "
-                        "checking mechanism to prevent overcharge/overheat "
-                        "and control discharging duration");
+               dev_info(&pdev->dev, "Cannot limit charging duration checking mechanism to prevent overcharge/overheat and control discharging duration\n");
                desc->charging_max_duration_ms = 0;
                desc->discharging_max_duration_ms = 0;
        }
@@ -1598,7 +1575,6 @@ static int charger_manager_probe(struct platform_device *pdev)
                                NUM_CHARGER_PSY_OPTIONAL),
                                GFP_KERNEL);
        if (!cm->charger_psy.properties) {
-               dev_err(&pdev->dev, "Cannot allocate for psy properties.\n");
                ret = -ENOMEM;
                goto err_chg_stat;
        }
@@ -1636,8 +1612,8 @@ static int charger_manager_probe(struct platform_device *pdev)
 
        ret = power_supply_register(NULL, &cm->charger_psy);
        if (ret) {
-               dev_err(&pdev->dev, "Cannot register charger-manager with"
-                               " name \"%s\".\n", cm->charger_psy.name);
+               dev_err(&pdev->dev, "Cannot register charger-manager with name \"%s\"\n",
+                       cm->charger_psy.name);
                goto err_register;
        }
 
@@ -1689,7 +1665,9 @@ err_reg_extcon:
                charger = &desc->charger_regulators[i];
                for (j = 0; j < charger->num_cables; j++) {
                        struct charger_cable *cable = &charger->cables[j];
-                       extcon_unregister_interest(&cable->extcon_dev);
+                       /* Remove notifier block if only edev exists */
+                       if (cable->extcon_dev.edev)
+                               extcon_unregister_interest(&cable->extcon_dev);
                }
 
                regulator_put(desc->charger_regulators[i].consumer);
@@ -1948,7 +1926,7 @@ void cm_notify_event(struct power_supply *psy, enum cm_event_types type,
                uevent_notify(cm, msg ? msg : default_event_names[type]);
                break;
        default:
-               dev_err(cm->dev, "%s type not specified.\n", __func__);
+               dev_err(cm->dev, "%s: type not specified\n", __func__);
                break;
        }
 }
index 8cb5d7f..59a1421 100644 (file)
@@ -299,8 +299,10 @@ static int gab_probe(struct platform_device *pdev)
        }
 
        /* none of the channels are supported so let's bail out */
-       if (index == ARRAY_SIZE(gab_chan_name))
+       if (index == 0) {
+               ret = -ENODEV;
                goto second_mem_fail;
+       }
 
        /*
         * Total number of properties is equal to static properties
index e9883ee..4e858a2 100644 (file)
@@ -155,8 +155,6 @@ static int gpio_charger_remove(struct platform_device *pdev)
 
        gpio_free(gpio_charger->pdata->gpio);
 
-       platform_set_drvdata(pdev, NULL);
-
        return 0;
 }
 
index 18d136b..4520811 100644 (file)
@@ -756,7 +756,7 @@ static int platform_pmic_battery_probe(struct platform_device *pdev)
 
 static int platform_pmic_battery_remove(struct platform_device *pdev)
 {
-       struct pmic_power_module_info *pbi = dev_get_drvdata(&pdev->dev);
+       struct pmic_power_module_info *pbi = platform_get_drvdata(pdev);
 
        free_irq(pbi->irq, pbi);
        cancel_delayed_work_sync(&pbi->monitor_battery);
index c675553..d9686aa 100644 (file)
@@ -292,7 +292,7 @@ static int jz_battery_probe(struct platform_device *pdev)
                        jz_battery);
        if (ret) {
                dev_err(&pdev->dev, "Failed to request irq %d\n", ret);
-               goto err;
+               return ret;
        }
        disable_irq(jz_battery->irq);
 
@@ -349,8 +349,6 @@ err_free_gpio:
                gpio_free(jz_battery->pdata->gpio_charge);
 err_free_irq:
        free_irq(jz_battery->irq, jz_battery);
-err:
-       platform_set_drvdata(pdev, NULL);
        return ret;
 }
 
index 5ef41b8..32de636 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/i2c.h>
 #include <linux/power_supply.h>
 #include <linux/platform_data/lp8727.h>
+#include <linux/of.h>
 
 #define LP8788_NUM_INTREGS     2
 #define DEFAULT_DEBOUNCE_MSEC  270
@@ -481,6 +482,60 @@ static void lp8727_unregister_psy(struct lp8727_chg *pchg)
        power_supply_unregister(&psy->batt);
 }
 
+#ifdef CONFIG_OF
+static struct lp8727_chg_param
+*lp8727_parse_charge_pdata(struct device *dev, struct device_node *np)
+{
+       struct lp8727_chg_param *param;
+
+       param = devm_kzalloc(dev, sizeof(*param), GFP_KERNEL);
+       if (!param)
+               goto out;
+
+       of_property_read_u8(np, "eoc-level", (u8 *)&param->eoc_level);
+       of_property_read_u8(np, "charging-current", (u8 *)&param->ichg);
+out:
+       return param;
+}
+
+static int lp8727_parse_dt(struct device *dev)
+{
+       struct device_node *np = dev->of_node;
+       struct device_node *child;
+       struct lp8727_platform_data *pdata;
+       const char *type;
+
+       /* If charging parameter is not defined, just skip parsing the dt */
+       if (of_get_child_count(np) == 0)
+               goto out;
+
+       pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+       if (!pdata)
+               return -ENOMEM;
+
+       of_property_read_u32(np, "debounce-ms", &pdata->debounce_msec);
+
+       for_each_child_of_node(np, child) {
+               of_property_read_string(child, "charger-type", &type);
+
+               if (!strcmp(type, "ac"))
+                       pdata->ac = lp8727_parse_charge_pdata(dev, child);
+
+               if (!strcmp(type, "usb"))
+                       pdata->usb = lp8727_parse_charge_pdata(dev, child);
+       }
+
+       dev->platform_data = pdata;
+out:
+       return 0;
+}
+#else
+static int lp8727_parse_dt(struct device *dev)
+{
+       return 0;
+}
+#endif
+
 static int lp8727_probe(struct i2c_client *cl, const struct i2c_device_id *id)
 {
        struct lp8727_chg *pchg;
@@ -489,6 +544,12 @@ static int lp8727_probe(struct i2c_client *cl, const struct i2c_device_id *id)
        if (!i2c_check_functionality(cl->adapter, I2C_FUNC_SMBUS_I2C_BLOCK))
                return -EIO;
 
+       if (cl->dev.of_node) {
+               ret = lp8727_parse_dt(&cl->dev);
+               if (ret)
+                       return ret;
+       }
+
        pchg = devm_kzalloc(&cl->dev, sizeof(*pchg), GFP_KERNEL);
        if (!pchg)
                return -ENOMEM;
@@ -531,6 +592,12 @@ static int lp8727_remove(struct i2c_client *cl)
        return 0;
 }
 
+static const struct of_device_id lp8727_dt_ids[] = {
+       { .compatible = "ti,lp8727", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, lp8727_dt_ids);
+
 static const struct i2c_device_id lp8727_ids[] = {
        {"lp8727", 0},
        { }
@@ -540,6 +607,7 @@ MODULE_DEVICE_TABLE(i2c, lp8727_ids);
 static struct i2c_driver lp8727_driver = {
        .driver = {
                   .name = "lp8727",
+                  .of_match_table = of_match_ptr(lp8727_dt_ids),
                   },
        .probe = lp8727_probe,
        .remove = lp8727_remove,
index 17fd77f..771c4f0 100644 (file)
@@ -191,9 +191,9 @@ static ssize_t set_usblim(struct device *dev,
        unsigned long ma;
        int ret;
 
-       ret = strict_strtoul(buf, 10, &ma);
+       ret = kstrtoul(buf, 10, &ma);
        if (ret)
-               return -EINVAL;
+               return ret;
 
        pcf50633_mbc_usb_curlim_set(mbc->pcf, ma);
 
@@ -228,9 +228,9 @@ static ssize_t set_chglim(struct device *dev,
        if (!mbc->pcf->pdata->charger_reference_current_ma)
                return -ENODEV;
 
-       ret = strict_strtoul(buf, 10, &ma);
+       ret = kstrtoul(buf, 10, &ma);
        if (ret)
-               return -EINVAL;
+               return ret;
 
        mbcc5 = (ma << 8) / mbc->pcf->pdata->charger_reference_current_ma;
        if (mbcc5 > 255)
index fef56e2..1c0bfcb 100644 (file)
@@ -1007,9 +1007,14 @@ static int pm2xxx_wall_charger_probe(struct i2c_client *i2c_client,
        u8 val;
        int i;
 
+       if (!pl_data) {
+               dev_err(&i2c_client->dev, "No platform data supplied\n");
+               return -EINVAL;
+       }
+
        pm2 = kzalloc(sizeof(struct pm2xxx_charger), GFP_KERNEL);
        if (!pm2) {
-               dev_err(pm2->dev, "pm2xxx_charger allocation failed\n");
+               dev_err(&i2c_client->dev, "pm2xxx_charger allocation failed\n");
                return -ENOMEM;
        }
 
@@ -1070,9 +1075,9 @@ static int pm2xxx_wall_charger_probe(struct i2c_client *i2c_client,
        pm2->ac_chg.external = true;
 
        /* Create a work queue for the charger */
-       pm2->charger_wq =
-               create_singlethread_workqueue("pm2xxx_charger_wq");
+       pm2->charger_wq = create_singlethread_workqueue("pm2xxx_charger_wq");
        if (pm2->charger_wq == NULL) {
+               ret = -ENOMEM;
                dev_err(pm2->dev, "failed to create work queue\n");
                goto free_device_info;
        }
index 1c517c3..3b2d5df 100644 (file)
@@ -109,8 +109,10 @@ static int __power_supply_populate_supplied_from(struct device *dev,
                                psy->name, epsy->name);
                        psy->supplied_from[i-1] = (char *)epsy->name;
                        psy->num_supplies++;
+                       of_node_put(np);
                        break;
                }
+               of_node_put(np);
        } while (np);
 
        return 0;
@@ -193,8 +195,10 @@ static int power_supply_check_supplies(struct power_supply *psy)
                ret = power_supply_find_supply_from_node(np);
                if (ret) {
                        dev_dbg(psy->dev, "Failed to find supply, defer!\n");
+                       of_node_put(np);
                        return -EPROBE_DEFER;
                }
+               of_node_put(np);
        } while (np);
 
        /* All supplies found, allocate char ** array for filling */
index 349e9ae..ee039dc 100644 (file)
@@ -32,7 +32,8 @@ config POWER_RESET_RESTART
          user presses a key. u-boot then boots into Linux.
 
 config POWER_RESET_VEXPRESS
-       bool
+       bool "ARM Versatile Express power-off and reset driver"
+       depends on ARM || ARM64
        depends on POWER_RESET
        help
          Power off and reset support for the ARM Ltd. Versatile
index cbde1d6..8a6288d 100644 (file)
@@ -216,10 +216,8 @@ static int rx51_battery_probe(struct platform_device *pdev)
        di->bat.get_property = rx51_battery_get_property;
 
        ret = power_supply_register(di->dev, &di->bat);
-       if (ret) {
-               platform_set_drvdata(pdev, NULL);
+       if (ret)
                return ret;
-       }
 
        return 0;
 }
@@ -229,7 +227,6 @@ static int rx51_battery_remove(struct platform_device *pdev)
        struct rx51_device_info *di = platform_get_drvdata(pdev);
 
        power_supply_unregister(&di->bat);
-       platform_set_drvdata(pdev, NULL);
 
        return 0;
 }
index c8c78a7..b5f2a76 100644 (file)
@@ -704,6 +704,7 @@ static int sbs_probe(struct i2c_client *client,
        chip->power_supply.properties = sbs_properties;
        chip->power_supply.num_properties = ARRAY_SIZE(sbs_properties);
        chip->power_supply.get_property = sbs_get_property;
+       chip->power_supply.of_node = client->dev.of_node;
        /* ignore first notification of external change, it is generated
         * from the power_supply_register call back
         */
index 9fbca31..bdd7b9b 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/mfd/tps65090.h>
 
 #define TPS65090_REG_INTR_STS  0x00
+#define TPS65090_REG_INTR_MASK 0x02
 #define TPS65090_REG_CG_CTRL0  0x04
 #define TPS65090_REG_CG_CTRL1  0x05
 #define TPS65090_REG_CG_CTRL2  0x06
@@ -67,8 +68,7 @@ static int tps65090_low_chrg_current(struct tps65090_charger *charger)
        return 0;
 }
 
-static int tps65090_enable_charging(struct tps65090_charger *charger,
-       uint8_t enable)
+static int tps65090_enable_charging(struct tps65090_charger *charger)
 {
        int ret;
        uint8_t ctrl0 = 0;
@@ -84,7 +84,7 @@ static int tps65090_enable_charging(struct tps65090_charger *charger,
        ret = tps65090_write(charger->dev->parent, TPS65090_REG_CG_CTRL0,
                                (ctrl0 | TPS65090_CHARGER_ENABLE));
        if (ret < 0) {
-               dev_err(charger->dev, "%s(): error reading in register 0x%x\n",
+               dev_err(charger->dev, "%s(): error writing in register 0x%x\n",
                                __func__, TPS65090_REG_CG_CTRL0);
                return ret;
        }
@@ -93,6 +93,7 @@ static int tps65090_enable_charging(struct tps65090_charger *charger,
 
 static int tps65090_config_charger(struct tps65090_charger *charger)
 {
+       uint8_t intrmask = 0;
        int ret;
 
        if (charger->pdata->enable_low_current_chrg) {
@@ -104,6 +105,23 @@ static int tps65090_config_charger(struct tps65090_charger *charger)
                }
        }
 
+       /* Enable the VACG interrupt for AC power detect */
+       ret = tps65090_read(charger->dev->parent, TPS65090_REG_INTR_MASK,
+                           &intrmask);
+       if (ret < 0) {
+               dev_err(charger->dev, "%s(): error reading in register 0x%x\n",
+                       __func__, TPS65090_REG_INTR_MASK);
+               return ret;
+       }
+
+       ret = tps65090_write(charger->dev->parent, TPS65090_REG_INTR_MASK,
+                            (intrmask | TPS65090_VACG));
+       if (ret < 0) {
+               dev_err(charger->dev, "%s(): error writing in register 0x%x\n",
+                       __func__, TPS65090_REG_CG_CTRL0);
+               return ret;
+       }
+
        return 0;
 }
 
@@ -146,7 +164,7 @@ static irqreturn_t tps65090_charger_isr(int irq, void *dev_id)
        }
 
        if (intrsts & TPS65090_VACG) {
-               ret = tps65090_enable_charging(charger, 1);
+               ret = tps65090_enable_charging(charger);
                if (ret < 0)
                        return IRQ_HANDLED;
                charger->ac_online = 1;
@@ -154,6 +172,13 @@ static irqreturn_t tps65090_charger_isr(int irq, void *dev_id)
                charger->ac_online = 0;
        }
 
+       /* Clear interrupts. */
+       ret = tps65090_write(charger->dev->parent, TPS65090_REG_INTR_STS, 0x00);
+       if (ret < 0) {
+               dev_err(charger->dev, "%s(): Error in writing reg 0x%x\n",
+                               __func__, TPS65090_REG_INTR_STS);
+       }
+
        if (charger->prev_ac_online != charger->ac_online)
                power_supply_changed(&charger->ac);
 
@@ -218,7 +243,7 @@ static int tps65090_charger_probe(struct platform_device *pdev)
                return -ENOMEM;
        }
 
-       dev_set_drvdata(&pdev->dev, cdata);
+       platform_set_drvdata(pdev, cdata);
 
        cdata->dev                      = &pdev->dev;
        cdata->pdata                    = pdata;
@@ -230,6 +255,7 @@ static int tps65090_charger_probe(struct platform_device *pdev)
        cdata->ac.num_properties        = ARRAY_SIZE(tps65090_ac_props);
        cdata->ac.supplied_to           = pdata->supplied_to;
        cdata->ac.num_supplicants       = pdata->num_supplicants;
+       cdata->ac.of_node               = pdev->dev.of_node;
 
        ret = power_supply_register(&pdev->dev, &cdata->ac);
        if (ret) {
@@ -270,7 +296,7 @@ static int tps65090_charger_probe(struct platform_device *pdev)
        }
 
        if (status1 != 0) {
-               ret = tps65090_enable_charging(cdata, 1);
+               ret = tps65090_enable_charging(cdata);
                if (ret < 0) {
                        dev_err(cdata->dev, "error enabling charger\n");
                        goto fail_free_irq;
@@ -291,7 +317,7 @@ fail_unregister_supply:
 
 static int tps65090_charger_remove(struct platform_device *pdev)
 {
-       struct tps65090_charger *cdata = dev_get_drvdata(&pdev->dev);
+       struct tps65090_charger *cdata = platform_get_drvdata(pdev);
 
        devm_free_irq(cdata->dev, cdata->irq, cdata);
        power_supply_unregister(&cdata->ac);
index bed4581..be98e70 100644 (file)
@@ -594,7 +594,6 @@ fail_chg_irq:
 fail_register_usb:
        power_supply_unregister(&bci->ac);
 fail_register_ac:
-       platform_set_drvdata(pdev, NULL);
        kfree(bci);
 
        return ret;
@@ -622,7 +621,6 @@ static int __exit twl4030_bci_remove(struct platform_device *pdev)
        free_irq(bci->irq_chg, bci);
        power_supply_unregister(&bci->usb);
        power_supply_unregister(&bci->ac);
-       platform_set_drvdata(pdev, NULL);
        kfree(bci);
 
        return 0;
index 115b644..75840b5 100644 (file)
@@ -28,6 +28,10 @@ menuconfig PWM
 
 if PWM
 
+config PWM_SYSFS
+       bool
+       default y if SYSFS
+
 config PWM_AB8500
        tristate "AB8500 PWM support"
        depends on AB8500_CORE && ARCH_U8500
@@ -97,6 +101,15 @@ config PWM_MXS
          To compile this driver as a module, choose M here: the module
          will be called pwm-mxs.
 
+config PWM_PCA9685
+       tristate "NXP PCA9685 PWM driver"
+       depends on OF && REGMAP_I2C
+       help
+         Generic PWM framework driver for NXP PCA9685 LED controller.
+
+         To compile this driver as a module, choose M here: the module
+         will be called pwm-pca9685.
+
 config PWM_PUV3
        tristate "PKUnity NetBook-0916 PWM support"
        depends on ARCH_PUV3
@@ -115,6 +128,16 @@ config PWM_PXA
          To compile this driver as a module, choose M here: the module
          will be called pwm-pxa.
 
+config PWM_RENESAS_TPU
+       tristate "Renesas TPU PWM support"
+       depends on ARCH_SHMOBILE
+       help
+         This driver exposes the Timer Pulse Unit (TPU) PWM controller found
+         in Renesas chips through the PWM API.
+
+         To compile this driver as a module, choose M here: the module
+         will be called pwm-renesas-tpu.
+
 config PWM_SAMSUNG
        tristate "Samsung PWM support"
        depends on PLAT_SAMSUNG
index 94ba21e..77a8c18 100644 (file)
@@ -1,4 +1,5 @@
 obj-$(CONFIG_PWM)              += core.o
+obj-$(CONFIG_PWM_SYSFS)                += sysfs.o
 obj-$(CONFIG_PWM_AB8500)       += pwm-ab8500.o
 obj-$(CONFIG_PWM_ATMEL_TCB)    += pwm-atmel-tcb.o
 obj-$(CONFIG_PWM_BFIN)         += pwm-bfin.o
@@ -6,8 +7,10 @@ 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_PCA9685)      += pwm-pca9685.o
 obj-$(CONFIG_PWM_PUV3)         += pwm-puv3.o
 obj-$(CONFIG_PWM_PXA)          += pwm-pxa.o
+obj-$(CONFIG_PWM_RENESAS_TPU)  += pwm-renesas-tpu.o
 obj-$(CONFIG_PWM_SAMSUNG)      += pwm-samsung.o
 obj-$(CONFIG_PWM_SPEAR)                += pwm-spear.o
 obj-$(CONFIG_PWM_TEGRA)                += pwm-tegra.o
index 32221cb..dfbfbc5 100644 (file)
@@ -274,6 +274,8 @@ int pwmchip_add(struct pwm_chip *chip)
        if (IS_ENABLED(CONFIG_OF))
                of_pwmchip_add(chip);
 
+       pwmchip_sysfs_export(chip);
+
 out:
        mutex_unlock(&pwm_lock);
        return ret;
@@ -310,6 +312,8 @@ int pwmchip_remove(struct pwm_chip *chip)
 
        free_pwms(chip);
 
+       pwmchip_sysfs_unexport(chip);
+
 out:
        mutex_unlock(&pwm_lock);
        return ret;
@@ -402,10 +406,19 @@ EXPORT_SYMBOL_GPL(pwm_free);
  */
 int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
 {
+       int err;
+
        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);
+       err = pwm->chip->ops->config(pwm->chip, pwm, duty_ns, period_ns);
+       if (err)
+               return err;
+
+       pwm->duty_cycle = duty_ns;
+       pwm->period = period_ns;
+
+       return 0;
 }
 EXPORT_SYMBOL_GPL(pwm_config);
 
@@ -418,6 +431,8 @@ EXPORT_SYMBOL_GPL(pwm_config);
  */
 int pwm_set_polarity(struct pwm_device *pwm, enum pwm_polarity polarity)
 {
+       int err;
+
        if (!pwm || !pwm->chip->ops)
                return -EINVAL;
 
@@ -427,7 +442,13 @@ int pwm_set_polarity(struct pwm_device *pwm, enum pwm_polarity polarity)
        if (test_bit(PWMF_ENABLED, &pwm->flags))
                return -EBUSY;
 
-       return pwm->chip->ops->set_polarity(pwm->chip, pwm, polarity);
+       err = pwm->chip->ops->set_polarity(pwm->chip, pwm, polarity);
+       if (err)
+               return err;
+
+       pwm->polarity = polarity;
+
+       return 0;
 }
 EXPORT_SYMBOL_GPL(pwm_set_polarity);
 
@@ -694,7 +715,7 @@ 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);
+       ptr = devres_alloc(devm_pwm_release, sizeof(*ptr), GFP_KERNEL);
        if (!ptr)
                return ERR_PTR(-ENOMEM);
 
@@ -724,7 +745,7 @@ struct pwm_device *devm_of_pwm_get(struct device *dev, struct device_node *np,
 {
        struct pwm_device **ptr, *pwm;
 
-       ptr = devres_alloc(devm_pwm_release, sizeof(**ptr), GFP_KERNEL);
+       ptr = devres_alloc(devm_pwm_release, sizeof(*ptr), GFP_KERNEL);
        if (!ptr)
                return ERR_PTR(-ENOMEM);
 
index 0a7b658..ba6ce01 100644 (file)
@@ -76,7 +76,7 @@ static int atmel_tcb_pwm_request(struct pwm_chip *chip,
        if (!tcbpwm)
                return -ENOMEM;
 
-       ret = clk_enable(tc->clk[group]);
+       ret = clk_prepare_enable(tc->clk[group]);
        if (ret) {
                devm_kfree(chip->dev, tcbpwm);
                return ret;
@@ -124,7 +124,7 @@ static void atmel_tcb_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
        struct atmel_tcb_pwm_device *tcbpwm = pwm_get_chip_data(pwm);
        struct atmel_tc *tc = tcbpwmc->tc;
 
-       clk_disable(tc->clk[pwm->hwpwm / 2]);
+       clk_disable_unprepare(tc->clk[pwm->hwpwm / 2]);
        tcbpwmc->pwms[pwm->hwpwm] = NULL;
        devm_kfree(chip->dev, tcbpwm);
 }
@@ -434,6 +434,7 @@ MODULE_DEVICE_TABLE(of, atmel_tcb_pwm_dt_ids);
 static struct platform_driver atmel_tcb_pwm_driver = {
        .driver = {
                .name = "atmel-tcb-pwm",
+               .owner = THIS_MODULE,
                .of_match_table = atmel_tcb_pwm_dt_ids,
        },
        .probe = atmel_tcb_pwm_probe,
index 7631ef1..9985d83 100644 (file)
@@ -149,6 +149,7 @@ static int bfin_pwm_remove(struct platform_device *pdev)
 static struct platform_driver bfin_pwm_driver = {
        .driver = {
                .name = "bfin-pwm",
+               .owner = THIS_MODULE,
        },
        .probe = bfin_pwm_probe,
        .remove = bfin_pwm_remove,
index c938bae..2b7c4f8 100644 (file)
@@ -295,6 +295,7 @@ static int imx_pwm_remove(struct platform_device *pdev)
 static struct platform_driver imx_pwm_driver = {
        .driver         = {
                .name   = "imx-pwm",
+               .owner = THIS_MODULE,
                .of_match_table = of_match_ptr(imx_pwm_dt_ids),
        },
        .probe          = imx_pwm_probe,
index 8272883..efb6c7b 100644 (file)
@@ -171,6 +171,7 @@ MODULE_DEVICE_TABLE(of, lpc32xx_pwm_dt_ids);
 static struct platform_driver lpc32xx_pwm_driver = {
        .driver = {
                .name = "lpc32xx-pwm",
+               .owner = THIS_MODULE,
                .of_match_table = of_match_ptr(lpc32xx_pwm_dt_ids),
        },
        .probe = lpc32xx_pwm_probe,
index 3febddd..2c77b81 100644 (file)
@@ -16,7 +16,6 @@
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
-#include <linux/pinctrl/consumer.h>
 #include <linux/platform_device.h>
 #include <linux/pwm.h>
 #include <linux/slab.h>
@@ -130,7 +129,6 @@ static int mxs_pwm_probe(struct platform_device *pdev)
        struct device_node *np = pdev->dev.of_node;
        struct mxs_pwm_chip *mxs;
        struct resource *res;
-       struct pinctrl *pinctrl;
        int ret;
 
        mxs = devm_kzalloc(&pdev->dev, sizeof(*mxs), GFP_KERNEL);
@@ -142,10 +140,6 @@ static int mxs_pwm_probe(struct platform_device *pdev)
        if (IS_ERR(mxs->base))
                return PTR_ERR(mxs->base);
 
-       pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
-       if (IS_ERR(pinctrl))
-               return PTR_ERR(pinctrl);
-
        mxs->clk = devm_clk_get(&pdev->dev, NULL);
        if (IS_ERR(mxs->clk))
                return PTR_ERR(mxs->clk);
@@ -188,6 +182,7 @@ MODULE_DEVICE_TABLE(of, mxs_pwm_dt_ids);
 static struct platform_driver mxs_pwm_driver = {
        .driver = {
                .name = "mxs-pwm",
+               .owner = THIS_MODULE,
                .of_match_table = of_match_ptr(mxs_pwm_dt_ids),
        },
        .probe = mxs_pwm_probe,
diff --git a/drivers/pwm/pwm-pca9685.c b/drivers/pwm/pwm-pca9685.c
new file mode 100644 (file)
index 0000000..3fb775d
--- /dev/null
@@ -0,0 +1,300 @@
+/*
+ * Driver for PCA9685 16-channel 12-bit PWM LED controller
+ *
+ * Copyright (C) 2013 Steffen Trumtrar <s.trumtrar@pengutronix.de>
+ *
+ * based on the pwm-twl-led.c 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/i2c.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pwm.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+#define PCA9685_MODE1          0x00
+#define PCA9685_MODE2          0x01
+#define PCA9685_SUBADDR1       0x02
+#define PCA9685_SUBADDR2       0x03
+#define PCA9685_SUBADDR3       0x04
+#define PCA9685_ALLCALLADDR    0x05
+#define PCA9685_LEDX_ON_L      0x06
+#define PCA9685_LEDX_ON_H      0x07
+#define PCA9685_LEDX_OFF_L     0x08
+#define PCA9685_LEDX_OFF_H     0x09
+
+#define PCA9685_ALL_LED_ON_L   0xFA
+#define PCA9685_ALL_LED_ON_H   0xFB
+#define PCA9685_ALL_LED_OFF_L  0xFC
+#define PCA9685_ALL_LED_OFF_H  0xFD
+#define PCA9685_PRESCALE       0xFE
+
+#define PCA9685_NUMREGS                0xFF
+#define PCA9685_MAXCHAN                0x10
+
+#define LED_FULL               (1 << 4)
+#define MODE1_SLEEP            (1 << 4)
+#define MODE2_INVRT            (1 << 4)
+#define MODE2_OUTDRV           (1 << 2)
+
+#define LED_N_ON_H(N)  (PCA9685_LEDX_ON_H + (4 * (N)))
+#define LED_N_ON_L(N)  (PCA9685_LEDX_ON_L + (4 * (N)))
+#define LED_N_OFF_H(N) (PCA9685_LEDX_OFF_H + (4 * (N)))
+#define LED_N_OFF_L(N) (PCA9685_LEDX_OFF_L + (4 * (N)))
+
+struct pca9685 {
+       struct pwm_chip chip;
+       struct regmap *regmap;
+       int active_cnt;
+};
+
+static inline struct pca9685 *to_pca(struct pwm_chip *chip)
+{
+       return container_of(chip, struct pca9685, chip);
+}
+
+static int pca9685_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
+                             int duty_ns, int period_ns)
+{
+       struct pca9685 *pca = to_pca(chip);
+       unsigned long long duty;
+       unsigned int reg;
+
+       if (duty_ns < 1) {
+               if (pwm->hwpwm >= PCA9685_MAXCHAN)
+                       reg = PCA9685_ALL_LED_OFF_H;
+               else
+                       reg = LED_N_OFF_H(pwm->hwpwm);
+
+               regmap_write(pca->regmap, reg, LED_FULL);
+
+               return 0;
+       }
+
+       if (duty_ns == period_ns) {
+               if (pwm->hwpwm >= PCA9685_MAXCHAN)
+                       reg = PCA9685_ALL_LED_ON_H;
+               else
+                       reg = LED_N_ON_H(pwm->hwpwm);
+
+               regmap_write(pca->regmap, reg, LED_FULL);
+
+               return 0;
+       }
+
+       duty = 4096 * (unsigned long long)duty_ns;
+       duty = DIV_ROUND_UP_ULL(duty, period_ns);
+
+       if (pwm->hwpwm >= PCA9685_MAXCHAN)
+               reg = PCA9685_ALL_LED_OFF_L;
+       else
+               reg = LED_N_OFF_L(pwm->hwpwm);
+
+       regmap_write(pca->regmap, reg, (int)duty & 0xff);
+
+       if (pwm->hwpwm >= PCA9685_MAXCHAN)
+               reg = PCA9685_ALL_LED_OFF_H;
+       else
+               reg = LED_N_OFF_H(pwm->hwpwm);
+
+       regmap_write(pca->regmap, reg, ((int)duty >> 8) & 0xf);
+
+       return 0;
+}
+
+static int pca9685_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+       struct pca9685 *pca = to_pca(chip);
+       unsigned int reg;
+
+       /*
+        * The PWM subsystem does not support a pre-delay.
+        * So, set the ON-timeout to 0
+        */
+       if (pwm->hwpwm >= PCA9685_MAXCHAN)
+               reg = PCA9685_ALL_LED_ON_L;
+       else
+               reg = LED_N_ON_L(pwm->hwpwm);
+
+       regmap_write(pca->regmap, reg, 0);
+
+       if (pwm->hwpwm >= PCA9685_MAXCHAN)
+               reg = PCA9685_ALL_LED_ON_H;
+       else
+               reg = LED_N_ON_H(pwm->hwpwm);
+
+       regmap_write(pca->regmap, reg, 0);
+
+       /*
+        * Clear the full-off bit.
+        * It has precedence over the others and must be off.
+        */
+       if (pwm->hwpwm >= PCA9685_MAXCHAN)
+               reg = PCA9685_ALL_LED_OFF_H;
+       else
+               reg = LED_N_OFF_H(pwm->hwpwm);
+
+       regmap_update_bits(pca->regmap, reg, LED_FULL, 0x0);
+
+       return 0;
+}
+
+static void pca9685_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+       struct pca9685 *pca = to_pca(chip);
+       unsigned int reg;
+
+       if (pwm->hwpwm >= PCA9685_MAXCHAN)
+               reg = PCA9685_ALL_LED_OFF_H;
+       else
+               reg = LED_N_OFF_H(pwm->hwpwm);
+
+       regmap_write(pca->regmap, reg, LED_FULL);
+
+       /* Clear the LED_OFF counter. */
+       if (pwm->hwpwm >= PCA9685_MAXCHAN)
+               reg = PCA9685_ALL_LED_OFF_L;
+       else
+               reg = LED_N_OFF_L(pwm->hwpwm);
+
+       regmap_write(pca->regmap, reg, 0x0);
+}
+
+static int pca9685_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+       struct pca9685 *pca = to_pca(chip);
+
+       if (pca->active_cnt++ == 0)
+               return regmap_update_bits(pca->regmap, PCA9685_MODE1,
+                                         MODE1_SLEEP, 0x0);
+
+       return 0;
+}
+
+static void pca9685_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+       struct pca9685 *pca = to_pca(chip);
+
+       if (--pca->active_cnt == 0)
+               regmap_update_bits(pca->regmap, PCA9685_MODE1, MODE1_SLEEP,
+                                  MODE1_SLEEP);
+}
+
+static const struct pwm_ops pca9685_pwm_ops = {
+       .enable = pca9685_pwm_enable,
+       .disable = pca9685_pwm_disable,
+       .config = pca9685_pwm_config,
+       .request = pca9685_pwm_request,
+       .free = pca9685_pwm_free,
+       .owner = THIS_MODULE,
+};
+
+static struct regmap_config pca9685_regmap_i2c_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+       .max_register = PCA9685_NUMREGS,
+       .cache_type = REGCACHE_NONE,
+};
+
+static int pca9685_pwm_probe(struct i2c_client *client,
+                               const struct i2c_device_id *id)
+{
+       struct device_node *np = client->dev.of_node;
+       struct pca9685 *pca;
+       int ret;
+       int mode2;
+
+       pca = devm_kzalloc(&client->dev, sizeof(*pca), GFP_KERNEL);
+       if (!pca)
+               return -ENOMEM;
+
+       pca->regmap = devm_regmap_init_i2c(client, &pca9685_regmap_i2c_config);
+       if (IS_ERR(pca->regmap)) {
+               ret = PTR_ERR(pca->regmap);
+               dev_err(&client->dev, "Failed to initialize register map: %d\n",
+                       ret);
+               return ret;
+       }
+
+       i2c_set_clientdata(client, pca);
+
+       regmap_read(pca->regmap, PCA9685_MODE2, &mode2);
+
+       if (of_property_read_bool(np, "invert"))
+               mode2 |= MODE2_INVRT;
+       else
+               mode2 &= ~MODE2_INVRT;
+
+       if (of_property_read_bool(np, "open-drain"))
+               mode2 &= ~MODE2_OUTDRV;
+       else
+               mode2 |= MODE2_OUTDRV;
+
+       regmap_write(pca->regmap, PCA9685_MODE2, mode2);
+
+       /* clear all "full off" bits */
+       regmap_write(pca->regmap, PCA9685_ALL_LED_OFF_L, 0);
+       regmap_write(pca->regmap, PCA9685_ALL_LED_OFF_H, 0);
+
+       pca->chip.ops = &pca9685_pwm_ops;
+       /* add an extra channel for ALL_LED */
+       pca->chip.npwm = PCA9685_MAXCHAN + 1;
+
+       pca->chip.dev = &client->dev;
+       pca->chip.base = -1;
+       pca->chip.can_sleep = true;
+
+       return pwmchip_add(&pca->chip);
+}
+
+static int pca9685_pwm_remove(struct i2c_client *client)
+{
+       struct pca9685 *pca = i2c_get_clientdata(client);
+
+       regmap_update_bits(pca->regmap, PCA9685_MODE1, MODE1_SLEEP,
+                          MODE1_SLEEP);
+
+       return pwmchip_remove(&pca->chip);
+}
+
+static const struct i2c_device_id pca9685_id[] = {
+       { "pca9685", 0 },
+       { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(i2c, pca9685_id);
+
+static const struct of_device_id pca9685_dt_ids[] = {
+       { .compatible = "nxp,pca9685-pwm", },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, pca9685_dt_ids);
+
+static struct i2c_driver pca9685_i2c_driver = {
+       .driver = {
+               .name = "pca9685-pwm",
+               .owner = THIS_MODULE,
+               .of_match_table = pca9685_dt_ids,
+       },
+       .probe = pca9685_pwm_probe,
+       .remove = pca9685_pwm_remove,
+       .id_table = pca9685_id,
+};
+
+module_i2c_driver(pca9685_i2c_driver);
+
+MODULE_AUTHOR("Steffen Trumtrar <s.trumtrar@pengutronix.de>");
+MODULE_DESCRIPTION("PWM driver for PCA9685");
+MODULE_LICENSE("GPL");
index ed6007b..a9a2808 100644 (file)
@@ -146,6 +146,7 @@ static int pwm_remove(struct platform_device *pdev)
 static struct platform_driver puv3_pwm_driver = {
        .driver = {
                .name = "PKUnity-v3-PWM",
+               .owner = THIS_MODULE,
        },
        .probe = pwm_probe,
        .remove = pwm_remove,
diff --git a/drivers/pwm/pwm-renesas-tpu.c b/drivers/pwm/pwm-renesas-tpu.c
new file mode 100644 (file)
index 0000000..2600892
--- /dev/null
@@ -0,0 +1,474 @@
+/*
+ * R-Mobile TPU PWM driver
+ *
+ * Copyright (C) 2012 Renesas Solutions Corp.
+ *
+ * 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.
+ */
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_data/pwm-renesas-tpu.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/pwm.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+#define TPU_TSTR               0x00    /* Timer start register (shared) */
+
+#define TPU_TCRn               0x00    /* Timer control register */
+#define TPU_TCR_CCLR_NONE      (0 << 5)
+#define TPU_TCR_CCLR_TGRA      (1 << 5)
+#define TPU_TCR_CCLR_TGRB      (2 << 5)
+#define TPU_TCR_CCLR_TGRC      (5 << 5)
+#define TPU_TCR_CCLR_TGRD      (6 << 5)
+#define TPU_TCR_CKEG_RISING    (0 << 3)
+#define TPU_TCR_CKEG_FALLING   (1 << 3)
+#define TPU_TCR_CKEG_BOTH      (2 << 3)
+#define TPU_TMDRn              0x04    /* Timer mode register */
+#define TPU_TMDR_BFWT          (1 << 6)
+#define TPU_TMDR_BFB           (1 << 5)
+#define TPU_TMDR_BFA           (1 << 4)
+#define TPU_TMDR_MD_NORMAL     (0 << 0)
+#define TPU_TMDR_MD_PWM                (2 << 0)
+#define TPU_TIORn              0x08    /* Timer I/O control register */
+#define TPU_TIOR_IOA_0         (0 << 0)
+#define TPU_TIOR_IOA_0_CLR     (1 << 0)
+#define TPU_TIOR_IOA_0_SET     (2 << 0)
+#define TPU_TIOR_IOA_0_TOGGLE  (3 << 0)
+#define TPU_TIOR_IOA_1         (4 << 0)
+#define TPU_TIOR_IOA_1_CLR     (5 << 0)
+#define TPU_TIOR_IOA_1_SET     (6 << 0)
+#define TPU_TIOR_IOA_1_TOGGLE  (7 << 0)
+#define TPU_TIERn              0x0c    /* Timer interrupt enable register */
+#define TPU_TSRn               0x10    /* Timer status register */
+#define TPU_TCNTn              0x14    /* Timer counter */
+#define TPU_TGRAn              0x18    /* Timer general register A */
+#define TPU_TGRBn              0x1c    /* Timer general register B */
+#define TPU_TGRCn              0x20    /* Timer general register C */
+#define TPU_TGRDn              0x24    /* Timer general register D */
+
+#define TPU_CHANNEL_OFFSET     0x10
+#define TPU_CHANNEL_SIZE       0x40
+
+enum tpu_pin_state {
+       TPU_PIN_INACTIVE,               /* Pin is driven inactive */
+       TPU_PIN_PWM,                    /* Pin is driven by PWM */
+       TPU_PIN_ACTIVE,                 /* Pin is driven active */
+};
+
+struct tpu_device;
+
+struct tpu_pwm_device {
+       bool timer_on;                  /* Whether the timer is running */
+
+       struct tpu_device *tpu;
+       unsigned int channel;           /* Channel number in the TPU */
+
+       enum pwm_polarity polarity;
+       unsigned int prescaler;
+       u16 period;
+       u16 duty;
+};
+
+struct tpu_device {
+       struct platform_device *pdev;
+       struct tpu_pwm_platform_data *pdata;
+       struct pwm_chip chip;
+       spinlock_t lock;
+
+       void __iomem *base;
+       struct clk *clk;
+};
+
+#define to_tpu_device(c)       container_of(c, struct tpu_device, chip)
+
+static void tpu_pwm_write(struct tpu_pwm_device *pwm, int reg_nr, u16 value)
+{
+       void __iomem *base = pwm->tpu->base + TPU_CHANNEL_OFFSET
+                          + pwm->channel * TPU_CHANNEL_SIZE;
+
+       iowrite16(value, base + reg_nr);
+}
+
+static void tpu_pwm_set_pin(struct tpu_pwm_device *pwm,
+                           enum tpu_pin_state state)
+{
+       static const char * const states[] = { "inactive", "PWM", "active" };
+
+       dev_dbg(&pwm->tpu->pdev->dev, "%u: configuring pin as %s\n",
+               pwm->channel, states[state]);
+
+       switch (state) {
+       case TPU_PIN_INACTIVE:
+               tpu_pwm_write(pwm, TPU_TIORn,
+                             pwm->polarity == PWM_POLARITY_INVERSED ?
+                             TPU_TIOR_IOA_1 : TPU_TIOR_IOA_0);
+               break;
+       case TPU_PIN_PWM:
+               tpu_pwm_write(pwm, TPU_TIORn,
+                             pwm->polarity == PWM_POLARITY_INVERSED ?
+                             TPU_TIOR_IOA_0_SET : TPU_TIOR_IOA_1_CLR);
+               break;
+       case TPU_PIN_ACTIVE:
+               tpu_pwm_write(pwm, TPU_TIORn,
+                             pwm->polarity == PWM_POLARITY_INVERSED ?
+                             TPU_TIOR_IOA_0 : TPU_TIOR_IOA_1);
+               break;
+       }
+}
+
+static void tpu_pwm_start_stop(struct tpu_pwm_device *pwm, int start)
+{
+       unsigned long flags;
+       u16 value;
+
+       spin_lock_irqsave(&pwm->tpu->lock, flags);
+       value = ioread16(pwm->tpu->base + TPU_TSTR);
+
+       if (start)
+               value |= 1 << pwm->channel;
+       else
+               value &= ~(1 << pwm->channel);
+
+       iowrite16(value, pwm->tpu->base + TPU_TSTR);
+       spin_unlock_irqrestore(&pwm->tpu->lock, flags);
+}
+
+static int tpu_pwm_timer_start(struct tpu_pwm_device *pwm)
+{
+       int ret;
+
+       if (!pwm->timer_on) {
+               /* Wake up device and enable clock. */
+               pm_runtime_get_sync(&pwm->tpu->pdev->dev);
+               ret = clk_prepare_enable(pwm->tpu->clk);
+               if (ret) {
+                       dev_err(&pwm->tpu->pdev->dev, "cannot enable clock\n");
+                       return ret;
+               }
+               pwm->timer_on = true;
+       }
+
+       /*
+        * Make sure the channel is stopped, as we need to reconfigure it
+        * completely. First drive the pin to the inactive state to avoid
+        * glitches.
+        */
+       tpu_pwm_set_pin(pwm, TPU_PIN_INACTIVE);
+       tpu_pwm_start_stop(pwm, false);
+
+       /*
+        * - Clear TCNT on TGRB match
+        * - Count on rising edge
+        * - Set prescaler
+        * - Output 0 until TGRA, output 1 until TGRB (active low polarity)
+        * - Output 1 until TGRA, output 0 until TGRB (active high polarity
+        * - PWM mode
+        */
+       tpu_pwm_write(pwm, TPU_TCRn, TPU_TCR_CCLR_TGRB | TPU_TCR_CKEG_RISING |
+                     pwm->prescaler);
+       tpu_pwm_write(pwm, TPU_TMDRn, TPU_TMDR_MD_PWM);
+       tpu_pwm_set_pin(pwm, TPU_PIN_PWM);
+       tpu_pwm_write(pwm, TPU_TGRAn, pwm->duty);
+       tpu_pwm_write(pwm, TPU_TGRBn, pwm->period);
+
+       dev_dbg(&pwm->tpu->pdev->dev, "%u: TGRA 0x%04x TGRB 0x%04x\n",
+               pwm->channel, pwm->duty, pwm->period);
+
+       /* Start the channel. */
+       tpu_pwm_start_stop(pwm, true);
+
+       return 0;
+}
+
+static void tpu_pwm_timer_stop(struct tpu_pwm_device *pwm)
+{
+       if (!pwm->timer_on)
+               return;
+
+       /* Disable channel. */
+       tpu_pwm_start_stop(pwm, false);
+
+       /* Stop clock and mark device as idle. */
+       clk_disable_unprepare(pwm->tpu->clk);
+       pm_runtime_put(&pwm->tpu->pdev->dev);
+
+       pwm->timer_on = false;
+}
+
+/* -----------------------------------------------------------------------------
+ * PWM API
+ */
+
+static int tpu_pwm_request(struct pwm_chip *chip, struct pwm_device *_pwm)
+{
+       struct tpu_device *tpu = to_tpu_device(chip);
+       struct tpu_pwm_device *pwm;
+
+       if (_pwm->hwpwm >= TPU_CHANNEL_MAX)
+               return -EINVAL;
+
+       pwm = kzalloc(sizeof(*pwm), GFP_KERNEL);
+       if (pwm == NULL)
+               return -ENOMEM;
+
+       pwm->tpu = tpu;
+       pwm->channel = _pwm->hwpwm;
+       pwm->polarity = tpu->pdata ? tpu->pdata->channels[pwm->channel].polarity
+                     : PWM_POLARITY_NORMAL;
+       pwm->prescaler = 0;
+       pwm->period = 0;
+       pwm->duty = 0;
+
+       pwm->timer_on = false;
+
+       pwm_set_chip_data(_pwm, pwm);
+
+       return 0;
+}
+
+static void tpu_pwm_free(struct pwm_chip *chip, struct pwm_device *_pwm)
+{
+       struct tpu_pwm_device *pwm = pwm_get_chip_data(_pwm);
+
+       tpu_pwm_timer_stop(pwm);
+       kfree(pwm);
+}
+
+static int tpu_pwm_config(struct pwm_chip *chip, struct pwm_device *_pwm,
+                         int duty_ns, int period_ns)
+{
+       static const unsigned int prescalers[] = { 1, 4, 16, 64 };
+       struct tpu_pwm_device *pwm = pwm_get_chip_data(_pwm);
+       struct tpu_device *tpu = to_tpu_device(chip);
+       unsigned int prescaler;
+       bool duty_only = false;
+       u32 clk_rate;
+       u32 period;
+       u32 duty;
+       int ret;
+
+       /*
+        * Pick a prescaler to avoid overflowing the counter.
+        * TODO: Pick the highest acceptable prescaler.
+        */
+       clk_rate = clk_get_rate(tpu->clk);
+
+       for (prescaler = 0; prescaler < ARRAY_SIZE(prescalers); ++prescaler) {
+               period = clk_rate / prescalers[prescaler]
+                      / (NSEC_PER_SEC / period_ns);
+               if (period <= 0xffff)
+                       break;
+       }
+
+       if (prescaler == ARRAY_SIZE(prescalers) || period == 0) {
+               dev_err(&tpu->pdev->dev, "clock rate mismatch\n");
+               return -ENOTSUPP;
+       }
+
+       if (duty_ns) {
+               duty = clk_rate / prescalers[prescaler]
+                    / (NSEC_PER_SEC / duty_ns);
+               if (duty > period)
+                       return -EINVAL;
+       } else {
+               duty = 0;
+       }
+
+       dev_dbg(&tpu->pdev->dev,
+               "rate %u, prescaler %u, period %u, duty %u\n",
+               clk_rate, prescalers[prescaler], period, duty);
+
+       if (pwm->prescaler == prescaler && pwm->period == period)
+               duty_only = true;
+
+       pwm->prescaler = prescaler;
+       pwm->period = period;
+       pwm->duty = duty;
+
+       /* If the channel is disabled we're done. */
+       if (!test_bit(PWMF_ENABLED, &_pwm->flags))
+               return 0;
+
+       if (duty_only && pwm->timer_on) {
+               /*
+                * If only the duty cycle changed and the timer is already
+                * running, there's no need to reconfigure it completely, Just
+                * modify the duty cycle.
+                */
+               tpu_pwm_write(pwm, TPU_TGRAn, pwm->duty);
+               dev_dbg(&tpu->pdev->dev, "%u: TGRA 0x%04x\n", pwm->channel,
+                       pwm->duty);
+       } else {
+               /* Otherwise perform a full reconfiguration. */
+               ret = tpu_pwm_timer_start(pwm);
+               if (ret < 0)
+                       return ret;
+       }
+
+       if (duty == 0 || duty == period) {
+               /*
+                * To avoid running the timer when not strictly required, handle
+                * 0% and 100% duty cycles as fixed levels and stop the timer.
+                */
+               tpu_pwm_set_pin(pwm, duty ? TPU_PIN_ACTIVE : TPU_PIN_INACTIVE);
+               tpu_pwm_timer_stop(pwm);
+       }
+
+       return 0;
+}
+
+static int tpu_pwm_set_polarity(struct pwm_chip *chip, struct pwm_device *_pwm,
+                               enum pwm_polarity polarity)
+{
+       struct tpu_pwm_device *pwm = pwm_get_chip_data(_pwm);
+
+       pwm->polarity = polarity;
+
+       return 0;
+}
+
+static int tpu_pwm_enable(struct pwm_chip *chip, struct pwm_device *_pwm)
+{
+       struct tpu_pwm_device *pwm = pwm_get_chip_data(_pwm);
+       int ret;
+
+       ret = tpu_pwm_timer_start(pwm);
+       if (ret < 0)
+               return ret;
+
+       /*
+        * To avoid running the timer when not strictly required, handle 0% and
+        * 100% duty cycles as fixed levels and stop the timer.
+        */
+       if (pwm->duty == 0 || pwm->duty == pwm->period) {
+               tpu_pwm_set_pin(pwm, pwm->duty ?
+                               TPU_PIN_ACTIVE : TPU_PIN_INACTIVE);
+               tpu_pwm_timer_stop(pwm);
+       }
+
+       return 0;
+}
+
+static void tpu_pwm_disable(struct pwm_chip *chip, struct pwm_device *_pwm)
+{
+       struct tpu_pwm_device *pwm = pwm_get_chip_data(_pwm);
+
+       /* The timer must be running to modify the pin output configuration. */
+       tpu_pwm_timer_start(pwm);
+       tpu_pwm_set_pin(pwm, TPU_PIN_INACTIVE);
+       tpu_pwm_timer_stop(pwm);
+}
+
+static const struct pwm_ops tpu_pwm_ops = {
+       .request = tpu_pwm_request,
+       .free = tpu_pwm_free,
+       .config = tpu_pwm_config,
+       .set_polarity = tpu_pwm_set_polarity,
+       .enable = tpu_pwm_enable,
+       .disable = tpu_pwm_disable,
+       .owner = THIS_MODULE,
+};
+
+/* -----------------------------------------------------------------------------
+ * Probe and remove
+ */
+
+static int tpu_probe(struct platform_device *pdev)
+{
+       struct tpu_device *tpu;
+       struct resource *res;
+       int ret;
+
+       tpu = devm_kzalloc(&pdev->dev, sizeof(*tpu), GFP_KERNEL);
+       if (tpu == NULL) {
+               dev_err(&pdev->dev, "failed to allocate driver data\n");
+               return -ENOMEM;
+       }
+
+       tpu->pdata = pdev->dev.platform_data;
+
+       /* Map memory, get clock and pin control. */
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(&pdev->dev, "failed to get I/O memory\n");
+               return -ENXIO;
+       }
+
+       tpu->base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(tpu->base))
+               return PTR_ERR(tpu->base);
+
+       tpu->clk = devm_clk_get(&pdev->dev, NULL);
+       if (IS_ERR(tpu->clk)) {
+               dev_err(&pdev->dev, "cannot get clock\n");
+               return PTR_ERR(tpu->clk);
+       }
+
+       /* Initialize and register the device. */
+       platform_set_drvdata(pdev, tpu);
+
+       spin_lock_init(&tpu->lock);
+       tpu->pdev = pdev;
+
+       tpu->chip.dev = &pdev->dev;
+       tpu->chip.ops = &tpu_pwm_ops;
+       tpu->chip.base = -1;
+       tpu->chip.npwm = TPU_CHANNEL_MAX;
+
+       ret = pwmchip_add(&tpu->chip);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "failed to register PWM chip\n");
+               return ret;
+       }
+
+       dev_info(&pdev->dev, "TPU PWM %d registered\n", tpu->pdev->id);
+
+       pm_runtime_enable(&pdev->dev);
+
+       return 0;
+}
+
+static int tpu_remove(struct platform_device *pdev)
+{
+       struct tpu_device *tpu = platform_get_drvdata(pdev);
+       int ret;
+
+       ret = pwmchip_remove(&tpu->chip);
+       if (ret)
+               return ret;
+
+       pm_runtime_disable(&pdev->dev);
+
+       return 0;
+}
+
+static struct platform_driver tpu_driver = {
+       .probe          = tpu_probe,
+       .remove         = tpu_remove,
+       .driver         = {
+               .name   = "renesas-tpu-pwm",
+               .owner  = THIS_MODULE,
+       }
+};
+
+module_platform_driver(tpu_driver);
+
+MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
+MODULE_DESCRIPTION("Renesas TPU PWM Driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:renesas-tpu-pwm");
index 6d99e2c..a54d214 100644 (file)
@@ -259,6 +259,7 @@ MODULE_DEVICE_TABLE(of, spear_pwm_of_match);
 static struct platform_driver spear_pwm_driver = {
        .driver = {
                .name = "spear-pwm",
+               .owner = THIS_MODULE,
                .of_match_table = spear_pwm_of_match,
        },
        .probe = spear_pwm_probe,
index a540293..74298c5 100644 (file)
@@ -239,6 +239,7 @@ MODULE_DEVICE_TABLE(of, tegra_pwm_of_match);
 static struct platform_driver tegra_pwm_driver = {
        .driver = {
                .name = "tegra-pwm",
+               .owner = THIS_MODULE,
                .of_match_table = tegra_pwm_of_match,
        },
        .probe = tegra_pwm_probe,
index 48a485c..aa4c558 100644 (file)
@@ -359,7 +359,7 @@ static int ehrpwm_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
        configure_polarity(pc, pwm->hwpwm);
 
        /* Enable TBCLK before enabling PWM device */
-       ret = clk_prepare_enable(pc->tbclk);
+       ret = clk_enable(pc->tbclk);
        if (ret) {
                pr_err("Failed to enable TBCLK for %s\n",
                                dev_name(pc->chip.dev));
@@ -395,7 +395,7 @@ static void ehrpwm_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
        ehrpwm_modify(pc->mmio_base, AQCSFRC, aqcsfrc_mask, aqcsfrc_val);
 
        /* Disabling TBCLK on PWM disable */
-       clk_disable_unprepare(pc->tbclk);
+       clk_disable(pc->tbclk);
 
        /* Stop Time base counter */
        ehrpwm_modify(pc->mmio_base, TBCTL, TBCTL_RUN_MASK, TBCTL_STOP_NEXT);
@@ -482,6 +482,12 @@ static int ehrpwm_pwm_probe(struct platform_device *pdev)
                return PTR_ERR(pc->tbclk);
        }
 
+       ret = clk_prepare(pc->tbclk);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "clk_prepare() failed: %d\n", ret);
+               return ret;
+       }
+
        ret = pwmchip_add(&pc->chip);
        if (ret < 0) {
                dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret);
@@ -508,6 +514,7 @@ pwmss_clk_failure:
        pm_runtime_put_sync(&pdev->dev);
        pm_runtime_disable(&pdev->dev);
        pwmchip_remove(&pc->chip);
+       clk_unprepare(pc->tbclk);
        return ret;
 }
 
@@ -515,6 +522,8 @@ static int ehrpwm_pwm_remove(struct platform_device *pdev)
 {
        struct ehrpwm_pwm_chip *pc = platform_get_drvdata(pdev);
 
+       clk_unprepare(pc->tbclk);
+
        pm_runtime_get_sync(&pdev->dev);
        /*
         * Due to hardware misbehaviour, acknowledge of the stop_req
diff --git a/drivers/pwm/sysfs.c b/drivers/pwm/sysfs.c
new file mode 100644 (file)
index 0000000..8ca5de3
--- /dev/null
@@ -0,0 +1,352 @@
+/*
+ * A simple sysfs interface for the generic PWM framework
+ *
+ * Copyright (C) 2013 H Hartley Sweeten <hsweeten@visionengravers.com>
+ *
+ * Based on previous work by Lars Poeschel <poeschel@lemonage.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, 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/device.h>
+#include <linux/mutex.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/kdev_t.h>
+#include <linux/pwm.h>
+
+struct pwm_export {
+       struct device child;
+       struct pwm_device *pwm;
+};
+
+static struct pwm_export *child_to_pwm_export(struct device *child)
+{
+       return container_of(child, struct pwm_export, child);
+}
+
+static struct pwm_device *child_to_pwm_device(struct device *child)
+{
+       struct pwm_export *export = child_to_pwm_export(child);
+
+       return export->pwm;
+}
+
+static ssize_t pwm_period_show(struct device *child,
+                              struct device_attribute *attr,
+                              char *buf)
+{
+       const struct pwm_device *pwm = child_to_pwm_device(child);
+
+       return sprintf(buf, "%u\n", pwm->period);
+}
+
+static ssize_t pwm_period_store(struct device *child,
+                               struct device_attribute *attr,
+                               const char *buf, size_t size)
+{
+       struct pwm_device *pwm = child_to_pwm_device(child);
+       unsigned int val;
+       int ret;
+
+       ret = kstrtouint(buf, 0, &val);
+       if (ret)
+               return ret;
+
+       ret = pwm_config(pwm, pwm->duty_cycle, val);
+
+       return ret ? : size;
+}
+
+static ssize_t pwm_duty_cycle_show(struct device *child,
+                                  struct device_attribute *attr,
+                                  char *buf)
+{
+       const struct pwm_device *pwm = child_to_pwm_device(child);
+
+       return sprintf(buf, "%u\n", pwm->duty_cycle);
+}
+
+static ssize_t pwm_duty_cycle_store(struct device *child,
+                                   struct device_attribute *attr,
+                                   const char *buf, size_t size)
+{
+       struct pwm_device *pwm = child_to_pwm_device(child);
+       unsigned int val;
+       int ret;
+
+       ret = kstrtouint(buf, 0, &val);
+       if (ret)
+               return ret;
+
+       ret = pwm_config(pwm, val, pwm->period);
+
+       return ret ? : size;
+}
+
+static ssize_t pwm_enable_show(struct device *child,
+                              struct device_attribute *attr,
+                              char *buf)
+{
+       const struct pwm_device *pwm = child_to_pwm_device(child);
+       int enabled = test_bit(PWMF_ENABLED, &pwm->flags);
+
+       return sprintf(buf, "%d\n", enabled);
+}
+
+static ssize_t pwm_enable_store(struct device *child,
+                               struct device_attribute *attr,
+                               const char *buf, size_t size)
+{
+       struct pwm_device *pwm = child_to_pwm_device(child);
+       int val, ret;
+
+       ret = kstrtoint(buf, 0, &val);
+       if (ret)
+               return ret;
+
+       switch (val) {
+       case 0:
+               pwm_disable(pwm);
+               break;
+       case 1:
+               ret = pwm_enable(pwm);
+               break;
+       default:
+               ret = -EINVAL;
+               break;
+       }
+
+       return ret ? : size;
+}
+
+static ssize_t pwm_polarity_show(struct device *child,
+                                struct device_attribute *attr,
+                                char *buf)
+{
+       const struct pwm_device *pwm = child_to_pwm_device(child);
+
+       return sprintf(buf, "%s\n", pwm->polarity ? "inversed" : "normal");
+}
+
+static ssize_t pwm_polarity_store(struct device *child,
+                                 struct device_attribute *attr,
+                                 const char *buf, size_t size)
+{
+       struct pwm_device *pwm = child_to_pwm_device(child);
+       enum pwm_polarity polarity;
+       int ret;
+
+       if (sysfs_streq(buf, "normal"))
+               polarity = PWM_POLARITY_NORMAL;
+       else if (sysfs_streq(buf, "inversed"))
+               polarity = PWM_POLARITY_INVERSED;
+       else
+               return -EINVAL;
+
+       ret = pwm_set_polarity(pwm, polarity);
+
+       return ret ? : size;
+}
+
+static DEVICE_ATTR(period, 0644, pwm_period_show, pwm_period_store);
+static DEVICE_ATTR(duty_cycle, 0644, pwm_duty_cycle_show, pwm_duty_cycle_store);
+static DEVICE_ATTR(enable, 0644, pwm_enable_show, pwm_enable_store);
+static DEVICE_ATTR(polarity, 0644, pwm_polarity_show, pwm_polarity_store);
+
+static struct attribute *pwm_attrs[] = {
+       &dev_attr_period.attr,
+       &dev_attr_duty_cycle.attr,
+       &dev_attr_enable.attr,
+       &dev_attr_polarity.attr,
+       NULL
+};
+
+static const struct attribute_group pwm_attr_group = {
+       .attrs          = pwm_attrs,
+};
+
+static const struct attribute_group *pwm_attr_groups[] = {
+       &pwm_attr_group,
+       NULL,
+};
+
+static void pwm_export_release(struct device *child)
+{
+       struct pwm_export *export = child_to_pwm_export(child);
+
+       kfree(export);
+}
+
+static int pwm_export_child(struct device *parent, struct pwm_device *pwm)
+{
+       struct pwm_export *export;
+       int ret;
+
+       if (test_and_set_bit(PWMF_EXPORTED, &pwm->flags))
+               return -EBUSY;
+
+       export = kzalloc(sizeof(*export), GFP_KERNEL);
+       if (!export) {
+               clear_bit(PWMF_EXPORTED, &pwm->flags);
+               return -ENOMEM;
+       }
+
+       export->pwm = pwm;
+
+       export->child.release = pwm_export_release;
+       export->child.parent = parent;
+       export->child.devt = MKDEV(0, 0);
+       export->child.groups = pwm_attr_groups;
+       dev_set_name(&export->child, "pwm%u", pwm->hwpwm);
+
+       ret = device_register(&export->child);
+       if (ret) {
+               clear_bit(PWMF_EXPORTED, &pwm->flags);
+               kfree(export);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int pwm_unexport_match(struct device *child, void *data)
+{
+       return child_to_pwm_device(child) == data;
+}
+
+static int pwm_unexport_child(struct device *parent, struct pwm_device *pwm)
+{
+       struct device *child;
+
+       if (!test_and_clear_bit(PWMF_EXPORTED, &pwm->flags))
+               return -ENODEV;
+
+       child = device_find_child(parent, pwm, pwm_unexport_match);
+       if (!child)
+               return -ENODEV;
+
+       /* for device_find_child() */
+       put_device(child);
+       device_unregister(child);
+       pwm_put(pwm);
+
+       return 0;
+}
+
+static ssize_t pwm_export_store(struct device *parent,
+                               struct device_attribute *attr,
+                               const char *buf, size_t len)
+{
+       struct pwm_chip *chip = dev_get_drvdata(parent);
+       struct pwm_device *pwm;
+       unsigned int hwpwm;
+       int ret;
+
+       ret = kstrtouint(buf, 0, &hwpwm);
+       if (ret < 0)
+               return ret;
+
+       if (hwpwm >= chip->npwm)
+               return -ENODEV;
+
+       pwm = pwm_request_from_chip(chip, hwpwm, "sysfs");
+       if (IS_ERR(pwm))
+               return PTR_ERR(pwm);
+
+       ret = pwm_export_child(parent, pwm);
+       if (ret < 0)
+               pwm_put(pwm);
+
+       return ret ? : len;
+}
+
+static ssize_t pwm_unexport_store(struct device *parent,
+                                 struct device_attribute *attr,
+                                 const char *buf, size_t len)
+{
+       struct pwm_chip *chip = dev_get_drvdata(parent);
+       unsigned int hwpwm;
+       int ret;
+
+       ret = kstrtouint(buf, 0, &hwpwm);
+       if (ret < 0)
+               return ret;
+
+       if (hwpwm >= chip->npwm)
+               return -ENODEV;
+
+       ret = pwm_unexport_child(parent, &chip->pwms[hwpwm]);
+
+       return ret ? : len;
+}
+
+static ssize_t pwm_npwm_show(struct device *parent,
+                            struct device_attribute *attr,
+                            char *buf)
+{
+       const struct pwm_chip *chip = dev_get_drvdata(parent);
+
+       return sprintf(buf, "%u\n", chip->npwm);
+}
+
+static struct device_attribute pwm_chip_attrs[] = {
+       __ATTR(export, 0200, NULL, pwm_export_store),
+       __ATTR(unexport, 0200, NULL, pwm_unexport_store),
+       __ATTR(npwm, 0444, pwm_npwm_show, NULL),
+       __ATTR_NULL,
+};
+
+static struct class pwm_class = {
+       .name           = "pwm",
+       .owner          = THIS_MODULE,
+       .dev_attrs      = pwm_chip_attrs,
+};
+
+static int pwmchip_sysfs_match(struct device *parent, const void *data)
+{
+       return dev_get_drvdata(parent) == data;
+}
+
+void pwmchip_sysfs_export(struct pwm_chip *chip)
+{
+       struct device *parent;
+
+       /*
+        * If device_create() fails the pwm_chip is still usable by
+        * the kernel its just not exported.
+        */
+       parent = device_create(&pwm_class, chip->dev, MKDEV(0, 0), chip,
+                              "pwmchip%d", chip->base);
+       if (IS_ERR(parent)) {
+               dev_warn(chip->dev,
+                        "device_create failed for pwm_chip sysfs export\n");
+       }
+}
+
+void pwmchip_sysfs_unexport(struct pwm_chip *chip)
+{
+       struct device *parent;
+
+       parent = class_find_device(&pwm_class, NULL, chip,
+                                  pwmchip_sysfs_match);
+       if (parent) {
+               /* for class_find_device() */
+               put_device(parent);
+               device_unregister(parent);
+       }
+}
+
+static int __init pwm_sysfs_init(void)
+{
+       return class_register(&pwm_class);
+}
+subsys_initcall(pwm_sysfs_init);
index 00a71eb..9f7fe21 100644 (file)
@@ -16,6 +16,8 @@
 #include <linux/rio_drv.h>
 #include <linux/rio_ids.h>
 #include <linux/delay.h>
+
+#include <asm/page.h>
 #include "../rio.h"
 
 #define LOCAL_RTE_CONF_DESTID_SEL      0x010070
index a57a1b1..a4c53b2 100644 (file)
 #include <linux/slab.h>
 #include <linux/interrupt.h>
 #include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
 #include <linux/platform_device.h>
 #include <linux/regulator/driver.h>
+#include <linux/regulator/of_regulator.h>
 #include <linux/mfd/max8998.h>
 #include <linux/mfd/max8998-private.h>
 
@@ -589,13 +592,13 @@ static struct regulator_desc regulators[] = {
                .type           = REGULATOR_VOLTAGE,
                .owner          = THIS_MODULE,
        }, {
-               .name           = "EN32KHz AP",
+               .name           = "EN32KHz-AP",
                .id             = MAX8998_EN32KHZ_AP,
                .ops            = &max8998_others_ops,
                .type           = REGULATOR_VOLTAGE,
                .owner          = THIS_MODULE,
        }, {
-               .name           = "EN32KHz CP",
+               .name           = "EN32KHz-CP",
                .id             = MAX8998_EN32KHZ_CP,
                .ops            = &max8998_others_ops,
                .type           = REGULATOR_VOLTAGE,
@@ -621,21 +624,140 @@ static struct regulator_desc regulators[] = {
        }
 };
 
+static int max8998_pmic_dt_parse_dvs_gpio(struct max8998_dev *iodev,
+                       struct max8998_platform_data *pdata,
+                       struct device_node *pmic_np)
+{
+       int gpio;
+
+       gpio = of_get_named_gpio(pmic_np, "max8998,pmic-buck1-dvs-gpios", 0);
+       if (!gpio_is_valid(gpio)) {
+               dev_err(iodev->dev, "invalid buck1 gpio[0]: %d\n", gpio);
+               return -EINVAL;
+       }
+       pdata->buck1_set1 = gpio;
+
+       gpio = of_get_named_gpio(pmic_np, "max8998,pmic-buck1-dvs-gpios", 1);
+       if (!gpio_is_valid(gpio)) {
+               dev_err(iodev->dev, "invalid buck1 gpio[1]: %d\n", gpio);
+               return -EINVAL;
+       }
+       pdata->buck1_set2 = gpio;
+
+       gpio = of_get_named_gpio(pmic_np, "max8998,pmic-buck2-dvs-gpio", 0);
+       if (!gpio_is_valid(gpio)) {
+               dev_err(iodev->dev, "invalid buck 2 gpio: %d\n", gpio);
+               return -EINVAL;
+       }
+       pdata->buck2_set3 = gpio;
+
+       return 0;
+}
+
+static int max8998_pmic_dt_parse_pdata(struct max8998_dev *iodev,
+                                       struct max8998_platform_data *pdata)
+{
+       struct device_node *pmic_np = iodev->dev->of_node;
+       struct device_node *regulators_np, *reg_np;
+       struct max8998_regulator_data *rdata;
+       unsigned int i;
+       int ret;
+
+       regulators_np = of_get_child_by_name(pmic_np, "regulators");
+       if (!regulators_np) {
+               dev_err(iodev->dev, "could not find regulators sub-node\n");
+               return -EINVAL;
+       }
+
+       /* count the number of regulators to be supported in pmic */
+       pdata->num_regulators = of_get_child_count(regulators_np);
+
+       rdata = devm_kzalloc(iodev->dev, sizeof(*rdata) *
+                               pdata->num_regulators, GFP_KERNEL);
+       if (!rdata)
+               return -ENOMEM;
+
+       pdata->regulators = rdata;
+       for (i = 0; i < ARRAY_SIZE(regulators); ++i) {
+               reg_np = of_get_child_by_name(regulators_np,
+                                                       regulators[i].name);
+               if (!reg_np)
+                       continue;
+
+               rdata->id = regulators[i].id;
+               rdata->initdata = of_get_regulator_init_data(
+                                                       iodev->dev, reg_np);
+               rdata->reg_node = reg_np;
+               ++rdata;
+       }
+       pdata->num_regulators = rdata - pdata->regulators;
+
+       ret = max8998_pmic_dt_parse_dvs_gpio(iodev, pdata, pmic_np);
+       if (ret)
+               return -EINVAL;
+
+       if (of_find_property(pmic_np, "max8998,pmic-buck-voltage-lock", NULL))
+               pdata->buck_voltage_lock = true;
+
+       ret = of_property_read_u32(pmic_np,
+                                       "max8998,pmic-buck1-default-dvs-idx",
+                                       &pdata->buck1_default_idx);
+       if (!ret && pdata->buck1_default_idx >= 4) {
+               pdata->buck1_default_idx = 0;
+               dev_warn(iodev->dev, "invalid value for default dvs index, using 0 instead\n");
+       }
+
+       ret = of_property_read_u32(pmic_np,
+                                       "max8998,pmic-buck2-default-dvs-idx",
+                                       &pdata->buck2_default_idx);
+       if (!ret && pdata->buck2_default_idx >= 2) {
+               pdata->buck2_default_idx = 0;
+               dev_warn(iodev->dev, "invalid value for default dvs index, using 0 instead\n");
+       }
+
+       ret = of_property_read_u32_array(pmic_np,
+                                       "max8998,pmic-buck1-dvs-voltage",
+                                       pdata->buck1_voltage,
+                                       ARRAY_SIZE(pdata->buck1_voltage));
+       if (ret) {
+               dev_err(iodev->dev, "buck1 voltages not specified\n");
+               return -EINVAL;
+       }
+
+       ret = of_property_read_u32_array(pmic_np,
+                                       "max8998,pmic-buck2-dvs-voltage",
+                                       pdata->buck2_voltage,
+                                       ARRAY_SIZE(pdata->buck2_voltage));
+       if (ret) {
+               dev_err(iodev->dev, "buck2 voltages not specified\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
 static int max8998_pmic_probe(struct platform_device *pdev)
 {
        struct max8998_dev *iodev = dev_get_drvdata(pdev->dev.parent);
-       struct max8998_platform_data *pdata = dev_get_platdata(iodev->dev);
+       struct max8998_platform_data *pdata = iodev->pdata;
        struct regulator_config config = { };
        struct regulator_dev **rdev;
        struct max8998_data *max8998;
        struct i2c_client *i2c;
        int i, ret, size;
+       unsigned int v;
 
        if (!pdata) {
                dev_err(pdev->dev.parent, "No platform init data supplied\n");
                return -ENODEV;
        }
 
+       if (IS_ENABLED(CONFIG_OF) && iodev->dev->of_node) {
+               ret = max8998_pmic_dt_parse_pdata(iodev, pdata);
+               if (ret)
+                       return ret;
+       }
+
        max8998 = devm_kzalloc(&pdev->dev, sizeof(struct max8998_data),
                               GFP_KERNEL);
        if (!max8998)
@@ -688,53 +810,21 @@ static int max8998_pmic_probe(struct platform_device *pdev)
                gpio_request(pdata->buck1_set2, "MAX8998 BUCK1_SET2");
                gpio_direction_output(pdata->buck1_set2,
                                      (max8998->buck1_idx >> 1) & 0x1);
-               /* Set predefined value for BUCK1 register 1 */
-               i = 0;
-               while (buck12_voltage_map_desc.min +
-                      buck12_voltage_map_desc.step*i
-                      < pdata->buck1_voltage1)
-                       i++;
-               max8998->buck1_vol[0] = i;
-               ret = max8998_write_reg(i2c, MAX8998_REG_BUCK1_VOLTAGE1, i);
-               if (ret)
-                       goto err_out;
-
-               /* Set predefined value for BUCK1 register 2 */
-               i = 0;
-               while (buck12_voltage_map_desc.min +
-                      buck12_voltage_map_desc.step*i
-                      < pdata->buck1_voltage2)
-                       i++;
-
-               max8998->buck1_vol[1] = i;
-               ret = max8998_write_reg(i2c, MAX8998_REG_BUCK1_VOLTAGE2, i);
-               if (ret)
-                       goto err_out;
-
-               /* Set predefined value for BUCK1 register 3 */
-               i = 0;
-               while (buck12_voltage_map_desc.min +
-                      buck12_voltage_map_desc.step*i
-                      < pdata->buck1_voltage3)
-                       i++;
-
-               max8998->buck1_vol[2] = i;
-               ret = max8998_write_reg(i2c, MAX8998_REG_BUCK1_VOLTAGE3, i);
-               if (ret)
-                       goto err_out;
-
-               /* Set predefined value for BUCK1 register 4 */
-               i = 0;
-               while (buck12_voltage_map_desc.min +
-                      buck12_voltage_map_desc.step*i
-                      < pdata->buck1_voltage4)
-                       i++;
-
-               max8998->buck1_vol[3] = i;
-               ret = max8998_write_reg(i2c, MAX8998_REG_BUCK1_VOLTAGE4, i);
-               if (ret)
-                       goto err_out;
 
+               /* Set predefined values for BUCK1 registers */
+               for (v = 0; v < ARRAY_SIZE(pdata->buck1_voltage); ++v) {
+                       i = 0;
+                       while (buck12_voltage_map_desc.min +
+                              buck12_voltage_map_desc.step*i
+                              < pdata->buck1_voltage[v])
+                               i++;
+
+                       max8998->buck1_vol[v] = i;
+                       ret = max8998_write_reg(i2c,
+                                       MAX8998_REG_BUCK1_VOLTAGE1 + v, i);
+                       if (ret)
+                               goto err_out;
+               }
        }
 
        if (gpio_is_valid(pdata->buck2_set3)) {
@@ -750,27 +840,20 @@ static int max8998_pmic_probe(struct platform_device *pdev)
                gpio_direction_output(pdata->buck2_set3,
                                      max8998->buck2_idx & 0x1);
 
-               /* BUCK2 register 1 */
-               i = 0;
-               while (buck12_voltage_map_desc.min +
-                      buck12_voltage_map_desc.step*i
-                      < pdata->buck2_voltage1)
-                       i++;
-               max8998->buck2_vol[0] = i;
-               ret = max8998_write_reg(i2c, MAX8998_REG_BUCK2_VOLTAGE1, i);
-               if (ret)
-                       goto err_out;
-
-               /* BUCK2 register 2 */
-               i = 0;
-               while (buck12_voltage_map_desc.min +
-                      buck12_voltage_map_desc.step*i
-                      < pdata->buck2_voltage2)
-                       i++;
-               max8998->buck2_vol[1] = i;
-               ret = max8998_write_reg(i2c, MAX8998_REG_BUCK2_VOLTAGE2, i);
-               if (ret)
-                       goto err_out;
+               /* Set predefined values for BUCK2 registers */
+               for (v = 0; v < ARRAY_SIZE(pdata->buck2_voltage); ++v) {
+                       i = 0;
+                       while (buck12_voltage_map_desc.min +
+                              buck12_voltage_map_desc.step*i
+                              < pdata->buck2_voltage[v])
+                               i++;
+
+                       max8998->buck2_vol[v] = i;
+                       ret = max8998_write_reg(i2c,
+                                       MAX8998_REG_BUCK2_VOLTAGE1 + v, i);
+                       if (ret)
+                               goto err_out;
+               }
        }
 
        for (i = 0; i < pdata->num_regulators; i++) {
@@ -788,13 +871,15 @@ static int max8998_pmic_probe(struct platform_device *pdev)
                }
 
                config.dev = max8998->dev;
+               config.of_node = pdata->regulators[i].reg_node;
                config.init_data = pdata->regulators[i].initdata;
                config.driver_data = max8998;
 
                rdev[i] = regulator_register(&regulators[index], &config);
                if (IS_ERR(rdev[i])) {
                        ret = PTR_ERR(rdev[i]);
-                       dev_err(max8998->dev, "regulator init failed\n");
+                       dev_err(max8998->dev, "regulator %s init failed (%d)\n",
+                                               regulators[index].name, ret);
                        rdev[i] = NULL;
                        goto err;
                }
index 3ae44ac..d0c8785 100644 (file)
@@ -838,6 +838,9 @@ static int palmas_regulators_probe(struct platform_device *pdev)
                                continue;
                        ramp_delay_support = true;
                        break;
+               case PALMAS_REG_SMPS10:
+                       if (!PALMAS_PMIC_HAS(palmas, SMPS10_BOOST))
+                               continue;
                }
 
                if ((id == PALMAS_REG_SMPS6) || (id == PALMAS_REG_SMPS8))
@@ -1051,6 +1054,7 @@ static struct of_device_id of_palmas_match_tbl[] = {
        { .compatible = "ti,tps65913-pmic", },
        { .compatible = "ti,tps65914-pmic", },
        { .compatible = "ti,tps80036-pmic", },
+       { .compatible = "ti,tps659038-pmic", },
        { /* end */ }
 };
 
index c9f16e1..2f62564 100644 (file)
@@ -42,7 +42,7 @@ static int get_ramp_delay(int ramp_delay)
 {
        unsigned char cnt = 0;
 
-       ramp_delay /= 6;
+       ramp_delay /= 6250;
 
        while (true) {
                ramp_delay = ramp_delay >> 1;
@@ -113,6 +113,7 @@ static struct regulator_ops s2mps11_buck_ops = {
        .min_uV         = S2MPS11_BUCK_MIN1,                    \
        .uV_step        = S2MPS11_BUCK_STEP1,                   \
        .n_voltages     = S2MPS11_BUCK_N_VOLTAGES,              \
+       .ramp_delay     = S2MPS11_RAMP_DELAY,                   \
        .vsel_reg       = S2MPS11_REG_B1CTRL2 + (num - 1) * 2,  \
        .vsel_mask      = S2MPS11_BUCK_VSEL_MASK,               \
        .enable_reg     = S2MPS11_REG_B1CTRL1 + (num - 1) * 2,  \
@@ -128,6 +129,7 @@ static struct regulator_ops s2mps11_buck_ops = {
        .min_uV         = S2MPS11_BUCK_MIN1,                    \
        .uV_step        = S2MPS11_BUCK_STEP1,                   \
        .n_voltages     = S2MPS11_BUCK_N_VOLTAGES,              \
+       .ramp_delay     = S2MPS11_RAMP_DELAY,                   \
        .vsel_reg       = S2MPS11_REG_B5CTRL2,                  \
        .vsel_mask      = S2MPS11_BUCK_VSEL_MASK,               \
        .enable_reg     = S2MPS11_REG_B5CTRL1,                  \
@@ -143,6 +145,7 @@ static struct regulator_ops s2mps11_buck_ops = {
        .min_uV         = S2MPS11_BUCK_MIN1,                    \
        .uV_step        = S2MPS11_BUCK_STEP1,                   \
        .n_voltages     = S2MPS11_BUCK_N_VOLTAGES,              \
+       .ramp_delay     = S2MPS11_RAMP_DELAY,                   \
        .vsel_reg       = S2MPS11_REG_B6CTRL2 + (num - 6) * 2,  \
        .vsel_mask      = S2MPS11_BUCK_VSEL_MASK,               \
        .enable_reg     = S2MPS11_REG_B6CTRL1 + (num - 6) * 2,  \
@@ -158,6 +161,7 @@ static struct regulator_ops s2mps11_buck_ops = {
        .min_uV         = S2MPS11_BUCK_MIN3,                    \
        .uV_step        = S2MPS11_BUCK_STEP3,                   \
        .n_voltages     = S2MPS11_BUCK_N_VOLTAGES,              \
+       .ramp_delay     = S2MPS11_RAMP_DELAY,                   \
        .vsel_reg       = S2MPS11_REG_B9CTRL2,                  \
        .vsel_mask      = S2MPS11_BUCK_VSEL_MASK,               \
        .enable_reg     = S2MPS11_REG_B9CTRL1,                  \
@@ -173,6 +177,7 @@ static struct regulator_ops s2mps11_buck_ops = {
        .min_uV         = S2MPS11_BUCK_MIN2,                    \
        .uV_step        = S2MPS11_BUCK_STEP2,                   \
        .n_voltages     = S2MPS11_BUCK_N_VOLTAGES,              \
+       .ramp_delay     = S2MPS11_RAMP_DELAY,                   \
        .vsel_reg       = S2MPS11_REG_B10CTRL2,                 \
        .vsel_mask      = S2MPS11_BUCK_VSEL_MASK,               \
        .enable_reg     = S2MPS11_REG_B10CTRL1,                 \
index fb6e67d..93bc4f4 100644 (file)
@@ -109,7 +109,7 @@ struct twlreg_info {
 #define SMPS_OFFSET_EN         BIT(0)
 #define SMPS_EXTENDED_EN       BIT(1)
 
-/* twl6025 SMPS EPROM values */
+/* twl6032 SMPS EPROM values */
 #define TWL6030_SMPS_OFFSET            0xB0
 #define TWL6030_SMPS_MULT              0xB3
 #define SMPS_MULTOFFSET_SMPS4  BIT(0)
@@ -173,7 +173,7 @@ static int twl6030reg_is_enabled(struct regulator_dev *rdev)
        struct twlreg_info      *info = rdev_get_drvdata(rdev);
        int                     grp = 0, val;
 
-       if (!(twl_class_is_6030() && (info->features & TWL6025_SUBCLASS))) {
+       if (!(twl_class_is_6030() && (info->features & TWL6032_SUBCLASS))) {
                grp = twlreg_grp(rdev);
                if (grp < 0)
                        return grp;
@@ -211,7 +211,7 @@ static int twl6030reg_enable(struct regulator_dev *rdev)
        int                     grp = 0;
        int                     ret;
 
-       if (!(twl_class_is_6030() && (info->features & TWL6025_SUBCLASS)))
+       if (!(twl_class_is_6030() && (info->features & TWL6032_SUBCLASS)))
                grp = twlreg_grp(rdev);
        if (grp < 0)
                return grp;
@@ -245,7 +245,7 @@ static int twl6030reg_disable(struct regulator_dev *rdev)
        int                     grp = 0;
        int                     ret;
 
-       if (!(twl_class_is_6030() && (info->features & TWL6025_SUBCLASS)))
+       if (!(twl_class_is_6030() && (info->features & TWL6032_SUBCLASS)))
                grp = P1_GRP_6030 | P2_GRP_6030 | P3_GRP_6030;
 
        /* For 6030, set the off state for all grps enabled */
@@ -339,7 +339,7 @@ static int twl6030reg_set_mode(struct regulator_dev *rdev, unsigned mode)
        int grp = 0;
        int val;
 
-       if (!(twl_class_is_6030() && (info->features & TWL6025_SUBCLASS)))
+       if (!(twl_class_is_6030() && (info->features & TWL6032_SUBCLASS)))
                grp = twlreg_grp(rdev);
 
        if (grp < 0)
@@ -899,14 +899,14 @@ static const struct twlreg_info TWL6030_INFO_##label = { \
                }, \
        }
 
-#define TWL6025_ADJUSTABLE_LDO(label, offset, min_mVolts, max_mVolts) \
-static const struct twlreg_info TWL6025_INFO_##label = { \
+#define TWL6032_ADJUSTABLE_LDO(label, offset, min_mVolts, max_mVolts) \
+static const struct twlreg_info TWL6032_INFO_##label = { \
        .base = offset, \
        .min_mV = min_mVolts, \
        .max_mV = max_mVolts, \
        .desc = { \
                .name = #label, \
-               .id = TWL6025_REG_##label, \
+               .id = TWL6032_REG_##label, \
                .n_voltages = 32, \
                .ops = &twl6030ldo_ops, \
                .type = REGULATOR_VOLTAGE, \
@@ -933,14 +933,14 @@ static const struct twlreg_info TWLFIXED_INFO_##label = { \
                }, \
        }
 
-#define TWL6025_ADJUSTABLE_SMPS(label, offset) \
+#define TWL6032_ADJUSTABLE_SMPS(label, offset) \
 static const struct twlreg_info TWLSMPS_INFO_##label = { \
        .base = offset, \
        .min_mV = 600, \
        .max_mV = 2100, \
        .desc = { \
                .name = #label, \
-               .id = TWL6025_REG_##label, \
+               .id = TWL6032_REG_##label, \
                .n_voltages = 63, \
                .ops = &twlsmps_ops, \
                .type = REGULATOR_VOLTAGE, \
@@ -981,15 +981,15 @@ TWL6030_ADJUSTABLE_LDO(VMMC, 0x68, 1000, 3300);
 TWL6030_ADJUSTABLE_LDO(VPP, 0x6c, 1000, 3300);
 TWL6030_ADJUSTABLE_LDO(VUSIM, 0x74, 1000, 3300);
 /* 6025 are renamed compared to 6030 versions */
-TWL6025_ADJUSTABLE_LDO(LDO2, 0x54, 1000, 3300);
-TWL6025_ADJUSTABLE_LDO(LDO4, 0x58, 1000, 3300);
-TWL6025_ADJUSTABLE_LDO(LDO3, 0x5c, 1000, 3300);
-TWL6025_ADJUSTABLE_LDO(LDO5, 0x68, 1000, 3300);
-TWL6025_ADJUSTABLE_LDO(LDO1, 0x6c, 1000, 3300);
-TWL6025_ADJUSTABLE_LDO(LDO7, 0x74, 1000, 3300);
-TWL6025_ADJUSTABLE_LDO(LDO6, 0x60, 1000, 3300);
-TWL6025_ADJUSTABLE_LDO(LDOLN, 0x64, 1000, 3300);
-TWL6025_ADJUSTABLE_LDO(LDOUSB, 0x70, 1000, 3300);
+TWL6032_ADJUSTABLE_LDO(LDO2, 0x54, 1000, 3300);
+TWL6032_ADJUSTABLE_LDO(LDO4, 0x58, 1000, 3300);
+TWL6032_ADJUSTABLE_LDO(LDO3, 0x5c, 1000, 3300);
+TWL6032_ADJUSTABLE_LDO(LDO5, 0x68, 1000, 3300);
+TWL6032_ADJUSTABLE_LDO(LDO1, 0x6c, 1000, 3300);
+TWL6032_ADJUSTABLE_LDO(LDO7, 0x74, 1000, 3300);
+TWL6032_ADJUSTABLE_LDO(LDO6, 0x60, 1000, 3300);
+TWL6032_ADJUSTABLE_LDO(LDOLN, 0x64, 1000, 3300);
+TWL6032_ADJUSTABLE_LDO(LDOUSB, 0x70, 1000, 3300);
 TWL4030_FIXED_LDO(VINTANA1, 0x3f, 1500, 11, 100, 0x08);
 TWL4030_FIXED_LDO(VINTDIG, 0x47, 1500, 13, 100, 0x08);
 TWL4030_FIXED_LDO(VUSB1V5, 0x71, 1500, 17, 100, 0x08);
@@ -1001,9 +1001,9 @@ TWL6030_FIXED_LDO(VDAC, 0x64, 1800, 0);
 TWL6030_FIXED_LDO(VUSB, 0x70, 3300, 0);
 TWL6030_FIXED_LDO(V1V8, 0x16, 1800, 0);
 TWL6030_FIXED_LDO(V2V1, 0x1c, 2100, 0);
-TWL6025_ADJUSTABLE_SMPS(SMPS3, 0x34);
-TWL6025_ADJUSTABLE_SMPS(SMPS4, 0x10);
-TWL6025_ADJUSTABLE_SMPS(VIO, 0x16);
+TWL6032_ADJUSTABLE_SMPS(SMPS3, 0x34);
+TWL6032_ADJUSTABLE_SMPS(SMPS4, 0x10);
+TWL6032_ADJUSTABLE_SMPS(VIO, 0x16);
 
 static u8 twl_get_smps_offset(void)
 {
@@ -1031,7 +1031,7 @@ static u8 twl_get_smps_mult(void)
 
 #define TWL4030_OF_MATCH(comp, label) TWL_OF_MATCH(comp, TWL4030, label)
 #define TWL6030_OF_MATCH(comp, label) TWL_OF_MATCH(comp, TWL6030, label)
-#define TWL6025_OF_MATCH(comp, label) TWL_OF_MATCH(comp, TWL6025, label)
+#define TWL6032_OF_MATCH(comp, label) TWL_OF_MATCH(comp, TWL6032, label)
 #define TWLFIXED_OF_MATCH(comp, label) TWL_OF_MATCH(comp, TWLFIXED, label)
 #define TWLSMPS_OF_MATCH(comp, label) TWL_OF_MATCH(comp, TWLSMPS, label)
 
@@ -1060,15 +1060,15 @@ static const struct of_device_id twl_of_match[] = {
        TWL6030_OF_MATCH("ti,twl6030-vmmc", VMMC),
        TWL6030_OF_MATCH("ti,twl6030-vpp", VPP),
        TWL6030_OF_MATCH("ti,twl6030-vusim", VUSIM),
-       TWL6025_OF_MATCH("ti,twl6025-ldo2", LDO2),
-       TWL6025_OF_MATCH("ti,twl6025-ldo4", LDO4),
-       TWL6025_OF_MATCH("ti,twl6025-ldo3", LDO3),
-       TWL6025_OF_MATCH("ti,twl6025-ldo5", LDO5),
-       TWL6025_OF_MATCH("ti,twl6025-ldo1", LDO1),
-       TWL6025_OF_MATCH("ti,twl6025-ldo7", LDO7),
-       TWL6025_OF_MATCH("ti,twl6025-ldo6", LDO6),
-       TWL6025_OF_MATCH("ti,twl6025-ldoln", LDOLN),
-       TWL6025_OF_MATCH("ti,twl6025-ldousb", LDOUSB),
+       TWL6032_OF_MATCH("ti,twl6032-ldo2", LDO2),
+       TWL6032_OF_MATCH("ti,twl6032-ldo4", LDO4),
+       TWL6032_OF_MATCH("ti,twl6032-ldo3", LDO3),
+       TWL6032_OF_MATCH("ti,twl6032-ldo5", LDO5),
+       TWL6032_OF_MATCH("ti,twl6032-ldo1", LDO1),
+       TWL6032_OF_MATCH("ti,twl6032-ldo7", LDO7),
+       TWL6032_OF_MATCH("ti,twl6032-ldo6", LDO6),
+       TWL6032_OF_MATCH("ti,twl6032-ldoln", LDOLN),
+       TWL6032_OF_MATCH("ti,twl6032-ldousb", LDOUSB),
        TWLFIXED_OF_MATCH("ti,twl4030-vintana1", VINTANA1),
        TWLFIXED_OF_MATCH("ti,twl4030-vintdig", VINTDIG),
        TWLFIXED_OF_MATCH("ti,twl4030-vusb1v5", VUSB1V5),
@@ -1080,9 +1080,9 @@ static const struct of_device_id twl_of_match[] = {
        TWLFIXED_OF_MATCH("ti,twl6030-vusb", VUSB),
        TWLFIXED_OF_MATCH("ti,twl6030-v1v8", V1V8),
        TWLFIXED_OF_MATCH("ti,twl6030-v2v1", V2V1),
-       TWLSMPS_OF_MATCH("ti,twl6025-smps3", SMPS3),
-       TWLSMPS_OF_MATCH("ti,twl6025-smps4", SMPS4),
-       TWLSMPS_OF_MATCH("ti,twl6025-vio", VIO),
+       TWLSMPS_OF_MATCH("ti,twl6032-smps3", SMPS3),
+       TWLSMPS_OF_MATCH("ti,twl6032-smps4", SMPS4),
+       TWLSMPS_OF_MATCH("ti,twl6032-vio", VIO),
        {},
 };
 MODULE_DEVICE_TABLE(of, twl_of_match);
@@ -1163,19 +1163,19 @@ static int twlreg_probe(struct platform_device *pdev)
        }
 
        switch (id) {
-       case TWL6025_REG_SMPS3:
+       case TWL6032_REG_SMPS3:
                if (twl_get_smps_mult() & SMPS_MULTOFFSET_SMPS3)
                        info->flags |= SMPS_EXTENDED_EN;
                if (twl_get_smps_offset() & SMPS_MULTOFFSET_SMPS3)
                        info->flags |= SMPS_OFFSET_EN;
                break;
-       case TWL6025_REG_SMPS4:
+       case TWL6032_REG_SMPS4:
                if (twl_get_smps_mult() & SMPS_MULTOFFSET_SMPS4)
                        info->flags |= SMPS_EXTENDED_EN;
                if (twl_get_smps_offset() & SMPS_MULTOFFSET_SMPS4)
                        info->flags |= SMPS_OFFSET_EN;
                break;
-       case TWL6025_REG_VIO:
+       case TWL6032_REG_VIO:
                if (twl_get_smps_mult() & SMPS_MULTOFFSET_VIO)
                        info->flags |= SMPS_EXTENDED_EN;
                if (twl_get_smps_offset() & SMPS_MULTOFFSET_VIO)
index 022dc63..3cd85a6 100644 (file)
@@ -762,13 +762,6 @@ static void rproc_resource_cleanup(struct rproc *rproc)
                kfree(entry);
        }
 
-       /* clean up carveout allocations */
-       list_for_each_entry_safe(entry, tmp, &rproc->carveouts, node) {
-               dma_free_coherent(dev->parent, entry->len, entry->va, entry->dma);
-               list_del(&entry->node);
-               kfree(entry);
-       }
-
        /* clean up iommu mapping entries */
        list_for_each_entry_safe(entry, tmp, &rproc->mappings, node) {
                size_t unmapped;
@@ -783,6 +776,13 @@ static void rproc_resource_cleanup(struct rproc *rproc)
                list_del(&entry->node);
                kfree(entry);
        }
+
+       /* clean up carveout allocations */
+       list_for_each_entry_safe(entry, tmp, &rproc->carveouts, node) {
+               dma_free_coherent(dev->parent, entry->len, entry->va, entry->dma);
+               list_del(&entry->node);
+               kfree(entry);
+       }
 }
 
 /*
@@ -815,18 +815,17 @@ static int rproc_fw_boot(struct rproc *rproc, const struct firmware *fw)
        }
 
        rproc->bootaddr = rproc_get_boot_addr(rproc, fw);
+       ret = -EINVAL;
 
        /* look for the resource table */
        table = rproc_find_rsc_table(rproc, fw, &tablesz);
        if (!table) {
-               ret = -EINVAL;
                goto clean_up;
        }
 
        /* Verify that resource table in loaded fw is unchanged */
        if (rproc->table_csum != crc32(0, table, tablesz)) {
                dev_err(dev, "resource checksum failed, fw changed?\n");
-               ret = -EINVAL;
                goto clean_up;
        }
 
@@ -852,8 +851,10 @@ static int rproc_fw_boot(struct rproc *rproc, const struct firmware *fw)
         * copy this information to device memory.
         */
        loaded_table = rproc_find_loaded_rsc_table(rproc, fw);
-       if (!loaded_table)
+       if (!loaded_table) {
+               ret = -EINVAL;
                goto clean_up;
+       }
 
        memcpy(loaded_table, rproc->cached_table, tablesz);
 
@@ -913,11 +914,10 @@ static void rproc_fw_config_virtio(const struct firmware *fw, void *context)
         * will be stored in the cached_table. Before the device is started,
         * cached_table will be copied into devic memory.
         */
-       rproc->cached_table = kmalloc(tablesz, GFP_KERNEL);
+       rproc->cached_table = kmemdup(table, tablesz, GFP_KERNEL);
        if (!rproc->cached_table)
                goto out;
 
-       memcpy(rproc->cached_table, table, tablesz);
        rproc->table_ptr = rproc->cached_table;
 
        /* count the number of notify-ids */
index 157a573..9d30809 100644 (file)
@@ -248,6 +248,5 @@ void __init rproc_init_debugfs(void)
 
 void __exit rproc_exit_debugfs(void)
 {
-       if (rproc_dbg)
-               debugfs_remove(rproc_dbg);
+       debugfs_remove(rproc_dbg);
 }
index 157e762..70701a5 100644 (file)
@@ -107,12 +107,12 @@ struct resource_table *rproc_find_rsc_table(struct rproc *rproc,
 
 static inline
 struct resource_table *rproc_find_loaded_rsc_table(struct rproc *rproc,
-                                const struct firmware *fw)
+                                               const struct firmware *fw)
 {
        if (rproc->fw_ops->find_loaded_rsc_table)
                return rproc->fw_ops->find_loaded_rsc_table(rproc, fw);
 
-        return NULL;
+       return NULL;
 }
 
 extern const struct rproc_fw_ops rproc_elf_fw_ops;
index 5388336..f098ad8 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/i2c.h>
 #include <linux/slab.h>
 #include <linux/bcd.h>
+#include <linux/irqdomain.h>
 #include <linux/rtc.h>
 #include <linux/platform_device.h>
 #include <linux/mfd/max8998.h>
@@ -252,7 +253,7 @@ static const struct rtc_class_ops max8998_rtc_ops = {
 static int max8998_rtc_probe(struct platform_device *pdev)
 {
        struct max8998_dev *max8998 = dev_get_drvdata(pdev->dev.parent);
-       struct max8998_platform_data *pdata = dev_get_platdata(max8998->dev);
+       struct max8998_platform_data *pdata = max8998->pdata;
        struct max8998_rtc_info *info;
        int ret;
 
@@ -264,7 +265,6 @@ static int max8998_rtc_probe(struct platform_device *pdev)
        info->dev = &pdev->dev;
        info->max8998 = max8998;
        info->rtc = max8998->rtc;
-       info->irq = max8998->irq_base + MAX8998_IRQ_ALARM0;
 
        platform_set_drvdata(pdev, info);
 
@@ -277,6 +277,15 @@ static int max8998_rtc_probe(struct platform_device *pdev)
                return ret;
        }
 
+       if (!max8998->irq_domain)
+               goto no_irq;
+
+       info->irq = irq_create_mapping(max8998->irq_domain, MAX8998_IRQ_ALARM0);
+       if (!info->irq) {
+               dev_warn(&pdev->dev, "Failed to map alarm IRQ\n");
+               goto no_irq;
+       }
+
        ret = devm_request_threaded_irq(&pdev->dev, info->irq, NULL,
                                max8998_rtc_alarm_irq, 0, "rtc-alarm0", info);
 
@@ -284,6 +293,7 @@ static int max8998_rtc_probe(struct platform_device *pdev)
                dev_err(&pdev->dev, "Failed to request alarm IRQ: %d: %d\n",
                        info->irq, ret);
 
+no_irq:
        dev_info(&pdev->dev, "RTC CHIP NAME: %s\n", pdev->id_entry->name);
        if (pdata && pdata->rtc_delay) {
                info->lp3974_bug_workaround = true;
index 76e4c03..d35a5d6 100644 (file)
@@ -1,10 +1,10 @@
-/* 
+/*
  * ASCII values for a number of symbolic constants, printing functions,
  * etc.
  * Additions for SCSI 2 and Linux 2.2.x by D. Gilbert (990422)
  * Additions for SCSI 3+ (SPC-3 T10/1416-D Rev 07 3 May 2002)
  *   by D. Gilbert and aeb (20020609)
- * Update to SPC-4 T10/1713-D Rev 20, 22 May 2009, D. Gilbert 20090624
+ * Updated to SPC-4 T10/1713-D Rev 36g, D. Gilbert 20130701
  */
 
 #include <linux/blkdev.h>
 
 
 /* Commands with service actions that change the command name */
-#define MAINTENANCE_IN 0xa3
-#define MAINTENANCE_OUT 0xa4
 #define SERVICE_ACTION_IN_12 0xab
 #define SERVICE_ACTION_OUT_12 0xa9
+#define SERVICE_ACTION_BIDIRECTIONAL 0x9d
 #define SERVICE_ACTION_IN_16 0x9e
 #define SERVICE_ACTION_OUT_16 0x9f
+#define THIRD_PARTY_COPY_OUT 0x83
+#define THIRD_PARTY_COPY_IN 0x84
 
 
 
@@ -36,11 +37,11 @@ static const char * cdb_byte0_names[] = {
 /* 04-07 */ "Format Unit/Medium", "Read Block Limits", NULL,
            "Reassign Blocks",
 /* 08-0d */ "Read(6)", NULL, "Write(6)", "Seek(6)", NULL, NULL,
-/* 0e-12 */ NULL, "Read Reverse", "Write Filemarks", "Space", "Inquiry",  
+/* 0e-12 */ NULL, "Read Reverse", "Write Filemarks", "Space", "Inquiry",
 /* 13-16 */ "Verify(6)", "Recover Buffered Data", "Mode Select(6)",
            "Reserve(6)",
 /* 17-1a */ "Release(6)", "Copy", "Erase", "Mode Sense(6)",
-/* 1b-1d */ "Start/Stop Unit", "Receive Diagnostic", "Send Diagnostic", 
+/* 1b-1d */ "Start/Stop Unit", "Receive Diagnostic", "Send Diagnostic",
 /* 1e-1f */ "Prevent/Allow Medium Removal", NULL,
 /* 20-22 */  NULL, NULL, NULL,
 /* 23-28 */ "Read Format Capacities", "Set Window",
@@ -48,16 +49,16 @@ static const char * cdb_byte0_names[] = {
 /* 29-2d */ "Read Generation", "Write(10)", "Seek(10)", "Erase(10)",
             "Read updated block",
 /* 2e-31 */ "Write Verify(10)", "Verify(10)", "Search High", "Search Equal",
-/* 32-34 */ "Search Low", "Set Limits", "Prefetch/Read Position", 
+/* 32-34 */ "Search Low", "Set Limits", "Prefetch/Read Position",
 /* 35-37 */ "Synchronize Cache(10)", "Lock/Unlock Cache(10)",
-           "Read Defect Data(10)", 
-/* 38-3c */ "Medium Scan", "Compare", "Copy Verify", "Write Buffer", 
-            "Read Buffer", 
+           "Read Defect Data(10)",
+/* 38-3c */ "Medium Scan", "Compare", "Copy Verify", "Write Buffer",
+           "Read Buffer",
 /* 3d-3f */ "Update Block", "Read Long(10)",  "Write Long(10)",
 /* 40-41 */ "Change Definition", "Write Same(10)",
 /* 42-48 */ "Unmap/Read sub-channel", "Read TOC/PMA/ATIP",
            "Read density support", "Play audio(10)", "Get configuration",
-           "Play audio msf", "Play audio track/index",
+           "Play audio msf", "Sanitize/Play audio track/index",
 /* 49-4f */ "Play track relative(10)", "Get event status notification",
             "Pause/resume", "Log Select", "Log Sense", "Stop play/scan",
             NULL,
@@ -72,17 +73,17 @@ static const char * cdb_byte0_names[] = {
 /* 70-77 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
 /* 78-7f */ NULL, NULL, NULL, NULL, NULL, NULL, "Extended CDB",
            "Variable length",
-/* 80-84 */ "Xdwrite(16)", "Rebuild(16)", "Regenerate(16)", "Extended copy",
-            "Receive copy results",
+/* 80-84 */ "Xdwrite(16)", "Rebuild(16)", "Regenerate(16)",
+           "Third party copy out", "Third party copy in",
 /* 85-89 */ "ATA command pass through(16)", "Access control in",
-           "Access control out", "Read(16)", "Memory Export Out(16)",
+           "Access control out", "Read(16)", "Compare and Write",
 /* 8a-8f */ "Write(16)", "ORWrite", "Read attributes", "Write attributes",
             "Write and verify(16)", "Verify(16)",
 /* 90-94 */ "Pre-fetch(16)", "Synchronize cache(16)",
             "Lock/unlock cache(16)", "Write same(16)", NULL,
 /* 95-99 */ NULL, NULL, NULL, NULL, NULL,
-/* 9a-9f */ NULL, NULL, NULL, NULL, "Service action in(16)",
-            "Service action out(16)",
+/* 9a-9f */ NULL, NULL, NULL, "Service action bidirectional",
+           "Service action in(16)", "Service action out(16)",
 /* a0-a5 */ "Report luns", "ATA command pass through(12)/Blank",
             "Security protocol in", "Maintenance in", "Maintenance out",
            "Move medium/play audio(12)",
@@ -122,6 +123,7 @@ static const struct value_name_pair maint_out_arr[] = {
        {0x6, "Set identifying information"},
        {0xa, "Set target port groups"},
        {0xb, "Change aliases"},
+       {0xc, "Remove I_T nexus"},
        {0xe, "Set priority"},
        {0xf, "Set timestamp"},
        {0x10, "Management protocol out"},
@@ -138,10 +140,16 @@ static const struct value_name_pair serv_out12_arr[] = {
 };
 #define SERV_OUT12_SZ ARRAY_SIZE(serv_out12_arr)
 
+static const struct value_name_pair serv_bidi_arr[] = {
+       {-1, "dummy entry"},
+};
+#define SERV_BIDI_SZ ARRAY_SIZE(serv_bidi_arr)
+
 static const struct value_name_pair serv_in16_arr[] = {
        {0x10, "Read capacity(16)"},
        {0x11, "Read long(16)"},
        {0x12, "Get LBA status"},
+       {0x13, "Report referrals"},
 };
 #define SERV_IN16_SZ ARRAY_SIZE(serv_in16_arr)
 
@@ -151,6 +159,51 @@ static const struct value_name_pair serv_out16_arr[] = {
 };
 #define SERV_OUT16_SZ ARRAY_SIZE(serv_out16_arr)
 
+static const struct value_name_pair pr_in_arr[] = {
+       {0x0, "Persistent reserve in, read keys"},
+       {0x1, "Persistent reserve in, read reservation"},
+       {0x2, "Persistent reserve in, report capabilities"},
+       {0x3, "Persistent reserve in, read full status"},
+};
+#define PR_IN_SZ ARRAY_SIZE(pr_in_arr)
+
+static const struct value_name_pair pr_out_arr[] = {
+       {0x0, "Persistent reserve out, register"},
+       {0x1, "Persistent reserve out, reserve"},
+       {0x2, "Persistent reserve out, release"},
+       {0x3, "Persistent reserve out, clear"},
+       {0x4, "Persistent reserve out, preempt"},
+       {0x5, "Persistent reserve out, preempt and abort"},
+       {0x6, "Persistent reserve out, register and ignore existing key"},
+       {0x7, "Persistent reserve out, register and move"},
+};
+#define PR_OUT_SZ ARRAY_SIZE(pr_out_arr)
+
+/* SPC-4 rev 34 renamed the Extended Copy opcode to Third Party Copy Out.
+   LID1 (List Identifier length: 1 byte) is the Extended Copy found in SPC-2
+   and SPC-3 */
+static const struct value_name_pair tpc_out_arr[] = {
+       {0x0, "Extended copy(LID1)"},
+       {0x1, "Extended copy(LID4)"},
+       {0x10, "Populate token"},
+       {0x11, "Write using token"},
+       {0x1c, "Copy operation abort"},
+};
+#define TPC_OUT_SZ ARRAY_SIZE(tpc_out_arr)
+
+static const struct value_name_pair tpc_in_arr[] = {
+       {0x0, "Receive copy status(LID1)"},
+       {0x1, "Receive copy data(LID1)"},
+       {0x3, "Receive copy operating parameters"},
+       {0x4, "Receive copy failure details(LID1)"},
+       {0x5, "Receive copy status(LID4)"},
+       {0x6, "Receive copy data(LID4)"},
+       {0x7, "Receive ROD token information"},
+       {0x8, "Report all ROD tokens"},
+};
+#define TPC_IN_SZ ARRAY_SIZE(tpc_in_arr)
+
+
 static const struct value_name_pair variable_length_arr[] = {
        {0x1, "Rebuild(32)"},
        {0x2, "Regenerate(32)"},
@@ -207,6 +260,7 @@ static const char * get_sa_name(const struct value_name_pair * arr,
 static void print_opcode_name(unsigned char * cdbp, int cdb_len)
 {
        int sa, len, cdb0;
+       int fin_name = 0;
        const char * name;
 
        cdb0 = cdbp[0];
@@ -219,7 +273,8 @@ static void print_opcode_name(unsigned char * cdbp, int cdb_len)
                        break;
                }
                sa = (cdbp[8] << 8) + cdbp[9];
-               name = get_sa_name(variable_length_arr, VARIABLE_LENGTH_SZ, sa);
+               name = get_sa_name(variable_length_arr, VARIABLE_LENGTH_SZ,
+                                  sa);
                if (name)
                        printk("%s", name);
                else
@@ -232,50 +287,57 @@ static void print_opcode_name(unsigned char * cdbp, int cdb_len)
        case MAINTENANCE_IN:
                sa = cdbp[1] & 0x1f;
                name = get_sa_name(maint_in_arr, MAINT_IN_SZ, sa);
-               if (name)
-                       printk("%s", name);
-               else
-                       printk("cdb[0]=0x%x, sa=0x%x", cdb0, sa);
+               fin_name = 1;
                break;
        case MAINTENANCE_OUT:
                sa = cdbp[1] & 0x1f;
                name = get_sa_name(maint_out_arr, MAINT_OUT_SZ, sa);
-               if (name)
-                       printk("%s", name);
-               else
-                       printk("cdb[0]=0x%x, sa=0x%x", cdb0, sa);
+               fin_name = 1;
+               break;
+       case PERSISTENT_RESERVE_IN:
+               sa = cdbp[1] & 0x1f;
+               name = get_sa_name(pr_in_arr, PR_IN_SZ, sa);
+               fin_name = 1;
+               break;
+       case PERSISTENT_RESERVE_OUT:
+               sa = cdbp[1] & 0x1f;
+               name = get_sa_name(pr_out_arr, PR_OUT_SZ, sa);
+               fin_name = 1;
                break;
        case SERVICE_ACTION_IN_12:
                sa = cdbp[1] & 0x1f;
                name = get_sa_name(serv_in12_arr, SERV_IN12_SZ, sa);
-               if (name)
-                       printk("%s", name);
-               else
-                       printk("cdb[0]=0x%x, sa=0x%x", cdb0, sa);
+               fin_name = 1;
                break;
        case SERVICE_ACTION_OUT_12:
                sa = cdbp[1] & 0x1f;
                name = get_sa_name(serv_out12_arr, SERV_OUT12_SZ, sa);
-               if (name)
-                       printk("%s", name);
-               else
-                       printk("cdb[0]=0x%x, sa=0x%x", cdb0, sa);
+               fin_name = 1;
+               break;
+       case SERVICE_ACTION_BIDIRECTIONAL:
+               sa = cdbp[1] & 0x1f;
+               name = get_sa_name(serv_bidi_arr, SERV_BIDI_SZ, sa);
+               fin_name = 1;
                break;
        case SERVICE_ACTION_IN_16:
                sa = cdbp[1] & 0x1f;
                name = get_sa_name(serv_in16_arr, SERV_IN16_SZ, sa);
-               if (name)
-                       printk("%s", name);
-               else
-                       printk("cdb[0]=0x%x, sa=0x%x", cdb0, sa);
+               fin_name = 1;
                break;
        case SERVICE_ACTION_OUT_16:
                sa = cdbp[1] & 0x1f;
                name = get_sa_name(serv_out16_arr, SERV_OUT16_SZ, sa);
-               if (name)
-                       printk("%s", name);
-               else
-                       printk("cdb[0]=0x%x, sa=0x%x", cdb0, sa);
+               fin_name = 1;
+               break;
+       case THIRD_PARTY_COPY_IN:
+               sa = cdbp[1] & 0x1f;
+               name = get_sa_name(tpc_in_arr, TPC_IN_SZ, sa);
+               fin_name = 1;
+               break;
+       case THIRD_PARTY_COPY_OUT:
+               sa = cdbp[1] & 0x1f;
+               name = get_sa_name(tpc_out_arr, TPC_OUT_SZ, sa);
+               fin_name = 1;
                break;
        default:
                if (cdb0 < 0xc0) {
@@ -288,6 +350,12 @@ static void print_opcode_name(unsigned char * cdbp, int cdb_len)
                        printk("cdb[0]=0x%x (vendor)", cdb0);
                break;
        }
+       if (fin_name) {
+               if (name)
+                       printk("%s", name);
+               else
+                       printk("cdb[0]=0x%x, sa=0x%x", cdb0, sa);
+       }
 }
 
 #else /* ifndef CONFIG_SCSI_CONSTANTS */
@@ -312,10 +380,15 @@ static void print_opcode_name(unsigned char * cdbp, int cdb_len)
                break;
        case MAINTENANCE_IN:
        case MAINTENANCE_OUT:
+       case PERSISTENT_RESERVE_IN:
+       case PERSISTENT_RESERVE_OUT:
        case SERVICE_ACTION_IN_12:
        case SERVICE_ACTION_OUT_12:
+       case SERVICE_ACTION_BIDIRECTIONAL:
        case SERVICE_ACTION_IN_16:
        case SERVICE_ACTION_OUT_16:
+       case THIRD_PARTY_COPY_IN:
+       case THIRD_PARTY_COPY_OUT:
                sa = cdbp[1] & 0x1f;
                printk("cdb[0]=0x%x, sa=0x%x", cdb0, sa);
                break;
@@ -327,7 +400,7 @@ static void print_opcode_name(unsigned char * cdbp, int cdb_len)
                break;
        }
 }
-#endif  
+#endif
 
 void __scsi_print_command(unsigned char *cdb)
 {
@@ -336,7 +409,7 @@ void __scsi_print_command(unsigned char *cdb)
        print_opcode_name(cdb, 0);
        len = scsi_command_size(cdb);
        /* print out all bytes in cdb */
-       for (k = 0; k < len; ++k) 
+       for (k = 0; k < len; ++k)
                printk(" %02x", cdb[k]);
        printk("\n");
 }
@@ -404,8 +477,9 @@ struct error_info {
 
 /*
  * The canonical list of T10 Additional Sense Codes is available at:
- * http://www.t10.org/lists/asc-num.txt
+ * http://www.t10.org/lists/asc-num.txt [most recent: 20130605]
  */
+
 static const struct error_info additional[] =
 {
        {0x0000, "No additional sense information"},
@@ -430,6 +504,8 @@ static const struct error_info additional[] =
        {0x001C, "Verify operation in progress"},
        {0x001D, "ATA pass through information available"},
        {0x001E, "Conflicting SA creation request"},
+       {0x001F, "Logical unit transitioning to another power condition"},
+       {0x0020, "Extended copy information available"},
 
        {0x0100, "No index/sector signal"},
 
@@ -460,6 +536,17 @@ static const struct error_info additional[] =
        {0x0412, "Logical unit not ready, offline"},
        {0x0413, "Logical unit not ready, SA creation in progress"},
        {0x0414, "Logical unit not ready, space allocation in progress"},
+       {0x0415, "Logical unit not ready, robotics disabled"},
+       {0x0416, "Logical unit not ready, configuration required"},
+       {0x0417, "Logical unit not ready, calibration required"},
+       {0x0418, "Logical unit not ready, a door is open"},
+       {0x0419, "Logical unit not ready, operating in sequential mode"},
+       {0x041A, "Logical unit not ready, start stop unit command in "
+        "progress"},
+       {0x041B, "Logical unit not ready, sanitize in progress"},
+       {0x041C, "Logical unit not ready, additional power use not yet "
+        "granted"},
+       {0x041D, "Logical unit not ready, configuration in progress"},
 
        {0x0500, "Logical unit does not respond to selection"},
 
@@ -490,6 +577,7 @@ static const struct error_info additional[] =
        {0x0B06, "Warning - non-volatile cache now volatile"},
        {0x0B07, "Warning - degraded power to non-volatile cache"},
        {0x0B08, "Warning - power loss expected"},
+       {0x0B09, "Warning - device statistics notification active"},
 
        {0x0C00, "Write error"},
        {0x0C01, "Write error - recovered with auto reallocation"},
@@ -505,6 +593,7 @@ static const struct error_info additional[] =
        {0x0C0B, "Auxiliary memory write error"},
        {0x0C0C, "Write error - unexpected unsolicited data"},
        {0x0C0D, "Write error - not enough unsolicited data"},
+       {0x0C0E, "Multiple write errors"},
        {0x0C0F, "Defects in error window"},
 
        {0x0D00, "Error detected by third party temporary initiator"},
@@ -523,6 +612,8 @@ static const struct error_info additional[] =
        {0x1001, "Logical block guard check failed"},
        {0x1002, "Logical block application tag check failed"},
        {0x1003, "Logical block reference tag check failed"},
+       {0x1004, "Logical block protection error on recover buffered data"},
+       {0x1005, "Logical block protection method error"},
 
        {0x1100, "Unrecovered read error"},
        {0x1101, "Read retries exhausted"},
@@ -545,6 +636,7 @@ static const struct error_info additional[] =
        {0x1112, "Auxiliary memory read error"},
        {0x1113, "Read error - failed retransmission request"},
        {0x1114, "Read error - lba marked bad by application client"},
+       {0x1115, "Write after sanitize required"},
 
        {0x1200, "Address mark not found for id field"},
 
@@ -622,6 +714,7 @@ static const struct error_info additional[] =
        {0x2009, "Access denied - invalid LU identifier"},
        {0x200A, "Access denied - invalid proxy token"},
        {0x200B, "Access denied - ACL LUN conflict"},
+       {0x200C, "Illegal command when not in append-only mode"},
 
        {0x2100, "Logical block address out of range"},
        {0x2101, "Invalid element address"},
@@ -630,6 +723,19 @@ static const struct error_info additional[] =
 
        {0x2200, "Illegal function (use 20 00, 24 00, or 26 00)"},
 
+       {0x2300, "Invalid token operation, cause not reportable"},
+       {0x2301, "Invalid token operation, unsupported token type"},
+       {0x2302, "Invalid token operation, remote token usage not supported"},
+       {0x2303, "Invalid token operation, remote rod token creation not "
+        "supported"},
+       {0x2304, "Invalid token operation, token unknown"},
+       {0x2305, "Invalid token operation, token corrupt"},
+       {0x2306, "Invalid token operation, token revoked"},
+       {0x2307, "Invalid token operation, token expired"},
+       {0x2308, "Invalid token operation, token cancelled"},
+       {0x2309, "Invalid token operation, token deleted"},
+       {0x230A, "Invalid token operation, invalid token length"},
+
        {0x2400, "Invalid field in cdb"},
        {0x2401, "CDB decryption error"},
        {0x2402, "Obsolete"},
@@ -705,6 +811,7 @@ static const struct error_info additional[] =
                 "event"},
        {0x2A13, "Data encryption key instance counter has changed"},
        {0x2A14, "SA creation capabilities data has changed"},
+       {0x2A15, "Medium removal prevention preempted"},
 
        {0x2B00, "Copy cannot execute since host cannot disconnect"},
 
@@ -720,6 +827,7 @@ static const struct error_info additional[] =
        {0x2C09, "Previous reservation conflict status"},
        {0x2C0A, "Partition or collection contains user objects"},
        {0x2C0B, "Not reserved"},
+       {0x2C0C, "Orwrite generation does not match"},
 
        {0x2D00, "Overwrite error on update in place"},
 
@@ -728,6 +836,7 @@ static const struct error_info additional[] =
        {0x2F00, "Commands cleared by another initiator"},
        {0x2F01, "Commands cleared by power loss notification"},
        {0x2F02, "Commands cleared by device server"},
+       {0x2F03, "Some commands cleared by queuing layer event"},
 
        {0x3000, "Incompatible medium installed"},
        {0x3001, "Cannot read medium - unknown format"},
@@ -745,10 +854,12 @@ static const struct error_info additional[] =
        {0x3010, "Medium not formatted"},
        {0x3011, "Incompatible volume type"},
        {0x3012, "Incompatible volume qualifier"},
+       {0x3013, "Cleaning volume expired"},
 
        {0x3100, "Medium format corrupted"},
        {0x3101, "Format command failed"},
        {0x3102, "Zoned formatting failed due to spare linking"},
+       {0x3103, "Sanitize command failed"},
 
        {0x3200, "No defect spare location available"},
        {0x3201, "Defect list update failure"},
@@ -809,6 +920,8 @@ static const struct error_info additional[] =
        {0x3B19, "Element enabled"},
        {0x3B1A, "Data transfer device removed"},
        {0x3B1B, "Data transfer device inserted"},
+       {0x3B1C, "Too many logical objects on partition to support "
+        "operation"},
 
        {0x3D00, "Invalid bits in identify message"},
 
@@ -839,6 +952,7 @@ static const struct error_info additional[] =
        {0x3F12, "iSCSI IP address added"},
        {0x3F13, "iSCSI IP address removed"},
        {0x3F14, "iSCSI IP address changed"},
+       {0x3F15, "Inspect referrals sense descriptors"},
 /*
  *     {0x40NN, "Ram failure"},
  *     {0x40NN, "Diagnostic failure on component nn"},
@@ -848,6 +962,7 @@ static const struct error_info additional[] =
        {0x4300, "Message error"},
 
        {0x4400, "Internal target failure"},
+       {0x4401, "Persistent reservation information lost"},
        {0x4471, "ATA device failed set features"},
 
        {0x4500, "Select or reselect failure"},
@@ -876,6 +991,21 @@ static const struct error_info additional[] =
        {0x4B04, "Nak received"},
        {0x4B05, "Data offset error"},
        {0x4B06, "Initiator response timeout"},
+       {0x4B07, "Connection lost"},
+       {0x4B08, "Data-in buffer overflow - data buffer size"},
+       {0x4B09, "Data-in buffer overflow - data buffer descriptor area"},
+       {0x4B0A, "Data-in buffer error"},
+       {0x4B0B, "Data-out buffer overflow - data buffer size"},
+       {0x4B0C, "Data-out buffer overflow - data buffer descriptor area"},
+       {0x4B0D, "Data-out buffer error"},
+       {0x4B0E, "PCIe fabric error"},
+       {0x4B0F, "PCIe completion timeout"},
+       {0x4B10, "PCIe completer abort"},
+       {0x4B11, "PCIe poisoned tlp received"},
+       {0x4B12, "PCIe eCRC check failed"},
+       {0x4B13, "PCIe unsupported request"},
+       {0x4B14, "PCIe acs violation"},
+       {0x4B15, "PCIe tlp prefix blocked"},
 
        {0x4C00, "Logical unit failed self-configuration"},
 /*
@@ -897,6 +1027,10 @@ static const struct error_info additional[] =
        {0x5302, "Medium removal prevented"},
        {0x5303, "Medium removal prevented by data transfer element"},
        {0x5304, "Medium thread or unthread failure"},
+       {0x5305, "Volume identifier invalid"},
+       {0x5306, "Volume identifier missing"},
+       {0x5307, "Duplicate volume identifier"},
+       {0x5308, "Element status unknown"},
 
        {0x5400, "Scsi to host system interface failure"},
 
@@ -911,6 +1045,9 @@ static const struct error_info additional[] =
        {0x5508, "Maximum number of supplemental decryption keys exceeded"},
        {0x5509, "Medium auxiliary memory not accessible"},
        {0x550A, "Data currently unavailable"},
+       {0x550B, "Insufficient power for operation"},
+       {0x550C, "Insufficient resources to create rod"},
+       {0x550D, "Insufficient resources to create rod token"},
 
        {0x5700, "Unable to recover table-of-contents"},
 
@@ -1069,6 +1206,7 @@ static const struct error_info additional[] =
        {0x670B, "ATA device feature not enabled"},
 
        {0x6800, "Logical unit not configured"},
+       {0x6801, "Subsidiary logical unit not configured"},
 
        {0x6900, "Data loss on logical unit"},
        {0x6901, "Multiple logical unit failures"},
@@ -1185,10 +1323,13 @@ static const char * const snstext[] = {
        "Vendor Specific(9)",
        "Copy Aborted",     /* A: COPY or COMPARE was aborted */
        "Aborted Command",  /* B: The target aborted the command */
-       "Equal",            /* C: A SEARCH DATA command found data equal */
+       "Equal",            /* C: A SEARCH DATA command found data equal,
+                                 reserved in SPC-4 rev 36 */
        "Volume Overflow",  /* D: Medium full with still data to be written */
        "Miscompare",       /* E: Source data and data on the medium
                                  do not agree */
+       "Completed",        /* F: command completed sense data reported,
+                                 may occur for successful command */
 };
 #endif
 
@@ -1306,7 +1447,7 @@ scsi_decode_sense_buffer(const unsigned char *sense_buffer, int sense_len,
                       struct scsi_sense_hdr *sshdr)
 {
        int k, num, res;
-    
+
        res = scsi_normalize_sense(sense_buffer, sense_len, sshdr);
        if (0 == res) {
                /* this may be SCSI-1 sense data */
@@ -1459,5 +1600,3 @@ void scsi_print_result(struct scsi_cmnd *cmd)
        scsi_show_result(cmd->result);
 }
 EXPORT_SYMBOL(scsi_print_result);
-
-
index 4a05d04..07453bb 100644 (file)
@@ -774,7 +774,6 @@ static void fcoe_fdmi_info(struct fc_lport *lport, struct net_device *netdev)
        struct fcoe_port *port;
        struct net_device *realdev;
        int rc;
-       struct netdev_fcoe_hbainfo fdmi;
 
        port = lport_priv(lport);
        fcoe = port->priv;
@@ -788,9 +787,13 @@ static void fcoe_fdmi_info(struct fc_lport *lport, struct net_device *netdev)
                return;
 
        if (realdev->netdev_ops->ndo_fcoe_get_hbainfo) {
-               memset(&fdmi, 0, sizeof(fdmi));
+               struct netdev_fcoe_hbainfo *fdmi;
+               fdmi = kzalloc(sizeof(*fdmi), GFP_KERNEL);
+               if (!fdmi)
+                       return;
+
                rc = realdev->netdev_ops->ndo_fcoe_get_hbainfo(realdev,
-                                                              &fdmi);
+                                                              fdmi);
                if (rc) {
                        printk(KERN_INFO "fcoe: Failed to retrieve FDMI "
                                        "information from netdev.\n");
@@ -800,38 +803,39 @@ static void fcoe_fdmi_info(struct fc_lport *lport, struct net_device *netdev)
                snprintf(fc_host_serial_number(lport->host),
                         FC_SERIAL_NUMBER_SIZE,
                         "%s",
-                        fdmi.serial_number);
+                        fdmi->serial_number);
                snprintf(fc_host_manufacturer(lport->host),
                         FC_SERIAL_NUMBER_SIZE,
                         "%s",
-                        fdmi.manufacturer);
+                        fdmi->manufacturer);
                snprintf(fc_host_model(lport->host),
                         FC_SYMBOLIC_NAME_SIZE,
                         "%s",
-                        fdmi.model);
+                        fdmi->model);
                snprintf(fc_host_model_description(lport->host),
                         FC_SYMBOLIC_NAME_SIZE,
                         "%s",
-                        fdmi.model_description);
+                        fdmi->model_description);
                snprintf(fc_host_hardware_version(lport->host),
                         FC_VERSION_STRING_SIZE,
                         "%s",
-                        fdmi.hardware_version);
+                        fdmi->hardware_version);
                snprintf(fc_host_driver_version(lport->host),
                         FC_VERSION_STRING_SIZE,
                         "%s",
-                        fdmi.driver_version);
+                        fdmi->driver_version);
                snprintf(fc_host_optionrom_version(lport->host),
                         FC_VERSION_STRING_SIZE,
                         "%s",
-                        fdmi.optionrom_version);
+                        fdmi->optionrom_version);
                snprintf(fc_host_firmware_version(lport->host),
                         FC_VERSION_STRING_SIZE,
                         "%s",
-                        fdmi.firmware_version);
+                        fdmi->firmware_version);
 
                /* Enable FDMI lport states */
                lport->fdmi_enabled = 1;
+               kfree(fdmi);
        } else {
                lport->fdmi_enabled = 0;
                printk(KERN_INFO "fcoe: No FDMI support.\n");
index 795843d..203415e 100644 (file)
@@ -2090,7 +2090,11 @@ static struct fc_rport_operations fcoe_ctlr_vn_rport_ops = {
  */
 static void fcoe_ctlr_disc_stop_locked(struct fc_lport *lport)
 {
+       struct fc_rport_priv *rdata;
+
        mutex_lock(&lport->disc.disc_mutex);
+       list_for_each_entry_rcu(rdata, &lport->disc.rports, peers)
+               lport->tt.rport_logoff(rdata);
        lport->disc.disc_callback = NULL;
        mutex_unlock(&lport->disc.disc_mutex);
 }
index 8c05ae0..c9382d6 100644 (file)
@@ -507,7 +507,7 @@ static const struct attribute_group *fcoe_fcf_attr_groups[] = {
        NULL,
 };
 
-struct bus_type fcoe_bus_type;
+static struct bus_type fcoe_bus_type;
 
 static int fcoe_bus_match(struct device *dev,
                          struct device_driver *drv)
@@ -541,25 +541,25 @@ static void fcoe_fcf_device_release(struct device *dev)
        kfree(fcf);
 }
 
-struct device_type fcoe_ctlr_device_type = {
+static struct device_type fcoe_ctlr_device_type = {
        .name = "fcoe_ctlr",
        .groups = fcoe_ctlr_attr_groups,
        .release = fcoe_ctlr_device_release,
 };
 
-struct device_type fcoe_fcf_device_type = {
+static struct device_type fcoe_fcf_device_type = {
        .name = "fcoe_fcf",
        .groups = fcoe_fcf_attr_groups,
        .release = fcoe_fcf_device_release,
 };
 
-struct bus_attribute fcoe_bus_attr_group[] = {
+static struct bus_attribute fcoe_bus_attr_group[] = {
        __ATTR(ctlr_create, S_IWUSR, NULL, fcoe_ctlr_create_store),
        __ATTR(ctlr_destroy, S_IWUSR, NULL, fcoe_ctlr_destroy_store),
        __ATTR_NULL
 };
 
-struct bus_type fcoe_bus_type = {
+static struct bus_type fcoe_bus_type = {
        .name = "fcoe",
        .match = &fcoe_bus_match,
        .bus_attrs = fcoe_bus_attr_group,
@@ -569,7 +569,7 @@ struct bus_type fcoe_bus_type = {
  * fcoe_ctlr_device_flush_work() - Flush a FIP ctlr's workqueue
  * @ctlr: Pointer to the FIP ctlr whose workqueue is to be flushed
  */
-void fcoe_ctlr_device_flush_work(struct fcoe_ctlr_device *ctlr)
+static void fcoe_ctlr_device_flush_work(struct fcoe_ctlr_device *ctlr)
 {
        if (!fcoe_ctlr_work_q(ctlr)) {
                printk(KERN_ERR
@@ -590,8 +590,8 @@ void fcoe_ctlr_device_flush_work(struct fcoe_ctlr_device *ctlr)
  * Return value:
  *     1 on success / 0 already queued / < 0 for error
  */
-int fcoe_ctlr_device_queue_work(struct fcoe_ctlr_device *ctlr,
-                              struct work_struct *work)
+static int fcoe_ctlr_device_queue_work(struct fcoe_ctlr_device *ctlr,
+                                      struct work_struct *work)
 {
        if (unlikely(!fcoe_ctlr_work_q(ctlr))) {
                printk(KERN_ERR
@@ -609,7 +609,7 @@ int fcoe_ctlr_device_queue_work(struct fcoe_ctlr_device *ctlr,
  * fcoe_ctlr_device_flush_devloss() - Flush a FIP ctlr's devloss workqueue
  * @ctlr: Pointer to FIP ctlr whose workqueue is to be flushed
  */
-void fcoe_ctlr_device_flush_devloss(struct fcoe_ctlr_device *ctlr)
+static void fcoe_ctlr_device_flush_devloss(struct fcoe_ctlr_device *ctlr)
 {
        if (!fcoe_ctlr_devloss_work_q(ctlr)) {
                printk(KERN_ERR
@@ -631,9 +631,9 @@ void fcoe_ctlr_device_flush_devloss(struct fcoe_ctlr_device *ctlr)
  * Return value:
  *     1 on success / 0 already queued / < 0 for error
  */
-int fcoe_ctlr_device_queue_devloss_work(struct fcoe_ctlr_device *ctlr,
-                                      struct delayed_work *work,
-                                      unsigned long delay)
+static int fcoe_ctlr_device_queue_devloss_work(struct fcoe_ctlr_device *ctlr,
+                                              struct delayed_work *work,
+                                              unsigned long delay)
 {
        if (unlikely(!fcoe_ctlr_devloss_work_q(ctlr))) {
                printk(KERN_ERR
index 01adbe0..74277c2 100644 (file)
@@ -180,24 +180,10 @@ void fcoe_ctlr_get_lesb(struct fcoe_ctlr_device *ctlr_dev)
 {
        struct fcoe_ctlr *fip = fcoe_ctlr_device_priv(ctlr_dev);
        struct net_device *netdev = fcoe_get_netdev(fip->lp);
-       struct fcoe_fc_els_lesb *fcoe_lesb;
-       struct fc_els_lesb fc_lesb;
-
-       __fcoe_get_lesb(fip->lp, &fc_lesb, netdev);
-       fcoe_lesb = (struct fcoe_fc_els_lesb *)(&fc_lesb);
-
-       ctlr_dev->lesb.lesb_link_fail =
-               ntohl(fcoe_lesb->lesb_link_fail);
-       ctlr_dev->lesb.lesb_vlink_fail =
-               ntohl(fcoe_lesb->lesb_vlink_fail);
-       ctlr_dev->lesb.lesb_miss_fka =
-               ntohl(fcoe_lesb->lesb_miss_fka);
-       ctlr_dev->lesb.lesb_symb_err =
-               ntohl(fcoe_lesb->lesb_symb_err);
-       ctlr_dev->lesb.lesb_err_block =
-               ntohl(fcoe_lesb->lesb_err_block);
-       ctlr_dev->lesb.lesb_fcs_error =
-               ntohl(fcoe_lesb->lesb_fcs_error);
+       struct fc_els_lesb *fc_lesb;
+
+       fc_lesb = (struct fc_els_lesb *)(&ctlr_dev->lesb);
+       __fcoe_get_lesb(fip->lp, fc_lesb, netdev);
 }
 EXPORT_SYMBOL_GPL(fcoe_ctlr_get_lesb);
 
@@ -721,7 +707,6 @@ ssize_t fcoe_ctlr_create_store(struct bus_type *bus,
 {
        struct net_device *netdev = NULL;
        struct fcoe_transport *ft = NULL;
-       struct fcoe_ctlr_device *ctlr_dev = NULL;
        int rc = 0;
        int err;
 
@@ -768,9 +753,8 @@ ssize_t fcoe_ctlr_create_store(struct bus_type *bus,
                goto out_putdev;
        }
 
-       LIBFCOE_TRANSPORT_DBG("transport %s %s to create fcoe on %s.\n",
-                             ft->name, (ctlr_dev) ? "succeeded" : "failed",
-                             netdev->name);
+       LIBFCOE_TRANSPORT_DBG("transport %s succeeded to create fcoe on %s.\n",
+                             ft->name, netdev->name);
 
 out_putdev:
        dev_put(netdev);
index 8b928c6..5879929 100644 (file)
@@ -337,7 +337,7 @@ static void fc_exch_release(struct fc_exch *ep)
  * fc_exch_timer_cancel() - cancel exch timer
  * @ep:                The exchange whose timer to be canceled
  */
-static inline  void fc_exch_timer_cancel(struct fc_exch *ep)
+static inline void fc_exch_timer_cancel(struct fc_exch *ep)
 {
        if (cancel_delayed_work(&ep->timeout_work)) {
                FC_EXCH_DBG(ep, "Exchange timer canceled\n");
@@ -1567,7 +1567,7 @@ static void fc_exch_abts_resp(struct fc_exch *ep, struct fc_frame *fp)
                    fc_exch_rctl_name(fh->fh_r_ctl));
 
        if (cancel_delayed_work_sync(&ep->timeout_work)) {
-               FC_EXCH_DBG(ep, "Exchange timer canceled\n");
+               FC_EXCH_DBG(ep, "Exchange timer canceled due to ABTS response\n");
                fc_exch_release(ep);    /* release from pending timer hold */
        }
 
index 6bbb944..c710d90 100644 (file)
@@ -926,6 +926,20 @@ err:
        kref_put(&rdata->kref, rdata->local_port->tt.rport_destroy);
 }
 
+static bool
+fc_rport_compatible_roles(struct fc_lport *lport, struct fc_rport_priv *rdata)
+{
+       if (rdata->ids.roles == FC_PORT_ROLE_UNKNOWN)
+               return true;
+       if ((rdata->ids.roles & FC_PORT_ROLE_FCP_TARGET) &&
+           (lport->service_params & FCP_SPPF_INIT_FCN))
+               return true;
+       if ((rdata->ids.roles & FC_PORT_ROLE_FCP_INITIATOR) &&
+           (lport->service_params & FCP_SPPF_TARG_FCN))
+               return true;
+       return false;
+}
+
 /**
  * fc_rport_enter_plogi() - Send Port Login (PLOGI) request
  * @rdata: The remote port to send a PLOGI to
@@ -938,6 +952,12 @@ static void fc_rport_enter_plogi(struct fc_rport_priv *rdata)
        struct fc_lport *lport = rdata->local_port;
        struct fc_frame *fp;
 
+       if (!fc_rport_compatible_roles(lport, rdata)) {
+               FC_RPORT_DBG(rdata, "PLOGI suppressed for incompatible role\n");
+               fc_rport_state_enter(rdata, RPORT_ST_PLOGI_WAIT);
+               return;
+       }
+
        FC_RPORT_DBG(rdata, "Port entered PLOGI state from %s state\n",
                     fc_rport_state(rdata));
 
@@ -1646,6 +1666,13 @@ static void fc_rport_recv_plogi_req(struct fc_lport *lport,
                rjt_data.explan = ELS_EXPL_NONE;
                goto reject;
        }
+       if (!fc_rport_compatible_roles(lport, rdata)) {
+               FC_RPORT_DBG(rdata, "Received PLOGI for incompatible role\n");
+               mutex_unlock(&rdata->rp_mutex);
+               rjt_data.reason = ELS_RJT_LOGIC;
+               rjt_data.explan = ELS_EXPL_NONE;
+               goto reject;
+       }
 
        /*
         * Get session payload size from incoming PLOGI.
index 6002d36..0177295 100644 (file)
@@ -4958,10 +4958,12 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance,
                                    sense, sense_handle);
        }
 
-       for (i = 0; i < ioc->sge_count && kbuff_arr[i]; i++) {
-               dma_free_coherent(&instance->pdev->dev,
-                                   kern_sge32[i].length,
-                                   kbuff_arr[i], kern_sge32[i].phys_addr);
+       for (i = 0; i < ioc->sge_count; i++) {
+               if (kbuff_arr[i])
+                       dma_free_coherent(&instance->pdev->dev,
+                                         kern_sge32[i].length,
+                                         kbuff_arr[i],
+                                         kern_sge32[i].phys_addr);
        }
 
        megasas_return_cmd(instance, cmd);
index 8056eac..4f401f7 100644 (file)
@@ -585,7 +585,7 @@ u8 get_arm(struct megasas_instance *instance, u32 ld, u8 span, u64 stripe,
        case 1:
                /* start with logical arm */
                arm = get_arm_from_strip(instance, ld, stripe, map);
-               if (arm != -1UL)
+               if (arm != -1U)
                        arm *= 2;
                break;
        }
@@ -637,7 +637,7 @@ static u8 mr_spanset_get_phy_params(struct megasas_instance *instance, u32 ld,
 
        if (raid->level == 6) {
                logArm = get_arm_from_strip(instance, ld, stripRow, map);
-               if (logArm == -1UL)
+               if (logArm == -1U)
                        return FALSE;
                rowMod = mega_mod64(row, SPAN_ROW_SIZE(map, ld, span));
                armQ = SPAN_ROW_SIZE(map, ld, span) - 1 - rowMod;
index 81471bf..d53e1b0 100644 (file)
@@ -2,7 +2,7 @@
 # Kernel configuration file for the MPT3SAS
 #
 # This code is based on drivers/scsi/mpt3sas/Kconfig
-# Copyright (C) 2012  LSI Corporation
+# Copyright (C) 2012-2013  LSI Corporation
 #  (mailto:DL-MPTFusionLinux@lsi.com)
 
 # This program is free software; you can redistribute it and/or
index 03317ff..20da8f9 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2012 LSI Corporation.
+ * Copyright (c) 2000-2013 LSI Corporation.
  *
  *
  *          Name:  mpi2.h
@@ -8,7 +8,7 @@
  *                 scatter/gather formats.
  * Creation Date:  June 21, 2006
  *
- * mpi2.h Version:  02.00.26
+ * mpi2.h Version:  02.00.29
  *
  * NOTE: Names (typedefs, defines, etc.) beginning with an MPI25 or Mpi25
  *       prefix are for use only on MPI v2.5 products, and must not be used
  * 03-29-12  02.00.25  Bumped MPI2_HEADER_VERSION_UNIT.
  *                     Added Hard Reset delay timings.
  * 07-10-12  02.00.26  Bumped MPI2_HEADER_VERSION_UNIT.
+ * 07-26-12  02.00.27  Bumped MPI2_HEADER_VERSION_UNIT.
+ * 11-27-12  02.00.28  Bumped MPI2_HEADER_VERSION_UNIT.
+ * 12-20-12  02.00.29  Bumped MPI2_HEADER_VERSION_UNIT.
+ *                     Added MPI25_SUP_REPLY_POST_HOST_INDEX_OFFSET.
  * --------------------------------------------------------------------------
  */
 
 #define MPI2_VERSION_02_05                  (0x0205)
 
 /*Unit and Dev versioning for this MPI header set */
-#define MPI2_HEADER_VERSION_UNIT            (0x1A)
+#define MPI2_HEADER_VERSION_UNIT            (0x1D)
 #define MPI2_HEADER_VERSION_DEV             (0x00)
 #define MPI2_HEADER_VERSION_UNIT_MASK       (0xFF00)
 #define MPI2_HEADER_VERSION_UNIT_SHIFT      (8)
@@ -274,6 +278,8 @@ typedef volatile struct _MPI2_SYSTEM_INTERFACE_REGS {
 #define MPI2_REPLY_POST_HOST_INDEX_MASK         (0x00FFFFFF)
 #define MPI2_RPHI_MSIX_INDEX_MASK               (0xFF000000)
 #define MPI2_RPHI_MSIX_INDEX_SHIFT              (24)
+#define MPI25_SUP_REPLY_POST_HOST_INDEX_OFFSET  (0x0000030C) /*MPI v2.5 only*/
+
 
 /*
  *Defines for the HCBSize and address
index d8b2c3e..889aa70 100644 (file)
@@ -1,12 +1,12 @@
 /*
- * Copyright (c) 2000-2011 LSI Corporation.
+ * Copyright (c) 2000-2013 LSI Corporation.
  *
  *
  *          Name:  mpi2_cnfg.h
  *         Title:  MPI Configuration messages and pages
  * Creation Date:  November 10, 2006
  *
- *   mpi2_cnfg.h Version:  02.00.22
+ *   mpi2_cnfg.h Version:  02.00.24
  *
  * NOTE: Names (typedefs, defines, etc.) beginning with an MPI25 or Mpi25
  *       prefix are for use only on MPI v2.5 products, and must not be used
  *                     Added UEFIVersion field to BIOS Page 1 and defined new
  *                     BiosOptions bits.
  *                     Incorporating additions for MPI v2.5.
+ * 11-27-12  02.00.23  Added MPI2_MANPAGE7_FLAG_EVENTREPLAY_SLOT_ORDER.
+ *                     Added MPI2_BIOSPAGE1_OPTIONS_MASK_OEM_ID.
+ * 12-20-12  02.00.24  Marked MPI2_SASIOUNIT1_CONTROL_CLEAR_AFFILIATION as
+ *                     obsolete for MPI v2.5 and later.
+ *                     Added some defines for 12G SAS speeds.
  * --------------------------------------------------------------------------
  */
 
@@ -714,6 +719,7 @@ typedef struct _MPI2_CONFIG_PAGE_MAN_7 {
 #define MPI2_MANUFACTURING7_PAGEVERSION                 (0x01)
 
 /*defines for the Flags field */
+#define MPI2_MANPAGE7_FLAG_EVENTREPLAY_SLOT_ORDER       (0x00000002)
 #define MPI2_MANPAGE7_FLAG_USE_SLOT_INFO                (0x00000001)
 
 
@@ -1310,6 +1316,9 @@ typedef struct _MPI2_CONFIG_PAGE_BIOS_1 {
 #define MPI2_BIOSPAGE1_PAGEVERSION                      (0x05)
 
 /*values for BIOS Page 1 BiosOptions field */
+#define MPI2_BIOSPAGE1_OPTIONS_MASK_OEM_ID                  (0x000000F0)
+#define MPI2_BIOSPAGE1_OPTIONS_LSI_OEM_ID                   (0x00000000)
+
 #define MPI2_BIOSPAGE1_OPTIONS_MASK_UEFI_HII_REGISTRATION   (0x00000006)
 #define MPI2_BIOSPAGE1_OPTIONS_ENABLE_UEFI_HII              (0x00000000)
 #define MPI2_BIOSPAGE1_OPTIONS_DISABLE_UEFI_HII             (0x00000002)
@@ -1884,6 +1893,7 @@ typedef struct _MPI2_CONFIG_PAGE_RD_PDISK_1 {
 #define MPI2_SAS_PRATE_MAX_RATE_1_5                     (0x80)
 #define MPI2_SAS_PRATE_MAX_RATE_3_0                     (0x90)
 #define MPI2_SAS_PRATE_MAX_RATE_6_0                     (0xA0)
+#define MPI25_SAS_PRATE_MAX_RATE_12_0                   (0xB0)
 #define MPI2_SAS_PRATE_MIN_RATE_MASK                    (0x0F)
 #define MPI2_SAS_PRATE_MIN_RATE_NOT_PROGRAMMABLE        (0x00)
 #define MPI2_SAS_PRATE_MIN_RATE_1_5                     (0x08)
@@ -1897,6 +1907,7 @@ typedef struct _MPI2_CONFIG_PAGE_RD_PDISK_1 {
 #define MPI2_SAS_HWRATE_MAX_RATE_1_5                    (0x80)
 #define MPI2_SAS_HWRATE_MAX_RATE_3_0                    (0x90)
 #define MPI2_SAS_HWRATE_MAX_RATE_6_0                    (0xA0)
+#define MPI25_SAS_HWRATE_MAX_RATE_12_0                  (0xB0)
 #define MPI2_SAS_HWRATE_MIN_RATE_MASK                   (0x0F)
 #define MPI2_SAS_HWRATE_MIN_RATE_1_5                    (0x08)
 #define MPI2_SAS_HWRATE_MIN_RATE_3_0                    (0x09)
index a079e52..f7928bf 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2012 LSI Corporation.
+ * Copyright (c) 2000-2013 LSI Corporation.
  *
  *
  *          Name:  mpi2_init.h
index 0de425d..e2bb821 100644 (file)
@@ -1,12 +1,12 @@
 /*
- * Copyright (c) 2000-2012 LSI Corporation.
+ * Copyright (c) 2000-2013 LSI Corporation.
  *
  *
  *          Name:  mpi2_ioc.h
  *         Title:  MPI IOC, Port, Event, FW Download, and FW Upload messages
  * Creation Date:  October 11, 2006
  *
- * mpi2_ioc.h Version:  02.00.21
+ * mpi2_ioc.h Version:  02.00.22
  *
  * NOTE: Names (typedefs, defines, etc.) beginning with an MPI25 or Mpi25
  *       prefix are for use only on MPI v2.5 products, and must not be used
  *                     Marked MPI2_PM_CONTROL_FEATURE_PCIE_LINK as obsolete.
  * 11-18-11  02.00.20  Incorporating additions for MPI v2.5.
  * 03-29-12  02.00.21  Added a product specific range to event values.
+ * 07-26-12  02.00.22  Added MPI2_IOCFACTS_EXCEPT_PARTIAL_MEMORY_FAILURE.
+ *                     Added ElapsedSeconds field to
+ *                     MPI2_EVENT_DATA_IR_OPERATION_STATUS.
  * --------------------------------------------------------------------------
  */
 
@@ -283,6 +286,7 @@ typedef struct _MPI2_IOC_FACTS_REPLY {
 #define MPI2_IOCFACTS_HDRVERSION_DEV_SHIFT              (0)
 
 /*IOCExceptions */
+#define MPI2_IOCFACTS_EXCEPT_PARTIAL_MEMORY_FAILURE     (0x0200)
 #define MPI2_IOCFACTS_EXCEPT_IR_FOREIGN_CONFIG_MAX      (0x0100)
 
 #define MPI2_IOCFACTS_EXCEPT_BOOTSTAT_MASK              (0x00E0)
@@ -634,7 +638,7 @@ typedef struct _MPI2_EVENT_DATA_IR_OPERATION_STATUS {
        U8 RAIDOperation;       /*0x04 */
        U8 PercentComplete;     /*0x05 */
        U16 Reserved2;          /*0x06 */
-       U32 Resereved3;         /*0x08 */
+       U32 ElapsedSeconds;     /*0x08 */
 } MPI2_EVENT_DATA_IR_OPERATION_STATUS,
        *PTR_MPI2_EVENT_DATA_IR_OPERATION_STATUS,
        Mpi2EventDataIrOperationStatus_t,
index d1d9866..7176523 100644 (file)
@@ -1,12 +1,12 @@
 /*
- * Copyright (c) 2000-2012 LSI Corporation.
+ * Copyright (c) 2000-2013 LSI Corporation.
  *
  *
  *          Name:  mpi2_raid.h
  *         Title:  MPI Integrated RAID messages and structures
  * Creation Date:  April 26, 2007
  *
- *   mpi2_raid.h Version:  02.00.08
+ *   mpi2_raid.h Version:  02.00.09
  *
  * Version History
  * ---------------
@@ -28,6 +28,8 @@
  *                     Added product-specific range to RAID Action values.
  * 11-18-11  02.00.07  Incorporating additions for MPI v2.5.
  * 02-06-12  02.00.08  Added MPI2_RAID_ACTION_PHYSDISK_HIDDEN.
+ * 07-26-12  02.00.09  Added ElapsedSeconds field to MPI2_RAID_VOL_INDICATOR.
+ *                     Added MPI2_RAID_VOL_FLAGS_ELAPSED_SECONDS_VALID define.
  * --------------------------------------------------------------------------
  */
 
@@ -269,10 +271,12 @@ typedef struct _MPI2_RAID_VOL_INDICATOR {
        U64 TotalBlocks;        /*0x00 */
        U64 BlocksRemaining;    /*0x08 */
        U32 Flags;              /*0x10 */
+       U32 ElapsedSeconds;     /* 0x14 */
 } MPI2_RAID_VOL_INDICATOR, *PTR_MPI2_RAID_VOL_INDICATOR,
        Mpi2RaidVolIndicator_t, *pMpi2RaidVolIndicator_t;
 
 /*defines for RAID Volume Indicator Flags field */
+#define MPI2_RAID_VOL_FLAGS_ELAPSED_SECONDS_VALID   (0x80000000)
 #define MPI2_RAID_VOL_FLAGS_OP_MASK                 (0x0000000F)
 #define MPI2_RAID_VOL_FLAGS_OP_BACKGROUND_INIT      (0x00000000)
 #define MPI2_RAID_VOL_FLAGS_OP_ONLINE_CAP_EXPANSION (0x00000001)
@@ -312,7 +316,7 @@ typedef struct _MPI2_RAID_COMPATIBILITY_RESULT_STRUCT {
 
 /*RAID Action Reply ActionData union */
 typedef union _MPI2_RAID_ACTION_REPLY_DATA {
-       U32 Word[5];
+       U32 Word[6];
        MPI2_RAID_VOL_INDICATOR RaidVolumeIndicator;
        U16 VolDevHandle;
        U8 VolumeState;
index b4e7084..cba046f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2012 LSI Corporation.
+ * Copyright (c) 2000-2013 LSI Corporation.
  *
  *
  *          Name:  mpi2_sas.h
index 71453d1..34e9a7b 100644 (file)
@@ -1,12 +1,12 @@
 /*
- * Copyright (c) 2000-2012 LSI Corporation.
+ * Copyright (c) 2000-2013 LSI Corporation.
  *
  *
  *          Name:  mpi2_tool.h
  *         Title:  MPI diagnostic tool structures and definitions
  * Creation Date:  March 26, 2007
  *
- *   mpi2_tool.h Version:  02.00.09
+ *   mpi2_tool.h Version:  02.00.10
  *
  * Version History
  * ---------------
@@ -30,6 +30,8 @@
  * 11-18-11  02.00.08  Incorporating additions for MPI v2.5.
  * 07-10-12  02.00.09  Add MPI v2.5 Toolbox Diagnostic CLI Tool Request
  *                     message.
+ * 07-26-12  02.00.10  Modified MPI2_TOOLBOX_DIAGNOSTIC_CLI_REQUEST so that
+ *                     it uses MPI Chain SGE as well as MPI Simple SGE.
  * --------------------------------------------------------------------------
  */
 
@@ -279,7 +281,7 @@ typedef struct _MPI2_TOOLBOX_DIAGNOSTIC_CLI_REQUEST {
        U16 Reserved6;          /*0x0E */
        U32 DataLength;         /*0x10 */
        U8 DiagnosticCliCommand[MPI2_TOOLBOX_DIAG_CLI_CMD_LENGTH];/*0x14 */
-       MPI2_SGE_SIMPLE_UNION SGL;      /*0x70 */
+       MPI2_MPI_SGE_IO_UNION SGL;      /*0x70 */
 } MPI2_TOOLBOX_DIAGNOSTIC_CLI_REQUEST,
        *PTR_MPI2_TOOLBOX_DIAGNOSTIC_CLI_REQUEST,
        Mpi2ToolboxDiagnosticCliRequest_t,
@@ -302,7 +304,7 @@ typedef struct _MPI25_TOOLBOX_DIAGNOSTIC_CLI_REQUEST {
        U32 Reserved5;          /*0x0C */
        U32 DataLength;         /*0x10 */
        U8 DiagnosticCliCommand[MPI2_TOOLBOX_DIAG_CLI_CMD_LENGTH];/*0x14 */
-       MPI25_SGE_IO_UNION SGL; /*0x70 */
+       MPI25_SGE_IO_UNION      SGL;                        /* 0x70 */
 } MPI25_TOOLBOX_DIAGNOSTIC_CLI_REQUEST,
        *PTR_MPI25_TOOLBOX_DIAGNOSTIC_CLI_REQUEST,
        Mpi25ToolboxDiagnosticCliRequest_t,
index 516f959..ba1fed5 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2000-2007 LSI Corporation.
+ *  Copyright (c) 2000-2013 LSI Corporation.
  *
  *
  *           Name:  mpi2_type.h
index 1836003..5dc280c 100644 (file)
@@ -3,7 +3,7 @@
  * for access to MPT (Message Passing Technology) firmware.
  *
  * This code is based on drivers/scsi/mpt3sas/mpt3sas_base.c
- * Copyright (C) 2012  LSI Corporation
+ * Copyright (C) 2012-2013  LSI Corporation
  *  (mailto:DL-MPTFusionLinux@lsi.com)
  *
  * This program is free software; you can redistribute it and/or
@@ -4090,11 +4090,15 @@ _base_diag_reset(struct MPT3SAS_ADAPTER *ioc, int sleep_flag)
        writel(host_diagnostic | MPI2_DIAG_RESET_ADAPTER,
             &ioc->chip->HostDiagnostic);
 
-       /* don't access any registers for 50 milliseconds */
-       msleep(50);
+       /*This delay allows the chip PCIe hardware time to finish reset tasks*/
+       if (sleep_flag == CAN_SLEEP)
+               msleep(MPI2_HARD_RESET_PCIE_FIRST_READ_DELAY_MICRO_SEC/1000);
+       else
+               mdelay(MPI2_HARD_RESET_PCIE_FIRST_READ_DELAY_MICRO_SEC/1000);
 
-       /* 300 second max wait */
-       for (count = 0; count < 3000000 ; count++) {
+       /* Approximately 300 second max wait */
+       for (count = 0; count < (300000000 /
+               MPI2_HARD_RESET_PCIE_SECOND_READ_DELAY_MICRO_SEC); count++) {
 
                host_diagnostic = readl(&ioc->chip->HostDiagnostic);
 
@@ -4103,11 +4107,13 @@ _base_diag_reset(struct MPT3SAS_ADAPTER *ioc, int sleep_flag)
                if (!(host_diagnostic & MPI2_DIAG_RESET_ADAPTER))
                        break;
 
-               /* wait 1 msec */
+               /* Wait to pass the second read delay window */
                if (sleep_flag == CAN_SLEEP)
-                       usleep_range(1000, 1500);
+                       msleep(MPI2_HARD_RESET_PCIE_SECOND_READ_DELAY_MICRO_SEC
+                                                               / 1000);
                else
-                       mdelay(1);
+                       mdelay(MPI2_HARD_RESET_PCIE_SECOND_READ_DELAY_MICRO_SEC
+                                                               / 1000);
        }
 
        if (host_diagnostic & MPI2_DIAG_HCB_MODE) {
index 994656c..0ebf5d9 100644 (file)
@@ -3,7 +3,7 @@
  * for access to MPT (Message Passing Technology) firmware.
  *
  * This code is based on drivers/scsi/mpt3sas/mpt3sas_base.h
- * Copyright (C) 2012  LSI Corporation
+ * Copyright (C) 2012-2013  LSI Corporation
  *  (mailto:DL-MPTFusionLinux@lsi.com)
  *
  * This program is free software; you can redistribute it and/or
 #define MPT3SAS_DRIVER_NAME            "mpt3sas"
 #define MPT3SAS_AUTHOR "LSI Corporation <DL-MPTFusionLinux@lsi.com>"
 #define MPT3SAS_DESCRIPTION    "LSI MPT Fusion SAS 3.0 Device Driver"
-#define MPT3SAS_DRIVER_VERSION         "01.100.01.00"
-#define MPT3SAS_MAJOR_VERSION          1
+#define MPT3SAS_DRIVER_VERSION         "02.100.00.00"
+#define MPT3SAS_MAJOR_VERSION          2
 #define MPT3SAS_MINOR_VERSION          100
-#define MPT3SAS_BUILD_VERSION          1
+#define MPT3SAS_BUILD_VERSION          0
 #define MPT3SAS_RELEASE_VERSION        00
 
 /*
index 4db0c7a..936ec03 100644 (file)
@@ -2,7 +2,7 @@
  * This module provides common API for accessing firmware configuration pages
  *
  * This code is based on drivers/scsi/mpt3sas/mpt3sas_base.c
- * Copyright (C) 2012  LSI Corporation
+ * Copyright (C) 2012-2013  LSI Corporation
  *  (mailto:DL-MPTFusionLinux@lsi.com)
  *
  * This program is free software; you can redistribute it and/or
index 0b402b6..9b89de1 100644 (file)
@@ -3,7 +3,7 @@
  * controllers
  *
  * This code is based on drivers/scsi/mpt3sas/mpt3sas_ctl.c
- * Copyright (C) 2012  LSI Corporation
+ * Copyright (C) 2012-2013  LSI Corporation
  *  (mailto:DL-MPTFusionLinux@lsi.com)
  *
  * This program is free software; you can redistribute it and/or
index bd89f4f..53b0c48 100644 (file)
@@ -3,7 +3,7 @@
  * controllers
  *
  * This code is based on drivers/scsi/mpt3sas/mpt3sas_ctl.h
- * Copyright (C) 2012  LSI Corporation
+ * Copyright (C) 2012-2013  LSI Corporation
  *  (mailto:DL-MPTFusionLinux@lsi.com)
  *
  * This program is free software; you can redistribute it and/or
index 35405e7..545b22d 100644 (file)
@@ -2,7 +2,7 @@
  * Logging Support for MPT (Message Passing Technology) based controllers
  *
  * This code is based on drivers/scsi/mpt3sas/mpt3sas_debug.c
- * Copyright (C) 2012  LSI Corporation
+ * Copyright (C) 2012-2013  LSI Corporation
  *  (mailto:DL-MPTFusionLinux@lsi.com)
  *
  * This program is free software; you can redistribute it and/or
index dcbf7c8..8cbe8fd 100644 (file)
@@ -2,7 +2,7 @@
  * Scsi Host Layer for MPT (Message Passing Technology) based controllers
  *
  * This code is based on drivers/scsi/mpt3sas/mpt3sas_scsih.c
- * Copyright (C) 2012  LSI Corporation
+ * Copyright (C) 2012-2013  LSI Corporation
  *  (mailto:DL-MPTFusionLinux@lsi.com)
  *
  * This program is free software; you can redistribute it and/or
@@ -675,11 +675,12 @@ _scsih_sas_device_add(struct MPT3SAS_ADAPTER *ioc,
                 * devices while scanning is turned on due to an oops in
                 * scsi_sysfs_add_sdev()->add_device()->sysfs_addrm_start()
                 */
-               if (!ioc->is_driver_loading)
+               if (!ioc->is_driver_loading) {
                        mpt3sas_transport_port_remove(ioc,
                            sas_device->sas_address,
                            sas_device->sas_address_parent);
-               _scsih_sas_device_remove(ioc, sas_device);
+                       _scsih_sas_device_remove(ioc, sas_device);
+               }
        }
 }
 
@@ -1273,6 +1274,7 @@ _scsih_slave_alloc(struct scsi_device *sdev)
        struct MPT3SAS_DEVICE *sas_device_priv_data;
        struct scsi_target *starget;
        struct _raid_device *raid_device;
+       struct _sas_device *sas_device;
        unsigned long flags;
 
        sas_device_priv_data = kzalloc(sizeof(struct scsi_device), GFP_KERNEL);
@@ -1301,6 +1303,19 @@ _scsih_slave_alloc(struct scsi_device *sdev)
                spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
        }
 
+       if (!(sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME)) {
+               spin_lock_irqsave(&ioc->sas_device_lock, flags);
+               sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc,
+                                       sas_target_priv_data->sas_address);
+               if (sas_device && (sas_device->starget == NULL)) {
+                       sdev_printk(KERN_INFO, sdev,
+                       "%s : sas_device->starget set to starget @ %d\n",
+                               __func__, __LINE__);
+                       sas_device->starget = starget;
+               }
+               spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+       }
+
        return 0;
 }
 
@@ -6392,7 +6407,7 @@ _scsih_search_responding_sas_devices(struct MPT3SAS_ADAPTER *ioc)
            handle))) {
                ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
                    MPI2_IOCSTATUS_MASK;
-               if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
+               if (ioc_status != MPI2_IOCSTATUS_SUCCESS)
                        break;
                handle = le16_to_cpu(sas_device_pg0.DevHandle);
                device_info = le32_to_cpu(sas_device_pg0.DeviceInfo);
@@ -6494,7 +6509,7 @@ _scsih_search_responding_raid_devices(struct MPT3SAS_ADAPTER *ioc)
            &volume_pg1, MPI2_RAID_VOLUME_PGAD_FORM_GET_NEXT_HANDLE, handle))) {
                ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
                    MPI2_IOCSTATUS_MASK;
-               if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
+               if (ioc_status != MPI2_IOCSTATUS_SUCCESS)
                        break;
                handle = le16_to_cpu(volume_pg1.DevHandle);
 
@@ -6518,7 +6533,7 @@ _scsih_search_responding_raid_devices(struct MPT3SAS_ADAPTER *ioc)
                    phys_disk_num))) {
                        ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
                            MPI2_IOCSTATUS_MASK;
-                       if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
+                       if (ioc_status != MPI2_IOCSTATUS_SUCCESS)
                                break;
                        phys_disk_num = pd_pg0.PhysDiskNum;
                        handle = le16_to_cpu(pd_pg0.DevHandle);
@@ -6597,7 +6612,7 @@ _scsih_search_responding_expanders(struct MPT3SAS_ADAPTER *ioc)
 
                ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
                    MPI2_IOCSTATUS_MASK;
-               if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
+               if (ioc_status != MPI2_IOCSTATUS_SUCCESS)
                        break;
 
                handle = le16_to_cpu(expander_pg0.DevHandle);
@@ -6742,8 +6757,6 @@ _scsih_scan_for_devices_after_reset(struct MPT3SAS_ADAPTER *ioc)
            MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL, handle))) {
                ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
                    MPI2_IOCSTATUS_MASK;
-               if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
-                       break;
                if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
                        pr_info(MPT3SAS_FMT "\tbreak from expander scan: " \
                            "ioc_status(0x%04x), loginfo(0x%08x)\n",
@@ -6787,8 +6800,6 @@ _scsih_scan_for_devices_after_reset(struct MPT3SAS_ADAPTER *ioc)
            phys_disk_num))) {
                ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
                    MPI2_IOCSTATUS_MASK;
-               if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
-                       break;
                if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
                        pr_info(MPT3SAS_FMT "\tbreak from phys disk scan: "\
                            "ioc_status(0x%04x), loginfo(0x%08x)\n",
@@ -6854,8 +6865,6 @@ _scsih_scan_for_devices_after_reset(struct MPT3SAS_ADAPTER *ioc)
            &volume_pg1, MPI2_RAID_VOLUME_PGAD_FORM_GET_NEXT_HANDLE, handle))) {
                ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
                    MPI2_IOCSTATUS_MASK;
-               if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
-                       break;
                if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
                        pr_info(MPT3SAS_FMT "\tbreak from volume scan: " \
                            "ioc_status(0x%04x), loginfo(0x%08x)\n",
@@ -6914,8 +6923,6 @@ _scsih_scan_for_devices_after_reset(struct MPT3SAS_ADAPTER *ioc)
            handle))) {
                ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
                    MPI2_IOCSTATUS_MASK;
-               if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
-                       break;
                if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
                        pr_info(MPT3SAS_FMT "\tbreak from end device scan:"\
                            " ioc_status(0x%04x), loginfo(0x%08x)\n",
@@ -7525,10 +7532,12 @@ _scsih_probe_boot_devices(struct MPT3SAS_ADAPTER *ioc)
                    sas_address_parent)) {
                        _scsih_sas_device_remove(ioc, sas_device);
                } else if (!sas_device->starget) {
-                       if (!ioc->is_driver_loading)
-                               mpt3sas_transport_port_remove(ioc, sas_address,
+                       if (!ioc->is_driver_loading) {
+                               mpt3sas_transport_port_remove(ioc,
+                                   sas_address,
                                    sas_address_parent);
-                       _scsih_sas_device_remove(ioc, sas_device);
+                               _scsih_sas_device_remove(ioc, sas_device);
+                       }
                }
        }
 }
@@ -7584,13 +7593,14 @@ _scsih_probe_sas(struct MPT3SAS_ADAPTER *ioc)
                         * oops in scsi_sysfs_add_sdev()->add_device()->
                         * sysfs_addrm_start()
                         */
-                       if (!ioc->is_driver_loading)
+                       if (!ioc->is_driver_loading) {
                                mpt3sas_transport_port_remove(ioc,
                                    sas_device->sas_address,
                                    sas_device->sas_address_parent);
-                       list_del(&sas_device->list);
-                       kfree(sas_device);
-                       continue;
+                               list_del(&sas_device->list);
+                               kfree(sas_device);
+                               continue;
+                       }
                }
 
                spin_lock_irqsave(&ioc->sas_device_lock, flags);
index 87ca2b7..dcadd56 100644 (file)
@@ -2,7 +2,7 @@
  * SAS Transport Layer for MPT (Message Passing Technology) based controllers
  *
  * This code is based on drivers/scsi/mpt3sas/mpt3sas_transport.c
- * Copyright (C) 2012  LSI Corporation
+ * Copyright (C) 2012-2013  LSI Corporation
  *  (mailto:DL-MPTFusionLinux@lsi.com)
  *
  * This program is free software; you can redistribute it and/or
index 6f8d621..f6533ab 100644 (file)
@@ -3,7 +3,7 @@
  * (Message Passing Technology) based controllers
  *
  * This code is based on drivers/scsi/mpt3sas/mpt3sas_trigger_diag.c
- * Copyright (C) 2012  LSI Corporation
+ * Copyright (C) 2012-2013  LSI Corporation
  *  (mailto:DL-MPTFusionLinux@lsi.com)
  *
  * This program is free software; you can redistribute it and/or
index a10c309..bb69392 100644 (file)
@@ -4,7 +4,7 @@
  * controllers
  *
  * This code is based on drivers/scsi/mpt3sas/mpt3sas_base.h
- * Copyright (C) 2012  LSI Corporation
+ * Copyright (C) 2012-2013  LSI Corporation
  *  (mailto:DL-MPTFusionLinux@lsi.com)
  *
  * This program is free software; you can redistribute it and/or
index e4b9bc7..3861aa1 100644 (file)
@@ -912,14 +912,13 @@ static int pm8001_pci_suspend(struct pci_dev *pdev, pm_message_t state)
 {
        struct sas_ha_struct *sha = pci_get_drvdata(pdev);
        struct pm8001_hba_info *pm8001_ha;
-       int i , pos;
+       int i;
        u32 device_state;
        pm8001_ha = sha->lldd_ha;
        flush_workqueue(pm8001_wq);
        scsi_block_requests(pm8001_ha->shost);
-       pos = pci_find_capability(pdev, PCI_CAP_ID_PM);
-       if (pos == 0) {
-               printk(KERN_ERR " PCI PM not supported\n");
+       if (!pdev->pm_cap) {
+               dev_err(&pdev->dev, " PCI PM not supported\n");
                return -ENODEV;
        }
        PM8001_CHIP_DISP->interrupt_disable(pm8001_ha, 0xFF);
index bf60c63..d7a99ae 100644 (file)
@@ -1691,6 +1691,9 @@ qla2x00_get_fc_host_stats(struct Scsi_Host *shost)
        if (unlikely(pci_channel_offline(ha->pdev)))
                goto done;
 
+       if (qla2x00_reset_active(vha))
+               goto done;
+
        stats = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &stats_dma);
        if (stats == NULL) {
                ql_log(ql_log_warn, vha, 0x707d,
@@ -1703,7 +1706,7 @@ qla2x00_get_fc_host_stats(struct Scsi_Host *shost)
        if (IS_FWI2_CAPABLE(ha)) {
                rval = qla24xx_get_isp_stats(base_vha, stats, stats_dma);
        } else if (atomic_read(&base_vha->loop_state) == LOOP_READY &&
-           !qla2x00_reset_active(vha) && !ha->dpc_active) {
+           !ha->dpc_active) {
                /* Must be in a 'READY' state for statistics retrieval. */
                rval = qla2x00_get_link_status(base_vha, base_vha->loop_id,
                                                stats, stats_dma);
index 39719f8..417eaad 100644 (file)
@@ -269,6 +269,12 @@ qla2x00_process_els(struct fc_bsg_job *bsg_job)
                type = "FC_BSG_HST_ELS_NOLOGIN";
        }
 
+       if (!vha->flags.online) {
+               ql_log(ql_log_warn, vha, 0x7005, "Host not online.\n");
+               rval = -EIO;
+               goto done;
+       }
+
        /* pass through is supported only for ISP 4Gb or higher */
        if (!IS_FWI2_CAPABLE(ha)) {
                ql_dbg(ql_dbg_user, vha, 0x7001,
@@ -326,12 +332,6 @@ qla2x00_process_els(struct fc_bsg_job *bsg_job)
                        NPH_FABRIC_CONTROLLER : NPH_F_PORT;
        }
 
-       if (!vha->flags.online) {
-               ql_log(ql_log_warn, vha, 0x7005, "Host not online.\n");
-               rval = -EIO;
-               goto done;
-       }
-
        req_sg_cnt =
                dma_map_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list,
                bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE);
@@ -399,7 +399,7 @@ done_unmap_sg:
        goto done_free_fcport;
 
 done_free_fcport:
-       if (bsg_job->request->msgcode == FC_BSG_HST_ELS_NOLOGIN)
+       if (bsg_job->request->msgcode == FC_BSG_RPT_ELS)
                kfree(fcport);
 done:
        return rval;
@@ -1084,14 +1084,6 @@ qla84xx_mgmt_cmd(struct fc_bsg_job *bsg_job)
                return -EINVAL;
        }
 
-       ql84_mgmt = (struct qla_bsg_a84_mgmt *)((char *)bsg_job->request +
-               sizeof(struct fc_bsg_request));
-       if (!ql84_mgmt) {
-               ql_log(ql_log_warn, vha, 0x703b,
-                   "MGMT header not provided, exiting.\n");
-               return -EINVAL;
-       }
-
        mn = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &mn_dma);
        if (!mn) {
                ql_log(ql_log_warn, vha, 0x703c,
@@ -1102,7 +1094,7 @@ qla84xx_mgmt_cmd(struct fc_bsg_job *bsg_job)
        memset(mn, 0, sizeof(struct access_chip_84xx));
        mn->entry_type = ACCESS_CHIP_IOCB_TYPE;
        mn->entry_count = 1;
-
+       ql84_mgmt = (void *)bsg_job->request + sizeof(struct fc_bsg_request);
        switch (ql84_mgmt->mgmt.cmd) {
        case QLA84_MGMT_READ_MEM:
        case QLA84_MGMT_GET_INFO:
@@ -1282,14 +1274,7 @@ qla24xx_iidma(struct fc_bsg_job *bsg_job)
                return -EINVAL;
        }
 
-       port_param = (struct qla_port_param *)((char *)bsg_job->request +
-               sizeof(struct fc_bsg_request));
-       if (!port_param) {
-               ql_log(ql_log_warn, vha, 0x7047,
-                   "port_param header not provided.\n");
-               return -EINVAL;
-       }
-
+       port_param = (void *)bsg_job->request + sizeof(struct fc_bsg_request);
        if (port_param->fc_scsi_addr.dest_type != EXT_DEF_TYPE_WWPN) {
                ql_log(ql_log_warn, vha, 0x7048,
                    "Invalid destination type.\n");
@@ -2153,6 +2138,7 @@ qla24xx_bsg_timeout(struct fc_bsg_job *bsg_job)
                                        (sp->type == SRB_ELS_CMD_HST) ||
                                        (sp->type == SRB_FXIOCB_BCMD))
                                        && (sp->u.bsg_job == bsg_job)) {
+                                       req->outstanding_cmds[cnt] = NULL;
                                        spin_unlock_irqrestore(&ha->hardware_lock, flags);
                                        if (ha->isp_ops->abort_command(sp)) {
                                                ql_log(ql_log_warn, vha, 0x7089,
@@ -2180,8 +2166,6 @@ qla24xx_bsg_timeout(struct fc_bsg_job *bsg_job)
 
 done:
        spin_unlock_irqrestore(&ha->hardware_lock, flags);
-       if (bsg_job->request->msgcode == FC_BSG_HST_CT)
-               kfree(sp->fcport);
-       qla2x00_rel_sp(vha, sp);
+       sp->free(vha, sp);
        return 0;
 }
index cfa2a20..df132fe 100644 (file)
  * |             Level            |   Last Value Used  |     Holes     |
  * ----------------------------------------------------------------------
  * | Module Init and Probe        |       0x014f       | 0x4b,0xba,0xfa |
- * | Mailbox commands             |       0x1179       | 0x111a-0x111b  |
+ * | Mailbox commands             |       0x117a       | 0x111a-0x111b  |
  * |                              |                    | 0x1155-0x1158  |
  * | Device Discovery             |       0x2095       | 0x2020-0x2022, |
+ * |                              |                    | 0x2011-0x2012, |
  * |                              |                    | 0x2016         |
  * | Queue Command and IO tracing |       0x3058       | 0x3006-0x300b  |
  * |                              |                    | 0x3027-0x3028  |
@@ -35,7 +36,8 @@
  * |                              |                    | 0x70a5,0x70a6, |
  * |                              |                    | 0x70a8,0x70ab, |
  * |                              |                    | 0x70ad-0x70ae, |
- * |                              |                    | 0x70d1-0x70da  |
+ * |                              |                    | 0x70d1-0x70da, |
+ * |                              |                    | 0x7047,0x703b |
  * | Task Management              |       0x803c       | 0x8025-0x8026  |
  * |                              |                    | 0x800b,0x8039  |
  * | AER/EEH                      |       0x9011       |               |
@@ -1468,7 +1470,7 @@ qla25xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked)
 
        nxt = qla2xxx_copy_queues(ha, nxt);
 
-       nxt = qla24xx_copy_eft(ha, nxt);
+       qla24xx_copy_eft(ha, nxt);
 
        /* Chain entries -- started with MQ. */
        nxt_chain = qla25xx_copy_fce(ha, nxt_chain, &last_chain);
@@ -1787,7 +1789,7 @@ qla81xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked)
 
        nxt = qla2xxx_copy_queues(ha, nxt);
 
-       nxt = qla24xx_copy_eft(ha, nxt);
+       qla24xx_copy_eft(ha, nxt);
 
        /* Chain entries -- started with MQ. */
        nxt_chain = qla25xx_copy_fce(ha, nxt_chain, &last_chain);
@@ -2289,7 +2291,7 @@ qla83xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked)
 copy_queue:
        nxt = qla2xxx_copy_queues(ha, nxt);
 
-       nxt = qla24xx_copy_eft(ha, nxt);
+       qla24xx_copy_eft(ha, nxt);
 
        /* Chain entries -- started with MQ. */
        nxt_chain = qla25xx_copy_fce(ha, nxt_chain, &last_chain);
index c32efc7..95ca32a 100644 (file)
@@ -323,7 +323,7 @@ struct srb_iocb {
                        uint32_t lun;
                        uint32_t data;
                        struct completion comp;
-                       uint32_t comp_status;
+                       __le16 comp_status;
                } tmf;
                struct {
 #define SRB_FXDISC_REQ_DMA_VALID       BIT_0
@@ -338,21 +338,21 @@ struct srb_iocb {
                        void *rsp_addr;
                        dma_addr_t req_dma_handle;
                        dma_addr_t rsp_dma_handle;
-                       uint32_t adapter_id;
-                       uint32_t adapter_id_hi;
-                       uint32_t req_func_type;
-                       uint32_t req_data;
-                       uint32_t req_data_extra;
-                       uint32_t result;
-                       uint32_t seq_number;
-                       uint32_t fw_flags;
+                       __le32 adapter_id;
+                       __le32 adapter_id_hi;
+                       __le16 req_func_type;
+                       __le32 req_data;
+                       __le32 req_data_extra;
+                       __le32 result;
+                       __le32 seq_number;
+                       __le16 fw_flags;
                        struct completion fxiocb_comp;
-                       uint32_t reserved_0;
+                       __le32 reserved_0;
                        uint8_t reserved_1;
                } fxiocb;
                struct {
                        uint32_t cmd_hndl;
-                       uint32_t comp_status;
+                       __le16 comp_status;
                        struct completion comp;
                } abt;
        } u;
@@ -1196,14 +1196,14 @@ typedef struct {
 struct init_cb_fx {
        uint16_t        version;
        uint16_t        reserved_1[13];
-       uint16_t        request_q_outpointer;
-       uint16_t        response_q_inpointer;
+       __le16          request_q_outpointer;
+       __le16          response_q_inpointer;
        uint16_t        reserved_2[2];
-       uint16_t        response_q_length;
-       uint16_t        request_q_length;
+       __le16          response_q_length;
+       __le16          request_q_length;
        uint16_t        reserved_3[2];
-       uint32_t        request_q_address[2];
-       uint32_t        response_q_address[2];
+       __le32          request_q_address[2];
+       __le32          response_q_address[2];
        uint16_t        reserved_4[4];
        uint8_t         response_q_msivec;
        uint8_t         reserved_5[19];
index 026bfde..2d98232 100644 (file)
@@ -587,7 +587,7 @@ extern int qlafx00_init_firmware(scsi_qla_host_t *, uint16_t);
 extern int qlafx00_fw_ready(scsi_qla_host_t *);
 extern int qlafx00_configure_devices(scsi_qla_host_t *);
 extern int qlafx00_reset_initialize(scsi_qla_host_t *);
-extern int qlafx00_fx_disc(scsi_qla_host_t *, fc_port_t *, uint8_t);
+extern int qlafx00_fx_disc(scsi_qla_host_t *, fc_port_t *, uint16_t);
 extern int qlafx00_process_aen(struct scsi_qla_host *, struct qla_work_evt *);
 extern int qlafx00_post_aenfx_work(struct scsi_qla_host *,  uint32_t,
                                   uint32_t *, int);
index d0ea8b9..0926451 100644 (file)
@@ -99,17 +99,17 @@ qla24xx_prep_ms_iocb(scsi_qla_host_t *vha, uint32_t req_size, uint32_t rsp_size)
  * Returns a pointer to the intitialized @ct_req.
  */
 static inline struct ct_sns_req *
-qla2x00_prep_ct_req(struct ct_sns_req *ct_req, uint16_t cmd, uint16_t rsp_size)
+qla2x00_prep_ct_req(struct ct_sns_pkt *p, uint16_t cmd, uint16_t rsp_size)
 {
-       memset(ct_req, 0, sizeof(struct ct_sns_pkt));
+       memset(p, 0, sizeof(struct ct_sns_pkt));
 
-       ct_req->header.revision = 0x01;
-       ct_req->header.gs_type = 0xFC;
-       ct_req->header.gs_subtype = 0x02;
-       ct_req->command = cpu_to_be16(cmd);
-       ct_req->max_rsp_size = cpu_to_be16((rsp_size - 16) / 4);
+       p->p.req.header.revision = 0x01;
+       p->p.req.header.gs_type = 0xFC;
+       p->p.req.header.gs_subtype = 0x02;
+       p->p.req.command = cpu_to_be16(cmd);
+       p->p.req.max_rsp_size = cpu_to_be16((rsp_size - 16) / 4);
 
-       return (ct_req);
+       return &p->p.req;
 }
 
 static int
@@ -188,7 +188,7 @@ qla2x00_ga_nxt(scsi_qla_host_t *vha, fc_port_t *fcport)
            GA_NXT_RSP_SIZE);
 
        /* Prepare CT request */
-       ct_req = qla2x00_prep_ct_req(&ha->ct_sns->p.req, GA_NXT_CMD,
+       ct_req = qla2x00_prep_ct_req(ha->ct_sns, GA_NXT_CMD,
            GA_NXT_RSP_SIZE);
        ct_rsp = &ha->ct_sns->p.rsp;
 
@@ -284,8 +284,7 @@ qla2x00_gid_pt(scsi_qla_host_t *vha, sw_info_t *list)
            gid_pt_rsp_size);
 
        /* Prepare CT request */
-       ct_req = qla2x00_prep_ct_req(&ha->ct_sns->p.req, GID_PT_CMD,
-           gid_pt_rsp_size);
+       ct_req = qla2x00_prep_ct_req(ha->ct_sns, GID_PT_CMD, gid_pt_rsp_size);
        ct_rsp = &ha->ct_sns->p.rsp;
 
        /* Prepare CT arguments -- port_type */
@@ -359,7 +358,7 @@ qla2x00_gpn_id(scsi_qla_host_t *vha, sw_info_t *list)
                    GPN_ID_RSP_SIZE);
 
                /* Prepare CT request */
-               ct_req = qla2x00_prep_ct_req(&ha->ct_sns->p.req, GPN_ID_CMD,
+               ct_req = qla2x00_prep_ct_req(ha->ct_sns, GPN_ID_CMD,
                    GPN_ID_RSP_SIZE);
                ct_rsp = &ha->ct_sns->p.rsp;
 
@@ -421,7 +420,7 @@ qla2x00_gnn_id(scsi_qla_host_t *vha, sw_info_t *list)
                    GNN_ID_RSP_SIZE);
 
                /* Prepare CT request */
-               ct_req = qla2x00_prep_ct_req(&ha->ct_sns->p.req, GNN_ID_CMD,
+               ct_req = qla2x00_prep_ct_req(ha->ct_sns, GNN_ID_CMD,
                    GNN_ID_RSP_SIZE);
                ct_rsp = &ha->ct_sns->p.rsp;
 
@@ -495,7 +494,7 @@ qla2x00_rft_id(scsi_qla_host_t *vha)
            RFT_ID_RSP_SIZE);
 
        /* Prepare CT request */
-       ct_req = qla2x00_prep_ct_req(&ha->ct_sns->p.req, RFT_ID_CMD,
+       ct_req = qla2x00_prep_ct_req(ha->ct_sns, RFT_ID_CMD,
            RFT_ID_RSP_SIZE);
        ct_rsp = &ha->ct_sns->p.rsp;
 
@@ -551,7 +550,7 @@ qla2x00_rff_id(scsi_qla_host_t *vha)
            RFF_ID_RSP_SIZE);
 
        /* Prepare CT request */
-       ct_req = qla2x00_prep_ct_req(&ha->ct_sns->p.req, RFF_ID_CMD,
+       ct_req = qla2x00_prep_ct_req(ha->ct_sns, RFF_ID_CMD,
            RFF_ID_RSP_SIZE);
        ct_rsp = &ha->ct_sns->p.rsp;
 
@@ -606,8 +605,7 @@ qla2x00_rnn_id(scsi_qla_host_t *vha)
            RNN_ID_RSP_SIZE);
 
        /* Prepare CT request */
-       ct_req = qla2x00_prep_ct_req(&ha->ct_sns->p.req, RNN_ID_CMD,
-           RNN_ID_RSP_SIZE);
+       ct_req = qla2x00_prep_ct_req(ha->ct_sns, RNN_ID_CMD, RNN_ID_RSP_SIZE);
        ct_rsp = &ha->ct_sns->p.rsp;
 
        /* Prepare CT arguments -- port_id, node_name */
@@ -676,7 +674,7 @@ qla2x00_rsnn_nn(scsi_qla_host_t *vha)
        ms_pkt = ha->isp_ops->prep_ms_iocb(vha, 0, RSNN_NN_RSP_SIZE);
 
        /* Prepare CT request */
-       ct_req = qla2x00_prep_ct_req(&ha->ct_sns->p.req, RSNN_NN_CMD,
+       ct_req = qla2x00_prep_ct_req(ha->ct_sns, RSNN_NN_CMD,
            RSNN_NN_RSP_SIZE);
        ct_rsp = &ha->ct_sns->p.rsp;
 
@@ -1262,18 +1260,18 @@ qla2x00_update_ms_fdmi_iocb(scsi_qla_host_t *vha, uint32_t req_size)
  * Returns a pointer to the intitialized @ct_req.
  */
 static inline struct ct_sns_req *
-qla2x00_prep_ct_fdmi_req(struct ct_sns_req *ct_req, uint16_t cmd,
+qla2x00_prep_ct_fdmi_req(struct ct_sns_pkt *p, uint16_t cmd,
     uint16_t rsp_size)
 {
-       memset(ct_req, 0, sizeof(struct ct_sns_pkt));
+       memset(p, 0, sizeof(struct ct_sns_pkt));
 
-       ct_req->header.revision = 0x01;
-       ct_req->header.gs_type = 0xFA;
-       ct_req->header.gs_subtype = 0x10;
-       ct_req->command = cpu_to_be16(cmd);
-       ct_req->max_rsp_size = cpu_to_be16((rsp_size - 16) / 4);
+       p->p.req.header.revision = 0x01;
+       p->p.req.header.gs_type = 0xFA;
+       p->p.req.header.gs_subtype = 0x10;
+       p->p.req.command = cpu_to_be16(cmd);
+       p->p.req.max_rsp_size = cpu_to_be16((rsp_size - 16) / 4);
 
-       return ct_req;
+       return &p->p.req;
 }
 
 /**
@@ -1301,8 +1299,7 @@ qla2x00_fdmi_rhba(scsi_qla_host_t *vha)
        ms_pkt = ha->isp_ops->prep_ms_fdmi_iocb(vha, 0, RHBA_RSP_SIZE);
 
        /* Prepare CT request */
-       ct_req = qla2x00_prep_ct_fdmi_req(&ha->ct_sns->p.req, RHBA_CMD,
-           RHBA_RSP_SIZE);
+       ct_req = qla2x00_prep_ct_fdmi_req(ha->ct_sns, RHBA_CMD, RHBA_RSP_SIZE);
        ct_rsp = &ha->ct_sns->p.rsp;
 
        /* Prepare FDMI command arguments -- attribute block, attributes. */
@@ -1370,8 +1367,7 @@ qla2x00_fdmi_rhba(scsi_qla_host_t *vha)
        /* Model description. */
        eiter = (struct ct_fdmi_hba_attr *) (entries + size);
        eiter->type = __constant_cpu_to_be16(FDMI_HBA_MODEL_DESCRIPTION);
-       if (ha->model_desc)
-               strncpy(eiter->a.model_desc, ha->model_desc, 80);
+       strncpy(eiter->a.model_desc, ha->model_desc, 80);
        alen = strlen(eiter->a.model_desc);
        alen += (alen & 3) ? (4 - (alen & 3)) : 4;
        eiter->len = cpu_to_be16(4 + alen);
@@ -1491,8 +1487,7 @@ qla2x00_fdmi_dhba(scsi_qla_host_t *vha)
            DHBA_RSP_SIZE);
 
        /* Prepare CT request */
-       ct_req = qla2x00_prep_ct_fdmi_req(&ha->ct_sns->p.req, DHBA_CMD,
-           DHBA_RSP_SIZE);
+       ct_req = qla2x00_prep_ct_fdmi_req(ha->ct_sns, DHBA_CMD, DHBA_RSP_SIZE);
        ct_rsp = &ha->ct_sns->p.rsp;
 
        /* Prepare FDMI command arguments -- portname. */
@@ -1548,8 +1543,7 @@ qla2x00_fdmi_rpa(scsi_qla_host_t *vha)
        ms_pkt = ha->isp_ops->prep_ms_fdmi_iocb(vha, 0, RPA_RSP_SIZE);
 
        /* Prepare CT request */
-       ct_req = qla2x00_prep_ct_fdmi_req(&ha->ct_sns->p.req, RPA_CMD,
-           RPA_RSP_SIZE);
+       ct_req = qla2x00_prep_ct_fdmi_req(ha->ct_sns, RPA_CMD, RPA_RSP_SIZE);
        ct_rsp = &ha->ct_sns->p.rsp;
 
        /* Prepare FDMI command arguments -- attribute block, attributes. */
@@ -1776,7 +1770,7 @@ qla2x00_gfpn_id(scsi_qla_host_t *vha, sw_info_t *list)
                    GFPN_ID_RSP_SIZE);
 
                /* Prepare CT request */
-               ct_req = qla2x00_prep_ct_req(&ha->ct_sns->p.req, GFPN_ID_CMD,
+               ct_req = qla2x00_prep_ct_req(ha->ct_sns, GFPN_ID_CMD,
                    GFPN_ID_RSP_SIZE);
                ct_rsp = &ha->ct_sns->p.rsp;
 
@@ -1843,18 +1837,18 @@ qla24xx_prep_ms_fm_iocb(scsi_qla_host_t *vha, uint32_t req_size,
 
 
 static inline struct ct_sns_req *
-qla24xx_prep_ct_fm_req(struct ct_sns_req *ct_req, uint16_t cmd,
+qla24xx_prep_ct_fm_req(struct ct_sns_pkt *p, uint16_t cmd,
     uint16_t rsp_size)
 {
-       memset(ct_req, 0, sizeof(struct ct_sns_pkt));
+       memset(p, 0, sizeof(struct ct_sns_pkt));
 
-       ct_req->header.revision = 0x01;
-       ct_req->header.gs_type = 0xFA;
-       ct_req->header.gs_subtype = 0x01;
-       ct_req->command = cpu_to_be16(cmd);
-       ct_req->max_rsp_size = cpu_to_be16((rsp_size - 16) / 4);
+       p->p.req.header.revision = 0x01;
+       p->p.req.header.gs_type = 0xFA;
+       p->p.req.header.gs_subtype = 0x01;
+       p->p.req.command = cpu_to_be16(cmd);
+       p->p.req.max_rsp_size = cpu_to_be16((rsp_size - 16) / 4);
 
-       return ct_req;
+       return &p->p.req;
 }
 
 /**
@@ -1890,8 +1884,8 @@ qla2x00_gpsc(scsi_qla_host_t *vha, sw_info_t *list)
                    GPSC_RSP_SIZE);
 
                /* Prepare CT request */
-               ct_req = qla24xx_prep_ct_fm_req(&ha->ct_sns->p.req,
-                   GPSC_CMD, GPSC_RSP_SIZE);
+               ct_req = qla24xx_prep_ct_fm_req(ha->ct_sns, GPSC_CMD,
+                   GPSC_RSP_SIZE);
                ct_rsp = &ha->ct_sns->p.rsp;
 
                /* Prepare CT arguments -- port_name */
@@ -2001,7 +1995,7 @@ qla2x00_gff_id(scsi_qla_host_t *vha, sw_info_t *list)
                    GFF_ID_RSP_SIZE);
 
                /* Prepare CT request */
-               ct_req = qla2x00_prep_ct_req(&ha->ct_sns->p.req, GFF_ID_CMD,
+               ct_req = qla2x00_prep_ct_req(ha->ct_sns, GFF_ID_CMD,
                    GFF_ID_RSP_SIZE);
                ct_rsp = &ha->ct_sns->p.rsp;
 
index 3565dfd..f2216ed 100644 (file)
@@ -2309,14 +2309,6 @@ qla2x00_configure_hba(scsi_qla_host_t *vha)
                    "Topology - %s, Host Loop address 0x%x.\n",
                    connect_type, vha->loop_id);
 
-       if (rval) {
-               ql_log(ql_log_warn, vha, 0x2011,
-                   "%s FAILED\n", __func__);
-       } else {
-               ql_dbg(ql_dbg_disc, vha, 0x2012,
-                   "%s success\n", __func__);
-       }
-
        return(rval);
 }
 
index 0a5c895..28c38b4 100644 (file)
@@ -83,7 +83,7 @@ static inline void
 host_to_adap(uint8_t *src, uint8_t *dst, uint32_t bsize)
 {
        uint32_t *isrc = (uint32_t *) src;
-       uint32_t *odest = (uint32_t *) dst;
+       __le32 *odest = (__le32 *) dst;
        uint32_t iter = bsize >> 2;
 
        for (; iter ; iter--)
index 15e4080..42ef481 100644 (file)
@@ -1189,7 +1189,6 @@ qla24xx_build_scsi_crc_2_iocbs(srb_t *sp, struct cmd_type_crc_2 *cmd_pkt,
        uint32_t                *cur_dsd, *fcp_dl;
        scsi_qla_host_t         *vha;
        struct scsi_cmnd        *cmd;
-       struct scatterlist      *cur_seg;
        int                     sgc;
        uint32_t                total_bytes = 0;
        uint32_t                data_bytes;
@@ -1396,7 +1395,6 @@ qla24xx_build_scsi_crc_2_iocbs(srb_t *sp, struct cmd_type_crc_2 *cmd_pkt,
 
        if (bundling && tot_prot_dsds) {
                /* Walks dif segments */
-               cur_seg = scsi_prot_sglist(cmd);
                cmd_pkt->control_flags |=
                        __constant_cpu_to_le16(CF_DIF_SEG_DESCR_ENABLE);
                cur_dsd = (uint32_t *) &crc_ctx_pkt->u.bundling.dif_address;
@@ -1863,8 +1861,8 @@ skip_cmd_array:
        pkt = req->ring_ptr;
        memset(pkt, 0, REQUEST_ENTRY_SIZE);
        if (IS_QLAFX00(ha)) {
-               WRT_REG_BYTE(&pkt->entry_count, req_cnt);
-               WRT_REG_WORD(&pkt->handle, handle);
+               WRT_REG_BYTE((void __iomem *)&pkt->entry_count, req_cnt);
+               WRT_REG_WORD((void __iomem *)&pkt->handle, handle);
        } else {
                pkt->entry_count = req_cnt;
                pkt->handle = handle;
index d2a4c75..2d8e7b8 100644 (file)
@@ -2485,6 +2485,7 @@ qla2xxx_check_risc_status(scsi_qla_host_t *vha)
        if (rval == QLA_SUCCESS)
                goto next_test;
 
+       rval = QLA_SUCCESS;
        WRT_REG_DWORD(&reg->iobase_window, 0x0003);
        for (cnt = 100; (RD_REG_DWORD(&reg->iobase_window) & BIT_0) == 0 &&
            rval == QLA_SUCCESS; cnt--) {
index 3587ec2..7257c3c 100644 (file)
@@ -177,8 +177,14 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
                        WRT_REG_WORD(&reg->isp.hccr, HCCR_SET_HOST_INT);
                spin_unlock_irqrestore(&ha->hardware_lock, flags);
 
-               wait_for_completion_timeout(&ha->mbx_intr_comp, mcp->tov * HZ);
-
+               if (!wait_for_completion_timeout(&ha->mbx_intr_comp,
+                   mcp->tov * HZ)) {
+                       ql_dbg(ql_dbg_mbx, vha, 0x117a,
+                           "cmd=%x Timeout.\n", command);
+                       spin_lock_irqsave(&ha->hardware_lock, flags);
+                       clear_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags);
+                       spin_unlock_irqrestore(&ha->hardware_lock, flags);
+               }
        } else {
                ql_dbg(ql_dbg_mbx, vha, 0x1011,
                    "Cmd=%x Polling Mode.\n", command);
@@ -275,9 +281,11 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
 
                /*
                 * Attempt to capture a firmware dump for further analysis
-                * of the current firmware state
+                * of the current firmware state.  We do not need to do this
+                * if we are intentionally generating a dump.
                 */
-               ha->isp_ops->fw_dump(vha, 0);
+               if (mcp->mb[0] != MBC_GEN_SYSTEM_ERROR)
+                       ha->isp_ops->fw_dump(vha, 0);
 
                rval = QLA_FUNCTION_TIMEOUT;
        }
index a6df558..d799379 100644 (file)
@@ -707,7 +707,7 @@ qlafx00_tmf_iocb_timeout(void *data)
        srb_t *sp = (srb_t *)data;
        struct srb_iocb *tmf = &sp->u.iocb_cmd;
 
-       tmf->u.tmf.comp_status = CS_TIMEOUT;
+       tmf->u.tmf.comp_status = cpu_to_le16((uint16_t)CS_TIMEOUT);
        complete(&tmf->u.tmf.comp);
 }
 
@@ -1418,7 +1418,8 @@ qlafx00_init_response_q_entries(struct rsp_que *rsp)
        pkt = rsp->ring_ptr;
        for (cnt = 0; cnt < rsp->length; cnt++) {
                pkt->signature = RESPONSE_PROCESSED;
-               WRT_REG_DWORD(&pkt->signature, RESPONSE_PROCESSED);
+               WRT_REG_DWORD((void __iomem *)&pkt->signature,
+                   RESPONSE_PROCESSED);
                pkt++;
        }
 }
@@ -1733,7 +1734,7 @@ qla2x00_fxdisc_sp_done(void *data, void *ptr, int res)
 }
 
 int
-qlafx00_fx_disc(scsi_qla_host_t *vha, fc_port_t *fcport, uint8_t fx_type)
+qlafx00_fx_disc(scsi_qla_host_t *vha, fc_port_t *fcport, uint16_t fx_type)
 {
        srb_t *sp;
        struct srb_iocb *fdisc;
@@ -1759,13 +1760,13 @@ qlafx00_fx_disc(scsi_qla_host_t *vha, fc_port_t *fcport, uint8_t fx_type)
                fdisc->u.fxiocb.flags =
                    SRB_FXDISC_RESP_DMA_VALID | SRB_FXDISC_REQ_DWRD_VALID;
                fdisc->u.fxiocb.rsp_len = QLAFX00_PORT_DATA_INFO;
-               fdisc->u.fxiocb.req_data = fcport->port_id;
+               fdisc->u.fxiocb.req_data = cpu_to_le32(fcport->port_id);
                break;
        case FXDISC_GET_TGT_NODE_INFO:
                fdisc->u.fxiocb.flags =
                    SRB_FXDISC_RESP_DMA_VALID | SRB_FXDISC_REQ_DWRD_VALID;
                fdisc->u.fxiocb.rsp_len = QLAFX00_TGT_NODE_INFO;
-               fdisc->u.fxiocb.req_data = fcport->tgt_id;
+               fdisc->u.fxiocb.req_data = cpu_to_le32(fcport->tgt_id);
                break;
        case FXDISC_GET_TGT_NODE_LIST:
                fdisc->u.fxiocb.flags =
@@ -1851,7 +1852,7 @@ qlafx00_fx_disc(scsi_qla_host_t *vha, fc_port_t *fcport, uint8_t fx_type)
        sp->name = "fxdisc";
        qla2x00_init_timer(sp, FXDISC_TIMEOUT);
        fdisc->timeout = qla2x00_fxdisc_iocb_timeout;
-       fdisc->u.fxiocb.req_func_type = fx_type;
+       fdisc->u.fxiocb.req_func_type = cpu_to_le16(fx_type);
        sp->done = qla2x00_fxdisc_sp_done;
 
        rval = qla2x00_start_sp(sp);
@@ -1904,7 +1905,7 @@ qlafx00_fx_disc(scsi_qla_host_t *vha, fc_port_t *fcport, uint8_t fx_type)
                    (uint8_t *)pinfo, 16);
                memcpy(vha->hw->gid_list, pinfo, QLAFX00_TGT_NODE_LIST_SIZE);
        }
-       rval = fdisc->u.fxiocb.result;
+       rval = le32_to_cpu(fdisc->u.fxiocb.result);
 
 done_unmap_dma:
        if (fdisc->u.fxiocb.rsp_addr)
@@ -1927,7 +1928,7 @@ qlafx00_abort_iocb_timeout(void *data)
        srb_t *sp = (srb_t *)data;
        struct srb_iocb *abt = &sp->u.iocb_cmd;
 
-       abt->u.abt.comp_status = CS_TIMEOUT;
+       abt->u.abt.comp_status = cpu_to_le16((uint16_t)CS_TIMEOUT);
        complete(&abt->u.abt.comp);
 }
 
@@ -2169,14 +2170,14 @@ qlafx00_handle_sense(srb_t *sp, uint8_t *sense_data, uint32_t par_sense_len,
 static void
 qlafx00_tm_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
                      struct tsk_mgmt_entry_fx00 *pkt, srb_t *sp,
-                     uint16_t sstatus, uint16_t cpstatus)
+                     __le16 sstatus, __le16 cpstatus)
 {
        struct srb_iocb *tmf;
 
        tmf = &sp->u.iocb_cmd;
-       if (cpstatus != CS_COMPLETE ||
-           (sstatus & SS_RESPONSE_INFO_LEN_VALID))
-               cpstatus = CS_INCOMPLETE;
+       if (cpstatus != cpu_to_le16((uint16_t)CS_COMPLETE) ||
+           (sstatus & cpu_to_le16((uint16_t)SS_RESPONSE_INFO_LEN_VALID)))
+               cpstatus = cpu_to_le16((uint16_t)CS_INCOMPLETE);
        tmf->u.tmf.comp_status = cpstatus;
        sp->done(vha, sp, 0);
 }
@@ -2194,7 +2195,7 @@ qlafx00_abort_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
                return;
 
        abt = &sp->u.iocb_cmd;
-       abt->u.abt.comp_status = le32_to_cpu(pkt->tgt_id_sts);
+       abt->u.abt.comp_status = pkt->tgt_id_sts;
        sp->done(vha, sp, 0);
 }
 
@@ -2216,12 +2217,12 @@ qlafx00_ioctl_iosb_entry(scsi_qla_host_t *vha, struct req_que *req,
 
        if (sp->type == SRB_FXIOCB_DCMD) {
                iocb_job = &sp->u.iocb_cmd;
-               iocb_job->u.fxiocb.seq_number = le32_to_cpu(pkt->seq_no);
-               iocb_job->u.fxiocb.fw_flags = le32_to_cpu(pkt->fw_iotcl_flags);
-               iocb_job->u.fxiocb.result = le32_to_cpu(pkt->status);
+               iocb_job->u.fxiocb.seq_number = pkt->seq_no;
+               iocb_job->u.fxiocb.fw_flags = pkt->fw_iotcl_flags;
+               iocb_job->u.fxiocb.result = pkt->status;
                if (iocb_job->u.fxiocb.flags & SRB_FXDISC_RSP_DWRD_VALID)
                        iocb_job->u.fxiocb.req_data =
-                           le32_to_cpu(pkt->dataword_r);
+                           pkt->dataword_r;
        } else {
                bsg_job = sp->u.bsg_job;
 
@@ -2275,10 +2276,10 @@ qlafx00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
        fc_port_t       *fcport;
        struct scsi_cmnd *cp;
        struct sts_entry_fx00 *sts;
-       uint16_t        comp_status;
-       uint16_t        scsi_status;
+       __le16          comp_status;
+       __le16          scsi_status;
        uint16_t        ox_id;
-       uint8_t         lscsi_status;
+       __le16          lscsi_status;
        int32_t         resid;
        uint32_t        sense_len, par_sense_len, rsp_info_len, resid_len,
            fw_resid_len;
@@ -2292,8 +2293,8 @@ qlafx00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
 
        sts = (struct sts_entry_fx00 *) pkt;
 
-       comp_status = le16_to_cpu(sts->comp_status);
-       scsi_status = le16_to_cpu(sts->scsi_status) & SS_MASK;
+       comp_status = sts->comp_status;
+       scsi_status = sts->scsi_status & cpu_to_le16((uint16_t)SS_MASK);
        hindex = sts->handle;
        handle = LSW(hindex);
 
@@ -2339,38 +2340,40 @@ qlafx00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
                return;
        }
 
-       lscsi_status = scsi_status & STATUS_MASK;
+       lscsi_status = scsi_status & cpu_to_le16((uint16_t)STATUS_MASK);
 
        fcport = sp->fcport;
 
        ox_id = 0;
        sense_len = par_sense_len = rsp_info_len = resid_len =
                fw_resid_len = 0;
-       if (scsi_status & SS_SENSE_LEN_VALID)
-               sense_len = le32_to_cpu(sts->sense_len);
-       if (scsi_status & (SS_RESIDUAL_UNDER | SS_RESIDUAL_OVER))
+       if (scsi_status & cpu_to_le16((uint16_t)SS_SENSE_LEN_VALID))
+               sense_len = sts->sense_len;
+       if (scsi_status & cpu_to_le16(((uint16_t)SS_RESIDUAL_UNDER
+           | (uint16_t)SS_RESIDUAL_OVER)))
                resid_len = le32_to_cpu(sts->residual_len);
-       if (comp_status == CS_DATA_UNDERRUN)
+       if (comp_status == cpu_to_le16((uint16_t)CS_DATA_UNDERRUN))
                fw_resid_len = le32_to_cpu(sts->residual_len);
        rsp_info = sense_data = sts->data;
        par_sense_len = sizeof(sts->data);
 
        /* Check for overrun. */
        if (comp_status == CS_COMPLETE &&
-           scsi_status & SS_RESIDUAL_OVER)
-               comp_status = CS_DATA_OVERRUN;
+           scsi_status & cpu_to_le16((uint16_t)SS_RESIDUAL_OVER))
+               comp_status = cpu_to_le16((uint16_t)CS_DATA_OVERRUN);
 
        /*
         * Based on Host and scsi status generate status code for Linux
         */
-       switch (comp_status) {
+       switch (le16_to_cpu(comp_status)) {
        case CS_COMPLETE:
        case CS_QUEUE_FULL:
                if (scsi_status == 0) {
                        res = DID_OK << 16;
                        break;
                }
-               if (scsi_status & (SS_RESIDUAL_UNDER | SS_RESIDUAL_OVER)) {
+               if (scsi_status & cpu_to_le16(((uint16_t)SS_RESIDUAL_UNDER
+                   | (uint16_t)SS_RESIDUAL_OVER))) {
                        resid = resid_len;
                        scsi_set_resid(cp, resid);
 
@@ -2386,19 +2389,20 @@ qlafx00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
                                break;
                        }
                }
-               res = DID_OK << 16 | lscsi_status;
+               res = DID_OK << 16 | le16_to_cpu(lscsi_status);
 
-               if (lscsi_status == SAM_STAT_TASK_SET_FULL) {
+               if (lscsi_status ==
+                   cpu_to_le16((uint16_t)SAM_STAT_TASK_SET_FULL)) {
                        ql_dbg(ql_dbg_io, fcport->vha, 0x3051,
                            "QUEUE FULL detected.\n");
                        break;
                }
                logit = 0;
-               if (lscsi_status != SS_CHECK_CONDITION)
+               if (lscsi_status != cpu_to_le16((uint16_t)SS_CHECK_CONDITION))
                        break;
 
                memset(cp->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
-               if (!(scsi_status & SS_SENSE_LEN_VALID))
+               if (!(scsi_status & cpu_to_le16((uint16_t)SS_SENSE_LEN_VALID)))
                        break;
 
                qlafx00_handle_sense(sp, sense_data, par_sense_len, sense_len,
@@ -2412,7 +2416,7 @@ qlafx00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
                else
                        resid = resid_len;
                scsi_set_resid(cp, resid);
-               if (scsi_status & SS_RESIDUAL_UNDER) {
+               if (scsi_status & cpu_to_le16((uint16_t)SS_RESIDUAL_UNDER)) {
                        if ((IS_FWI2_CAPABLE(ha) || IS_QLAFX00(ha))
                            && fw_resid_len != resid_len) {
                                ql_dbg(ql_dbg_io, fcport->vha, 0x3052,
@@ -2420,7 +2424,8 @@ qlafx00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
                                    "(0x%x of 0x%x bytes).\n",
                                    resid, scsi_bufflen(cp));
 
-                               res = DID_ERROR << 16 | lscsi_status;
+                               res = DID_ERROR << 16 |
+                                   le16_to_cpu(lscsi_status);
                                goto check_scsi_status;
                        }
 
@@ -2436,8 +2441,9 @@ qlafx00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
                                res = DID_ERROR << 16;
                                break;
                        }
-               } else if (lscsi_status != SAM_STAT_TASK_SET_FULL &&
-                           lscsi_status != SAM_STAT_BUSY) {
+               } else if (lscsi_status !=
+                   cpu_to_le16((uint16_t)SAM_STAT_TASK_SET_FULL) &&
+                   lscsi_status != cpu_to_le16((uint16_t)SAM_STAT_BUSY)) {
                        /*
                         * scsi status of task set and busy are considered
                         * to be task not completed.
@@ -2448,7 +2454,7 @@ qlafx00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
                            "of 0x%x bytes).\n", resid,
                            scsi_bufflen(cp));
 
-                       res = DID_ERROR << 16 | lscsi_status;
+                       res = DID_ERROR << 16 | le16_to_cpu(lscsi_status);
                        goto check_scsi_status;
                } else {
                        ql_dbg(ql_dbg_io, fcport->vha, 0x3055,
@@ -2456,7 +2462,7 @@ qlafx00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
                            scsi_status, lscsi_status);
                }
 
-               res = DID_OK << 16 | lscsi_status;
+               res = DID_OK << 16 | le16_to_cpu(lscsi_status);
                logit = 0;
 
 check_scsi_status:
@@ -2465,17 +2471,20 @@ check_scsi_status:
                 * Status.
                 */
                if (lscsi_status != 0) {
-                       if (lscsi_status == SAM_STAT_TASK_SET_FULL) {
+                       if (lscsi_status ==
+                           cpu_to_le16((uint16_t)SAM_STAT_TASK_SET_FULL)) {
                                ql_dbg(ql_dbg_io, fcport->vha, 0x3056,
                                    "QUEUE FULL detected.\n");
                                logit = 1;
                                break;
                        }
-                       if (lscsi_status != SS_CHECK_CONDITION)
+                       if (lscsi_status !=
+                           cpu_to_le16((uint16_t)SS_CHECK_CONDITION))
                                break;
 
                        memset(cp->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
-                       if (!(scsi_status & SS_SENSE_LEN_VALID))
+                       if (!(scsi_status &
+                           cpu_to_le16((uint16_t)SS_SENSE_LEN_VALID)))
                                break;
 
                        qlafx00_handle_sense(sp, sense_data, par_sense_len,
@@ -2629,7 +2638,7 @@ qlafx00_multistatus_entry(struct scsi_qla_host *vha,
        uint32_t handle, hindex, handle_count, i;
        uint16_t que;
        struct req_que *req;
-       uint32_t *handle_ptr;
+       __le32 *handle_ptr;
 
        stsmfx = (struct multi_sts_entry_fx00 *) pkt;
 
@@ -2643,7 +2652,7 @@ qlafx00_multistatus_entry(struct scsi_qla_host *vha,
                return;
        }
 
-       handle_ptr = (uint32_t *) &stsmfx->handles[0];
+       handle_ptr =  &stsmfx->handles[0];
 
        for (i = 0; i < handle_count; i++) {
                hindex = le32_to_cpu(*handle_ptr);
@@ -2714,10 +2723,11 @@ qlafx00_process_response_queue(struct scsi_qla_host *vha,
        if (!vha->flags.online)
                return;
 
-       while (RD_REG_DWORD(&(rsp->ring_ptr->signature)) !=
+       while (RD_REG_DWORD((void __iomem *)&(rsp->ring_ptr->signature)) !=
            RESPONSE_PROCESSED) {
                lptr = rsp->ring_ptr;
-               memcpy_fromio(rsp->rsp_pkt, lptr, sizeof(rsp->rsp_pkt));
+               memcpy_fromio(rsp->rsp_pkt, (void __iomem *)lptr,
+                   sizeof(rsp->rsp_pkt));
                pkt = (struct sts_entry_fx00 *)rsp->rsp_pkt;
 
                rsp->ring_index++;
@@ -2768,7 +2778,8 @@ qlafx00_process_response_queue(struct scsi_qla_host *vha,
                        break;
                }
 next_iter:
-               WRT_REG_DWORD(&lptr->signature, RESPONSE_PROCESSED);
+               WRT_REG_DWORD((void __iomem *)&lptr->signature,
+                   RESPONSE_PROCESSED);
                wmb();
        }
 
@@ -2958,8 +2969,7 @@ qlafx00_prep_cont_type1_iocb(struct req_que *req,
        cont_pkt = (cont_a64_entry_t *)req->ring_ptr;
 
        /* Load packet defaults. */
-       *((uint32_t *)(&lcont_pkt->entry_type)) =
-           __constant_cpu_to_le32(CONTINUE_A64_TYPE_FX00);
+       lcont_pkt->entry_type = CONTINUE_A64_TYPE_FX00;
 
        return cont_pkt;
 }
@@ -2969,7 +2979,7 @@ qlafx00_build_scsi_iocbs(srb_t *sp, struct cmd_type_7_fx00 *cmd_pkt,
                         uint16_t tot_dsds, struct cmd_type_7_fx00 *lcmd_pkt)
 {
        uint16_t        avail_dsds;
-       uint32_t        *cur_dsd;
+       __le32 *cur_dsd;
        scsi_qla_host_t *vha;
        struct scsi_cmnd *cmd;
        struct scatterlist *sg;
@@ -2986,8 +2996,7 @@ qlafx00_build_scsi_iocbs(srb_t *sp, struct cmd_type_7_fx00 *cmd_pkt,
        cont_pkt = NULL;
 
        /* Update entry type to indicate Command Type 3 IOCB */
-       *((uint32_t *)(&lcmd_pkt->entry_type)) =
-           __constant_cpu_to_le32(FX00_COMMAND_TYPE_7);
+       lcmd_pkt->entry_type = FX00_COMMAND_TYPE_7;
 
        /* No data transfer */
        if (!scsi_bufflen(cmd) || cmd->sc_data_direction == DMA_NONE) {
@@ -3006,7 +3015,7 @@ qlafx00_build_scsi_iocbs(srb_t *sp, struct cmd_type_7_fx00 *cmd_pkt,
 
        /* One DSD is available in the Command Type 3 IOCB */
        avail_dsds = 1;
-       cur_dsd = (uint32_t *)&lcmd_pkt->dseg_0_address;
+       cur_dsd = (__le32 *)&lcmd_pkt->dseg_0_address;
 
        /* Load data segments */
        scsi_for_each_sg(cmd, sg, tot_dsds, i) {
@@ -3021,7 +3030,7 @@ qlafx00_build_scsi_iocbs(srb_t *sp, struct cmd_type_7_fx00 *cmd_pkt,
                        memset(&lcont_pkt, 0, REQUEST_ENTRY_SIZE);
                        cont_pkt =
                            qlafx00_prep_cont_type1_iocb(req, &lcont_pkt);
-                       cur_dsd = (uint32_t *)lcont_pkt.dseg_0_address;
+                       cur_dsd = (__le32 *)lcont_pkt.dseg_0_address;
                        avail_dsds = 5;
                        cont = 1;
                }
@@ -3224,13 +3233,13 @@ qlafx00_tm_iocb(srb_t *sp, struct tsk_mgmt_entry_fx00 *ptm_iocb)
        tm_iocb.timeout = cpu_to_le16(qla2x00_get_async_timeout(vha) + 2);
        tm_iocb.tgt_id = cpu_to_le16(sp->fcport->tgt_id);
        tm_iocb.control_flags = cpu_to_le32(fxio->u.tmf.flags);
-       if (tm_iocb.control_flags == TCF_LUN_RESET) {
+       if (tm_iocb.control_flags == cpu_to_le32((uint32_t)TCF_LUN_RESET)) {
                int_to_scsilun(fxio->u.tmf.lun, &llun);
                host_to_adap((uint8_t *)&llun, (uint8_t *)&tm_iocb.lun,
                    sizeof(struct scsi_lun));
        }
 
-       memcpy((void __iomem *)ptm_iocb, &tm_iocb,
+       memcpy((void *)ptm_iocb, &tm_iocb,
            sizeof(struct tsk_mgmt_entry_fx00));
        wmb();
 }
@@ -3252,7 +3261,7 @@ qlafx00_abort_iocb(srb_t *sp, struct abort_iocb_entry_fx00 *pabt_iocb)
        abt_iocb.tgt_id_sts = cpu_to_le16(sp->fcport->tgt_id);
        abt_iocb.req_que_no = cpu_to_le16(req->id);
 
-       memcpy((void __iomem *)pabt_iocb, &abt_iocb,
+       memcpy((void *)pabt_iocb, &abt_iocb,
            sizeof(struct abort_iocb_entry_fx00));
        wmb();
 }
@@ -3273,13 +3282,12 @@ qlafx00_fxdisc_iocb(srb_t *sp, struct fxdisc_entry_fx00 *pfxiocb)
 
        if (sp->type == SRB_FXIOCB_DCMD) {
                fx_iocb.func_num =
-                   cpu_to_le16(sp->u.iocb_cmd.u.fxiocb.req_func_type);
-               fx_iocb.adapid = cpu_to_le32(fxio->u.fxiocb.adapter_id);
-               fx_iocb.adapid_hi = cpu_to_le32(fxio->u.fxiocb.adapter_id_hi);
-               fx_iocb.reserved_0 = cpu_to_le32(fxio->u.fxiocb.reserved_0);
-               fx_iocb.reserved_1 = cpu_to_le32(fxio->u.fxiocb.reserved_1);
-               fx_iocb.dataword_extra =
-                   cpu_to_le32(fxio->u.fxiocb.req_data_extra);
+                   sp->u.iocb_cmd.u.fxiocb.req_func_type;
+               fx_iocb.adapid = fxio->u.fxiocb.adapter_id;
+               fx_iocb.adapid_hi = fxio->u.fxiocb.adapter_id_hi;
+               fx_iocb.reserved_0 = fxio->u.fxiocb.reserved_0;
+               fx_iocb.reserved_1 = fxio->u.fxiocb.reserved_1;
+               fx_iocb.dataword_extra = fxio->u.fxiocb.req_data_extra;
 
                if (fxio->u.fxiocb.flags & SRB_FXDISC_REQ_DMA_VALID) {
                        fx_iocb.req_dsdcnt = cpu_to_le16(1);
@@ -3306,8 +3314,7 @@ qlafx00_fxdisc_iocb(srb_t *sp, struct fxdisc_entry_fx00 *pfxiocb)
                }
 
                if (fxio->u.fxiocb.flags & SRB_FXDISC_REQ_DWRD_VALID) {
-                       fx_iocb.dataword =
-                           cpu_to_le32(fxio->u.fxiocb.req_data);
+                       fx_iocb.dataword = fxio->u.fxiocb.req_data;
                }
                fx_iocb.flags = fxio->u.fxiocb.flags;
        } else {
@@ -3323,21 +3330,21 @@ qlafx00_fxdisc_iocb(srb_t *sp, struct fxdisc_entry_fx00 *pfxiocb)
                fx_iocb.reserved_1 = piocb_rqst->reserved_1;
                fx_iocb.dataword_extra = piocb_rqst->dataword_extra;
                fx_iocb.dataword = piocb_rqst->dataword;
-               fx_iocb.req_xfrcnt = cpu_to_le16(piocb_rqst->req_len);
-               fx_iocb.rsp_xfrcnt = cpu_to_le16(piocb_rqst->rsp_len);
+               fx_iocb.req_xfrcnt = piocb_rqst->req_len;
+               fx_iocb.rsp_xfrcnt = piocb_rqst->rsp_len;
 
                if (piocb_rqst->flags & SRB_FXDISC_REQ_DMA_VALID) {
                        int avail_dsds, tot_dsds;
                        cont_a64_entry_t lcont_pkt;
                        cont_a64_entry_t *cont_pkt = NULL;
-                       uint32_t *cur_dsd;
+                       __le32 *cur_dsd;
                        int index = 0, cont = 0;
 
                        fx_iocb.req_dsdcnt =
                            cpu_to_le16(bsg_job->request_payload.sg_cnt);
                        tot_dsds =
-                           cpu_to_le32(bsg_job->request_payload.sg_cnt);
-                       cur_dsd = (uint32_t *)&fx_iocb.dseg_rq_address[0];
+                           bsg_job->request_payload.sg_cnt;
+                       cur_dsd = (__le32 *)&fx_iocb.dseg_rq_address[0];
                        avail_dsds = 1;
                        for_each_sg(bsg_job->request_payload.sg_list, sg,
                            tot_dsds, index) {
@@ -3355,7 +3362,7 @@ qlafx00_fxdisc_iocb(srb_t *sp, struct fxdisc_entry_fx00 *pfxiocb)
                                            qlafx00_prep_cont_type1_iocb(
                                                sp->fcport->vha->req,
                                                &lcont_pkt);
-                                       cur_dsd = (uint32_t *)
+                                       cur_dsd = (__le32 *)
                                            lcont_pkt.dseg_0_address;
                                        avail_dsds = 5;
                                        cont = 1;
@@ -3393,13 +3400,13 @@ qlafx00_fxdisc_iocb(srb_t *sp, struct fxdisc_entry_fx00 *pfxiocb)
                        int avail_dsds, tot_dsds;
                        cont_a64_entry_t lcont_pkt;
                        cont_a64_entry_t *cont_pkt = NULL;
-                       uint32_t *cur_dsd;
+                       __le32 *cur_dsd;
                        int index = 0, cont = 0;
 
                        fx_iocb.rsp_dsdcnt =
                           cpu_to_le16(bsg_job->reply_payload.sg_cnt);
-                       tot_dsds = cpu_to_le32(bsg_job->reply_payload.sg_cnt);
-                       cur_dsd = (uint32_t *)&fx_iocb.dseg_rsp_address[0];
+                       tot_dsds = bsg_job->reply_payload.sg_cnt;
+                       cur_dsd = (__le32 *)&fx_iocb.dseg_rsp_address[0];
                        avail_dsds = 1;
 
                        for_each_sg(bsg_job->reply_payload.sg_list, sg,
@@ -3418,7 +3425,7 @@ qlafx00_fxdisc_iocb(srb_t *sp, struct fxdisc_entry_fx00 *pfxiocb)
                                            qlafx00_prep_cont_type1_iocb(
                                                sp->fcport->vha->req,
                                                &lcont_pkt);
-                                       cur_dsd = (uint32_t *)
+                                       cur_dsd = (__le32 *)
                                            lcont_pkt.dseg_0_address;
                                        avail_dsds = 5;
                                        cont = 1;
@@ -3453,7 +3460,7 @@ qlafx00_fxdisc_iocb(srb_t *sp, struct fxdisc_entry_fx00 *pfxiocb)
                }
 
                if (piocb_rqst->flags & SRB_FXDISC_REQ_DWRD_VALID)
-                       fx_iocb.dataword = cpu_to_le32(piocb_rqst->dataword);
+                       fx_iocb.dataword = piocb_rqst->dataword;
                fx_iocb.flags = piocb_rqst->flags;
                fx_iocb.entry_count = entry_cnt;
        }
@@ -3462,7 +3469,7 @@ qlafx00_fxdisc_iocb(srb_t *sp, struct fxdisc_entry_fx00 *pfxiocb)
            sp->fcport->vha, 0x3047,
            (uint8_t *)&fx_iocb, sizeof(struct fxdisc_entry_fx00));
 
-       memcpy((void __iomem *)pfxiocb, &fx_iocb,
+       memcpy((void *)pfxiocb, &fx_iocb,
            sizeof(struct fxdisc_entry_fx00));
        wmb();
 }
index cc327dc..1a092af 100644 (file)
@@ -24,10 +24,10 @@ struct cmd_type_7_fx00 {
        uint32_t handle;                /* System handle. */
        uint32_t handle_hi;
 
-       uint16_t tgt_idx;               /* Target Idx. */
+       __le16 tgt_idx;         /* Target Idx. */
        uint16_t timeout;               /* Command timeout. */
 
-       uint16_t dseg_count;            /* Data segment count. */
+       __le16 dseg_count;              /* Data segment count. */
        uint16_t scsi_rsp_dsd_len;
 
        struct scsi_lun lun;            /* LUN (LE). */
@@ -41,7 +41,7 @@ struct cmd_type_7_fx00 {
        uint8_t crn;
 
        uint8_t fcp_cdb[MAX_CMDSZ];     /* SCSI command words. */
-       uint32_t byte_count;            /* Total byte count. */
+       __le32 byte_count;              /* Total byte count. */
 
        uint32_t dseg_0_address[2];     /* Data segment 0 address. */
        uint32_t dseg_0_len;            /* Data segment 0 length. */
@@ -81,16 +81,16 @@ struct sts_entry_fx00 {
        uint32_t handle;                /* System handle. */
        uint32_t handle_hi;             /* System handle. */
 
-       uint16_t comp_status;           /* Completion status. */
+       __le16 comp_status;             /* Completion status. */
        uint16_t reserved_0;            /* OX_ID used by the firmware. */
 
-       uint32_t residual_len;          /* FW calc residual transfer length. */
+       __le32 residual_len;            /* FW calc residual transfer length. */
 
        uint16_t reserved_1;
        uint16_t state_flags;           /* State flags. */
 
        uint16_t reserved_2;
-       uint16_t scsi_status;           /* SCSI status. */
+       __le16 scsi_status;             /* SCSI status. */
 
        uint32_t sense_len;             /* FCP SENSE length. */
        uint8_t data[32];               /* FCP response/sense information. */
@@ -106,7 +106,7 @@ struct multi_sts_entry_fx00 {
        uint8_t handle_count;
        uint8_t entry_status;
 
-       uint32_t handles[MAX_HANDLE_COUNT];
+       __le32 handles[MAX_HANDLE_COUNT];
 };
 
 #define TSK_MGMT_IOCB_TYPE_FX00                0x05
@@ -116,21 +116,21 @@ struct tsk_mgmt_entry_fx00 {
        uint8_t sys_define;
        uint8_t entry_status;           /* Entry Status. */
 
-       uint32_t handle;                /* System handle. */
+       __le32 handle;          /* System handle. */
 
        uint32_t handle_hi;             /* System handle. */
 
-       uint16_t tgt_id;                /* Target Idx. */
+       __le16 tgt_id;          /* Target Idx. */
 
        uint16_t reserved_1;
 
        uint16_t delay;                 /* Activity delay in seconds. */
 
-       uint16_t timeout;               /* Command timeout. */
+       __le16 timeout;         /* Command timeout. */
 
        struct scsi_lun lun;            /* LUN (LE). */
 
-       uint32_t control_flags;         /* Control Flags. */
+       __le32 control_flags;           /* Control Flags. */
 
        uint8_t reserved_2[32];
 };
@@ -143,16 +143,16 @@ struct abort_iocb_entry_fx00 {
        uint8_t sys_define;             /* System defined. */
        uint8_t entry_status;           /* Entry Status. */
 
-       uint32_t handle;                /* System handle. */
-       uint32_t handle_hi;             /* System handle. */
+       __le32 handle;          /* System handle. */
+       __le32 handle_hi;               /* System handle. */
 
-       uint16_t tgt_id_sts;            /* Completion status. */
-       uint16_t options;
+       __le16 tgt_id_sts;              /* Completion status. */
+       __le16 options;
 
-       uint32_t abort_handle;          /* System handle. */
-       uint32_t abort_handle_hi;       /* System handle. */
+       __le32 abort_handle;            /* System handle. */
+       __le32 abort_handle_hi; /* System handle. */
 
-       uint16_t req_que_no;
+       __le16 req_que_no;
        uint8_t reserved_1[38];
 };
 
@@ -167,17 +167,17 @@ struct ioctl_iocb_entry_fx00 {
        uint32_t reserved_0;            /* System handle. */
 
        uint16_t comp_func_num;
-       uint16_t fw_iotcl_flags;
+       __le16 fw_iotcl_flags;
 
-       uint32_t dataword_r;            /* Data word returned */
+       __le32 dataword_r;              /* Data word returned */
        uint32_t adapid;                /* Adapter ID */
        uint32_t adapid_hi;             /* Adapter ID high */
        uint32_t reserved_1;
 
-       uint32_t seq_no;
+       __le32 seq_no;
        uint8_t reserved_2[20];
        uint32_t residuallen;
-       uint32_t status;
+       __le32 status;
 };
 
 #define STATUS_CONT_TYPE_FX00 0x04
@@ -189,26 +189,26 @@ struct fxdisc_entry_fx00 {
        uint8_t sys_define;             /* System Defined. */
        uint8_t entry_status;           /* Entry Status. */
 
-       uint32_t handle;                /* System handle. */
-       uint32_t reserved_0;            /* System handle. */
+       __le32 handle;          /* System handle. */
+       __le32 reserved_0;              /* System handle. */
 
-       uint16_t func_num;
-       uint16_t req_xfrcnt;
-       uint16_t req_dsdcnt;
-       uint16_t rsp_xfrcnt;
-       uint16_t rsp_dsdcnt;
+       __le16 func_num;
+       __le16 req_xfrcnt;
+       __le16 req_dsdcnt;
+       __le16 rsp_xfrcnt;
+       __le16 rsp_dsdcnt;
        uint8_t flags;
        uint8_t reserved_1;
 
-       uint32_t dseg_rq_address[2];    /* Data segment 0 address. */
-       uint32_t dseg_rq_len;           /* Data segment 0 length. */
-       uint32_t dseg_rsp_address[2];   /* Data segment 1 address. */
-       uint32_t dseg_rsp_len;          /* Data segment 1 length. */
+       __le32 dseg_rq_address[2];      /* Data segment 0 address. */
+       __le32 dseg_rq_len;             /* Data segment 0 length. */
+       __le32 dseg_rsp_address[2];     /* Data segment 1 address. */
+       __le32 dseg_rsp_len;            /* Data segment 1 length. */
 
-       uint32_t dataword;
-       uint32_t adapid;
-       uint32_t adapid_hi;
-       uint32_t dataword_extra;
+       __le32 dataword;
+       __le32 adapid;
+       __le32 adapid_hi;
+       __le32 dataword_extra;
 };
 
 struct qlafx00_tgt_node_info {
@@ -421,43 +421,43 @@ struct config_info_data {
        WRT_REG_DWORD((ha)->cregbase + off, val)
 
 struct qla_mt_iocb_rqst_fx00 {
-       uint32_t reserved_0;
+       __le32 reserved_0;
 
-       uint16_t func_type;
+       __le16 func_type;
        uint8_t flags;
        uint8_t reserved_1;
 
-       uint32_t dataword;
+       __le32 dataword;
 
-       uint32_t adapid;
-       uint32_t adapid_hi;
+       __le32 adapid;
+       __le32 adapid_hi;
 
-       uint32_t dataword_extra;
+       __le32 dataword_extra;
 
-       uint32_t req_len;
+       __le32 req_len;
 
-       uint32_t rsp_len;
+       __le32 rsp_len;
 };
 
 struct qla_mt_iocb_rsp_fx00 {
        uint32_t reserved_1;
 
        uint16_t func_type;
-       uint16_t ioctl_flags;
+       __le16 ioctl_flags;
 
-       uint32_t ioctl_data;
+       __le32 ioctl_data;
 
        uint32_t adapid;
        uint32_t adapid_hi;
 
        uint32_t reserved_2;
-       uint32_t seq_number;
+       __le32 seq_number;
 
        uint8_t reserved_3[20];
 
        int32_t res_count;
 
-       uint32_t status;
+       __le32 status;
 };
 
 
index ad72c1d..3e21e9f 100644 (file)
@@ -104,8 +104,6 @@ MODULE_PARM_DESC(ql2xshiftctondsd,
                "Set to control shifting of command type processing "
                "based on total number of SG elements.");
 
-static void qla2x00_free_device(scsi_qla_host_t *);
-
 int ql2xfdmienable=1;
 module_param(ql2xfdmienable, int, S_IRUGO);
 MODULE_PARM_DESC(ql2xfdmienable,
@@ -237,6 +235,7 @@ static int qla2xxx_eh_host_reset(struct scsi_cmnd *);
 
 static int qla2x00_change_queue_depth(struct scsi_device *, int, int);
 static int qla2x00_change_queue_type(struct scsi_device *, int);
+static void qla2x00_free_device(scsi_qla_host_t *);
 
 struct scsi_host_template qla2xxx_driver_template = {
        .module                 = THIS_MODULE,
@@ -2840,8 +2839,7 @@ skip_dpc:
        qla2x00_dfs_setup(base_vha);
 
        ql_log(ql_log_info, base_vha, 0x00fb,
-           "QLogic %s - %s.\n",
-           ha->model_number, ha->model_desc ? ha->model_desc : "");
+           "QLogic %s - %s.\n", ha->model_number, ha->model_desc);
        ql_log(ql_log_info, base_vha, 0x00fc,
            "ISP%04X: %s @ %s hdma%c host#=%ld fw=%s.\n",
            pdev->device, ha->isp_ops->pci_info_str(base_vha, pci_info),
@@ -2981,14 +2979,12 @@ qla2x00_remove_one(struct pci_dev *pdev)
        set_bit(UNLOADING, &base_vha->dpc_flags);
        mutex_lock(&ha->vport_lock);
        while (ha->cur_vport_count) {
-               struct Scsi_Host *scsi_host;
-
                spin_lock_irqsave(&ha->vport_slock, flags);
 
                BUG_ON(base_vha->list.next == &ha->vp_list);
                /* This assumes first entry in ha->vp_list is always base vha */
                vha = list_first_entry(&base_vha->list, scsi_qla_host_t, list);
-               scsi_host = scsi_host_get(vha->host);
+               scsi_host_get(vha->host);
 
                spin_unlock_irqrestore(&ha->vport_slock, flags);
                mutex_unlock(&ha->vport_lock);
index fcdc223..83a8f7a 100644 (file)
@@ -544,102 +544,6 @@ out_free_id_list:
        return res;
 }
 
-static bool qlt_check_fcport_exist(struct scsi_qla_host *vha,
-       struct qla_tgt_sess *sess)
-{
-       struct qla_hw_data *ha = vha->hw;
-       struct qla_port_24xx_data *pmap24;
-       bool res, found = false;
-       int rc, i;
-       uint16_t loop_id = 0xFFFF; /* to eliminate compiler's warning */
-       uint16_t entries;
-       void *pmap;
-       int pmap_len;
-       fc_port_t *fcport;
-       int global_resets;
-       unsigned long flags;
-
-retry:
-       global_resets = atomic_read(&ha->tgt.qla_tgt->tgt_global_resets_count);
-
-       rc = qla2x00_get_node_name_list(vha, &pmap, &pmap_len);
-       if (rc != QLA_SUCCESS) {
-               res = false;
-               goto out;
-       }
-
-       pmap24 = pmap;
-       entries = pmap_len/sizeof(*pmap24);
-
-       for (i = 0; i < entries; ++i) {
-               if (!memcmp(sess->port_name, pmap24[i].port_name, WWN_SIZE)) {
-                       loop_id = le16_to_cpu(pmap24[i].loop_id);
-                       found = true;
-                       break;
-               }
-       }
-
-       kfree(pmap);
-
-       if (!found) {
-               res = false;
-               goto out;
-       }
-
-       ql_dbg(ql_dbg_tgt_mgt, vha, 0xf046,
-           "qlt_check_fcport_exist(): loop_id %d", loop_id);
-
-       fcport = kzalloc(sizeof(*fcport), GFP_KERNEL);
-       if (fcport == NULL) {
-               ql_dbg(ql_dbg_tgt_mgt, vha, 0xf047,
-                   "qla_target(%d): Allocation of tmp FC port failed",
-                   vha->vp_idx);
-               res = false;
-               goto out;
-       }
-
-       fcport->loop_id = loop_id;
-
-       rc = qla2x00_get_port_database(vha, fcport, 0);
-       if (rc != QLA_SUCCESS) {
-               ql_dbg(ql_dbg_tgt_mgt, vha, 0xf048,
-                   "qla_target(%d): Failed to retrieve fcport "
-                   "information -- get_port_database() returned %x "
-                   "(loop_id=0x%04x)", vha->vp_idx, rc, loop_id);
-               res = false;
-               goto out_free_fcport;
-       }
-
-       if (global_resets !=
-           atomic_read(&ha->tgt.qla_tgt->tgt_global_resets_count)) {
-               ql_dbg(ql_dbg_tgt_mgt, vha, 0xf002,
-                   "qla_target(%d): global reset during session discovery"
-                   " (counter was %d, new %d), retrying",
-                   vha->vp_idx, global_resets,
-                   atomic_read(&ha->tgt.qla_tgt->tgt_global_resets_count));
-               goto retry;
-       }
-
-       ql_dbg(ql_dbg_tgt_mgt, vha, 0xf003,
-           "Updating sess %p s_id %x:%x:%x, loop_id %d) to d_id %x:%x:%x, "
-           "loop_id %d", sess, sess->s_id.b.domain, sess->s_id.b.al_pa,
-           sess->s_id.b.area, sess->loop_id, fcport->d_id.b.domain,
-           fcport->d_id.b.al_pa, fcport->d_id.b.area, fcport->loop_id);
-
-       spin_lock_irqsave(&ha->hardware_lock, flags);
-       ha->tgt.tgt_ops->update_sess(sess, fcport->d_id, fcport->loop_id,
-                               (fcport->flags & FCF_CONF_COMP_SUPPORTED));
-       spin_unlock_irqrestore(&ha->hardware_lock, flags);
-
-       res = true;
-
-out_free_fcport:
-       kfree(fcport);
-
-out:
-       return res;
-}
-
 /* ha->hardware_lock supposed to be held on entry */
 static void qlt_undelete_sess(struct qla_tgt_sess *sess)
 {
@@ -663,43 +567,13 @@ static void qlt_del_sess_work_fn(struct delayed_work *work)
                sess = list_entry(tgt->del_sess_list.next, typeof(*sess),
                    del_list_entry);
                if (time_after_eq(jiffies, sess->expires)) {
-                       bool cancel;
-
                        qlt_undelete_sess(sess);
 
-                       spin_unlock_irqrestore(&ha->hardware_lock, flags);
-                       cancel = qlt_check_fcport_exist(vha, sess);
-
-                       if (cancel) {
-                               if (sess->deleted) {
-                                       /*
-                                        * sess was again deleted while we were
-                                        * discovering it
-                                        */
-                                       spin_lock_irqsave(&ha->hardware_lock,
-                                           flags);
-                                       continue;
-                               }
-
-                               ql_dbg(ql_dbg_tgt_mgt, vha, 0xf049,
-                                   "qla_target(%d): cancel deletion of "
-                                   "session for port %02x:%02x:%02x:%02x:%02x:"
-                                   "%02x:%02x:%02x (loop ID %d), because "
-                                   " it isn't deleted by firmware",
-                                   vha->vp_idx, sess->port_name[0],
-                                   sess->port_name[1], sess->port_name[2],
-                                   sess->port_name[3], sess->port_name[4],
-                                   sess->port_name[5], sess->port_name[6],
-                                   sess->port_name[7], sess->loop_id);
-                       } else {
-                               ql_dbg(ql_dbg_tgt_mgt, vha, 0xf004,
-                                   "Timeout: sess %p about to be deleted\n",
-                                   sess);
-                               ha->tgt.tgt_ops->shutdown_sess(sess);
-                               ha->tgt.tgt_ops->put_sess(sess);
-                       }
-
-                       spin_lock_irqsave(&ha->hardware_lock, flags);
+                       ql_dbg(ql_dbg_tgt_mgt, vha, 0xf004,
+                           "Timeout: sess %p about to be deleted\n",
+                           sess);
+                       ha->tgt.tgt_ops->shutdown_sess(sess);
+                       ha->tgt.tgt_ops->put_sess(sess);
                } else {
                        schedule_delayed_work(&tgt->sess_del_work,
                            jiffies - sess->expires);
@@ -884,9 +758,8 @@ void qlt_fc_port_added(struct scsi_qla_host *vha, fc_port_t *fcport)
                    sess->loop_id);
                sess->local = 0;
        }
-       spin_unlock_irqrestore(&ha->hardware_lock, flags);
-
        ha->tgt.tgt_ops->put_sess(sess);
+       spin_unlock_irqrestore(&ha->hardware_lock, flags);
 }
 
 void qlt_fc_port_deleted(struct scsi_qla_host *vha, fc_port_t *fcport)
@@ -2706,7 +2579,9 @@ static void qlt_do_work(struct work_struct *work)
        /*
         * Drop extra session reference from qla_tgt_handle_cmd_for_atio*(
         */
+       spin_lock_irqsave(&ha->hardware_lock, flags);
        ha->tgt.tgt_ops->put_sess(sess);
+       spin_unlock_irqrestore(&ha->hardware_lock, flags);
        return;
 
 out_term:
@@ -2718,9 +2593,9 @@ out_term:
        spin_lock_irqsave(&ha->hardware_lock, flags);
        qlt_send_term_exchange(vha, NULL, &cmd->atio, 1);
        kmem_cache_free(qla_tgt_cmd_cachep, cmd);
-       spin_unlock_irqrestore(&ha->hardware_lock, flags);
        if (sess)
                ha->tgt.tgt_ops->put_sess(sess);
+       spin_unlock_irqrestore(&ha->hardware_lock, flags);
 }
 
 /* ha->hardware_lock supposed to be held on entry */
@@ -4169,16 +4044,16 @@ static void qlt_abort_work(struct qla_tgt *tgt,
        rc = __qlt_24xx_handle_abts(vha, &prm->abts, sess);
        if (rc != 0)
                goto out_term;
-       spin_unlock_irqrestore(&ha->hardware_lock, flags);
 
        ha->tgt.tgt_ops->put_sess(sess);
+       spin_unlock_irqrestore(&ha->hardware_lock, flags);
        return;
 
 out_term:
        qlt_24xx_send_abts_resp(vha, &prm->abts, FCP_TMF_REJECTED, false);
-       spin_unlock_irqrestore(&ha->hardware_lock, flags);
        if (sess)
                ha->tgt.tgt_ops->put_sess(sess);
+       spin_unlock_irqrestore(&ha->hardware_lock, flags);
 }
 
 static void qlt_tmr_work(struct qla_tgt *tgt,
@@ -4226,16 +4101,16 @@ static void qlt_tmr_work(struct qla_tgt *tgt,
        rc = qlt_issue_task_mgmt(sess, unpacked_lun, fn, iocb, 0);
        if (rc != 0)
                goto out_term;
-       spin_unlock_irqrestore(&ha->hardware_lock, flags);
 
        ha->tgt.tgt_ops->put_sess(sess);
+       spin_unlock_irqrestore(&ha->hardware_lock, flags);
        return;
 
 out_term:
        qlt_send_term_exchange(vha, NULL, &prm->tm_iocb2, 1);
-       spin_unlock_irqrestore(&ha->hardware_lock, flags);
        if (sess)
                ha->tgt.tgt_ops->put_sess(sess);
+       spin_unlock_irqrestore(&ha->hardware_lock, flags);
 }
 
 static void qlt_sess_work_fn(struct work_struct *work)
index 66b0b26..a318092 100644 (file)
@@ -703,7 +703,7 @@ static int tcm_qla2xxx_queue_status(struct se_cmd *se_cmd)
        return qlt_xmit_response(cmd, xmit_type, se_cmd->scsi_status);
 }
 
-static int tcm_qla2xxx_queue_tm_rsp(struct se_cmd *se_cmd)
+static void tcm_qla2xxx_queue_tm_rsp(struct se_cmd *se_cmd)
 {
        struct se_tmr_req *se_tmr = se_cmd->se_tmr_req;
        struct qla_tgt_mgmt_cmd *mcmd = container_of(se_cmd,
@@ -735,8 +735,6 @@ static int tcm_qla2xxx_queue_tm_rsp(struct se_cmd *se_cmd)
         * CTIO response packet.
         */
        qlt_xmit_tm_rsp(mcmd);
-
-       return 0;
 }
 
 /* Local pointer to allocated TCM configfs fabric module */
@@ -799,12 +797,14 @@ static void tcm_qla2xxx_put_session(struct se_session *se_sess)
 
 static void tcm_qla2xxx_put_sess(struct qla_tgt_sess *sess)
 {
-       tcm_qla2xxx_put_session(sess->se_sess);
+       assert_spin_locked(&sess->vha->hw->hardware_lock);
+       kref_put(&sess->se_sess->sess_kref, tcm_qla2xxx_release_session);
 }
 
 static void tcm_qla2xxx_shutdown_sess(struct qla_tgt_sess *sess)
 {
-       tcm_qla2xxx_shutdown_session(sess->se_sess);
+       assert_spin_locked(&sess->vha->hw->hardware_lock);
+       target_sess_cmd_list_set_waiting(sess->se_sess);
 }
 
 static struct se_node_acl *tcm_qla2xxx_make_nodeacl(
index d055450..cb4fefa 100644 (file)
@@ -258,7 +258,7 @@ struct sdebug_queued_cmd {
 static struct sdebug_queued_cmd queued_arr[SCSI_DEBUG_CANQUEUE];
 
 static unsigned char * fake_storep;    /* ramdisk storage */
-static unsigned char *dif_storep;      /* protection info */
+static struct sd_dif_tuple *dif_storep;        /* protection info */
 static void *map_storep;               /* provisioning map */
 
 static unsigned long map_size;
@@ -277,11 +277,6 @@ static char sdebug_proc_name[] = "scsi_debug";
 
 static struct bus_type pseudo_lld_bus;
 
-static inline sector_t dif_offset(sector_t sector)
-{
-       return sector << 3;
-}
-
 static struct device_driver sdebug_driverfs_driver = {
        .name           = sdebug_proc_name,
        .bus            = &pseudo_lld_bus,
@@ -1736,6 +1731,50 @@ static int do_device_access(struct scsi_cmnd *scmd,
        return ret;
 }
 
+static u16 dif_compute_csum(const void *buf, int len)
+{
+       u16 csum;
+
+       switch (scsi_debug_guard) {
+       case 1:
+               csum = ip_compute_csum(buf, len);
+               break;
+       case 0:
+               csum = cpu_to_be16(crc_t10dif(buf, len));
+               break;
+       }
+       return csum;
+}
+
+static int dif_verify(struct sd_dif_tuple *sdt, const void *data,
+                     sector_t sector, u32 ei_lba)
+{
+       u16 csum = dif_compute_csum(data, scsi_debug_sector_size);
+
+       if (sdt->guard_tag != csum) {
+               pr_err("%s: GUARD check failed on sector %lu rcvd 0x%04x, data 0x%04x\n",
+                       __func__,
+                       (unsigned long)sector,
+                       be16_to_cpu(sdt->guard_tag),
+                       be16_to_cpu(csum));
+               return 0x01;
+       }
+       if (scsi_debug_dif == SD_DIF_TYPE1_PROTECTION &&
+           be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) {
+               pr_err("%s: REF check failed on sector %lu\n",
+                       __func__, (unsigned long)sector);
+               return 0x03;
+       }
+       if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
+           be32_to_cpu(sdt->ref_tag) != ei_lba) {
+               pr_err("%s: REF check failed on sector %lu\n",
+                       __func__, (unsigned long)sector);
+                       dif_errors++;
+               return 0x03;
+       }
+       return 0;
+}
+
 static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec,
                            unsigned int sectors, u32 ei_lba)
 {
@@ -1748,71 +1787,38 @@ static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec,
 
        start_sec = do_div(tmp_sec, sdebug_store_sectors);
 
-       sdt = (struct sd_dif_tuple *)(dif_storep + dif_offset(start_sec));
+       sdt = dif_storep + start_sec;
 
        for (i = 0 ; i < sectors ; i++) {
-               u16 csum;
+               int ret;
 
                if (sdt[i].app_tag == 0xffff)
                        continue;
 
                sector = start_sec + i;
 
-               switch (scsi_debug_guard) {
-               case 1:
-                       csum = ip_compute_csum(fake_storep +
-                                              sector * scsi_debug_sector_size,
-                                              scsi_debug_sector_size);
-                       break;
-               case 0:
-                       csum = crc_t10dif(fake_storep +
-                                         sector * scsi_debug_sector_size,
-                                         scsi_debug_sector_size);
-                       csum = cpu_to_be16(csum);
-                       break;
-               default:
-                       BUG();
-               }
-
-               if (sdt[i].guard_tag != csum) {
-                       printk(KERN_ERR "%s: GUARD check failed on sector %lu" \
-                              " rcvd 0x%04x, data 0x%04x\n", __func__,
-                              (unsigned long)sector,
-                              be16_to_cpu(sdt[i].guard_tag),
-                              be16_to_cpu(csum));
-                       dif_errors++;
-                       return 0x01;
-               }
-
-               if (scsi_debug_dif == SD_DIF_TYPE1_PROTECTION &&
-                   be32_to_cpu(sdt[i].ref_tag) != (sector & 0xffffffff)) {
-                       printk(KERN_ERR "%s: REF check failed on sector %lu\n",
-                              __func__, (unsigned long)sector);
+               ret = dif_verify(&sdt[i],
+                                fake_storep + sector * scsi_debug_sector_size,
+                                sector, ei_lba);
+               if (ret) {
                        dif_errors++;
-                       return 0x03;
-               }
-
-               if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
-                   be32_to_cpu(sdt[i].ref_tag) != ei_lba) {
-                       printk(KERN_ERR "%s: REF check failed on sector %lu\n",
-                              __func__, (unsigned long)sector);
-                       dif_errors++;
-                       return 0x03;
+                       return ret;
                }
 
                ei_lba++;
        }
 
-       resid = sectors * 8; /* Bytes of protection data to copy into sgl */
+       /* Bytes of protection data to copy into sgl */
+       resid = sectors * sizeof(*dif_storep);
        sector = start_sec;
 
        scsi_for_each_prot_sg(SCpnt, psgl, scsi_prot_sg_count(SCpnt), i) {
                int len = min(psgl->length, resid);
 
                paddr = kmap_atomic(sg_page(psgl)) + psgl->offset;
-               memcpy(paddr, dif_storep + dif_offset(sector), len);
+               memcpy(paddr, dif_storep + sector, len);
 
-               sector += len >> 3;
+               sector += len / sizeof(*dif_storep);
                if (sector >= sdebug_store_sectors) {
                        /* Force wrap */
                        tmp_sec = sector;
@@ -1910,22 +1916,21 @@ static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
        sector_t tmp_sec = start_sec;
        sector_t sector;
        int ppage_offset;
-       unsigned short csum;
 
        sector = do_div(tmp_sec, sdebug_store_sectors);
 
        BUG_ON(scsi_sg_count(SCpnt) == 0);
        BUG_ON(scsi_prot_sg_count(SCpnt) == 0);
 
-       paddr = kmap_atomic(sg_page(psgl)) + psgl->offset;
        ppage_offset = 0;
 
        /* For each data page */
        scsi_for_each_sg(SCpnt, dsgl, scsi_sg_count(SCpnt), i) {
                daddr = kmap_atomic(sg_page(dsgl)) + dsgl->offset;
+               paddr = kmap_atomic(sg_page(psgl)) + psgl->offset;
 
                /* For each sector-sized chunk in data page */
-               for (j = 0 ; j < dsgl->length ; j += scsi_debug_sector_size) {
+               for (j = 0; j < dsgl->length; j += scsi_debug_sector_size) {
 
                        /* If we're at the end of the current
                         * protection page advance to the next one
@@ -1941,51 +1946,9 @@ static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
 
                        sdt = paddr + ppage_offset;
 
-                       switch (scsi_debug_guard) {
-                       case 1:
-                               csum = ip_compute_csum(daddr,
-                                                      scsi_debug_sector_size);
-                               break;
-                       case 0:
-                               csum = cpu_to_be16(crc_t10dif(daddr,
-                                                     scsi_debug_sector_size));
-                               break;
-                       default:
-                               BUG();
-                               ret = 0;
-                               goto out;
-                       }
-
-                       if (sdt->guard_tag != csum) {
-                               printk(KERN_ERR
-                                      "%s: GUARD check failed on sector %lu " \
-                                      "rcvd 0x%04x, calculated 0x%04x\n",
-                                      __func__, (unsigned long)sector,
-                                      be16_to_cpu(sdt->guard_tag),
-                                      be16_to_cpu(csum));
-                               ret = 0x01;
-                               dump_sector(daddr, scsi_debug_sector_size);
-                               goto out;
-                       }
-
-                       if (scsi_debug_dif == SD_DIF_TYPE1_PROTECTION &&
-                           be32_to_cpu(sdt->ref_tag)
-                           != (start_sec & 0xffffffff)) {
-                               printk(KERN_ERR
-                                      "%s: REF check failed on sector %lu\n",
-                                      __func__, (unsigned long)sector);
-                               ret = 0x03;
-                               dump_sector(daddr, scsi_debug_sector_size);
-                               goto out;
-                       }
-
-                       if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
-                           be32_to_cpu(sdt->ref_tag) != ei_lba) {
-                               printk(KERN_ERR
-                                      "%s: REF check failed on sector %lu\n",
-                                      __func__, (unsigned long)sector);
-                               ret = 0x03;
-                               dump_sector(daddr, scsi_debug_sector_size);
+                       ret = dif_verify(sdt, daddr + j, start_sec, ei_lba);
+                       if (ret) {
+                               dump_sector(daddr + j, scsi_debug_sector_size);
                                goto out;
                        }
 
@@ -1994,7 +1957,7 @@ static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
                         * correctness we need to verify each sector
                         * before writing it to "stable" storage
                         */
-                       memcpy(dif_storep + dif_offset(sector), sdt, 8);
+                       memcpy(dif_storep + sector, sdt, sizeof(*sdt));
 
                        sector++;
 
@@ -2003,23 +1966,21 @@ static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
 
                        start_sec++;
                        ei_lba++;
-                       daddr += scsi_debug_sector_size;
                        ppage_offset += sizeof(struct sd_dif_tuple);
                }
 
+               kunmap_atomic(paddr);
                kunmap_atomic(daddr);
        }
 
-       kunmap_atomic(paddr);
-
        dix_writes++;
 
        return 0;
 
 out:
        dif_errors++;
-       kunmap_atomic(daddr);
        kunmap_atomic(paddr);
+       kunmap_atomic(daddr);
        return ret;
 }
 
@@ -2092,6 +2053,11 @@ static void unmap_region(sector_t lba, unsigned int len)
                                       scsi_debug_sector_size *
                                       scsi_debug_unmap_granularity);
                        }
+                       if (dif_storep) {
+                               memset(dif_storep + lba, 0xff,
+                                      sizeof(*dif_storep) *
+                                      scsi_debug_unmap_granularity);
+                       }
                }
                lba = map_index_to_lba(index + 1);
        }
@@ -3400,7 +3366,7 @@ static int __init scsi_debug_init(void)
        if (scsi_debug_num_parts > 0)
                sdebug_build_parts(fake_storep, sz);
 
-       if (scsi_debug_dif) {
+       if (scsi_debug_dix) {
                int dif_size;
 
                dif_size = sdebug_store_sectors * sizeof(struct sd_dif_tuple);
index 86d5220..124392f 100644 (file)
@@ -434,6 +434,8 @@ static void scsi_run_queue(struct request_queue *q)
        list_splice_init(&shost->starved_list, &starved_list);
 
        while (!list_empty(&starved_list)) {
+               struct request_queue *slq;
+
                /*
                 * As long as shost is accepting commands and we have
                 * starved queues, call blk_run_queue. scsi_request_fn
@@ -456,11 +458,25 @@ static void scsi_run_queue(struct request_queue *q)
                        continue;
                }
 
-               spin_unlock(shost->host_lock);
-               spin_lock(sdev->request_queue->queue_lock);
-               __blk_run_queue(sdev->request_queue);
-               spin_unlock(sdev->request_queue->queue_lock);
-               spin_lock(shost->host_lock);
+               /*
+                * Once we drop the host lock, a racing scsi_remove_device()
+                * call may remove the sdev from the starved list and destroy
+                * it and the queue.  Mitigate by taking a reference to the
+                * queue and never touching the sdev again after we drop the
+                * host lock.  Note: if __scsi_remove_device() invokes
+                * blk_cleanup_queue() before the queue is run from this
+                * function then blk_run_queue() will return immediately since
+                * blk_cleanup_queue() marks the queue with QUEUE_FLAG_DYING.
+                */
+               slq = sdev->request_queue;
+               if (!blk_get_queue(slq))
+                       continue;
+               spin_unlock_irqrestore(shost->host_lock, flags);
+
+               blk_run_queue(slq);
+               blk_put_queue(slq);
+
+               spin_lock_irqsave(shost->host_lock, flags);
        }
        /* put any unprocessed entries back */
        list_splice(&starved_list, &shost->starved_list);
@@ -2177,6 +2193,7 @@ scsi_device_set_state(struct scsi_device *sdev, enum scsi_device_state state)
                case SDEV_OFFLINE:
                case SDEV_TRANSPORT_OFFLINE:
                case SDEV_CANCEL:
+               case SDEV_CREATED_BLOCK:
                        break;
                default:
                        goto illegal;
index 9451989..83ec1aa 100644 (file)
@@ -326,7 +326,9 @@ MODULE_PARM_DESC(storvsc_ringbuffer_size, "Ring buffer size (bytes)");
  */
 static int storvsc_timeout = 180;
 
-#define STORVSC_MAX_IO_REQUESTS                                128
+#define STORVSC_MAX_IO_REQUESTS                                200
+
+static void storvsc_on_channel_callback(void *context);
 
 /*
  * In Hyper-V, each port/path/target maps to 1 scsi host adapter.  In
@@ -364,6 +366,7 @@ struct storvsc_device {
 
        bool     destroy;
        bool     drain_notify;
+       bool     open_sub_channel;
        atomic_t num_outstanding_req;
        struct Scsi_Host *host;
 
@@ -755,12 +758,104 @@ static unsigned int copy_to_bounce_buffer(struct scatterlist *orig_sgl,
        return total_copied;
 }
 
+static void handle_sc_creation(struct vmbus_channel *new_sc)
+{
+       struct hv_device *device = new_sc->primary_channel->device_obj;
+       struct storvsc_device *stor_device;
+       struct vmstorage_channel_properties props;
+
+       stor_device = get_out_stor_device(device);
+       if (!stor_device)
+               return;
+
+       if (stor_device->open_sub_channel == false)
+               return;
+
+       memset(&props, 0, sizeof(struct vmstorage_channel_properties));
+
+       vmbus_open(new_sc,
+                  storvsc_ringbuffer_size,
+                  storvsc_ringbuffer_size,
+                  (void *)&props,
+                  sizeof(struct vmstorage_channel_properties),
+                  storvsc_on_channel_callback, new_sc);
+}
+
+static void  handle_multichannel_storage(struct hv_device *device, int max_chns)
+{
+       struct storvsc_device *stor_device;
+       int num_cpus = num_online_cpus();
+       int num_sc;
+       struct storvsc_cmd_request *request;
+       struct vstor_packet *vstor_packet;
+       int ret, t;
+
+       num_sc = ((max_chns > num_cpus) ? num_cpus : max_chns);
+       stor_device = get_out_stor_device(device);
+       if (!stor_device)
+               return;
+
+       request = &stor_device->init_request;
+       vstor_packet = &request->vstor_packet;
+
+       stor_device->open_sub_channel = true;
+       /*
+        * Establish a handler for dealing with subchannels.
+        */
+       vmbus_set_sc_create_callback(device->channel, handle_sc_creation);
+
+       /*
+        * Check to see if sub-channels have already been created. This
+        * can happen when this driver is re-loaded after unloading.
+        */
+
+       if (vmbus_are_subchannels_present(device->channel))
+               return;
+
+       stor_device->open_sub_channel = false;
+       /*
+        * Request the host to create sub-channels.
+        */
+       memset(request, 0, sizeof(struct storvsc_cmd_request));
+       init_completion(&request->wait_event);
+       vstor_packet->operation = VSTOR_OPERATION_CREATE_SUB_CHANNELS;
+       vstor_packet->flags = REQUEST_COMPLETION_FLAG;
+       vstor_packet->sub_channel_count = num_sc;
+
+       ret = vmbus_sendpacket(device->channel, vstor_packet,
+                              (sizeof(struct vstor_packet) -
+                              vmscsi_size_delta),
+                              (unsigned long)request,
+                              VM_PKT_DATA_INBAND,
+                              VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
+
+       if (ret != 0)
+               return;
+
+       t = wait_for_completion_timeout(&request->wait_event, 10*HZ);
+       if (t == 0)
+               return;
+
+       if (vstor_packet->operation != VSTOR_OPERATION_COMPLETE_IO ||
+           vstor_packet->status != 0)
+               return;
+
+       /*
+        * Now that we created the sub-channels, invoke the check; this
+        * may trigger the callback.
+        */
+       stor_device->open_sub_channel = true;
+       vmbus_are_subchannels_present(device->channel);
+}
+
 static int storvsc_channel_init(struct hv_device *device)
 {
        struct storvsc_device *stor_device;
        struct storvsc_cmd_request *request;
        struct vstor_packet *vstor_packet;
        int ret, t;
+       int max_chns;
+       bool process_sub_channels = false;
 
        stor_device = get_out_stor_device(device);
        if (!stor_device)
@@ -855,6 +950,19 @@ static int storvsc_channel_init(struct hv_device *device)
            vstor_packet->status != 0)
                goto cleanup;
 
+       /*
+        * Check to see if multi-channel support is there.
+        * Hosts that implement protocol version of 5.1 and above
+        * support multi-channel.
+        */
+       max_chns = vstor_packet->storage_channel_properties.max_channel_cnt;
+       if ((vmbus_proto_version != VERSION_WIN7) &&
+          (vmbus_proto_version != VERSION_WS2008))  {
+               if (vstor_packet->storage_channel_properties.flags &
+                   STORAGE_CHANNEL_SUPPORTS_MULTI_CHANNEL)
+                       process_sub_channels = true;
+       }
+
        memset(vstor_packet, 0, sizeof(struct vstor_packet));
        vstor_packet->operation = VSTOR_OPERATION_END_INITIALIZATION;
        vstor_packet->flags = REQUEST_COMPLETION_FLAG;
@@ -879,6 +987,9 @@ static int storvsc_channel_init(struct hv_device *device)
            vstor_packet->status != 0)
                goto cleanup;
 
+       if (process_sub_channels)
+               handle_multichannel_storage(device, max_chns);
+
 
 cleanup:
        return ret;
@@ -1100,7 +1211,8 @@ static void storvsc_on_receive(struct hv_device *device,
 
 static void storvsc_on_channel_callback(void *context)
 {
-       struct hv_device *device = (struct hv_device *)context;
+       struct vmbus_channel *channel = (struct vmbus_channel *)context;
+       struct hv_device *device;
        struct storvsc_device *stor_device;
        u32 bytes_recvd;
        u64 request_id;
@@ -1108,13 +1220,17 @@ static void storvsc_on_channel_callback(void *context)
        struct storvsc_cmd_request *request;
        int ret;
 
+       if (channel->primary_channel != NULL)
+               device = channel->primary_channel->device_obj;
+       else
+               device = channel->device_obj;
 
        stor_device = get_in_stor_device(device);
        if (!stor_device)
                return;
 
        do {
-               ret = vmbus_recvpacket(device->channel, packet,
+               ret = vmbus_recvpacket(channel, packet,
                                       ALIGN((sizeof(struct vstor_packet) -
                                             vmscsi_size_delta), 8),
                                       &bytes_recvd, &request_id);
@@ -1155,7 +1271,7 @@ static int storvsc_connect_to_vsp(struct hv_device *device, u32 ring_size)
                         ring_size,
                         (void *)&props,
                         sizeof(struct vmstorage_channel_properties),
-                        storvsc_on_channel_callback, device);
+                        storvsc_on_channel_callback, device->channel);
 
        if (ret != 0)
                return ret;
@@ -1207,6 +1323,7 @@ static int storvsc_do_io(struct hv_device *device,
 {
        struct storvsc_device *stor_device;
        struct vstor_packet *vstor_packet;
+       struct vmbus_channel *outgoing_channel;
        int ret = 0;
 
        vstor_packet = &request->vstor_packet;
@@ -1217,6 +1334,11 @@ static int storvsc_do_io(struct hv_device *device,
 
 
        request->device  = device;
+       /*
+        * Select an an appropriate channel to send the request out.
+        */
+
+       outgoing_channel = vmbus_get_outgoing_channel(device->channel);
 
 
        vstor_packet->flags |= REQUEST_COMPLETION_FLAG;
@@ -1234,7 +1356,7 @@ static int storvsc_do_io(struct hv_device *device,
        vstor_packet->operation = VSTOR_OPERATION_EXECUTE_SRB;
 
        if (request->data_buffer.len) {
-               ret = vmbus_sendpacket_multipagebuffer(device->channel,
+               ret = vmbus_sendpacket_multipagebuffer(outgoing_channel,
                                &request->data_buffer,
                                vstor_packet,
                                (sizeof(struct vstor_packet) -
@@ -1580,6 +1702,7 @@ static struct scsi_host_template scsi_driver = {
 enum {
        SCSI_GUID,
        IDE_GUID,
+       SFC_GUID,
 };
 
 static const struct hv_vmbus_device_id id_table[] = {
@@ -1591,6 +1714,11 @@ static const struct hv_vmbus_device_id id_table[] = {
        { HV_IDE_GUID,
          .driver_data = IDE_GUID
        },
+       /* Fibre Channel GUID */
+       {
+         HV_SYNTHFC_GUID,
+         .driver_data = SFC_GUID
+       },
        { },
 };
 
@@ -1643,6 +1771,7 @@ static int storvsc_probe(struct hv_device *device,
        }
 
        stor_device->destroy = false;
+       stor_device->open_sub_channel = false;
        init_waitqueue_head(&stor_device->waiting_to_drain);
        stor_device->device = device;
        stor_device->host = host;
index 10f99f4..89cbbab 100644 (file)
@@ -266,7 +266,7 @@ config SPI_OC_TINY
 
 config SPI_OCTEON
        tristate "Cavium OCTEON SPI controller"
-       depends on CPU_CAVIUM_OCTEON
+       depends on CAVIUM_OCTEON_SOC
        help
          SPI host driver for the hardware found on some Cavium OCTEON
          SOCs.
index 5ff3a4f..36171fd 100644 (file)
@@ -144,7 +144,7 @@ config SSB_SFLASH
 # Assumption: We are on embedded, if we compile the MIPS core.
 config SSB_EMBEDDED
        bool
-       depends on SSB_DRIVER_MIPS
+       depends on SSB_DRIVER_MIPS && SSB_PCICORE_HOSTMODE
        default y
 
 config SSB_DRIVER_EXTIF
diff --git a/drivers/ssbi/Kconfig b/drivers/ssbi/Kconfig
deleted file mode 100644 (file)
index 1ae4040..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-#
-# SSBI bus support
-#
-
-menu "Qualcomm MSM SSBI bus support"
-
-config SSBI
-       tristate "Qualcomm Single-wire Serial Bus Interface (SSBI)"
-       help
-         If you say yes to this option, support will be included for the
-         built-in SSBI interface on Qualcomm MSM family processors.
-
-         This is required for communicating with Qualcomm PMICs and
-         other devices that have the SSBI interface.
-
-endmenu
diff --git a/drivers/ssbi/Makefile b/drivers/ssbi/Makefile
deleted file mode 100644 (file)
index 38fb70c..0000000
+++ /dev/null
@@ -1 +0,0 @@
-obj-$(CONFIG_SSBI) += ssbi.o
index f64b662..3227ebe 100644 (file)
@@ -120,8 +120,6 @@ source "drivers/staging/gdm72xx/Kconfig"
 
 source "drivers/staging/csr/Kconfig"
 
-source "drivers/staging/ti-soc-thermal/Kconfig"
-
 source "drivers/staging/silicom/Kconfig"
 
 source "drivers/staging/ced1401/Kconfig"
index 1fb58a1..4d79ebe 100644 (file)
@@ -53,7 +53,6 @@ obj-$(CONFIG_ANDROID)         += android/
 obj-$(CONFIG_USB_WPAN_HCD)     += ozwpan/
 obj-$(CONFIG_WIMAX_GDM72XX)    += gdm72xx/
 obj-$(CONFIG_CSR_WIFI)         += csr/
-obj-$(CONFIG_TI_SOC_THERMAL)   += ti-soc-thermal/
 obj-$(CONFIG_NET_VENDOR_SILICOM)       += silicom/
 obj-$(CONFIG_CED1401)          += ced1401/
 obj-$(CONFIG_DRM_IMX)          += imx-drm/
index 4e1cd5e..ff92f34 100644 (file)
@@ -2446,9 +2446,9 @@ free_ports:
  * last peer for a given fw_card triggering the destruction of the same
  * fw_serial for the same fw_card.
  */
-static int fwserial_probe(struct device *dev)
+static int fwserial_probe(struct fw_unit *unit,
+                         const struct ieee1394_device_id *id)
 {
-       struct fw_unit *unit = fw_unit(dev);
        struct fw_serial *serial;
        int err;
 
@@ -2470,9 +2470,9 @@ static int fwserial_probe(struct device *dev)
  * specific fw_card). If this is the last peer being removed, then trigger
  * the destruction of the underlying TTYs.
  */
-static int fwserial_remove(struct device *dev)
+static void fwserial_remove(struct fw_unit *unit)
 {
-       struct fwtty_peer *peer = dev_get_drvdata(dev);
+       struct fwtty_peer *peer = dev_get_drvdata(&unit->device);
        struct fw_serial *serial = peer->serial;
        int i;
 
@@ -2492,8 +2492,6 @@ static int fwserial_remove(struct device *dev)
                kref_put(&serial->kref, fwserial_destroy);
        }
        mutex_unlock(&fwserial_list_mutex);
-
-       return 0;
 }
 
 /**
@@ -2538,10 +2536,10 @@ static struct fw_driver fwserial_driver = {
                .owner  = THIS_MODULE,
                .name   = KBUILD_MODNAME,
                .bus    = &fw_bus_type,
-               .probe  = fwserial_probe,
-               .remove = fwserial_remove,
        },
+       .probe    = fwserial_probe,
        .update   = fwserial_update,
+       .remove   = fwserial_remove,
        .id_table = fwserial_id_table,
 };
 
index 05673ed..766a071 100644 (file)
@@ -1751,10 +1751,10 @@ static const struct media_entity_operations ipipe_media_ops = {
  */
 void vpfe_ipipe_unregister_entities(struct vpfe_ipipe_device *vpfe_ipipe)
 {
-       /* cleanup entity */
-       media_entity_cleanup(&vpfe_ipipe->subdev.entity);
        /* unregister subdev */
        v4l2_device_unregister_subdev(&vpfe_ipipe->subdev);
+       /* cleanup entity */
+       media_entity_cleanup(&vpfe_ipipe->subdev.entity);
 }
 
 /*
index b2f4ef8..59540cd 100644 (file)
@@ -947,10 +947,10 @@ void vpfe_ipipeif_unregister_entities(struct vpfe_ipipeif_device *ipipeif)
        /* unregister video device */
        vpfe_video_unregister(&ipipeif->video_in);
 
-       /* cleanup entity */
-       media_entity_cleanup(&ipipeif->subdev.entity);
        /* unregister subdev */
        v4l2_device_unregister_subdev(&ipipeif->subdev);
+       /* cleanup entity */
+       media_entity_cleanup(&ipipeif->subdev.entity);
 }
 
 int
index 5829360..ff48fce 100644 (file)
@@ -1750,10 +1750,10 @@ static const struct media_entity_operations isif_media_ops = {
 void vpfe_isif_unregister_entities(struct vpfe_isif_device *isif)
 {
        vpfe_video_unregister(&isif->video_out);
-       /* cleanup entity */
-       media_entity_cleanup(&isif->subdev.entity);
        /* unregister subdev */
        v4l2_device_unregister_subdev(&isif->subdev);
+       /* cleanup entity */
+       media_entity_cleanup(&isif->subdev.entity);
 }
 
 static void isif_restore_defaults(struct vpfe_isif_device *isif)
index 126f84c..8e13bd4 100644 (file)
@@ -1777,14 +1777,14 @@ void vpfe_resizer_unregister_entities(struct vpfe_resizer_device *vpfe_rsz)
        vpfe_video_unregister(&vpfe_rsz->resizer_a.video_out);
        vpfe_video_unregister(&vpfe_rsz->resizer_b.video_out);
 
-       /* cleanup entity */
-       media_entity_cleanup(&vpfe_rsz->crop_resizer.subdev.entity);
-       media_entity_cleanup(&vpfe_rsz->resizer_a.subdev.entity);
-       media_entity_cleanup(&vpfe_rsz->resizer_b.subdev.entity);
        /* unregister subdev */
        v4l2_device_unregister_subdev(&vpfe_rsz->crop_resizer.subdev);
        v4l2_device_unregister_subdev(&vpfe_rsz->resizer_a.subdev);
        v4l2_device_unregister_subdev(&vpfe_rsz->resizer_b.subdev);
+       /* cleanup entity */
+       media_entity_cleanup(&vpfe_rsz->crop_resizer.subdev.entity);
+       media_entity_cleanup(&vpfe_rsz->resizer_a.subdev.entity);
+       media_entity_cleanup(&vpfe_rsz->resizer_b.subdev.entity);
 }
 
 /*
@@ -1865,12 +1865,12 @@ out_create_link:
        vpfe_video_unregister(&resizer->resizer_b.video_out);
 out_video_out2_register:
        vpfe_video_unregister(&resizer->resizer_a.video_out);
-       media_entity_cleanup(&resizer->crop_resizer.subdev.entity);
-       media_entity_cleanup(&resizer->resizer_a.subdev.entity);
-       media_entity_cleanup(&resizer->resizer_b.subdev.entity);
        v4l2_device_unregister_subdev(&resizer->crop_resizer.subdev);
        v4l2_device_unregister_subdev(&resizer->resizer_a.subdev);
        v4l2_device_unregister_subdev(&resizer->resizer_b.subdev);
+       media_entity_cleanup(&resizer->crop_resizer.subdev.entity);
+       media_entity_cleanup(&resizer->resizer_a.subdev.entity);
+       media_entity_cleanup(&resizer->resizer_b.subdev.entity);
        return ret;
 }
 
index ba913f1..24d98a6 100644 (file)
@@ -39,7 +39,7 @@ static struct media_entity *vpfe_get_input_entity
        struct vpfe_device *vpfe_dev = video->vpfe_dev;
        struct media_pad *remote;
 
-       remote = media_entity_remote_source(&vpfe_dev->vpfe_isif.pads[0]);
+       remote = media_entity_remote_pad(&vpfe_dev->vpfe_isif.pads[0]);
        if (remote == NULL) {
                pr_err("Invalid media connection to isif/ccdc\n");
                return NULL;
@@ -56,7 +56,7 @@ static int vpfe_update_current_ext_subdev(struct vpfe_video_device *video)
        struct media_pad *remote;
        int i;
 
-       remote = media_entity_remote_source(&vpfe_dev->vpfe_isif.pads[0]);
+       remote = media_entity_remote_pad(&vpfe_dev->vpfe_isif.pads[0]);
        if (remote == NULL) {
                pr_err("Invalid media connection to isif/ccdc\n");
                return -EINVAL;
@@ -89,7 +89,7 @@ static int vpfe_update_current_ext_subdev(struct vpfe_video_device *video)
 static struct v4l2_subdev *
 vpfe_video_remote_subdev(struct vpfe_video_device *video, u32 *pad)
 {
-       struct media_pad *remote = media_entity_remote_source(&video->pad);
+       struct media_pad *remote = media_entity_remote_pad(&video->pad);
 
        if (remote == NULL || remote->entity->type != MEDIA_ENT_T_V4L2_SUBDEV)
                return NULL;
@@ -114,7 +114,7 @@ __vpfe_video_get_format(struct vpfe_video_device *video,
                return -EINVAL;
 
        fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
-       remote = media_entity_remote_source(&video->pad);
+       remote = media_entity_remote_pad(&video->pad);
        fmt.pad = remote->index;
 
        ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt);
@@ -245,7 +245,7 @@ static int vpfe_video_validate_pipeline(struct vpfe_pipeline *pipe)
                        return -EPIPE;
 
                /* Retrieve the source format */
-               pad = media_entity_remote_source(pad);
+               pad = media_entity_remote_pad(pad);
                if (pad == NULL ||
                        pad->entity->type != MEDIA_ENT_T_V4L2_SUBDEV)
                        break;
@@ -667,7 +667,7 @@ static int vpfe_enum_fmt(struct file *file, void  *priv,
                return -EINVAL;
        }
        /* get the remote pad */
-       remote = media_entity_remote_source(&video->pad);
+       remote = media_entity_remote_pad(&video->pad);
        if (remote == NULL) {
                v4l2_err(&vpfe_dev->v4l2_dev,
                         "invalid remote pad for video node\n");
@@ -1614,7 +1614,7 @@ int vpfe_video_register(struct vpfe_video_device *video,
 void vpfe_video_unregister(struct vpfe_video_device *video)
 {
        if (video_is_registered(&video->video_dev)) {
-               media_entity_cleanup(&video->video_dev.entity);
                video_unregister_device(&video->video_dev);
+               media_entity_cleanup(&video->video_dev.entity);
        }
 }
index c32e0ac..90d6ac4 100644 (file)
@@ -829,7 +829,6 @@ static struct video_device dt3155_vdev = {
        .minor = -1,
        .release = video_device_release,
        .tvnorms = DT3155_CURRENT_NORM,
-       .current_norm = DT3155_CURRENT_NORM,
 };
 
 /* same as in drivers/base/dma-coherent.c */
index 50066e0..46ed832 100644 (file)
@@ -1124,7 +1124,7 @@ static int go7007_usb_probe(struct usb_interface *intf,
        case GO7007_BOARDID_LIFEVIEW_LR192:
                printk(KERN_ERR "go7007-usb: The Lifeview TV Walker Ultra "
                                "is not supported.  Sorry!\n");
-               return 0;
+               return -ENODEV;
                name = "Lifeview TV Walker Ultra";
                board = &board_lifeview_lr192;
                break;
@@ -1140,7 +1140,7 @@ static int go7007_usb_probe(struct usb_interface *intf,
        default:
                printk(KERN_ERR "go7007-usb: unknown board ID %d!\n",
                                (unsigned int)id->driver_info);
-               return 0;
+               return -ENODEV;
        }
 
        go = go7007_alloc(&board->main_info, &intf->dev);
index 0a2c45d..4afa7da 100644 (file)
@@ -911,8 +911,8 @@ static int imon_probe(struct usb_interface *interface,
        if (retval) {
                dev_err(dev, "%s: usb_submit_urb failed for intf0 (%d)\n",
                        __func__, retval);
-               mutex_unlock(&context->ctx_lock);
-               goto exit;
+               alloc_status = 8;
+               goto unlock;
        }
 
        usb_set_intfdata(interface, context);
@@ -937,6 +937,8 @@ unlock:
 alloc_status_switch:
 
        switch (alloc_status) {
+       case 8:
+               lirc_unregister_driver(driver->minor);
        case 7:
                usb_free_urb(tx_urb);
        case 6:
@@ -959,7 +961,6 @@ alloc_status_switch:
                retval = 0;
        }
 
-exit:
        mutex_unlock(&driver_lock);
 
        return retval;
index ad00e2b..af65ea6 100644 (file)
@@ -513,62 +513,82 @@ static int tw2815_setup(struct solo_dev *solo_dev, u8 dev_addr)
 #define FIRST_ACTIVE_LINE      0x0008
 #define LAST_ACTIVE_LINE       0x0102
 
-static void saa7128_setup(struct solo_dev *solo_dev)
+static void saa712x_write_regs(struct solo_dev *dev, const uint8_t *vals,
+               int start, int n)
 {
-       int i;
-       unsigned char regs[128] = {
-               0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00,
-               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       for (;start < n; start++, vals++) {
+               /* Skip read-only registers */
+               switch (start) {
+               /* case 0x00 ... 0x25: */
+               case 0x2e ... 0x37:
+               case 0x60:
+               case 0x7d:
+                       continue;
+               }
+               solo_i2c_writebyte(dev, SOLO_I2C_SAA, 0x46, start, *vals);
+       }
+}
+
+#define SAA712x_reg7c (0x80 | ((LAST_ACTIVE_LINE & 0x100) >> 2) \
+               | ((FIRST_ACTIVE_LINE & 0x100) >> 4))
+
+static void saa712x_setup(struct solo_dev *dev)
+{
+       const int reg_start = 0x26;
+       const uint8_t saa7128_regs_ntsc[] = {
+       /* :0x26 */
+               0x0d, 0x00,
+       /* :0x28 */
+               0x59, 0x1d, 0x75, 0x3f, 0x06, 0x3f,
+       /* :0x2e XXX: read-only */
+               0x00, 0x00,
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-               0x1C, 0x2B, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00,
-               0x59, 0x1d, 0x75, 0x3f, 0x06, 0x3f, 0x00, 0x00,
-               0x1c, 0x33, 0x00, 0x3f, 0x00, 0x00, 0x3f, 0x00,
+       /* :0x38 */
                0x1a, 0x1a, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00,
+       /* :0x40 */
                0x00, 0x00, 0x00, 0x68, 0x10, 0x97, 0x4c, 0x18,
                0x9b, 0x93, 0x9f, 0xff, 0x7c, 0x34, 0x3f, 0x3f,
+       /* :0x50 */
                0x3f, 0x83, 0x83, 0x80, 0x0d, 0x0f, 0xc3, 0x06,
                0x02, 0x80, 0x71, 0x77, 0xa7, 0x67, 0x66, 0x2e,
+       /* :0x60 */
                0x7b, 0x11, 0x4f, 0x1f, 0x7c, 0xf0, 0x21, 0x77,
-               0x41, 0x88, 0x41, 0x12, 0xed, 0x10, 0x10, 0x00,
+               0x41, 0x88, 0x41, 0x52, 0xed, 0x10, 0x10, 0x00,
+       /* :0x70 */
+               0x41, 0xc3, 0x00, 0x3e, 0xb8, 0x02, 0x00, 0x00,
+               0x00, 0x00, FIRST_ACTIVE_LINE, LAST_ACTIVE_LINE & 0xff,
+               SAA712x_reg7c, 0x00, 0xff, 0xff,
+       }, saa7128_regs_pal[] = {
+       /* :0x26 */
+               0x0d, 0x00,
+       /* :0x28 */
+               0xe1, 0x1d, 0x75, 0x3f, 0x06, 0x3f,
+       /* :0x2e XXX: read-only */
+               0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       /* :0x38 */
+               0x1a, 0x1a, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00,
+       /* :0x40 */
+               0x00, 0x00, 0x00, 0x68, 0x10, 0x97, 0x4c, 0x18,
+               0x9b, 0x93, 0x9f, 0xff, 0x7c, 0x34, 0x3f, 0x3f,
+       /* :0x50 */
+               0x3f, 0x83, 0x83, 0x80, 0x0d, 0x0f, 0xc3, 0x06,
+               0x02, 0x80, 0x0f, 0x77, 0xa7, 0x67, 0x66, 0x2e,
+       /* :0x60 */
+               0x7b, 0x02, 0x35, 0xcb, 0x8a, 0x09, 0x2a, 0x77,
+               0x41, 0x88, 0x41, 0x52, 0xf1, 0x10, 0x20, 0x00,
+       /* :0x70 */
                0x41, 0xc3, 0x00, 0x3e, 0xb8, 0x02, 0x00, 0x00,
-               0x00, 0x00, 0x08, 0xff, 0x80, 0x00, 0xff, 0xff,
+               0x00, 0x00, 0x12, 0x30,
+               SAA712x_reg7c | 0x40, 0x00, 0xff, 0xff,
        };
 
-       regs[0x7A] = FIRST_ACTIVE_LINE & 0xff;
-       regs[0x7B] = LAST_ACTIVE_LINE & 0xff;
-       regs[0x7C] = ((1 << 7) |
-                       (((LAST_ACTIVE_LINE >> 8) & 1) << 6) |
-                       (((FIRST_ACTIVE_LINE >> 8) & 1) << 4));
-
-       /* PAL: XXX: We could do a second set of regs to avoid this */
-       if (solo_dev->video_type != SOLO_VO_FMT_TYPE_NTSC) {
-               regs[0x28] = 0xE1;
-
-               regs[0x5A] = 0x0F;
-               regs[0x61] = 0x02;
-               regs[0x62] = 0x35;
-               regs[0x63] = 0xCB;
-               regs[0x64] = 0x8A;
-               regs[0x65] = 0x09;
-               regs[0x66] = 0x2A;
-
-               regs[0x6C] = 0xf1;
-               regs[0x6E] = 0x20;
-
-               regs[0x7A] = 0x06 + 12;
-               regs[0x7b] = 0x24 + 12;
-               regs[0x7c] |= 1 << 6;
-       }
-
-       /* First 0x25 bytes are read-only? */
-       for (i = 0x26; i < 128; i++) {
-               if (i == 0x60 || i == 0x7D)
-                       continue;
-               solo_i2c_writebyte(solo_dev, SOLO_I2C_SAA, 0x46, i, regs[i]);
-       }
-
-       return;
+       if (dev->video_type == SOLO_VO_FMT_TYPE_PAL)
+               saa712x_write_regs(dev, saa7128_regs_pal, reg_start,
+                               sizeof(saa7128_regs_pal));
+       else
+               saa712x_write_regs(dev, saa7128_regs_ntsc, reg_start,
+                               sizeof(saa7128_regs_ntsc));
 }
 
 int solo_tw28_init(struct solo_dev *solo_dev)
@@ -609,7 +629,7 @@ int solo_tw28_init(struct solo_dev *solo_dev)
                return -EINVAL;
        }
 
-       saa7128_setup(solo_dev);
+       saa712x_setup(solo_dev);
 
        for (i = 0; i < solo_dev->tw28_cnt; i++) {
                if ((solo_dev->tw2865 & (1 << i)))
index 98e2902..a4c5896 100644 (file)
@@ -996,12 +996,11 @@ static int solo_g_parm(struct file *file, void *priv,
                       struct v4l2_streamparm *sp)
 {
        struct solo_enc_dev *solo_enc = video_drvdata(file);
-       struct solo_dev *solo_dev = solo_enc->solo_dev;
        struct v4l2_captureparm *cp = &sp->parm.capture;
 
        cp->capability = V4L2_CAP_TIMEPERFRAME;
        cp->timeperframe.numerator = solo_enc->interval;
-       cp->timeperframe.denominator = solo_dev->fps;
+       cp->timeperframe.denominator = solo_enc->solo_dev->fps;
        cp->capturemode = 0;
        /* XXX: Shouldn't we be able to get/set this from videobuf? */
        cp->readbuffers = 2;
@@ -1009,36 +1008,29 @@ static int solo_g_parm(struct file *file, void *priv,
        return 0;
 }
 
+static inline int calc_interval(u8 fps, u32 n, u32 d)
+{
+       if (!n || !d)
+               return 1;
+       if (d == fps)
+               return n;
+       n *= fps;
+       return min(15U, n / d + (n % d >= (fps >> 1)));
+}
+
 static int solo_s_parm(struct file *file, void *priv,
                       struct v4l2_streamparm *sp)
 {
        struct solo_enc_dev *solo_enc = video_drvdata(file);
-       struct solo_dev *solo_dev = solo_enc->solo_dev;
-       struct v4l2_captureparm *cp = &sp->parm.capture;
+       struct v4l2_fract *t = &sp->parm.capture.timeperframe;
+       u8 fps = solo_enc->solo_dev->fps;
 
        if (vb2_is_streaming(&solo_enc->vidq))
                return -EBUSY;
 
-       if ((cp->timeperframe.numerator == 0) ||
-           (cp->timeperframe.denominator == 0)) {
-               /* reset framerate */
-               cp->timeperframe.numerator = 1;
-               cp->timeperframe.denominator = solo_dev->fps;
-       }
-
-       if (cp->timeperframe.denominator != solo_dev->fps)
-               cp->timeperframe.denominator = solo_dev->fps;
-
-       if (cp->timeperframe.numerator > 15)
-               cp->timeperframe.numerator = 15;
-
-       solo_enc->interval = cp->timeperframe.numerator;
-
-       cp->capability = V4L2_CAP_TIMEPERFRAME;
-       cp->readbuffers = 2;
-
+       solo_enc->interval = calc_interval(fps, t->numerator, t->denominator);
        solo_update_mode(solo_enc);
-       return 0;
+       return solo_g_parm(file, priv, sp);
 }
 
 static long solo_enc_default(struct file *file, void *fh,
index 9493128..6e1d5f8 100644 (file)
@@ -1,6 +1,6 @@
 config OCTEON_ETHERNET
        tristate "Cavium Networks Octeon Ethernet support"
-       depends on CPU_CAVIUM_OCTEON && NETDEVICES
+       depends on CAVIUM_OCTEON_SOC && NETDEVICES
        select PHYLIB
        select MDIO_OCTEON
        help
index d7705e5..f73da43 100644 (file)
@@ -628,25 +628,18 @@ static void __exit iscsi_target_cleanup_module(void)
 }
 
 static int iscsit_add_reject(
+       struct iscsi_conn *conn,
        u8 reason,
-       int fail_conn,
-       unsigned char *buf,
-       struct iscsi_conn *conn)
+       unsigned char *buf)
 {
        struct iscsi_cmd *cmd;
-       struct iscsi_reject *hdr;
-       int ret;
 
        cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);
        if (!cmd)
                return -1;
 
        cmd->iscsi_opcode = ISCSI_OP_REJECT;
-       if (fail_conn)
-               cmd->cmd_flags |= ICF_REJECT_FAIL_CONN;
-
-       hdr     = (struct iscsi_reject *) cmd->pdu;
-       hdr->reason = reason;
+       cmd->reject_reason = reason;
 
        cmd->buf_ptr = kmemdup(buf, ISCSI_HDR_LEN, GFP_KERNEL);
        if (!cmd->buf_ptr) {
@@ -662,23 +655,16 @@ static int iscsit_add_reject(
        cmd->i_state = ISTATE_SEND_REJECT;
        iscsit_add_cmd_to_response_queue(cmd, conn, cmd->i_state);
 
-       ret = wait_for_completion_interruptible(&cmd->reject_comp);
-       if (ret != 0)
-               return -1;
-
-       return (!fail_conn) ? 0 : -1;
+       return -1;
 }
 
-int iscsit_add_reject_from_cmd(
+static int iscsit_add_reject_from_cmd(
+       struct iscsi_cmd *cmd,
        u8 reason,
-       int fail_conn,
-       int add_to_conn,
-       unsigned char *buf,
-       struct iscsi_cmd *cmd)
+       bool add_to_conn,
+       unsigned char *buf)
 {
        struct iscsi_conn *conn;
-       struct iscsi_reject *hdr;
-       int ret;
 
        if (!cmd->conn) {
                pr_err("cmd->conn is NULL for ITT: 0x%08x\n",
@@ -688,11 +674,7 @@ int iscsit_add_reject_from_cmd(
        conn = cmd->conn;
 
        cmd->iscsi_opcode = ISCSI_OP_REJECT;
-       if (fail_conn)
-               cmd->cmd_flags |= ICF_REJECT_FAIL_CONN;
-
-       hdr     = (struct iscsi_reject *) cmd->pdu;
-       hdr->reason = reason;
+       cmd->reject_reason = reason;
 
        cmd->buf_ptr = kmemdup(buf, ISCSI_HDR_LEN, GFP_KERNEL);
        if (!cmd->buf_ptr) {
@@ -709,8 +691,6 @@ int iscsit_add_reject_from_cmd(
 
        cmd->i_state = ISTATE_SEND_REJECT;
        iscsit_add_cmd_to_response_queue(cmd, conn, cmd->i_state);
-
-       ret = wait_for_completion_interruptible(&cmd->reject_comp);
        /*
         * Perform the kref_put now if se_cmd has already been setup by
         * scsit_setup_scsi_cmd()
@@ -719,12 +699,19 @@ int iscsit_add_reject_from_cmd(
                pr_debug("iscsi reject: calling target_put_sess_cmd >>>>>>\n");
                target_put_sess_cmd(conn->sess->se_sess, &cmd->se_cmd);
        }
-       if (ret != 0)
-               return -1;
+       return -1;
+}
 
-       return (!fail_conn) ? 0 : -1;
+static int iscsit_add_reject_cmd(struct iscsi_cmd *cmd, u8 reason,
+                                unsigned char *buf)
+{
+       return iscsit_add_reject_from_cmd(cmd, reason, true, buf);
+}
+
+int iscsit_reject_cmd(struct iscsi_cmd *cmd, u8 reason, unsigned char *buf)
+{
+       return iscsit_add_reject_from_cmd(cmd, reason, false, buf);
 }
-EXPORT_SYMBOL(iscsit_add_reject_from_cmd);
 
 /*
  * Map some portion of the allocated scatterlist to an iovec, suitable for
@@ -844,8 +831,8 @@ int iscsit_setup_scsi_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
            !(hdr->flags & ISCSI_FLAG_CMD_FINAL)) {
                pr_err("ISCSI_FLAG_CMD_WRITE & ISCSI_FLAG_CMD_FINAL"
                                " not set. Bad iSCSI Initiator.\n");
-               return iscsit_add_reject_from_cmd(ISCSI_REASON_BOOKMARK_INVALID,
-                               1, 1, buf, cmd);
+               return iscsit_add_reject_cmd(cmd,
+                                            ISCSI_REASON_BOOKMARK_INVALID, buf);
        }
 
        if (((hdr->flags & ISCSI_FLAG_CMD_READ) ||
@@ -865,8 +852,8 @@ int iscsit_setup_scsi_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
                pr_err("ISCSI_FLAG_CMD_READ or ISCSI_FLAG_CMD_WRITE"
                        " set when Expected Data Transfer Length is 0 for"
                        " CDB: 0x%02x. Bad iSCSI Initiator.\n", hdr->cdb[0]);
-               return iscsit_add_reject_from_cmd(ISCSI_REASON_BOOKMARK_INVALID,
-                               1, 1, buf, cmd);
+               return iscsit_add_reject_cmd(cmd,
+                                            ISCSI_REASON_BOOKMARK_INVALID, buf);
        }
 done:
 
@@ -875,62 +862,62 @@ done:
                pr_err("ISCSI_FLAG_CMD_READ and/or ISCSI_FLAG_CMD_WRITE"
                        " MUST be set if Expected Data Transfer Length is not 0."
                        " Bad iSCSI Initiator\n");
-               return iscsit_add_reject_from_cmd(ISCSI_REASON_BOOKMARK_INVALID,
-                               1, 1, buf, cmd);
+               return iscsit_add_reject_cmd(cmd,
+                                            ISCSI_REASON_BOOKMARK_INVALID, buf);
        }
 
        if ((hdr->flags & ISCSI_FLAG_CMD_READ) &&
            (hdr->flags & ISCSI_FLAG_CMD_WRITE)) {
                pr_err("Bidirectional operations not supported!\n");
-               return iscsit_add_reject_from_cmd(ISCSI_REASON_BOOKMARK_INVALID,
-                               1, 1, buf, cmd);
+               return iscsit_add_reject_cmd(cmd,
+                                            ISCSI_REASON_BOOKMARK_INVALID, buf);
        }
 
        if (hdr->opcode & ISCSI_OP_IMMEDIATE) {
                pr_err("Illegally set Immediate Bit in iSCSI Initiator"
                                " Scsi Command PDU.\n");
-               return iscsit_add_reject_from_cmd(ISCSI_REASON_BOOKMARK_INVALID,
-                               1, 1, buf, cmd);
+               return iscsit_add_reject_cmd(cmd,
+                                            ISCSI_REASON_BOOKMARK_INVALID, buf);
        }
 
        if (payload_length && !conn->sess->sess_ops->ImmediateData) {
                pr_err("ImmediateData=No but DataSegmentLength=%u,"
                        " protocol error.\n", payload_length);
-               return iscsit_add_reject_from_cmd(ISCSI_REASON_PROTOCOL_ERROR,
-                               1, 1, buf, cmd);
+               return iscsit_add_reject_cmd(cmd,
+                                            ISCSI_REASON_PROTOCOL_ERROR, buf);
        }
 
-       if ((be32_to_cpu(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"
                        " bit is not set protocol error\n");
-               return iscsit_add_reject_from_cmd(ISCSI_REASON_PROTOCOL_ERROR,
-                               1, 1, buf, cmd);
+               return iscsit_add_reject_cmd(cmd,
+                                            ISCSI_REASON_PROTOCOL_ERROR, buf);
        }
 
        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);
-               return iscsit_add_reject_from_cmd(ISCSI_REASON_PROTOCOL_ERROR,
-                               1, 1, buf, cmd);
+               return iscsit_add_reject_cmd(cmd,
+                                            ISCSI_REASON_PROTOCOL_ERROR, buf);
        }
 
        if (payload_length > conn->conn_ops->MaxXmitDataSegmentLength) {
                pr_err("DataSegmentLength: %u is greater than"
                        " MaxXmitDataSegmentLength: %u, protocol error.\n",
                        payload_length, conn->conn_ops->MaxXmitDataSegmentLength);
-               return iscsit_add_reject_from_cmd(ISCSI_REASON_PROTOCOL_ERROR,
-                               1, 1, buf, cmd);
+               return iscsit_add_reject_cmd(cmd,
+                                            ISCSI_REASON_PROTOCOL_ERROR, buf);
        }
 
        if (payload_length > conn->sess->sess_ops->FirstBurstLength) {
                pr_err("DataSegmentLength: %u is greater than"
                        " FirstBurstLength: %u, protocol error.\n",
                        payload_length, conn->sess->sess_ops->FirstBurstLength);
-               return iscsit_add_reject_from_cmd(ISCSI_REASON_BOOKMARK_INVALID,
-                               1, 1, buf, cmd);
+               return iscsit_add_reject_cmd(cmd,
+                                            ISCSI_REASON_BOOKMARK_INVALID, buf);
        }
 
        data_direction = (hdr->flags & ISCSI_FLAG_CMD_WRITE) ? DMA_TO_DEVICE :
@@ -985,9 +972,8 @@ done:
 
                dr = iscsit_allocate_datain_req();
                if (!dr)
-                       return iscsit_add_reject_from_cmd(
-                                       ISCSI_REASON_BOOKMARK_NO_RESOURCES,
-                                       1, 1, buf, cmd);
+                       return iscsit_add_reject_cmd(cmd,
+                                       ISCSI_REASON_BOOKMARK_NO_RESOURCES, buf);
 
                iscsit_attach_datain_req(cmd, dr);
        }
@@ -1015,18 +1001,16 @@ done:
        cmd->sense_reason = target_setup_cmd_from_cdb(&cmd->se_cmd, hdr->cdb);
        if (cmd->sense_reason) {
                if (cmd->sense_reason == TCM_OUT_OF_RESOURCES) {
-                       return iscsit_add_reject_from_cmd(
-                                       ISCSI_REASON_BOOKMARK_NO_RESOURCES,
-                                       1, 1, buf, cmd);
+                       return iscsit_add_reject_cmd(cmd,
+                                       ISCSI_REASON_BOOKMARK_NO_RESOURCES, buf);
                }
 
                goto attach_cmd;
        }
 
        if (iscsit_build_pdu_and_seq_lists(cmd, payload_length) < 0) {
-               return iscsit_add_reject_from_cmd(
-                       ISCSI_REASON_BOOKMARK_NO_RESOURCES,
-                       1, 1, buf, cmd);
+               return iscsit_add_reject_cmd(cmd,
+                               ISCSI_REASON_BOOKMARK_NO_RESOURCES, buf);
        }
 
 attach_cmd:
@@ -1068,17 +1052,13 @@ int iscsit_process_scsi_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
         * be acknowledged. (See below)
         */
        if (!cmd->immediate_data) {
-               cmdsn_ret = iscsit_sequence_cmd(conn, cmd, hdr->cmdsn);
-               if (cmdsn_ret == CMDSN_LOWER_THAN_EXP) {
-                       if (!cmd->sense_reason)
-                               return 0;
-
+               cmdsn_ret = iscsit_sequence_cmd(conn, cmd,
+                                       (unsigned char *)hdr, hdr->cmdsn);
+               if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER)
+                       return -1;
+               else if (cmdsn_ret == CMDSN_LOWER_THAN_EXP) {
                        target_put_sess_cmd(conn->sess->se_sess, &cmd->se_cmd);
                        return 0;
-               } else if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER) {
-                       return iscsit_add_reject_from_cmd(
-                               ISCSI_REASON_PROTOCOL_ERROR,
-                               1, 0, (unsigned char *)hdr, cmd);
                }
        }
 
@@ -1103,6 +1083,9 @@ int iscsit_process_scsi_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
         * iscsit_check_received_cmdsn() in iscsit_get_immediate_data() below.
         */
        if (cmd->sense_reason) {
+               if (cmd->reject_reason)
+                       return 0;
+
                target_put_sess_cmd(conn->sess->se_sess, &cmd->se_cmd);
                return 1;
        }
@@ -1111,10 +1094,8 @@ int iscsit_process_scsi_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
         * the backend memory allocation.
         */
        cmd->sense_reason = transport_generic_new_cmd(&cmd->se_cmd);
-       if (cmd->sense_reason) {
-               target_put_sess_cmd(conn->sess->se_sess, &cmd->se_cmd);
+       if (cmd->sense_reason)
                return 1;
-       }
 
        return 0;
 }
@@ -1124,6 +1105,7 @@ static int
 iscsit_get_immediate_data(struct iscsi_cmd *cmd, struct iscsi_scsi_req *hdr,
                          bool dump_payload)
 {
+       struct iscsi_conn *conn = cmd->conn;
        int cmdsn_ret = 0, immed_ret = IMMEDIATE_DATA_NORMAL_OPERATION;
        /*
         * Special case for Unsupported SAM WRITE Opcodes and ImmediateData=Yes.
@@ -1140,20 +1122,25 @@ after_immediate_data:
                 * DataCRC, check against ExpCmdSN/MaxCmdSN if
                 * Immediate Bit is not set.
                 */
-               cmdsn_ret = iscsit_sequence_cmd(cmd->conn, cmd, hdr->cmdsn);
+               cmdsn_ret = iscsit_sequence_cmd(cmd->conn, cmd,
+                                       (unsigned char *)hdr, hdr->cmdsn);
+               if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER) {
+                       return -1;
+               } else if (cmdsn_ret == CMDSN_LOWER_THAN_EXP) {
+                       target_put_sess_cmd(conn->sess->se_sess, &cmd->se_cmd);
+                       return 0;
+               }
 
                if (cmd->sense_reason) {
-                       if (iscsit_dump_data_payload(cmd->conn,
-                                       cmd->first_burst_len, 1) < 0)
-                               return -1;
+                       int rc;
+
+                       rc = iscsit_dump_data_payload(cmd->conn,
+                                                     cmd->first_burst_len, 1);
+                       target_put_sess_cmd(conn->sess->se_sess, &cmd->se_cmd);
+                       return rc;
                } else if (cmd->unsolicited_data)
                        iscsit_set_unsoliticed_dataout(cmd);
 
-               if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER)
-                       return iscsit_add_reject_from_cmd(
-                               ISCSI_REASON_PROTOCOL_ERROR,
-                               1, 0, (unsigned char *)hdr, cmd);
-
        } else if (immed_ret == IMMEDIATE_DATA_ERL1_CRC_FAILURE) {
                /*
                 * Immediate Data failed DataCRC and ERL>=1,
@@ -1184,15 +1171,14 @@ iscsit_handle_scsi_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
 
        rc = iscsit_setup_scsi_cmd(conn, cmd, buf);
        if (rc < 0)
-               return rc;
+               return 0;
        /*
         * Allocation iovecs needed for struct socket operations for
         * traditional iSCSI block I/O.
         */
        if (iscsit_allocate_iovecs(cmd) < 0) {
-               return iscsit_add_reject_from_cmd(
-                               ISCSI_REASON_BOOKMARK_NO_RESOURCES,
-                               1, 0, buf, cmd);
+               return iscsit_add_reject_cmd(cmd,
+                               ISCSI_REASON_BOOKMARK_NO_RESOURCES, buf);
        }
        immed_data = cmd->immediate_data;
 
@@ -1277,14 +1263,13 @@ iscsit_check_dataout_hdr(struct iscsi_conn *conn, unsigned char *buf,
        struct iscsi_data *hdr = (struct iscsi_data *)buf;
        struct iscsi_cmd *cmd = NULL;
        struct se_cmd *se_cmd;
-       unsigned long flags;
        u32 payload_length = ntoh24(hdr->dlength);
        int rc;
 
        if (!payload_length) {
                pr_err("DataOUT payload is ZERO, protocol error.\n");
-               return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1,
-                                       buf, conn);
+               return iscsit_add_reject(conn, ISCSI_REASON_PROTOCOL_ERROR,
+                                        buf);
        }
 
        /* iSCSI write */
@@ -1301,8 +1286,8 @@ iscsit_check_dataout_hdr(struct iscsi_conn *conn, unsigned char *buf,
                pr_err("DataSegmentLength: %u is greater than"
                        " MaxXmitDataSegmentLength: %u\n", payload_length,
                        conn->conn_ops->MaxXmitDataSegmentLength);
-               return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1,
-                                       buf, conn);
+               return iscsit_add_reject(conn, ISCSI_REASON_PROTOCOL_ERROR,
+                                        buf);
        }
 
        cmd = iscsit_find_cmd_from_itt_or_dump(conn, hdr->itt,
@@ -1325,8 +1310,7 @@ iscsit_check_dataout_hdr(struct iscsi_conn *conn, unsigned char *buf,
        if (cmd->data_direction != DMA_TO_DEVICE) {
                pr_err("Command ITT: 0x%08x received DataOUT for a"
                        " NON-WRITE command.\n", cmd->init_task_tag);
-               return iscsit_add_reject_from_cmd(ISCSI_REASON_PROTOCOL_ERROR,
-                               1, 0, buf, cmd);
+               return iscsit_reject_cmd(cmd, ISCSI_REASON_PROTOCOL_ERROR, buf);
        }
        se_cmd = &cmd->se_cmd;
        iscsit_mod_dataout_timer(cmd);
@@ -1335,8 +1319,7 @@ iscsit_check_dataout_hdr(struct iscsi_conn *conn, unsigned char *buf,
                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);
-               return iscsit_add_reject_from_cmd(ISCSI_REASON_BOOKMARK_INVALID,
-                               1, 0, buf, cmd);
+               return iscsit_reject_cmd(cmd, ISCSI_REASON_BOOKMARK_INVALID, buf);
        }
 
        if (cmd->unsolicited_data) {
@@ -1356,14 +1339,9 @@ iscsit_check_dataout_hdr(struct iscsi_conn *conn, unsigned char *buf,
                 */
 
                /* Something's amiss if we're not in WRITE_PENDING state... */
-               spin_lock_irqsave(&se_cmd->t_state_lock, flags);
                WARN_ON(se_cmd->t_state != TRANSPORT_WRITE_PENDING);
-               spin_unlock_irqrestore(&se_cmd->t_state_lock, flags);
-
-               spin_lock_irqsave(&se_cmd->t_state_lock, flags);
                if (!(se_cmd->se_cmd_flags & SCF_SUPPORTED_SAM_OPCODE))
                        dump_unsolicited_data = 1;
-               spin_unlock_irqrestore(&se_cmd->t_state_lock, flags);
 
                if (dump_unsolicited_data) {
                        /*
@@ -1528,7 +1506,7 @@ static int iscsit_handle_data_out(struct iscsi_conn *conn, unsigned char *buf)
 
        rc = iscsit_check_dataout_hdr(conn, buf, &cmd);
        if (rc < 0)
-               return rc;
+               return 0;
        else if (!cmd)
                return 0;
 
@@ -1541,24 +1519,16 @@ static int iscsit_handle_data_out(struct iscsi_conn *conn, unsigned char *buf)
        return iscsit_check_dataout_payload(cmd, hdr, data_crc_failed);
 }
 
-int iscsit_handle_nop_out(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
-                       unsigned char *buf)
+int iscsit_setup_nop_out(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
+                        struct iscsi_nopout *hdr)
 {
-       unsigned char *ping_data = NULL;
-       int cmdsn_ret, niov = 0, ret = 0, rx_got, rx_size;
-       u32 checksum, data_crc, padding = 0, payload_length;
-       struct iscsi_cmd *cmd_p = NULL;
-       struct kvec *iov = NULL;
-       struct iscsi_nopout *hdr;
-
-       hdr                     = (struct iscsi_nopout *) buf;
-       payload_length          = ntoh24(hdr->dlength);
+       u32 payload_length = ntoh24(hdr->dlength);
 
        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);
+               return iscsit_reject_cmd(cmd, ISCSI_REASON_PROTOCOL_ERROR,
+                                        (unsigned char *)hdr);
        }
 
        if (payload_length > conn->conn_ops->MaxXmitDataSegmentLength) {
@@ -1566,8 +1536,8 @@ int iscsit_handle_nop_out(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
                        " greater than MaxXmitDataSegmentLength: %u, protocol"
                        " error.\n", payload_length,
                        conn->conn_ops->MaxXmitDataSegmentLength);
-               return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1,
-                                       buf, conn);
+               return iscsit_reject_cmd(cmd, ISCSI_REASON_PROTOCOL_ERROR,
+                                        (unsigned char *)hdr);
        }
 
        pr_debug("Got NOPOUT Ping %s ITT: 0x%08x, TTT: 0x%08x,"
@@ -1583,11 +1553,6 @@ int iscsit_handle_nop_out(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
         * can contain ping data.
         */
        if (hdr->ttt == cpu_to_be32(0xFFFFFFFF)) {
-               if (!cmd)
-                       return iscsit_add_reject(
-                                       ISCSI_REASON_BOOKMARK_NO_RESOURCES,
-                                       1, buf, conn);
-
                cmd->iscsi_opcode       = ISCSI_OP_NOOP_OUT;
                cmd->i_state            = ISTATE_SEND_NOPIN;
                cmd->immediate_cmd      = ((hdr->opcode & ISCSI_OP_IMMEDIATE) ?
@@ -1599,8 +1564,85 @@ int iscsit_handle_nop_out(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
                cmd->data_direction     = DMA_NONE;
        }
 
+       return 0;
+}
+EXPORT_SYMBOL(iscsit_setup_nop_out);
+
+int iscsit_process_nop_out(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
+                          struct iscsi_nopout *hdr)
+{
+       struct iscsi_cmd *cmd_p = NULL;
+       int cmdsn_ret = 0;
+       /*
+        * Initiator is expecting a NopIN ping reply..
+        */
+       if (hdr->itt != RESERVED_ITT) {
+               BUG_ON(!cmd);
+
+               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, be32_to_cpu(hdr->exp_statsn));
+
+               if (hdr->opcode & ISCSI_OP_IMMEDIATE) {
+                       iscsit_add_cmd_to_response_queue(cmd, conn,
+                                                        cmd->i_state);
+                       return 0;
+               }
+
+               cmdsn_ret = iscsit_sequence_cmd(conn, cmd,
+                               (unsigned char *)hdr, hdr->cmdsn);
+                if (cmdsn_ret == CMDSN_LOWER_THAN_EXP)
+                       return 0;
+               if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER)
+                       return -1;
+
+               return 0;
+       }
+       /*
+        * This was a response to a unsolicited NOPIN ping.
+        */
+       if (hdr->ttt != cpu_to_be32(0xFFFFFFFF)) {
+               cmd_p = iscsit_find_cmd_from_ttt(conn, be32_to_cpu(hdr->ttt));
+               if (!cmd_p)
+                       return -EINVAL;
+
+               iscsit_stop_nopin_response_timer(conn);
+
+               cmd_p->i_state = ISTATE_REMOVE;
+               iscsit_add_cmd_to_immediate_queue(cmd_p, conn, cmd_p->i_state);
+
+               iscsit_start_nopin_timer(conn);
+               return 0;
+       }
+       /*
+        * Otherwise, initiator is not expecting a NOPIN is response.
+        * Just ignore for now.
+        */
+        return 0;
+}
+EXPORT_SYMBOL(iscsit_process_nop_out);
+
+static int iscsit_handle_nop_out(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
+                                unsigned char *buf)
+{
+       unsigned char *ping_data = NULL;
+       struct iscsi_nopout *hdr = (struct iscsi_nopout *)buf;
+       struct kvec *iov = NULL;
+       u32 payload_length = ntoh24(hdr->dlength);
+       int ret;
+
+       ret = iscsit_setup_nop_out(conn, cmd, hdr);
+       if (ret < 0)
+               return 0;
+       /*
+        * Handle NOP-OUT payload for traditional iSCSI sockets
+        */
        if (payload_length && hdr->ttt == cpu_to_be32(0xFFFFFFFF)) {
-               rx_size = payload_length;
+               u32 checksum, data_crc, padding = 0;
+               int niov = 0, rx_got, rx_size = payload_length;
+
                ping_data = kzalloc(payload_length + 1, GFP_KERNEL);
                if (!ping_data) {
                        pr_err("Unable to allocate memory for"
@@ -1679,76 +1721,14 @@ int iscsit_handle_nop_out(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
                pr_debug("Ping Data: \"%s\"\n", ping_data);
        }
 
-       if (hdr->itt != RESERVED_ITT) {
-               if (!cmd) {
-                       pr_err("Checking CmdSN for NOPOUT,"
-                               " but cmd is NULL!\n");
-                       return -1;
-               }
-               /*
-                * Initiator is expecting a NopIN ping reply,
-                */
-               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, be32_to_cpu(hdr->exp_statsn));
-
-               if (hdr->opcode & ISCSI_OP_IMMEDIATE) {
-                       iscsit_add_cmd_to_response_queue(cmd, conn,
-                                       cmd->i_state);
-                       return 0;
-               }
-
-               cmdsn_ret = iscsit_sequence_cmd(conn, cmd, hdr->cmdsn);
-               if (cmdsn_ret == CMDSN_LOWER_THAN_EXP) {
-                       ret = 0;
-                       goto ping_out;
-               }
-               if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER)
-                       return iscsit_add_reject_from_cmd(
-                                       ISCSI_REASON_PROTOCOL_ERROR,
-                                       1, 0, buf, cmd);
-
-               return 0;
-       }
-
-       if (hdr->ttt != cpu_to_be32(0xFFFFFFFF)) {
-               /*
-                * This was a response to a unsolicited NOPIN ping.
-                */
-               cmd_p = iscsit_find_cmd_from_ttt(conn, be32_to_cpu(hdr->ttt));
-               if (!cmd_p)
-                       return -1;
-
-               iscsit_stop_nopin_response_timer(conn);
-
-               cmd_p->i_state = ISTATE_REMOVE;
-               iscsit_add_cmd_to_immediate_queue(cmd_p, conn, cmd_p->i_state);
-               iscsit_start_nopin_timer(conn);
-       } else {
-               /*
-                * Initiator is not expecting a NOPIN is response.
-                * Just ignore for now.
-                *
-                * iSCSI v19-91 10.18
-                * "A NOP-OUT may also be used to confirm a changed
-                *  ExpStatSN if another PDU will not be available
-                *  for a long time."
-                */
-               ret = 0;
-               goto out;
-       }
-
-       return 0;
+       return iscsit_process_nop_out(conn, cmd, hdr);
 out:
        if (cmd)
                iscsit_free_cmd(cmd, false);
-ping_out:
+
        kfree(ping_data);
        return ret;
 }
-EXPORT_SYMBOL(iscsit_handle_nop_out);
 
 int
 iscsit_handle_task_mgt_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
@@ -1757,8 +1737,8 @@ iscsit_handle_task_mgt_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
        struct se_tmr_req *se_tmr;
        struct iscsi_tmr_req *tmr_req;
        struct iscsi_tm *hdr;
-       int out_of_order_cmdsn = 0;
-       int ret;
+       int out_of_order_cmdsn = 0, ret;
+       bool sess_ref = false;
        u8 function;
 
        hdr                     = (struct iscsi_tm *) buf;
@@ -1782,8 +1762,8 @@ iscsit_handle_task_mgt_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
                pr_err("Task Management Request TASK_REASSIGN not"
                        " issued as immediate command, bad iSCSI Initiator"
                                "implementation\n");
-               return iscsit_add_reject_from_cmd(ISCSI_REASON_PROTOCOL_ERROR,
-                                       1, 1, buf, cmd);
+               return iscsit_add_reject_cmd(cmd,
+                                            ISCSI_REASON_PROTOCOL_ERROR, buf);
        }
        if ((function != ISCSI_TM_FUNC_ABORT_TASK) &&
            be32_to_cpu(hdr->refcmdsn) != ISCSI_RESERVED_TAG)
@@ -1795,9 +1775,9 @@ iscsit_handle_task_mgt_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
        if (!cmd->tmr_req) {
                pr_err("Unable to allocate memory for"
                        " Task Management command!\n");
-               return iscsit_add_reject_from_cmd(
-                       ISCSI_REASON_BOOKMARK_NO_RESOURCES,
-                       1, 1, buf, cmd);
+               return iscsit_add_reject_cmd(cmd,
+                                            ISCSI_REASON_BOOKMARK_NO_RESOURCES,
+                                            buf);
        }
 
        /*
@@ -1814,6 +1794,9 @@ iscsit_handle_task_mgt_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
                                      conn->sess->se_sess, 0, DMA_NONE,
                                      MSG_SIMPLE_TAG, cmd->sense_buffer + 2);
 
+               target_get_sess_cmd(conn->sess->se_sess, &cmd->se_cmd, true);
+               sess_ref = true;
+
                switch (function) {
                case ISCSI_TM_FUNC_ABORT_TASK:
                        tcm_function = TMR_ABORT_TASK;
@@ -1839,17 +1822,15 @@ iscsit_handle_task_mgt_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
                default:
                        pr_err("Unknown iSCSI TMR Function:"
                               " 0x%02x\n", function);
-                       return iscsit_add_reject_from_cmd(
-                               ISCSI_REASON_BOOKMARK_NO_RESOURCES,
-                               1, 1, buf, cmd);
+                       return iscsit_add_reject_cmd(cmd,
+                               ISCSI_REASON_BOOKMARK_NO_RESOURCES, buf);
                }
 
                ret = core_tmr_alloc_req(&cmd->se_cmd, cmd->tmr_req,
                                         tcm_function, GFP_KERNEL);
                if (ret < 0)
-                       return iscsit_add_reject_from_cmd(
-                               ISCSI_REASON_BOOKMARK_NO_RESOURCES,
-                               1, 1, buf, cmd);
+                       return iscsit_add_reject_cmd(cmd,
+                               ISCSI_REASON_BOOKMARK_NO_RESOURCES, buf);
 
                cmd->tmr_req->se_tmr_req = cmd->se_cmd.se_tmr_req;
        }
@@ -1908,9 +1889,8 @@ iscsit_handle_task_mgt_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
                        break;
 
                if (iscsit_check_task_reassign_expdatasn(tmr_req, conn) < 0)
-                       return iscsit_add_reject_from_cmd(
-                                       ISCSI_REASON_BOOKMARK_INVALID, 1, 1,
-                                       buf, cmd);
+                       return iscsit_add_reject_cmd(cmd,
+                                       ISCSI_REASON_BOOKMARK_INVALID, buf);
                break;
        default:
                pr_err("Unknown TMR function: 0x%02x, protocol"
@@ -1928,15 +1908,13 @@ attach:
        spin_unlock_bh(&conn->cmd_lock);
 
        if (!(hdr->opcode & ISCSI_OP_IMMEDIATE)) {
-               int cmdsn_ret = iscsit_sequence_cmd(conn, cmd, hdr->cmdsn);
+               int cmdsn_ret = iscsit_sequence_cmd(conn, cmd, buf, hdr->cmdsn);
                if (cmdsn_ret == CMDSN_HIGHER_THAN_EXP)
                        out_of_order_cmdsn = 1;
                else if (cmdsn_ret == CMDSN_LOWER_THAN_EXP)
                        return 0;
                else if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER)
-                       return iscsit_add_reject_from_cmd(
-                                       ISCSI_REASON_PROTOCOL_ERROR,
-                                       1, 0, buf, cmd);
+                       return -1;
        }
        iscsit_ack_from_expstatsn(conn, be32_to_cpu(hdr->exp_statsn));
 
@@ -1956,51 +1934,135 @@ attach:
         * For connection recovery, this is also the default action for
         * TMR TASK_REASSIGN.
         */
+       if (sess_ref) {
+               pr_debug("Handle TMR, using sess_ref=true check\n");
+               target_put_sess_cmd(conn->sess->se_sess, &cmd->se_cmd);
+       }
+
        iscsit_add_cmd_to_response_queue(cmd, conn, cmd->i_state);
        return 0;
 }
 EXPORT_SYMBOL(iscsit_handle_task_mgt_cmd);
 
 /* #warning FIXME: Support Text Command parameters besides SendTargets */
-static int iscsit_handle_text_cmd(
-       struct iscsi_conn *conn,
-       unsigned char *buf)
+int
+iscsit_setup_text_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
+                     struct iscsi_text *hdr)
 {
-       char *text_ptr, *text_in;
-       int cmdsn_ret, niov = 0, rx_got, rx_size;
-       u32 checksum = 0, data_crc = 0, payload_length;
-       u32 padding = 0, pad_bytes = 0, text_length = 0;
-       struct iscsi_cmd *cmd;
-       struct kvec iov[3];
-       struct iscsi_text *hdr;
-
-       hdr                     = (struct iscsi_text *) buf;
-       payload_length          = ntoh24(hdr->dlength);
+       u32 payload_length = ntoh24(hdr->dlength);
 
        if (payload_length > conn->conn_ops->MaxXmitDataSegmentLength) {
                pr_err("Unable to accept text parameter length: %u"
                        "greater than MaxXmitDataSegmentLength %u.\n",
                       payload_length, conn->conn_ops->MaxXmitDataSegmentLength);
-               return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1,
-                                       buf, conn);
+               return iscsit_reject_cmd(cmd, ISCSI_REASON_PROTOCOL_ERROR,
+                                        (unsigned char *)hdr);
        }
 
        pr_debug("Got Text Request: ITT: 0x%08x, CmdSN: 0x%08x,"
                " ExpStatSN: 0x%08x, Length: %u\n", hdr->itt, hdr->cmdsn,
                hdr->exp_statsn, payload_length);
 
-       rx_size = text_length = payload_length;
-       if (text_length) {
-               text_in = kzalloc(text_length, GFP_KERNEL);
+       cmd->iscsi_opcode       = ISCSI_OP_TEXT;
+       cmd->i_state            = ISTATE_SEND_TEXTRSP;
+       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             = be32_to_cpu(hdr->cmdsn);
+       cmd->exp_stat_sn        = be32_to_cpu(hdr->exp_statsn);
+       cmd->data_direction     = DMA_NONE;
+
+       return 0;
+}
+EXPORT_SYMBOL(iscsit_setup_text_cmd);
+
+int
+iscsit_process_text_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
+                       struct iscsi_text *hdr)
+{
+       unsigned char *text_in = cmd->text_in_ptr, *text_ptr;
+       int cmdsn_ret;
+
+       if (!text_in) {
+               pr_err("Unable to locate text_in buffer for sendtargets"
+                      " discovery\n");
+               goto reject;
+       }
+       if (strncmp("SendTargets", text_in, 11) != 0) {
+               pr_err("Received Text Data that is not"
+                       " SendTargets, cannot continue.\n");
+               goto reject;
+       }
+       text_ptr = strchr(text_in, '=');
+       if (!text_ptr) {
+               pr_err("No \"=\" separator found in Text Data,"
+                       "  cannot continue.\n");
+               goto reject;
+       }
+       if (!strncmp("=All", text_ptr, 4)) {
+               cmd->cmd_flags |= IFC_SENDTARGETS_ALL;
+       } else if (!strncmp("=iqn.", text_ptr, 5) ||
+                  !strncmp("=eui.", text_ptr, 5)) {
+               cmd->cmd_flags |= IFC_SENDTARGETS_SINGLE;
+       } else {
+               pr_err("Unable to locate valid SendTargets=%s value\n", text_ptr);
+               goto reject;
+       }
+
+       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, be32_to_cpu(hdr->exp_statsn));
+
+       if (!(hdr->opcode & ISCSI_OP_IMMEDIATE)) {
+               cmdsn_ret = iscsit_sequence_cmd(conn, cmd,
+                               (unsigned char *)hdr, hdr->cmdsn);
+               if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER)
+                       return -1;
+
+               return 0;
+       }
+
+       return iscsit_execute_cmd(cmd, 0);
+
+reject:
+       return iscsit_reject_cmd(cmd, ISCSI_REASON_PROTOCOL_ERROR,
+                                (unsigned char *)hdr);
+}
+EXPORT_SYMBOL(iscsit_process_text_cmd);
+
+static int
+iscsit_handle_text_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
+                      unsigned char *buf)
+{
+       struct iscsi_text *hdr = (struct iscsi_text *)buf;
+       char *text_in = NULL;
+       u32 payload_length = ntoh24(hdr->dlength);
+       int rx_size, rc;
+
+       rc = iscsit_setup_text_cmd(conn, cmd, hdr);
+       if (rc < 0)
+               return 0;
+
+       rx_size = payload_length;
+       if (payload_length) {
+               u32 checksum = 0, data_crc = 0;
+               u32 padding = 0, pad_bytes = 0;
+               int niov = 0, rx_got;
+               struct kvec iov[3];
+
+               text_in = kzalloc(payload_length, GFP_KERNEL);
                if (!text_in) {
                        pr_err("Unable to allocate memory for"
                                " incoming text parameters\n");
-                       return -1;
+                       goto reject;
                }
+               cmd->text_in_ptr = text_in;
 
                memset(iov, 0, 3 * sizeof(struct kvec));
                iov[niov].iov_base      = text_in;
-               iov[niov++].iov_len     = text_length;
+               iov[niov++].iov_len     = payload_length;
 
                padding = ((-payload_length) & 3);
                if (padding != 0) {
@@ -2017,14 +2079,12 @@ static int iscsit_handle_text_cmd(
                }
 
                rx_got = rx_data(conn, &iov[0], niov, rx_size);
-               if (rx_got != rx_size) {
-                       kfree(text_in);
-                       return -1;
-               }
+               if (rx_got != rx_size)
+                       goto reject;
 
                if (conn->conn_ops->DataDigest) {
                        iscsit_do_crypto_hash_buf(&conn->conn_rx_hash,
-                                       text_in, text_length,
+                                       text_in, payload_length,
                                        padding, (u8 *)&pad_bytes,
                                        (u8 *)&data_crc);
 
@@ -2036,8 +2096,7 @@ static int iscsit_handle_text_cmd(
                                        pr_err("Unable to recover from"
                                        " Text Data digest failure while in"
                                                " ERL=0.\n");
-                                       kfree(text_in);
-                                       return -1;
+                                       goto reject;
                                } else {
                                        /*
                                         * Silently drop this PDU and let the
@@ -2052,68 +2111,22 @@ static int iscsit_handle_text_cmd(
                        } else {
                                pr_debug("Got CRC32C DataDigest"
                                        " 0x%08x for %u bytes of text data.\n",
-                                               checksum, text_length);
+                                               checksum, payload_length);
                        }
                }
-               text_in[text_length - 1] = '\0';
+               text_in[payload_length - 1] = '\0';
                pr_debug("Successfully read %d bytes of text"
-                               " data.\n", text_length);
-
-               if (strncmp("SendTargets", text_in, 11) != 0) {
-                       pr_err("Received Text Data that is not"
-                               " SendTargets, cannot continue.\n");
-                       kfree(text_in);
-                       return -1;
-               }
-               text_ptr = strchr(text_in, '=');
-               if (!text_ptr) {
-                       pr_err("No \"=\" separator found in Text Data,"
-                               "  cannot continue.\n");
-                       kfree(text_in);
-                       return -1;
-               }
-               if (strncmp("=All", text_ptr, 4) != 0) {
-                       pr_err("Unable to locate All value for"
-                               " SendTargets key,  cannot continue.\n");
-                       kfree(text_in);
-                       return -1;
-               }
-/*#warning Support SendTargets=(iSCSI Target Name/Nothing) values. */
-               kfree(text_in);
+                               " data.\n", payload_length);
        }
 
-       cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);
-       if (!cmd)
-               return iscsit_add_reject(ISCSI_REASON_BOOKMARK_NO_RESOURCES,
-                                       1, buf, conn);
-
-       cmd->iscsi_opcode       = ISCSI_OP_TEXT;
-       cmd->i_state            = ISTATE_SEND_TEXTRSP;
-       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             = 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);
+       return iscsit_process_text_cmd(conn, cmd, hdr);
 
-       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);
-               if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER)
-                       return iscsit_add_reject_from_cmd(
-                                       ISCSI_REASON_PROTOCOL_ERROR,
-                                       1, 0, buf, cmd);
-
-               return 0;
-       }
-
-       return iscsit_execute_cmd(cmd, 0);
+reject:
+       kfree(cmd->text_in_ptr);
+       cmd->text_in_ptr = NULL;
+       return iscsit_reject_cmd(cmd, ISCSI_REASON_PROTOCOL_ERROR, buf);
 }
+EXPORT_SYMBOL(iscsit_handle_text_cmd);
 
 int iscsit_logout_closesession(struct iscsi_cmd *cmd, struct iscsi_conn *conn)
 {
@@ -2292,14 +2305,11 @@ iscsit_handle_logout_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
                if (ret < 0)
                        return ret;
        } else {
-               cmdsn_ret = iscsit_sequence_cmd(conn, cmd, hdr->cmdsn);
-               if (cmdsn_ret == CMDSN_LOWER_THAN_EXP) {
+               cmdsn_ret = iscsit_sequence_cmd(conn, cmd, buf, hdr->cmdsn);
+               if (cmdsn_ret == CMDSN_LOWER_THAN_EXP)
                        logout_remove = 0;
-               } else if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER) {
-                       return iscsit_add_reject_from_cmd(
-                               ISCSI_REASON_PROTOCOL_ERROR,
-                               1, 0, buf, cmd);
-               }
+               else if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER)
+                       return -1;
        }
 
        return logout_remove;
@@ -2323,8 +2333,8 @@ static int iscsit_handle_snack(
        if (!conn->sess->sess_ops->ErrorRecoveryLevel) {
                pr_err("Initiator sent SNACK request while in"
                        " ErrorRecoveryLevel=0.\n");
-               return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1,
-                                       buf, conn);
+               return iscsit_add_reject(conn, ISCSI_REASON_PROTOCOL_ERROR,
+                                        buf);
        }
        /*
         * SNACK_DATA and SNACK_R2T are both 0,  so check which function to
@@ -2348,13 +2358,13 @@ static int iscsit_handle_snack(
        case ISCSI_FLAG_SNACK_TYPE_RDATA:
                /* FIXME: Support R-Data SNACK */
                pr_err("R-Data SNACK Not Supported.\n");
-               return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1,
-                                       buf, conn);
+               return iscsit_add_reject(conn, ISCSI_REASON_PROTOCOL_ERROR,
+                                        buf);
        default:
                pr_err("Unknown SNACK type 0x%02x, protocol"
                        " error.\n", hdr->flags & 0x0f);
-               return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1,
-                                       buf, conn);
+               return iscsit_add_reject(conn, ISCSI_REASON_PROTOCOL_ERROR,
+                                        buf);
        }
 
        return 0;
@@ -2426,14 +2436,14 @@ static int iscsit_handle_immediate_data(
                                pr_err("Unable to recover from"
                                        " Immediate Data digest failure while"
                                        " in ERL=0.\n");
-                               iscsit_add_reject_from_cmd(
+                               iscsit_reject_cmd(cmd,
                                                ISCSI_REASON_DATA_DIGEST_ERROR,
-                                               1, 0, (unsigned char *)hdr, cmd);
+                                               (unsigned char *)hdr);
                                return IMMEDIATE_DATA_CANNOT_RECOVER;
                        } else {
-                               iscsit_add_reject_from_cmd(
+                               iscsit_reject_cmd(cmd,
                                                ISCSI_REASON_DATA_DIGEST_ERROR,
-                                               0, 0, (unsigned char *)hdr, cmd);
+                                               (unsigned char *)hdr);
                                return IMMEDIATE_DATA_ERL1_CRC_FAILURE;
                        }
                } else {
@@ -3276,8 +3286,6 @@ static u8 iscsit_convert_tcm_tmr_rsp(struct se_tmr_req *se_tmr)
                return ISCSI_TMF_RSP_NO_LUN;
        case TMR_TASK_MGMT_FUNCTION_NOT_SUPPORTED:
                return ISCSI_TMF_RSP_NOT_SUPPORTED;
-       case TMR_FUNCTION_AUTHORIZATION_FAILED:
-               return ISCSI_TMF_RSP_AUTH_FAILED;
        case TMR_FUNCTION_REJECTED:
        default:
                return ISCSI_TMF_RSP_REJECTED;
@@ -3372,6 +3380,7 @@ static int iscsit_build_sendtargets_response(struct iscsi_cmd *cmd)
        struct iscsi_tpg_np *tpg_np;
        int buffer_len, end_of_buf = 0, len = 0, payload_len = 0;
        unsigned char buf[ISCSI_IQN_LEN+12]; /* iqn + "TargetName=" + \0 */
+       unsigned char *text_in = cmd->text_in_ptr, *text_ptr = NULL;
 
        buffer_len = max(conn->conn_ops->MaxRecvDataSegmentLength,
                         SENDTARGETS_BUF_LIMIT);
@@ -3382,9 +3391,31 @@ static int iscsit_build_sendtargets_response(struct iscsi_cmd *cmd)
                                " response.\n");
                return -ENOMEM;
        }
+       /*
+        * Locate pointer to iqn./eui. string for IFC_SENDTARGETS_SINGLE
+        * explicit case..
+        */
+       if (cmd->cmd_flags & IFC_SENDTARGETS_SINGLE) {
+               text_ptr = strchr(text_in, '=');
+               if (!text_ptr) {
+                       pr_err("Unable to locate '=' string in text_in:"
+                              " %s\n", text_in);
+                       kfree(payload);
+                       return -EINVAL;
+               }
+               /*
+                * Skip over '=' character..
+                */
+               text_ptr += 1;
+       }
 
        spin_lock(&tiqn_lock);
        list_for_each_entry(tiqn, &g_tiqn_list, tiqn_list) {
+               if ((cmd->cmd_flags & IFC_SENDTARGETS_SINGLE) &&
+                    strcmp(tiqn->tiqn, text_ptr)) {
+                       continue;
+               }
+
                len = sprintf(buf, "TargetName=%s", tiqn->tiqn);
                len += 1;
 
@@ -3438,6 +3469,9 @@ static int iscsit_build_sendtargets_response(struct iscsi_cmd *cmd)
 eob:
                if (end_of_buf)
                        break;
+
+               if (cmd->cmd_flags & IFC_SENDTARGETS_SINGLE)
+                       break;
        }
        spin_unlock(&tiqn_lock);
 
@@ -3446,52 +3480,62 @@ eob:
        return payload_len;
 }
 
-/*
- *     FIXME: Add support for F_BIT and C_BIT when the length is longer than
- *     MaxRecvDataSegmentLength.
- */
-static int iscsit_send_text_rsp(
-       struct iscsi_cmd *cmd,
-       struct iscsi_conn *conn)
+int
+iscsit_build_text_rsp(struct iscsi_cmd *cmd, struct iscsi_conn *conn,
+                     struct iscsi_text_rsp *hdr)
 {
-       struct iscsi_text_rsp *hdr;
-       struct kvec *iov;
-       u32 padding = 0, tx_size = 0;
-       int text_length, iov_count = 0;
+       int text_length, padding;
 
        text_length = iscsit_build_sendtargets_response(cmd);
        if (text_length < 0)
                return text_length;
 
+       hdr->opcode = ISCSI_OP_TEXT_RSP;
+       hdr->flags |= ISCSI_FLAG_CMD_FINAL;
        padding = ((-text_length) & 3);
-       if (padding != 0) {
-               memset(cmd->buf_ptr + text_length, 0, padding);
-               pr_debug("Attaching %u additional bytes for"
-                       " padding.\n", padding);
-       }
-
-       hdr                     = (struct iscsi_text_rsp *) cmd->pdu;
-       memset(hdr, 0, ISCSI_HDR_LEN);
-       hdr->opcode             = ISCSI_OP_TEXT_RSP;
-       hdr->flags              |= ISCSI_FLAG_CMD_FINAL;
        hton24(hdr->dlength, text_length);
-       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);
+       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);
 
        iscsit_increment_maxcmdsn(cmd, conn->sess);
-       hdr->exp_cmdsn          = cpu_to_be32(conn->sess->exp_cmd_sn);
-       hdr->max_cmdsn          = cpu_to_be32(conn->sess->max_cmd_sn);
+       hdr->exp_cmdsn = cpu_to_be32(conn->sess->exp_cmd_sn);
+       hdr->max_cmdsn = cpu_to_be32(conn->sess->max_cmd_sn);
 
-       iov = &cmd->iov_misc[0];
+       pr_debug("Built Text Response: ITT: 0x%08x, StatSN: 0x%08x,"
+               " Length: %u, CID: %hu\n", cmd->init_task_tag, cmd->stat_sn,
+               text_length, conn->cid);
+
+       return text_length + padding;
+}
+EXPORT_SYMBOL(iscsit_build_text_rsp);
 
+/*
+ *     FIXME: Add support for F_BIT and C_BIT when the length is longer than
+ *     MaxRecvDataSegmentLength.
+ */
+static int iscsit_send_text_rsp(
+       struct iscsi_cmd *cmd,
+       struct iscsi_conn *conn)
+{
+       struct iscsi_text_rsp *hdr = (struct iscsi_text_rsp *)cmd->pdu;
+       struct kvec *iov;
+       u32 tx_size = 0;
+       int text_length, iov_count = 0, rc;
+
+       rc = iscsit_build_text_rsp(cmd, conn, hdr);
+       if (rc < 0)
+               return rc;
+
+       text_length = rc;
+       iov = &cmd->iov_misc[0];
        iov[iov_count].iov_base = cmd->pdu;
        iov[iov_count++].iov_len = ISCSI_HDR_LEN;
        iov[iov_count].iov_base = cmd->buf_ptr;
-       iov[iov_count++].iov_len = text_length + padding;
+       iov[iov_count++].iov_len = text_length;
 
-       tx_size += (ISCSI_HDR_LEN + text_length + padding);
+       tx_size += (ISCSI_HDR_LEN + text_length);
 
        if (conn->conn_ops->HeaderDigest) {
                u32 *header_digest = (u32 *)&cmd->pdu[ISCSI_HDR_LEN];
@@ -3507,7 +3551,7 @@ static int iscsit_send_text_rsp(
 
        if (conn->conn_ops->DataDigest) {
                iscsit_do_crypto_hash_buf(&conn->conn_tx_hash,
-                               cmd->buf_ptr, (text_length + padding),
+                               cmd->buf_ptr, text_length,
                                0, NULL, (u8 *)&cmd->data_crc);
 
                iov[iov_count].iov_base = &cmd->data_crc;
@@ -3515,16 +3559,13 @@ static int iscsit_send_text_rsp(
                tx_size += ISCSI_CRC_LEN;
 
                pr_debug("Attaching DataDigest for %u bytes of text"
-                       " data, CRC 0x%08x\n", (text_length + padding),
+                       " data, CRC 0x%08x\n", text_length,
                        cmd->data_crc);
        }
 
        cmd->iov_misc_count = iov_count;
        cmd->tx_size = tx_size;
 
-       pr_debug("Built Text Response: ITT: 0x%08x, StatSN: 0x%08x,"
-               " Length: %u, CID: %hu\n", cmd->init_task_tag, cmd->stat_sn,
-                       text_length, conn->cid);
        return 0;
 }
 
@@ -3533,6 +3574,7 @@ iscsit_build_reject(struct iscsi_cmd *cmd, struct iscsi_conn *conn,
                    struct iscsi_reject *hdr)
 {
        hdr->opcode             = ISCSI_OP_REJECT;
+       hdr->reason             = cmd->reject_reason;
        hdr->flags              |= ISCSI_FLAG_CMD_FINAL;
        hton24(hdr->dlength, ISCSI_HDR_LEN);
        hdr->ffffffff           = cpu_to_be32(0xffffffff);
@@ -3806,18 +3848,11 @@ check_rsp_state:
        case ISTATE_SEND_STATUS_RECOVERY:
        case ISTATE_SEND_TEXTRSP:
        case ISTATE_SEND_TASKMGTRSP:
+       case ISTATE_SEND_REJECT:
                spin_lock_bh(&cmd->istate_lock);
                cmd->i_state = ISTATE_SENT_STATUS;
                spin_unlock_bh(&cmd->istate_lock);
                break;
-       case ISTATE_SEND_REJECT:
-               if (cmd->cmd_flags & ICF_REJECT_FAIL_CONN) {
-                       cmd->cmd_flags &= ~ICF_REJECT_FAIL_CONN;
-                       complete(&cmd->reject_comp);
-                       goto err;
-               }
-               complete(&cmd->reject_comp);
-               break;
        default:
                pr_err("Unknown Opcode: 0x%02x ITT:"
                       " 0x%08x, i_state: %d on CID: %hu\n",
@@ -3922,8 +3957,7 @@ static int iscsi_target_rx_opcode(struct iscsi_conn *conn, unsigned char *buf)
        case ISCSI_OP_SCSI_CMD:
                cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);
                if (!cmd)
-                       return iscsit_add_reject(ISCSI_REASON_BOOKMARK_NO_RESOURCES,
-                                               1, buf, conn);
+                       goto reject;
 
                ret = iscsit_handle_scsi_cmd(conn, cmd, buf);
                break;
@@ -3935,27 +3969,28 @@ static int iscsi_target_rx_opcode(struct iscsi_conn *conn, unsigned char *buf)
                if (hdr->ttt == cpu_to_be32(0xFFFFFFFF)) {
                        cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);
                        if (!cmd)
-                               return iscsit_add_reject(ISCSI_REASON_BOOKMARK_NO_RESOURCES,
-                                               1, buf, conn);
+                               goto reject;
                }
                ret = iscsit_handle_nop_out(conn, cmd, buf);
                break;
        case ISCSI_OP_SCSI_TMFUNC:
                cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);
                if (!cmd)
-                       return iscsit_add_reject(ISCSI_REASON_BOOKMARK_NO_RESOURCES,
-                                               1, buf, conn);
+                       goto reject;
 
                ret = iscsit_handle_task_mgt_cmd(conn, cmd, buf);
                break;
        case ISCSI_OP_TEXT:
-               ret = iscsit_handle_text_cmd(conn, buf);
+               cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);
+               if (!cmd)
+                       goto reject;
+
+               ret = iscsit_handle_text_cmd(conn, cmd, buf);
                break;
        case ISCSI_OP_LOGOUT:
                cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);
                if (!cmd)
-                       return iscsit_add_reject(ISCSI_REASON_BOOKMARK_NO_RESOURCES,
-                                               1, buf, conn);
+                       goto reject;
 
                ret = iscsit_handle_logout_cmd(conn, cmd, buf);
                if (ret > 0)
@@ -3987,6 +4022,8 @@ static int iscsi_target_rx_opcode(struct iscsi_conn *conn, unsigned char *buf)
        }
 
        return ret;
+reject:
+       return iscsit_add_reject(conn, ISCSI_REASON_BOOKMARK_NO_RESOURCES, buf);
 }
 
 int iscsi_target_rx_thread(void *arg)
@@ -4039,11 +4076,6 @@ restart:
                        goto transport_err;
                }
 
-               /*
-                * Set conn->bad_hdr for use with REJECT PDUs.
-                */
-               memcpy(&conn->bad_hdr, &buffer, ISCSI_HDR_LEN);
-
                if (conn->conn_ops->HeaderDigest) {
                        iov.iov_base    = &digest;
                        iov.iov_len     = ISCSI_CRC_LEN;
@@ -4086,8 +4118,8 @@ restart:
                    (!(opcode & ISCSI_OP_LOGOUT)))) {
                        pr_err("Received illegal iSCSI Opcode: 0x%02x"
                        " while in Discovery Session, rejecting.\n", opcode);
-                       iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1,
-                                       buffer, conn);
+                       iscsit_add_reject(conn, ISCSI_REASON_PROTOCOL_ERROR,
+                                         buffer);
                        goto transport_err;
                }
 
index a0050b2..2c437cb 100644 (file)
@@ -15,7 +15,7 @@ extern struct iscsi_np *iscsit_add_np(struct __kernel_sockaddr_storage *,
 extern int iscsit_reset_np_thread(struct iscsi_np *, struct iscsi_tpg_np *,
                                struct iscsi_portal_group *);
 extern int iscsit_del_np(struct iscsi_np *);
-extern int iscsit_add_reject_from_cmd(u8, int, int, unsigned char *, struct iscsi_cmd *);
+extern int iscsit_reject_cmd(struct iscsi_cmd *cmd, u8, unsigned char *);
 extern void iscsit_set_unsoliticed_dataout(struct iscsi_cmd *);
 extern int iscsit_logout_closesession(struct iscsi_cmd *, struct iscsi_conn *);
 extern int iscsit_logout_closeconnection(struct iscsi_cmd *, struct iscsi_conn *);
index 8d8b3ff..bbfd288 100644 (file)
@@ -20,6 +20,7 @@
  ****************************************************************************/
 
 #include <linux/configfs.h>
+#include <linux/ctype.h>
 #include <linux/export.h>
 #include <linux/inet.h>
 #include <target/target_core_base.h>
@@ -78,11 +79,12 @@ static ssize_t lio_target_np_store_sctp(
        struct iscsi_tpg_np *tpg_np = container_of(se_tpg_np,
                                struct iscsi_tpg_np, se_tpg_np);
        struct iscsi_tpg_np *tpg_np_sctp = NULL;
-       char *endptr;
        u32 op;
        int ret;
 
-       op = simple_strtoul(page, &endptr, 0);
+       ret = kstrtou32(page, 0, &op);
+       if (ret)
+               return ret;
        if ((op != 1) && (op != 0)) {
                pr_err("Illegal value for tpg_enable: %u\n", op);
                return -EINVAL;
@@ -382,11 +384,12 @@ static ssize_t iscsi_nacl_attrib_store_##name(                            \
 {                                                                      \
        struct iscsi_node_acl *nacl = container_of(se_nacl, struct iscsi_node_acl, \
                                        se_node_acl);                   \
-       char *endptr;                                                   \
        u32 val;                                                        \
        int ret;                                                        \
                                                                        \
-       val = simple_strtoul(page, &endptr, 0);                         \
+       ret = kstrtou32(page, 0, &val);                                 \
+       if (ret)                                                        \
+               return ret;                                             \
        ret = iscsit_na_##name(nacl, val);                              \
        if (ret < 0)                                                    \
                return ret;                                             \
@@ -474,7 +477,7 @@ static ssize_t __iscsi_##prefix##_store_##name(                             \
        if (!capable(CAP_SYS_ADMIN))                                    \
                return -EPERM;                                          \
                                                                        \
-       snprintf(auth->name, PAGE_SIZE, "%s", page);                    \
+       snprintf(auth->name, sizeof(auth->name), "%s", page);           \
        if (!strncmp("NULL", auth->name, 4))                            \
                auth->naf_flags &= ~flags;                              \
        else                                                            \
@@ -789,11 +792,12 @@ static ssize_t lio_target_nacl_store_cmdsn_depth(
        struct iscsi_portal_group *tpg = container_of(se_tpg,
                        struct iscsi_portal_group, tpg_se_tpg);
        struct config_item *acl_ci, *tpg_ci, *wwn_ci;
-       char *endptr;
        u32 cmdsn_depth = 0;
        int ret;
 
-       cmdsn_depth = simple_strtoul(page, &endptr, 0);
+       ret = kstrtou32(page, 0, &cmdsn_depth);
+       if (ret)
+               return ret;
        if (cmdsn_depth > TA_DEFAULT_CMDSN_DEPTH_MAX) {
                pr_err("Passed cmdsn_depth: %u exceeds"
                        " TA_DEFAULT_CMDSN_DEPTH_MAX: %u\n", cmdsn_depth,
@@ -977,14 +981,15 @@ static ssize_t iscsi_tpg_attrib_store_##name(                             \
 {                                                                      \
        struct iscsi_portal_group *tpg = container_of(se_tpg,           \
                        struct iscsi_portal_group, tpg_se_tpg); \
-       char *endptr;                                                   \
        u32 val;                                                        \
        int ret;                                                        \
                                                                        \
        if (iscsit_get_tpg(tpg) < 0)                                    \
                return -EINVAL;                                         \
                                                                        \
-       val = simple_strtoul(page, &endptr, 0);                         \
+       ret = kstrtou32(page, 0, &val);                                 \
+       if (ret)                                                        \
+               goto out;                                               \
        ret = iscsit_ta_##name(tpg, val);                               \
        if (ret < 0)                                                    \
                goto out;                                               \
@@ -1053,6 +1058,131 @@ static struct configfs_attribute *lio_target_tpg_attrib_attrs[] = {
 
 /* End items for lio_target_tpg_attrib_cit */
 
+/* Start items for lio_target_tpg_auth_cit */
+
+#define __DEF_TPG_AUTH_STR(prefix, name, flags)                                        \
+static ssize_t __iscsi_##prefix##_show_##name(                                 \
+       struct se_portal_group *se_tpg,                                         \
+       char *page)                                                             \
+{                                                                              \
+       struct iscsi_portal_group *tpg = container_of(se_tpg,                   \
+                               struct iscsi_portal_group, tpg_se_tpg);         \
+       struct iscsi_node_auth *auth = &tpg->tpg_demo_auth;                     \
+                                                                               \
+       if (!capable(CAP_SYS_ADMIN))                                            \
+               return -EPERM;                                                  \
+                                                                               \
+       return snprintf(page, PAGE_SIZE, "%s\n", auth->name);                   \
+}                                                                              \
+                                                                               \
+static ssize_t __iscsi_##prefix##_store_##name(                                        \
+       struct se_portal_group *se_tpg,                                         \
+       const char *page,                                                       \
+       size_t count)                                                           \
+{                                                                              \
+       struct iscsi_portal_group *tpg = container_of(se_tpg,                   \
+                               struct iscsi_portal_group, tpg_se_tpg);         \
+       struct iscsi_node_auth *auth = &tpg->tpg_demo_auth;                     \
+                                                                               \
+       if (!capable(CAP_SYS_ADMIN))                                            \
+               return -EPERM;                                                  \
+                                                                               \
+       snprintf(auth->name, sizeof(auth->name), "%s", page);                   \
+       if (!(strncmp("NULL", auth->name, 4)))                                  \
+               auth->naf_flags &= ~flags;                                      \
+       else                                                                    \
+               auth->naf_flags |= flags;                                       \
+                                                                               \
+       if ((auth->naf_flags & NAF_USERID_IN_SET) &&                            \
+           (auth->naf_flags & NAF_PASSWORD_IN_SET))                            \
+               auth->authenticate_target = 1;                                  \
+       else                                                                    \
+               auth->authenticate_target = 0;                                  \
+                                                                               \
+       return count;                                                           \
+}
+
+#define __DEF_TPG_AUTH_INT(prefix, name)                                       \
+static ssize_t __iscsi_##prefix##_show_##name(                                 \
+       struct se_portal_group *se_tpg,                                         \
+       char *page)                                                             \
+{                                                                              \
+       struct iscsi_portal_group *tpg = container_of(se_tpg,                   \
+                               struct iscsi_portal_group, tpg_se_tpg);         \
+       struct iscsi_node_auth *auth = &tpg->tpg_demo_auth;                     \
+                                                                               \
+       if (!capable(CAP_SYS_ADMIN))                                            \
+               return -EPERM;                                                  \
+                                                                               \
+       return snprintf(page, PAGE_SIZE, "%d\n", auth->name);                   \
+}
+
+#define DEF_TPG_AUTH_STR(name, flags)                                          \
+       __DEF_TPG_AUTH_STR(tpg_auth, name, flags)                               \
+static ssize_t iscsi_tpg_auth_show_##name(                                     \
+       struct se_portal_group *se_tpg,                                         \
+       char *page)                                                             \
+{                                                                              \
+       return __iscsi_tpg_auth_show_##name(se_tpg, page);                      \
+}                                                                              \
+                                                                               \
+static ssize_t iscsi_tpg_auth_store_##name(                                    \
+       struct se_portal_group *se_tpg,                                         \
+       const char *page,                                                       \
+       size_t count)                                                           \
+{                                                                              \
+       return __iscsi_tpg_auth_store_##name(se_tpg, page, count);              \
+}
+
+#define DEF_TPG_AUTH_INT(name)                                                 \
+       __DEF_TPG_AUTH_INT(tpg_auth, name)                                      \
+static ssize_t iscsi_tpg_auth_show_##name(                                     \
+       struct se_portal_group *se_tpg,                                         \
+       char *page)                                                             \
+{                                                                              \
+       return __iscsi_tpg_auth_show_##name(se_tpg, page);                      \
+}
+
+#define TPG_AUTH_ATTR(_name, _mode) TF_TPG_AUTH_ATTR(iscsi, _name, _mode);
+#define TPG_AUTH_ATTR_RO(_name) TF_TPG_AUTH_ATTR_RO(iscsi, _name);
+
+/*
+ *  * One-way authentication userid
+ *   */
+DEF_TPG_AUTH_STR(userid, NAF_USERID_SET);
+TPG_AUTH_ATTR(userid, S_IRUGO | S_IWUSR);
+/*
+ *  * One-way authentication password
+ *   */
+DEF_TPG_AUTH_STR(password, NAF_PASSWORD_SET);
+TPG_AUTH_ATTR(password, S_IRUGO | S_IWUSR);
+/*
+ *  * Enforce mutual authentication
+ *   */
+DEF_TPG_AUTH_INT(authenticate_target);
+TPG_AUTH_ATTR_RO(authenticate_target);
+/*
+ *  * Mutual authentication userid
+ *   */
+DEF_TPG_AUTH_STR(userid_mutual, NAF_USERID_IN_SET);
+TPG_AUTH_ATTR(userid_mutual, S_IRUGO | S_IWUSR);
+/*
+ *  * Mutual authentication password
+ *   */
+DEF_TPG_AUTH_STR(password_mutual, NAF_PASSWORD_IN_SET);
+TPG_AUTH_ATTR(password_mutual, S_IRUGO | S_IWUSR);
+
+static struct configfs_attribute *lio_target_tpg_auth_attrs[] = {
+       &iscsi_tpg_auth_userid.attr,
+       &iscsi_tpg_auth_password.attr,
+       &iscsi_tpg_auth_authenticate_target.attr,
+       &iscsi_tpg_auth_userid_mutual.attr,
+       &iscsi_tpg_auth_password_mutual.attr,
+       NULL,
+};
+
+/* End items for lio_target_tpg_auth_cit */
+
 /* Start items for lio_target_tpg_param_cit */
 
 #define DEF_TPG_PARAM(name)                                            \
@@ -1087,13 +1217,14 @@ static ssize_t iscsi_tpg_param_store_##name(                            \
        struct iscsi_portal_group *tpg = container_of(se_tpg,           \
                        struct iscsi_portal_group, tpg_se_tpg);         \
        char *buf;                                                      \
-       int ret;                                                        \
+       int ret, len;                                                   \
                                                                        \
        buf = kzalloc(PAGE_SIZE, GFP_KERNEL);                           \
        if (!buf)                                                       \
                return -ENOMEM;                                         \
-       snprintf(buf, PAGE_SIZE, "%s=%s", __stringify(name), page);     \
-       buf[strlen(buf)-1] = '\0'; /* Kill newline */                   \
+       len = snprintf(buf, PAGE_SIZE, "%s=%s", __stringify(name), page);       \
+       if (isspace(buf[len-1]))                                        \
+               buf[len-1] = '\0'; /* Kill newline */                   \
                                                                        \
        if (iscsit_get_tpg(tpg) < 0) {                                  \
                kfree(buf);                                             \
@@ -1230,11 +1361,12 @@ static ssize_t lio_target_tpg_store_enable(
 {
        struct iscsi_portal_group *tpg = container_of(se_tpg,
                        struct iscsi_portal_group, tpg_se_tpg);
-       char *endptr;
        u32 op;
-       int ret = 0;
+       int ret;
 
-       op = simple_strtoul(page, &endptr, 0);
+       ret = kstrtou32(page, 0, &op);
+       if (ret)
+               return ret;
        if ((op != 1) && (op != 0)) {
                pr_err("Illegal value for tpg_enable: %u\n", op);
                return -EINVAL;
@@ -1282,15 +1414,15 @@ static struct se_portal_group *lio_target_tiqn_addtpg(
 {
        struct iscsi_portal_group *tpg;
        struct iscsi_tiqn *tiqn;
-       char *tpgt_str, *end_ptr;
-       int ret = 0;
-       unsigned short int tpgt;
+       char *tpgt_str;
+       int ret;
+       u16 tpgt;
 
        tiqn = container_of(wwn, struct iscsi_tiqn, tiqn_wwn);
        /*
         * Only tpgt_# directory groups can be created below
         * target/iscsi/iqn.superturodiskarry/
-       */
+        */
        tpgt_str = strstr(name, "tpgt_");
        if (!tpgt_str) {
                pr_err("Unable to locate \"tpgt_#\" directory"
@@ -1298,7 +1430,9 @@ static struct se_portal_group *lio_target_tiqn_addtpg(
                return NULL;
        }
        tpgt_str += 5; /* Skip ahead of "tpgt_" */
-       tpgt = (unsigned short int) simple_strtoul(tpgt_str, &end_ptr, 0);
+       ret = kstrtou16(tpgt_str, 0, &tpgt);
+       if (ret)
+               return NULL;
 
        tpg = iscsit_alloc_portal_group(tiqn, tpgt);
        if (!tpg)
@@ -1506,10 +1640,12 @@ static ssize_t iscsi_disc_store_enforce_discovery_auth(
 {
        struct iscsi_param *param;
        struct iscsi_portal_group *discovery_tpg = iscsit_global->discovery_tpg;
-       char *endptr;
        u32 op;
+       int err;
 
-       op = simple_strtoul(page, &endptr, 0);
+       err = kstrtou32(page, 0, &op);
+       if (err)
+               return -EINVAL;
        if ((op != 1) && (op != 0)) {
                pr_err("Illegal value for enforce_discovery_auth:"
                                " %u\n", op);
@@ -1655,13 +1791,12 @@ static int lio_queue_status(struct se_cmd *se_cmd)
        return 0;
 }
 
-static int lio_queue_tm_rsp(struct se_cmd *se_cmd)
+static void lio_queue_tm_rsp(struct se_cmd *se_cmd)
 {
        struct iscsi_cmd *cmd = container_of(se_cmd, struct iscsi_cmd, se_cmd);
 
        cmd->i_state = ISTATE_SEND_TASKMGTRSP;
        iscsit_add_cmd_to_response_queue(cmd, cmd->conn, cmd->i_state);
-       return 0;
 }
 
 static char *lio_tpg_get_endpoint_wwn(struct se_portal_group *se_tpg)
@@ -1866,6 +2001,7 @@ int iscsi_target_register_configfs(void)
        TF_CIT_TMPL(fabric)->tfc_wwn_cit.ct_attrs = lio_target_wwn_attrs;
        TF_CIT_TMPL(fabric)->tfc_tpg_base_cit.ct_attrs = lio_target_tpg_attrs;
        TF_CIT_TMPL(fabric)->tfc_tpg_attrib_cit.ct_attrs = lio_target_tpg_attrib_attrs;
+       TF_CIT_TMPL(fabric)->tfc_tpg_auth_cit.ct_attrs = lio_target_tpg_auth_attrs;
        TF_CIT_TMPL(fabric)->tfc_tpg_param_cit.ct_attrs = lio_target_tpg_param_attrs;
        TF_CIT_TMPL(fabric)->tfc_tpg_np_base_cit.ct_attrs = lio_target_portal_attrs;
        TF_CIT_TMPL(fabric)->tfc_tpg_nacl_base_cit.ct_attrs = lio_target_initiator_attrs;
index 60ec4b9..4f77a78 100644 (file)
@@ -132,7 +132,8 @@ enum cmd_flags_table {
        ICF_CONTIG_MEMORY                       = 0x00000020,
        ICF_ATTACHED_TO_RQUEUE                  = 0x00000040,
        ICF_OOO_CMDSN                           = 0x00000080,
-       ICF_REJECT_FAIL_CONN                    = 0x00000100,
+       IFC_SENDTARGETS_ALL                     = 0x00000100,
+       IFC_SENDTARGETS_SINGLE                  = 0x00000200,
 };
 
 /* struct iscsi_cmd->i_state */
@@ -366,6 +367,8 @@ struct iscsi_cmd {
        u8                      maxcmdsn_inc;
        /* Immediate Unsolicited Dataout */
        u8                      unsolicited_data;
+       /* Reject reason code */
+       u8                      reject_reason;
        /* CID contained in logout PDU when opcode == ISCSI_INIT_LOGOUT_CMND */
        u16                     logout_cid;
        /* Command flags */
@@ -427,6 +430,8 @@ struct iscsi_cmd {
        u32                     tx_size;
        /* Buffer used for various purposes */
        void                    *buf_ptr;
+       /* Used by SendTargets=[iqn.,eui.] discovery */
+       void                    *text_in_ptr;
        /* See include/linux/dma-mapping.h */
        enum dma_data_direction data_direction;
        /* iSCSI PDU Header + CRC */
@@ -446,7 +451,6 @@ struct iscsi_cmd {
        struct list_head        datain_list;
        /* R2T List */
        struct list_head        cmd_r2t_list;
-       struct completion       reject_comp;
        /* Timer for DataOUT */
        struct timer_list       dataout_timer;
        /* Iovecs for SCSI data payload RX/TX w/ kernel level sockets */
@@ -528,8 +532,6 @@ struct iscsi_conn {
        u32                     of_marker;
        /* Used for calculating OFMarker offset to next PDU */
        u32                     of_marker_offset;
-       /* Complete Bad PDU for sending reject */
-       unsigned char           bad_hdr[ISCSI_HDR_LEN];
 #define IPV6_ADDRESS_SPACE                             48
        unsigned char           login_ip[IPV6_ADDRESS_SPACE];
        unsigned char           local_ip[IPV6_ADDRESS_SPACE];
@@ -809,6 +811,7 @@ struct iscsi_portal_group {
        struct mutex            tpg_access_lock;
        struct mutex            np_login_lock;
        struct iscsi_tpg_attrib tpg_attrib;
+       struct iscsi_node_auth  tpg_demo_auth;
        /* Pointer to default list of iSCSI parameters for TPG */
        struct iscsi_param_list *param_list;
        struct iscsi_tiqn       *tpg_tiqn;
index dcb199d..08bd878 100644 (file)
@@ -746,13 +746,12 @@ int iscsit_check_post_dataout(
                if (!conn->sess->sess_ops->ErrorRecoveryLevel) {
                        pr_err("Unable to recover from DataOUT CRC"
                                " failure while ERL=0, closing session.\n");
-                       iscsit_add_reject_from_cmd(ISCSI_REASON_DATA_DIGEST_ERROR,
-                                       1, 0, buf, cmd);
+                       iscsit_reject_cmd(cmd, ISCSI_REASON_DATA_DIGEST_ERROR,
+                                         buf);
                        return DATAOUT_CANNOT_RECOVER;
                }
 
-               iscsit_add_reject_from_cmd(ISCSI_REASON_DATA_DIGEST_ERROR,
-                               0, 0, buf, cmd);
+               iscsit_reject_cmd(cmd, ISCSI_REASON_DATA_DIGEST_ERROR, buf);
                return iscsit_dataout_post_crc_failed(cmd, buf);
        }
 }
@@ -909,6 +908,7 @@ void iscsit_cause_connection_reinstatement(struct iscsi_conn *conn, int sleep)
        wait_for_completion(&conn->conn_wait_comp);
        complete(&conn->conn_post_wait_comp);
 }
+EXPORT_SYMBOL(iscsit_cause_connection_reinstatement);
 
 void iscsit_fall_back_to_erl0(struct iscsi_session *sess)
 {
index 40d9dbc..586c268 100644 (file)
@@ -162,9 +162,8 @@ static int iscsit_handle_r2t_snack(
                        " protocol error.\n", cmd->init_task_tag, begrun,
                        (begrun + runlength), cmd->acked_data_sn);
 
-                       return iscsit_add_reject_from_cmd(
-                                       ISCSI_REASON_PROTOCOL_ERROR,
-                                       1, 0, buf, cmd);
+                       return iscsit_reject_cmd(cmd,
+                                       ISCSI_REASON_PROTOCOL_ERROR, buf);
        }
 
        if (runlength) {
@@ -173,8 +172,8 @@ static int iscsit_handle_r2t_snack(
                        " with BegRun: 0x%08x, RunLength: 0x%08x, exceeds"
                        " current R2TSN: 0x%08x, protocol error.\n",
                        cmd->init_task_tag, begrun, runlength, cmd->r2t_sn);
-                       return iscsit_add_reject_from_cmd(
-                               ISCSI_REASON_BOOKMARK_INVALID, 1, 0, buf, cmd);
+                       return iscsit_reject_cmd(cmd,
+                                       ISCSI_REASON_BOOKMARK_INVALID, buf);
                }
                last_r2tsn = (begrun + runlength);
        } else
@@ -433,8 +432,7 @@ static int iscsit_handle_recovery_datain(
                        " protocol error.\n", cmd->init_task_tag, begrun,
                        (begrun + runlength), cmd->acked_data_sn);
 
-               return iscsit_add_reject_from_cmd(ISCSI_REASON_PROTOCOL_ERROR,
-                               1, 0, buf, cmd);
+               return iscsit_reject_cmd(cmd, ISCSI_REASON_PROTOCOL_ERROR, buf);
        }
 
        /*
@@ -445,14 +443,14 @@ static int iscsit_handle_recovery_datain(
                pr_err("Initiator requesting BegRun: 0x%08x, RunLength"
                        ": 0x%08x greater than maximum DataSN: 0x%08x.\n",
                                begrun, runlength, (cmd->data_sn - 1));
-               return iscsit_add_reject_from_cmd(ISCSI_REASON_BOOKMARK_INVALID,
-                               1, 0, buf, cmd);
+               return iscsit_reject_cmd(cmd, ISCSI_REASON_BOOKMARK_INVALID,
+                                        buf);
        }
 
        dr = iscsit_allocate_datain_req();
        if (!dr)
-               return iscsit_add_reject_from_cmd(ISCSI_REASON_BOOKMARK_NO_RESOURCES,
-                               1, 0, buf, cmd);
+               return iscsit_reject_cmd(cmd, ISCSI_REASON_BOOKMARK_NO_RESOURCES,
+                                        buf);
 
        dr->data_sn = dr->begrun = begrun;
        dr->runlength = runlength;
@@ -1090,7 +1088,7 @@ int iscsit_handle_ooo_cmdsn(
 
        ooo_cmdsn = iscsit_allocate_ooo_cmdsn();
        if (!ooo_cmdsn)
-               return CMDSN_ERROR_CANNOT_RECOVER;
+               return -ENOMEM;
 
        ooo_cmdsn->cmd                  = cmd;
        ooo_cmdsn->batch_count          = (batch) ?
@@ -1101,10 +1099,10 @@ int iscsit_handle_ooo_cmdsn(
 
        if (iscsit_attach_ooo_cmdsn(sess, ooo_cmdsn) < 0) {
                kmem_cache_free(lio_ooo_cache, ooo_cmdsn);
-               return CMDSN_ERROR_CANNOT_RECOVER;
+               return -ENOMEM;
        }
 
-       return CMDSN_HIGHER_THAN_EXP;
+       return 0;
 }
 
 static int iscsit_set_dataout_timeout_values(
index cd5018f..c4675b4 100644 (file)
@@ -112,6 +112,7 @@ static u32 iscsi_handle_authentication(
        struct iscsi_session *sess = conn->sess;
        struct iscsi_node_auth *auth;
        struct iscsi_node_acl *iscsi_nacl;
+       struct iscsi_portal_group *iscsi_tpg;
        struct se_node_acl *se_nacl;
 
        if (!sess->sess_ops->SessionType) {
@@ -132,7 +133,17 @@ static u32 iscsi_handle_authentication(
                        return -1;
                }
 
-               auth = ISCSI_NODE_AUTH(iscsi_nacl);
+               if (se_nacl->dynamic_node_acl) {
+                       iscsi_tpg = container_of(se_nacl->se_tpg,
+                                       struct iscsi_portal_group, tpg_se_tpg);
+
+                       auth = &iscsi_tpg->tpg_demo_auth;
+               } else {
+                       iscsi_nacl = container_of(se_nacl, struct iscsi_node_acl,
+                                                 se_node_acl);
+
+                       auth = ISCSI_NODE_AUTH(iscsi_nacl);
+               }
        } else {
                /*
                 * For SessionType=Discovery
index e382221..35fd643 100644 (file)
@@ -1799,9 +1799,6 @@ void iscsi_set_connection_parameters(
                 * this key is not sent over the wire.
                 */
                if (!strcmp(param->name, MAXXMITDATASEGMENTLENGTH)) {
-                       if (param_list->iser == true)
-                               continue;
-
                        ops->MaxXmitDataSegmentLength =
                                simple_strtoul(param->value, &tmpptr, 0);
                        pr_debug("MaxXmitDataSegmentLength:     %s\n",
index 08a3bac..1df06d5 100644 (file)
@@ -178,7 +178,6 @@ struct iscsi_cmd *iscsit_allocate_cmd(struct iscsi_conn *conn, gfp_t gfp_mask)
        INIT_LIST_HEAD(&cmd->i_conn_node);
        INIT_LIST_HEAD(&cmd->datain_list);
        INIT_LIST_HEAD(&cmd->cmd_r2t_list);
-       init_completion(&cmd->reject_comp);
        spin_lock_init(&cmd->datain_lock);
        spin_lock_init(&cmd->dataout_timeout_lock);
        spin_lock_init(&cmd->istate_lock);
@@ -284,13 +283,12 @@ static inline int iscsit_check_received_cmdsn(struct iscsi_session *sess, u32 cm
  * Commands may be received out of order if MC/S is in use.
  * Ensure they are executed in CmdSN order.
  */
-int iscsit_sequence_cmd(
-       struct iscsi_conn *conn,
-       struct iscsi_cmd *cmd,
-       __be32 cmdsn)
+int iscsit_sequence_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
+                       unsigned char *buf, __be32 cmdsn)
 {
-       int ret;
-       int cmdsn_ret;
+       int ret, cmdsn_ret;
+       bool reject = false;
+       u8 reason = ISCSI_REASON_BOOKMARK_NO_RESOURCES;
 
        mutex_lock(&conn->sess->cmdsn_mutex);
 
@@ -300,9 +298,19 @@ int iscsit_sequence_cmd(
                ret = iscsit_execute_cmd(cmd, 0);
                if ((ret >= 0) && !list_empty(&conn->sess->sess_ooo_cmdsn_list))
                        iscsit_execute_ooo_cmdsns(conn->sess);
+               else if (ret < 0) {
+                       reject = true;
+                       ret = CMDSN_ERROR_CANNOT_RECOVER;
+               }
                break;
        case CMDSN_HIGHER_THAN_EXP:
                ret = iscsit_handle_ooo_cmdsn(conn->sess, cmd, be32_to_cpu(cmdsn));
+               if (ret < 0) {
+                       reject = true;
+                       ret = CMDSN_ERROR_CANNOT_RECOVER;
+                       break;
+               }
+               ret = CMDSN_HIGHER_THAN_EXP;
                break;
        case CMDSN_LOWER_THAN_EXP:
                cmd->i_state = ISTATE_REMOVE;
@@ -310,11 +318,16 @@ int iscsit_sequence_cmd(
                ret = cmdsn_ret;
                break;
        default:
+               reason = ISCSI_REASON_PROTOCOL_ERROR;
+               reject = true;
                ret = cmdsn_ret;
                break;
        }
        mutex_unlock(&conn->sess->cmdsn_mutex);
 
+       if (reject)
+               iscsit_reject_cmd(cmd, reason, buf);
+
        return ret;
 }
 EXPORT_SYMBOL(iscsit_sequence_cmd);
@@ -681,6 +694,7 @@ void iscsit_release_cmd(struct iscsi_cmd *cmd)
        kfree(cmd->seq_list);
        kfree(cmd->tmr_req);
        kfree(cmd->iov_data);
+       kfree(cmd->text_in_ptr);
 
        kmem_cache_free(lio_cmd_cache, cmd);
 }
index a442265..e4fc34a 100644 (file)
@@ -13,7 +13,8 @@ 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, __be32 cmdsn);
+extern int iscsit_sequence_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
+                              unsigned char * ,__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 *, itt_t);
 extern struct iscsi_cmd *iscsit_find_cmd_from_itt_or_dump(struct iscsi_conn *,
index 7c90814..568ad25 100644 (file)
@@ -786,7 +786,7 @@ static int tcm_loop_queue_status(struct se_cmd *se_cmd)
        return 0;
 }
 
-static int tcm_loop_queue_tm_rsp(struct se_cmd *se_cmd)
+static void tcm_loop_queue_tm_rsp(struct se_cmd *se_cmd)
 {
        struct se_tmr_req *se_tmr = se_cmd->se_tmr_req;
        struct tcm_loop_tmr *tl_tmr = se_tmr->fabric_tmr_ptr;
@@ -796,7 +796,6 @@ static int tcm_loop_queue_tm_rsp(struct se_cmd *se_cmd)
         */
        atomic_set(&tl_tmr->tmr_complete, 1);
        wake_up(&tl_tmr->tl_tmr_wait);
-       return 0;
 }
 
 static char *tcm_loop_dump_proto_id(struct tcm_loop_hba *tl_hba)
index d3536f5..e51b09a 100644 (file)
@@ -1842,9 +1842,8 @@ static int sbp_queue_status(struct se_cmd *se_cmd)
        return sbp_send_sense(req);
 }
 
-static int sbp_queue_tm_rsp(struct se_cmd *se_cmd)
+static void sbp_queue_tm_rsp(struct se_cmd *se_cmd)
 {
-       return 0;
 }
 
 static int sbp_check_stop_free(struct se_cmd *se_cmd)
index 4a8bd36..e4d2293 100644 (file)
@@ -983,7 +983,6 @@ static ssize_t target_core_dev_pr_show_spc3_res(struct se_device *dev,
        struct se_node_acl *se_nacl;
        struct t10_pr_registration *pr_reg;
        char i_buf[PR_REG_ISID_ID_LEN];
-       int prf_isid;
 
        memset(i_buf, 0, PR_REG_ISID_ID_LEN);
 
@@ -992,12 +991,11 @@ static ssize_t target_core_dev_pr_show_spc3_res(struct se_device *dev,
                return sprintf(page, "No SPC-3 Reservation holder\n");
 
        se_nacl = pr_reg->pr_reg_nacl;
-       prf_isid = core_pr_dump_initiator_port(pr_reg, &i_buf[0],
-                               PR_REG_ISID_ID_LEN);
+       core_pr_dump_initiator_port(pr_reg, i_buf, PR_REG_ISID_ID_LEN);
 
        return sprintf(page, "SPC-3 Reservation: %s Initiator: %s%s\n",
                se_nacl->se_tpg->se_tpg_tfo->get_fabric_name(),
-               se_nacl->initiatorname, (prf_isid) ? &i_buf[0] : "");
+               se_nacl->initiatorname, i_buf);
 }
 
 static ssize_t target_core_dev_pr_show_spc2_res(struct se_device *dev,
@@ -1116,7 +1114,7 @@ static ssize_t target_core_dev_pr_show_attr_res_pr_registered_i_pts(
        unsigned char buf[384];
        char i_buf[PR_REG_ISID_ID_LEN];
        ssize_t len = 0;
-       int reg_count = 0, prf_isid;
+       int reg_count = 0;
 
        len += sprintf(page+len, "SPC-3 PR Registrations:\n");
 
@@ -1127,12 +1125,11 @@ static ssize_t target_core_dev_pr_show_attr_res_pr_registered_i_pts(
                memset(buf, 0, 384);
                memset(i_buf, 0, PR_REG_ISID_ID_LEN);
                tfo = pr_reg->pr_reg_nacl->se_tpg->se_tpg_tfo;
-               prf_isid = core_pr_dump_initiator_port(pr_reg, &i_buf[0],
+               core_pr_dump_initiator_port(pr_reg, i_buf,
                                        PR_REG_ISID_ID_LEN);
                sprintf(buf, "%s Node: %s%s Key: 0x%016Lx PRgen: 0x%08x\n",
                        tfo->get_fabric_name(),
-                       pr_reg->pr_reg_nacl->initiatorname, (prf_isid) ?
-                       &i_buf[0] : "", pr_reg->pr_res_key,
+                       pr_reg->pr_reg_nacl->initiatorname, i_buf, pr_reg->pr_res_key,
                        pr_reg->pr_res_generation);
 
                if (len + strlen(buf) >= PAGE_SIZE)
index 4630481..8f4142f 100644 (file)
@@ -1410,7 +1410,6 @@ struct se_device *target_alloc_device(struct se_hba *hba, const char *name)
        INIT_LIST_HEAD(&dev->t10_alua.tg_pt_gps_list);
        spin_lock_init(&dev->t10_alua.tg_pt_gps_lock);
 
-       dev->t10_pr.pr_aptpl_buf_len = PR_APTPL_BUF_LEN;
        dev->t10_wwn.t10_dev = dev;
        dev->t10_alua.t10_dev = dev;
 
@@ -1545,7 +1544,7 @@ int core_dev_setup_virtual_lun0(void)
 {
        struct se_hba *hba;
        struct se_device *dev;
-       char buf[16];
+       char buf[] = "rd_pages=8,rd_nullio=1";
        int ret;
 
        hba = core_alloc_hba("rd_mcp", 0, HBA_FLAGS_INTERNAL_USE);
@@ -1558,8 +1557,6 @@ int core_dev_setup_virtual_lun0(void)
                goto out_free_hba;
        }
 
-       memset(buf, 0, 16);
-       sprintf(buf, "rd_pages=8");
        hba->transport->set_configfs_dev_params(dev, buf, sizeof(buf));
 
        ret = target_configure_device(dev);
index 04c775c..eb56eb1 100644 (file)
@@ -965,6 +965,19 @@ TF_CIT_SETUP(tpg_attrib, &target_fabric_tpg_attrib_item_ops, NULL, NULL);
 
 /* End of tfc_tpg_attrib_cit */
 
+/* Start of tfc_tpg_auth_cit */
+
+CONFIGFS_EATTR_OPS(target_fabric_tpg_auth, se_portal_group, tpg_auth_group);
+
+static struct configfs_item_operations target_fabric_tpg_auth_item_ops = {
+       .show_attribute         = target_fabric_tpg_auth_attr_show,
+       .store_attribute        = target_fabric_tpg_auth_attr_store,
+};
+
+TF_CIT_SETUP(tpg_auth, &target_fabric_tpg_auth_item_ops, NULL, NULL);
+
+/* End of tfc_tpg_attrib_cit */
+
 /* Start of tfc_tpg_param_cit */
 
 CONFIGFS_EATTR_OPS(target_fabric_tpg_param, se_portal_group, tpg_param_group);
@@ -1030,8 +1043,9 @@ static struct config_group *target_fabric_make_tpg(
        se_tpg->tpg_group.default_groups[1] = &se_tpg->tpg_np_group;
        se_tpg->tpg_group.default_groups[2] = &se_tpg->tpg_acl_group;
        se_tpg->tpg_group.default_groups[3] = &se_tpg->tpg_attrib_group;
-       se_tpg->tpg_group.default_groups[4] = &se_tpg->tpg_param_group;
-       se_tpg->tpg_group.default_groups[5] = NULL;
+       se_tpg->tpg_group.default_groups[4] = &se_tpg->tpg_auth_group;
+       se_tpg->tpg_group.default_groups[5] = &se_tpg->tpg_param_group;
+       se_tpg->tpg_group.default_groups[6] = NULL;
 
        config_group_init_type_name(&se_tpg->tpg_group, name,
                        &TF_CIT_TMPL(tf)->tfc_tpg_base_cit);
@@ -1043,6 +1057,8 @@ static struct config_group *target_fabric_make_tpg(
                        &TF_CIT_TMPL(tf)->tfc_tpg_nacl_cit);
        config_group_init_type_name(&se_tpg->tpg_attrib_group, "attrib",
                        &TF_CIT_TMPL(tf)->tfc_tpg_attrib_cit);
+       config_group_init_type_name(&se_tpg->tpg_auth_group, "auth",
+                       &TF_CIT_TMPL(tf)->tfc_tpg_auth_cit);
        config_group_init_type_name(&se_tpg->tpg_param_group, "param",
                        &TF_CIT_TMPL(tf)->tfc_tpg_param_cit);
 
@@ -1202,6 +1218,7 @@ int target_fabric_setup_cits(struct target_fabric_configfs *tf)
        target_fabric_setup_tpg_np_cit(tf);
        target_fabric_setup_tpg_np_base_cit(tf);
        target_fabric_setup_tpg_attrib_cit(tf);
+       target_fabric_setup_tpg_auth_cit(tf);
        target_fabric_setup_tpg_param_cit(tf);
        target_fabric_setup_tpg_nacl_cit(tf);
        target_fabric_setup_tpg_nacl_base_cit(tf);
index 3240f2c..bd78faf 100644 (file)
@@ -53,18 +53,28 @@ struct pr_transport_id_holder {
        struct list_head dest_list;
 };
 
-int core_pr_dump_initiator_port(
+void core_pr_dump_initiator_port(
        struct t10_pr_registration *pr_reg,
        char *buf,
        u32 size)
 {
        if (!pr_reg->isid_present_at_reg)
-               return 0;
+               buf[0] = '\0';
 
-       snprintf(buf, size, ",i,0x%s", &pr_reg->pr_reg_isid[0]);
-       return 1;
+       snprintf(buf, size, ",i,0x%s", pr_reg->pr_reg_isid);
 }
 
+enum register_type {
+       REGISTER,
+       REGISTER_AND_IGNORE_EXISTING_KEY,
+       REGISTER_AND_MOVE,
+};
+
+enum preempt_type {
+       PREEMPT,
+       PREEMPT_AND_ABORT,
+};
+
 static void __core_scsi3_complete_pro_release(struct se_device *, struct se_node_acl *,
                        struct t10_pr_registration *, int);
 
@@ -596,14 +606,6 @@ static struct t10_pr_registration *__core_scsi3_do_alloc_registration(
                return NULL;
        }
 
-       pr_reg->pr_aptpl_buf = kzalloc(dev->t10_pr.pr_aptpl_buf_len,
-                                       GFP_ATOMIC);
-       if (!pr_reg->pr_aptpl_buf) {
-               pr_err("Unable to allocate pr_reg->pr_aptpl_buf\n");
-               kmem_cache_free(t10_pr_reg_cache, pr_reg);
-               return NULL;
-       }
-
        INIT_LIST_HEAD(&pr_reg->pr_reg_list);
        INIT_LIST_HEAD(&pr_reg->pr_reg_abort_list);
        INIT_LIST_HEAD(&pr_reg->pr_reg_aptpl_list);
@@ -794,7 +796,6 @@ int core_scsi3_alloc_aptpl_registration(
                pr_err("Unable to allocate struct t10_pr_registration\n");
                return -ENOMEM;
        }
-       pr_reg->pr_aptpl_buf = kzalloc(pr_tmpl->pr_aptpl_buf_len, GFP_KERNEL);
 
        INIT_LIST_HEAD(&pr_reg->pr_reg_list);
        INIT_LIST_HEAD(&pr_reg->pr_reg_abort_list);
@@ -848,11 +849,9 @@ static void core_scsi3_aptpl_reserve(
        struct t10_pr_registration *pr_reg)
 {
        char i_buf[PR_REG_ISID_ID_LEN];
-       int prf_isid;
 
        memset(i_buf, 0, PR_REG_ISID_ID_LEN);
-       prf_isid = core_pr_dump_initiator_port(pr_reg, &i_buf[0],
-                               PR_REG_ISID_ID_LEN);
+       core_pr_dump_initiator_port(pr_reg, i_buf, PR_REG_ISID_ID_LEN);
 
        spin_lock(&dev->dev_reservation_lock);
        dev->dev_pr_res_holder = pr_reg;
@@ -865,11 +864,11 @@ static void core_scsi3_aptpl_reserve(
                (pr_reg->pr_reg_all_tg_pt) ? 1 : 0);
        pr_debug("SPC-3 PR [%s] RESERVE Node: %s%s\n",
                tpg->se_tpg_tfo->get_fabric_name(), node_acl->initiatorname,
-               (prf_isid) ? &i_buf[0] : "");
+               i_buf);
 }
 
 static void __core_scsi3_add_registration(struct se_device *, struct se_node_acl *,
-                               struct t10_pr_registration *, int, int);
+                               struct t10_pr_registration *, enum register_type, int);
 
 static int __core_scsi3_check_aptpl_registration(
        struct se_device *dev,
@@ -962,21 +961,19 @@ static void __core_scsi3_dump_registration(
        struct se_device *dev,
        struct se_node_acl *nacl,
        struct t10_pr_registration *pr_reg,
-       int register_type)
+       enum register_type register_type)
 {
        struct se_portal_group *se_tpg = nacl->se_tpg;
        char i_buf[PR_REG_ISID_ID_LEN];
-       int prf_isid;
 
        memset(&i_buf[0], 0, PR_REG_ISID_ID_LEN);
-       prf_isid = core_pr_dump_initiator_port(pr_reg, &i_buf[0],
-                               PR_REG_ISID_ID_LEN);
+       core_pr_dump_initiator_port(pr_reg, i_buf, PR_REG_ISID_ID_LEN);
 
        pr_debug("SPC-3 PR [%s] Service Action: REGISTER%s Initiator"
-               " Node: %s%s\n", tfo->get_fabric_name(), (register_type == 2) ?
-               "_AND_MOVE" : (register_type == 1) ?
+               " Node: %s%s\n", tfo->get_fabric_name(), (register_type == REGISTER_AND_MOVE) ?
+               "_AND_MOVE" : (register_type == REGISTER_AND_IGNORE_EXISTING_KEY) ?
                "_AND_IGNORE_EXISTING_KEY" : "", nacl->initiatorname,
-               (prf_isid) ? i_buf : "");
+               i_buf);
        pr_debug("SPC-3 PR [%s] registration on Target Port: %s,0x%04x\n",
                 tfo->get_fabric_name(), tfo->tpg_get_wwn(se_tpg),
                tfo->tpg_get_tag(se_tpg));
@@ -998,7 +995,7 @@ static void __core_scsi3_add_registration(
        struct se_device *dev,
        struct se_node_acl *nacl,
        struct t10_pr_registration *pr_reg,
-       int register_type,
+       enum register_type register_type,
        int register_move)
 {
        struct target_core_fabric_ops *tfo = nacl->se_tpg->se_tpg_tfo;
@@ -1064,7 +1061,7 @@ static int core_scsi3_alloc_registration(
        u64 sa_res_key,
        int all_tg_pt,
        int aptpl,
-       int register_type,
+       enum register_type register_type,
        int register_move)
 {
        struct t10_pr_registration *pr_reg;
@@ -1225,11 +1222,9 @@ static void __core_scsi3_free_registration(
                        pr_reg->pr_reg_nacl->se_tpg->se_tpg_tfo;
        struct t10_reservation *pr_tmpl = &dev->t10_pr;
        char i_buf[PR_REG_ISID_ID_LEN];
-       int prf_isid;
 
        memset(i_buf, 0, PR_REG_ISID_ID_LEN);
-       prf_isid = core_pr_dump_initiator_port(pr_reg, &i_buf[0],
-                               PR_REG_ISID_ID_LEN);
+       core_pr_dump_initiator_port(pr_reg, i_buf, PR_REG_ISID_ID_LEN);
 
        pr_reg->pr_reg_deve->def_pr_registered = 0;
        pr_reg->pr_reg_deve->pr_res_key = 0;
@@ -1257,7 +1252,7 @@ static void __core_scsi3_free_registration(
        pr_debug("SPC-3 PR [%s] Service Action: UNREGISTER Initiator"
                " Node: %s%s\n", tfo->get_fabric_name(),
                pr_reg->pr_reg_nacl->initiatorname,
-               (prf_isid) ? &i_buf[0] : "");
+               i_buf);
        pr_debug("SPC-3 PR [%s] for %s TCM Subsystem %s Object Target"
                " Port(s)\n", tfo->get_fabric_name(),
                (pr_reg->pr_reg_all_tg_pt) ? "ALL" : "SINGLE",
@@ -1269,7 +1264,6 @@ static void __core_scsi3_free_registration(
        if (!preempt_and_abort_list) {
                pr_reg->pr_reg_deve = NULL;
                pr_reg->pr_reg_nacl = NULL;
-               kfree(pr_reg->pr_aptpl_buf);
                kmem_cache_free(t10_pr_reg_cache, pr_reg);
                return;
        }
@@ -1338,7 +1332,6 @@ void core_scsi3_free_all_registrations(
        list_for_each_entry_safe(pr_reg, pr_reg_tmp, &pr_tmpl->aptpl_reg_list,
                                pr_reg_aptpl_list) {
                list_del(&pr_reg->pr_reg_aptpl_list);
-               kfree(pr_reg->pr_aptpl_buf);
                kmem_cache_free(t10_pr_reg_cache, pr_reg);
        }
        spin_unlock(&pr_tmpl->aptpl_reg_lock);
@@ -1453,7 +1446,7 @@ core_scsi3_decode_spec_i_port(
        char *iport_ptr = NULL, dest_iport[64], i_buf[PR_REG_ISID_ID_LEN];
        sense_reason_t ret;
        u32 tpdl, tid_len = 0;
-       int dest_local_nexus, prf_isid;
+       int dest_local_nexus;
        u32 dest_rtpi = 0;
 
        memset(dest_iport, 0, 64);
@@ -1764,8 +1757,7 @@ core_scsi3_decode_spec_i_port(
                kfree(tidh);
 
                memset(i_buf, 0, PR_REG_ISID_ID_LEN);
-               prf_isid = core_pr_dump_initiator_port(dest_pr_reg, &i_buf[0],
-                                               PR_REG_ISID_ID_LEN);
+               core_pr_dump_initiator_port(dest_pr_reg, i_buf, PR_REG_ISID_ID_LEN);
 
                __core_scsi3_add_registration(cmd->se_dev, dest_node_acl,
                                        dest_pr_reg, 0, 0);
@@ -1773,8 +1765,7 @@ core_scsi3_decode_spec_i_port(
                pr_debug("SPC-3 PR [%s] SPEC_I_PT: Successfully"
                        " registered Transport ID for Node: %s%s Mapped LUN:"
                        " %u\n", dest_tpg->se_tpg_tfo->get_fabric_name(),
-                       dest_node_acl->initiatorname, (prf_isid) ?
-                       &i_buf[0] : "", dest_se_deve->mapped_lun);
+                       dest_node_acl->initiatorname, i_buf, dest_se_deve->mapped_lun);
 
                if (dest_local_nexus)
                        continue;
@@ -1813,7 +1804,6 @@ out:
                        kmem_cache_free(t10_pr_reg_cache, pr_reg_tmp);
                }
 
-               kfree(dest_pr_reg->pr_aptpl_buf);
                kmem_cache_free(t10_pr_reg_cache, dest_pr_reg);
 
                if (dest_local_nexus)
@@ -1826,14 +1816,10 @@ out:
        return ret;
 }
 
-/*
- * Called with struct se_device->dev_reservation_lock held
- */
-static int __core_scsi3_update_aptpl_buf(
+static int core_scsi3_update_aptpl_buf(
        struct se_device *dev,
        unsigned char *buf,
-       u32 pr_aptpl_buf_len,
-       int clear_aptpl_metadata)
+       u32 pr_aptpl_buf_len)
 {
        struct se_lun *lun;
        struct se_portal_group *tpg;
@@ -1841,20 +1827,13 @@ static int __core_scsi3_update_aptpl_buf(
        unsigned char tmp[512], isid_buf[32];
        ssize_t len = 0;
        int reg_count = 0;
+       int ret = 0;
 
-       memset(buf, 0, pr_aptpl_buf_len);
-       /*
-        * Called to clear metadata once APTPL has been deactivated.
-        */
-       if (clear_aptpl_metadata) {
-               snprintf(buf, pr_aptpl_buf_len,
-                               "No Registrations or Reservations\n");
-               return 0;
-       }
+       spin_lock(&dev->dev_reservation_lock);
+       spin_lock(&dev->t10_pr.registration_lock);
        /*
         * Walk the registration list..
         */
-       spin_lock(&dev->t10_pr.registration_lock);
        list_for_each_entry(pr_reg, &dev->t10_pr.registration_list,
                        pr_reg_list) {
 
@@ -1900,8 +1879,8 @@ static int __core_scsi3_update_aptpl_buf(
                if ((len + strlen(tmp) >= pr_aptpl_buf_len)) {
                        pr_err("Unable to update renaming"
                                " APTPL metadata\n");
-                       spin_unlock(&dev->t10_pr.registration_lock);
-                       return -EMSGSIZE;
+                       ret = -EMSGSIZE;
+                       goto out;
                }
                len += sprintf(buf+len, "%s", tmp);
 
@@ -1918,48 +1897,32 @@ static int __core_scsi3_update_aptpl_buf(
                if ((len + strlen(tmp) >= pr_aptpl_buf_len)) {
                        pr_err("Unable to update renaming"
                                " APTPL metadata\n");
-                       spin_unlock(&dev->t10_pr.registration_lock);
-                       return -EMSGSIZE;
+                       ret = -EMSGSIZE;
+                       goto out;
                }
                len += sprintf(buf+len, "%s", tmp);
                reg_count++;
        }
-       spin_unlock(&dev->t10_pr.registration_lock);
 
        if (!reg_count)
                len += sprintf(buf+len, "No Registrations or Reservations");
 
-       return 0;
-}
-
-static int core_scsi3_update_aptpl_buf(
-       struct se_device *dev,
-       unsigned char *buf,
-       u32 pr_aptpl_buf_len,
-       int clear_aptpl_metadata)
-{
-       int ret;
-
-       spin_lock(&dev->dev_reservation_lock);
-       ret = __core_scsi3_update_aptpl_buf(dev, buf, pr_aptpl_buf_len,
-                               clear_aptpl_metadata);
+out:
+       spin_unlock(&dev->t10_pr.registration_lock);
        spin_unlock(&dev->dev_reservation_lock);
 
        return ret;
 }
 
-/*
- * Called with struct se_device->aptpl_file_mutex held
- */
 static int __core_scsi3_write_aptpl_to_file(
        struct se_device *dev,
-       unsigned char *buf,
-       u32 pr_aptpl_buf_len)
+       unsigned char *buf)
 {
        struct t10_wwn *wwn = &dev->t10_wwn;
        struct file *file;
        int flags = O_RDWR | O_CREAT | O_TRUNC;
        char path[512];
+       u32 pr_aptpl_buf_len;
        int ret;
 
        memset(path, 0, 512);
@@ -1978,8 +1941,7 @@ static int __core_scsi3_write_aptpl_to_file(
                return PTR_ERR(file);
        }
 
-       if (!pr_aptpl_buf_len)
-               pr_aptpl_buf_len = (strlen(&buf[0]) + 1); /* Add extra for NULL */
+       pr_aptpl_buf_len = (strlen(buf) + 1); /* Add extra for NULL */
 
        ret = kernel_write(file, buf, pr_aptpl_buf_len, 0);
 
@@ -1990,60 +1952,64 @@ static int __core_scsi3_write_aptpl_to_file(
        return ret ? -EIO : 0;
 }
 
-static int
-core_scsi3_update_and_write_aptpl(struct se_device *dev, unsigned char *in_buf,
-               u32 in_pr_aptpl_buf_len)
+/*
+ * Clear the APTPL metadata if APTPL has been disabled, otherwise
+ * write out the updated metadata to struct file for this SCSI device.
+ */
+static sense_reason_t core_scsi3_update_and_write_aptpl(struct se_device *dev, bool aptpl)
 {
-       unsigned char null_buf[64], *buf;
-       u32 pr_aptpl_buf_len;
-       int clear_aptpl_metadata = 0;
-       int ret;
+       unsigned char *buf;
+       int rc;
 
-       /*
-        * Can be called with a NULL pointer from PROUT service action CLEAR
-        */
-       if (!in_buf) {
-               memset(null_buf, 0, 64);
-               buf = &null_buf[0];
-               /*
-                * This will clear the APTPL metadata to:
-                * "No Registrations or Reservations" status
-                */
-               pr_aptpl_buf_len = 64;
-               clear_aptpl_metadata = 1;
-       } else {
-               buf = in_buf;
-               pr_aptpl_buf_len = in_pr_aptpl_buf_len;
+       if (!aptpl) {
+               char *null_buf = "No Registrations or Reservations\n";
+
+               rc = __core_scsi3_write_aptpl_to_file(dev, null_buf);
+               dev->t10_pr.pr_aptpl_active = 0;
+               pr_debug("SPC-3 PR: Set APTPL Bit Deactivated\n");
+
+               if (rc)
+                       return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
+
+               return 0;
        }
 
-       ret = core_scsi3_update_aptpl_buf(dev, buf, pr_aptpl_buf_len,
-                               clear_aptpl_metadata);
-       if (ret != 0)
-               return ret;
+       buf = kzalloc(PR_APTPL_BUF_LEN, GFP_KERNEL);
+       if (!buf)
+               return TCM_OUT_OF_RESOURCES;
 
-       /*
-        * __core_scsi3_write_aptpl_to_file() will call strlen()
-        * on the passed buf to determine pr_aptpl_buf_len.
-        */
-       return __core_scsi3_write_aptpl_to_file(dev, buf, 0);
+       rc = core_scsi3_update_aptpl_buf(dev, buf, PR_APTPL_BUF_LEN);
+       if (rc < 0) {
+               kfree(buf);
+               return TCM_OUT_OF_RESOURCES;
+       }
+
+       rc = __core_scsi3_write_aptpl_to_file(dev, buf);
+       if (rc != 0) {
+               pr_err("SPC-3 PR: Could not update APTPL\n");
+               kfree(buf);
+               return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
+       }
+       dev->t10_pr.pr_aptpl_active = 1;
+       kfree(buf);
+       pr_debug("SPC-3 PR: Set APTPL Bit Activated\n");
+       return 0;
 }
 
 static sense_reason_t
 core_scsi3_emulate_pro_register(struct se_cmd *cmd, u64 res_key, u64 sa_res_key,
-               int aptpl, int all_tg_pt, int spec_i_pt, int ignore_key)
+               bool aptpl, bool all_tg_pt, bool spec_i_pt, enum register_type register_type)
 {
        struct se_session *se_sess = cmd->se_sess;
        struct se_device *dev = cmd->se_dev;
        struct se_dev_entry *se_deve;
        struct se_lun *se_lun = cmd->se_lun;
        struct se_portal_group *se_tpg;
-       struct t10_pr_registration *pr_reg, *pr_reg_p, *pr_reg_tmp, *pr_reg_e;
+       struct t10_pr_registration *pr_reg, *pr_reg_p, *pr_reg_tmp;
        struct t10_reservation *pr_tmpl = &dev->t10_pr;
-       /* Used for APTPL metadata w/ UNREGISTER */
-       unsigned char *pr_aptpl_buf = NULL;
        unsigned char isid_buf[PR_REG_ISID_LEN], *isid_ptr = NULL;
        sense_reason_t ret = TCM_NO_SENSE;
-       int pr_holder = 0, type;
+       int pr_holder = 0;
 
        if (!se_sess || !se_lun) {
                pr_err("SPC-3 PR: se_sess || struct se_lun is NULL!\n");
@@ -2061,8 +2027,8 @@ core_scsi3_emulate_pro_register(struct se_cmd *cmd, u64 res_key, u64 sa_res_key,
        /*
         * Follow logic from spc4r17 Section 5.7.7, Register Behaviors Table 47
         */
-       pr_reg_e = core_scsi3_locate_pr_reg(dev, se_sess->se_node_acl, se_sess);
-       if (!pr_reg_e) {
+       pr_reg = core_scsi3_locate_pr_reg(dev, se_sess->se_node_acl, se_sess);
+       if (!pr_reg) {
                if (res_key) {
                        pr_warn("SPC-3 PR: Reservation Key non-zero"
                                " for SA REGISTER, returning CONFLICT\n");
@@ -2083,7 +2049,7 @@ core_scsi3_emulate_pro_register(struct se_cmd *cmd, u64 res_key, u64 sa_res_key,
                        if (core_scsi3_alloc_registration(cmd->se_dev,
                                        se_sess->se_node_acl, se_deve, isid_ptr,
                                        sa_res_key, all_tg_pt, aptpl,
-                                       ignore_key, 0)) {
+                                       register_type, 0)) {
                                pr_err("Unable to allocate"
                                        " struct t10_pr_registration\n");
                                return TCM_INVALID_PARAMETER_LIST;
@@ -2102,97 +2068,68 @@ core_scsi3_emulate_pro_register(struct se_cmd *cmd, u64 res_key, u64 sa_res_key,
                        if (ret != 0)
                                return ret;
                }
-               /*
-                * Nothing left to do for the APTPL=0 case.
-                */
-               if (!aptpl) {
-                       pr_tmpl->pr_aptpl_active = 0;
-                       core_scsi3_update_and_write_aptpl(cmd->se_dev, NULL, 0);
-                       pr_debug("SPC-3 PR: Set APTPL Bit Deactivated for"
-                                       " REGISTER\n");
-                       return 0;
-               }
-               /*
-                * Locate the newly allocated local I_T Nexus *pr_reg, and
-                * update the APTPL metadata information using its
-                * preallocated *pr_reg->pr_aptpl_buf.
-                */
-               pr_reg = core_scsi3_locate_pr_reg(cmd->se_dev,
-                               se_sess->se_node_acl, se_sess);
-
-               if (core_scsi3_update_and_write_aptpl(cmd->se_dev,
-                               &pr_reg->pr_aptpl_buf[0],
-                               pr_tmpl->pr_aptpl_buf_len)) {
-                       pr_tmpl->pr_aptpl_active = 1;
-                       pr_debug("SPC-3 PR: Set APTPL Bit Activated for REGISTER\n");
-               }
 
-               goto out_put_pr_reg;
+               return core_scsi3_update_and_write_aptpl(dev, aptpl);
        }
 
-       /*
-        * Locate the existing *pr_reg via struct se_node_acl pointers
-        */
-       pr_reg = pr_reg_e;
-       type = pr_reg->pr_res_type;
-
-       if (!ignore_key) {
-               if (res_key != pr_reg->pr_res_key) {
-                       pr_err("SPC-3 PR REGISTER: Received"
-                               " res_key: 0x%016Lx does not match"
-                               " existing SA REGISTER res_key:"
-                               " 0x%016Lx\n", res_key,
-                               pr_reg->pr_res_key);
-                       ret = TCM_RESERVATION_CONFLICT;
-                       goto out_put_pr_reg;
-               }
+       /* ok, existing registration */
+
+       if ((register_type == REGISTER) && (res_key != pr_reg->pr_res_key)) {
+               pr_err("SPC-3 PR REGISTER: Received"
+                      " res_key: 0x%016Lx does not match"
+                      " existing SA REGISTER res_key:"
+                      " 0x%016Lx\n", res_key,
+                      pr_reg->pr_res_key);
+               ret = TCM_RESERVATION_CONFLICT;
+               goto out;
        }
 
        if (spec_i_pt) {
-               pr_err("SPC-3 PR UNREGISTER: SPEC_I_PT"
-                       " set while sa_res_key=0\n");
+               pr_err("SPC-3 PR REGISTER: SPEC_I_PT"
+                       " set on a registered nexus\n");
                ret = TCM_INVALID_PARAMETER_LIST;
-               goto out_put_pr_reg;
+               goto out;
        }
 
        /*
         * An existing ALL_TG_PT=1 registration being released
         * must also set ALL_TG_PT=1 in the incoming PROUT.
         */
-       if (pr_reg->pr_reg_all_tg_pt && !(all_tg_pt)) {
-               pr_err("SPC-3 PR UNREGISTER: ALL_TG_PT=1"
+       if (pr_reg->pr_reg_all_tg_pt && !all_tg_pt) {
+               pr_err("SPC-3 PR REGISTER: ALL_TG_PT=1"
                        " registration exists, but ALL_TG_PT=1 bit not"
                        " present in received PROUT\n");
                ret = TCM_INVALID_CDB_FIELD;
-               goto out_put_pr_reg;
+               goto out;
        }
 
        /*
-        * Allocate APTPL metadata buffer used for UNREGISTER ops
+        * sa_res_key=1 Change Reservation Key for registered I_T Nexus.
         */
-       if (aptpl) {
-               pr_aptpl_buf = kzalloc(pr_tmpl->pr_aptpl_buf_len,
-                                       GFP_KERNEL);
-               if (!pr_aptpl_buf) {
-                       pr_err("Unable to allocate"
-                               " pr_aptpl_buf\n");
-                       ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
-                       goto out_put_pr_reg;
-               }
-       }
+       if (sa_res_key) {
+               /*
+                * Increment PRgeneration counter for struct se_device"
+                * upon a successful REGISTER, see spc4r17 section 6.3.2
+                * READ_KEYS service action.
+                */
+               pr_reg->pr_res_generation = core_scsi3_pr_generation(cmd->se_dev);
+               pr_reg->pr_res_key = sa_res_key;
+               pr_debug("SPC-3 PR [%s] REGISTER%s: Changed Reservation"
+                        " Key for %s to: 0x%016Lx PRgeneration:"
+                        " 0x%08x\n", cmd->se_tfo->get_fabric_name(),
+                        (register_type == REGISTER_AND_IGNORE_EXISTING_KEY) ? "_AND_IGNORE_EXISTING_KEY" : "",
+                        pr_reg->pr_reg_nacl->initiatorname,
+                        pr_reg->pr_res_key, pr_reg->pr_res_generation);
 
-       /*
-        * sa_res_key=0 Unregister Reservation Key for registered I_T
-        * Nexus sa_res_key=1 Change Reservation Key for registered I_T
-        * Nexus.
-        */
-       if (!sa_res_key) {
+       } else {
+               /*
+                * sa_res_key=0 Unregister Reservation Key for registered I_T Nexus.
+                */
                pr_holder = core_scsi3_check_implict_release(
                                cmd->se_dev, pr_reg);
                if (pr_holder < 0) {
-                       kfree(pr_aptpl_buf);
                        ret = TCM_RESERVATION_CONFLICT;
-                       goto out_put_pr_reg;
+                       goto out;
                }
 
                spin_lock(&pr_tmpl->registration_lock);
@@ -2237,8 +2174,8 @@ core_scsi3_emulate_pro_register(struct se_cmd *cmd, u64 res_key, u64 sa_res_key,
                 * RESERVATIONS RELEASED.
                 */
                if (pr_holder &&
-                  (type == PR_TYPE_WRITE_EXCLUSIVE_REGONLY ||
-                   type == PR_TYPE_EXCLUSIVE_ACCESS_REGONLY)) {
+                   (pr_reg->pr_res_type == PR_TYPE_WRITE_EXCLUSIVE_REGONLY ||
+                    pr_reg->pr_res_type == PR_TYPE_EXCLUSIVE_ACCESS_REGONLY)) {
                        list_for_each_entry(pr_reg_p,
                                        &pr_tmpl->registration_list,
                                        pr_reg_list) {
@@ -2250,60 +2187,13 @@ core_scsi3_emulate_pro_register(struct se_cmd *cmd, u64 res_key, u64 sa_res_key,
                                        ASCQ_2AH_RESERVATIONS_RELEASED);
                        }
                }
-               spin_unlock(&pr_tmpl->registration_lock);
-
-               if (!aptpl) {
-                       pr_tmpl->pr_aptpl_active = 0;
-                       core_scsi3_update_and_write_aptpl(dev, NULL, 0);
-                       pr_debug("SPC-3 PR: Set APTPL Bit Deactivated"
-                                       " for UNREGISTER\n");
-                       return 0;
-               }
 
-               if (!core_scsi3_update_and_write_aptpl(dev, &pr_aptpl_buf[0],
-                               pr_tmpl->pr_aptpl_buf_len)) {
-                       pr_tmpl->pr_aptpl_active = 1;
-                       pr_debug("SPC-3 PR: Set APTPL Bit Activated"
-                                       " for UNREGISTER\n");
-               }
-
-               goto out_free_aptpl_buf;
-       }
-
-       /*
-        * Increment PRgeneration counter for struct se_device"
-        * upon a successful REGISTER, see spc4r17 section 6.3.2
-        * READ_KEYS service action.
-        */
-       pr_reg->pr_res_generation = core_scsi3_pr_generation(cmd->se_dev);
-       pr_reg->pr_res_key = sa_res_key;
-       pr_debug("SPC-3 PR [%s] REGISTER%s: Changed Reservation"
-               " Key for %s to: 0x%016Lx PRgeneration:"
-               " 0x%08x\n", cmd->se_tfo->get_fabric_name(),
-               (ignore_key) ? "_AND_IGNORE_EXISTING_KEY" : "",
-               pr_reg->pr_reg_nacl->initiatorname,
-               pr_reg->pr_res_key, pr_reg->pr_res_generation);
-
-       if (!aptpl) {
-               pr_tmpl->pr_aptpl_active = 0;
-               core_scsi3_update_and_write_aptpl(dev, NULL, 0);
-               pr_debug("SPC-3 PR: Set APTPL Bit Deactivated"
-                               " for REGISTER\n");
-               ret = 0;
-               goto out_put_pr_reg;
+               spin_unlock(&pr_tmpl->registration_lock);
        }
 
-       if (!core_scsi3_update_and_write_aptpl(dev, &pr_aptpl_buf[0],
-                                               pr_tmpl->pr_aptpl_buf_len)) {
-               pr_tmpl->pr_aptpl_active = 1;
-               pr_debug("SPC-3 PR: Set APTPL Bit Activated"
-                       " for REGISTER\n");
-       }
+       ret = core_scsi3_update_and_write_aptpl(dev, aptpl);
 
-out_free_aptpl_buf:
-       kfree(pr_aptpl_buf);
-       ret = 0;
-out_put_pr_reg:
+out:
        core_scsi3_put_pr_reg(pr_reg);
        return ret;
 }
@@ -2340,7 +2230,6 @@ core_scsi3_pro_reserve(struct se_cmd *cmd, int type, int scope, u64 res_key)
        struct t10_reservation *pr_tmpl = &dev->t10_pr;
        char i_buf[PR_REG_ISID_ID_LEN];
        sense_reason_t ret;
-       int prf_isid;
 
        memset(i_buf, 0, PR_REG_ISID_ID_LEN);
 
@@ -2466,8 +2355,7 @@ core_scsi3_pro_reserve(struct se_cmd *cmd, int type, int scope, u64 res_key)
        pr_reg->pr_res_type = type;
        pr_reg->pr_res_holder = 1;
        dev->dev_pr_res_holder = pr_reg;
-       prf_isid = core_pr_dump_initiator_port(pr_reg, &i_buf[0],
-                               PR_REG_ISID_ID_LEN);
+       core_pr_dump_initiator_port(pr_reg, i_buf, PR_REG_ISID_ID_LEN);
 
        pr_debug("SPC-3 PR [%s] Service Action: RESERVE created new"
                " reservation holder TYPE: %s ALL_TG_PT: %d\n",
@@ -2476,17 +2364,11 @@ core_scsi3_pro_reserve(struct se_cmd *cmd, int type, int scope, u64 res_key)
        pr_debug("SPC-3 PR [%s] RESERVE Node: %s%s\n",
                        cmd->se_tfo->get_fabric_name(),
                        se_sess->se_node_acl->initiatorname,
-                       (prf_isid) ? &i_buf[0] : "");
+                       i_buf);
        spin_unlock(&dev->dev_reservation_lock);
 
-       if (pr_tmpl->pr_aptpl_active) {
-               if (!core_scsi3_update_and_write_aptpl(cmd->se_dev,
-                               &pr_reg->pr_aptpl_buf[0],
-                               pr_tmpl->pr_aptpl_buf_len)) {
-                       pr_debug("SPC-3 PR: Updated APTPL metadata"
-                                       " for RESERVE\n");
-               }
-       }
+       if (pr_tmpl->pr_aptpl_active)
+               core_scsi3_update_and_write_aptpl(cmd->se_dev, true);
 
        ret = 0;
 out_put_pr_reg:
@@ -2524,11 +2406,9 @@ static void __core_scsi3_complete_pro_release(
 {
        struct target_core_fabric_ops *tfo = se_nacl->se_tpg->se_tpg_tfo;
        char i_buf[PR_REG_ISID_ID_LEN];
-       int prf_isid;
 
        memset(i_buf, 0, PR_REG_ISID_ID_LEN);
-       prf_isid = core_pr_dump_initiator_port(pr_reg, &i_buf[0],
-                               PR_REG_ISID_ID_LEN);
+       core_pr_dump_initiator_port(pr_reg, i_buf, PR_REG_ISID_ID_LEN);
        /*
         * Go ahead and release the current PR reservation holder.
         */
@@ -2541,7 +2421,7 @@ static void __core_scsi3_complete_pro_release(
                (pr_reg->pr_reg_all_tg_pt) ? 1 : 0);
        pr_debug("SPC-3 PR [%s] RELEASE Node: %s%s\n",
                tfo->get_fabric_name(), se_nacl->initiatorname,
-               (prf_isid) ? &i_buf[0] : "");
+               i_buf);
        /*
         * Clear TYPE and SCOPE for the next PROUT Service Action: RESERVE
         */
@@ -2702,12 +2582,9 @@ core_scsi3_emulate_pro_release(struct se_cmd *cmd, int type, int scope,
        spin_unlock(&pr_tmpl->registration_lock);
 
 write_aptpl:
-       if (pr_tmpl->pr_aptpl_active) {
-               if (!core_scsi3_update_and_write_aptpl(cmd->se_dev,
-                       &pr_reg->pr_aptpl_buf[0], pr_tmpl->pr_aptpl_buf_len)) {
-                       pr_debug("SPC-3 PR: Updated APTPL metadata for RELEASE\n");
-               }
-       }
+       if (pr_tmpl->pr_aptpl_active)
+               core_scsi3_update_and_write_aptpl(cmd->se_dev, true);
+
 out_put_pr_reg:
        core_scsi3_put_pr_reg(pr_reg);
        return ret;
@@ -2791,11 +2668,7 @@ core_scsi3_emulate_pro_clear(struct se_cmd *cmd, u64 res_key)
        pr_debug("SPC-3 PR [%s] Service Action: CLEAR complete\n",
                cmd->se_tfo->get_fabric_name());
 
-       if (pr_tmpl->pr_aptpl_active) {
-               core_scsi3_update_and_write_aptpl(cmd->se_dev, NULL, 0);
-               pr_debug("SPC-3 PR: Updated APTPL metadata"
-                               " for CLEAR\n");
-       }
+       core_scsi3_update_and_write_aptpl(cmd->se_dev, false);
 
        core_scsi3_pr_generation(dev);
        return 0;
@@ -2810,16 +2683,14 @@ static void __core_scsi3_complete_pro_preempt(
        struct list_head *preempt_and_abort_list,
        int type,
        int scope,
-       int abort)
+       enum preempt_type preempt_type)
 {
        struct se_node_acl *nacl = pr_reg->pr_reg_nacl;
        struct target_core_fabric_ops *tfo = nacl->se_tpg->se_tpg_tfo;
        char i_buf[PR_REG_ISID_ID_LEN];
-       int prf_isid;
 
        memset(i_buf, 0, PR_REG_ISID_ID_LEN);
-       prf_isid = core_pr_dump_initiator_port(pr_reg, &i_buf[0],
-                               PR_REG_ISID_ID_LEN);
+       core_pr_dump_initiator_port(pr_reg, i_buf, PR_REG_ISID_ID_LEN);
        /*
         * Do an implict RELEASE of the existing reservation.
         */
@@ -2834,12 +2705,12 @@ static void __core_scsi3_complete_pro_preempt(
 
        pr_debug("SPC-3 PR [%s] Service Action: PREEMPT%s created new"
                " reservation holder TYPE: %s ALL_TG_PT: %d\n",
-               tfo->get_fabric_name(), (abort) ? "_AND_ABORT" : "",
+               tfo->get_fabric_name(), (preempt_type == PREEMPT_AND_ABORT) ? "_AND_ABORT" : "",
                core_scsi3_pr_dump_type(type),
                (pr_reg->pr_reg_all_tg_pt) ? 1 : 0);
        pr_debug("SPC-3 PR [%s] PREEMPT%s from Node: %s%s\n",
-               tfo->get_fabric_name(), (abort) ? "_AND_ABORT" : "",
-               nacl->initiatorname, (prf_isid) ? &i_buf[0] : "");
+               tfo->get_fabric_name(), (preempt_type == PREEMPT_AND_ABORT) ? "_AND_ABORT" : "",
+               nacl->initiatorname, i_buf);
        /*
         * For PREEMPT_AND_ABORT, add the preempting reservation's
         * struct t10_pr_registration to the list that will be compared
@@ -2869,14 +2740,13 @@ static void core_scsi3_release_preempt_and_abort(
 
                pr_reg->pr_reg_deve = NULL;
                pr_reg->pr_reg_nacl = NULL;
-               kfree(pr_reg->pr_aptpl_buf);
                kmem_cache_free(t10_pr_reg_cache, pr_reg);
        }
 }
 
 static sense_reason_t
 core_scsi3_pro_preempt(struct se_cmd *cmd, int type, int scope, u64 res_key,
-               u64 sa_res_key, int abort)
+               u64 sa_res_key, enum preempt_type preempt_type)
 {
        struct se_device *dev = cmd->se_dev;
        struct se_node_acl *pr_reg_nacl;
@@ -2896,7 +2766,7 @@ core_scsi3_pro_preempt(struct se_cmd *cmd, int type, int scope, u64 res_key,
        if (!pr_reg_n) {
                pr_err("SPC-3 PR: Unable to locate"
                        " PR_REGISTERED *pr_reg for PREEMPT%s\n",
-                       (abort) ? "_AND_ABORT" : "");
+                       (preempt_type == PREEMPT_AND_ABORT) ? "_AND_ABORT" : "");
                return TCM_RESERVATION_CONFLICT;
        }
        if (pr_reg_n->pr_res_key != res_key) {
@@ -2965,7 +2835,7 @@ core_scsi3_pro_preempt(struct se_cmd *cmd, int type, int scope, u64 res_key,
                                pr_reg_nacl = pr_reg->pr_reg_nacl;
                                pr_res_mapped_lun = pr_reg->pr_res_mapped_lun;
                                __core_scsi3_free_registration(dev, pr_reg,
-                                       (abort) ? &preempt_and_abort_list :
+                                       (preempt_type == PREEMPT_AND_ABORT) ? &preempt_and_abort_list :
                                                NULL, calling_it_nexus);
                                released_regs++;
                        } else {
@@ -2993,7 +2863,7 @@ core_scsi3_pro_preempt(struct se_cmd *cmd, int type, int scope, u64 res_key,
                                pr_reg_nacl = pr_reg->pr_reg_nacl;
                                pr_res_mapped_lun = pr_reg->pr_res_mapped_lun;
                                __core_scsi3_free_registration(dev, pr_reg,
-                                       (abort) ? &preempt_and_abort_list :
+                                       (preempt_type == PREEMPT_AND_ABORT) ? &preempt_and_abort_list :
                                                NULL, 0);
                                released_regs++;
                        }
@@ -3022,24 +2892,17 @@ core_scsi3_pro_preempt(struct se_cmd *cmd, int type, int scope, u64 res_key,
                 */
                if (pr_res_holder && all_reg && !(sa_res_key)) {
                        __core_scsi3_complete_pro_preempt(dev, pr_reg_n,
-                               (abort) ? &preempt_and_abort_list : NULL,
-                               type, scope, abort);
+                               (preempt_type == PREEMPT_AND_ABORT) ? &preempt_and_abort_list : NULL,
+                               type, scope, preempt_type);
 
-                       if (abort)
+                       if (preempt_type == PREEMPT_AND_ABORT)
                                core_scsi3_release_preempt_and_abort(
                                        &preempt_and_abort_list, pr_reg_n);
                }
                spin_unlock(&dev->dev_reservation_lock);
 
-               if (pr_tmpl->pr_aptpl_active) {
-                       if (!core_scsi3_update_and_write_aptpl(cmd->se_dev,
-                                       &pr_reg_n->pr_aptpl_buf[0],
-                                       pr_tmpl->pr_aptpl_buf_len)) {
-                               pr_debug("SPC-3 PR: Updated APTPL"
-                                       " metadata for  PREEMPT%s\n", (abort) ?
-                                       "_AND_ABORT" : "");
-                       }
-               }
+               if (pr_tmpl->pr_aptpl_active)
+                       core_scsi3_update_and_write_aptpl(cmd->se_dev, true);
 
                core_scsi3_put_pr_reg(pr_reg_n);
                core_scsi3_pr_generation(cmd->se_dev);
@@ -3103,7 +2966,7 @@ core_scsi3_pro_preempt(struct se_cmd *cmd, int type, int scope, u64 res_key,
                pr_reg_nacl = pr_reg->pr_reg_nacl;
                pr_res_mapped_lun = pr_reg->pr_res_mapped_lun;
                __core_scsi3_free_registration(dev, pr_reg,
-                               (abort) ? &preempt_and_abort_list : NULL,
+                               (preempt_type == PREEMPT_AND_ABORT) ? &preempt_and_abort_list : NULL,
                                calling_it_nexus);
                /*
                 * e) Establish a unit attention condition for the initiator
@@ -3120,8 +2983,8 @@ core_scsi3_pro_preempt(struct se_cmd *cmd, int type, int scope, u64 res_key,
         *    I_T nexus using the contents of the SCOPE and TYPE fields;
         */
        __core_scsi3_complete_pro_preempt(dev, pr_reg_n,
-                       (abort) ? &preempt_and_abort_list : NULL,
-                       type, scope, abort);
+                       (preempt_type == PREEMPT_AND_ABORT) ? &preempt_and_abort_list : NULL,
+                       type, scope, preempt_type);
        /*
         * d) Process tasks as defined in 5.7.1;
         * e) See above..
@@ -3161,20 +3024,14 @@ core_scsi3_pro_preempt(struct se_cmd *cmd, int type, int scope, u64 res_key,
         * been removed from the primary pr_reg list), except the
         * new persistent reservation holder, the calling Initiator Port.
         */
-       if (abort) {
+       if (preempt_type == PREEMPT_AND_ABORT) {
                core_tmr_lun_reset(dev, NULL, &preempt_and_abort_list, cmd);
                core_scsi3_release_preempt_and_abort(&preempt_and_abort_list,
                                                pr_reg_n);
        }
 
-       if (pr_tmpl->pr_aptpl_active) {
-               if (!core_scsi3_update_and_write_aptpl(cmd->se_dev,
-                               &pr_reg_n->pr_aptpl_buf[0],
-                               pr_tmpl->pr_aptpl_buf_len)) {
-                       pr_debug("SPC-3 PR: Updated APTPL metadata for PREEMPT"
-                               "%s\n", abort ? "_AND_ABORT" : "");
-               }
-       }
+       if (pr_tmpl->pr_aptpl_active)
+               core_scsi3_update_and_write_aptpl(cmd->se_dev, true);
 
        core_scsi3_put_pr_reg(pr_reg_n);
        core_scsi3_pr_generation(cmd->se_dev);
@@ -3183,7 +3040,7 @@ core_scsi3_pro_preempt(struct se_cmd *cmd, int type, int scope, u64 res_key,
 
 static sense_reason_t
 core_scsi3_emulate_pro_preempt(struct se_cmd *cmd, int type, int scope,
-               u64 res_key, u64 sa_res_key, int abort)
+               u64 res_key, u64 sa_res_key, enum preempt_type preempt_type)
 {
        switch (type) {
        case PR_TYPE_WRITE_EXCLUSIVE:
@@ -3193,10 +3050,10 @@ core_scsi3_emulate_pro_preempt(struct se_cmd *cmd, int type, int scope,
        case PR_TYPE_WRITE_EXCLUSIVE_ALLREG:
        case PR_TYPE_EXCLUSIVE_ACCESS_ALLREG:
                return core_scsi3_pro_preempt(cmd, type, scope, res_key,
-                                             sa_res_key, abort);
+                                             sa_res_key, preempt_type);
        default:
                pr_err("SPC-3 PR: Unknown Service Action PREEMPT%s"
-                       " Type: 0x%02x\n", (abort) ? "_AND_ABORT" : "", type);
+                       " Type: 0x%02x\n", (preempt_type == PREEMPT_AND_ABORT) ? "_AND_ABORT" : "", type);
                return TCM_INVALID_CDB_FIELD;
        }
 }
@@ -3220,7 +3077,7 @@ core_scsi3_emulate_pro_register_and_move(struct se_cmd *cmd, u64 res_key,
        unsigned char *initiator_str;
        char *iport_ptr = NULL, dest_iport[64], i_buf[PR_REG_ISID_ID_LEN];
        u32 tid_len, tmp_tid_len;
-       int new_reg = 0, type, scope, matching_iname, prf_isid;
+       int new_reg = 0, type, scope, matching_iname;
        sense_reason_t ret;
        unsigned short rtpi;
        unsigned char proto_ident;
@@ -3564,8 +3421,7 @@ after_iport_check:
        dest_pr_reg->pr_res_holder = 1;
        dest_pr_reg->pr_res_type = type;
        pr_reg->pr_res_scope = scope;
-       prf_isid = core_pr_dump_initiator_port(pr_reg, &i_buf[0],
-                               PR_REG_ISID_ID_LEN);
+       core_pr_dump_initiator_port(pr_reg, i_buf, PR_REG_ISID_ID_LEN);
        /*
         * Increment PRGeneration for existing registrations..
         */
@@ -3581,7 +3437,7 @@ after_iport_check:
        pr_debug("SPC-3 PR Successfully moved reservation from"
                " %s Fabric Node: %s%s -> %s Fabric Node: %s %s\n",
                tf_ops->get_fabric_name(), pr_reg_nacl->initiatorname,
-               (prf_isid) ? &i_buf[0] : "", dest_tf_ops->get_fabric_name(),
+               i_buf, dest_tf_ops->get_fabric_name(),
                dest_node_acl->initiatorname, (iport_ptr != NULL) ?
                iport_ptr : "");
        /*
@@ -3602,24 +3458,7 @@ after_iport_check:
        } else
                core_scsi3_put_pr_reg(pr_reg);
 
-       /*
-        * Clear the APTPL metadata if APTPL has been disabled, otherwise
-        * write out the updated metadata to struct file for this SCSI device.
-        */
-       if (!aptpl) {
-               pr_tmpl->pr_aptpl_active = 0;
-               core_scsi3_update_and_write_aptpl(cmd->se_dev, NULL, 0);
-               pr_debug("SPC-3 PR: Set APTPL Bit Deactivated for"
-                               " REGISTER_AND_MOVE\n");
-       } else {
-               pr_tmpl->pr_aptpl_active = 1;
-               if (!core_scsi3_update_and_write_aptpl(cmd->se_dev,
-                               &dest_pr_reg->pr_aptpl_buf[0],
-                               pr_tmpl->pr_aptpl_buf_len)) {
-                       pr_debug("SPC-3 PR: Set APTPL Bit Activated for"
-                                       " REGISTER_AND_MOVE\n");
-               }
-       }
+       core_scsi3_update_and_write_aptpl(cmd->se_dev, aptpl);
 
        transport_kunmap_data_sg(cmd);
 
@@ -3752,7 +3591,7 @@ target_scsi3_emulate_pr_out(struct se_cmd *cmd)
        switch (sa) {
        case PRO_REGISTER:
                ret = core_scsi3_emulate_pro_register(cmd,
-                       res_key, sa_res_key, aptpl, all_tg_pt, spec_i_pt, 0);
+                       res_key, sa_res_key, aptpl, all_tg_pt, spec_i_pt, REGISTER);
                break;
        case PRO_RESERVE:
                ret = core_scsi3_emulate_pro_reserve(cmd, type, scope, res_key);
@@ -3765,15 +3604,15 @@ target_scsi3_emulate_pr_out(struct se_cmd *cmd)
                break;
        case PRO_PREEMPT:
                ret = core_scsi3_emulate_pro_preempt(cmd, type, scope,
-                                       res_key, sa_res_key, 0);
+                                       res_key, sa_res_key, PREEMPT);
                break;
        case PRO_PREEMPT_AND_ABORT:
                ret = core_scsi3_emulate_pro_preempt(cmd, type, scope,
-                                       res_key, sa_res_key, 1);
+                                       res_key, sa_res_key, PREEMPT_AND_ABORT);
                break;
        case PRO_REGISTER_AND_IGNORE_EXISTING_KEY:
                ret = core_scsi3_emulate_pro_register(cmd,
-                       0, sa_res_key, aptpl, all_tg_pt, spec_i_pt, 1);
+                       0, sa_res_key, aptpl, all_tg_pt, spec_i_pt, REGISTER_AND_IGNORE_EXISTING_KEY);
                break;
        case PRO_REGISTER_AND_MOVE:
                ret = core_scsi3_emulate_pro_register_and_move(cmd, res_key,
index b4a0042..ed75cdd 100644 (file)
@@ -45,7 +45,7 @@
 
 extern struct kmem_cache *t10_pr_reg_cache;
 
-extern int core_pr_dump_initiator_port(struct t10_pr_registration *,
+extern void core_pr_dump_initiator_port(struct t10_pr_registration *,
                        char *, u32);
 extern sense_reason_t target_scsi2_reservation_release(struct se_cmd *);
 extern sense_reason_t target_scsi2_reservation_reserve(struct se_cmd *);
index 0921a64..51127d1 100644 (file)
@@ -139,6 +139,11 @@ static int rd_build_device_space(struct rd_dev *rd_dev)
                        rd_dev->rd_page_count);
                return -EINVAL;
        }
+
+       /* Don't need backing pages for NULLIO */
+       if (rd_dev->rd_flags & RDF_NULLIO)
+               return 0;
+
        total_sg_needed = rd_dev->rd_page_count;
 
        sg_tables = (total_sg_needed / max_sg_per_table) + 1;
index bbc5b0e..8a46277 100644 (file)
@@ -38,11 +38,27 @@ static sense_reason_t
 sbc_emulate_readcapacity(struct se_cmd *cmd)
 {
        struct se_device *dev = cmd->se_dev;
+       unsigned char *cdb = cmd->t_task_cdb;
        unsigned long long blocks_long = dev->transport->get_blocks(dev);
        unsigned char *rbuf;
        unsigned char buf[8];
        u32 blocks;
 
+       /*
+        * SBC-2 says:
+        *   If the PMI bit is set to zero and the LOGICAL BLOCK
+        *   ADDRESS field is not set to zero, the device server shall
+        *   terminate the command with CHECK CONDITION status with
+        *   the sense key set to ILLEGAL REQUEST and the additional
+        *   sense code set to INVALID FIELD IN CDB.
+        *
+        * In SBC-3, these fields are obsolete, but some SCSI
+        * compliance tests actually check this, so we might as well
+        * follow SBC-2.
+        */
+       if (!(cdb[8] & 1) && !!(cdb[2] | cdb[3] | cdb[4] | cdb[5]))
+               return TCM_INVALID_CDB_FIELD;
+
        if (blocks_long >= 0x00000000ffffffff)
                blocks = 0xffffffff;
        else
@@ -581,7 +597,7 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops)
                        pr_err("cmd exceeds last lba %llu "
                                "(lba %llu, sectors %u)\n",
                                end_lba, cmd->t_task_lba, sectors);
-                       return TCM_INVALID_CDB_FIELD;
+                       return TCM_ADDRESS_OUT_OF_RANGE;
                }
 
                size = sbc_get_size(cmd, sectors);
index d0b4dd9..0d7cacb 100644 (file)
@@ -85,13 +85,8 @@ void core_tmr_release_req(
 static void core_tmr_handle_tas_abort(
        struct se_node_acl *tmr_nacl,
        struct se_cmd *cmd,
-       int tas,
-       int fe_count)
+       int tas)
 {
-       if (!fe_count) {
-               transport_cmd_finish_abort(cmd, 1);
-               return;
-       }
        /*
         * TASK ABORTED status (TAS) bit support
        */
@@ -253,7 +248,6 @@ static void core_tmr_drain_state_list(
        LIST_HEAD(drain_task_list);
        struct se_cmd *cmd, *next;
        unsigned long flags;
-       int fe_count;
 
        /*
         * Complete outstanding commands with TASK_ABORTED SAM status.
@@ -329,12 +323,10 @@ static void core_tmr_drain_state_list(
                spin_lock_irqsave(&cmd->t_state_lock, flags);
                target_stop_cmd(cmd, &flags);
 
-               fe_count = atomic_read(&cmd->t_fe_count);
-
                cmd->transport_state |= CMD_T_ABORTED;
                spin_unlock_irqrestore(&cmd->t_state_lock, flags);
 
-               core_tmr_handle_tas_abort(tmr_nacl, cmd, tas, fe_count);
+               core_tmr_handle_tas_abort(tmr_nacl, cmd, tas);
        }
 }
 
index 21e3158..7172d00 100644 (file)
@@ -52,6 +52,9 @@
 #include "target_core_pr.h"
 #include "target_core_ua.h"
 
+#define CREATE_TRACE_POINTS
+#include <trace/events/target.h>
+
 static struct workqueue_struct *target_completion_wq;
 static struct kmem_cache *se_sess_cache;
 struct kmem_cache *se_ua_cache;
@@ -446,11 +449,15 @@ static void target_remove_from_state_list(struct se_cmd *cmd)
        spin_unlock_irqrestore(&dev->execute_task_lock, flags);
 }
 
-static int transport_cmd_check_stop(struct se_cmd *cmd, bool remove_from_lists)
+static int transport_cmd_check_stop(struct se_cmd *cmd, bool remove_from_lists,
+                                   bool write_pending)
 {
        unsigned long flags;
 
        spin_lock_irqsave(&cmd->t_state_lock, flags);
+       if (write_pending)
+               cmd->t_state = TRANSPORT_WRITE_PENDING;
+
        /*
         * Determine if IOCTL context caller in requesting the stopping of this
         * command for LUN shutdown purposes.
@@ -515,7 +522,7 @@ static int transport_cmd_check_stop(struct se_cmd *cmd, bool remove_from_lists)
 
 static int transport_cmd_check_stop_to_fabric(struct se_cmd *cmd)
 {
-       return transport_cmd_check_stop(cmd, true);
+       return transport_cmd_check_stop(cmd, true, false);
 }
 
 static void transport_lun_remove_cmd(struct se_cmd *cmd)
@@ -526,13 +533,6 @@ static void transport_lun_remove_cmd(struct se_cmd *cmd)
        if (!lun)
                return;
 
-       spin_lock_irqsave(&cmd->t_state_lock, flags);
-       if (cmd->transport_state & CMD_T_DEV_ACTIVE) {
-               cmd->transport_state &= ~CMD_T_DEV_ACTIVE;
-               target_remove_from_state_list(cmd);
-       }
-       spin_unlock_irqrestore(&cmd->t_state_lock, flags);
-
        spin_lock_irqsave(&lun->lun_cmd_lock, flags);
        if (!list_empty(&cmd->se_lun_node))
                list_del_init(&cmd->se_lun_node);
@@ -1092,7 +1092,6 @@ sense_reason_t
 target_setup_cmd_from_cdb(struct se_cmd *cmd, unsigned char *cdb)
 {
        struct se_device *dev = cmd->se_dev;
-       unsigned long flags;
        sense_reason_t ret;
 
        /*
@@ -1127,6 +1126,8 @@ target_setup_cmd_from_cdb(struct se_cmd *cmd, unsigned char *cdb)
         */
        memcpy(cmd->t_task_cdb, cdb, scsi_command_size(cdb));
 
+       trace_target_sequencer_start(cmd);
+
        /*
         * Check for an existing UNIT ATTENTION condition
         */
@@ -1152,9 +1153,7 @@ target_setup_cmd_from_cdb(struct se_cmd *cmd, unsigned char *cdb)
        if (ret)
                return ret;
 
-       spin_lock_irqsave(&cmd->t_state_lock, flags);
        cmd->se_cmd_flags |= SCF_SUPPORTED_SAM_OPCODE;
-       spin_unlock_irqrestore(&cmd->t_state_lock, flags);
 
        spin_lock(&cmd->se_lun->lun_sep_lock);
        if (cmd->se_lun->lun_sep)
@@ -1552,7 +1551,8 @@ void transport_generic_request_failure(struct se_cmd *cmd,
                                cmd->orig_fe_lun, 0x2C,
                                ASCQ_2CH_PREVIOUS_RESERVATION_CONFLICT_STATUS);
 
-               ret = cmd->se_tfo->queue_status(cmd);
+               trace_target_cmd_complete(cmd);
+               ret = cmd->se_tfo-> queue_status(cmd);
                if (ret == -EAGAIN || ret == -ENOMEM)
                        goto queue_full;
                goto check_stop;
@@ -1583,10 +1583,6 @@ static void __target_execute_cmd(struct se_cmd *cmd)
 {
        sense_reason_t ret;
 
-       spin_lock_irq(&cmd->t_state_lock);
-       cmd->transport_state |= (CMD_T_BUSY|CMD_T_SENT);
-       spin_unlock_irq(&cmd->t_state_lock);
-
        if (cmd->execute_cmd) {
                ret = cmd->execute_cmd(cmd);
                if (ret) {
@@ -1693,11 +1689,17 @@ void target_execute_cmd(struct se_cmd *cmd)
        }
 
        cmd->t_state = TRANSPORT_PROCESSING;
-       cmd->transport_state |= CMD_T_ACTIVE;
+       cmd->transport_state |= CMD_T_ACTIVE|CMD_T_BUSY|CMD_T_SENT;
        spin_unlock_irq(&cmd->t_state_lock);
 
-       if (!target_handle_task_attr(cmd))
-               __target_execute_cmd(cmd);
+       if (target_handle_task_attr(cmd)) {
+               spin_lock_irq(&cmd->t_state_lock);
+               cmd->transport_state &= ~CMD_T_BUSY|CMD_T_SENT;
+               spin_unlock_irq(&cmd->t_state_lock);
+               return;
+       }
+
+       __target_execute_cmd(cmd);
 }
 EXPORT_SYMBOL(target_execute_cmd);
 
@@ -1770,6 +1772,7 @@ static void transport_complete_qf(struct se_cmd *cmd)
        transport_complete_task_attr(cmd);
 
        if (cmd->se_cmd_flags & SCF_TRANSPORT_TASK_SENSE) {
+               trace_target_cmd_complete(cmd);
                ret = cmd->se_tfo->queue_status(cmd);
                if (ret)
                        goto out;
@@ -1777,6 +1780,7 @@ static void transport_complete_qf(struct se_cmd *cmd)
 
        switch (cmd->data_direction) {
        case DMA_FROM_DEVICE:
+               trace_target_cmd_complete(cmd);
                ret = cmd->se_tfo->queue_data_in(cmd);
                break;
        case DMA_TO_DEVICE:
@@ -1787,6 +1791,7 @@ static void transport_complete_qf(struct se_cmd *cmd)
                }
                /* Fall through for DMA_TO_DEVICE */
        case DMA_NONE:
+               trace_target_cmd_complete(cmd);
                ret = cmd->se_tfo->queue_status(cmd);
                break;
        default:
@@ -1865,6 +1870,7 @@ static void target_complete_ok_work(struct work_struct *work)
                }
                spin_unlock(&cmd->se_lun->lun_sep_lock);
 
+               trace_target_cmd_complete(cmd);
                ret = cmd->se_tfo->queue_data_in(cmd);
                if (ret == -EAGAIN || ret == -ENOMEM)
                        goto queue_full;
@@ -1893,6 +1899,7 @@ static void target_complete_ok_work(struct work_struct *work)
                }
                /* Fall through for DMA_TO_DEVICE */
        case DMA_NONE:
+               trace_target_cmd_complete(cmd);
                ret = cmd->se_tfo->queue_status(cmd);
                if (ret == -EAGAIN || ret == -ENOMEM)
                        goto queue_full;
@@ -1956,11 +1963,7 @@ static int transport_release_cmd(struct se_cmd *cmd)
         * If this cmd has been setup with target_get_sess_cmd(), drop
         * the kref and call ->release_cmd() in kref callback.
         */
-        if (cmd->check_release != 0)
-               return target_put_sess_cmd(cmd->se_sess, cmd);
-
-       cmd->se_tfo->release_cmd(cmd);
-       return 1;
+       return target_put_sess_cmd(cmd->se_sess, cmd);
 }
 
 /**
@@ -1971,21 +1974,6 @@ static int transport_release_cmd(struct se_cmd *cmd)
  */
 static int transport_put_cmd(struct se_cmd *cmd)
 {
-       unsigned long flags;
-
-       spin_lock_irqsave(&cmd->t_state_lock, flags);
-       if (atomic_read(&cmd->t_fe_count) &&
-           !atomic_dec_and_test(&cmd->t_fe_count)) {
-               spin_unlock_irqrestore(&cmd->t_state_lock, flags);
-               return 0;
-       }
-
-       if (cmd->transport_state & CMD_T_DEV_ACTIVE) {
-               cmd->transport_state &= ~CMD_T_DEV_ACTIVE;
-               target_remove_from_state_list(cmd);
-       }
-       spin_unlock_irqrestore(&cmd->t_state_lock, flags);
-
        transport_free_pages(cmd);
        return transport_release_cmd(cmd);
 }
@@ -2103,9 +2091,6 @@ transport_generic_new_cmd(struct se_cmd *cmd)
                if (ret < 0)
                        return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
        }
-
-       atomic_inc(&cmd->t_fe_count);
-
        /*
         * If this command is not a write we can execute it right here,
         * for write buffers we need to notify the fabric driver first
@@ -2116,12 +2101,7 @@ transport_generic_new_cmd(struct se_cmd *cmd)
                target_execute_cmd(cmd);
                return 0;
        }
-
-       spin_lock_irq(&cmd->t_state_lock);
-       cmd->t_state = TRANSPORT_WRITE_PENDING;
-       spin_unlock_irq(&cmd->t_state_lock);
-
-       transport_cmd_check_stop(cmd, false);
+       transport_cmd_check_stop(cmd, false, true);
 
        ret = cmd->se_tfo->write_pending(cmd);
        if (ret == -EAGAIN || ret == -ENOMEM)
@@ -2202,8 +2182,6 @@ int target_get_sess_cmd(struct se_session *se_sess, struct se_cmd *se_cmd,
                goto out;
        }
        list_add_tail(&se_cmd->se_cmd_list, &se_sess->sess_cmd_list);
-       se_cmd->check_release = 1;
-
 out:
        spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
        return ret;
@@ -2319,7 +2297,7 @@ static int transport_lun_wait_for_tasks(struct se_cmd *cmd, struct se_lun *lun)
                pr_debug("ConfigFS ITT[0x%08x] - CMD_T_STOP, skipping\n",
                         cmd->se_tfo->get_task_tag(cmd));
                spin_unlock_irqrestore(&cmd->t_state_lock, flags);
-               transport_cmd_check_stop(cmd, false);
+               transport_cmd_check_stop(cmd, false, false);
                return -EPERM;
        }
        cmd->transport_state |= CMD_T_LUN_FE_STOP;
@@ -2427,7 +2405,7 @@ check_cond:
 
                        spin_unlock_irqrestore(&cmd->t_state_lock,
                                        cmd_flags);
-                       transport_cmd_check_stop(cmd, false);
+                       transport_cmd_check_stop(cmd, false, false);
                        complete(&cmd->transport_lun_fe_stop_comp);
                        spin_lock_irqsave(&lun->lun_cmd_lock, lun_flags);
                        continue;
@@ -2778,6 +2756,7 @@ transport_send_check_condition_and_sense(struct se_cmd *cmd,
        cmd->scsi_sense_length  = TRANSPORT_SENSE_BUFFER;
 
 after_reason:
+       trace_target_cmd_complete(cmd);
        return cmd->se_tfo->queue_status(cmd);
 }
 EXPORT_SYMBOL(transport_send_check_condition_and_sense);
@@ -2794,6 +2773,7 @@ int transport_check_aborted_status(struct se_cmd *cmd, int send_status)
                 cmd->t_task_cdb[0], cmd->se_tfo->get_task_tag(cmd));
 
        cmd->se_cmd_flags |= SCF_SENT_DELAYED_TAS;
+       trace_target_cmd_complete(cmd);
        cmd->se_tfo->queue_status(cmd);
 
        return 1;
@@ -2831,6 +2811,7 @@ void transport_send_task_abort(struct se_cmd *cmd)
                " ITT: 0x%08x\n", cmd->t_task_cdb[0],
                cmd->se_tfo->get_task_tag(cmd));
 
+       trace_target_cmd_complete(cmd);
        cmd->se_tfo->queue_status(cmd);
 }
 
index eea6935..0dd54a4 100644 (file)
@@ -161,7 +161,7 @@ int ft_write_pending(struct se_cmd *);
 int ft_write_pending_status(struct se_cmd *);
 u32 ft_get_task_tag(struct se_cmd *);
 int ft_get_cmd_state(struct se_cmd *);
-int ft_queue_tm_resp(struct se_cmd *);
+void ft_queue_tm_resp(struct se_cmd *);
 
 /*
  * other internal functions.
index b406f17..0e5a1ca 100644 (file)
@@ -394,14 +394,14 @@ static void ft_send_tm(struct ft_cmd *cmd)
 /*
  * Send status from completed task management request.
  */
-int ft_queue_tm_resp(struct se_cmd *se_cmd)
+void ft_queue_tm_resp(struct se_cmd *se_cmd)
 {
        struct ft_cmd *cmd = container_of(se_cmd, struct ft_cmd, se_cmd);
        struct se_tmr_req *tmr = se_cmd->se_tmr_req;
        enum fcp_resp_rsp_codes code;
 
        if (cmd->aborted)
-               return 0;
+               return;
        switch (tmr->response) {
        case TMR_FUNCTION_COMPLETE:
                code = FCP_TMF_CMPL;
@@ -413,10 +413,7 @@ int ft_queue_tm_resp(struct se_cmd *se_cmd)
                code = FCP_TMF_REJECTED;
                break;
        case TMR_TASK_DOES_NOT_EXIST:
-       case TMR_TASK_STILL_ALLEGIANT:
-       case TMR_TASK_FAILOVER_NOT_SUPPORTED:
        case TMR_TASK_MGMT_FUNCTION_NOT_SUPPORTED:
-       case TMR_FUNCTION_AUTHORIZATION_FAILED:
        default:
                code = FCP_TMF_FAILED;
                break;
@@ -424,7 +421,6 @@ int ft_queue_tm_resp(struct se_cmd *se_cmd)
        pr_debug("tmr fn %d resp %d fcp code %d\n",
                  tmr->function, tmr->response, code);
        ft_send_resp_code(cmd, code);
-       return 0;
 }
 
 static void ft_send_work(struct work_struct *work);
index 5e3c025..e988c81 100644 (file)
@@ -169,4 +169,19 @@ config INTEL_POWERCLAMP
          enforce idle time which results in more package C-state residency. The
          user interface is exposed via generic thermal framework.
 
+config X86_PKG_TEMP_THERMAL
+       tristate "X86 package temperature thermal driver"
+       depends on X86_THERMAL_VECTOR
+       select THERMAL_GOV_USER_SPACE
+       default m
+       help
+         Enable this to register CPU digital sensor for package temperature as
+         thermal zone. Each package will have its own thermal zone. There are
+         two trip points which can be set by user to get notifications via thermal
+         notification methods.
+
+menu "Texas Instruments thermal drivers"
+source "drivers/thermal/ti-soc-thermal/Kconfig"
+endmenu
+
 endif
index c054d41..67184a2 100644 (file)
@@ -23,4 +23,5 @@ obj-$(CONFIG_DB8500_THERMAL)  += db8500_thermal.o
 obj-$(CONFIG_ARMADA_THERMAL)   += armada_thermal.o
 obj-$(CONFIG_DB8500_CPUFREQ_COOLING)   += db8500_cpufreq_cooling.o
 obj-$(CONFIG_INTEL_POWERCLAMP) += intel_powerclamp.o
-
+obj-$(CONFIG_X86_PKG_TEMP_THERMAL)     += x86_pkg_temp_thermal.o
+obj-$(CONFIG_TI_SOC_THERMAL)   += ti-soc-thermal/
index 54ffd64..5e53212 100644 (file)
@@ -200,7 +200,6 @@ static int armada_thermal_exit(struct platform_device *pdev)
                platform_get_drvdata(pdev);
 
        thermal_zone_device_unregister(armada_thermal);
-       platform_set_drvdata(pdev, NULL);
 
        return 0;
 }
@@ -211,7 +210,7 @@ static struct platform_driver armada_thermal_driver = {
        .driver = {
                .name = "armada_thermal",
                .owner = THIS_MODULE,
-               .of_match_table = of_match_ptr(armada_thermal_id_table),
+               .of_match_table = armada_thermal_id_table,
        },
 };
 
index c94bf2e..82e15db 100644 (file)
@@ -167,7 +167,7 @@ static int get_property(unsigned int cpu, unsigned long input,
                        continue;
 
                /* get the frequency order */
-               if (freq != CPUFREQ_ENTRY_INVALID && descend != -1)
+               if (freq != CPUFREQ_ENTRY_INVALID && descend == -1)
                        descend = !!(freq > table[i].frequency);
 
                freq = table[i].frequency;
index a088d13..828f5e3 100644 (file)
@@ -134,16 +134,11 @@ static int dove_thermal_probe(struct platform_device *pdev)
        struct resource *res;
        int ret;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res) {
-               dev_err(&pdev->dev, "Failed to get platform resource\n");
-               return -ENODEV;
-       }
-
        priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
        if (!priv)
                return -ENOMEM;
 
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        priv->sensor = devm_ioremap_resource(&pdev->dev, res);
        if (IS_ERR(priv->sensor))
                return PTR_ERR(priv->sensor);
@@ -178,7 +173,6 @@ static int dove_thermal_exit(struct platform_device *pdev)
                platform_get_drvdata(pdev);
 
        thermal_zone_device_unregister(dove_thermal);
-       platform_set_drvdata(pdev, NULL);
 
        return 0;
 }
@@ -191,7 +185,7 @@ static struct platform_driver dove_thermal_driver = {
        .driver = {
                .name = "dove_thermal",
                .owner = THIS_MODULE,
-               .of_match_table = of_match_ptr(dove_thermal_id_table),
+               .of_match_table = dove_thermal_id_table,
        },
 };
 
index 4cbe3ee..9af4b93 100644 (file)
@@ -997,7 +997,6 @@ static int exynos_tmu_probe(struct platform_device *pdev)
 
        return 0;
 err_clk:
-       platform_set_drvdata(pdev, NULL);
        clk_unprepare(data->clk);
        return ret;
 }
@@ -1012,8 +1011,6 @@ static int exynos_tmu_remove(struct platform_device *pdev)
 
        clk_unprepare(data->clk);
 
-       platform_set_drvdata(pdev, NULL);
-
        return 0;
 }
 
index dfeceaf..3b034a0 100644 (file)
@@ -75,16 +75,11 @@ static int kirkwood_thermal_probe(struct platform_device *pdev)
        struct kirkwood_thermal_priv *priv;
        struct resource *res;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res) {
-               dev_err(&pdev->dev, "Failed to get platform resource\n");
-               return -ENODEV;
-       }
-
        priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
        if (!priv)
                return -ENOMEM;
 
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        priv->sensor = devm_ioremap_resource(&pdev->dev, res);
        if (IS_ERR(priv->sensor))
                return PTR_ERR(priv->sensor);
@@ -108,7 +103,6 @@ static int kirkwood_thermal_exit(struct platform_device *pdev)
                platform_get_drvdata(pdev);
 
        thermal_zone_device_unregister(kirkwood_thermal);
-       platform_set_drvdata(pdev, NULL);
 
        return 0;
 }
@@ -121,7 +115,7 @@ static struct platform_driver kirkwood_thermal_driver = {
        .driver = {
                .name = "kirkwood_thermal",
                .owner = THIS_MODULE,
-               .of_match_table = of_match_ptr(kirkwood_thermal_id_table),
+               .of_match_table = kirkwood_thermal_id_table,
        },
 };
 
index 8d7edd4..88f92e1 100644 (file)
@@ -389,11 +389,6 @@ static int rcar_thermal_probe(struct platform_device *pdev)
                 * platform has IRQ support.
                 * Then, drier use common register
                 */
-               res = platform_get_resource(pdev, IORESOURCE_MEM, mres++);
-               if (!res) {
-                       dev_err(dev, "Could not get platform resource\n");
-                       return -ENODEV;
-               }
 
                ret = devm_request_irq(dev, irq->start, rcar_thermal_irq, 0,
                                       dev_name(dev), common);
@@ -405,6 +400,7 @@ static int rcar_thermal_probe(struct platform_device *pdev)
                /*
                 * rcar_has_irq_support() will be enabled
                 */
+               res = platform_get_resource(pdev, IORESOURCE_MEM, mres++);
                common->base = devm_ioremap_resource(dev, res);
                if (IS_ERR(common->base))
                        return PTR_ERR(common->base);
@@ -458,7 +454,7 @@ static int rcar_thermal_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, common);
 
-       dev_info(dev, "%d sensor proved\n", i);
+       dev_info(dev, "%d sensor probed\n", i);
 
        return 0;
 
@@ -487,8 +483,6 @@ static int rcar_thermal_remove(struct platform_device *pdev)
                        rcar_thermal_irq_disable(priv);
        }
 
-       platform_set_drvdata(pdev, NULL);
-
        pm_runtime_put_sync(dev);
        pm_runtime_disable(dev);
 
index 3c5ee56..ab79ea4 100644 (file)
@@ -104,7 +104,7 @@ static int spear_thermal_probe(struct platform_device *pdev)
        struct thermal_zone_device *spear_thermal = NULL;
        struct spear_thermal_dev *stdev;
        struct device_node *np = pdev->dev.of_node;
-       struct resource *stres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       struct resource *res;
        int ret = 0, val;
 
        if (!np || !of_property_read_u32(np, "st,thermal-flags", &val)) {
@@ -112,11 +112,6 @@ static int spear_thermal_probe(struct platform_device *pdev)
                return -EINVAL;
        }
 
-       if (!stres) {
-               dev_err(&pdev->dev, "memory resource missing\n");
-               return -ENODEV;
-       }
-
        stdev = devm_kzalloc(&pdev->dev, sizeof(*stdev), GFP_KERNEL);
        if (!stdev) {
                dev_err(&pdev->dev, "kzalloc fail\n");
@@ -124,12 +119,10 @@ static int spear_thermal_probe(struct platform_device *pdev)
        }
 
        /* Enable thermal sensor */
-       stdev->thermal_base = devm_ioremap(&pdev->dev, stres->start,
-                       resource_size(stres));
-       if (!stdev->thermal_base) {
-               dev_err(&pdev->dev, "ioremap failed\n");
-               return -ENOMEM;
-       }
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       stdev->thermal_base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(stdev->thermal_base))
+               return PTR_ERR(stdev->thermal_base);
 
        stdev->clk = devm_clk_get(&pdev->dev, NULL);
        if (IS_ERR(stdev->clk)) {
@@ -174,7 +167,6 @@ static int spear_thermal_exit(struct platform_device *pdev)
        struct spear_thermal_dev *stdev = spear_thermal->devdata;
 
        thermal_zone_device_unregister(spear_thermal);
-       platform_set_drvdata(pdev, NULL);
 
        /* Disable SPEAr Thermal Sensor */
        actual_mask = readl_relaxed(stdev->thermal_base);
@@ -198,7 +190,7 @@ static struct platform_driver spear_thermal_driver = {
                .name = "spear_thermal",
                .owner = THIS_MODULE,
                .pm = &spear_thermal_pm_ops,
-               .of_match_table = of_match_ptr(spear_thermal_id_table),
+               .of_match_table = spear_thermal_id_table,
        },
 };
 
index d755440..1f02e8e 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/idr.h>
 #include <linux/thermal.h>
 #include <linux/reboot.h>
+#include <linux/string.h>
 #include <net/netlink.h>
 #include <net/genetlink.h>
 
@@ -155,7 +156,8 @@ int get_tz_trend(struct thermal_zone_device *tz, int trip)
 {
        enum thermal_trend trend;
 
-       if (!tz->ops->get_trend || tz->ops->get_trend(tz, trip, &trend)) {
+       if (tz->emul_temperature || !tz->ops->get_trend ||
+           tz->ops->get_trend(tz, trip, &trend)) {
                if (tz->temperature > tz->last_temperature)
                        trend = THERMAL_TREND_RAISING;
                else if (tz->temperature < tz->last_temperature)
@@ -713,10 +715,13 @@ policy_store(struct device *dev, struct device_attribute *attr,
        int ret = -EINVAL;
        struct thermal_zone_device *tz = to_thermal_zone(dev);
        struct thermal_governor *gov;
+       char name[THERMAL_NAME_LENGTH];
+
+       snprintf(name, sizeof(name), "%s", buf);
 
        mutex_lock(&thermal_governor_lock);
 
-       gov = __find_governor(buf);
+       gov = __find_governor(strim(name));
        if (!gov)
                goto exit;
 
@@ -1624,7 +1629,7 @@ struct thermal_zone_device *thermal_zone_device_register(const char *type,
        if (!ops || !ops->get_temp)
                return ERR_PTR(-EINVAL);
 
-       if (trips > 0 && !ops->get_trip_type)
+       if (trips > 0 && (!ops->get_trip_type || !ops->get_trip_temp))
                return ERR_PTR(-EINVAL);
 
        tz = kzalloc(sizeof(struct thermal_zone_device), GFP_KERNEL);
similarity index 81%
rename from drivers/staging/ti-soc-thermal/Kconfig
rename to drivers/thermal/ti-soc-thermal/Kconfig
index e81375f..bd4c7be 100644 (file)
@@ -46,3 +46,15 @@ config OMAP5_THERMAL
 
          This includes alert interrupts generation and also the TSHUT
          support.
+
+config DRA752_THERMAL
+       bool "Texas Instruments DRA752 thermal support"
+       depends on TI_SOC_THERMAL
+       depends on SOC_DRA7XX
+       help
+         If you say yes here you get thermal support for the Texas Instruments
+         DRA752 SoC family. The current chip supported are:
+          - DRA752
+
+         This includes alert interrupts generation and also the TSHUT
+         support.
similarity index 80%
rename from drivers/staging/ti-soc-thermal/Makefile
rename to drivers/thermal/ti-soc-thermal/Makefile
index 0ca034f..1226b24 100644 (file)
@@ -1,5 +1,6 @@
 obj-$(CONFIG_TI_SOC_THERMAL)           += ti-soc-thermal.o
 ti-soc-thermal-y                       := ti-bandgap.o
 ti-soc-thermal-$(CONFIG_TI_THERMAL)    += ti-thermal-common.o
+ti-soc-thermal-$(CONFIG_DRA752_THERMAL)        += dra752-thermal-data.o
 ti-soc-thermal-$(CONFIG_OMAP4_THERMAL) += omap4-thermal-data.o
 ti-soc-thermal-$(CONFIG_OMAP5_THERMAL) += omap5-thermal-data.o
diff --git a/drivers/thermal/ti-soc-thermal/dra752-bandgap.h b/drivers/thermal/ti-soc-thermal/dra752-bandgap.h
new file mode 100644 (file)
index 0000000..6b0f2b1
--- /dev/null
@@ -0,0 +1,280 @@
+/*
+ * DRA752 bandgap registers, bitfields and temperature definitions
+ *
+ * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/
+ * Contact:
+ *   Eduardo Valentin <eduardo.valentin@ti.com>
+ *   Tero Kristo <t-kristo@ti.com>
+ *
+ * This is an auto generated file.
+ *
+ * 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 __DRA752_BANDGAP_H
+#define __DRA752_BANDGAP_H
+
+/**
+ * *** DRA752 ***
+ *
+ * Below, in sequence, are the Register definitions,
+ * the bitfields and the temperature definitions for DRA752.
+ */
+
+/**
+ * DRA752 register definitions
+ *
+ * Registers are defined as offsets. The offsets are
+ * relative to FUSE_OPP_BGAP_GPU on DRA752.
+ * DRA752_BANDGAP_BASE         0x4a0021e0
+ *
+ * Register below are grouped by domain (not necessarily in offset order)
+ */
+
+
+/* DRA752.common register offsets */
+#define DRA752_BANDGAP_CTRL_1_OFFSET           0x1a0
+#define DRA752_BANDGAP_STATUS_1_OFFSET         0x1c8
+#define DRA752_BANDGAP_CTRL_2_OFFSET           0x39c
+#define DRA752_BANDGAP_STATUS_2_OFFSET         0x3b8
+
+/* DRA752.core register offsets */
+#define DRA752_STD_FUSE_OPP_BGAP_CORE_OFFSET           0x8
+#define DRA752_TEMP_SENSOR_CORE_OFFSET                 0x154
+#define DRA752_BANDGAP_THRESHOLD_CORE_OFFSET           0x1ac
+#define DRA752_BANDGAP_TSHUT_CORE_OFFSET               0x1b8
+#define DRA752_BANDGAP_CUMUL_DTEMP_CORE_OFFSET         0x1c4
+#define DRA752_DTEMP_CORE_0_OFFSET                     0x208
+#define DRA752_DTEMP_CORE_1_OFFSET                     0x20c
+#define DRA752_DTEMP_CORE_2_OFFSET                     0x210
+#define DRA752_DTEMP_CORE_3_OFFSET                     0x214
+#define DRA752_DTEMP_CORE_4_OFFSET                     0x218
+
+/* DRA752.iva register offsets */
+#define DRA752_STD_FUSE_OPP_BGAP_IVA_OFFSET            0x388
+#define DRA752_TEMP_SENSOR_IVA_OFFSET                  0x398
+#define DRA752_BANDGAP_THRESHOLD_IVA_OFFSET            0x3a4
+#define DRA752_BANDGAP_TSHUT_IVA_OFFSET                        0x3ac
+#define DRA752_BANDGAP_CUMUL_DTEMP_IVA_OFFSET          0x3b4
+#define DRA752_DTEMP_IVA_0_OFFSET                      0x3d0
+#define DRA752_DTEMP_IVA_1_OFFSET                      0x3d4
+#define DRA752_DTEMP_IVA_2_OFFSET                      0x3d8
+#define DRA752_DTEMP_IVA_3_OFFSET                      0x3dc
+#define DRA752_DTEMP_IVA_4_OFFSET                      0x3e0
+
+/* DRA752.mpu register offsets */
+#define DRA752_STD_FUSE_OPP_BGAP_MPU_OFFSET            0x4
+#define DRA752_TEMP_SENSOR_MPU_OFFSET                  0x14c
+#define DRA752_BANDGAP_THRESHOLD_MPU_OFFSET            0x1a4
+#define DRA752_BANDGAP_TSHUT_MPU_OFFSET                        0x1b0
+#define DRA752_BANDGAP_CUMUL_DTEMP_MPU_OFFSET          0x1bc
+#define DRA752_DTEMP_MPU_0_OFFSET                      0x1e0
+#define DRA752_DTEMP_MPU_1_OFFSET                      0x1e4
+#define DRA752_DTEMP_MPU_2_OFFSET                      0x1e8
+#define DRA752_DTEMP_MPU_3_OFFSET                      0x1ec
+#define DRA752_DTEMP_MPU_4_OFFSET                      0x1f0
+
+/* DRA752.dspeve register offsets */
+#define DRA752_STD_FUSE_OPP_BGAP_DSPEVE_OFFSET                 0x384
+#define DRA752_TEMP_SENSOR_DSPEVE_OFFSET                       0x394
+#define DRA752_BANDGAP_THRESHOLD_DSPEVE_OFFSET                 0x3a0
+#define DRA752_BANDGAP_TSHUT_DSPEVE_OFFSET                     0x3a8
+#define DRA752_BANDGAP_CUMUL_DTEMP_DSPEVE_OFFSET               0x3b0
+#define DRA752_DTEMP_DSPEVE_0_OFFSET                           0x3bc
+#define DRA752_DTEMP_DSPEVE_1_OFFSET                           0x3c0
+#define DRA752_DTEMP_DSPEVE_2_OFFSET                           0x3c4
+#define DRA752_DTEMP_DSPEVE_3_OFFSET                           0x3c8
+#define DRA752_DTEMP_DSPEVE_4_OFFSET                           0x3cc
+
+/* DRA752.gpu register offsets */
+#define DRA752_STD_FUSE_OPP_BGAP_GPU_OFFSET            0x0
+#define DRA752_TEMP_SENSOR_GPU_OFFSET                  0x150
+#define DRA752_BANDGAP_THRESHOLD_GPU_OFFSET            0x1a8
+#define DRA752_BANDGAP_TSHUT_GPU_OFFSET                        0x1b4
+#define DRA752_BANDGAP_CUMUL_DTEMP_GPU_OFFSET          0x1c0
+#define DRA752_DTEMP_GPU_0_OFFSET                      0x1f4
+#define DRA752_DTEMP_GPU_1_OFFSET                      0x1f8
+#define DRA752_DTEMP_GPU_2_OFFSET                      0x1fc
+#define DRA752_DTEMP_GPU_3_OFFSET                      0x200
+#define DRA752_DTEMP_GPU_4_OFFSET                      0x204
+
+/**
+ * Register bitfields for DRA752
+ *
+ * All the macros bellow define the required bits for
+ * controlling temperature on DRA752. Bit defines are
+ * grouped by register.
+ */
+
+/* DRA752.BANDGAP_STATUS_1 */
+#define DRA752_BANDGAP_STATUS_1_ALERT_MASK             BIT(31)
+#define DRA752_BANDGAP_STATUS_1_HOT_CORE_MASK          BIT(5)
+#define DRA752_BANDGAP_STATUS_1_COLD_CORE_MASK         BIT(4)
+#define DRA752_BANDGAP_STATUS_1_HOT_GPU_MASK           BIT(3)
+#define DRA752_BANDGAP_STATUS_1_COLD_GPU_MASK          BIT(2)
+#define DRA752_BANDGAP_STATUS_1_HOT_MPU_MASK           BIT(1)
+#define DRA752_BANDGAP_STATUS_1_COLD_MPU_MASK          BIT(0)
+
+/* DRA752.BANDGAP_CTRL_2 */
+#define DRA752_BANDGAP_CTRL_2_FREEZE_IVA_MASK                  BIT(22)
+#define DRA752_BANDGAP_CTRL_2_FREEZE_DSPEVE_MASK               BIT(21)
+#define DRA752_BANDGAP_CTRL_2_CLEAR_IVA_MASK                   BIT(19)
+#define DRA752_BANDGAP_CTRL_2_CLEAR_DSPEVE_MASK                        BIT(18)
+#define DRA752_BANDGAP_CTRL_2_CLEAR_ACCUM_IVA_MASK             BIT(16)
+#define DRA752_BANDGAP_CTRL_2_CLEAR_ACCUM_DSPEVE_MASK          BIT(15)
+#define DRA752_BANDGAP_CTRL_2_MASK_HOT_IVA_MASK                        BIT(3)
+#define DRA752_BANDGAP_CTRL_2_MASK_COLD_IVA_MASK               BIT(2)
+#define DRA752_BANDGAP_CTRL_2_MASK_HOT_DSPEVE_MASK             BIT(1)
+#define DRA752_BANDGAP_CTRL_2_MASK_COLD_DSPEVE_MASK            BIT(0)
+
+/* DRA752.BANDGAP_STATUS_2 */
+#define DRA752_BANDGAP_STATUS_2_HOT_IVA_MASK                   BIT(3)
+#define DRA752_BANDGAP_STATUS_2_COLD_IVA_MASK                  BIT(2)
+#define DRA752_BANDGAP_STATUS_2_HOT_DSPEVE_MASK                        BIT(1)
+#define DRA752_BANDGAP_STATUS_2_COLD_DSPEVE_MASK               BIT(0)
+
+/* DRA752.BANDGAP_CTRL_1 */
+#define DRA752_BANDGAP_CTRL_1_SIDLEMODE_MASK                   (0x3 << 30)
+#define DRA752_BANDGAP_CTRL_1_COUNTER_DELAY_MASK               (0x7 << 27)
+#define DRA752_BANDGAP_CTRL_1_FREEZE_CORE_MASK                 BIT(23)
+#define DRA752_BANDGAP_CTRL_1_FREEZE_GPU_MASK                  BIT(22)
+#define DRA752_BANDGAP_CTRL_1_FREEZE_MPU_MASK                  BIT(21)
+#define DRA752_BANDGAP_CTRL_1_CLEAR_CORE_MASK                  BIT(20)
+#define DRA752_BANDGAP_CTRL_1_CLEAR_GPU_MASK                   BIT(19)
+#define DRA752_BANDGAP_CTRL_1_CLEAR_MPU_MASK                   BIT(18)
+#define DRA752_BANDGAP_CTRL_1_CLEAR_ACCUM_CORE_MASK            BIT(17)
+#define DRA752_BANDGAP_CTRL_1_CLEAR_ACCUM_GPU_MASK             BIT(16)
+#define DRA752_BANDGAP_CTRL_1_CLEAR_ACCUM_MPU_MASK             BIT(15)
+#define DRA752_BANDGAP_CTRL_1_MASK_HOT_CORE_MASK               BIT(5)
+#define DRA752_BANDGAP_CTRL_1_MASK_COLD_CORE_MASK              BIT(4)
+#define DRA752_BANDGAP_CTRL_1_MASK_HOT_GPU_MASK                        BIT(3)
+#define DRA752_BANDGAP_CTRL_1_MASK_COLD_GPU_MASK               BIT(2)
+#define DRA752_BANDGAP_CTRL_1_MASK_HOT_MPU_MASK                        BIT(1)
+#define DRA752_BANDGAP_CTRL_1_MASK_COLD_MPU_MASK               BIT(0)
+
+/* DRA752.TEMP_SENSOR */
+#define DRA752_TEMP_SENSOR_TMPSOFF_MASK                BIT(11)
+#define DRA752_TEMP_SENSOR_EOCZ_MASK           BIT(10)
+#define DRA752_TEMP_SENSOR_DTEMP_MASK          (0x3ff << 0)
+
+/* DRA752.BANDGAP_THRESHOLD */
+#define DRA752_BANDGAP_THRESHOLD_HOT_MASK              (0x3ff << 16)
+#define DRA752_BANDGAP_THRESHOLD_COLD_MASK             (0x3ff << 0)
+
+/* DRA752.TSHUT_THRESHOLD */
+#define DRA752_TSHUT_THRESHOLD_MUXCTRL_MASK            BIT(31)
+#define DRA752_TSHUT_THRESHOLD_HOT_MASK                        (0x3ff << 16)
+#define DRA752_TSHUT_THRESHOLD_COLD_MASK               (0x3ff << 0)
+
+/* DRA752.BANDGAP_CUMUL_DTEMP_CORE */
+#define DRA752_BANDGAP_CUMUL_DTEMP_CORE_MASK           (0xffffffff << 0)
+
+/* DRA752.BANDGAP_CUMUL_DTEMP_IVA */
+#define DRA752_BANDGAP_CUMUL_DTEMP_IVA_MASK            (0xffffffff << 0)
+
+/* DRA752.BANDGAP_CUMUL_DTEMP_MPU */
+#define DRA752_BANDGAP_CUMUL_DTEMP_MPU_MASK            (0xffffffff << 0)
+
+/* DRA752.BANDGAP_CUMUL_DTEMP_DSPEVE */
+#define DRA752_BANDGAP_CUMUL_DTEMP_DSPEVE_MASK         (0xffffffff << 0)
+
+/* DRA752.BANDGAP_CUMUL_DTEMP_GPU */
+#define DRA752_BANDGAP_CUMUL_DTEMP_GPU_MASK            (0xffffffff << 0)
+
+/**
+ * Temperature limits and thresholds for DRA752
+ *
+ * All the macros bellow are definitions for handling the
+ * ADC conversions and representation of temperature limits
+ * and thresholds for DRA752. Definitions are grouped
+ * by temperature domain.
+ */
+
+/* DRA752.common temperature definitions */
+/* ADC conversion table limits */
+#define DRA752_ADC_START_VALUE         540
+#define DRA752_ADC_END_VALUE           945
+
+/* DRA752.GPU temperature definitions */
+/* bandgap clock limits */
+#define DRA752_GPU_MAX_FREQ                            1500000
+#define DRA752_GPU_MIN_FREQ                            1000000
+/* sensor limits */
+#define DRA752_GPU_MIN_TEMP                            -40000
+#define DRA752_GPU_MAX_TEMP                            125000
+#define DRA752_GPU_HYST_VAL                            5000
+/* interrupts thresholds */
+#define DRA752_GPU_TSHUT_HOT                           915
+#define DRA752_GPU_TSHUT_COLD                          900
+#define DRA752_GPU_T_HOT                               800
+#define DRA752_GPU_T_COLD                              795
+
+/* DRA752.MPU temperature definitions */
+/* bandgap clock limits */
+#define DRA752_MPU_MAX_FREQ                            1500000
+#define DRA752_MPU_MIN_FREQ                            1000000
+/* sensor limits */
+#define DRA752_MPU_MIN_TEMP                            -40000
+#define DRA752_MPU_MAX_TEMP                            125000
+#define DRA752_MPU_HYST_VAL                            5000
+/* interrupts thresholds */
+#define DRA752_MPU_TSHUT_HOT                           915
+#define DRA752_MPU_TSHUT_COLD                          900
+#define DRA752_MPU_T_HOT                               800
+#define DRA752_MPU_T_COLD                              795
+
+/* DRA752.CORE temperature definitions */
+/* bandgap clock limits */
+#define DRA752_CORE_MAX_FREQ                           1500000
+#define DRA752_CORE_MIN_FREQ                           1000000
+/* sensor limits */
+#define DRA752_CORE_MIN_TEMP                           -40000
+#define DRA752_CORE_MAX_TEMP                           125000
+#define DRA752_CORE_HYST_VAL                           5000
+/* interrupts thresholds */
+#define DRA752_CORE_TSHUT_HOT                          915
+#define DRA752_CORE_TSHUT_COLD                         900
+#define DRA752_CORE_T_HOT                              800
+#define DRA752_CORE_T_COLD                             795
+
+/* DRA752.DSPEVE temperature definitions */
+/* bandgap clock limits */
+#define DRA752_DSPEVE_MAX_FREQ                         1500000
+#define DRA752_DSPEVE_MIN_FREQ                         1000000
+/* sensor limits */
+#define DRA752_DSPEVE_MIN_TEMP                         -40000
+#define DRA752_DSPEVE_MAX_TEMP                         125000
+#define DRA752_DSPEVE_HYST_VAL                         5000
+/* interrupts thresholds */
+#define DRA752_DSPEVE_TSHUT_HOT                                915
+#define DRA752_DSPEVE_TSHUT_COLD                       900
+#define DRA752_DSPEVE_T_HOT                            800
+#define DRA752_DSPEVE_T_COLD                           795
+
+/* DRA752.IVA temperature definitions */
+/* bandgap clock limits */
+#define DRA752_IVA_MAX_FREQ                            1500000
+#define DRA752_IVA_MIN_FREQ                            1000000
+/* sensor limits */
+#define DRA752_IVA_MIN_TEMP                            -40000
+#define DRA752_IVA_MAX_TEMP                            125000
+#define DRA752_IVA_HYST_VAL                            5000
+/* interrupts thresholds */
+#define DRA752_IVA_TSHUT_HOT                           915
+#define DRA752_IVA_TSHUT_COLD                          900
+#define DRA752_IVA_T_HOT                               800
+#define DRA752_IVA_T_COLD                              795
+
+#endif /* __DRA752_BANDGAP_H */
diff --git a/drivers/thermal/ti-soc-thermal/dra752-thermal-data.c b/drivers/thermal/ti-soc-thermal/dra752-thermal-data.c
new file mode 100644 (file)
index 0000000..e5d8326
--- /dev/null
@@ -0,0 +1,476 @@
+/*
+ * DRA752 thermal data.
+ *
+ * Copyright (C) 2013 Texas Instruments Inc.
+ * Contact:
+ *     Eduardo Valentin <eduardo.valentin@ti.com>
+ *     Tero Kristo <t-kristo@ti.com>
+ *
+ * This file is partially autogenerated.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include "ti-thermal.h"
+#include "ti-bandgap.h"
+#include "dra752-bandgap.h"
+
+/*
+ * DRA752 has five instances of thermal sensor: MPU, GPU, CORE,
+ * IVA and DSPEVE need to describe the individual registers and
+ * bit fields.
+ */
+
+/*
+ * DRA752 CORE thermal sensor register offsets and bit-fields
+ */
+static struct temp_sensor_registers
+dra752_core_temp_sensor_registers = {
+       .temp_sensor_ctrl = DRA752_TEMP_SENSOR_CORE_OFFSET,
+       .bgap_tempsoff_mask = DRA752_TEMP_SENSOR_TMPSOFF_MASK,
+       .bgap_eocz_mask = DRA752_TEMP_SENSOR_EOCZ_MASK,
+       .bgap_dtemp_mask = DRA752_TEMP_SENSOR_DTEMP_MASK,
+       .bgap_mask_ctrl = DRA752_BANDGAP_CTRL_1_OFFSET,
+       .mask_hot_mask = DRA752_BANDGAP_CTRL_1_MASK_HOT_CORE_MASK,
+       .mask_cold_mask = DRA752_BANDGAP_CTRL_1_MASK_COLD_CORE_MASK,
+       .mask_sidlemode_mask = DRA752_BANDGAP_CTRL_1_SIDLEMODE_MASK,
+       .mask_freeze_mask = DRA752_BANDGAP_CTRL_1_FREEZE_CORE_MASK,
+       .mask_clear_mask = DRA752_BANDGAP_CTRL_1_CLEAR_CORE_MASK,
+       .mask_clear_accum_mask = DRA752_BANDGAP_CTRL_1_CLEAR_ACCUM_CORE_MASK,
+       .bgap_threshold = DRA752_BANDGAP_THRESHOLD_CORE_OFFSET,
+       .threshold_thot_mask = DRA752_BANDGAP_THRESHOLD_HOT_MASK,
+       .threshold_tcold_mask = DRA752_BANDGAP_THRESHOLD_COLD_MASK,
+       .tshut_threshold = DRA752_BANDGAP_TSHUT_CORE_OFFSET,
+       .tshut_hot_mask = DRA752_TSHUT_THRESHOLD_HOT_MASK,
+       .tshut_cold_mask = DRA752_TSHUT_THRESHOLD_COLD_MASK,
+       .bgap_status = DRA752_BANDGAP_STATUS_1_OFFSET,
+       .status_bgap_alert_mask = DRA752_BANDGAP_STATUS_1_ALERT_MASK,
+       .status_hot_mask = DRA752_BANDGAP_STATUS_1_HOT_CORE_MASK,
+       .status_cold_mask = DRA752_BANDGAP_STATUS_1_COLD_CORE_MASK,
+       .bgap_cumul_dtemp = DRA752_BANDGAP_CUMUL_DTEMP_CORE_OFFSET,
+       .ctrl_dtemp_0 = DRA752_DTEMP_CORE_0_OFFSET,
+       .ctrl_dtemp_1 = DRA752_DTEMP_CORE_1_OFFSET,
+       .ctrl_dtemp_2 = DRA752_DTEMP_CORE_2_OFFSET,
+       .ctrl_dtemp_3 = DRA752_DTEMP_CORE_3_OFFSET,
+       .ctrl_dtemp_4 = DRA752_DTEMP_CORE_4_OFFSET,
+       .bgap_efuse = DRA752_STD_FUSE_OPP_BGAP_CORE_OFFSET,
+};
+
+/*
+ * DRA752 IVA thermal sensor register offsets and bit-fields
+ */
+static struct temp_sensor_registers
+dra752_iva_temp_sensor_registers = {
+       .temp_sensor_ctrl = DRA752_TEMP_SENSOR_IVA_OFFSET,
+       .bgap_tempsoff_mask = DRA752_TEMP_SENSOR_TMPSOFF_MASK,
+       .bgap_eocz_mask = DRA752_TEMP_SENSOR_EOCZ_MASK,
+       .bgap_dtemp_mask = DRA752_TEMP_SENSOR_DTEMP_MASK,
+       .bgap_mask_ctrl = DRA752_BANDGAP_CTRL_2_OFFSET,
+       .mask_hot_mask = DRA752_BANDGAP_CTRL_2_MASK_HOT_IVA_MASK,
+       .mask_cold_mask = DRA752_BANDGAP_CTRL_2_MASK_COLD_IVA_MASK,
+       .mask_sidlemode_mask = DRA752_BANDGAP_CTRL_1_SIDLEMODE_MASK,
+       .mask_freeze_mask = DRA752_BANDGAP_CTRL_2_FREEZE_IVA_MASK,
+       .mask_clear_mask = DRA752_BANDGAP_CTRL_2_CLEAR_IVA_MASK,
+       .mask_clear_accum_mask = DRA752_BANDGAP_CTRL_2_CLEAR_ACCUM_IVA_MASK,
+       .bgap_threshold = DRA752_BANDGAP_THRESHOLD_IVA_OFFSET,
+       .threshold_thot_mask = DRA752_BANDGAP_THRESHOLD_HOT_MASK,
+       .threshold_tcold_mask = DRA752_BANDGAP_THRESHOLD_COLD_MASK,
+       .tshut_threshold = DRA752_BANDGAP_TSHUT_IVA_OFFSET,
+       .tshut_hot_mask = DRA752_TSHUT_THRESHOLD_HOT_MASK,
+       .tshut_cold_mask = DRA752_TSHUT_THRESHOLD_COLD_MASK,
+       .bgap_status = DRA752_BANDGAP_STATUS_2_OFFSET,
+       .status_bgap_alert_mask = DRA752_BANDGAP_STATUS_1_ALERT_MASK,
+       .status_hot_mask = DRA752_BANDGAP_STATUS_2_HOT_IVA_MASK,
+       .status_cold_mask = DRA752_BANDGAP_STATUS_2_COLD_IVA_MASK,
+       .bgap_cumul_dtemp = DRA752_BANDGAP_CUMUL_DTEMP_IVA_OFFSET,
+       .ctrl_dtemp_0 = DRA752_DTEMP_IVA_0_OFFSET,
+       .ctrl_dtemp_1 = DRA752_DTEMP_IVA_1_OFFSET,
+       .ctrl_dtemp_2 = DRA752_DTEMP_IVA_2_OFFSET,
+       .ctrl_dtemp_3 = DRA752_DTEMP_IVA_3_OFFSET,
+       .ctrl_dtemp_4 = DRA752_DTEMP_IVA_4_OFFSET,
+       .bgap_efuse = DRA752_STD_FUSE_OPP_BGAP_IVA_OFFSET,
+};
+
+/*
+ * DRA752 MPU thermal sensor register offsets and bit-fields
+ */
+static struct temp_sensor_registers
+dra752_mpu_temp_sensor_registers = {
+       .temp_sensor_ctrl = DRA752_TEMP_SENSOR_MPU_OFFSET,
+       .bgap_tempsoff_mask = DRA752_TEMP_SENSOR_TMPSOFF_MASK,
+       .bgap_eocz_mask = DRA752_TEMP_SENSOR_EOCZ_MASK,
+       .bgap_dtemp_mask = DRA752_TEMP_SENSOR_DTEMP_MASK,
+       .bgap_mask_ctrl = DRA752_BANDGAP_CTRL_1_OFFSET,
+       .mask_hot_mask = DRA752_BANDGAP_CTRL_1_MASK_HOT_MPU_MASK,
+       .mask_cold_mask = DRA752_BANDGAP_CTRL_1_MASK_COLD_MPU_MASK,
+       .mask_sidlemode_mask = DRA752_BANDGAP_CTRL_1_SIDLEMODE_MASK,
+       .mask_freeze_mask = DRA752_BANDGAP_CTRL_1_FREEZE_MPU_MASK,
+       .mask_clear_mask = DRA752_BANDGAP_CTRL_1_CLEAR_MPU_MASK,
+       .mask_clear_accum_mask = DRA752_BANDGAP_CTRL_1_CLEAR_ACCUM_MPU_MASK,
+       .bgap_threshold = DRA752_BANDGAP_THRESHOLD_MPU_OFFSET,
+       .threshold_thot_mask = DRA752_BANDGAP_THRESHOLD_HOT_MASK,
+       .threshold_tcold_mask = DRA752_BANDGAP_THRESHOLD_COLD_MASK,
+       .tshut_threshold = DRA752_BANDGAP_TSHUT_MPU_OFFSET,
+       .tshut_hot_mask = DRA752_TSHUT_THRESHOLD_HOT_MASK,
+       .tshut_cold_mask = DRA752_TSHUT_THRESHOLD_COLD_MASK,
+       .bgap_status = DRA752_BANDGAP_STATUS_1_OFFSET,
+       .status_bgap_alert_mask = DRA752_BANDGAP_STATUS_1_ALERT_MASK,
+       .status_hot_mask = DRA752_BANDGAP_STATUS_1_HOT_MPU_MASK,
+       .status_cold_mask = DRA752_BANDGAP_STATUS_1_COLD_MPU_MASK,
+       .bgap_cumul_dtemp = DRA752_BANDGAP_CUMUL_DTEMP_MPU_OFFSET,
+       .ctrl_dtemp_0 = DRA752_DTEMP_MPU_0_OFFSET,
+       .ctrl_dtemp_1 = DRA752_DTEMP_MPU_1_OFFSET,
+       .ctrl_dtemp_2 = DRA752_DTEMP_MPU_2_OFFSET,
+       .ctrl_dtemp_3 = DRA752_DTEMP_MPU_3_OFFSET,
+       .ctrl_dtemp_4 = DRA752_DTEMP_MPU_4_OFFSET,
+       .bgap_efuse = DRA752_STD_FUSE_OPP_BGAP_MPU_OFFSET,
+};
+
+/*
+ * DRA752 DSPEVE thermal sensor register offsets and bit-fields
+ */
+static struct temp_sensor_registers
+dra752_dspeve_temp_sensor_registers = {
+       .temp_sensor_ctrl = DRA752_TEMP_SENSOR_DSPEVE_OFFSET,
+       .bgap_tempsoff_mask = DRA752_TEMP_SENSOR_TMPSOFF_MASK,
+       .bgap_eocz_mask = DRA752_TEMP_SENSOR_EOCZ_MASK,
+       .bgap_dtemp_mask = DRA752_TEMP_SENSOR_DTEMP_MASK,
+       .bgap_mask_ctrl = DRA752_BANDGAP_CTRL_2_OFFSET,
+       .mask_hot_mask = DRA752_BANDGAP_CTRL_2_MASK_HOT_DSPEVE_MASK,
+       .mask_cold_mask = DRA752_BANDGAP_CTRL_2_MASK_COLD_DSPEVE_MASK,
+       .mask_sidlemode_mask = DRA752_BANDGAP_CTRL_1_SIDLEMODE_MASK,
+       .mask_freeze_mask = DRA752_BANDGAP_CTRL_2_FREEZE_DSPEVE_MASK,
+       .mask_clear_mask = DRA752_BANDGAP_CTRL_2_CLEAR_DSPEVE_MASK,
+       .mask_clear_accum_mask = DRA752_BANDGAP_CTRL_2_CLEAR_ACCUM_DSPEVE_MASK,
+       .bgap_threshold = DRA752_BANDGAP_THRESHOLD_DSPEVE_OFFSET,
+       .threshold_thot_mask = DRA752_BANDGAP_THRESHOLD_HOT_MASK,
+       .threshold_tcold_mask = DRA752_BANDGAP_THRESHOLD_COLD_MASK,
+       .tshut_threshold = DRA752_BANDGAP_TSHUT_DSPEVE_OFFSET,
+       .tshut_hot_mask = DRA752_TSHUT_THRESHOLD_HOT_MASK,
+       .tshut_cold_mask = DRA752_TSHUT_THRESHOLD_COLD_MASK,
+       .bgap_status = DRA752_BANDGAP_STATUS_2_OFFSET,
+       .status_bgap_alert_mask = DRA752_BANDGAP_STATUS_1_ALERT_MASK,
+       .status_hot_mask = DRA752_BANDGAP_STATUS_2_HOT_DSPEVE_MASK,
+       .status_cold_mask = DRA752_BANDGAP_STATUS_2_COLD_DSPEVE_MASK,
+       .bgap_cumul_dtemp = DRA752_BANDGAP_CUMUL_DTEMP_DSPEVE_OFFSET,
+       .ctrl_dtemp_0 = DRA752_DTEMP_DSPEVE_0_OFFSET,
+       .ctrl_dtemp_1 = DRA752_DTEMP_DSPEVE_1_OFFSET,
+       .ctrl_dtemp_2 = DRA752_DTEMP_DSPEVE_2_OFFSET,
+       .ctrl_dtemp_3 = DRA752_DTEMP_DSPEVE_3_OFFSET,
+       .ctrl_dtemp_4 = DRA752_DTEMP_DSPEVE_4_OFFSET,
+       .bgap_efuse = DRA752_STD_FUSE_OPP_BGAP_DSPEVE_OFFSET,
+};
+
+/*
+ * DRA752 GPU thermal sensor register offsets and bit-fields
+ */
+static struct temp_sensor_registers
+dra752_gpu_temp_sensor_registers = {
+       .temp_sensor_ctrl = DRA752_TEMP_SENSOR_GPU_OFFSET,
+       .bgap_tempsoff_mask = DRA752_TEMP_SENSOR_TMPSOFF_MASK,
+       .bgap_eocz_mask = DRA752_TEMP_SENSOR_EOCZ_MASK,
+       .bgap_dtemp_mask = DRA752_TEMP_SENSOR_DTEMP_MASK,
+       .bgap_mask_ctrl = DRA752_BANDGAP_CTRL_1_OFFSET,
+       .mask_hot_mask = DRA752_BANDGAP_CTRL_1_MASK_HOT_GPU_MASK,
+       .mask_cold_mask = DRA752_BANDGAP_CTRL_1_MASK_COLD_GPU_MASK,
+       .mask_sidlemode_mask = DRA752_BANDGAP_CTRL_1_SIDLEMODE_MASK,
+       .mask_freeze_mask = DRA752_BANDGAP_CTRL_1_FREEZE_GPU_MASK,
+       .mask_clear_mask = DRA752_BANDGAP_CTRL_1_CLEAR_GPU_MASK,
+       .mask_clear_accum_mask = DRA752_BANDGAP_CTRL_1_CLEAR_ACCUM_GPU_MASK,
+       .bgap_threshold = DRA752_BANDGAP_THRESHOLD_GPU_OFFSET,
+       .threshold_thot_mask = DRA752_BANDGAP_THRESHOLD_HOT_MASK,
+       .threshold_tcold_mask = DRA752_BANDGAP_THRESHOLD_COLD_MASK,
+       .tshut_threshold = DRA752_BANDGAP_TSHUT_GPU_OFFSET,
+       .tshut_hot_mask = DRA752_TSHUT_THRESHOLD_HOT_MASK,
+       .tshut_cold_mask = DRA752_TSHUT_THRESHOLD_COLD_MASK,
+       .bgap_status = DRA752_BANDGAP_STATUS_1_OFFSET,
+       .status_bgap_alert_mask = DRA752_BANDGAP_STATUS_1_ALERT_MASK,
+       .status_hot_mask = DRA752_BANDGAP_STATUS_1_HOT_GPU_MASK,
+       .status_cold_mask = DRA752_BANDGAP_STATUS_1_COLD_GPU_MASK,
+       .bgap_cumul_dtemp = DRA752_BANDGAP_CUMUL_DTEMP_GPU_OFFSET,
+       .ctrl_dtemp_0 = DRA752_DTEMP_GPU_0_OFFSET,
+       .ctrl_dtemp_1 = DRA752_DTEMP_GPU_1_OFFSET,
+       .ctrl_dtemp_2 = DRA752_DTEMP_GPU_2_OFFSET,
+       .ctrl_dtemp_3 = DRA752_DTEMP_GPU_3_OFFSET,
+       .ctrl_dtemp_4 = DRA752_DTEMP_GPU_4_OFFSET,
+       .bgap_efuse = DRA752_STD_FUSE_OPP_BGAP_GPU_OFFSET,
+};
+
+/* Thresholds and limits for DRA752 MPU temperature sensor */
+static struct temp_sensor_data dra752_mpu_temp_sensor_data = {
+       .tshut_hot = DRA752_MPU_TSHUT_HOT,
+       .tshut_cold = DRA752_MPU_TSHUT_COLD,
+       .t_hot = DRA752_MPU_T_HOT,
+       .t_cold = DRA752_MPU_T_COLD,
+       .min_freq = DRA752_MPU_MIN_FREQ,
+       .max_freq = DRA752_MPU_MAX_FREQ,
+       .max_temp = DRA752_MPU_MAX_TEMP,
+       .min_temp = DRA752_MPU_MIN_TEMP,
+       .hyst_val = DRA752_MPU_HYST_VAL,
+       .update_int1 = 1000,
+       .update_int2 = 2000,
+};
+
+/* Thresholds and limits for DRA752 GPU temperature sensor */
+static struct temp_sensor_data dra752_gpu_temp_sensor_data = {
+       .tshut_hot = DRA752_GPU_TSHUT_HOT,
+       .tshut_cold = DRA752_GPU_TSHUT_COLD,
+       .t_hot = DRA752_GPU_T_HOT,
+       .t_cold = DRA752_GPU_T_COLD,
+       .min_freq = DRA752_GPU_MIN_FREQ,
+       .max_freq = DRA752_GPU_MAX_FREQ,
+       .max_temp = DRA752_GPU_MAX_TEMP,
+       .min_temp = DRA752_GPU_MIN_TEMP,
+       .hyst_val = DRA752_GPU_HYST_VAL,
+       .update_int1 = 1000,
+       .update_int2 = 2000,
+};
+
+/* Thresholds and limits for DRA752 CORE temperature sensor */
+static struct temp_sensor_data dra752_core_temp_sensor_data = {
+       .tshut_hot = DRA752_CORE_TSHUT_HOT,
+       .tshut_cold = DRA752_CORE_TSHUT_COLD,
+       .t_hot = DRA752_CORE_T_HOT,
+       .t_cold = DRA752_CORE_T_COLD,
+       .min_freq = DRA752_CORE_MIN_FREQ,
+       .max_freq = DRA752_CORE_MAX_FREQ,
+       .max_temp = DRA752_CORE_MAX_TEMP,
+       .min_temp = DRA752_CORE_MIN_TEMP,
+       .hyst_val = DRA752_CORE_HYST_VAL,
+       .update_int1 = 1000,
+       .update_int2 = 2000,
+};
+
+/* Thresholds and limits for DRA752 DSPEVE temperature sensor */
+static struct temp_sensor_data dra752_dspeve_temp_sensor_data = {
+       .tshut_hot = DRA752_DSPEVE_TSHUT_HOT,
+       .tshut_cold = DRA752_DSPEVE_TSHUT_COLD,
+       .t_hot = DRA752_DSPEVE_T_HOT,
+       .t_cold = DRA752_DSPEVE_T_COLD,
+       .min_freq = DRA752_DSPEVE_MIN_FREQ,
+       .max_freq = DRA752_DSPEVE_MAX_FREQ,
+       .max_temp = DRA752_DSPEVE_MAX_TEMP,
+       .min_temp = DRA752_DSPEVE_MIN_TEMP,
+       .hyst_val = DRA752_DSPEVE_HYST_VAL,
+       .update_int1 = 1000,
+       .update_int2 = 2000,
+};
+
+/* Thresholds and limits for DRA752 IVA temperature sensor */
+static struct temp_sensor_data dra752_iva_temp_sensor_data = {
+       .tshut_hot = DRA752_IVA_TSHUT_HOT,
+       .tshut_cold = DRA752_IVA_TSHUT_COLD,
+       .t_hot = DRA752_IVA_T_HOT,
+       .t_cold = DRA752_IVA_T_COLD,
+       .min_freq = DRA752_IVA_MIN_FREQ,
+       .max_freq = DRA752_IVA_MAX_FREQ,
+       .max_temp = DRA752_IVA_MAX_TEMP,
+       .min_temp = DRA752_IVA_MIN_TEMP,
+       .hyst_val = DRA752_IVA_HYST_VAL,
+       .update_int1 = 1000,
+       .update_int2 = 2000,
+};
+
+/*
+ * DRA752 : Temperature values in milli degree celsius
+ * ADC code values from 540 to 945
+ */
+static
+int dra752_adc_to_temp[DRA752_ADC_END_VALUE - DRA752_ADC_START_VALUE + 1] = {
+       /* Index 540 - 549 */
+       -40000, -40000, -40000, -40000, -39800, -39400, -39000, -38600, -38200,
+       -37800,
+       /* Index 550 - 559 */
+       -37400, -37000, -36600, -36200, -35800, -35300, -34700, -34200, -33800,
+       -33400,
+       /* Index 560 - 569 */
+       -33000, -32600, -32200, -31800, -31400, -31000, -30600, -30200, -29800,
+       -29400,
+       /* Index 570 - 579 */
+       -29000, -28600, -28200, -27700, -27100, -26600, -26200, -25800, -25400,
+       -25000,
+       /* Index 580 - 589 */
+       -24600, -24200, -23800, -23400, -23000, -22600, -22200, -21800, -21400,
+       -21000,
+       /* Index 590 - 599 */
+       -20500, -19900, -19400, -19000, -18600, -18200, -17800, -17400, -17000,
+       -16600,
+       /* Index 600 - 609 */
+       -16200, -15800, -15400, -15000, -14600, -14200, -13800, -13400, -13000,
+       -12500,
+       /* Index 610 - 619 */
+       -11900, -11400, -11000, -10600, -10200, -9800, -9400, -9000, -8600,
+       -8200,
+       /* Index 620 - 629 */
+       -7800, -7400, -7000, -6600, -6200, -5800, -5400, -5000, -4500,
+       -3900,
+       /* Index 630 - 639 */
+       -3400, -3000, -2600, -2200, -1800, -1400, -1000, -600, -200,
+       200,
+       /* Index 640 - 649 */
+       600, 1000, 1400, 1800, 2200, 2600, 3000, 3400, 3900,
+       4500,
+       /* Index 650 - 659 */
+       5000, 5400, 5800, 6200, 6600, 7000, 7400, 7800, 8200,
+       8600,
+       /* Index 660 - 669 */
+       9000, 9400, 9800, 10200, 10600, 11000, 11400, 11800, 12200,
+       12700,
+       /* Index 670 - 679 */
+       13300, 13800, 14200, 14600, 15000, 15400, 15800, 16200, 16600,
+       17000,
+       /* Index 680 - 689 */
+       17400, 17800, 18200, 18600, 19000, 19400, 19800, 20200, 20600,
+       21000,
+       /* Index 690 - 699 */
+       21400, 21900, 22500, 23000, 23400, 23800, 24200, 24600, 25000,
+       25400,
+       /* Index 700 - 709 */
+       25800, 26200, 26600, 27000, 27400, 27800, 28200, 28600, 29000,
+       29400,
+       /* Index 710 - 719 */
+       29800, 30200, 30600, 31000, 31400, 31900, 32500, 33000, 33400,
+       33800,
+       /* Index 720 - 729 */
+       34200, 34600, 35000, 35400, 35800, 36200, 36600, 37000, 37400,
+       37800,
+       /* Index 730 - 739 */
+       38200, 38600, 39000, 39400, 39800, 40200, 40600, 41000, 41400,
+       41800,
+       /* Index 740 - 749 */
+       42200, 42600, 43100, 43700, 44200, 44600, 45000, 45400, 45800,
+       46200,
+       /* Index 750 - 759 */
+       46600, 47000, 47400, 47800, 48200, 48600, 49000, 49400, 49800,
+       50200,
+       /* Index 760 - 769 */
+       50600, 51000, 51400, 51800, 52200, 52600, 53000, 53400, 53800,
+       54200,
+       /* Index 770 - 779 */
+       54600, 55000, 55400, 55900, 56500, 57000, 57400, 57800, 58200,
+       58600,
+       /* Index 780 - 789 */
+       59000, 59400, 59800, 60200, 60600, 61000, 61400, 61800, 62200,
+       62600,
+       /* Index 790 - 799 */
+       63000, 63400, 63800, 64200, 64600, 65000, 65400, 65800, 66200,
+       66600,
+       /* Index 800 - 809 */
+       67000, 67400, 67800, 68200, 68600, 69000, 69400, 69800, 70200,
+       70600,
+       /* Index 810 - 819 */
+       71000, 71500, 72100, 72600, 73000, 73400, 73800, 74200, 74600,
+       75000,
+       /* Index 820 - 829 */
+       75400, 75800, 76200, 76600, 77000, 77400, 77800, 78200, 78600,
+       79000,
+       /* Index 830 - 839 */
+       79400, 79800, 80200, 80600, 81000, 81400, 81800, 82200, 82600,
+       83000,
+       /* Index 840 - 849 */
+       83400, 83800, 84200, 84600, 85000, 85400, 85800, 86200, 86600,
+       87000,
+       /* Index 850 - 859 */
+       87400, 87800, 88200, 88600, 89000, 89400, 89800, 90200, 90600,
+       91000,
+       /* Index 860 - 869 */
+       91400, 91800, 92200, 92600, 93000, 93400, 93800, 94200, 94600,
+       95000,
+       /* Index 870 - 879 */
+       95400, 95800, 96200, 96600, 97000, 97500, 98100, 98600, 99000,
+       99400,
+       /* Index 880 - 889 */
+       99800, 100200, 100600, 101000, 101400, 101800, 102200, 102600, 103000,
+       103400,
+       /* Index 890 - 899 */
+       103800, 104200, 104600, 105000, 105400, 105800, 106200, 106600, 107000,
+       107400,
+       /* Index 900 - 909 */
+       107800, 108200, 108600, 109000, 109400, 109800, 110200, 110600, 111000,
+       111400,
+       /* Index 910 - 919 */
+       111800, 112200, 112600, 113000, 113400, 113800, 114200, 114600, 115000,
+       115400,
+       /* Index 920 - 929 */
+       115800, 116200, 116600, 117000, 117400, 117800, 118200, 118600, 119000,
+       119400,
+       /* Index 930 - 939 */
+       119800, 120200, 120600, 121000, 121400, 121800, 122200, 122600, 123000,
+       123400,
+       /* Index 940 - 945 */
+       123800, 124200, 124600, 124900, 125000, 125000,
+};
+
+/* DRA752 data */
+const struct ti_bandgap_data dra752_data = {
+       .features = TI_BANDGAP_FEATURE_TSHUT_CONFIG |
+                       TI_BANDGAP_FEATURE_FREEZE_BIT |
+                       TI_BANDGAP_FEATURE_TALERT |
+                       TI_BANDGAP_FEATURE_COUNTER_DELAY |
+                       TI_BANDGAP_FEATURE_HISTORY_BUFFER,
+       .fclock_name = "l3instr_ts_gclk_div",
+       .div_ck_name = "l3instr_ts_gclk_div",
+       .conv_table = dra752_adc_to_temp,
+       .adc_start_val = DRA752_ADC_START_VALUE,
+       .adc_end_val = DRA752_ADC_END_VALUE,
+       .expose_sensor = ti_thermal_expose_sensor,
+       .remove_sensor = ti_thermal_remove_sensor,
+       .sensors = {
+               {
+               .registers = &dra752_mpu_temp_sensor_registers,
+               .ts_data = &dra752_mpu_temp_sensor_data,
+               .domain = "cpu",
+               .register_cooling = ti_thermal_register_cpu_cooling,
+               .unregister_cooling = ti_thermal_unregister_cpu_cooling,
+               .slope = DRA752_GRADIENT_SLOPE,
+               .constant = DRA752_GRADIENT_CONST,
+               .slope_pcb = DRA752_GRADIENT_SLOPE_W_PCB,
+               .constant_pcb = DRA752_GRADIENT_CONST_W_PCB,
+               },
+               {
+               .registers = &dra752_gpu_temp_sensor_registers,
+               .ts_data = &dra752_gpu_temp_sensor_data,
+               .domain = "gpu",
+               .slope = DRA752_GRADIENT_SLOPE,
+               .constant = DRA752_GRADIENT_CONST,
+               .slope_pcb = DRA752_GRADIENT_SLOPE_W_PCB,
+               .constant_pcb = DRA752_GRADIENT_CONST_W_PCB,
+               },
+               {
+               .registers = &dra752_core_temp_sensor_registers,
+               .ts_data = &dra752_core_temp_sensor_data,
+               .domain = "core",
+               .slope = DRA752_GRADIENT_SLOPE,
+               .constant = DRA752_GRADIENT_CONST,
+               .slope_pcb = DRA752_GRADIENT_SLOPE_W_PCB,
+               .constant_pcb = DRA752_GRADIENT_CONST_W_PCB,
+               },
+               {
+               .registers = &dra752_dspeve_temp_sensor_registers,
+               .ts_data = &dra752_dspeve_temp_sensor_data,
+               .domain = "dspeve",
+               .slope = DRA752_GRADIENT_SLOPE,
+               .constant = DRA752_GRADIENT_CONST,
+               .slope_pcb = DRA752_GRADIENT_SLOPE_W_PCB,
+               .constant_pcb = DRA752_GRADIENT_CONST_W_PCB,
+               },
+               {
+               .registers = &dra752_iva_temp_sensor_registers,
+               .ts_data = &dra752_iva_temp_sensor_data,
+               .domain = "iva",
+               .slope = DRA752_GRADIENT_SLOPE,
+               .constant = DRA752_GRADIENT_CONST,
+               .slope_pcb = DRA752_GRADIENT_SLOPE_W_PCB,
+               .constant_pcb = DRA752_GRADIENT_CONST_W_PCB,
+               },
+       },
+       .sensor_count = 5,
+};
similarity index 98%
rename from drivers/staging/ti-soc-thermal/ti-bandgap.c
rename to drivers/thermal/ti-soc-thermal/ti-bandgap.c
index f20c1cf..9dfd471 100644 (file)
@@ -38,6 +38,7 @@
 #include <linux/of_device.h>
 #include <linux/of_platform.h>
 #include <linux/of_irq.h>
+#include <linux/of_gpio.h>
 #include <linux/io.h>
 
 #include "ti-bandgap.h"
@@ -469,7 +470,7 @@ static inline int ti_bandgap_validate(struct ti_bandgap *bgp, int id)
 {
        int ret = 0;
 
-       if (IS_ERR_OR_NULL(bgp)) {
+       if (!bgp || IS_ERR(bgp)) {
                pr_err("%s: invalid bandgap pointer\n", __func__);
                ret = -EINVAL;
                goto exit;
@@ -992,9 +993,12 @@ int ti_bandgap_get_trend(struct ti_bandgap *bgp, int id, int *trend)
                goto exit;
        }
 
+       spin_lock(&bgp->lock);
+
        tsr = bgp->conf->sensors[id].registers;
 
        /* Freeze and read the last 2 valid readings */
+       RMW_BITS(bgp, id, bgap_mask_ctrl, mask_freeze_mask, 1);
        reg1 = tsr->ctrl_dtemp_1;
        reg2 = tsr->ctrl_dtemp_2;
 
@@ -1008,22 +1012,25 @@ int ti_bandgap_get_trend(struct ti_bandgap *bgp, int id, int *trend)
        /* Convert from adc values to mCelsius temperature */
        ret = ti_bandgap_adc_to_mcelsius(bgp, temp1, &t1);
        if (ret)
-               goto exit;
+               goto unfreeze;
 
        ret = ti_bandgap_adc_to_mcelsius(bgp, temp2, &t2);
        if (ret)
-               goto exit;
+               goto unfreeze;
 
        /* Fetch the update interval */
        ret = ti_bandgap_read_update_interval(bgp, id, &interval);
        if (ret || !interval)
-               goto exit;
+               goto unfreeze;
 
        *trend = (t1 - t2) / interval;
 
        dev_dbg(bgp->dev, "The temperatures are t1 = %d and t2 = %d and trend =%d\n",
                t1, t2, *trend);
 
+unfreeze:
+       RMW_BITS(bgp, id, bgap_mask_ctrl, mask_freeze_mask, 0);
+       spin_unlock(&bgp->lock);
 exit:
        return ret;
 }
@@ -1123,7 +1130,6 @@ static struct ti_bandgap *ti_bandgap_build(struct platform_device *pdev)
        const struct of_device_id *of_id;
        struct ti_bandgap *bgp;
        struct resource *res;
-       u32 prop;
        int i;
 
        /* just for the sake */
@@ -1167,11 +1173,7 @@ static struct ti_bandgap *ti_bandgap_build(struct platform_device *pdev)
        } while (res);
 
        if (TI_BANDGAP_HAS(bgp, TSHUT)) {
-               if (of_property_read_u32(node, "ti,tshut-gpio", &prop) < 0) {
-                       dev_err(&pdev->dev, "missing tshut gpio in device tree\n");
-                       return ERR_PTR(-EINVAL);
-               }
-               bgp->tshut_gpio = prop;
+               bgp->tshut_gpio = of_get_gpio(node, 0);
                if (!gpio_is_valid(bgp->tshut_gpio)) {
                        dev_err(&pdev->dev, "invalid gpio for tshut (%d)\n",
                                bgp->tshut_gpio);
@@ -1191,7 +1193,7 @@ int ti_bandgap_probe(struct platform_device *pdev)
        int clk_rate, ret = 0, i;
 
        bgp = ti_bandgap_build(pdev);
-       if (IS_ERR_OR_NULL(bgp)) {
+       if (IS_ERR(bgp)) {
                dev_err(&pdev->dev, "failed to fetch platform data\n");
                return PTR_ERR(bgp);
        }
@@ -1207,17 +1209,19 @@ int ti_bandgap_probe(struct platform_device *pdev)
        }
 
        bgp->fclock = clk_get(NULL, bgp->conf->fclock_name);
-       ret = IS_ERR_OR_NULL(bgp->fclock);
+       ret = IS_ERR(bgp->fclock);
        if (ret) {
                dev_err(&pdev->dev, "failed to request fclock reference\n");
+               ret = PTR_ERR(bgp->fclock);
                goto free_irqs;
        }
 
        bgp->div_clk = clk_get(NULL,  bgp->conf->div_ck_name);
-       ret = IS_ERR_OR_NULL(bgp->div_clk);
+       ret = IS_ERR(bgp->div_clk);
        if (ret) {
                dev_err(&pdev->dev,
                        "failed to request div_ts_ck clock ref\n");
+               ret = PTR_ERR(bgp->div_clk);
                goto free_irqs;
        }
 
@@ -1523,6 +1527,12 @@ static const struct of_device_id of_ti_bandgap_match[] = {
                .data = (void *)&omap5430_data,
        },
 #endif
+#ifdef CONFIG_DRA752_THERMAL
+       {
+               .compatible = "ti,dra752-bandgap",
+               .data = (void *)&dra752_data,
+       },
+#endif
        /* Sentinel */
        { },
 };
similarity index 99%
rename from drivers/staging/ti-soc-thermal/ti-bandgap.h
rename to drivers/thermal/ti-soc-thermal/ti-bandgap.h
index 5f4794a..b3adf72 100644 (file)
@@ -400,4 +400,9 @@ extern const struct ti_bandgap_data omap5430_data;
 #define omap5430_data                                  NULL
 #endif
 
+#ifdef CONFIG_DRA752_THERMAL
+extern const struct ti_bandgap_data dra752_data;
+#else
+#define dra752_data                                    NULL
+#endif
 #endif
@@ -101,7 +101,7 @@ static inline int ti_thermal_get_temp(struct thermal_zone_device *thermal,
 
        pcb_tz = data->pcb_tz;
        /* In case pcb zone is available, use the extrapolation rule with it */
-       if (!IS_ERR_OR_NULL(pcb_tz)) {
+       if (!IS_ERR(pcb_tz)) {
                ret = thermal_zone_get_temp(pcb_tz, &pcb_temp);
                if (!ret) {
                        tmp -= pcb_temp; /* got a valid PCB temp */
@@ -124,7 +124,7 @@ static int ti_thermal_bind(struct thermal_zone_device *thermal,
        struct ti_thermal_data *data = thermal->devdata;
        int id;
 
-       if (IS_ERR_OR_NULL(data))
+       if (!data || IS_ERR(data))
                return -ENODEV;
 
        /* check if this is the cooling device we registered */
@@ -146,7 +146,7 @@ static int ti_thermal_unbind(struct thermal_zone_device *thermal,
 {
        struct ti_thermal_data *data = thermal->devdata;
 
-       if (IS_ERR_OR_NULL(data))
+       if (!data || IS_ERR(data))
                return -ENODEV;
 
        /* check if this is the cooling device we registered */
@@ -282,6 +282,7 @@ static struct ti_thermal_data
        data->sensor_id = id;
        data->bgp = bgp;
        data->mode = THERMAL_DEVICE_ENABLED;
+       /* pcb_tz will be either valid or PTR_ERR() */
        data->pcb_tz = thermal_zone_get_zone_by_name("pcb");
        INIT_WORK(&data->thermal_wq, ti_thermal_work);
 
@@ -295,7 +296,7 @@ int ti_thermal_expose_sensor(struct ti_bandgap *bgp, int id,
 
        data = ti_bandgap_get_sensor_data(bgp, id);
 
-       if (IS_ERR_OR_NULL(data))
+       if (!data || IS_ERR(data))
                data = ti_thermal_build_data(bgp, id);
 
        if (!data)
@@ -306,7 +307,7 @@ int ti_thermal_expose_sensor(struct ti_bandgap *bgp, int id,
                                OMAP_TRIP_NUMBER, 0, data, &ti_thermal_ops,
                                NULL, FAST_TEMP_MONITORING_RATE,
                                FAST_TEMP_MONITORING_RATE);
-       if (IS_ERR_OR_NULL(data->ti_thermal)) {
+       if (IS_ERR(data->ti_thermal)) {
                dev_err(bgp->dev, "thermal zone device is NULL\n");
                return PTR_ERR(data->ti_thermal);
        }
@@ -343,7 +344,7 @@ int ti_thermal_register_cpu_cooling(struct ti_bandgap *bgp, int id)
        struct ti_thermal_data *data;
 
        data = ti_bandgap_get_sensor_data(bgp, id);
-       if (IS_ERR_OR_NULL(data))
+       if (!data || IS_ERR(data))
                data = ti_thermal_build_data(bgp, id);
 
        if (!data)
@@ -356,7 +357,7 @@ int ti_thermal_register_cpu_cooling(struct ti_bandgap *bgp, int id)
 
        /* Register cooling device */
        data->cool_dev = cpufreq_cooling_register(cpu_present_mask);
-       if (IS_ERR_OR_NULL(data->cool_dev)) {
+       if (IS_ERR(data->cool_dev)) {
                dev_err(bgp->dev,
                        "Failed to register cpufreq cooling device\n");
                return PTR_ERR(data->cool_dev);
similarity index 95%
rename from drivers/staging/ti-soc-thermal/ti-thermal.h
rename to drivers/thermal/ti-soc-thermal/ti-thermal.h
index 5055777..f8b7ffe 100644 (file)
@@ -38,6 +38,9 @@
 #define OMAP_GRADIENT_SLOPE_5430_GPU                           117
 #define OMAP_GRADIENT_CONST_5430_GPU                           -2992
 
+#define DRA752_GRADIENT_SLOPE                                  0
+#define DRA752_GRADIENT_CONST                                  2000
+
 /* PCB sensor calculation constants */
 #define OMAP_GRADIENT_SLOPE_W_PCB_4430                         0
 #define OMAP_GRADIENT_CONST_W_PCB_4430                         20000
@@ -51,6 +54,9 @@
 #define OMAP_GRADIENT_SLOPE_W_PCB_5430_GPU                     464
 #define OMAP_GRADIENT_CONST_W_PCB_5430_GPU                     -5102
 
+#define DRA752_GRADIENT_SLOPE_W_PCB                            0
+#define DRA752_GRADIENT_CONST_W_PCB                            2000
+
 /* trip points of interest in milicelsius (at hotspot level) */
 #define OMAP_TRIP_COLD                                         100000
 #define OMAP_TRIP_HOT                                          110000
diff --git a/drivers/thermal/x86_pkg_temp_thermal.c b/drivers/thermal/x86_pkg_temp_thermal.c
new file mode 100644 (file)
index 0000000..5de56f6
--- /dev/null
@@ -0,0 +1,642 @@
+/*
+ * x86_pkg_temp_thermal driver
+ * Copyright (c) 2013, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ *
+ */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/param.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/cpu.h>
+#include <linux/smp.h>
+#include <linux/slab.h>
+#include <linux/pm.h>
+#include <linux/thermal.h>
+#include <linux/debugfs.h>
+#include <asm/cpu_device_id.h>
+#include <asm/mce.h>
+
+/*
+* Rate control delay: Idea is to introduce denounce effect
+* This should be long enough to avoid reduce events, when
+* threshold is set to a temperature, which is constantly
+* violated, but at the short enough to take any action.
+* The action can be remove threshold or change it to next
+* interesting setting. Based on experiments, in around
+* every 5 seconds under load will give us a significant
+* temperature change.
+*/
+#define PKG_TEMP_THERMAL_NOTIFY_DELAY  5000
+static int notify_delay_ms = PKG_TEMP_THERMAL_NOTIFY_DELAY;
+module_param(notify_delay_ms, int, 0644);
+MODULE_PARM_DESC(notify_delay_ms,
+       "User space notification delay in milli seconds.");
+
+/* Number of trip points in thermal zone. Currently it can't
+* be more than 2. MSR can allow setting and getting notifications
+* for only 2 thresholds. This define enforces this, if there
+* is some wrong values returned by cpuid for number of thresholds.
+*/
+#define MAX_NUMBER_OF_TRIPS    2
+
+struct phy_dev_entry {
+       struct list_head list;
+       u16 phys_proc_id;
+       u16 first_cpu;
+       u32 tj_max;
+       int ref_cnt;
+       u32 start_pkg_therm_low;
+       u32 start_pkg_therm_high;
+       struct thermal_zone_device *tzone;
+};
+
+/* List maintaining number of package instances */
+static LIST_HEAD(phy_dev_list);
+static DEFINE_MUTEX(phy_dev_list_mutex);
+
+/* Interrupt to work function schedule queue */
+static DEFINE_PER_CPU(struct delayed_work, pkg_temp_thermal_threshold_work);
+
+/* To track if the work is already scheduled on a package */
+static u8 *pkg_work_scheduled;
+
+/* Spin lock to prevent races with pkg_work_scheduled */
+static spinlock_t pkg_work_lock;
+static u16 max_phy_id;
+
+/* Debug counters to show using debugfs */
+static struct dentry *debugfs;
+static unsigned int pkg_interrupt_cnt;
+static unsigned int pkg_work_cnt;
+
+static int pkg_temp_debugfs_init(void)
+{
+       struct dentry *d;
+
+       debugfs = debugfs_create_dir("pkg_temp_thermal", NULL);
+       if (!debugfs)
+               return -ENOENT;
+
+       d = debugfs_create_u32("pkg_thres_interrupt", S_IRUGO, debugfs,
+                               (u32 *)&pkg_interrupt_cnt);
+       if (!d)
+               goto err_out;
+
+       d = debugfs_create_u32("pkg_thres_work", S_IRUGO, debugfs,
+                               (u32 *)&pkg_work_cnt);
+       if (!d)
+               goto err_out;
+
+       return 0;
+
+err_out:
+       debugfs_remove_recursive(debugfs);
+       return -ENOENT;
+}
+
+static struct phy_dev_entry
+                       *pkg_temp_thermal_get_phy_entry(unsigned int cpu)
+{
+       u16 phys_proc_id = topology_physical_package_id(cpu);
+       struct phy_dev_entry *phy_ptr;
+
+       mutex_lock(&phy_dev_list_mutex);
+
+       list_for_each_entry(phy_ptr, &phy_dev_list, list)
+               if (phy_ptr->phys_proc_id == phys_proc_id) {
+                       mutex_unlock(&phy_dev_list_mutex);
+                       return phy_ptr;
+               }
+
+       mutex_unlock(&phy_dev_list_mutex);
+
+       return NULL;
+}
+
+/*
+* tj-max is is interesting because threshold is set relative to this
+* temperature.
+*/
+static int get_tj_max(int cpu, u32 *tj_max)
+{
+       u32 eax, edx;
+       u32 val;
+       int err;
+
+       err = rdmsr_safe_on_cpu(cpu, MSR_IA32_TEMPERATURE_TARGET, &eax, &edx);
+       if (err)
+               goto err_ret;
+       else {
+               val = (eax >> 16) & 0xff;
+               if (val)
+                       *tj_max = val * 1000;
+               else {
+                       err = -EINVAL;
+                       goto err_ret;
+               }
+       }
+
+       return 0;
+err_ret:
+       *tj_max = 0;
+       return err;
+}
+
+static int sys_get_curr_temp(struct thermal_zone_device *tzd, unsigned long *temp)
+{
+       u32 eax, edx;
+       struct phy_dev_entry *phy_dev_entry;
+
+       phy_dev_entry = tzd->devdata;
+       rdmsr_on_cpu(phy_dev_entry->first_cpu, MSR_IA32_PACKAGE_THERM_STATUS,
+                       &eax, &edx);
+       if (eax & 0x80000000) {
+               *temp = phy_dev_entry->tj_max -
+                               ((eax >> 16) & 0x7f) * 1000;
+               pr_debug("sys_get_curr_temp %ld\n", *temp);
+               return 0;
+       }
+
+       return -EINVAL;
+}
+
+static int sys_get_trip_temp(struct thermal_zone_device *tzd,
+               int trip, unsigned long *temp)
+{
+       u32 eax, edx;
+       struct phy_dev_entry *phy_dev_entry;
+       u32 mask, shift;
+       unsigned long thres_reg_value;
+       int ret;
+
+       if (trip >= MAX_NUMBER_OF_TRIPS)
+               return -EINVAL;
+
+       phy_dev_entry = tzd->devdata;
+
+       if (trip) {
+               mask = THERM_MASK_THRESHOLD1;
+               shift = THERM_SHIFT_THRESHOLD1;
+       } else {
+               mask = THERM_MASK_THRESHOLD0;
+               shift = THERM_SHIFT_THRESHOLD0;
+       }
+
+       ret = rdmsr_on_cpu(phy_dev_entry->first_cpu,
+                               MSR_IA32_PACKAGE_THERM_INTERRUPT, &eax, &edx);
+       if (ret < 0)
+               return -EINVAL;
+
+       thres_reg_value = (eax & mask) >> shift;
+       if (thres_reg_value)
+               *temp = phy_dev_entry->tj_max - thres_reg_value * 1000;
+       else
+               *temp = 0;
+       pr_debug("sys_get_trip_temp %ld\n", *temp);
+
+       return 0;
+}
+
+int sys_set_trip_temp(struct thermal_zone_device *tzd, int trip,
+                                                       unsigned long temp)
+{
+       u32 l, h;
+       struct phy_dev_entry *phy_dev_entry;
+       u32 mask, shift, intr;
+       int ret;
+
+       phy_dev_entry = tzd->devdata;
+
+       if (trip >= MAX_NUMBER_OF_TRIPS || temp >= phy_dev_entry->tj_max)
+               return -EINVAL;
+
+       ret = rdmsr_on_cpu(phy_dev_entry->first_cpu,
+                                       MSR_IA32_PACKAGE_THERM_INTERRUPT,
+                                       &l, &h);
+       if (ret < 0)
+               return -EINVAL;
+
+       if (trip) {
+               mask = THERM_MASK_THRESHOLD1;
+               shift = THERM_SHIFT_THRESHOLD1;
+               intr = THERM_INT_THRESHOLD1_ENABLE;
+       } else {
+               mask = THERM_MASK_THRESHOLD0;
+               shift = THERM_SHIFT_THRESHOLD0;
+               intr = THERM_INT_THRESHOLD0_ENABLE;
+       }
+       l &= ~mask;
+       /*
+       * When users space sets a trip temperature == 0, which is indication
+       * that, it is no longer interested in receiving notifications.
+       */
+       if (!temp)
+               l &= ~intr;
+       else {
+               l |= (phy_dev_entry->tj_max - temp)/1000 << shift;
+               l |= intr;
+       }
+
+       return wrmsr_on_cpu(phy_dev_entry->first_cpu,
+                                       MSR_IA32_PACKAGE_THERM_INTERRUPT,
+                                       l, h);
+}
+
+static int sys_get_trip_type(struct thermal_zone_device *thermal,
+               int trip, enum thermal_trip_type *type)
+{
+
+       *type = THERMAL_TRIP_PASSIVE;
+
+       return 0;
+}
+
+/* Thermal zone callback registry */
+static struct thermal_zone_device_ops tzone_ops = {
+       .get_temp = sys_get_curr_temp,
+       .get_trip_temp = sys_get_trip_temp,
+       .get_trip_type = sys_get_trip_type,
+       .set_trip_temp = sys_set_trip_temp,
+};
+
+static bool pkg_temp_thermal_platform_thermal_rate_control(void)
+{
+       return true;
+}
+
+/* Enable threshold interrupt on local package/cpu */
+static inline void enable_pkg_thres_interrupt(void)
+{
+       u32 l, h;
+       u8 thres_0, thres_1;
+
+       rdmsr(MSR_IA32_PACKAGE_THERM_INTERRUPT, l, h);
+       /* only enable/disable if it had valid threshold value */
+       thres_0 = (l & THERM_MASK_THRESHOLD0) >> THERM_SHIFT_THRESHOLD0;
+       thres_1 = (l & THERM_MASK_THRESHOLD1) >> THERM_SHIFT_THRESHOLD1;
+       if (thres_0)
+               l |= THERM_INT_THRESHOLD0_ENABLE;
+       if (thres_1)
+               l |= THERM_INT_THRESHOLD1_ENABLE;
+       wrmsr(MSR_IA32_PACKAGE_THERM_INTERRUPT, l, h);
+}
+
+/* Disable threshold interrupt on local package/cpu */
+static inline void disable_pkg_thres_interrupt(void)
+{
+       u32 l, h;
+       rdmsr(MSR_IA32_PACKAGE_THERM_INTERRUPT, l, h);
+       wrmsr(MSR_IA32_PACKAGE_THERM_INTERRUPT,
+                       l & (~THERM_INT_THRESHOLD0_ENABLE) &
+                               (~THERM_INT_THRESHOLD1_ENABLE), h);
+}
+
+static void pkg_temp_thermal_threshold_work_fn(struct work_struct *work)
+{
+       __u64 msr_val;
+       int cpu = smp_processor_id();
+       int phy_id = topology_physical_package_id(cpu);
+       struct phy_dev_entry *phdev = pkg_temp_thermal_get_phy_entry(cpu);
+       bool notify = false;
+
+       if (!phdev)
+               return;
+
+       spin_lock(&pkg_work_lock);
+       ++pkg_work_cnt;
+       if (unlikely(phy_id > max_phy_id)) {
+               spin_unlock(&pkg_work_lock);
+               return;
+       }
+       pkg_work_scheduled[phy_id] = 0;
+       spin_unlock(&pkg_work_lock);
+
+       enable_pkg_thres_interrupt();
+       rdmsrl(MSR_IA32_PACKAGE_THERM_STATUS, msr_val);
+       if (msr_val & THERM_LOG_THRESHOLD0) {
+               wrmsrl(MSR_IA32_PACKAGE_THERM_STATUS,
+                               msr_val & ~THERM_LOG_THRESHOLD0);
+               notify = true;
+       }
+       if (msr_val & THERM_LOG_THRESHOLD1) {
+               wrmsrl(MSR_IA32_PACKAGE_THERM_STATUS,
+                               msr_val & ~THERM_LOG_THRESHOLD1);
+               notify = true;
+       }
+       if (notify) {
+               pr_debug("thermal_zone_device_update\n");
+               thermal_zone_device_update(phdev->tzone);
+       }
+}
+
+static int pkg_temp_thermal_platform_thermal_notify(__u64 msr_val)
+{
+       unsigned long flags;
+       int cpu = smp_processor_id();
+       int phy_id = topology_physical_package_id(cpu);
+
+       /*
+       * When a package is in interrupted state, all CPU's in that package
+       * are in the same interrupt state. So scheduling on any one CPU in
+       * the package is enough and simply return for others.
+       */
+       spin_lock_irqsave(&pkg_work_lock, flags);
+       ++pkg_interrupt_cnt;
+       if (unlikely(phy_id > max_phy_id) || unlikely(!pkg_work_scheduled) ||
+                       pkg_work_scheduled[phy_id]) {
+               disable_pkg_thres_interrupt();
+               spin_unlock_irqrestore(&pkg_work_lock, flags);
+               return -EINVAL;
+       }
+       pkg_work_scheduled[phy_id] = 1;
+       spin_unlock_irqrestore(&pkg_work_lock, flags);
+
+       disable_pkg_thres_interrupt();
+       schedule_delayed_work_on(cpu,
+                               &per_cpu(pkg_temp_thermal_threshold_work, cpu),
+                               msecs_to_jiffies(notify_delay_ms));
+       return 0;
+}
+
+static int find_siblings_cpu(int cpu)
+{
+       int i;
+       int id = topology_physical_package_id(cpu);
+
+       for_each_online_cpu(i)
+               if (i != cpu && topology_physical_package_id(i) == id)
+                       return i;
+
+       return 0;
+}
+
+static int pkg_temp_thermal_device_add(unsigned int cpu)
+{
+       int err;
+       u32 tj_max;
+       struct phy_dev_entry *phy_dev_entry;
+       char buffer[30];
+       int thres_count;
+       u32 eax, ebx, ecx, edx;
+
+       cpuid(6, &eax, &ebx, &ecx, &edx);
+       thres_count = ebx & 0x07;
+       if (!thres_count)
+               return -ENODEV;
+
+       thres_count = clamp_val(thres_count, 0, MAX_NUMBER_OF_TRIPS);
+
+       err = get_tj_max(cpu, &tj_max);
+       if (err)
+               goto err_ret;
+
+       mutex_lock(&phy_dev_list_mutex);
+
+       phy_dev_entry = kzalloc(sizeof(*phy_dev_entry), GFP_KERNEL);
+       if (!phy_dev_entry) {
+               err = -ENOMEM;
+               goto err_ret_unlock;
+       }
+
+       spin_lock(&pkg_work_lock);
+       if (topology_physical_package_id(cpu) > max_phy_id)
+               max_phy_id = topology_physical_package_id(cpu);
+       pkg_work_scheduled = krealloc(pkg_work_scheduled,
+                               (max_phy_id+1) * sizeof(u8), GFP_ATOMIC);
+       if (!pkg_work_scheduled) {
+               spin_unlock(&pkg_work_lock);
+               err = -ENOMEM;
+               goto err_ret_free;
+       }
+       pkg_work_scheduled[topology_physical_package_id(cpu)] = 0;
+       spin_unlock(&pkg_work_lock);
+
+       phy_dev_entry->phys_proc_id = topology_physical_package_id(cpu);
+       phy_dev_entry->first_cpu = cpu;
+       phy_dev_entry->tj_max = tj_max;
+       phy_dev_entry->ref_cnt = 1;
+       snprintf(buffer, sizeof(buffer), "pkg-temp-%d\n",
+                                       phy_dev_entry->phys_proc_id);
+       phy_dev_entry->tzone = thermal_zone_device_register(buffer,
+                       thres_count,
+                       (thres_count == MAX_NUMBER_OF_TRIPS) ?
+                               0x03 : 0x01,
+                       phy_dev_entry, &tzone_ops, NULL, 0, 0);
+       if (IS_ERR(phy_dev_entry->tzone)) {
+               err = PTR_ERR(phy_dev_entry->tzone);
+               goto err_ret_free;
+       }
+       /* Store MSR value for package thermal interrupt, to restore at exit */
+       rdmsr_on_cpu(cpu, MSR_IA32_PACKAGE_THERM_INTERRUPT,
+                               &phy_dev_entry->start_pkg_therm_low,
+                               &phy_dev_entry->start_pkg_therm_high);
+
+       list_add_tail(&phy_dev_entry->list, &phy_dev_list);
+       pr_debug("pkg_temp_thermal_device_add :phy_id %d cpu %d\n",
+                       phy_dev_entry->phys_proc_id, cpu);
+
+       mutex_unlock(&phy_dev_list_mutex);
+
+       return 0;
+
+err_ret_free:
+       kfree(phy_dev_entry);
+err_ret_unlock:
+       mutex_unlock(&phy_dev_list_mutex);
+
+err_ret:
+       return err;
+}
+
+static int pkg_temp_thermal_device_remove(unsigned int cpu)
+{
+       struct phy_dev_entry *n;
+       u16 phys_proc_id = topology_physical_package_id(cpu);
+       struct phy_dev_entry *phdev =
+                       pkg_temp_thermal_get_phy_entry(cpu);
+
+       if (!phdev)
+               return -ENODEV;
+
+       mutex_lock(&phy_dev_list_mutex);
+       /* If we are loosing the first cpu for this package, we need change */
+       if (phdev->first_cpu == cpu) {
+               phdev->first_cpu = find_siblings_cpu(cpu);
+               pr_debug("thermal_device_remove: first cpu switched %d\n",
+                                       phdev->first_cpu);
+       }
+       /*
+       * It is possible that no siblings left as this was the last cpu
+       * going offline. We don't need to worry about this assignment
+       * as the phydev entry will be removed in this case and
+       * thermal zone is removed.
+       */
+       --phdev->ref_cnt;
+       pr_debug("thermal_device_remove: pkg: %d cpu %d ref_cnt %d\n",
+                                       phys_proc_id, cpu, phdev->ref_cnt);
+       if (!phdev->ref_cnt)
+               list_for_each_entry_safe(phdev, n, &phy_dev_list, list) {
+                       if (phdev->phys_proc_id == phys_proc_id) {
+                               thermal_zone_device_unregister(phdev->tzone);
+                               list_del(&phdev->list);
+                               kfree(phdev);
+                               break;
+                       }
+               }
+       mutex_unlock(&phy_dev_list_mutex);
+
+       return 0;
+}
+
+static int get_core_online(unsigned int cpu)
+{
+       struct cpuinfo_x86 *c = &cpu_data(cpu);
+       struct phy_dev_entry *phdev = pkg_temp_thermal_get_phy_entry(cpu);
+
+       /* Check if there is already an instance for this package */
+       if (!phdev) {
+               if (!cpu_has(c, X86_FEATURE_DTHERM) &&
+                                       !cpu_has(c, X86_FEATURE_PTS))
+                       return -ENODEV;
+               if (pkg_temp_thermal_device_add(cpu))
+                       return -ENODEV;
+       } else {
+               mutex_lock(&phy_dev_list_mutex);
+               ++phdev->ref_cnt;
+               pr_debug("get_core_online: cpu %d ref_cnt %d\n",
+                                               cpu, phdev->ref_cnt);
+               mutex_unlock(&phy_dev_list_mutex);
+       }
+       INIT_DELAYED_WORK(&per_cpu(pkg_temp_thermal_threshold_work, cpu),
+                       pkg_temp_thermal_threshold_work_fn);
+
+       pr_debug("get_core_online: cpu %d successful\n", cpu);
+
+       return 0;
+}
+
+static void put_core_offline(unsigned int cpu)
+{
+       if (!pkg_temp_thermal_device_remove(cpu))
+               cancel_delayed_work_sync(
+                       &per_cpu(pkg_temp_thermal_threshold_work, cpu));
+
+       pr_debug("put_core_offline: cpu %d\n", cpu);
+}
+
+static int pkg_temp_thermal_cpu_callback(struct notifier_block *nfb,
+                                unsigned long action, void *hcpu)
+{
+       unsigned int cpu = (unsigned long) hcpu;
+
+       switch (action) {
+       case CPU_ONLINE:
+       case CPU_DOWN_FAILED:
+               get_core_online(cpu);
+               break;
+       case CPU_DOWN_PREPARE:
+               put_core_offline(cpu);
+               break;
+       }
+       return NOTIFY_OK;
+}
+
+static struct notifier_block pkg_temp_thermal_notifier __refdata = {
+       .notifier_call = pkg_temp_thermal_cpu_callback,
+};
+
+static const struct x86_cpu_id __initconst pkg_temp_thermal_ids[] = {
+       { X86_VENDOR_INTEL, X86_FAMILY_ANY, X86_MODEL_ANY, X86_FEATURE_DTHERM },
+       {}
+};
+MODULE_DEVICE_TABLE(x86cpu, pkg_temp_thermal_ids);
+
+static int __init pkg_temp_thermal_init(void)
+{
+       int i;
+
+       if (!x86_match_cpu(pkg_temp_thermal_ids))
+               return -ENODEV;
+
+       spin_lock_init(&pkg_work_lock);
+       platform_thermal_package_notify =
+                       pkg_temp_thermal_platform_thermal_notify;
+       platform_thermal_package_rate_control =
+                       pkg_temp_thermal_platform_thermal_rate_control;
+
+       get_online_cpus();
+       for_each_online_cpu(i)
+               if (get_core_online(i))
+                       goto err_ret;
+       register_hotcpu_notifier(&pkg_temp_thermal_notifier);
+       put_online_cpus();
+
+       pkg_temp_debugfs_init(); /* Don't care if fails */
+
+       return 0;
+
+err_ret:
+       get_online_cpus();
+       for_each_online_cpu(i)
+               put_core_offline(i);
+       put_online_cpus();
+       kfree(pkg_work_scheduled);
+       platform_thermal_package_notify = NULL;
+       platform_thermal_package_rate_control = NULL;
+
+       return -ENODEV;
+}
+
+static void __exit pkg_temp_thermal_exit(void)
+{
+       struct phy_dev_entry *phdev, *n;
+       int i;
+
+       get_online_cpus();
+       unregister_hotcpu_notifier(&pkg_temp_thermal_notifier);
+       mutex_lock(&phy_dev_list_mutex);
+       list_for_each_entry_safe(phdev, n, &phy_dev_list, list) {
+               /* Retore old MSR value for package thermal interrupt */
+               wrmsr_on_cpu(phdev->first_cpu,
+                       MSR_IA32_PACKAGE_THERM_INTERRUPT,
+                       phdev->start_pkg_therm_low,
+                       phdev->start_pkg_therm_high);
+               thermal_zone_device_unregister(phdev->tzone);
+               list_del(&phdev->list);
+               kfree(phdev);
+       }
+       mutex_unlock(&phy_dev_list_mutex);
+       platform_thermal_package_notify = NULL;
+       platform_thermal_package_rate_control = NULL;
+       for_each_online_cpu(i)
+               cancel_delayed_work_sync(
+                       &per_cpu(pkg_temp_thermal_threshold_work, i));
+       put_online_cpus();
+
+       kfree(pkg_work_scheduled);
+
+       debugfs_remove_recursive(debugfs);
+}
+
+module_init(pkg_temp_thermal_init)
+module_exit(pkg_temp_thermal_exit)
+
+MODULE_DESCRIPTION("X86 PKG TEMP Thermal Driver");
+MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
+MODULE_LICENSE("GPL v2");
index d07b6af..76a8daa 100644 (file)
@@ -29,6 +29,8 @@
 #include <linux/clk.h>
 #include <linux/pm_runtime.h>
 
+#include <asm/byteorder.h>
+
 #include "8250.h"
 
 /* Offsets for the DesignWare specific registers */
@@ -57,6 +59,7 @@ struct dw8250_data {
        int             last_lcr;
        int             line;
        struct clk      *clk;
+       u8              usr_reg;
 };
 
 static void dw8250_serial_out(struct uart_port *p, int offset, int value)
@@ -77,6 +80,13 @@ static unsigned int dw8250_serial_in(struct uart_port *p, int offset)
        return readb(p->membase + offset);
 }
 
+/* Read Back (rb) version to ensure register access ording. */
+static void dw8250_serial_out_rb(struct uart_port *p, int offset, int value)
+{
+       dw8250_serial_out(p, offset, value);
+       dw8250_serial_in(p, UART_LCR);
+}
+
 static void dw8250_serial_out32(struct uart_port *p, int offset, int value)
 {
        struct dw8250_data *d = p->private_data;
@@ -104,7 +114,7 @@ static int dw8250_handle_irq(struct uart_port *p)
                return 1;
        } else if ((iir & UART_IIR_BUSY) == UART_IIR_BUSY) {
                /* Clear the USR and write the LCR again. */
-               (void)p->serial_in(p, DW_UART_USR);
+               (void)p->serial_in(p, d->usr_reg);
                p->serial_out(p, UART_LCR, d->last_lcr);
 
                return 1;
@@ -125,12 +135,60 @@ dw8250_do_pm(struct uart_port *port, unsigned int state, unsigned int old)
                pm_runtime_put_sync_suspend(port->dev);
 }
 
-static int dw8250_probe_of(struct uart_port *p)
+static void dw8250_setup_port(struct uart_8250_port *up)
+{
+       struct uart_port        *p = &up->port;
+       u32                     reg = readl(p->membase + DW_UART_UCV);
+
+       /*
+        * If the Component Version Register returns zero, we know that
+        * ADDITIONAL_FEATURES are not enabled. No need to go any further.
+        */
+       if (!reg)
+               return;
+
+       dev_dbg_ratelimited(p->dev, "Designware UART version %c.%c%c\n",
+               (reg >> 24) & 0xff, (reg >> 16) & 0xff, (reg >> 8) & 0xff);
+
+       reg = readl(p->membase + DW_UART_CPR);
+       if (!reg)
+               return;
+
+       /* Select the type based on fifo */
+       if (reg & DW_UART_CPR_FIFO_MODE) {
+               p->type = PORT_16550A;
+               p->flags |= UPF_FIXED_TYPE;
+               p->fifosize = DW_UART_CPR_FIFO_SIZE(reg);
+               up->tx_loadsz = p->fifosize;
+               up->capabilities = UART_CAP_FIFO;
+       }
+
+       if (reg & DW_UART_CPR_AFCE_MODE)
+               up->capabilities |= UART_CAP_AFE;
+}
+
+static int dw8250_probe_of(struct uart_port *p,
+                          struct dw8250_data *data)
 {
        struct device_node      *np = p->dev->of_node;
        u32                     val;
-
-       if (!of_property_read_u32(np, "reg-io-width", &val)) {
+       bool has_ucv = true;
+
+       if (of_device_is_compatible(np, "cavium,octeon-3860-uart")) {
+#ifdef __BIG_ENDIAN
+               /*
+                * Low order bits of these 64-bit registers, when
+                * accessed as a byte, are 7 bytes further down in the
+                * address space in big endian mode.
+                */
+               p->membase += 7;
+#endif
+               p->serial_out = dw8250_serial_out_rb;
+               p->flags = ASYNC_SKIP_TEST | UPF_SHARE_IRQ | UPF_FIXED_TYPE;
+               p->type = PORT_OCTEON;
+               data->usr_reg = 0x27;
+               has_ucv = false;
+       } else if (!of_property_read_u32(np, "reg-io-width", &val)) {
                switch (val) {
                case 1:
                        break;
@@ -144,6 +202,8 @@ static int dw8250_probe_of(struct uart_port *p)
                        return -EINVAL;
                }
        }
+       if (has_ucv)
+               dw8250_setup_port(container_of(p, struct uart_8250_port, port));
 
        if (!of_property_read_u32(np, "reg-shift", &val))
                p->regshift = val;
@@ -168,6 +228,8 @@ static int dw8250_probe_acpi(struct uart_8250_port *up)
        const struct acpi_device_id *id;
        struct uart_port *p = &up->port;
 
+       dw8250_setup_port(up);
+
        id = acpi_match_device(p->dev->driver->acpi_match_table, p->dev);
        if (!id)
                return -ENODEV;
@@ -196,38 +258,6 @@ static inline int dw8250_probe_acpi(struct uart_8250_port *up)
 }
 #endif /* CONFIG_ACPI */
 
-static void dw8250_setup_port(struct uart_8250_port *up)
-{
-       struct uart_port        *p = &up->port;
-       u32                     reg = readl(p->membase + DW_UART_UCV);
-
-       /*
-        * If the Component Version Register returns zero, we know that
-        * ADDITIONAL_FEATURES are not enabled. No need to go any further.
-        */
-       if (!reg)
-               return;
-
-       dev_dbg_ratelimited(p->dev, "Designware UART version %c.%c%c\n",
-               (reg >> 24) & 0xff, (reg >> 16) & 0xff, (reg >> 8) & 0xff);
-
-       reg = readl(p->membase + DW_UART_CPR);
-       if (!reg)
-               return;
-
-       /* Select the type based on fifo */
-       if (reg & DW_UART_CPR_FIFO_MODE) {
-               p->type = PORT_16550A;
-               p->flags |= UPF_FIXED_TYPE;
-               p->fifosize = DW_UART_CPR_FIFO_SIZE(reg);
-               up->tx_loadsz = p->fifosize;
-               up->capabilities = UART_CAP_FIFO;
-       }
-
-       if (reg & DW_UART_CPR_AFCE_MODE)
-               up->capabilities |= UART_CAP_AFE;
-}
-
 static int dw8250_probe(struct platform_device *pdev)
 {
        struct uart_8250_port uart = {};
@@ -259,6 +289,7 @@ static int dw8250_probe(struct platform_device *pdev)
        if (!data)
                return -ENOMEM;
 
+       data->usr_reg = DW_UART_USR;
        data->clk = devm_clk_get(&pdev->dev, NULL);
        if (!IS_ERR(data->clk)) {
                clk_prepare_enable(data->clk);
@@ -270,10 +301,8 @@ static int dw8250_probe(struct platform_device *pdev)
        uart.port.serial_out = dw8250_serial_out;
        uart.port.private_data = data;
 
-       dw8250_setup_port(&uart);
-
        if (pdev->dev.of_node) {
-               err = dw8250_probe_of(&uart.port);
+               err = dw8250_probe_of(&uart.port, data);
                if (err)
                        return err;
        } else if (ACPI_HANDLE(&pdev->dev)) {
@@ -362,6 +391,7 @@ static const struct dev_pm_ops dw8250_pm_ops = {
 
 static const struct of_device_id dw8250_of_match[] = {
        { .compatible = "snps,dw-apb-uart" },
+       { .compatible = "cavium,octeon-3860-uart" },
        { /* Sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, dw8250_of_match);
index 5f91c7a..e2a1f50 100644 (file)
@@ -406,7 +406,7 @@ uvc_register_video(struct uvc_device *uvc)
        if (video == NULL)
                return -ENOMEM;
 
-       video->parent = &cdev->gadget->dev;
+       video->v4l2_dev = &uvc->v4l2_dev;
        video->fops = &uvc_v4l2_fops;
        video->release = video_device_release;
        strlcpy(video->name, cdev->gadget->name, sizeof(video->name));
@@ -563,6 +563,7 @@ uvc_function_unbind(struct usb_configuration *c, struct usb_function *f)
        INFO(cdev, "uvc_function_unbind\n");
 
        video_unregister_device(uvc->vdev);
+       v4l2_device_unregister(&uvc->v4l2_dev);
        uvc->control_ep->driver_data = NULL;
        uvc->video.ep->driver_data = NULL;
 
@@ -690,6 +691,11 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
        if ((ret = usb_function_deactivate(f)) < 0)
                goto error;
 
+       if (v4l2_device_register(&cdev->gadget->dev, &uvc->v4l2_dev)) {
+               printk(KERN_INFO "v4l2_device_register failed\n");
+               goto error;
+       }
+
        /* Initialise video. */
        ret = uvc_video_init(&uvc->video);
        if (ret < 0)
@@ -705,6 +711,7 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
        return 0;
 
 error:
+       v4l2_device_unregister(&uvc->v4l2_dev);
        if (uvc->vdev)
                video_device_release(uvc->vdev);
 
index 7cacd6a..0ff3339 100644 (file)
@@ -1467,9 +1467,8 @@ static int usbg_get_cmd_state(struct se_cmd *se_cmd)
        return 0;
 }
 
-static int usbg_queue_tm_rsp(struct se_cmd *se_cmd)
+static void usbg_queue_tm_rsp(struct se_cmd *se_cmd)
 {
-       return 0;
 }
 
 static const char *usbg_check_wwn(const char *name)
index 817e9e1..7a9111d 100644 (file)
@@ -57,6 +57,7 @@ struct uvc_event
 #include <linux/videodev2.h>
 #include <linux/version.h>
 #include <media/v4l2-fh.h>
+#include <media/v4l2-device.h>
 
 #include "uvc_queue.h"
 
@@ -145,6 +146,7 @@ enum uvc_state
 struct uvc_device
 {
        struct video_device *vdev;
+       struct v4l2_device v4l2_dev;
        enum uvc_state state;
        struct usb_function func;
        struct uvc_video video;
index 2817013..4263d01 100644 (file)
@@ -283,7 +283,7 @@ config USB_EHCI_HCD_PLATFORM
 
 config USB_OCTEON_EHCI
        bool "Octeon on-chip EHCI support"
-       depends on CPU_CAVIUM_OCTEON
+       depends on CAVIUM_OCTEON_SOC
        default n
        select USB_EHCI_BIG_ENDIAN_MMIO
        help
@@ -488,7 +488,7 @@ config USB_OHCI_HCD_PLATFORM
 
 config USB_OCTEON_OHCI
        bool "Octeon on-chip OHCI support"
-       depends on CPU_CAVIUM_OCTEON
+       depends on CAVIUM_OCTEON_SOC
        default USB_OCTEON_EHCI
        select USB_OHCI_BIG_ENDIAN_MMIO
        select USB_OHCI_LITTLE_ENDIAN
index 9de7ada..1753bd3 100644 (file)
@@ -347,7 +347,7 @@ static int twl6030_usb_probe(struct platform_device *pdev)
        if (np) {
                twl->regulator = "usb";
        } else if (pdata) {
-               if (pdata->features & TWL6025_SUBCLASS)
+               if (pdata->features & TWL6032_SUBCLASS)
                        twl->regulator = "ldousb";
                else
                        twl->regulator = "vusb";
index 259ad28..c488da5 100644 (file)
@@ -76,6 +76,7 @@ struct vfio_group {
        struct notifier_block           nb;
        struct list_head                vfio_next;
        struct list_head                container_next;
+       atomic_t                        opened;
 };
 
 struct vfio_device {
@@ -206,6 +207,7 @@ static struct vfio_group *vfio_create_group(struct iommu_group *iommu_group)
        INIT_LIST_HEAD(&group->device_list);
        mutex_init(&group->device_lock);
        atomic_set(&group->container_users, 0);
+       atomic_set(&group->opened, 0);
        group->iommu_group = iommu_group;
 
        group->nb.notifier_call = vfio_iommu_group_notifier;
@@ -1236,12 +1238,22 @@ static long vfio_group_fops_compat_ioctl(struct file *filep,
 static int vfio_group_fops_open(struct inode *inode, struct file *filep)
 {
        struct vfio_group *group;
+       int opened;
 
        group = vfio_group_get_from_minor(iminor(inode));
        if (!group)
                return -ENODEV;
 
+       /* Do we need multiple instances of the group open?  Seems not. */
+       opened = atomic_cmpxchg(&group->opened, 0, 1);
+       if (opened) {
+               vfio_group_put(group);
+               return -EBUSY;
+       }
+
+       /* Is something still in use from a previous open? */
        if (group->container) {
+               atomic_dec(&group->opened);
                vfio_group_put(group);
                return -EBUSY;
        }
@@ -1259,6 +1271,8 @@ static int vfio_group_fops_release(struct inode *inode, struct file *filep)
 
        vfio_group_try_dissolve_container(group);
 
+       atomic_dec(&group->opened);
+
        vfio_group_put(group);
 
        return 0;
index 6f3fbc4..a9807de 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/module.h>
 #include <linux/mm.h>
 #include <linux/pci.h>         /* pci_bus_type */
+#include <linux/rbtree.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/uaccess.h>
@@ -47,19 +48,25 @@ module_param_named(allow_unsafe_interrupts,
 MODULE_PARM_DESC(allow_unsafe_interrupts,
                 "Enable VFIO IOMMU support for on platforms without interrupt remapping support.");
 
+static bool disable_hugepages;
+module_param_named(disable_hugepages,
+                  disable_hugepages, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(disable_hugepages,
+                "Disable VFIO IOMMU support for IOMMU hugepages.");
+
 struct vfio_iommu {
        struct iommu_domain     *domain;
        struct mutex            lock;
-       struct list_head        dma_list;
+       struct rb_root          dma_list;
        struct list_head        group_list;
        bool                    cache;
 };
 
 struct vfio_dma {
-       struct list_head        next;
+       struct rb_node          node;
        dma_addr_t              iova;           /* Device address */
        unsigned long           vaddr;          /* Process virtual addr */
-       long                    npage;          /* Number of pages */
+       size_t                  size;           /* Map size (bytes) */
        int                     prot;           /* IOMMU_READ/WRITE */
 };
 
@@ -73,7 +80,48 @@ struct vfio_group {
  * into DMA'ble space using the IOMMU
  */
 
-#define NPAGE_TO_SIZE(npage)   ((size_t)(npage) << PAGE_SHIFT)
+static struct vfio_dma *vfio_find_dma(struct vfio_iommu *iommu,
+                                     dma_addr_t start, size_t size)
+{
+       struct rb_node *node = iommu->dma_list.rb_node;
+
+       while (node) {
+               struct vfio_dma *dma = rb_entry(node, struct vfio_dma, node);
+
+               if (start + size <= dma->iova)
+                       node = node->rb_left;
+               else if (start >= dma->iova + dma->size)
+                       node = node->rb_right;
+               else
+                       return dma;
+       }
+
+       return NULL;
+}
+
+static void vfio_insert_dma(struct vfio_iommu *iommu, struct vfio_dma *new)
+{
+       struct rb_node **link = &iommu->dma_list.rb_node, *parent = NULL;
+       struct vfio_dma *dma;
+
+       while (*link) {
+               parent = *link;
+               dma = rb_entry(parent, struct vfio_dma, node);
+
+               if (new->iova + new->size <= dma->iova)
+                       link = &(*link)->rb_left;
+               else
+                       link = &(*link)->rb_right;
+       }
+
+       rb_link_node(&new->node, parent, link);
+       rb_insert_color(&new->node, &iommu->dma_list);
+}
+
+static void vfio_remove_dma(struct vfio_iommu *iommu, struct vfio_dma *old)
+{
+       rb_erase(&old->node, &iommu->dma_list);
+}
 
 struct vwork {
        struct mm_struct        *mm;
@@ -100,8 +148,8 @@ static void vfio_lock_acct(long npage)
        struct vwork *vwork;
        struct mm_struct *mm;
 
-       if (!current->mm)
-               return; /* process exited */
+       if (!current->mm || !npage)
+               return; /* process exited or nothing to do */
 
        if (down_write_trylock(&current->mm->mmap_sem)) {
                current->mm->locked_vm += npage;
@@ -173,33 +221,6 @@ static int put_pfn(unsigned long pfn, int prot)
        return 0;
 }
 
-/* Unmap DMA region */
-static long __vfio_dma_do_unmap(struct vfio_iommu *iommu, dma_addr_t iova,
-                            long npage, int prot)
-{
-       long i, unlocked = 0;
-
-       for (i = 0; i < npage; i++, iova += PAGE_SIZE) {
-               unsigned long pfn;
-
-               pfn = iommu_iova_to_phys(iommu->domain, iova) >> PAGE_SHIFT;
-               if (pfn) {
-                       iommu_unmap(iommu->domain, iova, PAGE_SIZE);
-                       unlocked += put_pfn(pfn, prot);
-               }
-       }
-       return unlocked;
-}
-
-static void vfio_dma_unmap(struct vfio_iommu *iommu, dma_addr_t iova,
-                          long npage, int prot)
-{
-       long unlocked;
-
-       unlocked = __vfio_dma_do_unmap(iommu, iova, npage, prot);
-       vfio_lock_acct(-unlocked);
-}
-
 static int vaddr_get_pfn(unsigned long vaddr, int prot, unsigned long *pfn)
 {
        struct page *page[1];
@@ -226,198 +247,306 @@ static int vaddr_get_pfn(unsigned long vaddr, int prot, unsigned long *pfn)
        return ret;
 }
 
-/* Map DMA region */
-static int __vfio_dma_map(struct vfio_iommu *iommu, dma_addr_t iova,
-                         unsigned long vaddr, long npage, int prot)
+/*
+ * Attempt to pin pages.  We really don't want to track all the pfns and
+ * the iommu can only map chunks of consecutive pfns anyway, so get the
+ * first page and all consecutive pages with the same locking.
+ */
+static long vfio_pin_pages(unsigned long vaddr, long npage,
+                          int prot, unsigned long *pfn_base)
 {
-       dma_addr_t start = iova;
-       long i, locked = 0;
-       int ret;
+       unsigned long limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
+       bool lock_cap = capable(CAP_IPC_LOCK);
+       long ret, i;
 
-       /* Verify that pages are not already mapped */
-       for (i = 0; i < npage; i++, iova += PAGE_SIZE)
-               if (iommu_iova_to_phys(iommu->domain, iova))
-                       return -EBUSY;
+       if (!current->mm)
+               return -ENODEV;
 
-       iova = start;
+       ret = vaddr_get_pfn(vaddr, prot, pfn_base);
+       if (ret)
+               return ret;
 
-       if (iommu->cache)
-               prot |= IOMMU_CACHE;
+       if (is_invalid_reserved_pfn(*pfn_base))
+               return 1;
 
-       /*
-        * XXX We break mappings into pages and use get_user_pages_fast to
-        * pin the pages in memory.  It's been suggested that mlock might
-        * provide a more efficient mechanism, but nothing prevents the
-        * user from munlocking the pages, which could then allow the user
-        * access to random host memory.  We also have no guarantee from the
-        * IOMMU API that the iommu driver can unmap sub-pages of previous
-        * mappings.  This means we might lose an entire range if a single
-        * page within it is unmapped.  Single page mappings are inefficient,
-        * but provide the most flexibility for now.
-        */
-       for (i = 0; i < npage; i++, iova += PAGE_SIZE, vaddr += PAGE_SIZE) {
+       if (!lock_cap && current->mm->locked_vm + 1 > limit) {
+               put_pfn(*pfn_base, prot);
+               pr_warn("%s: RLIMIT_MEMLOCK (%ld) exceeded\n", __func__,
+                       limit << PAGE_SHIFT);
+               return -ENOMEM;
+       }
+
+       if (unlikely(disable_hugepages)) {
+               vfio_lock_acct(1);
+               return 1;
+       }
+
+       /* Lock all the consecutive pages from pfn_base */
+       for (i = 1, vaddr += PAGE_SIZE; i < npage; i++, vaddr += PAGE_SIZE) {
                unsigned long pfn = 0;
 
                ret = vaddr_get_pfn(vaddr, prot, &pfn);
-               if (ret) {
-                       __vfio_dma_do_unmap(iommu, start, i, prot);
-                       return ret;
-               }
+               if (ret)
+                       break;
 
-               /*
-                * Only add actual locked pages to accounting
-                * XXX We're effectively marking a page locked for every
-                * IOVA page even though it's possible the user could be
-                * backing multiple IOVAs with the same vaddr.  This over-
-                * penalizes the user process, but we currently have no
-                * easy way to do this properly.
-                */
-               if (!is_invalid_reserved_pfn(pfn))
-                       locked++;
+               if (pfn != *pfn_base + i || is_invalid_reserved_pfn(pfn)) {
+                       put_pfn(pfn, prot);
+                       break;
+               }
 
-               ret = iommu_map(iommu->domain, iova,
-                               (phys_addr_t)pfn << PAGE_SHIFT,
-                               PAGE_SIZE, prot);
-               if (ret) {
-                       /* Back out mappings on error */
+               if (!lock_cap && current->mm->locked_vm + i + 1 > limit) {
                        put_pfn(pfn, prot);
-                       __vfio_dma_do_unmap(iommu, start, i, prot);
-                       return ret;
+                       pr_warn("%s: RLIMIT_MEMLOCK (%ld) exceeded\n",
+                               __func__, limit << PAGE_SHIFT);
+                       break;
                }
        }
-       vfio_lock_acct(locked);
-       return 0;
+
+       vfio_lock_acct(i);
+
+       return i;
 }
 
-static inline bool ranges_overlap(dma_addr_t start1, size_t size1,
-                                 dma_addr_t start2, size_t size2)
+static long vfio_unpin_pages(unsigned long pfn, long npage,
+                            int prot, bool do_accounting)
 {
-       if (start1 < start2)
-               return (start2 - start1 < size1);
-       else if (start2 < start1)
-               return (start1 - start2 < size2);
-       return (size1 > 0 && size2 > 0);
+       unsigned long unlocked = 0;
+       long i;
+
+       for (i = 0; i < npage; i++)
+               unlocked += put_pfn(pfn++, prot);
+
+       if (do_accounting)
+               vfio_lock_acct(-unlocked);
+
+       return unlocked;
 }
 
-static struct vfio_dma *vfio_find_dma(struct vfio_iommu *iommu,
-                                               dma_addr_t start, size_t size)
+static int vfio_unmap_unpin(struct vfio_iommu *iommu, struct vfio_dma *dma,
+                           dma_addr_t iova, size_t *size)
 {
-       struct vfio_dma *dma;
+       dma_addr_t start = iova, end = iova + *size;
+       long unlocked = 0;
 
-       list_for_each_entry(dma, &iommu->dma_list, next) {
-               if (ranges_overlap(dma->iova, NPAGE_TO_SIZE(dma->npage),
-                                  start, size))
-                       return dma;
+       while (iova < end) {
+               size_t unmapped;
+               phys_addr_t phys;
+
+               /*
+                * We use the IOMMU to track the physical address.  This
+                * saves us from having a lot more entries in our mapping
+                * tree.  The downside is that we don't track the size
+                * used to do the mapping.  We request unmap of a single
+                * page, but expect IOMMUs that support large pages to
+                * unmap a larger chunk.
+                */
+               phys = iommu_iova_to_phys(iommu->domain, iova);
+               if (WARN_ON(!phys)) {
+                       iova += PAGE_SIZE;
+                       continue;
+               }
+
+               unmapped = iommu_unmap(iommu->domain, iova, PAGE_SIZE);
+               if (!unmapped)
+                       break;
+
+               unlocked += vfio_unpin_pages(phys >> PAGE_SHIFT,
+                                            unmapped >> PAGE_SHIFT,
+                                            dma->prot, false);
+               iova += unmapped;
        }
-       return NULL;
+
+       vfio_lock_acct(-unlocked);
+
+       *size = iova - start;
+
+       return 0;
 }
 
-static long vfio_remove_dma_overlap(struct vfio_iommu *iommu, dma_addr_t start,
-                                   size_t size, struct vfio_dma *dma)
+static int vfio_remove_dma_overlap(struct vfio_iommu *iommu, dma_addr_t start,
+                                  size_t *size, struct vfio_dma *dma)
 {
+       size_t offset, overlap, tmp;
        struct vfio_dma *split;
-       long npage_lo, npage_hi;
-
-       /* Existing dma region is completely covered, unmap all */
-       if (start <= dma->iova &&
-           start + size >= dma->iova + NPAGE_TO_SIZE(dma->npage)) {
-               vfio_dma_unmap(iommu, dma->iova, dma->npage, dma->prot);
-               list_del(&dma->next);
-               npage_lo = dma->npage;
+       int ret;
+
+       if (!*size)
+               return 0;
+
+       /*
+        * Existing dma region is completely covered, unmap all.  This is
+        * the likely case since userspace tends to map and unmap buffers
+        * in one shot rather than multiple mappings within a buffer.
+        */
+       if (likely(start <= dma->iova &&
+                  start + *size >= dma->iova + dma->size)) {
+               *size = dma->size;
+               ret = vfio_unmap_unpin(iommu, dma, dma->iova, size);
+               if (ret)
+                       return ret;
+
+               /*
+                * Did we remove more than we have?  Should never happen
+                * since a vfio_dma is contiguous in iova and vaddr.
+                */
+               WARN_ON(*size != dma->size);
+
+               vfio_remove_dma(iommu, dma);
                kfree(dma);
-               return npage_lo;
+               return 0;
        }
 
        /* Overlap low address of existing range */
        if (start <= dma->iova) {
-               size_t overlap;
+               overlap = start + *size - dma->iova;
+               ret = vfio_unmap_unpin(iommu, dma, dma->iova, &overlap);
+               if (ret)
+                       return ret;
 
-               overlap = start + size - dma->iova;
-               npage_lo = overlap >> PAGE_SHIFT;
+               vfio_remove_dma(iommu, dma);
 
-               vfio_dma_unmap(iommu, dma->iova, npage_lo, dma->prot);
-               dma->iova += overlap;
-               dma->vaddr += overlap;
-               dma->npage -= npage_lo;
-               return npage_lo;
+               /*
+                * Check, we may have removed to whole vfio_dma.  If not
+                * fixup and re-insert.
+                */
+               if (overlap < dma->size) {
+                       dma->iova += overlap;
+                       dma->vaddr += overlap;
+                       dma->size -= overlap;
+                       vfio_insert_dma(iommu, dma);
+               } else
+                       kfree(dma);
+
+               *size = overlap;
+               return 0;
        }
 
        /* Overlap high address of existing range */
-       if (start + size >= dma->iova + NPAGE_TO_SIZE(dma->npage)) {
-               size_t overlap;
+       if (start + *size >= dma->iova + dma->size) {
+               offset = start - dma->iova;
+               overlap = dma->size - offset;
 
-               overlap = dma->iova + NPAGE_TO_SIZE(dma->npage) - start;
-               npage_hi = overlap >> PAGE_SHIFT;
+               ret = vfio_unmap_unpin(iommu, dma, start, &overlap);
+               if (ret)
+                       return ret;
 
-               vfio_dma_unmap(iommu, start, npage_hi, dma->prot);
-               dma->npage -= npage_hi;
-               return npage_hi;
+               dma->size -= overlap;
+               *size = overlap;
+               return 0;
        }
 
        /* Split existing */
-       npage_lo = (start - dma->iova) >> PAGE_SHIFT;
-       npage_hi = dma->npage - (size >> PAGE_SHIFT) - npage_lo;
 
-       split = kzalloc(sizeof *split, GFP_KERNEL);
+       /*
+        * Allocate our tracking structure early even though it may not
+        * be used.  An Allocation failure later loses track of pages and
+        * is more difficult to unwind.
+        */
+       split = kzalloc(sizeof(*split), GFP_KERNEL);
        if (!split)
                return -ENOMEM;
 
-       vfio_dma_unmap(iommu, start, size >> PAGE_SHIFT, dma->prot);
+       offset = start - dma->iova;
+
+       ret = vfio_unmap_unpin(iommu, dma, start, size);
+       if (ret || !*size) {
+               kfree(split);
+               return ret;
+       }
+
+       tmp = dma->size;
 
-       dma->npage = npage_lo;
+       /* Resize the lower vfio_dma in place, before the below insert */
+       dma->size = offset;
 
-       split->npage = npage_hi;
-       split->iova = start + size;
-       split->vaddr = dma->vaddr + NPAGE_TO_SIZE(npage_lo) + size;
-       split->prot = dma->prot;
-       list_add(&split->next, &iommu->dma_list);
-       return size >> PAGE_SHIFT;
+       /* Insert new for remainder, assuming it didn't all get unmapped */
+       if (likely(offset + *size < tmp)) {
+               split->size = tmp - offset - *size;
+               split->iova = dma->iova + offset + *size;
+               split->vaddr = dma->vaddr + offset + *size;
+               split->prot = dma->prot;
+               vfio_insert_dma(iommu, split);
+       } else
+               kfree(split);
+
+       return 0;
 }
 
 static int vfio_dma_do_unmap(struct vfio_iommu *iommu,
                             struct vfio_iommu_type1_dma_unmap *unmap)
 {
-       long ret = 0, npage = unmap->size >> PAGE_SHIFT;
-       struct vfio_dma *dma, *tmp;
        uint64_t mask;
+       struct vfio_dma *dma;
+       size_t unmapped = 0, size;
+       int ret = 0;
 
        mask = ((uint64_t)1 << __ffs(iommu->domain->ops->pgsize_bitmap)) - 1;
 
        if (unmap->iova & mask)
                return -EINVAL;
-       if (unmap->size & mask)
+       if (!unmap->size || unmap->size & mask)
                return -EINVAL;
 
-       /* XXX We still break these down into PAGE_SIZE */
        WARN_ON(mask & PAGE_MASK);
 
        mutex_lock(&iommu->lock);
 
-       list_for_each_entry_safe(dma, tmp, &iommu->dma_list, next) {
-               if (ranges_overlap(dma->iova, NPAGE_TO_SIZE(dma->npage),
-                                  unmap->iova, unmap->size)) {
-                       ret = vfio_remove_dma_overlap(iommu, unmap->iova,
-                                                     unmap->size, dma);
-                       if (ret > 0)
-                               npage -= ret;
-                       if (ret < 0 || npage == 0)
-                               break;
-               }
+       while ((dma = vfio_find_dma(iommu, unmap->iova, unmap->size))) {
+               size = unmap->size;
+               ret = vfio_remove_dma_overlap(iommu, unmap->iova, &size, dma);
+               if (ret || !size)
+                       break;
+               unmapped += size;
        }
+
        mutex_unlock(&iommu->lock);
-       return ret > 0 ? 0 : (int)ret;
+
+       /*
+        * We may unmap more than requested, update the unmap struct so
+        * userspace can know.
+        */
+       unmap->size = unmapped;
+
+       return ret;
+}
+
+/*
+ * Turns out AMD IOMMU has a page table bug where it won't map large pages
+ * to a region that previously mapped smaller pages.  This should be fixed
+ * soon, so this is just a temporary workaround to break mappings down into
+ * PAGE_SIZE.  Better to map smaller pages than nothing.
+ */
+static int map_try_harder(struct vfio_iommu *iommu, dma_addr_t iova,
+                         unsigned long pfn, long npage, int prot)
+{
+       long i;
+       int ret;
+
+       for (i = 0; i < npage; i++, pfn++, iova += PAGE_SIZE) {
+               ret = iommu_map(iommu->domain, iova,
+                               (phys_addr_t)pfn << PAGE_SHIFT,
+                               PAGE_SIZE, prot);
+               if (ret)
+                       break;
+       }
+
+       for (; i < npage && i > 0; i--, iova -= PAGE_SIZE)
+               iommu_unmap(iommu->domain, iova, PAGE_SIZE);
+
+       return ret;
 }
 
 static int vfio_dma_do_map(struct vfio_iommu *iommu,
                           struct vfio_iommu_type1_dma_map *map)
 {
-       struct vfio_dma *dma, *pdma = NULL;
-       dma_addr_t iova = map->iova;
-       unsigned long locked, lock_limit, vaddr = map->vaddr;
+       dma_addr_t end, iova;
+       unsigned long vaddr = map->vaddr;
        size_t size = map->size;
+       long npage;
        int ret = 0, prot = 0;
        uint64_t mask;
-       long npage;
+
+       end = map->iova + map->size;
 
        mask = ((uint64_t)1 << __ffs(iommu->domain->ops->pgsize_bitmap)) - 1;
 
@@ -430,104 +559,144 @@ static int vfio_dma_do_map(struct vfio_iommu *iommu,
        if (!prot)
                return -EINVAL; /* No READ/WRITE? */
 
+       if (iommu->cache)
+               prot |= IOMMU_CACHE;
+
        if (vaddr & mask)
                return -EINVAL;
-       if (iova & mask)
+       if (map->iova & mask)
                return -EINVAL;
-       if (size & mask)
+       if (!map->size || map->size & mask)
                return -EINVAL;
 
-       /* XXX We still break these down into PAGE_SIZE */
        WARN_ON(mask & PAGE_MASK);
 
        /* Don't allow IOVA wrap */
-       if (iova + size && iova + size < iova)
+       if (end && end < map->iova)
                return -EINVAL;
 
        /* Don't allow virtual address wrap */
-       if (vaddr + size && vaddr + size < vaddr)
-               return -EINVAL;
-
-       npage = size >> PAGE_SHIFT;
-       if (!npage)
+       if (vaddr + map->size && vaddr + map->size < vaddr)
                return -EINVAL;
 
        mutex_lock(&iommu->lock);
 
-       if (vfio_find_dma(iommu, iova, size)) {
-               ret = -EBUSY;
-               goto out_lock;
+       if (vfio_find_dma(iommu, map->iova, map->size)) {
+               mutex_unlock(&iommu->lock);
+               return -EEXIST;
        }
 
-       /* account for locked pages */
-       locked = current->mm->locked_vm + npage;
-       lock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
-       if (locked > lock_limit && !capable(CAP_IPC_LOCK)) {
-               pr_warn("%s: RLIMIT_MEMLOCK (%ld) exceeded\n",
-                       __func__, rlimit(RLIMIT_MEMLOCK));
-               ret = -ENOMEM;
-               goto out_lock;
-       }
+       for (iova = map->iova; iova < end; iova += size, vaddr += size) {
+               struct vfio_dma *dma = NULL;
+               unsigned long pfn;
+               long i;
+
+               /* Pin a contiguous chunk of memory */
+               npage = vfio_pin_pages(vaddr, (end - iova) >> PAGE_SHIFT,
+                                      prot, &pfn);
+               if (npage <= 0) {
+                       WARN_ON(!npage);
+                       ret = (int)npage;
+                       break;
+               }
 
-       ret = __vfio_dma_map(iommu, iova, vaddr, npage, prot);
-       if (ret)
-               goto out_lock;
+               /* Verify pages are not already mapped */
+               for (i = 0; i < npage; i++) {
+                       if (iommu_iova_to_phys(iommu->domain,
+                                              iova + (i << PAGE_SHIFT))) {
+                               vfio_unpin_pages(pfn, npage, prot, true);
+                               ret = -EBUSY;
+                               break;
+                       }
+               }
 
-       /* Check if we abut a region below - nothing below 0 */
-       if (iova) {
-               dma = vfio_find_dma(iommu, iova - 1, 1);
-               if (dma && dma->prot == prot &&
-                   dma->vaddr + NPAGE_TO_SIZE(dma->npage) == vaddr) {
+               ret = iommu_map(iommu->domain, iova,
+                               (phys_addr_t)pfn << PAGE_SHIFT,
+                               npage << PAGE_SHIFT, prot);
+               if (ret) {
+                       if (ret != -EBUSY ||
+                           map_try_harder(iommu, iova, pfn, npage, prot)) {
+                               vfio_unpin_pages(pfn, npage, prot, true);
+                               break;
+                       }
+               }
 
-                       dma->npage += npage;
-                       iova = dma->iova;
-                       vaddr = dma->vaddr;
-                       npage = dma->npage;
-                       size = NPAGE_TO_SIZE(npage);
+               size = npage << PAGE_SHIFT;
 
-                       pdma = dma;
+               /*
+                * Check if we abut a region below - nothing below 0.
+                * This is the most likely case when mapping chunks of
+                * physically contiguous regions within a virtual address
+                * range.  Update the abutting entry in place since iova
+                * doesn't change.
+                */
+               if (likely(iova)) {
+                       struct vfio_dma *tmp;
+                       tmp = vfio_find_dma(iommu, iova - 1, 1);
+                       if (tmp && tmp->prot == prot &&
+                           tmp->vaddr + tmp->size == vaddr) {
+                               tmp->size += size;
+                               iova = tmp->iova;
+                               size = tmp->size;
+                               vaddr = tmp->vaddr;
+                               dma = tmp;
+                       }
+               }
+
+               /*
+                * Check if we abut a region above - nothing above ~0 + 1.
+                * If we abut above and below, remove and free.  If only
+                * abut above, remove, modify, reinsert.
+                */
+               if (likely(iova + size)) {
+                       struct vfio_dma *tmp;
+                       tmp = vfio_find_dma(iommu, iova + size, 1);
+                       if (tmp && tmp->prot == prot &&
+                           tmp->vaddr == vaddr + size) {
+                               vfio_remove_dma(iommu, tmp);
+                               if (dma) {
+                                       dma->size += tmp->size;
+                                       kfree(tmp);
+                               } else {
+                                       size += tmp->size;
+                                       tmp->size = size;
+                                       tmp->iova = iova;
+                                       tmp->vaddr = vaddr;
+                                       vfio_insert_dma(iommu, tmp);
+                                       dma = tmp;
+                               }
+                       }
                }
-       }
 
-       /* Check if we abut a region above - nothing above ~0 + 1 */
-       if (iova + size) {
-               dma = vfio_find_dma(iommu, iova + size, 1);
-               if (dma && dma->prot == prot &&
-                   dma->vaddr == vaddr + size) {
+               if (!dma) {
+                       dma = kzalloc(sizeof(*dma), GFP_KERNEL);
+                       if (!dma) {
+                               iommu_unmap(iommu->domain, iova, size);
+                               vfio_unpin_pages(pfn, npage, prot, true);
+                               ret = -ENOMEM;
+                               break;
+                       }
 
-                       dma->npage += npage;
+                       dma->size = size;
                        dma->iova = iova;
                        dma->vaddr = vaddr;
-
-                       /*
-                        * If merged above and below, remove previously
-                        * merged entry.  New entry covers it.
-                        */
-                       if (pdma) {
-                               list_del(&pdma->next);
-                               kfree(pdma);
-                       }
-                       pdma = dma;
+                       dma->prot = prot;
+                       vfio_insert_dma(iommu, dma);
                }
        }
 
-       /* Isolated, new region */
-       if (!pdma) {
-               dma = kzalloc(sizeof *dma, GFP_KERNEL);
-               if (!dma) {
-                       ret = -ENOMEM;
-                       vfio_dma_unmap(iommu, iova, npage, prot);
-                       goto out_lock;
+       if (ret) {
+               struct vfio_dma *tmp;
+               iova = map->iova;
+               size = map->size;
+               while ((tmp = vfio_find_dma(iommu, iova, size))) {
+                       int r = vfio_remove_dma_overlap(iommu, iova,
+                                                       &size, tmp);
+                       if (WARN_ON(r || !size))
+                               break;
                }
-
-               dma->npage = npage;
-               dma->iova = iova;
-               dma->vaddr = vaddr;
-               dma->prot = prot;
-               list_add(&dma->next, &iommu->dma_list);
        }
 
-out_lock:
        mutex_unlock(&iommu->lock);
        return ret;
 }
@@ -606,7 +775,7 @@ static void *vfio_iommu_type1_open(unsigned long arg)
                return ERR_PTR(-ENOMEM);
 
        INIT_LIST_HEAD(&iommu->group_list);
-       INIT_LIST_HEAD(&iommu->dma_list);
+       iommu->dma_list = RB_ROOT;
        mutex_init(&iommu->lock);
 
        /*
@@ -640,7 +809,7 @@ static void vfio_iommu_type1_release(void *iommu_data)
 {
        struct vfio_iommu *iommu = iommu_data;
        struct vfio_group *group, *group_tmp;
-       struct vfio_dma *dma, *dma_tmp;
+       struct rb_node *node;
 
        list_for_each_entry_safe(group, group_tmp, &iommu->group_list, next) {
                iommu_detach_group(iommu->domain, group->iommu_group);
@@ -648,10 +817,12 @@ static void vfio_iommu_type1_release(void *iommu_data)
                kfree(group);
        }
 
-       list_for_each_entry_safe(dma, dma_tmp, &iommu->dma_list, next) {
-               vfio_dma_unmap(iommu, dma->iova, dma->npage, dma->prot);
-               list_del(&dma->next);
-               kfree(dma);
+       while ((node = rb_first(&iommu->dma_list))) {
+               struct vfio_dma *dma = rb_entry(node, struct vfio_dma, node);
+               size_t size = dma->size;
+               vfio_remove_dma_overlap(iommu, dma->iova, &size, dma);
+               if (WARN_ON(!size))
+                       break;
        }
 
        iommu_domain_free(iommu->domain);
@@ -706,6 +877,7 @@ static long vfio_iommu_type1_ioctl(void *iommu_data,
 
        } else if (cmd == VFIO_IOMMU_UNMAP_DMA) {
                struct vfio_iommu_type1_dma_unmap unmap;
+               long ret;
 
                minsz = offsetofend(struct vfio_iommu_type1_dma_unmap, size);
 
@@ -715,7 +887,11 @@ static long vfio_iommu_type1_ioctl(void *iommu_data,
                if (unmap.argsz < minsz || unmap.flags)
                        return -EINVAL;
 
-               return vfio_dma_do_unmap(iommu, &unmap);
+               ret = vfio_dma_do_unmap(iommu, &unmap);
+               if (ret)
+                       return ret;
+
+               return copy_to_user((void __user *)arg, &unmap, minsz);
        }
 
        return -ENOTTY;
index 8b9226d..017a1e8 100644 (file)
@@ -1,6 +1,7 @@
 config VHOST_NET
        tristate "Host kernel accelerator for virtio net"
        depends on NET && EVENTFD && (TUN || !TUN) && (MACVTAP || !MACVTAP)
+       select VHOST
        select VHOST_RING
        ---help---
          This kernel module can be loaded in host kernel to accelerate
@@ -13,6 +14,7 @@ config VHOST_NET
 config VHOST_SCSI
        tristate "VHOST_SCSI TCM fabric driver"
        depends on TARGET_CORE && EVENTFD && m
+       select VHOST
        select VHOST_RING
        default n
        ---help---
@@ -24,3 +26,9 @@ config VHOST_RING
        ---help---
          This option is selected by any driver which needs to access
          the host side of a virtio ring.
+
+config VHOST
+       tristate
+       ---help---
+         This option is selected by any driver which needs to access
+         the core of vhost.
index 654e9af..e0441c3 100644 (file)
@@ -1,7 +1,8 @@
 obj-$(CONFIG_VHOST_NET) += vhost_net.o
-vhost_net-y := vhost.o net.o
+vhost_net-y := net.o
 
 obj-$(CONFIG_VHOST_SCSI) += vhost_scsi.o
 vhost_scsi-y := scsi.o
 
 obj-$(CONFIG_VHOST_RING) += vringh.o
+obj-$(CONFIG_VHOST)    += vhost.o
index 8ca5ac7..027be91 100644 (file)
@@ -168,7 +168,7 @@ static void vhost_net_clear_ubuf_info(struct vhost_net *n)
        }
 }
 
-int vhost_net_set_ubuf_info(struct vhost_net *n)
+static int vhost_net_set_ubuf_info(struct vhost_net *n)
 {
        bool zcopy;
        int i;
@@ -189,7 +189,7 @@ err:
        return -ENOMEM;
 }
 
-void vhost_net_vq_reset(struct vhost_net *n)
+static void vhost_net_vq_reset(struct vhost_net *n)
 {
        int i;
 
index 7014202..06adf31 100644 (file)
@@ -49,7 +49,6 @@
 #include <linux/llist.h>
 #include <linux/bitmap.h>
 
-#include "vhost.c"
 #include "vhost.h"
 
 #define TCM_VHOST_VERSION  "v0.1"
@@ -116,7 +115,6 @@ struct tcm_vhost_nacl {
        struct se_node_acl se_node_acl;
 };
 
-struct vhost_scsi;
 struct tcm_vhost_tpg {
        /* Vhost port target portal group tag for TCM */
        u16 tport_tpgt;
@@ -218,7 +216,7 @@ static int iov_num_pages(struct iovec *iov)
               ((unsigned long)iov->iov_base & PAGE_MASK)) >> PAGE_SHIFT;
 }
 
-void tcm_vhost_done_inflight(struct kref *kref)
+static void tcm_vhost_done_inflight(struct kref *kref)
 {
        struct vhost_scsi_inflight *inflight;
 
@@ -329,11 +327,12 @@ static u32 tcm_vhost_get_default_depth(struct se_portal_group *se_tpg)
        return 1;
 }
 
-static u32 tcm_vhost_get_pr_transport_id(struct se_portal_group *se_tpg,
-       struct se_node_acl *se_nacl,
-       struct t10_pr_registration *pr_reg,
-       int *format_code,
-       unsigned char *buf)
+static u32
+tcm_vhost_get_pr_transport_id(struct se_portal_group *se_tpg,
+                             struct se_node_acl *se_nacl,
+                             struct t10_pr_registration *pr_reg,
+                             int *format_code,
+                             unsigned char *buf)
 {
        struct tcm_vhost_tpg *tpg = container_of(se_tpg,
                                struct tcm_vhost_tpg, se_tpg);
@@ -359,10 +358,11 @@ static u32 tcm_vhost_get_pr_transport_id(struct se_portal_group *se_tpg,
                        format_code, buf);
 }
 
-static u32 tcm_vhost_get_pr_transport_id_len(struct se_portal_group *se_tpg,
-       struct se_node_acl *se_nacl,
-       struct t10_pr_registration *pr_reg,
-       int *format_code)
+static u32
+tcm_vhost_get_pr_transport_id_len(struct se_portal_group *se_tpg,
+                                 struct se_node_acl *se_nacl,
+                                 struct t10_pr_registration *pr_reg,
+                                 int *format_code)
 {
        struct tcm_vhost_tpg *tpg = container_of(se_tpg,
                                struct tcm_vhost_tpg, se_tpg);
@@ -388,10 +388,11 @@ static u32 tcm_vhost_get_pr_transport_id_len(struct se_portal_group *se_tpg,
                        format_code);
 }
 
-static char *tcm_vhost_parse_pr_out_transport_id(struct se_portal_group *se_tpg,
-       const char *buf,
-       u32 *out_tid_len,
-       char **port_nexus_ptr)
+static char *
+tcm_vhost_parse_pr_out_transport_id(struct se_portal_group *se_tpg,
+                                   const char *buf,
+                                   u32 *out_tid_len,
+                                   char **port_nexus_ptr)
 {
        struct tcm_vhost_tpg *tpg = container_of(se_tpg,
                                struct tcm_vhost_tpg, se_tpg);
@@ -417,8 +418,8 @@ static char *tcm_vhost_parse_pr_out_transport_id(struct se_portal_group *se_tpg,
                        port_nexus_ptr);
 }
 
-static struct se_node_acl *tcm_vhost_alloc_fabric_acl(
-       struct se_portal_group *se_tpg)
+static struct se_node_acl *
+tcm_vhost_alloc_fabric_acl(struct se_portal_group *se_tpg)
 {
        struct tcm_vhost_nacl *nacl;
 
@@ -431,8 +432,9 @@ static struct se_node_acl *tcm_vhost_alloc_fabric_acl(
        return &nacl->se_node_acl;
 }
 
-static void tcm_vhost_release_fabric_acl(struct se_portal_group *se_tpg,
-       struct se_node_acl *se_nacl)
+static void
+tcm_vhost_release_fabric_acl(struct se_portal_group *se_tpg,
+                            struct se_node_acl *se_nacl)
 {
        struct tcm_vhost_nacl *nacl = container_of(se_nacl,
                        struct tcm_vhost_nacl, se_node_acl);
@@ -446,7 +448,19 @@ static u32 tcm_vhost_tpg_get_inst_index(struct se_portal_group *se_tpg)
 
 static void tcm_vhost_release_cmd(struct se_cmd *se_cmd)
 {
-       return;
+       struct tcm_vhost_cmd *tv_cmd = container_of(se_cmd,
+                               struct tcm_vhost_cmd, tvc_se_cmd);
+
+       if (tv_cmd->tvc_sgl_count) {
+               u32 i;
+               for (i = 0; i < tv_cmd->tvc_sgl_count; i++)
+                       put_page(sg_page(&tv_cmd->tvc_sgl[i]));
+
+               kfree(tv_cmd->tvc_sgl);
+        }
+
+       tcm_vhost_put_inflight(tv_cmd->inflight);
+       kfree(tv_cmd);
 }
 
 static int tcm_vhost_shutdown_session(struct se_session *se_sess)
@@ -491,34 +505,34 @@ static int tcm_vhost_get_cmd_state(struct se_cmd *se_cmd)
        return 0;
 }
 
-static void vhost_scsi_complete_cmd(struct tcm_vhost_cmd *tv_cmd)
+static void vhost_scsi_complete_cmd(struct tcm_vhost_cmd *cmd)
 {
-       struct vhost_scsi *vs = tv_cmd->tvc_vhost;
+       struct vhost_scsi *vs = cmd->tvc_vhost;
 
-       llist_add(&tv_cmd->tvc_completion_list, &vs->vs_completion_list);
+       llist_add(&cmd->tvc_completion_list, &vs->vs_completion_list);
 
        vhost_work_queue(&vs->dev, &vs->vs_completion_work);
 }
 
 static int tcm_vhost_queue_data_in(struct se_cmd *se_cmd)
 {
-       struct tcm_vhost_cmd *tv_cmd = container_of(se_cmd,
+       struct tcm_vhost_cmd *cmd = container_of(se_cmd,
                                struct tcm_vhost_cmd, tvc_se_cmd);
-       vhost_scsi_complete_cmd(tv_cmd);
+       vhost_scsi_complete_cmd(cmd);
        return 0;
 }
 
 static int tcm_vhost_queue_status(struct se_cmd *se_cmd)
 {
-       struct tcm_vhost_cmd *tv_cmd = container_of(se_cmd,
+       struct tcm_vhost_cmd *cmd = container_of(se_cmd,
                                struct tcm_vhost_cmd, tvc_se_cmd);
-       vhost_scsi_complete_cmd(tv_cmd);
+       vhost_scsi_complete_cmd(cmd);
        return 0;
 }
 
-static int tcm_vhost_queue_tm_rsp(struct se_cmd *se_cmd)
+static void tcm_vhost_queue_tm_rsp(struct se_cmd *se_cmd)
 {
-       return 0;
+       return;
 }
 
 static void tcm_vhost_free_evt(struct vhost_scsi *vs, struct tcm_vhost_evt *evt)
@@ -527,8 +541,9 @@ static void tcm_vhost_free_evt(struct vhost_scsi *vs, struct tcm_vhost_evt *evt)
        kfree(evt);
 }
 
-static struct tcm_vhost_evt *tcm_vhost_allocate_evt(struct vhost_scsi *vs,
-       u32 event, u32 reason)
+static struct tcm_vhost_evt *
+tcm_vhost_allocate_evt(struct vhost_scsi *vs,
+                      u32 event, u32 reason)
 {
        struct vhost_virtqueue *vq = &vs->vqs[VHOST_SCSI_VQ_EVT].vq;
        struct tcm_vhost_evt *evt;
@@ -552,28 +567,22 @@ static struct tcm_vhost_evt *tcm_vhost_allocate_evt(struct vhost_scsi *vs,
        return evt;
 }
 
-static void vhost_scsi_free_cmd(struct tcm_vhost_cmd *tv_cmd)
+static void vhost_scsi_free_cmd(struct tcm_vhost_cmd *cmd)
 {
-       struct se_cmd *se_cmd = &tv_cmd->tvc_se_cmd;
+       struct se_cmd *se_cmd = &cmd->tvc_se_cmd;
 
        /* TODO locking against target/backend threads? */
-       transport_generic_free_cmd(se_cmd, 1);
-
-       if (tv_cmd->tvc_sgl_count) {
-               u32 i;
-               for (i = 0; i < tv_cmd->tvc_sgl_count; i++)
-                       put_page(sg_page(&tv_cmd->tvc_sgl[i]));
+       transport_generic_free_cmd(se_cmd, 0);
 
-               kfree(tv_cmd->tvc_sgl);
-       }
-
-       tcm_vhost_put_inflight(tv_cmd->inflight);
+}
 
-       kfree(tv_cmd);
+static int vhost_scsi_check_stop_free(struct se_cmd *se_cmd)
+{
+       return target_put_sess_cmd(se_cmd->se_sess, se_cmd);
 }
 
-static void tcm_vhost_do_evt_work(struct vhost_scsi *vs,
-       struct tcm_vhost_evt *evt)
+static void
+tcm_vhost_do_evt_work(struct vhost_scsi *vs, struct tcm_vhost_evt *evt)
 {
        struct vhost_virtqueue *vq = &vs->vqs[VHOST_SCSI_VQ_EVT].vq;
        struct virtio_scsi_event *event = &evt->event;
@@ -652,7 +661,7 @@ static void vhost_scsi_complete_cmd_work(struct vhost_work *work)
                                        vs_completion_work);
        DECLARE_BITMAP(signal, VHOST_SCSI_MAX_VQ);
        struct virtio_scsi_cmd_resp v_rsp;
-       struct tcm_vhost_cmd *tv_cmd;
+       struct tcm_vhost_cmd *cmd;
        struct llist_node *llnode;
        struct se_cmd *se_cmd;
        int ret, vq;
@@ -660,32 +669,32 @@ static void vhost_scsi_complete_cmd_work(struct vhost_work *work)
        bitmap_zero(signal, VHOST_SCSI_MAX_VQ);
        llnode = llist_del_all(&vs->vs_completion_list);
        while (llnode) {
-               tv_cmd = llist_entry(llnode, struct tcm_vhost_cmd,
+               cmd = llist_entry(llnode, struct tcm_vhost_cmd,
                                     tvc_completion_list);
                llnode = llist_next(llnode);
-               se_cmd = &tv_cmd->tvc_se_cmd;
+               se_cmd = &cmd->tvc_se_cmd;
 
                pr_debug("%s tv_cmd %p resid %u status %#02x\n", __func__,
-                       tv_cmd, se_cmd->residual_count, se_cmd->scsi_status);
+                       cmd, se_cmd->residual_count, se_cmd->scsi_status);
 
                memset(&v_rsp, 0, sizeof(v_rsp));
                v_rsp.resid = se_cmd->residual_count;
                /* TODO is status_qualifier field needed? */
                v_rsp.status = se_cmd->scsi_status;
                v_rsp.sense_len = se_cmd->scsi_sense_length;
-               memcpy(v_rsp.sense, tv_cmd->tvc_sense_buf,
+               memcpy(v_rsp.sense, cmd->tvc_sense_buf,
                       v_rsp.sense_len);
-               ret = copy_to_user(tv_cmd->tvc_resp, &v_rsp, sizeof(v_rsp));
+               ret = copy_to_user(cmd->tvc_resp, &v_rsp, sizeof(v_rsp));
                if (likely(ret == 0)) {
                        struct vhost_scsi_virtqueue *q;
-                       vhost_add_used(tv_cmd->tvc_vq, tv_cmd->tvc_vq_desc, 0);
-                       q = container_of(tv_cmd->tvc_vq, struct vhost_scsi_virtqueue, vq);
+                       vhost_add_used(cmd->tvc_vq, cmd->tvc_vq_desc, 0);
+                       q = container_of(cmd->tvc_vq, struct vhost_scsi_virtqueue, vq);
                        vq = q - vs->vqs;
                        __set_bit(vq, signal);
                } else
                        pr_err("Faulted on virtio_scsi_cmd_resp\n");
 
-               vhost_scsi_free_cmd(tv_cmd);
+               vhost_scsi_free_cmd(cmd);
        }
 
        vq = -1;
@@ -694,35 +703,35 @@ static void vhost_scsi_complete_cmd_work(struct vhost_work *work)
                vhost_signal(&vs->dev, &vs->vqs[vq].vq);
 }
 
-static struct tcm_vhost_cmd *vhost_scsi_allocate_cmd(
-       struct vhost_virtqueue *vq,
-       struct tcm_vhost_tpg *tv_tpg,
-       struct virtio_scsi_cmd_req *v_req,
-       u32 exp_data_len,
-       int data_direction)
+static struct tcm_vhost_cmd *
+vhost_scsi_allocate_cmd(struct vhost_virtqueue *vq,
+                       struct tcm_vhost_tpg *tpg,
+                       struct virtio_scsi_cmd_req *v_req,
+                       u32 exp_data_len,
+                       int data_direction)
 {
-       struct tcm_vhost_cmd *tv_cmd;
+       struct tcm_vhost_cmd *cmd;
        struct tcm_vhost_nexus *tv_nexus;
 
-       tv_nexus = tv_tpg->tpg_nexus;
+       tv_nexus = tpg->tpg_nexus;
        if (!tv_nexus) {
                pr_err("Unable to locate active struct tcm_vhost_nexus\n");
                return ERR_PTR(-EIO);
        }
 
-       tv_cmd = kzalloc(sizeof(struct tcm_vhost_cmd), GFP_ATOMIC);
-       if (!tv_cmd) {
+       cmd = kzalloc(sizeof(struct tcm_vhost_cmd), GFP_ATOMIC);
+       if (!cmd) {
                pr_err("Unable to allocate struct tcm_vhost_cmd\n");
                return ERR_PTR(-ENOMEM);
        }
-       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;
-       tv_cmd->inflight = tcm_vhost_get_inflight(vq);
+       cmd->tvc_tag = v_req->tag;
+       cmd->tvc_task_attr = v_req->task_attr;
+       cmd->tvc_exp_data_len = exp_data_len;
+       cmd->tvc_data_direction = data_direction;
+       cmd->tvc_nexus = tv_nexus;
+       cmd->inflight = tcm_vhost_get_inflight(vq);
 
-       return tv_cmd;
+       return cmd;
 }
 
 /*
@@ -730,8 +739,11 @@ static struct tcm_vhost_cmd *vhost_scsi_allocate_cmd(
  *
  * Returns the number of scatterlist entries used or -errno on error.
  */
-static int vhost_scsi_map_to_sgl(struct scatterlist *sgl,
-       unsigned int sgl_count, struct iovec *iov, int write)
+static int
+vhost_scsi_map_to_sgl(struct scatterlist *sgl,
+                     unsigned int sgl_count,
+                     struct iovec *iov,
+                     int write)
 {
        unsigned int npages = 0, pages_nr, offset, nbytes;
        struct scatterlist *sg = sgl;
@@ -775,8 +787,11 @@ out:
        return ret;
 }
 
-static int vhost_scsi_map_iov_to_sgl(struct tcm_vhost_cmd *tv_cmd,
-       struct iovec *iov, unsigned int niov, int write)
+static int
+vhost_scsi_map_iov_to_sgl(struct tcm_vhost_cmd *cmd,
+                         struct iovec *iov,
+                         unsigned int niov,
+                         int write)
 {
        int ret;
        unsigned int i;
@@ -792,25 +807,25 @@ static int vhost_scsi_map_iov_to_sgl(struct tcm_vhost_cmd *tv_cmd,
 
        /* TODO overflow checking */
 
-       sg = kmalloc(sizeof(tv_cmd->tvc_sgl[0]) * sgl_count, GFP_ATOMIC);
+       sg = kmalloc(sizeof(cmd->tvc_sgl[0]) * sgl_count, GFP_ATOMIC);
        if (!sg)
                return -ENOMEM;
        pr_debug("%s sg %p sgl_count %u is_err %d\n", __func__,
               sg, sgl_count, !sg);
        sg_init_table(sg, sgl_count);
 
-       tv_cmd->tvc_sgl = sg;
-       tv_cmd->tvc_sgl_count = sgl_count;
+       cmd->tvc_sgl = sg;
+       cmd->tvc_sgl_count = sgl_count;
 
        pr_debug("Mapping %u iovecs for %u pages\n", niov, sgl_count);
        for (i = 0; i < niov; i++) {
                ret = vhost_scsi_map_to_sgl(sg, sgl_count, &iov[i], write);
                if (ret < 0) {
-                       for (i = 0; i < tv_cmd->tvc_sgl_count; i++)
-                               put_page(sg_page(&tv_cmd->tvc_sgl[i]));
-                       kfree(tv_cmd->tvc_sgl);
-                       tv_cmd->tvc_sgl = NULL;
-                       tv_cmd->tvc_sgl_count = 0;
+                       for (i = 0; i < cmd->tvc_sgl_count; i++)
+                               put_page(sg_page(&cmd->tvc_sgl[i]));
+                       kfree(cmd->tvc_sgl);
+                       cmd->tvc_sgl = NULL;
+                       cmd->tvc_sgl_count = 0;
                        return ret;
                }
 
@@ -822,15 +837,15 @@ static int vhost_scsi_map_iov_to_sgl(struct tcm_vhost_cmd *tv_cmd,
 
 static void tcm_vhost_submission_work(struct work_struct *work)
 {
-       struct tcm_vhost_cmd *tv_cmd =
+       struct tcm_vhost_cmd *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 se_cmd *se_cmd = &cmd->tvc_se_cmd;
        struct scatterlist *sg_ptr, *sg_bidi_ptr = NULL;
        int rc, sg_no_bidi = 0;
 
-       if (tv_cmd->tvc_sgl_count) {
-               sg_ptr = tv_cmd->tvc_sgl;
+       if (cmd->tvc_sgl_count) {
+               sg_ptr = cmd->tvc_sgl;
 /* FIXME: Fix BIDI operation in tcm_vhost_submission_work() */
 #if 0
                if (se_cmd->se_cmd_flags & SCF_BIDI) {
@@ -841,13 +856,13 @@ static void tcm_vhost_submission_work(struct work_struct *work)
        } else {
                sg_ptr = NULL;
        }
-       tv_nexus = tv_cmd->tvc_nexus;
+       tv_nexus = 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,
+                       cmd->tvc_cdb, &cmd->tvc_sense_buf[0],
+                       cmd->tvc_lun, cmd->tvc_exp_data_len,
+                       cmd->tvc_task_attr, cmd->tvc_data_direction,
+                       TARGET_SCF_ACK_KREF, sg_ptr, cmd->tvc_sgl_count,
                        sg_bidi_ptr, sg_no_bidi);
        if (rc < 0) {
                transport_send_check_condition_and_sense(se_cmd,
@@ -856,8 +871,10 @@ static void tcm_vhost_submission_work(struct work_struct *work)
        }
 }
 
-static void vhost_scsi_send_bad_target(struct vhost_scsi *vs,
-       struct vhost_virtqueue *vq, int head, unsigned out)
+static void
+vhost_scsi_send_bad_target(struct vhost_scsi *vs,
+                          struct vhost_virtqueue *vq,
+                          int head, unsigned out)
 {
        struct virtio_scsi_cmd_resp __user *resp;
        struct virtio_scsi_cmd_resp rsp;
@@ -873,13 +890,13 @@ static void vhost_scsi_send_bad_target(struct vhost_scsi *vs,
                pr_err("Faulted on virtio_scsi_cmd_resp\n");
 }
 
-static void vhost_scsi_handle_vq(struct vhost_scsi *vs,
-       struct vhost_virtqueue *vq)
+static void
+vhost_scsi_handle_vq(struct vhost_scsi *vs, struct vhost_virtqueue *vq)
 {
        struct tcm_vhost_tpg **vs_tpg;
        struct virtio_scsi_cmd_req v_req;
-       struct tcm_vhost_tpg *tv_tpg;
-       struct tcm_vhost_cmd *tv_cmd;
+       struct tcm_vhost_tpg *tpg;
+       struct tcm_vhost_cmd *cmd;
        u32 exp_data_len, data_first, data_num, data_direction;
        unsigned out, in, i;
        int head, ret;
@@ -964,10 +981,10 @@ static void vhost_scsi_handle_vq(struct vhost_scsi *vs,
 
                /* Extract the tpgt */
                target = v_req.lun[1];
-               tv_tpg = ACCESS_ONCE(vs_tpg[target]);
+               tpg = ACCESS_ONCE(vs_tpg[target]);
 
                /* Target does not exist, fail the request */
-               if (unlikely(!tv_tpg)) {
+               if (unlikely(!tpg)) {
                        vhost_scsi_send_bad_target(vs, vq, head, out);
                        continue;
                }
@@ -976,46 +993,46 @@ static void vhost_scsi_handle_vq(struct vhost_scsi *vs,
                for (i = 0; i < data_num; i++)
                        exp_data_len += vq->iov[data_first + i].iov_len;
 
-               tv_cmd = vhost_scsi_allocate_cmd(vq, tv_tpg, &v_req,
+               cmd = vhost_scsi_allocate_cmd(vq, tpg, &v_req,
                                        exp_data_len, data_direction);
-               if (IS_ERR(tv_cmd)) {
+               if (IS_ERR(cmd)) {
                        vq_err(vq, "vhost_scsi_allocate_cmd failed %ld\n",
-                                       PTR_ERR(tv_cmd));
+                                       PTR_ERR(cmd));
                        goto err_cmd;
                }
                pr_debug("Allocated tv_cmd: %p exp_data_len: %d, data_direction"
-                       ": %d\n", tv_cmd, exp_data_len, data_direction);
+                       ": %d\n", cmd, exp_data_len, data_direction);
 
-               tv_cmd->tvc_vhost = vs;
-               tv_cmd->tvc_vq = vq;
-               tv_cmd->tvc_resp = vq->iov[out].iov_base;
+               cmd->tvc_vhost = vs;
+               cmd->tvc_vq = vq;
+               cmd->tvc_resp = vq->iov[out].iov_base;
 
                /*
-                * Copy in the recieved CDB descriptor into tv_cmd->tvc_cdb
+                * Copy in the recieved CDB descriptor into cmd->tvc_cdb
                 * that will be used by tcm_vhost_new_cmd_map() and down into
                 * target_setup_cmd_from_cdb()
                 */
-               memcpy(tv_cmd->tvc_cdb, v_req.cdb, TCM_VHOST_MAX_CDB_SIZE);
+               memcpy(cmd->tvc_cdb, v_req.cdb, TCM_VHOST_MAX_CDB_SIZE);
                /*
                 * Check that the recieved CDB size does not exceeded our
                 * hardcoded max for tcm_vhost
                 */
                /* TODO what if cdb was too small for varlen cdb header? */
-               if (unlikely(scsi_command_size(tv_cmd->tvc_cdb) >
+               if (unlikely(scsi_command_size(cmd->tvc_cdb) >
                                        TCM_VHOST_MAX_CDB_SIZE)) {
                        vq_err(vq, "Received SCSI CDB with command_size: %d that"
                                " exceeds SCSI_MAX_VARLEN_CDB_SIZE: %d\n",
-                               scsi_command_size(tv_cmd->tvc_cdb),
+                               scsi_command_size(cmd->tvc_cdb),
                                TCM_VHOST_MAX_CDB_SIZE);
                        goto err_free;
                }
-               tv_cmd->tvc_lun = ((v_req.lun[2] << 8) | v_req.lun[3]) & 0x3FFF;
+               cmd->tvc_lun = ((v_req.lun[2] << 8) | v_req.lun[3]) & 0x3FFF;
 
                pr_debug("vhost_scsi got command opcode: %#02x, lun: %d\n",
-                       tv_cmd->tvc_cdb[0], tv_cmd->tvc_lun);
+                       cmd->tvc_cdb[0], cmd->tvc_lun);
 
                if (data_direction != DMA_NONE) {
-                       ret = vhost_scsi_map_iov_to_sgl(tv_cmd,
+                       ret = vhost_scsi_map_iov_to_sgl(cmd,
                                        &vq->iov[data_first], data_num,
                                        data_direction == DMA_TO_DEVICE);
                        if (unlikely(ret)) {
@@ -1029,22 +1046,22 @@ static void vhost_scsi_handle_vq(struct vhost_scsi *vs,
                 * complete the virtio-scsi request in TCM callback context via
                 * tcm_vhost_queue_data_in() and tcm_vhost_queue_status()
                 */
-               tv_cmd->tvc_vq_desc = head;
+               cmd->tvc_vq_desc = head;
                /*
                 * Dispatch tv_cmd descriptor for cmwq execution in process
                 * context provided by tcm_vhost_workqueue.  This also ensures
                 * tv_cmd is executed on the same kworker CPU as this vhost
                 * thread to gain positive L2 cache locality effects..
                 */
-               INIT_WORK(&tv_cmd->work, tcm_vhost_submission_work);
-               queue_work(tcm_vhost_workqueue, &tv_cmd->work);
+               INIT_WORK(&cmd->work, tcm_vhost_submission_work);
+               queue_work(tcm_vhost_workqueue, &cmd->work);
        }
 
        mutex_unlock(&vq->mutex);
        return;
 
 err_free:
-       vhost_scsi_free_cmd(tv_cmd);
+       vhost_scsi_free_cmd(cmd);
 err_cmd:
        vhost_scsi_send_bad_target(vs, vq, head, out);
        mutex_unlock(&vq->mutex);
@@ -1055,8 +1072,12 @@ static void vhost_scsi_ctl_handle_kick(struct vhost_work *work)
        pr_debug("%s: The handling func for control queue.\n", __func__);
 }
 
-static void tcm_vhost_send_evt(struct vhost_scsi *vs, struct tcm_vhost_tpg *tpg,
-       struct se_lun *lun, u32 event, u32 reason)
+static void
+tcm_vhost_send_evt(struct vhost_scsi *vs,
+                  struct tcm_vhost_tpg *tpg,
+                  struct se_lun *lun,
+                  u32 event,
+                  u32 reason)
 {
        struct tcm_vhost_evt *evt;
 
@@ -1146,12 +1167,12 @@ static void vhost_scsi_flush(struct vhost_scsi *vs)
  *  The lock nesting rule is:
  *    tcm_vhost_mutex -> vs->dev.mutex -> tpg->tv_tpg_mutex -> vq->mutex
  */
-static int vhost_scsi_set_endpoint(
-       struct vhost_scsi *vs,
-       struct vhost_scsi_target *t)
+static int
+vhost_scsi_set_endpoint(struct vhost_scsi *vs,
+                       struct vhost_scsi_target *t)
 {
        struct tcm_vhost_tport *tv_tport;
-       struct tcm_vhost_tpg *tv_tpg;
+       struct tcm_vhost_tpg *tpg;
        struct tcm_vhost_tpg **vs_tpg;
        struct vhost_virtqueue *vq;
        int index, ret, i, len;
@@ -1178,32 +1199,32 @@ static int vhost_scsi_set_endpoint(
        if (vs->vs_tpg)
                memcpy(vs_tpg, vs->vs_tpg, len);
 
-       list_for_each_entry(tv_tpg, &tcm_vhost_list, tv_tpg_list) {
-               mutex_lock(&tv_tpg->tv_tpg_mutex);
-               if (!tv_tpg->tpg_nexus) {
-                       mutex_unlock(&tv_tpg->tv_tpg_mutex);
+       list_for_each_entry(tpg, &tcm_vhost_list, tv_tpg_list) {
+               mutex_lock(&tpg->tv_tpg_mutex);
+               if (!tpg->tpg_nexus) {
+                       mutex_unlock(&tpg->tv_tpg_mutex);
                        continue;
                }
-               if (tv_tpg->tv_tpg_vhost_count != 0) {
-                       mutex_unlock(&tv_tpg->tv_tpg_mutex);
+               if (tpg->tv_tpg_vhost_count != 0) {
+                       mutex_unlock(&tpg->tv_tpg_mutex);
                        continue;
                }
-               tv_tport = tv_tpg->tport;
+               tv_tport = tpg->tport;
 
                if (!strcmp(tv_tport->tport_name, t->vhost_wwpn)) {
-                       if (vs->vs_tpg && vs->vs_tpg[tv_tpg->tport_tpgt]) {
+                       if (vs->vs_tpg && vs->vs_tpg[tpg->tport_tpgt]) {
                                kfree(vs_tpg);
-                               mutex_unlock(&tv_tpg->tv_tpg_mutex);
+                               mutex_unlock(&tpg->tv_tpg_mutex);
                                ret = -EEXIST;
                                goto out;
                        }
-                       tv_tpg->tv_tpg_vhost_count++;
-                       tv_tpg->vhost_scsi = vs;
-                       vs_tpg[tv_tpg->tport_tpgt] = tv_tpg;
+                       tpg->tv_tpg_vhost_count++;
+                       tpg->vhost_scsi = vs;
+                       vs_tpg[tpg->tport_tpgt] = tpg;
                        smp_mb__after_atomic_inc();
                        match = true;
                }
-               mutex_unlock(&tv_tpg->tv_tpg_mutex);
+               mutex_unlock(&tpg->tv_tpg_mutex);
        }
 
        if (match) {
@@ -1236,12 +1257,12 @@ out:
        return ret;
 }
 
-static int vhost_scsi_clear_endpoint(
-       struct vhost_scsi *vs,
-       struct vhost_scsi_target *t)
+static int
+vhost_scsi_clear_endpoint(struct vhost_scsi *vs,
+                         struct vhost_scsi_target *t)
 {
        struct tcm_vhost_tport *tv_tport;
-       struct tcm_vhost_tpg *tv_tpg;
+       struct tcm_vhost_tpg *tpg;
        struct vhost_virtqueue *vq;
        bool match = false;
        int index, ret, i;
@@ -1264,30 +1285,30 @@ static int vhost_scsi_clear_endpoint(
 
        for (i = 0; i < VHOST_SCSI_MAX_TARGET; i++) {
                target = i;
-               tv_tpg = vs->vs_tpg[target];
-               if (!tv_tpg)
+               tpg = vs->vs_tpg[target];
+               if (!tpg)
                        continue;
 
-               mutex_lock(&tv_tpg->tv_tpg_mutex);
-               tv_tport = tv_tpg->tport;
+               mutex_lock(&tpg->tv_tpg_mutex);
+               tv_tport = tpg->tport;
                if (!tv_tport) {
                        ret = -ENODEV;
                        goto err_tpg;
                }
 
                if (strcmp(tv_tport->tport_name, t->vhost_wwpn)) {
-                       pr_warn("tv_tport->tport_name: %s, tv_tpg->tport_tpgt: %hu"
+                       pr_warn("tv_tport->tport_name: %s, tpg->tport_tpgt: %hu"
                                " does not match t->vhost_wwpn: %s, t->vhost_tpgt: %hu\n",
-                               tv_tport->tport_name, tv_tpg->tport_tpgt,
+                               tv_tport->tport_name, tpg->tport_tpgt,
                                t->vhost_wwpn, t->vhost_tpgt);
                        ret = -EINVAL;
                        goto err_tpg;
                }
-               tv_tpg->tv_tpg_vhost_count--;
-               tv_tpg->vhost_scsi = NULL;
+               tpg->tv_tpg_vhost_count--;
+               tpg->vhost_scsi = NULL;
                vs->vs_tpg[target] = NULL;
                match = true;
-               mutex_unlock(&tv_tpg->tv_tpg_mutex);
+               mutex_unlock(&tpg->tv_tpg_mutex);
        }
        if (match) {
                for (i = 0; i < VHOST_SCSI_MAX_VQ; i++) {
@@ -1311,7 +1332,7 @@ static int vhost_scsi_clear_endpoint(
        return 0;
 
 err_tpg:
-       mutex_unlock(&tv_tpg->tv_tpg_mutex);
+       mutex_unlock(&tpg->tv_tpg_mutex);
 err_dev:
        mutex_unlock(&vs->dev.mutex);
        mutex_unlock(&tcm_vhost_mutex);
@@ -1338,68 +1359,70 @@ static int vhost_scsi_set_features(struct vhost_scsi *vs, u64 features)
 
 static int vhost_scsi_open(struct inode *inode, struct file *f)
 {
-       struct vhost_scsi *s;
+       struct vhost_scsi *vs;
        struct vhost_virtqueue **vqs;
        int r, i;
 
-       s = kzalloc(sizeof(*s), GFP_KERNEL);
-       if (!s)
+       vs = kzalloc(sizeof(*vs), GFP_KERNEL);
+       if (!vs)
                return -ENOMEM;
 
        vqs = kmalloc(VHOST_SCSI_MAX_VQ * sizeof(*vqs), GFP_KERNEL);
        if (!vqs) {
-               kfree(s);
+               kfree(vs);
                return -ENOMEM;
        }
 
-       vhost_work_init(&s->vs_completion_work, vhost_scsi_complete_cmd_work);
-       vhost_work_init(&s->vs_event_work, tcm_vhost_evt_work);
+       vhost_work_init(&vs->vs_completion_work, vhost_scsi_complete_cmd_work);
+       vhost_work_init(&vs->vs_event_work, tcm_vhost_evt_work);
 
-       s->vs_events_nr = 0;
-       s->vs_events_missed = false;
+       vs->vs_events_nr = 0;
+       vs->vs_events_missed = false;
 
-       vqs[VHOST_SCSI_VQ_CTL] = &s->vqs[VHOST_SCSI_VQ_CTL].vq;
-       vqs[VHOST_SCSI_VQ_EVT] = &s->vqs[VHOST_SCSI_VQ_EVT].vq;
-       s->vqs[VHOST_SCSI_VQ_CTL].vq.handle_kick = vhost_scsi_ctl_handle_kick;
-       s->vqs[VHOST_SCSI_VQ_EVT].vq.handle_kick = vhost_scsi_evt_handle_kick;
+       vqs[VHOST_SCSI_VQ_CTL] = &vs->vqs[VHOST_SCSI_VQ_CTL].vq;
+       vqs[VHOST_SCSI_VQ_EVT] = &vs->vqs[VHOST_SCSI_VQ_EVT].vq;
+       vs->vqs[VHOST_SCSI_VQ_CTL].vq.handle_kick = vhost_scsi_ctl_handle_kick;
+       vs->vqs[VHOST_SCSI_VQ_EVT].vq.handle_kick = vhost_scsi_evt_handle_kick;
        for (i = VHOST_SCSI_VQ_IO; i < VHOST_SCSI_MAX_VQ; i++) {
-               vqs[i] = &s->vqs[i].vq;
-               s->vqs[i].vq.handle_kick = vhost_scsi_handle_kick;
+               vqs[i] = &vs->vqs[i].vq;
+               vs->vqs[i].vq.handle_kick = vhost_scsi_handle_kick;
        }
-       r = vhost_dev_init(&s->dev, vqs, VHOST_SCSI_MAX_VQ);
+       r = vhost_dev_init(&vs->dev, vqs, VHOST_SCSI_MAX_VQ);
 
-       tcm_vhost_init_inflight(s, NULL);
+       tcm_vhost_init_inflight(vs, NULL);
 
        if (r < 0) {
                kfree(vqs);
-               kfree(s);
+               kfree(vs);
                return r;
        }
 
-       f->private_data = s;
+       f->private_data = vs;
        return 0;
 }
 
 static int vhost_scsi_release(struct inode *inode, struct file *f)
 {
-       struct vhost_scsi *s = f->private_data;
+       struct vhost_scsi *vs = f->private_data;
        struct vhost_scsi_target t;
 
-       mutex_lock(&s->dev.mutex);
-       memcpy(t.vhost_wwpn, s->vs_vhost_wwpn, sizeof(t.vhost_wwpn));
-       mutex_unlock(&s->dev.mutex);
-       vhost_scsi_clear_endpoint(s, &t);
-       vhost_dev_stop(&s->dev);
-       vhost_dev_cleanup(&s->dev, false);
+       mutex_lock(&vs->dev.mutex);
+       memcpy(t.vhost_wwpn, vs->vs_vhost_wwpn, sizeof(t.vhost_wwpn));
+       mutex_unlock(&vs->dev.mutex);
+       vhost_scsi_clear_endpoint(vs, &t);
+       vhost_dev_stop(&vs->dev);
+       vhost_dev_cleanup(&vs->dev, false);
        /* Jobs can re-queue themselves in evt kick handler. Do extra flush. */
-       vhost_scsi_flush(s);
-       kfree(s->dev.vqs);
-       kfree(s);
+       vhost_scsi_flush(vs);
+       kfree(vs->dev.vqs);
+       kfree(vs);
        return 0;
 }
 
-static long vhost_scsi_ioctl(struct file *f, unsigned int ioctl,
-                               unsigned long arg)
+static long
+vhost_scsi_ioctl(struct file *f,
+                unsigned int ioctl,
+                unsigned long arg)
 {
        struct vhost_scsi *vs = f->private_data;
        struct vhost_scsi_target backend;
@@ -1515,8 +1538,9 @@ static char *tcm_vhost_dump_proto_id(struct tcm_vhost_tport *tport)
        return "Unknown";
 }
 
-static void tcm_vhost_do_plug(struct tcm_vhost_tpg *tpg,
-       struct se_lun *lun, bool plug)
+static void
+tcm_vhost_do_plug(struct tcm_vhost_tpg *tpg,
+                 struct se_lun *lun, bool plug)
 {
 
        struct vhost_scsi *vs = tpg->vhost_scsi;
@@ -1556,18 +1580,18 @@ static void tcm_vhost_hotunplug(struct tcm_vhost_tpg *tpg, struct se_lun *lun)
 }
 
 static int tcm_vhost_port_link(struct se_portal_group *se_tpg,
-       struct se_lun *lun)
+                              struct se_lun *lun)
 {
-       struct tcm_vhost_tpg *tv_tpg = container_of(se_tpg,
+       struct tcm_vhost_tpg *tpg = container_of(se_tpg,
                                struct tcm_vhost_tpg, se_tpg);
 
        mutex_lock(&tcm_vhost_mutex);
 
-       mutex_lock(&tv_tpg->tv_tpg_mutex);
-       tv_tpg->tv_tpg_port_count++;
-       mutex_unlock(&tv_tpg->tv_tpg_mutex);
+       mutex_lock(&tpg->tv_tpg_mutex);
+       tpg->tv_tpg_port_count++;
+       mutex_unlock(&tpg->tv_tpg_mutex);
 
-       tcm_vhost_hotplug(tv_tpg, lun);
+       tcm_vhost_hotplug(tpg, lun);
 
        mutex_unlock(&tcm_vhost_mutex);
 
@@ -1575,26 +1599,26 @@ static int tcm_vhost_port_link(struct se_portal_group *se_tpg,
 }
 
 static void tcm_vhost_port_unlink(struct se_portal_group *se_tpg,
-       struct se_lun *lun)
+                                 struct se_lun *lun)
 {
-       struct tcm_vhost_tpg *tv_tpg = container_of(se_tpg,
+       struct tcm_vhost_tpg *tpg = container_of(se_tpg,
                                struct tcm_vhost_tpg, se_tpg);
 
        mutex_lock(&tcm_vhost_mutex);
 
-       mutex_lock(&tv_tpg->tv_tpg_mutex);
-       tv_tpg->tv_tpg_port_count--;
-       mutex_unlock(&tv_tpg->tv_tpg_mutex);
+       mutex_lock(&tpg->tv_tpg_mutex);
+       tpg->tv_tpg_port_count--;
+       mutex_unlock(&tpg->tv_tpg_mutex);
 
-       tcm_vhost_hotunplug(tv_tpg, lun);
+       tcm_vhost_hotunplug(tpg, lun);
 
        mutex_unlock(&tcm_vhost_mutex);
 }
 
-static struct se_node_acl *tcm_vhost_make_nodeacl(
-       struct se_portal_group *se_tpg,
-       struct config_group *group,
-       const char *name)
+static struct se_node_acl *
+tcm_vhost_make_nodeacl(struct se_portal_group *se_tpg,
+                      struct config_group *group,
+                      const char *name)
 {
        struct se_node_acl *se_nacl, *se_nacl_new;
        struct tcm_vhost_nacl *nacl;
@@ -1635,23 +1659,23 @@ static void tcm_vhost_drop_nodeacl(struct se_node_acl *se_acl)
        kfree(nacl);
 }
 
-static int tcm_vhost_make_nexus(struct tcm_vhost_tpg *tv_tpg,
-       const char *name)
+static int tcm_vhost_make_nexus(struct tcm_vhost_tpg *tpg,
+                               const char *name)
 {
        struct se_portal_group *se_tpg;
        struct tcm_vhost_nexus *tv_nexus;
 
-       mutex_lock(&tv_tpg->tv_tpg_mutex);
-       if (tv_tpg->tpg_nexus) {
-               mutex_unlock(&tv_tpg->tv_tpg_mutex);
-               pr_debug("tv_tpg->tpg_nexus already exists\n");
+       mutex_lock(&tpg->tv_tpg_mutex);
+       if (tpg->tpg_nexus) {
+               mutex_unlock(&tpg->tv_tpg_mutex);
+               pr_debug("tpg->tpg_nexus already exists\n");
                return -EEXIST;
        }
-       se_tpg = &tv_tpg->se_tpg;
+       se_tpg = &tpg->se_tpg;
 
        tv_nexus = kzalloc(sizeof(struct tcm_vhost_nexus), GFP_KERNEL);
        if (!tv_nexus) {
-               mutex_unlock(&tv_tpg->tv_tpg_mutex);
+               mutex_unlock(&tpg->tv_tpg_mutex);
                pr_err("Unable to allocate struct tcm_vhost_nexus\n");
                return -ENOMEM;
        }
@@ -1660,7 +1684,7 @@ static int tcm_vhost_make_nexus(struct tcm_vhost_tpg *tv_tpg,
         */
        tv_nexus->tvn_se_sess = transport_init_session();
        if (IS_ERR(tv_nexus->tvn_se_sess)) {
-               mutex_unlock(&tv_tpg->tv_tpg_mutex);
+               mutex_unlock(&tpg->tv_tpg_mutex);
                kfree(tv_nexus);
                return -ENOMEM;
        }
@@ -1672,7 +1696,7 @@ static int tcm_vhost_make_nexus(struct tcm_vhost_tpg *tv_tpg,
        tv_nexus->tvn_se_sess->se_node_acl = core_tpg_check_initiator_node_acl(
                                se_tpg, (unsigned char *)name);
        if (!tv_nexus->tvn_se_sess->se_node_acl) {
-               mutex_unlock(&tv_tpg->tv_tpg_mutex);
+               mutex_unlock(&tpg->tv_tpg_mutex);
                pr_debug("core_tpg_check_initiator_node_acl() failed"
                                " for %s\n", name);
                transport_free_session(tv_nexus->tvn_se_sess);
@@ -1685,9 +1709,9 @@ static int tcm_vhost_make_nexus(struct tcm_vhost_tpg *tv_tpg,
         */
        __transport_register_session(se_tpg, tv_nexus->tvn_se_sess->se_node_acl,
                        tv_nexus->tvn_se_sess, tv_nexus);
-       tv_tpg->tpg_nexus = tv_nexus;
+       tpg->tpg_nexus = tv_nexus;
 
-       mutex_unlock(&tv_tpg->tv_tpg_mutex);
+       mutex_unlock(&tpg->tv_tpg_mutex);
        return 0;
 }
 
@@ -1740,40 +1764,40 @@ static int tcm_vhost_drop_nexus(struct tcm_vhost_tpg *tpg)
 }
 
 static ssize_t tcm_vhost_tpg_show_nexus(struct se_portal_group *se_tpg,
-       char *page)
+                                       char *page)
 {
-       struct tcm_vhost_tpg *tv_tpg = container_of(se_tpg,
+       struct tcm_vhost_tpg *tpg = container_of(se_tpg,
                                struct tcm_vhost_tpg, se_tpg);
        struct tcm_vhost_nexus *tv_nexus;
        ssize_t ret;
 
-       mutex_lock(&tv_tpg->tv_tpg_mutex);
-       tv_nexus = tv_tpg->tpg_nexus;
+       mutex_lock(&tpg->tv_tpg_mutex);
+       tv_nexus = tpg->tpg_nexus;
        if (!tv_nexus) {
-               mutex_unlock(&tv_tpg->tv_tpg_mutex);
+               mutex_unlock(&tpg->tv_tpg_mutex);
                return -ENODEV;
        }
        ret = snprintf(page, PAGE_SIZE, "%s\n",
                        tv_nexus->tvn_se_sess->se_node_acl->initiatorname);
-       mutex_unlock(&tv_tpg->tv_tpg_mutex);
+       mutex_unlock(&tpg->tv_tpg_mutex);
 
        return ret;
 }
 
 static ssize_t tcm_vhost_tpg_store_nexus(struct se_portal_group *se_tpg,
-       const char *page,
-       size_t count)
+                                        const char *page,
+                                        size_t count)
 {
-       struct tcm_vhost_tpg *tv_tpg = container_of(se_tpg,
+       struct tcm_vhost_tpg *tpg = container_of(se_tpg,
                                struct tcm_vhost_tpg, se_tpg);
-       struct tcm_vhost_tport *tport_wwn = tv_tpg->tport;
+       struct tcm_vhost_tport *tport_wwn = tpg->tport;
        unsigned char i_port[TCM_VHOST_NAMELEN], *ptr, *port_ptr;
        int ret;
        /*
         * Shutdown the active I_T nexus if 'NULL' is passed..
         */
        if (!strncmp(page, "NULL", 4)) {
-               ret = tcm_vhost_drop_nexus(tv_tpg);
+               ret = tcm_vhost_drop_nexus(tpg);
                return (!ret) ? count : ret;
        }
        /*
@@ -1831,7 +1855,7 @@ check_newline:
        if (i_port[strlen(i_port)-1] == '\n')
                i_port[strlen(i_port)-1] = '\0';
 
-       ret = tcm_vhost_make_nexus(tv_tpg, port_ptr);
+       ret = tcm_vhost_make_nexus(tpg, port_ptr);
        if (ret < 0)
                return ret;
 
@@ -1845,9 +1869,10 @@ static struct configfs_attribute *tcm_vhost_tpg_attrs[] = {
        NULL,
 };
 
-static struct se_portal_group *tcm_vhost_make_tpg(struct se_wwn *wwn,
-       struct config_group *group,
-       const char *name)
+static struct se_portal_group *
+tcm_vhost_make_tpg(struct se_wwn *wwn,
+                  struct config_group *group,
+                  const char *name)
 {
        struct tcm_vhost_tport *tport = container_of(wwn,
                        struct tcm_vhost_tport, tport_wwn);
@@ -1903,9 +1928,10 @@ static void tcm_vhost_drop_tpg(struct se_portal_group *se_tpg)
        kfree(tpg);
 }
 
-static struct se_wwn *tcm_vhost_make_tport(struct target_fabric_configfs *tf,
-       struct config_group *group,
-       const char *name)
+static struct se_wwn *
+tcm_vhost_make_tport(struct target_fabric_configfs *tf,
+                    struct config_group *group,
+                    const char *name)
 {
        struct tcm_vhost_tport *tport;
        char *ptr;
@@ -1975,9 +2001,9 @@ static void tcm_vhost_drop_tport(struct se_wwn *wwn)
        kfree(tport);
 }
 
-static ssize_t tcm_vhost_wwn_show_attr_version(
-       struct target_fabric_configfs *tf,
-       char *page)
+static ssize_t
+tcm_vhost_wwn_show_attr_version(struct target_fabric_configfs *tf,
+                               char *page)
 {
        return sprintf(page, "TCM_VHOST fabric module %s on %s/%s"
                "on "UTS_RELEASE"\n", TCM_VHOST_VERSION, utsname()->sysname,
@@ -2008,6 +2034,7 @@ static struct target_core_fabric_ops tcm_vhost_ops = {
        .tpg_release_fabric_acl         = tcm_vhost_release_fabric_acl,
        .tpg_get_inst_index             = tcm_vhost_tpg_get_inst_index,
        .release_cmd                    = tcm_vhost_release_cmd,
+       .check_stop_free                = vhost_scsi_check_stop_free,
        .shutdown_session               = tcm_vhost_shutdown_session,
        .close_session                  = tcm_vhost_close_session,
        .sess_get_index                 = tcm_vhost_sess_get_index,
index 1ee45bc..a73ea21 100644 (file)
@@ -18,7 +18,7 @@
 #include <linux/slab.h>
 
 #include "test.h"
-#include "vhost.c"
+#include "vhost.h"
 
 /* Max number of bytes transferred before requeueing the job.
  * Using this limit prevents one virtqueue from starving others. */
@@ -38,17 +38,19 @@ struct vhost_test {
  * read-size critical section for our kind of RCU. */
 static void handle_vq(struct vhost_test *n)
 {
-       struct vhost_virtqueue *vq = &n->dev.vqs[VHOST_TEST_VQ];
+       struct vhost_virtqueue *vq = &n->vqs[VHOST_TEST_VQ];
        unsigned out, in;
        int head;
        size_t len, total_len = 0;
        void *private;
 
-       private = rcu_dereference_check(vq->private_data, 1);
-       if (!private)
+       mutex_lock(&vq->mutex);
+       private = vq->private_data;
+       if (!private) {
+               mutex_unlock(&vq->mutex);
                return;
+       }
 
-       mutex_lock(&vq->mutex);
        vhost_disable_notify(&n->dev, vq);
 
        for (;;) {
@@ -102,15 +104,23 @@ static int vhost_test_open(struct inode *inode, struct file *f)
 {
        struct vhost_test *n = kmalloc(sizeof *n, GFP_KERNEL);
        struct vhost_dev *dev;
+       struct vhost_virtqueue **vqs;
        int r;
 
        if (!n)
                return -ENOMEM;
+       vqs = kmalloc(VHOST_TEST_VQ_MAX * sizeof(*vqs), GFP_KERNEL);
+       if (!vqs) {
+               kfree(n);
+               return -ENOMEM;
+       }
 
        dev = &n->dev;
+       vqs[VHOST_TEST_VQ] = &n->vqs[VHOST_TEST_VQ];
        n->vqs[VHOST_TEST_VQ].handle_kick = handle_vq_kick;
-       r = vhost_dev_init(dev, n->vqs, VHOST_TEST_VQ_MAX);
+       r = vhost_dev_init(dev, vqs, VHOST_TEST_VQ_MAX);
        if (r < 0) {
+               kfree(vqs);
                kfree(n);
                return r;
        }
@@ -126,9 +136,8 @@ static void *vhost_test_stop_vq(struct vhost_test *n,
        void *private;
 
        mutex_lock(&vq->mutex);
-       private = rcu_dereference_protected(vq->private_data,
-                                        lockdep_is_held(&vq->mutex));
-       rcu_assign_pointer(vq->private_data, NULL);
+       private = vq->private_data;
+       vq->private_data = NULL;
        mutex_unlock(&vq->mutex);
        return private;
 }
@@ -140,7 +149,7 @@ static void vhost_test_stop(struct vhost_test *n, void **privatep)
 
 static void vhost_test_flush_vq(struct vhost_test *n, int index)
 {
-       vhost_poll_flush(&n->dev.vqs[index].poll);
+       vhost_poll_flush(&n->vqs[index].poll);
 }
 
 static void vhost_test_flush(struct vhost_test *n)
@@ -268,14 +277,14 @@ static long vhost_test_ioctl(struct file *f, unsigned int ioctl,
                        return -EFAULT;
                return vhost_test_run(n, test);
        case VHOST_GET_FEATURES:
-               features = VHOST_NET_FEATURES;
+               features = VHOST_FEATURES;
                if (copy_to_user(featurep, &features, sizeof features))
                        return -EFAULT;
                return 0;
        case VHOST_SET_FEATURES:
                if (copy_from_user(&features, featurep, sizeof features))
                        return -EFAULT;
-               if (features & ~VHOST_NET_FEATURES)
+               if (features & ~VHOST_FEATURES)
                        return -EOPNOTSUPP;
                return vhost_test_set_features(n, features);
        case VHOST_RESET_OWNER:
index 60aa5ad..e58cf00 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/slab.h>
 #include <linux/kthread.h>
 #include <linux/cgroup.h>
+#include <linux/module.h>
 
 #include "vhost.h"
 
@@ -66,6 +67,7 @@ void vhost_work_init(struct vhost_work *work, vhost_work_fn_t fn)
        work->flushing = 0;
        work->queue_seq = work->done_seq = 0;
 }
+EXPORT_SYMBOL_GPL(vhost_work_init);
 
 /* Init poll structure */
 void vhost_poll_init(struct vhost_poll *poll, vhost_work_fn_t fn,
@@ -79,6 +81,7 @@ void vhost_poll_init(struct vhost_poll *poll, vhost_work_fn_t fn,
 
        vhost_work_init(&poll->work, fn);
 }
+EXPORT_SYMBOL_GPL(vhost_poll_init);
 
 /* Start polling a file. We add ourselves to file's wait queue. The caller must
  * keep a reference to a file until after vhost_poll_stop is called. */
@@ -101,6 +104,7 @@ int vhost_poll_start(struct vhost_poll *poll, struct file *file)
 
        return ret;
 }
+EXPORT_SYMBOL_GPL(vhost_poll_start);
 
 /* Stop polling a file. After this function returns, it becomes safe to drop the
  * file reference. You must also flush afterwards. */
@@ -111,6 +115,7 @@ void vhost_poll_stop(struct vhost_poll *poll)
                poll->wqh = NULL;
        }
 }
+EXPORT_SYMBOL_GPL(vhost_poll_stop);
 
 static bool vhost_work_seq_done(struct vhost_dev *dev, struct vhost_work *work,
                                unsigned seq)
@@ -123,7 +128,7 @@ static bool vhost_work_seq_done(struct vhost_dev *dev, struct vhost_work *work,
        return left <= 0;
 }
 
-static void vhost_work_flush(struct vhost_dev *dev, struct vhost_work *work)
+void vhost_work_flush(struct vhost_dev *dev, struct vhost_work *work)
 {
        unsigned seq;
        int flushing;
@@ -138,6 +143,7 @@ static void vhost_work_flush(struct vhost_dev *dev, struct vhost_work *work)
        spin_unlock_irq(&dev->work_lock);
        BUG_ON(flushing < 0);
 }
+EXPORT_SYMBOL_GPL(vhost_work_flush);
 
 /* Flush any work that has been scheduled. When calling this, don't hold any
  * locks that are also used by the callback. */
@@ -145,6 +151,7 @@ void vhost_poll_flush(struct vhost_poll *poll)
 {
        vhost_work_flush(poll->dev, &poll->work);
 }
+EXPORT_SYMBOL_GPL(vhost_poll_flush);
 
 void vhost_work_queue(struct vhost_dev *dev, struct vhost_work *work)
 {
@@ -158,11 +165,13 @@ void vhost_work_queue(struct vhost_dev *dev, struct vhost_work *work)
        }
        spin_unlock_irqrestore(&dev->work_lock, flags);
 }
+EXPORT_SYMBOL_GPL(vhost_work_queue);
 
 void vhost_poll_queue(struct vhost_poll *poll)
 {
        vhost_work_queue(poll->dev, &poll->work);
 }
+EXPORT_SYMBOL_GPL(vhost_poll_queue);
 
 static void vhost_vq_reset(struct vhost_dev *dev,
                           struct vhost_virtqueue *vq)
@@ -251,17 +260,16 @@ static void vhost_vq_free_iovecs(struct vhost_virtqueue *vq)
 /* Helper to allocate iovec buffers for all vqs. */
 static long vhost_dev_alloc_iovecs(struct vhost_dev *dev)
 {
+       struct vhost_virtqueue *vq;
        int i;
 
        for (i = 0; i < dev->nvqs; ++i) {
-               dev->vqs[i]->indirect = kmalloc(sizeof *dev->vqs[i]->indirect *
-                                              UIO_MAXIOV, GFP_KERNEL);
-               dev->vqs[i]->log = kmalloc(sizeof *dev->vqs[i]->log * UIO_MAXIOV,
-                                         GFP_KERNEL);
-               dev->vqs[i]->heads = kmalloc(sizeof *dev->vqs[i]->heads *
-                                           UIO_MAXIOV, GFP_KERNEL);
-               if (!dev->vqs[i]->indirect || !dev->vqs[i]->log ||
-                       !dev->vqs[i]->heads)
+               vq = dev->vqs[i];
+               vq->indirect = kmalloc(sizeof *vq->indirect * UIO_MAXIOV,
+                                      GFP_KERNEL);
+               vq->log = kmalloc(sizeof *vq->log * UIO_MAXIOV, GFP_KERNEL);
+               vq->heads = kmalloc(sizeof *vq->heads * UIO_MAXIOV, GFP_KERNEL);
+               if (!vq->indirect || !vq->log || !vq->heads)
                        goto err_nomem;
        }
        return 0;
@@ -283,6 +291,7 @@ static void vhost_dev_free_iovecs(struct vhost_dev *dev)
 long vhost_dev_init(struct vhost_dev *dev,
                    struct vhost_virtqueue **vqs, int nvqs)
 {
+       struct vhost_virtqueue *vq;
        int i;
 
        dev->vqs = vqs;
@@ -297,19 +306,21 @@ long vhost_dev_init(struct vhost_dev *dev,
        dev->worker = NULL;
 
        for (i = 0; i < dev->nvqs; ++i) {
-               dev->vqs[i]->log = NULL;
-               dev->vqs[i]->indirect = NULL;
-               dev->vqs[i]->heads = NULL;
-               dev->vqs[i]->dev = dev;
-               mutex_init(&dev->vqs[i]->mutex);
-               vhost_vq_reset(dev, dev->vqs[i]);
-               if (dev->vqs[i]->handle_kick)
-                       vhost_poll_init(&dev->vqs[i]->poll,
-                                       dev->vqs[i]->handle_kick, POLLIN, dev);
+               vq = dev->vqs[i];
+               vq->log = NULL;
+               vq->indirect = NULL;
+               vq->heads = NULL;
+               vq->dev = dev;
+               mutex_init(&vq->mutex);
+               vhost_vq_reset(dev, vq);
+               if (vq->handle_kick)
+                       vhost_poll_init(&vq->poll, vq->handle_kick,
+                                       POLLIN, dev);
        }
 
        return 0;
 }
+EXPORT_SYMBOL_GPL(vhost_dev_init);
 
 /* Caller should have device mutex */
 long vhost_dev_check_owner(struct vhost_dev *dev)
@@ -317,6 +328,7 @@ long vhost_dev_check_owner(struct vhost_dev *dev)
        /* Are you the owner? If not, I don't think you mean to do that */
        return dev->mm == current->mm ? 0 : -EPERM;
 }
+EXPORT_SYMBOL_GPL(vhost_dev_check_owner);
 
 struct vhost_attach_cgroups_struct {
        struct vhost_work work;
@@ -348,6 +360,7 @@ bool vhost_dev_has_owner(struct vhost_dev *dev)
 {
        return dev->mm;
 }
+EXPORT_SYMBOL_GPL(vhost_dev_has_owner);
 
 /* Caller should have device mutex */
 long vhost_dev_set_owner(struct vhost_dev *dev)
@@ -391,11 +404,13 @@ err_worker:
 err_mm:
        return err;
 }
+EXPORT_SYMBOL_GPL(vhost_dev_set_owner);
 
 struct vhost_memory *vhost_dev_reset_owner_prepare(void)
 {
        return kmalloc(offsetof(struct vhost_memory, regions), GFP_KERNEL);
 }
+EXPORT_SYMBOL_GPL(vhost_dev_reset_owner_prepare);
 
 /* Caller should have device mutex */
 void vhost_dev_reset_owner(struct vhost_dev *dev, struct vhost_memory *memory)
@@ -406,6 +421,7 @@ void vhost_dev_reset_owner(struct vhost_dev *dev, struct vhost_memory *memory)
        memory->nregions = 0;
        RCU_INIT_POINTER(dev->memory, memory);
 }
+EXPORT_SYMBOL_GPL(vhost_dev_reset_owner);
 
 void vhost_dev_stop(struct vhost_dev *dev)
 {
@@ -418,6 +434,7 @@ void vhost_dev_stop(struct vhost_dev *dev)
                }
        }
 }
+EXPORT_SYMBOL_GPL(vhost_dev_stop);
 
 /* Caller should have device mutex if and only if locked is set */
 void vhost_dev_cleanup(struct vhost_dev *dev, bool locked)
@@ -458,6 +475,7 @@ void vhost_dev_cleanup(struct vhost_dev *dev, bool locked)
                mmput(dev->mm);
        dev->mm = NULL;
 }
+EXPORT_SYMBOL_GPL(vhost_dev_cleanup);
 
 static int log_access_ok(void __user *log_base, u64 addr, unsigned long sz)
 {
@@ -543,6 +561,7 @@ int vhost_log_access_ok(struct vhost_dev *dev)
                                       lockdep_is_held(&dev->mutex));
        return memory_access_ok(dev, mp, 1);
 }
+EXPORT_SYMBOL_GPL(vhost_log_access_ok);
 
 /* Verify access for write logging. */
 /* Caller should have vq mutex and device mutex */
@@ -568,6 +587,7 @@ int vhost_vq_access_ok(struct vhost_virtqueue *vq)
        return vq_access_ok(vq->dev, vq->num, vq->desc, vq->avail, vq->used) &&
                vq_log_access_ok(vq->dev, vq, vq->log_base);
 }
+EXPORT_SYMBOL_GPL(vhost_vq_access_ok);
 
 static long vhost_set_memory(struct vhost_dev *d, struct vhost_memory __user *m)
 {
@@ -797,6 +817,7 @@ long vhost_vring_ioctl(struct vhost_dev *d, int ioctl, void __user *argp)
                vhost_poll_flush(&vq->poll);
        return r;
 }
+EXPORT_SYMBOL_GPL(vhost_vring_ioctl);
 
 /* Caller must have device mutex */
 long vhost_dev_ioctl(struct vhost_dev *d, unsigned int ioctl, void __user *argp)
@@ -877,6 +898,7 @@ long vhost_dev_ioctl(struct vhost_dev *d, unsigned int ioctl, void __user *argp)
 done:
        return r;
 }
+EXPORT_SYMBOL_GPL(vhost_dev_ioctl);
 
 static const struct vhost_memory_region *find_region(struct vhost_memory *mem,
                                                     __u64 addr, __u32 len)
@@ -968,6 +990,7 @@ int vhost_log_write(struct vhost_virtqueue *vq, struct vhost_log *log,
        BUG();
        return 0;
 }
+EXPORT_SYMBOL_GPL(vhost_log_write);
 
 static int vhost_update_used_flags(struct vhost_virtqueue *vq)
 {
@@ -1019,6 +1042,7 @@ int vhost_init_used(struct vhost_virtqueue *vq)
        vq->signalled_used_valid = false;
        return get_user(vq->last_used_idx, &vq->used->idx);
 }
+EXPORT_SYMBOL_GPL(vhost_init_used);
 
 static int translate_desc(struct vhost_dev *dev, u64 addr, u32 len,
                          struct iovec iov[], int iov_size)
@@ -1295,12 +1319,14 @@ int vhost_get_vq_desc(struct vhost_dev *dev, struct vhost_virtqueue *vq,
        BUG_ON(!(vq->used_flags & VRING_USED_F_NO_NOTIFY));
        return head;
 }
+EXPORT_SYMBOL_GPL(vhost_get_vq_desc);
 
 /* Reverse the effect of vhost_get_vq_desc. Useful for error handling. */
 void vhost_discard_vq_desc(struct vhost_virtqueue *vq, int n)
 {
        vq->last_avail_idx -= n;
 }
+EXPORT_SYMBOL_GPL(vhost_discard_vq_desc);
 
 /* After we've used one of their buffers, we tell them about it.  We'll then
  * want to notify the guest, using eventfd. */
@@ -1349,6 +1375,7 @@ int vhost_add_used(struct vhost_virtqueue *vq, unsigned int head, int len)
                vq->signalled_used_valid = false;
        return 0;
 }
+EXPORT_SYMBOL_GPL(vhost_add_used);
 
 static int __vhost_add_used_n(struct vhost_virtqueue *vq,
                            struct vring_used_elem *heads,
@@ -1418,6 +1445,7 @@ int vhost_add_used_n(struct vhost_virtqueue *vq, struct vring_used_elem *heads,
        }
        return r;
 }
+EXPORT_SYMBOL_GPL(vhost_add_used_n);
 
 static bool vhost_notify(struct vhost_dev *dev, struct vhost_virtqueue *vq)
 {
@@ -1462,6 +1490,7 @@ void vhost_signal(struct vhost_dev *dev, struct vhost_virtqueue *vq)
        if (vq->call_ctx && vhost_notify(dev, vq))
                eventfd_signal(vq->call_ctx, 1);
 }
+EXPORT_SYMBOL_GPL(vhost_signal);
 
 /* And here's the combo meal deal.  Supersize me! */
 void vhost_add_used_and_signal(struct vhost_dev *dev,
@@ -1471,6 +1500,7 @@ void vhost_add_used_and_signal(struct vhost_dev *dev,
        vhost_add_used(vq, head, len);
        vhost_signal(dev, vq);
 }
+EXPORT_SYMBOL_GPL(vhost_add_used_and_signal);
 
 /* multi-buffer version of vhost_add_used_and_signal */
 void vhost_add_used_and_signal_n(struct vhost_dev *dev,
@@ -1480,6 +1510,7 @@ void vhost_add_used_and_signal_n(struct vhost_dev *dev,
        vhost_add_used_n(vq, heads, count);
        vhost_signal(dev, vq);
 }
+EXPORT_SYMBOL_GPL(vhost_add_used_and_signal_n);
 
 /* OK, now we need to know about added descriptors. */
 bool vhost_enable_notify(struct vhost_dev *dev, struct vhost_virtqueue *vq)
@@ -1517,6 +1548,7 @@ bool vhost_enable_notify(struct vhost_dev *dev, struct vhost_virtqueue *vq)
 
        return avail_idx != vq->avail_idx;
 }
+EXPORT_SYMBOL_GPL(vhost_enable_notify);
 
 /* We don't need to be notified again. */
 void vhost_disable_notify(struct vhost_dev *dev, struct vhost_virtqueue *vq)
@@ -1533,3 +1565,21 @@ void vhost_disable_notify(struct vhost_dev *dev, struct vhost_virtqueue *vq)
                               &vq->used->flags, r);
        }
 }
+EXPORT_SYMBOL_GPL(vhost_disable_notify);
+
+static int __init vhost_init(void)
+{
+       return 0;
+}
+
+static void __exit vhost_exit(void)
+{
+}
+
+module_init(vhost_init);
+module_exit(vhost_exit);
+
+MODULE_VERSION("0.0.1");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Michael S. Tsirkin");
+MODULE_DESCRIPTION("Host kernel accelerator for virtio");
index 64adcf9..42298cd 100644 (file)
@@ -46,6 +46,8 @@ int vhost_poll_start(struct vhost_poll *poll, struct file *file);
 void vhost_poll_stop(struct vhost_poll *poll);
 void vhost_poll_flush(struct vhost_poll *poll);
 void vhost_poll_queue(struct vhost_poll *poll);
+void vhost_work_flush(struct vhost_dev *dev, struct vhost_work *work);
+long vhost_vring_ioctl(struct vhost_dev *d, int ioctl, void __user *argp);
 
 struct vhost_log {
        u64 addr;
index 3c14e43..285d552 100644 (file)
 P3
-# Standard 224-color Linux logo
 80 80
 255
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  6   6   6   6   6   6  10  10  10  10  10  10
- 10  10  10   6   6   6   6   6   6   6   6   6
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   6   6   6  10  10  10  14  14  14
- 22  22  22  26  26  26  30  30  30  34  34  34
- 30  30  30  30  30  30  26  26  26  18  18  18
- 14  14  14  10  10  10   6   6   6   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   1   0   0   1   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  6   6   6  14  14  14  26  26  26  42  42  42
- 54  54  54  66  66  66  78  78  78  78  78  78
- 78  78  78  74  74  74  66  66  66  54  54  54
- 42  42  42  26  26  26  18  18  18  10  10  10
-  6   6   6   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   1   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0  10  10  10
- 22  22  22  42  42  42  66  66  66  86  86  86
- 66  66  66  38  38  38  38  38  38  22  22  22
- 26  26  26  34  34  34  54  54  54  66  66  66
- 86  86  86  70  70  70  46  46  46  26  26  26
- 14  14  14   6   6   6   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   1   0   0   1   0   0   1   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0  10  10  10  26  26  26
- 50  50  50  82  82  82  58  58  58   6   6   6
-  2   2   6   2   2   6   2   2   6   2   2   6
-  2   2   6   2   2   6   2   2   6   2   2   6
-  6   6   6  54  54  54  86  86  86  66  66  66
- 38  38  38  18  18  18   6   6   6   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   6   6   6  22  22  22  50  50  50
- 78  78  78  34  34  34   2   2   6   2   2   6
-  2   2   6   2   2   6   2   2   6   2   2   6
-  2   2   6   2   2   6   2   2   6   2   2   6
-  2   2   6   2   2   6   6   6   6  70  70  70
- 78  78  78  46  46  46  22  22  22   6   6   6
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   1   0   0   1   0   0   1   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  6   6   6  18  18  18  42  42  42  82  82  82
- 26  26  26   2   2   6   2   2   6   2   2   6
-  2   2   6   2   2   6   2   2   6   2   2   6
-  2   2   6   2   2   6   2   2   6  14  14  14
- 46  46  46  34  34  34   6   6   6   2   2   6
- 42  42  42  78  78  78  42  42  42  18  18  18
-  6   6   6   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   1   0   0   0   0   0   1   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
- 10  10  10  30  30  30  66  66  66  58  58  58
-  2   2   6   2   2   6   2   2   6   2   2   6
-  2   2   6   2   2   6   2   2   6   2   2   6
-  2   2   6   2   2   6   2   2   6  26  26  26
- 86  86  86 101 101 101  46  46  46  10  10  10
-  2   2   6  58  58  58  70  70  70  34  34  34
- 10  10  10   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   1   0   0   1   0   0   1   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
- 14  14  14  42  42  42  86  86  86  10  10  10
-  2   2   6   2   2   6   2   2   6   2   2   6
-  2   2   6   2   2   6   2   2   6   2   2   6
-  2   2   6   2   2   6   2   2   6  30  30  30
- 94  94  94  94  94  94  58  58  58  26  26  26
-  2   2   6   6   6   6  78  78  78  54  54  54
- 22  22  22   6   6   6   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   6   6   6
- 22  22  22  62  62  62  62  62  62   2   2   6
-  2   2   6   2   2   6   2   2   6   2   2   6
-  2   2   6   2   2   6   2   2   6   2   2   6
-  2   2   6   2   2   6   2   2   6  26  26  26
- 54  54  54  38  38  38  18  18  18  10  10  10
-  2   2   6   2   2   6  34  34  34  82  82  82
- 38  38  38  14  14  14   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   1   0   0   1   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   6   6   6
- 30  30  30  78  78  78  30  30  30   2   2   6
-  2   2   6   2   2   6   2   2   6   2   2   6
-  2   2   6   2   2   6   2   2   6   2   2   6
-  2   2   6   2   2   6   2   2   6  10  10  10
- 10  10  10   2   2   6   2   2   6   2   2   6
-  2   2   6   2   2   6   2   2   6  78  78  78
- 50  50  50  18  18  18   6   6   6   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   1   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0  10  10  10
- 38  38  38  86  86  86  14  14  14   2   2   6
-  2   2   6   2   2   6   2   2   6   2   2   6
-  2   2   6   2   2   6   2   2   6   2   2   6
-  2   2   6   2   2   6   2   2   6   2   2   6
-  2   2   6   2   2   6   2   2   6   2   2   6
-  2   2   6   2   2   6   2   2   6  54  54  54
- 66  66  66  26  26  26   6   6   6   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   1   0   0   1   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0  14  14  14
- 42  42  42  82  82  82   2   2   6   2   2   6
-  2   2   6   6   6   6  10  10  10   2   2   6
-  2   2   6   2   2   6   2   2   6   2   2   6
-  2   2   6   2   2   6   2   2   6   6   6   6
- 14  14  14  10  10  10   2   2   6   2   2   6
-  2   2   6   2   2   6   2   2   6  18  18  18
- 82  82  82  34  34  34  10  10  10   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   1   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0  14  14  14
- 46  46  46  86  86  86   2   2   6   2   2   6
-  6   6   6   6   6   6  22  22  22  34  34  34
-  6   6   6   2   2   6   2   2   6   2   2   6
-  2   2   6   2   2   6  18  18  18  34  34  34
- 10  10  10  50  50  50  22  22  22   2   2   6
-  2   2   6   2   2   6   2   2   6  10  10  10
- 86  86  86  42  42  42  14  14  14   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   1   0   0   1   0   0   1   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0  14  14  14
- 46  46  46  86  86  86   2   2   6   2   2   6
- 38  38  38 116 116 116  94  94  94  22  22  22
- 22  22  22   2   2   6   2   2   6   2   2   6
- 14  14  14  86  86  86 138 138 138 162 162 162
-154 154 154  38  38  38  26  26  26   6   6   6
-  2   2   6   2   2   6   2   2   6   2   2   6
- 86  86  86  46  46  46  14  14  14   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0  14  14  14
- 46  46  46  86  86  86   2   2   6  14  14  14
-134 134 134 198 198 198 195 195 195 116 116 116
- 10  10  10   2   2   6   2   2   6   6   6   6
-101  98  89 187 187 187 210 210 210 218 218 218
-214 214 214 134 134 134  14  14  14   6   6   6
-  2   2   6   2   2   6   2   2   6   2   2   6
- 86  86  86  50  50  50  18  18  18   6   6   6
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   1   0   0   0
-  0   0   1   0   0   1   0   0   1   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0  14  14  14
- 46  46  46  86  86  86   2   2   6  54  54  54
-218 218 218 195 195 195 226 226 226 246 246 246
- 58  58  58   2   2   6   2   2   6  30  30  30
-210 210 210 253 253 253 174 174 174 123 123 123
-221 221 221 234 234 234  74  74  74   2   2   6
-  2   2   6   2   2   6   2   2   6   2   2   6
- 70  70  70  58  58  58  22  22  22   6   6   6
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0  14  14  14
- 46  46  46  82  82  82   2   2   6 106 106 106
-170 170 170  26  26  26  86  86  86 226 226 226
-123 123 123  10  10  10  14  14  14  46  46  46
-231 231 231 190 190 190   6   6   6  70  70  70
- 90  90  90 238 238 238 158 158 158   2   2   6
-  2   2   6   2   2   6   2   2   6   2   2   6
- 70  70  70  58  58  58  22  22  22   6   6   6
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   1   0   0   0
-  0   0   1   0   0   1   0   0   1   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0  14  14  14
- 42  42  42  86  86  86   6   6   6 116 116 116
-106 106 106   6   6   6  70  70  70 149 149 149
-128 128 128  18  18  18  38  38  38  54  54  54
-221 221 221 106 106 106   2   2   6  14  14  14
- 46  46  46 190 190 190 198 198 198   2   2   6
-  2   2   6   2   2   6   2   2   6   2   2   6
- 74  74  74  62  62  62  22  22  22   6   6   6
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   1   0   0   0
-  0   0   1   0   0   0   0   0   1   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0  14  14  14
- 42  42  42  94  94  94  14  14  14 101 101 101
-128 128 128   2   2   6  18  18  18 116 116 116
-118  98  46 121  92   8 121  92   8  98  78  10
-162 162 162 106 106 106   2   2   6   2   2   6
-  2   2   6 195 195 195 195 195 195   6   6   6
-  2   2   6   2   2   6   2   2   6   2   2   6
- 74  74  74  62  62  62  22  22  22   6   6   6
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   1   0   0   1
-  0   0   1   0   0   0   0   0   1   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0  10  10  10
- 38  38  38  90  90  90  14  14  14  58  58  58
-210 210 210  26  26  26  54  38   6 154 114  10
-226 170  11 236 186  11 225 175  15 184 144  12
-215 174  15 175 146  61  37  26   9   2   2   6
- 70  70  70 246 246 246 138 138 138   2   2   6
-  2   2   6   2   2   6   2   2   6   2   2   6
- 70  70  70  66  66  66  26  26  26   6   6   6
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0  10  10  10
- 38  38  38  86  86  86  14  14  14  10  10  10
-195 195 195 188 164 115 192 133   9 225 175  15
-239 182  13 234 190  10 232 195  16 232 200  30
-245 207  45 241 208  19 232 195  16 184 144  12
-218 194 134 211 206 186  42  42  42   2   2   6
-  2   2   6   2   2   6   2   2   6   2   2   6
- 50  50  50  74  74  74  30  30  30   6   6   6
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0  10  10  10
- 34  34  34  86  86  86  14  14  14   2   2   6
-121  87  25 192 133   9 219 162  10 239 182  13
-236 186  11 232 195  16 241 208  19 244 214  54
-246 218  60 246 218  38 246 215  20 241 208  19
-241 208  19 226 184  13 121  87  25   2   2   6
-  2   2   6   2   2   6   2   2   6   2   2   6
- 50  50  50  82  82  82  34  34  34  10  10  10
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0  10  10  10
- 34  34  34  82  82  82  30  30  30  61  42   6
-180 123   7 206 145  10 230 174  11 239 182  13
-234 190  10 238 202  15 241 208  19 246 218  74
-246 218  38 246 215  20 246 215  20 246 215  20
-226 184  13 215 174  15 184 144  12   6   6   6
-  2   2   6   2   2   6   2   2   6   2   2   6
- 26  26  26  94  94  94  42  42  42  14  14  14
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0  10  10  10
- 30  30  30  78  78  78  50  50  50 104  69   6
-192 133   9 216 158  10 236 178  12 236 186  11
-232 195  16 241 208  19 244 214  54 245 215  43
-246 215  20 246 215  20 241 208  19 198 155  10
-200 144  11 216 158  10 156 118  10   2   2   6
-  2   2   6   2   2   6   2   2   6   2   2   6
-  6   6   6  90  90  90  54  54  54  18  18  18
-  6   6   6   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0  10  10  10
- 30  30  30  78  78  78  46  46  46  22  22  22
-137  92   6 210 162  10 239 182  13 238 190  10
-238 202  15 241 208  19 246 215  20 246 215  20
-241 208  19 203 166  17 185 133  11 210 150  10
-216 158  10 210 150  10 102  78  10   2   2   6
-  6   6   6  54  54  54  14  14  14   2   2   6
-  2   2   6  62  62  62  74  74  74  30  30  30
- 10  10  10   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0  10  10  10
- 34  34  34  78  78  78  50  50  50   6   6   6
- 94  70  30 139 102  15 190 146  13 226 184  13
-232 200  30 232 195  16 215 174  15 190 146  13
-168 122  10 192 133   9 210 150  10 213 154  11
-202 150  34 182 157 106 101  98  89   2   2   6
-  2   2   6  78  78  78 116 116 116  58  58  58
-  2   2   6  22  22  22  90  90  90  46  46  46
- 18  18  18   6   6   6   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0  10  10  10
- 38  38  38  86  86  86  50  50  50   6   6   6
-128 128 128 174 154 114 156 107  11 168 122  10
-198 155  10 184 144  12 197 138  11 200 144  11
-206 145  10 206 145  10 197 138  11 188 164 115
-195 195 195 198 198 198 174 174 174  14  14  14
-  2   2   6  22  22  22 116 116 116 116 116 116
- 22  22  22   2   2   6  74  74  74  70  70  70
- 30  30  30  10  10  10   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   6   6   6  18  18  18
- 50  50  50 101 101 101  26  26  26  10  10  10
-138 138 138 190 190 190 174 154 114 156 107  11
-197 138  11 200 144  11 197 138  11 192 133   9
-180 123   7 190 142  34 190 178 144 187 187 187
-202 202 202 221 221 221 214 214 214  66  66  66
-  2   2   6   2   2   6  50  50  50  62  62  62
-  6   6   6   2   2   6  10  10  10  90  90  90
- 50  50  50  18  18  18   6   6   6   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0  10  10  10  34  34  34
- 74  74  74  74  74  74   2   2   6   6   6   6
-144 144 144 198 198 198 190 190 190 178 166 146
-154 121  60 156 107  11 156 107  11 168 124  44
-174 154 114 187 187 187 190 190 190 210 210 210
-246 246 246 253 253 253 253 253 253 182 182 182
-  6   6   6   2   2   6   2   2   6   2   2   6
-  2   2   6   2   2   6   2   2   6  62  62  62
- 74  74  74  34  34  34  14  14  14   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0  10  10  10  22  22  22  54  54  54
- 94  94  94  18  18  18   2   2   6  46  46  46
-234 234 234 221 221 221 190 190 190 190 190 190
-190 190 190 187 187 187 187 187 187 190 190 190
-190 190 190 195 195 195 214 214 214 242 242 242
-253 253 253 253 253 253 253 253 253 253 253 253
- 82  82  82   2   2   6   2   2   6   2   2   6
-  2   2   6   2   2   6   2   2   6  14  14  14
- 86  86  86  54  54  54  22  22  22   6   6   6
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  6   6   6  18  18  18  46  46  46  90  90  90
- 46  46  46  18  18  18   6   6   6 182 182 182
-253 253 253 246 246 246 206 206 206 190 190 190
-190 190 190 190 190 190 190 190 190 190 190 190
-206 206 206 231 231 231 250 250 250 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-202 202 202  14  14  14   2   2   6   2   2   6
-  2   2   6   2   2   6   2   2   6   2   2   6
- 42  42  42  86  86  86  42  42  42  18  18  18
-  6   6   6   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   6   6   6
- 14  14  14  38  38  38  74  74  74  66  66  66
-  2   2   6   6   6   6  90  90  90 250 250 250
-253 253 253 253 253 253 238 238 238 198 198 198
-190 190 190 190 190 190 195 195 195 221 221 221
-246 246 246 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253  82  82  82   2   2   6   2   2   6
-  2   2   6   2   2   6   2   2   6   2   2   6
-  2   2   6  78  78  78  70  70  70  34  34  34
- 14  14  14   6   6   6   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0  14  14  14
- 34  34  34  66  66  66  78  78  78   6   6   6
-  2   2   6  18  18  18 218 218 218 253 253 253
-253 253 253 253 253 253 253 253 253 246 246 246
-226 226 226 231 231 231 246 246 246 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 178 178 178   2   2   6   2   2   6
-  2   2   6   2   2   6   2   2   6   2   2   6
-  2   2   6  18  18  18  90  90  90  62  62  62
- 30  30  30  10  10  10   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0  10  10  10  26  26  26
- 58  58  58  90  90  90  18  18  18   2   2   6
-  2   2   6 110 110 110 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-250 250 250 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 231 231 231  18  18  18   2   2   6
-  2   2   6   2   2   6   2   2   6   2   2   6
-  2   2   6   2   2   6  18  18  18  94  94  94
- 54  54  54  26  26  26  10  10  10   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   6   6   6  22  22  22  50  50  50
- 90  90  90  26  26  26   2   2   6   2   2   6
- 14  14  14 195 195 195 250 250 250 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-250 250 250 242 242 242  54  54  54   2   2   6
-  2   2   6   2   2   6   2   2   6   2   2   6
-  2   2   6   2   2   6   2   2   6  38  38  38
- 86  86  86  50  50  50  22  22  22   6   6   6
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  6   6   6  14  14  14  38  38  38  82  82  82
- 34  34  34   2   2   6   2   2   6   2   2   6
- 42  42  42 195 195 195 246 246 246 253 253 253
-253 253 253 253 253 253 253 253 253 250 250 250
-242 242 242 242 242 242 250 250 250 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 250 250 250 246 246 246 238 238 238
-226 226 226 231 231 231 101 101 101   6   6   6
-  2   2   6   2   2   6   2   2   6   2   2   6
-  2   2   6   2   2   6   2   2   6   2   2   6
- 38  38  38  82  82  82  42  42  42  14  14  14
-  6   6   6   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
- 10  10  10  26  26  26  62  62  62  66  66  66
-  2   2   6   2   2   6   2   2   6   6   6   6
- 70  70  70 170 170 170 206 206 206 234 234 234
-246 246 246 250 250 250 250 250 250 238 238 238
-226 226 226 231 231 231 238 238 238 250 250 250
-250 250 250 250 250 250 246 246 246 231 231 231
-214 214 214 206 206 206 202 202 202 202 202 202
-198 198 198 202 202 202 182 182 182  18  18  18
-  2   2   6   2   2   6   2   2   6   2   2   6
-  2   2   6   2   2   6   2   2   6   2   2   6
-  2   2   6  62  62  62  66  66  66  30  30  30
- 10  10  10   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
- 14  14  14  42  42  42  82  82  82  18  18  18
-  2   2   6   2   2   6   2   2   6  10  10  10
- 94  94  94 182 182 182 218 218 218 242 242 242
-250 250 250 253 253 253 253 253 253 250 250 250
-234 234 234 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 246 246 246
-238 238 238 226 226 226 210 210 210 202 202 202
-195 195 195 195 195 195 210 210 210 158 158 158
-  6   6   6  14  14  14  50  50  50  14  14  14
-  2   2   6   2   2   6   2   2   6   2   2   6
-  2   2   6   6   6   6  86  86  86  46  46  46
- 18  18  18   6   6   6   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   6   6   6
- 22  22  22  54  54  54  70  70  70   2   2   6
-  2   2   6  10  10  10   2   2   6  22  22  22
-166 166 166 231 231 231 250 250 250 253 253 253
-253 253 253 253 253 253 253 253 253 250 250 250
-242 242 242 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 246 246 246
-231 231 231 206 206 206 198 198 198 226 226 226
- 94  94  94   2   2   6   6   6   6  38  38  38
- 30  30  30   2   2   6   2   2   6   2   2   6
-  2   2   6   2   2   6  62  62  62  66  66  66
- 26  26  26  10  10  10   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0  10  10  10
- 30  30  30  74  74  74  50  50  50   2   2   6
- 26  26  26  26  26  26   2   2   6 106 106 106
-238 238 238 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 246 246 246 218 218 218 202 202 202
-210 210 210  14  14  14   2   2   6   2   2   6
- 30  30  30  22  22  22   2   2   6   2   2   6
-  2   2   6   2   2   6  18  18  18  86  86  86
- 42  42  42  14  14  14   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0  14  14  14
- 42  42  42  90  90  90  22  22  22   2   2   6
- 42  42  42   2   2   6  18  18  18 218 218 218
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 250 250 250 221 221 221
-218 218 218 101 101 101   2   2   6  14  14  14
- 18  18  18  38  38  38  10  10  10   2   2   6
-  2   2   6   2   2   6   2   2   6  78  78  78
- 58  58  58  22  22  22   6   6   6   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   6   6   6  18  18  18
- 54  54  54  82  82  82   2   2   6  26  26  26
- 22  22  22   2   2   6 123 123 123 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 250 250 250
-238 238 238 198 198 198   6   6   6  38  38  38
- 58  58  58  26  26  26  38  38  38   2   2   6
-  2   2   6   2   2   6   2   2   6  46  46  46
- 78  78  78  30  30  30  10  10  10   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0  10  10  10  30  30  30
- 74  74  74  58  58  58   2   2   6  42  42  42
-  2   2   6  22  22  22 231 231 231 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 250 250 250
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 246 246 246  46  46  46  38  38  38
- 42  42  42  14  14  14  38  38  38  14  14  14
-  2   2   6   2   2   6   2   2   6   6   6   6
- 86  86  86  46  46  46  14  14  14   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   6   6   6  14  14  14  42  42  42
- 90  90  90  18  18  18  18  18  18  26  26  26
-  2   2   6 116 116 116 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 250 250 250 238 238 238
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253  94  94  94   6   6   6
-  2   2   6   2   2   6  10  10  10  34  34  34
-  2   2   6   2   2   6   2   2   6   2   2   6
- 74  74  74  58  58  58  22  22  22   6   6   6
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0  10  10  10  26  26  26  66  66  66
- 82  82  82   2   2   6  38  38  38   6   6   6
- 14  14  14 210 210 210 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 246 246 246 242 242 242
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 144 144 144   2   2   6
-  2   2   6   2   2   6   2   2   6  46  46  46
-  2   2   6   2   2   6   2   2   6   2   2   6
- 42  42  42  74  74  74  30  30  30  10  10  10
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  6   6   6  14  14  14  42  42  42  90  90  90
- 26  26  26   6   6   6  42  42  42   2   2   6
- 74  74  74 250 250 250 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 242 242 242 242 242 242
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 182 182 182   2   2   6
-  2   2   6   2   2   6   2   2   6  46  46  46
-  2   2   6   2   2   6   2   2   6   2   2   6
- 10  10  10  86  86  86  38  38  38  10  10  10
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
- 10  10  10  26  26  26  66  66  66  82  82  82
-  2   2   6  22  22  22  18  18  18   2   2   6
-149 149 149 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 234 234 234 242 242 242
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 206 206 206   2   2   6
-  2   2   6   2   2   6   2   2   6  38  38  38
-  2   2   6   2   2   6   2   2   6   2   2   6
-  6   6   6  86  86  86  46  46  46  14  14  14
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   6   6   6
- 18  18  18  46  46  46  86  86  86  18  18  18
-  2   2   6  34  34  34  10  10  10   6   6   6
-210 210 210 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 234 234 234 242 242 242
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 221 221 221   6   6   6
-  2   2   6   2   2   6   6   6   6  30  30  30
-  2   2   6   2   2   6   2   2   6   2   2   6
-  2   2   6  82  82  82  54  54  54  18  18  18
-  6   6   6   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0  10  10  10
- 26  26  26  66  66  66  62  62  62   2   2   6
-  2   2   6  38  38  38  10  10  10  26  26  26
-238 238 238 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 231 231 231 238 238 238
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 231 231 231   6   6   6
-  2   2   6   2   2   6  10  10  10  30  30  30
-  2   2   6   2   2   6   2   2   6   2   2   6
-  2   2   6  66  66  66  58  58  58  22  22  22
-  6   6   6   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0  10  10  10
- 38  38  38  78  78  78   6   6   6   2   2   6
-  2   2   6  46  46  46  14  14  14  42  42  42
-246 246 246 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 231 231 231 242 242 242
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 234 234 234  10  10  10
-  2   2   6   2   2   6  22  22  22  14  14  14
-  2   2   6   2   2   6   2   2   6   2   2   6
-  2   2   6  66  66  66  62  62  62  22  22  22
-  6   6   6   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   6   6   6  18  18  18
- 50  50  50  74  74  74   2   2   6   2   2   6
- 14  14  14  70  70  70  34  34  34  62  62  62
-250 250 250 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 231 231 231 246 246 246
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 234 234 234  14  14  14
-  2   2   6   2   2   6  30  30  30   2   2   6
-  2   2   6   2   2   6   2   2   6   2   2   6
-  2   2   6  66  66  66  62  62  62  22  22  22
-  6   6   6   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   6   6   6  18  18  18
- 54  54  54  62  62  62   2   2   6   2   2   6
-  2   2   6  30  30  30  46  46  46  70  70  70
-250 250 250 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 231 231 231 246 246 246
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 226 226 226  10  10  10
-  2   2   6   6   6   6  30  30  30   2   2   6
-  2   2   6   2   2   6   2   2   6   2   2   6
-  2   2   6  66  66  66  58  58  58  22  22  22
-  6   6   6   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   6   6   6  22  22  22
- 58  58  58  62  62  62   2   2   6   2   2   6
-  2   2   6   2   2   6  30  30  30  78  78  78
-250 250 250 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 231 231 231 246 246 246
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 206 206 206   2   2   6
- 22  22  22  34  34  34  18  14   6  22  22  22
- 26  26  26  18  18  18   6   6   6   2   2   6
-  2   2   6  82  82  82  54  54  54  18  18  18
-  6   6   6   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   6   6   6  26  26  26
- 62  62  62 106 106 106  74  54  14 185 133  11
-210 162  10 121  92   8   6   6   6  62  62  62
-238 238 238 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 231 231 231 246 246 246
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 158 158 158  18  18  18
- 14  14  14   2   2   6   2   2   6   2   2   6
-  6   6   6  18  18  18  66  66  66  38  38  38
-  6   6   6  94  94  94  50  50  50  18  18  18
-  6   6   6   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   6   6   6
- 10  10  10  10  10  10  18  18  18  38  38  38
- 78  78  78 142 134 106 216 158  10 242 186  14
-246 190  14 246 190  14 156 118  10  10  10  10
- 90  90  90 238 238 238 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 231 231 231 250 250 250
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 246 230 190
-238 204  91 238 204  91 181 142  44  37  26   9
-  2   2   6   2   2   6   2   2   6   2   2   6
-  2   2   6   2   2   6  38  38  38  46  46  46
- 26  26  26 106 106 106  54  54  54  18  18  18
-  6   6   6   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   6   6   6  14  14  14  22  22  22
- 30  30  30  38  38  38  50  50  50  70  70  70
-106 106 106 190 142  34 226 170  11 242 186  14
-246 190  14 246 190  14 246 190  14 154 114  10
-  6   6   6  74  74  74 226 226 226 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 231 231 231 250 250 250
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 228 184  62
-241 196  14 241 208  19 232 195  16  38  30  10
-  2   2   6   2   2   6   2   2   6   2   2   6
-  2   2   6   6   6   6  30  30  30  26  26  26
-203 166  17 154 142  90  66  66  66  26  26  26
-  6   6   6   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  6   6   6  18  18  18  38  38  38  58  58  58
- 78  78  78  86  86  86 101 101 101 123 123 123
-175 146  61 210 150  10 234 174  13 246 186  14
-246 190  14 246 190  14 246 190  14 238 190  10
-102  78  10   2   2   6  46  46  46 198 198 198
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 234 234 234 242 242 242
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 224 178  62
-242 186  14 241 196  14 210 166  10  22  18   6
-  2   2   6   2   2   6   2   2   6   2   2   6
-  2   2   6   2   2   6   6   6   6 121  92   8
-238 202  15 232 195  16  82  82  82  34  34  34
- 10  10  10   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
- 14  14  14  38  38  38  70  70  70 154 122  46
-190 142  34 200 144  11 197 138  11 197 138  11
-213 154  11 226 170  11 242 186  14 246 190  14
-246 190  14 246 190  14 246 190  14 246 190  14
-225 175  15  46  32   6   2   2   6  22  22  22
-158 158 158 250 250 250 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 250 250 250 242 242 242 224 178  62
-239 182  13 236 186  11 213 154  11  46  32   6
-  2   2   6   2   2   6   2   2   6   2   2   6
-  2   2   6   2   2   6  61  42   6 225 175  15
-238 190  10 236 186  11 112 100  78  42  42  42
- 14  14  14   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   6   6   6
- 22  22  22  54  54  54 154 122  46 213 154  11
-226 170  11 230 174  11 226 170  11 226 170  11
-236 178  12 242 186  14 246 190  14 246 190  14
-246 190  14 246 190  14 246 190  14 246 190  14
-241 196  14 184 144  12  10  10  10   2   2   6
-  6   6   6 116 116 116 242 242 242 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 231 231 231 198 198 198 214 170  54
-236 178  12 236 178  12 210 150  10 137  92   6
- 18  14   6   2   2   6   2   2   6   2   2   6
-  6   6   6  70  47   6 200 144  11 236 178  12
-239 182  13 239 182  13 124 112  88  58  58  58
- 22  22  22   6   6   6   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0  10  10  10
- 30  30  30  70  70  70 180 133  36 226 170  11
-239 182  13 242 186  14 242 186  14 246 186  14
-246 190  14 246 190  14 246 190  14 246 190  14
-246 190  14 246 190  14 246 190  14 246 190  14
-246 190  14 232 195  16  98  70   6   2   2   6
-  2   2   6   2   2   6  66  66  66 221 221 221
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 206 206 206 198 198 198 214 166  58
-230 174  11 230 174  11 216 158  10 192 133   9
-163 110   8 116  81   8 102  78  10 116  81   8
-167 114   7 197 138  11 226 170  11 239 182  13
-242 186  14 242 186  14 162 146  94  78  78  78
- 34  34  34  14  14  14   6   6   6   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   6   6   6
- 30  30  30  78  78  78 190 142  34 226 170  11
-239 182  13 246 190  14 246 190  14 246 190  14
-246 190  14 246 190  14 246 190  14 246 190  14
-246 190  14 246 190  14 246 190  14 246 190  14
-246 190  14 241 196  14 203 166  17  22  18   6
-  2   2   6   2   2   6   2   2   6  38  38  38
-218 218 218 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-250 250 250 206 206 206 198 198 198 202 162  69
-226 170  11 236 178  12 224 166  10 210 150  10
-200 144  11 197 138  11 192 133   9 197 138  11
-210 150  10 226 170  11 242 186  14 246 190  14
-246 190  14 246 186  14 225 175  15 124 112  88
- 62  62  62  30  30  30  14  14  14   6   6   6
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0  10  10  10
- 30  30  30  78  78  78 174 135  50 224 166  10
-239 182  13 246 190  14 246 190  14 246 190  14
-246 190  14 246 190  14 246 190  14 246 190  14
-246 190  14 246 190  14 246 190  14 246 190  14
-246 190  14 246 190  14 241 196  14 139 102  15
-  2   2   6   2   2   6   2   2   6   2   2   6
- 78  78  78 250 250 250 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-250 250 250 214 214 214 198 198 198 190 150  46
-219 162  10 236 178  12 234 174  13 224 166  10
-216 158  10 213 154  11 213 154  11 216 158  10
-226 170  11 239 182  13 246 190  14 246 190  14
-246 190  14 246 190  14 242 186  14 206 162  42
-101 101 101  58  58  58  30  30  30  14  14  14
-  6   6   6   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0  10  10  10
- 30  30  30  74  74  74 174 135  50 216 158  10
-236 178  12 246 190  14 246 190  14 246 190  14
-246 190  14 246 190  14 246 190  14 246 190  14
-246 190  14 246 190  14 246 190  14 246 190  14
-246 190  14 246 190  14 241 196  14 226 184  13
- 61  42   6   2   2   6   2   2   6   2   2   6
- 22  22  22 238 238 238 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 226 226 226 187 187 187 180 133  36
-216 158  10 236 178  12 239 182  13 236 178  12
-230 174  11 226 170  11 226 170  11 230 174  11
-236 178  12 242 186  14 246 190  14 246 190  14
-246 190  14 246 190  14 246 186  14 239 182  13
-206 162  42 106 106 106  66  66  66  34  34  34
- 14  14  14   6   6   6   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   6   6   6
- 26  26  26  70  70  70 163 133  67 213 154  11
-236 178  12 246 190  14 246 190  14 246 190  14
-246 190  14 246 190  14 246 190  14 246 190  14
-246 190  14 246 190  14 246 190  14 246 190  14
-246 190  14 246 190  14 246 190  14 241 196  14
-190 146  13  18  14   6   2   2   6   2   2   6
- 46  46  46 246 246 246 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 221 221 221  86  86  86 156 107  11
-216 158  10 236 178  12 242 186  14 246 186  14
-242 186  14 239 182  13 239 182  13 242 186  14
-242 186  14 246 186  14 246 190  14 246 190  14
-246 190  14 246 190  14 246 190  14 246 190  14
-242 186  14 225 175  15 142 122  72  66  66  66
- 30  30  30  10  10  10   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   6   6   6
- 26  26  26  70  70  70 163 133  67 210 150  10
-236 178  12 246 190  14 246 190  14 246 190  14
-246 190  14 246 190  14 246 190  14 246 190  14
-246 190  14 246 190  14 246 190  14 246 190  14
-246 190  14 246 190  14 246 190  14 246 190  14
-232 195  16 121  92   8  34  34  34 106 106 106
-221 221 221 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-242 242 242  82  82  82  18  14   6 163 110   8
-216 158  10 236 178  12 242 186  14 246 190  14
-246 190  14 246 190  14 246 190  14 246 190  14
-246 190  14 246 190  14 246 190  14 246 190  14
-246 190  14 246 190  14 246 190  14 246 190  14
-246 190  14 246 190  14 242 186  14 163 133  67
- 46  46  46  18  18  18   6   6   6   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0  10  10  10
- 30  30  30  78  78  78 163 133  67 210 150  10
-236 178  12 246 186  14 246 190  14 246 190  14
-246 190  14 246 190  14 246 190  14 246 190  14
-246 190  14 246 190  14 246 190  14 246 190  14
-246 190  14 246 190  14 246 190  14 246 190  14
-241 196  14 215 174  15 190 178 144 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 218 218 218
- 58  58  58   2   2   6  22  18   6 167 114   7
-216 158  10 236 178  12 246 186  14 246 190  14
-246 190  14 246 190  14 246 190  14 246 190  14
-246 190  14 246 190  14 246 190  14 246 190  14
-246 190  14 246 190  14 246 190  14 246 190  14
-246 190  14 246 186  14 242 186  14 190 150  46
- 54  54  54  22  22  22   6   6   6   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0  14  14  14
- 38  38  38  86  86  86 180 133  36 213 154  11
-236 178  12 246 186  14 246 190  14 246 190  14
-246 190  14 246 190  14 246 190  14 246 190  14
-246 190  14 246 190  14 246 190  14 246 190  14
-246 190  14 246 190  14 246 190  14 246 190  14
-246 190  14 232 195  16 190 146  13 214 214 214
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 250 250 250 170 170 170  26  26  26
-  2   2   6   2   2   6  37  26   9 163 110   8
-219 162  10 239 182  13 246 186  14 246 190  14
-246 190  14 246 190  14 246 190  14 246 190  14
-246 190  14 246 190  14 246 190  14 246 190  14
-246 190  14 246 190  14 246 190  14 246 190  14
-246 186  14 236 178  12 224 166  10 142 122  72
- 46  46  46  18  18  18   6   6   6   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   6   6   6  18  18  18
- 50  50  50 109 106  95 192 133   9 224 166  10
-242 186  14 246 190  14 246 190  14 246 190  14
-246 190  14 246 190  14 246 190  14 246 190  14
-246 190  14 246 190  14 246 190  14 246 190  14
-246 190  14 246 190  14 246 190  14 246 190  14
-242 186  14 226 184  13 210 162  10 142 110  46
-226 226 226 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-253 253 253 253 253 253 253 253 253 253 253 253
-198 198 198  66  66  66   2   2   6   2   2   6
-  2   2   6   2   2   6  50  34   6 156 107  11
-219 162  10 239 182  13 246 186  14 246 190  14
-246 190  14 246 190  14 246 190  14 246 190  14
-246 190  14 246 190  14 246 190  14 246 190  14
-246 190  14 246 190  14 246 190  14 242 186  14
-234 174  13 213 154  11 154 122  46  66  66  66
- 30  30  30  10  10  10   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   6   6   6  22  22  22
- 58  58  58 154 121  60 206 145  10 234 174  13
-242 186  14 246 186  14 246 190  14 246 190  14
-246 190  14 246 190  14 246 190  14 246 190  14
-246 190  14 246 190  14 246 190  14 246 190  14
-246 190  14 246 190  14 246 190  14 246 190  14
-246 186  14 236 178  12 210 162  10 163 110   8
- 61  42   6 138 138 138 218 218 218 250 250 250
-253 253 253 253 253 253 253 253 253 250 250 250
-242 242 242 210 210 210 144 144 144  66  66  66
-  6   6   6   2   2   6   2   2   6   2   2   6
-  2   2   6   2   2   6  61  42   6 163 110   8
-216 158  10 236 178  12 246 190  14 246 190  14
-246 190  14 246 190  14 246 190  14 246 190  14
-246 190  14 246 190  14 246 190  14 246 190  14
-246 190  14 239 182  13 230 174  11 216 158  10
-190 142  34 124 112  88  70  70  70  38  38  38
- 18  18  18   6   6   6   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   6   6   6  22  22  22
- 62  62  62 168 124  44 206 145  10 224 166  10
-236 178  12 239 182  13 242 186  14 242 186  14
-246 186  14 246 190  14 246 190  14 246 190  14
-246 190  14 246 190  14 246 190  14 246 190  14
-246 190  14 246 190  14 246 190  14 246 190  14
-246 190  14 236 178  12 216 158  10 175 118   6
- 80  54   7   2   2   6   6   6   6  30  30  30
- 54  54  54  62  62  62  50  50  50  38  38  38
- 14  14  14   2   2   6   2   2   6   2   2   6
-  2   2   6   2   2   6   2   2   6   2   2   6
-  2   2   6   6   6   6  80  54   7 167 114   7
-213 154  11 236 178  12 246 190  14 246 190  14
-246 190  14 246 190  14 246 190  14 246 190  14
-246 190  14 242 186  14 239 182  13 239 182  13
-230 174  11 210 150  10 174 135  50 124 112  88
- 82  82  82  54  54  54  34  34  34  18  18  18
-  6   6   6   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   6   6   6  18  18  18
- 50  50  50 158 118  36 192 133   9 200 144  11
-216 158  10 219 162  10 224 166  10 226 170  11
-230 174  11 236 178  12 239 182  13 239 182  13
-242 186  14 246 186  14 246 190  14 246 190  14
-246 190  14 246 190  14 246 190  14 246 190  14
-246 186  14 230 174  11 210 150  10 163 110   8
-104  69   6  10  10  10   2   2   6   2   2   6
-  2   2   6   2   2   6   2   2   6   2   2   6
-  2   2   6   2   2   6   2   2   6   2   2   6
-  2   2   6   2   2   6   2   2   6   2   2   6
-  2   2   6   6   6   6  91  60   6 167 114   7
-206 145  10 230 174  11 242 186  14 246 190  14
-246 190  14 246 190  14 246 186  14 242 186  14
-239 182  13 230 174  11 224 166  10 213 154  11
-180 133  36 124 112  88  86  86  86  58  58  58
- 38  38  38  22  22  22  10  10  10   6   6   6
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0  14  14  14
- 34  34  34  70  70  70 138 110  50 158 118  36
-167 114   7 180 123   7 192 133   9 197 138  11
-200 144  11 206 145  10 213 154  11 219 162  10
-224 166  10 230 174  11 239 182  13 242 186  14
-246 186  14 246 186  14 246 186  14 246 186  14
-239 182  13 216 158  10 185 133  11 152  99   6
-104  69   6  18  14   6   2   2   6   2   2   6
-  2   2   6   2   2   6   2   2   6   2   2   6
-  2   2   6   2   2   6   2   2   6   2   2   6
-  2   2   6   2   2   6   2   2   6   2   2   6
-  2   2   6   6   6   6  80  54   7 152  99   6
-192 133   9 219 162  10 236 178  12 239 182  13
-246 186  14 242 186  14 239 182  13 236 178  12
-224 166  10 206 145  10 192 133   9 154 121  60
- 94  94  94  62  62  62  42  42  42  22  22  22
- 14  14  14   6   6   6   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   6   6   6
- 18  18  18  34  34  34  58  58  58  78  78  78
-101  98  89 124 112  88 142 110  46 156 107  11
-163 110   8 167 114   7 175 118   6 180 123   7
-185 133  11 197 138  11 210 150  10 219 162  10
-226 170  11 236 178  12 236 178  12 234 174  13
-219 162  10 197 138  11 163 110   8 130  83   6
- 91  60   6  10  10  10   2   2   6   2   2   6
- 18  18  18  38  38  38  38  38  38  38  38  38
- 38  38  38  38  38  38  38  38  38  38  38  38
- 38  38  38  38  38  38  26  26  26   2   2   6
-  2   2   6   6   6   6  70  47   6 137  92   6
-175 118   6 200 144  11 219 162  10 230 174  11
-234 174  13 230 174  11 219 162  10 210 150  10
-192 133   9 163 110   8 124 112  88  82  82  82
- 50  50  50  30  30  30  14  14  14   6   6   6
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  6   6   6  14  14  14  22  22  22  34  34  34
- 42  42  42  58  58  58  74  74  74  86  86  86
-101  98  89 122 102  70 130  98  46 121  87  25
-137  92   6 152  99   6 163 110   8 180 123   7
-185 133  11 197 138  11 206 145  10 200 144  11
-180 123   7 156 107  11 130  83   6 104  69   6
- 50  34   6  54  54  54 110 110 110 101  98  89
- 86  86  86  82  82  82  78  78  78  78  78  78
- 78  78  78  78  78  78  78  78  78  78  78  78
- 78  78  78  82  82  82  86  86  86  94  94  94
-106 106 106 101 101 101  86  66  34 124  80   6
-156 107  11 180 123   7 192 133   9 200 144  11
-206 145  10 200 144  11 192 133   9 175 118   6
-139 102  15 109 106  95  70  70  70  42  42  42
- 22  22  22  10  10  10   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   6   6   6  10  10  10
- 14  14  14  22  22  22  30  30  30  38  38  38
- 50  50  50  62  62  62  74  74  74  90  90  90
-101  98  89 112 100  78 121  87  25 124  80   6
-137  92   6 152  99   6 152  99   6 152  99   6
-138  86   6 124  80   6  98  70   6  86  66  30
-101  98  89  82  82  82  58  58  58  46  46  46
- 38  38  38  34  34  34  34  34  34  34  34  34
- 34  34  34  34  34  34  34  34  34  34  34  34
- 34  34  34  34  34  34  38  38  38  42  42  42
- 54  54  54  82  82  82  94  86  76  91  60   6
-134  86   6 156 107  11 167 114   7 175 118   6
-175 118   6 167 114   7 152  99   6 121  87  25
-101  98  89  62  62  62  34  34  34  18  18  18
-  6   6   6   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   6   6   6   6   6   6  10  10  10
- 18  18  18  22  22  22  30  30  30  42  42  42
- 50  50  50  66  66  66  86  86  86 101  98  89
-106  86  58  98  70   6 104  69   6 104  69   6
-104  69   6  91  60   6  82  62  34  90  90  90
- 62  62  62  38  38  38  22  22  22  14  14  14
- 10  10  10  10  10  10  10  10  10  10  10  10
- 10  10  10  10  10  10   6   6   6  10  10  10
- 10  10  10  10  10  10  10  10  10  14  14  14
- 22  22  22  42  42  42  70  70  70  89  81  66
- 80  54   7 104  69   6 124  80   6 137  92   6
-134  86   6 116  81   8 100  82  52  86  86  86
- 58  58  58  30  30  30  14  14  14   6   6   6
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   6   6   6  10  10  10  14  14  14
- 18  18  18  26  26  26  38  38  38  54  54  54
- 70  70  70  86  86  86  94  86  76  89  81  66
- 89  81  66  86  86  86  74  74  74  50  50  50
- 30  30  30  14  14  14   6   6   6   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  6   6   6  18  18  18  34  34  34  58  58  58
- 82  82  82  89  81  66  89  81  66  89  81  66
- 94  86  66  94  86  76  74  74  74  50  50  50
- 26  26  26  14  14  14   6   6   6   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  6   6   6   6   6   6  14  14  14  18  18  18
- 30  30  30  38  38  38  46  46  46  54  54  54
- 50  50  50  42  42  42  30  30  30  18  18  18
- 10  10  10   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   6   6   6  14  14  14  26  26  26
- 38  38  38  50  50  50  58  58  58  58  58  58
- 54  54  54  42  42  42  30  30  30  18  18  18
- 10  10  10   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   6   6   6
-  6   6   6  10  10  10  14  14  14  18  18  18
- 18  18  18  14  14  14  10  10  10   6   6   6
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   6   6   6
- 14  14  14  18  18  18  22  22  22  22  22  22
- 18  18  18  14  14  14  10  10  10   6   6   6
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
-  0   0   0   0   0   0   0   0   0   0   0   0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 11 15 17 33 49 54 59 85 92 73 97 106 
+83 116 129 105 131 142 115 114 122 74 88 93 20 29 31 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 6 6 6 6 6 6 10 10 10 10 10 10 
+10 10 10 6 6 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 2 3 3 17 23 26 50 67 72 73 97 106 59 85 92 73 97 106 
+105 131 142 124 127 131 105 131 142 105 131 142 53 75 83 6 8 8 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 6 6 6 10 10 10 14 14 14 22 22 22 26 26 26 30 30 30 34 34 34 
+30 30 30 30 30 30 26 26 26 18 18 18 14 14 14 10 10 10 6 6 6 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 0 0 0 
+0 0 0 1 1 1 26 35 39 59 85 92 59 85 92 59 85 92 29 43 47 53 75 83 
+108 122 132 132 98 104 108 122 132 105 131 142 101 101 101 43 45 48 6 8 8 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+6 6 6 14 14 14 26 26 26 42 42 42 54 54 54 66 66 66 78 78 78 78 78 78 
+78 78 78 74 74 74 66 66 66 54 54 54 42 42 42 26 26 26 18 18 18 10 10 10 
+6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+
+0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 
+11 15 17 27 40 45 59 85 92 59 85 92 27 40 45 31 45 49 73 97 106 93 121 133 
+108 122 132 108 122 132 105 131 142 108 122 132 105 131 142 73 97 106 26 35 39 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 10 10 
+22 22 22 42 42 42 66 66 66 86 86 86 66 66 66 38 38 38 38 38 38 22 22 22 
+26 26 26 34 34 34 54 54 54 66 66 66 86 86 86 70 70 70 46 46 46 26 26 26 
+14 14 14 6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+
+0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 7 12 13 21 31 35 42 59 64 
+53 75 83 53 75 83 50 67 72 42 59 64 32 40 45 42 59 64 73 97 106 116 116 116 
+132 98 104 116 116 116 108 122 132 117 104 110 105 131 142 83 116 129 50 67 72 7 12 13 
+1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 10 10 26 26 26 
+50 50 50 82 82 82 58 58 58 6 6 6 2 2 6 2 2 6 2 2 6 2 2 6 
+2 2 6 2 2 6 2 2 6 2 2 6 6 6 6 54 54 54 86 86 86 66 66 66 
+38 38 38 18 18 18 6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+
+0 0 0 1 1 1 6 8 8 15 22 25 26 35 39 36 54 60 53 75 83 59 85 92 
+59 85 92 48 63 69 15 22 25 12 17 20 52 67 79 94 94 94 132 98 104 132 98 104 
+117 104 110 108 122 132 108 122 132 115 114 122 105 131 142 77 105 114 59 85 92 36 54 60 
+7 12 13 0 0 0 0 0 0 0 0 0 0 0 0 6 6 6 22 22 22 50 50 50 
+78 78 78 34 34 34 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 
+2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 6 6 6 70 70 70 
+78 78 78 46 46 46 22 22 22 6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+
+0 0 0 15 22 25 29 43 47 36 54 60 42 59 64 42 59 64 48 63 69 21 31 35 
+6 8 8 29 43 47 36 50 56 43 45 48 79 78 84 132 98 104 165 78 79 132 98 104 
+108 122 132 117 104 110 117 104 110 108 122 132 77 105 114 73 97 106 95 131 149 78 102 129 
+36 50 56 0 0 0 0 0 0 0 0 0 6 6 6 18 18 18 42 42 42 82 82 82 
+26 26 26 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 
+2 2 6 2 2 6 2 2 6 14 14 14 46 46 46 34 34 34 6 6 6 2 2 6 
+42 42 42 78 78 78 42 42 42 18 18 18 6 6 6 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+
+27 40 45 53 75 83 48 63 69 24 31 37 6 8 12 0 0 0 18 25 28 26 35 39 
+12 17 20 26 35 39 65 78 84 112 81 86 152 81 83 137 83 86 132 98 104 117 104 110 
+117 104 110 132 98 104 132 98 104 115 114 122 73 97 106 53 75 83 95 131 149 93 124 152 
+68 78 128 15 22 25 0 0 0 0 0 0 10 10 10 30 30 30 66 66 66 58 58 58 
+2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 
+2 2 6 2 2 6 2 2 6 26 26 26 86 86 86 101 101 101 46 46 46 10 10 10 
+2 2 6 58 58 58 70 70 70 34 34 34 10 10 10 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+
+36 50 56 21 30 33 4 7 7 0 0 0 1 1 1 17 12 12 69 31 31 68 59 64 
+57 59 63 21 31 35 32 40 45 86 73 69 152 81 83 152 81 83 117 104 110 132 98 104 
+152 81 83 132 98 104 108 122 132 77 105 114 77 105 114 93 121 133 95 131 149 93 124 152 
+95 131 149 53 75 83 11 15 17 0 0 0 14 14 14 42 42 42 86 86 86 10 10 10 
+2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 
+2 2 6 2 2 6 2 2 6 30 30 30 94 94 94 94 94 94 58 58 58 26 26 26 
+2 2 6 6 6 6 78 78 78 54 54 54 22 22 22 6 6 6 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+
+17 23 26 2 3 3 0 0 0 17 12 12 69 31 31 123 55 55 123 55 55 152 81 83 
+86 73 69 17 23 26 7 12 13 45 54 57 101 101 101 137 83 86 132 98 104 132 98 104 
+137 83 86 117 104 110 77 105 114 42 59 64 50 67 72 78 102 129 91 117 157 91 117 157 
+95 131 149 83 116 129 40 48 73 6 6 6 22 22 22 62 62 62 62 62 62 2 2 6 
+2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 
+2 2 6 2 2 6 2 2 6 26 26 26 54 54 54 38 38 38 18 18 18 10 10 10 
+2 2 6 2 2 6 34 34 34 82 82 82 38 38 38 14 14 14 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+
+1 1 1 1 2 2 2 3 3 28 12 12 123 55 55 174 79 79 174 79 79 174 79 79 
+152 81 83 68 59 64 26 35 39 27 40 45 79 78 84 137 83 86 165 78 79 137 83 86 
+94 94 94 48 63 69 36 50 56 50 67 72 73 97 106 93 121 133 93 124 152 93 124 152 
+95 131 149 91 118 149 78 102 129 27 40 45 30 30 30 78 78 78 30 30 30 2 2 6 
+2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 
+2 2 6 2 2 6 2 2 6 10 10 10 10 10 10 2 2 6 2 2 6 2 2 6 
+2 2 6 2 2 6 2 2 6 78 78 78 50 50 50 18 18 18 6 6 6 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+
+4 5 3 24 53 24 19 31 15 8 7 3 90 61 47 165 78 79 174 79 79 174 79 79 
+174 79 79 137 83 86 60 52 57 7 12 13 17 23 26 70 70 70 132 98 104 112 81 86 
+79 78 84 31 45 49 15 22 25 53 75 83 91 118 149 86 106 160 91 117 157 93 124 152 
+91 117 157 93 124 152 95 131 149 53 75 83 50 50 50 86 86 86 14 14 14 2 2 6 
+2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 
+2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 
+2 2 6 2 2 6 2 2 6 54 54 54 66 66 66 26 26 26 6 6 6 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+
+19 31 15 34 76 34 34 76 34 19 31 15 28 12 12 123 55 55 174 79 79 174 79 79 
+174 79 79 165 78 79 112 81 86 32 40 45 15 22 25 38 53 58 65 78 84 29 31 32 
+21 30 33 42 59 64 60 80 103 78 102 129 87 112 149 84 96 162 91 117 157 93 124 152 
+91 117 157 93 124 152 93 121 133 59 85 92 57 68 71 82 85 86 2 2 6 2 2 6 
+2 2 6 6 6 6 10 10 10 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 
+2 2 6 2 2 6 2 2 6 6 6 6 14 14 14 10 10 10 2 2 6 2 2 6 
+2 2 6 2 2 6 2 2 6 18 18 18 82 82 82 34 34 34 10 10 10 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+
+34 76 34 40 89 40 40 89 40 34 76 34 8 15 6 48 26 18 123 55 55 174 79 79 
+174 79 79 174 79 79 137 83 86 68 59 64 32 40 45 21 30 33 31 45 49 21 31 35 
+12 17 20 48 63 69 78 102 129 81 88 166 84 96 162 91 117 157 93 124 152 91 117 157 
+93 124 152 95 131 149 83 116 129 59 85 92 57 68 71 86 86 86 2 2 6 2 2 6 
+6 6 6 6 6 6 22 22 22 34 34 34 6 6 6 2 2 6 2 2 6 2 2 6 
+2 2 6 2 2 6 18 18 18 34 34 34 10 10 10 50 50 50 22 22 22 2 2 6 
+2 2 6 2 2 6 2 2 6 10 10 10 86 86 86 42 42 42 14 14 14 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+
+40 89 40 40 89 40 40 89 40 40 89 40 24 53 24 6 6 6 69 31 31 123 55 55 
+123 55 55 90 61 47 69 31 31 36 32 33 21 31 35 7 12 13 18 25 28 48 63 69 
+60 80 103 68 78 128 84 101 153 84 96 162 84 96 162 91 117 157 91 117 157 84 96 162 
+91 117 157 73 97 106 48 63 69 50 67 72 57 59 63 86 86 86 2 2 6 2 2 6 
+38 38 38 116 116 116 94 94 94 22 22 22 22 22 22 2 2 6 2 2 6 2 2 6 
+14 14 14 86 86 86 124 131 137 170 170 170 151 151 151 38 38 38 26 26 26 6 6 6 
+2 2 6 2 2 6 2 2 6 2 2 6 86 86 86 46 46 46 14 14 14 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+
+34 76 34 40 89 40 40 89 40 40 89 40 34 76 34 19 31 15 17 12 12 48 26 18 
+48 26 18 8 7 3 10 10 22 23 29 47 51 61 92 42 59 64 21 30 33 34 45 54 
+68 78 128 81 88 166 81 82 173 86 106 160 86 106 160 84 96 162 86 106 160 87 112 149 
+91 118 149 77 105 114 52 67 79 32 40 45 50 50 50 86 86 86 2 2 6 14 14 14 
+124 131 137 198 198 198 195 195 195 116 116 116 10 10 10 2 2 6 2 2 6 6 6 6 
+101 98 89 187 187 187 210 210 210 218 218 218 214 214 214 124 131 137 14 14 14 6 6 6 
+2 2 6 2 2 6 2 2 6 2 2 6 86 86 86 50 50 50 18 18 18 6 6 6 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+
+19 31 15 34 76 34 40 89 40 40 89 40 40 89 40 24 53 24 8 7 3 0 0 0 
+6 8 12 28 32 52 51 61 92 54 54 122 74 77 160 68 78 128 26 35 39 6 8 8 
+34 45 54 68 78 128 84 96 162 86 106 160 86 106 160 81 88 166 84 96 162 87 112 149 
+73 97 106 36 50 56 33 49 54 18 18 18 46 46 46 86 86 86 2 2 6 54 54 54 
+218 218 218 195 195 195 226 226 226 246 246 246 58 58 58 2 2 6 2 2 6 30 30 30 
+210 210 210 253 253 253 170 170 170 124 127 131 221 221 221 234 234 234 74 74 74 2 2 6 
+2 2 6 2 2 6 2 2 6 2 2 6 70 70 70 58 58 58 22 22 22 6 6 6 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+
+4 5 3 24 53 24 40 89 40 40 89 40 34 76 34 12 22 15 4 5 3 4 5 3 
+13 17 26 54 54 122 78 78 174 78 78 174 78 78 174 74 77 160 51 61 92 21 31 35 
+26 35 39 53 75 83 84 101 153 81 82 173 81 88 166 84 101 153 60 80 103 60 80 103 
+53 75 83 38 53 58 42 59 64 22 22 22 46 46 46 82 82 82 2 2 6 106 106 106 
+170 170 170 26 26 26 86 86 86 226 226 226 124 127 131 10 10 10 14 14 14 46 46 46 
+231 231 231 190 190 190 6 6 6 70 70 70 90 90 90 238 238 238 151 151 151 2 2 6 
+2 2 6 2 2 6 2 2 6 2 2 6 70 70 70 58 58 58 22 22 22 6 6 6 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+
+1 2 2 8 15 6 24 53 24 34 76 34 19 31 15 8 15 6 63 55 20 63 55 20 
+18 18 18 40 48 73 74 77 160 78 78 174 78 78 174 81 82 173 74 77 160 52 67 79 
+17 23 26 21 31 35 60 80 103 81 88 166 74 77 160 78 102 129 36 54 60 12 17 20 
+42 59 64 48 63 69 21 31 35 18 18 18 42 42 42 86 86 86 6 6 6 116 116 116 
+106 106 106 6 6 6 70 70 70 151 151 151 124 127 131 18 18 18 38 38 38 54 54 54 
+221 221 221 106 106 106 2 2 6 14 14 14 46 46 46 190 190 190 198 198 198 2 2 6 
+2 2 6 2 2 6 2 2 6 2 2 6 74 74 74 62 62 62 22 22 22 6 6 6 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+
+11 15 17 0 0 0 12 22 15 19 31 15 8 15 6 63 55 20 149 139 69 149 139 69 
+63 55 20 10 10 22 54 54 122 78 78 174 78 78 174 78 78 174 81 82 173 68 78 128 
+24 31 37 6 6 6 36 50 56 60 80 103 51 61 92 42 59 64 36 50 56 31 45 49 
+29 43 47 27 40 45 6 8 8 14 14 14 42 42 42 94 94 94 14 14 14 101 101 101 
+124 127 131 2 2 6 18 18 18 116 116 116 106 107 48 121 92 8 121 92 8 98 70 6 
+170 170 170 106 106 106 2 2 6 2 2 6 2 2 6 195 195 195 195 195 195 6 6 6 
+2 2 6 2 2 6 2 2 6 2 2 6 74 74 74 62 62 62 22 22 22 6 6 6 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+
+26 35 39 3 5 6 1 1 1 2 3 3 35 31 12 133 118 54 175 176 80 175 176 80 
+133 118 54 35 31 12 23 29 47 54 54 122 78 78 174 78 78 174 74 77 160 68 78 128 
+51 61 92 31 45 49 26 35 39 36 50 56 29 43 47 7 12 13 21 30 33 42 59 64 
+18 25 28 7 12 13 1 1 1 10 10 10 38 38 38 90 90 90 14 14 14 58 58 58 
+210 210 210 26 26 26 62 42 6 154 114 10 226 170 11 237 188 10 220 174 15 184 138 11 
+220 174 15 174 140 55 35 31 12 2 2 6 70 70 70 246 246 246 124 131 137 2 2 6 
+2 2 6 2 2 6 2 2 6 2 2 6 70 70 70 66 66 66 26 26 26 6 6 6 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+
+27 40 45 17 23 26 2 3 3 1 1 1 56 77 35 165 152 80 175 176 80 175 176 80 
+175 176 80 106 107 48 22 22 22 28 32 52 54 54 122 54 54 122 51 61 92 28 32 52 
+20 27 34 31 45 49 11 15 17 7 12 13 36 50 56 31 45 49 29 43 47 36 50 56 
+6 8 8 0 0 0 0 0 0 10 10 10 38 38 38 86 86 86 14 14 14 10 10 10 
+195 195 195 198 179 130 192 133 9 220 174 15 239 182 13 237 188 10 232 195 16 239 207 25 
+237 201 50 241 208 19 232 195 16 184 138 11 198 179 130 208 206 196 42 42 42 2 2 6 
+2 2 6 2 2 6 2 2 6 2 2 6 50 50 50 74 74 74 30 30 30 6 6 6 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+
+15 22 25 26 35 39 15 22 25 0 0 0 35 31 12 133 118 54 175 176 80 175 176 80 
+175 176 80 165 152 80 56 77 35 6 8 12 23 29 47 13 17 26 2 2 6 0 0 0 
+1 2 2 26 35 39 26 35 39 26 35 39 42 59 64 42 59 64 20 29 31 6 8 8 
+0 0 0 0 0 0 0 0 0 10 10 10 34 34 34 86 86 86 14 14 14 2 2 6 
+121 92 8 192 133 9 219 162 10 239 182 13 237 188 10 232 195 16 241 208 19 237 201 50 
+237 201 50 239 207 25 241 208 19 241 208 19 241 208 19 230 187 11 121 92 8 2 2 6 
+2 2 6 2 2 6 2 2 6 2 2 6 50 50 50 82 82 82 34 34 34 10 10 10 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+
+1 2 2 15 22 25 31 45 49 6 8 12 4 5 3 63 55 20 149 139 69 175 176 80 
+175 176 80 175 176 80 106 107 48 20 16 6 1 1 1 0 0 0 2 3 3 11 15 17 
+21 30 33 36 50 56 36 50 56 24 31 37 15 22 25 6 8 8 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 10 10 10 34 34 34 82 82 82 30 30 30 62 42 6 
+180 123 7 206 145 10 230 174 11 239 182 13 237 188 10 238 202 15 241 208 19 237 201 50 
+239 207 25 241 208 19 241 208 19 241 208 19 230 187 11 220 174 15 184 138 11 6 6 6 
+2 2 6 2 2 6 2 2 6 2 2 6 26 26 26 94 94 94 42 42 42 14 14 14 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+
+0 0 0 1 2 2 29 43 47 26 35 39 3 5 6 8 7 3 106 107 48 165 152 80 
+175 176 80 149 139 69 63 55 20 4 5 3 2 3 3 12 17 20 26 35 39 26 35 39 
+17 23 26 7 12 13 6 8 8 3 5 6 1 2 2 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 10 10 10 30 30 30 78 78 78 50 50 50 104 69 6 
+192 133 9 216 158 10 236 178 12 237 188 10 232 195 16 241 208 19 237 201 50 237 201 50 
+241 208 19 241 208 19 241 208 19 204 160 10 200 144 11 216 158 10 156 118 10 2 2 6 
+2 2 6 2 2 6 2 2 6 2 2 6 6 6 6 90 90 90 54 54 54 18 18 18 
+6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+
+0 0 0 0 0 0 12 17 20 27 40 45 18 25 28 1 1 1 35 31 12 106 107 48 
+149 139 69 56 77 35 8 7 3 1 2 2 12 17 20 26 35 39 21 31 35 11 15 17 
+3 5 6 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 10 10 10 30 30 30 78 78 78 46 46 46 22 22 22 
+137 92 6 204 160 10 239 182 13 237 188 10 238 202 15 241 208 19 241 208 19 241 208 19 
+241 208 19 204 160 10 184 138 11 210 150 10 216 158 10 210 150 10 98 70 6 2 2 6 
+6 6 6 54 54 54 14 14 14 2 2 6 2 2 6 62 62 62 74 74 74 30 30 30 
+10 10 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+
+0 0 0 0 0 0 1 1 1 15 22 25 33 49 54 12 17 20 2 3 3 35 31 12 
+56 77 35 20 16 6 1 1 1 18 25 28 21 31 35 11 15 17 1 1 1 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 10 10 10 34 34 34 78 78 78 50 50 50 6 6 6 
+88 55 22 139 102 15 190 146 13 230 187 11 239 207 25 232 195 16 220 174 15 190 146 13 
+171 120 8 192 133 9 210 150 10 213 154 11 185 146 40 165 152 80 101 98 89 2 2 6 
+2 2 6 78 78 78 116 116 116 58 58 58 2 2 6 22 22 22 90 90 90 46 46 46 
+18 18 18 6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+
+0 0 0 0 0 0 0 0 0 1 1 1 27 40 45 29 43 47 3 5 6 2 3 3 
+8 7 3 1 1 1 17 23 26 31 45 49 15 22 25 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 10 10 10 38 38 38 86 86 86 50 50 50 6 6 6 
+124 127 131 168 158 138 156 107 11 171 120 8 204 160 10 184 138 11 197 138 11 200 144 11 
+206 145 10 206 145 10 197 138 11 198 179 130 195 195 195 198 198 198 170 170 170 14 14 14 
+2 2 6 22 22 22 116 116 116 116 116 116 22 22 22 2 2 6 74 74 74 70 70 70 
+30 30 30 10 10 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+
+0 0 0 0 0 0 0 0 0 0 0 0 11 15 17 31 45 49 26 35 39 3 5 6 
+0 0 0 7 12 13 27 40 45 18 25 28 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 6 6 6 18 18 18 50 50 50 101 101 101 26 26 26 10 10 10 
+124 131 137 190 190 190 168 158 138 156 107 11 197 138 11 200 144 11 197 138 11 192 133 9 
+180 123 7 185 146 40 198 179 130 187 187 187 202 202 202 221 221 221 214 214 214 66 66 66 
+2 2 6 2 2 6 50 50 50 62 62 62 6 6 6 2 2 6 10 10 10 90 90 90 
+50 50 50 18 18 18 6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+
+0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 15 22 25 36 54 60 18 25 28 
+0 0 0 21 30 33 27 40 45 2 3 3 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 10 10 10 34 34 34 74 74 74 74 74 74 2 2 6 6 6 6 
+151 151 151 198 198 198 190 190 190 168 158 138 148 132 55 156 107 11 156 107 11 169 125 40 
+168 158 138 187 187 187 190 190 190 210 210 210 246 246 246 253 253 253 253 253 253 180 180 180 
+6 6 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 62 62 62 
+74 74 74 34 34 34 14 14 14 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 27 40 45 35 52 58 
+18 25 28 35 52 58 17 23 26 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 10 10 10 22 22 22 54 54 54 94 94 94 18 18 18 2 2 6 46 46 46 
+234 234 234 221 221 221 190 190 190 190 190 190 190 190 190 187 187 187 187 187 187 190 190 190 
+190 190 190 195 195 195 214 214 214 242 242 242 253 253 253 253 253 253 253 253 253 253 253 253 
+82 82 82 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 14 14 14 
+86 86 86 54 54 54 22 22 22 6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 12 13 33 49 54 
+52 72 81 36 54 60 6 8 8 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+6 6 6 18 18 18 46 46 46 90 90 90 46 46 46 18 18 18 6 6 6 180 180 180 
+253 253 253 246 246 246 202 202 202 190 190 190 190 190 190 190 190 190 190 190 190 190 190 190 
+202 202 202 231 231 231 250 250 250 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
+202 202 202 14 14 14 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 
+42 42 42 86 86 86 42 42 42 18 18 18 6 6 6 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 12 17 20 
+36 54 60 29 43 47 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 6 6 
+14 14 14 38 38 38 74 74 74 66 66 66 2 2 6 6 6 6 90 90 90 250 250 250 
+253 253 253 253 253 253 238 238 238 198 198 198 190 190 190 190 190 190 195 195 195 221 221 221 
+246 246 246 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
+253 253 253 82 82 82 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 
+2 2 6 78 78 78 70 70 70 34 34 34 14 14 14 6 6 6 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+21 30 33 35 52 58 6 8 12 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 14 14 14 
+34 34 34 66 66 66 78 78 78 6 6 6 2 2 6 18 18 18 218 218 218 253 253 253 
+253 253 253 253 253 253 253 253 253 246 246 246 226 226 226 231 231 231 246 246 246 253 253 253 
+253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
+253 253 253 180 180 180 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 
+2 2 6 18 18 18 90 90 90 62 62 62 30 30 30 10 10 10 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+12 17 20 36 54 60 29 43 47 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 10 10 26 26 26 
+58 58 58 90 90 90 18 18 18 2 2 6 2 2 6 106 106 106 253 253 253 253 253 253 
+253 253 253 253 253 253 253 253 253 253 253 253 250 250 250 253 253 253 253 253 253 253 253 253 
+253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
+253 253 253 231 231 231 18 18 18 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 
+2 2 6 2 2 6 18 18 18 94 94 94 54 54 54 26 26 26 10 10 10 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 21 30 33 35 52 58 6 8 12 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 6 6 22 22 22 50 50 50 
+90 90 90 26 26 26 2 2 6 2 2 6 14 14 14 195 195 195 250 250 250 253 253 253 
+253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
+253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
+250 250 250 242 242 242 54 54 54 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 
+2 2 6 2 2 6 2 2 6 38 38 38 86 86 86 50 50 50 22 22 22 6 6 6 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 12 17 20 36 54 60 29 43 47 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 6 6 6 14 14 14 38 38 38 82 82 82 
+34 34 34 2 2 6 2 2 6 2 2 6 42 42 42 195 195 195 246 246 246 253 253 253 
+253 253 253 253 253 253 253 253 253 250 250 250 242 242 242 242 242 242 250 250 250 253 253 253 
+253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 250 250 250 246 246 246 238 238 238 
+226 226 226 231 231 231 101 101 101 6 6 6 2 2 6 2 2 6 2 2 6 2 2 6 
+2 2 6 2 2 6 2 2 6 2 2 6 38 38 38 82 82 82 42 42 42 14 14 14 
+6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 21 30 33 35 52 58 6 8 12 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 10 10 10 26 26 26 62 62 62 66 66 66 
+2 2 6 2 2 6 2 2 6 6 6 6 70 70 70 170 170 170 202 202 202 234 234 234 
+246 246 246 250 250 250 250 250 250 238 238 238 226 226 226 231 231 231 238 238 238 250 250 250 
+250 250 250 250 250 250 246 246 246 231 231 231 214 214 214 202 202 202 202 202 202 202 202 202 
+198 198 198 202 202 202 180 180 180 18 18 18 2 2 6 2 2 6 2 2 6 2 2 6 
+2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 62 62 62 66 66 66 30 30 30 
+10 10 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 12 17 20 36 54 60 29 43 47 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 14 14 14 42 42 42 82 82 82 18 18 18 
+2 2 6 2 2 6 2 2 6 10 10 10 94 94 94 180 180 180 218 218 218 242 242 242 
+250 250 250 253 253 253 253 253 253 250 250 250 234 234 234 253 253 253 253 253 253 253 253 253 
+253 253 253 253 253 253 253 253 253 246 246 246 238 238 238 226 226 226 210 210 210 202 202 202 
+195 195 195 195 195 195 210 210 210 151 151 151 6 6 6 14 14 14 50 50 50 14 14 14 
+2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 6 6 6 86 86 86 46 46 46 
+18 18 18 6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 21 30 33 35 52 58 6 8 12 0 0 0 
+0 0 0 0 0 0 0 0 0 6 6 6 22 22 22 54 54 54 70 70 70 2 2 6 
+2 2 6 10 10 10 2 2 6 22 22 22 170 170 170 231 231 231 250 250 250 253 253 253 
+253 253 253 253 253 253 253 253 253 250 250 250 242 242 242 253 253 253 253 253 253 253 253 253 
+253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 246 246 246 
+231 231 231 202 202 202 198 198 198 226 226 226 94 94 94 2 2 6 6 6 6 38 38 38 
+30 30 30 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 62 62 62 66 66 66 
+26 26 26 10 10 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 6 8 8 33 49 54 29 43 47 6 8 12 
+0 0 0 0 0 0 0 0 0 10 10 10 30 30 30 74 74 74 50 50 50 2 2 6 
+26 26 26 26 26 26 2 2 6 106 106 106 238 238 238 253 253 253 253 253 253 253 253 253 
+253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
+253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
+253 253 253 246 246 246 218 218 218 202 202 202 210 210 210 14 14 14 2 2 6 2 2 6 
+30 30 30 22 22 22 2 2 6 2 2 6 2 2 6 2 2 6 18 18 18 86 86 86 
+42 42 42 14 14 14 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 12 17 20 33 49 54 17 23 26 
+0 0 0 0 0 0 0 0 0 14 14 14 42 42 42 90 90 90 22 22 22 2 2 6 
+42 42 42 2 2 6 18 18 18 218 218 218 253 253 253 253 253 253 253 253 253 253 253 253 
+253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
+253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
+253 253 253 253 253 253 250 250 250 221 221 221 218 218 218 101 101 101 2 2 6 14 14 14 
+18 18 18 38 38 38 10 10 10 2 2 6 2 2 6 2 2 6 2 2 6 78 78 78 
+58 58 58 22 22 22 6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 15 22 25 36 54 60 
+0 0 0 0 0 0 0 0 0 18 18 18 54 54 54 82 82 82 2 2 6 26 26 26 
+22 22 22 2 2 6 124 127 131 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
+253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
+253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
+253 253 253 253 253 253 253 253 253 250 250 250 238 238 238 198 198 198 6 6 6 38 38 38 
+58 58 58 26 26 26 38 38 38 2 2 6 2 2 6 2 2 6 2 2 6 46 46 46 
+78 78 78 30 30 30 10 10 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 21 30 33 
+36 54 60 0 0 0 0 0 0 30 30 30 74 74 74 58 58 58 2 2 6 42 42 42 
+2 2 6 22 22 22 231 231 231 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
+253 253 253 253 253 253 253 253 253 250 250 250 253 253 253 253 253 253 253 253 253 253 253 253 
+253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
+253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 246 246 246 46 46 46 38 38 38 
+42 42 42 14 14 14 38 38 38 14 14 14 2 2 6 2 2 6 2 2 6 6 6 6 
+86 86 86 46 46 46 14 14 14 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+36 54 60 0 0 0 0 0 0 42 42 42 90 90 90 18 18 18 18 18 18 26 26 26 
+2 2 6 116 116 116 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
+253 253 253 253 253 253 250 250 250 238 238 238 253 253 253 253 253 253 253 253 253 253 253 253 
+253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
+253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 94 94 94 6 6 6 
+2 2 6 2 2 6 10 10 10 34 34 34 2 2 6 2 2 6 2 2 6 2 2 6 
+74 74 74 58 58 58 22 22 22 6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 36 54 60 26 26 26 66 66 66 82 82 82 2 2 6 38 38 38 6 6 6 
+14 14 14 210 210 210 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
+253 253 253 253 253 253 246 246 246 242 242 242 253 253 253 253 253 253 253 253 253 253 253 253 
+253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
+253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 151 151 151 2 2 6 
+2 2 6 2 2 6 2 2 6 46 46 46 2 2 6 2 2 6 2 2 6 2 2 6 
+42 42 42 74 74 74 30 30 30 10 10 10 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+6 6 6 36 54 60 21 30 33 90 90 90 26 26 26 6 6 6 42 42 42 2 2 6 
+74 74 74 250 250 250 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
+253 253 253 253 253 253 242 242 242 242 242 242 253 253 253 253 253 253 253 253 253 253 253 253 
+253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
+253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 180 180 180 2 2 6 
+2 2 6 2 2 6 2 2 6 46 46 46 2 2 6 2 2 6 2 2 6 2 2 6 
+10 10 10 86 86 86 38 38 38 10 10 10 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+10 10 10 26 26 26 36 54 60 82 82 82 2 2 6 22 22 22 18 18 18 2 2 6 
+151 151 151 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
+253 253 253 253 253 253 234 234 234 242 242 242 253 253 253 253 253 253 253 253 253 253 253 253 
+253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
+253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 202 202 202 2 2 6 
+2 2 6 2 2 6 2 2 6 38 38 38 2 2 6 2 2 6 2 2 6 2 2 6 
+6 6 6 86 86 86 46 46 46 14 14 14 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 6 6 
+18 18 18 46 46 46 86 86 86 36 54 60 2 2 6 34 34 34 10 10 10 6 6 6 
+210 210 210 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
+253 253 253 253 253 253 234 234 234 242 242 242 253 253 253 253 253 253 253 253 253 253 253 253 
+253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
+253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 221 221 221 6 6 6 
+2 2 6 2 2 6 6 6 6 30 30 30 2 2 6 2 2 6 2 2 6 2 2 6 
+2 2 6 82 82 82 54 54 54 18 18 18 6 6 6 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 10 10 
+26 26 26 66 66 66 62 62 62 2 2 6 2 2 6 38 38 38 10 10 10 26 26 26 
+238 238 238 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
+253 253 253 253 253 253 231 231 231 238 238 238 253 253 253 253 253 253 253 253 253 253 253 253 
+253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
+253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 231 231 231 6 6 6 
+2 2 6 2 2 6 10 10 10 30 30 30 2 2 6 2 2 6 2 2 6 2 2 6 
+2 2 6 66 66 66 58 58 58 22 22 22 6 6 6 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 10 10 
+38 38 38 78 78 78 6 6 6 2 2 6 2 2 6 46 46 46 14 14 14 42 42 42 
+246 246 246 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
+253 253 253 253 253 253 231 231 231 242 242 242 253 253 253 253 253 253 253 253 253 253 253 253 
+253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
+253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 234 234 234 10 10 10 
+2 2 6 2 2 6 22 22 22 14 14 14 2 2 6 2 2 6 2 2 6 2 2 6 
+2 2 6 66 66 66 62 62 62 22 22 22 6 6 6 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 6 6 18 18 18 
+50 50 50 74 74 74 2 2 6 2 2 6 14 14 14 70 70 70 34 34 34 62 62 62 
+250 250 250 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
+253 253 253 253 253 253 231 231 231 246 246 246 253 253 253 253 253 253 253 253 253 253 253 253 
+253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
+253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 234 234 234 14 14 14 
+2 2 6 2 2 6 30 30 30 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 
+2 2 6 66 66 66 62 62 62 22 22 22 6 6 6 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 6 6 18 18 18 
+54 54 54 62 62 62 2 2 6 2 2 6 2 2 6 30 30 30 46 46 46 70 70 70 
+250 250 250 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
+253 253 253 253 253 253 231 231 231 246 246 246 253 253 253 253 253 253 253 253 253 253 253 253 
+253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
+253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 226 226 226 10 10 10 
+2 2 6 6 6 6 30 30 30 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 
+2 2 6 66 66 66 58 58 58 22 22 22 6 6 6 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 6 6 22 22 22 
+58 58 58 62 62 62 2 2 6 2 2 6 2 2 6 2 2 6 30 30 30 78 78 78 
+250 250 250 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
+253 253 253 253 253 253 231 231 231 246 246 246 253 253 253 253 253 253 253 253 253 253 253 253 
+253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
+253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 202 202 202 2 2 6 
+22 22 22 34 34 34 20 16 6 22 22 22 26 26 26 18 18 18 6 6 6 2 2 6 
+2 2 6 82 82 82 54 54 54 18 18 18 6 6 6 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 6 6 26 26 26 
+62 62 62 106 106 106 63 55 20 184 138 11 204 160 10 121 92 8 6 6 6 62 62 62 
+238 238 238 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
+253 253 253 253 253 253 231 231 231 246 246 246 253 253 253 253 253 253 253 253 253 253 253 253 
+253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
+253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 151 151 151 18 18 18 
+14 14 14 2 2 6 2 2 6 2 2 6 6 6 6 18 18 18 66 66 66 38 38 38 
+6 6 6 94 94 94 50 50 50 18 18 18 6 6 6 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 6 6 6 10 10 10 10 10 10 18 18 18 38 38 38 
+78 78 78 138 132 106 216 158 10 242 186 14 246 190 14 246 190 14 156 118 10 10 10 10 
+90 90 90 238 238 238 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
+253 253 253 253 253 253 231 231 231 250 250 250 253 253 253 253 253 253 253 253 253 253 253 253 
+253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
+253 253 253 253 253 253 253 253 253 246 230 190 214 187 87 214 187 87 185 146 40 35 31 12 
+2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 38 38 38 46 46 46 
+26 26 26 106 106 106 54 54 54 18 18 18 6 6 6 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 6 6 6 14 14 14 22 22 22 30 30 30 38 38 38 50 50 50 70 70 70 
+106 106 106 185 146 40 226 170 11 242 186 14 246 190 14 246 190 14 246 190 14 154 114 10 
+6 6 6 74 74 74 226 226 226 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
+253 253 253 253 253 253 231 231 231 250 250 250 253 253 253 253 253 253 253 253 253 253 253 253 
+253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
+253 253 253 253 253 253 253 253 253 237 201 50 241 196 14 241 208 19 232 195 16 35 31 12 
+2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 6 6 6 30 30 30 26 26 26 
+204 160 10 165 152 80 66 66 66 26 26 26 6 6 6 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+6 6 6 18 18 18 38 38 38 58 58 58 78 78 78 86 86 86 101 101 101 124 127 131 
+174 140 55 210 150 10 234 174 13 246 186 14 246 190 14 246 190 14 246 190 14 237 188 10 
+98 70 6 2 2 6 46 46 46 198 198 198 253 253 253 253 253 253 253 253 253 253 253 253 
+253 253 253 253 253 253 234 234 234 242 242 242 253 253 253 253 253 253 253 253 253 253 253 253 
+253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
+253 253 253 253 253 253 253 253 253 214 187 87 242 186 14 241 196 14 204 160 10 20 16 6 
+2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 6 6 6 121 92 8 
+238 202 15 232 195 16 82 82 82 34 34 34 10 10 10 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+14 14 14 38 38 38 70 70 70 148 132 55 185 146 40 200 144 11 197 138 11 197 138 11 
+213 154 11 226 170 11 242 186 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 
+220 174 15 35 31 12 2 2 6 22 22 22 151 151 151 250 250 250 253 253 253 253 253 253 
+253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
+253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
+253 253 253 250 250 250 242 242 242 214 187 87 239 182 13 237 188 10 213 154 11 35 31 12 
+2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 62 42 6 220 174 15 
+237 188 10 237 188 10 113 101 86 42 42 42 14 14 14 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 6 6 
+22 22 22 54 54 54 148 132 55 213 154 11 226 170 11 230 174 11 226 170 11 226 170 11 
+236 178 12 242 186 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 
+241 196 14 184 138 11 10 10 10 2 2 6 6 6 6 116 116 116 242 242 242 253 253 253 
+253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
+253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
+253 253 253 231 231 231 198 198 198 213 164 39 236 178 12 236 178 12 210 150 10 137 92 6 
+20 16 6 2 2 6 2 2 6 2 2 6 6 6 6 62 42 6 200 144 11 236 178 12 
+239 182 13 239 182 13 124 112 88 58 58 58 22 22 22 6 6 6 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 10 10 
+30 30 30 70 70 70 169 125 40 226 170 11 239 182 13 242 186 14 242 186 14 246 186 14 
+246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 
+246 190 14 232 195 16 98 70 6 2 2 6 2 2 6 2 2 6 66 66 66 221 221 221 
+253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
+253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
+253 253 253 202 202 202 198 198 198 213 164 39 230 174 11 230 174 11 216 158 10 192 133 9 
+163 110 8 120 80 7 98 70 6 120 80 7 167 114 7 197 138 11 226 170 11 239 182 13 
+242 186 14 242 186 14 165 152 80 78 78 78 34 34 34 14 14 14 6 6 6 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 6 6 
+30 30 30 78 78 78 185 146 40 226 170 11 239 182 13 246 190 14 246 190 14 246 190 14 
+246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 
+246 190 14 241 196 14 204 160 10 20 16 6 2 2 6 2 2 6 2 2 6 38 38 38 
+218 218 218 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
+253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
+250 250 250 202 202 202 198 198 198 213 164 39 226 170 11 236 178 12 224 166 10 210 150 10 
+200 144 11 197 138 11 192 133 9 197 138 11 210 150 10 226 170 11 242 186 14 246 190 14 
+246 190 14 246 186 14 220 174 15 124 112 88 62 62 62 30 30 30 14 14 14 6 6 6 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 10 10 
+30 30 30 78 78 78 174 140 55 224 166 10 239 182 13 246 190 14 246 190 14 246 190 14 
+246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 
+246 190 14 246 190 14 241 196 14 139 102 15 2 2 6 2 2 6 2 2 6 2 2 6 
+78 78 78 250 250 250 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
+253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
+250 250 250 214 214 214 198 198 198 185 146 40 219 162 10 236 178 12 234 174 13 224 166 10 
+216 158 10 213 154 11 213 154 11 216 158 10 226 170 11 239 182 13 246 190 14 246 190 14 
+246 190 14 246 190 14 242 186 14 213 164 39 101 101 101 58 58 58 30 30 30 14 14 14 
+6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 10 10 
+30 30 30 74 74 74 174 140 55 216 158 10 236 178 12 246 190 14 246 190 14 246 190 14 
+246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 
+246 190 14 246 190 14 241 196 14 230 187 11 62 42 6 2 2 6 2 2 6 2 2 6 
+22 22 22 238 238 238 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
+253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
+253 253 253 226 226 226 187 187 187 169 125 40 216 158 10 236 178 12 239 182 13 236 178 12 
+230 174 11 226 170 11 226 170 11 230 174 11 236 178 12 242 186 14 246 190 14 246 190 14 
+246 190 14 246 190 14 246 186 14 239 182 13 213 164 39 106 106 106 66 66 66 34 34 34 
+14 14 14 6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 6 6 
+26 26 26 70 70 70 149 139 69 213 154 11 236 178 12 246 190 14 246 190 14 246 190 14 
+246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 
+246 190 14 246 190 14 246 190 14 241 196 14 190 146 13 20 16 6 2 2 6 2 2 6 
+46 46 46 246 246 246 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
+253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
+253 253 253 221 221 221 86 86 86 156 107 11 216 158 10 236 178 12 242 186 14 246 186 14 
+242 186 14 239 182 13 239 182 13 242 186 14 242 186 14 246 186 14 246 190 14 246 190 14 
+246 190 14 246 190 14 246 190 14 246 190 14 242 186 14 220 174 15 149 139 69 66 66 66 
+30 30 30 10 10 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 6 6 
+26 26 26 70 70 70 149 139 69 210 150 10 236 178 12 246 190 14 246 190 14 246 190 14 
+246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 
+246 190 14 246 190 14 246 190 14 246 190 14 232 195 16 121 92 8 34 34 34 106 106 106 
+221 221 221 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
+253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
+242 242 242 82 82 82 20 16 6 163 110 8 216 158 10 236 178 12 242 186 14 246 190 14 
+246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 
+246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 242 186 14 149 139 69 
+46 46 46 18 18 18 6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 10 10 
+30 30 30 78 78 78 149 139 69 210 150 10 236 178 12 246 186 14 246 190 14 246 190 14 
+246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 
+246 190 14 246 190 14 246 190 14 246 190 14 241 196 14 220 174 15 198 179 130 253 253 253 
+253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
+253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 218 218 218 
+58 58 58 2 2 6 20 16 6 167 114 7 216 158 10 236 178 12 246 186 14 246 190 14 
+246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 
+246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 186 14 242 186 14 185 146 40 
+54 54 54 22 22 22 6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 14 14 14 
+38 38 38 86 86 86 169 125 40 213 154 11 236 178 12 246 186 14 246 190 14 246 190 14 
+246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 
+246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 232 195 16 190 146 13 214 214 214 
+253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
+253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 250 250 250 170 170 170 26 26 26 
+2 2 6 2 2 6 35 31 12 163 110 8 219 162 10 239 182 13 246 186 14 246 190 14 
+246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 
+246 190 14 246 190 14 246 190 14 246 190 14 246 186 14 236 178 12 224 166 10 149 139 69 
+46 46 46 18 18 18 6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 6 6 18 18 18 
+50 50 50 113 101 86 192 133 9 224 166 10 242 186 14 246 190 14 246 190 14 246 190 14 
+246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 
+246 190 14 246 190 14 246 190 14 246 190 14 242 186 14 230 187 11 204 160 10 133 118 54 
+226 226 226 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
+253 253 253 253 253 253 253 253 253 253 253 253 198 198 198 66 66 66 2 2 6 2 2 6 
+2 2 6 2 2 6 62 42 6 156 107 11 219 162 10 239 182 13 246 186 14 246 190 14 
+246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 
+246 190 14 246 190 14 246 190 14 242 186 14 234 174 13 213 154 11 148 132 55 66 66 66 
+30 30 30 10 10 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 6 6 22 22 22 
+58 58 58 148 132 55 206 145 10 234 174 13 242 186 14 246 186 14 246 190 14 246 190 14 
+246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 
+246 190 14 246 190 14 246 190 14 246 190 14 246 186 14 236 178 12 204 160 10 163 110 8 
+62 42 6 124 131 137 218 218 218 250 250 250 253 253 253 253 253 253 253 253 253 250 250 250 
+242 242 242 210 210 210 151 151 151 66 66 66 6 6 6 2 2 6 2 2 6 2 2 6 
+2 2 6 2 2 6 62 42 6 163 110 8 216 158 10 236 178 12 246 190 14 246 190 14 
+246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 
+246 190 14 239 182 13 230 174 11 216 158 10 185 146 40 124 112 88 70 70 70 38 38 38 
+18 18 18 6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 6 6 22 22 22 
+62 62 62 169 125 40 206 145 10 224 166 10 236 178 12 239 182 13 242 186 14 242 186 14 
+246 186 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 
+246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 236 178 12 216 158 10 171 120 8 
+85 57 6 2 2 6 6 6 6 30 30 30 54 54 54 62 62 62 50 50 50 38 38 38 
+14 14 14 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 
+2 2 6 6 6 6 85 57 6 167 114 7 213 154 11 236 178 12 246 190 14 246 190 14 
+246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 242 186 14 239 182 13 239 182 13 
+230 174 11 210 150 10 174 140 55 124 112 88 82 82 82 54 54 54 34 34 34 18 18 18 
+6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 6 6 18 18 18 
+50 50 50 169 125 40 192 133 9 200 144 11 216 158 10 219 162 10 224 166 10 226 170 11 
+230 174 11 236 178 12 239 182 13 239 182 13 242 186 14 246 186 14 246 190 14 246 190 14 
+246 190 14 246 190 14 246 190 14 246 190 14 246 186 14 230 174 11 210 150 10 163 110 8 
+104 69 6 10 10 10 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 
+2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 
+2 2 6 6 6 6 85 57 6 167 114 7 206 145 10 230 174 11 242 186 14 246 190 14 
+246 190 14 246 190 14 246 186 14 242 186 14 239 182 13 230 174 11 224 166 10 213 154 11 
+169 125 40 124 112 88 86 86 86 58 58 58 38 38 38 22 22 22 10 10 10 6 6 6 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 14 14 14 
+34 34 34 70 70 70 133 118 54 169 125 40 167 114 7 180 123 7 192 133 9 197 138 11 
+200 144 11 206 145 10 213 154 11 219 162 10 224 166 10 230 174 11 239 182 13 242 186 14 
+246 186 14 246 186 14 246 186 14 246 186 14 239 182 13 216 158 10 184 138 11 152 99 6 
+104 69 6 20 16 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 
+2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 
+2 2 6 6 6 6 85 57 6 152 99 6 192 133 9 219 162 10 236 178 12 239 182 13 
+246 186 14 242 186 14 239 182 13 236 178 12 224 166 10 206 145 10 192 133 9 148 132 55 
+94 94 94 62 62 62 42 42 42 22 22 22 14 14 14 6 6 6 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 6 6 
+18 18 18 34 34 34 58 58 58 78 78 78 101 98 89 124 112 88 133 118 54 156 107 11 
+163 110 8 167 114 7 171 120 8 180 123 7 184 138 11 197 138 11 210 150 10 219 162 10 
+226 170 11 236 178 12 236 178 12 234 174 13 219 162 10 197 138 11 163 110 8 134 84 6 
+85 57 6 10 10 10 2 2 6 2 2 6 18 18 18 38 38 38 38 38 38 38 38 38 
+38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 26 26 26 2 2 6 
+2 2 6 6 6 6 62 42 6 137 92 6 171 120 8 200 144 11 219 162 10 230 174 11 
+234 174 13 230 174 11 219 162 10 210 150 10 192 133 9 163 110 8 124 112 88 82 82 82 
+50 50 50 30 30 30 14 14 14 6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+6 6 6 14 14 14 22 22 22 34 34 34 42 42 42 58 58 58 74 74 74 86 86 86 
+101 98 89 113 101 86 133 118 54 121 92 8 137 92 6 152 99 6 163 110 8 180 123 7 
+184 138 11 197 138 11 206 145 10 200 144 11 180 123 7 156 107 11 134 84 6 104 69 6 
+62 42 6 54 54 54 106 106 106 101 98 89 86 86 86 82 82 82 78 78 78 78 78 78 
+78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 82 82 82 86 86 86 94 94 94 
+106 106 106 101 101 101 90 61 47 120 80 7 156 107 11 180 123 7 192 133 9 200 144 11 
+206 145 10 200 144 11 192 133 9 171 120 8 139 102 15 113 101 86 70 70 70 42 42 42 
+22 22 22 10 10 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 6 6 6 10 10 10 14 14 14 22 22 22 30 30 30 38 38 38 
+50 50 50 62 62 62 74 74 74 90 90 90 101 98 89 113 101 86 121 92 8 120 80 7 
+137 92 6 152 99 6 152 99 6 152 99 6 134 84 6 120 80 7 98 70 6 88 55 22 
+101 98 89 82 82 82 58 58 58 46 46 46 38 38 38 34 34 34 34 34 34 34 34 34 
+34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 38 38 38 42 42 42 
+54 54 54 82 82 82 94 86 71 85 57 6 134 84 6 156 107 11 167 114 7 171 120 8 
+171 120 8 167 114 7 152 99 6 121 92 8 101 98 89 62 62 62 34 34 34 18 18 18 
+6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 6 6 6 6 6 10 10 10 
+18 18 18 22 22 22 30 30 30 42 42 42 50 50 50 66 66 66 86 86 86 101 98 89 
+94 86 71 98 70 6 104 69 6 104 69 6 104 69 6 85 57 6 88 55 22 90 90 90 
+62 62 62 38 38 38 22 22 22 14 14 14 10 10 10 10 10 10 10 10 10 10 10 10 
+10 10 10 10 10 10 6 6 6 10 10 10 10 10 10 10 10 10 10 10 10 14 14 14 
+22 22 22 42 42 42 70 70 70 94 86 71 85 57 6 104 69 6 120 80 7 137 92 6 
+134 84 6 120 80 7 94 86 71 86 86 86 58 58 58 30 30 30 14 14 14 6 6 6 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 6 6 6 10 10 10 14 14 14 18 18 18 26 26 26 38 38 38 54 54 54 
+70 70 70 86 86 86 94 86 71 94 86 71 94 86 71 86 86 86 74 74 74 50 50 50 
+30 30 30 14 14 14 6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+6 6 6 18 18 18 34 34 34 58 58 58 82 82 82 94 86 71 94 86 71 94 86 71 
+94 86 71 94 86 71 74 74 74 50 50 50 26 26 26 14 14 14 6 6 6 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 6 6 6 6 6 6 14 14 14 18 18 18 
+30 30 30 38 38 38 46 46 46 54 54 54 50 50 50 42 42 42 30 30 30 18 18 18 
+10 10 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 6 6 6 14 14 14 26 26 26 38 38 38 50 50 50 58 58 58 58 58 58 
+54 54 54 42 42 42 30 30 30 18 18 18 10 10 10 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 6 6 
+6 6 6 10 10 10 14 14 14 18 18 18 18 18 18 14 14 14 10 10 10 6 6 6 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 6 6 6 14 14 14 18 18 18 22 22 22 22 22 22 
+18 18 18 14 14 14 10 10 10 6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+
index 0098810..1f572c0 100644 (file)
@@ -192,7 +192,8 @@ static void leak_balloon(struct virtio_balloon *vb, size_t num)
         * virtio_has_feature(vdev, VIRTIO_BALLOON_F_MUST_TELL_HOST);
         * is true, we *have* to do it in this order
         */
-       tell_host(vb, vb->deflate_vq);
+       if (vb->num_pfns != 0)
+               tell_host(vb, vb->deflate_vq);
        mutex_unlock(&vb->balloon_lock);
        release_pages_by_pfn(vb->pfns, vb->num_pfns);
 }
index a7ce730..1aba255 100644 (file)
@@ -289,9 +289,9 @@ static void vp_free_vectors(struct virtio_device *vdev)
 
                pci_disable_msix(vp_dev->pci_dev);
                vp_dev->msix_enabled = 0;
-               vp_dev->msix_vectors = 0;
        }
 
+       vp_dev->msix_vectors = 0;
        vp_dev->msix_used_vectors = 0;
        kfree(vp_dev->msix_names);
        vp_dev->msix_names = NULL;
@@ -309,6 +309,8 @@ static int vp_request_msix_vectors(struct virtio_device *vdev, int nvectors,
        unsigned i, v;
        int err = -ENOMEM;
 
+       vp_dev->msix_vectors = nvectors;
+
        vp_dev->msix_entries = kmalloc(nvectors * sizeof *vp_dev->msix_entries,
                                       GFP_KERNEL);
        if (!vp_dev->msix_entries)
@@ -336,7 +338,6 @@ static int vp_request_msix_vectors(struct virtio_device *vdev, int nvectors,
                err = -ENOSPC;
        if (err)
                goto error;
-       vp_dev->msix_vectors = nvectors;
        vp_dev->msix_enabled = 1;
 
        /* Set the vector used for configuration */
index e89fc31..362085d 100644 (file)
@@ -221,15 +221,6 @@ config DW_WATCHDOG
          To compile this driver as a module, choose M here: the
          module will be called dw_wdt.
 
-config MPCORE_WATCHDOG
-       tristate "MPcore watchdog"
-       depends on HAVE_ARM_TWD
-       help
-         Watchdog timer embedded into the MPcore system.
-
-         To compile this driver as a module, choose M here: the
-         module will be called mpcore_wdt.
-
 config EP93XX_WATCHDOG
        tristate "EP93xx Watchdog"
        depends on ARCH_EP93XX
@@ -291,7 +282,7 @@ config DAVINCI_WATCHDOG
 
 config ORION_WATCHDOG
        tristate "Orion watchdog"
-       depends on ARCH_ORION5X || ARCH_KIRKWOOD
+       depends on ARCH_ORION5X || ARCH_KIRKWOOD || ARCH_DOVE
        select WATCHDOG_CORE
        help
          Say Y here if to include support for the watchdog timer
@@ -687,6 +678,17 @@ config HP_WATCHDOG
          To compile this driver as a module, choose M here: the module will be
          called hpwdt.
 
+config KEMPLD_WDT
+       tristate "Kontron COM Watchdog Timer"
+       depends on MFD_KEMPLD
+       select WATCHDOG_CORE
+       help
+         Support for the PLD watchdog on some Kontron ETX and COMexpress
+         (ETXexpress) modules
+
+         This driver can also be built as a module. If so, the module will be
+         called kempld_wdt.
+
 config HPWDT_NMI_DECODING
        bool "NMI decoding support for the HP ProLiant iLO2+ Hardware Watchdog Timer"
        depends on HP_WATCHDOG
@@ -1072,7 +1074,7 @@ config TXX9_WDT
 
 config OCTEON_WDT
        tristate "Cavium OCTEON SOC family Watchdog Timer"
-       depends on CPU_CAVIUM_OCTEON
+       depends on CAVIUM_OCTEON_SOC
        default y
        select EXPORT_UASM if OCTEON_WDT = m
        help
@@ -1098,6 +1100,17 @@ config BCM63XX_WDT
          To compile this driver as a loadable module, choose M here.
          The module will be called bcm63xx_wdt.
 
+config BCM2835_WDT
+       tristate "Broadcom BCM2835 hardware watchdog"
+       depends on ARCH_BCM2835
+       select WATCHDOG_CORE
+       help
+         Watchdog driver for the built in watchdog hardware in Broadcom
+         BCM2835 SoC.
+
+         To compile this driver as a loadable module, choose M here.
+         The module will be called bcm2835_wdt.
+
 config LANTIQ_WDT
        tristate "Lantiq SoC watchdog"
        depends on LANTIQ
@@ -1172,6 +1185,18 @@ config BOOKE_WDT_DEFAULT_TIMEOUT
 
          The value can be overridden by the wdt_period command-line parameter.
 
+config MEN_A21_WDT
+       tristate "MEN A21 VME CPU Carrier Board Watchdog Timer"
+       select WATCHDOG_CORE
+       depends on GPIOLIB
+       help
+        Watchdog driver for MEN A21 VMEbus CPU Carrier Boards.
+
+       The driver can also be built as a module. If so, the module will be
+       called mena21_wdt.
+
+       If unsure select N here.
+
 # PPC64 Architecture
 
 config WATCHDOG_RTAS
index a300b94..2f26a0b 100644 (file)
@@ -41,7 +41,6 @@ obj-$(CONFIG_KS8695_WATCHDOG) += ks8695_wdt.o
 obj-$(CONFIG_S3C2410_WATCHDOG) += s3c2410_wdt.o
 obj-$(CONFIG_SA1100_WATCHDOG) += sa1100_wdt.o
 obj-$(CONFIG_DW_WATCHDOG) += dw_wdt.o
-obj-$(CONFIG_MPCORE_WATCHDOG) += mpcore_wdt.o
 obj-$(CONFIG_EP93XX_WATCHDOG) += ep93xx_wdt.o
 obj-$(CONFIG_PNX4008_WATCHDOG) += pnx4008_wdt.o
 obj-$(CONFIG_IOP_WATCHDOG) += iop_wdt.o
@@ -54,6 +53,7 @@ obj-$(CONFIG_TS72XX_WATCHDOG) += ts72xx_wdt.o
 obj-$(CONFIG_IMX2_WDT) += imx2_wdt.o
 obj-$(CONFIG_UX500_WATCHDOG) += ux500_wdt.o
 obj-$(CONFIG_RETU_WATCHDOG) += retu_wdt.o
+obj-$(CONFIG_BCM2835_WDT) += bcm2835_wdt.o
 
 # AVR32 Architecture
 obj-$(CONFIG_AT32AP700X_WDT) += at32ap700x_wdt.o
@@ -90,6 +90,7 @@ endif
 obj-$(CONFIG_IT8712F_WDT) += it8712f_wdt.o
 obj-$(CONFIG_IT87_WDT) += it87_wdt.o
 obj-$(CONFIG_HP_WATCHDOG) += hpwdt.o
+obj-$(CONFIG_KEMPLD_WDT) += kempld_wdt.o
 obj-$(CONFIG_SC1200_WDT) += sc1200wdt.o
 obj-$(CONFIG_SCx200_WDT) += scx200_wdt.o
 obj-$(CONFIG_PC87413_WDT) += pc87413_wdt.o
@@ -143,6 +144,7 @@ obj-$(CONFIG_8xxx_WDT) += mpc8xxx_wdt.o
 obj-$(CONFIG_MV64X60_WDT) += mv64x60_wdt.o
 obj-$(CONFIG_PIKA_WDT) += pika_wdt.o
 obj-$(CONFIG_BOOKE_WDT) += booke_wdt.o
+obj-$(CONFIG_MEN_A21_WDT) += mena21_wdt.o
 
 # PPC64 Architecture
 obj-$(CONFIG_WATCHDOG_RTAS) += wdrtas.o
index 7a715e3..b178e71 100644 (file)
@@ -321,13 +321,14 @@ static int __init at32_wdt_probe(struct platform_device *pdev)
                return -ENXIO;
        }
 
-       wdt = kzalloc(sizeof(struct wdt_at32ap700x), GFP_KERNEL);
+       wdt = devm_kzalloc(&pdev->dev, sizeof(struct wdt_at32ap700x),
+                       GFP_KERNEL);
        if (!wdt) {
                dev_dbg(&pdev->dev, "no memory for wdt structure\n");
                return -ENOMEM;
        }
 
-       wdt->regs = ioremap(regs->start, resource_size(regs));
+       wdt->regs = devm_ioremap(&pdev->dev, regs->start, resource_size(regs));
        if (!wdt->regs) {
                ret = -ENOMEM;
                dev_dbg(&pdev->dev, "could not map I/O memory\n");
@@ -342,7 +343,7 @@ static int __init at32_wdt_probe(struct platform_device *pdev)
                dev_info(&pdev->dev, "CPU must be reset with external "
                                "reset or POR due to silicon errata.\n");
                ret = -EIO;
-               goto err_iounmap;
+               goto err_free;
        } else {
                wdt->users = 0;
        }
@@ -364,7 +365,7 @@ static int __init at32_wdt_probe(struct platform_device *pdev)
        ret = misc_register(&wdt->miscdev);
        if (ret) {
                dev_dbg(&pdev->dev, "failed to register wdt miscdev\n");
-               goto err_register;
+               goto err_free;
        }
 
        dev_info(&pdev->dev,
@@ -373,12 +374,7 @@ static int __init at32_wdt_probe(struct platform_device *pdev)
 
        return 0;
 
-err_register:
-       platform_set_drvdata(pdev, NULL);
-err_iounmap:
-       iounmap(wdt->regs);
 err_free:
-       kfree(wdt);
        wdt = NULL;
        return ret;
 }
@@ -391,10 +387,7 @@ static int __exit at32_wdt_remove(struct platform_device *pdev)
                        at32_wdt_stop();
 
                misc_deregister(&wdt->miscdev);
-               iounmap(wdt->regs);
-               kfree(wdt);
                wdt = NULL;
-               platform_set_drvdata(pdev, NULL);
        }
        return 0;
 }
diff --git a/drivers/watchdog/bcm2835_wdt.c b/drivers/watchdog/bcm2835_wdt.c
new file mode 100644 (file)
index 0000000..61566fc
--- /dev/null
@@ -0,0 +1,189 @@
+/*
+ * Watchdog driver for Broadcom BCM2835
+ *
+ * "bcm2708_wdog" driver written by Luke Diamand that was obtained from
+ * branch "rpi-3.6.y" of git://github.com/raspberrypi/linux.git was used
+ * as a hardware reference for the Broadcom BCM2835 watchdog timer.
+ *
+ * Copyright (C) 2013 Lubomir Rintel <lkundrak@v3.sk>
+ *
+ * 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/types.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/watchdog.h>
+#include <linux/platform_device.h>
+#include <linux/of_address.h>
+#include <linux/miscdevice.h>
+
+#define PM_RSTC                                0x1c
+#define PM_WDOG                                0x24
+
+#define PM_PASSWORD                    0x5a000000
+
+#define PM_WDOG_TIME_SET               0x000fffff
+#define PM_RSTC_WRCFG_CLR              0xffffffcf
+#define PM_RSTC_WRCFG_SET              0x00000030
+#define PM_RSTC_WRCFG_FULL_RESET       0x00000020
+#define PM_RSTC_RESET                  0x00000102
+
+#define SECS_TO_WDOG_TICKS(x) ((x) << 16)
+#define WDOG_TICKS_TO_SECS(x) ((x) >> 16)
+
+struct bcm2835_wdt {
+       void __iomem            *base;
+       spinlock_t              lock;
+};
+
+static unsigned int heartbeat;
+static bool nowayout = WATCHDOG_NOWAYOUT;
+
+static int bcm2835_wdt_start(struct watchdog_device *wdog)
+{
+       struct bcm2835_wdt *wdt = watchdog_get_drvdata(wdog);
+       uint32_t cur;
+       unsigned long flags;
+
+       spin_lock_irqsave(&wdt->lock, flags);
+
+       writel_relaxed(PM_PASSWORD | (SECS_TO_WDOG_TICKS(wdog->timeout) &
+                               PM_WDOG_TIME_SET), wdt->base + PM_WDOG);
+       cur = readl_relaxed(wdt->base + PM_RSTC);
+       writel_relaxed(PM_PASSWORD | (cur & PM_RSTC_WRCFG_CLR) |
+                 PM_RSTC_WRCFG_FULL_RESET, wdt->base + PM_RSTC);
+
+       spin_unlock_irqrestore(&wdt->lock, flags);
+
+       return 0;
+}
+
+static int bcm2835_wdt_stop(struct watchdog_device *wdog)
+{
+       struct bcm2835_wdt *wdt = watchdog_get_drvdata(wdog);
+
+       writel_relaxed(PM_PASSWORD | PM_RSTC_RESET, wdt->base + PM_RSTC);
+       dev_info(wdog->dev, "Watchdog timer stopped");
+       return 0;
+}
+
+static int bcm2835_wdt_set_timeout(struct watchdog_device *wdog, unsigned int t)
+{
+       wdog->timeout = t;
+       return 0;
+}
+
+static unsigned int bcm2835_wdt_get_timeleft(struct watchdog_device *wdog)
+{
+       struct bcm2835_wdt *wdt = watchdog_get_drvdata(wdog);
+
+       uint32_t ret = readl_relaxed(wdt->base + PM_WDOG);
+       return WDOG_TICKS_TO_SECS(ret & PM_WDOG_TIME_SET);
+}
+
+static struct watchdog_ops bcm2835_wdt_ops = {
+       .owner =        THIS_MODULE,
+       .start =        bcm2835_wdt_start,
+       .stop =         bcm2835_wdt_stop,
+       .set_timeout =  bcm2835_wdt_set_timeout,
+       .get_timeleft = bcm2835_wdt_get_timeleft,
+};
+
+static struct watchdog_info bcm2835_wdt_info = {
+       .options =      WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE |
+                       WDIOF_KEEPALIVEPING,
+       .identity =     "Broadcom BCM2835 Watchdog timer",
+};
+
+static struct watchdog_device bcm2835_wdt_wdd = {
+       .info =         &bcm2835_wdt_info,
+       .ops =          &bcm2835_wdt_ops,
+       .min_timeout =  1,
+       .max_timeout =  WDOG_TICKS_TO_SECS(PM_WDOG_TIME_SET),
+       .timeout =      WDOG_TICKS_TO_SECS(PM_WDOG_TIME_SET),
+};
+
+static int bcm2835_wdt_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct device_node *np = dev->of_node;
+       struct bcm2835_wdt *wdt;
+       int err;
+
+       wdt = devm_kzalloc(dev, sizeof(struct bcm2835_wdt), GFP_KERNEL);
+       if (!wdt) {
+               dev_err(dev, "Failed to allocate memory for watchdog device");
+               return -ENOMEM;
+       }
+       platform_set_drvdata(pdev, wdt);
+
+       spin_lock_init(&wdt->lock);
+
+       wdt->base = of_iomap(np, 0);
+       if (!wdt->base) {
+               dev_err(dev, "Failed to remap watchdog regs");
+               return -ENODEV;
+       }
+
+       watchdog_set_drvdata(&bcm2835_wdt_wdd, wdt);
+       watchdog_init_timeout(&bcm2835_wdt_wdd, heartbeat, dev);
+       watchdog_set_nowayout(&bcm2835_wdt_wdd, nowayout);
+       err = watchdog_register_device(&bcm2835_wdt_wdd);
+       if (err) {
+               dev_err(dev, "Failed to register watchdog device");
+               iounmap(wdt->base);
+               return err;
+       }
+
+       dev_info(dev, "Broadcom BCM2835 watchdog timer");
+       return 0;
+}
+
+static int bcm2835_wdt_remove(struct platform_device *pdev)
+{
+       struct bcm2835_wdt *wdt = platform_get_drvdata(pdev);
+
+       watchdog_unregister_device(&bcm2835_wdt_wdd);
+       iounmap(wdt->base);
+
+       return 0;
+}
+
+static void bcm2835_wdt_shutdown(struct platform_device *pdev)
+{
+       bcm2835_wdt_stop(&bcm2835_wdt_wdd);
+}
+
+static const struct of_device_id bcm2835_wdt_of_match[] = {
+       { .compatible = "brcm,bcm2835-pm-wdt", },
+       {},
+};
+MODULE_DEVICE_TABLE(of, bcm2835_wdt_of_match);
+
+static struct platform_driver bcm2835_wdt_driver = {
+       .probe          = bcm2835_wdt_probe,
+       .remove         = bcm2835_wdt_remove,
+       .shutdown       = bcm2835_wdt_shutdown,
+       .driver = {
+               .name =         "bcm2835-wdt",
+               .owner =        THIS_MODULE,
+               .of_match_table = bcm2835_wdt_of_match,
+       },
+};
+module_platform_driver(bcm2835_wdt_driver);
+
+module_param(heartbeat, uint, 0);
+MODULE_PARM_DESC(heartbeat, "Initial watchdog heartbeat in seconds");
+
+module_param(nowayout, bool, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
+                               __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+
+MODULE_AUTHOR("Lubomir Rintel <lkundrak@v3.sk>");
+MODULE_DESCRIPTION("Driver for Broadcom BCM2835 watchdog timer");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
index b2b80d4..a14a58d 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/errno.h>
 #include <linux/fs.h>
 #include <linux/init.h>
+#include <linux/io.h>
 #include <linux/kernel.h>
 #include <linux/miscdevice.h>
 #include <linux/module.h>
@@ -249,7 +250,8 @@ static int bcm63xx_wdt_probe(struct platform_device *pdev)
                return -ENODEV;
        }
 
-       bcm63xx_wdt_device.regs = ioremap_nocache(r->start, resource_size(r));
+       bcm63xx_wdt_device.regs = devm_ioremap_nocache(&pdev->dev, r->start,
+                                                       resource_size(r));
        if (!bcm63xx_wdt_device.regs) {
                dev_err(&pdev->dev, "failed to remap I/O resources\n");
                return -ENXIO;
@@ -258,7 +260,7 @@ static int bcm63xx_wdt_probe(struct platform_device *pdev)
        ret = bcm63xx_timer_register(TIMER_WDT_ID, bcm63xx_wdt_isr, NULL);
        if (ret < 0) {
                dev_err(&pdev->dev, "failed to register wdt timer isr\n");
-               goto unmap;
+               return ret;
        }
 
        if (bcm63xx_wdt_settimeout(wdt_time)) {
@@ -281,8 +283,6 @@ static int bcm63xx_wdt_probe(struct platform_device *pdev)
 
 unregister_timer:
        bcm63xx_timer_unregister(TIMER_WDT_ID);
-unmap:
-       iounmap(bcm63xx_wdt_device.regs);
        return ret;
 }
 
@@ -293,7 +293,6 @@ static int bcm63xx_wdt_remove(struct platform_device *pdev)
 
        misc_deregister(&bcm63xx_wdt_miscdev);
        bcm63xx_timer_unregister(TIMER_WDT_ID);
-       iounmap(bcm63xx_wdt_device.regs);
        return 0;
 }
 
index 7038758..213225e 100644 (file)
@@ -621,7 +621,7 @@ static int cpwd_probe(struct platform_device *op)
                        WD_BADMODEL);
        }
 
-       dev_set_drvdata(&op->dev, p);
+       platform_set_drvdata(op, p);
        cpwd_device = p;
        err = 0;
 
@@ -642,7 +642,7 @@ out_free:
 
 static int cpwd_remove(struct platform_device *op)
 {
-       struct cpwd *p = dev_get_drvdata(&op->dev);
+       struct cpwd *p = platform_get_drvdata(op);
        int i;
 
        for (i = 0; i < WD_NUMDEVS; i++) {
index 3674450..f09c54e 100644 (file)
@@ -215,14 +215,14 @@ static int da9052_wdt_probe(struct platform_device *pdev)
                goto err;
        }
 
-       dev_set_drvdata(&pdev->dev, driver_data);
+       platform_set_drvdata(pdev, driver_data);
 err:
        return ret;
 }
 
 static int da9052_wdt_remove(struct platform_device *pdev)
 {
-       struct da9052_wdt_data *driver_data = dev_get_drvdata(&pdev->dev);
+       struct da9052_wdt_data *driver_data = platform_get_drvdata(pdev);
 
        watchdog_unregister_device(&driver_data->wdt);
        kref_put(&driver_data->kref, da9052_wdt_release_resources);
index f5ad105..575f37a 100644 (file)
@@ -174,7 +174,7 @@ static int da9055_wdt_probe(struct platform_device *pdev)
                goto err;
        }
 
-       dev_set_drvdata(&pdev->dev, driver_data);
+       platform_set_drvdata(pdev, driver_data);
 
        ret = watchdog_register_device(&driver_data->wdt);
        if (ret != 0)
@@ -187,7 +187,7 @@ err:
 
 static int da9055_wdt_remove(struct platform_device *pdev)
 {
-       struct da9055_wdt_data *driver_data = dev_get_drvdata(&pdev->dev);
+       struct da9055_wdt_data *driver_data = platform_get_drvdata(pdev);
 
        watchdog_unregister_device(&driver_data->wdt);
        kref_put(&driver_data->kref, da9055_wdt_release_resources);
index 2037669..e621098 100644 (file)
@@ -154,8 +154,8 @@ static int dw_wdt_open(struct inode *inode, struct file *filp)
        return nonseekable_open(inode, filp);
 }
 
-ssize_t dw_wdt_write(struct file *filp, const char __user *buf, size_t len,
-                    loff_t *offset)
+static ssize_t dw_wdt_write(struct file *filp, const char __user *buf,
+                           size_t len, loff_t *offset)
 {
        if (!len)
                return 0;
@@ -305,13 +305,13 @@ static int dw_wdt_drv_probe(struct platform_device *pdev)
        if (IS_ERR(dw_wdt.regs))
                return PTR_ERR(dw_wdt.regs);
 
-       dw_wdt.clk = clk_get(&pdev->dev, NULL);
+       dw_wdt.clk = devm_clk_get(&pdev->dev, NULL);
        if (IS_ERR(dw_wdt.clk))
                return PTR_ERR(dw_wdt.clk);
 
        ret = clk_enable(dw_wdt.clk);
        if (ret)
-               goto out_put_clk;
+               return ret;
 
        spin_lock_init(&dw_wdt.lock);
 
@@ -327,8 +327,6 @@ static int dw_wdt_drv_probe(struct platform_device *pdev)
 
 out_disable_clk:
        clk_disable(dw_wdt.clk);
-out_put_clk:
-       clk_put(dw_wdt.clk);
 
        return ret;
 }
@@ -338,7 +336,6 @@ static int dw_wdt_drv_remove(struct platform_device *pdev)
        misc_deregister(&dw_wdt_miscdev);
 
        clk_disable(dw_wdt.clk);
-       clk_put(dw_wdt.clk);
 
        return 0;
 }
index 11796b9..de7e4f4 100644 (file)
@@ -39,7 +39,7 @@
 #endif /* CONFIG_HPWDT_NMI_DECODING */
 #include <asm/nmi.h>
 
-#define HPWDT_VERSION                  "1.3.1"
+#define HPWDT_VERSION                  "1.3.2"
 #define SECS_TO_TICKS(secs)            ((secs) * 1000 / 128)
 #define TICKS_TO_SECS(ticks)           ((ticks) * 128 / 1000)
 #define HPWDT_MAX_TIMER                        TICKS_TO_SECS(65535)
@@ -148,6 +148,7 @@ struct cmn_registers {
 static unsigned int hpwdt_nmi_decoding;
 static unsigned int allow_kdump = 1;
 static unsigned int is_icru;
+static unsigned int is_uefi;
 static DEFINE_SPINLOCK(rom_lock);
 static void *cru_rom_addr;
 static struct cmn_registers cmn_regs;
@@ -484,7 +485,7 @@ static int hpwdt_pretimeout(unsigned int ulReason, struct pt_regs *regs)
                goto out;
 
        spin_lock_irqsave(&rom_lock, rom_pl);
-       if (!die_nmi_called && !is_icru)
+       if (!die_nmi_called && !is_icru && !is_uefi)
                asminline_call(&cmn_regs, cru_rom_addr);
        die_nmi_called = 1;
        spin_unlock_irqrestore(&rom_lock, rom_pl);
@@ -492,7 +493,7 @@ static int hpwdt_pretimeout(unsigned int ulReason, struct pt_regs *regs)
        if (allow_kdump)
                hpwdt_stop();
 
-       if (!is_icru) {
+       if (!is_icru && !is_uefi) {
                if (cmn_regs.u1.ral == 0) {
                        panic("An NMI occurred, "
                                "but unable to determine source.\n");
@@ -679,6 +680,8 @@ static void dmi_find_icru(const struct dmi_header *dm, void *dummy)
                smbios_proliant_ptr = (struct smbios_proliant_info *) dm;
                if (smbios_proliant_ptr->misc_features & 0x01)
                        is_icru = 1;
+               if (smbios_proliant_ptr->misc_features & 0x408)
+                       is_uefi = 1;
        }
 }
 
@@ -697,7 +700,7 @@ static int hpwdt_init_nmi_decoding(struct pci_dev *dev)
         * the old cru detect code.
         */
        dmi_walk(dmi_find_icru, NULL);
-       if (!is_icru) {
+       if (!is_icru && !is_uefi) {
 
                /*
                * We need to map the ROM to get the CRU service.
index 62946c2..693ac3f 100644 (file)
@@ -261,7 +261,7 @@ static int __init imx2_wdt_probe(struct platform_device *pdev)
        if (IS_ERR(imx2_wdt.base))
                return PTR_ERR(imx2_wdt.base);
 
-       imx2_wdt.clk = clk_get(&pdev->dev, NULL);
+       imx2_wdt.clk = devm_clk_get(&pdev->dev, NULL);
        if (IS_ERR(imx2_wdt.clk)) {
                dev_err(&pdev->dev, "can't get Watchdog clock\n");
                return PTR_ERR(imx2_wdt.clk);
@@ -286,7 +286,6 @@ static int __init imx2_wdt_probe(struct platform_device *pdev)
 
 fail:
        imx2_wdt_miscdev.parent = NULL;
-       clk_put(imx2_wdt.clk);
        return ret;
 }
 
@@ -299,8 +298,7 @@ static int __exit imx2_wdt_remove(struct platform_device *pdev)
 
                dev_crit(imx2_wdt_miscdev.parent,
                        "Device removed: Expect reboot!\n");
-       } else
-               clk_put(imx2_wdt.clk);
+       }
 
        imx2_wdt_miscdev.parent = NULL;
        return 0;
index 1cb25f6..d1afdf6 100644 (file)
@@ -177,7 +177,7 @@ static int jz4740_wdt_probe(struct platform_device *pdev)
                goto err_out;
        }
 
-       drvdata->rtc_clk = clk_get(NULL, "rtc");
+       drvdata->rtc_clk = clk_get(&pdev->dev, "rtc");
        if (IS_ERR(drvdata->rtc_clk)) {
                dev_err(&pdev->dev, "cannot find RTC clock\n");
                ret = PTR_ERR(drvdata->rtc_clk);
diff --git a/drivers/watchdog/kempld_wdt.c b/drivers/watchdog/kempld_wdt.c
new file mode 100644 (file)
index 0000000..491419e
--- /dev/null
@@ -0,0 +1,581 @@
+/*
+ * Kontron PLD watchdog driver
+ *
+ * Copyright (c) 2010-2013 Kontron Europe GmbH
+ * Author: Michael Brunner <michael.brunner@kontron.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License 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.
+ *
+ * Note: From the PLD watchdog point of view timeout and pretimeout are
+ *       defined differently than in the kernel.
+ *       First the pretimeout stage runs out before the timeout stage gets
+ *       active.
+ *
+ * Kernel/API:                     P-----| pretimeout
+ *               |-----------------------T timeout
+ * Watchdog:     |-----------------P       pretimeout_stage
+ *                                 |-----T timeout_stage
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/watchdog.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/kempld.h>
+
+#define KEMPLD_WDT_STAGE_TIMEOUT(x)    (0x1b + (x) * 4)
+#define KEMPLD_WDT_STAGE_CFG(x)                (0x18 + (x))
+#define STAGE_CFG_GET_PRESCALER(x)     (((x) & 0x30) >> 4)
+#define STAGE_CFG_SET_PRESCALER(x)     (((x) & 0x30) << 4)
+#define STAGE_CFG_PRESCALER_MASK       0x30
+#define STAGE_CFG_ACTION_MASK          0x7
+#define STAGE_CFG_ASSERT               (1 << 3)
+
+#define KEMPLD_WDT_MAX_STAGES          2
+#define KEMPLD_WDT_KICK                        0x16
+#define KEMPLD_WDT_CFG                 0x17
+#define KEMPLD_WDT_CFG_ENABLE          0x10
+#define KEMPLD_WDT_CFG_ENABLE_LOCK     0x8
+#define KEMPLD_WDT_CFG_GLOBAL_LOCK     0x80
+
+enum {
+       ACTION_NONE = 0,
+       ACTION_RESET,
+       ACTION_NMI,
+       ACTION_SMI,
+       ACTION_SCI,
+       ACTION_DELAY,
+};
+
+enum {
+       STAGE_TIMEOUT = 0,
+       STAGE_PRETIMEOUT,
+};
+
+enum {
+       PRESCALER_21 = 0,
+       PRESCALER_17,
+       PRESCALER_12,
+};
+
+const u32 kempld_prescaler[] = {
+       [PRESCALER_21] = (1 << 21) - 1,
+       [PRESCALER_17] = (1 << 17) - 1,
+       [PRESCALER_12] = (1 << 12) - 1,
+       0,
+};
+
+struct kempld_wdt_stage {
+       unsigned int    id;
+       u32             mask;
+};
+
+struct kempld_wdt_data {
+       struct kempld_device_data       *pld;
+       struct watchdog_device          wdd;
+       unsigned int                    pretimeout;
+       struct kempld_wdt_stage         stage[KEMPLD_WDT_MAX_STAGES];
+#ifdef CONFIG_PM
+       u8                              pm_status_store;
+#endif
+};
+
+#define DEFAULT_TIMEOUT                30 /* seconds */
+#define DEFAULT_PRETIMEOUT     0
+
+static unsigned int timeout = DEFAULT_TIMEOUT;
+module_param(timeout, uint, 0);
+MODULE_PARM_DESC(timeout,
+       "Watchdog timeout in seconds. (>=0, default="
+       __MODULE_STRING(DEFAULT_TIMEOUT) ")");
+
+static unsigned int pretimeout = DEFAULT_PRETIMEOUT;
+module_param(pretimeout, uint, 0);
+MODULE_PARM_DESC(pretimeout,
+       "Watchdog pretimeout in seconds. (>=0, default="
+       __MODULE_STRING(DEFAULT_PRETIMEOUT) ")");
+
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
+MODULE_PARM_DESC(nowayout,
+       "Watchdog cannot be stopped once started (default="
+       __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+
+static int kempld_wdt_set_stage_action(struct kempld_wdt_data *wdt_data,
+                                       struct kempld_wdt_stage *stage,
+                                       u8 action)
+{
+       struct kempld_device_data *pld = wdt_data->pld;
+       u8 stage_cfg;
+
+       if (!stage || !stage->mask)
+               return -EINVAL;
+
+       kempld_get_mutex(pld);
+       stage_cfg = kempld_read8(pld, KEMPLD_WDT_STAGE_CFG(stage->id));
+       stage_cfg &= ~STAGE_CFG_ACTION_MASK;
+       stage_cfg |= (action & STAGE_CFG_ACTION_MASK);
+
+       if (action == ACTION_RESET)
+               stage_cfg |= STAGE_CFG_ASSERT;
+       else
+               stage_cfg &= ~STAGE_CFG_ASSERT;
+
+       kempld_write8(pld, KEMPLD_WDT_STAGE_CFG(stage->id), stage_cfg);
+       kempld_release_mutex(pld);
+
+       return 0;
+}
+
+static int kempld_wdt_set_stage_timeout(struct kempld_wdt_data *wdt_data,
+                                       struct kempld_wdt_stage *stage,
+                                       unsigned int timeout)
+{
+       struct kempld_device_data *pld = wdt_data->pld;
+       u32 prescaler = kempld_prescaler[PRESCALER_21];
+       u64 stage_timeout64;
+       u32 stage_timeout;
+       u32 remainder;
+       u8 stage_cfg;
+
+       if (!stage)
+               return -EINVAL;
+
+       stage_timeout64 = (u64)timeout * pld->pld_clock;
+       remainder = do_div(stage_timeout64, prescaler);
+       if (remainder)
+               stage_timeout64++;
+
+       if (stage_timeout64 > stage->mask)
+               return -EINVAL;
+
+       stage_timeout = stage_timeout64 & stage->mask;
+
+       kempld_get_mutex(pld);
+       stage_cfg = kempld_read8(pld, KEMPLD_WDT_STAGE_CFG(stage->id));
+       stage_cfg &= ~STAGE_CFG_PRESCALER_MASK;
+       stage_cfg |= STAGE_CFG_SET_PRESCALER(prescaler);
+       kempld_write8(pld, KEMPLD_WDT_STAGE_CFG(stage->id), stage_cfg);
+       kempld_write32(pld, KEMPLD_WDT_STAGE_TIMEOUT(stage->id),
+                       stage_timeout);
+       kempld_release_mutex(pld);
+
+       return 0;
+}
+
+/*
+ * kempld_get_mutex must be called prior to calling this function.
+ */
+static unsigned int kempld_wdt_get_timeout(struct kempld_wdt_data *wdt_data,
+                                               struct kempld_wdt_stage *stage)
+{
+       struct kempld_device_data *pld = wdt_data->pld;
+       unsigned int timeout;
+       u64 stage_timeout;
+       u32 prescaler;
+       u32 remainder;
+       u8 stage_cfg;
+
+       if (!stage->mask)
+               return 0;
+
+       stage_cfg = kempld_read8(pld, KEMPLD_WDT_STAGE_CFG(stage->id));
+       stage_timeout = kempld_read32(pld, KEMPLD_WDT_STAGE_TIMEOUT(stage->id));
+       prescaler = kempld_prescaler[STAGE_CFG_GET_PRESCALER(stage_cfg)];
+
+       stage_timeout = (stage_timeout & stage->mask) * prescaler;
+       remainder = do_div(stage_timeout, pld->pld_clock);
+       if (remainder)
+               stage_timeout++;
+
+       timeout = stage_timeout;
+       WARN_ON_ONCE(timeout != stage_timeout);
+
+       return timeout;
+}
+
+static int kempld_wdt_set_timeout(struct watchdog_device *wdd,
+                                       unsigned int timeout)
+{
+       struct kempld_wdt_data *wdt_data = watchdog_get_drvdata(wdd);
+       struct kempld_wdt_stage *pretimeout_stage;
+       struct kempld_wdt_stage *timeout_stage;
+       int ret;
+
+       timeout_stage = &wdt_data->stage[STAGE_TIMEOUT];
+       pretimeout_stage = &wdt_data->stage[STAGE_PRETIMEOUT];
+
+       if (pretimeout_stage->mask && wdt_data->pretimeout > 0)
+               timeout = wdt_data->pretimeout;
+
+       ret = kempld_wdt_set_stage_action(wdt_data, timeout_stage,
+                                               ACTION_RESET);
+       if (ret)
+               return ret;
+       ret = kempld_wdt_set_stage_timeout(wdt_data, timeout_stage,
+                                               timeout);
+       if (ret)
+               return ret;
+
+       wdd->timeout = timeout;
+       return 0;
+}
+
+static int kempld_wdt_set_pretimeout(struct watchdog_device *wdd,
+                                       unsigned int pretimeout)
+{
+       struct kempld_wdt_data *wdt_data = watchdog_get_drvdata(wdd);
+       struct kempld_wdt_stage *pretimeout_stage;
+       u8 action = ACTION_NONE;
+       int ret;
+
+       pretimeout_stage = &wdt_data->stage[STAGE_PRETIMEOUT];
+
+       if (!pretimeout_stage->mask)
+               return -ENXIO;
+
+       if (pretimeout > wdd->timeout)
+               return -EINVAL;
+
+       if (pretimeout > 0)
+               action = ACTION_NMI;
+
+       ret = kempld_wdt_set_stage_action(wdt_data, pretimeout_stage,
+                                               action);
+       if (ret)
+               return ret;
+       ret = kempld_wdt_set_stage_timeout(wdt_data, pretimeout_stage,
+                                               wdd->timeout - pretimeout);
+       if (ret)
+               return ret;
+
+       wdt_data->pretimeout = pretimeout;
+       return 0;
+}
+
+static void kempld_wdt_update_timeouts(struct kempld_wdt_data *wdt_data)
+{
+       struct kempld_device_data *pld = wdt_data->pld;
+       struct kempld_wdt_stage *pretimeout_stage;
+       struct kempld_wdt_stage *timeout_stage;
+       unsigned int pretimeout, timeout;
+
+       pretimeout_stage = &wdt_data->stage[STAGE_PRETIMEOUT];
+       timeout_stage = &wdt_data->stage[STAGE_TIMEOUT];
+
+       kempld_get_mutex(pld);
+       pretimeout = kempld_wdt_get_timeout(wdt_data, pretimeout_stage);
+       timeout = kempld_wdt_get_timeout(wdt_data, timeout_stage);
+       kempld_release_mutex(pld);
+
+       if (pretimeout)
+               wdt_data->pretimeout = timeout;
+       else
+               wdt_data->pretimeout = 0;
+
+       wdt_data->wdd.timeout = pretimeout + timeout;
+}
+
+static int kempld_wdt_start(struct watchdog_device *wdd)
+{
+       struct kempld_wdt_data *wdt_data = watchdog_get_drvdata(wdd);
+       struct kempld_device_data *pld = wdt_data->pld;
+       u8 status;
+       int ret;
+
+       ret = kempld_wdt_set_timeout(wdd, wdd->timeout);
+       if (ret)
+               return ret;
+
+       kempld_get_mutex(pld);
+       status = kempld_read8(pld, KEMPLD_WDT_CFG);
+       status |= KEMPLD_WDT_CFG_ENABLE;
+       kempld_write8(pld, KEMPLD_WDT_CFG, status);
+       status = kempld_read8(pld, KEMPLD_WDT_CFG);
+       kempld_release_mutex(pld);
+
+       /* Check if the watchdog was enabled */
+       if (!(status & KEMPLD_WDT_CFG_ENABLE))
+               return -EACCES;
+
+       return 0;
+}
+
+static int kempld_wdt_stop(struct watchdog_device *wdd)
+{
+       struct kempld_wdt_data *wdt_data = watchdog_get_drvdata(wdd);
+       struct kempld_device_data *pld = wdt_data->pld;
+       u8 status;
+
+       kempld_get_mutex(pld);
+       status = kempld_read8(pld, KEMPLD_WDT_CFG);
+       status &= ~KEMPLD_WDT_CFG_ENABLE;
+       kempld_write8(pld, KEMPLD_WDT_CFG, status);
+       status = kempld_read8(pld, KEMPLD_WDT_CFG);
+       kempld_release_mutex(pld);
+
+       /* Check if the watchdog was disabled */
+       if (status & KEMPLD_WDT_CFG_ENABLE)
+               return -EACCES;
+
+       return 0;
+}
+
+static int kempld_wdt_keepalive(struct watchdog_device *wdd)
+{
+       struct kempld_wdt_data *wdt_data = watchdog_get_drvdata(wdd);
+       struct kempld_device_data *pld = wdt_data->pld;
+
+       kempld_get_mutex(pld);
+       kempld_write8(pld, KEMPLD_WDT_KICK, 'K');
+       kempld_release_mutex(pld);
+
+       return 0;
+}
+
+static long kempld_wdt_ioctl(struct watchdog_device *wdd, unsigned int cmd,
+                               unsigned long arg)
+{
+       struct kempld_wdt_data *wdt_data = watchdog_get_drvdata(wdd);
+       void __user *argp = (void __user *)arg;
+       int ret = -ENOIOCTLCMD;
+       int __user *p = argp;
+       int new_value;
+
+       switch (cmd) {
+       case WDIOC_SETPRETIMEOUT:
+               if (get_user(new_value, p))
+                       return -EFAULT;
+               ret = kempld_wdt_set_pretimeout(wdd, new_value);
+               if (ret)
+                       return ret;
+               ret = kempld_wdt_keepalive(wdd);
+               break;
+       case WDIOC_GETPRETIMEOUT:
+               ret = put_user(wdt_data->pretimeout, (int *)arg);
+               break;
+       }
+
+       return ret;
+}
+
+static int kempld_wdt_probe_stages(struct watchdog_device *wdd)
+{
+       struct kempld_wdt_data *wdt_data = watchdog_get_drvdata(wdd);
+       struct kempld_device_data *pld = wdt_data->pld;
+       struct kempld_wdt_stage *pretimeout_stage;
+       struct kempld_wdt_stage *timeout_stage;
+       u8 index, data, data_orig;
+       u32 mask;
+       int i, j;
+
+       pretimeout_stage = &wdt_data->stage[STAGE_PRETIMEOUT];
+       timeout_stage = &wdt_data->stage[STAGE_TIMEOUT];
+
+       pretimeout_stage->mask = 0;
+       timeout_stage->mask = 0;
+
+       for (i = 0; i < 3; i++) {
+               index = KEMPLD_WDT_STAGE_TIMEOUT(i);
+               mask = 0;
+
+               kempld_get_mutex(pld);
+               /* Probe each byte individually. */
+               for (j = 0; j < 4; j++) {
+                       data_orig = kempld_read8(pld, index + j);
+                       kempld_write8(pld, index + j, 0x00);
+                       data = kempld_read8(pld, index + j);
+                       /* A failed write means this byte is reserved */
+                       if (data != 0x00)
+                               break;
+                       kempld_write8(pld, index + j, data_orig);
+                       mask |= 0xff << (j * 8);
+               }
+               kempld_release_mutex(pld);
+
+               /* Assign available stages to timeout and pretimeout */
+               if (!timeout_stage->mask) {
+                       timeout_stage->mask = mask;
+                       timeout_stage->id = i;
+               } else {
+                       if (pld->feature_mask & KEMPLD_FEATURE_BIT_NMI) {
+                               pretimeout_stage->mask = timeout_stage->mask;
+                               timeout_stage->mask = mask;
+                               pretimeout_stage->id = timeout_stage->id;
+                               timeout_stage->id = i;
+                       }
+                       break;
+               }
+       }
+
+       if (!timeout_stage->mask)
+               return -ENODEV;
+
+       return 0;
+}
+
+static struct watchdog_info kempld_wdt_info = {
+       .identity       = "KEMPLD Watchdog",
+       .options        = WDIOF_SETTIMEOUT |
+                       WDIOF_KEEPALIVEPING |
+                       WDIOF_MAGICCLOSE |
+                       WDIOF_PRETIMEOUT
+};
+
+static struct watchdog_ops kempld_wdt_ops = {
+       .owner          = THIS_MODULE,
+       .start          = kempld_wdt_start,
+       .stop           = kempld_wdt_stop,
+       .ping           = kempld_wdt_keepalive,
+       .set_timeout    = kempld_wdt_set_timeout,
+       .ioctl          = kempld_wdt_ioctl,
+};
+
+static int kempld_wdt_probe(struct platform_device *pdev)
+{
+       struct kempld_device_data *pld = dev_get_drvdata(pdev->dev.parent);
+       struct kempld_wdt_data *wdt_data;
+       struct device *dev = &pdev->dev;
+       struct watchdog_device *wdd;
+       u8 status;
+       int ret = 0;
+
+       wdt_data = devm_kzalloc(dev, sizeof(*wdt_data), GFP_KERNEL);
+       if (!wdt_data)
+               return -ENOMEM;
+
+       wdt_data->pld = pld;
+       wdd = &wdt_data->wdd;
+       wdd->parent = dev;
+
+       kempld_get_mutex(pld);
+       status = kempld_read8(pld, KEMPLD_WDT_CFG);
+       kempld_release_mutex(pld);
+
+       /* Enable nowayout if watchdog is already locked */
+       if (status & (KEMPLD_WDT_CFG_ENABLE_LOCK |
+                       KEMPLD_WDT_CFG_GLOBAL_LOCK)) {
+               if (!nowayout)
+                       dev_warn(dev,
+                               "Forcing nowayout - watchdog lock enabled!\n");
+               nowayout = true;
+       }
+
+       wdd->info = &kempld_wdt_info;
+       wdd->ops = &kempld_wdt_ops;
+
+       watchdog_set_drvdata(wdd, wdt_data);
+       watchdog_set_nowayout(wdd, nowayout);
+
+       ret = kempld_wdt_probe_stages(wdd);
+       if (ret)
+               return ret;
+
+       kempld_wdt_set_timeout(wdd, timeout);
+       kempld_wdt_set_pretimeout(wdd, pretimeout);
+
+       /* Check if watchdog is already enabled */
+       if (status & KEMPLD_WDT_CFG_ENABLE) {
+               /* Get current watchdog settings */
+               kempld_wdt_update_timeouts(wdt_data);
+               dev_info(dev, "Watchdog was already enabled\n");
+       }
+
+       platform_set_drvdata(pdev, wdt_data);
+       ret = watchdog_register_device(wdd);
+       if (ret)
+               return ret;
+
+       dev_info(dev, "Watchdog registered with %ds timeout\n", wdd->timeout);
+
+       return 0;
+}
+
+static void kempld_wdt_shutdown(struct platform_device *pdev)
+{
+       struct kempld_wdt_data *wdt_data = platform_get_drvdata(pdev);
+
+       kempld_wdt_stop(&wdt_data->wdd);
+}
+
+static int kempld_wdt_remove(struct platform_device *pdev)
+{
+       struct kempld_wdt_data *wdt_data = platform_get_drvdata(pdev);
+       struct watchdog_device *wdd = &wdt_data->wdd;
+       int ret = 0;
+
+       if (!nowayout)
+               ret = kempld_wdt_stop(wdd);
+       watchdog_unregister_device(wdd);
+
+       return ret;
+}
+
+#ifdef CONFIG_PM
+/* Disable watchdog if it is active during suspend */
+static int kempld_wdt_suspend(struct platform_device *pdev,
+                               pm_message_t message)
+{
+       struct kempld_wdt_data *wdt_data = platform_get_drvdata(pdev);
+       struct kempld_device_data *pld = wdt_data->pld;
+       struct watchdog_device *wdd = &wdt_data->wdd;
+
+       kempld_get_mutex(pld);
+       wdt_data->pm_status_store = kempld_read8(pld, KEMPLD_WDT_CFG);
+       kempld_release_mutex(pld);
+
+       kempld_wdt_update_timeouts(wdt_data);
+
+       if (wdt_data->pm_status_store & KEMPLD_WDT_CFG_ENABLE)
+               return kempld_wdt_stop(wdd);
+
+       return 0;
+}
+
+/* Enable watchdog and configure it if necessary */
+static int kempld_wdt_resume(struct platform_device *pdev)
+{
+       struct kempld_wdt_data *wdt_data = platform_get_drvdata(pdev);
+       struct watchdog_device *wdd = &wdt_data->wdd;
+
+       /*
+        * If watchdog was stopped before suspend be sure it gets disabled
+        * again, for the case BIOS has enabled it during resume
+        */
+       if (wdt_data->pm_status_store & KEMPLD_WDT_CFG_ENABLE)
+               return kempld_wdt_start(wdd);
+       else
+               return kempld_wdt_stop(wdd);
+}
+#else
+#define kempld_wdt_suspend     NULL
+#define kempld_wdt_resume      NULL
+#endif
+
+static struct platform_driver kempld_wdt_driver = {
+       .driver         = {
+               .name   = "kempld-wdt",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = kempld_wdt_probe,
+       .remove         = kempld_wdt_remove,
+       .shutdown       = kempld_wdt_shutdown,
+       .suspend        = kempld_wdt_suspend,
+       .resume         = kempld_wdt_resume,
+};
+
+module_platform_driver(kempld_wdt_driver);
+
+MODULE_DESCRIPTION("KEM PLD Watchdog Driver");
+MODULE_AUTHOR("Michael Brunner <michael.brunner@kontron.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/watchdog/mena21_wdt.c b/drivers/watchdog/mena21_wdt.c
new file mode 100644 (file)
index 0000000..96dbba9
--- /dev/null
@@ -0,0 +1,270 @@
+/*
+ * Watchdog driver for the A21 VME CPU Boards
+ *
+ * Copyright (C) 2013 MEN Mikro Elektronik Nuernberg GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation
+ */
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/watchdog.h>
+#include <linux/uaccess.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/delay.h>
+#include <linux/bitops.h>
+
+#define NUM_GPIOS 6
+
+enum a21_wdt_gpios {
+       GPIO_WD_ENAB,
+       GPIO_WD_FAST,
+       GPIO_WD_TRIG,
+       GPIO_WD_RST0,
+       GPIO_WD_RST1,
+       GPIO_WD_RST2,
+};
+
+struct a21_wdt_drv {
+       struct watchdog_device wdt;
+       struct mutex lock;
+       unsigned gpios[NUM_GPIOS];
+};
+
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
+                           __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+
+static unsigned int a21_wdt_get_bootstatus(struct a21_wdt_drv *drv)
+{
+       int reset = 0;
+
+       reset |= gpio_get_value(drv->gpios[GPIO_WD_RST0]) ? (1 << 0) : 0;
+       reset |= gpio_get_value(drv->gpios[GPIO_WD_RST1]) ? (1 << 1) : 0;
+       reset |= gpio_get_value(drv->gpios[GPIO_WD_RST2]) ? (1 << 2) : 0;
+
+       return reset;
+}
+
+static int a21_wdt_start(struct watchdog_device *wdt)
+{
+       struct a21_wdt_drv *drv = watchdog_get_drvdata(wdt);
+
+       mutex_lock(&drv->lock);
+
+       gpio_set_value(drv->gpios[GPIO_WD_ENAB], 1);
+
+       mutex_unlock(&drv->lock);
+
+       return 0;
+}
+
+static int a21_wdt_stop(struct watchdog_device *wdt)
+{
+       struct a21_wdt_drv *drv = watchdog_get_drvdata(wdt);
+
+       mutex_lock(&drv->lock);
+
+       gpio_set_value(drv->gpios[GPIO_WD_ENAB], 0);
+
+       mutex_unlock(&drv->lock);
+
+       return 0;
+}
+
+static int a21_wdt_ping(struct watchdog_device *wdt)
+{
+       struct a21_wdt_drv *drv = watchdog_get_drvdata(wdt);
+
+       mutex_lock(&drv->lock);
+
+       gpio_set_value(drv->gpios[GPIO_WD_TRIG], 0);
+       ndelay(10);
+       gpio_set_value(drv->gpios[GPIO_WD_TRIG], 1);
+
+       mutex_unlock(&drv->lock);
+
+       return 0;
+}
+
+static int a21_wdt_set_timeout(struct watchdog_device *wdt,
+                              unsigned int timeout)
+{
+       struct a21_wdt_drv *drv = watchdog_get_drvdata(wdt);
+
+       if (timeout != 1 && timeout != 30) {
+               dev_err(wdt->dev, "Only 1 and 30 allowed as timeout\n");
+               return -EINVAL;
+       }
+
+       if (timeout == 30 && wdt->timeout == 1) {
+               dev_err(wdt->dev,
+                       "Transition from fast to slow mode not allowed\n");
+               return -EINVAL;
+       }
+
+       mutex_lock(&drv->lock);
+
+       if (timeout == 1)
+               gpio_set_value(drv->gpios[GPIO_WD_FAST], 1);
+       else
+               gpio_set_value(drv->gpios[GPIO_WD_FAST], 0);
+
+       wdt->timeout = timeout;
+
+       mutex_unlock(&drv->lock);
+
+       return 0;
+}
+
+static const struct watchdog_info a21_wdt_info = {
+       .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
+       .identity = "MEN A21 Watchdog",
+};
+
+static const struct watchdog_ops a21_wdt_ops = {
+       .owner = THIS_MODULE,
+       .start = a21_wdt_start,
+       .stop = a21_wdt_stop,
+       .ping = a21_wdt_ping,
+       .set_timeout = a21_wdt_set_timeout,
+};
+
+static struct watchdog_device a21_wdt = {
+       .info = &a21_wdt_info,
+       .ops = &a21_wdt_ops,
+       .min_timeout = 1,
+       .max_timeout = 30,
+};
+
+static int a21_wdt_probe(struct platform_device *pdev)
+{
+       struct device_node *node;
+       struct a21_wdt_drv *drv;
+       unsigned int reset = 0;
+       int num_gpios;
+       int ret;
+       int i;
+
+       drv = devm_kzalloc(&pdev->dev, sizeof(struct a21_wdt_drv), GFP_KERNEL);
+       if (!drv)
+               return -ENOMEM;
+
+       /* Fill GPIO pin array */
+       node = pdev->dev.of_node;
+
+       num_gpios = of_gpio_count(node);
+       if (num_gpios != NUM_GPIOS) {
+               dev_err(&pdev->dev, "gpios DT property wrong, got %d want %d",
+                       num_gpios, NUM_GPIOS);
+               return -ENODEV;
+       }
+
+       for (i = 0; i < num_gpios; i++) {
+               int val;
+
+               val = of_get_gpio(node, i);
+               if (val < 0)
+                       return val;
+
+               drv->gpios[i] = val;
+       }
+
+       /* Request the used GPIOs */
+       for (i = 0; i < num_gpios; i++) {
+               ret = devm_gpio_request(&pdev->dev, drv->gpios[i],
+                                       "MEN A21 Watchdog");
+               if (ret)
+                       return ret;
+
+               if (i < GPIO_WD_RST0)
+                       ret = gpio_direction_output(drv->gpios[i],
+                                               gpio_get_value(drv->gpios[i]));
+               else            /* GPIO_WD_RST[0..2] are inputs */
+                       ret = gpio_direction_input(drv->gpios[i]);
+               if (ret)
+                       return ret;
+       }
+
+       mutex_init(&drv->lock);
+       watchdog_init_timeout(&a21_wdt, 30, &pdev->dev);
+       watchdog_set_nowayout(&a21_wdt, nowayout);
+       watchdog_set_drvdata(&a21_wdt, drv);
+
+       reset = a21_wdt_get_bootstatus(drv);
+       if (reset == 2)
+               a21_wdt.bootstatus |= WDIOF_EXTERN1;
+       else if (reset == 4)
+               a21_wdt.bootstatus |= WDIOF_CARDRESET;
+       else if (reset == 5)
+               a21_wdt.bootstatus |= WDIOF_POWERUNDER;
+       else if (reset == 7)
+               a21_wdt.bootstatus |= WDIOF_EXTERN2;
+
+       ret = watchdog_register_device(&a21_wdt);
+       if (ret) {
+               dev_err(&pdev->dev, "Cannot register watchdog device\n");
+               goto err_register_wd;
+       }
+
+       dev_set_drvdata(&pdev->dev, drv);
+
+       dev_info(&pdev->dev, "MEN A21 watchdog timer driver enabled\n");
+
+       return 0;
+
+err_register_wd:
+       mutex_destroy(&drv->lock);
+
+       return ret;
+}
+
+static int a21_wdt_remove(struct platform_device *pdev)
+{
+       struct a21_wdt_drv *drv = dev_get_drvdata(&pdev->dev);
+
+       dev_warn(&pdev->dev,
+               "Unregistering A21 watchdog driver, board may reboot\n");
+
+       watchdog_unregister_device(&drv->wdt);
+
+       mutex_destroy(&drv->lock);
+
+       return 0;
+}
+
+static void a21_wdt_shutdown(struct platform_device *pdev)
+{
+       struct a21_wdt_drv *drv = dev_get_drvdata(&pdev->dev);
+
+       gpio_set_value(drv->gpios[GPIO_WD_ENAB], 0);
+}
+
+static const struct of_device_id a21_wdt_ids[] = {
+       { .compatible = "men,a021-wdt" },
+       { },
+};
+
+static struct platform_driver a21_wdt_driver = {
+       .probe = a21_wdt_probe,
+       .remove = a21_wdt_remove,
+       .shutdown = a21_wdt_shutdown,
+       .driver = {
+               .name = "a21-watchdog",
+               .of_match_table = a21_wdt_ids,
+       },
+};
+
+module_platform_driver(a21_wdt_driver);
+
+MODULE_AUTHOR("MEN Mikro Elektronik");
+MODULE_DESCRIPTION("MEN A21 Watchdog");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:a21-watchdog");
diff --git a/drivers/watchdog/mpcore_wdt.c b/drivers/watchdog/mpcore_wdt.c
deleted file mode 100644 (file)
index 233cfad..0000000
+++ /dev/null
@@ -1,456 +0,0 @@
-/*
- *     Watchdog driver for the mpcore watchdog timer
- *
- *     (c) Copyright 2004 ARM Limited
- *
- *     Based on the SoftDog driver:
- *     (c) Copyright 1996 Alan Cox <alan@lxorguk.ukuu.org.uk>,
- *                                             All Rights Reserved.
- *
- *     This program is free software; you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License
- *     as published by the Free Software Foundation; either version
- *     2 of the License, or (at your option) any later version.
- *
- *     Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
- *     warranty for any of this software. This material is provided
- *     "AS-IS" and at no charge.
- *
- *     (c) Copyright 1995    Alan Cox <alan@lxorguk.ukuu.org.uk>
- *
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/types.h>
-#include <linux/miscdevice.h>
-#include <linux/watchdog.h>
-#include <linux/fs.h>
-#include <linux/reboot.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/platform_device.h>
-#include <linux/uaccess.h>
-#include <linux/slab.h>
-#include <linux/io.h>
-
-#include <asm/smp_twd.h>
-
-struct mpcore_wdt {
-       unsigned long   timer_alive;
-       struct device   *dev;
-       void __iomem    *base;
-       int             irq;
-       unsigned int    perturb;
-       char            expect_close;
-};
-
-static struct platform_device *mpcore_wdt_pdev;
-static DEFINE_SPINLOCK(wdt_lock);
-
-#define TIMER_MARGIN   60
-static int mpcore_margin = TIMER_MARGIN;
-module_param(mpcore_margin, int, 0);
-MODULE_PARM_DESC(mpcore_margin,
-       "MPcore timer margin in seconds. (0 < mpcore_margin < 65536, default="
-                               __MODULE_STRING(TIMER_MARGIN) ")");
-
-static bool nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, bool, 0);
-MODULE_PARM_DESC(nowayout,
-       "Watchdog cannot be stopped once started (default="
-                               __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
-
-#define ONLY_TESTING   0
-static int mpcore_noboot = ONLY_TESTING;
-module_param(mpcore_noboot, int, 0);
-MODULE_PARM_DESC(mpcore_noboot, "MPcore watchdog action, "
-       "set to 1 to ignore reboots, 0 to reboot (default="
-                                       __MODULE_STRING(ONLY_TESTING) ")");
-
-/*
- *     This is the interrupt handler.  Note that we only use this
- *     in testing mode, so don't actually do a reboot here.
- */
-static irqreturn_t mpcore_wdt_fire(int irq, void *arg)
-{
-       struct mpcore_wdt *wdt = arg;
-
-       /* Check it really was our interrupt */
-       if (readl(wdt->base + TWD_WDOG_INTSTAT)) {
-               dev_crit(wdt->dev, "Triggered - Reboot ignored\n");
-               /* Clear the interrupt on the watchdog */
-               writel(1, wdt->base + TWD_WDOG_INTSTAT);
-               return IRQ_HANDLED;
-       }
-       return IRQ_NONE;
-}
-
-/*
- *     mpcore_wdt_keepalive - reload the timer
- *
- *     Note that the spec says a DIFFERENT value must be written to the reload
- *     register each time.  The "perturb" variable deals with this by adding 1
- *     to the count every other time the function is called.
- */
-static void mpcore_wdt_keepalive(struct mpcore_wdt *wdt)
-{
-       unsigned long count;
-
-       spin_lock(&wdt_lock);
-       /* Assume prescale is set to 256 */
-       count =  __raw_readl(wdt->base + TWD_WDOG_COUNTER);
-       count = (0xFFFFFFFFU - count) * (HZ / 5);
-       count = (count / 256) * mpcore_margin;
-
-       /* Reload the counter */
-       writel(count + wdt->perturb, wdt->base + TWD_WDOG_LOAD);
-       wdt->perturb = wdt->perturb ? 0 : 1;
-       spin_unlock(&wdt_lock);
-}
-
-static void mpcore_wdt_stop(struct mpcore_wdt *wdt)
-{
-       spin_lock(&wdt_lock);
-       writel(0x12345678, wdt->base + TWD_WDOG_DISABLE);
-       writel(0x87654321, wdt->base + TWD_WDOG_DISABLE);
-       writel(0x0, wdt->base + TWD_WDOG_CONTROL);
-       spin_unlock(&wdt_lock);
-}
-
-static void mpcore_wdt_start(struct mpcore_wdt *wdt)
-{
-       dev_info(wdt->dev, "enabling watchdog\n");
-
-       /* This loads the count register but does NOT start the count yet */
-       mpcore_wdt_keepalive(wdt);
-
-       if (mpcore_noboot) {
-               /* Enable watchdog - prescale=256, watchdog mode=0, enable=1 */
-               writel(0x0000FF01, wdt->base + TWD_WDOG_CONTROL);
-       } else {
-               /* Enable watchdog - prescale=256, watchdog mode=1, enable=1 */
-               writel(0x0000FF09, wdt->base + TWD_WDOG_CONTROL);
-       }
-}
-
-static int mpcore_wdt_set_heartbeat(int t)
-{
-       if (t < 0x0001 || t > 0xFFFF)
-               return -EINVAL;
-
-       mpcore_margin = t;
-       return 0;
-}
-
-/*
- *     /dev/watchdog handling
- */
-static int mpcore_wdt_open(struct inode *inode, struct file *file)
-{
-       struct mpcore_wdt *wdt = platform_get_drvdata(mpcore_wdt_pdev);
-
-       if (test_and_set_bit(0, &wdt->timer_alive))
-               return -EBUSY;
-
-       if (nowayout)
-               __module_get(THIS_MODULE);
-
-       file->private_data = wdt;
-
-       /*
-        *      Activate timer
-        */
-       mpcore_wdt_start(wdt);
-
-       return nonseekable_open(inode, file);
-}
-
-static int mpcore_wdt_release(struct inode *inode, struct file *file)
-{
-       struct mpcore_wdt *wdt = file->private_data;
-
-       /*
-        *      Shut off the timer.
-        *      Lock it in if it's a module and we set nowayout
-        */
-       if (wdt->expect_close == 42)
-               mpcore_wdt_stop(wdt);
-       else {
-               dev_crit(wdt->dev,
-                        "unexpected close, not stopping watchdog!\n");
-               mpcore_wdt_keepalive(wdt);
-       }
-       clear_bit(0, &wdt->timer_alive);
-       wdt->expect_close = 0;
-       return 0;
-}
-
-static ssize_t mpcore_wdt_write(struct file *file, const char *data,
-                                               size_t len, loff_t *ppos)
-{
-       struct mpcore_wdt *wdt = file->private_data;
-
-       /*
-        *      Refresh the timer.
-        */
-       if (len) {
-               if (!nowayout) {
-                       size_t i;
-
-                       /* In case it was set long ago */
-                       wdt->expect_close = 0;
-
-                       for (i = 0; i != len; i++) {
-                               char c;
-
-                               if (get_user(c, data + i))
-                                       return -EFAULT;
-                               if (c == 'V')
-                                       wdt->expect_close = 42;
-                       }
-               }
-               mpcore_wdt_keepalive(wdt);
-       }
-       return len;
-}
-
-static const struct watchdog_info ident = {
-       .options                = WDIOF_SETTIMEOUT |
-                                 WDIOF_KEEPALIVEPING |
-                                 WDIOF_MAGICCLOSE,
-       .identity               = "MPcore Watchdog",
-};
-
-static long mpcore_wdt_ioctl(struct file *file, unsigned int cmd,
-                                                       unsigned long arg)
-{
-       struct mpcore_wdt *wdt = file->private_data;
-       int ret;
-       union {
-               struct watchdog_info ident;
-               int i;
-       } uarg;
-
-       if (_IOC_DIR(cmd) && _IOC_SIZE(cmd) > sizeof(uarg))
-               return -ENOTTY;
-
-       if (_IOC_DIR(cmd) & _IOC_WRITE) {
-               ret = copy_from_user(&uarg, (void __user *)arg, _IOC_SIZE(cmd));
-               if (ret)
-                       return -EFAULT;
-       }
-
-       switch (cmd) {
-       case WDIOC_GETSUPPORT:
-               uarg.ident = ident;
-               ret = 0;
-               break;
-
-       case WDIOC_GETSTATUS:
-       case WDIOC_GETBOOTSTATUS:
-               uarg.i = 0;
-               ret = 0;
-               break;
-
-       case WDIOC_SETOPTIONS:
-               ret = -EINVAL;
-               if (uarg.i & WDIOS_DISABLECARD) {
-                       mpcore_wdt_stop(wdt);
-                       ret = 0;
-               }
-               if (uarg.i & WDIOS_ENABLECARD) {
-                       mpcore_wdt_start(wdt);
-                       ret = 0;
-               }
-               break;
-
-       case WDIOC_KEEPALIVE:
-               mpcore_wdt_keepalive(wdt);
-               ret = 0;
-               break;
-
-       case WDIOC_SETTIMEOUT:
-               ret = mpcore_wdt_set_heartbeat(uarg.i);
-               if (ret)
-                       break;
-
-               mpcore_wdt_keepalive(wdt);
-               /* Fall */
-       case WDIOC_GETTIMEOUT:
-               uarg.i = mpcore_margin;
-               ret = 0;
-               break;
-
-       default:
-               return -ENOTTY;
-       }
-
-       if (ret == 0 && _IOC_DIR(cmd) & _IOC_READ) {
-               ret = copy_to_user((void __user *)arg, &uarg, _IOC_SIZE(cmd));
-               if (ret)
-                       ret = -EFAULT;
-       }
-       return ret;
-}
-
-/*
- *     System shutdown handler.  Turn off the watchdog if we're
- *     restarting or halting the system.
- */
-static void mpcore_wdt_shutdown(struct platform_device *pdev)
-{
-       struct mpcore_wdt *wdt = platform_get_drvdata(pdev);
-
-       if (system_state == SYSTEM_RESTART || system_state == SYSTEM_HALT)
-               mpcore_wdt_stop(wdt);
-}
-
-/*
- *     Kernel Interfaces
- */
-static const struct file_operations mpcore_wdt_fops = {
-       .owner          = THIS_MODULE,
-       .llseek         = no_llseek,
-       .write          = mpcore_wdt_write,
-       .unlocked_ioctl = mpcore_wdt_ioctl,
-       .open           = mpcore_wdt_open,
-       .release        = mpcore_wdt_release,
-};
-
-static struct miscdevice mpcore_wdt_miscdev = {
-       .minor          = WATCHDOG_MINOR,
-       .name           = "watchdog",
-       .fops           = &mpcore_wdt_fops,
-};
-
-static int mpcore_wdt_probe(struct platform_device *pdev)
-{
-       struct mpcore_wdt *wdt;
-       struct resource *res;
-       int ret;
-
-       /* We only accept one device, and it must have an id of -1 */
-       if (pdev->id != -1)
-               return -ENODEV;
-
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res)
-               return -ENODEV;
-
-       wdt = devm_kzalloc(&pdev->dev, sizeof(struct mpcore_wdt), GFP_KERNEL);
-       if (!wdt)
-               return -ENOMEM;
-
-       wdt->dev = &pdev->dev;
-       wdt->irq = platform_get_irq(pdev, 0);
-       if (wdt->irq >= 0) {
-               ret = devm_request_irq(wdt->dev, wdt->irq, mpcore_wdt_fire, 0,
-                               "mpcore_wdt", wdt);
-               if (ret) {
-                       dev_err(wdt->dev,
-                               "cannot register IRQ%d for watchdog\n",
-                               wdt->irq);
-                       return ret;
-               }
-       }
-
-       wdt->base = devm_ioremap(wdt->dev, res->start, resource_size(res));
-       if (!wdt->base)
-               return -ENOMEM;
-
-       mpcore_wdt_miscdev.parent = &pdev->dev;
-       ret = misc_register(&mpcore_wdt_miscdev);
-       if (ret) {
-               dev_err(wdt->dev,
-                       "cannot register miscdev on minor=%d (err=%d)\n",
-                       WATCHDOG_MINOR, ret);
-               return ret;
-       }
-
-       mpcore_wdt_stop(wdt);
-       platform_set_drvdata(pdev, wdt);
-       mpcore_wdt_pdev = pdev;
-
-       return 0;
-}
-
-static int mpcore_wdt_remove(struct platform_device *pdev)
-{
-       platform_set_drvdata(pdev, NULL);
-
-       misc_deregister(&mpcore_wdt_miscdev);
-
-       mpcore_wdt_pdev = NULL;
-
-       return 0;
-}
-
-#ifdef CONFIG_PM
-static int mpcore_wdt_suspend(struct platform_device *pdev, pm_message_t msg)
-{
-       struct mpcore_wdt *wdt = platform_get_drvdata(pdev);
-       mpcore_wdt_stop(wdt);           /* Turn the WDT off */
-       return 0;
-}
-
-static int mpcore_wdt_resume(struct platform_device *pdev)
-{
-       struct mpcore_wdt *wdt = platform_get_drvdata(pdev);
-       /* re-activate timer */
-       if (test_bit(0, &wdt->timer_alive))
-               mpcore_wdt_start(wdt);
-       return 0;
-}
-#else
-#define mpcore_wdt_suspend     NULL
-#define mpcore_wdt_resume      NULL
-#endif
-
-/* work with hotplug and coldplug */
-MODULE_ALIAS("platform:mpcore_wdt");
-
-static struct platform_driver mpcore_wdt_driver = {
-       .probe          = mpcore_wdt_probe,
-       .remove         = mpcore_wdt_remove,
-       .suspend        = mpcore_wdt_suspend,
-       .resume         = mpcore_wdt_resume,
-       .shutdown       = mpcore_wdt_shutdown,
-       .driver         = {
-               .owner  = THIS_MODULE,
-               .name   = "mpcore_wdt",
-       },
-};
-
-static int __init mpcore_wdt_init(void)
-{
-       /*
-        * Check that the margin value is within it's range;
-        * if not reset to the default
-        */
-       if (mpcore_wdt_set_heartbeat(mpcore_margin)) {
-               mpcore_wdt_set_heartbeat(TIMER_MARGIN);
-               pr_info("mpcore_margin value must be 0 < mpcore_margin < 65536, using %d\n",
-                       TIMER_MARGIN);
-       }
-
-       pr_info("MPcore Watchdog Timer: 0.1. mpcore_noboot=%d mpcore_margin=%d sec (nowayout= %d)\n",
-               mpcore_noboot, mpcore_margin, nowayout);
-
-       return platform_driver_register(&mpcore_wdt_driver);
-}
-
-static void __exit mpcore_wdt_exit(void)
-{
-       platform_driver_unregister(&mpcore_wdt_driver);
-}
-
-module_init(mpcore_wdt_init);
-module_exit(mpcore_wdt_exit);
-
-MODULE_AUTHOR("ARM Limited");
-MODULE_DESCRIPTION("MPcore Watchdog Device Driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
index 14dab6f..b434111 100644 (file)
@@ -209,7 +209,7 @@ static int mtx1_wdt_probe(struct platform_device *pdev)
        int ret;
 
        mtx1_wdt_device.gpio = pdev->resource[0].start;
-       ret = gpio_request_one(mtx1_wdt_device.gpio,
+       ret = devm_gpio_request_one(&pdev->dev, mtx1_wdt_device.gpio,
                                GPIOF_OUT_INIT_HIGH, "mtx1-wdt");
        if (ret < 0) {
                dev_err(&pdev->dev, "failed to request gpio");
@@ -241,7 +241,6 @@ static int mtx1_wdt_remove(struct platform_device *pdev)
                wait_for_completion(&mtx1_wdt_device.stop);
        }
 
-       gpio_free(mtx1_wdt_device.gpio);
        misc_deregister(&mtx1_wdt_misc);
        return 0;
 }
index c7fb878..e4cf980 100644 (file)
@@ -276,7 +276,7 @@ static int mv64x60_wdt_probe(struct platform_device *dev)
        if (!r)
                return -ENODEV;
 
-       mv64x60_wdt_regs = ioremap(r->start, resource_size(r));
+       mv64x60_wdt_regs = devm_ioremap(&dev->dev, r->start, resource_size(r));
        if (mv64x60_wdt_regs == NULL)
                return -ENOMEM;
 
@@ -293,8 +293,6 @@ static int mv64x60_wdt_remove(struct platform_device *dev)
 
        mv64x60_wdt_handler_disable();
 
-       iounmap(mv64x60_wdt_regs);
-
        return 0;
 }
 
index 04c45a1..e2b6d2c 100644 (file)
@@ -61,7 +61,6 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
        "(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
 
 struct nuc900_wdt {
-       struct resource  *res;
        struct clk       *wdt_clock;
        struct platform_device *pdev;
        void __iomem     *wdt_base;
@@ -244,9 +243,11 @@ static struct miscdevice nuc900wdt_miscdev = {
 
 static int nuc900wdt_probe(struct platform_device *pdev)
 {
+       struct resource *res;
        int ret = 0;
 
-       nuc900_wdt = kzalloc(sizeof(struct nuc900_wdt), GFP_KERNEL);
+       nuc900_wdt = devm_kzalloc(&pdev->dev, sizeof(*nuc900_wdt),
+                               GFP_KERNEL);
        if (!nuc900_wdt)
                return -ENOMEM;
 
@@ -254,33 +255,20 @@ static int nuc900wdt_probe(struct platform_device *pdev)
 
        spin_lock_init(&nuc900_wdt->wdt_lock);
 
-       nuc900_wdt->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (nuc900_wdt->res == NULL) {
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (res == NULL) {
                dev_err(&pdev->dev, "no memory resource specified\n");
-               ret = -ENOENT;
-               goto err_get;
+               return -ENOENT;
        }
 
-       if (!request_mem_region(nuc900_wdt->res->start,
-                               resource_size(nuc900_wdt->res), pdev->name)) {
-               dev_err(&pdev->dev, "failed to get memory region\n");
-               ret = -ENOENT;
-               goto err_get;
-       }
-
-       nuc900_wdt->wdt_base = ioremap(nuc900_wdt->res->start,
-                                       resource_size(nuc900_wdt->res));
-       if (nuc900_wdt->wdt_base == NULL) {
-               dev_err(&pdev->dev, "failed to ioremap() region\n");
-               ret = -EINVAL;
-               goto err_req;
-       }
+       nuc900_wdt->wdt_base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(nuc900_wdt->wdt_base))
+               return PTR_ERR(nuc900_wdt->wdt_base);
 
-       nuc900_wdt->wdt_clock = clk_get(&pdev->dev, NULL);
+       nuc900_wdt->wdt_clock = devm_clk_get(&pdev->dev, NULL);
        if (IS_ERR(nuc900_wdt->wdt_clock)) {
                dev_err(&pdev->dev, "failed to find watchdog clock source\n");
-               ret = PTR_ERR(nuc900_wdt->wdt_clock);
-               goto err_map;
+               return PTR_ERR(nuc900_wdt->wdt_clock);
        }
 
        clk_enable(nuc900_wdt->wdt_clock);
@@ -298,14 +286,6 @@ static int nuc900wdt_probe(struct platform_device *pdev)
 
 err_clk:
        clk_disable(nuc900_wdt->wdt_clock);
-       clk_put(nuc900_wdt->wdt_clock);
-err_map:
-       iounmap(nuc900_wdt->wdt_base);
-err_req:
-       release_mem_region(nuc900_wdt->res->start,
-                                       resource_size(nuc900_wdt->res));
-err_get:
-       kfree(nuc900_wdt);
        return ret;
 }
 
@@ -314,14 +294,6 @@ static int nuc900wdt_remove(struct platform_device *pdev)
        misc_deregister(&nuc900wdt_miscdev);
 
        clk_disable(nuc900_wdt->wdt_clock);
-       clk_put(nuc900_wdt->wdt_clock);
-
-       iounmap(nuc900_wdt->wdt_base);
-
-       release_mem_region(nuc900_wdt->res->start,
-                                       resource_size(nuc900_wdt->res));
-
-       kfree(nuc900_wdt);
 
        return 0;
 }
index 2761ddb..4dd281f 100644 (file)
@@ -1,23 +1,13 @@
 /*
-*   of_xilinx_wdt.c  1.01  A Watchdog Device Driver for Xilinx xps_timebase_wdt
-*
-*   (C) Copyright 2011 (Alejandro Cabrera <aldaya@gmail.com>)
-*
-*       -----------------------
-*
-*   This program is free software; you can redistribute it and/or
-*   modify it under the terms of the GNU General Public License
-*   as published by the Free Software Foundation; either version
-*   2 of the License, or (at your option) any later version.
-*
-*       -----------------------
-*      30-May-2011 Alejandro Cabrera <aldaya@gmail.com>
-*              - If "xlnx,wdt-enable-once" wasn't found on device tree the
-*                module will use CONFIG_WATCHDOG_NOWAYOUT
-*              - If the device tree parameters ("clock-frequency" and
-*                "xlnx,wdt-interval") wasn't found the driver won't
-*                know the wdt reset interval
-*/
+ * Watchdog Device Driver for Xilinx axi/xps_timebase_wdt
+ *
+ * (C) Copyright 2011 (Alejandro Cabrera <aldaya@gmail.com>)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
@@ -394,6 +384,7 @@ static int xwdt_remove(struct platform_device *dev)
 
 /* Match table for of_platform binding */
 static struct of_device_id xwdt_of_match[] = {
+       { .compatible = "xlnx,xps-timebase-wdt-1.00.a", },
        { .compatible = "xlnx,xps-timebase-wdt-1.01.a", },
        {},
 };
@@ -413,5 +404,5 @@ module_platform_driver(xwdt_driver);
 
 MODULE_AUTHOR("Alejandro Cabrera <aldaya@gmail.com>");
 MODULE_DESCRIPTION("Xilinx Watchdog driver");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
 MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
index da57798..4ea5fcc 100644 (file)
@@ -38,6 +38,9 @@
 #define WDT_IN_USE             0
 #define WDT_OK_TO_CLOSE                1
 
+#define WDT_RESET_OUT_EN       BIT(1)
+#define WDT_INT_REQ            BIT(3)
+
 static bool nowayout = WATCHDOG_NOWAYOUT;
 static int heartbeat = -1;             /* module parameter (seconds) */
 static unsigned int wdt_max_duration;  /* (seconds) */
@@ -67,9 +70,7 @@ static int orion_wdt_start(struct watchdog_device *wdt_dev)
        writel(wdt_tclk * wdt_dev->timeout, wdt_reg + WDT_VAL);
 
        /* Clear watchdog timer interrupt */
-       reg = readl(BRIDGE_CAUSE);
-       reg &= ~WDT_INT_REQ;
-       writel(reg, BRIDGE_CAUSE);
+       writel(~WDT_INT_REQ, BRIDGE_CAUSE);
 
        /* Enable watchdog timer */
        reg = readl(wdt_reg + TIMER_CTRL);
index a3684a3..b30bd43 100644 (file)
@@ -159,13 +159,13 @@ static int pnx4008_wdt_probe(struct platform_device *pdev)
        if (IS_ERR(wdt_base))
                return PTR_ERR(wdt_base);
 
-       wdt_clk = clk_get(&pdev->dev, NULL);
+       wdt_clk = devm_clk_get(&pdev->dev, NULL);
        if (IS_ERR(wdt_clk))
                return PTR_ERR(wdt_clk);
 
        ret = clk_enable(wdt_clk);
        if (ret)
-               goto out;
+               return ret;
 
        pnx4008_wdd.bootstatus = (readl(WDTIM_RES(wdt_base)) & WDOG_RESET) ?
                        WDIOF_CARDRESET : 0;
@@ -186,8 +186,6 @@ static int pnx4008_wdt_probe(struct platform_device *pdev)
 
 disable_clk:
        clk_disable(wdt_clk);
-out:
-       clk_put(wdt_clk);
        return ret;
 }
 
@@ -196,7 +194,6 @@ static int pnx4008_wdt_remove(struct platform_device *pdev)
        watchdog_unregister_device(&pnx4008_wdd);
 
        clk_disable(wdt_clk);
-       clk_put(wdt_clk);
 
        return 0;
 }
index f78bc00..9cf6bc7 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/platform_device.h>     /* For platform_driver framework */
 #include <linux/spinlock.h>            /* For spin_lock/spin_unlock/... */
 #include <linux/uaccess.h>             /* For copy_to_user/put_user/... */
+#include <linux/io.h>                  /* For devm_ioremap_nocache */
 
 #include <asm/mach-rc32434/integ.h>    /* For the Watchdog registers */
 
@@ -271,7 +272,7 @@ static int rc32434_wdt_probe(struct platform_device *pdev)
                return -ENODEV;
        }
 
-       wdt_reg = ioremap_nocache(r->start, resource_size(r));
+       wdt_reg = devm_ioremap_nocache(&pdev->dev, r->start, resource_size(r));
        if (!wdt_reg) {
                pr_err("failed to remap I/O resources\n");
                return -ENXIO;
@@ -293,23 +294,18 @@ static int rc32434_wdt_probe(struct platform_device *pdev)
        ret = misc_register(&rc32434_wdt_miscdev);
        if (ret < 0) {
                pr_err("failed to register watchdog device\n");
-               goto unmap;
+               return ret;
        }
 
        pr_info("Watchdog Timer version " VERSION ", timer margin: %d sec\n",
                timeout);
 
        return 0;
-
-unmap:
-       iounmap(wdt_reg);
-       return ret;
 }
 
 static int rc32434_wdt_remove(struct platform_device *pdev)
 {
        misc_deregister(&rc32434_wdt_miscdev);
-       iounmap(wdt_reg);
        return 0;
 }
 
index 0040451..3dd8ed2 100644 (file)
@@ -183,7 +183,7 @@ static int riowd_probe(struct platform_device *op)
                goto out;
 
        err = -ENOMEM;
-       p = kzalloc(sizeof(*p), GFP_KERNEL);
+       p = devm_kzalloc(&op->dev, sizeof(*p), GFP_KERNEL);
        if (!p)
                goto out;
 
@@ -192,7 +192,7 @@ static int riowd_probe(struct platform_device *op)
        p->regs = of_ioremap(&op->resource[0], 0, 2, DRIVER_NAME);
        if (!p->regs) {
                pr_err("Cannot map registers\n");
-               goto out_free;
+               goto out;
        }
        /* Make miscdev useable right away */
        riowd_device = p;
@@ -206,27 +206,23 @@ static int riowd_probe(struct platform_device *op)
        pr_info("Hardware watchdog [%i minutes], regs at %p\n",
                riowd_timeout, p->regs);
 
-       dev_set_drvdata(&op->dev, p);
+       platform_set_drvdata(op, p);
        return 0;
 
 out_iounmap:
        riowd_device = NULL;
        of_iounmap(&op->resource[0], p->regs, 2);
 
-out_free:
-       kfree(p);
-
 out:
        return err;
 }
 
 static int riowd_remove(struct platform_device *op)
 {
-       struct riowd *p = dev_get_drvdata(&op->dev);
+       struct riowd *p = platform_get_drvdata(op);
 
        misc_deregister(&riowd_miscdev);
        of_iounmap(&op->resource[0], p->regs, 2);
-       kfree(p);
 
        return 0;
 }
index 3a9f696..6a22cf5 100644 (file)
@@ -358,7 +358,7 @@ static int s3c2410wdt_probe(struct platform_device *pdev)
 
        ret = s3c2410wdt_cpufreq_register();
        if (ret < 0) {
-               pr_err("failed to register cpufreq\n");
+               dev_err(dev, "failed to register cpufreq\n");
                goto err_clk;
        }
 
@@ -448,12 +448,12 @@ static void s3c2410wdt_shutdown(struct platform_device *dev)
        s3c2410wdt_stop(&s3c2410_wdd);
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 
 static unsigned long wtcon_save;
 static unsigned long wtdat_save;
 
-static int s3c2410wdt_suspend(struct platform_device *dev, pm_message_t state)
+static int s3c2410wdt_suspend(struct device *dev)
 {
        /* Save watchdog state, and turn it off. */
        wtcon_save = readl(wdt_base + S3C2410_WTCON);
@@ -465,7 +465,7 @@ static int s3c2410wdt_suspend(struct platform_device *dev, pm_message_t state)
        return 0;
 }
 
-static int s3c2410wdt_resume(struct platform_device *dev)
+static int s3c2410wdt_resume(struct device *dev)
 {
        /* Restore watchdog state. */
 
@@ -473,16 +473,15 @@ static int s3c2410wdt_resume(struct platform_device *dev)
        writel(wtdat_save, wdt_base + S3C2410_WTCNT); /* Reset count */
        writel(wtcon_save, wdt_base + S3C2410_WTCON);
 
-       pr_info("watchdog %sabled\n",
+       dev_info(dev, "watchdog %sabled\n",
                (wtcon_save & S3C2410_WTCON_ENABLE) ? "en" : "dis");
 
        return 0;
 }
+#endif
 
-#else
-#define s3c2410wdt_suspend NULL
-#define s3c2410wdt_resume  NULL
-#endif /* CONFIG_PM */
+static SIMPLE_DEV_PM_OPS(s3c2410wdt_pm_ops, s3c2410wdt_suspend,
+                       s3c2410wdt_resume);
 
 #ifdef CONFIG_OF
 static const struct of_device_id s3c2410_wdt_match[] = {
@@ -496,11 +495,10 @@ static struct platform_driver s3c2410wdt_driver = {
        .probe          = s3c2410wdt_probe,
        .remove         = s3c2410wdt_remove,
        .shutdown       = s3c2410wdt_shutdown,
-       .suspend        = s3c2410wdt_suspend,
-       .resume         = s3c2410wdt_resume,
        .driver         = {
                .owner  = THIS_MODULE,
                .name   = "s3c2410-wdt",
+               .pm     = &s3c2410wdt_pm_ops,
                .of_match_table = of_match_ptr(s3c2410_wdt_match),
        },
 };
index 25c7a3f..ea5d84a 100644 (file)
@@ -208,7 +208,7 @@ static long sbwdog_ioctl(struct file *file, unsigned int cmd,
                 * get the remaining count from the ... count register
                 * which is 1*8 before the config register
                 */
-               ret = put_user(__raw_readq(user_dog - 8) / 1000000, p);
+               ret = put_user((u32)__raw_readq(user_dog - 8) / 1000000, p);
                break;
        }
        return ret;
index 6185af2..5bca794 100644 (file)
@@ -241,7 +241,7 @@ static int sh_wdt_probe(struct platform_device *pdev)
 
        wdt->dev = &pdev->dev;
 
-       wdt->clk = clk_get(&pdev->dev, NULL);
+       wdt->clk = devm_clk_get(&pdev->dev, NULL);
        if (IS_ERR(wdt->clk)) {
                /*
                 * Clock framework support is optional, continue on
@@ -251,10 +251,8 @@ static int sh_wdt_probe(struct platform_device *pdev)
        }
 
        wdt->base = devm_ioremap_resource(wdt->dev, res);
-       if (IS_ERR(wdt->base)) {
-               rc = PTR_ERR(wdt->base);
-               goto err;
-       }
+       if (IS_ERR(wdt->base))
+               return PTR_ERR(wdt->base);
 
        watchdog_set_nowayout(&sh_wdt_dev, nowayout);
        watchdog_set_drvdata(&sh_wdt_dev, wdt);
@@ -277,7 +275,7 @@ static int sh_wdt_probe(struct platform_device *pdev)
        rc = watchdog_register_device(&sh_wdt_dev);
        if (unlikely(rc)) {
                dev_err(&pdev->dev, "Can't register watchdog (err=%d)\n", rc);
-               goto err;
+               return rc;
        }
 
        init_timer(&wdt->timer);
@@ -292,23 +290,15 @@ static int sh_wdt_probe(struct platform_device *pdev)
        pm_runtime_enable(&pdev->dev);
 
        return 0;
-
-err:
-       clk_put(wdt->clk);
-
-       return rc;
 }
 
 static int sh_wdt_remove(struct platform_device *pdev)
 {
        struct sh_wdt *wdt = platform_get_drvdata(pdev);
 
-       platform_set_drvdata(pdev, NULL);
-
        watchdog_unregister_device(&sh_wdt_dev);
 
        pm_runtime_disable(&pdev->dev);
-       clk_put(wdt->clk);
 
        return 0;
 }
index fe83beb..b68b1e5 100644 (file)
@@ -152,7 +152,6 @@ static struct watchdog_ops softdog_ops = {
        .owner = THIS_MODULE,
        .start = softdog_ping,
        .stop = softdog_stop,
-       .ping = softdog_ping,
        .set_timeout = softdog_set_timeout,
 };
 
index 8872642..58df98a 100644 (file)
@@ -231,7 +231,7 @@ sp805_wdt_probe(struct amba_device *adev, const struct amba_id *id)
                goto err;
        }
 
-       wdt->clk = clk_get(&adev->dev, NULL);
+       wdt->clk = devm_clk_get(&adev->dev, NULL);
        if (IS_ERR(wdt->clk)) {
                dev_warn(&adev->dev, "Clock not found\n");
                ret = PTR_ERR(wdt->clk);
@@ -251,15 +251,13 @@ sp805_wdt_probe(struct amba_device *adev, const struct amba_id *id)
        if (ret) {
                dev_err(&adev->dev, "watchdog_register_device() failed: %d\n",
                                ret);
-               goto err_register;
+               goto err;
        }
        amba_set_drvdata(adev, wdt);
 
        dev_info(&adev->dev, "registration successful\n");
        return 0;
 
-err_register:
-       clk_put(wdt->clk);
 err:
        dev_err(&adev->dev, "Probe Failed!!!\n");
        return ret;
@@ -272,7 +270,6 @@ static int sp805_wdt_remove(struct amba_device *adev)
        watchdog_unregister_device(&wdt->wdd);
        amba_set_drvdata(adev, NULL);
        watchdog_set_drvdata(&wdt->wdd, NULL);
-       clk_put(wdt->clk);
 
        return 0;
 }
index b8a9245..4da59b4 100644 (file)
@@ -396,7 +396,7 @@ static int ts72xx_wdt_probe(struct platform_device *pdev)
        struct resource *r1, *r2;
        int error = 0;
 
-       wdt = kzalloc(sizeof(struct ts72xx_wdt), GFP_KERNEL);
+       wdt = devm_kzalloc(&pdev->dev, sizeof(struct ts72xx_wdt), GFP_KERNEL);
        if (!wdt) {
                dev_err(&pdev->dev, "failed to allocate memory\n");
                return -ENOMEM;
@@ -405,44 +405,22 @@ static int ts72xx_wdt_probe(struct platform_device *pdev)
        r1 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!r1) {
                dev_err(&pdev->dev, "failed to get memory resource\n");
-               error = -ENODEV;
-               goto fail;
+               return -ENODEV;
        }
 
-       r1 = request_mem_region(r1->start, resource_size(r1), pdev->name);
-       if (!r1) {
-               dev_err(&pdev->dev, "cannot request memory region\n");
-               error = -EBUSY;
-               goto fail;
-       }
-
-       wdt->control_reg = ioremap(r1->start, resource_size(r1));
-       if (!wdt->control_reg) {
-               dev_err(&pdev->dev, "failed to map memory\n");
-               error = -ENODEV;
-               goto fail_free_control;
-       }
+       wdt->control_reg = devm_ioremap_resource(&pdev->dev, r1);
+       if (IS_ERR(wdt->control_reg))
+               return PTR_ERR(wdt->control_reg);
 
        r2 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
        if (!r2) {
                dev_err(&pdev->dev, "failed to get memory resource\n");
-               error = -ENODEV;
-               goto fail_unmap_control;
-       }
-
-       r2 = request_mem_region(r2->start, resource_size(r2), pdev->name);
-       if (!r2) {
-               dev_err(&pdev->dev, "cannot request memory region\n");
-               error = -EBUSY;
-               goto fail_unmap_control;
+               return -ENODEV;
        }
 
-       wdt->feed_reg = ioremap(r2->start, resource_size(r2));
-       if (!wdt->feed_reg) {
-               dev_err(&pdev->dev, "failed to map memory\n");
-               error = -ENODEV;
-               goto fail_free_feed;
-       }
+       wdt->feed_reg = devm_ioremap_resource(&pdev->dev, r2);
+       if (IS_ERR(wdt->feed_reg))
+               return PTR_ERR(wdt->feed_reg);
 
        platform_set_drvdata(pdev, wdt);
        ts72xx_wdt_pdev = pdev;
@@ -455,45 +433,20 @@ static int ts72xx_wdt_probe(struct platform_device *pdev)
        error = misc_register(&ts72xx_wdt_miscdev);
        if (error) {
                dev_err(&pdev->dev, "failed to register miscdev\n");
-               goto fail_unmap_feed;
+               return error;
        }
 
        dev_info(&pdev->dev, "TS-72xx Watchdog driver\n");
 
        return 0;
-
-fail_unmap_feed:
-       platform_set_drvdata(pdev, NULL);
-       iounmap(wdt->feed_reg);
-fail_free_feed:
-       release_mem_region(r2->start, resource_size(r2));
-fail_unmap_control:
-       iounmap(wdt->control_reg);
-fail_free_control:
-       release_mem_region(r1->start, resource_size(r1));
-fail:
-       kfree(wdt);
-       return error;
 }
 
 static int ts72xx_wdt_remove(struct platform_device *pdev)
 {
-       struct ts72xx_wdt *wdt = platform_get_drvdata(pdev);
-       struct resource *res;
        int error;
 
        error = misc_deregister(&ts72xx_wdt_miscdev);
-       platform_set_drvdata(pdev, NULL);
-
-       iounmap(wdt->feed_reg);
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-       release_mem_region(res->start, resource_size(res));
-
-       iounmap(wdt->control_reg);
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       release_mem_region(res->start, resource_size(res));
 
-       kfree(wdt);
        return error;
 }
 
index 0f03106..2d4535d 100644 (file)
@@ -90,10 +90,8 @@ static int twl4030_wdt_probe(struct platform_device *pdev)
        twl4030_wdt_stop(wdt);
 
        ret = watchdog_register_device(wdt);
-       if (ret) {
-               platform_set_drvdata(pdev, NULL);
+       if (ret)
                return ret;
-       }
 
        return 0;
 }
@@ -103,7 +101,6 @@ static int twl4030_wdt_remove(struct platform_device *pdev)
        struct watchdog_device *wdt = platform_get_drvdata(pdev);
 
        watchdog_unregister_device(wdt);
-       platform_set_drvdata(pdev, NULL);
 
        return 0;
 }
index faf4e18..6aaefba 100644 (file)
@@ -469,8 +469,10 @@ static int watchdog_release(struct inode *inode, struct file *file)
         * or if WDIOF_MAGICCLOSE is not set. If nowayout was set then
         * watchdog_stop will fail.
         */
-       if (test_and_clear_bit(WDOG_ALLOW_RELEASE, &wdd->status) ||
-           !(wdd->info->options & WDIOF_MAGICCLOSE))
+       if (!test_bit(WDOG_ACTIVE, &wdd->status))
+               err = 0;
+       else if (test_and_clear_bit(WDOG_ALLOW_RELEASE, &wdd->status) ||
+                !(wdd->info->options & WDIOF_MAGICCLOSE))
                err = watchdog_stop(wdd);
 
        /* If the watchdog was not stopped, send a keepalive ping */
index 0a77655..3045deb 100644 (file)
@@ -162,31 +162,6 @@ static void wdrtas_timer_stop(void)
 }
 
 /**
- * wdrtas_log_scanned_event - logs an event we received during keepalive
- *
- * wdrtas_log_scanned_event prints a message to the log buffer dumping
- * the results of the last event-scan call
- */
-static void wdrtas_log_scanned_event(void)
-{
-       int i;
-
-       for (i = 0; i < WDRTAS_LOGBUFFER_LEN; i += 16)
-               pr_info("dumping event (line %i/%i), data = "
-                       "%02x %02x %02x %02x  %02x %02x %02x %02x   "
-                       "%02x %02x %02x %02x  %02x %02x %02x %02x\n",
-                       (i / 16) + 1, (WDRTAS_LOGBUFFER_LEN / 16),
-                       wdrtas_logbuffer[i + 0], wdrtas_logbuffer[i + 1],
-                       wdrtas_logbuffer[i + 2], wdrtas_logbuffer[i + 3],
-                       wdrtas_logbuffer[i + 4], wdrtas_logbuffer[i + 5],
-                       wdrtas_logbuffer[i + 6], wdrtas_logbuffer[i + 7],
-                       wdrtas_logbuffer[i + 8], wdrtas_logbuffer[i + 9],
-                       wdrtas_logbuffer[i + 10], wdrtas_logbuffer[i + 11],
-                       wdrtas_logbuffer[i + 12], wdrtas_logbuffer[i + 13],
-                       wdrtas_logbuffer[i + 14], wdrtas_logbuffer[i + 15]);
-}
-
-/**
  * wdrtas_timer_keepalive - resets watchdog timer to keep system alive
  *
  * wdrtas_timer_keepalive restarts the watchdog timer by calling the
@@ -205,7 +180,9 @@ static void wdrtas_timer_keepalive(void)
                if (result < 0)
                        pr_err("event-scan failed: %li\n", result);
                if (result == 0)
-                       wdrtas_log_scanned_event();
+                       print_hex_dump(KERN_INFO, "dumping event, data: ",
+                               DUMP_PREFIX_OFFSET, 16, 1,
+                               wdrtas_logbuffer, WDRTAS_LOGBUFFER_LEN, false);
        } while (result == 0);
 }
 
index 9dcb6d0..d4e47ed 100644 (file)
@@ -247,9 +247,10 @@ static int wm831x_wdt_probe(struct platform_device *pdev)
                reg |= pdata->software << WM831X_WDOG_RST_SRC_SHIFT;
 
                if (pdata->update_gpio) {
-                       ret = gpio_request_one(pdata->update_gpio,
-                                              GPIOF_DIR_OUT | GPIOF_INIT_LOW,
-                                              "Watchdog update");
+                       ret = devm_gpio_request_one(&pdev->dev,
+                                               pdata->update_gpio,
+                                               GPIOF_OUT_INIT_LOW,
+                                               "Watchdog update");
                        if (ret < 0) {
                                dev_err(wm831x->dev,
                                        "Failed to request update GPIO: %d\n",
@@ -270,7 +271,7 @@ static int wm831x_wdt_probe(struct platform_device *pdev)
                } else {
                        dev_err(wm831x->dev,
                                "Failed to unlock security key: %d\n", ret);
-                       goto err_gpio;
+                       goto err;
                }
        }
 
@@ -278,29 +279,23 @@ static int wm831x_wdt_probe(struct platform_device *pdev)
        if (ret != 0) {
                dev_err(wm831x->dev, "watchdog_register_device() failed: %d\n",
                        ret);
-               goto err_gpio;
+               goto err;
        }
 
-       dev_set_drvdata(&pdev->dev, driver_data);
+       platform_set_drvdata(pdev, driver_data);
 
        return 0;
 
-err_gpio:
-       if (driver_data->update_gpio)
-               gpio_free(driver_data->update_gpio);
 err:
        return ret;
 }
 
 static int wm831x_wdt_remove(struct platform_device *pdev)
 {
-       struct wm831x_wdt_drvdata *driver_data = dev_get_drvdata(&pdev->dev);
+       struct wm831x_wdt_drvdata *driver_data = platform_get_drvdata(pdev);
 
        watchdog_unregister_device(&driver_data->wdt);
 
-       if (driver_data->update_gpio)
-               gpio_free(driver_data->update_gpio);
-
        return 0;
 }
 
index 55abfd6..6489e1f 100644 (file)
@@ -31,3 +31,16 @@ config 9P_FS_POSIX_ACL
          If you don't know what Access Control Lists are, say N
 
 endif
+
+
+config 9P_FS_SECURITY
+        bool "9P Security Labels"
+        depends on 9P_FS
+        help
+          Security labels support alternative access control models
+          implemented by security modules like SELinux.  This option
+          enables an extended attribute handler for file security
+          labels in the 9P filesystem.
+
+          If you are not using a security module that requires using
+          extended attributes for file security labels, say N.
index ab8c127..ff7be98 100644 (file)
@@ -11,7 +11,9 @@ obj-$(CONFIG_9P_FS) := 9p.o
        v9fs.o \
        fid.o  \
        xattr.o \
-       xattr_user.o
+       xattr_user.o \
+       xattr_trusted.o
 
 9p-$(CONFIG_9P_FSCACHE) += cache.o
 9p-$(CONFIG_9P_FS_POSIX_ACL) += acl.o
+9p-$(CONFIG_9P_FS_SECURITY) += xattr_security.o
index d86edc8..25b018e 100644 (file)
@@ -1054,13 +1054,11 @@ static int
 v9fs_vfs_getattr(struct vfsmount *mnt, struct dentry *dentry,
                 struct kstat *stat)
 {
-       int err;
        struct v9fs_session_info *v9ses;
        struct p9_fid *fid;
        struct p9_wstat *st;
 
        p9_debug(P9_DEBUG_VFS, "dentry: %p\n", dentry);
-       err = -EPERM;
        v9ses = v9fs_dentry2v9ses(dentry);
        if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE) {
                generic_fillattr(dentry->d_inode, stat);
index c45e016..3c28cdf 100644 (file)
@@ -167,9 +167,13 @@ ssize_t v9fs_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size)
 
 const struct xattr_handler *v9fs_xattr_handlers[] = {
        &v9fs_xattr_user_handler,
+       &v9fs_xattr_trusted_handler,
 #ifdef CONFIG_9P_FS_POSIX_ACL
        &v9fs_xattr_acl_access_handler,
        &v9fs_xattr_acl_default_handler,
 #endif
+#ifdef CONFIG_9P_FS_SECURITY
+       &v9fs_xattr_security_handler,
+#endif
        NULL
 };
index eec348a..d3e2ea3 100644 (file)
@@ -20,6 +20,8 @@
 
 extern const struct xattr_handler *v9fs_xattr_handlers[];
 extern struct xattr_handler v9fs_xattr_user_handler;
+extern struct xattr_handler v9fs_xattr_trusted_handler;
+extern struct xattr_handler v9fs_xattr_security_handler;
 extern const struct xattr_handler v9fs_xattr_acl_access_handler;
 extern const struct xattr_handler v9fs_xattr_acl_default_handler;
 
diff --git a/fs/9p/xattr_security.c b/fs/9p/xattr_security.c
new file mode 100644 (file)
index 0000000..cb247a1
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Copyright IBM Corporation, 2010
+ * Author Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2.1 of the GNU Lesser General Public License
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ */
+
+
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include "xattr.h"
+
+static int v9fs_xattr_security_get(struct dentry *dentry, const char *name,
+                       void *buffer, size_t size, int type)
+{
+       int retval;
+       char *full_name;
+       size_t name_len;
+       size_t prefix_len = XATTR_SECURITY_PREFIX_LEN;
+
+       if (name == NULL)
+               return -EINVAL;
+
+       if (strcmp(name, "") == 0)
+               return -EINVAL;
+
+       name_len = strlen(name);
+       full_name = kmalloc(prefix_len + name_len + 1 , GFP_KERNEL);
+       if (!full_name)
+               return -ENOMEM;
+       memcpy(full_name, XATTR_SECURITY_PREFIX, prefix_len);
+       memcpy(full_name+prefix_len, name, name_len);
+       full_name[prefix_len + name_len] = '\0';
+
+       retval = v9fs_xattr_get(dentry, full_name, buffer, size);
+       kfree(full_name);
+       return retval;
+}
+
+static int v9fs_xattr_security_set(struct dentry *dentry, const char *name,
+                       const void *value, size_t size, int flags, int type)
+{
+       int retval;
+       char *full_name;
+       size_t name_len;
+       size_t prefix_len = XATTR_SECURITY_PREFIX_LEN;
+
+       if (name == NULL)
+               return -EINVAL;
+
+       if (strcmp(name, "") == 0)
+               return -EINVAL;
+
+       name_len = strlen(name);
+       full_name = kmalloc(prefix_len + name_len + 1 , GFP_KERNEL);
+       if (!full_name)
+               return -ENOMEM;
+       memcpy(full_name, XATTR_SECURITY_PREFIX, prefix_len);
+       memcpy(full_name + prefix_len, name, name_len);
+       full_name[prefix_len + name_len] = '\0';
+
+       retval = v9fs_xattr_set(dentry, full_name, value, size, flags);
+       kfree(full_name);
+       return retval;
+}
+
+struct xattr_handler v9fs_xattr_security_handler = {
+       .prefix = XATTR_SECURITY_PREFIX,
+       .get    = v9fs_xattr_security_get,
+       .set    = v9fs_xattr_security_set,
+};
diff --git a/fs/9p/xattr_trusted.c b/fs/9p/xattr_trusted.c
new file mode 100644 (file)
index 0000000..e30d33b
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Copyright IBM Corporation, 2010
+ * Author Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2.1 of the GNU Lesser General Public License
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ */
+
+
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include "xattr.h"
+
+static int v9fs_xattr_trusted_get(struct dentry *dentry, const char *name,
+                       void *buffer, size_t size, int type)
+{
+       int retval;
+       char *full_name;
+       size_t name_len;
+       size_t prefix_len = XATTR_TRUSTED_PREFIX_LEN;
+
+       if (name == NULL)
+               return -EINVAL;
+
+       if (strcmp(name, "") == 0)
+               return -EINVAL;
+
+       name_len = strlen(name);
+       full_name = kmalloc(prefix_len + name_len + 1 , GFP_KERNEL);
+       if (!full_name)
+               return -ENOMEM;
+       memcpy(full_name, XATTR_TRUSTED_PREFIX, prefix_len);
+       memcpy(full_name+prefix_len, name, name_len);
+       full_name[prefix_len + name_len] = '\0';
+
+       retval = v9fs_xattr_get(dentry, full_name, buffer, size);
+       kfree(full_name);
+       return retval;
+}
+
+static int v9fs_xattr_trusted_set(struct dentry *dentry, const char *name,
+                       const void *value, size_t size, int flags, int type)
+{
+       int retval;
+       char *full_name;
+       size_t name_len;
+       size_t prefix_len = XATTR_TRUSTED_PREFIX_LEN;
+
+       if (name == NULL)
+               return -EINVAL;
+
+       if (strcmp(name, "") == 0)
+               return -EINVAL;
+
+       name_len = strlen(name);
+       full_name = kmalloc(prefix_len + name_len + 1 , GFP_KERNEL);
+       if (!full_name)
+               return -ENOMEM;
+       memcpy(full_name, XATTR_TRUSTED_PREFIX, prefix_len);
+       memcpy(full_name + prefix_len, name, name_len);
+       full_name[prefix_len + name_len] = '\0';
+
+       retval = v9fs_xattr_set(dentry, full_name, value, size, flags);
+       kfree(full_name);
+       return retval;
+}
+
+struct xattr_handler v9fs_xattr_trusted_handler = {
+       .prefix = XATTR_TRUSTED_PREFIX,
+       .get    = v9fs_xattr_trusted_get,
+       .set    = v9fs_xattr_trusted_set,
+};
index bce8769..89dec7f 100644 (file)
@@ -255,8 +255,6 @@ static int load_aout_binary(struct linux_binprm * bprm)
                (current->mm->start_data = N_DATADDR(ex));
        current->mm->brk = ex.a_bss +
                (current->mm->start_brk = N_BSSADDR(ex));
-       current->mm->free_area_cache = current->mm->mmap_base;
-       current->mm->cached_hole_size = 0;
 
        retval = setup_arg_pages(bprm, STACK_TOP, EXSTACK_DEFAULT);
        if (retval < 0) {
index f8a0b0e..100edcc 100644 (file)
@@ -738,8 +738,6 @@ static int load_elf_binary(struct linux_binprm *bprm)
 
        /* Do this so that we can load the interpreter, if need be.  We will
           change some of these later */
-       current->mm->free_area_cache = current->mm->mmap_base;
-       current->mm->cached_hole_size = 0;
        retval = setup_arg_pages(bprm, randomize_stack_top(STACK_TOP),
                                 executable_stack);
        if (retval < 0) {
index bb43ce0..c7bda5c 100644 (file)
@@ -58,17 +58,24 @@ static void bdev_inode_switch_bdi(struct inode *inode,
                        struct backing_dev_info *dst)
 {
        struct backing_dev_info *old = inode->i_data.backing_dev_info;
+       bool wakeup_bdi = false;
 
        if (unlikely(dst == old))               /* deadlock avoidance */
                return;
        bdi_lock_two(&old->wb, &dst->wb);
        spin_lock(&inode->i_lock);
        inode->i_data.backing_dev_info = dst;
-       if (inode->i_state & I_DIRTY)
+       if (inode->i_state & I_DIRTY) {
+               if (bdi_cap_writeback_dirty(dst) && !wb_has_dirty_io(&dst->wb))
+                       wakeup_bdi = true;
                list_move(&inode->i_wb_list, &dst->wb.b_dirty);
+       }
        spin_unlock(&inode->i_lock);
        spin_unlock(&old->wb.list_lock);
        spin_unlock(&dst->wb.list_lock);
+
+       if (wakeup_bdi)
+               bdi_wakeup_thread_delayed(dst);
 }
 
 /* Kill _all_ buffers and pagecache , dirty or not.. */
index 3d8bf94..45e57cc 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *   fs/cifs/cifsencrypt.c
  *
- *   Copyright (C) International Business Machines  Corp., 2005,2006
+ *   Copyright (C) International Business Machines  Corp., 2005,2013
  *   Author(s): Steve French (sfrench@us.ibm.com)
  *
  *   This library is free software; you can redistribute it and/or modify
 #include <linux/random.h>
 #include <linux/highmem.h>
 
+static int
+cifs_crypto_shash_md5_allocate(struct TCP_Server_Info *server)
+{
+       int rc;
+       unsigned int size;
+
+       if (server->secmech.sdescmd5 != NULL)
+               return 0; /* already allocated */
+
+       server->secmech.md5 = crypto_alloc_shash("md5", 0, 0);
+       if (IS_ERR(server->secmech.md5)) {
+               cifs_dbg(VFS, "could not allocate crypto md5\n");
+               return PTR_ERR(server->secmech.md5);
+       }
+
+       size = sizeof(struct shash_desc) +
+                       crypto_shash_descsize(server->secmech.md5);
+       server->secmech.sdescmd5 = kmalloc(size, GFP_KERNEL);
+       if (!server->secmech.sdescmd5) {
+               rc = -ENOMEM;
+               crypto_free_shash(server->secmech.md5);
+               server->secmech.md5 = NULL;
+               return rc;
+       }
+       server->secmech.sdescmd5->shash.tfm = server->secmech.md5;
+       server->secmech.sdescmd5->shash.flags = 0x0;
+
+       return 0;
+}
+
 /*
  * Calculate and return the CIFS signature based on the mac key and SMB PDU.
  * The 16 byte signature must be allocated by the caller. Note we only use the
@@ -50,8 +80,11 @@ static int cifs_calc_signature(struct smb_rqst *rqst,
                return -EINVAL;
 
        if (!server->secmech.sdescmd5) {
-               cifs_dbg(VFS, "%s: Can't generate signature\n", __func__);
-               return -1;
+               rc = cifs_crypto_shash_md5_allocate(server);
+               if (rc) {
+                       cifs_dbg(VFS, "%s: Can't alloc md5 crypto\n", __func__);
+                       return -1;
+               }
        }
 
        rc = crypto_shash_init(&server->secmech.sdescmd5->shash);
@@ -556,6 +589,33 @@ CalcNTLMv2_response(const struct cifs_ses *ses, char *ntlmv2_hash)
        return rc;
 }
 
+static int crypto_hmacmd5_alloc(struct TCP_Server_Info *server)
+{
+       unsigned int size;
+
+       /* check if already allocated */
+       if (server->secmech.sdeschmacmd5)
+               return 0;
+
+       server->secmech.hmacmd5 = crypto_alloc_shash("hmac(md5)", 0, 0);
+       if (IS_ERR(server->secmech.hmacmd5)) {
+               cifs_dbg(VFS, "could not allocate crypto hmacmd5\n");
+               return PTR_ERR(server->secmech.hmacmd5);
+       }
+
+       size = sizeof(struct shash_desc) +
+                       crypto_shash_descsize(server->secmech.hmacmd5);
+       server->secmech.sdeschmacmd5 = kmalloc(size, GFP_KERNEL);
+       if (!server->secmech.sdeschmacmd5) {
+               crypto_free_shash(server->secmech.hmacmd5);
+               server->secmech.hmacmd5 = NULL;
+               return -ENOMEM;
+       }
+       server->secmech.sdeschmacmd5->shash.tfm = server->secmech.hmacmd5;
+       server->secmech.sdeschmacmd5->shash.flags = 0x0;
+
+       return 0;
+}
 
 int
 setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp)
@@ -606,6 +666,12 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp)
 
        memcpy(ses->auth_key.response + baselen, tiblob, tilen);
 
+       rc = crypto_hmacmd5_alloc(ses->server);
+       if (rc) {
+               cifs_dbg(VFS, "could not crypto alloc hmacmd5 rc %d\n", rc);
+               goto setup_ntlmv2_rsp_ret;
+       }
+
        /* calculate ntlmv2_hash */
        rc = calc_ntlmv2_hash(ses, ntlmv2_hash, nls_cp);
        if (rc) {
@@ -705,123 +771,32 @@ calc_seckey(struct cifs_ses *ses)
 void
 cifs_crypto_shash_release(struct TCP_Server_Info *server)
 {
-       if (server->secmech.cmacaes)
+       if (server->secmech.cmacaes) {
                crypto_free_shash(server->secmech.cmacaes);
+               server->secmech.cmacaes = NULL;
+       }
 
-       if (server->secmech.hmacsha256)
+       if (server->secmech.hmacsha256) {
                crypto_free_shash(server->secmech.hmacsha256);
+               server->secmech.hmacsha256 = NULL;
+       }
 
-       if (server->secmech.md5)
+       if (server->secmech.md5) {
                crypto_free_shash(server->secmech.md5);
+               server->secmech.md5 = NULL;
+       }
 
-       if (server->secmech.hmacmd5)
+       if (server->secmech.hmacmd5) {
                crypto_free_shash(server->secmech.hmacmd5);
+               server->secmech.hmacmd5 = NULL;
+       }
 
        kfree(server->secmech.sdesccmacaes);
-
+       server->secmech.sdesccmacaes = NULL;
        kfree(server->secmech.sdeschmacsha256);
-
+       server->secmech.sdeschmacsha256 = NULL;
        kfree(server->secmech.sdeschmacmd5);
-
+       server->secmech.sdeschmacmd5 = NULL;
        kfree(server->secmech.sdescmd5);
-}
-
-int
-cifs_crypto_shash_allocate(struct TCP_Server_Info *server)
-{
-       int rc;
-       unsigned int size;
-
-       server->secmech.hmacmd5 = crypto_alloc_shash("hmac(md5)", 0, 0);
-       if (IS_ERR(server->secmech.hmacmd5)) {
-               cifs_dbg(VFS, "could not allocate crypto hmacmd5\n");
-               return PTR_ERR(server->secmech.hmacmd5);
-       }
-
-       server->secmech.md5 = crypto_alloc_shash("md5", 0, 0);
-       if (IS_ERR(server->secmech.md5)) {
-               cifs_dbg(VFS, "could not allocate crypto md5\n");
-               rc = PTR_ERR(server->secmech.md5);
-               goto crypto_allocate_md5_fail;
-       }
-
-       server->secmech.hmacsha256 = crypto_alloc_shash("hmac(sha256)", 0, 0);
-       if (IS_ERR(server->secmech.hmacsha256)) {
-               cifs_dbg(VFS, "could not allocate crypto hmacsha256\n");
-               rc = PTR_ERR(server->secmech.hmacsha256);
-               goto crypto_allocate_hmacsha256_fail;
-       }
-
-       server->secmech.cmacaes = crypto_alloc_shash("cmac(aes)", 0, 0);
-       if (IS_ERR(server->secmech.cmacaes)) {
-               cifs_dbg(VFS, "could not allocate crypto cmac-aes");
-               rc = PTR_ERR(server->secmech.cmacaes);
-               goto crypto_allocate_cmacaes_fail;
-       }
-
-       size = sizeof(struct shash_desc) +
-                       crypto_shash_descsize(server->secmech.hmacmd5);
-       server->secmech.sdeschmacmd5 = kmalloc(size, GFP_KERNEL);
-       if (!server->secmech.sdeschmacmd5) {
-               rc = -ENOMEM;
-               goto crypto_allocate_hmacmd5_sdesc_fail;
-       }
-       server->secmech.sdeschmacmd5->shash.tfm = server->secmech.hmacmd5;
-       server->secmech.sdeschmacmd5->shash.flags = 0x0;
-
-       size = sizeof(struct shash_desc) +
-                       crypto_shash_descsize(server->secmech.md5);
-       server->secmech.sdescmd5 = kmalloc(size, GFP_KERNEL);
-       if (!server->secmech.sdescmd5) {
-               rc = -ENOMEM;
-               goto crypto_allocate_md5_sdesc_fail;
-       }
-       server->secmech.sdescmd5->shash.tfm = server->secmech.md5;
-       server->secmech.sdescmd5->shash.flags = 0x0;
-
-       size = sizeof(struct shash_desc) +
-                       crypto_shash_descsize(server->secmech.hmacsha256);
-       server->secmech.sdeschmacsha256 = kmalloc(size, GFP_KERNEL);
-       if (!server->secmech.sdeschmacsha256) {
-               rc = -ENOMEM;
-               goto crypto_allocate_hmacsha256_sdesc_fail;
-       }
-       server->secmech.sdeschmacsha256->shash.tfm = server->secmech.hmacsha256;
-       server->secmech.sdeschmacsha256->shash.flags = 0x0;
-
-       size = sizeof(struct shash_desc) +
-                       crypto_shash_descsize(server->secmech.cmacaes);
-       server->secmech.sdesccmacaes = kmalloc(size, GFP_KERNEL);
-       if (!server->secmech.sdesccmacaes) {
-               cifs_dbg(VFS, "%s: Can't alloc cmacaes\n", __func__);
-               rc = -ENOMEM;
-               goto crypto_allocate_cmacaes_sdesc_fail;
-       }
-       server->secmech.sdesccmacaes->shash.tfm = server->secmech.cmacaes;
-       server->secmech.sdesccmacaes->shash.flags = 0x0;
-
-       return 0;
-
-crypto_allocate_cmacaes_sdesc_fail:
-       kfree(server->secmech.sdeschmacsha256);
-
-crypto_allocate_hmacsha256_sdesc_fail:
-       kfree(server->secmech.sdescmd5);
-
-crypto_allocate_md5_sdesc_fail:
-       kfree(server->secmech.sdeschmacmd5);
-
-crypto_allocate_hmacmd5_sdesc_fail:
-       crypto_free_shash(server->secmech.cmacaes);
-
-crypto_allocate_cmacaes_fail:
-       crypto_free_shash(server->secmech.hmacsha256);
-
-crypto_allocate_hmacsha256_fail:
-       crypto_free_shash(server->secmech.md5);
-
-crypto_allocate_md5_fail:
-       crypto_free_shash(server->secmech.hmacmd5);
-
-       return rc;
+       server->secmech.sdescmd5 = NULL;
 }
index e66b088..1fdc370 100644 (file)
@@ -194,6 +194,7 @@ struct cifs_writedata;
 struct cifs_io_parms;
 struct cifs_search_info;
 struct cifsInodeInfo;
+struct cifs_open_parms;
 
 struct smb_version_operations {
        int (*send_cancel)(struct TCP_Server_Info *, void *,
@@ -307,9 +308,8 @@ struct smb_version_operations {
                               const char *, const char *,
                               struct cifs_sb_info *);
        /* open a file for non-posix mounts */
-       int (*open)(const unsigned int, struct cifs_tcon *, const char *, int,
-                   int, int, struct cifs_fid *, __u32 *, FILE_ALL_INFO *,
-                   struct cifs_sb_info *);
+       int (*open)(const unsigned int, struct cifs_open_parms *,
+                   __u32 *, FILE_ALL_INFO *);
        /* set fid protocol-specific info */
        void (*set_fid)(struct cifsFileInfo *, struct cifs_fid *, __u32);
        /* close a file */
@@ -912,6 +912,17 @@ struct cifs_search_info {
        bool smallBuf:1; /* so we know which buf_release function to call */
 };
 
+struct cifs_open_parms {
+       struct cifs_tcon *tcon;
+       struct cifs_sb_info *cifs_sb;
+       int disposition;
+       int desired_access;
+       int create_options;
+       const char *path;
+       struct cifs_fid *fid;
+       bool reconnect:1;
+};
+
 struct cifs_fid {
        __u16 netfid;
 #ifdef CONFIG_CIFS_SMB2
index c8ff018..f7e584d 100644 (file)
@@ -433,7 +433,6 @@ extern int SMBNTencrypt(unsigned char *, unsigned char *, unsigned char *,
                        const struct nls_table *);
 extern int setup_ntlm_response(struct cifs_ses *, const struct nls_table *);
 extern int setup_ntlmv2_rsp(struct cifs_ses *, const struct nls_table *);
-extern int cifs_crypto_shash_allocate(struct TCP_Server_Info *);
 extern void cifs_crypto_shash_release(struct TCP_Server_Info *);
 extern int calc_seckey(struct cifs_ses *);
 extern void generate_smb3signingkey(struct TCP_Server_Info *);
index afcb8a1..fa68813 100644 (file)
@@ -2108,12 +2108,6 @@ cifs_get_tcp_session(struct smb_vol *volume_info)
                goto out_err;
        }
 
-       rc = cifs_crypto_shash_allocate(tcp_ses);
-       if (rc) {
-               cifs_dbg(VFS, "could not setup hash structures rc %d\n", rc);
-               goto out_err;
-       }
-
        tcp_ses->ops = volume_info->ops;
        tcp_ses->vals = volume_info->vals;
        cifs_set_net_ns(tcp_ses, get_net(current->nsproxy->net_ns));
index 5175aeb..d62ce0d 100644 (file)
@@ -204,6 +204,7 @@ cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned int xid,
        struct inode *newinode = NULL;
        int disposition;
        struct TCP_Server_Info *server = tcon->ses->server;
+       struct cifs_open_parms oparms;
 
        *oplock = 0;
        if (tcon->ses->server->oplocks)
@@ -319,9 +320,16 @@ cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned int xid,
        if (backup_cred(cifs_sb))
                create_options |= CREATE_OPEN_BACKUP_INTENT;
 
-       rc = server->ops->open(xid, tcon, full_path, disposition,
-                              desired_access, create_options, fid, oplock,
-                              buf, cifs_sb);
+       oparms.tcon = tcon;
+       oparms.cifs_sb = cifs_sb;
+       oparms.desired_access = desired_access;
+       oparms.create_options = create_options;
+       oparms.disposition = disposition;
+       oparms.path = full_path;
+       oparms.fid = fid;
+       oparms.reconnect = false;
+
+       rc = server->ops->open(xid, &oparms, oplock, buf);
        if (rc) {
                cifs_dbg(FYI, "cifs_create returned 0x%x\n", rc);
                goto out;
index 91d8629..1e57f36 100644 (file)
@@ -183,6 +183,7 @@ cifs_nt_open(char *full_path, struct inode *inode, struct cifs_sb_info *cifs_sb,
        int create_options = CREATE_NOT_DIR;
        FILE_ALL_INFO *buf;
        struct TCP_Server_Info *server = tcon->ses->server;
+       struct cifs_open_parms oparms;
 
        if (!server->ops->open)
                return -ENOSYS;
@@ -224,9 +225,16 @@ cifs_nt_open(char *full_path, struct inode *inode, struct cifs_sb_info *cifs_sb,
        if (backup_cred(cifs_sb))
                create_options |= CREATE_OPEN_BACKUP_INTENT;
 
-       rc = server->ops->open(xid, tcon, full_path, disposition,
-                              desired_access, create_options, fid, oplock, buf,
-                              cifs_sb);
+       oparms.tcon = tcon;
+       oparms.cifs_sb = cifs_sb;
+       oparms.desired_access = desired_access;
+       oparms.create_options = create_options;
+       oparms.disposition = disposition;
+       oparms.path = full_path;
+       oparms.fid = fid;
+       oparms.reconnect = false;
+
+       rc = server->ops->open(xid, &oparms, oplock, buf);
 
        if (rc)
                goto out;
@@ -553,11 +561,10 @@ cifs_relock_file(struct cifsFileInfo *cfile)
        struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
        int rc = 0;
 
-       /* we are going to update can_cache_brlcks here - need a write access */
-       down_write(&cinode->lock_sem);
+       down_read(&cinode->lock_sem);
        if (cinode->can_cache_brlcks) {
-               /* can cache locks - no need to push them */
-               up_write(&cinode->lock_sem);
+               /* can cache locks - no need to relock */
+               up_read(&cinode->lock_sem);
                return rc;
        }
 
@@ -568,7 +575,7 @@ cifs_relock_file(struct cifsFileInfo *cfile)
        else
                rc = tcon->ses->server->ops->push_mand_locks(cfile);
 
-       up_write(&cinode->lock_sem);
+       up_read(&cinode->lock_sem);
        return rc;
 }
 
@@ -587,7 +594,7 @@ cifs_reopen_file(struct cifsFileInfo *cfile, bool can_flush)
        int desired_access;
        int disposition = FILE_OPEN;
        int create_options = CREATE_NOT_DIR;
-       struct cifs_fid fid;
+       struct cifs_open_parms oparms;
 
        xid = get_xid();
        mutex_lock(&cfile->fh_mutex);
@@ -637,7 +644,7 @@ cifs_reopen_file(struct cifsFileInfo *cfile, bool can_flush)
 
                rc = cifs_posix_open(full_path, NULL, inode->i_sb,
                                     cifs_sb->mnt_file_mode /* ignored */,
-                                    oflags, &oplock, &fid.netfid, xid);
+                                    oflags, &oplock, &cfile->fid.netfid, xid);
                if (rc == 0) {
                        cifs_dbg(FYI, "posix reopen succeeded\n");
                        goto reopen_success;
@@ -654,7 +661,16 @@ cifs_reopen_file(struct cifsFileInfo *cfile, bool can_flush)
                create_options |= CREATE_OPEN_BACKUP_INTENT;
 
        if (server->ops->get_lease_key)
-               server->ops->get_lease_key(inode, &fid);
+               server->ops->get_lease_key(inode, &cfile->fid);
+
+       oparms.tcon = tcon;
+       oparms.cifs_sb = cifs_sb;
+       oparms.desired_access = desired_access;
+       oparms.create_options = create_options;
+       oparms.disposition = disposition;
+       oparms.path = full_path;
+       oparms.fid = &cfile->fid;
+       oparms.reconnect = true;
 
        /*
         * Can not refresh inode by passing in file_info buf to be returned by
@@ -663,9 +679,14 @@ cifs_reopen_file(struct cifsFileInfo *cfile, bool can_flush)
         * version of file size can be stale. If we knew for sure that inode was
         * not dirty locally we could do this.
         */
-       rc = server->ops->open(xid, tcon, full_path, disposition,
-                              desired_access, create_options, &fid, &oplock,
-                              NULL, cifs_sb);
+       rc = server->ops->open(xid, &oparms, &oplock, NULL);
+       if (rc == -ENOENT && oparms.reconnect == false) {
+               /* durable handle timeout is expired - open the file again */
+               rc = server->ops->open(xid, &oparms, &oplock, NULL);
+               /* indicate that we need to relock the file */
+               oparms.reconnect = true;
+       }
+
        if (rc) {
                mutex_unlock(&cfile->fh_mutex);
                cifs_dbg(FYI, "cifs_reopen returned 0x%x\n", rc);
@@ -696,8 +717,9 @@ reopen_success:
         * to the server to get the new inode info.
         */
 
-       server->ops->set_fid(cfile, &fid, oplock);
-       cifs_relock_file(cfile);
+       server->ops->set_fid(cfile, &cfile->fid, oplock);
+       if (oparms.reconnect)
+               cifs_relock_file(cfile);
 
 reopen_error_exit:
        kfree(full_path);
index 20efd81..449b6cf 100644 (file)
@@ -558,6 +558,11 @@ cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info,
                        fattr->cf_mode &= ~(S_IWUGO);
 
                fattr->cf_nlink = le32_to_cpu(info->NumberOfLinks);
+               if (fattr->cf_nlink < 1) {
+                       cifs_dbg(1, "replacing bogus file nlink value %u\n",
+                               fattr->cf_nlink);
+                       fattr->cf_nlink = 1;
+               }
        }
 
        fattr->cf_uid = cifs_sb->mnt_uid;
index e813f04..6457690 100644 (file)
@@ -674,20 +674,23 @@ cifs_mkdir_setinfo(struct inode *inode, const char *full_path,
 }
 
 static int
-cifs_open_file(const unsigned int xid, struct cifs_tcon *tcon, const char *path,
-              int disposition, int desired_access, int create_options,
-              struct cifs_fid *fid, __u32 *oplock, FILE_ALL_INFO *buf,
-              struct cifs_sb_info *cifs_sb)
-{
-       if (!(tcon->ses->capabilities & CAP_NT_SMBS))
-               return SMBLegacyOpen(xid, tcon, path, disposition,
-                                    desired_access, create_options,
-                                    &fid->netfid, oplock, buf,
-                                    cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
+cifs_open_file(const unsigned int xid, struct cifs_open_parms *oparms,
+              __u32 *oplock, FILE_ALL_INFO *buf)
+{
+       if (!(oparms->tcon->ses->capabilities & CAP_NT_SMBS))
+               return SMBLegacyOpen(xid, oparms->tcon, oparms->path,
+                                    oparms->disposition,
+                                    oparms->desired_access,
+                                    oparms->create_options,
+                                    &oparms->fid->netfid, oplock, buf,
+                                    oparms->cifs_sb->local_nls,
+                                    oparms->cifs_sb->mnt_cifs_flags
                                                & CIFS_MOUNT_MAP_SPECIAL_CHR);
-       return CIFSSMBOpen(xid, tcon, path, disposition, desired_access,
-                          create_options, &fid->netfid, oplock, buf,
-                          cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
+       return CIFSSMBOpen(xid, oparms->tcon, oparms->path,
+                          oparms->disposition, oparms->desired_access,
+                          oparms->create_options, &oparms->fid->netfid, oplock,
+                          buf, oparms->cifs_sb->local_nls,
+                          oparms->cifs_sb->mnt_cifs_flags &
                                                CIFS_MOUNT_MAP_SPECIAL_CHR);
 }
 
index 5da1b55..04a81a4 100644 (file)
@@ -40,7 +40,8 @@ smb2_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock)
        oplock &= 0xFF;
        if (oplock == SMB2_OPLOCK_LEVEL_NOCHANGE)
                return;
-       if (oplock == SMB2_OPLOCK_LEVEL_EXCLUSIVE) {
+       if (oplock == SMB2_OPLOCK_LEVEL_EXCLUSIVE ||
+           oplock == SMB2_OPLOCK_LEVEL_BATCH) {
                cinode->clientCanCacheAll = true;
                cinode->clientCanCacheRead = true;
                cifs_dbg(FYI, "Exclusive Oplock granted on inode %p\n",
@@ -57,17 +58,16 @@ smb2_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock)
 }
 
 int
-smb2_open_file(const unsigned int xid, struct cifs_tcon *tcon, const char *path,
-              int disposition, int desired_access, int create_options,
-              struct cifs_fid *fid, __u32 *oplock, FILE_ALL_INFO *buf,
-              struct cifs_sb_info *cifs_sb)
+smb2_open_file(const unsigned int xid, struct cifs_open_parms *oparms,
+              __u32 *oplock, FILE_ALL_INFO *buf)
 {
        int rc;
        __le16 *smb2_path;
        struct smb2_file_all_info *smb2_data = NULL;
        __u8 smb2_oplock[17];
+       struct cifs_fid *fid = oparms->fid;
 
-       smb2_path = cifs_convert_path_to_utf16(path, cifs_sb);
+       smb2_path = cifs_convert_path_to_utf16(oparms->path, oparms->cifs_sb);
        if (smb2_path == NULL) {
                rc = -ENOMEM;
                goto out;
@@ -80,21 +80,19 @@ smb2_open_file(const unsigned int xid, struct cifs_tcon *tcon, const char *path,
                goto out;
        }
 
-       desired_access |= FILE_READ_ATTRIBUTES;
-       *smb2_oplock = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
+       oparms->desired_access |= FILE_READ_ATTRIBUTES;
+       *smb2_oplock = SMB2_OPLOCK_LEVEL_BATCH;
 
-       if (tcon->ses->server->capabilities & SMB2_GLOBAL_CAP_LEASING)
+       if (oparms->tcon->ses->server->capabilities & SMB2_GLOBAL_CAP_LEASING)
                memcpy(smb2_oplock + 1, fid->lease_key, SMB2_LEASE_KEY_SIZE);
 
-       rc = SMB2_open(xid, tcon, smb2_path, &fid->persistent_fid,
-                      &fid->volatile_fid, desired_access, disposition,
-                      0, 0, smb2_oplock, smb2_data);
+       rc = SMB2_open(xid, oparms, smb2_path, smb2_oplock, smb2_data);
        if (rc)
                goto out;
 
        if (buf) {
                /* open response does not have IndexNumber field - get it */
-               rc = SMB2_get_srv_num(xid, tcon, fid->persistent_fid,
+               rc = SMB2_get_srv_num(xid, oparms->tcon, fid->persistent_fid,
                                      fid->volatile_fid,
                                      &smb2_data->IndexNumber);
                if (rc) {
index fff6dfb..c6ec163 100644 (file)
@@ -41,21 +41,26 @@ static int
 smb2_open_op_close(const unsigned int xid, struct cifs_tcon *tcon,
                   struct cifs_sb_info *cifs_sb, const char *full_path,
                   __u32 desired_access, __u32 create_disposition,
-                  __u32 file_attributes, __u32 create_options,
-                  void *data, int command)
+                  __u32 create_options, void *data, int command)
 {
        int rc, tmprc = 0;
-       u64 persistent_fid, volatile_fid;
        __le16 *utf16_path;
        __u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
+       struct cifs_open_parms oparms;
+       struct cifs_fid fid;
 
        utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb);
        if (!utf16_path)
                return -ENOMEM;
 
-       rc = SMB2_open(xid, tcon, utf16_path, &persistent_fid, &volatile_fid,
-                      desired_access, create_disposition, file_attributes,
-                      create_options, &oplock, NULL);
+       oparms.tcon = tcon;
+       oparms.desired_access = desired_access;
+       oparms.disposition = create_disposition;
+       oparms.create_options = create_options;
+       oparms.fid = &fid;
+       oparms.reconnect = false;
+
+       rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL);
        if (rc) {
                kfree(utf16_path);
                return rc;
@@ -65,8 +70,8 @@ smb2_open_op_close(const unsigned int xid, struct cifs_tcon *tcon,
        case SMB2_OP_DELETE:
                break;
        case SMB2_OP_QUERY_INFO:
-               tmprc = SMB2_query_info(xid, tcon, persistent_fid,
-                                       volatile_fid,
+               tmprc = SMB2_query_info(xid, tcon, fid.persistent_fid,
+                                       fid.volatile_fid,
                                        (struct smb2_file_all_info *)data);
                break;
        case SMB2_OP_MKDIR:
@@ -76,19 +81,21 @@ smb2_open_op_close(const unsigned int xid, struct cifs_tcon *tcon,
                 */
                break;
        case SMB2_OP_RENAME:
-               tmprc = SMB2_rename(xid, tcon, persistent_fid, volatile_fid,
-                                   (__le16 *)data);
+               tmprc = SMB2_rename(xid, tcon, fid.persistent_fid,
+                                   fid.volatile_fid, (__le16 *)data);
                break;
        case SMB2_OP_HARDLINK:
-               tmprc = SMB2_set_hardlink(xid, tcon, persistent_fid,
-                                         volatile_fid, (__le16 *)data);
+               tmprc = SMB2_set_hardlink(xid, tcon, fid.persistent_fid,
+                                         fid.volatile_fid, (__le16 *)data);
                break;
        case SMB2_OP_SET_EOF:
-               tmprc = SMB2_set_eof(xid, tcon, persistent_fid, volatile_fid,
-                                    current->tgid, (__le64 *)data);
+               tmprc = SMB2_set_eof(xid, tcon, fid.persistent_fid,
+                                    fid.volatile_fid, current->tgid,
+                                    (__le64 *)data);
                break;
        case SMB2_OP_SET_INFO:
-               tmprc = SMB2_set_info(xid, tcon, persistent_fid, volatile_fid,
+               tmprc = SMB2_set_info(xid, tcon, fid.persistent_fid,
+                                     fid.volatile_fid,
                                      (FILE_BASIC_INFO *)data);
                break;
        default:
@@ -96,7 +103,7 @@ smb2_open_op_close(const unsigned int xid, struct cifs_tcon *tcon,
                break;
        }
 
-       rc = SMB2_close(xid, tcon, persistent_fid, volatile_fid);
+       rc = SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
        if (tmprc)
                rc = tmprc;
        kfree(utf16_path);
@@ -129,8 +136,8 @@ smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
                return -ENOMEM;
 
        rc = smb2_open_op_close(xid, tcon, cifs_sb, full_path,
-                               FILE_READ_ATTRIBUTES, FILE_OPEN, 0, 0,
-                               smb2_data, SMB2_OP_QUERY_INFO);
+                               FILE_READ_ATTRIBUTES, FILE_OPEN, 0, smb2_data,
+                               SMB2_OP_QUERY_INFO);
        if (rc)
                goto out;
 
@@ -145,7 +152,7 @@ smb2_mkdir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
           struct cifs_sb_info *cifs_sb)
 {
        return smb2_open_op_close(xid, tcon, cifs_sb, name,
-                                 FILE_WRITE_ATTRIBUTES, FILE_CREATE, 0,
+                                 FILE_WRITE_ATTRIBUTES, FILE_CREATE,
                                  CREATE_NOT_FILE, NULL, SMB2_OP_MKDIR);
 }
 
@@ -164,7 +171,7 @@ smb2_mkdir_setinfo(struct inode *inode, const char *name,
        dosattrs = cifs_i->cifsAttrs | ATTR_READONLY;
        data.Attributes = cpu_to_le32(dosattrs);
        tmprc = smb2_open_op_close(xid, tcon, cifs_sb, name,
-                                  FILE_WRITE_ATTRIBUTES, FILE_CREATE, 0,
+                                  FILE_WRITE_ATTRIBUTES, FILE_CREATE,
                                   CREATE_NOT_FILE, &data, SMB2_OP_SET_INFO);
        if (tmprc == 0)
                cifs_i->cifsAttrs = dosattrs;
@@ -175,7 +182,7 @@ smb2_rmdir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
           struct cifs_sb_info *cifs_sb)
 {
        return smb2_open_op_close(xid, tcon, cifs_sb, name, DELETE, FILE_OPEN,
-                                 0, CREATE_NOT_FILE | CREATE_DELETE_ON_CLOSE,
+                                 CREATE_NOT_FILE | CREATE_DELETE_ON_CLOSE,
                                  NULL, SMB2_OP_DELETE);
 }
 
@@ -184,7 +191,7 @@ smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
            struct cifs_sb_info *cifs_sb)
 {
        return smb2_open_op_close(xid, tcon, cifs_sb, name, DELETE, FILE_OPEN,
-                                 0, CREATE_DELETE_ON_CLOSE, NULL,
+                                 CREATE_DELETE_ON_CLOSE, NULL,
                                  SMB2_OP_DELETE);
 }
 
@@ -203,7 +210,7 @@ smb2_set_path_attr(const unsigned int xid, struct cifs_tcon *tcon,
        }
 
        rc = smb2_open_op_close(xid, tcon, cifs_sb, from_name, access,
-                               FILE_OPEN, 0, 0, smb2_to_name, command);
+                               FILE_OPEN, 0, smb2_to_name, command);
 smb2_rename_path:
        kfree(smb2_to_name);
        return rc;
@@ -234,7 +241,7 @@ smb2_set_path_size(const unsigned int xid, struct cifs_tcon *tcon,
 {
        __le64 eof = cpu_to_le64(size);
        return smb2_open_op_close(xid, tcon, cifs_sb, full_path,
-                                 FILE_WRITE_DATA, FILE_OPEN, 0, 0, &eof,
+                                 FILE_WRITE_DATA, FILE_OPEN, 0, &eof,
                                  SMB2_OP_SET_EOF);
 }
 
@@ -250,7 +257,7 @@ smb2_set_file_info(struct inode *inode, const char *full_path,
        if (IS_ERR(tlink))
                return PTR_ERR(tlink);
        rc = smb2_open_op_close(xid, tlink_tcon(tlink), cifs_sb, full_path,
-                               FILE_WRITE_ATTRIBUTES, FILE_OPEN, 0, 0, buf,
+                               FILE_WRITE_ATTRIBUTES, FILE_OPEN, 0, buf,
                                SMB2_OP_SET_INFO);
        cifs_put_tlink(tlink);
        return rc;
index 6d15cab..f259e6c 100644 (file)
@@ -213,22 +213,29 @@ smb2_is_path_accessible(const unsigned int xid, struct cifs_tcon *tcon,
                        struct cifs_sb_info *cifs_sb, const char *full_path)
 {
        int rc;
-       __u64 persistent_fid, volatile_fid;
        __le16 *utf16_path;
        __u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
+       struct cifs_open_parms oparms;
+       struct cifs_fid fid;
 
        utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb);
        if (!utf16_path)
                return -ENOMEM;
 
-       rc = SMB2_open(xid, tcon, utf16_path, &persistent_fid, &volatile_fid,
-                      FILE_READ_ATTRIBUTES, FILE_OPEN, 0, 0, &oplock, NULL);
+       oparms.tcon = tcon;
+       oparms.desired_access = FILE_READ_ATTRIBUTES;
+       oparms.disposition = FILE_OPEN;
+       oparms.create_options = 0;
+       oparms.fid = &fid;
+       oparms.reconnect = false;
+
+       rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL);
        if (rc) {
                kfree(utf16_path);
                return rc;
        }
 
-       rc = SMB2_close(xid, tcon, persistent_fid, volatile_fid);
+       rc = SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
        kfree(utf16_path);
        return rc;
 }
@@ -443,15 +450,20 @@ smb2_query_dir_first(const unsigned int xid, struct cifs_tcon *tcon,
        __le16 *utf16_path;
        int rc;
        __u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
-       __u64 persistent_fid, volatile_fid;
+       struct cifs_open_parms oparms;
 
        utf16_path = cifs_convert_path_to_utf16(path, cifs_sb);
        if (!utf16_path)
                return -ENOMEM;
 
-       rc = SMB2_open(xid, tcon, utf16_path, &persistent_fid, &volatile_fid,
-                      FILE_READ_ATTRIBUTES | FILE_READ_DATA, FILE_OPEN, 0, 0,
-                      &oplock, NULL);
+       oparms.tcon = tcon;
+       oparms.desired_access = FILE_READ_ATTRIBUTES | FILE_READ_DATA;
+       oparms.disposition = FILE_OPEN;
+       oparms.create_options = 0;
+       oparms.fid = fid;
+       oparms.reconnect = false;
+
+       rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL);
        kfree(utf16_path);
        if (rc) {
                cifs_dbg(VFS, "open dir failed\n");
@@ -460,14 +472,12 @@ smb2_query_dir_first(const unsigned int xid, struct cifs_tcon *tcon,
 
        srch_inf->entries_in_buffer = 0;
        srch_inf->index_of_last_entry = 0;
-       fid->persistent_fid = persistent_fid;
-       fid->volatile_fid = volatile_fid;
 
-       rc = SMB2_query_directory(xid, tcon, persistent_fid, volatile_fid, 0,
-                                 srch_inf);
+       rc = SMB2_query_directory(xid, tcon, fid->persistent_fid,
+                                 fid->volatile_fid, 0, srch_inf);
        if (rc) {
                cifs_dbg(VFS, "query directory failed\n");
-               SMB2_close(xid, tcon, persistent_fid, volatile_fid);
+               SMB2_close(xid, tcon, fid->persistent_fid, fid->volatile_fid);
        }
        return rc;
 }
@@ -528,17 +538,25 @@ smb2_queryfs(const unsigned int xid, struct cifs_tcon *tcon,
             struct kstatfs *buf)
 {
        int rc;
-       u64 persistent_fid, volatile_fid;
        __le16 srch_path = 0; /* Null - open root of share */
        u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
+       struct cifs_open_parms oparms;
+       struct cifs_fid fid;
+
+       oparms.tcon = tcon;
+       oparms.desired_access = FILE_READ_ATTRIBUTES;
+       oparms.disposition = FILE_OPEN;
+       oparms.create_options = 0;
+       oparms.fid = &fid;
+       oparms.reconnect = false;
 
-       rc = SMB2_open(xid, tcon, &srch_path, &persistent_fid, &volatile_fid,
-                      FILE_READ_ATTRIBUTES, FILE_OPEN, 0, 0, &oplock, NULL);
+       rc = SMB2_open(xid, &oparms, &srch_path, &oplock, NULL);
        if (rc)
                return rc;
        buf->f_type = SMB2_MAGIC_NUMBER;
-       rc = SMB2_QFS_info(xid, tcon, persistent_fid, volatile_fid, buf);
-       SMB2_close(xid, tcon, persistent_fid, volatile_fid);
+       rc = SMB2_QFS_info(xid, tcon, fid.persistent_fid, fid.volatile_fid,
+                          buf);
+       SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
        return rc;
 }
 
index 2b312e4..abc9c28 100644 (file)
@@ -847,29 +847,76 @@ create_lease_buf(u8 *lease_key, u8 oplock)
        return buf;
 }
 
+static struct create_durable *
+create_durable_buf(void)
+{
+       struct create_durable *buf;
+
+       buf = kzalloc(sizeof(struct create_durable), GFP_KERNEL);
+       if (!buf)
+               return NULL;
+
+       buf->ccontext.DataOffset = cpu_to_le16(offsetof
+                                       (struct create_durable, Data));
+       buf->ccontext.DataLength = cpu_to_le32(16);
+       buf->ccontext.NameOffset = cpu_to_le16(offsetof
+                               (struct create_durable, Name));
+       buf->ccontext.NameLength = cpu_to_le16(4);
+       buf->Name[0] = 'D';
+       buf->Name[1] = 'H';
+       buf->Name[2] = 'n';
+       buf->Name[3] = 'Q';
+       return buf;
+}
+
+static struct create_durable *
+create_reconnect_durable_buf(struct cifs_fid *fid)
+{
+       struct create_durable *buf;
+
+       buf = kzalloc(sizeof(struct create_durable), GFP_KERNEL);
+       if (!buf)
+               return NULL;
+
+       buf->ccontext.DataOffset = cpu_to_le16(offsetof
+                                       (struct create_durable, Data));
+       buf->ccontext.DataLength = cpu_to_le32(16);
+       buf->ccontext.NameOffset = cpu_to_le16(offsetof
+                               (struct create_durable, Name));
+       buf->ccontext.NameLength = cpu_to_le16(4);
+       buf->Data.Fid.PersistentFileId = fid->persistent_fid;
+       buf->Data.Fid.VolatileFileId = fid->volatile_fid;
+       buf->Name[0] = 'D';
+       buf->Name[1] = 'H';
+       buf->Name[2] = 'n';
+       buf->Name[3] = 'C';
+       return buf;
+}
+
 static __u8
 parse_lease_state(struct smb2_create_rsp *rsp)
 {
        char *data_offset;
        struct create_lease *lc;
        bool found = false;
+       unsigned int next = 0;
+       char *name;
 
-       data_offset = (char *)rsp;
-       data_offset += 4 + le32_to_cpu(rsp->CreateContextsOffset);
+       data_offset = (char *)rsp + 4 + le32_to_cpu(rsp->CreateContextsOffset);
        lc = (struct create_lease *)data_offset;
        do {
-               char *name = le16_to_cpu(lc->ccontext.NameOffset) + (char *)lc;
+               lc = (struct create_lease *)((char *)lc + next);
+               name = le16_to_cpu(lc->ccontext.NameOffset) + (char *)lc;
                if (le16_to_cpu(lc->ccontext.NameLength) != 4 ||
                    strncmp(name, "RqLs", 4)) {
-                       lc = (struct create_lease *)((char *)lc
-                                       + le32_to_cpu(lc->ccontext.Next));
+                       next = le32_to_cpu(lc->ccontext.Next);
                        continue;
                }
                if (lc->lcontext.LeaseFlags & SMB2_LEASE_FLAG_BREAK_IN_PROGRESS)
                        return SMB2_OPLOCK_LEVEL_NOCHANGE;
                found = true;
                break;
-       } while (le32_to_cpu(lc->ccontext.Next) != 0);
+       } while (next != 0);
 
        if (!found)
                return 0;
@@ -877,23 +924,74 @@ parse_lease_state(struct smb2_create_rsp *rsp)
        return smb2_map_lease_to_oplock(lc->lcontext.LeaseState);
 }
 
+static int
+add_lease_context(struct kvec *iov, unsigned int *num_iovec, __u8 *oplock)
+{
+       struct smb2_create_req *req = iov[0].iov_base;
+       unsigned int num = *num_iovec;
+
+       iov[num].iov_base = create_lease_buf(oplock+1, *oplock);
+       if (iov[num].iov_base == NULL)
+               return -ENOMEM;
+       iov[num].iov_len = sizeof(struct create_lease);
+       req->RequestedOplockLevel = SMB2_OPLOCK_LEVEL_LEASE;
+       if (!req->CreateContextsOffset)
+               req->CreateContextsOffset = cpu_to_le32(
+                               sizeof(struct smb2_create_req) - 4 +
+                               iov[num - 1].iov_len);
+       req->CreateContextsLength = cpu_to_le32(
+                               le32_to_cpu(req->CreateContextsLength) +
+                               sizeof(struct create_lease));
+       inc_rfc1001_len(&req->hdr, sizeof(struct create_lease));
+       *num_iovec = num + 1;
+       return 0;
+}
+
+static int
+add_durable_context(struct kvec *iov, unsigned int *num_iovec,
+                   struct cifs_open_parms *oparms)
+{
+       struct smb2_create_req *req = iov[0].iov_base;
+       unsigned int num = *num_iovec;
+
+       if (oparms->reconnect) {
+               iov[num].iov_base = create_reconnect_durable_buf(oparms->fid);
+               /* indicate that we don't need to relock the file */
+               oparms->reconnect = false;
+       } else
+               iov[num].iov_base = create_durable_buf();
+       if (iov[num].iov_base == NULL)
+               return -ENOMEM;
+       iov[num].iov_len = sizeof(struct create_durable);
+       if (!req->CreateContextsOffset)
+               req->CreateContextsOffset =
+                       cpu_to_le32(sizeof(struct smb2_create_req) - 4 +
+                                                               iov[1].iov_len);
+       req->CreateContextsLength =
+                       cpu_to_le32(le32_to_cpu(req->CreateContextsLength) +
+                                               sizeof(struct create_durable));
+       inc_rfc1001_len(&req->hdr, sizeof(struct create_durable));
+       *num_iovec = num + 1;
+       return 0;
+}
+
 int
-SMB2_open(const unsigned int xid, struct cifs_tcon *tcon, __le16 *path,
-         u64 *persistent_fid, u64 *volatile_fid, __u32 desired_access,
-         __u32 create_disposition, __u32 file_attributes, __u32 create_options,
+SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
          __u8 *oplock, struct smb2_file_all_info *buf)
 {
        struct smb2_create_req *req;
        struct smb2_create_rsp *rsp;
        struct TCP_Server_Info *server;
+       struct cifs_tcon *tcon = oparms->tcon;
        struct cifs_ses *ses = tcon->ses;
-       struct kvec iov[3];
+       struct kvec iov[4];
        int resp_buftype;
        int uni_path_len;
        __le16 *copy_path = NULL;
        int copy_size;
        int rc = 0;
-       int num_iovecs = 2;
+       unsigned int num_iovecs = 2;
+       __u32 file_attributes = 0;
 
        cifs_dbg(FYI, "create/open\n");
 
@@ -906,55 +1004,47 @@ SMB2_open(const unsigned int xid, struct cifs_tcon *tcon, __le16 *path,
        if (rc)
                return rc;
 
+       if (oparms->create_options & CREATE_OPTION_READONLY)
+               file_attributes |= ATTR_READONLY;
+
        req->ImpersonationLevel = IL_IMPERSONATION;
-       req->DesiredAccess = cpu_to_le32(desired_access);
+       req->DesiredAccess = cpu_to_le32(oparms->desired_access);
        /* File attributes ignored on open (used in create though) */
        req->FileAttributes = cpu_to_le32(file_attributes);
        req->ShareAccess = FILE_SHARE_ALL_LE;
-       req->CreateDisposition = cpu_to_le32(create_disposition);
-       req->CreateOptions = cpu_to_le32(create_options);
+       req->CreateDisposition = cpu_to_le32(oparms->disposition);
+       req->CreateOptions = cpu_to_le32(oparms->create_options & CREATE_OPTIONS_MASK);
        uni_path_len = (2 * UniStrnlen((wchar_t *)path, PATH_MAX)) + 2;
-       req->NameOffset = cpu_to_le16(sizeof(struct smb2_create_req)
-                       - 8 /* pad */ - 4 /* do not count rfc1001 len field */);
+       /* do not count rfc1001 len field */
+       req->NameOffset = cpu_to_le16(sizeof(struct smb2_create_req) - 4);
 
        iov[0].iov_base = (char *)req;
        /* 4 for rfc1002 length field */
        iov[0].iov_len = get_rfc1002_length(req) + 4;
 
        /* MUST set path len (NameLength) to 0 opening root of share */
-       if (uni_path_len >= 4) {
-               req->NameLength = cpu_to_le16(uni_path_len - 2);
-               /* -1 since last byte is buf[0] which is sent below (path) */
-               iov[0].iov_len--;
-               if (uni_path_len % 8 != 0) {
-                       copy_size = uni_path_len / 8 * 8;
-                       if (copy_size < uni_path_len)
-                               copy_size += 8;
-
-                       copy_path = kzalloc(copy_size, GFP_KERNEL);
-                       if (!copy_path)
-                               return -ENOMEM;
-                       memcpy((char *)copy_path, (const char *)path,
-                               uni_path_len);
-                       uni_path_len = copy_size;
-                       path = copy_path;
-               }
-
-               iov[1].iov_len = uni_path_len;
-               iov[1].iov_base = path;
-               /*
-                * -1 since last byte is buf[0] which was counted in
-                * smb2_buf_len.
-                */
-               inc_rfc1001_len(req, uni_path_len - 1);
-       } else {
-               iov[0].iov_len += 7;
-               req->hdr.smb2_buf_length = cpu_to_be32(be32_to_cpu(
-                               req->hdr.smb2_buf_length) + 8 - 1);
-               num_iovecs = 1;
-               req->NameLength = 0;
+       req->NameLength = cpu_to_le16(uni_path_len - 2);
+       /* -1 since last byte is buf[0] which is sent below (path) */
+       iov[0].iov_len--;
+       if (uni_path_len % 8 != 0) {
+               copy_size = uni_path_len / 8 * 8;
+               if (copy_size < uni_path_len)
+                       copy_size += 8;
+
+               copy_path = kzalloc(copy_size, GFP_KERNEL);
+               if (!copy_path)
+                       return -ENOMEM;
+               memcpy((char *)copy_path, (const char *)path,
+                       uni_path_len);
+               uni_path_len = copy_size;
+               path = copy_path;
        }
 
+       iov[1].iov_len = uni_path_len;
+       iov[1].iov_base = path;
+       /* -1 since last byte is buf[0] which was counted in smb2_buf_len */
+       inc_rfc1001_len(req, uni_path_len - 1);
+
        if (!server->oplocks)
                *oplock = SMB2_OPLOCK_LEVEL_NONE;
 
@@ -962,21 +1052,29 @@ SMB2_open(const unsigned int xid, struct cifs_tcon *tcon, __le16 *path,
            *oplock == SMB2_OPLOCK_LEVEL_NONE)
                req->RequestedOplockLevel = *oplock;
        else {
-               iov[num_iovecs].iov_base = create_lease_buf(oplock+1, *oplock);
-               if (iov[num_iovecs].iov_base == NULL) {
+               rc = add_lease_context(iov, &num_iovecs, oplock);
+               if (rc) {
                        cifs_small_buf_release(req);
                        kfree(copy_path);
-                       return -ENOMEM;
+                       return rc;
+               }
+       }
+
+       if (*oplock == SMB2_OPLOCK_LEVEL_BATCH) {
+               /* need to set Next field of lease context if we request it */
+               if (tcon->ses->server->capabilities & SMB2_GLOBAL_CAP_LEASING) {
+                       struct create_context *ccontext =
+                           (struct create_context *)iov[num_iovecs-1].iov_base;
+                       ccontext->Next =
+                               cpu_to_le32(sizeof(struct create_lease));
+               }
+               rc = add_durable_context(iov, &num_iovecs, oparms);
+               if (rc) {
+                       cifs_small_buf_release(req);
+                       kfree(copy_path);
+                       kfree(iov[num_iovecs-1].iov_base);
+                       return rc;
                }
-               iov[num_iovecs].iov_len = sizeof(struct create_lease);
-               req->RequestedOplockLevel = SMB2_OPLOCK_LEVEL_LEASE;
-               req->CreateContextsOffset = cpu_to_le32(
-                       sizeof(struct smb2_create_req) - 4 - 8 +
-                       iov[num_iovecs-1].iov_len);
-               req->CreateContextsLength = cpu_to_le32(
-                       sizeof(struct create_lease));
-               inc_rfc1001_len(&req->hdr, sizeof(struct create_lease));
-               num_iovecs++;
        }
 
        rc = SendReceive2(xid, ses, iov, num_iovecs, &resp_buftype, 0);
@@ -987,8 +1085,8 @@ SMB2_open(const unsigned int xid, struct cifs_tcon *tcon, __le16 *path,
                goto creat_exit;
        }
 
-       *persistent_fid = rsp->PersistentFileId;
-       *volatile_fid = rsp->VolatileFileId;
+       oparms->fid->persistent_fid = rsp->PersistentFileId;
+       oparms->fid->volatile_fid = rsp->VolatileFileId;
 
        if (buf) {
                memcpy(buf, &rsp->CreationTime, 32);
index f31043b..36b0d37 100644 (file)
@@ -428,7 +428,7 @@ struct smb2_create_req {
        __le16 NameLength;
        __le32 CreateContextsOffset;
        __le32 CreateContextsLength;
-       __u8   Buffer[8];
+       __u8   Buffer[0];
 } __packed;
 
 struct smb2_create_rsp {
@@ -485,6 +485,18 @@ struct create_lease {
        struct lease_context lcontext;
 } __packed;
 
+struct create_durable {
+       struct create_context ccontext;
+       __u8   Name[8];
+       union {
+               __u8  Reserved[16];
+               struct {
+                       __u64 PersistentFileId;
+                       __u64 VolatileFileId;
+               } Fid;
+       } Data;
+} __packed;
+
 /* this goes in the ioctl buffer when doing a copychunk request */
 struct copychunk_ioctl {
        char SourceKey[24];
index d4e1eb8..1a5ecbe 100644 (file)
@@ -84,11 +84,9 @@ extern int smb2_create_hardlink(const unsigned int xid, struct cifs_tcon *tcon,
                                const char *from_name, const char *to_name,
                                struct cifs_sb_info *cifs_sb);
 
-extern int smb2_open_file(const unsigned int xid, struct cifs_tcon *tcon,
-                         const char *full_path, int disposition,
-                         int desired_access, int create_options,
-                         struct cifs_fid *fid, __u32 *oplock,
-                         FILE_ALL_INFO *buf, struct cifs_sb_info *cifs_sb);
+extern int smb2_open_file(const unsigned int xid,
+                         struct cifs_open_parms *oparms,
+                         __u32 *oplock, FILE_ALL_INFO *buf);
 extern void smb2_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock);
 extern int smb2_unlock_range(struct cifsFileInfo *cfile,
                             struct file_lock *flock, const unsigned int xid);
@@ -106,11 +104,9 @@ extern int SMB2_tcon(const unsigned int xid, struct cifs_ses *ses,
                     const char *tree, struct cifs_tcon *tcon,
                     const struct nls_table *);
 extern int SMB2_tdis(const unsigned int xid, struct cifs_tcon *tcon);
-extern int SMB2_open(const unsigned int xid, struct cifs_tcon *tcon,
-                    __le16 *path, u64 *persistent_fid, u64 *volatile_fid,
-                    __u32 desired_access, __u32 create_disposition,
-                    __u32 file_attributes, __u32 create_options,
-                    __u8 *oplock, struct smb2_file_all_info *buf);
+extern int SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms,
+                    __le16 *path, __u8 *oplock,
+                    struct smb2_file_all_info *buf);
 extern int SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon,
                     u64 persistent_fid, u64 volatile_fid, u32 opcode,
                     bool is_fsctl, char *in_data, u32 indatalen,
index 09b4fba..301b191 100644 (file)
 #include "smb2status.h"
 #include "smb2glob.h"
 
+static int
+smb2_crypto_shash_allocate(struct TCP_Server_Info *server)
+{
+       unsigned int size;
+
+       if (server->secmech.sdeschmacsha256 != NULL)
+               return 0; /* already allocated */
+
+       server->secmech.hmacsha256 = crypto_alloc_shash("hmac(sha256)", 0, 0);
+       if (IS_ERR(server->secmech.hmacsha256)) {
+               cifs_dbg(VFS, "could not allocate crypto hmacsha256\n");
+               return PTR_ERR(server->secmech.hmacsha256);
+       }
+
+       size = sizeof(struct shash_desc) +
+                       crypto_shash_descsize(server->secmech.hmacsha256);
+       server->secmech.sdeschmacsha256 = kmalloc(size, GFP_KERNEL);
+       if (!server->secmech.sdeschmacsha256) {
+               crypto_free_shash(server->secmech.hmacsha256);
+               server->secmech.hmacsha256 = NULL;
+               return -ENOMEM;
+       }
+       server->secmech.sdeschmacsha256->shash.tfm = server->secmech.hmacsha256;
+       server->secmech.sdeschmacsha256->shash.flags = 0x0;
+
+       return 0;
+}
+
+static int
+smb3_crypto_shash_allocate(struct TCP_Server_Info *server)
+{
+       unsigned int size;
+       int rc;
+
+       if (server->secmech.sdesccmacaes != NULL)
+               return 0;  /* already allocated */
+
+       rc = smb2_crypto_shash_allocate(server);
+       if (rc)
+               return rc;
+
+       server->secmech.cmacaes = crypto_alloc_shash("cmac(aes)", 0, 0);
+       if (IS_ERR(server->secmech.cmacaes)) {
+               cifs_dbg(VFS, "could not allocate crypto cmac-aes");
+               kfree(server->secmech.sdeschmacsha256);
+               server->secmech.sdeschmacsha256 = NULL;
+               crypto_free_shash(server->secmech.hmacsha256);
+               server->secmech.hmacsha256 = NULL;
+               return PTR_ERR(server->secmech.cmacaes);
+       }
+
+       size = sizeof(struct shash_desc) +
+                       crypto_shash_descsize(server->secmech.cmacaes);
+       server->secmech.sdesccmacaes = kmalloc(size, GFP_KERNEL);
+       if (!server->secmech.sdesccmacaes) {
+               cifs_dbg(VFS, "%s: Can't alloc cmacaes\n", __func__);
+               kfree(server->secmech.sdeschmacsha256);
+               server->secmech.sdeschmacsha256 = NULL;
+               crypto_free_shash(server->secmech.hmacsha256);
+               crypto_free_shash(server->secmech.cmacaes);
+               server->secmech.hmacsha256 = NULL;
+               server->secmech.cmacaes = NULL;
+               return -ENOMEM;
+       }
+       server->secmech.sdesccmacaes->shash.tfm = server->secmech.cmacaes;
+       server->secmech.sdesccmacaes->shash.flags = 0x0;
+
+       return 0;
+}
+
+
 int
 smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
 {
@@ -52,6 +123,12 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
        memset(smb2_signature, 0x0, SMB2_HMACSHA256_SIZE);
        memset(smb2_pdu->Signature, 0x0, SMB2_SIGNATURE_SIZE);
 
+       rc = smb2_crypto_shash_allocate(server);
+       if (rc) {
+               cifs_dbg(VFS, "%s: shah256 alloc failed\n", __func__);
+               return rc;
+       }
+
        rc = crypto_shash_setkey(server->secmech.hmacsha256,
                server->session_key.response, SMB2_NTLMV2_SESSKEY_SIZE);
        if (rc) {
@@ -61,7 +138,7 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
 
        rc = crypto_shash_init(&server->secmech.sdeschmacsha256->shash);
        if (rc) {
-               cifs_dbg(VFS, "%s: Could not init md5\n", __func__);
+               cifs_dbg(VFS, "%s: Could not init sha256", __func__);
                return rc;
        }
 
@@ -129,6 +206,12 @@ generate_smb3signingkey(struct TCP_Server_Info *server)
        memset(prfhash, 0x0, SMB2_HMACSHA256_SIZE);
        memset(server->smb3signingkey, 0x0, SMB3_SIGNKEY_SIZE);
 
+       rc = smb3_crypto_shash_allocate(server);
+       if (rc) {
+               cifs_dbg(VFS, "%s: crypto alloc failed\n", __func__);
+               goto smb3signkey_ret;
+       }
+
        rc = crypto_shash_setkey(server->secmech.hmacsha256,
                server->session_key.response, SMB2_NTLMV2_SESSKEY_SIZE);
        if (rc) {
@@ -210,6 +293,11 @@ smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
                return rc;
        }
 
+       /*
+        * we already allocate sdesccmacaes when we init smb3 signing key,
+        * so unlike smb2 case we do not have to check here if secmech are
+        * initialized
+        */
        rc = crypto_shash_init(&server->secmech.sdesccmacaes->shash);
        if (rc) {
                cifs_dbg(VFS, "%s: Could not init cmac aes\n", __func__);
index 5e7c60c..277bd1b 100644 (file)
@@ -660,19 +660,15 @@ static int create_default_group(struct config_group *parent_group,
                                struct config_group *group)
 {
        int ret;
-       struct qstr name;
        struct configfs_dirent *sd;
        /* We trust the caller holds a reference to parent */
        struct dentry *child, *parent = parent_group->cg_item.ci_dentry;
 
        if (!group->cg_item.ci_name)
                group->cg_item.ci_name = group->cg_item.ci_namebuf;
-       name.name = group->cg_item.ci_name;
-       name.len = strlen(name.name);
-       name.hash = full_name_hash(name.name, name.len);
 
        ret = -ENOMEM;
-       child = d_alloc(parent, &name);
+       child = d_alloc_name(parent, group->cg_item.ci_name);
        if (child) {
                d_add(child, NULL);
 
@@ -1650,7 +1646,6 @@ int configfs_register_subsystem(struct configfs_subsystem *subsys)
 {
        int err;
        struct config_group *group = &subsys->su_group;
-       struct qstr name;
        struct dentry *dentry;
        struct dentry *root;
        struct configfs_dirent *sd;
@@ -1667,12 +1662,8 @@ int configfs_register_subsystem(struct configfs_subsystem *subsys)
 
        mutex_lock_nested(&root->d_inode->i_mutex, I_MUTEX_PARENT);
 
-       name.name = group->cg_item.ci_name;
-       name.len = strlen(name.name);
-       name.hash = full_name_hash(name.name, name.len);
-
        err = -ENOMEM;
-       dentry = d_alloc(root, &name);
+       dentry = d_alloc_name(root, group->cg_item.ci_name);
        if (dentry) {
                d_add(dentry, NULL);
 
index cfa109a..d107576 100644 (file)
 #include <asm/unaligned.h>
 #include "ecryptfs_kernel.h"
 
-static int
-ecryptfs_decrypt_page_offset(struct ecryptfs_crypt_stat *crypt_stat,
-                            struct page *dst_page, int dst_offset,
-                            struct page *src_page, int src_offset, int size,
-                            unsigned char *iv);
-static int
-ecryptfs_encrypt_page_offset(struct ecryptfs_crypt_stat *crypt_stat,
-                            struct page *dst_page, int dst_offset,
-                            struct page *src_page, int src_offset, int size,
-                            unsigned char *iv);
+#define DECRYPT                0
+#define ENCRYPT                1
 
 /**
  * ecryptfs_to_hex
@@ -336,19 +328,20 @@ static void extent_crypt_complete(struct crypto_async_request *req, int rc)
 }
 
 /**
- * encrypt_scatterlist
+ * crypt_scatterlist
  * @crypt_stat: Pointer to the crypt_stat struct to initialize.
- * @dest_sg: Destination of encrypted data
- * @src_sg: Data to be encrypted
- * @size: Length of data to be encrypted
- * @iv: iv to use during encryption
+ * @dst_sg: Destination of the data after performing the crypto operation
+ * @src_sg: Data to be encrypted or decrypted
+ * @size: Length of data
+ * @iv: IV to use
+ * @op: ENCRYPT or DECRYPT to indicate the desired operation
  *
- * Returns the number of bytes encrypted; negative value on error
+ * Returns the number of bytes encrypted or decrypted; negative value on error
  */
-static int encrypt_scatterlist(struct ecryptfs_crypt_stat *crypt_stat,
-                              struct scatterlist *dest_sg,
-                              struct scatterlist *src_sg, int size,
-                              unsigned char *iv)
+static int crypt_scatterlist(struct ecryptfs_crypt_stat *crypt_stat,
+                            struct scatterlist *dst_sg,
+                            struct scatterlist *src_sg, int size,
+                            unsigned char *iv, int op)
 {
        struct ablkcipher_request *req = NULL;
        struct extent_crypt_result ecr;
@@ -391,9 +384,9 @@ static int encrypt_scatterlist(struct ecryptfs_crypt_stat *crypt_stat,
                crypt_stat->flags |= ECRYPTFS_KEY_SET;
        }
        mutex_unlock(&crypt_stat->cs_tfm_mutex);
-       ecryptfs_printk(KERN_DEBUG, "Encrypting [%d] bytes.\n", size);
-       ablkcipher_request_set_crypt(req, src_sg, dest_sg, size, iv);
-       rc = crypto_ablkcipher_encrypt(req);
+       ablkcipher_request_set_crypt(req, src_sg, dst_sg, size, iv);
+       rc = op == ENCRYPT ? crypto_ablkcipher_encrypt(req) :
+                            crypto_ablkcipher_decrypt(req);
        if (rc == -EINPROGRESS || rc == -EBUSY) {
                struct extent_crypt_result *ecr = req->base.data;
 
@@ -407,41 +400,43 @@ out:
 }
 
 /**
- * ecryptfs_lower_offset_for_extent
+ * lower_offset_for_page
  *
  * Convert an eCryptfs page index into a lower byte offset
  */
-static void ecryptfs_lower_offset_for_extent(loff_t *offset, loff_t extent_num,
-                                            struct ecryptfs_crypt_stat *crypt_stat)
+static loff_t lower_offset_for_page(struct ecryptfs_crypt_stat *crypt_stat,
+                                   struct page *page)
 {
-       (*offset) = ecryptfs_lower_header_size(crypt_stat)
-                   + (crypt_stat->extent_size * extent_num);
+       return ecryptfs_lower_header_size(crypt_stat) +
+              (page->index << PAGE_CACHE_SHIFT);
 }
 
 /**
- * ecryptfs_encrypt_extent
- * @enc_extent_page: Allocated page into which to encrypt the data in
- *                   @page
+ * crypt_extent
  * @crypt_stat: crypt_stat containing cryptographic context for the
  *              encryption operation
- * @page: Page containing plaintext data extent to encrypt
+ * @dst_page: The page to write the result into
+ * @src_page: The page to read from
  * @extent_offset: Page extent offset for use in generating IV
+ * @op: ENCRYPT or DECRYPT to indicate the desired operation
  *
- * Encrypts one extent of data.
+ * Encrypts or decrypts one extent of data.
  *
  * Return zero on success; non-zero otherwise
  */
-static int ecryptfs_encrypt_extent(struct page *enc_extent_page,
-                                  struct ecryptfs_crypt_stat *crypt_stat,
-                                  struct page *page,
-                                  unsigned long extent_offset)
+static int crypt_extent(struct ecryptfs_crypt_stat *crypt_stat,
+                       struct page *dst_page,
+                       struct page *src_page,
+                       unsigned long extent_offset, int op)
 {
+       pgoff_t page_index = op == ENCRYPT ? src_page->index : dst_page->index;
        loff_t extent_base;
        char extent_iv[ECRYPTFS_MAX_IV_BYTES];
+       struct scatterlist src_sg, dst_sg;
+       size_t extent_size = crypt_stat->extent_size;
        int rc;
 
-       extent_base = (((loff_t)page->index)
-                      * (PAGE_CACHE_SIZE / crypt_stat->extent_size));
+       extent_base = (((loff_t)page_index) * (PAGE_CACHE_SIZE / extent_size));
        rc = ecryptfs_derive_iv(extent_iv, crypt_stat,
                                (extent_base + extent_offset));
        if (rc) {
@@ -450,15 +445,21 @@ static int ecryptfs_encrypt_extent(struct page *enc_extent_page,
                        (unsigned long long)(extent_base + extent_offset), rc);
                goto out;
        }
-       rc = ecryptfs_encrypt_page_offset(crypt_stat, enc_extent_page, 0,
-                                         page, (extent_offset
-                                                * crypt_stat->extent_size),
-                                         crypt_stat->extent_size, extent_iv);
+
+       sg_init_table(&src_sg, 1);
+       sg_init_table(&dst_sg, 1);
+
+       sg_set_page(&src_sg, src_page, extent_size,
+                   extent_offset * extent_size);
+       sg_set_page(&dst_sg, dst_page, extent_size,
+                   extent_offset * extent_size);
+
+       rc = crypt_scatterlist(crypt_stat, &dst_sg, &src_sg, extent_size,
+                              extent_iv, op);
        if (rc < 0) {
-               printk(KERN_ERR "%s: Error attempting to encrypt page with "
-                      "page->index = [%ld], extent_offset = [%ld]; "
-                      "rc = [%d]\n", __func__, page->index, extent_offset,
-                      rc);
+               printk(KERN_ERR "%s: Error attempting to crypt page with "
+                      "page_index = [%ld], extent_offset = [%ld]; "
+                      "rc = [%d]\n", __func__, page_index, extent_offset, rc);
                goto out;
        }
        rc = 0;
@@ -489,6 +490,7 @@ int ecryptfs_encrypt_page(struct page *page)
        char *enc_extent_virt;
        struct page *enc_extent_page = NULL;
        loff_t extent_offset;
+       loff_t lower_offset;
        int rc = 0;
 
        ecryptfs_inode = page->mapping->host;
@@ -502,75 +504,35 @@ int ecryptfs_encrypt_page(struct page *page)
                                "encrypted extent\n");
                goto out;
        }
-       enc_extent_virt = kmap(enc_extent_page);
+
        for (extent_offset = 0;
             extent_offset < (PAGE_CACHE_SIZE / crypt_stat->extent_size);
             extent_offset++) {
-               loff_t offset;
-
-               rc = ecryptfs_encrypt_extent(enc_extent_page, crypt_stat, page,
-                                            extent_offset);
+               rc = crypt_extent(crypt_stat, enc_extent_page, page,
+                                 extent_offset, ENCRYPT);
                if (rc) {
                        printk(KERN_ERR "%s: Error encrypting extent; "
                               "rc = [%d]\n", __func__, rc);
                        goto out;
                }
-               ecryptfs_lower_offset_for_extent(
-                       &offset, ((((loff_t)page->index)
-                                  * (PAGE_CACHE_SIZE
-                                     / crypt_stat->extent_size))
-                                 + extent_offset), crypt_stat);
-               rc = ecryptfs_write_lower(ecryptfs_inode, enc_extent_virt,
-                                         offset, crypt_stat->extent_size);
-               if (rc < 0) {
-                       ecryptfs_printk(KERN_ERR, "Error attempting "
-                                       "to write lower page; rc = [%d]"
-                                       "\n", rc);
-                       goto out;
-               }
-       }
-       rc = 0;
-out:
-       if (enc_extent_page) {
-               kunmap(enc_extent_page);
-               __free_page(enc_extent_page);
        }
-       return rc;
-}
 
-static int ecryptfs_decrypt_extent(struct page *page,
-                                  struct ecryptfs_crypt_stat *crypt_stat,
-                                  struct page *enc_extent_page,
-                                  unsigned long extent_offset)
-{
-       loff_t extent_base;
-       char extent_iv[ECRYPTFS_MAX_IV_BYTES];
-       int rc;
-
-       extent_base = (((loff_t)page->index)
-                      * (PAGE_CACHE_SIZE / crypt_stat->extent_size));
-       rc = ecryptfs_derive_iv(extent_iv, crypt_stat,
-                               (extent_base + extent_offset));
-       if (rc) {
-               ecryptfs_printk(KERN_ERR, "Error attempting to derive IV for "
-                       "extent [0x%.16llx]; rc = [%d]\n",
-                       (unsigned long long)(extent_base + extent_offset), rc);
-               goto out;
-       }
-       rc = ecryptfs_decrypt_page_offset(crypt_stat, page,
-                                         (extent_offset
-                                          * crypt_stat->extent_size),
-                                         enc_extent_page, 0,
-                                         crypt_stat->extent_size, extent_iv);
+       lower_offset = lower_offset_for_page(crypt_stat, page);
+       enc_extent_virt = kmap(enc_extent_page);
+       rc = ecryptfs_write_lower(ecryptfs_inode, enc_extent_virt, lower_offset,
+                                 PAGE_CACHE_SIZE);
+       kunmap(enc_extent_page);
        if (rc < 0) {
-               printk(KERN_ERR "%s: Error attempting to decrypt to page with "
-                      "page->index = [%ld], extent_offset = [%ld]; "
-                      "rc = [%d]\n", __func__, page->index, extent_offset,
-                      rc);
+               ecryptfs_printk(KERN_ERR,
+                       "Error attempting to write lower page; rc = [%d]\n",
+                       rc);
                goto out;
        }
        rc = 0;
 out:
+       if (enc_extent_page) {
+               __free_page(enc_extent_page);
+       }
        return rc;
 }
 
@@ -594,43 +556,33 @@ int ecryptfs_decrypt_page(struct page *page)
 {
        struct inode *ecryptfs_inode;
        struct ecryptfs_crypt_stat *crypt_stat;
-       char *enc_extent_virt;
-       struct page *enc_extent_page = NULL;
+       char *page_virt;
        unsigned long extent_offset;
+       loff_t lower_offset;
        int rc = 0;
 
        ecryptfs_inode = page->mapping->host;
        crypt_stat =
                &(ecryptfs_inode_to_private(ecryptfs_inode)->crypt_stat);
        BUG_ON(!(crypt_stat->flags & ECRYPTFS_ENCRYPTED));
-       enc_extent_page = alloc_page(GFP_USER);
-       if (!enc_extent_page) {
-               rc = -ENOMEM;
-               ecryptfs_printk(KERN_ERR, "Error allocating memory for "
-                               "encrypted extent\n");
+
+       lower_offset = lower_offset_for_page(crypt_stat, page);
+       page_virt = kmap(page);
+       rc = ecryptfs_read_lower(page_virt, lower_offset, PAGE_CACHE_SIZE,
+                                ecryptfs_inode);
+       kunmap(page);
+       if (rc < 0) {
+               ecryptfs_printk(KERN_ERR,
+                       "Error attempting to read lower page; rc = [%d]\n",
+                       rc);
                goto out;
        }
-       enc_extent_virt = kmap(enc_extent_page);
+
        for (extent_offset = 0;
             extent_offset < (PAGE_CACHE_SIZE / crypt_stat->extent_size);
             extent_offset++) {
-               loff_t offset;
-
-               ecryptfs_lower_offset_for_extent(
-                       &offset, ((page->index * (PAGE_CACHE_SIZE
-                                                 / crypt_stat->extent_size))
-                                 + extent_offset), crypt_stat);
-               rc = ecryptfs_read_lower(enc_extent_virt, offset,
-                                        crypt_stat->extent_size,
-                                        ecryptfs_inode);
-               if (rc < 0) {
-                       ecryptfs_printk(KERN_ERR, "Error attempting "
-                                       "to read lower page; rc = [%d]"
-                                       "\n", rc);
-                       goto out;
-               }
-               rc = ecryptfs_decrypt_extent(page, crypt_stat, enc_extent_page,
-                                            extent_offset);
+               rc = crypt_extent(crypt_stat, page, page,
+                                 extent_offset, DECRYPT);
                if (rc) {
                        printk(KERN_ERR "%s: Error encrypting extent; "
                               "rc = [%d]\n", __func__, rc);
@@ -638,140 +590,7 @@ int ecryptfs_decrypt_page(struct page *page)
                }
        }
 out:
-       if (enc_extent_page) {
-               kunmap(enc_extent_page);
-               __free_page(enc_extent_page);
-       }
-       return rc;
-}
-
-/**
- * decrypt_scatterlist
- * @crypt_stat: Cryptographic context
- * @dest_sg: The destination scatterlist to decrypt into
- * @src_sg: The source scatterlist to decrypt from
- * @size: The number of bytes to decrypt
- * @iv: The initialization vector to use for the decryption
- *
- * Returns the number of bytes decrypted; negative value on error
- */
-static int decrypt_scatterlist(struct ecryptfs_crypt_stat *crypt_stat,
-                              struct scatterlist *dest_sg,
-                              struct scatterlist *src_sg, int size,
-                              unsigned char *iv)
-{
-       struct ablkcipher_request *req = NULL;
-       struct extent_crypt_result ecr;
-       int rc = 0;
-
-       BUG_ON(!crypt_stat || !crypt_stat->tfm
-              || !(crypt_stat->flags & ECRYPTFS_STRUCT_INITIALIZED));
-       if (unlikely(ecryptfs_verbosity > 0)) {
-               ecryptfs_printk(KERN_DEBUG, "Key size [%zd]; key:\n",
-                               crypt_stat->key_size);
-               ecryptfs_dump_hex(crypt_stat->key,
-                                 crypt_stat->key_size);
-       }
-
-       init_completion(&ecr.completion);
-
-       mutex_lock(&crypt_stat->cs_tfm_mutex);
-       req = ablkcipher_request_alloc(crypt_stat->tfm, GFP_NOFS);
-       if (!req) {
-               mutex_unlock(&crypt_stat->cs_tfm_mutex);
-               rc = -ENOMEM;
-               goto out;
-       }
-
-       ablkcipher_request_set_callback(req,
-                       CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP,
-                       extent_crypt_complete, &ecr);
-       /* Consider doing this once, when the file is opened */
-       if (!(crypt_stat->flags & ECRYPTFS_KEY_SET)) {
-               rc = crypto_ablkcipher_setkey(crypt_stat->tfm, crypt_stat->key,
-                                             crypt_stat->key_size);
-               if (rc) {
-                       ecryptfs_printk(KERN_ERR,
-                                       "Error setting key; rc = [%d]\n",
-                                       rc);
-                       mutex_unlock(&crypt_stat->cs_tfm_mutex);
-                       rc = -EINVAL;
-                       goto out;
-               }
-               crypt_stat->flags |= ECRYPTFS_KEY_SET;
-       }
-       mutex_unlock(&crypt_stat->cs_tfm_mutex);
-       ecryptfs_printk(KERN_DEBUG, "Decrypting [%d] bytes.\n", size);
-       ablkcipher_request_set_crypt(req, src_sg, dest_sg, size, iv);
-       rc = crypto_ablkcipher_decrypt(req);
-       if (rc == -EINPROGRESS || rc == -EBUSY) {
-               struct extent_crypt_result *ecr = req->base.data;
-
-               wait_for_completion(&ecr->completion);
-               rc = ecr->rc;
-               INIT_COMPLETION(ecr->completion);
-       }
-out:
-       ablkcipher_request_free(req);
        return rc;
-
-}
-
-/**
- * ecryptfs_encrypt_page_offset
- * @crypt_stat: The cryptographic context
- * @dst_page: The page to encrypt into
- * @dst_offset: The offset in the page to encrypt into
- * @src_page: The page to encrypt from
- * @src_offset: The offset in the page to encrypt from
- * @size: The number of bytes to encrypt
- * @iv: The initialization vector to use for the encryption
- *
- * Returns the number of bytes encrypted
- */
-static int
-ecryptfs_encrypt_page_offset(struct ecryptfs_crypt_stat *crypt_stat,
-                            struct page *dst_page, int dst_offset,
-                            struct page *src_page, int src_offset, int size,
-                            unsigned char *iv)
-{
-       struct scatterlist src_sg, dst_sg;
-
-       sg_init_table(&src_sg, 1);
-       sg_init_table(&dst_sg, 1);
-
-       sg_set_page(&src_sg, src_page, size, src_offset);
-       sg_set_page(&dst_sg, dst_page, size, dst_offset);
-       return encrypt_scatterlist(crypt_stat, &dst_sg, &src_sg, size, iv);
-}
-
-/**
- * ecryptfs_decrypt_page_offset
- * @crypt_stat: The cryptographic context
- * @dst_page: The page to decrypt into
- * @dst_offset: The offset in the page to decrypt into
- * @src_page: The page to decrypt from
- * @src_offset: The offset in the page to decrypt from
- * @size: The number of bytes to decrypt
- * @iv: The initialization vector to use for the decryption
- *
- * Returns the number of bytes decrypted
- */
-static int
-ecryptfs_decrypt_page_offset(struct ecryptfs_crypt_stat *crypt_stat,
-                            struct page *dst_page, int dst_offset,
-                            struct page *src_page, int src_offset, int size,
-                            unsigned char *iv)
-{
-       struct scatterlist src_sg, dst_sg;
-
-       sg_init_table(&src_sg, 1);
-       sg_set_page(&src_sg, src_page, size, src_offset);
-
-       sg_init_table(&dst_sg, 1);
-       sg_set_page(&dst_sg, dst_page, size, dst_offset);
-
-       return decrypt_scatterlist(crypt_stat, &dst_sg, &src_sg, size, iv);
 }
 
 #define ECRYPTFS_MAX_SCATTERLIST_LEN 4
index 24f1105..992cf95 100644 (file)
@@ -49,7 +49,7 @@ static ssize_t ecryptfs_read_update_atime(struct kiocb *iocb,
                                unsigned long nr_segs, loff_t pos)
 {
        ssize_t rc;
-       struct path lower;
+       struct path *path;
        struct file *file = iocb->ki_filp;
 
        rc = generic_file_aio_read(iocb, iov, nr_segs, pos);
@@ -60,9 +60,8 @@ static ssize_t ecryptfs_read_update_atime(struct kiocb *iocb,
        if (-EIOCBQUEUED == rc)
                rc = wait_on_sync_kiocb(iocb);
        if (rc >= 0) {
-               lower.dentry = ecryptfs_dentry_to_lower(file->f_path.dentry);
-               lower.mnt = ecryptfs_dentry_to_lower_mnt(file->f_path.dentry);
-               touch_atime(&lower);
+               path = ecryptfs_dentry_to_lower_path(file->f_path.dentry);
+               touch_atime(path);
        }
        return rc;
 }
index e924cf4..eb1c597 100644 (file)
@@ -120,16 +120,15 @@ static int ecryptfs_init_lower_file(struct dentry *dentry,
                                    struct file **lower_file)
 {
        const struct cred *cred = current_cred();
-       struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry);
-       struct vfsmount *lower_mnt = ecryptfs_dentry_to_lower_mnt(dentry);
+       struct path *path = ecryptfs_dentry_to_lower_path(dentry);
        int rc;
 
-       rc = ecryptfs_privileged_open(lower_file, lower_dentry, lower_mnt,
+       rc = ecryptfs_privileged_open(lower_file, path->dentry, path->mnt,
                                      cred);
        if (rc) {
                printk(KERN_ERR "Error opening lower file "
                       "for lower_dentry [0x%p] and lower_mnt [0x%p]; "
-                      "rc = [%d]\n", lower_dentry, lower_mnt, rc);
+                      "rc = [%d]\n", path->dentry, path->mnt, rc);
                (*lower_file) = NULL;
        }
        return rc;
index 49ff8ea..e57380e 100644 (file)
@@ -247,14 +247,13 @@ int ecryptfs_process_response(struct ecryptfs_daemon *daemon,
                goto unlock;
        }
        msg_size = (sizeof(*msg) + msg->data_len);
-       msg_ctx->msg = kmalloc(msg_size, GFP_KERNEL);
+       msg_ctx->msg = kmemdup(msg, msg_size, GFP_KERNEL);
        if (!msg_ctx->msg) {
                rc = -ENOMEM;
                printk(KERN_ERR "%s: Failed to allocate [%zd] bytes of "
                       "GFP_KERNEL memory\n", __func__, msg_size);
                goto unlock;
        }
-       memcpy(msg_ctx->msg, msg, msg_size);
        msg_ctx->state = ECRYPTFS_MSG_CTX_STATE_DONE;
        wake_up_process(msg_ctx->task);
        rc = 0;
index 7e787fb..07ab497 100644 (file)
@@ -155,20 +155,8 @@ static int efivarfs_unlink(struct inode *dir, struct dentry *dentry)
        return 0;
 };
 
-/*
- * Handle negative dentry.
- */
-static struct dentry *efivarfs_lookup(struct inode *dir, struct dentry *dentry,
-                                     unsigned int flags)
-{
-       if (dentry->d_name.len > NAME_MAX)
-               return ERR_PTR(-ENAMETOOLONG);
-       d_add(dentry, NULL);
-       return NULL;
-}
-
 const struct inode_operations efivarfs_dir_inode_operations = {
-       .lookup = efivarfs_lookup,
+       .lookup = simple_lookup,
        .unlink = efivarfs_unlink,
        .create = efivarfs_create,
 };
index 08e719b..b44e4c5 100644 (file)
@@ -265,18 +265,15 @@ static void __fput(struct file *file)
        mntput(mnt);
 }
 
-static DEFINE_SPINLOCK(delayed_fput_lock);
-static LIST_HEAD(delayed_fput_list);
+static LLIST_HEAD(delayed_fput_list);
 static void delayed_fput(struct work_struct *unused)
 {
-       LIST_HEAD(head);
-       spin_lock_irq(&delayed_fput_lock);
-       list_splice_init(&delayed_fput_list, &head);
-       spin_unlock_irq(&delayed_fput_lock);
-       while (!list_empty(&head)) {
-               struct file *f = list_first_entry(&head, struct file, f_u.fu_list);
-               list_del_init(&f->f_u.fu_list);
-               __fput(f);
+       struct llist_node *node = llist_del_all(&delayed_fput_list);
+       struct llist_node *next;
+
+       for (; node; node = next) {
+               next = llist_next(node);
+               __fput(llist_entry(node, struct file, f_u.fu_llist));
        }
 }
 
@@ -306,18 +303,22 @@ void fput(struct file *file)
 {
        if (atomic_long_dec_and_test(&file->f_count)) {
                struct task_struct *task = current;
-               unsigned long flags;
 
                file_sb_list_del(file);
                if (likely(!in_interrupt() && !(task->flags & PF_KTHREAD))) {
                        init_task_work(&file->f_u.fu_rcuhead, ____fput);
                        if (!task_work_add(task, &file->f_u.fu_rcuhead, true))
                                return;
+                       /*
+                        * After this task has run exit_task_work(),
+                        * task_work_add() will fail.  free_ipc_ns()->
+                        * shm_destroy() can do this.  Fall through to delayed
+                        * fput to avoid leaking *file.
+                        */
                }
-               spin_lock_irqsave(&delayed_fput_lock, flags);
-               list_add(&file->f_u.fu_list, &delayed_fput_list);
-               schedule_work(&delayed_fput_work);
-               spin_unlock_irqrestore(&delayed_fput_lock, flags);
+
+               if (llist_add(&file->f_u.fu_llist, &delayed_fput_list))
+                       schedule_work(&delayed_fput_work);
        }
 }
 
index 9a55f53..370d7b6 100644 (file)
@@ -346,8 +346,7 @@ int dbFree(struct inode *ip, s64 blkno, s64 nblocks)
                printk(KERN_ERR "blkno = %Lx, nblocks = %Lx\n",
                       (unsigned long long) blkno,
                       (unsigned long long) nblocks);
-               jfs_error(ip->i_sb,
-                         "dbFree: block to be freed is outside the map");
+               jfs_error(ip->i_sb, "block to be freed is outside the map\n");
                return -EIO;
        }
 
@@ -384,7 +383,7 @@ int dbFree(struct inode *ip, s64 blkno, s64 nblocks)
 
                /* free the blocks. */
                if ((rc = dbFreeDmap(bmp, dp, blkno, nb))) {
-                       jfs_error(ip->i_sb, "dbFree: error in block map\n");
+                       jfs_error(ip->i_sb, "error in block map\n");
                        release_metapage(mp);
                        IREAD_UNLOCK(ipbmap);
                        return (rc);
@@ -441,8 +440,7 @@ dbUpdatePMap(struct inode *ipbmap,
                printk(KERN_ERR "blkno = %Lx, nblocks = %Lx\n",
                       (unsigned long long) blkno,
                       (unsigned long long) nblocks);
-               jfs_error(ipbmap->i_sb,
-                         "dbUpdatePMap: blocks are outside the map");
+               jfs_error(ipbmap->i_sb, "blocks are outside the map\n");
                return -EIO;
        }
 
@@ -726,7 +724,7 @@ int dbAlloc(struct inode *ip, s64 hint, s64 nblocks, s64 * results)
 
        /* the hint should be within the map */
        if (hint >= mapSize) {
-               jfs_error(ip->i_sb, "dbAlloc: the hint is outside the map");
+               jfs_error(ip->i_sb, "the hint is outside the map\n");
                return -EIO;
        }
 
@@ -1057,8 +1055,7 @@ static int dbExtend(struct inode *ip, s64 blkno, s64 nblocks, s64 addnblocks)
        bmp = sbi->bmap;
        if (lastblkno < 0 || lastblkno >= bmp->db_mapsize) {
                IREAD_UNLOCK(ipbmap);
-               jfs_error(ip->i_sb,
-                         "dbExtend: the block is outside the filesystem");
+               jfs_error(ip->i_sb, "the block is outside the filesystem\n");
                return -EIO;
        }
 
@@ -1134,8 +1131,7 @@ static int dbAllocNext(struct bmap * bmp, struct dmap * dp, s64 blkno,
        u32 mask;
 
        if (dp->tree.leafidx != cpu_to_le32(LEAFIND)) {
-               jfs_error(bmp->db_ipbmap->i_sb,
-                         "dbAllocNext: Corrupt dmap page");
+               jfs_error(bmp->db_ipbmap->i_sb, "Corrupt dmap page\n");
                return -EIO;
        }
 
@@ -1265,8 +1261,7 @@ dbAllocNear(struct bmap * bmp,
        s8 *leaf;
 
        if (dp->tree.leafidx != cpu_to_le32(LEAFIND)) {
-               jfs_error(bmp->db_ipbmap->i_sb,
-                         "dbAllocNear: Corrupt dmap page");
+               jfs_error(bmp->db_ipbmap->i_sb, "Corrupt dmap page\n");
                return -EIO;
        }
 
@@ -1381,8 +1376,7 @@ dbAllocAG(struct bmap * bmp, int agno, s64 nblocks, int l2nb, s64 * results)
         */
        if (l2nb > bmp->db_agl2size) {
                jfs_error(bmp->db_ipbmap->i_sb,
-                         "dbAllocAG: allocation request is larger than the "
-                         "allocation group size");
+                         "allocation request is larger than the allocation group size\n");
                return -EIO;
        }
 
@@ -1417,7 +1411,7 @@ dbAllocAG(struct bmap * bmp, int agno, s64 nblocks, int l2nb, s64 * results)
                               (unsigned long long) blkno,
                               (unsigned long long) nblocks);
                        jfs_error(bmp->db_ipbmap->i_sb,
-                                 "dbAllocAG: dbAllocCtl failed in free AG");
+                                 "dbAllocCtl failed in free AG\n");
                }
                return (rc);
        }
@@ -1433,8 +1427,7 @@ dbAllocAG(struct bmap * bmp, int agno, s64 nblocks, int l2nb, s64 * results)
        budmin = dcp->budmin;
 
        if (dcp->leafidx != cpu_to_le32(CTLLEAFIND)) {
-               jfs_error(bmp->db_ipbmap->i_sb,
-                         "dbAllocAG: Corrupt dmapctl page");
+               jfs_error(bmp->db_ipbmap->i_sb, "Corrupt dmapctl page\n");
                release_metapage(mp);
                return -EIO;
        }
@@ -1475,7 +1468,7 @@ dbAllocAG(struct bmap * bmp, int agno, s64 nblocks, int l2nb, s64 * results)
                        }
                        if (n == 4) {
                                jfs_error(bmp->db_ipbmap->i_sb,
-                                         "dbAllocAG: failed descending stree");
+                                         "failed descending stree\n");
                                release_metapage(mp);
                                return -EIO;
                        }
@@ -1515,8 +1508,7 @@ dbAllocAG(struct bmap * bmp, int agno, s64 nblocks, int l2nb, s64 * results)
                                       &blkno))) {
                                if (rc == -ENOSPC) {
                                        jfs_error(bmp->db_ipbmap->i_sb,
-                                                 "dbAllocAG: control page "
-                                                 "inconsistent");
+                                                 "control page inconsistent\n");
                                        return -EIO;
                                }
                                return (rc);
@@ -1528,7 +1520,7 @@ dbAllocAG(struct bmap * bmp, int agno, s64 nblocks, int l2nb, s64 * results)
                rc = dbAllocCtl(bmp, nblocks, l2nb, blkno, results);
                if (rc == -ENOSPC) {
                        jfs_error(bmp->db_ipbmap->i_sb,
-                                 "dbAllocAG: unable to allocate blocks");
+                                 "unable to allocate blocks\n");
                        rc = -EIO;
                }
                return (rc);
@@ -1587,8 +1579,7 @@ static int dbAllocAny(struct bmap * bmp, s64 nblocks, int l2nb, s64 * results)
         */
        rc = dbAllocCtl(bmp, nblocks, l2nb, blkno, results);
        if (rc == -ENOSPC) {
-               jfs_error(bmp->db_ipbmap->i_sb,
-                         "dbAllocAny: unable to allocate blocks");
+               jfs_error(bmp->db_ipbmap->i_sb, "unable to allocate blocks\n");
                return -EIO;
        }
        return (rc);
@@ -1652,8 +1643,7 @@ s64 dbDiscardAG(struct inode *ip, int agno, s64 minlen)
        range_cnt = min_t(u64, max_ranges + 1, 32 * 1024);
        totrim = kmalloc(sizeof(struct range2trim) * range_cnt, GFP_NOFS);
        if (totrim == NULL) {
-               jfs_error(bmp->db_ipbmap->i_sb,
-                         "dbDiscardAG: no memory for trim array");
+               jfs_error(bmp->db_ipbmap->i_sb, "no memory for trim array\n");
                IWRITE_UNLOCK(ipbmap);
                return 0;
        }
@@ -1682,8 +1672,7 @@ s64 dbDiscardAG(struct inode *ip, int agno, s64 minlen)
                        nblocks = 1 << l2nb;
                } else {
                        /* Trim any already allocated blocks */
-                       jfs_error(bmp->db_ipbmap->i_sb,
-                               "dbDiscardAG: -EIO");
+                       jfs_error(bmp->db_ipbmap->i_sb, "-EIO\n");
                        break;
                }
 
@@ -1761,7 +1750,7 @@ static int dbFindCtl(struct bmap * bmp, int l2nb, int level, s64 * blkno)
 
                if (dcp->leafidx != cpu_to_le32(CTLLEAFIND)) {
                        jfs_error(bmp->db_ipbmap->i_sb,
-                                 "dbFindCtl: Corrupt dmapctl page");
+                                 "Corrupt dmapctl page\n");
                        release_metapage(mp);
                        return -EIO;
                }
@@ -1782,7 +1771,7 @@ static int dbFindCtl(struct bmap * bmp, int l2nb, int level, s64 * blkno)
                if (rc) {
                        if (lev != level) {
                                jfs_error(bmp->db_ipbmap->i_sb,
-                                         "dbFindCtl: dmap inconsistent");
+                                         "dmap inconsistent\n");
                                return -EIO;
                        }
                        return -ENOSPC;
@@ -1906,7 +1895,7 @@ dbAllocCtl(struct bmap * bmp, s64 nblocks, int l2nb, s64 blkno, s64 * results)
                if (dp->tree.stree[ROOT] != L2BPERDMAP) {
                        release_metapage(mp);
                        jfs_error(bmp->db_ipbmap->i_sb,
-                                 "dbAllocCtl: the dmap is not all free");
+                                 "the dmap is not all free\n");
                        rc = -EIO;
                        goto backout;
                }
@@ -1953,7 +1942,7 @@ dbAllocCtl(struct bmap * bmp, s64 nblocks, int l2nb, s64 blkno, s64 * results)
                         * to indicate that we have leaked blocks.
                         */
                        jfs_error(bmp->db_ipbmap->i_sb,
-                                 "dbAllocCtl: I/O Error: Block Leakage.");
+                                 "I/O Error: Block Leakage\n");
                        continue;
                }
                dp = (struct dmap *) mp->data;
@@ -1965,8 +1954,7 @@ dbAllocCtl(struct bmap * bmp, s64 nblocks, int l2nb, s64 blkno, s64 * results)
                         * to indicate that we have leaked blocks.
                         */
                        release_metapage(mp);
-                       jfs_error(bmp->db_ipbmap->i_sb,
-                                 "dbAllocCtl: Block Leakage.");
+                       jfs_error(bmp->db_ipbmap->i_sb, "Block Leakage\n");
                        continue;
                }
 
@@ -2263,8 +2251,7 @@ static void dbAllocBits(struct bmap * bmp, struct dmap * dp, s64 blkno,
                        for (; nwords > 0; nwords -= nw) {
                                if (leaf[word] < BUDMIN) {
                                        jfs_error(bmp->db_ipbmap->i_sb,
-                                                 "dbAllocBits: leaf page "
-                                                 "corrupt");
+                                                 "leaf page corrupt\n");
                                        break;
                                }
 
@@ -2536,8 +2523,7 @@ dbAdjCtl(struct bmap * bmp, s64 blkno, int newval, int alloc, int level)
        dcp = (struct dmapctl *) mp->data;
 
        if (dcp->leafidx != cpu_to_le32(CTLLEAFIND)) {
-               jfs_error(bmp->db_ipbmap->i_sb,
-                         "dbAdjCtl: Corrupt dmapctl page");
+               jfs_error(bmp->db_ipbmap->i_sb, "Corrupt dmapctl page\n");
                release_metapage(mp);
                return -EIO;
        }
@@ -2638,8 +2624,7 @@ dbAdjCtl(struct bmap * bmp, s64 blkno, int newval, int alloc, int level)
                        assert(level == bmp->db_maxlevel);
                        if (bmp->db_maxfreebud != oldroot) {
                                jfs_error(bmp->db_ipbmap->i_sb,
-                                         "dbAdjCtl: the maximum free buddy is "
-                                         "not the old root");
+                                         "the maximum free buddy is not the old root\n");
                        }
                        bmp->db_maxfreebud = dcp->stree[ROOT];
                }
@@ -3481,7 +3466,7 @@ int dbExtendFS(struct inode *ipbmap, s64 blkno,   s64 nblocks)
        p = BMAPBLKNO + nbperpage;      /* L2 page */
        l2mp = read_metapage(ipbmap, p, PSIZE, 0);
        if (!l2mp) {
-               jfs_error(ipbmap->i_sb, "dbExtendFS: L2 page could not be read");
+               jfs_error(ipbmap->i_sb, "L2 page could not be read\n");
                return -EIO;
        }
        l2dcp = (struct dmapctl *) l2mp->data;
@@ -3646,8 +3631,7 @@ int dbExtendFS(struct inode *ipbmap, s64 blkno,   s64 nblocks)
                }
        }                       /* for each L1 in a L2 */
 
-       jfs_error(ipbmap->i_sb,
-                 "dbExtendFS: function has not returned as expected");
+       jfs_error(ipbmap->i_sb, "function has not returned as expected\n");
 errout:
        if (l0mp)
                release_metapage(l0mp);
@@ -3717,7 +3701,7 @@ void dbFinalizeBmap(struct inode *ipbmap)
                }
                if (bmp->db_agpref >= bmp->db_numag) {
                        jfs_error(ipbmap->i_sb,
-                                 "cannot find ag with average freespace");
+                                 "cannot find ag with average freespace\n");
                }
        }
 
index 9f4ed13..8743ba9 100644 (file)
@@ -124,21 +124,21 @@ struct dtsplit {
 #define DT_PAGE(IP, MP) BT_PAGE(IP, MP, dtpage_t, i_dtroot)
 
 /* get page buffer for specified block address */
-#define DT_GETPAGE(IP, BN, MP, SIZE, P, RC)\
-{\
-       BT_GETPAGE(IP, BN, MP, dtpage_t, SIZE, P, RC, i_dtroot)\
-       if (!(RC))\
-       {\
-               if (((P)->header.nextindex > (((BN)==0)?DTROOTMAXSLOT:(P)->header.maxslot)) ||\
-                   ((BN) && ((P)->header.maxslot > DTPAGEMAXSLOT)))\
-               {\
-                       BT_PUTPAGE(MP);\
-                       jfs_error((IP)->i_sb, "DT_GETPAGE: dtree page corrupt");\
-                       MP = NULL;\
-                       RC = -EIO;\
-               }\
-       }\
-}
+#define DT_GETPAGE(IP, BN, MP, SIZE, P, RC)                            \
+do {                                                                   \
+       BT_GETPAGE(IP, BN, MP, dtpage_t, SIZE, P, RC, i_dtroot);        \
+       if (!(RC)) {                                                    \
+               if (((P)->header.nextindex >                            \
+                    (((BN) == 0) ? DTROOTMAXSLOT : (P)->header.maxslot)) || \
+                   ((BN) && ((P)->header.maxslot > DTPAGEMAXSLOT))) {  \
+                       BT_PUTPAGE(MP);                                 \
+                       jfs_error((IP)->i_sb,                           \
+                                 "DT_GETPAGE: dtree page corrupt\n");  \
+                       MP = NULL;                                      \
+                       RC = -EIO;                                      \
+               }                                                       \
+       }                                                               \
+} while (0)
 
 /* for consistency */
 #define DT_PUTPAGE(MP) BT_PUTPAGE(MP)
@@ -776,7 +776,7 @@ int dtSearch(struct inode *ip, struct component_name * key, ino_t * data,
                        /* Something's corrupted, mark filesystem dirty so
                         * chkdsk will fix it.
                         */
-                       jfs_error(sb, "stack overrun in dtSearch!");
+                       jfs_error(sb, "stack overrun!\n");
                        BT_STACK_DUMP(btstack);
                        rc = -EIO;
                        goto out;
@@ -3247,8 +3247,7 @@ int jfs_readdir(struct file *file, struct dir_context *ctx)
                                /* Sanity Check */
                                if (d_namleft == 0) {
                                        jfs_error(ip->i_sb,
-                                                 "JFS:Dtree error: ino = "
-                                                 "%ld, bn=%Ld, index = %d",
+                                                 "JFS:Dtree error: ino = %ld, bn=%lld, index = %d\n",
                                                  (long)ip->i_ino,
                                                  (long long)bn,
                                                  i);
@@ -3368,7 +3367,7 @@ static int dtReadFirst(struct inode *ip, struct btstack * btstack)
                 */
                if (BT_STACK_FULL(btstack)) {
                        DT_PUTPAGE(mp);
-                       jfs_error(ip->i_sb, "dtReadFirst: btstack overrun");
+                       jfs_error(ip->i_sb, "btstack overrun\n");
                        BT_STACK_DUMP(btstack);
                        return -EIO;
                }
index e5fe850..2ae7d59 100644 (file)
@@ -388,7 +388,7 @@ int extHint(struct inode *ip, s64 offset, xad_t * xp)
 
        if ((rc == 0) && xlen) {
                if (xlen != nbperpage) {
-                       jfs_error(ip->i_sb, "extHint: corrupt xtree");
+                       jfs_error(ip->i_sb, "corrupt xtree\n");
                        rc = -EIO;
                }
                XADaddress(xp, xaddr);
index f7e042b..f321986 100644 (file)
@@ -386,7 +386,7 @@ int diRead(struct inode *ip)
        dp += rel_inode;
 
        if (ip->i_ino != le32_to_cpu(dp->di_number)) {
-               jfs_error(ip->i_sb, "diRead: i_ino != di_number");
+               jfs_error(ip->i_sb, "i_ino != di_number\n");
                rc = -EIO;
        } else if (le32_to_cpu(dp->di_nlink) == 0)
                rc = -ESTALE;
@@ -625,7 +625,7 @@ int diWrite(tid_t tid, struct inode *ip)
        if (!addressPXD(&(jfs_ip->ixpxd)) ||
            (lengthPXD(&(jfs_ip->ixpxd)) !=
             JFS_IP(ipimap)->i_imap->im_nbperiext)) {
-               jfs_error(ip->i_sb, "diWrite: ixpxd invalid");
+               jfs_error(ip->i_sb, "ixpxd invalid\n");
                return -EIO;
        }
 
@@ -893,8 +893,7 @@ int diFree(struct inode *ip)
        if (iagno >= imap->im_nextiag) {
                print_hex_dump(KERN_ERR, "imap: ", DUMP_PREFIX_ADDRESS, 16, 4,
                               imap, 32, 0);
-               jfs_error(ip->i_sb,
-                         "diFree: inum = %d, iagno = %d, nextiag = %d",
+               jfs_error(ip->i_sb, "inum = %d, iagno = %d, nextiag = %d\n",
                          (uint) inum, iagno, imap->im_nextiag);
                return -EIO;
        }
@@ -930,15 +929,14 @@ int diFree(struct inode *ip)
        mask = HIGHORDER >> bitno;
 
        if (!(le32_to_cpu(iagp->wmap[extno]) & mask)) {
-               jfs_error(ip->i_sb,
-                         "diFree: wmap shows inode already free");
+               jfs_error(ip->i_sb, "wmap shows inode already free\n");
        }
 
        if (!addressPXD(&iagp->inoext[extno])) {
                release_metapage(mp);
                IREAD_UNLOCK(ipimap);
                AG_UNLOCK(imap, agno);
-               jfs_error(ip->i_sb, "diFree: invalid inoext");
+               jfs_error(ip->i_sb, "invalid inoext\n");
                return -EIO;
        }
 
@@ -950,7 +948,7 @@ int diFree(struct inode *ip)
                release_metapage(mp);
                IREAD_UNLOCK(ipimap);
                AG_UNLOCK(imap, agno);
-               jfs_error(ip->i_sb, "diFree: numfree > numinos");
+               jfs_error(ip->i_sb, "numfree > numinos\n");
                return -EIO;
        }
        /*
@@ -1199,7 +1197,7 @@ int diFree(struct inode *ip)
         * for the inode being freed.
         */
        if (iagp->pmap[extno] != 0) {
-               jfs_error(ip->i_sb, "diFree: the pmap does not show inode free");
+               jfs_error(ip->i_sb, "the pmap does not show inode free\n");
        }
        iagp->wmap[extno] = 0;
        PXDlength(&iagp->inoext[extno], 0);
@@ -1518,8 +1516,7 @@ int diAlloc(struct inode *pip, bool dir, struct inode *ip)
                                        release_metapage(mp);
                                        AG_UNLOCK(imap, agno);
                                        jfs_error(ip->i_sb,
-                                                 "diAlloc: can't find free bit "
-                                                 "in wmap");
+                                                 "can't find free bit in wmap\n");
                                        return -EIO;
                                }
 
@@ -1660,7 +1657,7 @@ diAllocAG(struct inomap * imap, int agno, bool dir, struct inode *ip)
        numinos = imap->im_agctl[agno].numinos;
 
        if (numfree > numinos) {
-               jfs_error(ip->i_sb, "diAllocAG: numfree > numinos");
+               jfs_error(ip->i_sb, "numfree > numinos\n");
                return -EIO;
        }
 
@@ -1811,8 +1808,7 @@ static int diAllocIno(struct inomap * imap, int agno, struct inode *ip)
        if (!iagp->nfreeinos) {
                IREAD_UNLOCK(imap->im_ipimap);
                release_metapage(mp);
-               jfs_error(ip->i_sb,
-                         "diAllocIno: nfreeinos = 0, but iag on freelist");
+               jfs_error(ip->i_sb, "nfreeinos = 0, but iag on freelist\n");
                return -EIO;
        }
 
@@ -1824,7 +1820,7 @@ static int diAllocIno(struct inomap * imap, int agno, struct inode *ip)
                        IREAD_UNLOCK(imap->im_ipimap);
                        release_metapage(mp);
                        jfs_error(ip->i_sb,
-                                 "diAllocIno: free inode not found in summary map");
+                                 "free inode not found in summary map\n");
                        return -EIO;
                }
 
@@ -1839,7 +1835,7 @@ static int diAllocIno(struct inomap * imap, int agno, struct inode *ip)
        if (rem >= EXTSPERSUM) {
                IREAD_UNLOCK(imap->im_ipimap);
                release_metapage(mp);
-               jfs_error(ip->i_sb, "diAllocIno: no free extent found");
+               jfs_error(ip->i_sb, "no free extent found\n");
                return -EIO;
        }
        extno = (sword << L2EXTSPERSUM) + rem;
@@ -1850,7 +1846,7 @@ static int diAllocIno(struct inomap * imap, int agno, struct inode *ip)
        if (rem >= INOSPEREXT) {
                IREAD_UNLOCK(imap->im_ipimap);
                release_metapage(mp);
-               jfs_error(ip->i_sb, "diAllocIno: free inode not found");
+               jfs_error(ip->i_sb, "free inode not found\n");
                return -EIO;
        }
 
@@ -1936,7 +1932,7 @@ static int diAllocExt(struct inomap * imap, int agno, struct inode *ip)
                IREAD_LOCK(imap->im_ipimap, RDWRLOCK_IMAP);
                if ((rc = diIAGRead(imap, iagno, &mp))) {
                        IREAD_UNLOCK(imap->im_ipimap);
-                       jfs_error(ip->i_sb, "diAllocExt: error reading iag");
+                       jfs_error(ip->i_sb, "error reading iag\n");
                        return rc;
                }
                iagp = (struct iag *) mp->data;
@@ -1948,8 +1944,7 @@ static int diAllocExt(struct inomap * imap, int agno, struct inode *ip)
                if (sword >= SMAPSZ) {
                        release_metapage(mp);
                        IREAD_UNLOCK(imap->im_ipimap);
-                       jfs_error(ip->i_sb,
-                                 "diAllocExt: free ext summary map not found");
+                       jfs_error(ip->i_sb, "free ext summary map not found\n");
                        return -EIO;
                }
                if (~iagp->extsmap[sword])
@@ -1962,7 +1957,7 @@ static int diAllocExt(struct inomap * imap, int agno, struct inode *ip)
        if (rem >= EXTSPERSUM) {
                release_metapage(mp);
                IREAD_UNLOCK(imap->im_ipimap);
-               jfs_error(ip->i_sb, "diAllocExt: free extent not found");
+               jfs_error(ip->i_sb, "free extent not found\n");
                return -EIO;
        }
        extno = (sword << L2EXTSPERSUM) + rem;
@@ -2081,8 +2076,7 @@ static int diAllocBit(struct inomap * imap, struct iag * iagp, int ino)
                if (bmp)
                        release_metapage(bmp);
 
-               jfs_error(imap->im_ipimap->i_sb,
-                         "diAllocBit: iag inconsistent");
+               jfs_error(imap->im_ipimap->i_sb, "iag inconsistent\n");
                return -EIO;
        }
 
@@ -2189,7 +2183,7 @@ static int diNewExt(struct inomap * imap, struct iag * iagp, int extno)
        /* better have free extents.
         */
        if (!iagp->nfreeexts) {
-               jfs_error(imap->im_ipimap->i_sb, "diNewExt: no free extents");
+               jfs_error(imap->im_ipimap->i_sb, "no free extents\n");
                return -EIO;
        }
 
@@ -2261,7 +2255,7 @@ static int diNewExt(struct inomap * imap, struct iag * iagp, int extno)
                        }
                        if (ciagp == NULL) {
                                jfs_error(imap->im_ipimap->i_sb,
-                                         "diNewExt: ciagp == NULL");
+                                         "ciagp == NULL\n");
                                rc = -EIO;
                                goto error_out;
                        }
@@ -2498,7 +2492,7 @@ diNewIAG(struct inomap * imap, int *iagnop, int agno, struct metapage ** mpp)
                        IWRITE_UNLOCK(ipimap);
                        IAGFREE_UNLOCK(imap);
                        jfs_error(imap->im_ipimap->i_sb,
-                                 "diNewIAG: ipimap->i_size is wrong");
+                                 "ipimap->i_size is wrong\n");
                        return -EIO;
                }
 
@@ -2758,8 +2752,7 @@ diUpdatePMap(struct inode *ipimap,
        iagno = INOTOIAG(inum);
        /* make sure that the iag is contained within the map */
        if (iagno >= imap->im_nextiag) {
-               jfs_error(ipimap->i_sb,
-                         "diUpdatePMap: the iag is outside the map");
+               jfs_error(ipimap->i_sb, "the iag is outside the map\n");
                return -EIO;
        }
        /* read the iag */
@@ -2788,13 +2781,13 @@ diUpdatePMap(struct inode *ipimap,
                 */
                if (!(le32_to_cpu(iagp->wmap[extno]) & mask)) {
                        jfs_error(ipimap->i_sb,
-                                 "diUpdatePMap: inode %ld not marked as "
-                                 "allocated in wmap!", inum);
+                                 "inode %ld not marked as allocated in wmap!\n",
+                                 inum);
                }
                if (!(le32_to_cpu(iagp->pmap[extno]) & mask)) {
                        jfs_error(ipimap->i_sb,
-                                 "diUpdatePMap: inode %ld not marked as "
-                                 "allocated in pmap!", inum);
+                                 "inode %ld not marked as allocated in pmap!\n",
+                                 inum);
                }
                /* update the bitmap for the extent of the freed inode */
                iagp->pmap[extno] &= cpu_to_le32(~mask);
@@ -2809,15 +2802,13 @@ diUpdatePMap(struct inode *ipimap,
                if (!(le32_to_cpu(iagp->wmap[extno]) & mask)) {
                        release_metapage(mp);
                        jfs_error(ipimap->i_sb,
-                                 "diUpdatePMap: the inode is not allocated in "
-                                 "the working map");
+                                 "the inode is not allocated in the working map\n");
                        return -EIO;
                }
                if ((le32_to_cpu(iagp->pmap[extno]) & mask) != 0) {
                        release_metapage(mp);
                        jfs_error(ipimap->i_sb,
-                                 "diUpdatePMap: the inode is not free in the "
-                                 "persistent map");
+                                 "the inode is not free in the persistent map\n");
                        return -EIO;
                }
                /* update the bitmap for the extent of the allocated inode */
@@ -2909,8 +2900,7 @@ int diExtendFS(struct inode *ipimap, struct inode *ipbmap)
                iagp = (struct iag *) bp->data;
                if (le32_to_cpu(iagp->iagnum) != i) {
                        release_metapage(bp);
-                       jfs_error(ipimap->i_sb,
-                                 "diExtendFs: unexpected value of iagnum");
+                       jfs_error(ipimap->i_sb, "unexpected value of iagnum\n");
                        return -EIO;
                }
 
@@ -2986,8 +2976,7 @@ int diExtendFS(struct inode *ipimap, struct inode *ipbmap)
 
        if (xnuminos != atomic_read(&imap->im_numinos) ||
            xnumfree != atomic_read(&imap->im_numfree)) {
-               jfs_error(ipimap->i_sb,
-                         "diExtendFs: numinos or numfree incorrect");
+               jfs_error(ipimap->i_sb, "numinos or numfree incorrect\n");
                return -EIO;
        }
 
index 9e3aaff..d165cde 100644 (file)
@@ -647,7 +647,7 @@ struct metapage *__get_metapage(struct inode *inode, unsigned long lblock,
        if (mp) {
                if (mp->logical_size != size) {
                        jfs_error(inode->i_sb,
-                                 "__get_metapage: mp->logical_size != size");
+                                 "get_mp->logical_size != size\n");
                        jfs_err("logical_size = %d, size = %d",
                                mp->logical_size, size);
                        dump_stack();
@@ -658,8 +658,7 @@ struct metapage *__get_metapage(struct inode *inode, unsigned long lblock,
                if (test_bit(META_discard, &mp->flag)) {
                        if (!new) {
                                jfs_error(inode->i_sb,
-                                         "__get_metapage: using a "
-                                         "discarded metapage");
+                                         "using a discarded metapage\n");
                                discard_metapage(mp);
                                goto unlock;
                        }
index 884fc21..04847b8 100644 (file)
@@ -108,6 +108,7 @@ struct jfs_superblock {
 
 extern int readSuper(struct super_block *, struct buffer_head **);
 extern int updateSuper(struct super_block *, uint);
+__printf(2, 3)
 extern void jfs_error(struct super_block *, const char *, ...);
 extern int jfs_mount(struct super_block *);
 extern int jfs_mount_rw(struct super_block *, int);
index 5fcc02e..564c4f2 100644 (file)
@@ -2684,7 +2684,7 @@ void txAbort(tid_t tid, int dirty)
         * mark filesystem dirty
         */
        if (dirty)
-               jfs_error(tblk->sb, "txAbort");
+               jfs_error(tblk->sb, "\n");
 
        return;
 }
index 6c50871..5ad7748 100644 (file)
 
 /* get page buffer for specified block address */
 /* ToDo: Replace this ugly macro with a function */
-#define XT_GETPAGE(IP, BN, MP, SIZE, P, RC)\
-{\
-       BT_GETPAGE(IP, BN, MP, xtpage_t, SIZE, P, RC, i_xtroot)\
-       if (!(RC))\
-       {\
-               if ((le16_to_cpu((P)->header.nextindex) < XTENTRYSTART) ||\
-                   (le16_to_cpu((P)->header.nextindex) > le16_to_cpu((P)->header.maxentry)) ||\
-                   (le16_to_cpu((P)->header.maxentry) > (((BN)==0)?XTROOTMAXSLOT:PSIZE>>L2XTSLOTSIZE)))\
-               {\
-                       jfs_error((IP)->i_sb, "XT_GETPAGE: xtree page corrupt");\
-                       BT_PUTPAGE(MP);\
-                       MP = NULL;\
-                       RC = -EIO;\
-               }\
-       }\
-}
+#define XT_GETPAGE(IP, BN, MP, SIZE, P, RC)                            \
+do {                                                                   \
+       BT_GETPAGE(IP, BN, MP, xtpage_t, SIZE, P, RC, i_xtroot);        \
+       if (!(RC)) {                                                    \
+               if ((le16_to_cpu((P)->header.nextindex) < XTENTRYSTART) || \
+                   (le16_to_cpu((P)->header.nextindex) >               \
+                    le16_to_cpu((P)->header.maxentry)) ||              \
+                   (le16_to_cpu((P)->header.maxentry) >                \
+                    (((BN) == 0) ? XTROOTMAXSLOT : PSIZE >> L2XTSLOTSIZE))) { \
+                       jfs_error((IP)->i_sb,                           \
+                                 "XT_GETPAGE: xtree page corrupt\n");  \
+                       BT_PUTPAGE(MP);                                 \
+                       MP = NULL;                                      \
+                       RC = -EIO;                                      \
+               }                                                       \
+       }                                                               \
+} while (0)
 
 /* for consistency */
 #define XT_PUTPAGE(MP) BT_PUTPAGE(MP)
@@ -499,7 +500,7 @@ static int xtSearch(struct inode *ip, s64 xoff,     s64 *nextp,
 
                /* push (bn, index) of the parent page/entry */
                if (BT_STACK_FULL(btstack)) {
-                       jfs_error(ip->i_sb, "stack overrun in xtSearch!");
+                       jfs_error(ip->i_sb, "stack overrun!\n");
                        XT_PUTPAGE(mp);
                        return -EIO;
                }
@@ -1385,7 +1386,7 @@ int xtExtend(tid_t tid,           /* transaction id */
 
        if (cmp != 0) {
                XT_PUTPAGE(mp);
-               jfs_error(ip->i_sb, "xtExtend: xtSearch did not find extent");
+               jfs_error(ip->i_sb, "xtSearch did not find extent\n");
                return -EIO;
        }
 
@@ -1393,7 +1394,7 @@ int xtExtend(tid_t tid,           /* transaction id */
        xad = &p->xad[index];
        if ((offsetXAD(xad) + lengthXAD(xad)) != xoff) {
                XT_PUTPAGE(mp);
-               jfs_error(ip->i_sb, "xtExtend: extension is not contiguous");
+               jfs_error(ip->i_sb, "extension is not contiguous\n");
                return -EIO;
        }
 
@@ -1552,7 +1553,7 @@ printf("xtTailgate: nxoff:0x%lx nxlen:0x%x nxaddr:0x%lx\n",
 
        if (cmp != 0) {
                XT_PUTPAGE(mp);
-               jfs_error(ip->i_sb, "xtTailgate: couldn't find extent");
+               jfs_error(ip->i_sb, "couldn't find extent\n");
                return -EIO;
        }
 
@@ -1560,8 +1561,7 @@ printf("xtTailgate: nxoff:0x%lx nxlen:0x%x nxaddr:0x%lx\n",
        nextindex = le16_to_cpu(p->header.nextindex);
        if (index != nextindex - 1) {
                XT_PUTPAGE(mp);
-               jfs_error(ip->i_sb,
-                         "xtTailgate: the entry found is not the last entry");
+               jfs_error(ip->i_sb, "the entry found is not the last entry\n");
                return -EIO;
        }
 
@@ -1734,7 +1734,7 @@ int xtUpdate(tid_t tid, struct inode *ip, xad_t * nxad)
 
        if (cmp != 0) {
                XT_PUTPAGE(mp);
-               jfs_error(ip->i_sb, "xtUpdate: Could not find extent");
+               jfs_error(ip->i_sb, "Could not find extent\n");
                return -EIO;
        }
 
@@ -1758,7 +1758,7 @@ int xtUpdate(tid_t tid, struct inode *ip, xad_t * nxad)
            (nxoff + nxlen > xoff + xlen)) {
                XT_PUTPAGE(mp);
                jfs_error(ip->i_sb,
-                         "xtUpdate: nXAD in not completely contained within XAD");
+                         "nXAD in not completely contained within XAD\n");
                return -EIO;
        }
 
@@ -1907,7 +1907,7 @@ int xtUpdate(tid_t tid, struct inode *ip, xad_t * nxad)
 
        if (xoff >= nxoff) {
                XT_PUTPAGE(mp);
-               jfs_error(ip->i_sb, "xtUpdate: xoff >= nxoff");
+               jfs_error(ip->i_sb, "xoff >= nxoff\n");
                return -EIO;
        }
 /* #endif _JFS_WIP_COALESCE */
@@ -2048,14 +2048,13 @@ int xtUpdate(tid_t tid, struct inode *ip, xad_t * nxad)
 
                if (cmp != 0) {
                        XT_PUTPAGE(mp);
-                       jfs_error(ip->i_sb, "xtUpdate: xtSearch failed");
+                       jfs_error(ip->i_sb, "xtSearch failed\n");
                        return -EIO;
                }
 
                if (index0 != index) {
                        XT_PUTPAGE(mp);
-                       jfs_error(ip->i_sb,
-                                 "xtUpdate: unexpected value of index");
+                       jfs_error(ip->i_sb, "unexpected value of index\n");
                        return -EIO;
                }
        }
@@ -3650,7 +3649,7 @@ s64 xtTruncate(tid_t tid, struct inode *ip, s64 newsize, int flag)
       getChild:
        /* save current parent entry for the child page */
        if (BT_STACK_FULL(&btstack)) {
-               jfs_error(ip->i_sb, "stack overrun in xtTruncate!");
+               jfs_error(ip->i_sb, "stack overrun!\n");
                XT_PUTPAGE(mp);
                return -EIO;
        }
@@ -3751,8 +3750,7 @@ s64 xtTruncate_pmap(tid_t tid, struct inode *ip, s64 committed_size)
 
                if (cmp != 0) {
                        XT_PUTPAGE(mp);
-                       jfs_error(ip->i_sb,
-                                 "xtTruncate_pmap: did not find extent");
+                       jfs_error(ip->i_sb, "did not find extent\n");
                        return -EIO;
                }
        } else {
@@ -3851,7 +3849,7 @@ s64 xtTruncate_pmap(tid_t tid, struct inode *ip, s64 committed_size)
       getChild:
        /* save current parent entry for the child page */
        if (BT_STACK_FULL(&btstack)) {
-               jfs_error(ip->i_sb, "stack overrun in xtTruncate_pmap!");
+               jfs_error(ip->i_sb, "stack overrun!\n");
                XT_PUTPAGE(mp);
                return -EIO;
        }
index 8b19027..aa8a337 100644 (file)
@@ -1176,7 +1176,7 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry,
                                if (!S_ISDIR(old_ip->i_mode) && new_ip)
                                        IWRITE_UNLOCK(new_ip);
                                jfs_error(new_ip->i_sb,
-                                         "jfs_rename: new_ip->i_nlink != 0");
+                                         "new_ip->i_nlink != 0\n");
                                return -EIO;
                        }
                        tblk = tid_to_tblock(tid);
index 8d0c1c7..90b3bc2 100644 (file)
@@ -530,7 +530,7 @@ int jfs_extendfs(struct super_block *sb, s64 newLVSize, int newLogSize)
        goto resume;
 
       error_out:
-       jfs_error(sb, "jfs_extendfs");
+       jfs_error(sb, "\n");
 
       resume:
        /*
index 788e0a9..6669aa2 100644 (file)
@@ -92,16 +92,20 @@ static void jfs_handle_error(struct super_block *sb)
        /* nothing is done for continue beyond marking the superblock dirty */
 }
 
-void jfs_error(struct super_block *sb, const char * function, ...)
+void jfs_error(struct super_block *sb, const char *fmt, ...)
 {
-       static char error_buf[256];
+       struct va_format vaf;
        va_list args;
 
-       va_start(args, function);
-       vsnprintf(error_buf, sizeof(error_buf), function, args);
-       va_end(args);
+       va_start(args, fmt);
+
+       vaf.fmt = fmt;
+       vaf.va = &args;
 
-       pr_err("ERROR: (device %s): %s\n", sb->s_id, error_buf);
+       pr_err("ERROR: (device %s): %pf: %pV\n",
+              sb->s_id, __builtin_return_address(0), &vaf);
+
+       va_end(args);
 
        jfs_handle_error(sb);
 }
@@ -617,7 +621,7 @@ static int jfs_freeze(struct super_block *sb)
                txQuiesce(sb);
                rc = lmLogShutdown(log);
                if (rc) {
-                       jfs_error(sb, "jfs_freeze: lmLogShutdown failed");
+                       jfs_error(sb, "lmLogShutdown failed\n");
 
                        /* let operations fail rather than hang */
                        txResume(sb);
@@ -646,12 +650,12 @@ static int jfs_unfreeze(struct super_block *sb)
        if (!(sb->s_flags & MS_RDONLY)) {
                rc = updateSuper(sb, FM_MOUNT);
                if (rc) {
-                       jfs_error(sb, "jfs_unfreeze: updateSuper failed");
+                       jfs_error(sb, "updateSuper failed\n");
                        goto out;
                }
                rc = lmLogInit(log);
                if (rc)
-                       jfs_error(sb, "jfs_unfreeze: lmLogInit failed");
+                       jfs_error(sb, "lmLogInit failed\n");
 out:
                txResume(sb);
        }
index 42d67f9..d3472f4 100644 (file)
@@ -382,7 +382,7 @@ static int ea_read(struct inode *ip, struct jfs_ea_list *ealist)
 
        nbytes = sizeDXD(&ji->ea);
        if (!nbytes) {
-               jfs_error(sb, "ea_read: nbytes is 0");
+               jfs_error(sb, "nbytes is 0\n");
                return -EIO;
        }
 
@@ -482,7 +482,7 @@ static int ea_get(struct inode *inode, struct ea_buffer *ea_buf, int min_size)
                current_blocks = 0;
        } else {
                if (!(ji->ea.flag & DXD_EXTENT)) {
-                       jfs_error(sb, "ea_get: invalid ea.flag)");
+                       jfs_error(sb, "invalid ea.flag\n");
                        return -EIO;
                }
                current_blocks = (ea_size + sb->s_blocksize - 1) >>
@@ -1089,8 +1089,8 @@ int jfs_removexattr(struct dentry *dentry, const char *name)
 }
 
 #ifdef CONFIG_JFS_SECURITY
-int jfs_initxattrs(struct inode *inode, const struct xattr *xattr_array,
-                  void *fs_info)
+static int jfs_initxattrs(struct inode *inode, const struct xattr *xattr_array,
+                         void *fs_info)
 {
        const struct xattr *xattr;
        tid_t *tid = fs_info;
index c3a0837..3a3a9b5 100644 (file)
@@ -61,7 +61,8 @@ struct dentry *simple_lookup(struct inode *dir, struct dentry *dentry, unsigned
 
        if (dentry->d_name.len > NAME_MAX)
                return ERR_PTR(-ENAMETOOLONG);
-       d_set_d_op(dentry, &simple_dentry_operations);
+       if (!dentry->d_sb->s_d_op)
+               d_set_d_op(dentry, &simple_dentry_operations);
        d_add(dentry, NULL);
        return NULL;
 }
index b2beee7..8b61d10 100644 (file)
@@ -2977,7 +2977,7 @@ static struct file *path_openat(int dfd, struct filename *pathname,
 
        file->f_flags = op->open_flag;
 
-       if (unlikely(file->f_flags & O_TMPFILE)) {
+       if (unlikely(file->f_flags & __O_TMPFILE)) {
                error = do_tmpfile(dfd, pathname, nd, flags, op, file, &opened);
                goto out;
        }
index 0fac2cb..e474ca2 100644 (file)
@@ -450,6 +450,7 @@ void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry)
        dentry = d_lookup(parent, &filename);
        if (dentry != NULL) {
                if (nfs_same_file(dentry, entry)) {
+                       nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
                        status = nfs_refresh_inode(dentry->d_inode, entry->fattr);
                        if (!status)
                                nfs_setsecurity(dentry->d_inode, entry->fattr, entry->label);
@@ -817,7 +818,7 @@ static int nfs_readdir(struct file *file, struct dir_context *ctx)
        nfs_readdir_descriptor_t my_desc,
                        *desc = &my_desc;
        struct nfs_open_dir_context *dir_ctx = file->private_data;
-       int res;
+       int res = 0;
 
        dfprintk(FILE, "NFS: readdir(%s/%s) starting at cookie %llu\n",
                        dentry->d_parent->d_name.name, dentry->d_name.name,
@@ -839,7 +840,8 @@ static int nfs_readdir(struct file *file, struct dir_context *ctx)
        desc->plus = nfs_use_readdirplus(inode, ctx) ? 1 : 0;
 
        nfs_block_sillyrename(dentry);
-       res = nfs_revalidate_mapping(inode, file->f_mapping);
+       if (ctx->pos == 0 || nfs_attribute_cache_expired(inode))
+               res = nfs_revalidate_mapping(inode, file->f_mapping);
        if (res < 0)
                goto out;
 
index c93639e..af6e806 100644 (file)
@@ -936,7 +936,7 @@ int nfs_attribute_timeout(struct inode *inode)
        return !time_in_range_open(jiffies, nfsi->read_cache_jiffies, nfsi->read_cache_jiffies + nfsi->attrtimeo);
 }
 
-static int nfs_attribute_cache_expired(struct inode *inode)
+int nfs_attribute_cache_expired(struct inode *inode)
 {
        if (nfs_have_delegated_attributes(inode))
                return 0;
index a2c7c28..f1bdb72 100644 (file)
@@ -888,6 +888,28 @@ out:
        return PageUptodate(page) != 0;
 }
 
+/* If we know the page is up to date, and we're not using byte range locks (or
+ * if we have the whole file locked for writing), it may be more efficient to
+ * extend the write to cover the entire page in order to avoid fragmentation
+ * inefficiencies.
+ *
+ * If the file is opened for synchronous writes or if we have a write delegation
+ * from the server then we can just skip the rest of the checks.
+ */
+static int nfs_can_extend_write(struct file *file, struct page *page, struct inode *inode)
+{
+       if (file->f_flags & O_DSYNC)
+               return 0;
+       if (NFS_PROTO(inode)->have_delegation(inode, FMODE_WRITE))
+               return 1;
+       if (nfs_write_pageuptodate(page, inode) && (inode->i_flock == NULL ||
+                       (inode->i_flock->fl_start == 0 &&
+                       inode->i_flock->fl_end == OFFSET_MAX &&
+                       inode->i_flock->fl_type != F_RDLCK)))
+               return 1;
+       return 0;
+}
+
 /*
  * Update and possibly write a cached page of an NFS file.
  *
@@ -908,14 +930,7 @@ int nfs_updatepage(struct file *file, struct page *page,
                file->f_path.dentry->d_name.name, count,
                (long long)(page_file_offset(page) + offset));
 
-       /* If we're not using byte range locks, and we know the page
-        * is up to date, it may be more efficient to extend the write
-        * to cover the entire page in order to avoid fragmentation
-        * inefficiencies.
-        */
-       if (nfs_write_pageuptodate(page, inode) &&
-                       inode->i_flock == NULL &&
-                       !(file->f_flags & O_DSYNC)) {
+       if (nfs_can_extend_write(file, page, inode)) {
                count = max(count + offset, nfs_page_length(page));
                offset = 0;
        }
index 430b687..dc8f1ef 100644 (file)
@@ -81,6 +81,22 @@ config NFSD_V4
 
          If unsure, say N.
 
+config NFSD_V4_SECURITY_LABEL
+       bool "Provide Security Label support for NFSv4 server"
+       depends on NFSD_V4 && SECURITY
+       help
+
+       Say Y here if you want enable fine-grained security label attribute
+       support for NFS version 4.  Security labels allow security modules like
+       SELinux and Smack to label files to facilitate enforcement of their policies.
+       Without this an NFSv4 mount will have the same label on each file.
+
+       If you do not wish to enable fine-grained security labels SELinux or
+       Smack policies on NFSv4 files, say N.
+
+       WARNING: there is still a chance of backwards-incompatible protocol changes.
+       For now we recommend "Y" only for developers and testers."
+
 config NFSD_FAULT_INJECTION
        bool "NFS server manual fault injection"
        depends on NFSD_V4 && DEBUG_KERNEL
index 27d74a2..a7cee86 100644 (file)
 #include "current_stateid.h"
 #include "netns.h"
 
+#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
+#include <linux/security.h>
+
+static inline void
+nfsd4_security_inode_setsecctx(struct svc_fh *resfh, struct xdr_netobj *label, u32 *bmval)
+{
+       struct inode *inode = resfh->fh_dentry->d_inode;
+       int status;
+
+       mutex_lock(&inode->i_mutex);
+       status = security_inode_setsecctx(resfh->fh_dentry,
+               label->data, label->len);
+       mutex_unlock(&inode->i_mutex);
+
+       if (status)
+               /*
+                * XXX: We should really fail the whole open, but we may
+                * already have created a new file, so it may be too
+                * late.  For now this seems the least of evils:
+                */
+               bmval[2] &= ~FATTR4_WORD2_SECURITY_LABEL;
+
+       return;
+}
+#else
+static inline void
+nfsd4_security_inode_setsecctx(struct svc_fh *resfh, struct xdr_netobj *label, u32 *bmval)
+{ }
+#endif
+
 #define NFSDDBG_FACILITY               NFSDDBG_PROC
 
 static u32 nfsd_attrmask[] = {
@@ -239,6 +269,9 @@ do_open_lookup(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, stru
                                        (u32 *)open->op_verf.data,
                                        &open->op_truncate, &open->op_created);
 
+               if (!status && open->op_label.len)
+                       nfsd4_security_inode_setsecctx(resfh, &open->op_label, open->op_bmval);
+
                /*
                 * Following rfc 3530 14.2.16, use the returned bitmask
                 * to indicate which attributes we used to store the
@@ -263,7 +296,8 @@ do_open_lookup(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, stru
 
        nfsd4_set_open_owner_reply_cache(cstate, open, resfh);
        accmode = NFSD_MAY_NOP;
-       if (open->op_created)
+       if (open->op_created ||
+                       open->op_claim_type == NFS4_OPEN_CLAIM_DELEGATE_CUR)
                accmode |= NFSD_MAY_OWNER_OVERRIDE;
        status = do_open_permission(rqstp, resfh, open, accmode);
        set_change_info(&open->op_cinfo, current_fh);
@@ -637,6 +671,9 @@ nfsd4_create(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
        if (status)
                goto out;
 
+       if (create->cr_label.len)
+               nfsd4_security_inode_setsecctx(&resfh, &create->cr_label, create->cr_bmval);
+
        if (create->cr_acl != NULL)
                do_set_nfs4_acl(rqstp, &resfh, create->cr_acl,
                                create->cr_bmval);
@@ -916,6 +953,11 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
                                            setattr->sa_acl);
        if (status)
                goto out;
+       if (setattr->sa_label.len)
+               status = nfsd4_set_nfs4_label(rqstp, &cstate->current_fh,
+                               &setattr->sa_label);
+       if (status)
+               goto out;
        status = nfsd_setattr(rqstp, &cstate->current_fh, &setattr->sa_iattr,
                                0, (time_t)0);
 out:
index f170518..280acef 100644 (file)
@@ -97,19 +97,20 @@ nfs4_lock_state(void)
 
 static void free_session(struct nfsd4_session *);
 
-void nfsd4_put_session(struct nfsd4_session *ses)
+static bool is_session_dead(struct nfsd4_session *ses)
 {
-       atomic_dec(&ses->se_ref);
+       return ses->se_flags & NFS4_SESSION_DEAD;
 }
 
-static bool is_session_dead(struct nfsd4_session *ses)
+void nfsd4_put_session(struct nfsd4_session *ses)
 {
-       return ses->se_flags & NFS4_SESSION_DEAD;
+       if (atomic_dec_and_test(&ses->se_ref) && is_session_dead(ses))
+               free_session(ses);
 }
 
-static __be32 mark_session_dead_locked(struct nfsd4_session *ses)
+static __be32 mark_session_dead_locked(struct nfsd4_session *ses, int ref_held_by_me)
 {
-       if (atomic_read(&ses->se_ref))
+       if (atomic_read(&ses->se_ref) > ref_held_by_me)
                return nfserr_jukebox;
        ses->se_flags |= NFS4_SESSION_DEAD;
        return nfs_ok;
@@ -364,19 +365,12 @@ static struct nfs4_ol_stateid * nfs4_alloc_stateid(struct nfs4_client *clp)
 }
 
 static struct nfs4_delegation *
-alloc_init_deleg(struct nfs4_client *clp, struct nfs4_ol_stateid *stp, struct svc_fh *current_fh, u32 type)
+alloc_init_deleg(struct nfs4_client *clp, struct nfs4_ol_stateid *stp, struct svc_fh *current_fh)
 {
        struct nfs4_delegation *dp;
        struct nfs4_file *fp = stp->st_file;
 
        dprintk("NFSD alloc_init_deleg\n");
-       /*
-        * Major work on the lease subsystem (for example, to support
-        * calbacks on stat) will be required before we can support
-        * write delegations properly.
-        */
-       if (type != NFS4_OPEN_DELEGATE_READ)
-               return NULL;
        if (fp->fi_had_conflict)
                return NULL;
        if (num_delegations > max_delegations)
@@ -397,7 +391,7 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_ol_stateid *stp, struct sv
        INIT_LIST_HEAD(&dp->dl_recall_lru);
        get_nfs4_file(fp);
        dp->dl_file = fp;
-       dp->dl_type = type;
+       dp->dl_type = NFS4_OPEN_DELEGATE_READ;
        fh_copy_shallow(&dp->dl_fh, &current_fh->fh_handle);
        dp->dl_time = 0;
        atomic_set(&dp->dl_count, 1);
@@ -1188,6 +1182,9 @@ static int copy_cred(struct svc_cred *target, struct svc_cred *source)
        target->cr_gid = source->cr_gid;
        target->cr_group_info = source->cr_group_info;
        get_group_info(target->cr_group_info);
+       target->cr_gss_mech = source->cr_gss_mech;
+       if (source->cr_gss_mech)
+               gss_mech_get(source->cr_gss_mech);
        return 0;
 }
 
@@ -1262,6 +1259,31 @@ same_creds(struct svc_cred *cr1, struct svc_cred *cr2)
        return 0 == strcmp(cr1->cr_principal, cr2->cr_principal);
 }
 
+static bool svc_rqst_integrity_protected(struct svc_rqst *rqstp)
+{
+       struct svc_cred *cr = &rqstp->rq_cred;
+       u32 service;
+
+       service = gss_pseudoflavor_to_service(cr->cr_gss_mech, cr->cr_flavor);
+       return service == RPC_GSS_SVC_INTEGRITY ||
+              service == RPC_GSS_SVC_PRIVACY;
+}
+
+static bool mach_creds_match(struct nfs4_client *cl, struct svc_rqst *rqstp)
+{
+       struct svc_cred *cr = &rqstp->rq_cred;
+
+       if (!cl->cl_mach_cred)
+               return true;
+       if (cl->cl_cred.cr_gss_mech != cr->cr_gss_mech)
+               return false;
+       if (!svc_rqst_integrity_protected(rqstp))
+               return false;
+       if (!cr->cr_principal)
+               return false;
+       return 0 == strcmp(cl->cl_cred.cr_principal, cr->cr_principal);
+}
+
 static void gen_clid(struct nfs4_client *clp, struct nfsd_net *nn)
 {
        static u32 current_clientid = 1;
@@ -1639,16 +1661,16 @@ nfsd4_exchange_id(struct svc_rqst *rqstp,
        if (exid->flags & ~EXCHGID4_FLAG_MASK_A)
                return nfserr_inval;
 
-       /* Currently only support SP4_NONE */
        switch (exid->spa_how) {
+       case SP4_MACH_CRED:
+               if (!svc_rqst_integrity_protected(rqstp))
+                       return nfserr_inval;
        case SP4_NONE:
                break;
        default:                                /* checked by xdr code */
                WARN_ON_ONCE(1);
        case SP4_SSV:
                return nfserr_encr_alg_unsupp;
-       case SP4_MACH_CRED:
-               return nfserr_serverfault;      /* no excuse :-/ */
        }
 
        /* Cases below refer to rfc 5661 section 18.35.4: */
@@ -1663,6 +1685,10 @@ nfsd4_exchange_id(struct svc_rqst *rqstp,
                                status = nfserr_inval;
                                goto out;
                        }
+                       if (!mach_creds_match(conf, rqstp)) {
+                               status = nfserr_wrong_cred;
+                               goto out;
+                       }
                        if (!creds_match) { /* case 9 */
                                status = nfserr_perm;
                                goto out;
@@ -1709,7 +1735,8 @@ out_new:
                status = nfserr_jukebox;
                goto out;
        }
-       new->cl_minorversion = 1;
+       new->cl_minorversion = cstate->minorversion;
+       new->cl_mach_cred = (exid->spa_how == SP4_MACH_CRED);
 
        gen_clid(new, nn);
        add_to_unconfirmed(new);
@@ -1839,6 +1866,24 @@ static __be32 check_backchannel_attrs(struct nfsd4_channel_attrs *ca)
        return nfs_ok;
 }
 
+static __be32 nfsd4_check_cb_sec(struct nfsd4_cb_sec *cbs)
+{
+       switch (cbs->flavor) {
+       case RPC_AUTH_NULL:
+       case RPC_AUTH_UNIX:
+               return nfs_ok;
+       default:
+               /*
+                * GSS case: the spec doesn't allow us to return this
+                * error.  But it also doesn't allow us not to support
+                * GSS.
+                * I'd rather this fail hard than return some error the
+                * client might think it can already handle:
+                */
+               return nfserr_encr_alg_unsupp;
+       }
+}
+
 __be32
 nfsd4_create_session(struct svc_rqst *rqstp,
                     struct nfsd4_compound_state *cstate,
@@ -1854,6 +1899,9 @@ nfsd4_create_session(struct svc_rqst *rqstp,
 
        if (cr_ses->flags & ~SESSION4_FLAG_MASK_A)
                return nfserr_inval;
+       status = nfsd4_check_cb_sec(&cr_ses->cb_sec);
+       if (status)
+               return status;
        status = check_forechannel_attrs(&cr_ses->fore_channel, nn);
        if (status)
                return status;
@@ -1874,6 +1922,9 @@ nfsd4_create_session(struct svc_rqst *rqstp,
        WARN_ON_ONCE(conf && unconf);
 
        if (conf) {
+               status = nfserr_wrong_cred;
+               if (!mach_creds_match(conf, rqstp))
+                       goto out_free_conn;
                cs_slot = &conf->cl_cs_slot;
                status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0);
                if (status == nfserr_replay_cache) {
@@ -1890,6 +1941,9 @@ nfsd4_create_session(struct svc_rqst *rqstp,
                        status = nfserr_clid_inuse;
                        goto out_free_conn;
                }
+               status = nfserr_wrong_cred;
+               if (!mach_creds_match(unconf, rqstp))
+                       goto out_free_conn;
                cs_slot = &unconf->cl_cs_slot;
                status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0);
                if (status) {
@@ -1957,7 +2011,11 @@ __be32 nfsd4_backchannel_ctl(struct svc_rqst *rqstp, struct nfsd4_compound_state
 {
        struct nfsd4_session *session = cstate->session;
        struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
+       __be32 status;
 
+       status = nfsd4_check_cb_sec(&bc->bc_cb_sec);
+       if (status)
+               return status;
        spin_lock(&nn->client_lock);
        session->se_cb_prog = bc->bc_cb_program;
        session->se_cb_sec = bc->bc_cb_sec;
@@ -1986,6 +2044,9 @@ __be32 nfsd4_bind_conn_to_session(struct svc_rqst *rqstp,
        status = nfserr_badsession;
        if (!session)
                goto out;
+       status = nfserr_wrong_cred;
+       if (!mach_creds_match(session->se_client, rqstp))
+               goto out;
        status = nfsd4_map_bcts_dir(&bcts->dir);
        if (status)
                goto out;
@@ -2014,6 +2075,7 @@ nfsd4_destroy_session(struct svc_rqst *r,
 {
        struct nfsd4_session *ses;
        __be32 status;
+       int ref_held_by_me = 0;
        struct nfsd_net *nn = net_generic(SVC_NET(r), nfsd_net_id);
 
        nfs4_lock_state();
@@ -2021,6 +2083,7 @@ nfsd4_destroy_session(struct svc_rqst *r,
        if (nfsd4_compound_in_session(cstate->session, &sessionid->sessionid)) {
                if (!nfsd4_last_compound_op(r))
                        goto out;
+               ref_held_by_me++;
        }
        dump_sessionid(__func__, &sessionid->sessionid);
        spin_lock(&nn->client_lock);
@@ -2028,17 +2091,22 @@ nfsd4_destroy_session(struct svc_rqst *r,
        status = nfserr_badsession;
        if (!ses)
                goto out_client_lock;
-       status = mark_session_dead_locked(ses);
-       if (status)
+       status = nfserr_wrong_cred;
+       if (!mach_creds_match(ses->se_client, r))
                goto out_client_lock;
+       nfsd4_get_session_locked(ses);
+       status = mark_session_dead_locked(ses, 1 + ref_held_by_me);
+       if (status)
+               goto out_put_session;
        unhash_session(ses);
        spin_unlock(&nn->client_lock);
 
        nfsd4_probe_callback_sync(ses->se_client);
 
        spin_lock(&nn->client_lock);
-       free_session(ses);
        status = nfs_ok;
+out_put_session:
+       nfsd4_put_session(ses);
 out_client_lock:
        spin_unlock(&nn->client_lock);
 out:
@@ -2058,26 +2126,31 @@ static struct nfsd4_conn *__nfsd4_find_conn(struct svc_xprt *xpt, struct nfsd4_s
        return NULL;
 }
 
-static void nfsd4_sequence_check_conn(struct nfsd4_conn *new, struct nfsd4_session *ses)
+static __be32 nfsd4_sequence_check_conn(struct nfsd4_conn *new, struct nfsd4_session *ses)
 {
        struct nfs4_client *clp = ses->se_client;
        struct nfsd4_conn *c;
+       __be32 status = nfs_ok;
        int ret;
 
        spin_lock(&clp->cl_lock);
        c = __nfsd4_find_conn(new->cn_xprt, ses);
-       if (c) {
-               spin_unlock(&clp->cl_lock);
-               free_conn(new);
-               return;
-       }
+       if (c)
+               goto out_free;
+       status = nfserr_conn_not_bound_to_session;
+       if (clp->cl_mach_cred)
+               goto out_free;
        __nfsd4_hash_conn(new, ses);
        spin_unlock(&clp->cl_lock);
        ret = nfsd4_register_conn(new);
        if (ret)
                /* oops; xprt is already down: */
                nfsd4_conn_lost(&new->cn_xpt_user);
-       return;
+       return nfs_ok;
+out_free:
+       spin_unlock(&clp->cl_lock);
+       free_conn(new);
+       return status;
 }
 
 static bool nfsd4_session_too_many_ops(struct svc_rqst *rqstp, struct nfsd4_session *session)
@@ -2169,8 +2242,10 @@ nfsd4_sequence(struct svc_rqst *rqstp,
        if (status)
                goto out_put_session;
 
-       nfsd4_sequence_check_conn(conn, session);
+       status = nfsd4_sequence_check_conn(conn, session);
        conn = NULL;
+       if (status)
+               goto out_put_session;
 
        /* Success! bump slot seqid */
        slot->sl_seqid = seq->seqid;
@@ -2232,7 +2307,10 @@ nfsd4_destroy_clientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *csta
                status = nfserr_stale_clientid;
                goto out;
        }
-
+       if (!mach_creds_match(clp, rqstp)) {
+               status = nfserr_wrong_cred;
+               goto out;
+       }
        expire_client(clp);
 out:
        nfs4_unlock_state();
@@ -2940,13 +3018,13 @@ static struct file_lock *nfs4_alloc_init_lease(struct nfs4_delegation *dp, int f
        return fl;
 }
 
-static int nfs4_setlease(struct nfs4_delegation *dp, int flag)
+static int nfs4_setlease(struct nfs4_delegation *dp)
 {
        struct nfs4_file *fp = dp->dl_file;
        struct file_lock *fl;
        int status;
 
-       fl = nfs4_alloc_init_lease(dp, flag);
+       fl = nfs4_alloc_init_lease(dp, NFS4_OPEN_DELEGATE_READ);
        if (!fl)
                return -ENOMEM;
        fl->fl_file = find_readable_file(fp);
@@ -2964,12 +3042,12 @@ static int nfs4_setlease(struct nfs4_delegation *dp, int flag)
        return 0;
 }
 
-static int nfs4_set_delegation(struct nfs4_delegation *dp, int flag)
+static int nfs4_set_delegation(struct nfs4_delegation *dp)
 {
        struct nfs4_file *fp = dp->dl_file;
 
        if (!fp->fi_lease)
-               return nfs4_setlease(dp, flag);
+               return nfs4_setlease(dp);
        spin_lock(&recall_lock);
        if (fp->fi_had_conflict) {
                spin_unlock(&recall_lock);
@@ -3005,6 +3083,9 @@ static void nfsd4_open_deleg_none_ext(struct nfsd4_open *open, int status)
 
 /*
  * Attempt to hand out a delegation.
+ *
+ * Note we don't support write delegations, and won't until the vfs has
+ * proper support for them.
  */
 static void
 nfs4_open_delegation(struct net *net, struct svc_fh *fh,
@@ -3013,39 +3094,45 @@ nfs4_open_delegation(struct net *net, struct svc_fh *fh,
        struct nfs4_delegation *dp;
        struct nfs4_openowner *oo = container_of(stp->st_stateowner, struct nfs4_openowner, oo_owner);
        int cb_up;
-       int status = 0, flag = 0;
+       int status = 0;
 
        cb_up = nfsd4_cb_channel_good(oo->oo_owner.so_client);
-       flag = NFS4_OPEN_DELEGATE_NONE;
        open->op_recall = 0;
        switch (open->op_claim_type) {
                case NFS4_OPEN_CLAIM_PREVIOUS:
                        if (!cb_up)
                                open->op_recall = 1;
-                       flag = open->op_delegate_type;
-                       if (flag == NFS4_OPEN_DELEGATE_NONE)
-                               goto out;
+                       if (open->op_delegate_type != NFS4_OPEN_DELEGATE_READ)
+                               goto out_no_deleg;
                        break;
                case NFS4_OPEN_CLAIM_NULL:
-                       /* Let's not give out any delegations till everyone's
-                        * had the chance to reclaim theirs.... */
+                       /*
+                        * Let's not give out any delegations till everyone's
+                        * had the chance to reclaim theirs....
+                        */
                        if (locks_in_grace(net))
-                               goto out;
+                               goto out_no_deleg;
                        if (!cb_up || !(oo->oo_flags & NFS4_OO_CONFIRMED))
-                               goto out;
+                               goto out_no_deleg;
+                       /*
+                        * Also, if the file was opened for write or
+                        * create, there's a good chance the client's
+                        * about to write to it, resulting in an
+                        * immediate recall (since we don't support
+                        * write delegations):
+                        */
                        if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE)
-                               flag = NFS4_OPEN_DELEGATE_WRITE;
-                       else
-                               flag = NFS4_OPEN_DELEGATE_READ;
+                               goto out_no_deleg;
+                       if (open->op_create == NFS4_OPEN_CREATE)
+                               goto out_no_deleg;
                        break;
                default:
-                       goto out;
+                       goto out_no_deleg;
        }
-
-       dp = alloc_init_deleg(oo->oo_owner.so_client, stp, fh, flag);
+       dp = alloc_init_deleg(oo->oo_owner.so_client, stp, fh);
        if (dp == NULL)
                goto out_no_deleg;
-       status = nfs4_set_delegation(dp, flag);
+       status = nfs4_set_delegation(dp);
        if (status)
                goto out_free;
 
@@ -3053,24 +3140,23 @@ nfs4_open_delegation(struct net *net, struct svc_fh *fh,
 
        dprintk("NFSD: delegation stateid=" STATEID_FMT "\n",
                STATEID_VAL(&dp->dl_stid.sc_stateid));
-out:
-       open->op_delegate_type = flag;
-       if (flag == NFS4_OPEN_DELEGATE_NONE) {
-               if (open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS &&
-                   open->op_delegate_type != NFS4_OPEN_DELEGATE_NONE)
-                       dprintk("NFSD: WARNING: refusing delegation reclaim\n");
-
-               /* 4.1 client asking for a delegation? */
-               if (open->op_deleg_want)
-                       nfsd4_open_deleg_none_ext(open, status);
-       }
+       open->op_delegate_type = NFS4_OPEN_DELEGATE_READ;
        return;
 out_free:
        unhash_stid(&dp->dl_stid);
        nfs4_put_delegation(dp);
 out_no_deleg:
-       flag = NFS4_OPEN_DELEGATE_NONE;
-       goto out;
+       open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE;
+       if (open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS &&
+           open->op_delegate_type != NFS4_OPEN_DELEGATE_NONE) {
+               dprintk("NFSD: WARNING: refusing delegation reclaim\n");
+               open->op_recall = 1;
+       }
+
+       /* 4.1 client asking for a delegation? */
+       if (open->op_deleg_want)
+               nfsd4_open_deleg_none_ext(open, status);
+       return;
 }
 
 static void nfsd4_deleg_xgrade_none_ext(struct nfsd4_open *open,
@@ -3427,7 +3513,7 @@ grace_disallows_io(struct net *net, struct inode *inode)
 /* Returns true iff a is later than b: */
 static bool stateid_generation_after(stateid_t *a, stateid_t *b)
 {
-       return (s32)a->si_generation - (s32)b->si_generation > 0;
+       return (s32)(a->si_generation - b->si_generation) > 0;
 }
 
 static __be32 check_stateid_generation(stateid_t *in, stateid_t *ref, bool has_session)
@@ -4435,7 +4521,6 @@ __be32
 nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
            struct nfsd4_locku *locku)
 {
-       struct nfs4_lockowner *lo;
        struct nfs4_ol_stateid *stp;
        struct file *filp = NULL;
        struct file_lock *file_lock = NULL;
@@ -4468,10 +4553,9 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
                status = nfserr_jukebox;
                goto out;
        }
-       lo = lockowner(stp->st_stateowner);
        locks_init_lock(file_lock);
        file_lock->fl_type = F_UNLCK;
-       file_lock->fl_owner = (fl_owner_t)lo;
+       file_lock->fl_owner = (fl_owner_t)lockowner(stp->st_stateowner);
        file_lock->fl_pid = current->tgid;
        file_lock->fl_file = filp;
        file_lock->fl_flags = FL_POSIX;
@@ -4490,11 +4574,6 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
        update_stateid(&stp->st_stid.sc_stateid);
        memcpy(&locku->lu_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t));
 
-       if (nfsd4_has_session(cstate) && !check_for_locks(stp->st_file, lo)) {
-               WARN_ON_ONCE(cstate->replay_owner);
-               release_lockowner(lo);
-       }
-
 out:
        nfsd4_bump_seqid(cstate, status);
        if (!cstate->replay_owner)
index 6cd86e0..0c0f3ea 100644 (file)
 #include "cache.h"
 #include "netns.h"
 
+#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
+#include <linux/security.h>
+#endif
+
+
 #define NFSDDBG_FACILITY               NFSDDBG_XDR
 
 /*
@@ -134,6 +139,19 @@ xdr_error:                                 \
        }                                       \
 } while (0)
 
+static void next_decode_page(struct nfsd4_compoundargs *argp)
+{
+       argp->pagelist++;
+       argp->p = page_address(argp->pagelist[0]);
+       if (argp->pagelen < PAGE_SIZE) {
+               argp->end = argp->p + (argp->pagelen>>2);
+               argp->pagelen = 0;
+       } else {
+               argp->end = argp->p + (PAGE_SIZE>>2);
+               argp->pagelen -= PAGE_SIZE;
+       }
+}
+
 static __be32 *read_buf(struct nfsd4_compoundargs *argp, u32 nbytes)
 {
        /* We want more bytes than seem to be available.
@@ -161,16 +179,7 @@ static __be32 *read_buf(struct nfsd4_compoundargs *argp, u32 nbytes)
         * guarantee p points to at least nbytes bytes.
         */
        memcpy(p, argp->p, avail);
-       /* step to next page */
-       argp->p = page_address(argp->pagelist[0]);
-       argp->pagelist++;
-       if (argp->pagelen < PAGE_SIZE) {
-               argp->end = argp->p + (argp->pagelen>>2);
-               argp->pagelen = 0;
-       } else {
-               argp->end = argp->p + (PAGE_SIZE>>2);
-               argp->pagelen -= PAGE_SIZE;
-       }
+       next_decode_page(argp);
        memcpy(((char*)p)+avail, argp->p, (nbytes - avail));
        argp->p += XDR_QUADLEN(nbytes - avail);
        return p;
@@ -242,7 +251,8 @@ nfsd4_decode_bitmap(struct nfsd4_compoundargs *argp, u32 *bmval)
 
 static __be32
 nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval,
-                  struct iattr *iattr, struct nfs4_acl **acl)
+                  struct iattr *iattr, struct nfs4_acl **acl,
+                  struct xdr_netobj *label)
 {
        int expected_len, len = 0;
        u32 dummy32;
@@ -380,6 +390,32 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval,
                        goto xdr_error;
                }
        }
+
+       label->len = 0;
+#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
+       if (bmval[2] & FATTR4_WORD2_SECURITY_LABEL) {
+               READ_BUF(4);
+               len += 4;
+               READ32(dummy32); /* lfs: we don't use it */
+               READ_BUF(4);
+               len += 4;
+               READ32(dummy32); /* pi: we don't use it either */
+               READ_BUF(4);
+               len += 4;
+               READ32(dummy32);
+               READ_BUF(dummy32);
+               if (dummy32 > NFSD4_MAX_SEC_LABEL_LEN)
+                       return nfserr_badlabel;
+               len += (XDR_QUADLEN(dummy32) << 2);
+               READMEM(buf, dummy32);
+               label->data = kzalloc(dummy32 + 1, GFP_KERNEL);
+               if (!label->data)
+                       return nfserr_jukebox;
+               defer_free(argp, kfree, label->data);
+               memcpy(label->data, buf, dummy32);
+       }
+#endif
+
        if (bmval[0] & ~NFSD_WRITEABLE_ATTRS_WORD0
            || bmval[1] & ~NFSD_WRITEABLE_ATTRS_WORD1
            || bmval[2] & ~NFSD_WRITEABLE_ATTRS_WORD2)
@@ -428,7 +464,11 @@ static __be32 nfsd4_decode_cb_sec(struct nfsd4_compoundargs *argp, struct nfsd4_
        /* callback_sec_params4 */
        READ_BUF(4);
        READ32(nr_secflavs);
-       cbs->flavor = (u32)(-1);
+       if (nr_secflavs)
+               cbs->flavor = (u32)(-1);
+       else
+               /* Is this legal? Be generous, take it to mean AUTH_NONE: */
+               cbs->flavor = 0;
        for (i = 0; i < nr_secflavs; ++i) {
                READ_BUF(4);
                READ32(dummy);
@@ -576,7 +616,7 @@ nfsd4_decode_create(struct nfsd4_compoundargs *argp, struct nfsd4_create *create
                return status;
 
        status = nfsd4_decode_fattr(argp, create->cr_bmval, &create->cr_iattr,
-                                   &create->cr_acl);
+                                   &create->cr_acl, &create->cr_label);
        if (status)
                goto out;
 
@@ -827,7 +867,7 @@ nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open)
                case NFS4_CREATE_UNCHECKED:
                case NFS4_CREATE_GUARDED:
                        status = nfsd4_decode_fattr(argp, open->op_bmval,
-                               &open->op_iattr, &open->op_acl);
+                               &open->op_iattr, &open->op_acl, &open->op_label);
                        if (status)
                                goto out;
                        break;
@@ -841,7 +881,7 @@ nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open)
                        READ_BUF(NFS4_VERIFIER_SIZE);
                        COPYMEM(open->op_verf.data, NFS4_VERIFIER_SIZE);
                        status = nfsd4_decode_fattr(argp, open->op_bmval,
-                               &open->op_iattr, &open->op_acl);
+                               &open->op_iattr, &open->op_acl, &open->op_label);
                        if (status)
                                goto out;
                        break;
@@ -1063,7 +1103,7 @@ nfsd4_decode_setattr(struct nfsd4_compoundargs *argp, struct nfsd4_setattr *seta
        if (status)
                return status;
        return nfsd4_decode_fattr(argp, setattr->sa_bmval, &setattr->sa_iattr,
-                                 &setattr->sa_acl);
+                                 &setattr->sa_acl, &setattr->sa_label);
 }
 
 static __be32
@@ -1567,6 +1607,7 @@ struct nfsd4_minorversion_ops {
 static struct nfsd4_minorversion_ops nfsd4_minorversion[] = {
        [0] = { nfsd4_dec_ops, ARRAY_SIZE(nfsd4_dec_ops) },
        [1] = { nfsd41_dec_ops, ARRAY_SIZE(nfsd41_dec_ops) },
+       [2] = { nfsd41_dec_ops, ARRAY_SIZE(nfsd41_dec_ops) },
 };
 
 static __be32
@@ -1953,6 +1994,36 @@ nfsd4_encode_aclname(struct svc_rqst *rqstp, struct nfs4_ace *ace,
                              FATTR4_WORD0_RDATTR_ERROR)
 #define WORD1_ABSENT_FS_ATTRS FATTR4_WORD1_MOUNTED_ON_FILEID
 
+#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
+static inline __be32
+nfsd4_encode_security_label(struct svc_rqst *rqstp, void *context, int len, __be32 **pp, int *buflen)
+{
+       __be32 *p = *pp;
+
+       if (*buflen < ((XDR_QUADLEN(len) << 2) + 4 + 4 + 4))
+               return nfserr_resource;
+
+       /*
+        * For now we use a 0 here to indicate the null translation; in
+        * the future we may place a call to translation code here.
+        */
+       if ((*buflen -= 8) < 0)
+               return nfserr_resource;
+
+       WRITE32(0); /* lfs */
+       WRITE32(0); /* pi */
+       p = xdr_encode_opaque(p, context, len);
+       *buflen -= (XDR_QUADLEN(len) << 2) + 4;
+
+       *pp = p;
+       return 0;
+}
+#else
+static inline __be32
+nfsd4_encode_security_label(struct svc_rqst *rqstp, void *context, int len, __be32 **pp, int *buflen)
+{ return 0; }
+#endif
+
 static __be32 fattr_handle_absent_fs(u32 *bmval0, u32 *bmval1, u32 *rdattr_err)
 {
        /* As per referral draft:  */
@@ -2012,6 +2083,9 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
        int err;
        int aclsupport = 0;
        struct nfs4_acl *acl = NULL;
+       void *context = NULL;
+       int contextlen;
+       bool contextsupport = false;
        struct nfsd4_compoundres *resp = rqstp->rq_resp;
        u32 minorversion = resp->cstate.minorversion;
        struct path path = {
@@ -2065,6 +2139,21 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
                }
        }
 
+#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
+       if ((bmval[2] & FATTR4_WORD2_SECURITY_LABEL) ||
+                       bmval[0] & FATTR4_WORD0_SUPPORTED_ATTRS) {
+               err = security_inode_getsecctx(dentry->d_inode,
+                                               &context, &contextlen);
+               contextsupport = (err == 0);
+               if (bmval2 & FATTR4_WORD2_SECURITY_LABEL) {
+                       if (err == -EOPNOTSUPP)
+                               bmval2 &= ~FATTR4_WORD2_SECURITY_LABEL;
+                       else if (err)
+                               goto out_nfserr;
+               }
+       }
+#endif /* CONFIG_NFSD_V4_SECURITY_LABEL */
+
        if (bmval2) {
                if ((buflen -= 16) < 0)
                        goto out_resource;
@@ -2093,6 +2182,8 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
 
                if (!aclsupport)
                        word0 &= ~FATTR4_WORD0_ACL;
+               if (!contextsupport)
+                       word2 &= ~FATTR4_WORD2_SECURITY_LABEL;
                if (!word2) {
                        if ((buflen -= 12) < 0)
                                goto out_resource;
@@ -2400,6 +2491,12 @@ out_acl:
                        get_parent_attributes(exp, &stat);
                WRITE64(stat.ino);
        }
+       if (bmval2 & FATTR4_WORD2_SECURITY_LABEL) {
+               status = nfsd4_encode_security_label(rqstp, context,
+                               contextlen, &p, &buflen);
+               if (status)
+                       goto out;
+       }
        if (bmval2 & FATTR4_WORD2_SUPPATTR_EXCLCREAT) {
                WRITE32(3);
                WRITE32(NFSD_SUPPATTR_EXCLCREAT_WORD0);
@@ -2412,6 +2509,10 @@ out_acl:
        status = nfs_ok;
 
 out:
+#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
+       if (context)
+               security_release_secctx(context, contextlen);
+#endif /* CONFIG_NFSD_V4_SECURITY_LABEL */
        kfree(acl);
        if (fhp == &tempfh)
                fh_put(&tempfh);
@@ -3176,16 +3277,18 @@ nfsd4_encode_setattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4
 {
        __be32 *p;
 
-       RESERVE_SPACE(12);
+       RESERVE_SPACE(16);
        if (nfserr) {
-               WRITE32(2);
+               WRITE32(3);
+               WRITE32(0);
                WRITE32(0);
                WRITE32(0);
        }
        else {
-               WRITE32(2);
+               WRITE32(3);
                WRITE32(setattr->sa_bmval[0]);
                WRITE32(setattr->sa_bmval[1]);
+               WRITE32(setattr->sa_bmval[2]);
        }
        ADJUST_ARGS();
        return nfserr;
@@ -3226,6 +3329,14 @@ nfsd4_encode_write(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_w
        return nfserr;
 }
 
+static const u32 nfs4_minimal_spo_must_enforce[2] = {
+       [1] = 1 << (OP_BIND_CONN_TO_SESSION - 32) |
+             1 << (OP_EXCHANGE_ID - 32) |
+             1 << (OP_CREATE_SESSION - 32) |
+             1 << (OP_DESTROY_SESSION - 32) |
+             1 << (OP_DESTROY_CLIENTID - 32)
+};
+
 static __be32
 nfsd4_encode_exchange_id(struct nfsd4_compoundres *resp, __be32 nfserr,
                         struct nfsd4_exchange_id *exid)
@@ -3264,6 +3375,20 @@ nfsd4_encode_exchange_id(struct nfsd4_compoundres *resp, __be32 nfserr,
        /* state_protect4_r. Currently only support SP4_NONE */
        BUG_ON(exid->spa_how != SP4_NONE);
        WRITE32(exid->spa_how);
+       switch (exid->spa_how) {
+       case SP4_NONE:
+               break;
+       case SP4_MACH_CRED:
+               /* spo_must_enforce bitmap: */
+               WRITE32(2);
+               WRITE32(nfs4_minimal_spo_must_enforce[0]);
+               WRITE32(nfs4_minimal_spo_must_enforce[1]);
+               /* empty spo_must_allow bitmap: */
+               WRITE32(0);
+               break;
+       default:
+               WARN_ON_ONCE(1);
+       }
 
        /* The server_owner struct */
        WRITE64(minor_id);      /* Minor id */
@@ -3635,13 +3760,17 @@ nfs4svc_encode_compoundres(struct svc_rqst *rqstp, __be32 *p, struct nfsd4_compo
        iov->iov_len = ((char*)resp->p) - (char*)iov->iov_base;
        BUG_ON(iov->iov_len > PAGE_SIZE);
        if (nfsd4_has_session(cs)) {
+               struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
+               struct nfs4_client *clp = cs->session->se_client;
                if (cs->status != nfserr_replay_cache) {
                        nfsd4_store_cache_entry(resp);
                        cs->slot->sl_flags &= ~NFSD4_SLOT_INUSE;
                }
                /* Renew the clientid on success and on replay */
-               put_client_renew(cs->session->se_client);
+               spin_lock(&nn->client_lock);
                nfsd4_put_session(cs->session);
+               spin_unlock(&nn->client_lock);
+               put_client_renew(clp);
        }
        return 1;
 }
index c0d9317..2bbd94e 100644 (file)
@@ -24,7 +24,7 @@
 /*
  * nfsd version
  */
-#define NFSD_SUPPORTED_MINOR_VERSION   1
+#define NFSD_SUPPORTED_MINOR_VERSION   2
 /*
  * Maximum blocksizes supported by daemon under various circumstances.
  */
@@ -328,6 +328,13 @@ void               nfsd_lockd_shutdown(void);
 #define NFSD4_1_SUPPORTED_ATTRS_WORD2 \
        (NFSD4_SUPPORTED_ATTRS_WORD2 | FATTR4_WORD2_SUPPATTR_EXCLCREAT)
 
+#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
+#define NFSD4_2_SUPPORTED_ATTRS_WORD2 \
+       (NFSD4_1_SUPPORTED_ATTRS_WORD2 | FATTR4_WORD2_SECURITY_LABEL)
+#else
+#define NFSD4_2_SUPPORTED_ATTRS_WORD2 0
+#endif
+
 static inline u32 nfsd_suppattrs0(u32 minorversion)
 {
        return minorversion ? NFSD4_1_SUPPORTED_ATTRS_WORD0
@@ -342,8 +349,11 @@ static inline u32 nfsd_suppattrs1(u32 minorversion)
 
 static inline u32 nfsd_suppattrs2(u32 minorversion)
 {
-       return minorversion ? NFSD4_1_SUPPORTED_ATTRS_WORD2
-                           : NFSD4_SUPPORTED_ATTRS_WORD2;
+       switch (minorversion) {
+       default: return NFSD4_2_SUPPORTED_ATTRS_WORD2;
+       case 1:  return NFSD4_1_SUPPORTED_ATTRS_WORD2;
+       case 0:  return NFSD4_SUPPORTED_ATTRS_WORD2;
+       }
 }
 
 /* These will return ERR_INVAL if specified in GETATTR or READDIR. */
@@ -356,7 +366,11 @@ static inline u32 nfsd_suppattrs2(u32 minorversion)
 #define NFSD_WRITEABLE_ATTRS_WORD1 \
        (FATTR4_WORD1_MODE | FATTR4_WORD1_OWNER | FATTR4_WORD1_OWNER_GROUP \
        | FATTR4_WORD1_TIME_ACCESS_SET | FATTR4_WORD1_TIME_MODIFY_SET)
+#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
+#define NFSD_WRITEABLE_ATTRS_WORD2 FATTR4_WORD2_SECURITY_LABEL
+#else
 #define NFSD_WRITEABLE_ATTRS_WORD2 0
+#endif
 
 #define NFSD_SUPPATTR_EXCLCREAT_WORD0 \
        NFSD_WRITEABLE_ATTRS_WORD0
index 262df5c..6b9f48c 100644 (file)
@@ -116,7 +116,7 @@ struct svc_program          nfsd_program = {
 
 };
 
-u32 nfsd_supported_minorversion;
+u32 nfsd_supported_minorversion = 1;
 
 int nfsd_vers(int vers, enum vers_op change)
 {
index 274e2a1..424d8f5 100644 (file)
@@ -246,6 +246,7 @@ struct nfs4_client {
        nfs4_verifier           cl_verifier;    /* generated by client */
        time_t                  cl_time;        /* time of last lease renewal */
        struct sockaddr_storage cl_addr;        /* client ipaddress */
+       bool                    cl_mach_cred;   /* SP4_MACH_CRED in force */
        struct svc_cred         cl_cred;        /* setclientid principal */
        clientid_t              cl_clientid;    /* generated by server */
        nfs4_verifier           cl_confirm;     /* generated by server */
index a6bc8a7..8ff6a00 100644 (file)
@@ -28,6 +28,7 @@
 #include <asm/uaccess.h>
 #include <linux/exportfs.h>
 #include <linux/writeback.h>
+#include <linux/security.h>
 
 #ifdef CONFIG_NFSD_V3
 #include "xdr3.h"
@@ -621,6 +622,33 @@ int nfsd4_is_junction(struct dentry *dentry)
                return 0;
        return 1;
 }
+#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
+__be32 nfsd4_set_nfs4_label(struct svc_rqst *rqstp, struct svc_fh *fhp,
+               struct xdr_netobj *label)
+{
+       __be32 error;
+       int host_error;
+       struct dentry *dentry;
+
+       error = fh_verify(rqstp, fhp, 0 /* S_IFREG */, NFSD_MAY_SATTR);
+       if (error)
+               return error;
+
+       dentry = fhp->fh_dentry;
+
+       mutex_lock(&dentry->d_inode->i_mutex);
+       host_error = security_inode_setsecctx(dentry, label->data, label->len);
+       mutex_unlock(&dentry->d_inode->i_mutex);
+       return nfserrno(host_error);
+}
+#else
+__be32 nfsd4_set_nfs4_label(struct svc_rqst *rqstp, struct svc_fh *fhp,
+               struct xdr_netobj *label)
+{
+       return nfserr_notsupp;
+}
+#endif
+
 #endif /* defined(CONFIG_NFSD_V4) */
 
 #ifdef CONFIG_NFSD_V3
index 5b58941..a4be2e3 100644 (file)
@@ -39,7 +39,6 @@
 typedef int (*nfsd_dirop_t)(struct inode *, struct dentry *, int, int);
 
 /* nfsd/vfs.c */
-int            fh_lock_parent(struct svc_fh *, struct dentry *);
 int            nfsd_racache_init(int);
 void           nfsd_racache_shutdown(void);
 int            nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp,
@@ -56,6 +55,8 @@ int nfsd_mountpoint(struct dentry *, struct svc_export *);
 __be32          nfsd4_set_nfs4_acl(struct svc_rqst *, struct svc_fh *,
                     struct nfs4_acl *);
 int             nfsd4_get_nfs4_acl(struct svc_rqst *, struct dentry *, struct nfs4_acl **);
+__be32          nfsd4_set_nfs4_label(struct svc_rqst *, struct svc_fh *,
+                   struct xdr_netobj *);
 #endif /* CONFIG_NFSD_V4 */
 __be32         nfsd_create(struct svc_rqst *, struct svc_fh *,
                                char *name, int len, struct iattr *attrs,
@@ -92,17 +93,13 @@ __be32              nfsd_remove(struct svc_rqst *,
                                struct svc_fh *, char *, int);
 __be32         nfsd_unlink(struct svc_rqst *, struct svc_fh *, int type,
                                char *name, int len);
-int            nfsd_truncate(struct svc_rqst *, struct svc_fh *,
-                               unsigned long size);
 __be32         nfsd_readdir(struct svc_rqst *, struct svc_fh *,
                             loff_t *, struct readdir_cd *, filldir_t);
 __be32         nfsd_statfs(struct svc_rqst *, struct svc_fh *,
                                struct kstatfs *, int access);
 
-int            nfsd_notify_change(struct inode *, struct iattr *);
 __be32         nfsd_permission(struct svc_rqst *, struct svc_export *,
                                struct dentry *, int);
-int            nfsd_sync_dir(struct dentry *dp);
 
 #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
 struct posix_acl *nfsd_get_posix_acl(struct svc_fh *, int);
index 3b271d2..b3ed644 100644 (file)
@@ -40,6 +40,7 @@
 #include "state.h"
 #include "nfsd.h"
 
+#define NFSD4_MAX_SEC_LABEL_LEN        2048
 #define NFSD4_MAX_TAGLEN       128
 #define XDR_LEN(n)                     (((n) + 3) & ~3)
 
@@ -118,6 +119,7 @@ struct nfsd4_create {
        struct iattr    cr_iattr;           /* request */
        struct nfsd4_change_info  cr_cinfo; /* response */
        struct nfs4_acl *cr_acl;
+       struct xdr_netobj cr_label;
 };
 #define cr_linklen     u.link.namelen
 #define cr_linkname    u.link.name
@@ -246,6 +248,7 @@ struct nfsd4_open {
        struct nfs4_file *op_file;          /* used during processing */
        struct nfs4_ol_stateid *op_stp;     /* used during processing */
        struct nfs4_acl *op_acl;
+       struct xdr_netobj op_label;
 };
 #define op_iattr       iattr
 
@@ -330,6 +333,7 @@ struct nfsd4_setattr {
        u32             sa_bmval[3];        /* request */
        struct iattr    sa_iattr;           /* request */
        struct nfs4_acl *sa_acl;
+       struct xdr_netobj sa_label;
 };
 
 struct nfsd4_setclientid {
index fca72c4..9156cb0 100644 (file)
--- a/fs/open.c
+++ b/fs/open.c
@@ -840,8 +840,8 @@ static inline int build_open_flags(int flags, umode_t mode, struct open_flags *o
        if (flags & __O_SYNC)
                flags |= O_DSYNC;
 
-       if (flags & O_TMPFILE) {
-               if (!(flags & O_CREAT))
+       if (flags & __O_TMPFILE) {
+               if ((flags & O_TMPFILE_MASK) != O_TMPFILE)
                        return -EINVAL;
                acc_mode = MAY_OPEN | ACC_MODE(flags);
        } else if (flags & O_PATH) {
index f9f49c4..35d4adc 100644 (file)
@@ -28,7 +28,7 @@
 #include <linux/hrtimer.h>
 #include <linux/sched/rt.h>
 #include <linux/freezer.h>
-#include <net/ll_poll.h>
+#include <net/busy_poll.h>
 
 #include <asm/uaccess.h>
 
index 31d3cd1..b800fbc 100644 (file)
@@ -690,6 +690,8 @@ xfs_attr_shortform_to_leaf(xfs_da_args_t *args)
        sf = (xfs_attr_shortform_t *)tmpbuffer;
 
        xfs_idata_realloc(dp, -size, XFS_ATTR_FORK);
+       xfs_bmap_local_to_extents_empty(dp, XFS_ATTR_FORK);
+
        bp = NULL;
        error = xfs_da_grow_inode(args, &blkno);
        if (error) {
index 8904284..05c698c 100644 (file)
@@ -1161,6 +1161,24 @@ xfs_bmap_extents_to_btree(
  * since the file data needs to get logged so things will stay consistent.
  * (The bmap-level manipulations are ok, though).
  */
+void
+xfs_bmap_local_to_extents_empty(
+       struct xfs_inode        *ip,
+       int                     whichfork)
+{
+       struct xfs_ifork        *ifp = XFS_IFORK_PTR(ip, whichfork);
+
+       ASSERT(XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL);
+       ASSERT(ifp->if_bytes == 0);
+       ASSERT(XFS_IFORK_NEXTENTS(ip, whichfork) == 0);
+
+       xfs_bmap_forkoff_reset(ip->i_mount, ip, whichfork);
+       ifp->if_flags &= ~XFS_IFINLINE;
+       ifp->if_flags |= XFS_IFEXTENTS;
+       XFS_IFORK_FMT_SET(ip, whichfork, XFS_DINODE_FMT_EXTENTS);
+}
+
+
 STATIC int                             /* error */
 xfs_bmap_local_to_extents(
        xfs_trans_t     *tp,            /* transaction pointer */
@@ -1174,9 +1192,12 @@ xfs_bmap_local_to_extents(
                                   struct xfs_inode *ip,
                                   struct xfs_ifork *ifp))
 {
-       int             error;          /* error return value */
+       int             error = 0;
        int             flags;          /* logging flags returned */
        xfs_ifork_t     *ifp;           /* inode fork pointer */
+       xfs_alloc_arg_t args;           /* allocation arguments */
+       xfs_buf_t       *bp;            /* buffer for extent block */
+       xfs_bmbt_rec_host_t *ep;        /* extent record pointer */
 
        /*
         * We don't want to deal with the case of keeping inode data inline yet.
@@ -1185,68 +1206,65 @@ xfs_bmap_local_to_extents(
        ASSERT(!(S_ISREG(ip->i_d.di_mode) && whichfork == XFS_DATA_FORK));
        ifp = XFS_IFORK_PTR(ip, whichfork);
        ASSERT(XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL);
+
+       if (!ifp->if_bytes) {
+               xfs_bmap_local_to_extents_empty(ip, whichfork);
+               flags = XFS_ILOG_CORE;
+               goto done;
+       }
+
        flags = 0;
        error = 0;
-       if (ifp->if_bytes) {
-               xfs_alloc_arg_t args;   /* allocation arguments */
-               xfs_buf_t       *bp;    /* buffer for extent block */
-               xfs_bmbt_rec_host_t *ep;/* extent record pointer */
-
-               ASSERT((ifp->if_flags &
-                       (XFS_IFINLINE|XFS_IFEXTENTS|XFS_IFEXTIREC)) == XFS_IFINLINE);
-               memset(&args, 0, sizeof(args));
-               args.tp = tp;
-               args.mp = ip->i_mount;
-               args.firstblock = *firstblock;
-               /*
-                * Allocate a block.  We know we need only one, since the
-                * file currently fits in an inode.
-                */
-               if (*firstblock == NULLFSBLOCK) {
-                       args.fsbno = XFS_INO_TO_FSB(args.mp, ip->i_ino);
-                       args.type = XFS_ALLOCTYPE_START_BNO;
-               } else {
-                       args.fsbno = *firstblock;
-                       args.type = XFS_ALLOCTYPE_NEAR_BNO;
-               }
-               args.total = total;
-               args.minlen = args.maxlen = args.prod = 1;
-               error = xfs_alloc_vextent(&args);
-               if (error)
-                       goto done;
-
-               /* Can't fail, the space was reserved. */
-               ASSERT(args.fsbno != NULLFSBLOCK);
-               ASSERT(args.len == 1);
-               *firstblock = args.fsbno;
-               bp = xfs_btree_get_bufl(args.mp, tp, args.fsbno, 0);
-
-               /* initialise the block and copy the data */
-               init_fn(tp, bp, ip, ifp);
-
-               /* account for the change in fork size and log everything */
-               xfs_trans_log_buf(tp, bp, 0, ifp->if_bytes - 1);
-               xfs_bmap_forkoff_reset(args.mp, ip, whichfork);
-               xfs_idata_realloc(ip, -ifp->if_bytes, whichfork);
-               xfs_iext_add(ifp, 0, 1);
-               ep = xfs_iext_get_ext(ifp, 0);
-               xfs_bmbt_set_allf(ep, 0, args.fsbno, 1, XFS_EXT_NORM);
-               trace_xfs_bmap_post_update(ip, 0,
-                               whichfork == XFS_ATTR_FORK ? BMAP_ATTRFORK : 0,
-                               _THIS_IP_);
-               XFS_IFORK_NEXT_SET(ip, whichfork, 1);
-               ip->i_d.di_nblocks = 1;
-               xfs_trans_mod_dquot_byino(tp, ip,
-                       XFS_TRANS_DQ_BCOUNT, 1L);
-               flags |= xfs_ilog_fext(whichfork);
+       ASSERT((ifp->if_flags & (XFS_IFINLINE|XFS_IFEXTENTS|XFS_IFEXTIREC)) ==
+                                                               XFS_IFINLINE);
+       memset(&args, 0, sizeof(args));
+       args.tp = tp;
+       args.mp = ip->i_mount;
+       args.firstblock = *firstblock;
+       /*
+        * Allocate a block.  We know we need only one, since the
+        * file currently fits in an inode.
+        */
+       if (*firstblock == NULLFSBLOCK) {
+               args.fsbno = XFS_INO_TO_FSB(args.mp, ip->i_ino);
+               args.type = XFS_ALLOCTYPE_START_BNO;
        } else {
-               ASSERT(XFS_IFORK_NEXTENTS(ip, whichfork) == 0);
-               xfs_bmap_forkoff_reset(ip->i_mount, ip, whichfork);
+               args.fsbno = *firstblock;
+               args.type = XFS_ALLOCTYPE_NEAR_BNO;
        }
-       ifp->if_flags &= ~XFS_IFINLINE;
-       ifp->if_flags |= XFS_IFEXTENTS;
-       XFS_IFORK_FMT_SET(ip, whichfork, XFS_DINODE_FMT_EXTENTS);
+       args.total = total;
+       args.minlen = args.maxlen = args.prod = 1;
+       error = xfs_alloc_vextent(&args);
+       if (error)
+               goto done;
+
+       /* Can't fail, the space was reserved. */
+       ASSERT(args.fsbno != NULLFSBLOCK);
+       ASSERT(args.len == 1);
+       *firstblock = args.fsbno;
+       bp = xfs_btree_get_bufl(args.mp, tp, args.fsbno, 0);
+
+       /* initialise the block and copy the data */
+       init_fn(tp, bp, ip, ifp);
+
+       /* account for the change in fork size and log everything */
+       xfs_trans_log_buf(tp, bp, 0, ifp->if_bytes - 1);
+       xfs_idata_realloc(ip, -ifp->if_bytes, whichfork);
+       xfs_bmap_local_to_extents_empty(ip, whichfork);
        flags |= XFS_ILOG_CORE;
+
+       xfs_iext_add(ifp, 0, 1);
+       ep = xfs_iext_get_ext(ifp, 0);
+       xfs_bmbt_set_allf(ep, 0, args.fsbno, 1, XFS_EXT_NORM);
+       trace_xfs_bmap_post_update(ip, 0,
+                       whichfork == XFS_ATTR_FORK ? BMAP_ATTRFORK : 0,
+                       _THIS_IP_);
+       XFS_IFORK_NEXT_SET(ip, whichfork, 1);
+       ip->i_d.di_nblocks = 1;
+       xfs_trans_mod_dquot_byino(tp, ip,
+               XFS_TRANS_DQ_BCOUNT, 1L);
+       flags |= xfs_ilog_fext(whichfork);
+
 done:
        *logflagsp = flags;
        return error;
@@ -1323,25 +1341,6 @@ xfs_bmap_add_attrfork_extents(
 }
 
 /*
- * Block initialisation function for local to extent format conversion.
- *
- * This shouldn't actually be called by anyone, so make sure debug kernels cause
- * a noticable failure.
- */
-STATIC void
-xfs_bmap_local_to_extents_init_fn(
-       struct xfs_trans        *tp,
-       struct xfs_buf          *bp,
-       struct xfs_inode        *ip,
-       struct xfs_ifork        *ifp)
-{
-       ASSERT(0);
-       bp->b_ops = &xfs_bmbt_buf_ops;
-       memcpy(bp->b_addr, ifp->if_u1.if_data, ifp->if_bytes);
-       xfs_trans_buf_set_type(tp, bp, XFS_BLFT_BTREE_BUF);
-}
-
-/*
  * Called from xfs_bmap_add_attrfork to handle local format files. Each
  * different data fork content type needs a different callout to do the
  * conversion. Some are basic and only require special block initialisation
@@ -1381,9 +1380,9 @@ xfs_bmap_add_attrfork_local(
                                                 flags, XFS_DATA_FORK,
                                                 xfs_symlink_local_to_remote);
 
-       return xfs_bmap_local_to_extents(tp, ip, firstblock, 1, flags,
-                                        XFS_DATA_FORK,
-                                        xfs_bmap_local_to_extents_init_fn);
+       /* should only be called for types that support local format data */
+       ASSERT(0);
+       return EFSCORRUPTED;
 }
 
 /*
@@ -4907,20 +4906,19 @@ xfs_bmapi_write(
        orig_mval = mval;
        orig_nmap = *nmap;
 #endif
+       whichfork = (flags & XFS_BMAPI_ATTRFORK) ?
+               XFS_ATTR_FORK : XFS_DATA_FORK;
 
        ASSERT(*nmap >= 1);
        ASSERT(*nmap <= XFS_BMAP_MAX_NMAP);
        ASSERT(!(flags & XFS_BMAPI_IGSTATE));
        ASSERT(tp != NULL);
        ASSERT(len > 0);
-
-       whichfork = (flags & XFS_BMAPI_ATTRFORK) ?
-               XFS_ATTR_FORK : XFS_DATA_FORK;
+       ASSERT(XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_LOCAL);
 
        if (unlikely(XFS_TEST_ERROR(
            (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS &&
-            XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE &&
-            XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_LOCAL),
+            XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE),
             mp, XFS_ERRTAG_BMAPIFORMAT, XFS_RANDOM_BMAPIFORMAT))) {
                XFS_ERROR_REPORT("xfs_bmapi_write", XFS_ERRLEVEL_LOW, mp);
                return XFS_ERROR(EFSCORRUPTED);
@@ -4933,37 +4931,6 @@ xfs_bmapi_write(
 
        XFS_STATS_INC(xs_blk_mapw);
 
-       if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL) {
-               /*
-                * XXX (dgc): This assumes we are only called for inodes that
-                * contain content neutral data in local format. Anything that
-                * contains caller-specific data in local format that needs
-                * transformation to move to a block format needs to do the
-                * conversion to extent format itself.
-                *
-                * Directory data forks and attribute forks handle this
-                * themselves, but with the addition of metadata verifiers every
-                * data fork in local format now contains caller specific data
-                * and as such conversion through this function is likely to be
-                * broken.
-                *
-                * The only likely user of this branch is for remote symlinks,
-                * but we cannot overwrite the data fork contents of the symlink
-                * (EEXIST occurs higher up the stack) and so it will never go
-                * from local format to extent format here. Hence I don't think
-                * this branch is ever executed intentionally and we should
-                * consider removing it and asserting that xfs_bmapi_write()
-                * cannot be called directly on local format forks. i.e. callers
-                * are completely responsible for local to extent format
-                * conversion, not xfs_bmapi_write().
-                */
-               error = xfs_bmap_local_to_extents(tp, ip, firstblock, total,
-                                       &bma.logflags, whichfork,
-                                       xfs_bmap_local_to_extents_init_fn);
-               if (error)
-                       goto error0;
-       }
-
        if (*firstblock == NULLFSBLOCK) {
                if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_BTREE)
                        bma.minleft = be16_to_cpu(ifp->if_broot->bb_level) + 1;
index 5f469c3..1cf1292 100644 (file)
@@ -172,6 +172,7 @@ void        xfs_bmap_trace_exlist(struct xfs_inode *ip, xfs_extnum_t cnt,
 #endif
 
 int    xfs_bmap_add_attrfork(struct xfs_inode *ip, int size, int rsvd);
+void   xfs_bmap_local_to_extents_empty(struct xfs_inode *ip, int whichfork);
 void   xfs_bmap_add_free(xfs_fsblock_t bno, xfs_filblks_t len,
                struct xfs_bmap_free *flist, struct xfs_mount *mp);
 void   xfs_bmap_cancel(struct xfs_bmap_free *flist);
index f7a0e95..07d735a 100644 (file)
@@ -132,9 +132,6 @@ typedef enum xfs_dinode_fmt {
 #define XFS_LITINO(mp, version) \
        ((int)(((mp)->m_sb.sb_inodesize) - xfs_dinode_size(version)))
 
-#define XFS_BROOT_SIZE_ADJ(ip) \
-       (XFS_BMBT_BLOCK_LEN((ip)->i_mount) - sizeof(xfs_bmdr_block_t))
-
 /*
  * Inode data & attribute fork sizes, per inode.
  */
index 09aea02..5e7fbd7 100644 (file)
@@ -29,6 +29,7 @@
 #include "xfs_dinode.h"
 #include "xfs_inode.h"
 #include "xfs_inode_item.h"
+#include "xfs_bmap.h"
 #include "xfs_buf_item.h"
 #include "xfs_dir2.h"
 #include "xfs_dir2_format.h"
@@ -1164,13 +1165,15 @@ xfs_dir2_sf_to_block(
        __be16                  *tagp;          /* end of data entry */
        xfs_trans_t             *tp;            /* transaction pointer */
        struct xfs_name         name;
+       struct xfs_ifork        *ifp;
 
        trace_xfs_dir2_sf_to_block(args);
 
        dp = args->dp;
        tp = args->trans;
        mp = dp->i_mount;
-       ASSERT(dp->i_df.if_flags & XFS_IFINLINE);
+       ifp = XFS_IFORK_PTR(dp, XFS_DATA_FORK);
+       ASSERT(ifp->if_flags & XFS_IFINLINE);
        /*
         * Bomb out if the shortform directory is way too short.
         */
@@ -1179,22 +1182,23 @@ xfs_dir2_sf_to_block(
                return XFS_ERROR(EIO);
        }
 
-       oldsfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
+       oldsfp = (xfs_dir2_sf_hdr_t *)ifp->if_u1.if_data;
 
-       ASSERT(dp->i_df.if_bytes == dp->i_d.di_size);
-       ASSERT(dp->i_df.if_u1.if_data != NULL);
+       ASSERT(ifp->if_bytes == dp->i_d.di_size);
+       ASSERT(ifp->if_u1.if_data != NULL);
        ASSERT(dp->i_d.di_size >= xfs_dir2_sf_hdr_size(oldsfp->i8count));
+       ASSERT(dp->i_d.di_nextents == 0);
 
        /*
         * Copy the directory into a temporary buffer.
         * Then pitch the incore inode data so we can make extents.
         */
-       sfp = kmem_alloc(dp->i_df.if_bytes, KM_SLEEP);
-       memcpy(sfp, oldsfp, dp->i_df.if_bytes);
+       sfp = kmem_alloc(ifp->if_bytes, KM_SLEEP);
+       memcpy(sfp, oldsfp, ifp->if_bytes);
 
-       xfs_idata_realloc(dp, -dp->i_df.if_bytes, XFS_DATA_FORK);
+       xfs_idata_realloc(dp, -ifp->if_bytes, XFS_DATA_FORK);
+       xfs_bmap_local_to_extents_empty(dp, XFS_DATA_FORK);
        dp->i_d.di_size = 0;
-       xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE);
 
        /*
         * Add block 0 to the inode.
index f01012d..0adf27e 100644 (file)
@@ -936,6 +936,7 @@ xfs_qm_dqput_final(
 {
        struct xfs_quotainfo    *qi = dqp->q_mount->m_quotainfo;
        struct xfs_dquot        *gdqp;
+       struct xfs_dquot        *pdqp;
 
        trace_xfs_dqput_free(dqp);
 
@@ -949,21 +950,29 @@ xfs_qm_dqput_final(
 
        /*
         * If we just added a udquot to the freelist, then we want to release
-        * the gdquot reference that it (probably) has. Otherwise it'll keep
-        * the gdquot from getting reclaimed.
+        * the gdquot/pdquot reference that it (probably) has. Otherwise it'll
+        * keep the gdquot/pdquot from getting reclaimed.
         */
        gdqp = dqp->q_gdquot;
        if (gdqp) {
                xfs_dqlock(gdqp);
                dqp->q_gdquot = NULL;
        }
+
+       pdqp = dqp->q_pdquot;
+       if (pdqp) {
+               xfs_dqlock(pdqp);
+               dqp->q_pdquot = NULL;
+       }
        xfs_dqunlock(dqp);
 
        /*
-        * If we had a group quota hint, release it now.
+        * If we had a group/project quota hint, release it now.
         */
        if (gdqp)
                xfs_qm_dqput(gdqp);
+       if (pdqp)
+               xfs_qm_dqput(pdqp);
 }
 
 /*
index b596626..55abbca 100644 (file)
@@ -53,6 +53,7 @@ typedef struct xfs_dquot {
        xfs_fileoff_t    q_fileoffset;  /* offset in quotas file */
 
        struct xfs_dquot*q_gdquot;      /* group dquot, hint only */
+       struct xfs_dquot*q_pdquot;      /* project dquot, hint only */
        xfs_disk_dquot_t q_core;        /* actual usage & quotas */
        xfs_dq_logitem_t q_logitem;     /* dquot log item */
        xfs_qcnt_t       q_res_bcount;  /* total regular nblks used+reserved */
@@ -118,8 +119,9 @@ static inline int xfs_this_quota_on(struct xfs_mount *mp, int type)
        case XFS_DQ_USER:
                return XFS_IS_UQUOTA_ON(mp);
        case XFS_DQ_GROUP:
+               return XFS_IS_GQUOTA_ON(mp);
        case XFS_DQ_PROJ:
-               return XFS_IS_OQUOTA_ON(mp);
+               return XFS_IS_PQUOTA_ON(mp);
        default:
                return 0;
        }
@@ -131,8 +133,9 @@ static inline xfs_dquot_t *xfs_inode_dquot(struct xfs_inode *ip, int type)
        case XFS_DQ_USER:
                return ip->i_udquot;
        case XFS_DQ_GROUP:
-       case XFS_DQ_PROJ:
                return ip->i_gdquot;
+       case XFS_DQ_PROJ:
+               return ip->i_pdquot;
        default:
                return NULL;
        }
index 9560dc1..3f90e1c 100644 (file)
@@ -337,6 +337,7 @@ xfs_iget_cache_miss(
                iflags |= XFS_IDONTCACHE;
        ip->i_udquot = NULL;
        ip->i_gdquot = NULL;
+       ip->i_pdquot = NULL;
        xfs_iflags_set(ip, iflags);
 
        /* insert the new inode */
index 9ecfe1e..b78481f 100644 (file)
@@ -2156,8 +2156,8 @@ xfs_iroot_realloc(
                np = (char *)XFS_BMAP_BROOT_PTR_ADDR(mp, ifp->if_broot, 1,
                                                     (int)new_size);
                ifp->if_broot_bytes = (int)new_size;
-               ASSERT(ifp->if_broot_bytes <=
-                       XFS_IFORK_SIZE(ip, whichfork) + XFS_BROOT_SIZE_ADJ(ip));
+               ASSERT(XFS_BMAP_BMDR_SPACE(ifp->if_broot) <=
+                       XFS_IFORK_SIZE(ip, whichfork));
                memmove(np, op, cur_max * (uint)sizeof(xfs_dfsbno_t));
                return;
        }
@@ -2210,8 +2210,9 @@ xfs_iroot_realloc(
        kmem_free(ifp->if_broot);
        ifp->if_broot = new_broot;
        ifp->if_broot_bytes = (int)new_size;
-       ASSERT(ifp->if_broot_bytes <=
-               XFS_IFORK_SIZE(ip, whichfork) + XFS_BROOT_SIZE_ADJ(ip));
+       if (ifp->if_broot)
+               ASSERT(XFS_BMAP_BMDR_SPACE(ifp->if_broot) <=
+                       XFS_IFORK_SIZE(ip, whichfork));
        return;
 }
 
@@ -2522,9 +2523,8 @@ xfs_iflush_fork(
                if ((iip->ili_fields & brootflag[whichfork]) &&
                    (ifp->if_broot_bytes > 0)) {
                        ASSERT(ifp->if_broot != NULL);
-                       ASSERT(ifp->if_broot_bytes <=
-                              (XFS_IFORK_SIZE(ip, whichfork) +
-                               XFS_BROOT_SIZE_ADJ(ip)));
+                       ASSERT(XFS_BMAP_BMDR_SPACE(ifp->if_broot) <=
+                               XFS_IFORK_SIZE(ip, whichfork));
                        xfs_bmbt_to_bmdr(mp, ifp->if_broot, ifp->if_broot_bytes,
                                (xfs_bmdr_block_t *)cp,
                                XFS_DFORK_SIZE(dip, mp, whichfork));
index 9112979..b55fd34 100644 (file)
@@ -250,6 +250,7 @@ typedef struct xfs_inode {
        struct xfs_mount        *i_mount;       /* fs mount struct ptr */
        struct xfs_dquot        *i_udquot;      /* user dquot */
        struct xfs_dquot        *i_gdquot;      /* group dquot */
+       struct xfs_dquot        *i_pdquot;      /* project dquot */
 
        /* Inode location stuff */
        xfs_ino_t               i_ino;          /* inode number (agno/agino)*/
index 5e99968..6e2bca5 100644 (file)
@@ -248,7 +248,7 @@ xfs_open_by_handle(
                goto out_dput;
        }
 
-       fd = get_unused_fd();
+       fd = get_unused_fd_flags(0);
        if (fd < 0) {
                error = fd;
                goto out_dput;
@@ -928,7 +928,7 @@ xfs_ioctl_setattr(
        struct xfs_trans        *tp;
        unsigned int            lock_flags = 0;
        struct xfs_dquot        *udqp = NULL;
-       struct xfs_dquot        *gdqp = NULL;
+       struct xfs_dquot        *pdqp = NULL;
        struct xfs_dquot        *olddquot = NULL;
        int                     code;
 
@@ -957,7 +957,7 @@ xfs_ioctl_setattr(
        if (XFS_IS_QUOTA_ON(mp) && (mask & FSX_PROJID)) {
                code = xfs_qm_vop_dqalloc(ip, ip->i_d.di_uid,
                                         ip->i_d.di_gid, fa->fsx_projid,
-                                        XFS_QMOPT_PQUOTA, &udqp, &gdqp);
+                                        XFS_QMOPT_PQUOTA, &udqp, NULL, &pdqp);
                if (code)
                        return code;
        }
@@ -994,8 +994,8 @@ xfs_ioctl_setattr(
                    XFS_IS_PQUOTA_ON(mp) &&
                    xfs_get_projid(ip) != fa->fsx_projid) {
                        ASSERT(tp);
-                       code = xfs_qm_vop_chown_reserve(tp, ip, udqp, gdqp,
-                                               capable(CAP_FOWNER) ?
+                       code = xfs_qm_vop_chown_reserve(tp, ip, udqp, NULL,
+                                               pdqp, capable(CAP_FOWNER) ?
                                                XFS_QMOPT_FORCE_RES : 0);
                        if (code)       /* out of quota */
                                goto error_return;
@@ -1113,7 +1113,7 @@ xfs_ioctl_setattr(
                if (xfs_get_projid(ip) != fa->fsx_projid) {
                        if (XFS_IS_QUOTA_RUNNING(mp) && XFS_IS_PQUOTA_ON(mp)) {
                                olddquot = xfs_qm_vop_chown(tp, ip,
-                                                       &ip->i_gdquot, gdqp);
+                                                       &ip->i_pdquot, pdqp);
                        }
                        xfs_set_projid(ip, fa->fsx_projid);
 
@@ -1160,13 +1160,13 @@ xfs_ioctl_setattr(
         */
        xfs_qm_dqrele(olddquot);
        xfs_qm_dqrele(udqp);
-       xfs_qm_dqrele(gdqp);
+       xfs_qm_dqrele(pdqp);
 
        return code;
 
  error_return:
        xfs_qm_dqrele(udqp);
-       xfs_qm_dqrele(gdqp);
+       xfs_qm_dqrele(pdqp);
        xfs_trans_cancel(tp, 0);
        if (lock_flags)
                xfs_iunlock(ip, lock_flags);
index c69bbc4..96dda62 100644 (file)
@@ -467,9 +467,6 @@ xfs_setattr_mode(
        ASSERT(tp);
        ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
 
-       if (!in_group_p(inode->i_gid) && !capable(CAP_FSETID))
-               mode &= ~S_ISGID;
-
        ip->i_d.di_mode &= S_IFMT;
        ip->i_d.di_mode |= mode & ~S_IFMT;
 
@@ -495,15 +492,18 @@ xfs_setattr_nonsize(
 
        trace_xfs_setattr(ip);
 
-       if (mp->m_flags & XFS_MOUNT_RDONLY)
-               return XFS_ERROR(EROFS);
+       /* If acls are being inherited, we already have this checked */
+       if (!(flags & XFS_ATTR_NOACL)) {
+               if (mp->m_flags & XFS_MOUNT_RDONLY)
+                       return XFS_ERROR(EROFS);
 
-       if (XFS_FORCED_SHUTDOWN(mp))
-               return XFS_ERROR(EIO);
+               if (XFS_FORCED_SHUTDOWN(mp))
+                       return XFS_ERROR(EIO);
 
-       error = -inode_change_ok(inode, iattr);
-       if (error)
-               return XFS_ERROR(error);
+               error = -inode_change_ok(inode, iattr);
+               if (error)
+                       return XFS_ERROR(error);
+       }
 
        ASSERT((mask & ATTR_SIZE) == 0);
 
@@ -539,7 +539,7 @@ xfs_setattr_nonsize(
                ASSERT(udqp == NULL);
                ASSERT(gdqp == NULL);
                error = xfs_qm_vop_dqalloc(ip, uid, gid, xfs_get_projid(ip),
-                                        qflags, &udqp, &gdqp);
+                                        qflags, &udqp, &gdqp, NULL);
                if (error)
                        return error;
        }
@@ -575,7 +575,7 @@ xfs_setattr_nonsize(
                     (XFS_IS_GQUOTA_ON(mp) && igid != gid))) {
                        ASSERT(tp);
                        error = xfs_qm_vop_chown_reserve(tp, ip, udqp, gdqp,
-                                               capable(CAP_FOWNER) ?
+                                               NULL, capable(CAP_FOWNER) ?
                                                XFS_QMOPT_FORCE_RES : 0);
                        if (error)      /* out of quota */
                                goto out_trans_cancel;
index bc92c53..b93e14b 100644 (file)
@@ -221,7 +221,6 @@ xfs_bulkstat(
        char                    __user *ubufp;  /* pointer into user's buffer */
        int                     ubelem; /* spaces used in user's buffer */
        int                     ubused; /* bytes used by formatter */
-       xfs_buf_t               *bp;    /* ptr to on-disk inode cluster buf */
 
        /*
         * Get the last inode value, see if there's nothing to do.
@@ -263,7 +262,6 @@ xfs_bulkstat(
        rval = 0;
        while (XFS_BULKSTAT_UBLEFT(ubleft) && agno < mp->m_sb.sb_agcount) {
                cond_resched();
-               bp = NULL;
                error = xfs_ialloc_read_agi(mp, NULL, agno, &agbp);
                if (error) {
                        /*
@@ -436,27 +434,7 @@ xfs_bulkstat(
                                irbp->ir_freecount < XFS_INODES_PER_CHUNK;
                             chunkidx++, clustidx++, agino++) {
                                ASSERT(chunkidx < XFS_INODES_PER_CHUNK);
-                               /*
-                                * Recompute agbno if this is the
-                                * first inode of the cluster.
-                                *
-                                * Careful with clustidx.   There can be
-                                * multiple clusters per chunk, a single
-                                * cluster per chunk or a cluster that has
-                                * inodes represented from several different
-                                * chunks (if blocksize is large).
-                                *
-                                * Because of this, the starting clustidx is
-                                * initialized to zero in this loop but must
-                                * later be reset after reading in the cluster
-                                * buffer.
-                                */
-                               if ((chunkidx & (nicluster - 1)) == 0) {
-                                       agbno = XFS_AGINO_TO_AGBNO(mp,
-                                                       irbp->ir_startino) +
-                                               ((chunkidx & nimask) >>
-                                                mp->m_sb.sb_inopblog);
-                               }
+
                                ino = XFS_AGINO_TO_INO(mp, agno, agino);
                                /*
                                 * Skip if this inode is free.
@@ -502,10 +480,6 @@ xfs_bulkstat(
 
                        cond_resched();
                }
-
-               if (bp)
-                       xfs_buf_relse(bp);
-
                /*
                 * Set up for the next loop iteration.
                 */
index 7a3e007..d320794 100644 (file)
@@ -137,6 +137,7 @@ xfs_qm_dqpurge(
        struct xfs_mount        *mp = dqp->q_mount;
        struct xfs_quotainfo    *qi = mp->m_quotainfo;
        struct xfs_dquot        *gdqp = NULL;
+       struct xfs_dquot        *pdqp = NULL;
 
        xfs_dqlock(dqp);
        if ((dqp->dq_flags & XFS_DQ_FREEING) || dqp->q_nrefs != 0) {
@@ -145,8 +146,7 @@ xfs_qm_dqpurge(
        }
 
        /*
-        * If this quota has a group hint attached, prepare for releasing it
-        * now.
+        * If this quota has a hint attached, prepare for releasing it now.
         */
        gdqp = dqp->q_gdquot;
        if (gdqp) {
@@ -154,6 +154,12 @@ xfs_qm_dqpurge(
                dqp->q_gdquot = NULL;
        }
 
+       pdqp = dqp->q_pdquot;
+       if (pdqp) {
+               xfs_dqlock(pdqp);
+               dqp->q_pdquot = NULL;
+       }
+
        dqp->dq_flags |= XFS_DQ_FREEING;
 
        xfs_dqflock(dqp);
@@ -208,6 +214,8 @@ xfs_qm_dqpurge(
 
        if (gdqp)
                xfs_qm_dqput(gdqp);
+       if (pdqp)
+               xfs_qm_dqput(pdqp);
        return 0;
 }
 
@@ -364,6 +372,10 @@ xfs_qm_unmount_quotas(
                        IRELE(mp->m_quotainfo->qi_gquotaip);
                        mp->m_quotainfo->qi_gquotaip = NULL;
                }
+               if (mp->m_quotainfo->qi_pquotaip) {
+                       IRELE(mp->m_quotainfo->qi_pquotaip);
+                       mp->m_quotainfo->qi_pquotaip = NULL;
+               }
        }
 }
 
@@ -410,7 +422,10 @@ xfs_qm_dqattach_one(
                 * be reclaimed as long as we have a ref from inode and we
                 * hold the ilock.
                 */
-               dqp = udqhint->q_gdquot;
+               if (type == XFS_DQ_GROUP)
+                       dqp = udqhint->q_gdquot;
+               else
+                       dqp = udqhint->q_pdquot;
                if (dqp && be32_to_cpu(dqp->q_core.d_id) == id) {
                        ASSERT(*IO_idqpp == NULL);
 
@@ -453,28 +468,42 @@ xfs_qm_dqattach_one(
 
 
 /*
- * Given a udquot and gdquot, attach a ptr to the group dquot in the
- * udquot as a hint for future lookups.
+ * Given a udquot and group/project type, attach the group/project
+ * dquot pointer to the udquot as a hint for future lookups.
  */
 STATIC void
-xfs_qm_dqattach_grouphint(
-       xfs_dquot_t     *udq,
-       xfs_dquot_t     *gdq)
+xfs_qm_dqattach_hint(
+       struct xfs_inode        *ip,
+       int                     type)
 {
-       xfs_dquot_t     *tmp;
+       struct xfs_dquot **dqhintp;
+       struct xfs_dquot *dqp;
+       struct xfs_dquot *udq = ip->i_udquot;
+
+       ASSERT(type == XFS_DQ_GROUP || type == XFS_DQ_PROJ);
 
        xfs_dqlock(udq);
 
-       tmp = udq->q_gdquot;
-       if (tmp) {
-               if (tmp == gdq)
+       if (type == XFS_DQ_GROUP) {
+               dqp = ip->i_gdquot;
+               dqhintp = &udq->q_gdquot;
+       } else {
+               dqp = ip->i_pdquot;
+               dqhintp = &udq->q_pdquot;
+       }
+
+       if (*dqhintp) {
+               struct xfs_dquot *tmp;
+
+               if (*dqhintp == dqp)
                        goto done;
 
-               udq->q_gdquot = NULL;
+               tmp = *dqhintp;
+               *dqhintp = NULL;
                xfs_qm_dqrele(tmp);
        }
 
-       udq->q_gdquot = xfs_qm_dqhold(gdq);
+       *dqhintp = xfs_qm_dqhold(dqp);
 done:
        xfs_dqunlock(udq);
 }
@@ -527,12 +556,8 @@ xfs_qm_dqattach_locked(
        }
 
        ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
-       if (XFS_IS_OQUOTA_ON(mp)) {
-               error = XFS_IS_GQUOTA_ON(mp) ?
-                       xfs_qm_dqattach_one(ip, ip->i_d.di_gid, XFS_DQ_GROUP,
-                                               flags & XFS_QMOPT_DQALLOC,
-                                               ip->i_udquot, &ip->i_gdquot) :
-                       xfs_qm_dqattach_one(ip, xfs_get_projid(ip), XFS_DQ_PROJ,
+       if (XFS_IS_GQUOTA_ON(mp)) {
+               error = xfs_qm_dqattach_one(ip, ip->i_d.di_gid, XFS_DQ_GROUP,
                                                flags & XFS_QMOPT_DQALLOC,
                                                ip->i_udquot, &ip->i_gdquot);
                /*
@@ -544,14 +569,28 @@ xfs_qm_dqattach_locked(
                nquotas++;
        }
 
+       ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
+       if (XFS_IS_PQUOTA_ON(mp)) {
+               error = xfs_qm_dqattach_one(ip, xfs_get_projid(ip), XFS_DQ_PROJ,
+                                               flags & XFS_QMOPT_DQALLOC,
+                                               ip->i_udquot, &ip->i_pdquot);
+               /*
+                * Don't worry about the udquot that we may have
+                * attached above. It'll get detached, if not already.
+                */
+               if (error)
+                       goto done;
+               nquotas++;
+       }
+
        /*
-        * Attach this group quota to the user quota as a hint.
+        * Attach this group/project quota to the user quota as a hint.
         * This WON'T, in general, result in a thrash.
         */
-       if (nquotas == 2) {
+       if (nquotas > 1 && ip->i_udquot) {
                ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
-               ASSERT(ip->i_udquot);
-               ASSERT(ip->i_gdquot);
+               ASSERT(ip->i_gdquot || !XFS_IS_GQUOTA_ON(mp));
+               ASSERT(ip->i_pdquot || !XFS_IS_PQUOTA_ON(mp));
 
                /*
                 * We do not have i_udquot locked at this point, but this check
@@ -560,7 +599,10 @@ xfs_qm_dqattach_locked(
                 * succeed in general.
                 */
                if (ip->i_udquot->q_gdquot != ip->i_gdquot)
-                       xfs_qm_dqattach_grouphint(ip->i_udquot, ip->i_gdquot);
+                       xfs_qm_dqattach_hint(ip, XFS_DQ_GROUP);
+
+               if (ip->i_udquot->q_pdquot != ip->i_pdquot)
+                       xfs_qm_dqattach_hint(ip, XFS_DQ_PROJ);
        }
 
  done:
@@ -568,8 +610,10 @@ xfs_qm_dqattach_locked(
        if (!error) {
                if (XFS_IS_UQUOTA_ON(mp))
                        ASSERT(ip->i_udquot);
-               if (XFS_IS_OQUOTA_ON(mp))
+               if (XFS_IS_GQUOTA_ON(mp))
                        ASSERT(ip->i_gdquot);
+               if (XFS_IS_PQUOTA_ON(mp))
+                       ASSERT(ip->i_pdquot);
        }
        ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
 #endif
@@ -602,7 +646,7 @@ void
 xfs_qm_dqdetach(
        xfs_inode_t     *ip)
 {
-       if (!(ip->i_udquot || ip->i_gdquot))
+       if (!(ip->i_udquot || ip->i_gdquot || ip->i_pdquot))
                return;
 
        trace_xfs_dquot_dqdetach(ip);
@@ -616,6 +660,10 @@ xfs_qm_dqdetach(
                xfs_qm_dqrele(ip->i_gdquot);
                ip->i_gdquot = NULL;
        }
+       if (ip->i_pdquot) {
+               xfs_qm_dqrele(ip->i_pdquot);
+               ip->i_pdquot = NULL;
+       }
 }
 
 int
@@ -660,6 +708,7 @@ xfs_qm_init_quotainfo(
 
        INIT_RADIX_TREE(&qinf->qi_uquota_tree, GFP_NOFS);
        INIT_RADIX_TREE(&qinf->qi_gquota_tree, GFP_NOFS);
+       INIT_RADIX_TREE(&qinf->qi_pquota_tree, GFP_NOFS);
        mutex_init(&qinf->qi_tree_lock);
 
        INIT_LIST_HEAD(&qinf->qi_lru_list);
@@ -761,6 +810,10 @@ xfs_qm_destroy_quotainfo(
                IRELE(qi->qi_gquotaip);
                qi->qi_gquotaip = NULL;
        }
+       if (qi->qi_pquotaip) {
+               IRELE(qi->qi_pquotaip);
+               qi->qi_pquotaip = NULL;
+       }
        mutex_destroy(&qi->qi_quotaofflock);
        kmem_free(qi);
        mp->m_quotainfo = NULL;
@@ -1269,13 +1322,14 @@ xfs_qm_quotacheck(
        LIST_HEAD               (buffer_list);
        struct xfs_inode        *uip = mp->m_quotainfo->qi_uquotaip;
        struct xfs_inode        *gip = mp->m_quotainfo->qi_gquotaip;
+       struct xfs_inode        *pip = mp->m_quotainfo->qi_pquotaip;
 
        count = INT_MAX;
        structsz = 1;
        lastino = 0;
        flags = 0;
 
-       ASSERT(uip || gip);
+       ASSERT(uip || gip || pip);
        ASSERT(XFS_IS_QUOTA_RUNNING(mp));
 
        xfs_notice(mp, "Quotacheck needed: Please wait.");
@@ -1294,13 +1348,19 @@ xfs_qm_quotacheck(
        }
 
        if (gip) {
-               error = xfs_qm_dqiterate(mp, gip, XFS_IS_GQUOTA_ON(mp) ?
-                                        XFS_QMOPT_GQUOTA : XFS_QMOPT_PQUOTA,
+               error = xfs_qm_dqiterate(mp, gip, XFS_QMOPT_GQUOTA,
                                         &buffer_list);
                if (error)
                        goto error_return;
-               flags |= XFS_IS_GQUOTA_ON(mp) ?
-                                       XFS_GQUOTA_CHKD : XFS_PQUOTA_CHKD;
+               flags |= XFS_GQUOTA_CHKD;
+       }
+
+       if (pip) {
+               error = xfs_qm_dqiterate(mp, pip, XFS_QMOPT_PQUOTA,
+                                        &buffer_list);
+               if (error)
+                       goto error_return;
+               flags |= XFS_PQUOTA_CHKD;
        }
 
        do {
@@ -1397,6 +1457,7 @@ xfs_qm_init_quotainos(
 {
        struct xfs_inode        *uip = NULL;
        struct xfs_inode        *gip = NULL;
+       struct xfs_inode        *pip = NULL;
        int                     error;
        __int64_t               sbflags = 0;
        uint                    flags = 0;
@@ -1415,7 +1476,7 @@ xfs_qm_init_quotainos(
                        if (error)
                                return XFS_ERROR(error);
                }
-               if (XFS_IS_OQUOTA_ON(mp) &&
+               if (XFS_IS_GQUOTA_ON(mp) &&
                    mp->m_sb.sb_gquotino != NULLFSINO) {
                        ASSERT(mp->m_sb.sb_gquotino > 0);
                        error = xfs_iget(mp, NULL, mp->m_sb.sb_gquotino,
@@ -1423,6 +1484,15 @@ xfs_qm_init_quotainos(
                        if (error)
                                goto error_rele;
                }
+               /* XXX: Use gquotino for now */
+               if (XFS_IS_PQUOTA_ON(mp) &&
+                   mp->m_sb.sb_gquotino != NULLFSINO) {
+                       ASSERT(mp->m_sb.sb_gquotino > 0);
+                       error = xfs_iget(mp, NULL, mp->m_sb.sb_gquotino,
+                                            0, 0, &pip);
+                       if (error)
+                               goto error_rele;
+               }
        } else {
                flags |= XFS_QMOPT_SBVERSION;
                sbflags |= (XFS_SB_VERSIONNUM | XFS_SB_UQUOTINO |
@@ -1430,7 +1500,7 @@ xfs_qm_init_quotainos(
        }
 
        /*
-        * Create the two inodes, if they don't exist already. The changes
+        * Create the three inodes, if they don't exist already. The changes
         * made above will get added to a transaction and logged in one of
         * the qino_alloc calls below.  If the device is readonly,
         * temporarily switch to read-write to do this.
@@ -1444,17 +1514,27 @@ xfs_qm_init_quotainos(
 
                flags &= ~XFS_QMOPT_SBVERSION;
        }
-       if (XFS_IS_OQUOTA_ON(mp) && gip == NULL) {
-               flags |= (XFS_IS_GQUOTA_ON(mp) ?
-                               XFS_QMOPT_GQUOTA : XFS_QMOPT_PQUOTA);
+       if (XFS_IS_GQUOTA_ON(mp) && gip == NULL) {
                error = xfs_qm_qino_alloc(mp, &gip,
-                                         sbflags | XFS_SB_GQUOTINO, flags);
+                                         sbflags | XFS_SB_GQUOTINO,
+                                         flags | XFS_QMOPT_GQUOTA);
+               if (error)
+                       goto error_rele;
+
+               flags &= ~XFS_QMOPT_SBVERSION;
+       }
+       if (XFS_IS_PQUOTA_ON(mp) && pip == NULL) {
+               /* XXX: Use XFS_SB_GQUOTINO for now */
+               error = xfs_qm_qino_alloc(mp, &pip,
+                                         sbflags | XFS_SB_GQUOTINO,
+                                         flags | XFS_QMOPT_PQUOTA);
                if (error)
                        goto error_rele;
        }
 
        mp->m_quotainfo->qi_uquotaip = uip;
        mp->m_quotainfo->qi_gquotaip = gip;
+       mp->m_quotainfo->qi_pquotaip = pip;
 
        return 0;
 
@@ -1463,6 +1543,8 @@ error_rele:
                IRELE(uip);
        if (gip)
                IRELE(gip);
+       if (pip)
+               IRELE(pip);
        return XFS_ERROR(error);
 }
 
@@ -1657,11 +1739,13 @@ xfs_qm_vop_dqalloc(
        prid_t                  prid,
        uint                    flags,
        struct xfs_dquot        **O_udqpp,
-       struct xfs_dquot        **O_gdqpp)
+       struct xfs_dquot        **O_gdqpp,
+       struct xfs_dquot        **O_pdqpp)
 {
        struct xfs_mount        *mp = ip->i_mount;
        struct xfs_dquot        *uq = NULL;
        struct xfs_dquot        *gq = NULL;
+       struct xfs_dquot        *pq = NULL;
        int                     error;
        uint                    lockflags;
 
@@ -1741,24 +1825,25 @@ xfs_qm_vop_dqalloc(
                        ASSERT(ip->i_gdquot);
                        gq = xfs_qm_dqhold(ip->i_gdquot);
                }
-       } else if ((flags & XFS_QMOPT_PQUOTA) && XFS_IS_PQUOTA_ON(mp)) {
+       }
+       if ((flags & XFS_QMOPT_PQUOTA) && XFS_IS_PQUOTA_ON(mp)) {
                if (xfs_get_projid(ip) != prid) {
                        xfs_iunlock(ip, lockflags);
                        error = xfs_qm_dqget(mp, NULL, (xfs_dqid_t)prid,
                                                 XFS_DQ_PROJ,
                                                 XFS_QMOPT_DQALLOC |
                                                 XFS_QMOPT_DOWARN,
-                                                &gq);
+                                                &pq);
                        if (error) {
                                ASSERT(error != ENOENT);
                                goto error_rele;
                        }
-                       xfs_dqunlock(gq);
+                       xfs_dqunlock(pq);
                        lockflags = XFS_ILOCK_SHARED;
                        xfs_ilock(ip, lockflags);
                } else {
-                       ASSERT(ip->i_gdquot);
-                       gq = xfs_qm_dqhold(ip->i_gdquot);
+                       ASSERT(ip->i_pdquot);
+                       pq = xfs_qm_dqhold(ip->i_pdquot);
                }
        }
        if (uq)
@@ -1773,9 +1858,15 @@ xfs_qm_vop_dqalloc(
                *O_gdqpp = gq;
        else if (gq)
                xfs_qm_dqrele(gq);
+       if (O_pdqpp)
+               *O_pdqpp = pq;
+       else if (pq)
+               xfs_qm_dqrele(pq);
        return 0;
 
 error_rele:
+       if (gq)
+               xfs_qm_dqrele(gq);
        if (uq)
                xfs_qm_dqrele(uq);
        return error;
@@ -1830,14 +1921,17 @@ xfs_qm_vop_chown_reserve(
        struct xfs_inode        *ip,
        struct xfs_dquot        *udqp,
        struct xfs_dquot        *gdqp,
+       struct xfs_dquot        *pdqp,
        uint                    flags)
 {
        struct xfs_mount        *mp = ip->i_mount;
        uint                    delblks, blkflags, prjflags = 0;
        struct xfs_dquot        *udq_unres = NULL;
        struct xfs_dquot        *gdq_unres = NULL;
+       struct xfs_dquot        *pdq_unres = NULL;
        struct xfs_dquot        *udq_delblks = NULL;
        struct xfs_dquot        *gdq_delblks = NULL;
+       struct xfs_dquot        *pdq_delblks = NULL;
        int                     error;
 
 
@@ -1861,24 +1955,28 @@ xfs_qm_vop_chown_reserve(
                        udq_unres = ip->i_udquot;
                }
        }
-       if (XFS_IS_OQUOTA_ON(ip->i_mount) && gdqp) {
-               if (XFS_IS_PQUOTA_ON(ip->i_mount) &&
-                    xfs_get_projid(ip) != be32_to_cpu(gdqp->q_core.d_id))
-                       prjflags = XFS_QMOPT_ENOSPC;
-
-               if (prjflags ||
-                   (XFS_IS_GQUOTA_ON(ip->i_mount) &&
-                    ip->i_d.di_gid != be32_to_cpu(gdqp->q_core.d_id))) {
-                       gdq_delblks = gdqp;
-                       if (delblks) {
-                               ASSERT(ip->i_gdquot);
-                               gdq_unres = ip->i_gdquot;
-                       }
+       if (XFS_IS_GQUOTA_ON(ip->i_mount) && gdqp &&
+           ip->i_d.di_gid != be32_to_cpu(gdqp->q_core.d_id)) {
+               gdq_delblks = gdqp;
+               if (delblks) {
+                       ASSERT(ip->i_gdquot);
+                       gdq_unres = ip->i_gdquot;
+               }
+       }
+
+       if (XFS_IS_PQUOTA_ON(ip->i_mount) && pdqp &&
+           xfs_get_projid(ip) != be32_to_cpu(pdqp->q_core.d_id)) {
+               prjflags = XFS_QMOPT_ENOSPC;
+               pdq_delblks = pdqp;
+               if (delblks) {
+                       ASSERT(ip->i_pdquot);
+                       pdq_unres = ip->i_pdquot;
                }
        }
 
        error = xfs_trans_reserve_quota_bydquots(tp, ip->i_mount,
-                               udq_delblks, gdq_delblks, ip->i_d.di_nblocks, 1,
+                               udq_delblks, gdq_delblks, pdq_delblks,
+                               ip->i_d.di_nblocks, 1,
                                flags | blkflags | prjflags);
        if (error)
                return error;
@@ -1893,16 +1991,17 @@ xfs_qm_vop_chown_reserve(
                /*
                 * Do the reservations first. Unreservation can't fail.
                 */
-               ASSERT(udq_delblks || gdq_delblks);
-               ASSERT(udq_unres || gdq_unres);
+               ASSERT(udq_delblks || gdq_delblks || pdq_delblks);
+               ASSERT(udq_unres || gdq_unres || pdq_unres);
                error = xfs_trans_reserve_quota_bydquots(NULL, ip->i_mount,
-                           udq_delblks, gdq_delblks, (xfs_qcnt_t)delblks, 0,
+                           udq_delblks, gdq_delblks, pdq_delblks,
+                           (xfs_qcnt_t)delblks, 0,
                            flags | blkflags | prjflags);
                if (error)
                        return error;
                xfs_trans_reserve_quota_bydquots(NULL, ip->i_mount,
-                               udq_unres, gdq_unres, -((xfs_qcnt_t)delblks), 0,
-                               blkflags);
+                               udq_unres, gdq_unres, pdq_unres,
+                               -((xfs_qcnt_t)delblks), 0, blkflags);
        }
 
        return (0);
@@ -1941,7 +2040,8 @@ xfs_qm_vop_create_dqattach(
        struct xfs_trans        *tp,
        struct xfs_inode        *ip,
        struct xfs_dquot        *udqp,
-       struct xfs_dquot        *gdqp)
+       struct xfs_dquot        *gdqp,
+       struct xfs_dquot        *pdqp)
 {
        struct xfs_mount        *mp = tp->t_mountp;
 
@@ -1961,13 +2061,18 @@ xfs_qm_vop_create_dqattach(
        }
        if (gdqp) {
                ASSERT(ip->i_gdquot == NULL);
-               ASSERT(XFS_IS_OQUOTA_ON(mp));
-               ASSERT((XFS_IS_GQUOTA_ON(mp) ?
-                       ip->i_d.di_gid : xfs_get_projid(ip)) ==
-                               be32_to_cpu(gdqp->q_core.d_id));
-
+               ASSERT(XFS_IS_GQUOTA_ON(mp));
+               ASSERT(ip->i_d.di_gid == be32_to_cpu(gdqp->q_core.d_id));
                ip->i_gdquot = xfs_qm_dqhold(gdqp);
                xfs_trans_mod_dquot(tp, gdqp, XFS_TRANS_DQ_ICOUNT, 1);
        }
+       if (pdqp) {
+               ASSERT(ip->i_pdquot == NULL);
+               ASSERT(XFS_IS_PQUOTA_ON(mp));
+               ASSERT(xfs_get_projid(ip) == be32_to_cpu(pdqp->q_core.d_id));
+
+               ip->i_pdquot = xfs_qm_dqhold(pdqp);
+               xfs_trans_mod_dquot(tp, pdqp, XFS_TRANS_DQ_ICOUNT, 1);
+       }
 }
 
index bdb4f8b..579d6a0 100644 (file)
@@ -44,9 +44,11 @@ extern struct kmem_zone      *xfs_qm_dqtrxzone;
 typedef struct xfs_quotainfo {
        struct radix_tree_root qi_uquota_tree;
        struct radix_tree_root qi_gquota_tree;
+       struct radix_tree_root qi_pquota_tree;
        struct mutex qi_tree_lock;
-       xfs_inode_t     *qi_uquotaip;    /* user quota inode */
-       xfs_inode_t     *qi_gquotaip;    /* group quota inode */
+       struct xfs_inode        *qi_uquotaip;   /* user quota inode */
+       struct xfs_inode        *qi_gquotaip;   /* group quota inode */
+       struct xfs_inode        *qi_pquotaip;   /* project quota inode */
        struct list_head qi_lru_list;
        struct mutex     qi_lru_lock;
        int              qi_lru_count;
@@ -78,8 +80,9 @@ xfs_dquot_tree(
        case XFS_DQ_USER:
                return &qi->qi_uquota_tree;
        case XFS_DQ_GROUP:
-       case XFS_DQ_PROJ:
                return &qi->qi_gquota_tree;
+       case XFS_DQ_PROJ:
+               return &qi->qi_pquota_tree;
        default:
                ASSERT(0);
        }
@@ -93,8 +96,9 @@ xfs_dq_to_quota_inode(struct xfs_dquot *dqp)
        case XFS_DQ_USER:
                return dqp->q_mount->m_quotainfo->qi_uquotaip;
        case XFS_DQ_GROUP:
-       case XFS_DQ_PROJ:
                return dqp->q_mount->m_quotainfo->qi_gquotaip;
+       case XFS_DQ_PROJ:
+               return dqp->q_mount->m_quotainfo->qi_pquotaip;
        default:
                ASSERT(0);
        }
@@ -107,18 +111,20 @@ extern void       xfs_trans_mod_dquot(struct xfs_trans *,
                                        struct xfs_dquot *, uint, long);
 extern int     xfs_trans_reserve_quota_bydquots(struct xfs_trans *,
                        struct xfs_mount *, struct xfs_dquot *,
-                       struct xfs_dquot *, long, long, uint);
+                       struct xfs_dquot *, struct xfs_dquot *,
+                       long, long, uint);
 extern void    xfs_trans_dqjoin(struct xfs_trans *, struct xfs_dquot *);
 extern void    xfs_trans_log_dquot(struct xfs_trans *, struct xfs_dquot *);
 
 /*
- * We keep the usr and grp dquots separately so that locking will be easier
- * to do at commit time. All transactions that we know of at this point
+ * We keep the usr, grp, and prj dquots separately so that locking will be
+ * easier to do at commit time. All transactions that we know of at this point
  * affect no more than two dquots of one type. Hence, the TRANS_MAXDQS value.
  */
 enum {
        XFS_QM_TRANS_USR = 0,
        XFS_QM_TRANS_GRP,
+       XFS_QM_TRANS_PRJ,
        XFS_QM_TRANS_DQTYPES
 };
 #define XFS_QM_TRANS_MAXDQS            2
index 2d02eac..437a52d 100644 (file)
@@ -112,16 +112,16 @@ xfs_qm_newmount(
 
        if (((uquotaondisk && !XFS_IS_UQUOTA_ON(mp)) ||
            (!uquotaondisk &&  XFS_IS_UQUOTA_ON(mp)) ||
-            (pquotaondisk && !XFS_IS_PQUOTA_ON(mp)) ||
-           (!pquotaondisk &&  XFS_IS_PQUOTA_ON(mp)) ||
             (gquotaondisk && !XFS_IS_GQUOTA_ON(mp)) ||
-           (!gquotaondisk &&  XFS_IS_OQUOTA_ON(mp)))  &&
+           (!gquotaondisk &&  XFS_IS_GQUOTA_ON(mp)) ||
+            (pquotaondisk && !XFS_IS_PQUOTA_ON(mp)) ||
+           (!pquotaondisk &&  XFS_IS_PQUOTA_ON(mp)))  &&
            xfs_dev_is_read_only(mp, "changing quota state")) {
                xfs_warn(mp, "please mount with%s%s%s%s.",
                        (!quotaondisk ? "out quota" : ""),
                        (uquotaondisk ? " usrquota" : ""),
-                       (pquotaondisk ? " prjquota" : ""),
-                       (gquotaondisk ? " grpquota" : ""));
+                       (gquotaondisk ? " grpquota" : ""),
+                       (pquotaondisk ? " prjquota" : ""));
                return XFS_ERROR(EPERM);
        }
 
index a08801a..e4f8b2d 100644 (file)
@@ -119,7 +119,8 @@ xfs_qm_scall_quotaoff(
                dqtype |= XFS_QMOPT_GQUOTA;
                flags |= (XFS_GQUOTA_CHKD | XFS_GQUOTA_ENFD);
                inactivate_flags |= XFS_GQUOTA_ACTIVE;
-       } else if (flags & XFS_PQUOTA_ACCT) {
+       }
+       if (flags & XFS_PQUOTA_ACCT) {
                dqtype |= XFS_QMOPT_PQUOTA;
                flags |= (XFS_PQUOTA_CHKD | XFS_PQUOTA_ENFD);
                inactivate_flags |= XFS_PQUOTA_ACTIVE;
@@ -198,10 +199,9 @@ xfs_qm_scall_quotaoff(
        }
 
        /*
-        * If quotas is completely disabled, close shop.
+        * If all quotas are completely turned off, close shop.
         */
-       if (((flags & XFS_MOUNT_QUOTA_ALL) == XFS_MOUNT_QUOTA_SET1) ||
-           ((flags & XFS_MOUNT_QUOTA_ALL) == XFS_MOUNT_QUOTA_SET2)) {
+       if (mp->m_qflags == 0) {
                mutex_unlock(&q->qi_quotaofflock);
                xfs_qm_destroy_quotainfo(mp);
                return (0);
@@ -214,10 +214,14 @@ xfs_qm_scall_quotaoff(
                IRELE(q->qi_uquotaip);
                q->qi_uquotaip = NULL;
        }
-       if ((dqtype & (XFS_QMOPT_GQUOTA|XFS_QMOPT_PQUOTA)) && q->qi_gquotaip) {
+       if ((dqtype & XFS_QMOPT_GQUOTA) && q->qi_gquotaip) {
                IRELE(q->qi_gquotaip);
                q->qi_gquotaip = NULL;
        }
+       if ((dqtype & XFS_QMOPT_PQUOTA) && q->qi_pquotaip) {
+               IRELE(q->qi_pquotaip);
+               q->qi_pquotaip = NULL;
+       }
 
 out_unlock:
        mutex_unlock(&q->qi_quotaofflock);
@@ -859,9 +863,11 @@ xfs_dqrele_inode(
 {
        /* skip quota inodes */
        if (ip == ip->i_mount->m_quotainfo->qi_uquotaip ||
-           ip == ip->i_mount->m_quotainfo->qi_gquotaip) {
+           ip == ip->i_mount->m_quotainfo->qi_gquotaip ||
+           ip == ip->i_mount->m_quotainfo->qi_pquotaip) {
                ASSERT(ip->i_udquot == NULL);
                ASSERT(ip->i_gdquot == NULL);
+               ASSERT(ip->i_pdquot == NULL);
                return 0;
        }
 
@@ -870,10 +876,14 @@ xfs_dqrele_inode(
                xfs_qm_dqrele(ip->i_udquot);
                ip->i_udquot = NULL;
        }
-       if (flags & (XFS_PQUOTA_ACCT|XFS_GQUOTA_ACCT) && ip->i_gdquot) {
+       if ((flags & XFS_GQUOTA_ACCT) && ip->i_gdquot) {
                xfs_qm_dqrele(ip->i_gdquot);
                ip->i_gdquot = NULL;
        }
+       if ((flags & XFS_PQUOTA_ACCT) && ip->i_pdquot) {
+               xfs_qm_dqrele(ip->i_pdquot);
+               ip->i_pdquot = NULL;
+       }
        xfs_iunlock(ip, XFS_ILOCK_EXCL);
        return 0;
 }
index c3483ba..b14f42c 100644 (file)
@@ -108,11 +108,28 @@ typedef struct xfs_dqblk {
        { XFS_DQ_FREEING,       "FREEING" }
 
 /*
- * In the worst case, when both user and group quotas are on,
- * we can have a max of three dquots changing in a single transaction.
+ * We have the possibility of all three quota types being active at once, and
+ * hence free space modification requires modification of all three current
+ * dquots in a single transaction. For this case we need to have a reservation
+ * of at least 3 dquots.
+ *
+ * However, a chmod operation can change both UID and GID in a single
+ * transaction, resulting in requiring {old, new} x {uid, gid} dquots to be
+ * modified. Hence for this case we need to reserve space for at least 4 dquots.
+ *
+ * And in the worst case, there's a rename operation that can be modifying up to
+ * 4 inodes with dquots attached to them. In reality, the only inodes that can
+ * have their dquots modified are the source and destination directory inodes
+ * due to directory name creation and removal. That can require space allocation
+ * and/or freeing on both directory inodes, and hence all three dquots on each
+ * inode can be modified. And if the directories are world writeable, all the
+ * dquots can be unique and so 6 dquots can be modified....
+ *
+ * And, of course, we also need to take into account the dquot log format item
+ * used to describe each dquot.
  */
-#define XFS_DQUOT_LOGRES(mp)   (sizeof(xfs_disk_dquot_t) * 3)
-
+#define XFS_DQUOT_LOGRES(mp)   \
+       ((sizeof(struct xfs_dq_logformat) + sizeof(struct xfs_disk_dquot)) * 6)
 
 /*
  * These are the structures used to lay out dquots and quotaoff
@@ -271,10 +288,10 @@ typedef struct xfs_qoff_logformat {
  * we didn't have the inode locked, the appropriate dquot(s) will be
  * attached atomically.
  */
-#define XFS_NOT_DQATTACHED(mp, ip) ((XFS_IS_UQUOTA_ON(mp) &&\
-                                    (ip)->i_udquot == NULL) || \
-                                   (XFS_IS_OQUOTA_ON(mp) && \
-                                    (ip)->i_gdquot == NULL))
+#define XFS_NOT_DQATTACHED(mp, ip) \
+       ((XFS_IS_UQUOTA_ON(mp) && (ip)->i_udquot == NULL) || \
+        (XFS_IS_GQUOTA_ON(mp) && (ip)->i_gdquot == NULL) || \
+        (XFS_IS_PQUOTA_ON(mp) && (ip)->i_pdquot == NULL))
 
 #define XFS_QM_NEED_QUOTACHECK(mp) \
        ((XFS_IS_UQUOTA_ON(mp) && \
@@ -284,14 +301,6 @@ typedef struct xfs_qoff_logformat {
         (XFS_IS_PQUOTA_ON(mp) && \
                (mp->m_sb.sb_qflags & XFS_PQUOTA_CHKD) == 0))
 
-#define XFS_MOUNT_QUOTA_SET1   (XFS_UQUOTA_ACCT|XFS_UQUOTA_ENFD|\
-                                XFS_UQUOTA_CHKD|XFS_GQUOTA_ACCT|\
-                                XFS_GQUOTA_ENFD|XFS_GQUOTA_CHKD)
-
-#define XFS_MOUNT_QUOTA_SET2   (XFS_UQUOTA_ACCT|XFS_UQUOTA_ENFD|\
-                                XFS_UQUOTA_CHKD|XFS_PQUOTA_ACCT|\
-                                XFS_PQUOTA_ENFD|XFS_PQUOTA_CHKD)
-
 #define XFS_MOUNT_QUOTA_ALL    (XFS_UQUOTA_ACCT|XFS_UQUOTA_ENFD|\
                                 XFS_UQUOTA_CHKD|XFS_GQUOTA_ACCT|\
                                 XFS_GQUOTA_ENFD|XFS_GQUOTA_CHKD|\
@@ -329,17 +338,18 @@ extern int xfs_trans_reserve_quota_nblks(struct xfs_trans *,
                struct xfs_inode *, long, long, uint);
 extern int xfs_trans_reserve_quota_bydquots(struct xfs_trans *,
                struct xfs_mount *, struct xfs_dquot *,
-               struct xfs_dquot *, long, long, uint);
+               struct xfs_dquot *, struct xfs_dquot *, long, long, uint);
 
 extern int xfs_qm_vop_dqalloc(struct xfs_inode *, uid_t, gid_t, prid_t, uint,
-               struct xfs_dquot **, struct xfs_dquot **);
+               struct xfs_dquot **, struct xfs_dquot **, struct xfs_dquot **);
 extern void xfs_qm_vop_create_dqattach(struct xfs_trans *, struct xfs_inode *,
-               struct xfs_dquot *, struct xfs_dquot *);
+               struct xfs_dquot *, struct xfs_dquot *, struct xfs_dquot *);
 extern int xfs_qm_vop_rename_dqattach(struct xfs_inode **);
 extern struct xfs_dquot *xfs_qm_vop_chown(struct xfs_trans *,
                struct xfs_inode *, struct xfs_dquot **, struct xfs_dquot *);
 extern int xfs_qm_vop_chown_reserve(struct xfs_trans *, struct xfs_inode *,
-               struct xfs_dquot *, struct xfs_dquot *, uint);
+               struct xfs_dquot *, struct xfs_dquot *,
+               struct xfs_dquot *, uint);
 extern int xfs_qm_dqattach(struct xfs_inode *, uint);
 extern int xfs_qm_dqattach_locked(struct xfs_inode *, uint);
 extern void xfs_qm_dqdetach(struct xfs_inode *);
@@ -353,10 +363,12 @@ extern void xfs_qm_unmount_quotas(struct xfs_mount *);
 #else
 static inline int
 xfs_qm_vop_dqalloc(struct xfs_inode *ip, uid_t uid, gid_t gid, prid_t prid,
-               uint flags, struct xfs_dquot **udqp, struct xfs_dquot **gdqp)
+               uint flags, struct xfs_dquot **udqp, struct xfs_dquot **gdqp,
+               struct xfs_dquot **pdqp)
 {
        *udqp = NULL;
        *gdqp = NULL;
+       *pdqp = NULL;
        return 0;
 }
 #define xfs_trans_dup_dqinfo(tp, tp2)
@@ -371,14 +383,15 @@ static inline int xfs_trans_reserve_quota_nblks(struct xfs_trans *tp,
 }
 static inline int xfs_trans_reserve_quota_bydquots(struct xfs_trans *tp,
                struct xfs_mount *mp, struct xfs_dquot *udqp,
-               struct xfs_dquot *gdqp, long nblks, long nions, uint flags)
+               struct xfs_dquot *gdqp, struct xfs_dquot *pdqp,
+               long nblks, long nions, uint flags)
 {
        return 0;
 }
-#define xfs_qm_vop_create_dqattach(tp, ip, u, g)
+#define xfs_qm_vop_create_dqattach(tp, ip, u, g, p)
 #define xfs_qm_vop_rename_dqattach(it)                                 (0)
 #define xfs_qm_vop_chown(tp, ip, old, new)                             (NULL)
-#define xfs_qm_vop_chown_reserve(tp, ip, u, g, fl)                     (0)
+#define xfs_qm_vop_chown_reserve(tp, ip, u, g, p, fl)                  (0)
 #define xfs_qm_dqattach(ip, fl)                                                (0)
 #define xfs_qm_dqattach_locked(ip, fl)                                 (0)
 #define xfs_qm_dqdetach(ip)
@@ -392,8 +405,8 @@ static inline int xfs_trans_reserve_quota_bydquots(struct xfs_trans *tp,
 
 #define xfs_trans_unreserve_quota_nblks(tp, ip, nblks, ninos, flags) \
        xfs_trans_reserve_quota_nblks(tp, ip, -(nblks), -(ninos), flags)
-#define xfs_trans_reserve_quota(tp, mp, ud, gd, nb, ni, f) \
-       xfs_trans_reserve_quota_bydquots(tp, mp, ud, gd, nb, ni, \
+#define xfs_trans_reserve_quota(tp, mp, ud, gd, pd, nb, ni, f) \
+       xfs_trans_reserve_quota_bydquots(tp, mp, ud, gd, pd, nb, ni, \
                                f | XFS_QMOPT_RES_REGBLKS)
 
 extern int xfs_qm_dqcheck(struct xfs_mount *, xfs_disk_dquot_t *,
index e830fb5..f4895b6 100644 (file)
@@ -360,6 +360,7 @@ xfs_symlink(
        prid_t                  prid;
        struct xfs_dquot        *udqp = NULL;
        struct xfs_dquot        *gdqp = NULL;
+       struct xfs_dquot        *pdqp = NULL;
        uint                    resblks;
 
        *ipp = NULL;
@@ -386,7 +387,7 @@ xfs_symlink(
         * Make sure that we have allocated dquot(s) on disk.
         */
        error = xfs_qm_vop_dqalloc(dp, current_fsuid(), current_fsgid(), prid,
-                       XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT, &udqp, &gdqp);
+               XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT, &udqp, &gdqp, &pdqp);
        if (error)
                goto std_return;
 
@@ -427,7 +428,8 @@ xfs_symlink(
        /*
         * Reserve disk quota : blocks and inode.
         */
-       error = xfs_trans_reserve_quota(tp, mp, udqp, gdqp, resblks, 1, 0);
+       error = xfs_trans_reserve_quota(tp, mp, udqp, gdqp,
+                                               pdqp, resblks, 1, 0);
        if (error)
                goto error_return;
 
@@ -465,7 +467,7 @@ xfs_symlink(
        /*
         * Also attach the dquot(s) to it, if applicable.
         */
-       xfs_qm_vop_create_dqattach(tp, ip, udqp, gdqp);
+       xfs_qm_vop_create_dqattach(tp, ip, udqp, gdqp, pdqp);
 
        if (resblks)
                resblks -= XFS_IALLOC_SPACE_RES(mp);
@@ -563,6 +565,7 @@ xfs_symlink(
        error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
        xfs_qm_dqrele(udqp);
        xfs_qm_dqrele(gdqp);
+       xfs_qm_dqrele(pdqp);
 
        *ipp = ip;
        return 0;
@@ -576,6 +579,7 @@ xfs_symlink(
        xfs_trans_cancel(tp, cancel_flags);
        xfs_qm_dqrele(udqp);
        xfs_qm_dqrele(gdqp);
+       xfs_qm_dqrele(pdqp);
 
        if (unlock_dp_on_error)
                xfs_iunlock(dp, XFS_ILOCK_EXCL);
index 3ba64d5..61407a8 100644 (file)
@@ -163,8 +163,10 @@ xfs_trans_mod_dquot_byino(
 
        if (XFS_IS_UQUOTA_ON(mp) && ip->i_udquot)
                (void) xfs_trans_mod_dquot(tp, ip->i_udquot, field, delta);
-       if (XFS_IS_OQUOTA_ON(mp) && ip->i_gdquot)
+       if (XFS_IS_GQUOTA_ON(mp) && ip->i_gdquot)
                (void) xfs_trans_mod_dquot(tp, ip->i_gdquot, field, delta);
+       if (XFS_IS_PQUOTA_ON(mp) && ip->i_pdquot)
+               (void) xfs_trans_mod_dquot(tp, ip->i_pdquot, field, delta);
 }
 
 STATIC struct xfs_dqtrx *
@@ -177,8 +179,12 @@ xfs_trans_get_dqtrx(
 
        if (XFS_QM_ISUDQ(dqp))
                qa = tp->t_dqinfo->dqs[XFS_QM_TRANS_USR];
-       else
+       else if (XFS_QM_ISGDQ(dqp))
                qa = tp->t_dqinfo->dqs[XFS_QM_TRANS_GRP];
+       else if (XFS_QM_ISPDQ(dqp))
+               qa = tp->t_dqinfo->dqs[XFS_QM_TRANS_PRJ];
+       else
+               return NULL;
 
        for (i = 0; i < XFS_QM_TRANS_MAXDQS; i++) {
                if (qa[i].qt_dquot == NULL ||
@@ -291,11 +297,10 @@ xfs_trans_mod_dquot(
 
 
 /*
- * Given an array of dqtrx structures, lock all the dquots associated
- * and join them to the transaction, provided they have been modified.
- * We know that the highest number of dquots (of one type - usr OR grp),
- * involved in a transaction is 2 and that both usr and grp combined - 3.
- * So, we don't attempt to make this very generic.
+ * Given an array of dqtrx structures, lock all the dquots associated and join
+ * them to the transaction, provided they have been modified.  We know that the
+ * highest number of dquots of one type - usr, grp OR prj - involved in a
+ * transaction is 2 so we don't need to make this very generic.
  */
 STATIC void
 xfs_trans_dqlockedjoin(
@@ -728,8 +733,8 @@ error_return:
 
 /*
  * Given dquot(s), make disk block and/or inode reservations against them.
- * The fact that this does the reservation against both the usr and
- * grp/prj quotas is important, because this follows a both-or-nothing
+ * The fact that this does the reservation against user, group and
+ * project quotas is important, because this follows a all-or-nothing
  * approach.
  *
  * flags = XFS_QMOPT_FORCE_RES evades limit enforcement. Used by chown.
@@ -744,6 +749,7 @@ xfs_trans_reserve_quota_bydquots(
        struct xfs_mount        *mp,
        struct xfs_dquot        *udqp,
        struct xfs_dquot        *gdqp,
+       struct xfs_dquot        *pdqp,
        long                    nblks,
        long                    ninos,
        uint                    flags)
@@ -771,11 +777,21 @@ xfs_trans_reserve_quota_bydquots(
                        goto unwind_usr;
        }
 
+       if (pdqp) {
+               error = xfs_trans_dqresv(tp, mp, pdqp, nblks, ninos, flags);
+               if (error)
+                       goto unwind_grp;
+       }
+
        /*
         * Didn't change anything critical, so, no need to log
         */
        return 0;
 
+unwind_grp:
+       flags |= XFS_QMOPT_FORCE_RES;
+       if (gdqp)
+               xfs_trans_dqresv(tp, mp, gdqp, -nblks, -ninos, flags);
 unwind_usr:
        flags |= XFS_QMOPT_FORCE_RES;
        if (udqp)
@@ -817,6 +833,7 @@ xfs_trans_reserve_quota_nblks(
         */
        return xfs_trans_reserve_quota_bydquots(tp, mp,
                                                ip->i_udquot, ip->i_gdquot,
+                                               ip->i_pdquot,
                                                nblks, ninos, flags);
 }
 
index 42c0ef2..dc730ac 100644 (file)
@@ -489,6 +489,7 @@ xfs_create(
        prid_t                  prid;
        struct xfs_dquot        *udqp = NULL;
        struct xfs_dquot        *gdqp = NULL;
+       struct xfs_dquot        *pdqp = NULL;
        uint                    resblks;
        uint                    log_res;
        uint                    log_count;
@@ -507,7 +508,8 @@ xfs_create(
         * Make sure that we have allocated dquot(s) on disk.
         */
        error = xfs_qm_vop_dqalloc(dp, current_fsuid(), current_fsgid(), prid,
-                       XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT, &udqp, &gdqp);
+                                       XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT,
+                                       &udqp, &gdqp, &pdqp);
        if (error)
                return error;
 
@@ -559,7 +561,8 @@ xfs_create(
        /*
         * Reserve disk quota and the inode.
         */
-       error = xfs_trans_reserve_quota(tp, mp, udqp, gdqp, resblks, 1, 0);
+       error = xfs_trans_reserve_quota(tp, mp, udqp, gdqp,
+                                               pdqp, resblks, 1, 0);
        if (error)
                goto out_trans_cancel;
 
@@ -623,7 +626,7 @@ xfs_create(
         * These ids of the inode couldn't have changed since the new
         * inode has been locked ever since it was created.
         */
-       xfs_qm_vop_create_dqattach(tp, ip, udqp, gdqp);
+       xfs_qm_vop_create_dqattach(tp, ip, udqp, gdqp, pdqp);
 
        error = xfs_bmap_finish(&tp, &free_list, &committed);
        if (error)
@@ -635,6 +638,7 @@ xfs_create(
 
        xfs_qm_dqrele(udqp);
        xfs_qm_dqrele(gdqp);
+       xfs_qm_dqrele(pdqp);
 
        *ipp = ip;
        return 0;
@@ -656,6 +660,7 @@ xfs_create(
 
        xfs_qm_dqrele(udqp);
        xfs_qm_dqrele(gdqp);
+       xfs_qm_dqrele(pdqp);
 
        if (unlock_dp_on_error)
                xfs_iunlock(dp, XFS_ILOCK_EXCL);
@@ -1568,7 +1573,7 @@ xfs_free_file_space(
                }
                xfs_ilock(ip, XFS_ILOCK_EXCL);
                error = xfs_trans_reserve_quota(tp, mp,
-                               ip->i_udquot, ip->i_gdquot,
+                               ip->i_udquot, ip->i_gdquot, ip->i_pdquot,
                                resblks, 0, XFS_QMOPT_RES_REGBLKS);
                if (error)
                        goto error1;
index ef24466..ec48bac 100644 (file)
@@ -97,11 +97,11 @@ static inline void *bio_data(struct bio *bio)
  * permanent PIO fall back, user is probably better off disabling highmem
  * I/O completely on that queue (see ide-dma for example)
  */
-#define __bio_kmap_atomic(bio, idx, kmtype)                            \
+#define __bio_kmap_atomic(bio, idx)                            \
        (kmap_atomic(bio_iovec_idx((bio), (idx))->bv_page) +    \
                bio_iovec_idx((bio), (idx))->bv_offset)
 
-#define __bio_kunmap_atomic(addr, kmtype) kunmap_atomic(addr)
+#define __bio_kunmap_atomic(addr) kunmap_atomic(addr)
 
 /*
  * merge helpers etc
index fd097ec..297462b 100644 (file)
@@ -278,6 +278,8 @@ enum {
         *
         * - memcg: use_hierarchy is on by default and the cgroup file for
         *   the flag is not created.
+        *
+        * - blkcg: blk-throttle becomes properly hierarchical.
         */
        CGRP_ROOT_SANE_BEHAVIOR = (1 << 0),
 
index 282e270..a5d52ee 100644 (file)
@@ -41,7 +41,7 @@ cpufreq_cooling_register(const struct cpumask *clip_cpus);
  */
 void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev);
 
-unsigned long cpufreq_cooling_get_level(unsigned int, unsigned int);
+unsigned long cpufreq_cooling_get_level(unsigned int cpu, unsigned int freq);
 #else /* !CONFIG_CPU_THERMAL */
 static inline struct thermal_cooling_device *
 cpufreq_cooling_register(const struct cpumask *clip_cpus)
@@ -54,7 +54,7 @@ void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev)
        return;
 }
 static inline
-unsigned long cpufreq_cooling_get_level(unsigned int, unsigned int)
+unsigned long cpufreq_cooling_get_level(unsigned int cpu, unsigned int freq)
 {
        return THERMAL_CSTATE_INVALID;
 }
index 4d7390b..90d5a15 100644 (file)
@@ -119,7 +119,7 @@ struct cpufreq_policy {
 
        struct kobject          kobj;
        struct completion       kobj_unregister;
-       bool                    transition_ongoing; /* Tracks transition status */
+       int                     transition_ongoing; /* Tracks transition status */
 };
 
 #define CPUFREQ_ADJUST                 (0)
index 3cd3247..e151d4c 100644 (file)
@@ -446,9 +446,9 @@ int __must_check dm_set_target_max_io_len(struct dm_target *ti, sector_t len);
 /*
  * Table reference counting.
  */
-struct dm_table *dm_get_live_table(struct mapped_device *md);
-void dm_table_get(struct dm_table *t);
-void dm_table_put(struct dm_table *t);
+struct dm_table *dm_get_live_table(struct mapped_device *md, int *srcu_idx);
+void dm_put_live_table(struct mapped_device *md, int srcu_idx);
+void dm_sync_table(struct mapped_device *md);
 
 /*
  * Queries
index acd0312..306dd8c 100644 (file)
@@ -7,6 +7,7 @@
 #ifdef CONFIG_BLOCK
 
 struct io_cq;
+struct elevator_type;
 
 typedef int (elevator_merge_fn) (struct request_queue *, struct request **,
                                 struct bio *);
@@ -35,7 +36,8 @@ typedef void (elevator_put_req_fn) (struct request *);
 typedef void (elevator_activate_req_fn) (struct request_queue *, struct request *);
 typedef void (elevator_deactivate_req_fn) (struct request_queue *, struct request *);
 
-typedef int (elevator_init_fn) (struct request_queue *);
+typedef int (elevator_init_fn) (struct request_queue *,
+                               struct elevator_type *e);
 typedef void (elevator_exit_fn) (struct elevator_queue *);
 
 struct elevator_ops
@@ -155,6 +157,8 @@ extern int elevator_init(struct request_queue *, char *);
 extern void elevator_exit(struct elevator_queue *);
 extern int elevator_change(struct request_queue *, const char *);
 extern bool elv_rq_merge_ok(struct request *, struct bio *);
+extern struct elevator_queue *elevator_alloc(struct request_queue *,
+                                       struct elevator_type *);
 
 /*
  * Helper functions.
index 191501a..3b0e820 100644 (file)
@@ -251,8 +251,10 @@ struct ieee1394_device_id;
 
 struct fw_driver {
        struct device_driver driver;
+       int (*probe)(struct fw_unit *unit, const struct ieee1394_device_id *id);
        /* Called when the parent device sits through a bus reset. */
        void (*update)(struct fw_unit *unit);
+       void (*remove)(struct fw_unit *unit);
        const struct ieee1394_device_id *id_table;
 };
 
index 37faaea..fff099f 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/stat.h>
 #include <linux/cache.h>
 #include <linux/list.h>
+#include <linux/llist.h>
 #include <linux/radix-tree.h>
 #include <linux/rbtree.h>
 #include <linux/init.h>
@@ -768,6 +769,7 @@ struct file {
         */
        union {
                struct list_head        fu_list;
+               struct llist_node       fu_llist;
                struct rcu_head         fu_rcuhead;
        } f_u;
        struct path             f_path;
index 99d0fbc..9f15c00 100644 (file)
@@ -566,10 +566,6 @@ static inline ssize_t ftrace_filter_write(struct file *file, const char __user *
                            size_t cnt, loff_t *ppos) { return -ENODEV; }
 static inline ssize_t ftrace_notrace_write(struct file *file, const char __user *ubuf,
                             size_t cnt, loff_t *ppos) { return -ENODEV; }
-static inline loff_t ftrace_regex_lseek(struct file *file, loff_t offset, int whence)
-{
-       return -ENODEV;
-}
 static inline int
 ftrace_regex_release(struct inode *inode, struct file *file) { return -ENODEV; }
 #endif /* CONFIG_DYNAMIC_FTRACE */
@@ -828,10 +824,15 @@ enum ftrace_dump_mode;
 
 extern enum ftrace_dump_mode ftrace_dump_on_oops;
 
+extern void disable_trace_on_warning(void);
+extern int __disable_trace_on_warning;
+
 #ifdef CONFIG_PREEMPT
 #define INIT_TRACE_RECURSION           .trace_recursion = 0,
 #endif
 
+#else /* CONFIG_TRACING */
+static inline void  disable_trace_on_warning(void) { }
 #endif /* CONFIG_TRACING */
 
 #ifndef INIT_TRACE_RECURSION
index 488debb..81cbbdb 100644 (file)
@@ -658,7 +658,6 @@ struct twl4030_power_data {
        bool use_poweroff;      /* Board is wired for TWL poweroff */
 };
 
-extern void twl4030_power_init(struct twl4030_power_data *triton2_scripts);
 extern int twl4030_remove_script(u8 flags);
 extern void twl4030_power_off(void);
 
@@ -726,7 +725,7 @@ struct twl4030_platform_data {
        struct regulator_init_data              *clk32kg;
        struct regulator_init_data              *v1v8;
        struct regulator_init_data              *v2v1;
-       /* TWL6025 LDO regulators */
+       /* TWL6032 LDO regulators */
        struct regulator_init_data              *ldo1;
        struct regulator_init_data              *ldo2;
        struct regulator_init_data              *ldo3;
@@ -736,7 +735,7 @@ struct twl4030_platform_data {
        struct regulator_init_data              *ldo7;
        struct regulator_init_data              *ldoln;
        struct regulator_init_data              *ldousb;
-       /* TWL6025 DCDC regulators */
+       /* TWL6032 DCDC regulators */
        struct regulator_init_data              *smps3;
        struct regulator_init_data              *smps4;
        struct regulator_init_data              *vio6025;
@@ -753,7 +752,7 @@ struct twl_regulator_driver_data {
 #define TPS_SUBSET             BIT(1)  /* tps659[23]0 have fewer LDOs */
 #define TWL5031                        BIT(2)  /* twl5031 has different registers */
 #define TWL6030_CLASS          BIT(3)  /* TWL6030 class */
-#define TWL6025_SUBCLASS       BIT(4)  /* TWL6025 has changed registers */
+#define TWL6032_SUBCLASS       BIT(4)  /* TWL6032 has changed registers */
 #define TWL4030_ALLOW_UNSUPPORTED BIT(5) /* Some voltages are possible
                                          * but not officially supported.
                                          * This flag is necessary to
@@ -840,20 +839,20 @@ static inline int twl4030charger_usb_en(int enable) { return 0; }
 #define TWL6030_REG_CLK32KG    48
 
 /* LDOs on 6025 have different names */
-#define TWL6025_REG_LDO2       49
-#define TWL6025_REG_LDO4       50
-#define TWL6025_REG_LDO3       51
-#define TWL6025_REG_LDO5       52
-#define TWL6025_REG_LDO1       53
-#define TWL6025_REG_LDO7       54
-#define TWL6025_REG_LDO6       55
-#define TWL6025_REG_LDOLN      56
-#define TWL6025_REG_LDOUSB     57
+#define TWL6032_REG_LDO2       49
+#define TWL6032_REG_LDO4       50
+#define TWL6032_REG_LDO3       51
+#define TWL6032_REG_LDO5       52
+#define TWL6032_REG_LDO1       53
+#define TWL6032_REG_LDO7       54
+#define TWL6032_REG_LDO6       55
+#define TWL6032_REG_LDOLN      56
+#define TWL6032_REG_LDOUSB     57
 
 /* 6025 DCDC supplies */
-#define TWL6025_REG_SMPS3      58
-#define TWL6025_REG_SMPS4      59
-#define TWL6025_REG_VIO                60
+#define TWL6032_REG_SMPS3      58
+#define TWL6032_REG_SMPS4      59
+#define TWL6032_REG_VIO                60
 
 
 #endif /* End of __TWL4030_H */
diff --git a/include/linux/input/ti_am335x_tsc.h b/include/linux/input/ti_am335x_tsc.h
deleted file mode 100644 (file)
index 49269a2..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-#ifndef __LINUX_TI_AM335X_TSC_H
-#define __LINUX_TI_AM335X_TSC_H
-
-/**
- * struct tsc_data     Touchscreen wire configuration
- * @wires:             Wires refer to application modes
- *                     i.e. 4/5/8 wire touchscreen support
- *                     on the platform.
- * @x_plate_resistance:        X plate resistance.
- * @steps_to_configure:        The sequencer supports a total of
- *                     16 programmable steps.
- *                     A step configured to read a single
- *                     co-ordinate value, can be applied
- *                     more number of times for better results.
- */
-
-struct tsc_data {
-       int wires;
-       int x_plate_resistance;
-       int steps_to_configure;
-};
-
-#endif
index a5199f6..cdaa7f0 100644 (file)
@@ -142,6 +142,9 @@ static inline struct llist_node *llist_next(struct llist_node *node)
        return node->next;
 }
 
+extern bool llist_add_batch(struct llist_node *new_first,
+                           struct llist_node *new_last,
+                           struct llist_head *head);
 /**
  * llist_add - add a new entry
  * @new:       new entry to be added
@@ -151,18 +154,7 @@ static inline struct llist_node *llist_next(struct llist_node *node)
  */
 static inline bool llist_add(struct llist_node *new, struct llist_head *head)
 {
-       struct llist_node *entry, *old_entry;
-
-       entry = head->first;
-       for (;;) {
-               old_entry = entry;
-               new->next = entry;
-               entry = cmpxchg(&head->first, old_entry, new);
-               if (entry == old_entry)
-                       break;
-       }
-
-       return old_entry == NULL;
+       return llist_add_batch(new, new, head);
 }
 
 /**
@@ -178,9 +170,6 @@ static inline struct llist_node *llist_del_all(struct llist_head *head)
        return xchg(&head->first, NULL);
 }
 
-extern bool llist_add_batch(struct llist_node *new_first,
-                           struct llist_node *new_last,
-                           struct llist_head *head);
 extern struct llist_node *llist_del_first(struct llist_head *head);
 
 #endif /* LLIST_H */
index e94537b..97cb283 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/regmap.h>
 #include <linux/atomic.h>
 
-#define PM80X_VERSION_MASK             (0xFF)  /* 80X chip ID mask */
 enum {
        CHIP_INVALID = 0,
        CHIP_PM800,
@@ -299,8 +298,7 @@ struct pm80x_chip {
        struct regmap *regmap;
        struct regmap_irq_chip *regmap_irq_chip;
        struct regmap_irq_chip_data *irq_data;
-       unsigned char version;
-       int id;
+       int type;
        int irq;
        int irq_mode;
        unsigned long wu_flag;
@@ -309,8 +307,14 @@ struct pm80x_chip {
 
 struct pm80x_platform_data {
        struct pm80x_rtc_pdata *rtc;
-       unsigned short power_page_addr; /* power page I2C address */
-       unsigned short gpadc_page_addr; /* gpadc page I2C address */
+       /*
+        * For the regulator not defined, set regulators[not_defined] to be
+        * NULL. num_regulators are the number of regulators supposed to be
+        * initialized. If all regulators are not defined, set num_regulators
+        * to be 0.
+        */
+       struct regulator_init_data *regulators[PM800_ID_RG_MAX];
+       unsigned int num_regulators;
        int irq_mode;           /* Clear interrupt by read/write(0/1) */
        int batt_det;           /* enable/disable */
        int (*plat_config)(struct pm80x_chip *chip,
@@ -363,7 +367,6 @@ static inline int pm80x_dev_resume(struct device *dev)
 }
 #endif
 
-extern int pm80x_init(struct i2c_client *client,
-                     const struct i2c_device_id *id);
+extern int pm80x_init(struct i2c_client *client);
 extern int pm80x_deinit(void);
 #endif /* __LINUX_MFD_88PM80X_H */
index 0390d59..f4acd89 100644 (file)
@@ -291,6 +291,8 @@ enum ab8500_version {
 #define AB8540_INT_FSYNC2R             213
 #define AB8540_INT_BITCLK2F            214
 #define AB8540_INT_BITCLK2R            215
+/* ab8540_irq_regoffset[27] -> IT[Source|Latch|Mask]33 */
+#define AB8540_INT_RTC_1S              216
 
 /*
  * AB8500_AB9540_NR_IRQS is used when configuring the IRQ numbers for the
index f797bb9..5cf8b91 100644 (file)
@@ -23,6 +23,7 @@
 enum arizona_type {
        WM5102 = 1,
        WM5110 = 2,
+       WM8997 = 3,
 };
 
 #define ARIZONA_IRQ_GP1                    0
@@ -121,5 +122,6 @@ int arizona_set_irq_wake(struct arizona *arizona, int irq, int on);
 
 int wm5102_patch(struct arizona *arizona);
 int wm5110_patch(struct arizona *arizona);
+int wm8997_patch(struct arizona *arizona);
 
 #endif
index 7dd6524..13a1ee9 100644 (file)
@@ -28,6 +28,8 @@
 #include <linux/mfd/core.h>
 #include <linux/platform_data/edma.h>
 
+#include <mach/hardware.h>
+
 /*
  * Register values.
  */
@@ -111,8 +113,6 @@ struct davinci_vc {
 
        /* Memory resources */
        void __iomem *base;
-       resource_size_t pbase;
-       size_t base_size;
 
        /* MFD cells */
        struct mfd_cell cells[DAVINCI_VC_CELLS];
diff --git a/include/linux/mfd/kempld.h b/include/linux/mfd/kempld.h
new file mode 100644 (file)
index 0000000..b911ef3
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * Kontron PLD driver definitions
+ *
+ * Copyright (c) 2010-2012 Kontron Europe GmbH
+ * Author: Michael Brunner <michael.brunner@kontron.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License 2 as published
+ * by the Free Software Foundation.
+ */
+
+#ifndef _LINUX_MFD_KEMPLD_H_
+#define _LINUX_MFD_KEMPLD_H_
+
+/* kempld register definitions */
+#define KEMPLD_IOINDEX                 0xa80
+#define KEMPLD_IODATA                  0xa81
+#define KEMPLD_MUTEX_KEY               0x80
+#define KEMPLD_VERSION                 0x00
+#define KEMPLD_VERSION_LSB             0x00
+#define KEMPLD_VERSION_MSB             0x01
+#define KEMPLD_VERSION_GET_MINOR(x)    (x & 0x1f)
+#define KEMPLD_VERSION_GET_MAJOR(x)    ((x >> 5) & 0x1f)
+#define KEMPLD_VERSION_GET_NUMBER(x)   ((x >> 10) & 0xf)
+#define KEMPLD_VERSION_GET_TYPE(x)     ((x >> 14) & 0x3)
+#define KEMPLD_BUILDNR                 0x02
+#define KEMPLD_BUILDNR_LSB             0x02
+#define KEMPLD_BUILDNR_MSB             0x03
+#define KEMPLD_FEATURE                 0x04
+#define KEMPLD_FEATURE_LSB             0x04
+#define KEMPLD_FEATURE_MSB             0x05
+#define KEMPLD_FEATURE_BIT_I2C         (1 << 0)
+#define KEMPLD_FEATURE_BIT_WATCHDOG    (1 << 1)
+#define KEMPLD_FEATURE_BIT_GPIO                (1 << 2)
+#define KEMPLD_FEATURE_MASK_UART       (7 << 3)
+#define KEMPLD_FEATURE_BIT_NMI         (1 << 8)
+#define KEMPLD_FEATURE_BIT_SMI         (1 << 9)
+#define KEMPLD_FEATURE_BIT_SCI         (1 << 10)
+#define KEMPLD_SPEC                    0x06
+#define KEMPLD_SPEC_GET_MINOR(x)       (x & 0x0f)
+#define KEMPLD_SPEC_GET_MAJOR(x)       ((x >> 4) & 0x0f)
+#define KEMPLD_IRQ_GPIO                        0x35
+#define KEMPLD_IRQ_I2C                 0x36
+#define KEMPLD_CFG                     0x37
+#define KEMPLD_CFG_GPIO_I2C_MUX                (1 << 0)
+#define KEMPLD_CFG_BIOS_WP             (1 << 7)
+
+#define KEMPLD_CLK                     33333333
+
+#define        KEMPLD_TYPE_RELEASE             0x0
+#define        KEMPLD_TYPE_DEBUG               0x1
+#define        KEMPLD_TYPE_CUSTOM              0x2
+
+/**
+ * struct kempld_info - PLD device information structure
+ * @major:     PLD major revision
+ * @minor:     PLD minor revision
+ * @buildnr:   PLD build number
+ * @number:    PLD board specific index
+ * @type:      PLD type
+ * @spec_major:        PLD FW specification major revision
+ * @spec_minor:        PLD FW specification minor revision
+ */
+struct kempld_info {
+       unsigned int major;
+       unsigned int minor;
+       unsigned int buildnr;
+       unsigned int number;
+       unsigned int type;
+       unsigned int spec_major;
+       unsigned int spec_minor;
+};
+
+/**
+ * struct kempld_device_data - Internal representation of the PLD device
+ * @io_base:           Pointer to the IO memory
+ * @io_index:          Pointer to the IO index register
+ * @io_data:           Pointer to the IO data register
+ * @pld_clock:         PLD clock frequency
+ * @feature_mask:      PLD feature mask
+ * @dev:               Pointer to kernel device structure
+ * @info:              KEMPLD info structure
+ * @lock:              PLD mutex
+ */
+struct kempld_device_data {
+       void __iomem            *io_base;
+       void __iomem            *io_index;
+       void __iomem            *io_data;
+       u32                     pld_clock;
+       u32                     feature_mask;
+       struct device           *dev;
+       struct kempld_info      info;
+       struct mutex            lock;
+};
+
+/**
+ * struct kempld_platform_data - PLD hardware configuration structure
+ * @pld_clock:                 PLD clock frequency
+ * @gpio_base                  GPIO base pin number
+ * @ioresource:                        IO addresses of the PLD
+ * @get_mutex:                 PLD specific get_mutex callback
+ * @release_mutex:             PLD specific release_mutex callback
+ * @get_info:                  PLD specific get_info callback
+ * @register_cells:            PLD specific register_cells callback
+ */
+struct kempld_platform_data {
+       u32                             pld_clock;
+       int                             gpio_base;
+       struct resource                 *ioresource;
+       void (*get_hardware_mutex)      (struct kempld_device_data *);
+       void (*release_hardware_mutex)  (struct kempld_device_data *);
+       int (*get_info)                 (struct kempld_device_data *);
+       int (*register_cells)           (struct kempld_device_data *);
+};
+
+extern void kempld_get_mutex(struct kempld_device_data *pld);
+extern void kempld_release_mutex(struct kempld_device_data *pld);
+extern u8 kempld_read8(struct kempld_device_data *pld, u8 index);
+extern void kempld_write8(struct kempld_device_data *pld, u8 index, u8 data);
+extern u16 kempld_read16(struct kempld_device_data *pld, u8 index);
+extern void kempld_write16(struct kempld_device_data *pld, u8 index, u16 data);
+extern u32 kempld_read32(struct kempld_device_data *pld, u8 index);
+extern void kempld_write32(struct kempld_device_data *pld, u8 index, u32 data);
+
+#endif /* _LINUX_MFD_KEMPLD_H_ */
index effa5d3..84844e0 100644 (file)
@@ -132,9 +132,12 @@ enum {
 
 #define MAX8998_ENRAMP                  (1 << 4)
 
+struct irq_domain;
+
 /**
  * struct max8998_dev - max8998 master device for sub-drivers
  * @dev: master device of the chip (can be used to access platform data)
+ * @pdata: platform data for the driver and subdrivers
  * @i2c: i2c client private data for regulator
  * @rtc: i2c client private data for rtc
  * @iolock: mutex for serializing io access
@@ -148,12 +151,14 @@ enum {
  */
 struct max8998_dev {
        struct device *dev;
+       struct max8998_platform_data *pdata;
        struct i2c_client *i2c;
        struct i2c_client *rtc;
        struct mutex iolock;
        struct mutex irqlock;
 
-       int irq_base;
+       unsigned int irq_base;
+       struct irq_domain *irq_domain;
        int irq;
        int ono;
        u8 irq_masks_cur[MAX8998_NUM_IRQ_REGS];
index 6823548..e3956a6 100644 (file)
@@ -58,10 +58,12 @@ enum {
  * max8998_regulator_data - regulator data
  * @id: regulator id
  * @initdata: regulator init data (contraints, supplies, ...)
+ * @reg_node: DT node of regulator (unused on non-DT platforms)
  */
 struct max8998_regulator_data {
        int                             id;
        struct regulator_init_data      *initdata;
+       struct device_node              *reg_node;
 };
 
 /**
@@ -73,12 +75,8 @@ struct max8998_regulator_data {
  * @buck_voltage_lock: Do NOT change the values of the following six
  *   registers set by buck?_voltage?. The voltage of BUCK1/2 cannot
  *   be other than the preset values.
- * @buck1_voltage1: BUCK1 DVS mode 1 voltage register
- * @buck1_voltage2: BUCK1 DVS mode 2 voltage register
- * @buck1_voltage3: BUCK1 DVS mode 3 voltage register
- * @buck1_voltage4: BUCK1 DVS mode 4 voltage register
- * @buck2_voltage1: BUCK2 DVS mode 1 voltage register
- * @buck2_voltage2: BUCK2 DVS mode 2 voltage register
+ * @buck1_voltage: BUCK1 DVS mode 1 voltage registers
+ * @buck2_voltage: BUCK2 DVS mode 2 voltage registers
  * @buck1_set1: BUCK1 gpio pin 1 to set output voltage
  * @buck1_set2: BUCK1 gpio pin 2 to set output voltage
  * @buck1_default_idx: Default for BUCK1 gpio pin 1, 2
@@ -100,15 +98,11 @@ struct max8998_regulator_data {
 struct max8998_platform_data {
        struct max8998_regulator_data   *regulators;
        int                             num_regulators;
-       int                             irq_base;
+       unsigned int                    irq_base;
        int                             ono;
        bool                            buck_voltage_lock;
-       int                             buck1_voltage1;
-       int                             buck1_voltage2;
-       int                             buck1_voltage3;
-       int                             buck1_voltage4;
-       int                             buck2_voltage1;
-       int                             buck2_voltage2;
+       int                             buck1_voltage[4];
+       int                             buck2_voltage[2];
        int                             buck1_set1;
        int                             buck1_set2;
        int                             buck1_default_idx;
index 9b81b2b..1a8dd7a 100644 (file)
                        ((a) == PALMAS_CHIP_ID))
 #define is_palmas_charger(a) ((a) == PALMAS_CHIP_CHARGER_ID)
 
+/**
+ * Palmas PMIC feature types
+ *
+ * PALMAS_PMIC_FEATURE_SMPS10_BOOST - used when the PMIC provides SMPS10_BOOST
+ *     regulator.
+ *
+ * PALMAS_PMIC_HAS(b, f) - macro to check if a bandgap device is capable of a
+ *     specific feature (above) or not. Return non-zero, if yes.
+ */
+#define PALMAS_PMIC_FEATURE_SMPS10_BOOST       BIT(0)
+#define PALMAS_PMIC_HAS(b, f)                  \
+                       ((b)->features & PALMAS_PMIC_FEATURE_ ## f)
+
 struct palmas_pmic;
 struct palmas_gpadc;
 struct palmas_resource;
@@ -54,6 +67,7 @@ struct palmas {
        /* Stored chip id */
        int id;
 
+       unsigned int features;
        /* IRQ Data */
        int irq;
        u32 irq_mask;
index 86bc635..7a9f708 100644 (file)
 
 #define CARD_PWR_CTL                   0xFD50
 #define CARD_CLK_SWITCH                        0xFD51
+#define RTL8411B_PACKAGE_MODE          0xFD51
 #define CARD_SHARE_MODE                        0xFD52
 #define CARD_DRIVE_SEL                 0xFD53
 #define CARD_STOP                      0xFD54
index f0f4de3..378ae8a 100644 (file)
@@ -14,8 +14,6 @@
 #ifndef __LINUX_MFD_SEC_CORE_H
 #define __LINUX_MFD_SEC_CORE_H
 
-#define NUM_IRQ_REGS   4
-
 enum sec_device_type {
        S5M8751X,
        S5M8763X,
@@ -44,8 +42,6 @@ struct sec_pmic_dev {
        struct regmap *regmap;
        struct i2c_client *i2c;
        struct i2c_client *rtc;
-       struct mutex iolock;
-       struct mutex irqlock;
 
        int device_type;
        int irq_base;
@@ -53,8 +49,6 @@ struct sec_pmic_dev {
        struct regmap_irq_chip_data *irq_data;
 
        int ono;
-       u8 irq_masks_cur[NUM_IRQ_REGS];
-       u8 irq_masks_cache[NUM_IRQ_REGS];
        int type;
        bool wakeup;
 };
index ad2252f..4e94dc6 100644 (file)
@@ -189,6 +189,7 @@ enum s2mps11_regulators {
 #define S2MPS11_ENABLE_SHIFT   0x06
 #define S2MPS11_LDO_N_VOLTAGES (S2MPS11_LDO_VSEL_MASK + 1)
 #define S2MPS11_BUCK_N_VOLTAGES (S2MPS11_BUCK_VSEL_MASK + 1)
+#define S2MPS11_RAMP_DELAY     25000           /* uV/us */
 
 #define S2MPS11_PMIC_EN_SHIFT  6
 #define S2MPS11_REGULATOR_MAX (S2MPS11_REG_MAX - 3)
index c79ad5d..8d73fe2 100644 (file)
@@ -30,8 +30,8 @@
 #define REG_IDLECONFIG         0x058
 #define REG_CHARGECONFIG       0x05C
 #define REG_CHARGEDELAY                0x060
-#define REG_STEPCONFIG(n)      (0x64 + ((n - 1) * 8))
-#define REG_STEPDELAY(n)       (0x68 + ((n - 1) * 8))
+#define REG_STEPCONFIG(n)      (0x64 + ((n) * 8))
+#define REG_STEPDELAY(n)       (0x68 + ((n) * 8))
 #define REG_FIFO0CNT           0xE4
 #define REG_FIFO0THR           0xE8
 #define REG_FIFO1CNT           0xF0
@@ -46,8 +46,6 @@
 /* Step Enable */
 #define STEPENB_MASK           (0x1FFFF << 0)
 #define STEPENB(val)           ((val) << 0)
-#define STPENB_STEPENB         STEPENB(0x1FFFF)
-#define STPENB_STEPENB_TC      STEPENB(0x1FFF)
 
 /* IRQ enable */
 #define IRQENB_HW_PEN          BIT(0)
@@ -73,8 +71,6 @@
 #define STEPCONFIG_INM_ADCREFM STEPCONFIG_INM(8)
 #define STEPCONFIG_INP_MASK    (0xF << 19)
 #define STEPCONFIG_INP(val)    ((val) << 19)
-#define STEPCONFIG_INP_AN2     STEPCONFIG_INP(2)
-#define STEPCONFIG_INP_AN3     STEPCONFIG_INP(3)
 #define STEPCONFIG_INP_AN4     STEPCONFIG_INP(4)
 #define STEPCONFIG_INP_ADCREFM STEPCONFIG_INP(8)
 #define STEPCONFIG_FIFO1       BIT(26)
@@ -96,7 +92,6 @@
 #define STEPCHARGE_INM_AN1     STEPCHARGE_INM(1)
 #define STEPCHARGE_INP_MASK    (0xF << 19)
 #define STEPCHARGE_INP(val)    ((val) << 19)
-#define STEPCHARGE_INP_AN1     STEPCHARGE_INP(1)
 #define STEPCHARGE_RFM_MASK    (3 << 23)
 #define STEPCHARGE_RFM(val)    ((val) << 23)
 #define STEPCHARGE_RFM_XNUR    STEPCHARGE_RFM(1)
 
 #define TSCADC_CELLS           2
 
-enum tscadc_cells {
-       TSC_CELL,
-       ADC_CELL,
-};
-
-struct mfd_tscadc_board {
-       struct tsc_data *tsc_init;
-       struct adc_data *adc_init;
-};
-
 struct ti_tscadc_dev {
        struct device *dev;
        struct regmap *regmap_tscadc;
        void __iomem *tscadc_base;
        int irq;
+       int used_cells; /* 1-2 */
+       int tsc_cell;   /* -1 if not used */
+       int adc_cell;   /* -1 if not used */
        struct mfd_cell cells[TSCADC_CELLS];
+       u32 reg_se_cache;
+       spinlock_t reg_lock;
 
        /* tsc device */
        struct titsc *tsc;
@@ -149,4 +139,15 @@ struct ti_tscadc_dev {
        struct adc_device *adc;
 };
 
+static inline struct ti_tscadc_dev *ti_tscadc_dev_get(struct platform_device *p)
+{
+       struct ti_tscadc_dev **tscadc_dev = p->dev.platform_data;
+
+       return *tscadc_dev;
+}
+
+void am335x_tsc_se_update(struct ti_tscadc_dev *tsadc);
+void am335x_tsc_se_set(struct ti_tscadc_dev *tsadc, u32 val);
+void am335x_tsc_se_clr(struct ti_tscadc_dev *tsadc, u32 val);
+
 #endif
index 99bf3e6..ce35113 100644 (file)
@@ -81,10 +81,15 @@ int tmio_core_mmc_resume(void __iomem *cnf, int shift, unsigned long base);
 void tmio_core_mmc_pwr(void __iomem *cnf, int shift, int state);
 void tmio_core_mmc_clk_div(void __iomem *cnf, int shift, int state);
 
+struct dma_chan;
+
 struct tmio_mmc_dma {
        void *chan_priv_tx;
        void *chan_priv_rx;
+       int slave_id_tx;
+       int slave_id_rx;
        int alignment_shift;
+       bool (*filter)(struct dma_chan *chan, void *arg);
 };
 
 struct tmio_mmc_host;
index ae5c249..40854ac 100644 (file)
@@ -29,6 +29,7 @@ enum wm8994_type {
 
 struct regulator_dev;
 struct regulator_bulk_data;
+struct irq_domain;
 
 #define WM8994_NUM_GPIO_REGS 11
 #define WM8994_NUM_LDO_REGS   2
@@ -73,6 +74,7 @@ struct wm8994 {
 
        int irq;
        struct regmap_irq_chip_data *irq_data;
+       struct irq_domain *edge_irq;
 
        /* Used over suspend/resume */
        bool suspended;
index b5046f6..90c6052 100644 (file)
@@ -228,6 +228,11 @@ struct wm8994_pdata {
         * lines is mastered.
         */
        int max_channels_clocked[WM8994_NUM_AIF];
+
+       /**
+        * GPIO for the IRQ pin if host only supports edge triggering
+        */
+       int irq_gpio;
 };
 
 #endif
diff --git a/include/linux/mlx5/cmd.h b/include/linux/mlx5/cmd.h
new file mode 100644 (file)
index 0000000..2826a4b
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2013, Mellanox Technologies inc.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef MLX5_CMD_H
+#define MLX5_CMD_H
+
+#include <linux/types.h>
+
+struct manage_pages_layout {
+       u64     ptr;
+       u32     reserved;
+       u16     num_entries;
+       u16     func_id;
+};
+
+
+struct mlx5_cmd_alloc_uar_imm_out {
+       u32     rsvd[3];
+       u32     uarn;
+};
+
+#endif /* MLX5_CMD_H */
diff --git a/include/linux/mlx5/cq.h b/include/linux/mlx5/cq.h
new file mode 100644 (file)
index 0000000..3db67f7
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2013, Mellanox Technologies inc.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef MLX5_CORE_CQ_H
+#define MLX5_CORE_CQ_H
+
+#include <rdma/ib_verbs.h>
+#include <linux/mlx5/driver.h>
+
+
+struct mlx5_core_cq {
+       u32                     cqn;
+       int                     cqe_sz;
+       __be32                 *set_ci_db;
+       __be32                 *arm_db;
+       atomic_t                refcount;
+       struct completion       free;
+       unsigned                vector;
+       int                     irqn;
+       void (*comp)            (struct mlx5_core_cq *);
+       void (*event)           (struct mlx5_core_cq *, enum mlx5_event);
+       struct mlx5_uar        *uar;
+       u32                     cons_index;
+       unsigned                arm_sn;
+       struct mlx5_rsc_debug   *dbg;
+       int                     pid;
+};
+
+
+enum {
+       MLX5_CQE_SYNDROME_LOCAL_LENGTH_ERR              = 0x01,
+       MLX5_CQE_SYNDROME_LOCAL_QP_OP_ERR               = 0x02,
+       MLX5_CQE_SYNDROME_LOCAL_PROT_ERR                = 0x04,
+       MLX5_CQE_SYNDROME_WR_FLUSH_ERR                  = 0x05,
+       MLX5_CQE_SYNDROME_MW_BIND_ERR                   = 0x06,
+       MLX5_CQE_SYNDROME_BAD_RESP_ERR                  = 0x10,
+       MLX5_CQE_SYNDROME_LOCAL_ACCESS_ERR              = 0x11,
+       MLX5_CQE_SYNDROME_REMOTE_INVAL_REQ_ERR          = 0x12,
+       MLX5_CQE_SYNDROME_REMOTE_ACCESS_ERR             = 0x13,
+       MLX5_CQE_SYNDROME_REMOTE_OP_ERR                 = 0x14,
+       MLX5_CQE_SYNDROME_TRANSPORT_RETRY_EXC_ERR       = 0x15,
+       MLX5_CQE_SYNDROME_RNR_RETRY_EXC_ERR             = 0x16,
+       MLX5_CQE_SYNDROME_REMOTE_ABORTED_ERR            = 0x22,
+};
+
+enum {
+       MLX5_CQE_OWNER_MASK     = 1,
+       MLX5_CQE_REQ            = 0,
+       MLX5_CQE_RESP_WR_IMM    = 1,
+       MLX5_CQE_RESP_SEND      = 2,
+       MLX5_CQE_RESP_SEND_IMM  = 3,
+       MLX5_CQE_RESP_SEND_INV  = 4,
+       MLX5_CQE_RESIZE_CQ      = 0xff, /* TBD */
+       MLX5_CQE_REQ_ERR        = 13,
+       MLX5_CQE_RESP_ERR       = 14,
+};
+
+enum {
+       MLX5_CQ_MODIFY_RESEIZE = 0,
+       MLX5_CQ_MODIFY_MODER = 1,
+       MLX5_CQ_MODIFY_MAPPING = 2,
+};
+
+struct mlx5_cq_modify_params {
+       int     type;
+       union {
+               struct {
+                       u32     page_offset;
+                       u8      log_cq_size;
+               } resize;
+
+               struct {
+               } moder;
+
+               struct {
+               } mapping;
+       } params;
+};
+
+enum {
+       CQE_SIZE_64 = 0,
+       CQE_SIZE_128 = 1,
+};
+
+static inline int cqe_sz_to_mlx_sz(u8 size)
+{
+       return size == 64 ? CQE_SIZE_64 : CQE_SIZE_128;
+}
+
+static inline void mlx5_cq_set_ci(struct mlx5_core_cq *cq)
+{
+       *cq->set_ci_db = cpu_to_be32(cq->cons_index & 0xffffff);
+}
+
+enum {
+       MLX5_CQ_DB_REQ_NOT_SOL          = 1 << 24,
+       MLX5_CQ_DB_REQ_NOT              = 0 << 24
+};
+
+static inline void mlx5_cq_arm(struct mlx5_core_cq *cq, u32 cmd,
+                              void __iomem *uar_page,
+                              spinlock_t *doorbell_lock)
+{
+       __be32 doorbell[2];
+       u32 sn;
+       u32 ci;
+
+       sn = cq->arm_sn & 3;
+       ci = cq->cons_index & 0xffffff;
+
+       *cq->arm_db = cpu_to_be32(sn << 28 | cmd | ci);
+
+       /* Make sure that the doorbell record in host memory is
+        * written before ringing the doorbell via PCI MMIO.
+        */
+       wmb();
+
+       doorbell[0] = cpu_to_be32(sn << 28 | cmd | ci);
+       doorbell[1] = cpu_to_be32(cq->cqn);
+
+       mlx5_write64(doorbell, uar_page + MLX5_CQ_DOORBELL, doorbell_lock);
+}
+
+int mlx5_init_cq_table(struct mlx5_core_dev *dev);
+void mlx5_cleanup_cq_table(struct mlx5_core_dev *dev);
+int mlx5_core_create_cq(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq,
+                       struct mlx5_create_cq_mbox_in *in, int inlen);
+int mlx5_core_destroy_cq(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq);
+int mlx5_core_query_cq(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq,
+                      struct mlx5_query_cq_mbox_out *out);
+int mlx5_core_modify_cq(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq,
+                       int type, struct mlx5_cq_modify_params *params);
+int mlx5_debug_cq_add(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq);
+void mlx5_debug_cq_remove(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq);
+
+#endif /* MLX5_CORE_CQ_H */
diff --git a/include/linux/mlx5/device.h b/include/linux/mlx5/device.h
new file mode 100644 (file)
index 0000000..8de8d8f
--- /dev/null
@@ -0,0 +1,893 @@
+/*
+ * Copyright (c) 2013, Mellanox Technologies inc.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef MLX5_DEVICE_H
+#define MLX5_DEVICE_H
+
+#include <linux/types.h>
+#include <rdma/ib_verbs.h>
+
+#if defined(__LITTLE_ENDIAN)
+#define MLX5_SET_HOST_ENDIANNESS       0
+#elif defined(__BIG_ENDIAN)
+#define MLX5_SET_HOST_ENDIANNESS       0x80
+#else
+#error Host endianness not defined
+#endif
+
+enum {
+       MLX5_MAX_COMMANDS               = 32,
+       MLX5_CMD_DATA_BLOCK_SIZE        = 512,
+       MLX5_PCI_CMD_XPORT              = 7,
+};
+
+enum {
+       MLX5_EXTENDED_UD_AV             = 0x80000000,
+};
+
+enum {
+       MLX5_CQ_STATE_ARMED             = 9,
+       MLX5_CQ_STATE_ALWAYS_ARMED      = 0xb,
+       MLX5_CQ_STATE_FIRED             = 0xa,
+};
+
+enum {
+       MLX5_STAT_RATE_OFFSET   = 5,
+};
+
+enum {
+       MLX5_INLINE_SEG = 0x80000000,
+};
+
+enum {
+       MLX5_PERM_LOCAL_READ    = 1 << 2,
+       MLX5_PERM_LOCAL_WRITE   = 1 << 3,
+       MLX5_PERM_REMOTE_READ   = 1 << 4,
+       MLX5_PERM_REMOTE_WRITE  = 1 << 5,
+       MLX5_PERM_ATOMIC        = 1 << 6,
+       MLX5_PERM_UMR_EN        = 1 << 7,
+};
+
+enum {
+       MLX5_PCIE_CTRL_SMALL_FENCE      = 1 << 0,
+       MLX5_PCIE_CTRL_RELAXED_ORDERING = 1 << 2,
+       MLX5_PCIE_CTRL_NO_SNOOP         = 1 << 3,
+       MLX5_PCIE_CTRL_TLP_PROCE_EN     = 1 << 6,
+       MLX5_PCIE_CTRL_TPH_MASK         = 3 << 4,
+};
+
+enum {
+       MLX5_ACCESS_MODE_PA     = 0,
+       MLX5_ACCESS_MODE_MTT    = 1,
+       MLX5_ACCESS_MODE_KLM    = 2
+};
+
+enum {
+       MLX5_MKEY_REMOTE_INVAL  = 1 << 24,
+       MLX5_MKEY_FLAG_SYNC_UMR = 1 << 29,
+       MLX5_MKEY_BSF_EN        = 1 << 30,
+       MLX5_MKEY_LEN64         = 1 << 31,
+};
+
+enum {
+       MLX5_EN_RD      = (u64)1,
+       MLX5_EN_WR      = (u64)2
+};
+
+enum {
+       MLX5_BF_REGS_PER_PAGE   = 4,
+       MLX5_MAX_UAR_PAGES      = 1 << 8,
+       MLX5_MAX_UUARS          = MLX5_MAX_UAR_PAGES * MLX5_BF_REGS_PER_PAGE,
+};
+
+enum {
+       MLX5_MKEY_MASK_LEN              = 1ull << 0,
+       MLX5_MKEY_MASK_PAGE_SIZE        = 1ull << 1,
+       MLX5_MKEY_MASK_START_ADDR       = 1ull << 6,
+       MLX5_MKEY_MASK_PD               = 1ull << 7,
+       MLX5_MKEY_MASK_EN_RINVAL        = 1ull << 8,
+       MLX5_MKEY_MASK_BSF_EN           = 1ull << 12,
+       MLX5_MKEY_MASK_KEY              = 1ull << 13,
+       MLX5_MKEY_MASK_QPN              = 1ull << 14,
+       MLX5_MKEY_MASK_LR               = 1ull << 17,
+       MLX5_MKEY_MASK_LW               = 1ull << 18,
+       MLX5_MKEY_MASK_RR               = 1ull << 19,
+       MLX5_MKEY_MASK_RW               = 1ull << 20,
+       MLX5_MKEY_MASK_A                = 1ull << 21,
+       MLX5_MKEY_MASK_SMALL_FENCE      = 1ull << 23,
+       MLX5_MKEY_MASK_FREE             = 1ull << 29,
+};
+
+enum mlx5_event {
+       MLX5_EVENT_TYPE_COMP               = 0x0,
+
+       MLX5_EVENT_TYPE_PATH_MIG           = 0x01,
+       MLX5_EVENT_TYPE_COMM_EST           = 0x02,
+       MLX5_EVENT_TYPE_SQ_DRAINED         = 0x03,
+       MLX5_EVENT_TYPE_SRQ_LAST_WQE       = 0x13,
+       MLX5_EVENT_TYPE_SRQ_RQ_LIMIT       = 0x14,
+
+       MLX5_EVENT_TYPE_CQ_ERROR           = 0x04,
+       MLX5_EVENT_TYPE_WQ_CATAS_ERROR     = 0x05,
+       MLX5_EVENT_TYPE_PATH_MIG_FAILED    = 0x07,
+       MLX5_EVENT_TYPE_WQ_INVAL_REQ_ERROR = 0x10,
+       MLX5_EVENT_TYPE_WQ_ACCESS_ERROR    = 0x11,
+       MLX5_EVENT_TYPE_SRQ_CATAS_ERROR    = 0x12,
+
+       MLX5_EVENT_TYPE_INTERNAL_ERROR     = 0x08,
+       MLX5_EVENT_TYPE_PORT_CHANGE        = 0x09,
+       MLX5_EVENT_TYPE_GPIO_EVENT         = 0x15,
+       MLX5_EVENT_TYPE_REMOTE_CONFIG      = 0x19,
+
+       MLX5_EVENT_TYPE_DB_BF_CONGESTION   = 0x1a,
+       MLX5_EVENT_TYPE_STALL_EVENT        = 0x1b,
+
+       MLX5_EVENT_TYPE_CMD                = 0x0a,
+       MLX5_EVENT_TYPE_PAGE_REQUEST       = 0xb,
+};
+
+enum {
+       MLX5_PORT_CHANGE_SUBTYPE_DOWN           = 1,
+       MLX5_PORT_CHANGE_SUBTYPE_ACTIVE         = 4,
+       MLX5_PORT_CHANGE_SUBTYPE_INITIALIZED    = 5,
+       MLX5_PORT_CHANGE_SUBTYPE_LID            = 6,
+       MLX5_PORT_CHANGE_SUBTYPE_PKEY           = 7,
+       MLX5_PORT_CHANGE_SUBTYPE_GUID           = 8,
+       MLX5_PORT_CHANGE_SUBTYPE_CLIENT_REREG   = 9,
+};
+
+enum {
+       MLX5_DEV_CAP_FLAG_RC            = 1LL <<  0,
+       MLX5_DEV_CAP_FLAG_UC            = 1LL <<  1,
+       MLX5_DEV_CAP_FLAG_UD            = 1LL <<  2,
+       MLX5_DEV_CAP_FLAG_XRC           = 1LL <<  3,
+       MLX5_DEV_CAP_FLAG_SRQ           = 1LL <<  6,
+       MLX5_DEV_CAP_FLAG_BAD_PKEY_CNTR = 1LL <<  8,
+       MLX5_DEV_CAP_FLAG_BAD_QKEY_CNTR = 1LL <<  9,
+       MLX5_DEV_CAP_FLAG_APM           = 1LL << 17,
+       MLX5_DEV_CAP_FLAG_ATOMIC        = 1LL << 18,
+       MLX5_DEV_CAP_FLAG_ON_DMND_PG    = 1LL << 24,
+       MLX5_DEV_CAP_FLAG_RESIZE_SRQ    = 1LL << 32,
+       MLX5_DEV_CAP_FLAG_REMOTE_FENCE  = 1LL << 38,
+       MLX5_DEV_CAP_FLAG_TLP_HINTS     = 1LL << 39,
+       MLX5_DEV_CAP_FLAG_SIG_HAND_OVER = 1LL << 40,
+       MLX5_DEV_CAP_FLAG_DCT           = 1LL << 41,
+       MLX5_DEV_CAP_FLAG_CMDIF_CSUM    = 1LL << 46,
+};
+
+enum {
+       MLX5_OPCODE_NOP                 = 0x00,
+       MLX5_OPCODE_SEND_INVAL          = 0x01,
+       MLX5_OPCODE_RDMA_WRITE          = 0x08,
+       MLX5_OPCODE_RDMA_WRITE_IMM      = 0x09,
+       MLX5_OPCODE_SEND                = 0x0a,
+       MLX5_OPCODE_SEND_IMM            = 0x0b,
+       MLX5_OPCODE_RDMA_READ           = 0x10,
+       MLX5_OPCODE_ATOMIC_CS           = 0x11,
+       MLX5_OPCODE_ATOMIC_FA           = 0x12,
+       MLX5_OPCODE_ATOMIC_MASKED_CS    = 0x14,
+       MLX5_OPCODE_ATOMIC_MASKED_FA    = 0x15,
+       MLX5_OPCODE_BIND_MW             = 0x18,
+       MLX5_OPCODE_CONFIG_CMD          = 0x1f,
+
+       MLX5_RECV_OPCODE_RDMA_WRITE_IMM = 0x00,
+       MLX5_RECV_OPCODE_SEND           = 0x01,
+       MLX5_RECV_OPCODE_SEND_IMM       = 0x02,
+       MLX5_RECV_OPCODE_SEND_INVAL     = 0x03,
+
+       MLX5_CQE_OPCODE_ERROR           = 0x1e,
+       MLX5_CQE_OPCODE_RESIZE          = 0x16,
+
+       MLX5_OPCODE_SET_PSV             = 0x20,
+       MLX5_OPCODE_GET_PSV             = 0x21,
+       MLX5_OPCODE_CHECK_PSV           = 0x22,
+       MLX5_OPCODE_RGET_PSV            = 0x26,
+       MLX5_OPCODE_RCHECK_PSV          = 0x27,
+
+       MLX5_OPCODE_UMR                 = 0x25,
+
+};
+
+enum {
+       MLX5_SET_PORT_RESET_QKEY        = 0,
+       MLX5_SET_PORT_GUID0             = 16,
+       MLX5_SET_PORT_NODE_GUID         = 17,
+       MLX5_SET_PORT_SYS_GUID          = 18,
+       MLX5_SET_PORT_GID_TABLE         = 19,
+       MLX5_SET_PORT_PKEY_TABLE        = 20,
+};
+
+enum {
+       MLX5_MAX_PAGE_SHIFT             = 31
+};
+
+struct mlx5_inbox_hdr {
+       __be16          opcode;
+       u8              rsvd[4];
+       __be16          opmod;
+};
+
+struct mlx5_outbox_hdr {
+       u8              status;
+       u8              rsvd[3];
+       __be32          syndrome;
+};
+
+struct mlx5_cmd_query_adapter_mbox_in {
+       struct mlx5_inbox_hdr   hdr;
+       u8                      rsvd[8];
+};
+
+struct mlx5_cmd_query_adapter_mbox_out {
+       struct mlx5_outbox_hdr  hdr;
+       u8                      rsvd0[24];
+       u8                      intapin;
+       u8                      rsvd1[13];
+       __be16                  vsd_vendor_id;
+       u8                      vsd[208];
+       u8                      vsd_psid[16];
+};
+
+struct mlx5_hca_cap {
+       u8      rsvd1[16];
+       u8      log_max_srq_sz;
+       u8      log_max_qp_sz;
+       u8      rsvd2;
+       u8      log_max_qp;
+       u8      log_max_strq_sz;
+       u8      log_max_srqs;
+       u8      rsvd4[2];
+       u8      rsvd5;
+       u8      log_max_cq_sz;
+       u8      rsvd6;
+       u8      log_max_cq;
+       u8      log_max_eq_sz;
+       u8      log_max_mkey;
+       u8      rsvd7;
+       u8      log_max_eq;
+       u8      max_indirection;
+       u8      log_max_mrw_sz;
+       u8      log_max_bsf_list_sz;
+       u8      log_max_klm_list_sz;
+       u8      rsvd_8_0;
+       u8      log_max_ra_req_dc;
+       u8      rsvd_8_1;
+       u8      log_max_ra_res_dc;
+       u8      rsvd9;
+       u8      log_max_ra_req_qp;
+       u8      rsvd10;
+       u8      log_max_ra_res_qp;
+       u8      rsvd11[4];
+       __be16  max_qp_count;
+       __be16  rsvd12;
+       u8      rsvd13;
+       u8      local_ca_ack_delay;
+       u8      rsvd14;
+       u8      num_ports;
+       u8      log_max_msg;
+       u8      rsvd15[3];
+       __be16  stat_rate_support;
+       u8      rsvd16[2];
+       __be64  flags;
+       u8      rsvd17;
+       u8      uar_sz;
+       u8      rsvd18;
+       u8      log_pg_sz;
+       __be16  bf_log_bf_reg_size;
+       u8      rsvd19[4];
+       __be16  max_desc_sz_sq;
+       u8      rsvd20[2];
+       __be16  max_desc_sz_rq;
+       u8      rsvd21[2];
+       __be16  max_desc_sz_sq_dc;
+       u8      rsvd22[4];
+       __be16  max_qp_mcg;
+       u8      rsvd23;
+       u8      log_max_mcg;
+       u8      rsvd24;
+       u8      log_max_pd;
+       u8      rsvd25;
+       u8      log_max_xrcd;
+       u8      rsvd26[42];
+       __be16  log_uar_page_sz;
+       u8      rsvd27[28];
+       u8      log_msx_atomic_size_qp;
+       u8      rsvd28[2];
+       u8      log_msx_atomic_size_dc;
+       u8      rsvd29[76];
+};
+
+
+struct mlx5_cmd_query_hca_cap_mbox_in {
+       struct mlx5_inbox_hdr   hdr;
+       u8                      rsvd[8];
+};
+
+
+struct mlx5_cmd_query_hca_cap_mbox_out {
+       struct mlx5_outbox_hdr  hdr;
+       u8                      rsvd0[8];
+       struct mlx5_hca_cap     hca_cap;
+};
+
+
+struct mlx5_cmd_set_hca_cap_mbox_in {
+       struct mlx5_inbox_hdr   hdr;
+       u8                      rsvd[8];
+       struct mlx5_hca_cap     hca_cap;
+};
+
+
+struct mlx5_cmd_set_hca_cap_mbox_out {
+       struct mlx5_outbox_hdr  hdr;
+       u8                      rsvd0[8];
+};
+
+
+struct mlx5_cmd_init_hca_mbox_in {
+       struct mlx5_inbox_hdr   hdr;
+       u8                      rsvd0[2];
+       __be16                  profile;
+       u8                      rsvd1[4];
+};
+
+struct mlx5_cmd_init_hca_mbox_out {
+       struct mlx5_outbox_hdr  hdr;
+       u8                      rsvd[8];
+};
+
+struct mlx5_cmd_teardown_hca_mbox_in {
+       struct mlx5_inbox_hdr   hdr;
+       u8                      rsvd0[2];
+       __be16                  profile;
+       u8                      rsvd1[4];
+};
+
+struct mlx5_cmd_teardown_hca_mbox_out {
+       struct mlx5_outbox_hdr  hdr;
+       u8                      rsvd[8];
+};
+
+struct mlx5_cmd_layout {
+       u8              type;
+       u8              rsvd0[3];
+       __be32          inlen;
+       __be64          in_ptr;
+       __be32          in[4];
+       __be32          out[4];
+       __be64          out_ptr;
+       __be32          outlen;
+       u8              token;
+       u8              sig;
+       u8              rsvd1;
+       u8              status_own;
+};
+
+
+struct health_buffer {
+       __be32          assert_var[5];
+       __be32          rsvd0[3];
+       __be32          assert_exit_ptr;
+       __be32          assert_callra;
+       __be32          rsvd1[2];
+       __be32          fw_ver;
+       __be32          hw_id;
+       __be32          rsvd2;
+       u8              irisc_index;
+       u8              synd;
+       __be16          ext_sync;
+};
+
+struct mlx5_init_seg {
+       __be32                  fw_rev;
+       __be32                  cmdif_rev_fw_sub;
+       __be32                  rsvd0[2];
+       __be32                  cmdq_addr_h;
+       __be32                  cmdq_addr_l_sz;
+       __be32                  cmd_dbell;
+       __be32                  rsvd1[121];
+       struct health_buffer    health;
+       __be32                  rsvd2[884];
+       __be32                  health_counter;
+       __be32                  rsvd3[1023];
+       __be64                  ieee1588_clk;
+       __be32                  ieee1588_clk_type;
+       __be32                  clr_intx;
+};
+
+struct mlx5_eqe_comp {
+       __be32  reserved[6];
+       __be32  cqn;
+};
+
+struct mlx5_eqe_qp_srq {
+       __be32  reserved[6];
+       __be32  qp_srq_n;
+};
+
+struct mlx5_eqe_cq_err {
+       __be32  cqn;
+       u8      reserved1[7];
+       u8      syndrome;
+};
+
+struct mlx5_eqe_dropped_packet {
+};
+
+struct mlx5_eqe_port_state {
+       u8      reserved0[8];
+       u8      port;
+};
+
+struct mlx5_eqe_gpio {
+       __be32  reserved0[2];
+       __be64  gpio_event;
+};
+
+struct mlx5_eqe_congestion {
+       u8      type;
+       u8      rsvd0;
+       u8      congestion_level;
+};
+
+struct mlx5_eqe_stall_vl {
+       u8      rsvd0[3];
+       u8      port_vl;
+};
+
+struct mlx5_eqe_cmd {
+       __be32  vector;
+       __be32  rsvd[6];
+};
+
+struct mlx5_eqe_page_req {
+       u8              rsvd0[2];
+       __be16          func_id;
+       u8              rsvd1[2];
+       __be16          num_pages;
+       __be32          rsvd2[5];
+};
+
+union ev_data {
+       __be32                          raw[7];
+       struct mlx5_eqe_cmd             cmd;
+       struct mlx5_eqe_comp            comp;
+       struct mlx5_eqe_qp_srq          qp_srq;
+       struct mlx5_eqe_cq_err          cq_err;
+       struct mlx5_eqe_dropped_packet  dp;
+       struct mlx5_eqe_port_state      port;
+       struct mlx5_eqe_gpio            gpio;
+       struct mlx5_eqe_congestion      cong;
+       struct mlx5_eqe_stall_vl        stall_vl;
+       struct mlx5_eqe_page_req        req_pages;
+} __packed;
+
+struct mlx5_eqe {
+       u8              rsvd0;
+       u8              type;
+       u8              rsvd1;
+       u8              sub_type;
+       __be32          rsvd2[7];
+       union ev_data   data;
+       __be16          rsvd3;
+       u8              signature;
+       u8              owner;
+} __packed;
+
+struct mlx5_cmd_prot_block {
+       u8              data[MLX5_CMD_DATA_BLOCK_SIZE];
+       u8              rsvd0[48];
+       __be64          next;
+       __be32          block_num;
+       u8              rsvd1;
+       u8              token;
+       u8              ctrl_sig;
+       u8              sig;
+};
+
+struct mlx5_err_cqe {
+       u8      rsvd0[32];
+       __be32  srqn;
+       u8      rsvd1[18];
+       u8      vendor_err_synd;
+       u8      syndrome;
+       __be32  s_wqe_opcode_qpn;
+       __be16  wqe_counter;
+       u8      signature;
+       u8      op_own;
+};
+
+struct mlx5_cqe64 {
+       u8              rsvd0[17];
+       u8              ml_path;
+       u8              rsvd20[4];
+       __be16          slid;
+       __be32          flags_rqpn;
+       u8              rsvd28[4];
+       __be32          srqn;
+       __be32          imm_inval_pkey;
+       u8              rsvd40[4];
+       __be32          byte_cnt;
+       __be64          timestamp;
+       __be32          sop_drop_qpn;
+       __be16          wqe_counter;
+       u8              signature;
+       u8              op_own;
+};
+
+struct mlx5_wqe_srq_next_seg {
+       u8                      rsvd0[2];
+       __be16                  next_wqe_index;
+       u8                      signature;
+       u8                      rsvd1[11];
+};
+
+union mlx5_ext_cqe {
+       struct ib_grh   grh;
+       u8              inl[64];
+};
+
+struct mlx5_cqe128 {
+       union mlx5_ext_cqe      inl_grh;
+       struct mlx5_cqe64       cqe64;
+};
+
+struct mlx5_srq_ctx {
+       u8                      state_log_sz;
+       u8                      rsvd0[3];
+       __be32                  flags_xrcd;
+       __be32                  pgoff_cqn;
+       u8                      rsvd1[4];
+       u8                      log_pg_sz;
+       u8                      rsvd2[7];
+       __be32                  pd;
+       __be16                  lwm;
+       __be16                  wqe_cnt;
+       u8                      rsvd3[8];
+       __be64                  db_record;
+};
+
+struct mlx5_create_srq_mbox_in {
+       struct mlx5_inbox_hdr   hdr;
+       __be32                  input_srqn;
+       u8                      rsvd0[4];
+       struct mlx5_srq_ctx     ctx;
+       u8                      rsvd1[208];
+       __be64                  pas[0];
+};
+
+struct mlx5_create_srq_mbox_out {
+       struct mlx5_outbox_hdr  hdr;
+       __be32                  srqn;
+       u8                      rsvd[4];
+};
+
+struct mlx5_destroy_srq_mbox_in {
+       struct mlx5_inbox_hdr   hdr;
+       __be32                  srqn;
+       u8                      rsvd[4];
+};
+
+struct mlx5_destroy_srq_mbox_out {
+       struct mlx5_outbox_hdr  hdr;
+       u8                      rsvd[8];
+};
+
+struct mlx5_query_srq_mbox_in {
+       struct mlx5_inbox_hdr   hdr;
+       __be32                  srqn;
+       u8                      rsvd0[4];
+};
+
+struct mlx5_query_srq_mbox_out {
+       struct mlx5_outbox_hdr  hdr;
+       u8                      rsvd0[8];
+       struct mlx5_srq_ctx     ctx;
+       u8                      rsvd1[32];
+       __be64                  pas[0];
+};
+
+struct mlx5_arm_srq_mbox_in {
+       struct mlx5_inbox_hdr   hdr;
+       __be32                  srqn;
+       __be16                  rsvd;
+       __be16                  lwm;
+};
+
+struct mlx5_arm_srq_mbox_out {
+       struct mlx5_outbox_hdr  hdr;
+       u8                      rsvd[8];
+};
+
+struct mlx5_cq_context {
+       u8                      status;
+       u8                      cqe_sz_flags;
+       u8                      st;
+       u8                      rsvd3;
+       u8                      rsvd4[6];
+       __be16                  page_offset;
+       __be32                  log_sz_usr_page;
+       __be16                  cq_period;
+       __be16                  cq_max_count;
+       __be16                  rsvd20;
+       __be16                  c_eqn;
+       u8                      log_pg_sz;
+       u8                      rsvd25[7];
+       __be32                  last_notified_index;
+       __be32                  solicit_producer_index;
+       __be32                  consumer_counter;
+       __be32                  producer_counter;
+       u8                      rsvd48[8];
+       __be64                  db_record_addr;
+};
+
+struct mlx5_create_cq_mbox_in {
+       struct mlx5_inbox_hdr   hdr;
+       __be32                  input_cqn;
+       u8                      rsvdx[4];
+       struct mlx5_cq_context  ctx;
+       u8                      rsvd6[192];
+       __be64                  pas[0];
+};
+
+struct mlx5_create_cq_mbox_out {
+       struct mlx5_outbox_hdr  hdr;
+       __be32                  cqn;
+       u8                      rsvd0[4];
+};
+
+struct mlx5_destroy_cq_mbox_in {
+       struct mlx5_inbox_hdr   hdr;
+       __be32                  cqn;
+       u8                      rsvd0[4];
+};
+
+struct mlx5_destroy_cq_mbox_out {
+       struct mlx5_outbox_hdr  hdr;
+       u8                      rsvd0[8];
+};
+
+struct mlx5_query_cq_mbox_in {
+       struct mlx5_inbox_hdr   hdr;
+       __be32                  cqn;
+       u8                      rsvd0[4];
+};
+
+struct mlx5_query_cq_mbox_out {
+       struct mlx5_outbox_hdr  hdr;
+       u8                      rsvd0[8];
+       struct mlx5_cq_context  ctx;
+       u8                      rsvd6[16];
+       __be64                  pas[0];
+};
+
+struct mlx5_eq_context {
+       u8                      status;
+       u8                      ec_oi;
+       u8                      st;
+       u8                      rsvd2[7];
+       __be16                  page_pffset;
+       __be32                  log_sz_usr_page;
+       u8                      rsvd3[7];
+       u8                      intr;
+       u8                      log_page_size;
+       u8                      rsvd4[15];
+       __be32                  consumer_counter;
+       __be32                  produser_counter;
+       u8                      rsvd5[16];
+};
+
+struct mlx5_create_eq_mbox_in {
+       struct mlx5_inbox_hdr   hdr;
+       u8                      rsvd0[3];
+       u8                      input_eqn;
+       u8                      rsvd1[4];
+       struct mlx5_eq_context  ctx;
+       u8                      rsvd2[8];
+       __be64                  events_mask;
+       u8                      rsvd3[176];
+       __be64                  pas[0];
+};
+
+struct mlx5_create_eq_mbox_out {
+       struct mlx5_outbox_hdr  hdr;
+       u8                      rsvd0[3];
+       u8                      eq_number;
+       u8                      rsvd1[4];
+};
+
+struct mlx5_destroy_eq_mbox_in {
+       struct mlx5_inbox_hdr   hdr;
+       u8                      rsvd0[3];
+       u8                      eqn;
+       u8                      rsvd1[4];
+};
+
+struct mlx5_destroy_eq_mbox_out {
+       struct mlx5_outbox_hdr  hdr;
+       u8                      rsvd[8];
+};
+
+struct mlx5_map_eq_mbox_in {
+       struct mlx5_inbox_hdr   hdr;
+       __be64                  mask;
+       u8                      mu;
+       u8                      rsvd0[2];
+       u8                      eqn;
+       u8                      rsvd1[24];
+};
+
+struct mlx5_map_eq_mbox_out {
+       struct mlx5_outbox_hdr  hdr;
+       u8                      rsvd[8];
+};
+
+struct mlx5_query_eq_mbox_in {
+       struct mlx5_inbox_hdr   hdr;
+       u8                      rsvd0[3];
+       u8                      eqn;
+       u8                      rsvd1[4];
+};
+
+struct mlx5_query_eq_mbox_out {
+       struct mlx5_outbox_hdr  hdr;
+       u8                      rsvd[8];
+       struct mlx5_eq_context  ctx;
+};
+
+struct mlx5_mkey_seg {
+       /* This is a two bit field occupying bits 31-30.
+        * bit 31 is always 0,
+        * bit 30 is zero for regular MRs and 1 (e.g free) for UMRs that do not have tanslation
+        */
+       u8              status;
+       u8              pcie_control;
+       u8              flags;
+       u8              version;
+       __be32          qpn_mkey7_0;
+       u8              rsvd1[4];
+       __be32          flags_pd;
+       __be64          start_addr;
+       __be64          len;
+       __be32          bsfs_octo_size;
+       u8              rsvd2[16];
+       __be32          xlt_oct_size;
+       u8              rsvd3[3];
+       u8              log2_page_size;
+       u8              rsvd4[4];
+};
+
+struct mlx5_query_special_ctxs_mbox_in {
+       struct mlx5_inbox_hdr   hdr;
+       u8                      rsvd[8];
+};
+
+struct mlx5_query_special_ctxs_mbox_out {
+       struct mlx5_outbox_hdr  hdr;
+       __be32                  dump_fill_mkey;
+       __be32                  reserved_lkey;
+};
+
+struct mlx5_create_mkey_mbox_in {
+       struct mlx5_inbox_hdr   hdr;
+       __be32                  input_mkey_index;
+       u8                      rsvd0[4];
+       struct mlx5_mkey_seg    seg;
+       u8                      rsvd1[16];
+       __be32                  xlat_oct_act_size;
+       __be32                  bsf_coto_act_size;
+       u8                      rsvd2[168];
+       __be64                  pas[0];
+};
+
+struct mlx5_create_mkey_mbox_out {
+       struct mlx5_outbox_hdr  hdr;
+       __be32                  mkey;
+       u8                      rsvd[4];
+};
+
+struct mlx5_destroy_mkey_mbox_in {
+       struct mlx5_inbox_hdr   hdr;
+       __be32                  mkey;
+       u8                      rsvd[4];
+};
+
+struct mlx5_destroy_mkey_mbox_out {
+       struct mlx5_outbox_hdr  hdr;
+       u8                      rsvd[8];
+};
+
+struct mlx5_query_mkey_mbox_in {
+       struct mlx5_inbox_hdr   hdr;
+       __be32                  mkey;
+};
+
+struct mlx5_query_mkey_mbox_out {
+       struct mlx5_outbox_hdr  hdr;
+       __be64                  pas[0];
+};
+
+struct mlx5_modify_mkey_mbox_in {
+       struct mlx5_inbox_hdr   hdr;
+       __be32                  mkey;
+       __be64                  pas[0];
+};
+
+struct mlx5_modify_mkey_mbox_out {
+       struct mlx5_outbox_hdr  hdr;
+};
+
+struct mlx5_dump_mkey_mbox_in {
+       struct mlx5_inbox_hdr   hdr;
+};
+
+struct mlx5_dump_mkey_mbox_out {
+       struct mlx5_outbox_hdr  hdr;
+       __be32                  mkey;
+};
+
+struct mlx5_mad_ifc_mbox_in {
+       struct mlx5_inbox_hdr   hdr;
+       __be16                  remote_lid;
+       u8                      rsvd0;
+       u8                      port;
+       u8                      rsvd1[4];
+       u8                      data[256];
+};
+
+struct mlx5_mad_ifc_mbox_out {
+       struct mlx5_outbox_hdr  hdr;
+       u8                      rsvd[8];
+       u8                      data[256];
+};
+
+struct mlx5_access_reg_mbox_in {
+       struct mlx5_inbox_hdr           hdr;
+       u8                              rsvd0[2];
+       __be16                          register_id;
+       __be32                          arg;
+       __be32                          data[0];
+};
+
+struct mlx5_access_reg_mbox_out {
+       struct mlx5_outbox_hdr          hdr;
+       u8                              rsvd[8];
+       __be32                          data[0];
+};
+
+#define MLX5_ATTR_EXTENDED_PORT_INFO   cpu_to_be16(0xff90)
+
+enum {
+       MLX_EXT_PORT_CAP_FLAG_EXTENDED_PORT_INFO        = 1 <<  0
+};
+
+#endif /* MLX5_DEVICE_H */
diff --git a/include/linux/mlx5/doorbell.h b/include/linux/mlx5/doorbell.h
new file mode 100644 (file)
index 0000000..163a818
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2013, Mellanox Technologies inc.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef MLX5_DOORBELL_H
+#define MLX5_DOORBELL_H
+
+#define MLX5_BF_OFFSET       0x800
+#define MLX5_CQ_DOORBELL      0x20
+
+#if BITS_PER_LONG == 64
+/* Assume that we can just write a 64-bit doorbell atomically.  s390
+ * actually doesn't have writeq() but S/390 systems don't even have
+ * PCI so we won't worry about it.
+ */
+
+#define MLX5_DECLARE_DOORBELL_LOCK(name)
+#define MLX5_INIT_DOORBELL_LOCK(ptr)    do { } while (0)
+#define MLX5_GET_DOORBELL_LOCK(ptr)      (NULL)
+
+static inline void mlx5_write64(__be32 val[2], void __iomem *dest,
+                               spinlock_t *doorbell_lock)
+{
+       __raw_writeq(*(u64 *)val, dest);
+}
+
+#else
+
+/* Just fall back to a spinlock to protect the doorbell if
+ * BITS_PER_LONG is 32 -- there's no portable way to do atomic 64-bit
+ * MMIO writes.
+ */
+
+#define MLX5_DECLARE_DOORBELL_LOCK(name) spinlock_t name;
+#define MLX5_INIT_DOORBELL_LOCK(ptr)     spin_lock_init(ptr)
+#define MLX5_GET_DOORBELL_LOCK(ptr)      (ptr)
+
+static inline void mlx5_write64(__be32 val[2], void __iomem *dest,
+                               spinlock_t *doorbell_lock)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(doorbell_lock, flags);
+       __raw_writel((__force u32) val[0], dest);
+       __raw_writel((__force u32) val[1], dest + 4);
+       spin_unlock_irqrestore(doorbell_lock, flags);
+}
+
+#endif
+
+#endif /* MLX5_DOORBELL_H */
diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h
new file mode 100644 (file)
index 0000000..f22e441
--- /dev/null
@@ -0,0 +1,769 @@
+/*
+ * Copyright (c) 2013, Mellanox Technologies inc.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef MLX5_DRIVER_H
+#define MLX5_DRIVER_H
+
+#include <linux/kernel.h>
+#include <linux/completion.h>
+#include <linux/pci.h>
+#include <linux/spinlock_types.h>
+#include <linux/semaphore.h>
+#include <linux/vmalloc.h>
+#include <linux/radix-tree.h>
+#include <linux/mlx5/device.h>
+#include <linux/mlx5/doorbell.h>
+
+enum {
+       MLX5_BOARD_ID_LEN = 64,
+       MLX5_MAX_NAME_LEN = 16,
+};
+
+enum {
+       /* one minute for the sake of bringup. Generally, commands must always
+        * complete and we may need to increase this timeout value
+        */
+       MLX5_CMD_TIMEOUT_MSEC   = 7200 * 1000,
+       MLX5_CMD_WQ_MAX_NAME    = 32,
+};
+
+enum {
+       CMD_OWNER_SW            = 0x0,
+       CMD_OWNER_HW            = 0x1,
+       CMD_STATUS_SUCCESS      = 0,
+};
+
+enum mlx5_sqp_t {
+       MLX5_SQP_SMI            = 0,
+       MLX5_SQP_GSI            = 1,
+       MLX5_SQP_IEEE_1588      = 2,
+       MLX5_SQP_SNIFFER        = 3,
+       MLX5_SQP_SYNC_UMR       = 4,
+};
+
+enum {
+       MLX5_MAX_PORTS  = 2,
+};
+
+enum {
+       MLX5_EQ_VEC_PAGES        = 0,
+       MLX5_EQ_VEC_CMD          = 1,
+       MLX5_EQ_VEC_ASYNC        = 2,
+       MLX5_EQ_VEC_COMP_BASE,
+};
+
+enum {
+       MLX5_MAX_EQ_NAME        = 20
+};
+
+enum {
+       MLX5_ATOMIC_MODE_IB_COMP        = 1 << 16,
+       MLX5_ATOMIC_MODE_CX             = 2 << 16,
+       MLX5_ATOMIC_MODE_8B             = 3 << 16,
+       MLX5_ATOMIC_MODE_16B            = 4 << 16,
+       MLX5_ATOMIC_MODE_32B            = 5 << 16,
+       MLX5_ATOMIC_MODE_64B            = 6 << 16,
+       MLX5_ATOMIC_MODE_128B           = 7 << 16,
+       MLX5_ATOMIC_MODE_256B           = 8 << 16,
+};
+
+enum {
+       MLX5_CMD_OP_QUERY_HCA_CAP               = 0x100,
+       MLX5_CMD_OP_QUERY_ADAPTER               = 0x101,
+       MLX5_CMD_OP_INIT_HCA                    = 0x102,
+       MLX5_CMD_OP_TEARDOWN_HCA                = 0x103,
+       MLX5_CMD_OP_QUERY_PAGES                 = 0x107,
+       MLX5_CMD_OP_MANAGE_PAGES                = 0x108,
+       MLX5_CMD_OP_SET_HCA_CAP                 = 0x109,
+
+       MLX5_CMD_OP_CREATE_MKEY                 = 0x200,
+       MLX5_CMD_OP_QUERY_MKEY                  = 0x201,
+       MLX5_CMD_OP_DESTROY_MKEY                = 0x202,
+       MLX5_CMD_OP_QUERY_SPECIAL_CONTEXTS      = 0x203,
+
+       MLX5_CMD_OP_CREATE_EQ                   = 0x301,
+       MLX5_CMD_OP_DESTROY_EQ                  = 0x302,
+       MLX5_CMD_OP_QUERY_EQ                    = 0x303,
+
+       MLX5_CMD_OP_CREATE_CQ                   = 0x400,
+       MLX5_CMD_OP_DESTROY_CQ                  = 0x401,
+       MLX5_CMD_OP_QUERY_CQ                    = 0x402,
+       MLX5_CMD_OP_MODIFY_CQ                   = 0x403,
+
+       MLX5_CMD_OP_CREATE_QP                   = 0x500,
+       MLX5_CMD_OP_DESTROY_QP                  = 0x501,
+       MLX5_CMD_OP_RST2INIT_QP                 = 0x502,
+       MLX5_CMD_OP_INIT2RTR_QP                 = 0x503,
+       MLX5_CMD_OP_RTR2RTS_QP                  = 0x504,
+       MLX5_CMD_OP_RTS2RTS_QP                  = 0x505,
+       MLX5_CMD_OP_SQERR2RTS_QP                = 0x506,
+       MLX5_CMD_OP_2ERR_QP                     = 0x507,
+       MLX5_CMD_OP_RTS2SQD_QP                  = 0x508,
+       MLX5_CMD_OP_SQD2RTS_QP                  = 0x509,
+       MLX5_CMD_OP_2RST_QP                     = 0x50a,
+       MLX5_CMD_OP_QUERY_QP                    = 0x50b,
+       MLX5_CMD_OP_CONF_SQP                    = 0x50c,
+       MLX5_CMD_OP_MAD_IFC                     = 0x50d,
+       MLX5_CMD_OP_INIT2INIT_QP                = 0x50e,
+       MLX5_CMD_OP_SUSPEND_QP                  = 0x50f,
+       MLX5_CMD_OP_UNSUSPEND_QP                = 0x510,
+       MLX5_CMD_OP_SQD2SQD_QP                  = 0x511,
+       MLX5_CMD_OP_ALLOC_QP_COUNTER_SET        = 0x512,
+       MLX5_CMD_OP_DEALLOC_QP_COUNTER_SET      = 0x513,
+       MLX5_CMD_OP_QUERY_QP_COUNTER_SET        = 0x514,
+
+       MLX5_CMD_OP_CREATE_PSV                  = 0x600,
+       MLX5_CMD_OP_DESTROY_PSV                 = 0x601,
+       MLX5_CMD_OP_QUERY_PSV                   = 0x602,
+       MLX5_CMD_OP_QUERY_SIG_RULE_TABLE        = 0x603,
+       MLX5_CMD_OP_QUERY_BLOCK_SIZE_TABLE      = 0x604,
+
+       MLX5_CMD_OP_CREATE_SRQ                  = 0x700,
+       MLX5_CMD_OP_DESTROY_SRQ                 = 0x701,
+       MLX5_CMD_OP_QUERY_SRQ                   = 0x702,
+       MLX5_CMD_OP_ARM_RQ                      = 0x703,
+       MLX5_CMD_OP_RESIZE_SRQ                  = 0x704,
+
+       MLX5_CMD_OP_ALLOC_PD                    = 0x800,
+       MLX5_CMD_OP_DEALLOC_PD                  = 0x801,
+       MLX5_CMD_OP_ALLOC_UAR                   = 0x802,
+       MLX5_CMD_OP_DEALLOC_UAR                 = 0x803,
+
+       MLX5_CMD_OP_ATTACH_TO_MCG               = 0x806,
+       MLX5_CMD_OP_DETACH_FROM_MCG             = 0x807,
+
+
+       MLX5_CMD_OP_ALLOC_XRCD                  = 0x80e,
+       MLX5_CMD_OP_DEALLOC_XRCD                = 0x80f,
+
+       MLX5_CMD_OP_ACCESS_REG                  = 0x805,
+       MLX5_CMD_OP_MAX                         = 0x810,
+};
+
+enum {
+       MLX5_REG_PCAP            = 0x5001,
+       MLX5_REG_PMTU            = 0x5003,
+       MLX5_REG_PTYS            = 0x5004,
+       MLX5_REG_PAOS            = 0x5006,
+       MLX5_REG_PMAOS           = 0x5012,
+       MLX5_REG_PUDE            = 0x5009,
+       MLX5_REG_PMPE            = 0x5010,
+       MLX5_REG_PELC            = 0x500e,
+       MLX5_REG_PMLP            = 0, /* TBD */
+       MLX5_REG_NODE_DESC       = 0x6001,
+       MLX5_REG_HOST_ENDIANNESS = 0x7004,
+};
+
+enum dbg_rsc_type {
+       MLX5_DBG_RSC_QP,
+       MLX5_DBG_RSC_EQ,
+       MLX5_DBG_RSC_CQ,
+};
+
+struct mlx5_field_desc {
+       struct dentry          *dent;
+       int                     i;
+};
+
+struct mlx5_rsc_debug {
+       struct mlx5_core_dev   *dev;
+       void                   *object;
+       enum dbg_rsc_type       type;
+       struct dentry          *root;
+       struct mlx5_field_desc  fields[0];
+};
+
+enum mlx5_dev_event {
+       MLX5_DEV_EVENT_SYS_ERROR,
+       MLX5_DEV_EVENT_PORT_UP,
+       MLX5_DEV_EVENT_PORT_DOWN,
+       MLX5_DEV_EVENT_PORT_INITIALIZED,
+       MLX5_DEV_EVENT_LID_CHANGE,
+       MLX5_DEV_EVENT_PKEY_CHANGE,
+       MLX5_DEV_EVENT_GUID_CHANGE,
+       MLX5_DEV_EVENT_CLIENT_REREG,
+};
+
+struct mlx5_uuar_info {
+       struct mlx5_uar        *uars;
+       int                     num_uars;
+       int                     num_low_latency_uuars;
+       unsigned long          *bitmap;
+       unsigned int           *count;
+       struct mlx5_bf         *bfs;
+
+       /*
+        * protect uuar allocation data structs
+        */
+       struct mutex            lock;
+};
+
+struct mlx5_bf {
+       void __iomem           *reg;
+       void __iomem           *regreg;
+       int                     buf_size;
+       struct mlx5_uar        *uar;
+       unsigned long           offset;
+       int                     need_lock;
+       /* protect blue flame buffer selection when needed
+        */
+       spinlock_t              lock;
+
+       /* serialize 64 bit writes when done as two 32 bit accesses
+        */
+       spinlock_t              lock32;
+       int                     uuarn;
+};
+
+struct mlx5_cmd_first {
+       __be32          data[4];
+};
+
+struct mlx5_cmd_msg {
+       struct list_head                list;
+       struct cache_ent               *cache;
+       u32                             len;
+       struct mlx5_cmd_first           first;
+       struct mlx5_cmd_mailbox        *next;
+};
+
+struct mlx5_cmd_debug {
+       struct dentry          *dbg_root;
+       struct dentry          *dbg_in;
+       struct dentry          *dbg_out;
+       struct dentry          *dbg_outlen;
+       struct dentry          *dbg_status;
+       struct dentry          *dbg_run;
+       void                   *in_msg;
+       void                   *out_msg;
+       u8                      status;
+       u16                     inlen;
+       u16                     outlen;
+};
+
+struct cache_ent {
+       /* protect block chain allocations
+        */
+       spinlock_t              lock;
+       struct list_head        head;
+};
+
+struct cmd_msg_cache {
+       struct cache_ent        large;
+       struct cache_ent        med;
+
+};
+
+struct mlx5_cmd_stats {
+       u64             sum;
+       u64             n;
+       struct dentry  *root;
+       struct dentry  *avg;
+       struct dentry  *count;
+       /* protect command average calculations */
+       spinlock_t      lock;
+};
+
+struct mlx5_cmd {
+       void           *cmd_buf;
+       dma_addr_t      dma;
+       u16             cmdif_rev;
+       u8              log_sz;
+       u8              log_stride;
+       int             max_reg_cmds;
+       int             events;
+       u32 __iomem    *vector;
+
+       /* protect command queue allocations
+        */
+       spinlock_t      alloc_lock;
+
+       /* protect token allocations
+        */
+       spinlock_t      token_lock;
+       u8              token;
+       unsigned long   bitmask;
+       char            wq_name[MLX5_CMD_WQ_MAX_NAME];
+       struct workqueue_struct *wq;
+       struct semaphore sem;
+       struct semaphore pages_sem;
+       int     mode;
+       struct mlx5_cmd_work_ent *ent_arr[MLX5_MAX_COMMANDS];
+       struct pci_pool *pool;
+       struct mlx5_cmd_debug dbg;
+       struct cmd_msg_cache cache;
+       int checksum_disabled;
+       struct mlx5_cmd_stats stats[MLX5_CMD_OP_MAX];
+};
+
+struct mlx5_port_caps {
+       int     gid_table_len;
+       int     pkey_table_len;
+};
+
+struct mlx5_caps {
+       u8      log_max_eq;
+       u8      log_max_cq;
+       u8      log_max_qp;
+       u8      log_max_mkey;
+       u8      log_max_pd;
+       u8      log_max_srq;
+       u32     max_cqes;
+       int     max_wqes;
+       int     max_sq_desc_sz;
+       int     max_rq_desc_sz;
+       u64     flags;
+       u16     stat_rate_support;
+       int     log_max_msg;
+       int     num_ports;
+       int     max_ra_res_qp;
+       int     max_ra_req_qp;
+       int     max_srq_wqes;
+       int     bf_reg_size;
+       int     bf_regs_per_page;
+       struct mlx5_port_caps   port[MLX5_MAX_PORTS];
+       u8                      ext_port_cap[MLX5_MAX_PORTS];
+       int     max_vf;
+       u32     reserved_lkey;
+       u8      local_ca_ack_delay;
+       u8      log_max_mcg;
+       u16     max_qp_mcg;
+       int     min_page_sz;
+};
+
+struct mlx5_cmd_mailbox {
+       void           *buf;
+       dma_addr_t      dma;
+       struct mlx5_cmd_mailbox *next;
+};
+
+struct mlx5_buf_list {
+       void                   *buf;
+       dma_addr_t              map;
+};
+
+struct mlx5_buf {
+       struct mlx5_buf_list    direct;
+       struct mlx5_buf_list   *page_list;
+       int                     nbufs;
+       int                     npages;
+       int                     page_shift;
+       int                     size;
+};
+
+struct mlx5_eq {
+       struct mlx5_core_dev   *dev;
+       __be32 __iomem         *doorbell;
+       u32                     cons_index;
+       struct mlx5_buf         buf;
+       int                     size;
+       u8                      irqn;
+       u8                      eqn;
+       int                     nent;
+       u64                     mask;
+       char                    name[MLX5_MAX_EQ_NAME];
+       struct list_head        list;
+       int                     index;
+       struct mlx5_rsc_debug   *dbg;
+};
+
+
+struct mlx5_core_mr {
+       u64                     iova;
+       u64                     size;
+       u32                     key;
+       u32                     pd;
+       u32                     access;
+};
+
+struct mlx5_core_srq {
+       u32             srqn;
+       int             max;
+       int             max_gs;
+       int             max_avail_gather;
+       int             wqe_shift;
+       void (*event)   (struct mlx5_core_srq *, enum mlx5_event);
+
+       atomic_t                refcount;
+       struct completion       free;
+};
+
+struct mlx5_eq_table {
+       void __iomem           *update_ci;
+       void __iomem           *update_arm_ci;
+       struct list_head       *comp_eq_head;
+       struct mlx5_eq          pages_eq;
+       struct mlx5_eq          async_eq;
+       struct mlx5_eq          cmd_eq;
+       struct msix_entry       *msix_arr;
+       int                     num_comp_vectors;
+       /* protect EQs list
+        */
+       spinlock_t              lock;
+};
+
+struct mlx5_uar {
+       u32                     index;
+       struct list_head        bf_list;
+       unsigned                free_bf_bmap;
+       void __iomem           *wc_map;
+       void __iomem           *map;
+};
+
+
+struct mlx5_core_health {
+       struct health_buffer __iomem   *health;
+       __be32 __iomem                 *health_counter;
+       struct timer_list               timer;
+       struct list_head                list;
+       u32                             prev;
+       int                             miss_counter;
+};
+
+struct mlx5_cq_table {
+       /* protect radix tree
+        */
+       spinlock_t              lock;
+       struct radix_tree_root  tree;
+};
+
+struct mlx5_qp_table {
+       /* protect radix tree
+        */
+       spinlock_t              lock;
+       struct radix_tree_root  tree;
+};
+
+struct mlx5_srq_table {
+       /* protect radix tree
+        */
+       spinlock_t              lock;
+       struct radix_tree_root  tree;
+};
+
+struct mlx5_priv {
+       char                    name[MLX5_MAX_NAME_LEN];
+       struct mlx5_eq_table    eq_table;
+       struct mlx5_uuar_info   uuari;
+       MLX5_DECLARE_DOORBELL_LOCK(cq_uar_lock);
+
+       /* pages stuff */
+       struct workqueue_struct *pg_wq;
+       struct rb_root          page_root;
+       int                     fw_pages;
+       int                     reg_pages;
+
+       struct mlx5_core_health health;
+
+       struct mlx5_srq_table   srq_table;
+
+       /* start: qp staff */
+       struct mlx5_qp_table    qp_table;
+       struct dentry          *qp_debugfs;
+       struct dentry          *eq_debugfs;
+       struct dentry          *cq_debugfs;
+       struct dentry          *cmdif_debugfs;
+       /* end: qp staff */
+
+       /* start: cq staff */
+       struct mlx5_cq_table    cq_table;
+       /* end: cq staff */
+
+       /* start: alloc staff */
+       struct mutex            pgdir_mutex;
+       struct list_head        pgdir_list;
+       /* end: alloc staff */
+       struct dentry          *dbg_root;
+
+       /* protect mkey key part */
+       spinlock_t              mkey_lock;
+       u8                      mkey_key;
+};
+
+struct mlx5_core_dev {
+       struct pci_dev         *pdev;
+       u8                      rev_id;
+       char                    board_id[MLX5_BOARD_ID_LEN];
+       struct mlx5_cmd         cmd;
+       struct mlx5_caps        caps;
+       phys_addr_t             iseg_base;
+       struct mlx5_init_seg __iomem *iseg;
+       void                    (*event) (struct mlx5_core_dev *dev,
+                                         enum mlx5_dev_event event,
+                                         void *data);
+       struct mlx5_priv        priv;
+       struct mlx5_profile     *profile;
+       atomic_t                num_qps;
+};
+
+struct mlx5_db {
+       __be32                  *db;
+       union {
+               struct mlx5_db_pgdir            *pgdir;
+               struct mlx5_ib_user_db_page     *user_page;
+       }                       u;
+       dma_addr_t              dma;
+       int                     index;
+};
+
+enum {
+       MLX5_DB_PER_PAGE = PAGE_SIZE / L1_CACHE_BYTES,
+};
+
+enum {
+       MLX5_COMP_EQ_SIZE = 1024,
+};
+
+struct mlx5_db_pgdir {
+       struct list_head        list;
+       DECLARE_BITMAP(bitmap, MLX5_DB_PER_PAGE);
+       __be32                 *db_page;
+       dma_addr_t              db_dma;
+};
+
+typedef void (*mlx5_cmd_cbk_t)(int status, void *context);
+
+struct mlx5_cmd_work_ent {
+       struct mlx5_cmd_msg    *in;
+       struct mlx5_cmd_msg    *out;
+       mlx5_cmd_cbk_t          callback;
+       void                   *context;
+       int idx;
+       struct completion       done;
+       struct mlx5_cmd        *cmd;
+       struct work_struct      work;
+       struct mlx5_cmd_layout *lay;
+       int                     ret;
+       int                     page_queue;
+       u8                      status;
+       u8                      token;
+       struct timespec         ts1;
+       struct timespec         ts2;
+};
+
+struct mlx5_pas {
+       u64     pa;
+       u8      log_sz;
+};
+
+static inline void *mlx5_buf_offset(struct mlx5_buf *buf, int offset)
+{
+       if (likely(BITS_PER_LONG == 64 || buf->nbufs == 1))
+               return buf->direct.buf + offset;
+       else
+               return buf->page_list[offset >> PAGE_SHIFT].buf +
+                       (offset & (PAGE_SIZE - 1));
+}
+
+extern struct workqueue_struct *mlx5_core_wq;
+
+#define STRUCT_FIELD(header, field) \
+       .struct_offset_bytes = offsetof(struct ib_unpacked_ ## header, field),      \
+       .struct_size_bytes   = sizeof((struct ib_unpacked_ ## header *)0)->field
+
+struct ib_field {
+       size_t struct_offset_bytes;
+       size_t struct_size_bytes;
+       int    offset_bits;
+       int    size_bits;
+};
+
+static inline struct mlx5_core_dev *pci2mlx5_core_dev(struct pci_dev *pdev)
+{
+       return pci_get_drvdata(pdev);
+}
+
+extern struct dentry *mlx5_debugfs_root;
+
+static inline u16 fw_rev_maj(struct mlx5_core_dev *dev)
+{
+       return ioread32be(&dev->iseg->fw_rev) & 0xffff;
+}
+
+static inline u16 fw_rev_min(struct mlx5_core_dev *dev)
+{
+       return ioread32be(&dev->iseg->fw_rev) >> 16;
+}
+
+static inline u16 fw_rev_sub(struct mlx5_core_dev *dev)
+{
+       return ioread32be(&dev->iseg->cmdif_rev_fw_sub) & 0xffff;
+}
+
+static inline u16 cmdif_rev(struct mlx5_core_dev *dev)
+{
+       return ioread32be(&dev->iseg->cmdif_rev_fw_sub) >> 16;
+}
+
+static inline void *mlx5_vzalloc(unsigned long size)
+{
+       void *rtn;
+
+       rtn = kzalloc(size, GFP_KERNEL | __GFP_NOWARN);
+       if (!rtn)
+               rtn = vzalloc(size);
+       return rtn;
+}
+
+static inline void mlx5_vfree(const void *addr)
+{
+       if (addr && is_vmalloc_addr(addr))
+               vfree(addr);
+       else
+               kfree(addr);
+}
+
+int mlx5_dev_init(struct mlx5_core_dev *dev, struct pci_dev *pdev);
+void mlx5_dev_cleanup(struct mlx5_core_dev *dev);
+int mlx5_cmd_init(struct mlx5_core_dev *dev);
+void mlx5_cmd_cleanup(struct mlx5_core_dev *dev);
+void mlx5_cmd_use_events(struct mlx5_core_dev *dev);
+void mlx5_cmd_use_polling(struct mlx5_core_dev *dev);
+int mlx5_cmd_status_to_err(struct mlx5_outbox_hdr *hdr);
+int mlx5_cmd_exec(struct mlx5_core_dev *dev, void *in, int in_size, void *out,
+                 int out_size);
+int mlx5_cmd_alloc_uar(struct mlx5_core_dev *dev, u32 *uarn);
+int mlx5_cmd_free_uar(struct mlx5_core_dev *dev, u32 uarn);
+int mlx5_alloc_uuars(struct mlx5_core_dev *dev, struct mlx5_uuar_info *uuari);
+int mlx5_free_uuars(struct mlx5_core_dev *dev, struct mlx5_uuar_info *uuari);
+void mlx5_health_cleanup(void);
+void  __init mlx5_health_init(void);
+void mlx5_start_health_poll(struct mlx5_core_dev *dev);
+void mlx5_stop_health_poll(struct mlx5_core_dev *dev);
+int mlx5_buf_alloc(struct mlx5_core_dev *dev, int size, int max_direct,
+                  struct mlx5_buf *buf);
+void mlx5_buf_free(struct mlx5_core_dev *dev, struct mlx5_buf *buf);
+struct mlx5_cmd_mailbox *mlx5_alloc_cmd_mailbox_chain(struct mlx5_core_dev *dev,
+                                                     gfp_t flags, int npages);
+void mlx5_free_cmd_mailbox_chain(struct mlx5_core_dev *dev,
+                                struct mlx5_cmd_mailbox *head);
+int mlx5_core_create_srq(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq,
+                        struct mlx5_create_srq_mbox_in *in, int inlen);
+int mlx5_core_destroy_srq(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq);
+int mlx5_core_query_srq(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq,
+                       struct mlx5_query_srq_mbox_out *out);
+int mlx5_core_arm_srq(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq,
+                     u16 lwm, int is_srq);
+int mlx5_core_create_mkey(struct mlx5_core_dev *dev, struct mlx5_core_mr *mr,
+                         struct mlx5_create_mkey_mbox_in *in, int inlen);
+int mlx5_core_destroy_mkey(struct mlx5_core_dev *dev, struct mlx5_core_mr *mr);
+int mlx5_core_query_mkey(struct mlx5_core_dev *dev, struct mlx5_core_mr *mr,
+                        struct mlx5_query_mkey_mbox_out *out, int outlen);
+int mlx5_core_dump_fill_mkey(struct mlx5_core_dev *dev, struct mlx5_core_mr *mr,
+                            u32 *mkey);
+int mlx5_core_alloc_pd(struct mlx5_core_dev *dev, u32 *pdn);
+int mlx5_core_dealloc_pd(struct mlx5_core_dev *dev, u32 pdn);
+int mlx5_core_mad_ifc(struct mlx5_core_dev *dev, void *inb, void *outb,
+                     u16 opmod, int port);
+void mlx5_pagealloc_init(struct mlx5_core_dev *dev);
+void mlx5_pagealloc_cleanup(struct mlx5_core_dev *dev);
+int mlx5_pagealloc_start(struct mlx5_core_dev *dev);
+void mlx5_pagealloc_stop(struct mlx5_core_dev *dev);
+void mlx5_core_req_pages_handler(struct mlx5_core_dev *dev, u16 func_id,
+                                s16 npages);
+int mlx5_satisfy_startup_pages(struct mlx5_core_dev *dev);
+int mlx5_reclaim_startup_pages(struct mlx5_core_dev *dev);
+void mlx5_register_debugfs(void);
+void mlx5_unregister_debugfs(void);
+int mlx5_eq_init(struct mlx5_core_dev *dev);
+void mlx5_eq_cleanup(struct mlx5_core_dev *dev);
+void mlx5_fill_page_array(struct mlx5_buf *buf, __be64 *pas);
+void mlx5_cq_completion(struct mlx5_core_dev *dev, u32 cqn);
+void mlx5_qp_event(struct mlx5_core_dev *dev, u32 qpn, int event_type);
+void mlx5_srq_event(struct mlx5_core_dev *dev, u32 srqn, int event_type);
+struct mlx5_core_srq *mlx5_core_get_srq(struct mlx5_core_dev *dev, u32 srqn);
+void mlx5_cmd_comp_handler(struct mlx5_core_dev *dev, unsigned long vector);
+void mlx5_cq_event(struct mlx5_core_dev *dev, u32 cqn, int event_type);
+int mlx5_create_map_eq(struct mlx5_core_dev *dev, struct mlx5_eq *eq, u8 vecidx,
+                      int nent, u64 mask, const char *name, struct mlx5_uar *uar);
+int mlx5_destroy_unmap_eq(struct mlx5_core_dev *dev, struct mlx5_eq *eq);
+int mlx5_start_eqs(struct mlx5_core_dev *dev);
+int mlx5_stop_eqs(struct mlx5_core_dev *dev);
+int mlx5_core_attach_mcg(struct mlx5_core_dev *dev, union ib_gid *mgid, u32 qpn);
+int mlx5_core_detach_mcg(struct mlx5_core_dev *dev, union ib_gid *mgid, u32 qpn);
+
+int mlx5_qp_debugfs_init(struct mlx5_core_dev *dev);
+void mlx5_qp_debugfs_cleanup(struct mlx5_core_dev *dev);
+int mlx5_core_access_reg(struct mlx5_core_dev *dev, void *data_in,
+                        int size_in, void *data_out, int size_out,
+                        u16 reg_num, int arg, int write);
+int mlx5_set_port_caps(struct mlx5_core_dev *dev, int port_num, u32 caps);
+
+int mlx5_debug_eq_add(struct mlx5_core_dev *dev, struct mlx5_eq *eq);
+void mlx5_debug_eq_remove(struct mlx5_core_dev *dev, struct mlx5_eq *eq);
+int mlx5_core_eq_query(struct mlx5_core_dev *dev, struct mlx5_eq *eq,
+                      struct mlx5_query_eq_mbox_out *out, int outlen);
+int mlx5_eq_debugfs_init(struct mlx5_core_dev *dev);
+void mlx5_eq_debugfs_cleanup(struct mlx5_core_dev *dev);
+int mlx5_cq_debugfs_init(struct mlx5_core_dev *dev);
+void mlx5_cq_debugfs_cleanup(struct mlx5_core_dev *dev);
+int mlx5_db_alloc(struct mlx5_core_dev *dev, struct mlx5_db *db);
+void mlx5_db_free(struct mlx5_core_dev *dev, struct mlx5_db *db);
+
+typedef void (*health_handler_t)(struct pci_dev *pdev, struct health_buffer __iomem *buf, int size);
+int mlx5_register_health_report_handler(health_handler_t handler);
+void mlx5_unregister_health_report_handler(void);
+const char *mlx5_command_str(int command);
+int mlx5_cmdif_debugfs_init(struct mlx5_core_dev *dev);
+void mlx5_cmdif_debugfs_cleanup(struct mlx5_core_dev *dev);
+
+static inline u32 mlx5_mkey_to_idx(u32 mkey)
+{
+       return mkey >> 8;
+}
+
+static inline u32 mlx5_idx_to_mkey(u32 mkey_idx)
+{
+       return mkey_idx << 8;
+}
+
+enum {
+       MLX5_PROF_MASK_QP_SIZE          = (u64)1 << 0,
+       MLX5_PROF_MASK_CMDIF_CSUM       = (u64)1 << 1,
+       MLX5_PROF_MASK_MR_CACHE         = (u64)1 << 2,
+};
+
+enum {
+       MAX_MR_CACHE_ENTRIES    = 16,
+};
+
+struct mlx5_profile {
+       u64     mask;
+       u32     log_max_qp;
+       int     cmdif_csum;
+       struct {
+               int     size;
+               int     limit;
+       } mr_cache[MAX_MR_CACHE_ENTRIES];
+};
+
+#endif /* MLX5_DRIVER_H */
diff --git a/include/linux/mlx5/qp.h b/include/linux/mlx5/qp.h
new file mode 100644 (file)
index 0000000..d9e3eac
--- /dev/null
@@ -0,0 +1,467 @@
+/*
+ * Copyright (c) 2013, Mellanox Technologies inc.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef MLX5_QP_H
+#define MLX5_QP_H
+
+#include <linux/mlx5/device.h>
+#include <linux/mlx5/driver.h>
+
+#define MLX5_INVALID_LKEY      0x100
+
+enum mlx5_qp_optpar {
+       MLX5_QP_OPTPAR_ALT_ADDR_PATH            = 1 << 0,
+       MLX5_QP_OPTPAR_RRE                      = 1 << 1,
+       MLX5_QP_OPTPAR_RAE                      = 1 << 2,
+       MLX5_QP_OPTPAR_RWE                      = 1 << 3,
+       MLX5_QP_OPTPAR_PKEY_INDEX               = 1 << 4,
+       MLX5_QP_OPTPAR_Q_KEY                    = 1 << 5,
+       MLX5_QP_OPTPAR_RNR_TIMEOUT              = 1 << 6,
+       MLX5_QP_OPTPAR_PRIMARY_ADDR_PATH        = 1 << 7,
+       MLX5_QP_OPTPAR_SRA_MAX                  = 1 << 8,
+       MLX5_QP_OPTPAR_RRA_MAX                  = 1 << 9,
+       MLX5_QP_OPTPAR_PM_STATE                 = 1 << 10,
+       MLX5_QP_OPTPAR_RETRY_COUNT              = 1 << 12,
+       MLX5_QP_OPTPAR_RNR_RETRY                = 1 << 13,
+       MLX5_QP_OPTPAR_ACK_TIMEOUT              = 1 << 14,
+       MLX5_QP_OPTPAR_PRI_PORT                 = 1 << 16,
+       MLX5_QP_OPTPAR_SRQN                     = 1 << 18,
+       MLX5_QP_OPTPAR_CQN_RCV                  = 1 << 19,
+       MLX5_QP_OPTPAR_DC_HS                    = 1 << 20,
+       MLX5_QP_OPTPAR_DC_KEY                   = 1 << 21,
+};
+
+enum mlx5_qp_state {
+       MLX5_QP_STATE_RST                       = 0,
+       MLX5_QP_STATE_INIT                      = 1,
+       MLX5_QP_STATE_RTR                       = 2,
+       MLX5_QP_STATE_RTS                       = 3,
+       MLX5_QP_STATE_SQER                      = 4,
+       MLX5_QP_STATE_SQD                       = 5,
+       MLX5_QP_STATE_ERR                       = 6,
+       MLX5_QP_STATE_SQ_DRAINING               = 7,
+       MLX5_QP_STATE_SUSPENDED                 = 9,
+       MLX5_QP_NUM_STATE
+};
+
+enum {
+       MLX5_QP_ST_RC                           = 0x0,
+       MLX5_QP_ST_UC                           = 0x1,
+       MLX5_QP_ST_UD                           = 0x2,
+       MLX5_QP_ST_XRC                          = 0x3,
+       MLX5_QP_ST_MLX                          = 0x4,
+       MLX5_QP_ST_DCI                          = 0x5,
+       MLX5_QP_ST_DCT                          = 0x6,
+       MLX5_QP_ST_QP0                          = 0x7,
+       MLX5_QP_ST_QP1                          = 0x8,
+       MLX5_QP_ST_RAW_ETHERTYPE                = 0x9,
+       MLX5_QP_ST_RAW_IPV6                     = 0xa,
+       MLX5_QP_ST_SNIFFER                      = 0xb,
+       MLX5_QP_ST_SYNC_UMR                     = 0xe,
+       MLX5_QP_ST_PTP_1588                     = 0xd,
+       MLX5_QP_ST_REG_UMR                      = 0xc,
+       MLX5_QP_ST_MAX
+};
+
+enum {
+       MLX5_QP_PM_MIGRATED                     = 0x3,
+       MLX5_QP_PM_ARMED                        = 0x0,
+       MLX5_QP_PM_REARM                        = 0x1
+};
+
+enum {
+       MLX5_NON_ZERO_RQ        = 0 << 24,
+       MLX5_SRQ_RQ             = 1 << 24,
+       MLX5_CRQ_RQ             = 2 << 24,
+       MLX5_ZERO_LEN_RQ        = 3 << 24
+};
+
+enum {
+       /* params1 */
+       MLX5_QP_BIT_SRE                         = 1 << 15,
+       MLX5_QP_BIT_SWE                         = 1 << 14,
+       MLX5_QP_BIT_SAE                         = 1 << 13,
+       /* params2 */
+       MLX5_QP_BIT_RRE                         = 1 << 15,
+       MLX5_QP_BIT_RWE                         = 1 << 14,
+       MLX5_QP_BIT_RAE                         = 1 << 13,
+       MLX5_QP_BIT_RIC                         = 1 <<  4,
+};
+
+enum {
+       MLX5_WQE_CTRL_CQ_UPDATE         = 2 << 2,
+       MLX5_WQE_CTRL_SOLICITED         = 1 << 1,
+};
+
+enum {
+       MLX5_SEND_WQE_BB        = 64,
+};
+
+enum {
+       MLX5_WQE_FMR_PERM_LOCAL_READ    = 1 << 27,
+       MLX5_WQE_FMR_PERM_LOCAL_WRITE   = 1 << 28,
+       MLX5_WQE_FMR_PERM_REMOTE_READ   = 1 << 29,
+       MLX5_WQE_FMR_PERM_REMOTE_WRITE  = 1 << 30,
+       MLX5_WQE_FMR_PERM_ATOMIC        = 1 << 31
+};
+
+enum {
+       MLX5_FENCE_MODE_NONE                    = 0 << 5,
+       MLX5_FENCE_MODE_INITIATOR_SMALL         = 1 << 5,
+       MLX5_FENCE_MODE_STRONG_ORDERING         = 3 << 5,
+       MLX5_FENCE_MODE_SMALL_AND_FENCE         = 4 << 5,
+};
+
+enum {
+       MLX5_QP_LAT_SENSITIVE   = 1 << 28,
+       MLX5_QP_ENABLE_SIG      = 1 << 31,
+};
+
+enum {
+       MLX5_RCV_DBR    = 0,
+       MLX5_SND_DBR    = 1,
+};
+
+struct mlx5_wqe_fmr_seg {
+       __be32                  flags;
+       __be32                  mem_key;
+       __be64                  buf_list;
+       __be64                  start_addr;
+       __be64                  reg_len;
+       __be32                  offset;
+       __be32                  page_size;
+       u32                     reserved[2];
+};
+
+struct mlx5_wqe_ctrl_seg {
+       __be32                  opmod_idx_opcode;
+       __be32                  qpn_ds;
+       u8                      signature;
+       u8                      rsvd[2];
+       u8                      fm_ce_se;
+       __be32                  imm;
+};
+
+struct mlx5_wqe_xrc_seg {
+       __be32                  xrc_srqn;
+       u8                      rsvd[12];
+};
+
+struct mlx5_wqe_masked_atomic_seg {
+       __be64                  swap_add;
+       __be64                  compare;
+       __be64                  swap_add_mask;
+       __be64                  compare_mask;
+};
+
+struct mlx5_av {
+       union {
+               struct {
+                       __be32  qkey;
+                       __be32  reserved;
+               } qkey;
+               __be64  dc_key;
+       } key;
+       __be32  dqp_dct;
+       u8      stat_rate_sl;
+       u8      fl_mlid;
+       __be16  rlid;
+       u8      reserved0[10];
+       u8      tclass;
+       u8      hop_limit;
+       __be32  grh_gid_fl;
+       u8      rgid[16];
+};
+
+struct mlx5_wqe_datagram_seg {
+       struct mlx5_av  av;
+};
+
+struct mlx5_wqe_raddr_seg {
+       __be64                  raddr;
+       __be32                  rkey;
+       u32                     reserved;
+};
+
+struct mlx5_wqe_atomic_seg {
+       __be64                  swap_add;
+       __be64                  compare;
+};
+
+struct mlx5_wqe_data_seg {
+       __be32                  byte_count;
+       __be32                  lkey;
+       __be64                  addr;
+};
+
+struct mlx5_wqe_umr_ctrl_seg {
+       u8              flags;
+       u8              rsvd0[3];
+       __be16          klm_octowords;
+       __be16          bsf_octowords;
+       __be64          mkey_mask;
+       u8              rsvd1[32];
+};
+
+struct mlx5_seg_set_psv {
+       __be32          psv_num;
+       __be16          syndrome;
+       __be16          status;
+       __be32          transient_sig;
+       __be32          ref_tag;
+};
+
+struct mlx5_seg_get_psv {
+       u8              rsvd[19];
+       u8              num_psv;
+       __be32          l_key;
+       __be64          va;
+       __be32          psv_index[4];
+};
+
+struct mlx5_seg_check_psv {
+       u8              rsvd0[2];
+       __be16          err_coalescing_op;
+       u8              rsvd1[2];
+       __be16          xport_err_op;
+       u8              rsvd2[2];
+       __be16          xport_err_mask;
+       u8              rsvd3[7];
+       u8              num_psv;
+       __be32          l_key;
+       __be64          va;
+       __be32          psv_index[4];
+};
+
+struct mlx5_rwqe_sig {
+       u8      rsvd0[4];
+       u8      signature;
+       u8      rsvd1[11];
+};
+
+struct mlx5_wqe_signature_seg {
+       u8      rsvd0[4];
+       u8      signature;
+       u8      rsvd1[11];
+};
+
+struct mlx5_wqe_inline_seg {
+       __be32  byte_count;
+};
+
+struct mlx5_core_qp {
+       void (*event)           (struct mlx5_core_qp *, int);
+       int                     qpn;
+       atomic_t                refcount;
+       struct completion       free;
+       struct mlx5_rsc_debug   *dbg;
+       int                     pid;
+};
+
+struct mlx5_qp_path {
+       u8                      fl;
+       u8                      rsvd3;
+       u8                      free_ar;
+       u8                      pkey_index;
+       u8                      rsvd0;
+       u8                      grh_mlid;
+       __be16                  rlid;
+       u8                      ackto_lt;
+       u8                      mgid_index;
+       u8                      static_rate;
+       u8                      hop_limit;
+       __be32                  tclass_flowlabel;
+       u8                      rgid[16];
+       u8                      rsvd1[4];
+       u8                      sl;
+       u8                      port;
+       u8                      rsvd2[6];
+};
+
+struct mlx5_qp_context {
+       __be32                  flags;
+       __be32                  flags_pd;
+       u8                      mtu_msgmax;
+       u8                      rq_size_stride;
+       __be16                  sq_crq_size;
+       __be32                  qp_counter_set_usr_page;
+       __be32                  wire_qpn;
+       __be32                  log_pg_sz_remote_qpn;
+       struct                  mlx5_qp_path pri_path;
+       struct                  mlx5_qp_path alt_path;
+       __be32                  params1;
+       u8                      reserved2[4];
+       __be32                  next_send_psn;
+       __be32                  cqn_send;
+       u8                      reserved3[8];
+       __be32                  last_acked_psn;
+       __be32                  ssn;
+       __be32                  params2;
+       __be32                  rnr_nextrecvpsn;
+       __be32                  xrcd;
+       __be32                  cqn_recv;
+       __be64                  db_rec_addr;
+       __be32                  qkey;
+       __be32                  rq_type_srqn;
+       __be32                  rmsn;
+       __be16                  hw_sq_wqe_counter;
+       __be16                  sw_sq_wqe_counter;
+       __be16                  hw_rcyclic_byte_counter;
+       __be16                  hw_rq_counter;
+       __be16                  sw_rcyclic_byte_counter;
+       __be16                  sw_rq_counter;
+       u8                      rsvd0[5];
+       u8                      cgs;
+       u8                      cs_req;
+       u8                      cs_res;
+       __be64                  dc_access_key;
+       u8                      rsvd1[24];
+};
+
+struct mlx5_create_qp_mbox_in {
+       struct mlx5_inbox_hdr   hdr;
+       __be32                  input_qpn;
+       u8                      rsvd0[4];
+       __be32                  opt_param_mask;
+       u8                      rsvd1[4];
+       struct mlx5_qp_context  ctx;
+       u8                      rsvd3[16];
+       __be64                  pas[0];
+};
+
+struct mlx5_create_qp_mbox_out {
+       struct mlx5_outbox_hdr  hdr;
+       __be32                  qpn;
+       u8                      rsvd0[4];
+};
+
+struct mlx5_destroy_qp_mbox_in {
+       struct mlx5_inbox_hdr   hdr;
+       __be32                  qpn;
+       u8                      rsvd0[4];
+};
+
+struct mlx5_destroy_qp_mbox_out {
+       struct mlx5_outbox_hdr  hdr;
+       u8                      rsvd0[8];
+};
+
+struct mlx5_modify_qp_mbox_in {
+       struct mlx5_inbox_hdr   hdr;
+       __be32                  qpn;
+       u8                      rsvd1[4];
+       __be32                  optparam;
+       u8                      rsvd0[4];
+       struct mlx5_qp_context  ctx;
+};
+
+struct mlx5_modify_qp_mbox_out {
+       struct mlx5_outbox_hdr  hdr;
+       u8                      rsvd0[8];
+};
+
+struct mlx5_query_qp_mbox_in {
+       struct mlx5_inbox_hdr   hdr;
+       __be32                  qpn;
+       u8                      rsvd[4];
+};
+
+struct mlx5_query_qp_mbox_out {
+       struct mlx5_outbox_hdr  hdr;
+       u8                      rsvd1[8];
+       __be32                  optparam;
+       u8                      rsvd0[4];
+       struct mlx5_qp_context  ctx;
+       u8                      rsvd2[16];
+       __be64                  pas[0];
+};
+
+struct mlx5_conf_sqp_mbox_in {
+       struct mlx5_inbox_hdr   hdr;
+       __be32                  qpn;
+       u8                      rsvd[3];
+       u8                      type;
+};
+
+struct mlx5_conf_sqp_mbox_out {
+       struct mlx5_outbox_hdr  hdr;
+       u8                      rsvd[8];
+};
+
+struct mlx5_alloc_xrcd_mbox_in {
+       struct mlx5_inbox_hdr   hdr;
+       u8                      rsvd[8];
+};
+
+struct mlx5_alloc_xrcd_mbox_out {
+       struct mlx5_outbox_hdr  hdr;
+       __be32                  xrcdn;
+       u8                      rsvd[4];
+};
+
+struct mlx5_dealloc_xrcd_mbox_in {
+       struct mlx5_inbox_hdr   hdr;
+       __be32                  xrcdn;
+       u8                      rsvd[4];
+};
+
+struct mlx5_dealloc_xrcd_mbox_out {
+       struct mlx5_outbox_hdr  hdr;
+       u8                      rsvd[8];
+};
+
+static inline struct mlx5_core_qp *__mlx5_qp_lookup(struct mlx5_core_dev *dev, u32 qpn)
+{
+       return radix_tree_lookup(&dev->priv.qp_table.tree, qpn);
+}
+
+int mlx5_core_create_qp(struct mlx5_core_dev *dev,
+                       struct mlx5_core_qp *qp,
+                       struct mlx5_create_qp_mbox_in *in,
+                       int inlen);
+int mlx5_core_qp_modify(struct mlx5_core_dev *dev, enum mlx5_qp_state cur_state,
+                       enum mlx5_qp_state new_state,
+                       struct mlx5_modify_qp_mbox_in *in, int sqd_event,
+                       struct mlx5_core_qp *qp);
+int mlx5_core_destroy_qp(struct mlx5_core_dev *dev,
+                        struct mlx5_core_qp *qp);
+int mlx5_core_qp_query(struct mlx5_core_dev *dev, struct mlx5_core_qp *qp,
+                      struct mlx5_query_qp_mbox_out *out, int outlen);
+
+int mlx5_core_xrcd_alloc(struct mlx5_core_dev *dev, u32 *xrcdn);
+int mlx5_core_xrcd_dealloc(struct mlx5_core_dev *dev, u32 xrcdn);
+void mlx5_init_qp_table(struct mlx5_core_dev *dev);
+void mlx5_cleanup_qp_table(struct mlx5_core_dev *dev);
+int mlx5_debug_qp_add(struct mlx5_core_dev *dev, struct mlx5_core_qp *qp);
+void mlx5_debug_qp_remove(struct mlx5_core_dev *dev, struct mlx5_core_qp *qp);
+
+#endif /* MLX5_QP_H */
diff --git a/include/linux/mlx5/srq.h b/include/linux/mlx5/srq.h
new file mode 100644 (file)
index 0000000..e1a363a
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2013, Mellanox Technologies inc.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef MLX5_SRQ_H
+#define MLX5_SRQ_H
+
+#include <linux/mlx5/driver.h>
+
+void mlx5_init_srq_table(struct mlx5_core_dev *dev);
+void mlx5_cleanup_srq_table(struct mlx5_core_dev *dev);
+
+#endif /* MLX5_SRQ_H */
index ace9a5f..fb425aa 100644 (file)
@@ -330,12 +330,9 @@ struct mm_struct {
        unsigned long (*get_unmapped_area) (struct file *filp,
                                unsigned long addr, unsigned long len,
                                unsigned long pgoff, unsigned long flags);
-       void (*unmap_area) (struct mm_struct *mm, unsigned long addr);
 #endif
        unsigned long mmap_base;                /* base of mmap area */
        unsigned long task_size;                /* size of task vm space */
-       unsigned long cached_hole_size;         /* if non-zero, the largest hole below free_area_cache */
-       unsigned long free_area_cache;          /* first hole of size cached_hole_size or larger */
        unsigned long highest_vm_end;           /* highest vma end address */
        pgd_t * pgd;
        atomic_t mm_users;                      /* How many users with user space? */
index f31725b..842de3e 100644 (file)
@@ -94,7 +94,11 @@ struct mmc_ext_csd {
        u8                      raw_ext_csd_structure;  /* 194 */
        u8                      raw_card_type;          /* 196 */
        u8                      out_of_int_time;        /* 198 */
-       u8                      raw_s_a_timeout;                /* 217 */
+       u8                      raw_pwr_cl_52_195;      /* 200 */
+       u8                      raw_pwr_cl_26_195;      /* 201 */
+       u8                      raw_pwr_cl_52_360;      /* 202 */
+       u8                      raw_pwr_cl_26_360;      /* 203 */
+       u8                      raw_s_a_timeout;        /* 217 */
        u8                      raw_hc_erase_gap_size;  /* 221 */
        u8                      raw_erase_timeout_mult; /* 223 */
        u8                      raw_hc_erase_grp_size;  /* 224 */
@@ -102,6 +106,10 @@ struct mmc_ext_csd {
        u8                      raw_sec_erase_mult;     /* 230 */
        u8                      raw_sec_feature_support;/* 231 */
        u8                      raw_trim_mult;          /* 232 */
+       u8                      raw_pwr_cl_200_195;     /* 236 */
+       u8                      raw_pwr_cl_200_360;     /* 237 */
+       u8                      raw_pwr_cl_ddr_52_195;  /* 238 */
+       u8                      raw_pwr_cl_ddr_52_360;  /* 239 */
        u8                      raw_bkops_status;       /* 246 */
        u8                      raw_sectors[4];         /* 212 - 4 bytes */
 
@@ -512,6 +520,7 @@ struct mmc_driver {
        void (*remove)(struct mmc_card *);
        int (*suspend)(struct mmc_card *);
        int (*resume)(struct mmc_card *);
+       void (*shutdown)(struct mmc_card *);
 };
 
 extern int mmc_register_driver(struct mmc_driver *);
index 39613b9..443243b 100644 (file)
@@ -96,6 +96,8 @@ struct mmc_command {
  */
 
        unsigned int            cmd_timeout_ms; /* in milliseconds */
+       /* Set this flag only for blocking sanitize request */
+       bool                    sanitize_busy;
 
        struct mmc_data         *data;          /* data segment associated with cmd */
        struct mmc_request      *mrq;           /* associated request */
@@ -188,6 +190,9 @@ extern int __mmc_claim_host(struct mmc_host *host, atomic_t *abort);
 extern void mmc_release_host(struct mmc_host *host);
 extern int mmc_try_claim_host(struct mmc_host *host);
 
+extern void mmc_get_card(struct mmc_card *card);
+extern void mmc_put_card(struct mmc_card *card);
+
 extern int mmc_flush_cache(struct mmc_card *);
 
 extern int mmc_detect_card_removed(struct mmc_host *host);
index e326ae2..3b0c33a 100644 (file)
@@ -239,7 +239,7 @@ struct mmc_host {
 #define MMC_CAP_SPI            (1 << 4)        /* Talks only SPI protocols */
 #define MMC_CAP_NEEDS_POLL     (1 << 5)        /* Needs polling for card-detection */
 #define MMC_CAP_8_BIT_DATA     (1 << 6)        /* Can the host do 8 bit transfers */
-
+#define MMC_CAP_AGGRESSIVE_PM  (1 << 7)        /* Suspend (e)MMC/SD at idle  */
 #define MMC_CAP_NONREMOVABLE   (1 << 8)        /* Nonremovable e.g. eMMC */
 #define MMC_CAP_WAIT_WHILE_BUSY        (1 << 9)        /* Waits while card is busy */
 #define MMC_CAP_ERASE          (1 << 10)       /* Allow erase/trim commands */
@@ -264,7 +264,7 @@ struct mmc_host {
 
 #define MMC_CAP2_BOOTPART_NOACC        (1 << 0)        /* Boot partition no access */
 #define MMC_CAP2_CACHE_CTRL    (1 << 1)        /* Allow cache control */
-#define MMC_CAP2_POWEROFF_NOTIFY (1 << 2)      /* Notify poweroff supported */
+#define MMC_CAP2_FULL_PWR_CYCLE        (1 << 2)        /* Can do full power cycle */
 #define MMC_CAP2_NO_MULTI_READ (1 << 3)        /* Multiblock reads don't work */
 #define MMC_CAP2_NO_SLEEP_CMD  (1 << 4)        /* Don't allow sleep command */
 #define MMC_CAP2_HS200_1_8V_SDR        (1 << 5)        /* can support */
@@ -272,7 +272,6 @@ struct mmc_host {
 #define MMC_CAP2_HS200         (MMC_CAP2_HS200_1_8V_SDR | \
                                 MMC_CAP2_HS200_1_2V_SDR)
 #define MMC_CAP2_BROKEN_VOLTAGE        (1 << 7)        /* Use the broken voltage */
-#define MMC_CAP2_DETECT_ON_ERR (1 << 8)        /* On I/O err check card removal */
 #define MMC_CAP2_HC_ERASE_SZ   (1 << 9)        /* High-capacity erase size */
 #define MMC_CAP2_CD_ACTIVE_HIGH        (1 << 10)       /* Card-detect signal active high */
 #define MMC_CAP2_RO_ACTIVE_HIGH        (1 << 11)       /* Write-protect signal active high */
@@ -281,6 +280,7 @@ struct mmc_host {
 #define MMC_CAP2_PACKED_CMD    (MMC_CAP2_PACKED_RD | \
                                 MMC_CAP2_PACKED_WR)
 #define MMC_CAP2_NO_PRESCAN_POWERUP (1 << 14)  /* Don't power up before scan */
+#define MMC_CAP2_SANITIZE      (1 << 15)               /* Support Sanitize */
 
        mmc_pm_flag_t           pm_caps;        /* supported pm features */
 
@@ -369,7 +369,7 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *);
 int mmc_add_host(struct mmc_host *);
 void mmc_remove_host(struct mmc_host *);
 void mmc_free_host(struct mmc_host *);
-void mmc_of_parse(struct mmc_host *host);
+int mmc_of_parse(struct mmc_host *host);
 
 static inline void *mmc_priv(struct mmc_host *host)
 {
@@ -425,10 +425,6 @@ static inline int mmc_regulator_get_supply(struct mmc_host *mmc)
 }
 #endif
 
-int mmc_card_awake(struct mmc_host *host);
-int mmc_card_sleep(struct mmc_host *host);
-int mmc_card_can_sleep(struct mmc_host *host);
-
 int mmc_pm_notify(struct notifier_block *notify_block, unsigned long, void *);
 
 /* Module parameter */
index b838ffc..e3c6a74 100644 (file)
@@ -95,6 +95,9 @@ struct sdhci_host {
 /* The system physically doesn't support 1.8v, even if the host does */
 #define SDHCI_QUIRK2_NO_1_8_V                          (1<<2)
 #define SDHCI_QUIRK2_PRESET_VALUE_BROKEN               (1<<3)
+#define SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON              (1<<4)
+/* Controller has a non-standard host control register */
+#define SDHCI_QUIRK2_BROKEN_HOST_CONTROL               (1<<5)
 
        int irq;                /* Device IRQ */
        void __iomem *ioaddr;   /* Mapped address */
@@ -126,7 +129,7 @@ struct sdhci_host {
 #define SDHCI_AUTO_CMD23       (1<<7)  /* Auto CMD23 support */
 #define SDHCI_PV_ENABLED       (1<<8)  /* Preset value enabled */
 #define SDHCI_SDIO_IRQ_ENABLED (1<<9)  /* SDIO irq enabled */
-#define SDHCI_HS200_NEEDS_TUNING (1<<10)       /* HS200 needs tuning */
+#define SDHCI_SDR104_NEEDS_TUNING (1<<10)      /* SDR104/HS200 needs tuning */
 #define SDHCI_USING_RETUNING_TIMER (1<<11)     /* Host is using a retuning timer for the card */
 
        unsigned int version;   /* SDHCI spec. version */
@@ -139,6 +142,7 @@ struct sdhci_host {
        u8 pwr;                 /* Current voltage */
 
        bool runtime_suspended; /* Host is runtime suspended */
+       bool bus_on;            /* Bus power prevents runtime suspend */
 
        struct mmc_request *mrq;        /* Current request */
        struct mmc_command *cmd;        /* Current command */
index 137b419..27d9da3 100644 (file)
@@ -439,7 +439,7 @@ extern struct kernel_param_ops param_ops_string;
 extern int param_set_copystring(const char *val, const struct kernel_param *);
 extern int param_get_string(char *buffer, const struct kernel_param *kp);
 
-/* for exporting parameters in /sys/parameters */
+/* for exporting parameters in /sys/module/.../parameters */
 
 struct module;
 
index 3793ed7..ccd4260 100644 (file)
@@ -78,40 +78,6 @@ struct mutex_waiter {
 #endif
 };
 
-struct ww_class {
-       atomic_long_t stamp;
-       struct lock_class_key acquire_key;
-       struct lock_class_key mutex_key;
-       const char *acquire_name;
-       const char *mutex_name;
-};
-
-struct ww_acquire_ctx {
-       struct task_struct *task;
-       unsigned long stamp;
-       unsigned acquired;
-#ifdef CONFIG_DEBUG_MUTEXES
-       unsigned done_acquire;
-       struct ww_class *ww_class;
-       struct ww_mutex *contending_lock;
-#endif
-#ifdef CONFIG_DEBUG_LOCK_ALLOC
-       struct lockdep_map dep_map;
-#endif
-#ifdef CONFIG_DEBUG_WW_MUTEX_SLOWPATH
-       unsigned deadlock_inject_interval;
-       unsigned deadlock_inject_countdown;
-#endif
-};
-
-struct ww_mutex {
-       struct mutex base;
-       struct ww_acquire_ctx *ctx;
-#ifdef CONFIG_DEBUG_MUTEXES
-       struct ww_class *ww_class;
-#endif
-};
-
 #ifdef CONFIG_DEBUG_MUTEXES
 # include <linux/mutex-debug.h>
 #else
@@ -136,11 +102,8 @@ static inline void mutex_destroy(struct mutex *lock) {}
 #ifdef CONFIG_DEBUG_LOCK_ALLOC
 # define __DEP_MAP_MUTEX_INITIALIZER(lockname) \
                , .dep_map = { .name = #lockname }
-# define __WW_CLASS_MUTEX_INITIALIZER(lockname, ww_class) \
-               , .ww_class = &ww_class
 #else
 # define __DEP_MAP_MUTEX_INITIALIZER(lockname)
-# define __WW_CLASS_MUTEX_INITIALIZER(lockname, ww_class)
 #endif
 
 #define __MUTEX_INITIALIZER(lockname) \
@@ -150,49 +113,13 @@ static inline void mutex_destroy(struct mutex *lock) {}
                __DEBUG_MUTEX_INITIALIZER(lockname) \
                __DEP_MAP_MUTEX_INITIALIZER(lockname) }
 
-#define __WW_CLASS_INITIALIZER(ww_class) \
-               { .stamp = ATOMIC_LONG_INIT(0) \
-               , .acquire_name = #ww_class "_acquire" \
-               , .mutex_name = #ww_class "_mutex" }
-
-#define __WW_MUTEX_INITIALIZER(lockname, class) \
-               { .base = { \__MUTEX_INITIALIZER(lockname) } \
-               __WW_CLASS_MUTEX_INITIALIZER(lockname, class) }
-
 #define DEFINE_MUTEX(mutexname) \
        struct mutex mutexname = __MUTEX_INITIALIZER(mutexname)
 
-#define DEFINE_WW_CLASS(classname) \
-       struct ww_class classname = __WW_CLASS_INITIALIZER(classname)
-
-#define DEFINE_WW_MUTEX(mutexname, ww_class) \
-       struct ww_mutex mutexname = __WW_MUTEX_INITIALIZER(mutexname, ww_class)
-
-
 extern void __mutex_init(struct mutex *lock, const char *name,
                         struct lock_class_key *key);
 
 /**
- * ww_mutex_init - initialize the w/w mutex
- * @lock: the mutex to be initialized
- * @ww_class: the w/w class the mutex should belong to
- *
- * Initialize the w/w mutex to unlocked state and associate it with the given
- * class.
- *
- * It is not allowed to initialize an already locked mutex.
- */
-static inline void ww_mutex_init(struct ww_mutex *lock,
-                                struct ww_class *ww_class)
-{
-       __mutex_init(&lock->base, ww_class->mutex_name, &ww_class->mutex_key);
-       lock->ctx = NULL;
-#ifdef CONFIG_DEBUG_MUTEXES
-       lock->ww_class = ww_class;
-#endif
-}
-
-/**
  * mutex_is_locked - is the mutex locked
  * @lock: the mutex to be queried
  *
@@ -246,291 +173,6 @@ extern int __must_check mutex_lock_killable(struct mutex *lock);
 extern int mutex_trylock(struct mutex *lock);
 extern void mutex_unlock(struct mutex *lock);
 
-/**
- * ww_acquire_init - initialize a w/w acquire context
- * @ctx: w/w acquire context to initialize
- * @ww_class: w/w class of the context
- *
- * Initializes an context to acquire multiple mutexes of the given w/w class.
- *
- * Context-based w/w mutex acquiring can be done in any order whatsoever within
- * a given lock class. Deadlocks will be detected and handled with the
- * wait/wound logic.
- *
- * Mixing of context-based w/w mutex acquiring and single w/w mutex locking can
- * result in undetected deadlocks and is so forbidden. Mixing different contexts
- * for the same w/w class when acquiring mutexes can also result in undetected
- * deadlocks, and is hence also forbidden. Both types of abuse will be caught by
- * enabling CONFIG_PROVE_LOCKING.
- *
- * Nesting of acquire contexts for _different_ w/w classes is possible, subject
- * to the usual locking rules between different lock classes.
- *
- * An acquire context must be released with ww_acquire_fini by the same task
- * before the memory is freed. It is recommended to allocate the context itself
- * on the stack.
- */
-static inline void ww_acquire_init(struct ww_acquire_ctx *ctx,
-                                  struct ww_class *ww_class)
-{
-       ctx->task = current;
-       ctx->stamp = atomic_long_inc_return(&ww_class->stamp);
-       ctx->acquired = 0;
-#ifdef CONFIG_DEBUG_MUTEXES
-       ctx->ww_class = ww_class;
-       ctx->done_acquire = 0;
-       ctx->contending_lock = NULL;
-#endif
-#ifdef CONFIG_DEBUG_LOCK_ALLOC
-       debug_check_no_locks_freed((void *)ctx, sizeof(*ctx));
-       lockdep_init_map(&ctx->dep_map, ww_class->acquire_name,
-                        &ww_class->acquire_key, 0);
-       mutex_acquire(&ctx->dep_map, 0, 0, _RET_IP_);
-#endif
-#ifdef CONFIG_DEBUG_WW_MUTEX_SLOWPATH
-       ctx->deadlock_inject_interval = 1;
-       ctx->deadlock_inject_countdown = ctx->stamp & 0xf;
-#endif
-}
-
-/**
- * ww_acquire_done - marks the end of the acquire phase
- * @ctx: the acquire context
- *
- * Marks the end of the acquire phase, any further w/w mutex lock calls using
- * this context are forbidden.
- *
- * Calling this function is optional, it is just useful to document w/w mutex
- * code and clearly designated the acquire phase from actually using the locked
- * data structures.
- */
-static inline void ww_acquire_done(struct ww_acquire_ctx *ctx)
-{
-#ifdef CONFIG_DEBUG_MUTEXES
-       lockdep_assert_held(ctx);
-
-       DEBUG_LOCKS_WARN_ON(ctx->done_acquire);
-       ctx->done_acquire = 1;
-#endif
-}
-
-/**
- * ww_acquire_fini - releases a w/w acquire context
- * @ctx: the acquire context to free
- *
- * Releases a w/w acquire context. This must be called _after_ all acquired w/w
- * mutexes have been released with ww_mutex_unlock.
- */
-static inline void ww_acquire_fini(struct ww_acquire_ctx *ctx)
-{
-#ifdef CONFIG_DEBUG_MUTEXES
-       mutex_release(&ctx->dep_map, 0, _THIS_IP_);
-
-       DEBUG_LOCKS_WARN_ON(ctx->acquired);
-       if (!config_enabled(CONFIG_PROVE_LOCKING))
-               /*
-                * lockdep will normally handle this,
-                * but fail without anyway
-                */
-               ctx->done_acquire = 1;
-
-       if (!config_enabled(CONFIG_DEBUG_LOCK_ALLOC))
-               /* ensure ww_acquire_fini will still fail if called twice */
-               ctx->acquired = ~0U;
-#endif
-}
-
-extern int __must_check __ww_mutex_lock(struct ww_mutex *lock,
-                                       struct ww_acquire_ctx *ctx);
-extern int __must_check __ww_mutex_lock_interruptible(struct ww_mutex *lock,
-                                                     struct ww_acquire_ctx *ctx);
-
-/**
- * ww_mutex_lock - acquire the w/w mutex
- * @lock: the mutex to be acquired
- * @ctx: w/w acquire context, or NULL to acquire only a single lock.
- *
- * Lock the w/w mutex exclusively for this task.
- *
- * Deadlocks within a given w/w class of locks are detected and handled with the
- * wait/wound algorithm. If the lock isn't immediately avaiable this function
- * will either sleep until it is (wait case). Or it selects the current context
- * for backing off by returning -EDEADLK (wound case). Trying to acquire the
- * same lock with the same context twice is also detected and signalled by
- * returning -EALREADY. Returns 0 if the mutex was successfully acquired.
- *
- * In the wound case the caller must release all currently held w/w mutexes for
- * the given context and then wait for this contending lock to be available by
- * calling ww_mutex_lock_slow. Alternatively callers can opt to not acquire this
- * lock and proceed with trying to acquire further w/w mutexes (e.g. when
- * scanning through lru lists trying to free resources).
- *
- * The mutex must later on be released by the same task that
- * acquired it. The task may not exit without first unlocking the mutex. Also,
- * kernel memory where the mutex resides must not be freed with the mutex still
- * locked. The mutex must first be initialized (or statically defined) before it
- * can be locked. memset()-ing the mutex to 0 is not allowed. The mutex must be
- * of the same w/w lock class as was used to initialize the acquire context.
- *
- * A mutex acquired with this function must be released with ww_mutex_unlock.
- */
-static inline int ww_mutex_lock(struct ww_mutex *lock, struct ww_acquire_ctx *ctx)
-{
-       if (ctx)
-               return __ww_mutex_lock(lock, ctx);
-       else {
-               mutex_lock(&lock->base);
-               return 0;
-       }
-}
-
-/**
- * ww_mutex_lock_interruptible - acquire the w/w mutex, interruptible
- * @lock: the mutex to be acquired
- * @ctx: w/w acquire context
- *
- * Lock the w/w mutex exclusively for this task.
- *
- * Deadlocks within a given w/w class of locks are detected and handled with the
- * wait/wound algorithm. If the lock isn't immediately avaiable this function
- * will either sleep until it is (wait case). Or it selects the current context
- * for backing off by returning -EDEADLK (wound case). Trying to acquire the
- * same lock with the same context twice is also detected and signalled by
- * returning -EALREADY. Returns 0 if the mutex was successfully acquired. If a
- * signal arrives while waiting for the lock then this function returns -EINTR.
- *
- * In the wound case the caller must release all currently held w/w mutexes for
- * the given context and then wait for this contending lock to be available by
- * calling ww_mutex_lock_slow_interruptible. Alternatively callers can opt to
- * not acquire this lock and proceed with trying to acquire further w/w mutexes
- * (e.g. when scanning through lru lists trying to free resources).
- *
- * The mutex must later on be released by the same task that
- * acquired it. The task may not exit without first unlocking the mutex. Also,
- * kernel memory where the mutex resides must not be freed with the mutex still
- * locked. The mutex must first be initialized (or statically defined) before it
- * can be locked. memset()-ing the mutex to 0 is not allowed. The mutex must be
- * of the same w/w lock class as was used to initialize the acquire context.
- *
- * A mutex acquired with this function must be released with ww_mutex_unlock.
- */
-static inline int __must_check ww_mutex_lock_interruptible(struct ww_mutex *lock,
-                                                          struct ww_acquire_ctx *ctx)
-{
-       if (ctx)
-               return __ww_mutex_lock_interruptible(lock, ctx);
-       else
-               return mutex_lock_interruptible(&lock->base);
-}
-
-/**
- * ww_mutex_lock_slow - slowpath acquiring of the w/w mutex
- * @lock: the mutex to be acquired
- * @ctx: w/w acquire context
- *
- * Acquires a w/w mutex with the given context after a wound case. This function
- * will sleep until the lock becomes available.
- *
- * The caller must have released all w/w mutexes already acquired with the
- * context and then call this function on the contended lock.
- *
- * Afterwards the caller may continue to (re)acquire the other w/w mutexes it
- * needs with ww_mutex_lock. Note that the -EALREADY return code from
- * ww_mutex_lock can be used to avoid locking this contended mutex twice.
- *
- * It is forbidden to call this function with any other w/w mutexes associated
- * with the context held. It is forbidden to call this on anything else than the
- * contending mutex.
- *
- * Note that the slowpath lock acquiring can also be done by calling
- * ww_mutex_lock directly. This function here is simply to help w/w mutex
- * locking code readability by clearly denoting the slowpath.
- */
-static inline void
-ww_mutex_lock_slow(struct ww_mutex *lock, struct ww_acquire_ctx *ctx)
-{
-       int ret;
-#ifdef CONFIG_DEBUG_MUTEXES
-       DEBUG_LOCKS_WARN_ON(!ctx->contending_lock);
-#endif
-       ret = ww_mutex_lock(lock, ctx);
-       (void)ret;
-}
-
-/**
- * ww_mutex_lock_slow_interruptible - slowpath acquiring of the w/w mutex,
- *                                   interruptible
- * @lock: the mutex to be acquired
- * @ctx: w/w acquire context
- *
- * Acquires a w/w mutex with the given context after a wound case. This function
- * will sleep until the lock becomes available and returns 0 when the lock has
- * been acquired. If a signal arrives while waiting for the lock then this
- * function returns -EINTR.
- *
- * The caller must have released all w/w mutexes already acquired with the
- * context and then call this function on the contended lock.
- *
- * Afterwards the caller may continue to (re)acquire the other w/w mutexes it
- * needs with ww_mutex_lock. Note that the -EALREADY return code from
- * ww_mutex_lock can be used to avoid locking this contended mutex twice.
- *
- * It is forbidden to call this function with any other w/w mutexes associated
- * with the given context held. It is forbidden to call this on anything else
- * than the contending mutex.
- *
- * Note that the slowpath lock acquiring can also be done by calling
- * ww_mutex_lock_interruptible directly. This function here is simply to help
- * w/w mutex locking code readability by clearly denoting the slowpath.
- */
-static inline int __must_check
-ww_mutex_lock_slow_interruptible(struct ww_mutex *lock,
-                                struct ww_acquire_ctx *ctx)
-{
-#ifdef CONFIG_DEBUG_MUTEXES
-       DEBUG_LOCKS_WARN_ON(!ctx->contending_lock);
-#endif
-       return ww_mutex_lock_interruptible(lock, ctx);
-}
-
-extern void ww_mutex_unlock(struct ww_mutex *lock);
-
-/**
- * ww_mutex_trylock - tries to acquire the w/w mutex without acquire context
- * @lock: mutex to lock
- *
- * Trylocks a mutex without acquire context, so no deadlock detection is
- * possible. Returns 1 if the mutex has been acquired successfully, 0 otherwise.
- */
-static inline int __must_check ww_mutex_trylock(struct ww_mutex *lock)
-{
-       return mutex_trylock(&lock->base);
-}
-
-/***
- * ww_mutex_destroy - mark a w/w mutex unusable
- * @lock: the mutex to be destroyed
- *
- * This function marks the mutex uninitialized, and any subsequent
- * use of the mutex is forbidden. The mutex must not be locked when
- * this function is called.
- */
-static inline void ww_mutex_destroy(struct ww_mutex *lock)
-{
-       mutex_destroy(&lock->base);
-}
-
-/**
- * ww_mutex_is_locked - is the w/w mutex locked
- * @lock: the mutex to be queried
- *
- * Returns 1 if the mutex is locked, 0 if unlocked.
- */
-static inline bool ww_mutex_is_locked(struct ww_mutex *lock)
-{
-       return mutex_is_locked(&lock->base);
-}
-
 extern int atomic_dec_and_mutex_lock(atomic_t *cnt, struct mutex *lock);
 
 #ifndef CONFIG_HAVE_ARCH_MUTEX_CPU_RELAX
index 09b4188..a450655 100644 (file)
@@ -974,7 +974,7 @@ struct net_device_ops {
        void                    (*ndo_netpoll_cleanup)(struct net_device *dev);
 #endif
 #ifdef CONFIG_NET_LL_RX_POLL
-       int                     (*ndo_ll_poll)(struct napi_struct *dev);
+       int                     (*ndo_busy_poll)(struct napi_struct *dev);
 #endif
        int                     (*ndo_set_vf_mac)(struct net_device *dev,
                                                  int queue, u8 *mac);
index 0b17629..7125cef 100644 (file)
@@ -348,6 +348,7 @@ extern int nfs_permission(struct inode *, int);
 extern int nfs_open(struct inode *, struct file *);
 extern int nfs_release(struct inode *, struct file *);
 extern int nfs_attribute_timeout(struct inode *inode);
+extern int nfs_attribute_cache_expired(struct inode *inode);
 extern int nfs_revalidate_inode(struct nfs_server *server, struct inode *inode);
 extern int __nfs_revalidate_inode(struct nfs_server *, struct inode *);
 extern int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping);
index db50840..6a45fb5 100644 (file)
@@ -46,7 +46,7 @@ static inline bool trigger_all_cpu_backtrace(void)
 #ifdef CONFIG_LOCKUP_DETECTOR
 int hw_nmi_is_cpu_stuck(struct pt_regs *);
 u64 hw_nmi_get_sample_period(int watchdog_thresh);
-extern int watchdog_enabled;
+extern int watchdog_user_enabled;
 extern int watchdog_thresh;
 struct ctl_table;
 extern int proc_dowatchdog(struct ctl_table *, int ,
index b4a0521..d44912d 100644 (file)
@@ -40,5 +40,6 @@ struct esdhc_platform_data {
        enum wp_types wp_type;
        enum cd_types cd_type;
        int max_bus_width;
+       unsigned int f_max;
 };
 #endif /* __ASM_ARCH_IMX_ESDHC_H */
diff --git a/include/linux/platform_data/pwm-renesas-tpu.h b/include/linux/platform_data/pwm-renesas-tpu.h
new file mode 100644 (file)
index 0000000..a7220b1
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef __PWM_RENESAS_TPU_H__
+#define __PWM_RENESAS_TPU_H__
+
+#include <linux/pwm.h>
+
+#define TPU_CHANNEL_MAX                4
+
+struct tpu_pwm_channel_data {
+       enum pwm_polarity polarity;
+};
+
+struct tpu_pwm_platform_data {
+       struct tpu_pwm_channel_data channels[TPU_CHANNEL_MAX];
+};
+
+#endif /* __PWM_RENESAS_TPU_H__ */
index 3c1c644..bfbd12b 100644 (file)
@@ -50,7 +50,7 @@ void __init omap_rproc_reserve_cma(void);
 
 #else
 
-void __init omap_rproc_reserve_cma(void)
+static inline void __init omap_rproc_reserve_cma(void)
 {
 }
 
diff --git a/include/linux/platform_data/ti_am335x_adc.h b/include/linux/platform_data/ti_am335x_adc.h
deleted file mode 100644 (file)
index e41d583..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-#ifndef __LINUX_TI_AM335X_ADC_H
-#define __LINUX_TI_AM335X_ADC_H
-
-/**
- * struct adc_data     ADC Input information
- * @adc_channels:      Number of analog inputs
- *                     available for ADC.
- */
-
-struct adc_data {
-       unsigned int adc_channels;
-};
-
-#endif
index 3828cef..804b906 100644 (file)
@@ -162,6 +162,8 @@ union power_supply_propval {
        const char *strval;
 };
 
+struct device_node;
+
 struct power_supply {
        const char *name;
        enum power_supply_type type;
@@ -173,9 +175,7 @@ struct power_supply {
 
        char **supplied_from;
        size_t num_supplies;
-#ifdef CONFIG_OF
        struct device_node *of_node;
-#endif
 
        int (*get_property)(struct power_supply *psy,
                            enum power_supply_property psp,
index a4df204..f0feafd 100644 (file)
@@ -76,6 +76,7 @@ enum pwm_polarity {
 enum {
        PWMF_REQUESTED = 1 << 0,
        PWMF_ENABLED = 1 << 1,
+       PWMF_EXPORTED = 1 << 2,
 };
 
 struct pwm_device {
@@ -86,7 +87,9 @@ struct pwm_device {
        struct pwm_chip         *chip;
        void                    *chip_data;
 
-       unsigned int            period; /* in nanoseconds */
+       unsigned int            period;         /* in nanoseconds */
+       unsigned int            duty_cycle;     /* in nanoseconds */
+       enum pwm_polarity       polarity;
 };
 
 static inline void pwm_set_period(struct pwm_device *pwm, unsigned int period)
@@ -100,6 +103,17 @@ static inline unsigned int pwm_get_period(struct pwm_device *pwm)
        return pwm ? pwm->period : 0;
 }
 
+static inline void pwm_set_duty_cycle(struct pwm_device *pwm, unsigned int duty)
+{
+       if (pwm)
+               pwm->duty_cycle = duty;
+}
+
+static inline unsigned int pwm_get_duty_cycle(struct pwm_device *pwm)
+{
+       return pwm ? pwm->duty_cycle : 0;
+}
+
 /*
  * pwm_set_polarity - configure the polarity of a PWM signal
  */
@@ -278,4 +292,17 @@ static inline void pwm_add_table(struct pwm_lookup *table, size_t num)
 }
 #endif
 
+#ifdef CONFIG_PWM_SYSFS
+void pwmchip_sysfs_export(struct pwm_chip *chip);
+void pwmchip_sysfs_unexport(struct pwm_chip *chip);
+#else
+static inline void pwmchip_sysfs_export(struct pwm_chip *chip)
+{
+}
+
+static inline void pwmchip_sysfs_unexport(struct pwm_chip *chip)
+{
+}
+#endif /* CONFIG_PWM_SYSFS */
+
 #endif /* __LINUX_PWM_H */
index e9ee806..813dae9 100644 (file)
@@ -39,7 +39,7 @@
 #ifndef _LINUX_RESERVATION_H
 #define _LINUX_RESERVATION_H
 
-#include <linux/mutex.h>
+#include <linux/ww_mutex.h>
 
 extern struct ww_class reservation_ww_class;
 
index f99d57e..50d04b9 100644 (file)
@@ -322,8 +322,6 @@ extern unsigned long
 arch_get_unmapped_area_topdown(struct file *filp, unsigned long addr,
                          unsigned long len, unsigned long pgoff,
                          unsigned long flags);
-extern void arch_unmap_area(struct mm_struct *, unsigned long);
-extern void arch_unmap_area_topdown(struct mm_struct *, unsigned long);
 #else
 static inline void arch_pick_mmap_layout(struct mm_struct *mm) {}
 #endif
index 0c62175..6c5cc0e 100644 (file)
@@ -169,11 +169,7 @@ struct kmem_cache {
        struct list_head list;  /* List of all slab caches on the system */
 };
 
-#define KMALLOC_MAX_SIZE (1UL << 30)
-
-#include <linux/slob_def.h>
-
-#else /* CONFIG_SLOB */
+#endif /* CONFIG_SLOB */
 
 /*
  * Kmalloc array related definitions
@@ -195,7 +191,9 @@ struct kmem_cache {
 #ifndef KMALLOC_SHIFT_LOW
 #define KMALLOC_SHIFT_LOW      5
 #endif
-#else
+#endif
+
+#ifdef CONFIG_SLUB
 /*
  * SLUB allocates up to order 2 pages directly and otherwise
  * passes the request to the page allocator.
@@ -207,6 +205,19 @@ struct kmem_cache {
 #endif
 #endif
 
+#ifdef CONFIG_SLOB
+/*
+ * SLOB passes all page size and larger requests to the page allocator.
+ * No kmalloc array is necessary since objects of different sizes can
+ * be allocated from the same page.
+ */
+#define KMALLOC_SHIFT_MAX      30
+#define KMALLOC_SHIFT_HIGH     PAGE_SHIFT
+#ifndef KMALLOC_SHIFT_LOW
+#define KMALLOC_SHIFT_LOW      3
+#endif
+#endif
+
 /* Maximum allocatable size */
 #define KMALLOC_MAX_SIZE       (1UL << KMALLOC_SHIFT_MAX)
 /* Maximum size for which we actually use a slab cache */
@@ -221,6 +232,7 @@ struct kmem_cache {
 #define KMALLOC_MIN_SIZE (1 << KMALLOC_SHIFT_LOW)
 #endif
 
+#ifndef CONFIG_SLOB
 extern struct kmem_cache *kmalloc_caches[KMALLOC_SHIFT_HIGH + 1];
 #ifdef CONFIG_ZONE_DMA
 extern struct kmem_cache *kmalloc_dma_caches[KMALLOC_SHIFT_HIGH + 1];
@@ -275,13 +287,18 @@ static __always_inline int kmalloc_index(size_t size)
        /* Will never be reached. Needed because the compiler may complain */
        return -1;
 }
+#endif /* !CONFIG_SLOB */
 
 #ifdef CONFIG_SLAB
 #include <linux/slab_def.h>
-#elif defined(CONFIG_SLUB)
+#endif
+
+#ifdef CONFIG_SLUB
 #include <linux/slub_def.h>
-#else
-#error "Unknown slab allocator"
+#endif
+
+#ifdef CONFIG_SLOB
+#include <linux/slob_def.h>
 #endif
 
 /*
@@ -291,6 +308,7 @@ static __always_inline int kmalloc_index(size_t size)
  */
 static __always_inline int kmalloc_size(int n)
 {
+#ifndef CONFIG_SLOB
        if (n > 2)
                return 1 << n;
 
@@ -299,10 +317,9 @@ static __always_inline int kmalloc_size(int n)
 
        if (n == 2 && KMALLOC_MIN_SIZE <= 64)
                return 192;
-
+#endif
        return 0;
 }
-#endif /* !CONFIG_SLOB */
 
 /*
  * Setting ARCH_SLAB_MINALIGN in arch headers allows a different alignment.
@@ -356,9 +373,8 @@ int cache_show(struct kmem_cache *s, struct seq_file *m);
 void print_slabinfo_header(struct seq_file *m);
 
 /**
- * kmalloc_array - allocate memory for an array.
- * @n: number of elements.
- * @size: element size.
+ * kmalloc - allocate memory
+ * @size: how many bytes of memory are required.
  * @flags: the type of memory to allocate.
  *
  * The @flags argument may be one of:
@@ -405,6 +421,17 @@ void print_slabinfo_header(struct seq_file *m);
  * There are other flags available as well, but these are not intended
  * for general use, and so are not documented here. For a full list of
  * potential flags, always refer to linux/gfp.h.
+ *
+ * kmalloc is the normal method of allocating memory
+ * in the kernel.
+ */
+static __always_inline void *kmalloc(size_t size, gfp_t flags);
+
+/**
+ * kmalloc_array - allocate memory for an array.
+ * @n: number of elements.
+ * @size: element size.
+ * @flags: the type of memory to allocate (see kmalloc).
  */
 static inline void *kmalloc_array(size_t n, size_t size, gfp_t flags)
 {
@@ -428,7 +455,7 @@ static inline void *kcalloc(size_t n, size_t size, gfp_t flags)
 /**
  * kmalloc_node - allocate memory from a specific node
  * @size: how many bytes of memory are required.
- * @flags: the type of memory to allocate (see kcalloc).
+ * @flags: the type of memory to allocate (see kmalloc).
  * @node: node to allocate from.
  *
  * kmalloc() for non-local nodes, used to allocate from a specific node
index f28e14a..095a5a4 100644 (file)
@@ -18,14 +18,6 @@ static __always_inline void *kmalloc_node(size_t size, gfp_t flags, int node)
        return __kmalloc_node(size, flags, node);
 }
 
-/**
- * kmalloc - allocate memory
- * @size: how many bytes of memory are required.
- * @flags: the type of memory to allocate (see kcalloc).
- *
- * kmalloc is the normal method of allocating memory
- * in the kernel.
- */
 static __always_inline void *kmalloc(size_t size, gfp_t flags)
 {
        return __kmalloc_node(size, flags, NUMA_NO_NODE);
index b10ce4b..230c04b 100644 (file)
@@ -167,6 +167,7 @@ struct ucred {
 #define AF_PPPOX       24      /* PPPoX sockets                */
 #define AF_WANPIPE     25      /* Wanpipe API Sockets */
 #define AF_LLC         26      /* Linux LLC                    */
+#define AF_IB          27      /* Native InfiniBand address    */
 #define AF_CAN         29      /* Controller Area Network      */
 #define AF_TIPC                30      /* TIPC sockets                 */
 #define AF_BLUETOOTH   31      /* Bluetooth sockets            */
@@ -211,6 +212,7 @@ struct ucred {
 #define PF_PPPOX       AF_PPPOX
 #define PF_WANPIPE     AF_WANPIPE
 #define PF_LLC         AF_LLC
+#define PF_IB          AF_IB
 #define PF_CAN         AF_CAN
 #define PF_TIPC                AF_TIPC
 #define PF_BLUETOOTH   AF_BLUETOOTH
index 09a545a..74575cb 100644 (file)
@@ -35,6 +35,7 @@ struct splice_desc {
                void *data;             /* cookie */
        } u;
        loff_t pos;                     /* file position */
+       loff_t *opos;                   /* sendfile: output position */
        size_t num_spliced;             /* number of bytes already spliced */
        bool need_wakeup;               /* need to wake up writer */
 };
index 303399b..6ce690d 100644 (file)
@@ -57,6 +57,7 @@ struct cache_head {
 #define        CACHE_VALID     0       /* Entry contains valid data */
 #define        CACHE_NEGATIVE  1       /* Negative entry - there is no match for the key */
 #define        CACHE_PENDING   2       /* An upcall has been sent but no reply received yet*/
+#define        CACHE_CLEANED   3       /* Entry has been cleaned from cache */
 
 #define        CACHE_NEW_EXPIRY 120    /* keep new things pending confirmation for 120 seconds */
 
@@ -148,6 +149,24 @@ struct cache_deferred_req {
                                           int too_many);
 };
 
+/*
+ * timestamps kept in the cache are expressed in seconds
+ * since boot.  This is the best for measuring differences in
+ * real time.
+ */
+static inline time_t seconds_since_boot(void)
+{
+       struct timespec boot;
+       getboottime(&boot);
+       return get_seconds() - boot.tv_sec;
+}
+
+static inline time_t convert_to_wallclock(time_t sinceboot)
+{
+       struct timespec boot;
+       getboottime(&boot);
+       return boot.tv_sec + sinceboot;
+}
 
 extern const struct file_operations cache_file_operations_pipefs;
 extern const struct file_operations content_file_operations_pipefs;
@@ -181,15 +200,10 @@ static inline void cache_put(struct cache_head *h, struct cache_detail *cd)
        kref_put(&h->ref, cd->cache_put);
 }
 
-static inline int cache_valid(struct cache_head *h)
+static inline int cache_is_expired(struct cache_detail *detail, struct cache_head *h)
 {
-       /* If an item has been unhashed pending removal when
-        * the refcount drops to 0, the expiry_time will be
-        * set to 0.  We don't want to consider such items
-        * valid in this context even though CACHE_VALID is
-        * set.
-        */
-       return (h->expiry_time != 0 && test_bit(CACHE_VALID, &h->flags));
+       return  (h->expiry_time < seconds_since_boot()) ||
+               (detail->flush_time > h->last_refresh);
 }
 
 extern int cache_check(struct cache_detail *detail,
@@ -250,25 +264,6 @@ static inline int get_uint(char **bpp, unsigned int *anint)
        return 0;
 }
 
-/*
- * timestamps kept in the cache are expressed in seconds
- * since boot.  This is the best for measuring differences in
- * real time.
- */
-static inline time_t seconds_since_boot(void)
-{
-       struct timespec boot;
-       getboottime(&boot);
-       return get_seconds() - boot.tv_sec;
-}
-
-static inline time_t convert_to_wallclock(time_t sinceboot)
-{
-       struct timespec boot;
-       getboottime(&boot);
-       return boot.tv_sec + sinceboot;
-}
-
 static inline time_t get_expiry(char **bpp)
 {
        int rv;
index 161463e..1f911cc 100644 (file)
@@ -151,6 +151,8 @@ struct gss_api_mech *gss_mech_get_by_pseudoflavor(u32);
 /* Fill in an array with a list of supported pseudoflavors */
 int gss_mech_list_pseudoflavors(rpc_authflavor_t *, int);
 
+struct gss_api_mech * gss_mech_get(struct gss_api_mech *);
+
 /* For every successful gss_mech_get or gss_mech_get_by_* call there must be a
  * corresponding call to gss_mech_put. */
 void gss_mech_put(struct gss_api_mech *);
index a7b422b..aa5b582 100644 (file)
@@ -73,12 +73,12 @@ extern ssize_t rpc_pipe_generic_upcall(struct file *, struct rpc_pipe_msg *,
 extern int rpc_queue_upcall(struct rpc_pipe *, struct rpc_pipe_msg *);
 
 struct rpc_clnt;
-extern struct dentry *rpc_create_client_dir(struct dentry *, struct qstr *, struct rpc_clnt *);
+extern struct dentry *rpc_create_client_dir(struct dentry *, const char *, struct rpc_clnt *);
 extern int rpc_remove_client_dir(struct dentry *);
 
 struct cache_detail;
 extern struct dentry *rpc_create_cache_dir(struct dentry *,
-                                          struct qstr *,
+                                          const char *,
                                           umode_t umode,
                                           struct cache_detail *);
 extern void rpc_remove_cache_dir(struct dentry *);
index ff374ab..8d71d65 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/string.h>
 #include <linux/sunrpc/msg_prot.h>
 #include <linux/sunrpc/cache.h>
+#include <linux/sunrpc/gss_api.h>
 #include <linux/hash.h>
 #include <linux/cred.h>
 
@@ -23,13 +24,23 @@ struct svc_cred {
        struct group_info       *cr_group_info;
        u32                     cr_flavor; /* pseudoflavor */
        char                    *cr_principal; /* for gss */
+       struct gss_api_mech     *cr_gss_mech;
 };
 
+static inline void init_svc_cred(struct svc_cred *cred)
+{
+       cred->cr_group_info = NULL;
+       cred->cr_principal = NULL;
+       cred->cr_gss_mech = NULL;
+}
+
 static inline void free_svc_cred(struct svc_cred *cred)
 {
        if (cred->cr_group_info)
                put_group_info(cred->cr_group_info);
        kfree(cred->cr_principal);
+       gss_mech_put(cred->cr_gss_mech);
+       init_svc_cred(cred);
 }
 
 struct svc_rqst;               /* forward decl */
index ca3ad41..b300787 100644 (file)
@@ -1,6 +1,7 @@
 #ifndef _LINUX_VIRTIO_RING_H
 #define _LINUX_VIRTIO_RING_H
 
+#include <asm/barrier.h>
 #include <linux/irqreturn.h>
 #include <uapi/linux/virtio_ring.h>
 
diff --git a/include/linux/ww_mutex.h b/include/linux/ww_mutex.h
new file mode 100644 (file)
index 0000000..760399a
--- /dev/null
@@ -0,0 +1,378 @@
+/*
+ * Wound/Wait Mutexes: blocking mutual exclusion locks with deadlock avoidance
+ *
+ * Original mutex implementation started by Ingo Molnar:
+ *
+ *  Copyright (C) 2004, 2005, 2006 Red Hat, Inc., Ingo Molnar <mingo@redhat.com>
+ *
+ * Wound/wait implementation:
+ *  Copyright (C) 2013 Canonical Ltd.
+ *
+ * This file contains the main data structure and API definitions.
+ */
+
+#ifndef __LINUX_WW_MUTEX_H
+#define __LINUX_WW_MUTEX_H
+
+#include <linux/mutex.h>
+
+struct ww_class {
+       atomic_long_t stamp;
+       struct lock_class_key acquire_key;
+       struct lock_class_key mutex_key;
+       const char *acquire_name;
+       const char *mutex_name;
+};
+
+struct ww_acquire_ctx {
+       struct task_struct *task;
+       unsigned long stamp;
+       unsigned acquired;
+#ifdef CONFIG_DEBUG_MUTEXES
+       unsigned done_acquire;
+       struct ww_class *ww_class;
+       struct ww_mutex *contending_lock;
+#endif
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+       struct lockdep_map dep_map;
+#endif
+#ifdef CONFIG_DEBUG_WW_MUTEX_SLOWPATH
+       unsigned deadlock_inject_interval;
+       unsigned deadlock_inject_countdown;
+#endif
+};
+
+struct ww_mutex {
+       struct mutex base;
+       struct ww_acquire_ctx *ctx;
+#ifdef CONFIG_DEBUG_MUTEXES
+       struct ww_class *ww_class;
+#endif
+};
+
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+# define __WW_CLASS_MUTEX_INITIALIZER(lockname, ww_class) \
+               , .ww_class = &ww_class
+#else
+# define __WW_CLASS_MUTEX_INITIALIZER(lockname, ww_class)
+#endif
+
+#define __WW_CLASS_INITIALIZER(ww_class) \
+               { .stamp = ATOMIC_LONG_INIT(0) \
+               , .acquire_name = #ww_class "_acquire" \
+               , .mutex_name = #ww_class "_mutex" }
+
+#define __WW_MUTEX_INITIALIZER(lockname, class) \
+               { .base = { \__MUTEX_INITIALIZER(lockname) } \
+               __WW_CLASS_MUTEX_INITIALIZER(lockname, class) }
+
+#define DEFINE_WW_CLASS(classname) \
+       struct ww_class classname = __WW_CLASS_INITIALIZER(classname)
+
+#define DEFINE_WW_MUTEX(mutexname, ww_class) \
+       struct ww_mutex mutexname = __WW_MUTEX_INITIALIZER(mutexname, ww_class)
+
+/**
+ * ww_mutex_init - initialize the w/w mutex
+ * @lock: the mutex to be initialized
+ * @ww_class: the w/w class the mutex should belong to
+ *
+ * Initialize the w/w mutex to unlocked state and associate it with the given
+ * class.
+ *
+ * It is not allowed to initialize an already locked mutex.
+ */
+static inline void ww_mutex_init(struct ww_mutex *lock,
+                                struct ww_class *ww_class)
+{
+       __mutex_init(&lock->base, ww_class->mutex_name, &ww_class->mutex_key);
+       lock->ctx = NULL;
+#ifdef CONFIG_DEBUG_MUTEXES
+       lock->ww_class = ww_class;
+#endif
+}
+
+/**
+ * ww_acquire_init - initialize a w/w acquire context
+ * @ctx: w/w acquire context to initialize
+ * @ww_class: w/w class of the context
+ *
+ * Initializes an context to acquire multiple mutexes of the given w/w class.
+ *
+ * Context-based w/w mutex acquiring can be done in any order whatsoever within
+ * a given lock class. Deadlocks will be detected and handled with the
+ * wait/wound logic.
+ *
+ * Mixing of context-based w/w mutex acquiring and single w/w mutex locking can
+ * result in undetected deadlocks and is so forbidden. Mixing different contexts
+ * for the same w/w class when acquiring mutexes can also result in undetected
+ * deadlocks, and is hence also forbidden. Both types of abuse will be caught by
+ * enabling CONFIG_PROVE_LOCKING.
+ *
+ * Nesting of acquire contexts for _different_ w/w classes is possible, subject
+ * to the usual locking rules between different lock classes.
+ *
+ * An acquire context must be released with ww_acquire_fini by the same task
+ * before the memory is freed. It is recommended to allocate the context itself
+ * on the stack.
+ */
+static inline void ww_acquire_init(struct ww_acquire_ctx *ctx,
+                                  struct ww_class *ww_class)
+{
+       ctx->task = current;
+       ctx->stamp = atomic_long_inc_return(&ww_class->stamp);
+       ctx->acquired = 0;
+#ifdef CONFIG_DEBUG_MUTEXES
+       ctx->ww_class = ww_class;
+       ctx->done_acquire = 0;
+       ctx->contending_lock = NULL;
+#endif
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+       debug_check_no_locks_freed((void *)ctx, sizeof(*ctx));
+       lockdep_init_map(&ctx->dep_map, ww_class->acquire_name,
+                        &ww_class->acquire_key, 0);
+       mutex_acquire(&ctx->dep_map, 0, 0, _RET_IP_);
+#endif
+#ifdef CONFIG_DEBUG_WW_MUTEX_SLOWPATH
+       ctx->deadlock_inject_interval = 1;
+       ctx->deadlock_inject_countdown = ctx->stamp & 0xf;
+#endif
+}
+
+/**
+ * ww_acquire_done - marks the end of the acquire phase
+ * @ctx: the acquire context
+ *
+ * Marks the end of the acquire phase, any further w/w mutex lock calls using
+ * this context are forbidden.
+ *
+ * Calling this function is optional, it is just useful to document w/w mutex
+ * code and clearly designated the acquire phase from actually using the locked
+ * data structures.
+ */
+static inline void ww_acquire_done(struct ww_acquire_ctx *ctx)
+{
+#ifdef CONFIG_DEBUG_MUTEXES
+       lockdep_assert_held(ctx);
+
+       DEBUG_LOCKS_WARN_ON(ctx->done_acquire);
+       ctx->done_acquire = 1;
+#endif
+}
+
+/**
+ * ww_acquire_fini - releases a w/w acquire context
+ * @ctx: the acquire context to free
+ *
+ * Releases a w/w acquire context. This must be called _after_ all acquired w/w
+ * mutexes have been released with ww_mutex_unlock.
+ */
+static inline void ww_acquire_fini(struct ww_acquire_ctx *ctx)
+{
+#ifdef CONFIG_DEBUG_MUTEXES
+       mutex_release(&ctx->dep_map, 0, _THIS_IP_);
+
+       DEBUG_LOCKS_WARN_ON(ctx->acquired);
+       if (!config_enabled(CONFIG_PROVE_LOCKING))
+               /*
+                * lockdep will normally handle this,
+                * but fail without anyway
+                */
+               ctx->done_acquire = 1;
+
+       if (!config_enabled(CONFIG_DEBUG_LOCK_ALLOC))
+               /* ensure ww_acquire_fini will still fail if called twice */
+               ctx->acquired = ~0U;
+#endif
+}
+
+extern int __must_check __ww_mutex_lock(struct ww_mutex *lock,
+                                       struct ww_acquire_ctx *ctx);
+extern int __must_check __ww_mutex_lock_interruptible(struct ww_mutex *lock,
+                                                     struct ww_acquire_ctx *ctx);
+
+/**
+ * ww_mutex_lock - acquire the w/w mutex
+ * @lock: the mutex to be acquired
+ * @ctx: w/w acquire context, or NULL to acquire only a single lock.
+ *
+ * Lock the w/w mutex exclusively for this task.
+ *
+ * Deadlocks within a given w/w class of locks are detected and handled with the
+ * wait/wound algorithm. If the lock isn't immediately avaiable this function
+ * will either sleep until it is (wait case). Or it selects the current context
+ * for backing off by returning -EDEADLK (wound case). Trying to acquire the
+ * same lock with the same context twice is also detected and signalled by
+ * returning -EALREADY. Returns 0 if the mutex was successfully acquired.
+ *
+ * In the wound case the caller must release all currently held w/w mutexes for
+ * the given context and then wait for this contending lock to be available by
+ * calling ww_mutex_lock_slow. Alternatively callers can opt to not acquire this
+ * lock and proceed with trying to acquire further w/w mutexes (e.g. when
+ * scanning through lru lists trying to free resources).
+ *
+ * The mutex must later on be released by the same task that
+ * acquired it. The task may not exit without first unlocking the mutex. Also,
+ * kernel memory where the mutex resides must not be freed with the mutex still
+ * locked. The mutex must first be initialized (or statically defined) before it
+ * can be locked. memset()-ing the mutex to 0 is not allowed. The mutex must be
+ * of the same w/w lock class as was used to initialize the acquire context.
+ *
+ * A mutex acquired with this function must be released with ww_mutex_unlock.
+ */
+static inline int ww_mutex_lock(struct ww_mutex *lock, struct ww_acquire_ctx *ctx)
+{
+       if (ctx)
+               return __ww_mutex_lock(lock, ctx);
+
+       mutex_lock(&lock->base);
+       return 0;
+}
+
+/**
+ * ww_mutex_lock_interruptible - acquire the w/w mutex, interruptible
+ * @lock: the mutex to be acquired
+ * @ctx: w/w acquire context
+ *
+ * Lock the w/w mutex exclusively for this task.
+ *
+ * Deadlocks within a given w/w class of locks are detected and handled with the
+ * wait/wound algorithm. If the lock isn't immediately avaiable this function
+ * will either sleep until it is (wait case). Or it selects the current context
+ * for backing off by returning -EDEADLK (wound case). Trying to acquire the
+ * same lock with the same context twice is also detected and signalled by
+ * returning -EALREADY. Returns 0 if the mutex was successfully acquired. If a
+ * signal arrives while waiting for the lock then this function returns -EINTR.
+ *
+ * In the wound case the caller must release all currently held w/w mutexes for
+ * the given context and then wait for this contending lock to be available by
+ * calling ww_mutex_lock_slow_interruptible. Alternatively callers can opt to
+ * not acquire this lock and proceed with trying to acquire further w/w mutexes
+ * (e.g. when scanning through lru lists trying to free resources).
+ *
+ * The mutex must later on be released by the same task that
+ * acquired it. The task may not exit without first unlocking the mutex. Also,
+ * kernel memory where the mutex resides must not be freed with the mutex still
+ * locked. The mutex must first be initialized (or statically defined) before it
+ * can be locked. memset()-ing the mutex to 0 is not allowed. The mutex must be
+ * of the same w/w lock class as was used to initialize the acquire context.
+ *
+ * A mutex acquired with this function must be released with ww_mutex_unlock.
+ */
+static inline int __must_check ww_mutex_lock_interruptible(struct ww_mutex *lock,
+                                                          struct ww_acquire_ctx *ctx)
+{
+       if (ctx)
+               return __ww_mutex_lock_interruptible(lock, ctx);
+       else
+               return mutex_lock_interruptible(&lock->base);
+}
+
+/**
+ * ww_mutex_lock_slow - slowpath acquiring of the w/w mutex
+ * @lock: the mutex to be acquired
+ * @ctx: w/w acquire context
+ *
+ * Acquires a w/w mutex with the given context after a wound case. This function
+ * will sleep until the lock becomes available.
+ *
+ * The caller must have released all w/w mutexes already acquired with the
+ * context and then call this function on the contended lock.
+ *
+ * Afterwards the caller may continue to (re)acquire the other w/w mutexes it
+ * needs with ww_mutex_lock. Note that the -EALREADY return code from
+ * ww_mutex_lock can be used to avoid locking this contended mutex twice.
+ *
+ * It is forbidden to call this function with any other w/w mutexes associated
+ * with the context held. It is forbidden to call this on anything else than the
+ * contending mutex.
+ *
+ * Note that the slowpath lock acquiring can also be done by calling
+ * ww_mutex_lock directly. This function here is simply to help w/w mutex
+ * locking code readability by clearly denoting the slowpath.
+ */
+static inline void
+ww_mutex_lock_slow(struct ww_mutex *lock, struct ww_acquire_ctx *ctx)
+{
+       int ret;
+#ifdef CONFIG_DEBUG_MUTEXES
+       DEBUG_LOCKS_WARN_ON(!ctx->contending_lock);
+#endif
+       ret = ww_mutex_lock(lock, ctx);
+       (void)ret;
+}
+
+/**
+ * ww_mutex_lock_slow_interruptible - slowpath acquiring of the w/w mutex, interruptible
+ * @lock: the mutex to be acquired
+ * @ctx: w/w acquire context
+ *
+ * Acquires a w/w mutex with the given context after a wound case. This function
+ * will sleep until the lock becomes available and returns 0 when the lock has
+ * been acquired. If a signal arrives while waiting for the lock then this
+ * function returns -EINTR.
+ *
+ * The caller must have released all w/w mutexes already acquired with the
+ * context and then call this function on the contended lock.
+ *
+ * Afterwards the caller may continue to (re)acquire the other w/w mutexes it
+ * needs with ww_mutex_lock. Note that the -EALREADY return code from
+ * ww_mutex_lock can be used to avoid locking this contended mutex twice.
+ *
+ * It is forbidden to call this function with any other w/w mutexes associated
+ * with the given context held. It is forbidden to call this on anything else
+ * than the contending mutex.
+ *
+ * Note that the slowpath lock acquiring can also be done by calling
+ * ww_mutex_lock_interruptible directly. This function here is simply to help
+ * w/w mutex locking code readability by clearly denoting the slowpath.
+ */
+static inline int __must_check
+ww_mutex_lock_slow_interruptible(struct ww_mutex *lock,
+                                struct ww_acquire_ctx *ctx)
+{
+#ifdef CONFIG_DEBUG_MUTEXES
+       DEBUG_LOCKS_WARN_ON(!ctx->contending_lock);
+#endif
+       return ww_mutex_lock_interruptible(lock, ctx);
+}
+
+extern void ww_mutex_unlock(struct ww_mutex *lock);
+
+/**
+ * ww_mutex_trylock - tries to acquire the w/w mutex without acquire context
+ * @lock: mutex to lock
+ *
+ * Trylocks a mutex without acquire context, so no deadlock detection is
+ * possible. Returns 1 if the mutex has been acquired successfully, 0 otherwise.
+ */
+static inline int __must_check ww_mutex_trylock(struct ww_mutex *lock)
+{
+       return mutex_trylock(&lock->base);
+}
+
+/***
+ * ww_mutex_destroy - mark a w/w mutex unusable
+ * @lock: the mutex to be destroyed
+ *
+ * This function marks the mutex uninitialized, and any subsequent
+ * use of the mutex is forbidden. The mutex must not be locked when
+ * this function is called.
+ */
+static inline void ww_mutex_destroy(struct ww_mutex *lock)
+{
+       mutex_destroy(&lock->base);
+}
+
+/**
+ * ww_mutex_is_locked - is the w/w mutex locked
+ * @lock: the mutex to be queried
+ *
+ * Returns 1 if the mutex is locked, 0 if unlocked.
+ */
+static inline bool ww_mutex_is_locked(struct ww_mutex *lock)
+{
+       return mutex_is_locked(&lock->base);
+}
+
+#endif
diff --git a/include/linux/zbud.h b/include/linux/zbud.h
new file mode 100644 (file)
index 0000000..2571a5c
--- /dev/null
@@ -0,0 +1,22 @@
+#ifndef _ZBUD_H_
+#define _ZBUD_H_
+
+#include <linux/types.h>
+
+struct zbud_pool;
+
+struct zbud_ops {
+       int (*evict)(struct zbud_pool *pool, unsigned long handle);
+};
+
+struct zbud_pool *zbud_create_pool(gfp_t gfp, struct zbud_ops *ops);
+void zbud_destroy_pool(struct zbud_pool *pool);
+int zbud_alloc(struct zbud_pool *pool, int size, gfp_t gfp,
+       unsigned long *handle);
+void zbud_free(struct zbud_pool *pool, unsigned long handle);
+int zbud_reclaim_page(struct zbud_pool *pool, unsigned int retries);
+void *zbud_map(struct zbud_pool *pool, unsigned long handle);
+void zbud_unmap(struct zbud_pool *pool, unsigned long handle);
+u64 zbud_get_pool_size(struct zbud_pool *pool);
+
+#endif /* _ZBUD_H_ */
index 42628fc..de59364 100644 (file)
@@ -82,9 +82,9 @@ enum osd_pix_format {
        PIXFMT_4BPP,
        PIXFMT_8BPP,
        PIXFMT_RGB565,
-       PIXFMT_YCbCrI,
+       PIXFMT_YCBCRI,
        PIXFMT_RGB888,
-       PIXFMT_YCrCbI,
+       PIXFMT_YCRCBI,
        PIXFMT_NV12,
        PIXFMT_OSD_ATTR,
 };
index eaade98..12155a9 100644 (file)
@@ -45,6 +45,7 @@ struct device;
  * @entities:  List of registered entities
  * @lock:      Entities list lock
  * @graph_mutex: Entities graph operation lock
+ * @link_notify: Link state change notification callback
  *
  * This structure represents an abstract high-level media device. It allows easy
  * access to entities and provides basic media device-level support. The
@@ -75,10 +76,14 @@ struct media_device {
        /* Serializes graph operations. */
        struct mutex graph_mutex;
 
-       int (*link_notify)(struct media_pad *source,
-                          struct media_pad *sink, u32 flags);
+       int (*link_notify)(struct media_link *link, u32 flags,
+                          unsigned int notification);
 };
 
+/* Supported link_notify @notification values. */
+#define MEDIA_DEV_NOTIFY_PRE_LINK_CH   0
+#define MEDIA_DEV_NOTIFY_POST_LINK_CH  1
+
 /* media_devnode to media_device */
 #define to_media_device(node) container_of(node, struct media_device, devnode)
 
index 0c16f51..06bacf9 100644 (file)
@@ -128,11 +128,14 @@ void media_entity_cleanup(struct media_entity *entity);
 
 int media_entity_create_link(struct media_entity *source, u16 source_pad,
                struct media_entity *sink, u16 sink_pad, u32 flags);
+void __media_entity_remove_links(struct media_entity *entity);
+void media_entity_remove_links(struct media_entity *entity);
+
 int __media_entity_setup_link(struct media_link *link, u32 flags);
 int media_entity_setup_link(struct media_link *link, u32 flags);
 struct media_link *media_entity_find_link(struct media_pad *source,
                struct media_pad *sink);
-struct media_pad *media_entity_remote_source(struct media_pad *pad);
+struct media_pad *media_entity_remote_pad(struct media_pad *pad);
 
 struct media_entity *media_entity_get(struct media_entity *entity);
 void media_entity_put(struct media_entity *entity);
index 5d5d3a3..6628f5d 100644 (file)
@@ -111,6 +111,7 @@ void rc_map_init(void);
 #define RC_MAP_BUDGET_CI_OLD             "rc-budget-ci-old"
 #define RC_MAP_CINERGY_1400              "rc-cinergy-1400"
 #define RC_MAP_CINERGY                   "rc-cinergy"
+#define RC_MAP_DELOCK_61959              "rc-delock-61959"
 #define RC_MAP_DIB0700_NEC_TABLE         "rc-dib0700-nec"
 #define RC_MAP_DIB0700_RC5_TABLE         "rc-dib0700-rc5"
 #define RC_MAP_DIGITALNOW_TINYTWIN       "rc-digitalnow-tinytwin"
index f509690..b975c28 100644 (file)
@@ -13,6 +13,7 @@
 #define S5P_FIMC_H_
 
 #include <media/media-entity.h>
+#include <media/v4l2-dev.h>
 #include <media/v4l2-mediabus.h>
 
 /*
@@ -115,6 +116,7 @@ struct s5p_platform_fimc {
  * @color: the driver's private color format id
  * @memplanes: number of physically non-contiguous data planes
  * @colplanes: number of physically contiguous data planes
+ * @colorspace: v4l2 colorspace (V4L2_COLORSPACE_*)
  * @depth: per plane driver's private 'number of bits per pixel'
  * @mdataplanes: bitmask indicating meta data plane(s), (1 << plane_no)
  * @flags: flags indicating which operation mode format applies to
@@ -126,6 +128,7 @@ struct fimc_fmt {
        u32     color;
        u16     memplanes;
        u16     colplanes;
+       u8      colorspace;
        u8      depth[FIMC_MAX_PLANES];
        u16     mdataplanes;
        u16     flags;
@@ -140,37 +143,40 @@ struct fimc_fmt {
 #define FMT_FLAGS_YUV          (1 << 7)
 };
 
-enum fimc_subdev_index {
-       IDX_SENSOR,
-       IDX_CSIS,
-       IDX_FLITE,
-       IDX_IS_ISP,
-       IDX_FIMC,
-       IDX_MAX,
-};
+struct exynos_media_pipeline;
 
-struct media_pipeline;
-struct v4l2_subdev;
+/*
+ * Media pipeline operations to be called from within a video node,  i.e. the
+ * last entity within the pipeline. Implemented by related media device driver.
+ */
+struct exynos_media_pipeline_ops {
+       int (*prepare)(struct exynos_media_pipeline *p,
+                                               struct media_entity *me);
+       int (*unprepare)(struct exynos_media_pipeline *p);
+       int (*open)(struct exynos_media_pipeline *p, struct media_entity *me,
+                                                       bool resume);
+       int (*close)(struct exynos_media_pipeline *p);
+       int (*set_stream)(struct exynos_media_pipeline *p, bool state);
+};
 
-struct fimc_pipeline {
-       struct v4l2_subdev *subdevs[IDX_MAX];
-       struct media_pipeline *m_pipeline;
+struct exynos_video_entity {
+       struct video_device vdev;
+       struct exynos_media_pipeline *pipe;
 };
 
-/*
- * Media pipeline operations to be called from within the fimc(-lite)
- * video node when it is the last entity of the pipeline. Implemented
- * by corresponding media device driver.
- */
-struct fimc_pipeline_ops {
-       int (*open)(struct fimc_pipeline *p, struct media_entity *me,
-                         bool resume);
-       int (*close)(struct fimc_pipeline *p);
-       int (*set_stream)(struct fimc_pipeline *p, bool state);
+struct exynos_media_pipeline {
+       struct media_pipeline mp;
+       const struct exynos_media_pipeline_ops *ops;
 };
 
-#define fimc_pipeline_call(f, op, p, args...)                          \
-       (!(f) ? -ENODEV : (((f)->pipeline_ops && (f)->pipeline_ops->op) ? \
-                           (f)->pipeline_ops->op((p), ##args) : -ENOIOCTLCMD))
+static inline struct exynos_video_entity *vdev_to_exynos_video_entity(
+                                       struct video_device *vdev)
+{
+       return container_of(vdev, struct exynos_video_entity, vdev);
+}
+
+#define fimc_pipeline_call(ent, op, args...)                             \
+       (!(ent) ? -ENOENT : (((ent)->pipe->ops && (ent)->pipe->ops->op) ? \
+       (ent)->pipe->ops->op(((ent)->pipe), ##args) : -ENOIOCTLCMD))      \
 
 #endif /* S5P_FIMC_H_ */
index 6fdb6ad..7f57056 100644 (file)
@@ -22,6 +22,8 @@ struct sh_mobile_ceu_info {
        int max_width;
        int max_height;
        struct sh_mobile_ceu_companion *csi2;
+       struct v4l2_async_subdev **asd; /* Flat array, arranged in groups */
+       unsigned int *asd_sizes;        /* 0-terminated array pf asd group sizes */
 };
 
 #endif /* __ASM_SH_MOBILE_CEU_H__ */
index c586c4f..14030db 100644 (file)
@@ -33,6 +33,7 @@ struct sh_csi2_client_config {
        unsigned char lanes;            /* bitmask[3:0] */
        unsigned char channel;          /* 0..3 */
        struct platform_device *pdev;   /* client platform device */
+       const char *name;               /* async matching: client name */
 };
 
 struct v4l2_device;
@@ -42,7 +43,6 @@ struct sh_csi2_pdata {
        unsigned int flags;
        struct sh_csi2_client_config *clients;
        int num_clients;
-       struct v4l2_device *v4l2_dev;
 };
 
 #endif
index ff77d08..34d2414 100644 (file)
 #include <linux/videodev2.h>
 #include <media/videobuf-core.h>
 #include <media/videobuf2-core.h>
+#include <media/v4l2-async.h>
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-device.h>
 
 struct file;
 struct soc_camera_desc;
+struct soc_camera_async_client;
 
 struct soc_camera_device {
        struct list_head list;          /* list of all registered devices */
@@ -49,6 +51,10 @@ struct soc_camera_device {
        /* soc_camera.c private count. Only accessed with .host_lock held */
        int use_count;
        struct file *streamer;          /* stream owner */
+       struct v4l2_clk *clk;
+       /* Asynchronous subdevice management */
+       struct soc_camera_async_client *sasc;
+       /* video buffer queue */
        union {
                struct videobuf_queue vb_vidq;
                struct vb2_queue vb2_vidq;
@@ -58,21 +64,38 @@ struct soc_camera_device {
 /* Host supports programmable stride */
 #define SOCAM_HOST_CAP_STRIDE          (1 << 0)
 
+enum soc_camera_subdev_role {
+       SOCAM_SUBDEV_DATA_SOURCE = 1,
+       SOCAM_SUBDEV_DATA_SINK,
+       SOCAM_SUBDEV_DATA_PROCESSOR,
+};
+
+struct soc_camera_async_subdev {
+       struct v4l2_async_subdev asd;
+       enum soc_camera_subdev_role role;
+};
+
 struct soc_camera_host {
        struct v4l2_device v4l2_dev;
        struct list_head list;
-       struct mutex host_lock;         /* Protect pipeline modifications */
+       struct mutex host_lock;         /* Main synchronisation lock */
+       struct mutex clk_lock;          /* Protect pipeline modifications */
        unsigned char nr;               /* Host number */
        u32 capabilities;
+       struct soc_camera_device *icd;  /* Currently attached client */
        void *priv;
        const char *drv_name;
        struct soc_camera_host_ops *ops;
+       struct v4l2_async_subdev **asd; /* Flat array, arranged in groups */
+       unsigned int *asd_sizes;        /* 0-terminated array of asd group sizes */
 };
 
 struct soc_camera_host_ops {
        struct module *owner;
        int (*add)(struct soc_camera_device *);
        void (*remove)(struct soc_camera_device *);
+       int (*clock_start)(struct soc_camera_host *);
+       void (*clock_stop)(struct soc_camera_host *);
        /*
         * .get_formats() is called for each client device format, but
         * .put_formats() is only called once. Further, if any of the calls to
@@ -157,6 +180,7 @@ struct soc_camera_host_desc {
 };
 
 /*
+ * Platform data for "soc-camera-pdrv"
  * This MUST be kept binary-identical to struct soc_camera_link below, until
  * it is completely replaced by this one, after which we can split it into its
  * two components.
@@ -322,14 +346,17 @@ static inline void soc_camera_limit_side(int *start, int *length,
 unsigned long soc_camera_apply_board_flags(struct soc_camera_subdev_desc *ssdd,
                                           const struct v4l2_mbus_config *cfg);
 
-int soc_camera_power_on(struct device *dev, struct soc_camera_subdev_desc *ssdd);
-int soc_camera_power_off(struct device *dev, struct soc_camera_subdev_desc *ssdd);
+int soc_camera_power_init(struct device *dev, struct soc_camera_subdev_desc *ssdd);
+int soc_camera_power_on(struct device *dev, struct soc_camera_subdev_desc *ssdd,
+                       struct v4l2_clk *clk);
+int soc_camera_power_off(struct device *dev, struct soc_camera_subdev_desc *ssdd,
+                        struct v4l2_clk *clk);
 
 static inline int soc_camera_set_power(struct device *dev,
-                               struct soc_camera_subdev_desc *ssdd, bool on)
+               struct soc_camera_subdev_desc *ssdd, struct v4l2_clk *clk, bool on)
 {
-       return on ? soc_camera_power_on(dev, ssdd)
-                 : soc_camera_power_off(dev, ssdd);
+       return on ? soc_camera_power_on(dev, ssdd, clk)
+                 : soc_camera_power_off(dev, ssdd, clk);
 }
 
 /* This is only temporary here - until v4l2-subdev begins to link to video_device */
@@ -346,9 +373,9 @@ static inline struct soc_camera_subdev_desc *soc_camera_i2c_to_desc(const struct
        return client->dev.platform_data;
 }
 
-static inline struct v4l2_subdev *soc_camera_vdev_to_subdev(const struct video_device *vdev)
+static inline struct v4l2_subdev *soc_camera_vdev_to_subdev(struct video_device *vdev)
 {
-       struct soc_camera_device *icd = dev_get_drvdata(vdev->parent);
+       struct soc_camera_device *icd = video_get_drvdata(vdev);
        return soc_camera_to_subdev(icd);
 }
 
index 980ec51..a7b4929 100644 (file)
  * @ch_1: Bias value for channel one.
  * @ch_2: Bias value for channel two.
  * @ch_3: Bias value for channel three.
- * @init_enable: initalize on init.
  */
 struct ths7303_platform_data {
        u8 ch_1;
        u8 ch_2;
        u8 ch_3;
-       u8 init_enable;
 };
 
 #endif
index a8ad75a..4a1191a 100644 (file)
@@ -1,6 +1,17 @@
 /*
  */
 
+enum tveeprom_audio_processor {
+       /* No audio processor present */
+       TVEEPROM_AUDPROC_NONE,
+       /* The audio processor is internal to the video processor */
+       TVEEPROM_AUDPROC_INTERNAL,
+       /* The audio processor is a MSPXXXX device */
+       TVEEPROM_AUDPROC_MSP,
+       /* The audio processor is another device */
+       TVEEPROM_AUDPROC_OTHER,
+};
+
 struct tveeprom {
        u32 has_radio;
        /* If has_ir == 0, then it is unknown what the IR capabilities are,
index ee43534..fadb6af 100644 (file)
 #ifndef _TVP7002_H_
 #define _TVP7002_H_
 
-/* Platform-dependent data
- *
- * clk_polarity:
- *                     0 -> data clocked out on rising edge of DATACLK signal
- *                     1 -> data clocked out on falling edge of DATACLK signal
- * hs_polarity:
- *                     0 -> active low HSYNC output
- *                     1 -> active high HSYNC output
- * sog_polarity:
- *                     0 -> normal operation
- *                     1 -> operation with polarity inverted
- * vs_polarity:
- *                     0 -> active low VSYNC output
- *                     1 -> active high VSYNC output
- * fid_polarity:
- *                     0 -> the field ID output is set to logic 1 for an odd
- *                          field (field 1) and set to logic 0 for an even
- *                          field (field 0).
- *                     1 -> operation with polarity inverted.
+#define TVP7002_MODULE_NAME "tvp7002"
+
+/**
+ * struct tvp7002_config - Platform dependent data
+ *@clk_polarity: Clock polarity
+ *             0 - Data clocked out on rising edge of DATACLK signal
+ *             1 - Data clocked out on falling edge of DATACLK signal
+ *@hs_polarity:  HSYNC polarity
+ *             0 - Active low HSYNC output, 1 - Active high HSYNC output
+ *@vs_polarity: VSYNC Polarity
+ *             0 - Active low VSYNC output, 1 - Active high VSYNC output
+ *@fid_polarity: Active-high Field ID polarity.
+ *             0 - The field ID output is set to logic 1 for an odd field
+ *                 (field 1) and set to logic 0 for an even field (field 0).
+ *             1 - Operation with polarity inverted.
+ *@sog_polarity: Active high Sync on Green output polarity.
+ *             0 - Normal operation, 1 - Operation with polarity inverted
  */
 struct tvp7002_config {
-       u8 clk_polarity;
-       u8 hs_polarity;
-       u8 vs_polarity;
-       u8 fid_polarity;
-       u8 sog_polarity;
+       bool clk_polarity;
+       bool hs_polarity;
+       bool vs_polarity;
+       bool fid_polarity;
+       bool sog_polarity;
 };
 #endif
diff --git a/include/media/v4l2-async.h b/include/media/v4l2-async.h
new file mode 100644 (file)
index 0000000..c3ec6ac
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * V4L2 asynchronous subdevice registration API
+ *
+ * Copyright (C) 2012-2013, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef V4L2_ASYNC_H
+#define V4L2_ASYNC_H
+
+#include <linux/list.h>
+#include <linux/mutex.h>
+
+struct device;
+struct v4l2_device;
+struct v4l2_subdev;
+struct v4l2_async_notifier;
+
+/* A random max subdevice number, used to allocate an array on stack */
+#define V4L2_MAX_SUBDEVS 128U
+
+enum v4l2_async_bus_type {
+       V4L2_ASYNC_BUS_CUSTOM,
+       V4L2_ASYNC_BUS_PLATFORM,
+       V4L2_ASYNC_BUS_I2C,
+};
+
+/**
+ * struct v4l2_async_subdev - sub-device descriptor, as known to a bridge
+ * @bus_type:  subdevice bus type to select the appropriate matching method
+ * @match:     union of per-bus type matching data sets
+ * @list:      used to link struct v4l2_async_subdev objects, waiting to be
+ *             probed, to a notifier->waiting list
+ */
+struct v4l2_async_subdev {
+       enum v4l2_async_bus_type bus_type;
+       union {
+               struct {
+                       const char *name;
+               } platform;
+               struct {
+                       int adapter_id;
+                       unsigned short address;
+               } i2c;
+               struct {
+                       bool (*match)(struct device *,
+                                     struct v4l2_async_subdev *);
+                       void *priv;
+               } custom;
+       } match;
+
+       /* v4l2-async core private: not to be used by drivers */
+       struct list_head list;
+};
+
+/**
+ * v4l2_async_subdev_list - provided by subdevices
+ * @list:      links struct v4l2_async_subdev_list objects to a global list
+ *             before probing, and onto notifier->done after probing
+ * @asd:       pointer to respective struct v4l2_async_subdev
+ * @notifier:  pointer to managing notifier
+ */
+struct v4l2_async_subdev_list {
+       struct list_head list;
+       struct v4l2_async_subdev *asd;
+       struct v4l2_async_notifier *notifier;
+};
+
+/**
+ * v4l2_async_notifier - v4l2_device notifier data
+ * @num_subdevs:number of subdevices
+ * @subdev:    array of pointers to subdevice descriptors
+ * @v4l2_dev:  pointer to struct v4l2_device
+ * @waiting:   list of struct v4l2_async_subdev, waiting for their drivers
+ * @done:      list of struct v4l2_async_subdev_list, already probed
+ * @list:      member in a global list of notifiers
+ * @bound:     a subdevice driver has successfully probed one of subdevices
+ * @complete:  all subdevices have been probed successfully
+ * @unbind:    a subdevice is leaving
+ */
+struct v4l2_async_notifier {
+       unsigned int num_subdevs;
+       struct v4l2_async_subdev **subdev;
+       struct v4l2_device *v4l2_dev;
+       struct list_head waiting;
+       struct list_head done;
+       struct list_head list;
+       int (*bound)(struct v4l2_async_notifier *notifier,
+                    struct v4l2_subdev *subdev,
+                    struct v4l2_async_subdev *asd);
+       int (*complete)(struct v4l2_async_notifier *notifier);
+       void (*unbind)(struct v4l2_async_notifier *notifier,
+                      struct v4l2_subdev *subdev,
+                      struct v4l2_async_subdev *asd);
+};
+
+int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
+                                struct v4l2_async_notifier *notifier);
+void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier);
+int v4l2_async_register_subdev(struct v4l2_subdev *sd);
+void v4l2_async_unregister_subdev(struct v4l2_subdev *sd);
+#endif
diff --git a/include/media/v4l2-chip-ident.h b/include/media/v4l2-chip-ident.h
deleted file mode 100644 (file)
index c259b36..0000000
+++ /dev/null
@@ -1,352 +0,0 @@
-/*
-    v4l2 chip identifiers header
-
-    This header provides a list of chip identifiers that can be returned
-    through the VIDIOC_DBG_G_CHIP_IDENT ioctl.
-
-    Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-#ifndef V4L2_CHIP_IDENT_H_
-#define V4L2_CHIP_IDENT_H_
-
-/* VIDIOC_DBG_G_CHIP_IDENT: identifies the actual chip installed on the board */
-
-/* KEEP THIS LIST ORDERED BY ID!
-   Otherwise it will be hard to see which ranges are already in use when
-   adding support to a new chip family. */
-enum {
-       /* general idents: reserved range 0-49 */
-       V4L2_IDENT_NONE      = 0,       /* No chip matched */
-       V4L2_IDENT_AMBIGUOUS = 1,       /* Match too general, multiple chips matched */
-       V4L2_IDENT_UNKNOWN   = 2,       /* Chip found, but cannot identify */
-
-       /* module tvaudio: reserved range 50-99 */
-       V4L2_IDENT_TVAUDIO = 50,        /* A tvaudio chip, unknown which it is exactly */
-
-       /* Sony IMX074 */
-       V4L2_IDENT_IMX074 = 74,
-
-       /* module saa7110: just ident 100 */
-       V4L2_IDENT_SAA7110 = 100,
-
-       /* module saa7115: reserved range 101-149 */
-       V4L2_IDENT_SAA7111 = 101,
-       V4L2_IDENT_SAA7111A = 102,
-       V4L2_IDENT_SAA7113 = 103,
-       V4L2_IDENT_SAA7114 = 104,
-       V4L2_IDENT_SAA7115 = 105,
-       V4L2_IDENT_SAA7118 = 108,
-
-       /* module saa7127: reserved range 150-199 */
-       V4L2_IDENT_SAA7127 = 157,
-       V4L2_IDENT_SAA7129 = 159,
-
-       /* module cx25840: reserved range 200-249 */
-       V4L2_IDENT_CX25836 = 236,
-       V4L2_IDENT_CX25837 = 237,
-       V4L2_IDENT_CX25840 = 240,
-       V4L2_IDENT_CX25841 = 241,
-       V4L2_IDENT_CX25842 = 242,
-       V4L2_IDENT_CX25843 = 243,
-
-       /* OmniVision sensors: reserved range 250-299 */
-       V4L2_IDENT_OV7670 = 250,
-       V4L2_IDENT_OV7720 = 251,
-       V4L2_IDENT_OV7725 = 252,
-       V4L2_IDENT_OV7660 = 253,
-       V4L2_IDENT_OV9650 = 254,
-       V4L2_IDENT_OV9655 = 255,
-       V4L2_IDENT_SOI968 = 256,
-       V4L2_IDENT_OV9640 = 257,
-       V4L2_IDENT_OV6650 = 258,
-       V4L2_IDENT_OV2640 = 259,
-       V4L2_IDENT_OV9740 = 260,
-       V4L2_IDENT_OV5642 = 261,
-
-       /* module saa7146: reserved range 300-309 */
-       V4L2_IDENT_SAA7146 = 300,
-
-       /* Conexant MPEG encoder/decoders: reserved range 400-420 */
-       V4L2_IDENT_CX23418_843 = 403, /* Integrated A/V Decoder on the '418 */
-       V4L2_IDENT_CX23415 = 415,
-       V4L2_IDENT_CX23416 = 416,
-       V4L2_IDENT_CX23417 = 417,
-       V4L2_IDENT_CX23418 = 418,
-
-       /* module bt819: reserved range 810-819 */
-       V4L2_IDENT_BT815A = 815,
-       V4L2_IDENT_BT817A = 817,
-       V4L2_IDENT_BT819A = 819,
-
-       /* module au0828 */
-       V4L2_IDENT_AU0828 = 828,
-
-       /* module bttv: ident 848 + 849 */
-       V4L2_IDENT_BT848 = 848,
-       V4L2_IDENT_BT849 = 849,
-
-       /* module bt856: just ident 856 */
-       V4L2_IDENT_BT856 = 856,
-
-       /* module bt866: just ident 866 */
-       V4L2_IDENT_BT866 = 866,
-
-       /* module bttv: ident 878 + 879 */
-       V4L2_IDENT_BT878 = 878,
-       V4L2_IDENT_BT879 = 879,
-
-       /* module ks0127: reserved range 1120-1129 */
-       V4L2_IDENT_KS0122S = 1122,
-       V4L2_IDENT_KS0127  = 1127,
-       V4L2_IDENT_KS0127B = 1128,
-
-       /* module indycam: just ident 2000 */
-       V4L2_IDENT_INDYCAM = 2000,
-
-       /* module vp27smpx: just ident 2700 */
-       V4L2_IDENT_VP27SMPX = 2700,
-
-       /* module vpx3220: reserved range: 3210-3229 */
-       V4L2_IDENT_VPX3214C = 3214,
-       V4L2_IDENT_VPX3216B = 3216,
-       V4L2_IDENT_VPX3220A = 3220,
-
-       /* VX855 just ident 3409 */
-       /* Other via devs could use 3314, 3324, 3327, 3336, 3364, 3353 */
-       V4L2_IDENT_VIA_VX855 = 3409,
-
-       /* module tvp5150 */
-       V4L2_IDENT_TVP5150 = 5150,
-
-       /* module saa5246a: just ident 5246 */
-       V4L2_IDENT_SAA5246A = 5246,
-
-       /* module saa5249: just ident 5249 */
-       V4L2_IDENT_SAA5249 = 5249,
-
-       /* module cs5345: just ident 5345 */
-       V4L2_IDENT_CS5345 = 5345,
-
-       /* module tea6415c: just ident 6415 */
-       V4L2_IDENT_TEA6415C = 6415,
-
-       /* module tea6420: just ident 6420 */
-       V4L2_IDENT_TEA6420 = 6420,
-
-       /* module saa6588: just ident 6588 */
-       V4L2_IDENT_SAA6588 = 6588,
-
-       /* module vs6624: just ident 6624 */
-       V4L2_IDENT_VS6624 = 6624,
-
-       /* module saa6752hs: reserved range 6750-6759 */
-       V4L2_IDENT_SAA6752HS = 6752,
-       V4L2_IDENT_SAA6752HS_AC3 = 6753,
-
-       /* modules tef6862: just ident 6862 */
-       V4L2_IDENT_TEF6862 = 6862,
-
-       /* module tvp7002: just ident 7002 */
-       V4L2_IDENT_TVP7002 = 7002,
-
-       /* module adv7170: just ident 7170 */
-       V4L2_IDENT_ADV7170 = 7170,
-
-       /* module adv7175: just ident 7175 */
-       V4L2_IDENT_ADV7175 = 7175,
-
-       /* module adv7180: just ident 7180 */
-       V4L2_IDENT_ADV7180 = 7180,
-
-       /* module adv7183: just ident 7183 */
-       V4L2_IDENT_ADV7183 = 7183,
-
-       /* module saa7185: just ident 7185 */
-       V4L2_IDENT_SAA7185 = 7185,
-
-       /* module saa7191: just ident 7191 */
-       V4L2_IDENT_SAA7191 = 7191,
-
-       /* module ths7303: just ident 7303 */
-       V4L2_IDENT_THS7303 = 7303,
-
-       /* module adv7343: just ident 7343 */
-       V4L2_IDENT_ADV7343 = 7343,
-
-       /* module ths7353: just ident 7353 */
-       V4L2_IDENT_THS7353 = 7353,
-
-       /* module adv7393: just ident 7393 */
-       V4L2_IDENT_ADV7393 = 7393,
-
-       /* module adv7604: just ident 7604 */
-       V4L2_IDENT_ADV7604 = 7604,
-
-       /* module saa7706h: just ident 7706 */
-       V4L2_IDENT_SAA7706H = 7706,
-
-       /* module mt9v011, just ident 8243 */
-       V4L2_IDENT_MT9V011 = 8243,
-
-       /* module wm8739: just ident 8739 */
-       V4L2_IDENT_WM8739 = 8739,
-
-       /* module wm8775: just ident 8775 */
-       V4L2_IDENT_WM8775 = 8775,
-
-       /* Marvell controllers starting at 8801 */
-       V4L2_IDENT_CAFE = 8801,
-       V4L2_IDENT_ARMADA610 = 8802,
-
-       /* AKM AK8813/AK8814 */
-       V4L2_IDENT_AK8813 = 8813,
-       V4L2_IDENT_AK8814 = 8814,
-
-       /* module cx23885 and cx25840 */
-       V4L2_IDENT_CX23885    = 8850,
-       V4L2_IDENT_CX23885_AV = 8851, /* Integrated A/V decoder */
-       V4L2_IDENT_CX23887    = 8870,
-       V4L2_IDENT_CX23887_AV = 8871, /* Integrated A/V decoder */
-       V4L2_IDENT_CX23888    = 8880,
-       V4L2_IDENT_CX23888_AV = 8881, /* Integrated A/V decoder */
-       V4L2_IDENT_CX23888_IR = 8882, /* Integrated infrared controller */
-
-       /* module ad9389b: just ident 9389 */
-       V4L2_IDENT_AD9389B = 9389,
-
-       /* module tda9840: just ident 9840 */
-       V4L2_IDENT_TDA9840 = 9840,
-
-       /* module tw9910: just ident 9910 */
-       V4L2_IDENT_TW9910 = 9910,
-
-       /* module sn9c20x: just ident 10000 */
-       V4L2_IDENT_SN9C20X = 10000,
-
-       /* module cx231xx and cx25840 */
-       V4L2_IDENT_CX2310X_AV = 23099, /* Integrated A/V decoder; not in '100 */
-       V4L2_IDENT_CX23100    = 23100,
-       V4L2_IDENT_CX23101    = 23101,
-       V4L2_IDENT_CX23102    = 23102,
-
-       /* module msp3400: reserved range 34000-34999 for msp34xx */
-       V4L2_IDENT_MSPX4XX  = 34000, /* generic MSPX4XX identifier, only
-                                       use internally (tveeprom.c). */
-
-       V4L2_IDENT_MSP3400B = 34002,
-       V4L2_IDENT_MSP3400C = 34003,
-       V4L2_IDENT_MSP3400D = 34004,
-       V4L2_IDENT_MSP3400G = 34007,
-       V4L2_IDENT_MSP3401G = 34017,
-       V4L2_IDENT_MSP3402G = 34027,
-       V4L2_IDENT_MSP3405D = 34054,
-       V4L2_IDENT_MSP3405G = 34057,
-       V4L2_IDENT_MSP3407D = 34074,
-       V4L2_IDENT_MSP3407G = 34077,
-
-       V4L2_IDENT_MSP3410B = 34102,
-       V4L2_IDENT_MSP3410C = 34103,
-       V4L2_IDENT_MSP3410D = 34104,
-       V4L2_IDENT_MSP3410G = 34107,
-       V4L2_IDENT_MSP3411G = 34117,
-       V4L2_IDENT_MSP3412G = 34127,
-       V4L2_IDENT_MSP3415D = 34154,
-       V4L2_IDENT_MSP3415G = 34157,
-       V4L2_IDENT_MSP3417D = 34174,
-       V4L2_IDENT_MSP3417G = 34177,
-
-       V4L2_IDENT_MSP3420G = 34207,
-       V4L2_IDENT_MSP3421G = 34217,
-       V4L2_IDENT_MSP3422G = 34227,
-       V4L2_IDENT_MSP3425G = 34257,
-       V4L2_IDENT_MSP3427G = 34277,
-
-       V4L2_IDENT_MSP3430G = 34307,
-       V4L2_IDENT_MSP3431G = 34317,
-       V4L2_IDENT_MSP3435G = 34357,
-       V4L2_IDENT_MSP3437G = 34377,
-
-       V4L2_IDENT_MSP3440G = 34407,
-       V4L2_IDENT_MSP3441G = 34417,
-       V4L2_IDENT_MSP3442G = 34427,
-       V4L2_IDENT_MSP3445G = 34457,
-       V4L2_IDENT_MSP3447G = 34477,
-
-       V4L2_IDENT_MSP3450G = 34507,
-       V4L2_IDENT_MSP3451G = 34517,
-       V4L2_IDENT_MSP3452G = 34527,
-       V4L2_IDENT_MSP3455G = 34557,
-       V4L2_IDENT_MSP3457G = 34577,
-
-       V4L2_IDENT_MSP3460G = 34607,
-       V4L2_IDENT_MSP3461G = 34617,
-       V4L2_IDENT_MSP3465G = 34657,
-       V4L2_IDENT_MSP3467G = 34677,
-
-       /* module msp3400: reserved range 44000-44999 for msp44xx */
-       V4L2_IDENT_MSP4400G = 44007,
-       V4L2_IDENT_MSP4408G = 44087,
-       V4L2_IDENT_MSP4410G = 44107,
-       V4L2_IDENT_MSP4418G = 44187,
-       V4L2_IDENT_MSP4420G = 44207,
-       V4L2_IDENT_MSP4428G = 44287,
-       V4L2_IDENT_MSP4440G = 44407,
-       V4L2_IDENT_MSP4448G = 44487,
-       V4L2_IDENT_MSP4450G = 44507,
-       V4L2_IDENT_MSP4458G = 44587,
-
-       /* Micron CMOS sensor chips: 45000-45099 */
-       V4L2_IDENT_MT9M001C12ST         = 45000,
-       V4L2_IDENT_MT9M001C12STM        = 45005,
-       V4L2_IDENT_MT9M111              = 45007,
-       V4L2_IDENT_MT9M112              = 45008,
-       V4L2_IDENT_MT9V022IX7ATC        = 45010, /* No way to detect "normal" I77ATx */
-       V4L2_IDENT_MT9V022IX7ATM        = 45015, /* and "lead free" IA7ATx chips */
-       V4L2_IDENT_MT9T031              = 45020,
-       V4L2_IDENT_MT9T111              = 45021,
-       V4L2_IDENT_MT9T112              = 45022,
-       V4L2_IDENT_MT9V111              = 45031,
-       V4L2_IDENT_MT9V112              = 45032,
-
-       /* HV7131R CMOS sensor: just ident 46000 */
-       V4L2_IDENT_HV7131R              = 46000,
-
-       /* Sharp RJ54N1CB0C, 0xCB0C = 51980 */
-       V4L2_IDENT_RJ54N1CB0C = 51980,
-
-       /* module m52790: just ident 52790 */
-       V4L2_IDENT_M52790 = 52790,
-
-       /* module cs53132a: just ident 53132 */
-       V4L2_IDENT_CS53l32A = 53132,
-
-       /* modules upd61151 MPEG2 encoder: just ident 54000 */
-       V4L2_IDENT_UPD61161 = 54000,
-       /* modules upd61152 MPEG2 encoder with AC3: just ident 54001 */
-       V4L2_IDENT_UPD61162 = 54001,
-
-       /* module upd64031a: just ident 64031 */
-       V4L2_IDENT_UPD64031A = 64031,
-
-       /* module upd64083: just ident 64083 */
-       V4L2_IDENT_UPD64083 = 64083,
-
-       /* Don't just add new IDs at the end: KEEP THIS LIST ORDERED BY ID! */
-};
-
-#endif
diff --git a/include/media/v4l2-clk.h b/include/media/v4l2-clk.h
new file mode 100644 (file)
index 0000000..0503a90
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * V4L2 clock service
+ *
+ * Copyright (C) 2012-2013, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * ATTENTION: This is a temporary API and it shall be replaced by the generic
+ * clock API, when the latter becomes widely available.
+ */
+
+#ifndef MEDIA_V4L2_CLK_H
+#define MEDIA_V4L2_CLK_H
+
+#include <linux/atomic.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+
+struct module;
+struct device;
+
+struct v4l2_clk {
+       struct list_head list;
+       const struct v4l2_clk_ops *ops;
+       const char *dev_id;
+       const char *id;
+       int enable;
+       struct mutex lock; /* Protect the enable count */
+       atomic_t use_count;
+       void *priv;
+};
+
+struct v4l2_clk_ops {
+       struct module   *owner;
+       int             (*enable)(struct v4l2_clk *clk);
+       void            (*disable)(struct v4l2_clk *clk);
+       unsigned long   (*get_rate)(struct v4l2_clk *clk);
+       int             (*set_rate)(struct v4l2_clk *clk, unsigned long);
+};
+
+struct v4l2_clk *v4l2_clk_register(const struct v4l2_clk_ops *ops,
+                                  const char *dev_name,
+                                  const char *name, void *priv);
+void v4l2_clk_unregister(struct v4l2_clk *clk);
+struct v4l2_clk *v4l2_clk_get(struct device *dev, const char *id);
+void v4l2_clk_put(struct v4l2_clk *clk);
+int v4l2_clk_enable(struct v4l2_clk *clk);
+void v4l2_clk_disable(struct v4l2_clk *clk);
+unsigned long v4l2_clk_get_rate(struct v4l2_clk *clk);
+int v4l2_clk_set_rate(struct v4l2_clk *clk, unsigned long rate);
+
+#endif
index 1d93c48..015ff82 100644 (file)
@@ -100,16 +100,6 @@ u32 v4l2_ctrl_next(const u32 * const *ctrl_classes, u32 id);
 
 /* ------------------------------------------------------------------------- */
 
-/* Register/chip ident helper function */
-
-struct i2c_client; /* forward reference */
-int v4l2_chip_match_i2c_client(struct i2c_client *c, const struct v4l2_dbg_match *match);
-int v4l2_chip_ident_i2c_client(struct i2c_client *c, struct v4l2_dbg_chip_ident *chip,
-               u32 ident, u32 revision);
-int v4l2_chip_match_host(const struct v4l2_dbg_match *match);
-
-/* ------------------------------------------------------------------------- */
-
 /* I2C Helper functions */
 
 struct i2c_driver;
index 95d1c91..c768c9f 100644 (file)
@@ -96,9 +96,9 @@ struct video_device
        struct device dev;              /* v4l device */
        struct cdev *cdev;              /* character device */
 
-       /* Set either parent or v4l2_dev if your driver uses v4l2_device */
-       struct device *parent;          /* device parent */
        struct v4l2_device *v4l2_dev;   /* v4l2_device parent */
+       /* Only set parent if that can't be deduced from v4l2_dev */
+       struct device *dev_parent;      /* device parent */
 
        /* Control handler associated with this device node. May be NULL. */
        struct v4l2_ctrl_handler *ctrl_handler;
@@ -129,7 +129,6 @@ struct video_device
 
        /* Video standard vars */
        v4l2_std_id tvnorms;            /* Supported tv norms */
-       v4l2_std_id current_norm;       /* Current tvnorm */
 
        /* callbacks */
        void (*release)(struct video_device *vdev);
index e6aa231..0286c95 100644 (file)
@@ -220,8 +220,6 @@ enum v4l2_int_ioctl_num {
        vidioc_int_reset_num,
        /* VIDIOC_INT_INIT */
        vidioc_int_init_num,
-       /* VIDIOC_DBG_G_CHIP_IDENT */
-       vidioc_int_g_chip_ident_num,
 
        /*
         *
@@ -303,6 +301,5 @@ V4L2_INT_WRAPPER_1(enum_frameintervals, struct v4l2_frmivalenum, *);
 
 V4L2_INT_WRAPPER_0(reset);
 V4L2_INT_WRAPPER_0(init);
-V4L2_INT_WRAPPER_1(g_chip_ident, int, *);
 
 #endif
index 931652f..e0b74a4 100644 (file)
@@ -247,8 +247,6 @@ struct v4l2_ioctl_ops {
        int (*vidioc_g_chip_info)      (struct file *file, void *fh,
                                        struct v4l2_dbg_chip_info *chip);
 #endif
-       int (*vidioc_g_chip_ident)     (struct file *file, void *fh,
-                                       struct v4l2_dbg_chip_ident *chip);
 
        int (*vidioc_enum_framesizes)   (struct file *file, void *fh,
                                         struct v4l2_frmsizeenum *fsize);
index 5298d67..3250cc5 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/types.h>
 #include <linux/v4l2-subdev.h>
 #include <media/media-entity.h>
+#include <media/v4l2-async.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-dev.h>
 #include <media/v4l2-fh.h>
@@ -88,7 +89,6 @@ struct v4l2_decode_vbi_line {
 
 /* Core ops: it is highly recommended to implement at least these ops:
 
-   g_chip_ident
    log_status
    g_register
    s_register
@@ -145,7 +145,6 @@ struct v4l2_subdev_io_pin_config {
        performed later.  It must not sleep.  *Called from an IRQ context*.
  */
 struct v4l2_subdev_core_ops {
-       int (*g_chip_ident)(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip);
        int (*log_status)(struct v4l2_subdev *sd);
        int (*s_io_pin_config)(struct v4l2_subdev *sd, size_t n,
                                      struct v4l2_subdev_io_pin_config *pincfg);
@@ -585,8 +584,17 @@ struct v4l2_subdev {
        void *host_priv;
        /* subdev device node */
        struct video_device *devnode;
+       /* pointer to the physical device, if any */
+       struct device *dev;
+       struct v4l2_async_subdev_list asdl;
 };
 
+static inline struct v4l2_subdev *v4l2_async_to_subdev(
+                       struct v4l2_async_subdev_list *asdl)
+{
+       return container_of(asdl, struct v4l2_subdev, asdl);
+}
+
 #define media_entity_to_v4l2_subdev(ent) \
        container_of(ent, struct v4l2_subdev, entity)
 #define vdev_to_v4l2_subdev(vdev) \
@@ -660,7 +668,7 @@ void v4l2_subdev_init(struct v4l2_subdev *sd,
 /* Call an ops of a v4l2_subdev, doing the right checks against
    NULL pointers.
 
-   Example: err = v4l2_subdev_call(sd, core, g_chip_ident, &chip);
+   Example: err = v4l2_subdev_call(sd, core, s_std, norm);
  */
 #define v4l2_subdev_call(sd, o, f, args...)                            \
        (!(sd) ? -ENODEV : (((sd)->ops->o && (sd)->ops->o->f) ? \
index adcbb20..d9fa68f 100644 (file)
@@ -26,6 +26,9 @@
 #ifndef NET_9P_TRANSPORT_H
 #define NET_9P_TRANSPORT_H
 
+#define P9_DEF_MIN_RESVPORT    (665U)
+#define P9_DEF_MAX_RESVPORT    (1023U)
+
 /**
  * struct p9_trans_module - transport module interface
  * @list: used to maintain a list of currently available transports
@@ -37,6 +40,8 @@
  * @close: member function to discard a connection on this transport
  * @request: member function to issue a request to the transport
  * @cancel: member function to cancel a request (if it hasn't been sent)
+ * @cancelled: member function to notify that a cancelled request will not
+ *             not receive a reply
  *
  * This is the basic API for a transport module which is registered by the
  * transport module with the 9P core network module and used by the client
@@ -55,6 +60,7 @@ struct p9_trans_module {
        void (*close) (struct p9_client *);
        int (*request) (struct p9_client *, struct p9_req_t *req);
        int (*cancel) (struct p9_client *, struct p9_req_t *req);
+       int (*cancelled)(struct p9_client *, struct p9_req_t *req);
        int (*zc_request)(struct p9_client *, struct p9_req_t *,
                          char *, char *, int , int, int, int);
 };
similarity index 83%
rename from include/net/ll_poll.h
rename to include/net/busy_poll.h
index 76f0340..a14339c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Low Latency Sockets
+ * net busy poll support
  * Copyright(c) 2013 Intel Corporation.
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -21,8 +21,8 @@
  * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
  */
 
-#ifndef _LINUX_NET_LL_POLL_H
-#define _LINUX_NET_LL_POLL_H
+#ifndef _LINUX_NET_BUSY_POLL_H
+#define _LINUX_NET_BUSY_POLL_H
 
 #include <linux/netdevice.h>
 #include <net/ip.h>
@@ -30,8 +30,8 @@
 #ifdef CONFIG_NET_LL_RX_POLL
 
 struct napi_struct;
-extern unsigned int sysctl_net_ll_read __read_mostly;
-extern unsigned int sysctl_net_ll_poll __read_mostly;
+extern unsigned int sysctl_net_busy_read __read_mostly;
+extern unsigned int sysctl_net_busy_poll __read_mostly;
 
 /* return values from ndo_ll_poll */
 #define LL_FLUSH_FAILED                -1
@@ -39,7 +39,7 @@ extern unsigned int sysctl_net_ll_poll __read_mostly;
 
 static inline bool net_busy_loop_on(void)
 {
-       return sysctl_net_ll_poll;
+       return sysctl_net_busy_poll;
 }
 
 /* a wrapper to make debug_smp_processor_id() happy
@@ -72,7 +72,7 @@ static inline unsigned long sk_busy_loop_end_time(struct sock *sk)
 /* in poll/select we use the global sysctl_net_ll_poll value */
 static inline unsigned long busy_loop_end_time(void)
 {
-       return busy_loop_us_clock() + ACCESS_ONCE(sysctl_net_ll_poll);
+       return busy_loop_us_clock() + ACCESS_ONCE(sysctl_net_busy_poll);
 }
 
 static inline bool sk_can_busy_loop(struct sock *sk)
@@ -110,11 +110,11 @@ static inline bool sk_busy_loop(struct sock *sk, int nonblock)
                goto out;
 
        ops = napi->dev->netdev_ops;
-       if (!ops->ndo_ll_poll)
+       if (!ops->ndo_busy_poll)
                goto out;
 
        do {
-               rc = ops->ndo_ll_poll(napi);
+               rc = ops->ndo_busy_poll(napi);
 
                if (rc == LL_FLUSH_FAILED)
                        break; /* permanent failure */
@@ -134,13 +134,14 @@ out:
 }
 
 /* used in the NIC receive handler to mark the skb */
-static inline void skb_mark_ll(struct sk_buff *skb, struct napi_struct *napi)
+static inline void skb_mark_napi_id(struct sk_buff *skb,
+                                   struct napi_struct *napi)
 {
        skb->napi_id = napi->napi_id;
 }
 
 /* used in the protocol hanlder to propagate the napi_id to the socket */
-static inline void sk_mark_ll(struct sock *sk, struct sk_buff *skb)
+static inline void sk_mark_napi_id(struct sock *sk, struct sk_buff *skb)
 {
        sk->sk_napi_id = skb->napi_id;
 }
@@ -166,11 +167,12 @@ static inline bool sk_busy_poll(struct sock *sk, int nonblock)
        return false;
 }
 
-static inline void skb_mark_ll(struct sk_buff *skb, struct napi_struct *napi)
+static inline void skb_mark_napi_id(struct sk_buff *skb,
+                                   struct napi_struct *napi)
 {
 }
 
-static inline void sk_mark_ll(struct sock *sk, struct sk_buff *skb)
+static inline void sk_mark_napi_id(struct sock *sk, struct sk_buff *skb)
 {
 }
 
@@ -180,4 +182,4 @@ static inline bool busy_loop_timeout(unsigned long end_time)
 }
 
 #endif /* CONFIG_NET_LL_RX_POLL */
-#endif /* _LINUX_NET_LL_POLL_H */
+#endif /* _LINUX_NET_BUSY_POLL_H */
diff --git a/include/rdma/ib.h b/include/rdma/ib.h
new file mode 100644 (file)
index 0000000..cf8f9e7
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2010 Intel Corporation.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#if !defined(_RDMA_IB_H)
+#define _RDMA_IB_H
+
+#include <linux/types.h>
+
+struct ib_addr {
+       union {
+               __u8            uib_addr8[16];
+               __be16          uib_addr16[8];
+               __be32          uib_addr32[4];
+               __be64          uib_addr64[2];
+       } ib_u;
+#define sib_addr8              ib_u.uib_addr8
+#define sib_addr16             ib_u.uib_addr16
+#define sib_addr32             ib_u.uib_addr32
+#define sib_addr64             ib_u.uib_addr64
+#define sib_raw                        ib_u.uib_addr8
+#define sib_subnet_prefix      ib_u.uib_addr64[0]
+#define sib_interface_id       ib_u.uib_addr64[1]
+};
+
+static inline int ib_addr_any(const struct ib_addr *a)
+{
+       return ((a->sib_addr64[0] | a->sib_addr64[1]) == 0);
+}
+
+static inline int ib_addr_loopback(const struct ib_addr *a)
+{
+       return ((a->sib_addr32[0] | a->sib_addr32[1] |
+                a->sib_addr32[2] | (a->sib_addr32[3] ^ htonl(1))) == 0);
+}
+
+static inline void ib_addr_set(struct ib_addr *addr,
+                              __be32 w1, __be32 w2, __be32 w3, __be32 w4)
+{
+       addr->sib_addr32[0] = w1;
+       addr->sib_addr32[1] = w2;
+       addr->sib_addr32[2] = w3;
+       addr->sib_addr32[3] = w4;
+}
+
+static inline int ib_addr_cmp(const struct ib_addr *a1, const struct ib_addr *a2)
+{
+       return memcmp(a1, a2, sizeof(struct ib_addr));
+}
+
+struct sockaddr_ib {
+       unsigned short int      sib_family;     /* AF_IB */
+       __be16                  sib_pkey;
+       __be32                  sib_flowinfo;
+       struct ib_addr          sib_addr;
+       __be64                  sib_sid;
+       __be64                  sib_sid_mask;
+       __u64                   sib_scope_id;
+};
+
+#endif /* _RDMA_IB_H */
index 9996539..f3ac0f2 100644 (file)
@@ -102,11 +102,7 @@ void rdma_addr_cancel(struct rdma_dev_addr *addr);
 int rdma_copy_addr(struct rdma_dev_addr *dev_addr, struct net_device *dev,
              const unsigned char *dst_dev_addr);
 
-static inline int ip_addr_size(struct sockaddr *addr)
-{
-       return addr->sa_family == AF_INET6 ?
-              sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in);
-}
+int rdma_addr_size(struct sockaddr *addr);
 
 static inline u16 ib_addr_get_pkey(struct rdma_dev_addr *dev_addr)
 {
index 8275e53..125f871 100644 (file)
@@ -402,6 +402,12 @@ int ib_init_ah_from_path(struct ib_device *device, u8 port_num,
                         struct ib_ah_attr *ah_attr);
 
 /**
+ * ib_sa_pack_path - Conert a path record from struct ib_sa_path_rec
+ * to IB MAD wire format.
+ */
+void ib_sa_pack_path(struct ib_sa_path_rec *rec, void *attribute);
+
+/**
  * ib_sa_unpack_path - Convert a path record from MAD format to struct
  * ib_sa_path_rec.
  */
@@ -418,4 +424,5 @@ int ib_sa_guid_info_rec_query(struct ib_sa_client *client,
                                               void *context),
                              void *context,
                              struct ib_sa_query **sa_query);
+
 #endif /* IB_SA_H */
index 98cc4b2..645c3ce 100644 (file)
@@ -610,7 +610,21 @@ enum ib_qp_type {
        IB_QPT_RAW_PACKET = 8,
        IB_QPT_XRC_INI = 9,
        IB_QPT_XRC_TGT,
-       IB_QPT_MAX
+       IB_QPT_MAX,
+       /* Reserve a range for qp types internal to the low level driver.
+        * These qp types will not be visible at the IB core layer, so the
+        * IB_QPT_MAX usages should not be affected in the core layer
+        */
+       IB_QPT_RESERVED1 = 0x1000,
+       IB_QPT_RESERVED2,
+       IB_QPT_RESERVED3,
+       IB_QPT_RESERVED4,
+       IB_QPT_RESERVED5,
+       IB_QPT_RESERVED6,
+       IB_QPT_RESERVED7,
+       IB_QPT_RESERVED8,
+       IB_QPT_RESERVED9,
+       IB_QPT_RESERVED10,
 };
 
 enum ib_qp_create_flags {
@@ -766,6 +780,19 @@ enum ib_wr_opcode {
        IB_WR_MASKED_ATOMIC_CMP_AND_SWP,
        IB_WR_MASKED_ATOMIC_FETCH_AND_ADD,
        IB_WR_BIND_MW,
+       /* reserve values for low level drivers' internal use.
+        * These values will not be used at all in the ib core layer.
+        */
+       IB_WR_RESERVED1 = 0xf0,
+       IB_WR_RESERVED2,
+       IB_WR_RESERVED3,
+       IB_WR_RESERVED4,
+       IB_WR_RESERVED5,
+       IB_WR_RESERVED6,
+       IB_WR_RESERVED7,
+       IB_WR_RESERVED8,
+       IB_WR_RESERVED9,
+       IB_WR_RESERVED10,
 };
 
 enum ib_send_flags {
@@ -773,7 +800,11 @@ enum ib_send_flags {
        IB_SEND_SIGNALED        = (1<<1),
        IB_SEND_SOLICITED       = (1<<2),
        IB_SEND_INLINE          = (1<<3),
-       IB_SEND_IP_CSUM         = (1<<4)
+       IB_SEND_IP_CSUM         = (1<<4),
+
+       /* reserve bits 26-31 for low level drivers' internal use */
+       IB_SEND_RESERVED_START  = (1 << 26),
+       IB_SEND_RESERVED_END    = (1 << 31),
 };
 
 struct ib_sge {
index ad3a314..1ed2088 100644 (file)
@@ -70,6 +70,11 @@ enum rdma_port_space {
        RDMA_PS_UDP   = 0x0111,
 };
 
+#define RDMA_IB_IP_PS_MASK   0xFFFFFFFFFFFF0000ULL
+#define RDMA_IB_IP_PS_TCP    0x0000000001060000ULL
+#define RDMA_IB_IP_PS_UDP    0x0000000001110000ULL
+#define RDMA_IB_IP_PS_IB     0x00000000013F0000ULL
+
 struct rdma_addr {
        struct sockaddr_storage src_addr;
        struct sockaddr_storage dst_addr;
@@ -93,6 +98,7 @@ struct rdma_conn_param {
        /* Fields below ignored if a QP is created on the rdma_cm_id. */
        u8 srq;
        u32 qp_num;
+       u32 qkey;
 };
 
 struct rdma_ud_param {
@@ -367,4 +373,11 @@ int rdma_set_reuseaddr(struct rdma_cm_id *id, int reuse);
  */
 int rdma_set_afonly(struct rdma_cm_id *id, int afonly);
 
+ /**
+ * rdma_get_service_id - Return the IB service ID for a specified address.
+ * @id: Communication identifier associated with the address.
+ * @addr: Address for the service ID.
+ */
+__be64 rdma_get_service_id(struct rdma_cm_id *id, struct sockaddr *addr);
+
 #endif /* RDMA_CM_H */
index 23a87d0..e5d09d2 100644 (file)
@@ -34,8 +34,6 @@ extern void iscsit_put_transport(struct iscsit_transport *);
 /*
  * From iscsi_target.c
  */
-extern int iscsit_add_reject_from_cmd(u8, int, int, unsigned char *,
-                               struct iscsi_cmd *);
 extern int iscsit_setup_scsi_cmd(struct iscsi_conn *, struct iscsi_cmd *,
                                unsigned char *);
 extern void iscsit_set_unsoliticed_dataout(struct iscsi_cmd *);
@@ -45,18 +43,26 @@ extern int iscsit_check_dataout_hdr(struct iscsi_conn *, unsigned char *,
                                struct iscsi_cmd **);
 extern int iscsit_check_dataout_payload(struct iscsi_cmd *, struct iscsi_data *,
                                bool);
-extern int iscsit_handle_nop_out(struct iscsi_conn *, struct iscsi_cmd *,
-                               unsigned char *);
+extern int iscsit_setup_nop_out(struct iscsi_conn *, struct iscsi_cmd *,
+                               struct iscsi_nopout *);
+extern int iscsit_process_nop_out(struct iscsi_conn *, struct iscsi_cmd *,
+                               struct iscsi_nopout *);
 extern int iscsit_handle_logout_cmd(struct iscsi_conn *, struct iscsi_cmd *,
                                unsigned char *);
 extern int iscsit_handle_task_mgt_cmd(struct iscsi_conn *, struct iscsi_cmd *,
                                unsigned char *);
+extern int iscsit_setup_text_cmd(struct iscsi_conn *, struct iscsi_cmd *,
+                                struct iscsi_text *);
+extern int iscsit_process_text_cmd(struct iscsi_conn *, struct iscsi_cmd *,
+                                  struct iscsi_text *);
 extern void iscsit_build_rsp_pdu(struct iscsi_cmd *, struct iscsi_conn *,
                                bool, struct iscsi_scsi_rsp *);
 extern void iscsit_build_nopin_rsp(struct iscsi_cmd *, struct iscsi_conn *,
                                struct iscsi_nopin *, bool);
 extern void iscsit_build_task_mgt_rsp(struct iscsi_cmd *, struct iscsi_conn *,
                                struct iscsi_tm_rsp *);
+extern int iscsit_build_text_rsp(struct iscsi_cmd *, struct iscsi_conn *,
+                               struct iscsi_text_rsp *);
 extern void iscsit_build_reject(struct iscsi_cmd *, struct iscsi_conn *,
                                struct iscsi_reject *);
 extern int iscsit_build_logout_rsp(struct iscsi_cmd *, struct iscsi_conn *,
@@ -67,6 +73,10 @@ extern int iscsit_logout_post_handler(struct iscsi_cmd *, struct iscsi_conn *);
  */
 extern void iscsit_increment_maxcmdsn(struct iscsi_cmd *, struct iscsi_session *);
 /*
+ * From iscsi_target_erl0.c
+ */
+extern void iscsit_cause_connection_reinstatement(struct iscsi_conn *, int);
+/*
  * From iscsi_target_erl1.c
  */
 extern void iscsit_stop_dataout_timer(struct iscsi_cmd *);
@@ -80,4 +90,5 @@ extern int iscsit_tmr_post_handler(struct iscsi_cmd *, struct iscsi_conn *);
  * From iscsi_target_util.c
  */
 extern struct iscsi_cmd *iscsit_allocate_cmd(struct iscsi_conn *, gfp_t);
-extern int iscsit_sequence_cmd(struct iscsi_conn *, struct iscsi_cmd *, __be32);
+extern int iscsit_sequence_cmd(struct iscsi_conn *, struct iscsi_cmd *,
+                              unsigned char *, __be32);
index 4ea4f98..e34fc90 100644 (file)
@@ -218,14 +218,11 @@ enum tcm_tmreq_table {
 
 /* fabric independent task management response values */
 enum tcm_tmrsp_table {
-       TMR_FUNCTION_COMPLETE           = 0,
-       TMR_TASK_DOES_NOT_EXIST         = 1,
-       TMR_LUN_DOES_NOT_EXIST          = 2,
-       TMR_TASK_STILL_ALLEGIANT        = 3,
-       TMR_TASK_FAILOVER_NOT_SUPPORTED = 4,
-       TMR_TASK_MGMT_FUNCTION_NOT_SUPPORTED    = 5,
-       TMR_FUNCTION_AUTHORIZATION_FAILED = 6,
-       TMR_FUNCTION_REJECTED           = 255,
+       TMR_FUNCTION_COMPLETE           = 1,
+       TMR_TASK_DOES_NOT_EXIST         = 2,
+       TMR_LUN_DOES_NOT_EXIST          = 3,
+       TMR_TASK_MGMT_FUNCTION_NOT_SUPPORTED    = 4,
+       TMR_FUNCTION_REJECTED           = 5,
 };
 
 /*
@@ -339,8 +336,6 @@ struct t10_pr_registration {
        /* Used during APTPL metadata reading */
 #define PR_APTPL_MAX_TPORT_LEN                 256
        unsigned char pr_tport[PR_APTPL_MAX_TPORT_LEN];
-       /* For writing out live meta data */
-       unsigned char *pr_aptpl_buf;
        u16 pr_aptpl_rpti;
        u16 pr_reg_tpgt;
        /* Reservation effects all target ports */
@@ -374,9 +369,7 @@ struct t10_reservation {
        /* Activate Persistence across Target Power Loss enabled
         * for SCSI device */
        int pr_aptpl_active;
-       /* Used by struct t10_reservation->pr_aptpl_buf_len */
 #define PR_APTPL_BUF_LEN                       8192
-       u32 pr_aptpl_buf_len;
        u32 pr_generation;
        spinlock_t registration_lock;
        spinlock_t aptpl_reg_lock;
@@ -424,8 +417,6 @@ struct se_cmd {
        int                     sam_task_attr;
        /* Transport protocol dependent state, see transport_state_table */
        enum transport_state_table t_state;
-       /* Used to signal cmd->se_tfo->check_release_cmd() usage per cmd */
-       unsigned                check_release:1;
        unsigned                cmd_wait_set:1;
        unsigned                unknown_data_length:1;
        /* See se_cmd_flags_table */
@@ -458,7 +449,6 @@ struct se_cmd {
        unsigned char           *t_task_cdb;
        unsigned char           __t_task_cdb[TCM_MAX_COMMAND_SIZE];
        unsigned long long      t_task_lba;
-       atomic_t                t_fe_count;
        unsigned int            transport_state;
 #define CMD_T_ABORTED          (1 << 0)
 #define CMD_T_ACTIVE           (1 << 1)
@@ -802,11 +792,12 @@ struct se_portal_group {
        struct target_core_fabric_ops *se_tpg_tfo;
        struct se_wwn           *se_tpg_wwn;
        struct config_group     tpg_group;
-       struct config_group     *tpg_default_groups[6];
+       struct config_group     *tpg_default_groups[7];
        struct config_group     tpg_lun_group;
        struct config_group     tpg_np_group;
        struct config_group     tpg_acl_group;
        struct config_group     tpg_attrib_group;
+       struct config_group     tpg_auth_group;
        struct config_group     tpg_param_group;
 };
 
index 6125095..713c500 100644 (file)
@@ -23,6 +23,7 @@ struct target_fabric_configfs_template {
        struct config_item_type tfc_tpg_np_cit;
        struct config_item_type tfc_tpg_np_base_cit;
        struct config_item_type tfc_tpg_attrib_cit;
+       struct config_item_type tfc_tpg_auth_cit;
        struct config_item_type tfc_tpg_param_cit;
        struct config_item_type tfc_tpg_nacl_cit;
        struct config_item_type tfc_tpg_nacl_base_cit;
index 1dcce9c..7a16178 100644 (file)
@@ -61,7 +61,7 @@ struct target_core_fabric_ops {
        int (*get_cmd_state)(struct se_cmd *);
        int (*queue_data_in)(struct se_cmd *);
        int (*queue_status)(struct se_cmd *);
-       int (*queue_tm_rsp)(struct se_cmd *);
+       void (*queue_tm_rsp)(struct se_cmd *);
        /*
         * fabric module calls for target_core_fabric_configfs.c
         */
index a26fb75..b32a149 100644 (file)
@@ -62,6 +62,17 @@ static struct target_fabric_tpg_attrib_attribute _fabric##_tpg_attrib_##_name =
        _fabric##_tpg_attrib_show_##_name,                              \
        _fabric##_tpg_attrib_store_##_name);
 
+CONFIGFS_EATTR_STRUCT(target_fabric_tpg_auth, se_portal_group);
+#define TF_TPG_AUTH_ATTR(_fabric, _name, _mode)                        \
+static struct target_fabric_tpg_auth_attribute _fabric##_tpg_auth_##_name = \
+       __CONFIGFS_EATTR(_name, _mode,                                  \
+       _fabric##_tpg_auth_show_##_name,                                \
+       _fabric##_tpg_auth_store_##_name);
+
+#define TF_TPG_AUTH_ATTR_RO(_fabric, _name)                            \
+static struct target_fabric_tpg_auth_attribute _fabric##_tpg_auth_##_name = \
+       __CONFIGFS_EATTR_RO(_name,                                      \
+       _fabric##_tpg_auth_show_##_name);
 
 CONFIGFS_EATTR_STRUCT(target_fabric_tpg_param, se_portal_group);
 #define TF_TPG_PARAM_ATTR(_fabric, _name, _mode)                       \
diff --git a/include/trace/events/target.h b/include/trace/events/target.h
new file mode 100644 (file)
index 0000000..aef8fc3
--- /dev/null
@@ -0,0 +1,214 @@
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM target
+
+#if !defined(_TRACE_TARGET_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_TARGET_H
+
+#include <linux/tracepoint.h>
+#include <linux/trace_seq.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_tcq.h>
+#include <target/target_core_base.h>
+
+/* cribbed verbatim from <trace/event/scsi.h> */
+#define scsi_opcode_name(opcode)       { opcode, #opcode }
+#define show_opcode_name(val)                                  \
+       __print_symbolic(val,                                   \
+               scsi_opcode_name(TEST_UNIT_READY),              \
+               scsi_opcode_name(REZERO_UNIT),                  \
+               scsi_opcode_name(REQUEST_SENSE),                \
+               scsi_opcode_name(FORMAT_UNIT),                  \
+               scsi_opcode_name(READ_BLOCK_LIMITS),            \
+               scsi_opcode_name(REASSIGN_BLOCKS),              \
+               scsi_opcode_name(INITIALIZE_ELEMENT_STATUS),    \
+               scsi_opcode_name(READ_6),                       \
+               scsi_opcode_name(WRITE_6),                      \
+               scsi_opcode_name(SEEK_6),                       \
+               scsi_opcode_name(READ_REVERSE),                 \
+               scsi_opcode_name(WRITE_FILEMARKS),              \
+               scsi_opcode_name(SPACE),                        \
+               scsi_opcode_name(INQUIRY),                      \
+               scsi_opcode_name(RECOVER_BUFFERED_DATA),        \
+               scsi_opcode_name(MODE_SELECT),                  \
+               scsi_opcode_name(RESERVE),                      \
+               scsi_opcode_name(RELEASE),                      \
+               scsi_opcode_name(COPY),                         \
+               scsi_opcode_name(ERASE),                        \
+               scsi_opcode_name(MODE_SENSE),                   \
+               scsi_opcode_name(START_STOP),                   \
+               scsi_opcode_name(RECEIVE_DIAGNOSTIC),           \
+               scsi_opcode_name(SEND_DIAGNOSTIC),              \
+               scsi_opcode_name(ALLOW_MEDIUM_REMOVAL),         \
+               scsi_opcode_name(SET_WINDOW),                   \
+               scsi_opcode_name(READ_CAPACITY),                \
+               scsi_opcode_name(READ_10),                      \
+               scsi_opcode_name(WRITE_10),                     \
+               scsi_opcode_name(SEEK_10),                      \
+               scsi_opcode_name(POSITION_TO_ELEMENT),          \
+               scsi_opcode_name(WRITE_VERIFY),                 \
+               scsi_opcode_name(VERIFY),                       \
+               scsi_opcode_name(SEARCH_HIGH),                  \
+               scsi_opcode_name(SEARCH_EQUAL),                 \
+               scsi_opcode_name(SEARCH_LOW),                   \
+               scsi_opcode_name(SET_LIMITS),                   \
+               scsi_opcode_name(PRE_FETCH),                    \
+               scsi_opcode_name(READ_POSITION),                \
+               scsi_opcode_name(SYNCHRONIZE_CACHE),            \
+               scsi_opcode_name(LOCK_UNLOCK_CACHE),            \
+               scsi_opcode_name(READ_DEFECT_DATA),             \
+               scsi_opcode_name(MEDIUM_SCAN),                  \
+               scsi_opcode_name(COMPARE),                      \
+               scsi_opcode_name(COPY_VERIFY),                  \
+               scsi_opcode_name(WRITE_BUFFER),                 \
+               scsi_opcode_name(READ_BUFFER),                  \
+               scsi_opcode_name(UPDATE_BLOCK),                 \
+               scsi_opcode_name(READ_LONG),                    \
+               scsi_opcode_name(WRITE_LONG),                   \
+               scsi_opcode_name(CHANGE_DEFINITION),            \
+               scsi_opcode_name(WRITE_SAME),                   \
+               scsi_opcode_name(UNMAP),                        \
+               scsi_opcode_name(READ_TOC),                     \
+               scsi_opcode_name(LOG_SELECT),                   \
+               scsi_opcode_name(LOG_SENSE),                    \
+               scsi_opcode_name(XDWRITEREAD_10),               \
+               scsi_opcode_name(MODE_SELECT_10),               \
+               scsi_opcode_name(RESERVE_10),                   \
+               scsi_opcode_name(RELEASE_10),                   \
+               scsi_opcode_name(MODE_SENSE_10),                \
+               scsi_opcode_name(PERSISTENT_RESERVE_IN),        \
+               scsi_opcode_name(PERSISTENT_RESERVE_OUT),       \
+               scsi_opcode_name(VARIABLE_LENGTH_CMD),          \
+               scsi_opcode_name(REPORT_LUNS),                  \
+               scsi_opcode_name(MAINTENANCE_IN),               \
+               scsi_opcode_name(MAINTENANCE_OUT),              \
+               scsi_opcode_name(MOVE_MEDIUM),                  \
+               scsi_opcode_name(EXCHANGE_MEDIUM),              \
+               scsi_opcode_name(READ_12),                      \
+               scsi_opcode_name(WRITE_12),                     \
+               scsi_opcode_name(WRITE_VERIFY_12),              \
+               scsi_opcode_name(SEARCH_HIGH_12),               \
+               scsi_opcode_name(SEARCH_EQUAL_12),              \
+               scsi_opcode_name(SEARCH_LOW_12),                \
+               scsi_opcode_name(READ_ELEMENT_STATUS),          \
+               scsi_opcode_name(SEND_VOLUME_TAG),              \
+               scsi_opcode_name(WRITE_LONG_2),                 \
+               scsi_opcode_name(READ_16),                      \
+               scsi_opcode_name(WRITE_16),                     \
+               scsi_opcode_name(VERIFY_16),                    \
+               scsi_opcode_name(WRITE_SAME_16),                \
+               scsi_opcode_name(SERVICE_ACTION_IN),            \
+               scsi_opcode_name(SAI_READ_CAPACITY_16),         \
+               scsi_opcode_name(SAI_GET_LBA_STATUS),           \
+               scsi_opcode_name(MI_REPORT_TARGET_PGS),         \
+               scsi_opcode_name(MO_SET_TARGET_PGS),            \
+               scsi_opcode_name(READ_32),                      \
+               scsi_opcode_name(WRITE_32),                     \
+               scsi_opcode_name(WRITE_SAME_32),                \
+               scsi_opcode_name(ATA_16),                       \
+               scsi_opcode_name(ATA_12))
+
+#define show_task_attribute_name(val)                          \
+       __print_symbolic(val,                                   \
+               { MSG_SIMPLE_TAG,       "SIMPLE"        },      \
+               { MSG_HEAD_TAG,         "HEAD"          },      \
+               { MSG_ORDERED_TAG,      "ORDERED"       },      \
+               { MSG_ACA_TAG,          "ACA"           } )
+
+#define show_scsi_status_name(val)                             \
+       __print_symbolic(val,                                   \
+               { SAM_STAT_GOOD,        "GOOD" },               \
+               { SAM_STAT_CHECK_CONDITION, "CHECK CONDITION" }, \
+               { SAM_STAT_CONDITION_MET, "CONDITION MET" },    \
+               { SAM_STAT_BUSY,        "BUSY" },               \
+               { SAM_STAT_INTERMEDIATE, "INTERMEDIATE" },      \
+               { SAM_STAT_INTERMEDIATE_CONDITION_MET, "INTERMEDIATE CONDITION MET" }, \
+               { SAM_STAT_RESERVATION_CONFLICT, "RESERVATION CONFLICT" }, \
+               { SAM_STAT_COMMAND_TERMINATED, "COMMAND TERMINATED" }, \
+               { SAM_STAT_TASK_SET_FULL, "TASK SET FULL" },    \
+               { SAM_STAT_ACA_ACTIVE, "ACA ACTIVE" },          \
+               { SAM_STAT_TASK_ABORTED, "TASK ABORTED" } )
+
+TRACE_EVENT(target_sequencer_start,
+
+       TP_PROTO(struct se_cmd *cmd),
+
+       TP_ARGS(cmd),
+
+       TP_STRUCT__entry(
+               __field( unsigned int,  unpacked_lun    )
+               __field( unsigned int,  opcode          )
+               __field( unsigned int,  data_length     )
+               __field( unsigned int,  task_attribute  )
+               __array( unsigned char, cdb, TCM_MAX_COMMAND_SIZE       )
+               __string( initiator,    cmd->se_sess->se_node_acl->initiatorname        )
+       ),
+
+       TP_fast_assign(
+               __entry->unpacked_lun   = cmd->se_lun->unpacked_lun;
+               __entry->opcode         = cmd->t_task_cdb[0];
+               __entry->data_length    = cmd->data_length;
+               __entry->task_attribute = cmd->sam_task_attr;
+               memcpy(__entry->cdb, cmd->t_task_cdb, TCM_MAX_COMMAND_SIZE);
+               __assign_str(initiator, cmd->se_sess->se_node_acl->initiatorname);
+       ),
+
+       TP_printk("%s -> LUN %03u %s data_length %6u  CDB %s  (TA:%s C:%02x)",
+                 __get_str(initiator), __entry->unpacked_lun,
+                 show_opcode_name(__entry->opcode),
+                 __entry->data_length, __print_hex(__entry->cdb, 16),
+                 show_task_attribute_name(__entry->task_attribute),
+                 scsi_command_size(__entry->cdb) <= 16 ?
+                       __entry->cdb[scsi_command_size(__entry->cdb) - 1] :
+                       __entry->cdb[1]
+       )
+);
+
+TRACE_EVENT(target_cmd_complete,
+
+       TP_PROTO(struct se_cmd *cmd),
+
+       TP_ARGS(cmd),
+
+       TP_STRUCT__entry(
+               __field( unsigned int,  unpacked_lun    )
+               __field( unsigned int,  opcode          )
+               __field( unsigned int,  data_length     )
+               __field( unsigned int,  task_attribute  )
+               __field( unsigned char, scsi_status     )
+               __field( unsigned char, sense_length    )
+               __array( unsigned char, cdb, TCM_MAX_COMMAND_SIZE       )
+               __array( unsigned char, sense_data, 18  )
+               __string(initiator,     cmd->se_sess->se_node_acl->initiatorname)
+       ),
+
+       TP_fast_assign(
+               __entry->unpacked_lun   = cmd->se_lun->unpacked_lun;
+               __entry->opcode         = cmd->t_task_cdb[0];
+               __entry->data_length    = cmd->data_length;
+               __entry->task_attribute = cmd->sam_task_attr;
+               __entry->scsi_status    = cmd->scsi_status;
+               __entry->sense_length   = cmd->scsi_status == SAM_STAT_CHECK_CONDITION ?
+                       min(18, ((u8 *) cmd->sense_buffer)[SPC_ADD_SENSE_LEN_OFFSET] + 8) : 0;
+               memcpy(__entry->cdb, cmd->t_task_cdb, TCM_MAX_COMMAND_SIZE);
+               memcpy(__entry->sense_data, cmd->sense_buffer, __entry->sense_length);
+               __assign_str(initiator, cmd->se_sess->se_node_acl->initiatorname);
+       ),
+
+       TP_printk("%s <- LUN %03u status %s (sense len %d%s%s)  %s data_length %6u  CDB %s  (TA:%s C:%02x)",
+                 __get_str(initiator), __entry->unpacked_lun,
+                 show_scsi_status_name(__entry->scsi_status),
+                 __entry->sense_length, __entry->sense_length ? " / " : "",
+                 __print_hex(__entry->sense_data, __entry->sense_length),
+                 show_opcode_name(__entry->opcode),
+                 __entry->data_length, __print_hex(__entry->cdb, 16),
+                 show_task_attribute_name(__entry->task_attribute),
+                 scsi_command_size(__entry->cdb) <= 16 ?
+                       __entry->cdb[scsi_command_size(__entry->cdb) - 1] :
+                       __entry->cdb[1]
+       )
+);
+
+#endif /*  _TRACE_TARGET_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
index 84bc419..fed853f 100644 (file)
@@ -16,6 +16,7 @@
  * @nb_args: number of parameters it takes
  * @types: list of types as strings
  * @args: list of args as strings (args[i] matches types[i])
+ * @enter_fields: list of fields for syscall_enter trace event
  * @enter_event: associated syscall_enter trace event
  * @exit_event: associated syscall_exit trace event
  */
index 06632be..05ac354 100644 (file)
 #define O_PATH         010000000
 #endif
 
-#ifndef O_TMPFILE
-#define O_TMPFILE      020000000
+#ifndef __O_TMPFILE
+#define __O_TMPFILE    020000000
 #endif
 
+/* a horrid kludge trying to make sure that this will fail on old kernels */
+#define O_TMPFILE (__O_TMPFILE | O_DIRECTORY | O_RDWR)
+#define O_TMPFILE_MASK (__O_TMPFILE | O_DIRECTORY | O_CREAT | O_ACCMODE)      
+
 #ifndef O_NDELAY
 #define O_NDELAY       O_NONBLOCK
 #endif
index ca3a20d..f04b69b 100644 (file)
@@ -76,6 +76,6 @@
 
 #define SO_SELECT_ERR_QUEUE    45
 
-#define SO_LL                  46
+#define SO_BUSY_POLL           46
 
 #endif /* __ASM_GENERIC_SOCKET_H */
index ab5d499..ba1c11a 100644 (file)
@@ -62,6 +62,7 @@ header-y += auxvec.h
 header-y += ax25.h
 header-y += b1lli.h
 header-y += baycom.h
+header-y += bcm933xx_hcs.h
 header-y += bfs_fs.h
 header-y += binfmts.h
 header-y += blkpg.h
diff --git a/include/uapi/linux/bcm933xx_hcs.h b/include/uapi/linux/bcm933xx_hcs.h
new file mode 100644 (file)
index 0000000..d228218
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * Broadcom Cable Modem firmware format
+ */
+
+#ifndef __BCM933XX_HCS_H
+#define __BCM933XX_HCS_H
+
+#include <linux/types.h>
+
+struct bcm_hcs {
+       __u16 magic;
+       __u16 control;
+       __u16 rev_maj;
+       __u16 rev_min;
+       __u32 build_date;
+       __u32 filelen;
+       __u32 ldaddress;
+       char filename[64];
+       __u16 hcs;
+       __u16 her_znaet_chto;
+       __u32 crc;
+};
+
+#endif /* __BCM933XX_HCS */
index 7e75b6f..afd0cbd 100644 (file)
@@ -267,9 +267,9 @@ enum {
 #define DM_DEV_SET_GEOMETRY    _IOWR(DM_IOCTL, DM_DEV_SET_GEOMETRY_CMD, struct dm_ioctl)
 
 #define DM_VERSION_MAJOR       4
-#define DM_VERSION_MINOR       24
+#define DM_VERSION_MINOR       25
 #define DM_VERSION_PATCHLEVEL  0
-#define DM_VERSION_EXTRA       "-ioctl (2013-01-15)"
+#define DM_VERSION_EXTRA       "-ioctl (2013-06-26)"
 
 /* Status bits */
 #define DM_READONLY_FLAG       (1 << 0) /* In/Out */
index 69bd5bb..e90a88a 100644 (file)
 #define V4L2_CTRL_CLASS_USER           0x00980000      /* Old-style 'user' controls */
 #define V4L2_CTRL_CLASS_MPEG           0x00990000      /* MPEG-compression controls */
 #define V4L2_CTRL_CLASS_CAMERA         0x009a0000      /* Camera class controls */
-#define V4L2_CTRL_CLASS_FM_TX          0x009b0000      /* FM Modulator control class */
+#define V4L2_CTRL_CLASS_FM_TX          0x009b0000      /* FM Modulator controls */
 #define V4L2_CTRL_CLASS_FLASH          0x009c0000      /* Camera flash controls */
 #define V4L2_CTRL_CLASS_JPEG           0x009d0000      /* JPEG-compression controls */
 #define V4L2_CTRL_CLASS_IMAGE_SOURCE   0x009e0000      /* Image source controls */
 #define V4L2_CTRL_CLASS_IMAGE_PROC     0x009f0000      /* Image processing controls */
 #define V4L2_CTRL_CLASS_DV             0x00a00000      /* Digital Video controls */
-#define V4L2_CTRL_CLASS_FM_RX          0x00a10000      /* Digital Video controls */
+#define V4L2_CTRL_CLASS_FM_RX          0x00a10000      /* FM Receiver controls */
 
 /* User-class control IDs */
 
index 87ee4f4..916e444 100644 (file)
@@ -362,10 +362,14 @@ struct vfio_iommu_type1_dma_map {
 #define VFIO_IOMMU_MAP_DMA _IO(VFIO_TYPE, VFIO_BASE + 13)
 
 /**
- * VFIO_IOMMU_UNMAP_DMA - _IOW(VFIO_TYPE, VFIO_BASE + 14, struct vfio_dma_unmap)
+ * VFIO_IOMMU_UNMAP_DMA - _IOWR(VFIO_TYPE, VFIO_BASE + 14,
+ *                                                     struct vfio_dma_unmap)
  *
  * Unmap IO virtual addresses using the provided struct vfio_dma_unmap.
- * Caller sets argsz.
+ * Caller sets argsz.  The actual unmapped size is returned in the size
+ * field.  No guarantee is made to the user that arbitrary unmaps of iova
+ * or size different from those used in the original mapping call will
+ * succeed.
  */
 struct vfio_iommu_type1_dma_unmap {
        __u32   argsz;
index f40b41c..95ef455 100644 (file)
@@ -395,7 +395,7 @@ struct v4l2_pix_format {
 #define V4L2_PIX_FMT_H263     v4l2_fourcc('H', '2', '6', '3') /* H263          */
 #define V4L2_PIX_FMT_MPEG1    v4l2_fourcc('M', 'P', 'G', '1') /* MPEG-1 ES     */
 #define V4L2_PIX_FMT_MPEG2    v4l2_fourcc('M', 'P', 'G', '2') /* MPEG-2 ES     */
-#define V4L2_PIX_FMT_MPEG4    v4l2_fourcc('M', 'P', 'G', '4') /* MPEG-4 ES     */
+#define V4L2_PIX_FMT_MPEG4    v4l2_fourcc('M', 'P', 'G', '4') /* MPEG-4 part 2 ES */
 #define V4L2_PIX_FMT_XVID     v4l2_fourcc('X', 'V', 'I', 'D') /* Xvid           */
 #define V4L2_PIX_FMT_VC1_ANNEX_G v4l2_fourcc('V', 'C', '1', 'G') /* SMPTE 421M Annex G compliant stream */
 #define V4L2_PIX_FMT_VC1_ANNEX_L v4l2_fourcc('V', 'C', '1', 'L') /* SMPTE 421M Annex L compliant stream */
@@ -555,7 +555,7 @@ struct v4l2_jpegcompression {
        __u32 jpeg_markers;     /* Which markers should go into the JPEG
                                 * output. Unless you exactly know what
                                 * you do, leave them untouched.
-                                * Inluding less markers will make the
+                                * Including less markers will make the
                                 * resulting code smaller, but there will
                                 * be fewer applications which can read it.
                                 * The presence of the APP and COM marker
@@ -567,7 +567,7 @@ struct v4l2_jpegcompression {
 #define V4L2_JPEG_MARKER_DRI (1<<5)    /* Define Restart Interval */
 #define V4L2_JPEG_MARKER_COM (1<<6)    /* Comment segment */
 #define V4L2_JPEG_MARKER_APP (1<<7)    /* App segment, driver will
-                                       * allways use APP0 */
+                                       * always use APP0 */
 };
 
 /*
@@ -900,7 +900,7 @@ typedef __u64 v4l2_std_id;
 /*
  * "Common" PAL - This macro is there to be compatible with the old
  * V4L1 concept of "PAL": /BGDKHI.
- * Several PAL standards are mising here: /M, /N and /Nc
+ * Several PAL standards are missing here: /M, /N and /Nc
  */
 #define V4L2_STD_PAL           (V4L2_STD_PAL_BG        |\
                                 V4L2_STD_PAL_DK        |\
@@ -1787,11 +1787,13 @@ struct v4l2_event_subscription {
 /* VIDIOC_DBG_G_REGISTER and VIDIOC_DBG_S_REGISTER */
 
 #define V4L2_CHIP_MATCH_BRIDGE      0  /* Match against chip ID on the bridge (0 for the bridge) */
+#define V4L2_CHIP_MATCH_SUBDEV      4  /* Match against subdev index */
+
+/* The following four defines are no longer in use */
 #define V4L2_CHIP_MATCH_HOST V4L2_CHIP_MATCH_BRIDGE
 #define V4L2_CHIP_MATCH_I2C_DRIVER  1  /* Match against I2C driver name */
 #define V4L2_CHIP_MATCH_I2C_ADDR    2  /* Match against I2C 7-bit address */
-#define V4L2_CHIP_MATCH_AC97        3  /* Match against anciliary AC97 chip */
-#define V4L2_CHIP_MATCH_SUBDEV      4  /* Match against subdev index */
+#define V4L2_CHIP_MATCH_AC97        3  /* Match against ancillary AC97 chip */
 
 struct v4l2_dbg_match {
        __u32 type; /* Match type */
@@ -1808,13 +1810,6 @@ struct v4l2_dbg_register {
        __u64 val;
 } __attribute__ ((packed));
 
-/* VIDIOC_DBG_G_CHIP_IDENT */
-struct v4l2_dbg_chip_ident {
-       struct v4l2_dbg_match match;
-       __u32 ident;       /* chip identifier as specified in <media/v4l2-chip-ident.h> */
-       __u32 revision;    /* chip revision, chip specific */
-} __attribute__ ((packed));
-
 #define V4L2_CHIP_FL_READABLE (1 << 0)
 #define V4L2_CHIP_FL_WRITABLE (1 << 1)
 
@@ -1915,12 +1910,6 @@ struct v4l2_create_buffers {
 #define        VIDIOC_DBG_S_REGISTER    _IOW('V', 79, struct v4l2_dbg_register)
 #define        VIDIOC_DBG_G_REGISTER   _IOWR('V', 80, struct v4l2_dbg_register)
 
-/* Experimental, meant for debugging, testing and internal use.
-   Never use this ioctl in applications!
-   Note: this ioctl is deprecated in favor of VIDIOC_DBG_G_CHIP_INFO and
-   will go away in the future. */
-#define VIDIOC_DBG_G_CHIP_IDENT _IOWR('V', 81, struct v4l2_dbg_chip_ident)
-
 #define VIDIOC_S_HW_FREQ_SEEK   _IOW('V', 82, struct v4l2_hw_freq_seek)
 
 #define        VIDIOC_S_DV_TIMINGS     _IOWR('V', 87, struct v4l2_dv_timings)
index b7cda39..3ce768c 100644 (file)
@@ -51,4 +51,7 @@
  * suppressed them? */
 #define VIRTIO_F_NOTIFY_ON_EMPTY       24
 
+/* Can the device handle any descriptor layout? */
+#define VIRTIO_F_ANY_LAYOUT            27
+
 #endif /* _UAPI_LINUX_VIRTIO_CONFIG_H */
index 1ee9239..99b80ab 100644 (file)
@@ -45,8 +45,8 @@
 enum {
        RDMA_USER_CM_CMD_CREATE_ID,
        RDMA_USER_CM_CMD_DESTROY_ID,
-       RDMA_USER_CM_CMD_BIND_ADDR,
-       RDMA_USER_CM_CMD_RESOLVE_ADDR,
+       RDMA_USER_CM_CMD_BIND_IP,
+       RDMA_USER_CM_CMD_RESOLVE_IP,
        RDMA_USER_CM_CMD_RESOLVE_ROUTE,
        RDMA_USER_CM_CMD_QUERY_ROUTE,
        RDMA_USER_CM_CMD_CONNECT,
@@ -59,9 +59,13 @@ enum {
        RDMA_USER_CM_CMD_GET_OPTION,
        RDMA_USER_CM_CMD_SET_OPTION,
        RDMA_USER_CM_CMD_NOTIFY,
-       RDMA_USER_CM_CMD_JOIN_MCAST,
+       RDMA_USER_CM_CMD_JOIN_IP_MCAST,
        RDMA_USER_CM_CMD_LEAVE_MCAST,
-       RDMA_USER_CM_CMD_MIGRATE_ID
+       RDMA_USER_CM_CMD_MIGRATE_ID,
+       RDMA_USER_CM_CMD_QUERY,
+       RDMA_USER_CM_CMD_BIND,
+       RDMA_USER_CM_CMD_RESOLVE_ADDR,
+       RDMA_USER_CM_CMD_JOIN_MCAST
 };
 
 /*
@@ -95,28 +99,51 @@ struct rdma_ucm_destroy_id_resp {
        __u32 events_reported;
 };
 
-struct rdma_ucm_bind_addr {
+struct rdma_ucm_bind_ip {
        __u64 response;
        struct sockaddr_in6 addr;
        __u32 id;
 };
 
-struct rdma_ucm_resolve_addr {
+struct rdma_ucm_bind {
+       __u32 id;
+       __u16 addr_size;
+       __u16 reserved;
+       struct sockaddr_storage addr;
+};
+
+struct rdma_ucm_resolve_ip {
        struct sockaddr_in6 src_addr;
        struct sockaddr_in6 dst_addr;
        __u32 id;
        __u32 timeout_ms;
 };
 
+struct rdma_ucm_resolve_addr {
+       __u32 id;
+       __u32 timeout_ms;
+       __u16 src_size;
+       __u16 dst_size;
+       __u32 reserved;
+       struct sockaddr_storage src_addr;
+       struct sockaddr_storage dst_addr;
+};
+
 struct rdma_ucm_resolve_route {
        __u32 id;
        __u32 timeout_ms;
 };
 
-struct rdma_ucm_query_route {
+enum {
+       RDMA_USER_CM_QUERY_ADDR,
+       RDMA_USER_CM_QUERY_PATH,
+       RDMA_USER_CM_QUERY_GID
+};
+
+struct rdma_ucm_query {
        __u64 response;
        __u32 id;
-       __u32 reserved;
+       __u32 option;
 };
 
 struct rdma_ucm_query_route_resp {
@@ -129,9 +156,26 @@ struct rdma_ucm_query_route_resp {
        __u8 reserved[3];
 };
 
+struct rdma_ucm_query_addr_resp {
+       __u64 node_guid;
+       __u8  port_num;
+       __u8  reserved;
+       __u16 pkey;
+       __u16 src_size;
+       __u16 dst_size;
+       struct sockaddr_storage src_addr;
+       struct sockaddr_storage dst_addr;
+};
+
+struct rdma_ucm_query_path_resp {
+       __u32 num_paths;
+       __u32 reserved;
+       struct ib_path_rec_data path_data[0];
+};
+
 struct rdma_ucm_conn_param {
        __u32 qp_num;
-       __u32 reserved;
+       __u32 qkey;
        __u8  private_data[RDMA_MAX_PRIVATE_DATA];
        __u8  private_data_len;
        __u8  srq;
@@ -192,13 +236,22 @@ struct rdma_ucm_notify {
        __u32 event;
 };
 
-struct rdma_ucm_join_mcast {
+struct rdma_ucm_join_ip_mcast {
        __u64 response;         /* rdma_ucm_create_id_resp */
        __u64 uid;
        struct sockaddr_in6 addr;
        __u32 id;
 };
 
+struct rdma_ucm_join_mcast {
+       __u64 response;         /* rdma_ucma_create_id_resp */
+       __u64 uid;
+       __u32 id;
+       __u16 addr_size;
+       __u16 reserved;
+       struct sockaddr_storage addr;
+};
+
 struct rdma_ucm_get_event {
        __u64 response;
 };
index 54d3fa5..247084b 100644 (file)
@@ -1596,6 +1596,17 @@ config SLOB
 
 endchoice
 
+config SLUB_CPU_PARTIAL
+       default y
+       depends on SLUB
+       bool "SLUB per cpu partial cache"
+       help
+         Per cpu partial caches accellerate objects allocation and freeing
+         that is local to a processor at the price of more indeterminism
+         in the latency of the free. On overflow these caches will be cleared
+         which requires the taking of locks that may cause latency spikes.
+         Typically one would choose no for a realtime system.
+
 config MMAP_ALLOW_UNINITIALIZED
        bool "Allow mmapped anonymous memory to be uninitialized"
        depends on EXPERT && !MMU
index e5583d1..0e0b20b 100644 (file)
@@ -802,7 +802,6 @@ static struct cgroup *task_cgroup_from_root(struct task_struct *task,
  */
 
 static int cgroup_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode);
-static struct dentry *cgroup_lookup(struct inode *, struct dentry *, unsigned int);
 static int cgroup_rmdir(struct inode *unused_dir, struct dentry *dentry);
 static int cgroup_populate_dir(struct cgroup *cgrp, bool base_files,
                               unsigned long subsys_mask);
@@ -2642,7 +2641,7 @@ static const struct inode_operations cgroup_file_inode_operations = {
 };
 
 static const struct inode_operations cgroup_dir_inode_operations = {
-       .lookup = cgroup_lookup,
+       .lookup = simple_lookup,
        .mkdir = cgroup_mkdir,
        .rmdir = cgroup_rmdir,
        .rename = cgroup_rename,
@@ -2652,14 +2651,6 @@ static const struct inode_operations cgroup_dir_inode_operations = {
        .removexattr = cgroup_removexattr,
 };
 
-static struct dentry *cgroup_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
-{
-       if (dentry->d_name.len > NAME_MAX)
-               return ERR_PTR(-ENAMETOOLONG);
-       d_add(dentry, NULL);
-       return NULL;
-}
-
 /*
  * Check if a file is a control file
  */
index 1db3af9..eba8fb5 100644 (file)
@@ -182,7 +182,7 @@ void update_perf_cpu_limits(void)
        u64 tmp = perf_sample_period_ns;
 
        tmp *= sysctl_perf_cpu_time_max_percent;
-       tmp = do_div(tmp, 100);
+       do_div(tmp, 100);
        atomic_set(&perf_sample_allowed_ns, tmp);
 }
 
@@ -232,7 +232,7 @@ DEFINE_PER_CPU(u64, running_sample_length);
 void perf_sample_event_took(u64 sample_len_ns)
 {
        u64 avg_local_sample_len;
-       u64 local_samples_len = __get_cpu_var(running_sample_length);
+       u64 local_samples_len;
 
        if (atomic_read(&perf_sample_allowed_ns) == 0)
                return;
@@ -947,8 +947,18 @@ perf_lock_task_context(struct task_struct *task, int ctxn, unsigned long *flags)
 {
        struct perf_event_context *ctx;
 
-       rcu_read_lock();
 retry:
+       /*
+        * One of the few rules of preemptible RCU is that one cannot do
+        * rcu_read_unlock() while holding a scheduler (or nested) lock when
+        * part of the read side critical section was preemptible -- see
+        * rcu_read_unlock_special().
+        *
+        * Since ctx->lock nests under rq->lock we must ensure the entire read
+        * side critical section is non-preemptible.
+        */
+       preempt_disable();
+       rcu_read_lock();
        ctx = rcu_dereference(task->perf_event_ctxp[ctxn]);
        if (ctx) {
                /*
@@ -964,6 +974,8 @@ retry:
                raw_spin_lock_irqsave(&ctx->lock, *flags);
                if (ctx != rcu_dereference(task->perf_event_ctxp[ctxn])) {
                        raw_spin_unlock_irqrestore(&ctx->lock, *flags);
+                       rcu_read_unlock();
+                       preempt_enable();
                        goto retry;
                }
 
@@ -973,6 +985,7 @@ retry:
                }
        }
        rcu_read_unlock();
+       preempt_enable();
        return ctx;
 }
 
@@ -1950,7 +1963,16 @@ static int __perf_event_enable(void *info)
        struct perf_cpu_context *cpuctx = __get_cpu_context(ctx);
        int err;
 
-       if (WARN_ON_ONCE(!ctx->is_active))
+       /*
+        * There's a time window between 'ctx->is_active' check
+        * in perf_event_enable function and this place having:
+        *   - IRQs on
+        *   - ctx->lock unlocked
+        *
+        * where the task could be killed and 'ctx' deactivated
+        * by perf_event_exit_task.
+        */
+       if (!ctx->is_active)
                return -EINVAL;
 
        raw_spin_lock(&ctx->lock);
@@ -7465,7 +7487,7 @@ inherit_task_group(struct perf_event *event, struct task_struct *parent,
                 * child.
                 */
 
-               child_ctx = alloc_perf_context(event->pmu, child);
+               child_ctx = alloc_perf_context(parent_ctx->pmu, child);
                if (!child_ctx)
                        return -ENOMEM;
 
index 6e6a1c1..66635c8 100644 (file)
@@ -365,8 +365,6 @@ static int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm)
        mm->locked_vm = 0;
        mm->mmap = NULL;
        mm->mmap_cache = NULL;
-       mm->free_area_cache = oldmm->mmap_base;
-       mm->cached_hole_size = ~0UL;
        mm->map_count = 0;
        cpumask_clear(mm_cpumask(mm));
        mm->mm_rb = RB_ROOT;
@@ -540,8 +538,6 @@ static struct mm_struct *mm_init(struct mm_struct *mm, struct task_struct *p)
        mm->nr_ptes = 0;
        memset(&mm->rss_stat, 0, sizeof(mm->rss_stat));
        spin_lock_init(&mm->page_table_lock);
-       mm->free_area_cache = TASK_UNMAPPED_BASE;
-       mm->cached_hole_size = ~0UL;
        mm_init_aio(mm);
        mm_init_owner(mm, p);
 
index 10e663a..452d6f2 100644 (file)
@@ -275,7 +275,7 @@ int irq_alloc_domain_generic_chips(struct irq_domain *d, int irqs_per_chip,
        if (d->gc)
                return -EBUSY;
 
-       numchips = d->revmap_size / irqs_per_chip;
+       numchips = DIV_ROUND_UP(d->revmap_size, irqs_per_chip);
        if (!numchips)
                return -EINVAL;
 
index 2d7cd34..706724e 100644 (file)
@@ -475,18 +475,6 @@ unsigned int irq_create_of_mapping(struct device_node *controller,
 
        domain = controller ? irq_find_host(controller) : irq_default_domain;
        if (!domain) {
-#ifdef CONFIG_MIPS
-               /*
-                * Workaround to avoid breaking interrupt controller drivers
-                * that don't yet register an irq_domain.  This is temporary
-                * code. ~~~gcl, Feb 24, 2012
-                *
-                * Scheduled for removal in Linux v3.6.  That should be enough
-                * time.
-                */
-               if (intsize > 0)
-                       return intspec[0];
-#endif
                pr_warn("no irq domain found for %s !\n",
                        of_node_full_name(controller));
                return 0;
index cab4bce..2069158 100644 (file)
@@ -455,7 +455,7 @@ const struct kernel_symbol *find_symbol(const char *name,
 EXPORT_SYMBOL_GPL(find_symbol);
 
 /* Search for module by name: must hold module_mutex. */
-static struct module *find_module_all(const char *name,
+static struct module *find_module_all(const char *name, size_t len,
                                      bool even_unformed)
 {
        struct module *mod;
@@ -463,7 +463,7 @@ static struct module *find_module_all(const char *name,
        list_for_each_entry(mod, &modules, list) {
                if (!even_unformed && mod->state == MODULE_STATE_UNFORMED)
                        continue;
-               if (strcmp(mod->name, name) == 0)
+               if (strlen(mod->name) == len && !memcmp(mod->name, name, len))
                        return mod;
        }
        return NULL;
@@ -471,7 +471,7 @@ static struct module *find_module_all(const char *name,
 
 struct module *find_module(const char *name)
 {
-       return find_module_all(name, false);
+       return find_module_all(name, strlen(name), false);
 }
 EXPORT_SYMBOL_GPL(find_module);
 
@@ -482,23 +482,28 @@ static inline void __percpu *mod_percpu(struct module *mod)
        return mod->percpu;
 }
 
-static int percpu_modalloc(struct module *mod,
-                          unsigned long size, unsigned long align)
+static int percpu_modalloc(struct module *mod, struct load_info *info)
 {
+       Elf_Shdr *pcpusec = &info->sechdrs[info->index.pcpu];
+       unsigned long align = pcpusec->sh_addralign;
+
+       if (!pcpusec->sh_size)
+               return 0;
+
        if (align > PAGE_SIZE) {
                printk(KERN_WARNING "%s: per-cpu alignment %li > %li\n",
                       mod->name, align, PAGE_SIZE);
                align = PAGE_SIZE;
        }
 
-       mod->percpu = __alloc_reserved_percpu(size, align);
+       mod->percpu = __alloc_reserved_percpu(pcpusec->sh_size, align);
        if (!mod->percpu) {
                printk(KERN_WARNING
                       "%s: Could not allocate %lu bytes percpu data\n",
-                      mod->name, size);
+                      mod->name, (unsigned long)pcpusec->sh_size);
                return -ENOMEM;
        }
-       mod->percpu_size = size;
+       mod->percpu_size = pcpusec->sh_size;
        return 0;
 }
 
@@ -563,10 +568,12 @@ static inline void __percpu *mod_percpu(struct module *mod)
 {
        return NULL;
 }
-static inline int percpu_modalloc(struct module *mod,
-                                 unsigned long size, unsigned long align)
+static int percpu_modalloc(struct module *mod, struct load_info *info)
 {
-       return -ENOMEM;
+       /* UP modules shouldn't have this section: ENOMEM isn't quite right */
+       if (info->sechdrs[info->index.pcpu].sh_size != 0)
+               return -ENOMEM;
+       return 0;
 }
 static inline void percpu_modfree(struct module *mod)
 {
@@ -2927,7 +2934,6 @@ static struct module *layout_and_allocate(struct load_info *info, int flags)
 {
        /* Module within temporary copy. */
        struct module *mod;
-       Elf_Shdr *pcpusec;
        int err;
 
        mod = setup_load_info(info, flags);
@@ -2942,17 +2948,10 @@ static struct module *layout_and_allocate(struct load_info *info, int flags)
        err = module_frob_arch_sections(info->hdr, info->sechdrs,
                                        info->secstrings, mod);
        if (err < 0)
-               goto out;
+               return ERR_PTR(err);
 
-       pcpusec = &info->sechdrs[info->index.pcpu];
-       if (pcpusec->sh_size) {
-               /* We have a special allocation for this section. */
-               err = percpu_modalloc(mod,
-                                     pcpusec->sh_size, pcpusec->sh_addralign);
-               if (err)
-                       goto out;
-               pcpusec->sh_flags &= ~(unsigned long)SHF_ALLOC;
-       }
+       /* We will do a special allocation for per-cpu sections later. */
+       info->sechdrs[info->index.pcpu].sh_flags &= ~(unsigned long)SHF_ALLOC;
 
        /* Determine total sizes, and put offsets in sh_entsize.  For now
           this is done generically; there doesn't appear to be any
@@ -2963,17 +2962,12 @@ static struct module *layout_and_allocate(struct load_info *info, int flags)
        /* Allocate and move to the final place */
        err = move_module(mod, info);
        if (err)
-               goto free_percpu;
+               return ERR_PTR(err);
 
        /* Module has been copied to its final place now: return it. */
        mod = (void *)info->sechdrs[info->index.mod].sh_addr;
        kmemleak_load_module(mod, info);
        return mod;
-
-free_percpu:
-       percpu_modfree(mod);
-out:
-       return ERR_PTR(err);
 }
 
 /* mod is no longer valid after this! */
@@ -3014,7 +3008,7 @@ static bool finished_loading(const char *name)
        bool ret;
 
        mutex_lock(&module_mutex);
-       mod = find_module_all(name, true);
+       mod = find_module_all(name, strlen(name), true);
        ret = !mod || mod->state == MODULE_STATE_LIVE
                || mod->state == MODULE_STATE_GOING;
        mutex_unlock(&module_mutex);
@@ -3152,7 +3146,8 @@ static int add_unformed_module(struct module *mod)
 
 again:
        mutex_lock(&module_mutex);
-       if ((old = find_module_all(mod->name, true)) != NULL) {
+       old = find_module_all(mod->name, strlen(mod->name), true);
+       if (old != NULL) {
                if (old->state == MODULE_STATE_COMING
                    || old->state == MODULE_STATE_UNFORMED) {
                        /* Wait in case it fails to load. */
@@ -3198,6 +3193,17 @@ out:
        return err;
 }
 
+static int unknown_module_param_cb(char *param, char *val, const char *modname)
+{
+       /* Check for magic 'dyndbg' arg */ 
+       int ret = ddebug_dyndbg_module_param_cb(param, val, modname);
+       if (ret != 0) {
+               printk(KERN_WARNING "%s: unknown parameter '%s' ignored\n",
+                      modname, param);
+       }
+       return 0;
+}
+
 /* Allocate and load the module: note that size of section 0 is always
    zero, and we rely on this for optional sections. */
 static int load_module(struct load_info *info, const char __user *uargs,
@@ -3237,6 +3243,11 @@ static int load_module(struct load_info *info, const char __user *uargs,
        }
 #endif
 
+       /* To avoid stressing percpu allocator, do this once we're unique. */
+       err = percpu_modalloc(mod, info);
+       if (err)
+               goto unlink_mod;
+
        /* Now module is in final location, initialize linked lists, etc. */
        err = module_unload_init(mod);
        if (err)
@@ -3284,7 +3295,7 @@ static int load_module(struct load_info *info, const char __user *uargs,
 
        /* Module is ready to execute: parsing args may do that. */
        err = parse_args(mod->name, mod->args, mod->kp, mod->num_kp,
-                        -32768, 32767, &ddebug_dyndbg_module_param_cb);
+                        -32768, 32767, unknown_module_param_cb);
        if (err < 0)
                goto bug_cleanup;
 
@@ -3563,10 +3574,8 @@ unsigned long module_kallsyms_lookup_name(const char *name)
        /* Don't lock: we're in enough trouble already. */
        preempt_disable();
        if ((colon = strchr(name, ':')) != NULL) {
-               *colon = '\0';
-               if ((mod = find_module(name)) != NULL)
+               if ((mod = find_module_all(name, colon - name, false)) != NULL)
                        ret = mod_find_symname(mod, colon+1);
-               *colon = ':';
        } else {
                list_for_each_entry_rcu(mod, &modules, list) {
                        if (mod->state == MODULE_STATE_UNFORMED)
index e581ada..ff05f4b 100644 (file)
@@ -18,6 +18,7 @@
  * Also see Documentation/mutex-design.txt.
  */
 #include <linux/mutex.h>
+#include <linux/ww_mutex.h>
 #include <linux/sched.h>
 #include <linux/sched/rt.h>
 #include <linux/export.h>
index 9771231..8018646 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/notifier.h>
 #include <linux/module.h>
 #include <linux/random.h>
+#include <linux/ftrace.h>
 #include <linux/reboot.h>
 #include <linux/delay.h>
 #include <linux/kexec.h>
@@ -399,6 +400,8 @@ struct slowpath_args {
 static void warn_slowpath_common(const char *file, int line, void *caller,
                                 unsigned taint, struct slowpath_args *args)
 {
+       disable_trace_on_warning();
+
        pr_warn("------------[ cut here ]------------\n");
        pr_warn("WARNING: CPU: %d PID: %d at %s:%d %pS()\n",
                raw_smp_processor_id(), current->pid, file, line, caller);
index 53b958f..440e65d 100644 (file)
@@ -787,7 +787,7 @@ static void __init kernel_add_sysfs_param(const char *name,
 }
 
 /*
- * param_sysfs_builtin - add contents in /sys/parameters for built-in modules
+ * param_sysfs_builtin - add sysfs parameters for built-in modules
  *
  * Add module_parameters to sysfs for "modules" built into the kernel.
  *
index 8212c1a..d37d45c 100644 (file)
@@ -1369,9 +1369,9 @@ static int console_trylock_for_printk(unsigned int cpu)
                }
        }
        logbuf_cpu = UINT_MAX;
+       raw_spin_unlock(&logbuf_lock);
        if (wake)
                up(&console_sem);
-       raw_spin_unlock(&logbuf_lock);
        return retval;
 }
 
index 9b1f2e5..0d8eb45 100644 (file)
@@ -370,13 +370,6 @@ static struct rq *this_rq_lock(void)
 #ifdef CONFIG_SCHED_HRTICK
 /*
  * Use HR-timers to deliver accurate preemption points.
- *
- * Its all a bit involved since we cannot program an hrt while holding the
- * rq->lock. So what we do is store a state in in rq->hrtick_* and ask for a
- * reschedule event.
- *
- * When we get rescheduled we reprogram the hrtick_timer outside of the
- * rq->lock.
  */
 
 static void hrtick_clear(struct rq *rq)
@@ -404,6 +397,15 @@ static enum hrtimer_restart hrtick(struct hrtimer *timer)
 }
 
 #ifdef CONFIG_SMP
+
+static int __hrtick_restart(struct rq *rq)
+{
+       struct hrtimer *timer = &rq->hrtick_timer;
+       ktime_t time = hrtimer_get_softexpires(timer);
+
+       return __hrtimer_start_range_ns(timer, time, 0, HRTIMER_MODE_ABS_PINNED, 0);
+}
+
 /*
  * called from hardirq (IPI) context
  */
@@ -412,7 +414,7 @@ static void __hrtick_start(void *arg)
        struct rq *rq = arg;
 
        raw_spin_lock(&rq->lock);
-       hrtimer_restart(&rq->hrtick_timer);
+       __hrtick_restart(rq);
        rq->hrtick_csd_pending = 0;
        raw_spin_unlock(&rq->lock);
 }
@@ -430,7 +432,7 @@ void hrtick_start(struct rq *rq, u64 delay)
        hrtimer_set_expires(timer, time);
 
        if (rq == this_rq()) {
-               hrtimer_restart(timer);
+               __hrtick_restart(rq);
        } else if (!rq->hrtick_csd_pending) {
                __smp_call_function_single(cpu_of(rq), &rq->hrtick_csd, 0);
                rq->hrtick_csd_pending = 1;
index 4ce13c3..ac09d98 100644 (file)
@@ -599,6 +599,13 @@ static struct ctl_table kern_table[] = {
                .mode           = 0644,
                .proc_handler   = proc_dointvec,
        },
+       {
+               .procname       = "traceoff_on_warning",
+               .data           = &__disable_trace_on_warning,
+               .maxlen         = sizeof(__disable_trace_on_warning),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec,
+       },
 #endif
 #ifdef CONFIG_MODULES
        {
@@ -800,7 +807,7 @@ static struct ctl_table kern_table[] = {
 #if defined(CONFIG_LOCKUP_DETECTOR)
        {
                .procname       = "watchdog",
-               .data           = &watchdog_enabled,
+               .data           = &watchdog_user_enabled,
                .maxlen         = sizeof (int),
                .mode           = 0644,
                .proc_handler   = proc_dowatchdog,
@@ -827,7 +834,7 @@ static struct ctl_table kern_table[] = {
        },
        {
                .procname       = "nmi_watchdog",
-               .data           = &watchdog_enabled,
+               .data           = &watchdog_user_enabled,
                .maxlen         = sizeof (int),
                .mode           = 0644,
                .proc_handler   = proc_dowatchdog,
index b38a43d..cdc198f 100644 (file)
@@ -157,7 +157,10 @@ int tick_device_uses_broadcast(struct clock_event_device *dev, int cpu)
                dev->event_handler = tick_handle_periodic;
                tick_device_setup_broadcast_func(dev);
                cpumask_set_cpu(cpu, tick_broadcast_mask);
-               tick_broadcast_start_periodic(bc);
+               if (tick_broadcast_device.mode == TICKDEV_MODE_PERIODIC)
+                       tick_broadcast_start_periodic(bc);
+               else
+                       tick_broadcast_setup_oneshot(bc);
                ret = 1;
        } else {
                /*
index 0cf1c14..6960172 100644 (file)
@@ -178,6 +178,11 @@ static bool can_stop_full_tick(void)
         */
        if (!sched_clock_stable) {
                trace_tick_stop(0, "unstable sched clock\n");
+               /*
+                * Don't allow the user to think they can get
+                * full NO_HZ with this machine.
+                */
+               WARN_ONCE(1, "NO_HZ FULL will not work with unstable sched clock");
                return false;
        }
 #endif
@@ -346,16 +351,6 @@ void __init tick_nohz_init(void)
        }
 
        cpu_notifier(tick_nohz_cpu_down_callback, 0);
-
-       /* Make sure full dynticks CPU are also RCU nocbs */
-       for_each_cpu(cpu, nohz_full_mask) {
-               if (!rcu_is_nocb_cpu(cpu)) {
-                       pr_warning("NO_HZ: CPU %d is not RCU nocb: "
-                                  "cleared from nohz_full range", cpu);
-                       cpumask_clear_cpu(cpu, nohz_full_mask);
-               }
-       }
-
        cpulist_scnprintf(nohz_full_buf, sizeof(nohz_full_buf), nohz_full_mask);
        pr_info("NO_HZ: Full dynticks CPUs: %s.\n", nohz_full_buf);
 }
index 6c508ff..67708f4 100644 (file)
@@ -413,6 +413,17 @@ static int __register_ftrace_function(struct ftrace_ops *ops)
        return 0;
 }
 
+static void ftrace_sync(struct work_struct *work)
+{
+       /*
+        * This function is just a stub to implement a hard force
+        * of synchronize_sched(). This requires synchronizing
+        * tasks even in userspace and idle.
+        *
+        * Yes, function tracing is rude.
+        */
+}
+
 static int __unregister_ftrace_function(struct ftrace_ops *ops)
 {
        int ret;
@@ -440,8 +451,12 @@ static int __unregister_ftrace_function(struct ftrace_ops *ops)
                         * so there'll be no new users. We must ensure
                         * all current users are done before we free
                         * the control data.
+                        * Note synchronize_sched() is not enough, as we
+                        * use preempt_disable() to do RCU, but the function
+                        * tracer can be called where RCU is not active
+                        * (before user_exit()).
                         */
-                       synchronize_sched();
+                       schedule_on_each_cpu(ftrace_sync);
                        control_ops_free(ops);
                }
        } else
@@ -456,9 +471,13 @@ static int __unregister_ftrace_function(struct ftrace_ops *ops)
        /*
         * Dynamic ops may be freed, we must make sure that all
         * callers are done before leaving this function.
+        *
+        * Again, normal synchronize_sched() is not good enough.
+        * We need to do a hard force of sched synchronization.
         */
        if (ops->flags & FTRACE_OPS_FL_DYNAMIC)
-               synchronize_sched();
+               schedule_on_each_cpu(ftrace_sync);
+
 
        return 0;
 }
@@ -622,12 +641,18 @@ static int function_stat_show(struct seq_file *m, void *v)
        if (rec->counter <= 1)
                stddev = 0;
        else {
-               stddev = rec->time_squared - rec->counter * avg * avg;
+               /*
+                * Apply Welford's method:
+                * s^2 = 1 / (n * (n-1)) * (n * \Sum (x_i)^2 - (\Sum x_i)^2)
+                */
+               stddev = rec->counter * rec->time_squared -
+                        rec->time * rec->time;
+
                /*
                 * Divide only 1000 for ns^2 -> us^2 conversion.
                 * trace_print_graph_duration will divide 1000 again.
                 */
-               do_div(stddev, (rec->counter - 1) * 1000);
+               do_div(stddev, rec->counter * (rec->counter - 1) * 1000);
        }
 
        trace_seq_init(&s);
@@ -3512,8 +3537,12 @@ EXPORT_SYMBOL_GPL(ftrace_set_global_notrace);
 static char ftrace_notrace_buf[FTRACE_FILTER_SIZE] __initdata;
 static char ftrace_filter_buf[FTRACE_FILTER_SIZE] __initdata;
 
+/* Used by function selftest to not test if filter is set */
+bool ftrace_filter_param __initdata;
+
 static int __init set_ftrace_notrace(char *str)
 {
+       ftrace_filter_param = true;
        strlcpy(ftrace_notrace_buf, str, FTRACE_FILTER_SIZE);
        return 1;
 }
@@ -3521,6 +3550,7 @@ __setup("ftrace_notrace=", set_ftrace_notrace);
 
 static int __init set_ftrace_filter(char *str)
 {
+       ftrace_filter_param = true;
        strlcpy(ftrace_filter_buf, str, FTRACE_FILTER_SIZE);
        return 1;
 }
index e71a8be..0cd500b 100644 (file)
@@ -115,6 +115,9 @@ cpumask_var_t __read_mostly tracing_buffer_mask;
 
 enum ftrace_dump_mode ftrace_dump_on_oops;
 
+/* When set, tracing will stop when a WARN*() is hit */
+int __disable_trace_on_warning;
+
 static int tracing_set_tracer(const char *buf);
 
 #define MAX_TRACER_SIZE                100
@@ -149,6 +152,13 @@ static int __init set_ftrace_dump_on_oops(char *str)
 }
 __setup("ftrace_dump_on_oops", set_ftrace_dump_on_oops);
 
+static int __init stop_trace_on_warning(char *str)
+{
+       __disable_trace_on_warning = 1;
+       return 1;
+}
+__setup("traceoff_on_warning=", stop_trace_on_warning);
+
 static int __init boot_alloc_snapshot(char *str)
 {
        allocate_snapshot = true;
@@ -170,6 +180,7 @@ static int __init set_trace_boot_options(char *str)
 }
 __setup("trace_options=", set_trace_boot_options);
 
+
 unsigned long long ns2usecs(cycle_t nsec)
 {
        nsec += 500;
@@ -193,6 +204,37 @@ static struct trace_array  global_trace;
 
 LIST_HEAD(ftrace_trace_arrays);
 
+int trace_array_get(struct trace_array *this_tr)
+{
+       struct trace_array *tr;
+       int ret = -ENODEV;
+
+       mutex_lock(&trace_types_lock);
+       list_for_each_entry(tr, &ftrace_trace_arrays, list) {
+               if (tr == this_tr) {
+                       tr->ref++;
+                       ret = 0;
+                       break;
+               }
+       }
+       mutex_unlock(&trace_types_lock);
+
+       return ret;
+}
+
+static void __trace_array_put(struct trace_array *this_tr)
+{
+       WARN_ON(!this_tr->ref);
+       this_tr->ref--;
+}
+
+void trace_array_put(struct trace_array *this_tr)
+{
+       mutex_lock(&trace_types_lock);
+       __trace_array_put(this_tr);
+       mutex_unlock(&trace_types_lock);
+}
+
 int filter_current_check_discard(struct ring_buffer *buffer,
                                 struct ftrace_event_call *call, void *rec,
                                 struct ring_buffer_event *event)
@@ -215,9 +257,24 @@ cycle_t ftrace_now(int cpu)
        return ts;
 }
 
+/**
+ * tracing_is_enabled - Show if global_trace has been disabled
+ *
+ * Shows if the global trace has been enabled or not. It uses the
+ * mirror flag "buffer_disabled" to be used in fast paths such as for
+ * the irqsoff tracer. But it may be inaccurate due to races. If you
+ * need to know the accurate state, use tracing_is_on() which is a little
+ * slower, but accurate.
+ */
 int tracing_is_enabled(void)
 {
-       return tracing_is_on();
+       /*
+        * For quick access (irqsoff uses this in fast path), just
+        * return the mirror variable of the state of the ring buffer.
+        * It's a little racy, but we don't really care.
+        */
+       smp_rmb();
+       return !global_trace.buffer_disabled;
 }
 
 /*
@@ -240,7 +297,7 @@ static struct tracer                *trace_types __read_mostly;
 /*
  * trace_types_lock is used to protect the trace_types list.
  */
-static DEFINE_MUTEX(trace_types_lock);
+DEFINE_MUTEX(trace_types_lock);
 
 /*
  * serialize the access of the ring buffer
@@ -330,6 +387,23 @@ unsigned long trace_flags = TRACE_ITER_PRINT_PARENT | TRACE_ITER_PRINTK |
        TRACE_ITER_GRAPH_TIME | TRACE_ITER_RECORD_CMD | TRACE_ITER_OVERWRITE |
        TRACE_ITER_IRQ_INFO | TRACE_ITER_MARKERS | TRACE_ITER_FUNCTION;
 
+static void tracer_tracing_on(struct trace_array *tr)
+{
+       if (tr->trace_buffer.buffer)
+               ring_buffer_record_on(tr->trace_buffer.buffer);
+       /*
+        * This flag is looked at when buffers haven't been allocated
+        * yet, or by some tracers (like irqsoff), that just want to
+        * know if the ring buffer has been disabled, but it can handle
+        * races of where it gets disabled but we still do a record.
+        * As the check is in the fast path of the tracers, it is more
+        * important to be fast than accurate.
+        */
+       tr->buffer_disabled = 0;
+       /* Make the flag seen by readers */
+       smp_wmb();
+}
+
 /**
  * tracing_on - enable tracing buffers
  *
@@ -338,15 +412,7 @@ unsigned long trace_flags = TRACE_ITER_PRINT_PARENT | TRACE_ITER_PRINTK |
  */
 void tracing_on(void)
 {
-       if (global_trace.trace_buffer.buffer)
-               ring_buffer_record_on(global_trace.trace_buffer.buffer);
-       /*
-        * This flag is only looked at when buffers haven't been
-        * allocated yet. We don't really care about the race
-        * between setting this flag and actually turning
-        * on the buffer.
-        */
-       global_trace.buffer_disabled = 0;
+       tracer_tracing_on(&global_trace);
 }
 EXPORT_SYMBOL_GPL(tracing_on);
 
@@ -540,6 +606,23 @@ void tracing_snapshot_alloc(void)
 EXPORT_SYMBOL_GPL(tracing_snapshot_alloc);
 #endif /* CONFIG_TRACER_SNAPSHOT */
 
+static void tracer_tracing_off(struct trace_array *tr)
+{
+       if (tr->trace_buffer.buffer)
+               ring_buffer_record_off(tr->trace_buffer.buffer);
+       /*
+        * This flag is looked at when buffers haven't been allocated
+        * yet, or by some tracers (like irqsoff), that just want to
+        * know if the ring buffer has been disabled, but it can handle
+        * races of where it gets disabled but we still do a record.
+        * As the check is in the fast path of the tracers, it is more
+        * important to be fast than accurate.
+        */
+       tr->buffer_disabled = 1;
+       /* Make the flag seen by readers */
+       smp_wmb();
+}
+
 /**
  * tracing_off - turn off tracing buffers
  *
@@ -550,26 +633,35 @@ EXPORT_SYMBOL_GPL(tracing_snapshot_alloc);
  */
 void tracing_off(void)
 {
-       if (global_trace.trace_buffer.buffer)
-               ring_buffer_record_off(global_trace.trace_buffer.buffer);
-       /*
-        * This flag is only looked at when buffers haven't been
-        * allocated yet. We don't really care about the race
-        * between setting this flag and actually turning
-        * on the buffer.
-        */
-       global_trace.buffer_disabled = 1;
+       tracer_tracing_off(&global_trace);
 }
 EXPORT_SYMBOL_GPL(tracing_off);
 
+void disable_trace_on_warning(void)
+{
+       if (__disable_trace_on_warning)
+               tracing_off();
+}
+
+/**
+ * tracer_tracing_is_on - show real state of ring buffer enabled
+ * @tr : the trace array to know if ring buffer is enabled
+ *
+ * Shows real state of the ring buffer if it is enabled or not.
+ */
+static int tracer_tracing_is_on(struct trace_array *tr)
+{
+       if (tr->trace_buffer.buffer)
+               return ring_buffer_record_is_on(tr->trace_buffer.buffer);
+       return !tr->buffer_disabled;
+}
+
 /**
  * tracing_is_on - show state of ring buffers enabled
  */
 int tracing_is_on(void)
 {
-       if (global_trace.trace_buffer.buffer)
-               return ring_buffer_record_is_on(global_trace.trace_buffer.buffer);
-       return !global_trace.buffer_disabled;
+       return tracer_tracing_is_on(&global_trace);
 }
 EXPORT_SYMBOL_GPL(tracing_is_on);
 
@@ -1543,15 +1635,6 @@ trace_function(struct trace_array *tr,
                __buffer_unlock_commit(buffer, event);
 }
 
-void
-ftrace(struct trace_array *tr, struct trace_array_cpu *data,
-       unsigned long ip, unsigned long parent_ip, unsigned long flags,
-       int pc)
-{
-       if (likely(!atomic_read(&data->disabled)))
-               trace_function(tr, ip, parent_ip, flags, pc);
-}
-
 #ifdef CONFIG_STACKTRACE
 
 #define FTRACE_STACK_MAX_ENTRIES (PAGE_SIZE / sizeof(unsigned long))
@@ -2768,10 +2851,9 @@ static const struct seq_operations tracer_seq_ops = {
 };
 
 static struct trace_iterator *
-__tracing_open(struct inode *inode, struct file *file, bool snapshot)
+__tracing_open(struct trace_array *tr, struct trace_cpu *tc,
+              struct inode *inode, struct file *file, bool snapshot)
 {
-       struct trace_cpu *tc = inode->i_private;
-       struct trace_array *tr = tc->tr;
        struct trace_iterator *iter;
        int cpu;
 
@@ -2850,8 +2932,6 @@ __tracing_open(struct inode *inode, struct file *file, bool snapshot)
                tracing_iter_reset(iter, cpu);
        }
 
-       tr->ref++;
-
        mutex_unlock(&trace_types_lock);
 
        return iter;
@@ -2874,6 +2954,43 @@ int tracing_open_generic(struct inode *inode, struct file *filp)
        return 0;
 }
 
+/*
+ * Open and update trace_array ref count.
+ * Must have the current trace_array passed to it.
+ */
+static int tracing_open_generic_tr(struct inode *inode, struct file *filp)
+{
+       struct trace_array *tr = inode->i_private;
+
+       if (tracing_disabled)
+               return -ENODEV;
+
+       if (trace_array_get(tr) < 0)
+               return -ENODEV;
+
+       filp->private_data = inode->i_private;
+
+       return 0;
+       
+}
+
+static int tracing_open_generic_tc(struct inode *inode, struct file *filp)
+{
+       struct trace_cpu *tc = inode->i_private;
+       struct trace_array *tr = tc->tr;
+
+       if (tracing_disabled)
+               return -ENODEV;
+
+       if (trace_array_get(tr) < 0)
+               return -ENODEV;
+
+       filp->private_data = inode->i_private;
+
+       return 0;
+       
+}
+
 static int tracing_release(struct inode *inode, struct file *file)
 {
        struct seq_file *m = file->private_data;
@@ -2881,17 +2998,20 @@ static int tracing_release(struct inode *inode, struct file *file)
        struct trace_array *tr;
        int cpu;
 
-       if (!(file->f_mode & FMODE_READ))
+       /* Writes do not use seq_file, need to grab tr from inode */
+       if (!(file->f_mode & FMODE_READ)) {
+               struct trace_cpu *tc = inode->i_private;
+
+               trace_array_put(tc->tr);
                return 0;
+       }
 
        iter = m->private;
        tr = iter->tr;
+       trace_array_put(tr);
 
        mutex_lock(&trace_types_lock);
 
-       WARN_ON(!tr->ref);
-       tr->ref--;
-
        for_each_tracing_cpu(cpu) {
                if (iter->buffer_iter[cpu])
                        ring_buffer_read_finish(iter->buffer_iter[cpu]);
@@ -2910,20 +3030,49 @@ static int tracing_release(struct inode *inode, struct file *file)
        kfree(iter->trace);
        kfree(iter->buffer_iter);
        seq_release_private(inode, file);
+
+       return 0;
+}
+
+static int tracing_release_generic_tr(struct inode *inode, struct file *file)
+{
+       struct trace_array *tr = inode->i_private;
+
+       trace_array_put(tr);
        return 0;
 }
 
+static int tracing_release_generic_tc(struct inode *inode, struct file *file)
+{
+       struct trace_cpu *tc = inode->i_private;
+       struct trace_array *tr = tc->tr;
+
+       trace_array_put(tr);
+       return 0;
+}
+
+static int tracing_single_release_tr(struct inode *inode, struct file *file)
+{
+       struct trace_array *tr = inode->i_private;
+
+       trace_array_put(tr);
+
+       return single_release(inode, file);
+}
+
 static int tracing_open(struct inode *inode, struct file *file)
 {
+       struct trace_cpu *tc = inode->i_private;
+       struct trace_array *tr = tc->tr;
        struct trace_iterator *iter;
        int ret = 0;
 
+       if (trace_array_get(tr) < 0)
+               return -ENODEV;
+
        /* If this file was open for write, then erase contents */
        if ((file->f_mode & FMODE_WRITE) &&
            (file->f_flags & O_TRUNC)) {
-               struct trace_cpu *tc = inode->i_private;
-               struct trace_array *tr = tc->tr;
-
                if (tc->cpu == RING_BUFFER_ALL_CPUS)
                        tracing_reset_online_cpus(&tr->trace_buffer);
                else
@@ -2931,12 +3080,16 @@ static int tracing_open(struct inode *inode, struct file *file)
        }
 
        if (file->f_mode & FMODE_READ) {
-               iter = __tracing_open(inode, file, false);
+               iter = __tracing_open(tr, tc, inode, file, false);
                if (IS_ERR(iter))
                        ret = PTR_ERR(iter);
                else if (trace_flags & TRACE_ITER_LATENCY_FMT)
                        iter->iter_flags |= TRACE_FILE_LAT_FMT;
        }
+
+       if (ret < 0)
+               trace_array_put(tr);
+
        return ret;
 }
 
@@ -3293,9 +3446,14 @@ tracing_trace_options_write(struct file *filp, const char __user *ubuf,
 
 static int tracing_trace_options_open(struct inode *inode, struct file *file)
 {
+       struct trace_array *tr = inode->i_private;
+
        if (tracing_disabled)
                return -ENODEV;
 
+       if (trace_array_get(tr) < 0)
+               return -ENODEV;
+
        return single_open(file, tracing_trace_options_show, inode->i_private);
 }
 
@@ -3303,7 +3461,7 @@ static const struct file_operations tracing_iter_fops = {
        .open           = tracing_trace_options_open,
        .read           = seq_read,
        .llseek         = seq_lseek,
-       .release        = single_release,
+       .release        = tracing_single_release_tr,
        .write          = tracing_trace_options_write,
 };
 
@@ -3791,6 +3949,9 @@ static int tracing_open_pipe(struct inode *inode, struct file *filp)
        if (tracing_disabled)
                return -ENODEV;
 
+       if (trace_array_get(tr) < 0)
+               return -ENODEV;
+
        mutex_lock(&trace_types_lock);
 
        /* create a buffer to store the information to pass to userspace */
@@ -3843,6 +4004,7 @@ out:
 fail:
        kfree(iter->trace);
        kfree(iter);
+       __trace_array_put(tr);
        mutex_unlock(&trace_types_lock);
        return ret;
 }
@@ -3850,6 +4012,8 @@ fail:
 static int tracing_release_pipe(struct inode *inode, struct file *file)
 {
        struct trace_iterator *iter = file->private_data;
+       struct trace_cpu *tc = inode->i_private;
+       struct trace_array *tr = tc->tr;
 
        mutex_lock(&trace_types_lock);
 
@@ -3863,6 +4027,8 @@ static int tracing_release_pipe(struct inode *inode, struct file *file)
        kfree(iter->trace);
        kfree(iter);
 
+       trace_array_put(tr);
+
        return 0;
 }
 
@@ -3939,7 +4105,7 @@ static int tracing_wait_pipe(struct file *filp)
                 *
                 * iter->pos will be 0 if we haven't read anything.
                 */
-               if (!tracing_is_enabled() && iter->pos)
+               if (!tracing_is_on() && iter->pos)
                        break;
        }
 
@@ -4320,6 +4486,8 @@ tracing_free_buffer_release(struct inode *inode, struct file *filp)
        /* resize the ring buffer to 0 */
        tracing_resize_ring_buffer(tr, 0, RING_BUFFER_ALL_CPUS);
 
+       trace_array_put(tr);
+
        return 0;
 }
 
@@ -4328,6 +4496,7 @@ tracing_mark_write(struct file *filp, const char __user *ubuf,
                                        size_t cnt, loff_t *fpos)
 {
        unsigned long addr = (unsigned long)ubuf;
+       struct trace_array *tr = filp->private_data;
        struct ring_buffer_event *event;
        struct ring_buffer *buffer;
        struct print_entry *entry;
@@ -4387,7 +4556,7 @@ tracing_mark_write(struct file *filp, const char __user *ubuf,
 
        local_save_flags(irq_flags);
        size = sizeof(*entry) + cnt + 2; /* possible \n added */
-       buffer = global_trace.trace_buffer.buffer;
+       buffer = tr->trace_buffer.buffer;
        event = trace_buffer_lock_reserve(buffer, TRACE_PRINT, size,
                                          irq_flags, preempt_count());
        if (!event) {
@@ -4495,10 +4664,20 @@ static ssize_t tracing_clock_write(struct file *filp, const char __user *ubuf,
 
 static int tracing_clock_open(struct inode *inode, struct file *file)
 {
+       struct trace_array *tr = inode->i_private;
+       int ret;
+
        if (tracing_disabled)
                return -ENODEV;
 
-       return single_open(file, tracing_clock_show, inode->i_private);
+       if (trace_array_get(tr))
+               return -ENODEV;
+
+       ret = single_open(file, tracing_clock_show, inode->i_private);
+       if (ret < 0)
+               trace_array_put(tr);
+
+       return ret;
 }
 
 struct ftrace_buffer_info {
@@ -4511,12 +4690,16 @@ struct ftrace_buffer_info {
 static int tracing_snapshot_open(struct inode *inode, struct file *file)
 {
        struct trace_cpu *tc = inode->i_private;
+       struct trace_array *tr = tc->tr;
        struct trace_iterator *iter;
        struct seq_file *m;
        int ret = 0;
 
+       if (trace_array_get(tr) < 0)
+               return -ENODEV;
+
        if (file->f_mode & FMODE_READ) {
-               iter = __tracing_open(inode, file, true);
+               iter = __tracing_open(tr, tc, inode, file, true);
                if (IS_ERR(iter))
                        ret = PTR_ERR(iter);
        } else {
@@ -4529,13 +4712,16 @@ static int tracing_snapshot_open(struct inode *inode, struct file *file)
                        kfree(m);
                        return -ENOMEM;
                }
-               iter->tr = tc->tr;
+               iter->tr = tr;
                iter->trace_buffer = &tc->tr->max_buffer;
                iter->cpu_file = tc->cpu;
                m->private = iter;
                file->private_data = m;
        }
 
+       if (ret < 0)
+               trace_array_put(tr);
+
        return ret;
 }
 
@@ -4616,9 +4802,12 @@ out:
 static int tracing_snapshot_release(struct inode *inode, struct file *file)
 {
        struct seq_file *m = file->private_data;
+       int ret;
+
+       ret = tracing_release(inode, file);
 
        if (file->f_mode & FMODE_READ)
-               return tracing_release(inode, file);
+               return ret;
 
        /* If write only, the seq_file is just a stub */
        if (m)
@@ -4684,34 +4873,38 @@ static const struct file_operations tracing_pipe_fops = {
 };
 
 static const struct file_operations tracing_entries_fops = {
-       .open           = tracing_open_generic,
+       .open           = tracing_open_generic_tc,
        .read           = tracing_entries_read,
        .write          = tracing_entries_write,
        .llseek         = generic_file_llseek,
+       .release        = tracing_release_generic_tc,
 };
 
 static const struct file_operations tracing_total_entries_fops = {
-       .open           = tracing_open_generic,
+       .open           = tracing_open_generic_tr,
        .read           = tracing_total_entries_read,
        .llseek         = generic_file_llseek,
+       .release        = tracing_release_generic_tr,
 };
 
 static const struct file_operations tracing_free_buffer_fops = {
+       .open           = tracing_open_generic_tr,
        .write          = tracing_free_buffer_write,
        .release        = tracing_free_buffer_release,
 };
 
 static const struct file_operations tracing_mark_fops = {
-       .open           = tracing_open_generic,
+       .open           = tracing_open_generic_tr,
        .write          = tracing_mark_write,
        .llseek         = generic_file_llseek,
+       .release        = tracing_release_generic_tr,
 };
 
 static const struct file_operations trace_clock_fops = {
        .open           = tracing_clock_open,
        .read           = seq_read,
        .llseek         = seq_lseek,
-       .release        = single_release,
+       .release        = tracing_single_release_tr,
        .write          = tracing_clock_write,
 };
 
@@ -4739,13 +4932,19 @@ static int tracing_buffers_open(struct inode *inode, struct file *filp)
        struct trace_cpu *tc = inode->i_private;
        struct trace_array *tr = tc->tr;
        struct ftrace_buffer_info *info;
+       int ret;
 
        if (tracing_disabled)
                return -ENODEV;
 
+       if (trace_array_get(tr) < 0)
+               return -ENODEV;
+
        info = kzalloc(sizeof(*info), GFP_KERNEL);
-       if (!info)
+       if (!info) {
+               trace_array_put(tr);
                return -ENOMEM;
+       }
 
        mutex_lock(&trace_types_lock);
 
@@ -4763,7 +4962,11 @@ static int tracing_buffers_open(struct inode *inode, struct file *filp)
 
        mutex_unlock(&trace_types_lock);
 
-       return nonseekable_open(inode, filp);
+       ret = nonseekable_open(inode, filp);
+       if (ret < 0)
+               trace_array_put(tr);
+
+       return ret;
 }
 
 static unsigned int
@@ -4863,8 +5066,7 @@ static int tracing_buffers_release(struct inode *inode, struct file *file)
 
        mutex_lock(&trace_types_lock);
 
-       WARN_ON(!iter->tr->ref);
-       iter->tr->ref--;
+       __trace_array_put(iter->tr);
 
        if (info->spare)
                ring_buffer_free_read_page(iter->trace_buffer->buffer, info->spare);
@@ -5612,15 +5814,10 @@ rb_simple_read(struct file *filp, char __user *ubuf,
               size_t cnt, loff_t *ppos)
 {
        struct trace_array *tr = filp->private_data;
-       struct ring_buffer *buffer = tr->trace_buffer.buffer;
        char buf[64];
        int r;
 
-       if (buffer)
-               r = ring_buffer_record_is_on(buffer);
-       else
-               r = 0;
-
+       r = tracer_tracing_is_on(tr);
        r = sprintf(buf, "%d\n", r);
 
        return simple_read_from_buffer(ubuf, cnt, ppos, buf, r);
@@ -5642,11 +5839,11 @@ rb_simple_write(struct file *filp, const char __user *ubuf,
        if (buffer) {
                mutex_lock(&trace_types_lock);
                if (val) {
-                       ring_buffer_record_on(buffer);
+                       tracer_tracing_on(tr);
                        if (tr->current_trace->start)
                                tr->current_trace->start(tr);
                } else {
-                       ring_buffer_record_off(buffer);
+                       tracer_tracing_off(tr);
                        if (tr->current_trace->stop)
                                tr->current_trace->stop(tr);
                }
@@ -5659,9 +5856,10 @@ rb_simple_write(struct file *filp, const char __user *ubuf,
 }
 
 static const struct file_operations rb_simple_fops = {
-       .open           = tracing_open_generic,
+       .open           = tracing_open_generic_tr,
        .read           = rb_simple_read,
        .write          = rb_simple_write,
+       .release        = tracing_release_generic_tr,
        .llseek         = default_llseek,
 };
 
@@ -5933,7 +6131,7 @@ init_tracer_debugfs(struct trace_array *tr, struct dentry *d_tracer)
        trace_create_file("buffer_total_size_kb", 0444, d_tracer,
                          tr, &tracing_total_entries_fops);
 
-       trace_create_file("free_buffer", 0644, d_tracer,
+       trace_create_file("free_buffer", 0200, d_tracer,
                          tr, &tracing_free_buffer_fops);
 
        trace_create_file("trace_marker", 0220, d_tracer,
index 20572ed..4a4f6e1 100644 (file)
@@ -224,6 +224,11 @@ enum {
 
 extern struct list_head ftrace_trace_arrays;
 
+extern struct mutex trace_types_lock;
+
+extern int trace_array_get(struct trace_array *tr);
+extern void trace_array_put(struct trace_array *tr);
+
 /*
  * The global tracer (top) should be the first trace array added,
  * but we check the flag anyway.
@@ -554,11 +559,6 @@ void tracing_iter_reset(struct trace_iterator *iter, int cpu);
 
 void poll_wait_pipe(struct trace_iterator *iter);
 
-void ftrace(struct trace_array *tr,
-                           struct trace_array_cpu *data,
-                           unsigned long ip,
-                           unsigned long parent_ip,
-                           unsigned long flags, int pc);
 void tracing_sched_switch_trace(struct trace_array *tr,
                                struct task_struct *prev,
                                struct task_struct *next,
@@ -774,6 +774,7 @@ print_graph_function_flags(struct trace_iterator *iter, u32 flags)
 extern struct list_head ftrace_pids;
 
 #ifdef CONFIG_FUNCTION_TRACER
+extern bool ftrace_filter_param __initdata;
 static inline int ftrace_trace_task(struct task_struct *task)
 {
        if (list_empty(&ftrace_pids))
@@ -899,12 +900,6 @@ static inline void trace_branch_disable(void)
 /* set ring buffers to default size if not already done so */
 int tracing_update_buffers(void);
 
-/* trace event type bit fields, not numeric */
-enum {
-       TRACE_EVENT_TYPE_PRINTF         = 1,
-       TRACE_EVENT_TYPE_RAW            = 2,
-};
-
 struct ftrace_event_field {
        struct list_head        link;
        const char              *name;
index 27963e2..7d85429 100644 (file)
@@ -41,6 +41,23 @@ static LIST_HEAD(ftrace_common_fields);
 static struct kmem_cache *field_cachep;
 static struct kmem_cache *file_cachep;
 
+#define SYSTEM_FL_FREE_NAME            (1 << 31)
+
+static inline int system_refcount(struct event_subsystem *system)
+{
+       return system->ref_count & ~SYSTEM_FL_FREE_NAME;
+}
+
+static int system_refcount_inc(struct event_subsystem *system)
+{
+       return (system->ref_count++) & ~SYSTEM_FL_FREE_NAME;
+}
+
+static int system_refcount_dec(struct event_subsystem *system)
+{
+       return (--system->ref_count) & ~SYSTEM_FL_FREE_NAME;
+}
+
 /* Double loops, do not use break, only goto's work */
 #define do_for_each_event_file(tr, file)                       \
        list_for_each_entry(tr, &ftrace_trace_arrays, list) {   \
@@ -97,7 +114,7 @@ static int __trace_define_field(struct list_head *head, const char *type,
 
        field = kmem_cache_alloc(field_cachep, GFP_TRACE);
        if (!field)
-               goto err;
+               return -ENOMEM;
 
        field->name = name;
        field->type = type;
@@ -114,11 +131,6 @@ static int __trace_define_field(struct list_head *head, const char *type,
        list_add(&field->link, head);
 
        return 0;
-
-err:
-       kmem_cache_free(field_cachep, field);
-
-       return -ENOMEM;
 }
 
 int trace_define_field(struct ftrace_event_call *call, const char *type,
@@ -279,9 +291,11 @@ static int __ftrace_event_enable_disable(struct ftrace_event_file *file,
                        }
                        call->class->reg(call, TRACE_REG_UNREGISTER, file);
                }
-               /* If in SOFT_MODE, just set the SOFT_DISABLE_BIT */
+               /* If in SOFT_MODE, just set the SOFT_DISABLE_BIT, else clear it */
                if (file->flags & FTRACE_EVENT_FL_SOFT_MODE)
                        set_bit(FTRACE_EVENT_FL_SOFT_DISABLED_BIT, &file->flags);
+               else
+                       clear_bit(FTRACE_EVENT_FL_SOFT_DISABLED_BIT, &file->flags);
                break;
        case 1:
                /*
@@ -349,8 +363,8 @@ static void __put_system(struct event_subsystem *system)
 {
        struct event_filter *filter = system->filter;
 
-       WARN_ON_ONCE(system->ref_count == 0);
-       if (--system->ref_count)
+       WARN_ON_ONCE(system_refcount(system) == 0);
+       if (system_refcount_dec(system))
                return;
 
        list_del(&system->list);
@@ -359,13 +373,15 @@ static void __put_system(struct event_subsystem *system)
                kfree(filter->filter_string);
                kfree(filter);
        }
+       if (system->ref_count & SYSTEM_FL_FREE_NAME)
+               kfree(system->name);
        kfree(system);
 }
 
 static void __get_system(struct event_subsystem *system)
 {
-       WARN_ON_ONCE(system->ref_count == 0);
-       system->ref_count++;
+       WARN_ON_ONCE(system_refcount(system) == 0);
+       system_refcount_inc(system);
 }
 
 static void __get_system_dir(struct ftrace_subsystem_dir *dir)
@@ -379,7 +395,7 @@ static void __put_system_dir(struct ftrace_subsystem_dir *dir)
 {
        WARN_ON_ONCE(dir->ref_count == 0);
        /* If the subsystem is about to be freed, the dir must be too */
-       WARN_ON_ONCE(dir->subsystem->ref_count == 1 && dir->ref_count != 1);
+       WARN_ON_ONCE(system_refcount(dir->subsystem) == 1 && dir->ref_count != 1);
 
        __put_system(dir->subsystem);
        if (!--dir->ref_count)
@@ -394,16 +410,45 @@ static void put_system(struct ftrace_subsystem_dir *dir)
 }
 
 /*
+ * Open and update trace_array ref count.
+ * Must have the current trace_array passed to it.
+ */
+static int tracing_open_generic_file(struct inode *inode, struct file *filp)
+{
+       struct ftrace_event_file *file = inode->i_private;
+       struct trace_array *tr = file->tr;
+       int ret;
+
+       if (trace_array_get(tr) < 0)
+               return -ENODEV;
+
+       ret = tracing_open_generic(inode, filp);
+       if (ret < 0)
+               trace_array_put(tr);
+       return ret;
+}
+
+static int tracing_release_generic_file(struct inode *inode, struct file *filp)
+{
+       struct ftrace_event_file *file = inode->i_private;
+       struct trace_array *tr = file->tr;
+
+       trace_array_put(tr);
+
+       return 0;
+}
+
+/*
  * __ftrace_set_clr_event(NULL, NULL, NULL, set) will set/unset all events.
  */
-static int __ftrace_set_clr_event(struct trace_array *tr, const char *match,
-                                 const char *sub, const char *event, int set)
+static int
+__ftrace_set_clr_event_nolock(struct trace_array *tr, const char *match,
+                             const char *sub, const char *event, int set)
 {
        struct ftrace_event_file *file;
        struct ftrace_event_call *call;
        int ret = -EINVAL;
 
-       mutex_lock(&event_mutex);
        list_for_each_entry(file, &tr->events, list) {
 
                call = file->event_call;
@@ -429,6 +474,17 @@ static int __ftrace_set_clr_event(struct trace_array *tr, const char *match,
 
                ret = 0;
        }
+
+       return ret;
+}
+
+static int __ftrace_set_clr_event(struct trace_array *tr, const char *match,
+                                 const char *sub, const char *event, int set)
+{
+       int ret;
+
+       mutex_lock(&event_mutex);
+       ret = __ftrace_set_clr_event_nolock(tr, match, sub, event, set);
        mutex_unlock(&event_mutex);
 
        return ret;
@@ -624,17 +680,17 @@ event_enable_read(struct file *filp, char __user *ubuf, size_t cnt,
                  loff_t *ppos)
 {
        struct ftrace_event_file *file = filp->private_data;
-       char *buf;
+       char buf[4] = "0";
 
-       if (file->flags & FTRACE_EVENT_FL_ENABLED) {
-               if (file->flags & FTRACE_EVENT_FL_SOFT_DISABLED)
-                       buf = "0*\n";
-               else if (file->flags & FTRACE_EVENT_FL_SOFT_MODE)
-                       buf = "1*\n";
-               else
-                       buf = "1\n";
-       } else
-               buf = "0\n";
+       if (file->flags & FTRACE_EVENT_FL_ENABLED &&
+           !(file->flags & FTRACE_EVENT_FL_SOFT_DISABLED))
+               strcpy(buf, "1");
+
+       if (file->flags & FTRACE_EVENT_FL_SOFT_DISABLED ||
+           file->flags & FTRACE_EVENT_FL_SOFT_MODE)
+               strcat(buf, "*");
+
+       strcat(buf, "\n");
 
        return simple_read_from_buffer(ubuf, cnt, ppos, buf, strlen(buf));
 }
@@ -992,6 +1048,7 @@ static int subsystem_open(struct inode *inode, struct file *filp)
        int ret;
 
        /* Make sure the system still exists */
+       mutex_lock(&trace_types_lock);
        mutex_lock(&event_mutex);
        list_for_each_entry(tr, &ftrace_trace_arrays, list) {
                list_for_each_entry(dir, &tr->systems, list) {
@@ -1007,6 +1064,7 @@ static int subsystem_open(struct inode *inode, struct file *filp)
        }
  exit_loop:
        mutex_unlock(&event_mutex);
+       mutex_unlock(&trace_types_lock);
 
        if (!system)
                return -ENODEV;
@@ -1014,9 +1072,17 @@ static int subsystem_open(struct inode *inode, struct file *filp)
        /* Some versions of gcc think dir can be uninitialized here */
        WARN_ON(!dir);
 
+       /* Still need to increment the ref count of the system */
+       if (trace_array_get(tr) < 0) {
+               put_system(dir);
+               return -ENODEV;
+       }
+
        ret = tracing_open_generic(inode, filp);
-       if (ret < 0)
+       if (ret < 0) {
+               trace_array_put(tr);
                put_system(dir);
+       }
 
        return ret;
 }
@@ -1027,16 +1093,23 @@ static int system_tr_open(struct inode *inode, struct file *filp)
        struct trace_array *tr = inode->i_private;
        int ret;
 
+       if (trace_array_get(tr) < 0)
+               return -ENODEV;
+
        /* Make a temporary dir that has no system but points to tr */
        dir = kzalloc(sizeof(*dir), GFP_KERNEL);
-       if (!dir)
+       if (!dir) {
+               trace_array_put(tr);
                return -ENOMEM;
+       }
 
        dir->tr = tr;
 
        ret = tracing_open_generic(inode, filp);
-       if (ret < 0)
+       if (ret < 0) {
+               trace_array_put(tr);
                kfree(dir);
+       }
 
        filp->private_data = dir;
 
@@ -1047,6 +1120,8 @@ static int subsystem_release(struct inode *inode, struct file *file)
 {
        struct ftrace_subsystem_dir *dir = file->private_data;
 
+       trace_array_put(dir->tr);
+
        /*
         * If dir->subsystem is NULL, then this is a temporary
         * descriptor that was made for a trace_array to enable
@@ -1174,9 +1249,10 @@ static const struct file_operations ftrace_set_event_fops = {
 };
 
 static const struct file_operations ftrace_enable_fops = {
-       .open = tracing_open_generic,
+       .open = tracing_open_generic_file,
        .read = event_enable_read,
        .write = event_enable_write,
+       .release = tracing_release_generic_file,
        .llseek = default_llseek,
 };
 
@@ -1279,7 +1355,15 @@ create_new_subsystem(const char *name)
                return NULL;
 
        system->ref_count = 1;
-       system->name = name;
+
+       /* Only allocate if dynamic (kprobes and modules) */
+       if (!core_kernel_data((unsigned long)name)) {
+               system->ref_count |= SYSTEM_FL_FREE_NAME;
+               system->name = kstrdup(name, GFP_KERNEL);
+               if (!system->name)
+                       goto out_free;
+       } else
+               system->name = name;
 
        system->filter = NULL;
 
@@ -1292,6 +1376,8 @@ create_new_subsystem(const char *name)
        return system;
 
  out_free:
+       if (system->ref_count & SYSTEM_FL_FREE_NAME)
+               kfree(system->name);
        kfree(system);
        return NULL;
 }
@@ -1591,6 +1677,7 @@ static void __add_event_to_tracers(struct ftrace_event_call *call,
 int trace_add_event_call(struct ftrace_event_call *call)
 {
        int ret;
+       mutex_lock(&trace_types_lock);
        mutex_lock(&event_mutex);
 
        ret = __register_event(call, NULL);
@@ -1598,11 +1685,13 @@ int trace_add_event_call(struct ftrace_event_call *call)
                __add_event_to_tracers(call, NULL);
 
        mutex_unlock(&event_mutex);
+       mutex_unlock(&trace_types_lock);
        return ret;
 }
 
 /*
- * Must be called under locking both of event_mutex and trace_event_sem.
+ * Must be called under locking of trace_types_lock, event_mutex and
+ * trace_event_sem.
  */
 static void __trace_remove_event_call(struct ftrace_event_call *call)
 {
@@ -1614,11 +1703,13 @@ static void __trace_remove_event_call(struct ftrace_event_call *call)
 /* Remove an event_call */
 void trace_remove_event_call(struct ftrace_event_call *call)
 {
+       mutex_lock(&trace_types_lock);
        mutex_lock(&event_mutex);
        down_write(&trace_event_sem);
        __trace_remove_event_call(call);
        up_write(&trace_event_sem);
        mutex_unlock(&event_mutex);
+       mutex_unlock(&trace_types_lock);
 }
 
 #define for_each_event(event, start, end)                      \
@@ -1762,6 +1853,7 @@ static int trace_module_notify(struct notifier_block *self,
 {
        struct module *mod = data;
 
+       mutex_lock(&trace_types_lock);
        mutex_lock(&event_mutex);
        switch (val) {
        case MODULE_STATE_COMING:
@@ -1772,6 +1864,7 @@ static int trace_module_notify(struct notifier_block *self,
                break;
        }
        mutex_unlock(&event_mutex);
+       mutex_unlock(&trace_types_lock);
 
        return 0;
 }
@@ -2011,10 +2104,7 @@ event_enable_func(struct ftrace_hash *hash,
        int ret;
 
        /* hash funcs only work with set_ftrace_filter */
-       if (!enabled)
-               return -EINVAL;
-
-       if (!param)
+       if (!enabled || !param)
                return -EINVAL;
 
        system = strsep(&param, ":");
@@ -2329,11 +2419,11 @@ early_event_add_tracer(struct dentry *parent, struct trace_array *tr)
 
 int event_trace_del_tracer(struct trace_array *tr)
 {
-       /* Disable any running events */
-       __ftrace_set_clr_event(tr, NULL, NULL, NULL, 0);
-
        mutex_lock(&event_mutex);
 
+       /* Disable any running events */
+       __ftrace_set_clr_event_nolock(tr, NULL, NULL, NULL, 0);
+
        down_write(&trace_event_sem);
        __trace_remove_event_dirs(tr);
        debugfs_remove_recursive(tr->event_dir);
index e1b653f..0d883dc 100644 (file)
@@ -44,6 +44,7 @@ enum filter_op_ids
        OP_LE,
        OP_GT,
        OP_GE,
+       OP_BAND,
        OP_NONE,
        OP_OPEN_PAREN,
 };
@@ -54,6 +55,7 @@ struct filter_op {
        int precedence;
 };
 
+/* Order must be the same as enum filter_op_ids above */
 static struct filter_op filter_ops[] = {
        { OP_OR,        "||",           1 },
        { OP_AND,       "&&",           2 },
@@ -64,6 +66,7 @@ static struct filter_op filter_ops[] = {
        { OP_LE,        "<=",           5 },
        { OP_GT,        ">",            5 },
        { OP_GE,        ">=",           5 },
+       { OP_BAND,      "&",            6 },
        { OP_NONE,      "OP_NONE",      0 },
        { OP_OPEN_PAREN, "(",           0 },
 };
@@ -156,6 +159,9 @@ static int filter_pred_##type(struct filter_pred *pred, void *event)        \
        case OP_GE:                                                     \
                match = (*addr >= val);                                 \
                break;                                                  \
+       case OP_BAND:                                                   \
+               match = (*addr & val);                                  \
+               break;                                                  \
        default:                                                        \
                break;                                                  \
        }                                                               \
index c4d6d71..b863f93 100644 (file)
@@ -290,6 +290,21 @@ ftrace_stacktrace_count(unsigned long ip, unsigned long parent_ip, void **data)
                trace_dump_stack(STACK_SKIP);
 }
 
+static void
+ftrace_dump_probe(unsigned long ip, unsigned long parent_ip, void **data)
+{
+       if (update_count(data))
+               ftrace_dump(DUMP_ALL);
+}
+
+/* Only dump the current CPU buffer. */
+static void
+ftrace_cpudump_probe(unsigned long ip, unsigned long parent_ip, void **data)
+{
+       if (update_count(data))
+               ftrace_dump(DUMP_ORIG);
+}
+
 static int
 ftrace_probe_print(const char *name, struct seq_file *m,
                   unsigned long ip, void *data)
@@ -327,6 +342,20 @@ ftrace_stacktrace_print(struct seq_file *m, unsigned long ip,
        return ftrace_probe_print("stacktrace", m, ip, data);
 }
 
+static int
+ftrace_dump_print(struct seq_file *m, unsigned long ip,
+                       struct ftrace_probe_ops *ops, void *data)
+{
+       return ftrace_probe_print("dump", m, ip, data);
+}
+
+static int
+ftrace_cpudump_print(struct seq_file *m, unsigned long ip,
+                       struct ftrace_probe_ops *ops, void *data)
+{
+       return ftrace_probe_print("cpudump", m, ip, data);
+}
+
 static struct ftrace_probe_ops traceon_count_probe_ops = {
        .func                   = ftrace_traceon_count,
        .print                  = ftrace_traceon_print,
@@ -342,6 +371,16 @@ static struct ftrace_probe_ops stacktrace_count_probe_ops = {
        .print                  = ftrace_stacktrace_print,
 };
 
+static struct ftrace_probe_ops dump_probe_ops = {
+       .func                   = ftrace_dump_probe,
+       .print                  = ftrace_dump_print,
+};
+
+static struct ftrace_probe_ops cpudump_probe_ops = {
+       .func                   = ftrace_cpudump_probe,
+       .print                  = ftrace_cpudump_print,
+};
+
 static struct ftrace_probe_ops traceon_probe_ops = {
        .func                   = ftrace_traceon,
        .print                  = ftrace_traceon_print,
@@ -425,6 +464,32 @@ ftrace_stacktrace_callback(struct ftrace_hash *hash,
                                           param, enable);
 }
 
+static int
+ftrace_dump_callback(struct ftrace_hash *hash,
+                          char *glob, char *cmd, char *param, int enable)
+{
+       struct ftrace_probe_ops *ops;
+
+       ops = &dump_probe_ops;
+
+       /* Only dump once. */
+       return ftrace_trace_probe_callback(ops, hash, glob, cmd,
+                                          "1", enable);
+}
+
+static int
+ftrace_cpudump_callback(struct ftrace_hash *hash,
+                          char *glob, char *cmd, char *param, int enable)
+{
+       struct ftrace_probe_ops *ops;
+
+       ops = &cpudump_probe_ops;
+
+       /* Only dump once. */
+       return ftrace_trace_probe_callback(ops, hash, glob, cmd,
+                                          "1", enable);
+}
+
 static struct ftrace_func_command ftrace_traceon_cmd = {
        .name                   = "traceon",
        .func                   = ftrace_trace_onoff_callback,
@@ -440,6 +505,16 @@ static struct ftrace_func_command ftrace_stacktrace_cmd = {
        .func                   = ftrace_stacktrace_callback,
 };
 
+static struct ftrace_func_command ftrace_dump_cmd = {
+       .name                   = "dump",
+       .func                   = ftrace_dump_callback,
+};
+
+static struct ftrace_func_command ftrace_cpudump_cmd = {
+       .name                   = "cpudump",
+       .func                   = ftrace_cpudump_callback,
+};
+
 static int __init init_func_cmd_traceon(void)
 {
        int ret;
@@ -450,13 +525,31 @@ static int __init init_func_cmd_traceon(void)
 
        ret = register_ftrace_command(&ftrace_traceon_cmd);
        if (ret)
-               unregister_ftrace_command(&ftrace_traceoff_cmd);
+               goto out_free_traceoff;
 
        ret = register_ftrace_command(&ftrace_stacktrace_cmd);
-       if (ret) {
-               unregister_ftrace_command(&ftrace_traceoff_cmd);
-               unregister_ftrace_command(&ftrace_traceon_cmd);
-       }
+       if (ret)
+               goto out_free_traceon;
+
+       ret = register_ftrace_command(&ftrace_dump_cmd);
+       if (ret)
+               goto out_free_stacktrace;
+
+       ret = register_ftrace_command(&ftrace_cpudump_cmd);
+       if (ret)
+               goto out_free_dump;
+
+       return 0;
+
+ out_free_dump:
+       unregister_ftrace_command(&ftrace_dump_cmd);
+ out_free_stacktrace:
+       unregister_ftrace_command(&ftrace_stacktrace_cmd);
+ out_free_traceon:
+       unregister_ftrace_command(&ftrace_traceon_cmd);
+ out_free_traceoff:
+       unregister_ftrace_command(&ftrace_traceoff_cmd);
+
        return ret;
 }
 #else
index b19d065..2aefbee 100644 (file)
@@ -373,7 +373,7 @@ start_critical_timing(unsigned long ip, unsigned long parent_ip)
        struct trace_array_cpu *data;
        unsigned long flags;
 
-       if (likely(!tracer_enabled))
+       if (!tracer_enabled || !tracing_is_enabled())
                return;
 
        cpu = raw_smp_processor_id();
@@ -416,7 +416,7 @@ stop_critical_timing(unsigned long ip, unsigned long parent_ip)
        else
                return;
 
-       if (!tracer_enabled)
+       if (!tracer_enabled || !tracing_is_enabled())
                return;
 
        data = per_cpu_ptr(tr->trace_buffer.data, cpu);
index 9f46e98..7ed6976 100644 (file)
@@ -35,12 +35,17 @@ struct trace_probe {
        const char              *symbol;        /* symbol name */
        struct ftrace_event_class       class;
        struct ftrace_event_call        call;
-       struct ftrace_event_file * __rcu *files;
+       struct list_head        files;
        ssize_t                 size;           /* trace entry size */
        unsigned int            nr_args;
        struct probe_arg        args[];
 };
 
+struct event_file_link {
+       struct ftrace_event_file        *file;
+       struct list_head                list;
+};
+
 #define SIZEOF_TRACE_PROBE(n)                  \
        (offsetof(struct trace_probe, args) +   \
        (sizeof(struct probe_arg) * (n)))
@@ -150,6 +155,7 @@ static struct trace_probe *alloc_trace_probe(const char *group,
                goto error;
 
        INIT_LIST_HEAD(&tp->list);
+       INIT_LIST_HEAD(&tp->files);
        return tp;
 error:
        kfree(tp->call.name);
@@ -183,25 +189,6 @@ static struct trace_probe *find_trace_probe(const char *event,
        return NULL;
 }
 
-static int trace_probe_nr_files(struct trace_probe *tp)
-{
-       struct ftrace_event_file **file;
-       int ret = 0;
-
-       /*
-        * Since all tp->files updater is protected by probe_enable_lock,
-        * we don't need to lock an rcu_read_lock.
-        */
-       file = rcu_dereference_raw(tp->files);
-       if (file)
-               while (*(file++))
-                       ret++;
-
-       return ret;
-}
-
-static DEFINE_MUTEX(probe_enable_lock);
-
 /*
  * Enable trace_probe
  * if the file is NULL, enable "perf" handler, or enable "trace" handler.
@@ -211,67 +198,42 @@ enable_trace_probe(struct trace_probe *tp, struct ftrace_event_file *file)
 {
        int ret = 0;
 
-       mutex_lock(&probe_enable_lock);
-
        if (file) {
-               struct ftrace_event_file **new, **old;
-               int n = trace_probe_nr_files(tp);
-
-               old = rcu_dereference_raw(tp->files);
-               /* 1 is for new one and 1 is for stopper */
-               new = kzalloc((n + 2) * sizeof(struct ftrace_event_file *),
-                             GFP_KERNEL);
-               if (!new) {
+               struct event_file_link *link;
+
+               link = kmalloc(sizeof(*link), GFP_KERNEL);
+               if (!link) {
                        ret = -ENOMEM;
-                       goto out_unlock;
+                       goto out;
                }
-               memcpy(new, old, n * sizeof(struct ftrace_event_file *));
-               new[n] = file;
-               /* The last one keeps a NULL */
 
-               rcu_assign_pointer(tp->files, new);
-               tp->flags |= TP_FLAG_TRACE;
+               link->file = file;
+               list_add_tail_rcu(&link->list, &tp->files);
 
-               if (old) {
-                       /* Make sure the probe is done with old files */
-                       synchronize_sched();
-                       kfree(old);
-               }
+               tp->flags |= TP_FLAG_TRACE;
        } else
                tp->flags |= TP_FLAG_PROFILE;
 
-       if (trace_probe_is_enabled(tp) && trace_probe_is_registered(tp) &&
-           !trace_probe_has_gone(tp)) {
+       if (trace_probe_is_registered(tp) && !trace_probe_has_gone(tp)) {
                if (trace_probe_is_return(tp))
                        ret = enable_kretprobe(&tp->rp);
                else
                        ret = enable_kprobe(&tp->rp.kp);
        }
-
- out_unlock:
-       mutex_unlock(&probe_enable_lock);
-
+ out:
        return ret;
 }
 
-static int
-trace_probe_file_index(struct trace_probe *tp, struct ftrace_event_file *file)
+static struct event_file_link *
+find_event_file_link(struct trace_probe *tp, struct ftrace_event_file *file)
 {
-       struct ftrace_event_file **files;
-       int i;
+       struct event_file_link *link;
 
-       /*
-        * Since all tp->files updater is protected by probe_enable_lock,
-        * we don't need to lock an rcu_read_lock.
-        */
-       files = rcu_dereference_raw(tp->files);
-       if (files) {
-               for (i = 0; files[i]; i++)
-                       if (files[i] == file)
-                               return i;
-       }
+       list_for_each_entry(link, &tp->files, list)
+               if (link->file == file)
+                       return link;
 
-       return -1;
+       return NULL;
 }
 
 /*
@@ -283,41 +245,24 @@ disable_trace_probe(struct trace_probe *tp, struct ftrace_event_file *file)
 {
        int ret = 0;
 
-       mutex_lock(&probe_enable_lock);
-
        if (file) {
-               struct ftrace_event_file **new, **old;
-               int n = trace_probe_nr_files(tp);
-               int i, j;
+               struct event_file_link *link;
 
-               old = rcu_dereference_raw(tp->files);
-               if (n == 0 || trace_probe_file_index(tp, file) < 0) {
+               link = find_event_file_link(tp, file);
+               if (!link) {
                        ret = -EINVAL;
-                       goto out_unlock;
+                       goto out;
                }
 
-               if (n == 1) {   /* Remove the last file */
-                       tp->flags &= ~TP_FLAG_TRACE;
-                       new = NULL;
-               } else {
-                       new = kzalloc(n * sizeof(struct ftrace_event_file *),
-                                     GFP_KERNEL);
-                       if (!new) {
-                               ret = -ENOMEM;
-                               goto out_unlock;
-                       }
-
-                       /* This copy & check loop copies the NULL stopper too */
-                       for (i = 0, j = 0; j < n && i < n + 1; i++)
-                               if (old[i] != file)
-                                       new[j++] = old[i];
-               }
+               list_del_rcu(&link->list);
+               /* synchronize with kprobe_trace_func/kretprobe_trace_func */
+               synchronize_sched();
+               kfree(link);
 
-               rcu_assign_pointer(tp->files, new);
+               if (!list_empty(&tp->files))
+                       goto out;
 
-               /* Make sure the probe is done with old files */
-               synchronize_sched();
-               kfree(old);
+               tp->flags &= ~TP_FLAG_TRACE;
        } else
                tp->flags &= ~TP_FLAG_PROFILE;
 
@@ -327,10 +272,7 @@ disable_trace_probe(struct trace_probe *tp, struct ftrace_event_file *file)
                else
                        disable_kprobe(&tp->rp.kp);
        }
-
- out_unlock:
-       mutex_unlock(&probe_enable_lock);
-
+ out:
        return ret;
 }
 
@@ -885,20 +827,10 @@ __kprobe_trace_func(struct trace_probe *tp, struct pt_regs *regs,
 static __kprobes void
 kprobe_trace_func(struct trace_probe *tp, struct pt_regs *regs)
 {
-       /*
-        * Note: preempt is already disabled around the kprobe handler.
-        * However, we still need an smp_read_barrier_depends() corresponding
-        * to smp_wmb() in rcu_assign_pointer() to access the pointer.
-        */
-       struct ftrace_event_file **file = rcu_dereference_raw(tp->files);
-
-       if (unlikely(!file))
-               return;
+       struct event_file_link *link;
 
-       while (*file) {
-               __kprobe_trace_func(tp, regs, *file);
-               file++;
-       }
+       list_for_each_entry_rcu(link, &tp->files, list)
+               __kprobe_trace_func(tp, regs, link->file);
 }
 
 /* Kretprobe handler */
@@ -945,20 +877,10 @@ static __kprobes void
 kretprobe_trace_func(struct trace_probe *tp, struct kretprobe_instance *ri,
                     struct pt_regs *regs)
 {
-       /*
-        * Note: preempt is already disabled around the kprobe handler.
-        * However, we still need an smp_read_barrier_depends() corresponding
-        * to smp_wmb() in rcu_assign_pointer() to access the pointer.
-        */
-       struct ftrace_event_file **file = rcu_dereference_raw(tp->files);
+       struct event_file_link *link;
 
-       if (unlikely(!file))
-               return;
-
-       while (*file) {
-               __kretprobe_trace_func(tp, ri, regs, *file);
-               file++;
-       }
+       list_for_each_entry_rcu(link, &tp->files, list)
+               __kretprobe_trace_func(tp, ri, regs, link->file);
 }
 
 /* Event entry printers */
@@ -1157,6 +1079,10 @@ kprobe_perf_func(struct trace_probe *tp, struct pt_regs *regs)
        int size, __size, dsize;
        int rctx;
 
+       head = this_cpu_ptr(call->perf_events);
+       if (hlist_empty(head))
+               return;
+
        dsize = __get_data_size(tp, regs);
        __size = sizeof(*entry) + tp->size + dsize;
        size = ALIGN(__size + sizeof(u32), sizeof(u64));
@@ -1172,10 +1098,7 @@ kprobe_perf_func(struct trace_probe *tp, struct pt_regs *regs)
        entry->ip = (unsigned long)tp->rp.kp.addr;
        memset(&entry[1], 0, dsize);
        store_trace_args(sizeof(*entry), tp, regs, (u8 *)&entry[1], dsize);
-
-       head = this_cpu_ptr(call->perf_events);
-       perf_trace_buf_submit(entry, size, rctx,
-                                       entry->ip, 1, regs, head, NULL);
+       perf_trace_buf_submit(entry, size, rctx, 0, 1, regs, head, NULL);
 }
 
 /* Kretprobe profile handler */
@@ -1189,6 +1112,10 @@ kretprobe_perf_func(struct trace_probe *tp, struct kretprobe_instance *ri,
        int size, __size, dsize;
        int rctx;
 
+       head = this_cpu_ptr(call->perf_events);
+       if (hlist_empty(head))
+               return;
+
        dsize = __get_data_size(tp, regs);
        __size = sizeof(*entry) + tp->size + dsize;
        size = ALIGN(__size + sizeof(u32), sizeof(u64));
@@ -1204,13 +1131,16 @@ kretprobe_perf_func(struct trace_probe *tp, struct kretprobe_instance *ri,
        entry->func = (unsigned long)tp->rp.kp.addr;
        entry->ret_ip = (unsigned long)ri->ret_addr;
        store_trace_args(sizeof(*entry), tp, regs, (u8 *)&entry[1], dsize);
-
-       head = this_cpu_ptr(call->perf_events);
-       perf_trace_buf_submit(entry, size, rctx,
-                                       entry->ret_ip, 1, regs, head, NULL);
+       perf_trace_buf_submit(entry, size, rctx, 0, 1, regs, head, NULL);
 }
 #endif /* CONFIG_PERF_EVENTS */
 
+/*
+ * called by perf_trace_init() or __ftrace_set_clr_event() under event_mutex.
+ *
+ * kprobe_trace_self_tests_init() does enable_trace_probe/disable_trace_probe
+ * lockless, but we can't race with this __init function.
+ */
 static __kprobes
 int kprobe_register(struct ftrace_event_call *event,
                    enum trace_reg type, void *data)
@@ -1376,6 +1306,10 @@ find_trace_probe_file(struct trace_probe *tp, struct trace_array *tr)
        return NULL;
 }
 
+/*
+ * Nobody but us can call enable_trace_probe/disable_trace_probe at this
+ * stage, we can do this lockless.
+ */
 static __init int kprobe_trace_self_tests_init(void)
 {
        int ret, warn = 0;
index 2901e3b..a7329b7 100644 (file)
@@ -640,13 +640,20 @@ out:
  * Enable ftrace, sleep 1/10 second, and then read the trace
  * buffer to see if all is in order.
  */
-int
+__init int
 trace_selftest_startup_function(struct tracer *trace, struct trace_array *tr)
 {
        int save_ftrace_enabled = ftrace_enabled;
        unsigned long count;
        int ret;
 
+#ifdef CONFIG_DYNAMIC_FTRACE
+       if (ftrace_filter_param) {
+               printk(KERN_CONT " ... kernel command line filter set: force PASS ... ");
+               return 0;
+       }
+#endif
+
        /* make sure msleep has been recorded */
        msleep(1);
 
@@ -727,13 +734,20 @@ static int trace_graph_entry_watchdog(struct ftrace_graph_ent *trace)
  * Pretty much the same than for the function tracer from which the selftest
  * has been borrowed.
  */
-int
+__init int
 trace_selftest_startup_function_graph(struct tracer *trace,
                                        struct trace_array *tr)
 {
        int ret;
        unsigned long count;
 
+#ifdef CONFIG_DYNAMIC_FTRACE
+       if (ftrace_filter_param) {
+               printk(KERN_CONT " ... kernel command line filter set: force PASS ... ");
+               return 0;
+       }
+#endif
+
        /*
         * Simulate the init() callback but we attach a watchdog callback
         * to detect and recover from possible hangs
index 8f2ac73..322e164 100644 (file)
@@ -306,6 +306,8 @@ static void ftrace_syscall_enter(void *data, struct pt_regs *regs, long id)
        struct syscall_metadata *sys_data;
        struct ring_buffer_event *event;
        struct ring_buffer *buffer;
+       unsigned long irq_flags;
+       int pc;
        int syscall_nr;
        int size;
 
@@ -321,9 +323,12 @@ static void ftrace_syscall_enter(void *data, struct pt_regs *regs, long id)
 
        size = sizeof(*entry) + sizeof(unsigned long) * sys_data->nb_args;
 
+       local_save_flags(irq_flags);
+       pc = preempt_count();
+
        buffer = tr->trace_buffer.buffer;
        event = trace_buffer_lock_reserve(buffer,
-                       sys_data->enter_event->event.type, size, 0, 0);
+                       sys_data->enter_event->event.type, size, irq_flags, pc);
        if (!event)
                return;
 
@@ -333,7 +338,8 @@ static void ftrace_syscall_enter(void *data, struct pt_regs *regs, long id)
 
        if (!filter_current_check_discard(buffer, sys_data->enter_event,
                                          entry, event))
-               trace_current_buffer_unlock_commit(buffer, event, 0, 0);
+               trace_current_buffer_unlock_commit(buffer, event,
+                                                  irq_flags, pc);
 }
 
 static void ftrace_syscall_exit(void *data, struct pt_regs *regs, long ret)
@@ -343,6 +349,8 @@ static void ftrace_syscall_exit(void *data, struct pt_regs *regs, long ret)
        struct syscall_metadata *sys_data;
        struct ring_buffer_event *event;
        struct ring_buffer *buffer;
+       unsigned long irq_flags;
+       int pc;
        int syscall_nr;
 
        syscall_nr = trace_get_syscall_nr(current, regs);
@@ -355,9 +363,13 @@ static void ftrace_syscall_exit(void *data, struct pt_regs *regs, long ret)
        if (!sys_data)
                return;
 
+       local_save_flags(irq_flags);
+       pc = preempt_count();
+
        buffer = tr->trace_buffer.buffer;
        event = trace_buffer_lock_reserve(buffer,
-                       sys_data->exit_event->event.type, sizeof(*entry), 0, 0);
+                       sys_data->exit_event->event.type, sizeof(*entry),
+                       irq_flags, pc);
        if (!event)
                return;
 
@@ -367,7 +379,8 @@ static void ftrace_syscall_exit(void *data, struct pt_regs *regs, long ret)
 
        if (!filter_current_check_discard(buffer, sys_data->exit_event,
                                          entry, event))
-               trace_current_buffer_unlock_commit(buffer, event, 0, 0);
+               trace_current_buffer_unlock_commit(buffer, event,
+                                                  irq_flags, pc);
 }
 
 static int reg_event_syscall_enter(struct ftrace_event_file *file,
index 32494fb..d5d0cd3 100644 (file)
@@ -283,8 +283,10 @@ static int create_trace_uprobe(int argc, char **argv)
                return -EINVAL;
        }
        arg = strchr(argv[1], ':');
-       if (!arg)
+       if (!arg) {
+               ret = -EINVAL;
                goto fail_address_parse;
+       }
 
        *arg++ = '\0';
        filename = argv[1];
index 05039e3..1241d8c 100644 (file)
@@ -29,9 +29,9 @@
 #include <linux/kvm_para.h>
 #include <linux/perf_event.h>
 
-int watchdog_enabled = 1;
+int watchdog_user_enabled = 1;
 int __read_mostly watchdog_thresh = 10;
-static int __read_mostly watchdog_disabled;
+static int __read_mostly watchdog_running;
 static u64 __read_mostly sample_period;
 
 static DEFINE_PER_CPU(unsigned long, watchdog_touch_ts);
@@ -63,7 +63,7 @@ static int __init hardlockup_panic_setup(char *str)
        else if (!strncmp(str, "nopanic", 7))
                hardlockup_panic = 0;
        else if (!strncmp(str, "0", 1))
-               watchdog_enabled = 0;
+               watchdog_user_enabled = 0;
        return 1;
 }
 __setup("nmi_watchdog=", hardlockup_panic_setup);
@@ -82,7 +82,7 @@ __setup("softlockup_panic=", softlockup_panic_setup);
 
 static int __init nowatchdog_setup(char *str)
 {
-       watchdog_enabled = 0;
+       watchdog_user_enabled = 0;
        return 1;
 }
 __setup("nowatchdog", nowatchdog_setup);
@@ -90,7 +90,7 @@ __setup("nowatchdog", nowatchdog_setup);
 /* deprecated */
 static int __init nosoftlockup_setup(char *str)
 {
-       watchdog_enabled = 0;
+       watchdog_user_enabled = 0;
        return 1;
 }
 __setup("nosoftlockup", nosoftlockup_setup);
@@ -158,7 +158,7 @@ void touch_all_softlockup_watchdogs(void)
 #ifdef CONFIG_HARDLOCKUP_DETECTOR
 void touch_nmi_watchdog(void)
 {
-       if (watchdog_enabled) {
+       if (watchdog_user_enabled) {
                unsigned cpu;
 
                for_each_present_cpu(cpu) {
@@ -347,11 +347,6 @@ static void watchdog_enable(unsigned int cpu)
        hrtimer_init(hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
        hrtimer->function = watchdog_timer_fn;
 
-       if (!watchdog_enabled) {
-               kthread_park(current);
-               return;
-       }
-
        /* Enable the perf event */
        watchdog_nmi_enable(cpu);
 
@@ -374,6 +369,11 @@ static void watchdog_disable(unsigned int cpu)
        watchdog_nmi_disable(cpu);
 }
 
+static void watchdog_cleanup(unsigned int cpu, bool online)
+{
+       watchdog_disable(cpu);
+}
+
 static int watchdog_should_run(unsigned int cpu)
 {
        return __this_cpu_read(hrtimer_interrupts) !=
@@ -475,28 +475,40 @@ static int watchdog_nmi_enable(unsigned int cpu) { return 0; }
 static void watchdog_nmi_disable(unsigned int cpu) { return; }
 #endif /* CONFIG_HARDLOCKUP_DETECTOR */
 
-/* prepare/enable/disable routines */
-/* sysctl functions */
-#ifdef CONFIG_SYSCTL
-static void watchdog_enable_all_cpus(void)
+static struct smp_hotplug_thread watchdog_threads = {
+       .store                  = &softlockup_watchdog,
+       .thread_should_run      = watchdog_should_run,
+       .thread_fn              = watchdog,
+       .thread_comm            = "watchdog/%u",
+       .setup                  = watchdog_enable,
+       .cleanup                = watchdog_cleanup,
+       .park                   = watchdog_disable,
+       .unpark                 = watchdog_enable,
+};
+
+static int watchdog_enable_all_cpus(void)
 {
-       unsigned int cpu;
+       int err = 0;
 
-       if (watchdog_disabled) {
-               watchdog_disabled = 0;
-               for_each_online_cpu(cpu)
-                       kthread_unpark(per_cpu(softlockup_watchdog, cpu));
+       if (!watchdog_running) {
+               err = smpboot_register_percpu_thread(&watchdog_threads);
+               if (err)
+                       pr_err("Failed to create watchdog threads, disabled\n");
+               else
+                       watchdog_running = 1;
        }
+
+       return err;
 }
 
+/* prepare/enable/disable routines */
+/* sysctl functions */
+#ifdef CONFIG_SYSCTL
 static void watchdog_disable_all_cpus(void)
 {
-       unsigned int cpu;
-
-       if (!watchdog_disabled) {
-               watchdog_disabled = 1;
-               for_each_online_cpu(cpu)
-                       kthread_park(per_cpu(softlockup_watchdog, cpu));
+       if (watchdog_running) {
+               watchdog_running = 0;
+               smpboot_unregister_percpu_thread(&watchdog_threads);
        }
 }
 
@@ -507,45 +519,48 @@ static void watchdog_disable_all_cpus(void)
 int proc_dowatchdog(struct ctl_table *table, int write,
                    void __user *buffer, size_t *lenp, loff_t *ppos)
 {
-       int ret;
+       int err, old_thresh, old_enabled;
 
-       if (watchdog_disabled < 0)
-               return -ENODEV;
+       old_thresh = ACCESS_ONCE(watchdog_thresh);
+       old_enabled = ACCESS_ONCE(watchdog_user_enabled);
 
-       ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos);
-       if (ret || !write)
-               return ret;
+       err = proc_dointvec_minmax(table, write, buffer, lenp, ppos);
+       if (err || !write)
+               return err;
 
        set_sample_period();
        /*
         * Watchdog threads shouldn't be enabled if they are
-        * disabled. The 'watchdog_disabled' variable check in
+        * disabled. The 'watchdog_running' variable check in
         * watchdog_*_all_cpus() function takes care of this.
         */
-       if (watchdog_enabled && watchdog_thresh)
-               watchdog_enable_all_cpus();
+       if (watchdog_user_enabled && watchdog_thresh)
+               err = watchdog_enable_all_cpus();
        else
                watchdog_disable_all_cpus();
 
-       return ret;
+       /* Restore old values on failure */
+       if (err) {
+               watchdog_thresh = old_thresh;
+               watchdog_user_enabled = old_enabled;
+       }
+
+       return err;
 }
 #endif /* CONFIG_SYSCTL */
 
-static struct smp_hotplug_thread watchdog_threads = {
-       .store                  = &softlockup_watchdog,
-       .thread_should_run      = watchdog_should_run,
-       .thread_fn              = watchdog,
-       .thread_comm            = "watchdog/%u",
-       .setup                  = watchdog_enable,
-       .park                   = watchdog_disable,
-       .unpark                 = watchdog_enable,
-};
-
 void __init lockup_detector_init(void)
 {
        set_sample_period();
-       if (smpboot_register_percpu_thread(&watchdog_threads)) {
-               pr_err("Failed to create watchdog threads, disabled\n");
-               watchdog_disabled = -ENODEV;
+
+#ifdef CONFIG_NO_HZ_FULL
+       if (watchdog_user_enabled) {
+               watchdog_user_enabled = 0;
+               pr_warning("Disabled lockup detectors by default for full dynticks\n");
+               pr_warning("You can reactivate it with 'sysctl -w kernel.watchdog=1'\n");
        }
+#endif
+
+       if (watchdog_user_enabled)
+               watchdog_enable_all_cpus();
 }
index 88c8d98..98ac17e 100644 (file)
@@ -1347,7 +1347,7 @@ config FAULT_INJECTION_STACKTRACE_FILTER
        depends on FAULT_INJECTION_DEBUG_FS && STACKTRACE_SUPPORT
        depends on !X86_64
        select STACKTRACE
-       select FRAME_POINTER if !PPC && !S390 && !MICROBLAZE && !ARM_UNWIND
+       select FRAME_POINTER if !MIPS && !PPC && !S390 && !MICROBLAZE && !ARM_UNWIND
        help
          Provide stacktrace filter for fault-injection capabilities
 
index 4a15115..4a70d12 100644 (file)
 bool llist_add_batch(struct llist_node *new_first, struct llist_node *new_last,
                     struct llist_head *head)
 {
-       struct llist_node *entry, *old_entry;
+       struct llist_node *first;
 
-       entry = head->first;
-       for (;;) {
-               old_entry = entry;
-               new_last->next = entry;
-               entry = cmpxchg(&head->first, old_entry, new_first);
-               if (entry == old_entry)
-                       break;
-       }
+       do {
+               new_last->next = first = ACCESS_ONCE(head->first);
+       } while (cmpxchg(&head->first, first, new_first) != first);
 
-       return old_entry == NULL;
+       return !first;
 }
 EXPORT_SYMBOL_GPL(llist_add_batch);
 
index aad024d..6dc09d8 100644 (file)
@@ -12,6 +12,7 @@
  */
 #include <linux/rwsem.h>
 #include <linux/mutex.h>
+#include <linux/ww_mutex.h>
 #include <linux/sched.h>
 #include <linux/delay.h>
 #include <linux/lockdep.h>
index 7e28ecf..8028dcc 100644 (file)
@@ -478,6 +478,36 @@ config FRONTSWAP
 
          If unsure, say Y to enable frontswap.
 
+config ZBUD
+       tristate
+       default n
+       help
+         A special purpose allocator for storing compressed pages.
+         It is designed to store up to two compressed pages per physical
+         page.  While this design limits storage density, it has simple and
+         deterministic reclaim properties that make it preferable to a higher
+         density approach when reclaim will be used.
+
+config ZSWAP
+       bool "Compressed cache for swap pages (EXPERIMENTAL)"
+       depends on FRONTSWAP && CRYPTO=y
+       select CRYPTO_LZO
+       select ZBUD
+       default n
+       help
+         A lightweight compressed cache for swap pages.  It takes
+         pages that are in the process of being swapped out and attempts to
+         compress them into a dynamically allocated RAM-based memory pool.
+         This can result in a significant I/O reduction on swap device and,
+         in the case where decompressing from RAM is faster that swap device
+         reads, can also improve workload performance.
+
+         This is marked experimental because it is a new feature (as of
+         v3.11) that interacts heavily with memory reclaim.  While these
+         interactions don't cause any known issues on simple memory setups,
+         they have not be fully explored on the large set of potential
+         configurations and workloads that exist.
+
 config MEM_SOFT_DIRTY
        bool "Track memory changes"
        depends on CHECKPOINT_RESTORE && HAVE_ARCH_SOFT_DIRTY
index 72c5acb..f008033 100644 (file)
@@ -32,6 +32,7 @@ obj-$(CONFIG_HAVE_MEMBLOCK) += memblock.o
 obj-$(CONFIG_BOUNCE)   += bounce.o
 obj-$(CONFIG_SWAP)     += page_io.o swap_state.o swapfile.o
 obj-$(CONFIG_FRONTSWAP)        += frontswap.o
+obj-$(CONFIG_ZSWAP)    += zswap.o
 obj-$(CONFIG_HAS_DMA)  += dmapool.o
 obj-$(CONFIG_HUGETLBFS)        += hugetlb.o
 obj-$(CONFIG_NUMA)     += mempolicy.o
@@ -58,3 +59,4 @@ obj-$(CONFIG_DEBUG_KMEMLEAK) += kmemleak.o
 obj-$(CONFIG_DEBUG_KMEMLEAK_TEST) += kmemleak-test.o
 obj-$(CONFIG_CLEANCACHE) += cleancache.o
 obj-$(CONFIG_MEMORY_ISOLATION) += page_isolation.o
+obj-$(CONFIG_ZBUD)     += zbud.o
index f813111..fbad7b0 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -1878,15 +1878,6 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr,
 }
 #endif 
 
-void arch_unmap_area(struct mm_struct *mm, unsigned long addr)
-{
-       /*
-        * Is this a new hole at the lowest possible address?
-        */
-       if (addr >= TASK_UNMAPPED_BASE && addr < mm->free_area_cache)
-               mm->free_area_cache = addr;
-}
-
 /*
  * This mmap-allocator allocates new areas top-down from below the
  * stack's low limit (the base):
@@ -1943,19 +1934,6 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0,
 }
 #endif
 
-void arch_unmap_area_topdown(struct mm_struct *mm, unsigned long addr)
-{
-       /*
-        * Is this a new hole at the highest possible address?
-        */
-       if (addr > mm->free_area_cache)
-               mm->free_area_cache = addr;
-
-       /* dont allow allocations above current base */
-       if (mm->free_area_cache > mm->mmap_base)
-               mm->free_area_cache = mm->mmap_base;
-}
-
 unsigned long
 get_unmapped_area(struct file *file, unsigned long addr, unsigned long len,
                unsigned long pgoff, unsigned long flags)
@@ -2376,7 +2354,6 @@ detach_vmas_to_be_unmapped(struct mm_struct *mm, struct vm_area_struct *vma,
 {
        struct vm_area_struct **insertion_point;
        struct vm_area_struct *tail_vma = NULL;
-       unsigned long addr;
 
        insertion_point = (prev ? &prev->vm_next : &mm->mmap);
        vma->vm_prev = NULL;
@@ -2393,11 +2370,6 @@ detach_vmas_to_be_unmapped(struct mm_struct *mm, struct vm_area_struct *vma,
        } else
                mm->highest_vm_end = prev ? prev->vm_end : 0;
        tail_vma->vm_next = NULL;
-       if (mm->unmap_area == arch_unmap_area)
-               addr = prev ? prev->vm_end : mm->mmap_base;
-       else
-               addr = vma ?  vma->vm_start : mm->mmap_base;
-       mm->unmap_area(mm, addr);
        mm->mmap_cache = NULL;          /* Kill the cache. */
 }
 
index e44e6e0..ecd1f15 100644 (file)
@@ -1871,10 +1871,6 @@ unsigned long arch_get_unmapped_area(struct file *file, unsigned long addr,
        return -ENOMEM;
 }
 
-void arch_unmap_area(struct mm_struct *mm, unsigned long addr)
-{
-}
-
 void unmap_mapping_range(struct address_space *mapping,
                         loff_t const holebegin, loff_t const holelen,
                         int even_cows)
index 8ccd296..35cb0c8 100644 (file)
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -565,7 +565,7 @@ static void init_node_lock_keys(int q)
        if (slab_state < UP)
                return;
 
-       for (i = 1; i < PAGE_SHIFT + MAX_ORDER; i++) {
+       for (i = 1; i <= KMALLOC_SHIFT_HIGH; i++) {
                struct kmem_cache_node *n;
                struct kmem_cache *cache = kmalloc_caches[i];
 
@@ -1180,6 +1180,12 @@ static int init_cache_node_node(int node)
        return 0;
 }
 
+static inline int slabs_tofree(struct kmem_cache *cachep,
+                                               struct kmem_cache_node *n)
+{
+       return (n->free_objects + cachep->num - 1) / cachep->num;
+}
+
 static void __cpuinit cpuup_canceled(long cpu)
 {
        struct kmem_cache *cachep;
@@ -1241,7 +1247,7 @@ free_array_cache:
                n = cachep->node[node];
                if (!n)
                        continue;
-               drain_freelist(cachep, n, n->free_objects);
+               drain_freelist(cachep, n, slabs_tofree(cachep, n));
        }
 }
 
@@ -1408,7 +1414,7 @@ static int __meminit drain_cache_node_node(int node)
                if (!n)
                        continue;
 
-               drain_freelist(cachep, n, n->free_objects);
+               drain_freelist(cachep, n, slabs_tofree(cachep, n));
 
                if (!list_empty(&n->slabs_full) ||
                    !list_empty(&n->slabs_partial)) {
@@ -2532,7 +2538,7 @@ static int __cache_shrink(struct kmem_cache *cachep)
                if (!n)
                        continue;
 
-               drain_freelist(cachep, n, n->free_objects);
+               drain_freelist(cachep, n, slabs_tofree(cachep, n));
 
                ret += !list_empty(&n->slabs_full) ||
                        !list_empty(&n->slabs_partial);
@@ -3338,18 +3344,6 @@ done:
        return obj;
 }
 
-/**
- * kmem_cache_alloc_node - Allocate an object on the specified node
- * @cachep: The cache to allocate from.
- * @flags: See kmalloc().
- * @nodeid: node number of the target node.
- * @caller: return address of caller, used for debug information
- *
- * Identical to kmem_cache_alloc but it will allocate memory on the given
- * node, which can improve the performance for cpu bound structures.
- *
- * Fallback to other node is possible if __GFP_THISNODE is not set.
- */
 static __always_inline void *
 slab_alloc_node(struct kmem_cache *cachep, gfp_t flags, int nodeid,
                   unsigned long caller)
@@ -3643,6 +3637,17 @@ EXPORT_SYMBOL(kmem_cache_alloc_trace);
 #endif
 
 #ifdef CONFIG_NUMA
+/**
+ * kmem_cache_alloc_node - Allocate an object on the specified node
+ * @cachep: The cache to allocate from.
+ * @flags: See kmalloc().
+ * @nodeid: node number of the target node.
+ *
+ * Identical to kmem_cache_alloc but it will allocate memory on the given
+ * node, which can improve the performance for cpu bound structures.
+ *
+ * Fallback to other node is possible if __GFP_THISNODE is not set.
+ */
 void *kmem_cache_alloc_node(struct kmem_cache *cachep, gfp_t flags, int nodeid)
 {
        void *ret = slab_alloc_node(cachep, flags, nodeid, _RET_IP_);
@@ -4431,20 +4436,10 @@ static int leaks_show(struct seq_file *m, void *p)
        return 0;
 }
 
-static void *s_next(struct seq_file *m, void *p, loff_t *pos)
-{
-       return seq_list_next(p, &slab_caches, pos);
-}
-
-static void s_stop(struct seq_file *m, void *p)
-{
-       mutex_unlock(&slab_mutex);
-}
-
 static const struct seq_operations slabstats_op = {
        .start = leaks_start,
-       .next = s_next,
-       .stop = s_stop,
+       .next = slab_next,
+       .stop = slab_stop,
        .show = leaks_show,
 };
 
index f96b49e..620ceed 100644 (file)
--- a/mm/slab.h
+++ b/mm/slab.h
@@ -271,3 +271,6 @@ struct kmem_cache_node {
 #endif
 
 };
+
+void *slab_next(struct seq_file *m, void *p, loff_t *pos);
+void slab_stop(struct seq_file *m, void *p);
index 2d41450..538bade 100644 (file)
@@ -497,6 +497,13 @@ void __init create_kmalloc_caches(unsigned long flags)
 
 
 #ifdef CONFIG_SLABINFO
+
+#ifdef CONFIG_SLAB
+#define SLABINFO_RIGHTS (S_IWUSR | S_IRUSR)
+#else
+#define SLABINFO_RIGHTS S_IRUSR
+#endif
+
 void print_slabinfo_header(struct seq_file *m)
 {
        /*
@@ -531,12 +538,12 @@ static void *s_start(struct seq_file *m, loff_t *pos)
        return seq_list_start(&slab_caches, *pos);
 }
 
-static void *s_next(struct seq_file *m, void *p, loff_t *pos)
+void *slab_next(struct seq_file *m, void *p, loff_t *pos)
 {
        return seq_list_next(p, &slab_caches, pos);
 }
 
-static void s_stop(struct seq_file *m, void *p)
+void slab_stop(struct seq_file *m, void *p)
 {
        mutex_unlock(&slab_mutex);
 }
@@ -613,8 +620,8 @@ static int s_show(struct seq_file *m, void *p)
  */
 static const struct seq_operations slabinfo_op = {
        .start = s_start,
-       .next = s_next,
-       .stop = s_stop,
+       .next = slab_next,
+       .stop = slab_stop,
        .show = s_show,
 };
 
@@ -633,7 +640,8 @@ static const struct file_operations proc_slabinfo_operations = {
 
 static int __init slab_proc_init(void)
 {
-       proc_create("slabinfo", S_IRUSR, NULL, &proc_slabinfo_operations);
+       proc_create("slabinfo", SLABINFO_RIGHTS, NULL,
+                                               &proc_slabinfo_operations);
        return 0;
 }
 module_init(slab_proc_init);
index eeed4a0..91bd3f2 100644 (file)
--- a/mm/slob.c
+++ b/mm/slob.c
@@ -122,7 +122,7 @@ static inline void clear_slob_page_free(struct page *sp)
 }
 
 #define SLOB_UNIT sizeof(slob_t)
-#define SLOB_UNITS(size) (((size) + SLOB_UNIT - 1)/SLOB_UNIT)
+#define SLOB_UNITS(size) DIV_ROUND_UP(size, SLOB_UNIT)
 
 /*
  * struct slob_rcu is inserted at the tail of allocated slob blocks, which
@@ -554,7 +554,7 @@ void *kmem_cache_alloc_node(struct kmem_cache *c, gfp_t flags, int node)
                                            flags, node);
        }
 
-       if (c->ctor)
+       if (b && c->ctor)
                c->ctor(b);
 
        kmemleak_alloc_recursive(b, c->size, 1, c->flags, flags);
index 57707f0..3b482c8 100644 (file)
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -123,6 +123,15 @@ static inline int kmem_cache_debug(struct kmem_cache *s)
 #endif
 }
 
+static inline bool kmem_cache_has_cpu_partial(struct kmem_cache *s)
+{
+#ifdef CONFIG_SLUB_CPU_PARTIAL
+       return !kmem_cache_debug(s);
+#else
+       return false;
+#endif
+}
+
 /*
  * Issues still to be resolved:
  *
@@ -1573,7 +1582,8 @@ static void *get_partial_node(struct kmem_cache *s, struct kmem_cache_node *n,
                        put_cpu_partial(s, page, 0);
                        stat(s, CPU_PARTIAL_NODE);
                }
-               if (kmem_cache_debug(s) || available > s->cpu_partial / 2)
+               if (!kmem_cache_has_cpu_partial(s)
+                       || available > s->cpu_partial / 2)
                        break;
 
        }
@@ -1884,6 +1894,7 @@ redo:
 static void unfreeze_partials(struct kmem_cache *s,
                struct kmem_cache_cpu *c)
 {
+#ifdef CONFIG_SLUB_CPU_PARTIAL
        struct kmem_cache_node *n = NULL, *n2 = NULL;
        struct page *page, *discard_page = NULL;
 
@@ -1938,6 +1949,7 @@ static void unfreeze_partials(struct kmem_cache *s,
                discard_slab(s, page);
                stat(s, FREE_SLAB);
        }
+#endif
 }
 
 /*
@@ -1951,10 +1963,14 @@ static void unfreeze_partials(struct kmem_cache *s,
  */
 static void put_cpu_partial(struct kmem_cache *s, struct page *page, int drain)
 {
+#ifdef CONFIG_SLUB_CPU_PARTIAL
        struct page *oldpage;
        int pages;
        int pobjects;
 
+       if (!s->cpu_partial)
+               return;
+
        do {
                pages = 0;
                pobjects = 0;
@@ -1987,6 +2003,7 @@ static void put_cpu_partial(struct kmem_cache *s, struct page *page, int drain)
                page->next = oldpage;
 
        } while (this_cpu_cmpxchg(s->cpu_slab->partial, oldpage, page) != oldpage);
+#endif
 }
 
 static inline void flush_slab(struct kmem_cache *s, struct kmem_cache_cpu *c)
@@ -2358,7 +2375,7 @@ redo:
 
        object = c->freelist;
        page = c->page;
-       if (unlikely(!object || !node_match(page, node)))
+       if (unlikely(!object || !page || !node_match(page, node)))
                object = __slab_alloc(s, gfpflags, node, addr, c);
 
        else {
@@ -2495,7 +2512,7 @@ static void __slab_free(struct kmem_cache *s, struct page *page,
                new.inuse--;
                if ((!new.inuse || !prior) && !was_frozen) {
 
-                       if (!kmem_cache_debug(s) && !prior)
+                       if (kmem_cache_has_cpu_partial(s) && !prior)
 
                                /*
                                 * Slab was on no list before and will be partially empty
@@ -2550,8 +2567,9 @@ static void __slab_free(struct kmem_cache *s, struct page *page,
         * Objects left in the slab. If it was not on the partial list before
         * then add it.
         */
-       if (kmem_cache_debug(s) && unlikely(!prior)) {
-               remove_full(s, page);
+       if (!kmem_cache_has_cpu_partial(s) && unlikely(!prior)) {
+               if (kmem_cache_debug(s))
+                       remove_full(s, page);
                add_partial(n, page, DEACTIVATE_TO_TAIL);
                stat(s, FREE_ADD_PARTIAL);
        }
@@ -3059,7 +3077,7 @@ static int kmem_cache_open(struct kmem_cache *s, unsigned long flags)
         *    per node list when we run out of per cpu objects. We only fetch 50%
         *    to keep some capacity around for frees.
         */
-       if (kmem_cache_debug(s))
+       if (!kmem_cache_has_cpu_partial(s))
                s->cpu_partial = 0;
        else if (s->size >= PAGE_SIZE)
                s->cpu_partial = 2;
@@ -4456,7 +4474,7 @@ static ssize_t cpu_partial_store(struct kmem_cache *s, const char *buf,
        err = strict_strtoul(buf, 10, &objects);
        if (err)
                return err;
-       if (objects && kmem_cache_debug(s))
+       if (objects && !kmem_cache_has_cpu_partial(s))
                return -EINVAL;
 
        s->cpu_partial = objects;
@@ -5269,7 +5287,6 @@ __initcall(slab_sysfs_init);
 #ifdef CONFIG_SLABINFO
 void get_slabinfo(struct kmem_cache *s, struct slabinfo *sinfo)
 {
-       unsigned long nr_partials = 0;
        unsigned long nr_slabs = 0;
        unsigned long nr_objs = 0;
        unsigned long nr_free = 0;
@@ -5281,9 +5298,8 @@ void get_slabinfo(struct kmem_cache *s, struct slabinfo *sinfo)
                if (!n)
                        continue;
 
-               nr_partials += n->nr_partial;
-               nr_slabs += atomic_long_read(&n->nr_slabs);
-               nr_objs += atomic_long_read(&n->total_objects);
+               nr_slabs += node_nr_slabs(n);
+               nr_objs += node_nr_objs(n);
                nr_free += count_partial(n, count_free);
        }
 
index ab1424d..7441c41 100644 (file)
--- a/mm/util.c
+++ b/mm/util.c
@@ -295,7 +295,6 @@ void arch_pick_mmap_layout(struct mm_struct *mm)
 {
        mm->mmap_base = TASK_UNMAPPED_BASE;
        mm->get_unmapped_area = arch_get_unmapped_area;
-       mm->unmap_area = arch_unmap_area;
 }
 #endif
 
diff --git a/mm/zbud.c b/mm/zbud.c
new file mode 100644 (file)
index 0000000..9bb4710
--- /dev/null
+++ b/mm/zbud.c
@@ -0,0 +1,527 @@
+/*
+ * zbud.c
+ *
+ * Copyright (C) 2013, Seth Jennings, IBM
+ *
+ * Concepts based on zcache internal zbud allocator by Dan Magenheimer.
+ *
+ * zbud is an special purpose allocator for storing compressed pages.  Contrary
+ * to what its name may suggest, zbud is not a buddy allocator, but rather an
+ * allocator that "buddies" two compressed pages together in a single memory
+ * page.
+ *
+ * While this design limits storage density, it has simple and deterministic
+ * reclaim properties that make it preferable to a higher density approach when
+ * reclaim will be used.
+ *
+ * zbud works by storing compressed pages, or "zpages", together in pairs in a
+ * single memory page called a "zbud page".  The first buddy is "left
+ * justifed" at the beginning of the zbud page, and the last buddy is "right
+ * justified" at the end of the zbud page.  The benefit is that if either
+ * buddy is freed, the freed buddy space, coalesced with whatever slack space
+ * that existed between the buddies, results in the largest possible free region
+ * within the zbud page.
+ *
+ * zbud also provides an attractive lower bound on density. The ratio of zpages
+ * to zbud pages can not be less than 1.  This ensures that zbud can never "do
+ * harm" by using more pages to store zpages than the uncompressed zpages would
+ * have used on their own.
+ *
+ * zbud pages are divided into "chunks".  The size of the chunks is fixed at
+ * compile time and determined by NCHUNKS_ORDER below.  Dividing zbud pages
+ * into chunks allows organizing unbuddied zbud pages into a manageable number
+ * of unbuddied lists according to the number of free chunks available in the
+ * zbud page.
+ *
+ * The zbud API differs from that of conventional allocators in that the
+ * allocation function, zbud_alloc(), returns an opaque handle to the user,
+ * not a dereferenceable pointer.  The user must map the handle using
+ * zbud_map() in order to get a usable pointer by which to access the
+ * allocation data and unmap the handle with zbud_unmap() when operations
+ * on the allocation data are complete.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/atomic.h>
+#include <linux/list.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/preempt.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/zbud.h>
+
+/*****************
+ * Structures
+*****************/
+/*
+ * NCHUNKS_ORDER determines the internal allocation granularity, effectively
+ * adjusting internal fragmentation.  It also determines the number of
+ * freelists maintained in each pool. NCHUNKS_ORDER of 6 means that the
+ * allocation granularity will be in chunks of size PAGE_SIZE/64, and there
+ * will be 64 freelists per pool.
+ */
+#define NCHUNKS_ORDER  6
+
+#define CHUNK_SHIFT    (PAGE_SHIFT - NCHUNKS_ORDER)
+#define CHUNK_SIZE     (1 << CHUNK_SHIFT)
+#define NCHUNKS                (PAGE_SIZE >> CHUNK_SHIFT)
+#define ZHDR_SIZE_ALIGNED CHUNK_SIZE
+
+/**
+ * struct zbud_pool - stores metadata for each zbud pool
+ * @lock:      protects all pool fields and first|last_chunk fields of any
+ *             zbud page in the pool
+ * @unbuddied: array of lists tracking zbud pages that only contain one buddy;
+ *             the lists each zbud page is added to depends on the size of
+ *             its free region.
+ * @buddied:   list tracking the zbud pages that contain two buddies;
+ *             these zbud pages are full
+ * @lru:       list tracking the zbud pages in LRU order by most recently
+ *             added buddy.
+ * @pages_nr:  number of zbud pages in the pool.
+ * @ops:       pointer to a structure of user defined operations specified at
+ *             pool creation time.
+ *
+ * This structure is allocated at pool creation time and maintains metadata
+ * pertaining to a particular zbud pool.
+ */
+struct zbud_pool {
+       spinlock_t lock;
+       struct list_head unbuddied[NCHUNKS];
+       struct list_head buddied;
+       struct list_head lru;
+       u64 pages_nr;
+       struct zbud_ops *ops;
+};
+
+/*
+ * struct zbud_header - zbud page metadata occupying the first chunk of each
+ *                     zbud page.
+ * @buddy:     links the zbud page into the unbuddied/buddied lists in the pool
+ * @lru:       links the zbud page into the lru list in the pool
+ * @first_chunks:      the size of the first buddy in chunks, 0 if free
+ * @last_chunks:       the size of the last buddy in chunks, 0 if free
+ */
+struct zbud_header {
+       struct list_head buddy;
+       struct list_head lru;
+       unsigned int first_chunks;
+       unsigned int last_chunks;
+       bool under_reclaim;
+};
+
+/*****************
+ * Helpers
+*****************/
+/* Just to make the code easier to read */
+enum buddy {
+       FIRST,
+       LAST
+};
+
+/* Converts an allocation size in bytes to size in zbud chunks */
+static int size_to_chunks(int size)
+{
+       return (size + CHUNK_SIZE - 1) >> CHUNK_SHIFT;
+}
+
+#define for_each_unbuddied_list(_iter, _begin) \
+       for ((_iter) = (_begin); (_iter) < NCHUNKS; (_iter)++)
+
+/* Initializes the zbud header of a newly allocated zbud page */
+static struct zbud_header *init_zbud_page(struct page *page)
+{
+       struct zbud_header *zhdr = page_address(page);
+       zhdr->first_chunks = 0;
+       zhdr->last_chunks = 0;
+       INIT_LIST_HEAD(&zhdr->buddy);
+       INIT_LIST_HEAD(&zhdr->lru);
+       zhdr->under_reclaim = 0;
+       return zhdr;
+}
+
+/* Resets the struct page fields and frees the page */
+static void free_zbud_page(struct zbud_header *zhdr)
+{
+       __free_page(virt_to_page(zhdr));
+}
+
+/*
+ * Encodes the handle of a particular buddy within a zbud page
+ * Pool lock should be held as this function accesses first|last_chunks
+ */
+static unsigned long encode_handle(struct zbud_header *zhdr, enum buddy bud)
+{
+       unsigned long handle;
+
+       /*
+        * For now, the encoded handle is actually just the pointer to the data
+        * but this might not always be the case.  A little information hiding.
+        * Add CHUNK_SIZE to the handle if it is the first allocation to jump
+        * over the zbud header in the first chunk.
+        */
+       handle = (unsigned long)zhdr;
+       if (bud == FIRST)
+               /* skip over zbud header */
+               handle += ZHDR_SIZE_ALIGNED;
+       else /* bud == LAST */
+               handle += PAGE_SIZE - (zhdr->last_chunks  << CHUNK_SHIFT);
+       return handle;
+}
+
+/* Returns the zbud page where a given handle is stored */
+static struct zbud_header *handle_to_zbud_header(unsigned long handle)
+{
+       return (struct zbud_header *)(handle & PAGE_MASK);
+}
+
+/* Returns the number of free chunks in a zbud page */
+static int num_free_chunks(struct zbud_header *zhdr)
+{
+       /*
+        * Rather than branch for different situations, just use the fact that
+        * free buddies have a length of zero to simplify everything. -1 at the
+        * end for the zbud header.
+        */
+       return NCHUNKS - zhdr->first_chunks - zhdr->last_chunks - 1;
+}
+
+/*****************
+ * API Functions
+*****************/
+/**
+ * zbud_create_pool() - create a new zbud pool
+ * @gfp:       gfp flags when allocating the zbud pool structure
+ * @ops:       user-defined operations for the zbud pool
+ *
+ * Return: pointer to the new zbud pool or NULL if the metadata allocation
+ * failed.
+ */
+struct zbud_pool *zbud_create_pool(gfp_t gfp, struct zbud_ops *ops)
+{
+       struct zbud_pool *pool;
+       int i;
+
+       pool = kmalloc(sizeof(struct zbud_pool), gfp);
+       if (!pool)
+               return NULL;
+       spin_lock_init(&pool->lock);
+       for_each_unbuddied_list(i, 0)
+               INIT_LIST_HEAD(&pool->unbuddied[i]);
+       INIT_LIST_HEAD(&pool->buddied);
+       INIT_LIST_HEAD(&pool->lru);
+       pool->pages_nr = 0;
+       pool->ops = ops;
+       return pool;
+}
+
+/**
+ * zbud_destroy_pool() - destroys an existing zbud pool
+ * @pool:      the zbud pool to be destroyed
+ *
+ * The pool should be emptied before this function is called.
+ */
+void zbud_destroy_pool(struct zbud_pool *pool)
+{
+       kfree(pool);
+}
+
+/**
+ * zbud_alloc() - allocates a region of a given size
+ * @pool:      zbud pool from which to allocate
+ * @size:      size in bytes of the desired allocation
+ * @gfp:       gfp flags used if the pool needs to grow
+ * @handle:    handle of the new allocation
+ *
+ * This function will attempt to find a free region in the pool large enough to
+ * satisfy the allocation request.  A search of the unbuddied lists is
+ * performed first. If no suitable free region is found, then a new page is
+ * allocated and added to the pool to satisfy the request.
+ *
+ * gfp should not set __GFP_HIGHMEM as highmem pages cannot be used
+ * as zbud pool pages.
+ *
+ * Return: 0 if success and handle is set, otherwise -EINVAL is the size or
+ * gfp arguments are invalid or -ENOMEM if the pool was unable to allocate
+ * a new page.
+ */
+int zbud_alloc(struct zbud_pool *pool, int size, gfp_t gfp,
+                       unsigned long *handle)
+{
+       int chunks, i, freechunks;
+       struct zbud_header *zhdr = NULL;
+       enum buddy bud;
+       struct page *page;
+
+       if (size <= 0 || gfp & __GFP_HIGHMEM)
+               return -EINVAL;
+       if (size > PAGE_SIZE - ZHDR_SIZE_ALIGNED)
+               return -ENOSPC;
+       chunks = size_to_chunks(size);
+       spin_lock(&pool->lock);
+
+       /* First, try to find an unbuddied zbud page. */
+       zhdr = NULL;
+       for_each_unbuddied_list(i, chunks) {
+               if (!list_empty(&pool->unbuddied[i])) {
+                       zhdr = list_first_entry(&pool->unbuddied[i],
+                                       struct zbud_header, buddy);
+                       list_del(&zhdr->buddy);
+                       if (zhdr->first_chunks == 0)
+                               bud = FIRST;
+                       else
+                               bud = LAST;
+                       goto found;
+               }
+       }
+
+       /* Couldn't find unbuddied zbud page, create new one */
+       spin_unlock(&pool->lock);
+       page = alloc_page(gfp);
+       if (!page)
+               return -ENOMEM;
+       spin_lock(&pool->lock);
+       pool->pages_nr++;
+       zhdr = init_zbud_page(page);
+       bud = FIRST;
+
+found:
+       if (bud == FIRST)
+               zhdr->first_chunks = chunks;
+       else
+               zhdr->last_chunks = chunks;
+
+       if (zhdr->first_chunks == 0 || zhdr->last_chunks == 0) {
+               /* Add to unbuddied list */
+               freechunks = num_free_chunks(zhdr);
+               list_add(&zhdr->buddy, &pool->unbuddied[freechunks]);
+       } else {
+               /* Add to buddied list */
+               list_add(&zhdr->buddy, &pool->buddied);
+       }
+
+       /* Add/move zbud page to beginning of LRU */
+       if (!list_empty(&zhdr->lru))
+               list_del(&zhdr->lru);
+       list_add(&zhdr->lru, &pool->lru);
+
+       *handle = encode_handle(zhdr, bud);
+       spin_unlock(&pool->lock);
+
+       return 0;
+}
+
+/**
+ * zbud_free() - frees the allocation associated with the given handle
+ * @pool:      pool in which the allocation resided
+ * @handle:    handle associated with the allocation returned by zbud_alloc()
+ *
+ * In the case that the zbud page in which the allocation resides is under
+ * reclaim, as indicated by the PG_reclaim flag being set, this function
+ * only sets the first|last_chunks to 0.  The page is actually freed
+ * once both buddies are evicted (see zbud_reclaim_page() below).
+ */
+void zbud_free(struct zbud_pool *pool, unsigned long handle)
+{
+       struct zbud_header *zhdr;
+       int freechunks;
+
+       spin_lock(&pool->lock);
+       zhdr = handle_to_zbud_header(handle);
+
+       /* If first buddy, handle will be page aligned */
+       if ((handle - ZHDR_SIZE_ALIGNED) & ~PAGE_MASK)
+               zhdr->last_chunks = 0;
+       else
+               zhdr->first_chunks = 0;
+
+       if (zhdr->under_reclaim) {
+               /* zbud page is under reclaim, reclaim will free */
+               spin_unlock(&pool->lock);
+               return;
+       }
+
+       /* Remove from existing buddy list */
+       list_del(&zhdr->buddy);
+
+       if (zhdr->first_chunks == 0 && zhdr->last_chunks == 0) {
+               /* zbud page is empty, free */
+               list_del(&zhdr->lru);
+               free_zbud_page(zhdr);
+               pool->pages_nr--;
+       } else {
+               /* Add to unbuddied list */
+               freechunks = num_free_chunks(zhdr);
+               list_add(&zhdr->buddy, &pool->unbuddied[freechunks]);
+       }
+
+       spin_unlock(&pool->lock);
+}
+
+#define list_tail_entry(ptr, type, member) \
+       list_entry((ptr)->prev, type, member)
+
+/**
+ * zbud_reclaim_page() - evicts allocations from a pool page and frees it
+ * @pool:      pool from which a page will attempt to be evicted
+ * @retires:   number of pages on the LRU list for which eviction will
+ *             be attempted before failing
+ *
+ * zbud reclaim is different from normal system reclaim in that the reclaim is
+ * done from the bottom, up.  This is because only the bottom layer, zbud, has
+ * information on how the allocations are organized within each zbud page. This
+ * has the potential to create interesting locking situations between zbud and
+ * the user, however.
+ *
+ * To avoid these, this is how zbud_reclaim_page() should be called:
+
+ * The user detects a page should be reclaimed and calls zbud_reclaim_page().
+ * zbud_reclaim_page() will remove a zbud page from the pool LRU list and call
+ * the user-defined eviction handler with the pool and handle as arguments.
+ *
+ * If the handle can not be evicted, the eviction handler should return
+ * non-zero. zbud_reclaim_page() will add the zbud page back to the
+ * appropriate list and try the next zbud page on the LRU up to
+ * a user defined number of retries.
+ *
+ * If the handle is successfully evicted, the eviction handler should
+ * return 0 _and_ should have called zbud_free() on the handle. zbud_free()
+ * contains logic to delay freeing the page if the page is under reclaim,
+ * as indicated by the setting of the PG_reclaim flag on the underlying page.
+ *
+ * If all buddies in the zbud page are successfully evicted, then the
+ * zbud page can be freed.
+ *
+ * Returns: 0 if page is successfully freed, otherwise -EINVAL if there are
+ * no pages to evict or an eviction handler is not registered, -EAGAIN if
+ * the retry limit was hit.
+ */
+int zbud_reclaim_page(struct zbud_pool *pool, unsigned int retries)
+{
+       int i, ret, freechunks;
+       struct zbud_header *zhdr;
+       unsigned long first_handle = 0, last_handle = 0;
+
+       spin_lock(&pool->lock);
+       if (!pool->ops || !pool->ops->evict || list_empty(&pool->lru) ||
+                       retries == 0) {
+               spin_unlock(&pool->lock);
+               return -EINVAL;
+       }
+       for (i = 0; i < retries; i++) {
+               zhdr = list_tail_entry(&pool->lru, struct zbud_header, lru);
+               list_del(&zhdr->lru);
+               list_del(&zhdr->buddy);
+               /* Protect zbud page against free */
+               zhdr->under_reclaim = true;
+               /*
+                * We need encode the handles before unlocking, since we can
+                * race with free that will set (first|last)_chunks to 0
+                */
+               first_handle = 0;
+               last_handle = 0;
+               if (zhdr->first_chunks)
+                       first_handle = encode_handle(zhdr, FIRST);
+               if (zhdr->last_chunks)
+                       last_handle = encode_handle(zhdr, LAST);
+               spin_unlock(&pool->lock);
+
+               /* Issue the eviction callback(s) */
+               if (first_handle) {
+                       ret = pool->ops->evict(pool, first_handle);
+                       if (ret)
+                               goto next;
+               }
+               if (last_handle) {
+                       ret = pool->ops->evict(pool, last_handle);
+                       if (ret)
+                               goto next;
+               }
+next:
+               spin_lock(&pool->lock);
+               zhdr->under_reclaim = false;
+               if (zhdr->first_chunks == 0 && zhdr->last_chunks == 0) {
+                       /*
+                        * Both buddies are now free, free the zbud page and
+                        * return success.
+                        */
+                       free_zbud_page(zhdr);
+                       pool->pages_nr--;
+                       spin_unlock(&pool->lock);
+                       return 0;
+               } else if (zhdr->first_chunks == 0 ||
+                               zhdr->last_chunks == 0) {
+                       /* add to unbuddied list */
+                       freechunks = num_free_chunks(zhdr);
+                       list_add(&zhdr->buddy, &pool->unbuddied[freechunks]);
+               } else {
+                       /* add to buddied list */
+                       list_add(&zhdr->buddy, &pool->buddied);
+               }
+
+               /* add to beginning of LRU */
+               list_add(&zhdr->lru, &pool->lru);
+       }
+       spin_unlock(&pool->lock);
+       return -EAGAIN;
+}
+
+/**
+ * zbud_map() - maps the allocation associated with the given handle
+ * @pool:      pool in which the allocation resides
+ * @handle:    handle associated with the allocation to be mapped
+ *
+ * While trivial for zbud, the mapping functions for others allocators
+ * implementing this allocation API could have more complex information encoded
+ * in the handle and could create temporary mappings to make the data
+ * accessible to the user.
+ *
+ * Returns: a pointer to the mapped allocation
+ */
+void *zbud_map(struct zbud_pool *pool, unsigned long handle)
+{
+       return (void *)(handle);
+}
+
+/**
+ * zbud_unmap() - maps the allocation associated with the given handle
+ * @pool:      pool in which the allocation resides
+ * @handle:    handle associated with the allocation to be unmapped
+ */
+void zbud_unmap(struct zbud_pool *pool, unsigned long handle)
+{
+}
+
+/**
+ * zbud_get_pool_size() - gets the zbud pool size in pages
+ * @pool:      pool whose size is being queried
+ *
+ * Returns: size in pages of the given pool.  The pool lock need not be
+ * taken to access pages_nr.
+ */
+u64 zbud_get_pool_size(struct zbud_pool *pool)
+{
+       return pool->pages_nr;
+}
+
+static int __init init_zbud(void)
+{
+       /* Make sure the zbud header will fit in one chunk */
+       BUILD_BUG_ON(sizeof(struct zbud_header) > ZHDR_SIZE_ALIGNED);
+       pr_info("loaded\n");
+       return 0;
+}
+
+static void __exit exit_zbud(void)
+{
+       pr_info("unloaded\n");
+}
+
+module_init(init_zbud);
+module_exit(exit_zbud);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Seth Jennings <sjenning@linux.vnet.ibm.com>");
+MODULE_DESCRIPTION("Buddy Allocator for Compressed Pages");
diff --git a/mm/zswap.c b/mm/zswap.c
new file mode 100644 (file)
index 0000000..deda2b6
--- /dev/null
@@ -0,0 +1,943 @@
+/*
+ * zswap.c - zswap driver file
+ *
+ * zswap is a backend for frontswap that takes pages that are in the process
+ * of being swapped out and attempts to compress and store them in a
+ * RAM-based memory pool.  This can result in a significant I/O reduction on
+ * the swap device and, in the case where decompressing from RAM is faster
+ * than reading from the swap device, can also improve workload performance.
+ *
+ * Copyright (C) 2012  Seth Jennings <sjenning@linux.vnet.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+*/
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/cpu.h>
+#include <linux/highmem.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <linux/atomic.h>
+#include <linux/frontswap.h>
+#include <linux/rbtree.h>
+#include <linux/swap.h>
+#include <linux/crypto.h>
+#include <linux/mempool.h>
+#include <linux/zbud.h>
+
+#include <linux/mm_types.h>
+#include <linux/page-flags.h>
+#include <linux/swapops.h>
+#include <linux/writeback.h>
+#include <linux/pagemap.h>
+
+/*********************************
+* statistics
+**********************************/
+/* Number of memory pages used by the compressed pool */
+static u64 zswap_pool_pages;
+/* The number of compressed pages currently stored in zswap */
+static atomic_t zswap_stored_pages = ATOMIC_INIT(0);
+
+/*
+ * The statistics below are not protected from concurrent access for
+ * performance reasons so they may not be a 100% accurate.  However,
+ * they do provide useful information on roughly how many times a
+ * certain event is occurring.
+*/
+
+/* Pool limit was hit (see zswap_max_pool_percent) */
+static u64 zswap_pool_limit_hit;
+/* Pages written back when pool limit was reached */
+static u64 zswap_written_back_pages;
+/* Store failed due to a reclaim failure after pool limit was reached */
+static u64 zswap_reject_reclaim_fail;
+/* Compressed page was too big for the allocator to (optimally) store */
+static u64 zswap_reject_compress_poor;
+/* Store failed because underlying allocator could not get memory */
+static u64 zswap_reject_alloc_fail;
+/* Store failed because the entry metadata could not be allocated (rare) */
+static u64 zswap_reject_kmemcache_fail;
+/* Duplicate store was encountered (rare) */
+static u64 zswap_duplicate_entry;
+
+/*********************************
+* tunables
+**********************************/
+/* Enable/disable zswap (disabled by default, fixed at boot for now) */
+static bool zswap_enabled __read_mostly;
+module_param_named(enabled, zswap_enabled, bool, 0);
+
+/* Compressor to be used by zswap (fixed at boot for now) */
+#define ZSWAP_COMPRESSOR_DEFAULT "lzo"
+static char *zswap_compressor = ZSWAP_COMPRESSOR_DEFAULT;
+module_param_named(compressor, zswap_compressor, charp, 0);
+
+/* The maximum percentage of memory that the compressed pool can occupy */
+static unsigned int zswap_max_pool_percent = 20;
+module_param_named(max_pool_percent,
+                       zswap_max_pool_percent, uint, 0644);
+
+/*********************************
+* compression functions
+**********************************/
+/* per-cpu compression transforms */
+static struct crypto_comp * __percpu *zswap_comp_pcpu_tfms;
+
+enum comp_op {
+       ZSWAP_COMPOP_COMPRESS,
+       ZSWAP_COMPOP_DECOMPRESS
+};
+
+static int zswap_comp_op(enum comp_op op, const u8 *src, unsigned int slen,
+                               u8 *dst, unsigned int *dlen)
+{
+       struct crypto_comp *tfm;
+       int ret;
+
+       tfm = *per_cpu_ptr(zswap_comp_pcpu_tfms, get_cpu());
+       switch (op) {
+       case ZSWAP_COMPOP_COMPRESS:
+               ret = crypto_comp_compress(tfm, src, slen, dst, dlen);
+               break;
+       case ZSWAP_COMPOP_DECOMPRESS:
+               ret = crypto_comp_decompress(tfm, src, slen, dst, dlen);
+               break;
+       default:
+               ret = -EINVAL;
+       }
+
+       put_cpu();
+       return ret;
+}
+
+static int __init zswap_comp_init(void)
+{
+       if (!crypto_has_comp(zswap_compressor, 0, 0)) {
+               pr_info("%s compressor not available\n", zswap_compressor);
+               /* fall back to default compressor */
+               zswap_compressor = ZSWAP_COMPRESSOR_DEFAULT;
+               if (!crypto_has_comp(zswap_compressor, 0, 0))
+                       /* can't even load the default compressor */
+                       return -ENODEV;
+       }
+       pr_info("using %s compressor\n", zswap_compressor);
+
+       /* alloc percpu transforms */
+       zswap_comp_pcpu_tfms = alloc_percpu(struct crypto_comp *);
+       if (!zswap_comp_pcpu_tfms)
+               return -ENOMEM;
+       return 0;
+}
+
+static void zswap_comp_exit(void)
+{
+       /* free percpu transforms */
+       if (zswap_comp_pcpu_tfms)
+               free_percpu(zswap_comp_pcpu_tfms);
+}
+
+/*********************************
+* data structures
+**********************************/
+/*
+ * struct zswap_entry
+ *
+ * This structure contains the metadata for tracking a single compressed
+ * page within zswap.
+ *
+ * rbnode - links the entry into red-black tree for the appropriate swap type
+ * refcount - the number of outstanding reference to the entry. This is needed
+ *            to protect against premature freeing of the entry by code
+ *            concurent calls to load, invalidate, and writeback.  The lock
+ *            for the zswap_tree structure that contains the entry must
+ *            be held while changing the refcount.  Since the lock must
+ *            be held, there is no reason to also make refcount atomic.
+ * offset - the swap offset for the entry.  Index into the red-black tree.
+ * handle - zsmalloc allocation handle that stores the compressed page data
+ * length - the length in bytes of the compressed page data.  Needed during
+ *           decompression
+ */
+struct zswap_entry {
+       struct rb_node rbnode;
+       pgoff_t offset;
+       int refcount;
+       unsigned int length;
+       unsigned long handle;
+};
+
+struct zswap_header {
+       swp_entry_t swpentry;
+};
+
+/*
+ * The tree lock in the zswap_tree struct protects a few things:
+ * - the rbtree
+ * - the refcount field of each entry in the tree
+ */
+struct zswap_tree {
+       struct rb_root rbroot;
+       spinlock_t lock;
+       struct zbud_pool *pool;
+};
+
+static struct zswap_tree *zswap_trees[MAX_SWAPFILES];
+
+/*********************************
+* zswap entry functions
+**********************************/
+static struct kmem_cache *zswap_entry_cache;
+
+static int zswap_entry_cache_create(void)
+{
+       zswap_entry_cache = KMEM_CACHE(zswap_entry, 0);
+       return (zswap_entry_cache == NULL);
+}
+
+static void zswap_entry_cache_destory(void)
+{
+       kmem_cache_destroy(zswap_entry_cache);
+}
+
+static struct zswap_entry *zswap_entry_cache_alloc(gfp_t gfp)
+{
+       struct zswap_entry *entry;
+       entry = kmem_cache_alloc(zswap_entry_cache, gfp);
+       if (!entry)
+               return NULL;
+       entry->refcount = 1;
+       return entry;
+}
+
+static void zswap_entry_cache_free(struct zswap_entry *entry)
+{
+       kmem_cache_free(zswap_entry_cache, entry);
+}
+
+/* caller must hold the tree lock */
+static void zswap_entry_get(struct zswap_entry *entry)
+{
+       entry->refcount++;
+}
+
+/* caller must hold the tree lock */
+static int zswap_entry_put(struct zswap_entry *entry)
+{
+       entry->refcount--;
+       return entry->refcount;
+}
+
+/*********************************
+* rbtree functions
+**********************************/
+static struct zswap_entry *zswap_rb_search(struct rb_root *root, pgoff_t offset)
+{
+       struct rb_node *node = root->rb_node;
+       struct zswap_entry *entry;
+
+       while (node) {
+               entry = rb_entry(node, struct zswap_entry, rbnode);
+               if (entry->offset > offset)
+                       node = node->rb_left;
+               else if (entry->offset < offset)
+                       node = node->rb_right;
+               else
+                       return entry;
+       }
+       return NULL;
+}
+
+/*
+ * In the case that a entry with the same offset is found, a pointer to
+ * the existing entry is stored in dupentry and the function returns -EEXIST
+ */
+static int zswap_rb_insert(struct rb_root *root, struct zswap_entry *entry,
+                       struct zswap_entry **dupentry)
+{
+       struct rb_node **link = &root->rb_node, *parent = NULL;
+       struct zswap_entry *myentry;
+
+       while (*link) {
+               parent = *link;
+               myentry = rb_entry(parent, struct zswap_entry, rbnode);
+               if (myentry->offset > entry->offset)
+                       link = &(*link)->rb_left;
+               else if (myentry->offset < entry->offset)
+                       link = &(*link)->rb_right;
+               else {
+                       *dupentry = myentry;
+                       return -EEXIST;
+               }
+       }
+       rb_link_node(&entry->rbnode, parent, link);
+       rb_insert_color(&entry->rbnode, root);
+       return 0;
+}
+
+/*********************************
+* per-cpu code
+**********************************/
+static DEFINE_PER_CPU(u8 *, zswap_dstmem);
+
+static int __zswap_cpu_notifier(unsigned long action, unsigned long cpu)
+{
+       struct crypto_comp *tfm;
+       u8 *dst;
+
+       switch (action) {
+       case CPU_UP_PREPARE:
+               tfm = crypto_alloc_comp(zswap_compressor, 0, 0);
+               if (IS_ERR(tfm)) {
+                       pr_err("can't allocate compressor transform\n");
+                       return NOTIFY_BAD;
+               }
+               *per_cpu_ptr(zswap_comp_pcpu_tfms, cpu) = tfm;
+               dst = kmalloc(PAGE_SIZE * 2, GFP_KERNEL);
+               if (!dst) {
+                       pr_err("can't allocate compressor buffer\n");
+                       crypto_free_comp(tfm);
+                       *per_cpu_ptr(zswap_comp_pcpu_tfms, cpu) = NULL;
+                       return NOTIFY_BAD;
+               }
+               per_cpu(zswap_dstmem, cpu) = dst;
+               break;
+       case CPU_DEAD:
+       case CPU_UP_CANCELED:
+               tfm = *per_cpu_ptr(zswap_comp_pcpu_tfms, cpu);
+               if (tfm) {
+                       crypto_free_comp(tfm);
+                       *per_cpu_ptr(zswap_comp_pcpu_tfms, cpu) = NULL;
+               }
+               dst = per_cpu(zswap_dstmem, cpu);
+               kfree(dst);
+               per_cpu(zswap_dstmem, cpu) = NULL;
+               break;
+       default:
+               break;
+       }
+       return NOTIFY_OK;
+}
+
+static int zswap_cpu_notifier(struct notifier_block *nb,
+                               unsigned long action, void *pcpu)
+{
+       unsigned long cpu = (unsigned long)pcpu;
+       return __zswap_cpu_notifier(action, cpu);
+}
+
+static struct notifier_block zswap_cpu_notifier_block = {
+       .notifier_call = zswap_cpu_notifier
+};
+
+static int zswap_cpu_init(void)
+{
+       unsigned long cpu;
+
+       get_online_cpus();
+       for_each_online_cpu(cpu)
+               if (__zswap_cpu_notifier(CPU_UP_PREPARE, cpu) != NOTIFY_OK)
+                       goto cleanup;
+       register_cpu_notifier(&zswap_cpu_notifier_block);
+       put_online_cpus();
+       return 0;
+
+cleanup:
+       for_each_online_cpu(cpu)
+               __zswap_cpu_notifier(CPU_UP_CANCELED, cpu);
+       put_online_cpus();
+       return -ENOMEM;
+}
+
+/*********************************
+* helpers
+**********************************/
+static bool zswap_is_full(void)
+{
+       return (totalram_pages * zswap_max_pool_percent / 100 <
+               zswap_pool_pages);
+}
+
+/*
+ * Carries out the common pattern of freeing and entry's zsmalloc allocation,
+ * freeing the entry itself, and decrementing the number of stored pages.
+ */
+static void zswap_free_entry(struct zswap_tree *tree, struct zswap_entry *entry)
+{
+       zbud_free(tree->pool, entry->handle);
+       zswap_entry_cache_free(entry);
+       atomic_dec(&zswap_stored_pages);
+       zswap_pool_pages = zbud_get_pool_size(tree->pool);
+}
+
+/*********************************
+* writeback code
+**********************************/
+/* return enum for zswap_get_swap_cache_page */
+enum zswap_get_swap_ret {
+       ZSWAP_SWAPCACHE_NEW,
+       ZSWAP_SWAPCACHE_EXIST,
+       ZSWAP_SWAPCACHE_NOMEM
+};
+
+/*
+ * zswap_get_swap_cache_page
+ *
+ * This is an adaption of read_swap_cache_async()
+ *
+ * This function tries to find a page with the given swap entry
+ * in the swapper_space address space (the swap cache).  If the page
+ * is found, it is returned in retpage.  Otherwise, a page is allocated,
+ * added to the swap cache, and returned in retpage.
+ *
+ * If success, the swap cache page is returned in retpage
+ * Returns 0 if page was already in the swap cache, page is not locked
+ * Returns 1 if the new page needs to be populated, page is locked
+ * Returns <0 on error
+ */
+static int zswap_get_swap_cache_page(swp_entry_t entry,
+                               struct page **retpage)
+{
+       struct page *found_page, *new_page = NULL;
+       struct address_space *swapper_space = &swapper_spaces[swp_type(entry)];
+       int err;
+
+       *retpage = NULL;
+       do {
+               /*
+                * First check the swap cache.  Since this is normally
+                * called after lookup_swap_cache() failed, re-calling
+                * that would confuse statistics.
+                */
+               found_page = find_get_page(swapper_space, entry.val);
+               if (found_page)
+                       break;
+
+               /*
+                * Get a new page to read into from swap.
+                */
+               if (!new_page) {
+                       new_page = alloc_page(GFP_KERNEL);
+                       if (!new_page)
+                               break; /* Out of memory */
+               }
+
+               /*
+                * call radix_tree_preload() while we can wait.
+                */
+               err = radix_tree_preload(GFP_KERNEL);
+               if (err)
+                       break;
+
+               /*
+                * Swap entry may have been freed since our caller observed it.
+                */
+               err = swapcache_prepare(entry);
+               if (err == -EEXIST) { /* seems racy */
+                       radix_tree_preload_end();
+                       continue;
+               }
+               if (err) { /* swp entry is obsolete ? */
+                       radix_tree_preload_end();
+                       break;
+               }
+
+               /* May fail (-ENOMEM) if radix-tree node allocation failed. */
+               __set_page_locked(new_page);
+               SetPageSwapBacked(new_page);
+               err = __add_to_swap_cache(new_page, entry);
+               if (likely(!err)) {
+                       radix_tree_preload_end();
+                       lru_cache_add_anon(new_page);
+                       *retpage = new_page;
+                       return ZSWAP_SWAPCACHE_NEW;
+               }
+               radix_tree_preload_end();
+               ClearPageSwapBacked(new_page);
+               __clear_page_locked(new_page);
+               /*
+                * add_to_swap_cache() doesn't return -EEXIST, so we can safely
+                * clear SWAP_HAS_CACHE flag.
+                */
+               swapcache_free(entry, NULL);
+       } while (err != -ENOMEM);
+
+       if (new_page)
+               page_cache_release(new_page);
+       if (!found_page)
+               return ZSWAP_SWAPCACHE_NOMEM;
+       *retpage = found_page;
+       return ZSWAP_SWAPCACHE_EXIST;
+}
+
+/*
+ * Attempts to free an entry by adding a page to the swap cache,
+ * decompressing the entry data into the page, and issuing a
+ * bio write to write the page back to the swap device.
+ *
+ * This can be thought of as a "resumed writeback" of the page
+ * to the swap device.  We are basically resuming the same swap
+ * writeback path that was intercepted with the frontswap_store()
+ * in the first place.  After the page has been decompressed into
+ * the swap cache, the compressed version stored by zswap can be
+ * freed.
+ */
+static int zswap_writeback_entry(struct zbud_pool *pool, unsigned long handle)
+{
+       struct zswap_header *zhdr;
+       swp_entry_t swpentry;
+       struct zswap_tree *tree;
+       pgoff_t offset;
+       struct zswap_entry *entry;
+       struct page *page;
+       u8 *src, *dst;
+       unsigned int dlen;
+       int ret, refcount;
+       struct writeback_control wbc = {
+               .sync_mode = WB_SYNC_NONE,
+       };
+
+       /* extract swpentry from data */
+       zhdr = zbud_map(pool, handle);
+       swpentry = zhdr->swpentry; /* here */
+       zbud_unmap(pool, handle);
+       tree = zswap_trees[swp_type(swpentry)];
+       offset = swp_offset(swpentry);
+       BUG_ON(pool != tree->pool);
+
+       /* find and ref zswap entry */
+       spin_lock(&tree->lock);
+       entry = zswap_rb_search(&tree->rbroot, offset);
+       if (!entry) {
+               /* entry was invalidated */
+               spin_unlock(&tree->lock);
+               return 0;
+       }
+       zswap_entry_get(entry);
+       spin_unlock(&tree->lock);
+       BUG_ON(offset != entry->offset);
+
+       /* try to allocate swap cache page */
+       switch (zswap_get_swap_cache_page(swpentry, &page)) {
+       case ZSWAP_SWAPCACHE_NOMEM: /* no memory */
+               ret = -ENOMEM;
+               goto fail;
+
+       case ZSWAP_SWAPCACHE_EXIST: /* page is unlocked */
+               /* page is already in the swap cache, ignore for now */
+               page_cache_release(page);
+               ret = -EEXIST;
+               goto fail;
+
+       case ZSWAP_SWAPCACHE_NEW: /* page is locked */
+               /* decompress */
+               dlen = PAGE_SIZE;
+               src = (u8 *)zbud_map(tree->pool, entry->handle) +
+                       sizeof(struct zswap_header);
+               dst = kmap_atomic(page);
+               ret = zswap_comp_op(ZSWAP_COMPOP_DECOMPRESS, src,
+                               entry->length, dst, &dlen);
+               kunmap_atomic(dst);
+               zbud_unmap(tree->pool, entry->handle);
+               BUG_ON(ret);
+               BUG_ON(dlen != PAGE_SIZE);
+
+               /* page is up to date */
+               SetPageUptodate(page);
+       }
+
+       /* start writeback */
+       __swap_writepage(page, &wbc, end_swap_bio_write);
+       page_cache_release(page);
+       zswap_written_back_pages++;
+
+       spin_lock(&tree->lock);
+
+       /* drop local reference */
+       zswap_entry_put(entry);
+       /* drop the initial reference from entry creation */
+       refcount = zswap_entry_put(entry);
+
+       /*
+        * There are three possible values for refcount here:
+        * (1) refcount is 1, load is in progress, unlink from rbtree,
+        *     load will free
+        * (2) refcount is 0, (normal case) entry is valid,
+        *     remove from rbtree and free entry
+        * (3) refcount is -1, invalidate happened during writeback,
+        *     free entry
+        */
+       if (refcount >= 0) {
+               /* no invalidate yet, remove from rbtree */
+               rb_erase(&entry->rbnode, &tree->rbroot);
+       }
+       spin_unlock(&tree->lock);
+       if (refcount <= 0) {
+               /* free the entry */
+               zswap_free_entry(tree, entry);
+               return 0;
+       }
+       return -EAGAIN;
+
+fail:
+       spin_lock(&tree->lock);
+       zswap_entry_put(entry);
+       spin_unlock(&tree->lock);
+       return ret;
+}
+
+/*********************************
+* frontswap hooks
+**********************************/
+/* attempts to compress and store an single page */
+static int zswap_frontswap_store(unsigned type, pgoff_t offset,
+                               struct page *page)
+{
+       struct zswap_tree *tree = zswap_trees[type];
+       struct zswap_entry *entry, *dupentry;
+       int ret;
+       unsigned int dlen = PAGE_SIZE, len;
+       unsigned long handle;
+       char *buf;
+       u8 *src, *dst;
+       struct zswap_header *zhdr;
+
+       if (!tree) {
+               ret = -ENODEV;
+               goto reject;
+       }
+
+       /* reclaim space if needed */
+       if (zswap_is_full()) {
+               zswap_pool_limit_hit++;
+               if (zbud_reclaim_page(tree->pool, 8)) {
+                       zswap_reject_reclaim_fail++;
+                       ret = -ENOMEM;
+                       goto reject;
+               }
+       }
+
+       /* allocate entry */
+       entry = zswap_entry_cache_alloc(GFP_KERNEL);
+       if (!entry) {
+               zswap_reject_kmemcache_fail++;
+               ret = -ENOMEM;
+               goto reject;
+       }
+
+       /* compress */
+       dst = get_cpu_var(zswap_dstmem);
+       src = kmap_atomic(page);
+       ret = zswap_comp_op(ZSWAP_COMPOP_COMPRESS, src, PAGE_SIZE, dst, &dlen);
+       kunmap_atomic(src);
+       if (ret) {
+               ret = -EINVAL;
+               goto freepage;
+       }
+
+       /* store */
+       len = dlen + sizeof(struct zswap_header);
+       ret = zbud_alloc(tree->pool, len, __GFP_NORETRY | __GFP_NOWARN,
+               &handle);
+       if (ret == -ENOSPC) {
+               zswap_reject_compress_poor++;
+               goto freepage;
+       }
+       if (ret) {
+               zswap_reject_alloc_fail++;
+               goto freepage;
+       }
+       zhdr = zbud_map(tree->pool, handle);
+       zhdr->swpentry = swp_entry(type, offset);
+       buf = (u8 *)(zhdr + 1);
+       memcpy(buf, dst, dlen);
+       zbud_unmap(tree->pool, handle);
+       put_cpu_var(zswap_dstmem);
+
+       /* populate entry */
+       entry->offset = offset;
+       entry->handle = handle;
+       entry->length = dlen;
+
+       /* map */
+       spin_lock(&tree->lock);
+       do {
+               ret = zswap_rb_insert(&tree->rbroot, entry, &dupentry);
+               if (ret == -EEXIST) {
+                       zswap_duplicate_entry++;
+                       /* remove from rbtree */
+                       rb_erase(&dupentry->rbnode, &tree->rbroot);
+                       if (!zswap_entry_put(dupentry)) {
+                               /* free */
+                               zswap_free_entry(tree, dupentry);
+                       }
+               }
+       } while (ret == -EEXIST);
+       spin_unlock(&tree->lock);
+
+       /* update stats */
+       atomic_inc(&zswap_stored_pages);
+       zswap_pool_pages = zbud_get_pool_size(tree->pool);
+
+       return 0;
+
+freepage:
+       put_cpu_var(zswap_dstmem);
+       zswap_entry_cache_free(entry);
+reject:
+       return ret;
+}
+
+/*
+ * returns 0 if the page was successfully decompressed
+ * return -1 on entry not found or error
+*/
+static int zswap_frontswap_load(unsigned type, pgoff_t offset,
+                               struct page *page)
+{
+       struct zswap_tree *tree = zswap_trees[type];
+       struct zswap_entry *entry;
+       u8 *src, *dst;
+       unsigned int dlen;
+       int refcount, ret;
+
+       /* find */
+       spin_lock(&tree->lock);
+       entry = zswap_rb_search(&tree->rbroot, offset);
+       if (!entry) {
+               /* entry was written back */
+               spin_unlock(&tree->lock);
+               return -1;
+       }
+       zswap_entry_get(entry);
+       spin_unlock(&tree->lock);
+
+       /* decompress */
+       dlen = PAGE_SIZE;
+       src = (u8 *)zbud_map(tree->pool, entry->handle) +
+                       sizeof(struct zswap_header);
+       dst = kmap_atomic(page);
+       ret = zswap_comp_op(ZSWAP_COMPOP_DECOMPRESS, src, entry->length,
+               dst, &dlen);
+       kunmap_atomic(dst);
+       zbud_unmap(tree->pool, entry->handle);
+       BUG_ON(ret);
+
+       spin_lock(&tree->lock);
+       refcount = zswap_entry_put(entry);
+       if (likely(refcount)) {
+               spin_unlock(&tree->lock);
+               return 0;
+       }
+       spin_unlock(&tree->lock);
+
+       /*
+        * We don't have to unlink from the rbtree because
+        * zswap_writeback_entry() or zswap_frontswap_invalidate page()
+        * has already done this for us if we are the last reference.
+        */
+       /* free */
+
+       zswap_free_entry(tree, entry);
+
+       return 0;
+}
+
+/* frees an entry in zswap */
+static void zswap_frontswap_invalidate_page(unsigned type, pgoff_t offset)
+{
+       struct zswap_tree *tree = zswap_trees[type];
+       struct zswap_entry *entry;
+       int refcount;
+
+       /* find */
+       spin_lock(&tree->lock);
+       entry = zswap_rb_search(&tree->rbroot, offset);
+       if (!entry) {
+               /* entry was written back */
+               spin_unlock(&tree->lock);
+               return;
+       }
+
+       /* remove from rbtree */
+       rb_erase(&entry->rbnode, &tree->rbroot);
+
+       /* drop the initial reference from entry creation */
+       refcount = zswap_entry_put(entry);
+
+       spin_unlock(&tree->lock);
+
+       if (refcount) {
+               /* writeback in progress, writeback will free */
+               return;
+       }
+
+       /* free */
+       zswap_free_entry(tree, entry);
+}
+
+/* frees all zswap entries for the given swap type */
+static void zswap_frontswap_invalidate_area(unsigned type)
+{
+       struct zswap_tree *tree = zswap_trees[type];
+       struct rb_node *node;
+       struct zswap_entry *entry;
+
+       if (!tree)
+               return;
+
+       /* walk the tree and free everything */
+       spin_lock(&tree->lock);
+       /*
+        * TODO: Even though this code should not be executed because
+        * the try_to_unuse() in swapoff should have emptied the tree,
+        * it is very wasteful to rebalance the tree after every
+        * removal when we are freeing the whole tree.
+        *
+        * If post-order traversal code is ever added to the rbtree
+        * implementation, it should be used here.
+        */
+       while ((node = rb_first(&tree->rbroot))) {
+               entry = rb_entry(node, struct zswap_entry, rbnode);
+               rb_erase(&entry->rbnode, &tree->rbroot);
+               zbud_free(tree->pool, entry->handle);
+               zswap_entry_cache_free(entry);
+               atomic_dec(&zswap_stored_pages);
+       }
+       tree->rbroot = RB_ROOT;
+       spin_unlock(&tree->lock);
+}
+
+static struct zbud_ops zswap_zbud_ops = {
+       .evict = zswap_writeback_entry
+};
+
+static void zswap_frontswap_init(unsigned type)
+{
+       struct zswap_tree *tree;
+
+       tree = kzalloc(sizeof(struct zswap_tree), GFP_KERNEL);
+       if (!tree)
+               goto err;
+       tree->pool = zbud_create_pool(GFP_KERNEL, &zswap_zbud_ops);
+       if (!tree->pool)
+               goto freetree;
+       tree->rbroot = RB_ROOT;
+       spin_lock_init(&tree->lock);
+       zswap_trees[type] = tree;
+       return;
+
+freetree:
+       kfree(tree);
+err:
+       pr_err("alloc failed, zswap disabled for swap type %d\n", type);
+}
+
+static struct frontswap_ops zswap_frontswap_ops = {
+       .store = zswap_frontswap_store,
+       .load = zswap_frontswap_load,
+       .invalidate_page = zswap_frontswap_invalidate_page,
+       .invalidate_area = zswap_frontswap_invalidate_area,
+       .init = zswap_frontswap_init
+};
+
+/*********************************
+* debugfs functions
+**********************************/
+#ifdef CONFIG_DEBUG_FS
+#include <linux/debugfs.h>
+
+static struct dentry *zswap_debugfs_root;
+
+static int __init zswap_debugfs_init(void)
+{
+       if (!debugfs_initialized())
+               return -ENODEV;
+
+       zswap_debugfs_root = debugfs_create_dir("zswap", NULL);
+       if (!zswap_debugfs_root)
+               return -ENOMEM;
+
+       debugfs_create_u64("pool_limit_hit", S_IRUGO,
+                       zswap_debugfs_root, &zswap_pool_limit_hit);
+       debugfs_create_u64("reject_reclaim_fail", S_IRUGO,
+                       zswap_debugfs_root, &zswap_reject_reclaim_fail);
+       debugfs_create_u64("reject_alloc_fail", S_IRUGO,
+                       zswap_debugfs_root, &zswap_reject_alloc_fail);
+       debugfs_create_u64("reject_kmemcache_fail", S_IRUGO,
+                       zswap_debugfs_root, &zswap_reject_kmemcache_fail);
+       debugfs_create_u64("reject_compress_poor", S_IRUGO,
+                       zswap_debugfs_root, &zswap_reject_compress_poor);
+       debugfs_create_u64("written_back_pages", S_IRUGO,
+                       zswap_debugfs_root, &zswap_written_back_pages);
+       debugfs_create_u64("duplicate_entry", S_IRUGO,
+                       zswap_debugfs_root, &zswap_duplicate_entry);
+       debugfs_create_u64("pool_pages", S_IRUGO,
+                       zswap_debugfs_root, &zswap_pool_pages);
+       debugfs_create_atomic_t("stored_pages", S_IRUGO,
+                       zswap_debugfs_root, &zswap_stored_pages);
+
+       return 0;
+}
+
+static void __exit zswap_debugfs_exit(void)
+{
+       debugfs_remove_recursive(zswap_debugfs_root);
+}
+#else
+static int __init zswap_debugfs_init(void)
+{
+       return 0;
+}
+
+static void __exit zswap_debugfs_exit(void) { }
+#endif
+
+/*********************************
+* module init and exit
+**********************************/
+static int __init init_zswap(void)
+{
+       if (!zswap_enabled)
+               return 0;
+
+       pr_info("loading zswap\n");
+       if (zswap_entry_cache_create()) {
+               pr_err("entry cache creation failed\n");
+               goto error;
+       }
+       if (zswap_comp_init()) {
+               pr_err("compressor initialization failed\n");
+               goto compfail;
+       }
+       if (zswap_cpu_init()) {
+               pr_err("per-cpu initialization failed\n");
+               goto pcpufail;
+       }
+       frontswap_register_ops(&zswap_frontswap_ops);
+       if (zswap_debugfs_init())
+               pr_warn("debugfs initialization failed\n");
+       return 0;
+pcpufail:
+       zswap_comp_exit();
+compfail:
+       zswap_entry_cache_destory();
+error:
+       return -ENOMEM;
+}
+/* must be late so crypto has time to come up */
+late_initcall(init_zswap);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Seth Jennings <sjenning@linux.vnet.ibm.com>");
+MODULE_DESCRIPTION("Compressed cache for swap pages");
index 01f1779..8b93cae 100644 (file)
@@ -204,6 +204,17 @@ free_and_return:
        return ret;
 }
 
+struct p9_fcall *p9_fcall_alloc(int alloc_msize)
+{
+       struct p9_fcall *fc;
+       fc = kmalloc(sizeof(struct p9_fcall) + alloc_msize, GFP_NOFS);
+       if (!fc)
+               return NULL;
+       fc->capacity = alloc_msize;
+       fc->sdata = (char *) fc + sizeof(struct p9_fcall);
+       return fc;
+}
+
 /**
  * p9_tag_alloc - lookup/allocate a request by tag
  * @c: client session to lookup tag within
@@ -256,39 +267,36 @@ p9_tag_alloc(struct p9_client *c, u16 tag, unsigned int max_size)
        col = tag % P9_ROW_MAXTAG;
 
        req = &c->reqs[row][col];
-       if (!req->tc) {
+       if (!req->wq) {
                req->wq = kmalloc(sizeof(wait_queue_head_t), GFP_NOFS);
-               if (!req->wq) {
-                       pr_err("Couldn't grow tag array\n");
-                       return ERR_PTR(-ENOMEM);
-               }
+               if (!req->wq)
+                       goto grow_failed;
                init_waitqueue_head(req->wq);
-               req->tc = kmalloc(sizeof(struct p9_fcall) + alloc_msize,
-                                 GFP_NOFS);
-               req->rc = kmalloc(sizeof(struct p9_fcall) + alloc_msize,
-                                 GFP_NOFS);
-               if ((!req->tc) || (!req->rc)) {
-                       pr_err("Couldn't grow tag array\n");
-                       kfree(req->tc);
-                       kfree(req->rc);
-                       kfree(req->wq);
-                       req->tc = req->rc = NULL;
-                       req->wq = NULL;
-                       return ERR_PTR(-ENOMEM);
-               }
-               req->tc->capacity = alloc_msize;
-               req->rc->capacity = alloc_msize;
-               req->tc->sdata = (char *) req->tc + sizeof(struct p9_fcall);
-               req->rc->sdata = (char *) req->rc + sizeof(struct p9_fcall);
        }
 
+       if (!req->tc)
+               req->tc = p9_fcall_alloc(alloc_msize);
+       if (!req->rc)
+               req->rc = p9_fcall_alloc(alloc_msize);
+       if (!req->tc || !req->rc)
+               goto grow_failed;
+
        p9pdu_reset(req->tc);
        p9pdu_reset(req->rc);
 
        req->tc->tag = tag-1;
        req->status = REQ_STATUS_ALLOC;
 
-       return &c->reqs[row][col];
+       return req;
+
+grow_failed:
+       pr_err("Couldn't grow tag array\n");
+       kfree(req->tc);
+       kfree(req->rc);
+       kfree(req->wq);
+       req->tc = req->rc = NULL;
+       req->wq = NULL;
+       return ERR_PTR(-ENOMEM);
 }
 
 /**
@@ -648,12 +656,20 @@ static int p9_client_flush(struct p9_client *c, struct p9_req_t *oldreq)
                return PTR_ERR(req);
 
 
-       /* if we haven't received a response for oldreq,
-          remove it from the list. */
+       /*
+        * if we haven't received a response for oldreq,
+        * remove it from the list, and notify the transport
+        * layer that the reply will never arrive.
+        */
        spin_lock(&c->lock);
-       if (oldreq->status == REQ_STATUS_FLSH)
+       if (oldreq->status == REQ_STATUS_FLSH) {
                list_del(&oldreq->req_list);
-       spin_unlock(&c->lock);
+               spin_unlock(&c->lock);
+               if (c->trans_mod->cancelled)
+                       c->trans_mod->cancelled(c, req);
+       } else {
+               spin_unlock(&c->lock);
+       }
 
        p9_free_req(c, req);
        return 0;
index de8df95..2ee3879 100644 (file)
  */
 void p9_release_pages(struct page **pages, int nr_pages)
 {
-       int i = 0;
-       while (pages[i] && nr_pages--) {
-               put_page(pages[i]);
-               i++;
-       }
+       int i;
+
+       for (i = 0; i < nr_pages; i++)
+               if (pages[i])
+                       put_page(pages[i]);
 }
 EXPORT_SYMBOL(p9_release_pages);
 
index 02efb25..3ffda1b 100644 (file)
@@ -63,6 +63,7 @@ struct p9_fd_opts {
        int rfd;
        int wfd;
        u16 port;
+       int privport;
 };
 
 /**
@@ -87,12 +88,15 @@ struct p9_trans_fd {
 enum {
        /* Options that take integer arguments */
        Opt_port, Opt_rfdno, Opt_wfdno, Opt_err,
+       /* Options that take no arguments */
+       Opt_privport,
 };
 
 static const match_table_t tokens = {
        {Opt_port, "port=%u"},
        {Opt_rfdno, "rfdno=%u"},
        {Opt_wfdno, "wfdno=%u"},
+       {Opt_privport, "privport"},
        {Opt_err, NULL},
 };
 
@@ -161,6 +165,9 @@ static DEFINE_SPINLOCK(p9_poll_lock);
 static LIST_HEAD(p9_poll_pending_list);
 static DECLARE_WORK(p9_poll_work, p9_poll_workfn);
 
+static unsigned int p9_ipport_resv_min = P9_DEF_MIN_RESVPORT;
+static unsigned int p9_ipport_resv_max = P9_DEF_MAX_RESVPORT;
+
 static void p9_mux_poll_stop(struct p9_conn *m)
 {
        unsigned long flags;
@@ -741,7 +748,7 @@ static int parse_opts(char *params, struct p9_fd_opts *opts)
                if (!*p)
                        continue;
                token = match_token(p, tokens, args);
-               if (token != Opt_err) {
+               if ((token != Opt_err) && (token != Opt_privport)) {
                        r = match_int(&args[0], &option);
                        if (r < 0) {
                                p9_debug(P9_DEBUG_ERROR,
@@ -759,6 +766,9 @@ static int parse_opts(char *params, struct p9_fd_opts *opts)
                case Opt_wfdno:
                        opts->wfd = option;
                        break;
+               case Opt_privport:
+                       opts->privport = 1;
+                       break;
                default:
                        continue;
                }
@@ -898,6 +908,24 @@ static inline int valid_ipaddr4(const char *buf)
        return 0;
 }
 
+static int p9_bind_privport(struct socket *sock)
+{
+       struct sockaddr_in cl;
+       int port, err = -EINVAL;
+
+       memset(&cl, 0, sizeof(cl));
+       cl.sin_family = AF_INET;
+       cl.sin_addr.s_addr = INADDR_ANY;
+       for (port = p9_ipport_resv_max; port >= p9_ipport_resv_min; port--) {
+               cl.sin_port = htons((ushort)port);
+               err = kernel_bind(sock, (struct sockaddr *)&cl, sizeof(cl));
+               if (err != -EADDRINUSE)
+                       break;
+       }
+       return err;
+}
+
+
 static int
 p9_fd_create_tcp(struct p9_client *client, const char *addr, char *args)
 {
@@ -926,6 +954,16 @@ p9_fd_create_tcp(struct p9_client *client, const char *addr, char *args)
                return err;
        }
 
+       if (opts.privport) {
+               err = p9_bind_privport(csocket);
+               if (err < 0) {
+                       pr_err("%s (%d): problem binding to privport\n",
+                              __func__, task_pid_nr(current));
+                       sock_release(csocket);
+                       return err;
+               }
+       }
+
        err = csocket->ops->connect(csocket,
                                    (struct sockaddr *)&sin_server,
                                    sizeof(struct sockaddr_in), 0);
index 2c69ddd..928f2bb 100644 (file)
@@ -57,9 +57,7 @@
 #define P9_RDMA_IRD            0
 #define P9_RDMA_ORD            0
 #define P9_RDMA_TIMEOUT                30000           /* 30 seconds */
-#define P9_RDMA_MAXSIZE                (4*4096)        /* Min SGE is 4, so we can
-                                                * safely advertise a maxsize
-                                                * of 64k */
+#define P9_RDMA_MAXSIZE                (1024*1024)     /* 1MB */
 
 /**
  * struct p9_trans_rdma - RDMA transport instance
@@ -75,7 +73,9 @@
  * @sq_depth: The depth of the Send Queue
  * @sq_sem: Semaphore for the SQ
  * @rq_depth: The depth of the Receive Queue.
- * @rq_count: Count of requests in the Receive Queue.
+ * @rq_sem: Semaphore for the RQ
+ * @excess_rc : Amount of posted Receive Contexts without a pending request.
+ *             See rdma_request()
  * @addr: The remote peer's address
  * @req_lock: Protects the active request list
  * @cm_done: Completion event for connection management tracking
@@ -100,7 +100,8 @@ struct p9_trans_rdma {
        int sq_depth;
        struct semaphore sq_sem;
        int rq_depth;
-       atomic_t rq_count;
+       struct semaphore rq_sem;
+       atomic_t excess_rc;
        struct sockaddr_in addr;
        spinlock_t req_lock;
 
@@ -296,6 +297,13 @@ handle_recv(struct p9_client *client, struct p9_trans_rdma *rdma,
        if (!req)
                goto err_out;
 
+       /* Check that we have not yet received a reply for this request.
+        */
+       if (unlikely(req->rc)) {
+               pr_err("Duplicate reply for request %d", tag);
+               goto err_out;
+       }
+
        req->rc = c->rc;
        req->status = REQ_STATUS_RCVD;
        p9_client_cb(client, req);
@@ -336,8 +344,8 @@ static void cq_comp_handler(struct ib_cq *cq, void *cq_context)
 
                switch (c->wc_op) {
                case IB_WC_RECV:
-                       atomic_dec(&rdma->rq_count);
                        handle_recv(client, rdma, c, wc.status, wc.byte_len);
+                       up(&rdma->rq_sem);
                        break;
 
                case IB_WC_SEND:
@@ -421,32 +429,33 @@ static int rdma_request(struct p9_client *client, struct p9_req_t *req)
        struct p9_rdma_context *c = NULL;
        struct p9_rdma_context *rpl_context = NULL;
 
+       /* When an error occurs between posting the recv and the send,
+        * there will be a receive context posted without a pending request.
+        * Since there is no way to "un-post" it, we remember it and skip
+        * post_recv() for the next request.
+        * So here,
+        * see if we are this `next request' and need to absorb an excess rc.
+        * If yes, then drop and free our own, and do not recv_post().
+        **/
+       if (unlikely(atomic_read(&rdma->excess_rc) > 0)) {
+               if ((atomic_sub_return(1, &rdma->excess_rc) >= 0)) {
+                       /* Got one ! */
+                       kfree(req->rc);
+                       req->rc = NULL;
+                       goto dont_need_post_recv;
+               } else {
+                       /* We raced and lost. */
+                       atomic_inc(&rdma->excess_rc);
+               }
+       }
+
        /* Allocate an fcall for the reply */
        rpl_context = kmalloc(sizeof *rpl_context, GFP_NOFS);
        if (!rpl_context) {
                err = -ENOMEM;
-               goto err_close;
-       }
-
-       /*
-        * If the request has a buffer, steal it, otherwise
-        * allocate a new one.  Typically, requests should already
-        * have receive buffers allocated and just swap them around
-        */
-       if (!req->rc) {
-               req->rc = kmalloc(sizeof(struct p9_fcall)+client->msize,
-                                 GFP_NOFS);
-               if (req->rc) {
-                       req->rc->sdata = (char *) req->rc +
-                                               sizeof(struct p9_fcall);
-                       req->rc->capacity = client->msize;
-               }
+               goto recv_error;
        }
        rpl_context->rc = req->rc;
-       if (!rpl_context->rc) {
-               err = -ENOMEM;
-               goto err_free2;
-       }
 
        /*
         * Post a receive buffer for this request. We need to ensure
@@ -455,29 +464,35 @@ static int rdma_request(struct p9_client *client, struct p9_req_t *req)
         * outstanding request, so we must keep a count to avoid
         * overflowing the RQ.
         */
-       if (atomic_inc_return(&rdma->rq_count) <= rdma->rq_depth) {
-               err = post_recv(client, rpl_context);
-               if (err)
-                       goto err_free1;
-       } else
-               atomic_dec(&rdma->rq_count);
+       if (down_interruptible(&rdma->rq_sem)) {
+               err = -EINTR;
+               goto recv_error;
+       }
 
+       err = post_recv(client, rpl_context);
+       if (err) {
+               p9_debug(P9_DEBUG_FCALL, "POST RECV failed\n");
+               goto recv_error;
+       }
        /* remove posted receive buffer from request structure */
        req->rc = NULL;
 
+dont_need_post_recv:
        /* Post the request */
        c = kmalloc(sizeof *c, GFP_NOFS);
        if (!c) {
                err = -ENOMEM;
-               goto err_free1;
+               goto send_error;
        }
        c->req = req;
 
        c->busa = ib_dma_map_single(rdma->cm_id->device,
                                    c->req->tc->sdata, c->req->tc->size,
                                    DMA_TO_DEVICE);
-       if (ib_dma_mapping_error(rdma->cm_id->device, c->busa))
-               goto error;
+       if (ib_dma_mapping_error(rdma->cm_id->device, c->busa)) {
+               err = -EIO;
+               goto send_error;
+       }
 
        sge.addr = c->busa;
        sge.length = c->req->tc->size;
@@ -491,22 +506,32 @@ static int rdma_request(struct p9_client *client, struct p9_req_t *req)
        wr.sg_list = &sge;
        wr.num_sge = 1;
 
-       if (down_interruptible(&rdma->sq_sem))
-               goto error;
+       if (down_interruptible(&rdma->sq_sem)) {
+               err = -EINTR;
+               goto send_error;
+       }
 
-       return ib_post_send(rdma->qp, &wr, &bad_wr);
+       err = ib_post_send(rdma->qp, &wr, &bad_wr);
+       if (err)
+               goto send_error;
 
- error:
+       /* Success */
+       return 0;
+
+ /* Handle errors that happened during or while preparing the send: */
+ send_error:
        kfree(c);
-       kfree(rpl_context->rc);
-       kfree(rpl_context);
-       p9_debug(P9_DEBUG_ERROR, "EIO\n");
-       return -EIO;
- err_free1:
-       kfree(rpl_context->rc);
- err_free2:
+       p9_debug(P9_DEBUG_ERROR, "Error %d in rdma_request()\n", err);
+
+       /* Ach.
+        *  We did recv_post(), but not send. We have one recv_post in excess.
+        */
+       atomic_inc(&rdma->excess_rc);
+       return err;
+
+ /* Handle errors that happened during or while preparing post_recv(): */
+ recv_error:
        kfree(rpl_context);
- err_close:
        spin_lock_irqsave(&rdma->req_lock, flags);
        if (rdma->state < P9_RDMA_CLOSING) {
                rdma->state = P9_RDMA_CLOSING;
@@ -551,7 +576,8 @@ static struct p9_trans_rdma *alloc_rdma(struct p9_rdma_opts *opts)
        spin_lock_init(&rdma->req_lock);
        init_completion(&rdma->cm_done);
        sema_init(&rdma->sq_sem, rdma->sq_depth);
-       atomic_set(&rdma->rq_count, 0);
+       sema_init(&rdma->rq_sem, rdma->rq_depth);
+       atomic_set(&rdma->excess_rc, 0);
 
        return rdma;
 }
@@ -562,6 +588,17 @@ static int rdma_cancel(struct p9_client *client, struct p9_req_t *req)
        return 1;
 }
 
+/* A request has been fully flushed without a reply.
+ * That means we have posted one buffer in excess.
+ */
+static int rdma_cancelled(struct p9_client *client, struct p9_req_t *req)
+{
+       struct p9_trans_rdma *rdma = client->trans;
+
+       atomic_inc(&rdma->excess_rc);
+       return 0;
+}
+
 /**
  * trans_create_rdma - Transport method for creating atransport instance
  * @client: client instance
index 6e9ab31..8ab48cd 100644 (file)
@@ -56,7 +56,7 @@
 #include <net/sock.h>
 #include <net/tcp_states.h>
 #include <trace/events/skb.h>
-#include <net/ll_poll.h>
+#include <net/busy_poll.h>
 
 /*
  *     Is a socket 'connection oriented' ?
index 6a93cd8..be35636 100644 (file)
@@ -2447,10 +2447,10 @@ static int dev_gso_segment(struct sk_buff *skb, netdev_features_t features)
 }
 
 static netdev_features_t harmonize_features(struct sk_buff *skb,
-       __be16 protocol, netdev_features_t features)
+       netdev_features_t features)
 {
        if (skb->ip_summed != CHECKSUM_NONE &&
-           !can_checksum_protocol(features, protocol)) {
+           !can_checksum_protocol(features, skb_network_protocol(skb))) {
                features &= ~NETIF_F_ALL_CSUM;
        } else if (illegal_highdma(skb->dev, skb)) {
                features &= ~NETIF_F_SG;
@@ -2471,20 +2471,18 @@ netdev_features_t netif_skb_features(struct sk_buff *skb)
                struct vlan_ethhdr *veh = (struct vlan_ethhdr *)skb->data;
                protocol = veh->h_vlan_encapsulated_proto;
        } else if (!vlan_tx_tag_present(skb)) {
-               return harmonize_features(skb, protocol, features);
+               return harmonize_features(skb, features);
        }
 
        features &= (skb->dev->vlan_features | NETIF_F_HW_VLAN_CTAG_TX |
                                               NETIF_F_HW_VLAN_STAG_TX);
 
-       if (protocol != htons(ETH_P_8021Q) && protocol != htons(ETH_P_8021AD)) {
-               return harmonize_features(skb, protocol, features);
-       } else {
+       if (protocol == htons(ETH_P_8021Q) || protocol == htons(ETH_P_8021AD))
                features &= NETIF_F_SG | NETIF_F_HIGHDMA | NETIF_F_FRAGLIST |
                                NETIF_F_GEN_CSUM | NETIF_F_HW_VLAN_CTAG_TX |
                                NETIF_F_HW_VLAN_STAG_TX;
-               return harmonize_features(skb, protocol, features);
-       }
+
+       return harmonize_features(skb, features);
 }
 EXPORT_SYMBOL(netif_skb_features);
 
index ee08e63..d11d2b1 100644 (file)
@@ -820,7 +820,7 @@ int skb_copy_ubufs(struct sk_buff *skb, gfp_t gfp_mask)
                page = alloc_page(gfp_mask);
                if (!page) {
                        while (head) {
-                               struct page *next = (struct page *)head->private;
+                               struct page *next = (struct page *)page_private(head);
                                put_page(head);
                                head = next;
                        }
@@ -830,7 +830,7 @@ int skb_copy_ubufs(struct sk_buff *skb, gfp_t gfp_mask)
                memcpy(page_address(page),
                       vaddr + f->page_offset, skb_frag_size(f));
                kunmap_atomic(vaddr);
-               page->private = (unsigned long)head;
+               set_page_private(page, (unsigned long)head);
                head = page;
        }
 
@@ -844,7 +844,7 @@ int skb_copy_ubufs(struct sk_buff *skb, gfp_t gfp_mask)
        for (i = num_frags - 1; i >= 0; i--) {
                __skb_fill_page_desc(skb, i, head, 0,
                                     skb_shinfo(skb)->frags[i].size);
-               head = (struct page *)head->private;
+               head = (struct page *)page_private(head);
        }
 
        skb_shinfo(skb)->tx_flags &= ~SKBTX_DEV_ZEROCOPY;
index b6c619f..d1e14b0 100644 (file)
 #include <net/tcp.h>
 #endif
 
-#include <net/ll_poll.h>
+#include <net/busy_poll.h>
 
 static DEFINE_MUTEX(proto_list_mutex);
 static LIST_HEAD(proto_list);
@@ -914,7 +914,7 @@ set_rcvbuf:
                break;
 
 #ifdef CONFIG_NET_LL_RX_POLL
-       case SO_LL:
+       case SO_BUSY_POLL:
                /* allow unprivileged users to decrease the value */
                if ((val > sk->sk_ll_usec) && !capable(CAP_NET_ADMIN))
                        ret = -EPERM;
@@ -1184,7 +1184,7 @@ int sock_getsockopt(struct socket *sock, int level, int optname,
                break;
 
 #ifdef CONFIG_NET_LL_RX_POLL
-       case SO_LL:
+       case SO_BUSY_POLL:
                v.val = sk->sk_ll_usec;
                break;
 #endif
@@ -2307,7 +2307,7 @@ void sock_init_data(struct socket *sock, struct sock *sk)
 
 #ifdef CONFIG_NET_LL_RX_POLL
        sk->sk_napi_id          =       0;
-       sk->sk_ll_usec          =       sysctl_net_ll_read;
+       sk->sk_ll_usec          =       sysctl_net_busy_read;
 #endif
 
        /*
index afc677e..6609686 100644 (file)
@@ -19,7 +19,7 @@
 #include <net/ip.h>
 #include <net/sock.h>
 #include <net/net_ratelimit.h>
-#include <net/ll_poll.h>
+#include <net/busy_poll.h>
 
 static int one = 1;
 
@@ -300,15 +300,15 @@ static struct ctl_table net_core_table[] = {
 #endif /* CONFIG_NET_FLOW_LIMIT */
 #ifdef CONFIG_NET_LL_RX_POLL
        {
-               .procname       = "low_latency_poll",
-               .data           = &sysctl_net_ll_poll,
+               .procname       = "busy_poll",
+               .data           = &sysctl_net_busy_poll,
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec
        },
        {
-               .procname       = "low_latency_read",
-               .data           = &sysctl_net_ll_read,
+               .procname       = "busy_read",
+               .data           = &sysctl_net_busy_read,
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec
index 0a69d07..f347a2c 100644 (file)
@@ -118,7 +118,7 @@ dns_resolver_instantiate(struct key *key, struct key_preparsed_payload *prep)
                                if (opt_vlen <= 0)
                                        goto bad_option_value;
 
-                               ret = strict_strtoul(eq, 10, &derrno);
+                               ret = kstrtoul(eq, 10, &derrno);
                                if (ret < 0)
                                        goto bad_option_value;
 
index 775d5b5..55e6bfb 100644 (file)
@@ -100,6 +100,9 @@ static struct sk_buff *gre_gso_segment(struct sk_buff *skb,
                }
                __skb_push(skb, tnl_hlen - ghl);
 
+               skb_reset_inner_headers(skb);
+               skb->encapsulation = 1;
+
                skb_reset_mac_header(skb);
                skb_set_network_header(skb, mac_len);
                skb->mac_len = mac_len;
index 6af375a..7bd8983 100644 (file)
@@ -467,7 +467,7 @@ void inet_unhash(struct sock *sk)
                lock = inet_ehash_lockp(hashinfo, sk->sk_hash);
 
        spin_lock_bh(lock);
-       done =__sk_nulls_del_node_init_rcu(sk);
+       done = __sk_nulls_del_node_init_rcu(sk);
        if (done)
                sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1);
        spin_unlock_bh(lock);
index 945734b..ca1cb2d 100644 (file)
@@ -476,7 +476,7 @@ static int tnl_update_pmtu(struct net_device *dev, struct sk_buff *skb,
                            struct rtable *rt, __be16 df)
 {
        struct ip_tunnel *tunnel = netdev_priv(dev);
-       int pkt_size = skb->len - tunnel->hlen;
+       int pkt_size = skb->len - tunnel->hlen - dev->hard_header_len;
        int mtu;
 
        if (df)
index 15cbfa9..5423223 100644 (file)
 
 #include <asm/uaccess.h>
 #include <asm/ioctls.h>
-#include <net/ll_poll.h>
+#include <net/busy_poll.h>
 
 int sysctl_tcp_fin_timeout __read_mostly = TCP_FIN_TIMEOUT;
 
index 1063bb8..ddf351e 100644 (file)
@@ -75,7 +75,7 @@
 #include <net/netdma.h>
 #include <net/secure_seq.h>
 #include <net/tcp_memcontrol.h>
-#include <net/ll_poll.h>
+#include <net/busy_poll.h>
 
 #include <linux/inet.h>
 #include <linux/ipv6.h>
@@ -1994,7 +1994,7 @@ process:
        if (sk_filter(sk, skb))
                goto discard_and_relse;
 
-       sk_mark_ll(sk, skb);
+       sk_mark_napi_id(sk, skb);
        skb->dev = NULL;
 
        bh_lock_sock_nested(sk);
index 3d60949..92fde8d 100644 (file)
@@ -2407,6 +2407,8 @@ int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb)
                 * see tcp_input.c tcp_sacktag_write_queue().
                 */
                TCP_SKB_CB(skb)->ack_seq = tp->snd_nxt;
+       } else {
+               NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPRETRANSFAIL);
        }
        return err;
 }
@@ -2528,10 +2530,9 @@ begin_fwd:
                if (sacked & (TCPCB_SACKED_ACKED|TCPCB_SACKED_RETRANS))
                        continue;
 
-               if (tcp_retransmit_skb(sk, skb)) {
-                       NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPRETRANSFAIL);
+               if (tcp_retransmit_skb(sk, skb))
                        return;
-               }
+
                NET_INC_STATS_BH(sock_net(sk), mib_idx);
 
                if (tcp_in_cwnd_reduction(sk))
index 6b270e5..766e6ba 100644 (file)
 #include <trace/events/udp.h>
 #include <linux/static_key.h>
 #include <trace/events/skb.h>
-#include <net/ll_poll.h>
+#include <net/busy_poll.h>
 #include "udp_impl.h"
 
 struct udp_table udp_table __read_mostly;
@@ -1713,7 +1713,7 @@ int __udp4_lib_rcv(struct sk_buff *skb, struct udp_table *udptable,
        if (sk != NULL) {
                int ret;
 
-               sk_mark_ll(sk, skb);
+               sk_mark_napi_id(sk, skb);
                ret = udp_queue_rcv_skb(sk, skb);
                sock_put(sk);
 
@@ -2323,6 +2323,9 @@ struct sk_buff *skb_udp_tunnel_segment(struct sk_buff *skb,
                struct udphdr *uh;
                int udp_offset = outer_hlen - tnl_hlen;
 
+               skb_reset_inner_headers(skb);
+               skb->encapsulation = 1;
+
                skb->mac_len = mac_len;
 
                skb_push(skb, outer_hlen);
@@ -2345,7 +2348,6 @@ struct sk_buff *skb_udp_tunnel_segment(struct sk_buff *skb,
                                uh->check = CSUM_MANGLED_0;
 
                }
-               skb->ip_summed = CHECKSUM_NONE;
                skb->protocol = protocol;
        } while ((skb = skb->next));
 out:
index 192dd1a..5fc9c7a 100644 (file)
@@ -632,6 +632,12 @@ insert_above:
        return ln;
 }
 
+static inline bool rt6_qualify_for_ecmp(struct rt6_info *rt)
+{
+       return (rt->rt6i_flags & (RTF_GATEWAY|RTF_ADDRCONF|RTF_DYNAMIC)) ==
+              RTF_GATEWAY;
+}
+
 /*
  *     Insert routing information in a node.
  */
@@ -646,6 +652,7 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt,
        int add = (!info->nlh ||
                   (info->nlh->nlmsg_flags & NLM_F_CREATE));
        int found = 0;
+       bool rt_can_ecmp = rt6_qualify_for_ecmp(rt);
 
        ins = &fn->leaf;
 
@@ -691,9 +698,8 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt,
                         * To avoid long list, we only had siblings if the
                         * route have a gateway.
                         */
-                       if (rt->rt6i_flags & RTF_GATEWAY &&
-                           !(rt->rt6i_flags & RTF_EXPIRES) &&
-                           !(iter->rt6i_flags & RTF_EXPIRES))
+                       if (rt_can_ecmp &&
+                           rt6_qualify_for_ecmp(iter))
                                rt->rt6i_nsiblings++;
                }
 
@@ -715,7 +721,8 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt,
                /* Find the first route that have the same metric */
                sibling = fn->leaf;
                while (sibling) {
-                       if (sibling->rt6i_metric == rt->rt6i_metric) {
+                       if (sibling->rt6i_metric == rt->rt6i_metric &&
+                           rt6_qualify_for_ecmp(sibling)) {
                                list_add_tail(&rt->rt6i_siblings,
                                              &sibling->rt6i_siblings);
                                break;
index bd5fd70..a8c891a 100644 (file)
 #include <linux/sysctl.h>
 #endif
 
+enum rt6_nud_state {
+       RT6_NUD_FAIL_HARD = -2,
+       RT6_NUD_FAIL_SOFT = -1,
+       RT6_NUD_SUCCEED = 1
+};
+
 static struct rt6_info *ip6_rt_copy(struct rt6_info *ort,
                                    const struct in6_addr *dest);
 static struct dst_entry        *ip6_dst_check(struct dst_entry *dst, u32 cookie);
@@ -531,28 +537,29 @@ static inline int rt6_check_dev(struct rt6_info *rt, int oif)
        return 0;
 }
 
-static inline bool rt6_check_neigh(struct rt6_info *rt)
+static inline enum rt6_nud_state rt6_check_neigh(struct rt6_info *rt)
 {
        struct neighbour *neigh;
-       bool ret = false;
+       enum rt6_nud_state ret = RT6_NUD_FAIL_HARD;
 
        if (rt->rt6i_flags & RTF_NONEXTHOP ||
            !(rt->rt6i_flags & RTF_GATEWAY))
-               return true;
+               return RT6_NUD_SUCCEED;
 
        rcu_read_lock_bh();
        neigh = __ipv6_neigh_lookup_noref(rt->dst.dev, &rt->rt6i_gateway);
        if (neigh) {
                read_lock(&neigh->lock);
                if (neigh->nud_state & NUD_VALID)
-                       ret = true;
+                       ret = RT6_NUD_SUCCEED;
 #ifdef CONFIG_IPV6_ROUTER_PREF
                else if (!(neigh->nud_state & NUD_FAILED))
-                       ret = true;
+                       ret = RT6_NUD_SUCCEED;
 #endif
                read_unlock(&neigh->lock);
-       } else if (IS_ENABLED(CONFIG_IPV6_ROUTER_PREF)) {
-               ret = true;
+       } else {
+               ret = IS_ENABLED(CONFIG_IPV6_ROUTER_PREF) ?
+                     RT6_NUD_SUCCEED : RT6_NUD_FAIL_SOFT;
        }
        rcu_read_unlock_bh();
 
@@ -566,43 +573,52 @@ static int rt6_score_route(struct rt6_info *rt, int oif,
 
        m = rt6_check_dev(rt, oif);
        if (!m && (strict & RT6_LOOKUP_F_IFACE))
-               return -1;
+               return RT6_NUD_FAIL_HARD;
 #ifdef CONFIG_IPV6_ROUTER_PREF
        m |= IPV6_DECODE_PREF(IPV6_EXTRACT_PREF(rt->rt6i_flags)) << 2;
 #endif
-       if (!rt6_check_neigh(rt) && (strict & RT6_LOOKUP_F_REACHABLE))
-               return -1;
+       if (strict & RT6_LOOKUP_F_REACHABLE) {
+               int n = rt6_check_neigh(rt);
+               if (n < 0)
+                       return n;
+       }
        return m;
 }
 
 static struct rt6_info *find_match(struct rt6_info *rt, int oif, int strict,
-                                  int *mpri, struct rt6_info *match)
+                                  int *mpri, struct rt6_info *match,
+                                  bool *do_rr)
 {
        int m;
+       bool match_do_rr = false;
 
        if (rt6_check_expired(rt))
                goto out;
 
        m = rt6_score_route(rt, oif, strict);
-       if (m < 0)
+       if (m == RT6_NUD_FAIL_SOFT && !IS_ENABLED(CONFIG_IPV6_ROUTER_PREF)) {
+               match_do_rr = true;
+               m = 0; /* lowest valid score */
+       } else if (m < 0) {
                goto out;
+       }
+
+       if (strict & RT6_LOOKUP_F_REACHABLE)
+               rt6_probe(rt);
 
        if (m > *mpri) {
-               if (strict & RT6_LOOKUP_F_REACHABLE)
-                       rt6_probe(match);
+               *do_rr = match_do_rr;
                *mpri = m;
                match = rt;
-       } else if (strict & RT6_LOOKUP_F_REACHABLE) {
-               rt6_probe(rt);
        }
-
 out:
        return match;
 }
 
 static struct rt6_info *find_rr_leaf(struct fib6_node *fn,
                                     struct rt6_info *rr_head,
-                                    u32 metric, int oif, int strict)
+                                    u32 metric, int oif, int strict,
+                                    bool *do_rr)
 {
        struct rt6_info *rt, *match;
        int mpri = -1;
@@ -610,10 +626,10 @@ static struct rt6_info *find_rr_leaf(struct fib6_node *fn,
        match = NULL;
        for (rt = rr_head; rt && rt->rt6i_metric == metric;
             rt = rt->dst.rt6_next)
-               match = find_match(rt, oif, strict, &mpri, match);
+               match = find_match(rt, oif, strict, &mpri, match, do_rr);
        for (rt = fn->leaf; rt && rt != rr_head && rt->rt6i_metric == metric;
             rt = rt->dst.rt6_next)
-               match = find_match(rt, oif, strict, &mpri, match);
+               match = find_match(rt, oif, strict, &mpri, match, do_rr);
 
        return match;
 }
@@ -622,15 +638,16 @@ static struct rt6_info *rt6_select(struct fib6_node *fn, int oif, int strict)
 {
        struct rt6_info *match, *rt0;
        struct net *net;
+       bool do_rr = false;
 
        rt0 = fn->rr_ptr;
        if (!rt0)
                fn->rr_ptr = rt0 = fn->leaf;
 
-       match = find_rr_leaf(fn, rt0, rt0->rt6i_metric, oif, strict);
+       match = find_rr_leaf(fn, rt0, rt0->rt6i_metric, oif, strict,
+                            &do_rr);
 
-       if (!match &&
-           (strict & RT6_LOOKUP_F_REACHABLE)) {
+       if (do_rr) {
                struct rt6_info *next = rt0->dst.rt6_next;
 
                /* no entries matched; do round-robin */
@@ -1080,10 +1097,13 @@ static void ip6_link_failure(struct sk_buff *skb)
 
        rt = (struct rt6_info *) skb_dst(skb);
        if (rt) {
-               if (rt->rt6i_flags & RTF_CACHE)
-                       rt6_update_expires(rt, 0);
-               else if (rt->rt6i_node && (rt->rt6i_flags & RTF_DEFAULT))
+               if (rt->rt6i_flags & RTF_CACHE) {
+                       dst_hold(&rt->dst);
+                       if (ip6_del_rt(rt))
+                               dst_free(&rt->dst);
+               } else if (rt->rt6i_node && (rt->rt6i_flags & RTF_DEFAULT)) {
                        rt->rt6i_node->fn_sernum = -1;
+               }
        }
 }
 
index 5cffa5c..6e1649d 100644 (file)
@@ -63,7 +63,7 @@
 #include <net/inet_common.h>
 #include <net/secure_seq.h>
 #include <net/tcp_memcontrol.h>
-#include <net/ll_poll.h>
+#include <net/busy_poll.h>
 
 #include <asm/uaccess.h>
 
@@ -1499,7 +1499,7 @@ process:
        if (sk_filter(sk, skb))
                goto discard_and_relse;
 
-       sk_mark_ll(sk, skb);
+       sk_mark_napi_id(sk, skb);
        skb->dev = NULL;
 
        bh_lock_sock_nested(sk);
index b6f3143..f405815 100644 (file)
@@ -46,7 +46,7 @@
 #include <net/ip6_checksum.h>
 #include <net/xfrm.h>
 #include <net/inet6_hashtables.h>
-#include <net/ll_poll.h>
+#include <net/busy_poll.h>
 
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
@@ -844,7 +844,7 @@ int __udp6_lib_rcv(struct sk_buff *skb, struct udp_table *udptable,
        if (sk != NULL) {
                int ret;
 
-               sk_mark_ll(sk, skb);
+               sk_mark_napi_id(sk, skb);
                ret = udpv6_queue_rcv_skb(sk, skb);
                sock_put(sk);
 
index 7c195d9..a7ab323 100644 (file)
@@ -821,7 +821,14 @@ static void qfq_make_eligible(struct qfq_sched *q)
        unsigned long old_vslot = q->oldV >> q->min_slot_shift;
 
        if (vslot != old_vslot) {
-               unsigned long mask = (1ULL << fls(vslot ^ old_vslot)) - 1;
+               unsigned long mask;
+               int last_flip_pos = fls(vslot ^ old_vslot);
+
+               if (last_flip_pos > 31) /* higher than the number of groups */
+                       mask = ~0UL;    /* make all groups eligible */
+               else
+                       mask = (1UL << last_flip_pos) - 1;
+
                qfq_move_groups(q, mask, IR, ER);
                qfq_move_groups(q, mask, IB, EB);
        }
@@ -1003,9 +1010,61 @@ static inline void charge_actual_service(struct qfq_aggregate *agg)
        agg->F = agg->S + (u64)service_received * agg->inv_w;
 }
 
-static inline void qfq_update_agg_ts(struct qfq_sched *q,
-                                    struct qfq_aggregate *agg,
-                                    enum update_reason reason);
+/* Assign a reasonable start time for a new aggregate in group i.
+ * Admissible values for \hat(F) are multiples of \sigma_i
+ * no greater than V+\sigma_i . Larger values mean that
+ * we had a wraparound so we consider the timestamp to be stale.
+ *
+ * If F is not stale and F >= V then we set S = F.
+ * Otherwise we should assign S = V, but this may violate
+ * the ordering in EB (see [2]). So, if we have groups in ER,
+ * set S to the F_j of the first group j which would be blocking us.
+ * We are guaranteed not to move S backward because
+ * otherwise our group i would still be blocked.
+ */
+static void qfq_update_start(struct qfq_sched *q, struct qfq_aggregate *agg)
+{
+       unsigned long mask;
+       u64 limit, roundedF;
+       int slot_shift = agg->grp->slot_shift;
+
+       roundedF = qfq_round_down(agg->F, slot_shift);
+       limit = qfq_round_down(q->V, slot_shift) + (1ULL << slot_shift);
+
+       if (!qfq_gt(agg->F, q->V) || qfq_gt(roundedF, limit)) {
+               /* timestamp was stale */
+               mask = mask_from(q->bitmaps[ER], agg->grp->index);
+               if (mask) {
+                       struct qfq_group *next = qfq_ffs(q, mask);
+                       if (qfq_gt(roundedF, next->F)) {
+                               if (qfq_gt(limit, next->F))
+                                       agg->S = next->F;
+                               else /* preserve timestamp correctness */
+                                       agg->S = limit;
+                               return;
+                       }
+               }
+               agg->S = q->V;
+       } else  /* timestamp is not stale */
+               agg->S = agg->F;
+}
+
+/* Update the timestamps of agg before scheduling/rescheduling it for
+ * service.  In particular, assign to agg->F its maximum possible
+ * value, i.e., the virtual finish time with which the aggregate
+ * should be labeled if it used all its budget once in service.
+ */
+static inline void
+qfq_update_agg_ts(struct qfq_sched *q,
+                   struct qfq_aggregate *agg, enum update_reason reason)
+{
+       if (reason != requeue)
+               qfq_update_start(q, agg);
+       else /* just charge agg for the service received */
+               agg->S = agg->F;
+
+       agg->F = agg->S + (u64)agg->budgetmax * agg->inv_w;
+}
 
 static void qfq_schedule_agg(struct qfq_sched *q, struct qfq_aggregate *agg);
 
@@ -1128,66 +1187,6 @@ static struct qfq_aggregate *qfq_choose_next_agg(struct qfq_sched *q)
        return agg;
 }
 
-/*
- * Assign a reasonable start time for a new aggregate in group i.
- * Admissible values for \hat(F) are multiples of \sigma_i
- * no greater than V+\sigma_i . Larger values mean that
- * we had a wraparound so we consider the timestamp to be stale.
- *
- * If F is not stale and F >= V then we set S = F.
- * Otherwise we should assign S = V, but this may violate
- * the ordering in EB (see [2]). So, if we have groups in ER,
- * set S to the F_j of the first group j which would be blocking us.
- * We are guaranteed not to move S backward because
- * otherwise our group i would still be blocked.
- */
-static void qfq_update_start(struct qfq_sched *q, struct qfq_aggregate *agg)
-{
-       unsigned long mask;
-       u64 limit, roundedF;
-       int slot_shift = agg->grp->slot_shift;
-
-       roundedF = qfq_round_down(agg->F, slot_shift);
-       limit = qfq_round_down(q->V, slot_shift) + (1ULL << slot_shift);
-
-       if (!qfq_gt(agg->F, q->V) || qfq_gt(roundedF, limit)) {
-               /* timestamp was stale */
-               mask = mask_from(q->bitmaps[ER], agg->grp->index);
-               if (mask) {
-                       struct qfq_group *next = qfq_ffs(q, mask);
-                       if (qfq_gt(roundedF, next->F)) {
-                               if (qfq_gt(limit, next->F))
-                                       agg->S = next->F;
-                               else /* preserve timestamp correctness */
-                                       agg->S = limit;
-                               return;
-                       }
-               }
-               agg->S = q->V;
-       } else  /* timestamp is not stale */
-               agg->S = agg->F;
-}
-
-/*
- * Update the timestamps of agg before scheduling/rescheduling it for
- * service.  In particular, assign to agg->F its maximum possible
- * value, i.e., the virtual finish time with which the aggregate
- * should be labeled if it used all its budget once in service.
- */
-static inline void
-qfq_update_agg_ts(struct qfq_sched *q,
-                   struct qfq_aggregate *agg, enum update_reason reason)
-{
-       if (reason != requeue)
-               qfq_update_start(q, agg);
-       else /* just charge agg for the service received */
-               agg->S = agg->F;
-
-       agg->F = agg->S + (u64)agg->budgetmax * agg->inv_w;
-}
-
-static void qfq_schedule_agg(struct qfq_sched *, struct qfq_aggregate *);
-
 static int qfq_enqueue(struct sk_buff *skb, struct Qdisc *sch)
 {
        struct qfq_sched *q = qdisc_priv(sch);
index 45afa64..829b460 100644 (file)
 #include <linux/route.h>
 #include <linux/sockios.h>
 #include <linux/atalk.h>
-#include <net/ll_poll.h>
+#include <net/busy_poll.h>
 
 #ifdef CONFIG_NET_LL_RX_POLL
-unsigned int sysctl_net_ll_read __read_mostly;
-unsigned int sysctl_net_ll_poll __read_mostly;
+unsigned int sysctl_net_busy_read __read_mostly;
+unsigned int sysctl_net_busy_poll __read_mostly;
 #endif
 
 static int sock_no_open(struct inode *irrelevant, struct file *dontcare);
index defa9d3..27ce262 100644 (file)
@@ -139,11 +139,12 @@ void gss_mech_unregister(struct gss_api_mech *gm)
 }
 EXPORT_SYMBOL_GPL(gss_mech_unregister);
 
-static struct gss_api_mech *gss_mech_get(struct gss_api_mech *gm)
+struct gss_api_mech *gss_mech_get(struct gss_api_mech *gm)
 {
        __module_get(gm->gm_owner);
        return gm;
 }
+EXPORT_SYMBOL(gss_mech_get);
 
 static struct gss_api_mech *
 _gss_mech_get_by_name(const char *name)
@@ -360,6 +361,7 @@ gss_pseudoflavor_to_service(struct gss_api_mech *gm, u32 pseudoflavor)
        }
        return 0;
 }
+EXPORT_SYMBOL(gss_pseudoflavor_to_service);
 
 char *
 gss_service_to_auth_domain_name(struct gss_api_mech *gm, u32 service)
@@ -379,6 +381,7 @@ gss_mech_put(struct gss_api_mech * gm)
        if (gm)
                module_put(gm->gm_owner);
 }
+EXPORT_SYMBOL(gss_mech_put);
 
 /* The mech could probably be determined from the token instead, but it's just
  * as easy for now to pass it in. */
index b05ace4..d0347d1 100644 (file)
@@ -377,8 +377,7 @@ rsc_init(struct cache_head *cnew, struct cache_head *ctmp)
        new->handle.data = tmp->handle.data;
        tmp->handle.data = NULL;
        new->mechctx = NULL;
-       new->cred.cr_group_info = NULL;
-       new->cred.cr_principal = NULL;
+       init_svc_cred(&new->cred);
 }
 
 static void
@@ -392,9 +391,7 @@ update_rsc(struct cache_head *cnew, struct cache_head *ctmp)
        memset(&new->seqdata, 0, sizeof(new->seqdata));
        spin_lock_init(&new->seqdata.sd_lock);
        new->cred = tmp->cred;
-       tmp->cred.cr_group_info = NULL;
-       new->cred.cr_principal = tmp->cred.cr_principal;
-       tmp->cred.cr_principal = NULL;
+       init_svc_cred(&tmp->cred);
 }
 
 static struct cache_head *
@@ -487,7 +484,7 @@ static int rsc_parse(struct cache_detail *cd,
                len = qword_get(&mesg, buf, mlen);
                if (len < 0)
                        goto out;
-               gm = gss_mech_get_by_name(buf);
+               gm = rsci.cred.cr_gss_mech = gss_mech_get_by_name(buf);
                status = -EOPNOTSUPP;
                if (!gm)
                        goto out;
@@ -517,7 +514,6 @@ static int rsc_parse(struct cache_detail *cd,
        rscp = rsc_update(cd, &rsci, rscp);
        status = 0;
 out:
-       gss_mech_put(gm);
        rsc_free(&rsci);
        if (rscp)
                cache_put(&rscp->h, cd);
index 80fe5c8..a72de07 100644 (file)
@@ -50,12 +50,6 @@ static void cache_init(struct cache_head *h)
        h->last_refresh = now;
 }
 
-static inline int cache_is_expired(struct cache_detail *detail, struct cache_head *h)
-{
-       return  (h->expiry_time < seconds_since_boot()) ||
-               (detail->flush_time > h->last_refresh);
-}
-
 struct cache_head *sunrpc_cache_lookup(struct cache_detail *detail,
                                       struct cache_head *key, int hash)
 {
@@ -201,7 +195,7 @@ static int cache_make_upcall(struct cache_detail *cd, struct cache_head *h)
        return sunrpc_cache_pipe_upcall(cd, h);
 }
 
-static inline int cache_is_valid(struct cache_detail *detail, struct cache_head *h)
+static inline int cache_is_valid(struct cache_head *h)
 {
        if (!test_bit(CACHE_VALID, &h->flags))
                return -EAGAIN;
@@ -227,16 +221,15 @@ static int try_to_negate_entry(struct cache_detail *detail, struct cache_head *h
        int rv;
 
        write_lock(&detail->hash_lock);
-       rv = cache_is_valid(detail, h);
-       if (rv != -EAGAIN) {
-               write_unlock(&detail->hash_lock);
-               return rv;
+       rv = cache_is_valid(h);
+       if (rv == -EAGAIN) {
+               set_bit(CACHE_NEGATIVE, &h->flags);
+               cache_fresh_locked(h, seconds_since_boot()+CACHE_NEW_EXPIRY);
+               rv = -ENOENT;
        }
-       set_bit(CACHE_NEGATIVE, &h->flags);
-       cache_fresh_locked(h, seconds_since_boot()+CACHE_NEW_EXPIRY);
        write_unlock(&detail->hash_lock);
        cache_fresh_unlocked(h, detail);
-       return -ENOENT;
+       return rv;
 }
 
 /*
@@ -260,7 +253,7 @@ int cache_check(struct cache_detail *detail,
        long refresh_age, age;
 
        /* First decide return status as best we can */
-       rv = cache_is_valid(detail, h);
+       rv = cache_is_valid(h);
 
        /* now see if we want to start an upcall */
        refresh_age = (h->expiry_time - h->last_refresh);
@@ -269,19 +262,17 @@ int cache_check(struct cache_detail *detail,
        if (rqstp == NULL) {
                if (rv == -EAGAIN)
                        rv = -ENOENT;
-       } else if (rv == -EAGAIN || age > refresh_age/2) {
+       } else if (rv == -EAGAIN ||
+                  (h->expiry_time != 0 && age > refresh_age/2)) {
                dprintk("RPC:       Want update, refage=%ld, age=%ld\n",
                                refresh_age, age);
                if (!test_and_set_bit(CACHE_PENDING, &h->flags)) {
                        switch (cache_make_upcall(detail, h)) {
                        case -EINVAL:
-                               clear_bit(CACHE_PENDING, &h->flags);
-                               cache_revisit_request(h);
                                rv = try_to_negate_entry(detail, h);
                                break;
                        case -EAGAIN:
-                               clear_bit(CACHE_PENDING, &h->flags);
-                               cache_revisit_request(h);
+                               cache_fresh_unlocked(h, detail);
                                break;
                        }
                }
@@ -293,7 +284,7 @@ int cache_check(struct cache_detail *detail,
                         * Request was not deferred; handle it as best
                         * we can ourselves:
                         */
-                       rv = cache_is_valid(detail, h);
+                       rv = cache_is_valid(h);
                        if (rv == -EAGAIN)
                                rv = -ETIMEDOUT;
                }
@@ -310,7 +301,7 @@ EXPORT_SYMBOL_GPL(cache_check);
  * a current pointer into that list and into the table
  * for that entry.
  *
- * Each time clean_cache is called it finds the next non-empty entry
+ * Each time cache_clean is called it finds the next non-empty entry
  * in the current table and walks the list in that entry
  * looking for entries that can be removed.
  *
@@ -457,9 +448,8 @@ static int cache_clean(void)
                        current_index ++;
                spin_unlock(&cache_list_lock);
                if (ch) {
-                       if (test_and_clear_bit(CACHE_PENDING, &ch->flags))
-                               cache_dequeue(current_detail, ch);
-                       cache_revisit_request(ch);
+                       set_bit(CACHE_CLEANED, &ch->flags);
+                       cache_fresh_unlocked(ch, d);
                        cache_put(ch, d);
                }
        } else
@@ -1036,23 +1026,32 @@ static int cache_release(struct inode *inode, struct file *filp,
 
 static void cache_dequeue(struct cache_detail *detail, struct cache_head *ch)
 {
-       struct cache_queue *cq;
+       struct cache_queue *cq, *tmp;
+       struct cache_request *cr;
+       struct list_head dequeued;
+
+       INIT_LIST_HEAD(&dequeued);
        spin_lock(&queue_lock);
-       list_for_each_entry(cq, &detail->queue, list)
+       list_for_each_entry_safe(cq, tmp, &detail->queue, list)
                if (!cq->reader) {
-                       struct cache_request *cr = container_of(cq, struct cache_request, q);
+                       cr = container_of(cq, struct cache_request, q);
                        if (cr->item != ch)
                                continue;
+                       if (test_bit(CACHE_PENDING, &ch->flags))
+                               /* Lost a race and it is pending again */
+                               break;
                        if (cr->readers != 0)
                                continue;
-                       list_del(&cr->q.list);
-                       spin_unlock(&queue_lock);
-                       cache_put(cr->item, detail);
-                       kfree(cr->buf);
-                       kfree(cr);
-                       return;
+                       list_move(&cr->q.list, &dequeued);
                }
        spin_unlock(&queue_lock);
+       while (!list_empty(&dequeued)) {
+               cr = list_entry(dequeued.next, struct cache_request, q.list);
+               list_del(&cr->q.list);
+               cache_put(cr->item, detail);
+               kfree(cr->buf);
+               kfree(cr);
+       }
 }
 
 /*
@@ -1166,6 +1165,7 @@ int sunrpc_cache_pipe_upcall(struct cache_detail *detail, struct cache_head *h)
 
        char *buf;
        struct cache_request *crq;
+       int ret = 0;
 
        if (!detail->cache_request)
                return -EINVAL;
@@ -1174,6 +1174,9 @@ int sunrpc_cache_pipe_upcall(struct cache_detail *detail, struct cache_head *h)
                warn_no_listener(detail);
                return -EINVAL;
        }
+       if (test_bit(CACHE_CLEANED, &h->flags))
+               /* Too late to make an upcall */
+               return -EAGAIN;
 
        buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
        if (!buf)
@@ -1191,10 +1194,18 @@ int sunrpc_cache_pipe_upcall(struct cache_detail *detail, struct cache_head *h)
        crq->len = 0;
        crq->readers = 0;
        spin_lock(&queue_lock);
-       list_add_tail(&crq->q.list, &detail->queue);
+       if (test_bit(CACHE_PENDING, &h->flags))
+               list_add_tail(&crq->q.list, &detail->queue);
+       else
+               /* Lost a race, no longer PENDING, so don't enqueue */
+               ret = -EAGAIN;
        spin_unlock(&queue_lock);
        wake_up(&queue_wait);
-       return 0;
+       if (ret == -EAGAIN) {
+               kfree(buf);
+               kfree(crq);
+       }
+       return ret;
 }
 EXPORT_SYMBOL_GPL(sunrpc_cache_pipe_upcall);
 
@@ -1812,19 +1823,11 @@ int sunrpc_cache_register_pipefs(struct dentry *parent,
                                 const char *name, umode_t umode,
                                 struct cache_detail *cd)
 {
-       struct qstr q;
-       struct dentry *dir;
-       int ret = 0;
-
-       q.name = name;
-       q.len = strlen(name);
-       q.hash = full_name_hash(q.name, q.len);
-       dir = rpc_create_cache_dir(parent, &q, umode, cd);
-       if (!IS_ERR(dir))
-               cd->u.pipefs.dir = dir;
-       else
-               ret = PTR_ERR(dir);
-       return ret;
+       struct dentry *dir = rpc_create_cache_dir(parent, name, umode, cd);
+       if (IS_ERR(dir))
+               return PTR_ERR(dir);
+       cd->u.pipefs.dir = dir;
+       return 0;
 }
 EXPORT_SYMBOL_GPL(sunrpc_cache_register_pipefs);
 
index f0339ae..9963584 100644 (file)
@@ -128,9 +128,7 @@ static struct dentry *rpc_setup_pipedir_sb(struct super_block *sb,
 {
        static uint32_t clntid;
        char name[15];
-       struct qstr q = { .name = name };
        struct dentry *dir, *dentry;
-       int error;
 
        dir = rpc_d_lookup_sb(sb, dir_name);
        if (dir == NULL) {
@@ -138,19 +136,17 @@ static struct dentry *rpc_setup_pipedir_sb(struct super_block *sb,
                return dir;
        }
        for (;;) {
-               q.len = snprintf(name, sizeof(name), "clnt%x", (unsigned int)clntid++);
+               snprintf(name, sizeof(name), "clnt%x", (unsigned int)clntid++);
                name[sizeof(name) - 1] = '\0';
-               q.hash = full_name_hash(q.name, q.len);
-               dentry = rpc_create_client_dir(dir, &q, clnt);
+               dentry = rpc_create_client_dir(dir, name, clnt);
                if (!IS_ERR(dentry))
                        break;
-               error = PTR_ERR(dentry);
-               if (error != -EEXIST) {
-                       printk(KERN_INFO "RPC: Couldn't create pipefs entry"
-                                       " %s/%s, error %d\n",
-                                       dir_name, name, error);
-                       break;
-               }
+               if (dentry == ERR_PTR(-EEXIST))
+                       continue;
+               printk(KERN_INFO "RPC: Couldn't create pipefs entry"
+                               " %s/%s, error %ld\n",
+                               dir_name, name, PTR_ERR(dentry));
+               break;
        }
        dput(dir);
        return dentry;
@@ -290,7 +286,7 @@ static int rpc_client_register(const struct rpc_create_args *args,
        struct rpc_auth *auth;
        struct net *net = rpc_net_ns(clnt);
        struct super_block *pipefs_sb;
-       int err = 0;
+       int err;
 
        pipefs_sb = rpc_get_sb_net(net);
        if (pipefs_sb) {
@@ -299,6 +295,10 @@ static int rpc_client_register(const struct rpc_create_args *args,
                        goto out;
        }
 
+       rpc_register_client(clnt);
+       if (pipefs_sb)
+               rpc_put_sb_net(net);
+
        auth = rpcauth_create(args->authflavor, clnt);
        if (IS_ERR(auth)) {
                dprintk("RPC:       Couldn't create auth handle (flavor %u)\n",
@@ -306,16 +306,14 @@ static int rpc_client_register(const struct rpc_create_args *args,
                err = PTR_ERR(auth);
                goto err_auth;
        }
-
-       rpc_register_client(clnt);
+       return 0;
+err_auth:
+       pipefs_sb = rpc_get_sb_net(net);
+       __rpc_clnt_remove_pipedir(clnt);
 out:
        if (pipefs_sb)
                rpc_put_sb_net(net);
        return err;
-
-err_auth:
-       __rpc_clnt_remove_pipedir(clnt);
-       goto out;
 }
 
 static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, struct rpc_xprt *xprt)
index 4679df5..406859c 100644 (file)
@@ -480,6 +480,23 @@ static const struct dentry_operations rpc_dentry_operations = {
        .d_delete = rpc_delete_dentry,
 };
 
+/*
+ * Lookup the data. This is trivial - if the dentry didn't already
+ * exist, we know it is negative.
+ */
+static struct dentry *
+rpc_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
+{
+       if (dentry->d_name.len > NAME_MAX)
+               return ERR_PTR(-ENAMETOOLONG);
+       d_add(dentry, NULL);
+       return NULL;
+}
+
+static const struct inode_operations rpc_dir_inode_operations = {
+       .lookup         = rpc_lookup,
+};
+
 static struct inode *
 rpc_get_inode(struct super_block *sb, umode_t mode)
 {
@@ -492,7 +509,7 @@ rpc_get_inode(struct super_block *sb, umode_t mode)
        switch (mode & S_IFMT) {
        case S_IFDIR:
                inode->i_fop = &simple_dir_operations;
-               inode->i_op = &simple_dir_inode_operations;
+               inode->i_op = &rpc_dir_inode_operations;
                inc_nlink(inode);
        default:
                break;
@@ -656,21 +673,17 @@ static int __rpc_rmpipe(struct inode *dir, struct dentry *dentry)
 }
 
 static struct dentry *__rpc_lookup_create_exclusive(struct dentry *parent,
-                                         struct qstr *name)
+                                         const char *name)
 {
-       struct dentry *dentry;
-
-       dentry = d_lookup(parent, name);
+       struct qstr q = QSTR_INIT(name, strlen(name));
+       struct dentry *dentry = d_hash_and_lookup(parent, &q);
        if (!dentry) {
-               dentry = d_alloc(parent, name);
+               dentry = d_alloc(parent, &q);
                if (!dentry)
                        return ERR_PTR(-ENOMEM);
        }
-       if (dentry->d_inode == NULL) {
-               if (!dentry->d_op)
-                       d_set_d_op(dentry, &rpc_dentry_operations);
+       if (dentry->d_inode == NULL)
                return dentry;
-       }
        dput(dentry);
        return ERR_PTR(-EEXIST);
 }
@@ -690,8 +703,7 @@ static void __rpc_depopulate(struct dentry *parent,
        for (i = start; i < eof; i++) {
                name.name = files[i].name;
                name.len = strlen(files[i].name);
-               name.hash = full_name_hash(name.name, name.len);
-               dentry = d_lookup(parent, &name);
+               dentry = d_hash_and_lookup(parent, &name);
 
                if (dentry == NULL)
                        continue;
@@ -733,12 +745,7 @@ static int rpc_populate(struct dentry *parent,
 
        mutex_lock(&dir->i_mutex);
        for (i = start; i < eof; i++) {
-               struct qstr q;
-
-               q.name = files[i].name;
-               q.len = strlen(files[i].name);
-               q.hash = full_name_hash(q.name, q.len);
-               dentry = __rpc_lookup_create_exclusive(parent, &q);
+               dentry = __rpc_lookup_create_exclusive(parent, files[i].name);
                err = PTR_ERR(dentry);
                if (IS_ERR(dentry))
                        goto out_bad;
@@ -771,7 +778,7 @@ out_bad:
 }
 
 static struct dentry *rpc_mkdir_populate(struct dentry *parent,
-               struct qstr *name, umode_t mode, void *private,
+               const char *name, umode_t mode, void *private,
                int (*populate)(struct dentry *, void *), void *args_populate)
 {
        struct dentry *dentry;
@@ -842,7 +849,6 @@ struct dentry *rpc_mkpipe_dentry(struct dentry *parent, const char *name,
        struct dentry *dentry;
        struct inode *dir = parent->d_inode;
        umode_t umode = S_IFIFO | S_IRUSR | S_IWUSR;
-       struct qstr q;
        int err;
 
        if (pipe->ops->upcall == NULL)
@@ -850,12 +856,8 @@ struct dentry *rpc_mkpipe_dentry(struct dentry *parent, const char *name,
        if (pipe->ops->downcall == NULL)
                umode &= ~S_IWUGO;
 
-       q.name = name;
-       q.len = strlen(name);
-       q.hash = full_name_hash(q.name, q.len),
-
        mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT);
-       dentry = __rpc_lookup_create_exclusive(parent, &q);
+       dentry = __rpc_lookup_create_exclusive(parent, name);
        if (IS_ERR(dentry))
                goto out;
        err = __rpc_mkpipe_dentry(dir, dentry, umode, &rpc_pipe_fops,
@@ -926,8 +928,8 @@ static void rpc_clntdir_depopulate(struct dentry *dentry)
 
 /**
  * rpc_create_client_dir - Create a new rpc_client directory in rpc_pipefs
- * @dentry: dentry from the rpc_pipefs root to the new directory
- * @name: &struct qstr for the name
+ * @dentry: the parent of new directory
+ * @name: the name of new directory
  * @rpc_client: rpc client to associate with this directory
  *
  * This creates a directory at the given @path associated with
@@ -936,7 +938,7 @@ static void rpc_clntdir_depopulate(struct dentry *dentry)
  * later be created using rpc_mkpipe().
  */
 struct dentry *rpc_create_client_dir(struct dentry *dentry,
-                                  struct qstr *name,
+                                  const char *name,
                                   struct rpc_clnt *rpc_client)
 {
        return rpc_mkdir_populate(dentry, name, S_IRUGO | S_IXUGO, NULL,
@@ -982,7 +984,7 @@ static void rpc_cachedir_depopulate(struct dentry *dentry)
        rpc_depopulate(dentry, cache_pipefs_files, 0, 3);
 }
 
-struct dentry *rpc_create_cache_dir(struct dentry *parent, struct qstr *name,
+struct dentry *rpc_create_cache_dir(struct dentry *parent, const char *name,
                                    umode_t umode, struct cache_detail *cd)
 {
        return rpc_mkdir_populate(parent, name, umode, NULL,
@@ -1062,9 +1064,7 @@ struct dentry *rpc_d_lookup_sb(const struct super_block *sb,
                               const unsigned char *dir_name)
 {
        struct qstr dir = QSTR_INIT(dir_name, strlen(dir_name));
-
-       dir.hash = full_name_hash(dir.name, dir.len);
-       return d_lookup(sb->s_root, &dir);
+       return d_hash_and_lookup(sb->s_root, &dir);
 }
 EXPORT_SYMBOL_GPL(rpc_d_lookup_sb);
 
@@ -1117,6 +1117,7 @@ rpc_fill_super(struct super_block *sb, void *data, int silent)
        sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
        sb->s_magic = RPCAUTH_GSSMAGIC;
        sb->s_op = &s_ops;
+       sb->s_d_op = &rpc_dentry_operations;
        sb->s_time_gran = 1;
 
        inode = rpc_get_inode(sb, S_IFDIR | S_IRUGO | S_IXUGO);
index 06bdf5a..621ca7b 100644 (file)
@@ -347,13 +347,13 @@ ip_map_cached_get(struct svc_xprt *xprt)
                spin_lock(&xprt->xpt_lock);
                ipm = xprt->xpt_auth_cache;
                if (ipm != NULL) {
-                       if (!cache_valid(&ipm->h)) {
+                       sn = net_generic(xprt->xpt_net, sunrpc_net_id);
+                       if (cache_is_expired(sn->ip_map_cache, &ipm->h)) {
                                /*
                                 * The entry has been invalidated since it was
                                 * remembered, e.g. by a second mount from the
                                 * same IP address.
                                 */
-                               sn = net_generic(xprt->xpt_net, sunrpc_net_id);
                                xprt->xpt_auth_cache = NULL;
                                spin_unlock(&xprt->xpt_lock);
                                cache_put(&ipm->h, sn->ip_map_cache);
@@ -493,8 +493,6 @@ static int unix_gid_parse(struct cache_detail *cd,
        if (rv)
                return -EINVAL;
        uid = make_kuid(&init_user_ns, id);
-       if (!uid_valid(uid))
-               return -EINVAL;
        ug.uid = uid;
 
        expiry = get_expiry(&mesg);
index 0f679df..305374d 100644 (file)
@@ -917,7 +917,10 @@ static void svc_tcp_clear_pages(struct svc_sock *svsk)
        len = svsk->sk_datalen;
        npages = (len + PAGE_SIZE - 1) >> PAGE_SHIFT;
        for (i = 0; i < npages; i++) {
-               BUG_ON(svsk->sk_pages[i] == NULL);
+               if (svsk->sk_pages[i] == NULL) {
+                       WARN_ON_ONCE(1);
+                       continue;
+               }
                put_page(svsk->sk_pages[i]);
                svsk->sk_pages[i] = NULL;
        }
@@ -1092,8 +1095,10 @@ static int svc_tcp_recvfrom(struct svc_rqst *rqstp)
                goto err_noclose;
        }
 
-       if (svc_sock_reclen(svsk) < 8)
+       if (svsk->sk_datalen < 8) {
+               svsk->sk_datalen = 0;
                goto err_delete; /* client is nuts. */
+       }
 
        rqstp->rq_arg.len = svsk->sk_datalen;
        rqstp->rq_arg.page_base = 0;
index 412de7c..ddf0602 100644 (file)
@@ -2534,7 +2534,6 @@ 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,
        .send_request           = bc_send_request,
index ad2e1ec..9934a32 100644 (file)
@@ -292,13 +292,7 @@ static int ib_addr2str(struct tipc_media_addr *a, char *str_buf, int str_size)
        if (str_size < 60)      /* 60 = 19 * strlen("xx:") + strlen("xx\0") */
                return 1;
 
-       sprintf(str_buf, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:"
-                        "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
-               a->value[0], a->value[1], a->value[2], a->value[3],
-               a->value[4], a->value[5], a->value[6], a->value[7],
-               a->value[8], a->value[9], a->value[10], a->value[11],
-               a->value[12], a->value[13], a->value[14], a->value[15],
-               a->value[16], a->value[17], a->value[18], a->value[19]);
+       sprintf(str_buf, "%20phC", a->value);
 
        return 0;
 }
index 182084d..8ccf830 100644 (file)
@@ -47,18 +47,24 @@ header-y      := $(filter-out $(generic-y), $(header-y))
 all-files     := $(header-y) $(genhdr-y) $(wrapper-files)
 output-files  := $(addprefix $(installdir)/, $(all-files))
 
-input-files   := $(foreach hdr, $(header-y), \
+input-files1  := $(foreach hdr, $(header-y), \
                   $(if $(wildcard $(srcdir)/$(hdr)), \
-                       $(wildcard $(srcdir)/$(hdr)), \
+                       $(wildcard $(srcdir)/$(hdr))) \
+                  )
+input-files1-name := $(notdir $(input-files1))
+input-files2  := $(foreach hdr, $(header-y), \
+                  $(if  $(wildcard $(srcdir)/$(hdr)),, \
                        $(if $(wildcard $(oldsrcdir)/$(hdr)), \
                                $(wildcard $(oldsrcdir)/$(hdr)), \
                                $(error Missing UAPI file $(srcdir)/$(hdr))) \
-                  )) \
-                $(foreach hdr, $(genhdr-y), \
+                  ))
+input-files2-name := $(notdir $(input-files2))
+input-files3  := $(foreach hdr, $(genhdr-y), \
                   $(if $(wildcard $(gendir)/$(hdr)), \
                        $(wildcard $(gendir)/$(hdr)), \
                        $(error Missing generated UAPI file $(gendir)/$(hdr)) \
                   ))
+input-files3-name := $(notdir $(input-files3))
 
 # Work out what needs to be removed
 oldheaders    := $(patsubst $(installdir)/%,%,$(wildcard $(installdir)/*.h))
@@ -72,7 +78,9 @@ printdir = $(patsubst $(INSTALL_HDR_PATH)/%/,%,$(dir $@))
 quiet_cmd_install = INSTALL $(printdir) ($(words $(all-files))\
                             file$(if $(word 2, $(all-files)),s))
       cmd_install = \
-        $(CONFIG_SHELL) $< $(installdir) $(input-files); \
+        $(CONFIG_SHELL) $< $(installdir) $(srcdir) $(input-files1-name); \
+        $(CONFIG_SHELL) $< $(installdir) $(oldsrcdir) $(input-files2-name); \
+        $(CONFIG_SHELL) $< $(installdir) $(gendir) $(input-files3-name); \
         for F in $(wrapper-files); do                                   \
                 echo "\#include <asm-generic/$$F>" > $(installdir)/$$F;    \
         done;                                                           \
@@ -98,7 +106,7 @@ __headersinst: $(subdirs) $(install-file)
        @:
 
 targets += $(install-file)
-$(install-file): scripts/headers_install.sh $(input-files) FORCE
+$(install-file): scripts/headers_install.sh $(input-files1) $(input-files2) $(input-files3) FORCE
        $(if $(unwanted),$(call cmd,remove),)
        $(if $(wildcard $(dir $@)),,$(shell mkdir -p $(dir $@)))
        $(call if_changed,install)
index 6031e23..49392ec 100644 (file)
@@ -63,7 +63,7 @@ multi-objs   := $(multi-objs-y) $(multi-objs-m)
 subdir-obj-y := $(filter %/built-in.o, $(obj-y))
 
 # $(obj-dirs) is a list of directories that contain object files
-obj-dirs := $(dir $(multi-objs) $(subdir-obj-y))
+obj-dirs := $(dir $(multi-objs) $(obj-y))
 
 # Replace multi-part objects by their individual parts, look at local dir only
 real-objs-y := $(foreach m, $(filter-out $(subdir-obj-y), $(obj-y)), $(if $(strip $($(m:.o=-objs)) $($(m:.o=-y))),$($(m:.o=-objs)) $($(m:.o=-y)),$(m))) $(extra-y)
@@ -244,7 +244,7 @@ cmd_gzip = (cat $(filter-out FORCE,$^) | gzip -n -f -9 > $@) || \
 # ---------------------------------------------------------------------------
 
 # Generate an assembly file to wrap the output of the device tree compiler
-quiet_cmd_dt_S_dtb= DTB    $@
+quiet_cmd_dt_S_dtb= DTB     $@
 cmd_dt_S_dtb=                                          \
 (                                                      \
        echo '\#include <asm-generic/vmlinux.lds.h>';   \
index 06fcb33..bbf901a 100755 (executable)
@@ -1,17 +1,31 @@
 #!/bin/bash
 
+#
+# This script requires at least spatch
+# version 1.0.0-rc11.
+#
+
 SPATCH="`which ${SPATCH:=spatch}`"
 
+trap kill_running SIGTERM SIGINT
+declare -a SPATCH_PID
+
 # The verbosity may be set by the environmental parameter V=
 # as for example with 'make V=1 coccicheck'
 
 if [ -n "$V" -a "$V" != "0" ]; then
-       VERBOSE=1
+       VERBOSE="$V"
 else
        VERBOSE=0
 fi
 
-FLAGS="$SPFLAGS -very_quiet"
+if [ -z "$J" ]; then
+       NPROC=$(getconf _NPROCESSORS_ONLN)
+else
+       NPROC="$J"
+fi
+
+FLAGS="$SPFLAGS --very-quiet"
 
 # spatch only allows include directories with the syntax "-I include"
 # while gcc also allows "-Iinclude" and "-include include"
@@ -27,14 +41,14 @@ if [ "$C" = "1" -o "$C" = "2" ]; then
 else
     ONLINE=0
     if [ "$KBUILD_EXTMOD" = "" ] ; then
-        OPTIONS="-dir $srctree $COCCIINCLUDE"
+        OPTIONS="--dir $srctree $COCCIINCLUDE"
     else
-        OPTIONS="-dir $KBUILD_EXTMOD $COCCIINCLUDE"
+        OPTIONS="--dir $KBUILD_EXTMOD $COCCIINCLUDE"
     fi
 fi
 
 if [ "$KBUILD_EXTMOD" != "" ] ; then
-    OPTIONS="-patch $srctree $OPTIONS"
+    OPTIONS="--patch $srctree $OPTIONS"
 fi
 
 if [ ! -x "$SPATCH" ]; then
@@ -44,13 +58,21 @@ fi
 
 if [ "$MODE" = "" ] ; then
     if [ "$ONLINE" = "0" ] ; then
-       echo 'You have not explicitly specified the mode to use. Using default "chain" mode.'
-       echo 'All available modes will be tried (in that order): patch, report, context, org'
+       echo 'You have not explicitly specified the mode to use. Using default "report" mode.'
+       echo 'Available modes are the following: patch, report, context, org'
        echo 'You can specify the mode with "make coccicheck MODE=<mode>"'
+       echo 'Note however that some modes are not implemented by some semantic patches.'
+    fi
+    MODE="report"
+fi
+
+if [ "$MODE" = "chain" ] ; then
+    if [ "$ONLINE" = "0" ] ; then
+       echo 'You have selected the "chain" mode.'
+       echo 'All available modes will be tried (in that order): patch, report, context, org'
     fi
-    MODE="chain"
 elif [ "$MODE" = "report" -o "$MODE" = "org" ] ; then
-    FLAGS="$FLAGS -no_show_diff"
+    FLAGS="$FLAGS --no-show-diff"
 fi
 
 if [ "$ONLINE" = "0" ] ; then
@@ -61,19 +83,35 @@ if [ "$ONLINE" = "0" ] ; then
 fi
 
 run_cmd() {
+       local i
        if [ $VERBOSE -ne 0 ] ; then
-               echo "Running: $@"
+               echo "Running ($NPROC in parallel): $@"
        fi
-       eval $@
+       for i in $(seq 0 $(( NPROC - 1)) ); do
+               eval "$@ --max $NPROC --index $i &"
+               SPATCH_PID[$i]=$!
+               if [ $VERBOSE -eq 2 ] ; then
+                       echo "${SPATCH_PID[$i]} running"
+               fi
+       done
+       wait
 }
 
+kill_running() {
+       for i in $(seq $(( NPROC - 1 )) ); do
+               if [ $VERBOSE -eq 2 ] ; then
+                       echo "Killing ${SPATCH_PID[$i]}"
+               fi
+               kill ${SPATCH_PID[$i]} 2>/dev/null
+       done
+}
 
 coccinelle () {
     COCCI="$1"
 
     OPT=`grep "Option" $COCCI | cut -d':' -f2`
 
-#   The option '-parse_cocci' can be used to syntactically check the SmPL files.
+#   The option '--parse-cocci' can be used to syntactically check the SmPL files.
 #
 #    $SPATCH -D $MODE $FLAGS -parse_cocci $COCCI $OPT > /dev/null
 
@@ -114,20 +152,20 @@ coccinelle () {
 
     if [ "$MODE" = "chain" ] ; then
        run_cmd $SPATCH -D patch   \
-               $FLAGS -sp_file $COCCI $OPT $OPTIONS               || \
+               $FLAGS --cocci-file $COCCI $OPT $OPTIONS               || \
        run_cmd $SPATCH -D report  \
-               $FLAGS -sp_file $COCCI $OPT $OPTIONS -no_show_diff || \
+               $FLAGS --cocci-file $COCCI $OPT $OPTIONS --no-show-diff || \
        run_cmd $SPATCH -D context \
-               $FLAGS -sp_file $COCCI $OPT $OPTIONS               || \
+               $FLAGS --cocci-file $COCCI $OPT $OPTIONS               || \
        run_cmd $SPATCH -D org     \
-               $FLAGS -sp_file $COCCI $OPT $OPTIONS -no_show_diff || exit 1
+               $FLAGS --cocci-file $COCCI $OPT $OPTIONS --no-show-diff || exit 1
     elif [ "$MODE" = "rep+ctxt" ] ; then
        run_cmd $SPATCH -D report  \
-               $FLAGS -sp_file $COCCI $OPT $OPTIONS -no_show_diff && \
+               $FLAGS --cocci-file $COCCI $OPT $OPTIONS --no-show-diff && \
        run_cmd $SPATCH -D context \
-               $FLAGS -sp_file $COCCI $OPT $OPTIONS || exit 1
+               $FLAGS --cocci-file $COCCI $OPT $OPTIONS || exit 1
     else
-       run_cmd $SPATCH -D $MODE   $FLAGS -sp_file $COCCI $OPT $OPTIONS || exit 1
+       run_cmd $SPATCH -D $MODE   $FLAGS --cocci-file $COCCI $OPT $OPTIONS || exit 1
     fi
 
 }
index 7d4771d..bd5d08b 100644 (file)
@@ -5,7 +5,7 @@
 // Confidence: High
 // Copyright: 2009,2010 Nicolas Palix, DIKU.  GPLv2.
 // URL: http://coccinelle.lip6.fr/
-// Options: -no_includes -include_headers
+// Options: --no-includes --include-headers
 //
 // Keywords: kmalloc, kzalloc, kcalloc
 // Version min: < 2.6.12 kmalloc
index 046b9b1..52c55e4 100644 (file)
@@ -9,7 +9,7 @@
 // Copyright: (C) 2009-2010 Julia Lawall, Nicolas Palix, DIKU.  GPLv2.
 // Copyright: (C) 2009-2010 Gilles Muller, INRIA/LiP6.  GPLv2.
 // URL: http://coccinelle.lip6.fr/rules/kzalloc.html
-// Options: -no_includes -include_headers
+// Options: --no-includes --include-headers
 //
 // Keywords: kmalloc, kzalloc
 // Version min: < 2.6.12 kmalloc
index a9694a8..9594c9f 100644 (file)
@@ -4,7 +4,7 @@
 //
 // Confidence: Moderate
 // URL: http://coccinelle.lip6.fr/
-// Options: -include_headers
+// Options: --include-headers
 
 virtual context
 virtual org
index 46beb81..562ec88 100644 (file)
@@ -10,7 +10,7 @@
 // Copyright: (C) 2011 Gilles Muller, INRIA/LiP6.  GPLv2.
 // URL: http://coccinelle.lip6.fr/
 // Comments:
-// Options: -no_includes -include_headers
+// Options: --no-includes --include-headers
 
 virtual patch
 virtual org
index 07a74b2..09cba54 100644 (file)
@@ -6,7 +6,7 @@
 // Copyright: (C) 2010-2012 Gilles Muller, INRIA/LiP6.  GPLv2.
 // URL: http://coccinelle.lip6.fr/
 // Comments:
-// Options: -no_includes -include_headers
+// Options: --no-includes --include-headers
 
 virtual patch
 virtual context
index 4dceab6..3d1aa71 100644 (file)
@@ -6,7 +6,7 @@
 // Copyright: (C) 2010-2012 Gilles Muller, INRIA/LiP6.  GPLv2.
 // URL: http://coccinelle.lip6.fr/
 // Comments:
-// Options: -no_includes -include_headers
+// Options: --no-includes --include-headers
 
 virtual patch
 virtual context
index 2b131a8..c606231 100644 (file)
@@ -7,7 +7,7 @@
 // Copyright: (C) 2010-2012 Gilles Muller, INRIA/LiP6.  GPLv2.
 // URL: http://coccinelle.lip6.fr/
 // Comments:
-// Options: -no_includes -include_headers
+// Options: --no-includes --include-headers
 
 virtual patch
 virtual context
index 15f076f..2274638 100644 (file)
@@ -5,7 +5,7 @@
 // Copyright: (C) 2012 Julia Lawall, INRIA/LIP6.  GPLv2.
 // Copyright: (C) 2012 Gilles Muller, INRIA/LiP6.  GPLv2.
 // URL: http://coccinelle.lip6.fr/
-// Options: -no_includes -include_headers
+// Options: --no-includes --include-headers
 //
 // Keywords: ERR_PTR, PTR_ERR, PTR_RET
 // Version min: 2.6.39
index 05962f7..b67e174 100644 (file)
@@ -4,7 +4,7 @@
 ///
 // Confidence: High
 // Comments:
-// Options: -no_includes -include_headers
+// Options: --no-includes --include-headers
 
 virtual patch
 virtual report
index 0a1e361..3d93490 100644 (file)
@@ -18,7 +18,7 @@
 // Copyright: (C) 2011 Gilles Muller, INRIA/LiP6.  GPLv2.
 // URL: http://coccinelle.lip6.fr/
 // Comments:
-// Options: -no_includes -include_headers
+// Options: --no-includes --include-headers
 
 virtual org
 virtual report
index d9ae6d8..577b780 100644 (file)
@@ -10,7 +10,7 @@
 // Copyright: (C) 2010-2012 Gilles Muller, INRIA/LiP6.  GPLv2.
 // URL: http://coccinelle.lip6.fr/
 // Comments:
-// Options: -no_includes -include_headers
+// Options: --no-includes --include-headers
 
 virtual org
 virtual report
diff --git a/scripts/coccinelle/free/kfreeaddr.cocci b/scripts/coccinelle/free/kfreeaddr.cocci
new file mode 100644 (file)
index 0000000..ce8aacc
--- /dev/null
@@ -0,0 +1,32 @@
+/// Free of a structure field
+///
+// Confidence: High
+// Copyright: (C) 2013 Julia Lawall, INRIA/LIP6.  GPLv2.
+// URL: http://coccinelle.lip6.fr/
+// Comments:
+// Options: --no-includes --include-headers
+
+virtual org
+virtual report
+virtual context
+
+@r depends on context || report || org @
+expression e;
+identifier f;
+position p;
+@@
+
+* kfree@p(&e->f)
+
+@script:python depends on org@
+p << r.p;
+@@
+
+cocci.print_main("kfree",p)
+
+@script:python depends on report@
+p << r.p;
+@@
+
+msg = "ERROR: kfree of structure field"
+coccilib.report.print_report(p[0],msg)
diff --git a/scripts/coccinelle/free/pci_free_consistent.cocci b/scripts/coccinelle/free/pci_free_consistent.cocci
new file mode 100644 (file)
index 0000000..43600cc
--- /dev/null
@@ -0,0 +1,52 @@
+/// Find missing pci_free_consistent for every pci_alloc_consistent.
+///
+// Confidence: Moderate
+// Copyright: (C) 2013 Petr Strnad.  GPLv2.
+// URL: http://coccinelle.lip6.fr/
+// Keywords: pci_free_consistent, pci_alloc_consistent
+// Options: --no-includes --include-headers
+
+virtual report
+virtual org
+
+@search@
+local idexpression id;
+expression x,y,z,e;
+position p1,p2;
+type T;
+@@
+
+id = pci_alloc_consistent@p1(x,y,&z)
+... when != e = id
+if (id == NULL || ...) { ... return ...; }
+... when != pci_free_consistent(x,y,id,z)
+    when != if (id) { ... pci_free_consistent(x,y,id,z) ... }
+    when != if (y) { ... pci_free_consistent(x,y,id,z) ... }
+    when != e = (T)id
+    when exists
+(
+return 0;
+|
+return 1;
+|
+return id;
+|
+return@p2 ...;
+)
+
+@script:python depends on report@
+p1 << search.p1;
+p2 << search.p2;
+@@
+
+msg = "ERROR: missing pci_free_consistent; pci_alloc_consistent on line %s and return without freeing on line %s" % (p1[0].line,p2[0].line)
+coccilib.report.print_report(p2[0],msg)
+
+@script:python depends on org@
+p1 << search.p1;
+p2 << search.p2;
+@@
+
+msg = "ERROR: missing pci_free_consistent; pci_alloc_consistent on line %s and return without freeing on line %s" % (p1[0].line,p2[0].line)
+cocci.print_main(msg,p1)
+cocci.print_secs("",p2)
index 0a40af8..48c152f 100644 (file)
@@ -7,7 +7,7 @@
 // Copyright: (C) 2010-2012 Gilles Muller, INRIA/LiP6.  GPLv2.
 // URL: http://coccinelle.lip6.fr/
 // Comments:
-// Options: -no_includes -include_headers
+// Options: --no-includes --include-headers
 
 virtual patch
 virtual context
index 259899f..f58732b 100644 (file)
@@ -11,7 +11,7 @@
 // Copyright: (C) 2010-2012 Gilles Muller, INRIA/LiP6.  GPLv2.
 // URL: http://coccinelle.lip6.fr/
 // Comments:
-// Options: -no_includes -include_headers
+// Options: --no-includes --include-headers
 
 virtual patch
 virtual context
index b296747..873f444 100644 (file)
@@ -9,7 +9,7 @@
 // Copyright: (C) 2010 Gilles Muller, INRIA/LiP6.  GPLv2.
 // URL: http://coccinelle.lip6.fr/
 // Comments:
-// Options: -no_includes -include_headers
+// Options: --no-includes --include-headers
 
 virtual context
 virtual org
index 06284c5..f085f59 100644 (file)
@@ -11,7 +11,7 @@
 // Copyright: (C) 2012 Gilles Muller, INRIA/LIP6.  GPLv2.
 // URL: http://coccinelle.lip6.fr/
 // Comments:
-// Options: -no_includes -include_headers
+// Options: --no-includes --include-headers
 
 virtual context
 virtual org
index 8f10b49..669b244 100644 (file)
@@ -9,7 +9,7 @@
 // Copyright: (C) 2012 Gilles Muller, INRIA/LiP6.  GPLv2.
 // URL: http://coccinelle.lip6.fr/
 // Comments:
-// Options: -no_includes -include_headers
+// Options: --no-includes --include-headers
 
 virtual patch
 virtual context
index 63b24e6..002752f 100644 (file)
@@ -8,7 +8,7 @@
 // Copyright: (C) 2010 Gilles Muller, INRIA/LiP6.  GPLv2.
 // URL: http://coccinelle.lip6.fr/
 // Comments:
-// Options: -no_includes -include_headers
+// Options: --no-includes --include-headers
 
 virtual org
 virtual report
index 1c4ffe6..debd70e 100644 (file)
@@ -6,7 +6,7 @@
 // Copyright: (C) 2010-2012 Gilles Muller, INRIA/LiP6.  GPLv2.
 // URL: http://coccinelle.lip6.fr/
 // Comments:
-// Options: -no_includes -include_headers
+// Options: --no-includes --include-headers
 
 virtual context
 virtual org
index 3267d74..47f649b 100644 (file)
@@ -11,7 +11,7 @@
 // Copyright: (C) 2010-2012 Gilles Muller, INRIA/LiP6.  GPLv2.
 // URL: http://coccinelle.lip6.fr/
 // Comments:
-// Options: -no_includes -include_headers
+// Options: --no-includes --include-headers
 
 virtual context
 virtual org
index 97ce41c..b9abed4 100644 (file)
@@ -6,7 +6,7 @@
 // Copyright: (C) 2012 Julia Lawall, INRIA/LIP6.  GPLv2.
 // Copyright: (C) 2012 Gilles Muller, INRIA/LiP6.  GPLv2.
 // URL: http://coccinelle.lip6.fr/
-// Options: -include_headers
+// Options: --include-headers
 
 virtual patch
 virtual context
index d425644..f0368b3 100644 (file)
@@ -6,7 +6,7 @@
 // Copyright: (C) 2012 Gilles Muller, INRIA/LiP6.  GPLv2.
 // URL: http://coccinelle.lip6.fr/
 // Comments:
-// Options: -no_includes -include_headers
+// Options: --no-includes --include-headers
 
 virtual org
 virtual report
index cf74a00..c0c3371 100644 (file)
@@ -8,7 +8,7 @@
 // Copyright: (C) 2010-2012 Gilles Muller, INRIA/LiP6.  GPLv2.
 // URL: http://coccinelle.lip6.fr/
 // Comments: requires at least Coccinelle 0.2.4, lex or parse error otherwise
-// Options: -no_includes -include_headers
+// Options: --no-includes --include-headers
 
 virtual org
 virtual report
index 3e4089a..8aebd18 100644 (file)
@@ -6,7 +6,7 @@
 // Copyright: (C) 2012 Gilles Muller, INRIA/LiP6.  GPLv2.
 // URL: http://coccinelle.lip6.fr/
 // Comments:
-// Options: -no_includes -include_headers
+// Options: --no-includes --include-headers
 
 virtual org
 virtual report
index b7ed91d..d0d00ef 100644 (file)
@@ -13,7 +13,7 @@
 // Copyright: (C) 2010 Gilles Muller, INRIA/LiP6.  GPLv2.
 // URL: http://coccinelle.lip6.fr/
 // Comments:
-// Options: -no_includes -include_headers
+// Options: --no-includes --include-headers
 
 virtual org
 virtual report
index c170721..80a831c 100644 (file)
@@ -6,7 +6,7 @@
 // Copyright: (C) 2012 Gilles Muller, INRIA/LiP6.  GPLv2.
 // URL: http://coccinelle.lip6.fr/
 // Comments:
-// Options: -no_includes -include_headers
+// Options: --no-includes --include-headers
 
 virtual org
 virtual report
index 4a28cef..81fabf3 100644 (file)
@@ -7,7 +7,7 @@
 // Copyright: (C) 2013 Gilles Muller, INRIA/LIP6.  GPLv2.
 // URL: http://coccinelle.lip6.fr/
 // Comments:
-// Options: -no_includes -include_headers
+// Options: --no-includes --include-headers
 
 virtual org
 virtual report
index fda8c35..d2e5b6c 100644 (file)
@@ -5,7 +5,7 @@
 // Copyright: (C) 2012 Gilles Muller, INRIA/LiP6.  GPLv2.
 // URL: http://coccinelle.lip6.fr/
 // Comments:
-// Options: -no_includes -include_headers
+// Options: --no-includes --include-headers
 
 virtual patch
 virtual context
index ed961a1..9bd29aa 100644 (file)
@@ -6,7 +6,7 @@
 // Copyright: (C) 2010-2012 Gilles Muller, INRIA/LiP6.  GPLv2.
 // URL: http://coccinelle.lip6.fr/
 // Comments:
-// Options: -no_includes -include_headers
+// Options: --no-includes --include-headers
 
 virtual patch
 virtual context
index 949bf65..5354a79 100644 (file)
@@ -10,7 +10,7 @@
 // Copyright: (C) 2010 Gilles Muller, INRIA/LiP6.  GPLv2.
 // URL: http://coccinelle.lip6.fr/
 // Comments:
-// Options: -no_includes -include_headers
+// Options: --no-includes --include-headers
 
 virtual context
 virtual org
index 9ba73d0..72f1572 100644 (file)
@@ -10,7 +10,7 @@
 // Copyright: (C) 2010 Gilles Muller, INRIA/LiP6.  GPLv2.
 // URL: http://coccinelle.lip6.fr/
 // Comments:
-// Options: -no_includes -include_headers
+// Options: --no-includes --include-headers
 
 virtual context
 virtual org
index 13a2c0e..78d74c2 100644 (file)
@@ -8,7 +8,7 @@
 // Copyright: (C) 2010 Gilles Muller, INRIA/LiP6.  GPLv2.
 // URL: http://coccinelle.lip6.fr/
 // Comments:
-// Options: -no_includes -include_headers
+// Options: --no-includes --include-headers
 
 virtual context
 virtual org
index e8dd8a6..cfe0a35 100644 (file)
@@ -7,7 +7,7 @@
 // Copyright: (C) 2012 Gilles Muller, INRIA.  GPLv2.
 // URL: http://coccinelle.lip6.fr/
 // Comments:
-// Options: -no_includes -include_headers
+// Options: --no-includes --include-headers
 
 virtual patch
 virtual context
index a65ecbb..567120a 100755 (executable)
@@ -1,6 +1,8 @@
 #!/bin/bash
 # Manipulate options in a .config file from the command line
 
+myname=${0##*/}
+
 # If no prefix forced, use the default CONFIG_
 CONFIG_="${CONFIG_-CONFIG_}"
 
@@ -8,7 +10,7 @@ usage() {
        cat >&2 <<EOL
 Manipulate options in a .config file from the command line.
 Usage:
-config options command ...
+$myname options command ...
 commands:
        --enable|-e option   Enable option
        --disable|-d option  Disable option
@@ -33,14 +35,14 @@ options:
        --file config-file   .config file to change (default .config)
        --keep-case|-k       Keep next symbols' case (dont' upper-case it)
 
-config doesn't check the validity of the .config file. This is done at next
+$myname doesn't check the validity of the .config file. This is done at next
 make time.
 
-By default, config will upper-case the given symbol. Use --keep-case to keep
+By default, $myname will upper-case the given symbol. Use --keep-case to keep
 the case of all following symbols unchanged.
 
-config uses 'CONFIG_' as the default symbol prefix. Set the environment
-variable CONFIG_ to the prefix to use. Eg.: CONFIG_="FOO_" config ...
+$myname uses 'CONFIG_' as the default symbol prefix. Set the environment
+variable CONFIG_ to the prefix to use. Eg.: CONFIG_="FOO_" $myname ...
 EOL
        exit 1
 }
index 643764f..5de5660 100644 (file)
@@ -2,7 +2,7 @@
 
 if [ $# -lt 1 ]
 then
-       echo "Usage: headers_install.sh OUTDIR [FILES...]
+       echo "Usage: headers_install.sh OUTDIR SRCDIR [FILES...]
        echo
        echo "Prepares kernel header files for use by user space, by removing"
        echo "all compiler.h definitions and #includes, removing any"
@@ -10,6 +10,7 @@ then
        echo "asm/inline/volatile keywords."
        echo
        echo "OUTDIR: directory to write each userspace header FILE to."
+       echo "SRCDIR: source directory where files are picked."
        echo "FILES:  list of header files to operate on."
 
        exit 1
@@ -19,6 +20,8 @@ fi
 
 OUTDIR="$1"
 shift
+SRCDIR="$1"
+shift
 
 # Iterate through files listed on command line
 
@@ -34,7 +37,7 @@ do
                -e 's/(^|[^a-zA-Z0-9])__packed([^a-zA-Z0-9_]|$)/\1__attribute__((packed))\2/g' \
                -e 's/(^|[ \t(])(inline|asm|volatile)([ \t(]|$)/\1__\2__\3/g' \
                -e 's@#(ifndef|define|endif[ \t]*/[*])[ \t]*_UAPI@#\1 @' \
-               "$i" > "$OUTDIR/$FILE.sed" || exit 1
+               "$SRCDIR/$i" > "$OUTDIR/$FILE.sed" || exit 1
        scripts/unifdef -U__KERNEL__ -D__EXPORTED_HEADERS__ "$OUTDIR/$FILE.sed" \
                > "$OUTDIR/$FILE"
        [ $? -gt 1 ] && exit 1
index bde5b95..d19944f 100644 (file)
@@ -527,11 +527,12 @@ int main(int ac, char **av)
                        seed_env = getenv("KCONFIG_SEED");
                        if( seed_env && *seed_env ) {
                                char *endp;
-                               int tmp = (int)strtol(seed_env, &endp, 10);
+                               int tmp = (int)strtol(seed_env, &endp, 0);
                                if (*endp == '\0') {
                                        seed = tmp;
                                }
                        }
+                       fprintf( stderr, "KCONFIG_SEED=0x%X\n", seed );
                        srand(seed);
                        break;
                }
@@ -653,7 +654,8 @@ int main(int ac, char **av)
                conf_set_all_new_symbols(def_default);
                break;
        case randconfig:
-               conf_set_all_new_symbols(def_random);
+               /* Really nothing to do in this loop */
+               while (conf_set_all_new_symbols(def_random)) ;
                break;
        case defconfig:
                conf_set_all_new_symbols(def_default);
index 43eda40..c55c227 100644 (file)
@@ -1040,7 +1040,7 @@ void conf_set_changed_callback(void (*fn)(void))
        conf_changed_callback = fn;
 }
 
-static void randomize_choice_values(struct symbol *csym)
+static bool randomize_choice_values(struct symbol *csym)
 {
        struct property *prop;
        struct symbol *sym;
@@ -1053,7 +1053,7 @@ static void randomize_choice_values(struct symbol *csym)
         * In both cases stop.
         */
        if (csym->curr.tri != yes)
-               return;
+               return false;
 
        prop = sym_get_choice_prop(csym);
 
@@ -1077,13 +1077,18 @@ static void randomize_choice_values(struct symbol *csym)
                else {
                        sym->def[S_DEF_USER].tri = no;
                }
+               sym->flags |= SYMBOL_DEF_USER;
+               /* clear VALID to get value calculated */
+               sym->flags &= ~SYMBOL_VALID;
        }
        csym->flags |= SYMBOL_DEF_USER;
        /* clear VALID to get value calculated */
        csym->flags &= ~(SYMBOL_VALID);
+
+       return true;
 }
 
-static void set_all_choice_values(struct symbol *csym)
+void set_all_choice_values(struct symbol *csym)
 {
        struct property *prop;
        struct symbol *sym;
@@ -1100,10 +1105,10 @@ static void set_all_choice_values(struct symbol *csym)
        }
        csym->flags |= SYMBOL_DEF_USER;
        /* clear VALID to get value calculated */
-       csym->flags &= ~(SYMBOL_VALID);
+       csym->flags &= ~(SYMBOL_VALID | SYMBOL_NEED_SET_CHOICE_VALUES);
 }
 
-void conf_set_all_new_symbols(enum conf_def_mode mode)
+bool conf_set_all_new_symbols(enum conf_def_mode mode)
 {
        struct symbol *sym, *csym;
        int i, cnt, pby, pty, ptm;      /* pby: probability of boolean  = y
@@ -1151,6 +1156,7 @@ void conf_set_all_new_symbols(enum conf_def_mode mode)
                        exit( 1 );
                }
        }
+       bool has_changed = false;
 
        for_all_symbols(i, sym) {
                if (sym_has_value(sym) || (sym->flags & SYMBOL_VALID))
@@ -1158,6 +1164,7 @@ void conf_set_all_new_symbols(enum conf_def_mode mode)
                switch (sym_get_type(sym)) {
                case S_BOOLEAN:
                case S_TRISTATE:
+                       has_changed = true;
                        switch (mode) {
                        case def_yes:
                                sym->def[S_DEF_USER].tri = yes;
@@ -1202,14 +1209,26 @@ void conf_set_all_new_symbols(enum conf_def_mode mode)
         * selected in a choice block and we set it to yes,
         * and the rest to no.
         */
+       if (mode != def_random) {
+               for_all_symbols(i, csym) {
+                       if ((sym_is_choice(csym) && !sym_has_value(csym)) ||
+                           sym_is_choice_value(csym))
+                               csym->flags |= SYMBOL_NEED_SET_CHOICE_VALUES;
+               }
+       }
+
        for_all_symbols(i, csym) {
                if (sym_has_value(csym) || !sym_is_choice(csym))
                        continue;
 
                sym_calc_value(csym);
                if (mode == def_random)
-                       randomize_choice_values(csym);
-               else
+                       has_changed = randomize_choice_values(csym);
+               else {
                        set_all_choice_values(csym);
+                       has_changed = true;
+               }
        }
+
+       return has_changed;
 }
index cdd4860..df198a5 100644 (file)
@@ -106,6 +106,9 @@ struct symbol {
 #define SYMBOL_DEF3       0x40000  /* symbol.def[S_DEF_3] is valid */
 #define SYMBOL_DEF4       0x80000  /* symbol.def[S_DEF_4] is valid */
 
+/* choice values need to be set before calculating this symbol value */
+#define SYMBOL_NEED_SET_CHOICE_VALUES  0x100000
+
 #define SYMBOL_MAXLENGTH       256
 #define SYMBOL_HASHSIZE                9973
 
index f8aee5f..09f4edf 100644 (file)
@@ -86,7 +86,8 @@ const char *conf_get_autoconfig_name(void);
 char *conf_get_default_confname(void);
 void sym_set_change_count(int count);
 void sym_add_change_count(int count);
-void conf_set_all_new_symbols(enum conf_def_mode mode);
+bool conf_set_all_new_symbols(enum conf_def_mode mode);
+void set_all_choice_values(struct symbol *csym);
 
 struct conf_printer {
        void (*print_symbol)(FILE *, struct symbol *, const char *, void *);
index ef1a738..ecdb965 100644 (file)
@@ -14,6 +14,7 @@ P(conf_set_message_callback, void,(void (*fn)(const char *fmt, va_list ap)));
 /* menu.c */
 P(rootmenu,struct menu,);
 
+P(menu_is_empty, bool, (struct menu *menu));
 P(menu_is_visible, bool, (struct menu *menu));
 P(menu_has_prompt, bool, (struct menu *menu));
 P(menu_get_prompt,const char *,(struct menu *menu));
index a2eb80f..3b15c08 100644 (file)
@@ -132,16 +132,16 @@ int dialog_checklist(const char *title, const char *prompt, int height,
        }
 
 do_resize:
-       if (getmaxy(stdscr) < (height + 6))
+       if (getmaxy(stdscr) < (height + CHECKLIST_HEIGTH_MIN))
                return -ERRDISPLAYTOOSMALL;
-       if (getmaxx(stdscr) < (width + 6))
+       if (getmaxx(stdscr) < (width + CHECKLIST_WIDTH_MIN))
                return -ERRDISPLAYTOOSMALL;
 
        max_choice = MIN(list_height, item_count());
 
        /* center dialog box on screen */
-       x = (COLS - width) / 2;
-       y = (LINES - height) / 2;
+       x = (getmaxx(stdscr) - width) / 2;
+       y = (getmaxy(stdscr) - height) / 2;
 
        draw_shadow(stdscr, y, x, height, width);
 
index 1099337..b4343d3 100644 (file)
@@ -200,6 +200,20 @@ int item_is_tag(char tag);
 int on_key_esc(WINDOW *win);
 int on_key_resize(void);
 
+/* minimum (re)size values */
+#define CHECKLIST_HEIGTH_MIN 6 /* For dialog_checklist() */
+#define CHECKLIST_WIDTH_MIN 6
+#define INPUTBOX_HEIGTH_MIN 2  /* For dialog_inputbox() */
+#define INPUTBOX_WIDTH_MIN 2
+#define MENUBOX_HEIGTH_MIN 15  /* For dialog_menu() */
+#define MENUBOX_WIDTH_MIN 65
+#define TEXTBOX_HEIGTH_MIN 8   /* For dialog_textbox() */
+#define TEXTBOX_WIDTH_MIN 8
+#define YESNO_HEIGTH_MIN 4     /* For dialog_yesno() */
+#define YESNO_WIDTH_MIN 4
+#define WINDOW_HEIGTH_MIN 19   /* For init_dialog() */
+#define WINDOW_WIDTH_MIN 80
+
 int init_dialog(const char *backtitle);
 void set_dialog_backtitle(const char *backtitle);
 void set_dialog_subtitles(struct subtitle_list *subtitles);
index 21404a0..447a582 100644 (file)
@@ -56,14 +56,14 @@ int dialog_inputbox(const char *title, const char *prompt, int height, int width
                strcpy(instr, init);
 
 do_resize:
-       if (getmaxy(stdscr) <= (height - 2))
+       if (getmaxy(stdscr) <= (height - INPUTBOX_HEIGTH_MIN))
                return -ERRDISPLAYTOOSMALL;
-       if (getmaxx(stdscr) <= (width - 2))
+       if (getmaxx(stdscr) <= (width - INPUTBOX_WIDTH_MIN))
                return -ERRDISPLAYTOOSMALL;
 
        /* center dialog box on screen */
-       x = (COLS - width) / 2;
-       y = (LINES - height) / 2;
+       x = (getmaxx(stdscr) - width) / 2;
+       y = (getmaxy(stdscr) - height) / 2;
 
        draw_shadow(stdscr, y, x, height, width);
 
index 38cd69c..c93de0b 100644 (file)
@@ -193,7 +193,7 @@ int dialog_menu(const char *title, const char *prompt,
 do_resize:
        height = getmaxy(stdscr);
        width = getmaxx(stdscr);
-       if (height < 15 || width < 65)
+       if (height < MENUBOX_HEIGTH_MIN || width < MENUBOX_WIDTH_MIN)
                return -ERRDISPLAYTOOSMALL;
 
        height -= 4;
@@ -203,8 +203,8 @@ do_resize:
        max_choice = MIN(menu_height, item_count());
 
        /* center dialog box on screen */
-       x = (COLS - width) / 2;
-       y = (LINES - height) / 2;
+       x = (getmaxx(stdscr) - width) / 2;
+       y = (getmaxy(stdscr) - height) / 2;
 
        draw_shadow(stdscr, y, x, height, width);
 
index a48bb93..1773319 100644 (file)
@@ -80,7 +80,7 @@ int dialog_textbox(const char *title, char *tbuf, int initial_height,
 
 do_resize:
        getmaxyx(stdscr, height, width);
-       if (height < 8 || width < 8)
+       if (height < TEXTBOX_HEIGTH_MIN || width < TEXTBOX_WIDTH_MIN)
                return -ERRDISPLAYTOOSMALL;
        if (initial_height != 0)
                height = initial_height;
@@ -98,8 +98,8 @@ do_resize:
                        width = 0;
 
        /* center dialog box on screen */
-       x = (COLS - width) / 2;
-       y = (LINES - height) / 2;
+       x = (getmaxx(stdscr) - width) / 2;
+       y = (getmaxy(stdscr) - height) / 2;
 
        draw_shadow(stdscr, y, x, height, width);
 
index a0e97c2..58a8289 100644 (file)
@@ -254,7 +254,12 @@ void attr_clear(WINDOW * win, int height, int width, chtype attr)
 
 void dialog_clear(void)
 {
-       attr_clear(stdscr, LINES, COLS, dlg.screen.atr);
+       int lines, columns;
+
+       lines = getmaxy(stdscr);
+       columns = getmaxx(stdscr);
+
+       attr_clear(stdscr, lines, columns, dlg.screen.atr);
        /* Display background title if it exists ... - SLH */
        if (dlg.backtitle != NULL) {
                int i, len = 0, skip = 0;
@@ -269,10 +274,10 @@ void dialog_clear(void)
                }
 
                wmove(stdscr, 1, 1);
-               if (len > COLS - 2) {
+               if (len > columns - 2) {
                        const char *ellipsis = "[...] ";
                        waddstr(stdscr, ellipsis);
-                       skip = len - (COLS - 2 - strlen(ellipsis));
+                       skip = len - (columns - 2 - strlen(ellipsis));
                }
 
                for (pos = dlg.subtitles; pos != NULL; pos = pos->next) {
@@ -298,7 +303,7 @@ void dialog_clear(void)
                                skip--;
                }
 
-               for (i = len + 1; i < COLS - 1; i++)
+               for (i = len + 1; i < columns - 1; i++)
                        waddch(stdscr, ACS_HLINE);
        }
        wnoutrefresh(stdscr);
@@ -317,7 +322,7 @@ int init_dialog(const char *backtitle)
        getyx(stdscr, saved_y, saved_x);
 
        getmaxyx(stdscr, height, width);
-       if (height < 19 || width < 80) {
+       if (height < WINDOW_HEIGTH_MIN || width < WINDOW_WIDTH_MIN) {
                endwin();
                return -ERRDISPLAYTOOSMALL;
        }
@@ -371,27 +376,19 @@ void print_title(WINDOW *dialog, const char *title, int width)
 /*
  * Print a string of text in a window, automatically wrap around to the
  * next line if the string is too long to fit on one line. Newline
- * characters '\n' are replaced by spaces.  We start on a new line
+ * characters '\n' are propperly processed.  We start on a new line
  * if there is no room for at least 4 nonblanks following a double-space.
  */
 void print_autowrap(WINDOW * win, const char *prompt, int width, int y, int x)
 {
        int newl, cur_x, cur_y;
-       int i, prompt_len, room, wlen;
-       char tempstr[MAX_LEN + 1], *word, *sp, *sp2;
+       int prompt_len, room, wlen;
+       char tempstr[MAX_LEN + 1], *word, *sp, *sp2, *newline_separator = 0;
 
        strcpy(tempstr, prompt);
 
        prompt_len = strlen(tempstr);
 
-       /*
-        * Remove newlines
-        */
-       for (i = 0; i < prompt_len; i++) {
-               if (tempstr[i] == '\n')
-                       tempstr[i] = ' ';
-       }
-
        if (prompt_len <= width - x * 2) {      /* If prompt is short */
                wmove(win, y, (width - prompt_len) / 2);
                waddstr(win, tempstr);
@@ -401,7 +398,10 @@ void print_autowrap(WINDOW * win, const char *prompt, int width, int y, int x)
                newl = 1;
                word = tempstr;
                while (word && *word) {
-                       sp = strchr(word, ' ');
+                       sp = strpbrk(word, "\n ");
+                       if (sp && *sp == '\n')
+                               newline_separator = sp;
+
                        if (sp)
                                *sp++ = 0;
 
@@ -413,7 +413,7 @@ void print_autowrap(WINDOW * win, const char *prompt, int width, int y, int x)
                        if (wlen > room ||
                            (newl && wlen < 4 && sp
                             && wlen + 1 + strlen(sp) > room
-                            && (!(sp2 = strchr(sp, ' '))
+                            && (!(sp2 = strpbrk(sp, "\n "))
                                 || wlen + 1 + (sp2 - sp) > room))) {
                                cur_y++;
                                cur_x = x;
@@ -421,7 +421,15 @@ void print_autowrap(WINDOW * win, const char *prompt, int width, int y, int x)
                        wmove(win, cur_y, cur_x);
                        waddstr(win, word);
                        getyx(win, cur_y, cur_x);
-                       cur_x++;
+
+                       /* Move to the next line if the word separator was a newline */
+                       if (newline_separator) {
+                               cur_y++;
+                               cur_x = x;
+                               newline_separator = 0;
+                       } else
+                               cur_x++;
+
                        if (sp && *sp == ' ') {
                                cur_x++;        /* double space */
                                while (*++sp == ' ') ;
index 4e6e809..676fb2f 100644 (file)
@@ -45,14 +45,14 @@ int dialog_yesno(const char *title, const char *prompt, int height, int width)
        WINDOW *dialog;
 
 do_resize:
-       if (getmaxy(stdscr) < (height + 4))
+       if (getmaxy(stdscr) < (height + YESNO_HEIGTH_MIN))
                return -ERRDISPLAYTOOSMALL;
-       if (getmaxx(stdscr) < (width + 4))
+       if (getmaxx(stdscr) < (width + YESNO_WIDTH_MIN))
                return -ERRDISPLAYTOOSMALL;
 
        /* center dialog box on screen */
-       x = (COLS - width) / 2;
-       y = (LINES - height) / 2;
+       x = (getmaxx(stdscr) - width) / 2;
+       y = (getmaxy(stdscr) - height) / 2;
 
        draw_shadow(stdscr, y, x, height, width);
 
index a69cbd7..6c9c45f 100644 (file)
@@ -48,7 +48,7 @@ static const char mconf_readme[] = N_(
 "----------\n"
 "o  Use the Up/Down arrow keys (cursor keys) to highlight the item\n"
 "   you wish to change or submenu wish to select and press <Enter>.\n"
-"   Submenus are designated by \"--->\".\n"
+"   Submenus are designated by \"--->\", empty ones by \"----\".\n"
 "\n"
 "   Shortcut: Press the option's highlighted letter (hotkey).\n"
 "             Pressing a hotkey more than once will sequence\n"
@@ -176,7 +176,7 @@ static const char mconf_readme[] = N_(
 "\n"),
 menu_instructions[] = N_(
        "Arrow keys navigate the menu.  "
-       "<Enter> selects submenus --->.  "
+       "<Enter> selects submenus ---> (or empty submenus ----).  "
        "Highlighted letters are hotkeys.  "
        "Pressing <Y> includes, <N> excludes, <M> modularizes features.  "
        "Press <Esc><Esc> to exit, <?> for Help, </> for Search.  "
@@ -401,7 +401,7 @@ static void search_conf(void)
        struct subtitle_part stpart;
 
        title = str_new();
-       str_printf( &title, _("Enter %s (sub)string to search for "
+       str_printf( &title, _("Enter %s (sub)string or regexp to search for "
                              "(with or without \"%s\")"), CONFIG_, CONFIG_);
 
 again:
@@ -498,8 +498,9 @@ static void build_conf(struct menu *menu)
                                                  menu->data ? "-->" : "++>",
                                                  indent + 1, ' ', prompt);
                                } else
-                                       item_make("   %*c%s  --->", indent + 1, ' ', prompt);
-
+                                       item_make("   %*c%s  %s",
+                                                 indent + 1, ' ', prompt,
+                                                 menu_is_empty(menu) ? "----" : "--->");
                                item_set_tag('m');
                                item_set_data(menu);
                                if (single_menu_mode && menu->data)
@@ -630,7 +631,7 @@ static void build_conf(struct menu *menu)
                          (sym_has_value(sym) || !sym_is_changable(sym)) ?
                          "" : _(" (NEW)"));
                if (menu->prompt->type == P_MENU) {
-                       item_add_str("  --->");
+                       item_add_str("  %s", menu_is_empty(menu) ? "----" : "--->");
                        return;
                }
        }
@@ -826,7 +827,9 @@ static void conf_choice(struct menu *menu)
                dialog_clear();
                res = dialog_checklist(prompt ? _(prompt) : _("Main Menu"),
                                        _(radiolist_instructions),
-                                        15, 70, 6);
+                                       MENUBOX_HEIGTH_MIN,
+                                       MENUBOX_WIDTH_MIN,
+                                       CHECKLIST_HEIGTH_MIN);
                selected = item_activate_selected();
                switch (res) {
                case 0:
@@ -957,8 +960,8 @@ static int handle_exit(void)
        dialog_clear();
        if (conf_get_changed())
                res = dialog_yesno(NULL,
-                                  _("Do you wish to save your new configuration ?\n"
-                                    "<ESC><ESC> to continue."),
+                                  _("Do you wish to save your new configuration?\n"
+                                    "(Press <ESC><ESC> to continue kernel configuration.)"),
                                   6, 60);
        else
                res = -1;
index fd3f018..7e233a6 100644 (file)
@@ -443,6 +443,22 @@ bool menu_has_prompt(struct menu *menu)
        return true;
 }
 
+/*
+ * Determine if a menu is empty.
+ * A menu is considered empty if it contains no or only
+ * invisible entries.
+ */
+bool menu_is_empty(struct menu *menu)
+{
+       struct menu *child;
+
+       for (child = menu->list; child; child = child->next) {
+               if (menu_is_visible(child))
+                       return(false);
+       }
+       return(true);
+}
+
 bool menu_is_visible(struct menu *menu)
 {
        struct menu *child;
index dbf31ed..7975d8d 100644 (file)
@@ -45,8 +45,8 @@ static const char nconf_global_help[] = N_(
 "<n> to remove it.  You may press the <Space> key to cycle through the\n"
 "available options.\n"
 "\n"
-"A trailing \"--->\" designates a submenu.\n"
-"\n"
+"A trailing \"--->\" designates a submenu, a trailing \"----\" an\n"
+"empty submenu.\n"
 "\n"
 "Menu navigation keys\n"
 "----------------------------------------------------------------------\n"
@@ -131,7 +131,7 @@ static const char nconf_global_help[] = N_(
 "\n"),
 menu_no_f_instructions[] = N_(
 "Legend:  [*] built-in  [ ] excluded  <M> module  < > module capable.\n"
-"Submenus are designated by a trailing \"--->\".\n"
+"Submenus are designated by a trailing \"--->\", empty ones by \"----\".\n"
 "\n"
 "Use the following keys to navigate the menus:\n"
 "Move up or down with <Up> and <Down>.\n"
@@ -148,7 +148,7 @@ menu_no_f_instructions[] = N_(
 "For help related to the current menu entry press <?> or <h>.\n"),
 menu_instructions[] = N_(
 "Legend:  [*] built-in  [ ] excluded  <M> module  < > module capable.\n"
-"Submenus are designated by a trailing \"--->\".\n"
+"Submenus are designated by a trailing \"--->\", empty ones by \"----\".\n"
 "\n"
 "Use the following keys to navigate the menus:\n"
 "Move up or down with <Up> or <Down>.\n"
@@ -365,15 +365,16 @@ static void print_function_line(void)
        int i;
        int offset = 1;
        const int skip = 1;
+       int lines = getmaxy(stdscr);
 
        for (i = 0; i < function_keys_num; i++) {
                (void) wattrset(main_window, attributes[FUNCTION_HIGHLIGHT]);
-               mvwprintw(main_window, LINES-3, offset,
+               mvwprintw(main_window, lines-3, offset,
                                "%s",
                                function_keys[i].key_str);
                (void) wattrset(main_window, attributes[FUNCTION_TEXT]);
                offset += strlen(function_keys[i].key_str);
-               mvwprintw(main_window, LINES-3,
+               mvwprintw(main_window, lines-3,
                                offset, "%s",
                                function_keys[i].func);
                offset += strlen(function_keys[i].func) + skip;
@@ -694,7 +695,7 @@ static void search_conf(void)
        int dres;
 
        title = str_new();
-       str_printf( &title, _("Enter %s (sub)string to search for "
+       str_printf( &title, _("Enter %s (sub)string or regexp to search for "
                              "(with or without \"%s\")"), CONFIG_, CONFIG_);
 
 again:
@@ -759,9 +760,9 @@ static void build_conf(struct menu *menu)
                                                indent + 1, ' ', prompt);
                                } else
                                        item_make(menu, 'm',
-                                               "   %*c%s  --->",
-                                               indent + 1,
-                                               ' ', prompt);
+                                                 "   %*c%s  %s",
+                                                 indent + 1, ' ', prompt,
+                                                 menu_is_empty(menu) ? "----" : "--->");
 
                                if (single_menu_mode && menu->data)
                                        goto conf_childs;
@@ -903,7 +904,7 @@ static void build_conf(struct menu *menu)
                                (sym_has_value(sym) || !sym_is_changable(sym)) ?
                                "" : _(" (NEW)"));
                if (menu->prompt && menu->prompt->type == P_MENU) {
-                       item_add_str("  --->");
+                       item_add_str("  %s", menu_is_empty(menu) ? "----" : "--->");
                        return;
                }
        }
@@ -954,7 +955,7 @@ static void show_menu(const char *prompt, const char *instructions,
 
        clear();
        (void) wattrset(main_window, attributes[NORMAL]);
-       print_in_middle(stdscr, 1, 0, COLS,
+       print_in_middle(stdscr, 1, 0, getmaxx(stdscr),
                        menu_backtitle,
                        attributes[MAIN_HEADING]);
 
@@ -1455,14 +1456,18 @@ static void conf_save(void)
 
 void setup_windows(void)
 {
+       int lines, columns;
+
+       getmaxyx(stdscr, lines, columns);
+
        if (main_window != NULL)
                delwin(main_window);
 
        /* set up the menu and menu window */
-       main_window = newwin(LINES-2, COLS-2, 2, 1);
+       main_window = newwin(lines-2, columns-2, 2, 1);
        keypad(main_window, TRUE);
-       mwin_max_lines = LINES-7;
-       mwin_max_cols = COLS-6;
+       mwin_max_lines = lines-7;
+       mwin_max_cols = columns-6;
 
        /* panels order is from bottom to top */
        new_panel(main_window);
@@ -1470,6 +1475,7 @@ void setup_windows(void)
 
 int main(int ac, char **av)
 {
+       int lines, columns;
        char *mode;
 
        setlocale(LC_ALL, "");
@@ -1495,7 +1501,8 @@ int main(int ac, char **av)
        keypad(stdscr, TRUE);
        curs_set(0);
 
-       if (COLS < 75 || LINES < 20) {
+       getmaxyx(stdscr, lines, columns);
+       if (columns < 75 || lines < 20) {
                endwin();
                printf("Your terminal should have at "
                        "least 20 lines and 75 columns\n");
index 9f8c44e..8275f0e 100644 (file)
@@ -276,8 +276,8 @@ int btn_dialog(WINDOW *main_window, const char *msg, int btn_num, ...)
 
        total_width = max(msg_width, btns_width);
        /* place dialog in middle of screen */
-       y = (LINES-(msg_lines+4))/2;
-       x = (COLS-(total_width+4))/2;
+       y = (getmaxy(stdscr)-(msg_lines+4))/2;
+       x = (getmaxx(stdscr)-(total_width+4))/2;
 
 
        /* create the windows */
@@ -387,8 +387,8 @@ int dialog_inputbox(WINDOW *main_window,
                prompt_width = max(prompt_width, strlen(title));
 
        /* place dialog in middle of screen */
-       y = (LINES-(prompt_lines+4))/2;
-       x = (COLS-(prompt_width+4))/2;
+       y = (getmaxy(stdscr)-(prompt_lines+4))/2;
+       x = (getmaxx(stdscr)-(prompt_width+4))/2;
 
        strncpy(result, init, *result_len);
 
@@ -545,7 +545,7 @@ void show_scroll_win(WINDOW *main_window,
 {
        int res;
        int total_lines = get_line_no(text);
-       int x, y;
+       int x, y, lines, columns;
        int start_x = 0, start_y = 0;
        int text_lines = 0, text_cols = 0;
        int total_cols = 0;
@@ -556,6 +556,8 @@ void show_scroll_win(WINDOW *main_window,
        WINDOW *pad;
        PANEL *panel;
 
+       getmaxyx(stdscr, lines, columns);
+
        /* find the widest line of msg: */
        total_lines = get_line_no(text);
        for (i = 0; i < total_lines; i++) {
@@ -569,14 +571,14 @@ void show_scroll_win(WINDOW *main_window,
        (void) wattrset(pad, attributes[SCROLLWIN_TEXT]);
        fill_window(pad, text);
 
-       win_lines = min(total_lines+4, LINES-2);
-       win_cols = min(total_cols+2, COLS-2);
+       win_lines = min(total_lines+4, lines-2);
+       win_cols = min(total_cols+2, columns-2);
        text_lines = max(win_lines-4, 0);
        text_cols = max(win_cols-2, 0);
 
        /* place window in middle of screen */
-       y = (LINES-win_lines)/2;
-       x = (COLS-win_cols)/2;
+       y = (lines-win_lines)/2;
+       x = (columns-win_cols)/2;
 
        win = newwin(win_lines, win_cols, y, x);
        keypad(win, TRUE);
index ecc5aa5..d550300 100644 (file)
@@ -136,7 +136,7 @@ static struct property *sym_get_range_prop(struct symbol *sym)
        return NULL;
 }
 
-static int sym_get_range_val(struct symbol *sym, int base)
+static long sym_get_range_val(struct symbol *sym, int base)
 {
        sym_calc_value(sym);
        switch (sym->type) {
@@ -155,7 +155,7 @@ static int sym_get_range_val(struct symbol *sym, int base)
 static void sym_validate_range(struct symbol *sym)
 {
        struct property *prop;
-       int base, val, val2;
+       long base, val, val2;
        char str[64];
 
        switch (sym->type) {
@@ -179,9 +179,9 @@ static void sym_validate_range(struct symbol *sym)
                        return;
        }
        if (sym->type == S_INT)
-               sprintf(str, "%d", val2);
+               sprintf(str, "%ld", val2);
        else
-               sprintf(str, "0x%x", val2);
+               sprintf(str, "0x%lx", val2);
        sym->curr.val = strdup(str);
 }
 
@@ -300,6 +300,14 @@ void sym_calc_value(struct symbol *sym)
 
        if (sym->flags & SYMBOL_VALID)
                return;
+
+       if (sym_is_choice_value(sym) &&
+           sym->flags & SYMBOL_NEED_SET_CHOICE_VALUES) {
+               sym->flags &= ~SYMBOL_NEED_SET_CHOICE_VALUES;
+               prop = sym_get_choice_prop(sym);
+               sym_calc_value(prop_get_symbol(prop));
+       }
+
        sym->flags |= SYMBOL_VALID;
 
        oldval = sym->curr;
@@ -425,6 +433,9 @@ void sym_calc_value(struct symbol *sym)
 
        if (sym->flags & SYMBOL_AUTO)
                sym->flags &= ~SYMBOL_WRITE;
+
+       if (sym->flags & SYMBOL_NEED_SET_CHOICE_VALUES)
+               set_all_choice_values(sym);
 }
 
 void sym_clear_all_valid(void)
@@ -583,7 +594,7 @@ bool sym_string_valid(struct symbol *sym, const char *str)
 bool sym_string_within_range(struct symbol *sym, const char *str)
 {
        struct property *prop;
-       int val;
+       long val;
 
        switch (sym->type) {
        case S_STRING:
@@ -943,38 +954,98 @@ const char *sym_escape_string_value(const char *in)
        return res;
 }
 
+struct sym_match {
+       struct symbol   *sym;
+       off_t           so, eo;
+};
+
+/* Compare matched symbols as thus:
+ * - first, symbols that match exactly
+ * - then, alphabetical sort
+ */
+static int sym_rel_comp( const void *sym1, const void *sym2 )
+{
+       struct sym_match *s1 = *(struct sym_match **)sym1;
+       struct sym_match *s2 = *(struct sym_match **)sym2;
+       int l1, l2;
+
+       /* Exact match:
+        * - if matched length on symbol s1 is the length of that symbol,
+        *   then this symbol should come first;
+        * - if matched length on symbol s2 is the length of that symbol,
+        *   then this symbol should come first.
+        * Note: since the search can be a regexp, both symbols may match
+        * exactly; if this is the case, we can't decide which comes first,
+        * and we fallback to sorting alphabetically.
+        */
+       l1 = s1->eo - s1->so;
+       l2 = s2->eo - s2->so;
+       if (l1 == strlen(s1->sym->name) && l2 != strlen(s2->sym->name))
+               return -1;
+       if (l1 != strlen(s1->sym->name) && l2 == strlen(s2->sym->name))
+               return 1;
+
+       /* As a fallback, sort symbols alphabetically */
+       return strcmp(s1->sym->name, s2->sym->name);
+}
+
 struct symbol **sym_re_search(const char *pattern)
 {
        struct symbol *sym, **sym_arr = NULL;
+       struct sym_match **sym_match_arr = NULL;
        int i, cnt, size;
        regex_t re;
+       regmatch_t match[1];
 
        cnt = size = 0;
        /* Skip if empty */
        if (strlen(pattern) == 0)
                return NULL;
-       if (regcomp(&re, pattern, REG_EXTENDED|REG_NOSUB|REG_ICASE))
+       if (regcomp(&re, pattern, REG_EXTENDED|REG_ICASE))
                return NULL;
 
        for_all_symbols(i, sym) {
+               struct sym_match *tmp_sym_match;
                if (sym->flags & SYMBOL_CONST || !sym->name)
                        continue;
-               if (regexec(&re, sym->name, 0, NULL, 0))
+               if (regexec(&re, sym->name, 1, match, 0))
                        continue;
                if (cnt + 1 >= size) {
-                       void *tmp = sym_arr;
+                       void *tmp;
                        size += 16;
-                       sym_arr = realloc(sym_arr, size * sizeof(struct symbol *));
-                       if (!sym_arr) {
-                               free(tmp);
-                               return NULL;
+                       tmp = realloc(sym_match_arr, size * sizeof(struct sym_match *));
+                       if (!tmp) {
+                               goto sym_re_search_free;
                        }
+                       sym_match_arr = tmp;
                }
                sym_calc_value(sym);
-               sym_arr[cnt++] = sym;
+               tmp_sym_match = (struct sym_match*)malloc(sizeof(struct sym_match));
+               if (!tmp_sym_match)
+                       goto sym_re_search_free;
+               tmp_sym_match->sym = sym;
+               /* As regexec return 0, we know we have a match, so
+                * we can use match[0].rm_[se]o without further checks
+                */
+               tmp_sym_match->so = match[0].rm_so;
+               tmp_sym_match->eo = match[0].rm_eo;
+               sym_match_arr[cnt++] = tmp_sym_match;
        }
-       if (sym_arr)
+       if (sym_match_arr) {
+               qsort(sym_match_arr, cnt, sizeof(struct sym_match*), sym_rel_comp);
+               sym_arr = malloc((cnt+1) * sizeof(struct symbol));
+               if (!sym_arr)
+                       goto sym_re_search_free;
+               for (i = 0; i < cnt; i++)
+                       sym_arr[i] = sym_match_arr[i]->sym;
                sym_arr[cnt] = NULL;
+       }
+sym_re_search_free:
+       if (sym_match_arr) {
+               for (i = 0; i < cnt; i++)
+                       free(sym_match_arr[i]);
+               free(sym_match_arr);
+       }
        regfree(&re);
 
        return sym_arr;
index 75d59fc..c11212f 100644 (file)
@@ -15,8 +15,8 @@ endef
 quiet_cmd_offsets = GEN     $@
 define cmd_offsets
        (set -e; \
-        echo "#ifndef __DEVICEVTABLE_OFFSETS_H__"; \
-        echo "#define __DEVICEVTABLE_OFFSETS_H__"; \
+        echo "#ifndef __DEVICETABLE_OFFSETS_H__"; \
+        echo "#define __DEVICETABLE_OFFSETS_H__"; \
         echo "/*"; \
         echo " * DO NOT MODIFY."; \
         echo " *"; \
@@ -29,15 +29,10 @@ define cmd_offsets
         echo "#endif" ) > $@
 endef
 
-# We use internal kbuild rules to avoid the "is up to date" message from make
-scripts/mod/devicetable-offsets.s: scripts/mod/devicetable-offsets.c FORCE
-       $(Q)mkdir -p $(dir $@)
-       $(call if_changed_dep,cc_s_c)
+$(obj)/$(devicetable-offsets-file): $(obj)/devicetable-offsets.s
+       $(call if_changed,offsets)
 
-$(obj)/$(devicetable-offsets-file): scripts/mod/devicetable-offsets.s
-       $(call cmd,offsets)
-
-targets += $(devicetable-offsets-file)
+targets += $(devicetable-offsets-file) devicetable-offsets.s
 
 # dependencies on generated files need to be listed explicitly
 
index d9e67b7..2370863 100644 (file)
@@ -79,10 +79,12 @@ struct devtable **__start___devtable, **__stop___devtable;
 extern struct devtable *__start___devtable[], *__stop___devtable[];
 #endif /* __MACH__ */
 
-#if __GNUC__ == 3 && __GNUC_MINOR__ < 3
-# define __used                        __attribute__((__unused__))
-#else
-# define __used                        __attribute__((__used__))
+#if !defined(__used)
+# if __GNUC__ == 3 && __GNUC_MINOR__ < 3
+#  define __used                       __attribute__((__unused__))
+# else
+#  define __used                       __attribute__((__used__))
+# endif
 #endif
 
 /* Define a variable f that holds the value of field f of struct devid
index fbbfd08..fdd3fbf 100755 (executable)
@@ -74,6 +74,7 @@ echo ""
 fi
 
 echo "%install"
+echo 'KBUILD_IMAGE=$(make image_name)'
 echo "%ifarch ia64"
 echo 'mkdir -p $RPM_BUILD_ROOT/boot/efi $RPM_BUILD_ROOT/lib/modules'
 echo 'mkdir -p $RPM_BUILD_ROOT/lib/firmware'
index 84b88f1..d105a44 100755 (executable)
@@ -71,9 +71,6 @@ scm_version()
                        printf -- '-svn%s' "`git svn find-rev $head`"
                fi
 
-               # Update index only on r/w media
-               [ -w . ] && git update-index --refresh --unmerged > /dev/null
-
                # Check for uncommitted changes
                if git diff-index --name-only HEAD | grep -qv "^scripts/package"; then
                        printf '%s' -dirty
index d32e16e..32b5157 100644 (file)
@@ -858,7 +858,7 @@ static int cap_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen)
 
 static int cap_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen)
 {
-       return 0;
+       return -EOPNOTSUPP;
 }
 #ifdef CONFIG_KEYS
 static int cap_key_alloc(struct key *key, const struct cred *cred,
index d428ffe..58a5afe 100644 (file)
@@ -626,9 +626,9 @@ static u64 get_unit_base(struct fw_unit *unit)
        return 0;
 }
 
-static int isight_probe(struct device *unit_dev)
+static int isight_probe(struct fw_unit *unit,
+                       const struct ieee1394_device_id *id)
 {
-       struct fw_unit *unit = fw_unit(unit_dev);
        struct fw_device *fw_dev = fw_parent_device(unit);
        struct snd_card *card;
        struct isight *isight;
@@ -637,7 +637,7 @@ static int isight_probe(struct device *unit_dev)
        err = snd_card_create(-1, NULL, THIS_MODULE, sizeof(*isight), &card);
        if (err < 0)
                return err;
-       snd_card_set_dev(card, unit_dev);
+       snd_card_set_dev(card, &unit->device);
 
        isight = card->private_data;
        isight->card = card;
@@ -674,7 +674,7 @@ static int isight_probe(struct device *unit_dev)
        if (err < 0)
                goto error;
 
-       dev_set_drvdata(unit_dev, isight);
+       dev_set_drvdata(&unit->device, isight);
 
        return 0;
 
@@ -686,23 +686,6 @@ error:
        return err;
 }
 
-static int isight_remove(struct device *dev)
-{
-       struct isight *isight = dev_get_drvdata(dev);
-
-       isight_pcm_abort(isight);
-
-       snd_card_disconnect(isight->card);
-
-       mutex_lock(&isight->mutex);
-       isight_stop_streaming(isight);
-       mutex_unlock(&isight->mutex);
-
-       snd_card_free_when_closed(isight->card);
-
-       return 0;
-}
-
 static void isight_bus_reset(struct fw_unit *unit)
 {
        struct isight *isight = dev_get_drvdata(&unit->device);
@@ -716,6 +699,21 @@ static void isight_bus_reset(struct fw_unit *unit)
        }
 }
 
+static void isight_remove(struct fw_unit *unit)
+{
+       struct isight *isight = dev_get_drvdata(&unit->device);
+
+       isight_pcm_abort(isight);
+
+       snd_card_disconnect(isight->card);
+
+       mutex_lock(&isight->mutex);
+       isight_stop_streaming(isight);
+       mutex_unlock(&isight->mutex);
+
+       snd_card_free_when_closed(isight->card);
+}
+
 static const struct ieee1394_device_id isight_id_table[] = {
        {
                .match_flags  = IEEE1394_MATCH_SPECIFIER_ID |
@@ -732,10 +730,10 @@ static struct fw_driver isight_driver = {
                .owner  = THIS_MODULE,
                .name   = KBUILD_MODNAME,
                .bus    = &fw_bus_type,
-               .probe  = isight_probe,
-               .remove = isight_remove,
        },
+       .probe    = isight_probe,
        .update   = isight_bus_reset,
+       .remove   = isight_remove,
        .id_table = isight_id_table,
 };
 
index b252c21..505fc81 100644 (file)
@@ -384,9 +384,8 @@ static void scs_card_free(struct snd_card *card)
        kfree(scs->buffer);
 }
 
-static int scs_probe(struct device *unit_dev)
+static int scs_probe(struct fw_unit *unit, const struct ieee1394_device_id *id)
 {
-       struct fw_unit *unit = fw_unit(unit_dev);
        struct fw_device *fw_dev = fw_parent_device(unit);
        struct snd_card *card;
        struct scs *scs;
@@ -395,7 +394,7 @@ static int scs_probe(struct device *unit_dev)
        err = snd_card_create(-16, NULL, THIS_MODULE, sizeof(*scs), &card);
        if (err < 0)
                return err;
-       snd_card_set_dev(card, unit_dev);
+       snd_card_set_dev(card, &unit->device);
 
        scs = card->private_data;
        scs->card = card;
@@ -442,7 +441,7 @@ static int scs_probe(struct device *unit_dev)
        if (err < 0)
                goto err_card;
 
-       dev_set_drvdata(unit_dev, scs);
+       dev_set_drvdata(&unit->device, scs);
 
        return 0;
 
@@ -453,9 +452,20 @@ err_card:
        return err;
 }
 
-static int scs_remove(struct device *dev)
+static void scs_update(struct fw_unit *unit)
 {
-       struct scs *scs = dev_get_drvdata(dev);
+       struct scs *scs = dev_get_drvdata(&unit->device);
+       __be64 data;
+
+       data = cpu_to_be64(((u64)HSS1394_TAG_CHANGE_ADDRESS << 56) |
+                          scs->hss_handler.offset);
+       snd_fw_transaction(scs->unit, TCODE_WRITE_BLOCK_REQUEST,
+                          HSS1394_ADDRESS, &data, 8);
+}
+
+static void scs_remove(struct fw_unit *unit)
+{
+       struct scs *scs = dev_get_drvdata(&unit->device);
 
        snd_card_disconnect(scs->card);
 
@@ -467,19 +477,6 @@ static int scs_remove(struct device *dev)
        tasklet_kill(&scs->tasklet);
 
        snd_card_free_when_closed(scs->card);
-
-       return 0;
-}
-
-static void scs_update(struct fw_unit *unit)
-{
-       struct scs *scs = dev_get_drvdata(&unit->device);
-       __be64 data;
-
-       data = cpu_to_be64(((u64)HSS1394_TAG_CHANGE_ADDRESS << 56) |
-                          scs->hss_handler.offset);
-       snd_fw_transaction(scs->unit, TCODE_WRITE_BLOCK_REQUEST,
-                          HSS1394_ADDRESS, &data, 8);
 }
 
 static const struct ieee1394_device_id scs_id_table[] = {
@@ -508,10 +505,10 @@ static struct fw_driver scs_driver = {
                .owner  = THIS_MODULE,
                .name   = KBUILD_MODNAME,
                .bus    = &fw_bus_type,
-               .probe  = scs_probe,
-               .remove = scs_remove,
        },
+       .probe    = scs_probe,
        .update   = scs_update,
+       .remove   = scs_remove,
        .id_table = scs_id_table,
 };
 
index d684655..2c63865 100644 (file)
@@ -663,45 +663,9 @@ static void fwspk_card_free(struct snd_card *card)
        mutex_destroy(&fwspk->mutex);
 }
 
-static const struct device_info *fwspk_detect(struct fw_device *dev)
+static int fwspk_probe(struct fw_unit *unit,
+                      const struct ieee1394_device_id *id)
 {
-       static const struct device_info griffin_firewave = {
-               .driver_name = "FireWave",
-               .short_name  = "FireWave",
-               .long_name   = "Griffin FireWave Surround",
-               .pcm_constraints = firewave_constraints,
-               .mixer_channels = 6,
-               .mute_fb_id   = 0x01,
-               .volume_fb_id = 0x02,
-       };
-       static const struct device_info lacie_speakers = {
-               .driver_name = "FWSpeakers",
-               .short_name  = "FireWire Speakers",
-               .long_name   = "LaCie FireWire Speakers",
-               .pcm_constraints = lacie_speakers_constraints,
-               .mixer_channels = 1,
-               .mute_fb_id   = 0x01,
-               .volume_fb_id = 0x01,
-       };
-       struct fw_csr_iterator i;
-       int key, value;
-
-       fw_csr_iterator_init(&i, dev->config_rom);
-       while (fw_csr_iterator_next(&i, &key, &value))
-               if (key == CSR_VENDOR)
-                       switch (value) {
-                       case VENDOR_GRIFFIN:
-                               return &griffin_firewave;
-                       case VENDOR_LACIE:
-                               return &lacie_speakers;
-                       }
-
-       return NULL;
-}
-
-static int fwspk_probe(struct device *unit_dev)
-{
-       struct fw_unit *unit = fw_unit(unit_dev);
        struct fw_device *fw_dev = fw_parent_device(unit);
        struct snd_card *card;
        struct fwspk *fwspk;
@@ -711,17 +675,13 @@ static int fwspk_probe(struct device *unit_dev)
        err = snd_card_create(-1, NULL, THIS_MODULE, sizeof(*fwspk), &card);
        if (err < 0)
                return err;
-       snd_card_set_dev(card, unit_dev);
+       snd_card_set_dev(card, &unit->device);
 
        fwspk = card->private_data;
        fwspk->card = card;
        mutex_init(&fwspk->mutex);
        fwspk->unit = fw_unit_get(unit);
-       fwspk->device_info = fwspk_detect(fw_dev);
-       if (!fwspk->device_info) {
-               err = -ENODEV;
-               goto err_unit;
-       }
+       fwspk->device_info = (const struct device_info *)id->driver_data;
 
        err = cmp_connection_init(&fwspk->connection, unit, 0);
        if (err < 0)
@@ -756,7 +716,7 @@ static int fwspk_probe(struct device *unit_dev)
        if (err < 0)
                goto error;
 
-       dev_set_drvdata(unit_dev, fwspk);
+       dev_set_drvdata(&unit->device, fwspk);
 
        return 0;
 
@@ -770,22 +730,6 @@ error:
        return err;
 }
 
-static int fwspk_remove(struct device *dev)
-{
-       struct fwspk *fwspk = dev_get_drvdata(dev);
-
-       amdtp_out_stream_pcm_abort(&fwspk->stream);
-       snd_card_disconnect(fwspk->card);
-
-       mutex_lock(&fwspk->mutex);
-       fwspk_stop_stream(fwspk);
-       mutex_unlock(&fwspk->mutex);
-
-       snd_card_free_when_closed(fwspk->card);
-
-       return 0;
-}
-
 static void fwspk_bus_reset(struct fw_unit *unit)
 {
        struct fwspk *fwspk = dev_get_drvdata(&unit->device);
@@ -803,6 +747,40 @@ static void fwspk_bus_reset(struct fw_unit *unit)
        amdtp_out_stream_update(&fwspk->stream);
 }
 
+static void fwspk_remove(struct fw_unit *unit)
+{
+       struct fwspk *fwspk = dev_get_drvdata(&unit->device);
+
+       amdtp_out_stream_pcm_abort(&fwspk->stream);
+       snd_card_disconnect(fwspk->card);
+
+       mutex_lock(&fwspk->mutex);
+       fwspk_stop_stream(fwspk);
+       mutex_unlock(&fwspk->mutex);
+
+       snd_card_free_when_closed(fwspk->card);
+}
+
+static const struct device_info griffin_firewave = {
+       .driver_name = "FireWave",
+       .short_name  = "FireWave",
+       .long_name   = "Griffin FireWave Surround",
+       .pcm_constraints = firewave_constraints,
+       .mixer_channels = 6,
+       .mute_fb_id   = 0x01,
+       .volume_fb_id = 0x02,
+};
+
+static const struct device_info lacie_speakers = {
+       .driver_name = "FWSpeakers",
+       .short_name  = "FireWire Speakers",
+       .long_name   = "LaCie FireWire Speakers",
+       .pcm_constraints = lacie_speakers_constraints,
+       .mixer_channels = 1,
+       .mute_fb_id   = 0x01,
+       .volume_fb_id = 0x01,
+};
+
 static const struct ieee1394_device_id fwspk_id_table[] = {
        {
                .match_flags  = IEEE1394_MATCH_VENDOR_ID |
@@ -813,6 +791,7 @@ static const struct ieee1394_device_id fwspk_id_table[] = {
                .model_id     = 0x00f970,
                .specifier_id = SPECIFIER_1394TA,
                .version      = VERSION_AVC,
+               .driver_data  = (kernel_ulong_t)&griffin_firewave,
        },
        {
                .match_flags  = IEEE1394_MATCH_VENDOR_ID |
@@ -823,6 +802,7 @@ static const struct ieee1394_device_id fwspk_id_table[] = {
                .model_id     = 0x00f970,
                .specifier_id = SPECIFIER_1394TA,
                .version      = VERSION_AVC,
+               .driver_data  = (kernel_ulong_t)&lacie_speakers,
        },
        { }
 };
@@ -833,10 +813,10 @@ static struct fw_driver fwspk_driver = {
                .owner  = THIS_MODULE,
                .name   = KBUILD_MODNAME,
                .bus    = &fw_bus_type,
-               .probe  = fwspk_probe,
-               .remove = fwspk_remove,
        },
+       .probe    = fwspk_probe,
        .update   = fwspk_bus_reset,
+       .remove   = fwspk_remove,
        .id_table = fwspk_id_table,
 };
 
index 977b0d8..d97f0d6 100644 (file)
@@ -2112,6 +2112,9 @@ static void ad_vmaster_eapd_hook(void *private_data, int enabled)
 {
        struct hda_codec *codec = private_data;
        struct ad198x_spec *spec = codec->spec;
+
+       if (!spec->eapd_nid)
+               return;
        snd_hda_codec_update_cache(codec, spec->eapd_nid, 0,
                                   AC_VERB_SET_EAPD_BTLENABLE,
                                   enabled ? 0x02 : 0x00);
@@ -3601,13 +3604,16 @@ static void ad1884_fixup_hp_eapd(struct hda_codec *codec,
 {
        struct ad198x_spec *spec = codec->spec;
 
-       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+       switch (action) {
+       case HDA_FIXUP_ACT_PRE_PROBE:
+               spec->gen.vmaster_mute.hook = ad_vmaster_eapd_hook;
+               break;
+       case HDA_FIXUP_ACT_PROBE:
                if (spec->gen.autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT)
                        spec->eapd_nid = spec->gen.autocfg.line_out_pins[0];
                else
                        spec->eapd_nid = spec->gen.autocfg.speaker_pins[0];
-               if (spec->eapd_nid)
-                       spec->gen.vmaster_mute.hook = ad_vmaster_eapd_hook;
+               break;
        }
 }
 
index 14ac9b0..8bd2261 100644 (file)
@@ -37,6 +37,9 @@
 #include "hda_jack.h"
 #include "hda_generic.h"
 
+/* keep halting ALC5505 DSP, for power saving */
+#define HALT_REALTEK_ALC5505
+
 /* unsol event tags */
 #define ALC_DCVOL_EVENT                0x08
 
@@ -2659,15 +2662,27 @@ static void alc5505_dsp_init(struct hda_codec *codec)
        alc5505_coef_set(codec, 0x880c, 0x00000004); /* DRAM Function control */
        alc5505_coef_set(codec, 0x880c, 0x00000003);
        alc5505_coef_set(codec, 0x880c, 0x00000010);
+
+#ifdef HALT_REALTEK_ALC5505
+       alc5505_dsp_halt(codec);
+#endif
 }
 
+#ifdef HALT_REALTEK_ALC5505
+#define alc5505_dsp_suspend(codec)     /* NOP */
+#define alc5505_dsp_resume(codec)      /* NOP */
+#else
+#define alc5505_dsp_suspend(codec)     alc5505_dsp_halt(codec)
+#define alc5505_dsp_resume(codec)      alc5505_dsp_back_from_halt(codec)
+#endif
+
 #ifdef CONFIG_PM
 static int alc269_suspend(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
 
        if (spec->has_alc5505_dsp)
-               alc5505_dsp_halt(codec);
+               alc5505_dsp_suspend(codec);
        return alc_suspend(codec);
 }
 
@@ -2696,7 +2711,7 @@ static int alc269_resume(struct hda_codec *codec)
        alc_inv_dmic_sync(codec, true);
        hda_call_check_power_status(codec, 0x01);
        if (spec->has_alc5505_dsp)
-               alc5505_dsp_back_from_halt(codec);
+               alc5505_dsp_resume(codec);
        return 0;
 }
 #endif /* CONFIG_PM */
index b1dc7d4..e2de9ec 100644 (file)
@@ -3377,7 +3377,7 @@ static int wm8962_probe(struct snd_soc_codec *codec)
 {
        int ret;
        struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
-       struct wm8962_pdata *pdata = dev_get_platdata(codec->dev);
+       struct wm8962_pdata *pdata = &wm8962->pdata;
        int i, trigger, irq_pol;
        bool dmicclk, dmicdat;
 
index 7a8bc12..3f726e4 100644 (file)
@@ -113,13 +113,13 @@ static int imx_sgtl5000_probe(struct platform_device *pdev)
        ssi_pdev = of_find_device_by_node(ssi_np);
        if (!ssi_pdev) {
                dev_err(&pdev->dev, "failed to find SSI platform device\n");
-               ret = -EINVAL;
+               ret = -EPROBE_DEFER;
                goto fail;
        }
        codec_dev = of_find_i2c_device_by_node(codec_np);
        if (!codec_dev) {
                dev_err(&pdev->dev, "failed to find codec platform device\n");
-               return -EINVAL;
+               return -EPROBE_DEFER;
        }
 
        data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
index 49d8700..54511c5 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/slab.h>
 #include <linux/dma-mapping.h>
 #include <linux/clk.h>
+#include <linux/clk-provider.h>
 #include <linux/delay.h>
 #include <linux/time.h>
 #include <sound/core.h>
@@ -658,6 +659,33 @@ static irqreturn_t mxs_saif_irq(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
+static int mxs_saif_mclk_init(struct platform_device *pdev)
+{
+       struct mxs_saif *saif = platform_get_drvdata(pdev);
+       struct device_node *np = pdev->dev.of_node;
+       struct clk *clk;
+       int ret;
+
+       clk = clk_register_divider(&pdev->dev, "mxs_saif_mclk",
+                                  __clk_get_name(saif->clk), 0,
+                                  saif->base + SAIF_CTRL,
+                                  BP_SAIF_CTRL_BITCLK_MULT_RATE, 3,
+                                  0, NULL);
+       if (IS_ERR(clk)) {
+               ret = PTR_ERR(clk);
+               if (ret == -EEXIST)
+                       return 0;
+               dev_err(&pdev->dev, "failed to register mclk: %d\n", ret);
+               return PTR_ERR(clk);
+       }
+
+       ret = of_clk_add_provider(np, of_clk_src_simple_get, clk);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
 static int mxs_saif_probe(struct platform_device *pdev)
 {
        struct device_node *np = pdev->dev.of_node;
@@ -734,6 +762,13 @@ static int mxs_saif_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, saif);
 
+       /* We only support saif0 being tx and clock master */
+       if (saif->id == 0) {
+               ret = mxs_saif_mclk_init(pdev);
+               if (ret)
+                       dev_warn(&pdev->dev, "failed to init clocks\n");
+       }
+
        ret = snd_soc_register_component(&pdev->dev, &mxs_saif_component,
                                         &mxs_saif_dai, 1);
        if (ret) {
index 249cd23..611179c 100644 (file)
@@ -396,7 +396,7 @@ static int __init rx51_soc_init(void)
 {
        int err;
 
-       if (!machine_is_nokia_rx51())
+       if (!machine_is_nokia_rx51() && !of_machine_is_compatible("nokia,omap3-n900"))
                return -ENODEV;
 
        err = gpio_request_one(RX51_TVOUT_SEL_GPIO,
index 82ebb1a..7a17346 100644 (file)
@@ -1016,52 +1016,6 @@ static struct i2s_dai *i2s_alloc_dai(struct platform_device *pdev, bool sec)
        return i2s;
 }
 
-#ifdef CONFIG_OF
-static int samsung_i2s_parse_dt_gpio(struct i2s_dai *i2s)
-{
-       struct device *dev = &i2s->pdev->dev;
-       int index, gpio, ret;
-
-       for (index = 0; index < 7; index++) {
-               gpio = of_get_gpio(dev->of_node, index);
-               if (!gpio_is_valid(gpio)) {
-                       dev_err(dev, "invalid gpio[%d]: %d\n", index, gpio);
-                       goto free_gpio;
-               }
-
-               ret = gpio_request(gpio, dev_name(dev));
-               if (ret) {
-                       dev_err(dev, "gpio [%d] request failed\n", gpio);
-                       goto free_gpio;
-               }
-               i2s->gpios[index] = gpio;
-       }
-       return 0;
-
-free_gpio:
-       while (--index >= 0)
-               gpio_free(i2s->gpios[index]);
-       return -EINVAL;
-}
-
-static void samsung_i2s_dt_gpio_free(struct i2s_dai *i2s)
-{
-       unsigned int index;
-       for (index = 0; index < 7; index++)
-               gpio_free(i2s->gpios[index]);
-}
-#else
-static int samsung_i2s_parse_dt_gpio(struct i2s_dai *dai)
-{
-       return -EINVAL;
-}
-
-static void samsung_i2s_dt_gpio_free(struct i2s_dai *dai)
-{
-}
-
-#endif
-
 static const struct of_device_id exynos_i2s_match[];
 
 static inline int samsung_i2s_get_driver_data(struct platform_device *pdev)
@@ -1235,18 +1189,10 @@ static int samsung_i2s_probe(struct platform_device *pdev)
                pri_dai->sec_dai = sec_dai;
        }
 
-       if (np) {
-               if (samsung_i2s_parse_dt_gpio(pri_dai)) {
-                       dev_err(&pdev->dev, "Unable to configure gpio\n");
-                       ret = -EINVAL;
-                       goto err;
-               }
-       } else {
-               if (i2s_pdata->cfg_gpio && i2s_pdata->cfg_gpio(pdev)) {
-                       dev_err(&pdev->dev, "Unable to configure gpio\n");
-                       ret = -EINVAL;
-                       goto err;
-               }
+       if (i2s_pdata && i2s_pdata->cfg_gpio && i2s_pdata->cfg_gpio(pdev)) {
+               dev_err(&pdev->dev, "Unable to configure gpio\n");
+               ret = -EINVAL;
+               goto err;
        }
 
        snd_soc_register_component(&pri_dai->pdev->dev, &samsung_i2s_component,
@@ -1267,14 +1213,10 @@ static int samsung_i2s_remove(struct platform_device *pdev)
 {
        struct i2s_dai *i2s, *other;
        struct resource *res;
-       struct s3c_audio_pdata *i2s_pdata = pdev->dev.platform_data;
 
        i2s = dev_get_drvdata(&pdev->dev);
        other = i2s->pri_dai ? : i2s->sec_dai;
 
-       if (!i2s_pdata->cfg_gpio && pdev->dev.of_node)
-               samsung_i2s_dt_gpio_free(i2s->pri_dai);
-
        if (other) {
                other->pri_dai = NULL;
                other->sec_dai = NULL;
index 20e98d1..e5e81b1 100644 (file)
@@ -1,6 +1,4 @@
-/* sound/soc/samsung/s3c-i2c-v2.c
- *
- * ALSA Soc Audio Layer - I2S core for newer Samsung SoCs.
+/* ALSA Soc Audio Layer - I2S core for newer Samsung SoCs.
  *
  * Copyright (c) 2006 Wolfson Microelectronics PLC.
  *     Graeme Gregory graeme.gregory@wolfsonmicro.com
index 5b01330..1bc45e7 100644 (file)
@@ -129,6 +129,7 @@ static int create_fixed_stream_quirk(struct snd_usb_audio *chip,
 {
        struct audioformat *fp;
        struct usb_host_interface *alts;
+       struct usb_interface_descriptor *altsd;
        int stream, err;
        unsigned *rate_table = NULL;
 
@@ -166,6 +167,9 @@ static int create_fixed_stream_quirk(struct snd_usb_audio *chip,
                return -EINVAL;
        }
        alts = &iface->altsetting[fp->altset_idx];
+       altsd = get_iface_desc(alts);
+       fp->protocol = altsd->bInterfaceProtocol;
+
        if (fp->datainterval == 0)
                fp->datainterval = snd_usb_parse_datainterval(chip, alts);
        if (fp->maxpacksize == 0)
index f4912e2..84c17d8 100644 (file)
@@ -1,68 +1,68 @@
 #ifndef _TOOLS_BE_BYTESHIFT_H
 #define _TOOLS_BE_BYTESHIFT_H
 
-#include <linux/types.h>
+#include <stdint.h>
 
-static inline __u16 __get_unaligned_be16(const __u8 *p)
+static inline uint16_t __get_unaligned_be16(const uint8_t *p)
 {
        return p[0] << 8 | p[1];
 }
 
-static inline __u32 __get_unaligned_be32(const __u8 *p)
+static inline uint32_t __get_unaligned_be32(const uint8_t *p)
 {
        return p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3];
 }
 
-static inline __u64 __get_unaligned_be64(const __u8 *p)
+static inline uint64_t __get_unaligned_be64(const uint8_t *p)
 {
-       return (__u64)__get_unaligned_be32(p) << 32 |
+       return (uint64_t)__get_unaligned_be32(p) << 32 |
               __get_unaligned_be32(p + 4);
 }
 
-static inline void __put_unaligned_be16(__u16 val, __u8 *p)
+static inline void __put_unaligned_be16(uint16_t val, uint8_t *p)
 {
        *p++ = val >> 8;
        *p++ = val;
 }
 
-static inline void __put_unaligned_be32(__u32 val, __u8 *p)
+static inline void __put_unaligned_be32(uint32_t val, uint8_t *p)
 {
        __put_unaligned_be16(val >> 16, p);
        __put_unaligned_be16(val, p + 2);
 }
 
-static inline void __put_unaligned_be64(__u64 val, __u8 *p)
+static inline void __put_unaligned_be64(uint64_t val, uint8_t *p)
 {
        __put_unaligned_be32(val >> 32, p);
        __put_unaligned_be32(val, p + 4);
 }
 
-static inline __u16 get_unaligned_be16(const void *p)
+static inline uint16_t get_unaligned_be16(const void *p)
 {
-       return __get_unaligned_be16((const __u8 *)p);
+       return __get_unaligned_be16((const uint8_t *)p);
 }
 
-static inline __u32 get_unaligned_be32(const void *p)
+static inline uint32_t get_unaligned_be32(const void *p)
 {
-       return __get_unaligned_be32((const __u8 *)p);
+       return __get_unaligned_be32((const uint8_t *)p);
 }
 
-static inline __u64 get_unaligned_be64(const void *p)
+static inline uint64_t get_unaligned_be64(const void *p)
 {
-       return __get_unaligned_be64((const __u8 *)p);
+       return __get_unaligned_be64((const uint8_t *)p);
 }
 
-static inline void put_unaligned_be16(__u16 val, void *p)
+static inline void put_unaligned_be16(uint16_t val, void *p)
 {
        __put_unaligned_be16(val, p);
 }
 
-static inline void put_unaligned_be32(__u32 val, void *p)
+static inline void put_unaligned_be32(uint32_t val, void *p)
 {
        __put_unaligned_be32(val, p);
 }
 
-static inline void put_unaligned_be64(__u64 val, void *p)
+static inline void put_unaligned_be64(uint64_t val, void *p)
 {
        __put_unaligned_be64(val, p);
 }
index c99d45a..8fe9f24 100644 (file)
@@ -1,68 +1,68 @@
 #ifndef _TOOLS_LE_BYTESHIFT_H
 #define _TOOLS_LE_BYTESHIFT_H
 
-#include <linux/types.h>
+#include <stdint.h>
 
-static inline __u16 __get_unaligned_le16(const __u8 *p)
+static inline uint16_t __get_unaligned_le16(const uint8_t *p)
 {
        return p[0] | p[1] << 8;
 }
 
-static inline __u32 __get_unaligned_le32(const __u8 *p)
+static inline uint32_t __get_unaligned_le32(const uint8_t *p)
 {
        return p[0] | p[1] << 8 | p[2] << 16 | p[3] << 24;
 }
 
-static inline __u64 __get_unaligned_le64(const __u8 *p)
+static inline uint64_t __get_unaligned_le64(const uint8_t *p)
 {
-       return (__u64)__get_unaligned_le32(p + 4) << 32 |
+       return (uint64_t)__get_unaligned_le32(p + 4) << 32 |
               __get_unaligned_le32(p);
 }
 
-static inline void __put_unaligned_le16(__u16 val, __u8 *p)
+static inline void __put_unaligned_le16(uint16_t val, uint8_t *p)
 {
        *p++ = val;
        *p++ = val >> 8;
 }
 
-static inline void __put_unaligned_le32(__u32 val, __u8 *p)
+static inline void __put_unaligned_le32(uint32_t val, uint8_t *p)
 {
        __put_unaligned_le16(val >> 16, p + 2);
        __put_unaligned_le16(val, p);
 }
 
-static inline void __put_unaligned_le64(__u64 val, __u8 *p)
+static inline void __put_unaligned_le64(uint64_t val, uint8_t *p)
 {
        __put_unaligned_le32(val >> 32, p + 4);
        __put_unaligned_le32(val, p);
 }
 
-static inline __u16 get_unaligned_le16(const void *p)
+static inline uint16_t get_unaligned_le16(const void *p)
 {
-       return __get_unaligned_le16((const __u8 *)p);
+       return __get_unaligned_le16((const uint8_t *)p);
 }
 
-static inline __u32 get_unaligned_le32(const void *p)
+static inline uint32_t get_unaligned_le32(const void *p)
 {
-       return __get_unaligned_le32((const __u8 *)p);
+       return __get_unaligned_le32((const uint8_t *)p);
 }
 
-static inline __u64 get_unaligned_le64(const void *p)
+static inline uint64_t get_unaligned_le64(const void *p)
 {
-       return __get_unaligned_le64((const __u8 *)p);
+       return __get_unaligned_le64((const uint8_t *)p);
 }
 
-static inline void put_unaligned_le16(__u16 val, void *p)
+static inline void put_unaligned_le16(uint16_t val, void *p)
 {
        __put_unaligned_le16(val, p);
 }
 
-static inline void put_unaligned_le32(__u32 val, void *p)
+static inline void put_unaligned_le32(uint32_t val, void *p)
 {
        __put_unaligned_le32(val, p);
 }
 
-static inline void put_unaligned_le64(__u64 val, void *p)
+static inline void put_unaligned_le64(uint64_t val, void *p)
 {
        __put_unaligned_le64(val, p);
 }
index 0ac3420..97bca48 100644 (file)
@@ -1,5 +1,4 @@
 # This creates the demonstration utility "lguest" which runs a Linux guest.
-# Missing headers?  Add "-I../../../include -I../../../arch/x86/include"
 CFLAGS:=-m32 -Wall -Wmissing-declarations -Wmissing-prototypes -O3 -U_FORTIFY_SOURCE
 
 all: lguest
index 07a0345..68f67cf 100644 (file)
 #include <pwd.h>
 #include <grp.h>
 
-#include <linux/virtio_config.h>
-#include <linux/virtio_net.h>
-#include <linux/virtio_blk.h>
-#include <linux/virtio_console.h>
-#include <linux/virtio_rng.h>
-#include <linux/virtio_ring.h>
-#include <asm/bootparam.h>
-#include "../../include/linux/lguest_launcher.h"
 /*L:110
  * We can ignore the 43 include files we need for this program, but I do want
  * to draw attention to the use of kernel-style types.
@@ -65,6 +57,15 @@ typedef uint16_t u16;
 typedef uint8_t u8;
 /*:*/
 
+#include <linux/virtio_config.h>
+#include <linux/virtio_net.h>
+#include <linux/virtio_blk.h>
+#include <linux/virtio_console.h>
+#include <linux/virtio_rng.h>
+#include <linux/virtio_ring.h>
+#include <asm/bootparam.h>
+#include "../../include/linux/lguest_launcher.h"
+
 #define BRIDGE_PFX "bridge:"
 #ifndef SIOCBRADDIF
 #define SIOCBRADDIF    0x89a2          /* add interface to bridge      */
@@ -177,7 +178,8 @@ static struct termios orig_term;
  * in precise order.
  */
 #define wmb() __asm__ __volatile__("" : : : "memory")
-#define mb() __asm__ __volatile__("" : : : "memory")
+#define rmb() __asm__ __volatile__("lock; addl $0,0(%%esp)" : : : "memory")
+#define mb() __asm__ __volatile__("lock; addl $0,0(%%esp)" : : : "memory")
 
 /* Wrapper for the last available index.  Makes it easier to change. */
 #define lg_last_avail(vq)      ((vq)->last_avail_idx)
@@ -676,6 +678,12 @@ static unsigned wait_for_vq_desc(struct virtqueue *vq,
                errx(1, "Guest moved used index from %u to %u",
                     last_avail, vq->vring.avail->idx);
 
+       /* 
+        * Make sure we read the descriptor number *after* we read the ring
+        * update; don't let the cpu or compiler change the order.
+        */
+       rmb();
+
        /*
         * Grab the next descriptor number they're advertising, and increment
         * the index we've seen.
@@ -695,6 +703,12 @@ static unsigned wait_for_vq_desc(struct virtqueue *vq,
        i = head;
 
        /*
+        * We have to read the descriptor after we read the descriptor number,
+        * but there's a data dependency there so the CPU shouldn't reorder
+        * that: no rmb() required.
+        */
+
+       /*
         * If this is an indirect entry, then this buffer contains a descriptor
         * table which we handle as if it's any normal descriptor chain.
         */
index 2c5a197..280dd82 100644 (file)
@@ -3,6 +3,21 @@ include ../../scripts/Makefile.include
 CC = $(CROSS_COMPILE)gcc
 AR = $(CROSS_COMPILE)ar
 
+# Makefiles suck: This macro sets a default value of $(2) for the
+# variable named by $(1), unless the variable has been set by
+# environment or command line. This is necessary for CC and AR
+# because make sets default values, so the simpler ?= approach
+# won't work as expected.
+define allow-override
+  $(if $(or $(findstring environment,$(origin $(1))),\
+            $(findstring command line,$(origin $(1)))),,\
+    $(eval $(1) = $(2)))
+endef
+
+# Allow setting CC and AR, or setting CROSS_COMPILE as a prefix.
+$(call allow-override,CC,$(CROSS_COMPILE)gcc)
+$(call allow-override,AR,$(CROSS_COMPILE)ar)
+
 # guard against environment variables
 LIB_H=
 LIB_OBJS=
@@ -14,7 +29,7 @@ LIB_OBJS += $(OUTPUT)debugfs.o
 LIBFILE = liblk.a
 
 CFLAGS = -ggdb3 -Wall -Wextra -std=gnu99 -Werror -O6 -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) $(EXTRA_CFLAGS) -fPIC
-EXTLIBS = -lpthread -lrt -lelf -lm
+EXTLIBS = -lelf -lpthread -lrt -lm
 ALL_CFLAGS = $(CFLAGS) $(BASIC_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64
 ALL_LDFLAGS = $(LDFLAGS)
 
index eb30044..5a37a7c 100644 (file)
@@ -1,12 +1,6 @@
+include ../../scripts/Makefile.include
 include ../config/utilities.mak
 
-OUTPUT := ./
-ifeq ("$(origin O)", "command line")
-  ifneq ($(O),)
-       OUTPUT := $(O)/
-  endif
-endif
-
 MAN1_TXT= \
        $(filter-out $(addsuffix .txt, $(ARTICLES) $(SP_ARTICLES)), \
                $(wildcard perf-*.txt)) \
@@ -150,7 +144,7 @@ NO_SUBDIR = :
 endif
 
 ifneq ($(findstring $(MAKEFLAGS),s),s)
-ifndef V
+ifneq ($(V),1)
        QUIET_ASCIIDOC  = @echo '   ' ASCIIDOC $@;
        QUIET_XMLTO     = @echo '   ' XMLTO $@;
        QUIET_DB2TEXI   = @echo '   ' DB2TEXI $@;
@@ -277,7 +271,7 @@ $(MAN_HTML): $(OUTPUT)%.html : %.txt
 
 $(OUTPUT)%.1 $(OUTPUT)%.5 $(OUTPUT)%.7 : $(OUTPUT)%.xml
        $(QUIET_XMLTO)$(RM) $@ && \
-       $(XMLTO) -o $(OUTPUT) -m $(MANPAGE_XSL) $(XMLTO_EXTRA) man $<
+       $(XMLTO) -o $(OUTPUT). -m $(MANPAGE_XSL) $(XMLTO_EXTRA) man $<
 
 $(OUTPUT)%.xml : %.txt
        $(QUIET_ASCIIDOC)$(RM) $@+ $@ && \
index 77f9527..a4e3921 100644 (file)
@@ -66,7 +66,7 @@ Furthermore, these tracepoints can be used to sample the workload as
 well. For example the page allocations done by a 'git gc' can be
 captured the following way:
 
- titan:~/git> perf record -f -e kmem:mm_page_alloc -c 1 ./git gc
+ titan:~/git> perf record -e kmem:mm_page_alloc -c 1 ./git gc
  Counting objects: 1148, done.
  Delta compression using up to 2 threads.
  Compressing objects: 100% (450/450), done.
@@ -120,7 +120,7 @@ Furthermore, call-graph sampling can be done too, of page
 allocations - to see precisely what kind of page allocations there
 are:
 
- titan:~/git> perf record -f -g -e kmem:mm_page_alloc -c 1 ./git gc
+ titan:~/git> perf record -g -e kmem:mm_page_alloc -c 1 ./git gc
  Counting objects: 1148, done.
  Delta compression using up to 2 threads.
  Compressing objects: 100% (450/450), done.
index d4da111..e297b74 100644 (file)
@@ -65,16 +65,10 @@ OPTIONS
 -r::
 --realtime=::
        Collect data with this RT SCHED_FIFO priority.
+
 -D::
 --no-delay::
        Collect data without buffering.
--A::
---append::
-       Append to the output file to do incremental profiling.
-
--f::
---force::
-       Overwrite existing data file. (deprecated)
 
 -c::
 --count=::
index 203cb0e..641fccd 100644 (file)
@@ -121,17 +121,16 @@ SCRIPT_SH += perf-archive.sh
 grep-libs = $(filter -l%,$(1))
 strip-libs = $(filter-out -l%,$(1))
 
-LK_PATH=$(LK_DIR)
-
 ifneq ($(OUTPUT),)
   TE_PATH=$(OUTPUT)
 ifneq ($(subdir),)
-  LK_PATH=$(OUTPUT)$(LK_DIR)
+  LK_PATH=$(objtree)/lib/lk/
 else
   LK_PATH=$(OUTPUT)
 endif
 else
   TE_PATH=$(TRACE_EVENT_DIR)
+  LK_PATH=$(LK_DIR)
 endif
 
 LIBTRACEEVENT = $(TE_PATH)libtraceevent.a
index 93c83e3..25fd3f1 100644 (file)
@@ -111,11 +111,11 @@ static double timeval2double(struct timeval *ts)
 static void alloc_mem(void **dst, void **src, size_t length)
 {
        *dst = zalloc(length);
-       if (!dst)
+       if (!*dst)
                die("memory allocation failed - maybe length is too large?\n");
 
        *src = zalloc(length);
-       if (!src)
+       if (!*src)
                die("memory allocation failed - maybe length is too large?\n");
 }
 
index c6e4bc5..4a2f120 100644 (file)
@@ -111,7 +111,7 @@ static double timeval2double(struct timeval *ts)
 static void alloc_mem(void **dst, size_t length)
 {
        *dst = zalloc(length);
-       if (!dst)
+       if (!*dst)
                die("memory allocation failed - maybe length is too large?\n");
 }
 
index da8f8eb..0aac5f3 100644 (file)
@@ -607,7 +607,6 @@ int cmd_diff(int argc, const char **argv, const char *prefix __maybe_unused)
                input_new = "perf.data.guest";
        }
 
-       symbol_conf.exclude_other = false;
        if (symbol__init() < 0)
                return -1;
 
index 46878da..0259502 100644 (file)
@@ -708,7 +708,7 @@ static int parse_line_opt(const struct option *opt __maybe_unused,
 static int __cmd_record(int argc, const char **argv)
 {
        const char * const record_args[] = {
-       "record", "-a", "-R", "-f", "-c", "1",
+       "record", "-a", "-R", "-c", "1",
        "-e", "kmem:kmalloc",
        "-e", "kmem:kmalloc_node",
        "-e", "kmem:kfree",
index 4258300..76543a4 100644 (file)
@@ -878,7 +878,7 @@ static int __cmd_report(void)
 static int __cmd_record(int argc, const char **argv)
 {
        const char *record_args[] = {
-               "record", "-R", "-f", "-m", "1024", "-c", "1",
+               "record", "-R", "-m", "1024", "-c", "1",
        };
        unsigned int rec_argc, i, j;
        const char **rec_argv;
index fff985c..ecca62e 100644 (file)
@@ -61,11 +61,6 @@ static void __handle_on_exit_funcs(void)
 }
 #endif
 
-enum write_mode_t {
-       WRITE_FORCE,
-       WRITE_APPEND
-};
-
 struct perf_record {
        struct perf_tool        tool;
        struct perf_record_opts opts;
@@ -77,12 +72,8 @@ struct perf_record {
        int                     output;
        unsigned int            page_size;
        int                     realtime_prio;
-       enum write_mode_t       write_mode;
        bool                    no_buildid;
        bool                    no_buildid_cache;
-       bool                    force;
-       bool                    file_new;
-       bool                    append_file;
        long                    samples;
        off_t                   post_processing_offset;
 };
@@ -200,25 +191,6 @@ static void perf_record__sig_exit(int exit_status __maybe_unused, void *arg)
        signal(signr, SIG_DFL);
 }
 
-static bool perf_evlist__equal(struct perf_evlist *evlist,
-                              struct perf_evlist *other)
-{
-       struct perf_evsel *pos, *pair;
-
-       if (evlist->nr_entries != other->nr_entries)
-               return false;
-
-       pair = perf_evlist__first(other);
-
-       list_for_each_entry(pos, &evlist->entries, node) {
-               if (memcmp(&pos->attr, &pair->attr, sizeof(pos->attr) != 0))
-                       return false;
-               pair = perf_evsel__next(pair);
-       }
-
-       return true;
-}
-
 static int perf_record__open(struct perf_record *rec)
 {
        char msg[512];
@@ -273,16 +245,7 @@ try_again:
                goto out;
        }
 
-       if (rec->file_new)
-               session->evlist = evlist;
-       else {
-               if (!perf_evlist__equal(session->evlist, evlist)) {
-                       fprintf(stderr, "incompatible append\n");
-                       rc = -1;
-                       goto out;
-               }
-       }
-
+       session->evlist = evlist;
        perf_session__set_id_hdr_size(session);
 out:
        return rc;
@@ -415,23 +378,15 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
                if (!strcmp(output_name, "-"))
                        opts->pipe_output = true;
                else if (!stat(output_name, &st) && st.st_size) {
-                       if (rec->write_mode == WRITE_FORCE) {
-                               char oldname[PATH_MAX];
-                               snprintf(oldname, sizeof(oldname), "%s.old",
-                                        output_name);
-                               unlink(oldname);
-                               rename(output_name, oldname);
-                       }
-               } else if (rec->write_mode == WRITE_APPEND) {
-                       rec->write_mode = WRITE_FORCE;
+                       char oldname[PATH_MAX];
+                       snprintf(oldname, sizeof(oldname), "%s.old",
+                                output_name);
+                       unlink(oldname);
+                       rename(output_name, oldname);
                }
        }
 
-       flags = O_CREAT|O_RDWR;
-       if (rec->write_mode == WRITE_APPEND)
-               rec->file_new = 0;
-       else
-               flags |= O_TRUNC;
+       flags = O_CREAT|O_RDWR|O_TRUNC;
 
        if (opts->pipe_output)
                output = STDOUT_FILENO;
@@ -445,7 +400,7 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
        rec->output = output;
 
        session = perf_session__new(output_name, O_WRONLY,
-                                   rec->write_mode == WRITE_FORCE, false, NULL);
+                                   true, false, NULL);
        if (session == NULL) {
                pr_err("Not enough memory for reading perf file header\n");
                return -1;
@@ -465,12 +420,6 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
        if (!rec->opts.branch_stack)
                perf_header__clear_feat(&session->header, HEADER_BRANCH_STACK);
 
-       if (!rec->file_new) {
-               err = perf_session__read_header(session, output);
-               if (err < 0)
-                       goto out_delete_session;
-       }
-
        if (forks) {
                err = perf_evlist__prepare_workload(evsel_list, &opts->target,
                                                    argv, opts->pipe_output,
@@ -498,7 +447,7 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
                err = perf_header__write_pipe(output);
                if (err < 0)
                        goto out_delete_session;
-       } else if (rec->file_new) {
+       } else {
                err = perf_session__write_header(session, evsel_list,
                                                 output, false);
                if (err < 0)
@@ -869,8 +818,6 @@ static struct perf_record record = {
                        .uses_mmap   = true,
                },
        },
-       .write_mode = WRITE_FORCE,
-       .file_new   = true,
 };
 
 #define CALLCHAIN_HELP "do call-graph (stack chain/backtrace) recording: "
@@ -906,12 +853,8 @@ const struct option record_options[] = {
                    "collect raw sample records from all opened counters"),
        OPT_BOOLEAN('a', "all-cpus", &record.opts.target.system_wide,
                            "system-wide collection from all CPUs"),
-       OPT_BOOLEAN('A', "append", &record.append_file,
-                           "append to the output file to do incremental profiling"),
        OPT_STRING('C', "cpu", &record.opts.target.cpu_list, "cpu",
                    "list of cpus to monitor"),
-       OPT_BOOLEAN('f', "force", &record.force,
-                       "overwrite existing data file (deprecated)"),
        OPT_U64('c', "count", &record.opts.user_interval, "event period to sample"),
        OPT_STRING('o', "output", &record.output_name, "file",
                    "output file name"),
@@ -977,16 +920,6 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
        if (!argc && perf_target__none(&rec->opts.target))
                usage_with_options(record_usage, record_options);
 
-       if (rec->force && rec->append_file) {
-               ui__error("Can't overwrite and append at the same time."
-                         " You need to choose between -f and -A");
-               usage_with_options(record_usage, record_options);
-       } else if (rec->append_file) {
-               rec->write_mode = WRITE_APPEND;
-       } else {
-               rec->write_mode = WRITE_FORCE;
-       }
-
        if (nr_cgroups && !rec->opts.target.system_wide) {
                ui__error("cgroup monitoring only available in"
                          " system-wide mode\n");
index ca98d34..3662047 100644 (file)
@@ -939,8 +939,7 @@ repeat:
                 */
                if (!strstr(sort_order, "parent"))
                        sort_parent.elide = 1;
-       } else
-               symbol_conf.exclude_other = false;
+       }
 
        if (argc) {
                /*
index 2da2a6c..fed9ae4 100644 (file)
@@ -1632,7 +1632,6 @@ static int __cmd_record(int argc, const char **argv)
                "record",
                "-a",
                "-R",
-               "-f",
                "-m", "1024",
                "-c", "1",
                "-e", "sched:sched_switch",
index 7e910ba..352fbd7 100644 (file)
@@ -87,7 +87,7 @@ static int                    run_count                       =  1;
 static bool                    no_inherit                      = false;
 static bool                    scale                           =  true;
 static enum aggr_mode          aggr_mode                       = AGGR_GLOBAL;
-static pid_t                   child_pid                       = -1;
+static volatile pid_t          child_pid                       = -1;
 static bool                    null_run                        =  false;
 static int                     detailed_run                    =  0;
 static bool                    big_num                         =  true;
@@ -924,7 +924,7 @@ static void abs_printout(int cpu, int nr, struct perf_evsel *evsel, double avg)
 static void print_aggr(char *prefix)
 {
        struct perf_evsel *counter;
-       int cpu, s, s2, id, nr;
+       int cpu, cpu2, s, s2, id, nr;
        u64 ena, run, val;
 
        if (!(aggr_map || aggr_get_id))
@@ -936,7 +936,8 @@ static void print_aggr(char *prefix)
                        val = ena = run = 0;
                        nr = 0;
                        for (cpu = 0; cpu < perf_evsel__nr_cpus(counter); cpu++) {
-                               s2 = aggr_get_id(evsel_list->cpus, cpu);
+                               cpu2 = perf_evsel__cpus(counter)->map[cpu];
+                               s2 = aggr_get_id(evsel_list->cpus, cpu2);
                                if (s2 != id)
                                        continue;
                                val += counter->counts->cpu[cpu].val;
@@ -948,7 +949,7 @@ static void print_aggr(char *prefix)
                                fprintf(output, "%s", prefix);
 
                        if (run == 0 || ena == 0) {
-                               aggr_printout(counter, cpu, nr);
+                               aggr_printout(counter, id, nr);
 
                                fprintf(output, "%*s%s%*s",
                                        csv_output ? 0 : 18,
@@ -1148,13 +1149,34 @@ static void skip_signal(int signo)
                done = 1;
 
        signr = signo;
+       /*
+        * render child_pid harmless
+        * won't send SIGTERM to a random
+        * process in case of race condition
+        * and fast PID recycling
+        */
+       child_pid = -1;
 }
 
 static void sig_atexit(void)
 {
+       sigset_t set, oset;
+
+       /*
+        * avoid race condition with SIGCHLD handler
+        * in skip_signal() which is modifying child_pid
+        * goal is to avoid send SIGTERM to a random
+        * process
+        */
+       sigemptyset(&set);
+       sigaddset(&set, SIGCHLD);
+       sigprocmask(SIG_BLOCK, &set, &oset);
+
        if (child_pid != -1)
                kill(child_pid, SIGTERM);
 
+       sigprocmask(SIG_SETMASK, &oset, NULL);
+
        if (signr == -1)
                return;
 
index ab4cf23..4536a92 100644 (file)
@@ -1005,7 +1005,7 @@ static int __cmd_record(int argc, const char **argv)
 {
 #ifdef SUPPORT_OLD_POWER_EVENTS
        const char * const record_old_args[] = {
-               "record", "-a", "-R", "-f", "-c", "1",
+               "record", "-a", "-R", "-c", "1",
                "-e", "power:power_start",
                "-e", "power:power_end",
                "-e", "power:power_frequency",
@@ -1014,7 +1014,7 @@ static int __cmd_record(int argc, const char **argv)
        };
 #endif
        const char * const record_new_args[] = {
-               "record", "-a", "-R", "-f", "-c", "1",
+               "record", "-a", "-R", "-c", "1",
                "-e", "power:cpu_frequency",
                "-e", "power:cpu_idle",
                "-e", "sched:sched_wakeup",
index f036af9..e06c4f8 100644 (file)
@@ -1130,8 +1130,6 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
        if (top.evlist == NULL)
                return -ENOMEM;
 
-       symbol_conf.exclude_other = false;
-
        argc = parse_options(argc, argv, options, top_usage, 0);
        if (argc)
                usage_with_options(top_usage, options);
index f139dcd..b5d9238 100644 (file)
@@ -39,7 +39,7 @@ src-perf := $(srctree)/tools/perf
 endif
 
 ifeq ($(obj-perf),)
-obj-perf := $(objtree)
+obj-perf := $(OUTPUT)
 endif
 
 ifneq ($(obj-perf),)
@@ -85,7 +85,7 @@ CFLAGS += -Wall
 CFLAGS += -Wextra
 CFLAGS += -std=gnu99
 
-EXTLIBS = -lpthread -lrt -lelf -lm
+EXTLIBS = -lelf -lpthread -lrt -lm
 
 ifeq ($(call try-cc,$(SOURCE_HELLO),$(CFLAGS) -Werror -fstack-protector-all,-fstack-protector-all),y)
   CFLAGS += -fstack-protector-all
@@ -165,7 +165,7 @@ else
     LIBDW_LDFLAGS := -L$(LIBDW_DIR)/lib
   endif
 
-  FLAGS_DWARF=$(CFLAGS) $(LIBDW_CFLAGS) -ldw -lelf $(LIBDW_LDFLAGS) $(LDFLAGS) $(EXTLIBS)
+  FLAGS_DWARF=$(CFLAGS) $(LIBDW_CFLAGS) -ldw -lz -lelf $(LIBDW_LDFLAGS) $(LDFLAGS) $(EXTLIBS)
   ifneq ($(call try-cc,$(SOURCE_DWARF),$(FLAGS_DWARF),libdw),y)
     msg := $(warning No libdw.h found or old libdw.h found or elfutils is older than 0.138, disables dwarf support. Please install new elfutils-devel/libdw-dev);
     NO_DWARF := 1
index 8ef3bd3..94d2d4f 100644 (file)
@@ -173,7 +173,7 @@ _ge-abspath = $(if $(is-executable),$(1))
 # Usage: absolute-executable-path-or-empty = $(call get-executable-or-default,variable,default)
 #
 define get-executable-or-default
-$(if $($(1)),$(call _ge_attempt,$($(1)),$(1)),$(call _ge_attempt,$(2),$(1)))
+$(if $($(1)),$(call _ge_attempt,$($(1)),$(1)),$(call _ge_attempt,$(2)))
 endef
 _ge_attempt = $(if $(get-executable),$(get-executable),$(_gea_warn)$(call _gea_err,$(2)))
 _gea_warn = $(warning The path '$(1)' is not executable.)
@@ -181,7 +181,7 @@ _gea_err  = $(if $(1),$(error Please set '$(1)' appropriately))
 
 # try-cc
 # Usage: option = $(call try-cc, source-to-build, cc-options, msg)
-ifndef V
+ifneq ($(V),1)
 TRY_CC_OUTPUT= > /dev/null 2>&1
 endif
 TRY_CC_MSG=echo "    CHK $(3)" 1>&2;
index c1e2ed1..8c7ea42 100644 (file)
@@ -23,7 +23,7 @@
 #include "perl.h"
 #include "XSUB.h"
 #include "../../../perf.h"
-#include "../../../util/script-event.h"
+#include "../../../util/trace-event.h"
 
 MODULE = Perf::Trace::Context          PACKAGE = Perf::Trace::Context
 PROTOTYPES: ENABLE
index 055fef3..15a77b7 100755 (executable)
@@ -13,13 +13,22 @@ LF='
 # First check if there is a .git to get the version from git describe
 # otherwise try to get the version from the kernel Makefile
 #
-if test -d ../../.git -o -f ../../.git &&
-       VN=$(git tag 2>/dev/null | tail -1 | grep -E "v[0-9].[0-9]*")
+CID=
+TAG=
+if test -d ../../.git -o -f ../../.git
 then
-       VN=$(echo $VN"-g"$(git log -1 --abbrev=4 --pretty=format:"%h" HEAD))
-       VN=$(echo "$VN" | sed -e 's/-/./g');
-else
-       VN=$(MAKEFLAGS= make -sC ../.. kernelversion)
+       TAG=$(git describe --abbrev=0 --match "v[0-9].[0-9]*" 2>/dev/null )
+       CID=$(git log -1 --abbrev=4 --pretty=format:"%h" 2>/dev/null) && CID="-g$CID"
+fi
+if test -z "$TAG"
+then
+       TAG=$(MAKEFLAGS= make -sC ../.. kernelversion)
+fi
+VN="$TAG$CID"
+if test -n "$CID"
+then
+       # format version string, strip trailing zero of sublevel:
+       VN=$(echo "$VN" | sed -e 's/-/./g;s/\([0-9]*[.][0-9]*\)[.]0/\1/')
 fi
 
 VN=$(expr "$VN" : v*'\(.*\)')
index 6f7d5a9..c4374f0 100644 (file)
@@ -513,10 +513,16 @@ void dsos__add(struct list_head *head, struct dso *dso)
        list_add_tail(&dso->node, head);
 }
 
-struct dso *dsos__find(struct list_head *head, const char *name)
+struct dso *dsos__find(struct list_head *head, const char *name, bool cmp_short)
 {
        struct dso *pos;
 
+       if (cmp_short) {
+               list_for_each_entry(pos, head, node)
+                       if (strcmp(pos->short_name, name) == 0)
+                               return pos;
+               return NULL;
+       }
        list_for_each_entry(pos, head, node)
                if (strcmp(pos->long_name, name) == 0)
                        return pos;
@@ -525,7 +531,7 @@ struct dso *dsos__find(struct list_head *head, const char *name)
 
 struct dso *__dsos__findnew(struct list_head *head, const char *name)
 {
-       struct dso *dso = dsos__find(head, name);
+       struct dso *dso = dsos__find(head, name, false);
 
        if (!dso) {
                dso = dso__new(name);
index 450199a..d51aaf2 100644 (file)
@@ -133,7 +133,8 @@ struct dso *dso__kernel_findnew(struct machine *machine, const char *name,
                                const char *short_name, int dso_type);
 
 void dsos__add(struct list_head *head, struct dso *dso);
-struct dso *dsos__find(struct list_head *head, const char *name);
+struct dso *dsos__find(struct list_head *head, const char *name,
+                      bool cmp_short);
 struct dso *__dsos__findnew(struct list_head *head, const char *name);
 bool __dsos__read_build_ids(struct list_head *head, bool with_hits);
 
index 99b43dd..8065ce8 100644 (file)
@@ -821,6 +821,7 @@ int perf_evlist__prepare_workload(struct perf_evlist *evlist,
                goto out_close_pipes;
        }
 
+       fcntl(go_pipe[1], F_SETFD, FD_CLOEXEC);
        evlist->workload.cork_fd = go_pipe[1];
        close(child_ready_pipe[0]);
        return 0;
@@ -837,10 +838,17 @@ out_close_ready_pipe:
 int perf_evlist__start_workload(struct perf_evlist *evlist)
 {
        if (evlist->workload.cork_fd > 0) {
+               char bf;
+               int ret;
                /*
                 * Remove the cork, let it rip!
                 */
-               return close(evlist->workload.cork_fd);
+               ret = write(evlist->workload.cork_fd, &bf, 1);
+               if (ret < 0)
+                       perror("enable to write to pipe");
+
+               close(evlist->workload.cork_fd);
+               return ret;
        }
 
        return 0;
index 63b6f8c..c9c7494 100644 (file)
@@ -124,7 +124,7 @@ struct event_format *event_format__new(const char *sys, const char *name)
                        bf = nbf;
                }
 
-               n = read(fd, bf + size, BUFSIZ);
+               n = read(fd, bf + size, alloc_size - size);
                if (n < 0)
                        goto out_free_bf;
                size += n;
@@ -1170,7 +1170,7 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
                } else {
                        data->user_stack.data = (char *)array;
                        array += size / sizeof(*array);
-                       data->user_stack.size = *array;
+                       data->user_stack.size = *array++;
                }
        }
 
index 738d3b8..a4dafbe 100644 (file)
@@ -2303,29 +2303,18 @@ int perf_session__write_header(struct perf_session *session,
        struct perf_file_header f_header;
        struct perf_file_attr   f_attr;
        struct perf_header *header = &session->header;
-       struct perf_evsel *evsel, *pair = NULL;
+       struct perf_evsel *evsel;
        int err;
 
        lseek(fd, sizeof(f_header), SEEK_SET);
 
-       if (session->evlist != evlist)
-               pair = perf_evlist__first(session->evlist);
-
        list_for_each_entry(evsel, &evlist->entries, node) {
                evsel->id_offset = lseek(fd, 0, SEEK_CUR);
                err = do_write(fd, evsel->id, evsel->ids * sizeof(u64));
                if (err < 0) {
-out_err_write:
                        pr_debug("failed to write perf header\n");
                        return err;
                }
-               if (session->evlist != evlist) {
-                       err = do_write(fd, pair->id, pair->ids * sizeof(u64));
-                       if (err < 0)
-                               goto out_err_write;
-                       evsel->ids += pair->ids;
-                       pair = perf_evsel__next(pair);
-               }
        }
 
        header->attr_offset = lseek(fd, 0, SEEK_CUR);
@@ -2967,6 +2956,8 @@ int perf_event__process_attr(union perf_event *event,
                perf_evlist__id_add(evlist, evsel, 0, i, event->attr.id[i]);
        }
 
+       symbol_conf.nr_events = evlist->nr_entries;
+
        return 0;
 }
 
index 6c8bb0f..995fc25 100644 (file)
@@ -860,7 +860,8 @@ int parse_events_terms(struct list_head *terms, const char *str)
                return 0;
        }
 
-       parse_events__free_terms(data.terms);
+       if (data.terms)
+               parse_events__free_terms(data.terms);
        return ret;
 }
 
@@ -1183,6 +1184,7 @@ static int new_term(struct parse_events_term **_term, int type_val,
                term->val.str = str;
                break;
        default:
+               free(term);
                return -EINVAL;
        }
 
index 8cf3b54..d5528e1 100644 (file)
@@ -32,7 +32,6 @@ int vmlinux_path__nr_entries;
 char **vmlinux_path;
 
 struct symbol_conf symbol_conf = {
-       .exclude_other    = true,
        .use_modules      = true,
        .try_vmlinux_path = true,
        .annotate_src     = true,
index 7a484c9..2732fad 100644 (file)
@@ -72,6 +72,7 @@
 #include "types.h"
 #include <sys/ttydefaults.h>
 #include <lk/debugfs.h>
+#include <termios.h>
 
 extern const char *graph_line;
 extern const char *graph_dotted_line;
@@ -274,6 +275,5 @@ void dump_stack(void);
 
 extern unsigned int page_size;
 
-struct winsize;
 void get_term_dimensions(struct winsize *ws);
 #endif /* GIT_COMPAT_UTIL_H */
index e60951f..3915982 100644 (file)
@@ -91,7 +91,7 @@ void vdso__exit(void)
 
 struct dso *vdso__dso_findnew(struct list_head *head)
 {
-       struct dso *dso = dsos__find(head, VDSO__MAP_NAME);
+       struct dso *dso = dsos__find(head, VDSO__MAP_NAME, true);
 
        if (!dso) {
                char *file;
index d875a74..cbfec92 100644 (file)
@@ -128,10 +128,12 @@ UTIL_OBJS =  utils/helpers/amd.o utils/helpers/topology.o utils/helpers/msr.o \
        utils/helpers/sysfs.o utils/helpers/misc.o utils/helpers/cpuid.o \
        utils/helpers/pci.o utils/helpers/bitmask.o \
        utils/idle_monitor/nhm_idle.o utils/idle_monitor/snb_idle.o \
+       utils/idle_monitor/hsw_ext_idle.o \
        utils/idle_monitor/amd_fam14h_idle.o utils/idle_monitor/cpuidle_sysfs.o \
        utils/idle_monitor/mperf_monitor.o utils/idle_monitor/cpupower-monitor.o \
        utils/cpupower.o utils/cpufreq-info.o utils/cpufreq-set.o \
-       utils/cpupower-set.o utils/cpupower-info.o utils/cpuidle-info.o
+       utils/cpupower-set.o utils/cpupower-info.o utils/cpuidle-info.o \
+       utils/cpuidle-set.o
 
 UTIL_SRC := $(UTIL_OBJS:.o=.c)
 
index e01c35d..914cbb9 100644 (file)
@@ -110,13 +110,21 @@ May work poorly on Linux-2.6.20 through 2.6.29, as the \fBacpi-cpufreq \fP
 kernel frequency driver periodically cleared aperf/mperf registers in those
 kernels.
 
-.SS "Nehalem" "SandyBridge"
+.SS "Nehalem" "SandyBridge" "HaswellExtended"
 Intel Core and Package sleep state counters.
 Threads (hyperthreaded cores) may not be able to enter deeper core states if
 its sibling is utilized.
 Deepest package sleep states may in reality show up as machine/platform wide
 sleep states and can only be entered if all cores are idle. Look up Intel
 manuals (some are provided in the References section) for further details.
+The monitors are named after the CPU family where the sleep state capabilities
+got introduced and may not match exactly the CPU name of the platform.
+For example an IvyBridge processor has sleep state capabilities which got
+introduced in Nehalem and SandyBridge processor families.
+Thus on an IvyBridge processor one will get Nehalem and SandyBridge sleep
+state monitors.
+HaswellExtended extra package sleep state capabilities are available only in a
+specific Haswell (family 0x45) and probably also other future processors.
 
 .SS "Fam_12h" "Fam_14h"
 AMD laptop and desktop processor (family 12h and 14h) sleep state counters.
index c10496f..2284c8e 100644 (file)
@@ -5,6 +5,7 @@ extern int cmd_set(int argc, const char **argv);
 extern int cmd_info(int argc, const char **argv);
 extern int cmd_freq_set(int argc, const char **argv);
 extern int cmd_freq_info(int argc, const char **argv);
+extern int cmd_idle_set(int argc, const char **argv);
 extern int cmd_idle_info(int argc, const char **argv);
 extern int cmd_monitor(int argc, const char **argv);
 
index 8145af5..75e66de 100644 (file)
@@ -22,7 +22,7 @@
 
 static void cpuidle_cpu_output(unsigned int cpu, int verbose)
 {
-       int idlestates, idlestate;
+       unsigned int idlestates, idlestate;
        char *tmp;
 
        printf(_ ("Analyzing CPU %d:\n"), cpu);
@@ -31,10 +31,8 @@ static void cpuidle_cpu_output(unsigned int cpu, int verbose)
        if (idlestates == 0) {
                printf(_("CPU %u: No idle states\n"), cpu);
                return;
-       } else if (idlestates <= 0) {
-               printf(_("CPU %u: Can't read idle state info\n"), cpu);
-               return;
        }
+
        printf(_("Number of idle states: %d\n"), idlestates);
        printf(_("Available idle states:"));
        for (idlestate = 0; idlestate < idlestates; idlestate++) {
@@ -50,10 +48,14 @@ static void cpuidle_cpu_output(unsigned int cpu, int verbose)
                return;
 
        for (idlestate = 0; idlestate < idlestates; idlestate++) {
+               int disabled = sysfs_is_idlestate_disabled(cpu, idlestate);
+               /* Disabled interface not supported on older kernels */
+               if (disabled < 0)
+                       disabled = 0;
                tmp = sysfs_get_idlestate_name(cpu, idlestate);
                if (!tmp)
                        continue;
-               printf("%s:\n", tmp);
+               printf("%s%s:\n", tmp, (disabled) ? " (DISABLED) " : "");
                free(tmp);
 
                tmp = sysfs_get_idlestate_desc(cpu, idlestate);
@@ -98,21 +100,13 @@ static void cpuidle_general_output(void)
 static void proc_cpuidle_cpu_output(unsigned int cpu)
 {
        long max_allowed_cstate = 2000000000;
-       int cstates, cstate;
+       unsigned int cstate, cstates;
 
        cstates = sysfs_get_idlestate_count(cpu);
        if (cstates == 0) {
-               /*
-                * Go on and print same useless info as you'd see with
-                * cat /proc/acpi/processor/../power
-                *      printf(_("CPU %u: No C-states available\n"), cpu);
-                *      return;
-                */
-       } else if (cstates <= 0) {
-               printf(_("CPU %u: Can't read C-state info\n"), cpu);
+               printf(_("CPU %u: No C-states info\n"), cpu);
                return;
        }
-       /* printf("Cstates: %d\n", cstates); */
 
        printf(_("active state:            C0\n"));
        printf(_("max_cstate:              C%u\n"), cstates-1);
diff --git a/tools/power/cpupower/utils/cpuidle-set.c b/tools/power/cpupower/utils/cpuidle-set.c
new file mode 100644 (file)
index 0000000..c78141c
--- /dev/null
@@ -0,0 +1,118 @@
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <string.h>
+#include <ctype.h>
+
+#include <getopt.h>
+
+#include "cpufreq.h"
+#include "helpers/helpers.h"
+#include "helpers/sysfs.h"
+
+static struct option info_opts[] = {
+       { .name = "disable",    .has_arg = required_argument,   .flag = NULL,   .val = 'd'},
+       { .name = "enable",     .has_arg = required_argument,   .flag = NULL,   .val = 'e'},
+       { },
+};
+
+
+int cmd_idle_set(int argc, char **argv)
+{
+       extern char *optarg;
+       extern int optind, opterr, optopt;
+       int ret = 0, cont = 1, param = 0, idlestate = 0;
+       unsigned int cpu = 0;
+
+       do {
+               ret = getopt_long(argc, argv, "d:e:", info_opts, NULL);
+               if (ret == -1)
+                       break;
+               switch (ret) {
+               case '?':
+                       param = '?';
+                       cont = 0;
+                       break;
+               case 'd':
+                       if (param) {
+                               param = -1;
+                               cont = 0;
+                               break;
+                       }
+                       param = ret;
+                       idlestate = atoi(optarg);
+                       break;
+               case 'e':
+                       if (param) {
+                               param = -1;
+                               cont = 0;
+                               break;
+                       }
+                       param = ret;
+                       idlestate = atoi(optarg);
+                       break;
+               case -1:
+                       cont = 0;
+                       break;
+               }
+       } while (cont);
+
+       switch (param) {
+       case -1:
+               printf(_("You can't specify more than one "
+                        "output-specific argument\n"));
+               exit(EXIT_FAILURE);
+       case '?':
+               printf(_("invalid or unknown argument\n"));
+               exit(EXIT_FAILURE);
+       }
+
+       /* Default is: set all CPUs */
+       if (bitmask_isallclear(cpus_chosen))
+               bitmask_setall(cpus_chosen);
+
+       for (cpu = bitmask_first(cpus_chosen);
+            cpu <= bitmask_last(cpus_chosen); cpu++) {
+
+               if (!bitmask_isbitset(cpus_chosen, cpu))
+                       continue;
+
+               switch (param) {
+
+               case 'd':
+                       ret = sysfs_idlestate_disable(cpu, idlestate, 1);
+                       if (ret == 0)
+               printf(_("Idlestate %u disabled on CPU %u\n"),  idlestate, cpu);
+                       else if (ret == -1)
+               printf(_("Idlestate %u not available on CPU %u\n"),
+                      idlestate, cpu);
+                       else if (ret == -2)
+               printf(_("Idlestate disabling not supported by kernel\n"));
+                       else
+               printf(_("Idlestate %u not disabled on CPU %u\n"),
+                      idlestate, cpu);
+                       break;
+               case 'e':
+                       ret = sysfs_idlestate_disable(cpu, idlestate, 0);
+                       if (ret == 0)
+               printf(_("Idlestate %u enabled on CPU %u\n"),  idlestate, cpu);
+                       else if (ret == -1)
+               printf(_("Idlestate %u not available on CPU %u\n"),
+                      idlestate, cpu);
+                       else if (ret == -2)
+               printf(_("Idlestate enabling not supported by kernel\n"));
+                       else
+               printf(_("Idlestate %u not enabled on CPU %u\n"),
+                      idlestate, cpu);
+                       break;
+               default:
+                       /* Not reachable with proper args checking */
+                       printf(_("Invalid or unknown argument\n"));
+                       exit(EXIT_FAILURE);
+                       break;
+               }
+       }
+       return EXIT_SUCCESS;
+}
index 52bee59..7efc570 100644 (file)
 #include "helpers/helpers.h"
 #include "helpers/bitmask.h"
 
-struct cmd_struct {
-       const char *cmd;
-       int (*main)(int, const char **);
-       int needs_root;
-};
-
 #define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
 
 static int cmd_help(int argc, const char **argv);
@@ -43,10 +37,17 @@ int be_verbose;
 
 static void print_help(void);
 
+struct cmd_struct {
+       const char *cmd;
+       int (*main)(int, const char **);
+       int needs_root;
+};
+
 static struct cmd_struct commands[] = {
        { "frequency-info",     cmd_freq_info,  0       },
        { "frequency-set",      cmd_freq_set,   1       },
        { "idle-info",          cmd_idle_info,  0       },
+       { "idle-set",           cmd_idle_set,   1       },
        { "set",                cmd_set,        1       },
        { "info",               cmd_info,       0       },
        { "monitor",            cmd_monitor,    0       },
index 38ab916..5cdc600 100644 (file)
@@ -89,6 +89,33 @@ int sysfs_is_cpu_online(unsigned int cpu)
 
 /* CPUidle idlestate specific /sys/devices/system/cpu/cpuX/cpuidle/ access */
 
+
+/* CPUidle idlestate specific /sys/devices/system/cpu/cpuX/cpuidle/ access */
+
+/*
+ * helper function to check whether a file under "../cpuX/cpuidle/stateX/" dir
+ * exists.
+ * For example the functionality to disable c-states was introduced in later
+ * kernel versions, this function can be used to explicitly check for this
+ * feature.
+ *
+ * returns 1 if the file exists, 0 otherwise.
+ */
+unsigned int sysfs_idlestate_file_exists(unsigned int cpu,
+                                        unsigned int idlestate,
+                                        const char *fname)
+{
+       char path[SYSFS_PATH_MAX];
+       struct stat statbuf;
+
+
+       snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpuidle/state%u/%s",
+                cpu, idlestate, fname);
+       if (stat(path, &statbuf) != 0)
+               return 0;
+       return 1;
+}
+
 /*
  * helper function to read file from /sys into given buffer
  * fname is a relative path under "cpuX/cpuidle/stateX/" dir
@@ -121,6 +148,40 @@ unsigned int sysfs_idlestate_read_file(unsigned int cpu, unsigned int idlestate,
        return (unsigned int) numread;
 }
 
+/* 
+ * helper function to write a new value to a /sys file
+ * fname is a relative path under "../cpuX/cpuidle/cstateY/" dir
+ *
+ * Returns the number of bytes written or 0 on error
+ */
+static
+unsigned int sysfs_idlestate_write_file(unsigned int cpu,
+                                       unsigned int idlestate,
+                                       const char *fname,
+                                       const char *value, size_t len)
+{
+       char path[SYSFS_PATH_MAX];
+       int fd;
+       ssize_t numwrite;
+
+       snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpuidle/state%u/%s",
+                cpu, idlestate, fname);
+
+       fd = open(path, O_WRONLY);
+       if (fd == -1)
+               return 0;
+
+       numwrite = write(fd, value, len);
+       if (numwrite < 1) {
+               close(fd);
+               return 0;
+       }
+
+       close(fd);
+
+       return (unsigned int) numwrite;
+}
+
 /* read access to files which contain one numeric value */
 
 enum idlestate_value {
@@ -128,6 +189,7 @@ enum idlestate_value {
        IDLESTATE_POWER,
        IDLESTATE_LATENCY,
        IDLESTATE_TIME,
+       IDLESTATE_DISABLE,
        MAX_IDLESTATE_VALUE_FILES
 };
 
@@ -136,6 +198,7 @@ static const char *idlestate_value_files[MAX_IDLESTATE_VALUE_FILES] = {
        [IDLESTATE_POWER] = "power",
        [IDLESTATE_LATENCY] = "latency",
        [IDLESTATE_TIME]  = "time",
+       [IDLESTATE_DISABLE]  = "disable",
 };
 
 static unsigned long long sysfs_idlestate_get_one_value(unsigned int cpu,
@@ -205,8 +268,59 @@ static char *sysfs_idlestate_get_one_string(unsigned int cpu,
        return result;
 }
 
+/*
+ * Returns:
+ *    1  if disabled
+ *    0  if enabled
+ *    -1 if idlestate is not available
+ *    -2 if disabling is not supported by the kernel
+ */
+int sysfs_is_idlestate_disabled(unsigned int cpu,
+                               unsigned int idlestate)
+{
+       if (sysfs_get_idlestate_count(cpu) < idlestate)
+               return -1;
+
+       if (!sysfs_idlestate_file_exists(cpu, idlestate,
+                                idlestate_value_files[IDLESTATE_DISABLE]))
+               return -2;
+       return sysfs_idlestate_get_one_value(cpu, idlestate, IDLESTATE_DISABLE);
+}
+
+/*
+ * Pass 1 as last argument to disable or 0 to enable the state
+ * Returns:
+ *    0  on success
+ *    negative values on error, for example:
+ *      -1 if idlestate is not available
+ *      -2 if disabling is not supported by the kernel
+ *      -3 No write access to disable/enable C-states
+ */
+int sysfs_idlestate_disable(unsigned int cpu,
+                           unsigned int idlestate,
+                           unsigned int disable)
+{
+       char value[SYSFS_PATH_MAX];
+       int bytes_written;
+
+       if (sysfs_get_idlestate_count(cpu) < idlestate)
+               return -1;
+
+       if (!sysfs_idlestate_file_exists(cpu, idlestate,
+                                idlestate_value_files[IDLESTATE_DISABLE]))
+               return -2;
+
+       snprintf(value, SYSFS_PATH_MAX, "%u", disable);
+
+       bytes_written = sysfs_idlestate_write_file(cpu, idlestate, "disable",
+                                                  value, sizeof(disable));
+       if (bytes_written)
+               return 0;
+       return -3;
+}
+
 unsigned long sysfs_get_idlestate_latency(unsigned int cpu,
-                                       unsigned int idlestate)
+                                         unsigned int idlestate)
 {
        return sysfs_idlestate_get_one_value(cpu, idlestate, IDLESTATE_LATENCY);
 }
@@ -238,7 +352,7 @@ char *sysfs_get_idlestate_desc(unsigned int cpu, unsigned int idlestate)
  * Negativ in error case
  * Zero if cpuidle does not export any C-states
  */
-int sysfs_get_idlestate_count(unsigned int cpu)
+unsigned int sysfs_get_idlestate_count(unsigned int cpu)
 {
        char file[SYSFS_PATH_MAX];
        struct stat statbuf;
index 8cb797b..d28f11f 100644 (file)
@@ -7,8 +7,16 @@
 
 extern unsigned int sysfs_read_file(const char *path, char *buf, size_t buflen);
 
+extern unsigned int sysfs_idlestate_file_exists(unsigned int cpu,
+                                               unsigned int idlestate,
+                                               const char *fname);
+
 extern int sysfs_is_cpu_online(unsigned int cpu);
 
+extern int sysfs_is_idlestate_disabled(unsigned int cpu,
+                                      unsigned int idlestate);
+extern int sysfs_idlestate_disable(unsigned int cpu, unsigned int idlestate,
+                                  unsigned int disable);
 extern unsigned long sysfs_get_idlestate_latency(unsigned int cpu,
                                                unsigned int idlestate);
 extern unsigned long sysfs_get_idlestate_usage(unsigned int cpu,
@@ -19,7 +27,7 @@ extern char *sysfs_get_idlestate_name(unsigned int cpu,
                                unsigned int idlestate);
 extern char *sysfs_get_idlestate_desc(unsigned int cpu,
                                unsigned int idlestate);
-extern int sysfs_get_idlestate_count(unsigned int cpu);
+extern unsigned int sysfs_get_idlestate_count(unsigned int cpu);
 
 extern char *sysfs_get_cpuidle_governor(void);
 extern char *sysfs_get_cpuidle_driver(void);
diff --git a/tools/power/cpupower/utils/idle_monitor/hsw_ext_idle.c b/tools/power/cpupower/utils/idle_monitor/hsw_ext_idle.c
new file mode 100644 (file)
index 0000000..ebeaba6
--- /dev/null
@@ -0,0 +1,196 @@
+/*
+ *  (C) 2010,2011       Thomas Renninger <trenn@suse.de>, Novell Inc.
+ *
+ *  Licensed under the terms of the GNU GPL License version 2.
+ *
+ *  Based on SandyBridge monitor. Implements the new package C-states
+ *  (PC8, PC9, PC10) coming with a specific Haswell (family 0x45) CPU.
+ */
+
+#if defined(__i386__) || defined(__x86_64__)
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "helpers/helpers.h"
+#include "idle_monitor/cpupower-monitor.h"
+
+#define MSR_PKG_C8_RESIDENCY           0x00000630
+#define MSR_PKG_C9_RESIDENCY           0x00000631
+#define MSR_PKG_C10_RESIDENCY          0x00000632
+
+#define MSR_TSC        0x10
+
+enum intel_hsw_ext_id { PC8 = 0, PC9, PC10, HSW_EXT_CSTATE_COUNT,
+                       TSC = 0xFFFF };
+
+static int hsw_ext_get_count_percent(unsigned int self_id, double *percent,
+                                unsigned int cpu);
+
+static cstate_t hsw_ext_cstates[HSW_EXT_CSTATE_COUNT] = {
+       {
+               .name                   = "PC8",
+               .desc                   = N_("Processor Package C8"),
+               .id                     = PC8,
+               .range                  = RANGE_PACKAGE,
+               .get_count_percent      = hsw_ext_get_count_percent,
+       },
+       {
+               .name                   = "PC9",
+               .desc                   = N_("Processor Package C9"),
+               .desc                   = N_("Processor Package C2"),
+               .id                     = PC9,
+               .range                  = RANGE_PACKAGE,
+               .get_count_percent      = hsw_ext_get_count_percent,
+       },
+       {
+               .name                   = "PC10",
+               .desc                   = N_("Processor Package C10"),
+               .id                     = PC10,
+               .range                  = RANGE_PACKAGE,
+               .get_count_percent      = hsw_ext_get_count_percent,
+       },
+};
+
+static unsigned long long tsc_at_measure_start;
+static unsigned long long tsc_at_measure_end;
+static unsigned long long *previous_count[HSW_EXT_CSTATE_COUNT];
+static unsigned long long *current_count[HSW_EXT_CSTATE_COUNT];
+/* valid flag for all CPUs. If a MSR read failed it will be zero */
+static int *is_valid;
+
+static int hsw_ext_get_count(enum intel_hsw_ext_id id, unsigned long long *val,
+                       unsigned int cpu)
+{
+       int msr;
+
+       switch (id) {
+       case PC8:
+               msr = MSR_PKG_C8_RESIDENCY;
+               break;
+       case PC9:
+               msr = MSR_PKG_C9_RESIDENCY;
+               break;
+       case PC10:
+               msr = MSR_PKG_C10_RESIDENCY;
+               break;
+       case TSC:
+               msr = MSR_TSC;
+               break;
+       default:
+               return -1;
+       };
+       if (read_msr(cpu, msr, val))
+               return -1;
+       return 0;
+}
+
+static int hsw_ext_get_count_percent(unsigned int id, double *percent,
+                                unsigned int cpu)
+{
+       *percent = 0.0;
+
+       if (!is_valid[cpu])
+               return -1;
+
+       *percent = (100.0 *
+               (current_count[id][cpu] - previous_count[id][cpu])) /
+               (tsc_at_measure_end - tsc_at_measure_start);
+
+       dprint("%s: previous: %llu - current: %llu - (%u)\n",
+               hsw_ext_cstates[id].name, previous_count[id][cpu],
+               current_count[id][cpu], cpu);
+
+       dprint("%s: tsc_diff: %llu - count_diff: %llu - percent: %2.f (%u)\n",
+              hsw_ext_cstates[id].name,
+              (unsigned long long) tsc_at_measure_end - tsc_at_measure_start,
+              current_count[id][cpu] - previous_count[id][cpu],
+              *percent, cpu);
+
+       return 0;
+}
+
+static int hsw_ext_start(void)
+{
+       int num, cpu;
+       unsigned long long val;
+
+       for (num = 0; num < HSW_EXT_CSTATE_COUNT; num++) {
+               for (cpu = 0; cpu < cpu_count; cpu++) {
+                       hsw_ext_get_count(num, &val, cpu);
+                       previous_count[num][cpu] = val;
+               }
+       }
+       hsw_ext_get_count(TSC, &tsc_at_measure_start, 0);
+       return 0;
+}
+
+static int hsw_ext_stop(void)
+{
+       unsigned long long val;
+       int num, cpu;
+
+       hsw_ext_get_count(TSC, &tsc_at_measure_end, 0);
+
+       for (num = 0; num < HSW_EXT_CSTATE_COUNT; num++) {
+               for (cpu = 0; cpu < cpu_count; cpu++) {
+                       is_valid[cpu] = !hsw_ext_get_count(num, &val, cpu);
+                       current_count[num][cpu] = val;
+               }
+       }
+       return 0;
+}
+
+struct cpuidle_monitor intel_hsw_ext_monitor;
+
+static struct cpuidle_monitor *hsw_ext_register(void)
+{
+       int num;
+
+       if (cpupower_cpu_info.vendor != X86_VENDOR_INTEL
+           || cpupower_cpu_info.family != 6)
+               return NULL;
+
+       switch (cpupower_cpu_info.model) {
+       case 0x45: /* HSW */
+               break;
+       default:
+               return NULL;
+       }
+
+       is_valid = calloc(cpu_count, sizeof(int));
+       for (num = 0; num < HSW_EXT_CSTATE_COUNT; num++) {
+               previous_count[num] = calloc(cpu_count,
+                                       sizeof(unsigned long long));
+               current_count[num]  = calloc(cpu_count,
+                                       sizeof(unsigned long long));
+       }
+       intel_hsw_ext_monitor.name_len = strlen(intel_hsw_ext_monitor.name);
+       return &intel_hsw_ext_monitor;
+}
+
+void hsw_ext_unregister(void)
+{
+       int num;
+       free(is_valid);
+       for (num = 0; num < HSW_EXT_CSTATE_COUNT; num++) {
+               free(previous_count[num]);
+               free(current_count[num]);
+       }
+}
+
+struct cpuidle_monitor intel_hsw_ext_monitor = {
+       .name                   = "HaswellExtended",
+       .hw_states              = hsw_ext_cstates,
+       .hw_states_num          = HSW_EXT_CSTATE_COUNT,
+       .start                  = hsw_ext_start,
+       .stop                   = hsw_ext_stop,
+       .do_register            = hsw_ext_register,
+       .unregister             = hsw_ext_unregister,
+       .needs_root             = 1,
+       .overflow_s             = 922000000 /* 922337203 seconds TSC overflow
+                                              at 20GHz */
+};
+#endif /* defined(__i386__) || defined(__x86_64__) */
index e3f8d9b..0d6ba4d 100644 (file)
@@ -2,6 +2,7 @@
 DEF(amd_fam14h)
 DEF(intel_nhm)
 DEF(intel_snb)
+DEF(intel_hsw_ext)
 DEF(mperf)
 #endif
 DEF(cpuidle_sysfs)
index a99b43b..efc8a69 100644 (file)
@@ -155,6 +155,10 @@ static struct cpuidle_monitor *snb_register(void)
        case 0x2D: /* SNB Xeon */
        case 0x3A: /* IVB */
        case 0x3E: /* IVB Xeon */
+       case 0x3C: /* HSW */
+       case 0x3F: /* HSW */
+       case 0x45: /* HSW */
+       case 0x46: /* HSW */
                break;
        default:
                return NULL;
index f03e681..0d0506d 100644 (file)
@@ -59,7 +59,7 @@ QUIET_SUBDIR0  = +$(MAKE) $(COMMAND_O) -C # space to separate -C and subdir
 QUIET_SUBDIR1  =
 
 ifneq ($(findstring $(MAKEFLAGS),s),s)
-ifndef V
+ifneq ($(V),1)
        QUIET_CC       = @echo '   ' CC $@;
        QUIET_AR       = @echo '   ' AR $@;
        QUIET_LINK     = @echo '   ' LINK $@;
index 3039a7e..28ce95a 100644 (file)
@@ -1 +1,6 @@
 #include <linux/export.h>
+
+#define MODULE_LICENSE(__MODULE_LICENSE_value) \
+       static __attribute__((unused)) const char *__MODULE_LICENSE_name = \
+               __MODULE_LICENSE_value
+
index cd80183..8447830 100644 (file)
@@ -45,9 +45,6 @@ struct virtqueue {
        void *priv;
 };
 
-#define MODULE_LICENSE(__MODULE_LICENSE_value) \
-       const char *__MODULE_LICENSE_name = __MODULE_LICENSE_value
-
 /* Interfaces exported by virtio_ring. */
 int virtqueue_add_sgs(struct virtqueue *vq,
                      struct scatterlist *sgs[],